| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- #include "StdAfx.h"
- #include "Queue.h"
- #include "IncomingCall.h"
- #include "AcdCore.h"
- #include "StrategyLoop.h"
- #include "StrategyMaxFree.h"
- #include "StrategyMinAnswer.h"
- #include "StrategySpecifiedAgent.h"
- #include "StrategyLoopByAgentId.h"
- CQueue::CQueue(UINT QueueNo) : m_QueueNo(QueueNo)
- {
- __initStrategy();
- }
- CQueue::~CQueue(void)
- {
- __freeStrategy();
- }
- /*****************************************************************
- **【函数名称】 __initStrategy
- **【函数功能】 初始化座席分配策略
- **【参数】
- **【返回值】
- ****************************************************************/
- void CQueue::__initStrategy(void)
- {
- CStrategyAD* pStrategy = NULL;
- // 循环接听
- pStrategy = new CStrategyLoop();
- m_StrategyMap.SetAt(AGENT_STRATEGY_LOOP, pStrategy);
- // 2020-01-13 循环接听,按照座席id大小顺序
- pStrategy = new CStrategyLoopByAgentId();
- m_StrategyMap.SetAt(AGENT_STRATEGY_LOOPBYAGENTID, pStrategy);
- // 目前空闲时间最长的座席
- pStrategy = new CStrategyMaxFree();
- m_StrategyMap.SetAt(AGENT_STRATEGY_MAX_CUR_FREE_TIME, pStrategy);
- // 目前接听次数最少的坐席
- pStrategy = new CStrategyMinAnswer();
- m_StrategyMap.SetAt(AGENT_STRATEGY_MINI_CALLS, pStrategy);
- // 指定座席
- pStrategy = new CStrategySpecifiedAgent();
- m_StrategyMap.SetAt(AGENT_STRATEGY_KNOWN, pStrategy);
- }
- /*****************************************************************
- **【函数名称】 __freeStrategy
- **【函数功能】 释放座席分配策略
- **【参数】
- **【返回值】
- ****************************************************************/
- void CQueue::__freeStrategy(void)
- {
- AGENT_STRATEGY Key;
- CStrategyAD* pStrategy = NULL;
- POSITION Pos = m_StrategyMap.GetStartPosition();
- while (Pos != NULL)
- {
- m_StrategyMap.GetNextAssoc(Pos, Key, pStrategy);
- ASSERT(pStrategy != NULL);
- delete pStrategy;
- pStrategy = NULL;
- }
- m_StrategyMap.RemoveAll();
- }
- /*****************************************************************
- **【函数名称】 __getStrategy
- **【函数功能】 获取指定的座席分配策略
- **【参数】
- **【返回值】
- ****************************************************************/
- CStrategyAD* CQueue::__getStrategy(AGENT_STRATEGY StrategyId)
- {
- // 找到对应的座席分配策略
- CStrategyAD* pStrategy = NULL;
- if (!m_StrategyMap.Lookup(StrategyId, pStrategy))
- pStrategy = m_StrategyMap[AGENT_STRATEGY_LOOP]; // 如果指定的策略不存在,则选取循环接听策略
- return pStrategy;
- }
- /*****************************************************************
- **【函数名称】 __onAgentDispatched
- **【函数功能】 处理请求座席结果
- **【参数】 Result: 请求座席结果
- Agent: 请求到的座席ID
- Exten: 请求到的座席分机号
- CallIndex: 请求座席的来电索引
- **【返回值】
- ****************************************************************/
- void CQueue::__onAgentDispatched(QUEUE_AGENT_RESULT Result, UINT Agent, UINT Exten, CIncomingCall* pCall)
- {
- switch (Result)
- {
- case QUEUE_AGENT_OK: // 请求座席成功
- {
- pCall->onQueueOK(Agent, Exten);
- m_CallGroup.delCall(pCall->index());
- }
- break;
- case QUEUE_AGENT_FAILED_NO_AGENT: // 无签入座席
- case QUEUE_AGENT_FAILED_NO_FREE: // 座席全忙
- case QUEUE_AGETN_FAILED_NO_SPEC: // 在指定策略下无匹配座席
- {
- pCall->onQueueFailed(Result, Agent);
- }
- break;
- } // end switch
- }
- /*****************************************************************
- **【函数名称】 clear
- **【函数功能】 清除所有资源
- **【参数】
- **【返回值】
- ****************************************************************/
- void CQueue::clear(void)
- {
- m_CallGroup.clear();
- m_AgentGroup.clear();
- }
- CString CQueue::callIndex()
- {
- int index = 0;
- CIncomingCall* pIncomingCall = NULL;
- CString str;
- /*
- POSITION pos = m_CallGroup.GetHeadPosition();
- while (pos != NULL)
- {
- index++;
- pIncomingCall = m_CallGroup.GetNext(pos);
- if (pIncomingCall)
- {
- str.Format("%d|%d#%s", pIncomingCall->index(), index,str);
- }
- }
- */
- std::stringstream ss;
- POSITION pos = m_CallGroup.GetHeadPosition();
- while (pos != NULL)
- {
- index++;
- pIncomingCall = m_CallGroup.GetNext(pos);
- if (pIncomingCall)
- {
- ss << pIncomingCall->index() << "|" << index << "#";
- }
- }
- str.Format("%s", ss.str().c_str());
- ss.str("");
- return str;
- }
- /*****************************************************************
- **【函数名称】 onQueueRequest
- **【函数功能】 呼叫请求排队响应
- **【参数】 pCmd: PDU命令内容
- **【返回值】 被操作呼叫
- ****************************************************************/
- void CQueue::onQueueRequest(CPduEntity* pCmd)
- {
- int CallPos = 0;
- // 是否为重复请求座席
- CIncomingCall* pCall = m_CallGroup.getCall(pCmd->GetDataInt(1));
- if (pCall != NULL)
- {
- pCall->updateQueueInfo(pCmd); // 重置座席分配策略及信息
- }
- else
- {
- pCall = m_CallGroup.addCall(pCmd, CallPos);
- ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, "{CQueue}: 呼叫请求排队, m_QueueNo=%d,Index = %d,Caller=%s,CallPos = %d", m_QueueNo, pCmd->GetDataInt(1), pCmd->GetDataString(6), CallPos);
- } // end if
- // 当前来电是否可以请求座席(如果不能,直接返回请求座席失败)
- if (pCall != m_CallGroup.getTopWaitedCall())
- {
- QUEUE_AGENT_RESULT Result = QUEUE_AGENT_FAILED_NO_FREE;
- if (m_AgentGroup.GetCount() == 0)
- Result = QUEUE_AGENT_FAILED_NO_AGENT;
- __onAgentDispatched(Result, CallPos, 0, pCall);
- } // end if
- else
- {
- // 处理排队请求
- distributeAgent();
- }
- }
- /*****************************************************************
- **【函数名称】 onQueueCancel
- **【函数功能】 呼叫取消排队
- **【参数】 pCmd: PDU命令内容
- **【返回值】
- ****************************************************************/
- bool CQueue::onQueueCancel(CPduEntity* pCmd)
- {
- // 删除呼叫
- ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, "{CQueue}: 呼叫取消排队, m_QueueNo=%d,Index = %d,Caller=%s", m_QueueNo, pCmd->GetDataInt(1), pCmd->GetDataString(6));
- return m_CallGroup.delCall(pCmd->GetDataInt(1));
- }
- /*****************************************************************
- **【函数名称】 onQueuePause
- **【函数功能】 呼叫暂停排队
- **【参数】 pCmd: PDU命令内容
- **【返回值】
- ****************************************************************/
- bool CQueue::onQueuePause(CPduEntity* pCmd)
- {
- CIncomingCall* pCall = m_CallGroup.getCall(pCmd->GetDataInt(0));
- if (pCall == NULL)
- return false;
- pCall->setCallState(OUTER_CALL_PAUSE);
- return true;
- }
- /*****************************************************************
- **【函数名称】 onQueueContinue
- **【函数功能】 呼叫继续排队
- **【参数】 pCmd: PDU命令内容
- **【返回值】
- ****************************************************************/
- bool CQueue::onQueueContinue(CPduEntity* pCmd)
- {
- CIncomingCall* pCall = m_CallGroup.getCall(pCmd->GetDataInt(1));
- if (pCall == NULL)
- return false;
- if (pCall->callId() != pCmd->GetDataULong(2)) { // 2023-05-25 判断获取到的来电callid是否和请求的相同,不相同删除
- m_CallGroup.delCall(pCmd->GetDataInt(1));
- ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_ERROR, _T("{继续排队故障,根据ivr索引获取到来电callid[%ld]与真实callid不同[%ld]"), pCall->callId(), pCmd->GetDataULong(2));
- return false;
- }
- pCall->updateQueueInfo(pCmd);
- // 主动请求坐席
- distributeAgent();
- return true;
- }
- /*****************************************************************
- **【函数名称】 addAgent
- **【函数功能】 添加座席
- **【参数】
- **【返回值】
- ****************************************************************/
- void CQueue::addAgent(CAgent* pAgent)
- {
- m_AgentGroup.add(pAgent);
-
- // 2022-09-07 保存签入后坐席所在组的位置
- saveCurAllAgent();
- }
- /*****************************************************************
- **【函数名称】 delAgent
- **【函数功能】 删除座席
- **【参数】
- **【返回值】
- ****************************************************************/
- void CQueue::delAgent(CAgent* pAgent, bool isSave)
- {
- m_AgentGroup.remove(pAgent);
- // 2022-09-07 保存签入后坐席所在组的位置
- if(isSave)
- saveCurAllAgent();
- }
- /*****************************************************************
- **【函数名称】 distributeAgent
- **【函数功能】
- **【参数】
- **【返回值】
- ****************************************************************/
- void CQueue::distributeAgent(void)
- {
- // 查找当前要排队的呼叫
- CIncomingCall* pCall = m_CallGroup.getTopWaitedCall();
- if (pCall == NULL)
- return;
- pCall->setCallState(OUTER_CALL_QUEUE);
- CStrategyAD* pStrategy = __getStrategy(pCall->agentStrategy()); // 请求座席的排队策略
- ASSERT(pStrategy != NULL);
- // 显示日志
- ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{坐席排队策略号: %lu, m_QueueNo=%d[%d],Index = %d,CallID=%ld,Caller=%s"), pCall->agentStrategy(), m_QueueNo, pCall->groupAsked(), pCall->index(), pCall->callId(), pCall->callerNum());
- // 开始请求座席
- UINT Agent = 0; // 要返回的座席工号
- UINT Exten = 0; // 要返回的座席分机号
- QUEUE_AGENT_RESULT Result = m_AgentGroup.distributeAgent(pStrategy, pCall->infoEx(), Agent, Exten);
- //2022-01-01
- if (QUEUE_AGENT_OK != Result)
- {
- int index = 0;
- POSITION pos, nextPos;
- pos = m_CallGroup.GetHeadPosition();
- while (pos)
- {
- index++;
- auto a = m_CallGroup.GetAt(pos);
- nextPos = pos;
- m_CallGroup.GetNext(nextPos);
- if (a->index() == pCall->index())
- {
- break;
- }
- pos = nextPos;
- }
- Agent = index;
- }
- else {
- saveCurAllAgent();
- ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{坐席排队成功,策略号: %lu, m_QueueNo=%d[%d],Index=%d,CallID=%ld,Caller=%s,Agent[%u|%u]"), pCall->agentStrategy(), m_QueueNo, pCall->groupAsked(), pCall->index(), pCall->callId(), pCall->callerNum(), Agent, Exten);
- }
- // 处理请求结果
- __onAgentDispatched(Result, Agent, Exten, pCall);
- }
- std::string CQueue::saveCurAllAgent()
- {
- // 2022-09-07 保存签入后坐席所在组的位置
- std::string allAgent = m_AgentGroup.GetCurAllAgent();
- std::string no = std::to_string(m_QueueNo);
- pushOnlineAgentGroupDetail(no, allAgent);
- return "";
- }
|