多数据源中间件标准版1.0

AcdCore.cpp 30KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. #include "StdAfx.h"
  2. #include "AcdCore.h"
  3. #include "Config.h"
  4. #include "Agent.h"
  5. #include "Exten.h"
  6. #include "NetworkAcd.h"
  7. #include "MsgCenter.h"
  8. #include "../Public/Auth/AuthMgr.h"
  9. #include "../Public/DaemonClient/DaemonClient.h"
  10. #include "SoftAuther.h"
  11. SINGLETON_IMPLEMENT(CAcdCore)
  12. CAcdCore::CAcdCore(void) : m_SubjectRepository(&m_AgentOffice, &m_ExtenCtrl, &m_QueueMgr)
  13. {
  14. //AllocConsole();//为当前的窗口程序申请一个Console窗口
  15. //freopen("CONOUT$", "w+", stdout);
  16. }
  17. CAcdCore::~CAcdCore(void)
  18. {
  19. }
  20. /*****************************************************************
  21. **【函数名称】 __onAgentStateUpdated
  22. **【函数功能】 座席状态变化事件响应
  23. **【参数】 AgentId: 座席工号
  24. ExtId: 分机号
  25. Status: 座席当前状态
  26. **【返回值】
  27. ****************************************************************/
  28. void CAcdCore::__onAgentStateUpdated( UINT AgentId )
  29. {
  30. CAgent* pAgent = m_AgentOffice.getAgentById(AgentId);
  31. if(pAgent == NULL)
  32. return;
  33. AGENT_STATE State = pAgent->state();
  34. // 通知事件订阅
  35. m_SubjectRepository.onAgentStateUpdated(pAgent->id(), pAgent->assoExten(), State);
  36. // 如果有座席变为空闲,通知来电队列刷新排队
  37. if(State == AGENT_STATE_FREE)
  38. m_QueueMgr.onAgentFree(pAgent);
  39. }
  40. /*****************************************************************
  41. **【函数名称】 __onPhoneStateUpdated
  42. **【函数功能】 分机状态变化事件响应
  43. **【参数】 AgentId: 座席工号
  44. ExtId: 分机号
  45. Status: 座席当前状态
  46. **【返回值】
  47. ****************************************************************/
  48. void CAcdCore::__onPhoneStateUpdated( UINT ExtenId )
  49. {
  50. CExten* pExten = m_ExtenCtrl.getExten(ExtenId);
  51. if(pExten == NULL)
  52. return;
  53. // 通知事件订阅
  54. m_SubjectRepository.onPhoneStateUpdated(pExten->assoAgent(), pExten->id(), pExten->state());
  55. }
  56. /*****************************************************************
  57. **【函数名称】 __onQueueStateUpdated
  58. **【函数功能】 排队状态变化事件响应
  59. **【参数】 Count: 等待排队的呼叫数量
  60. **【返回值】
  61. ****************************************************************/
  62. void CAcdCore::__onQueueStateUpdated( UINT QueueNo )
  63. {
  64. UINT Count = m_QueueMgr.callCount(QueueNo);
  65. // 通知事件订阅
  66. m_SubjectRepository.onQueueStateUpdated(QueueNo, Count);
  67. }
  68. /*****************************************************************
  69. **【函数名称】 __removeAgent
  70. **【函数功能】 关闭指定座席
  71. **【参数】 AgentId: 要关闭座席的工号
  72. ExtId: 要关闭座席的分机号
  73. HostAgent: 主控制坐席工号
  74. **【返回值】
  75. ****************************************************************/
  76. void CAcdCore::__removeAgent( UINT AgentId, UINT ExtId, UINT HostAgent )
  77. {
  78. if(!m_AgentOffice.isAgentExisted(AgentId))
  79. return;
  80. // 清空对应的座席信息
  81. m_ExtenCtrl.setAssoAgent(ExtId, 0); // 清除关联分机
  82. m_SubjectRepository.clearObserver(AgentId); // 清除订阅信息
  83. m_AgentOffice.removeAgent(AgentId, HostAgent); // 清除对应座席
  84. }
  85. /*****************************************************************
  86. **【函数名称】 __onCmdAgentReg
  87. **【函数功能】 PDU注册命令
  88. **【参数】 a_pCmd: PDU命令内容
  89. **【返回值】
  90. ****************************************************************/
  91. void CAcdCore::__onCmdAgentReg( CPduEntity* a_pCmd )
  92. {
  93. if(a_pCmd->GetLocalDevType() == PDU_DEV_TYPE_AGENT) // 仅处理座席注册
  94. {
  95. // 获取发送方的IP
  96. CString PeerIp = _T("");
  97. CNetworkAcd::GetInstance().getPduSource(a_pCmd, PeerIp);
  98. // 是否为相同主机的座席重复签入
  99. UINT AgentId = a_pCmd->GetLocalDevId();
  100. if(m_AgentOffice.isAgentExisted(AgentId, PeerIp))
  101. {
  102. //关闭原座席
  103. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 座席[%ld]重复登录, IP Address = %s"), AgentId, PeerIp);
  104. __removeAgent(AgentId, m_AgentOffice.getAgentAssoExten(AgentId), 0);
  105. } // end if
  106. // 查找当前座席是否已注册
  107. if(m_AgentOffice.isAgentExisted(AgentId))
  108. a_pCmd->SetDataBool(0, false);
  109. else
  110. a_pCmd->SetDataBool(0, true);
  111. // 返回执行结果
  112. a_pCmd->SetToExecReturn();
  113. CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  114. } // end if
  115. else if (a_pCmd->GetLocalDevType()==PDU_DEV_TYPE_SERVER)
  116. {
  117. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("-------------------Server已连接---------------------------"));
  118. a_pCmd->SetToExecReturn();
  119. a_pCmd->SetDataBool(0, true);
  120. CInterfaceWindow::getIocpCommInstance()->Send(a_pCmd, PDU_DEV_TYPE_SERVER, 0);
  121. }
  122. }
  123. /*****************************************************************
  124. **【函数名称】 __onCmdAgentDial
  125. **【函数功能】 处理呼叫相关的命令
  126. **【参数】 a_pCmd: PDU命令内容
  127. **【返回值】
  128. ****************************************************************/
  129. void CAcdCore::__onCmdAgentDial( CPduEntity* a_pCmd )
  130. {
  131. if(a_pCmd->GetIsExecReturn()) // CTI -> Agent 的返回命令
  132. {
  133. UINT DestDevId = a_pCmd->GetDataUInt(2);
  134. //CNetworkAcd::GetInstance().send2Agent(DestDevId, a_pCmd);
  135. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  136. }
  137. else // Agent -> CTI 的请求命令
  138. {
  139. CString DestNum = _T("");
  140. CString CmdHint = _T("");
  141. UINT AgentId = a_pCmd->GetDataUInt(2);
  142. switch(a_pCmd->GetCmdType())
  143. {
  144. case PDU_CMD_AGENT_TRANSTALK: // 座席转移
  145. {
  146. CmdHint = _T("座席转移");
  147. DestNum = a_pCmd->GetDataString(3);
  148. }
  149. break;
  150. case PDU_CMD_AGENT_THREETALK: // 三方会议
  151. {
  152. CmdHint = _T("座席三方");
  153. DestNum = a_pCmd->GetDataString(3);
  154. }
  155. break;
  156. case PDU_CMD_AGENT_CONSULTATION_CALL: // 协商呼叫
  157. {
  158. CmdHint = _T("座席协商");
  159. DestNum = a_pCmd->GetDataString(4);
  160. }
  161. break;
  162. case PDU_CMD_AGENT_MAKECALL: // 坐席外呼
  163. {
  164. CmdHint = _T("座席呼叫");
  165. DestNum = a_pCmd->GetDataString(4);
  166. // 如果主叫座席分机非空闲或摘机拨号,禁止呼出
  167. INNER_STATE ExtStatus = m_ExtenCtrl.getExtenState(a_pCmd->GetDataUInt(1));
  168. if (ExtStatus != INNER_STATE_FREE || ExtStatus == INNER_STATE_INIT)
  169. {
  170. a_pCmd->SetToExecReturn();
  171. a_pCmd->SetDataBool(0, false);
  172. //CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  173. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  174. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 座席[%ld]请求呼叫失败, 关联分机非空闲"), AgentId);
  175. return; // 不再向CTI转发
  176. } // end if
  177. if(!m_AgentOffice.setAgentState4Calling(AgentId))
  178. {
  179. a_pCmd->SetToExecReturn();
  180. a_pCmd->SetDataBool(0, false);
  181. //CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  182. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  183. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 座席[%u]请求呼叫失败, 座席状态异常或已被锁定"), AgentId);
  184. return; // 不再向CTI转发
  185. }
  186. }
  187. break;
  188. } // end switch
  189. if(!CConfig::isMatchCallPrefix(DestNum)) // 呼叫分机
  190. {
  191. if (false == m_ExtenCtrl.isExtenExisted(atoi(DestNum))) // 分机号不存在
  192. {
  193. a_pCmd->SetToExecReturn();
  194. a_pCmd->SetDataBool(0, false);
  195. // CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  196. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  197. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 请求呼叫分机 %s 失败,分机号不存在"), DestNum);
  198. return; // 不再向CTI转发
  199. }
  200. // 查找要呼叫的分机座席工号
  201. UINT DestAgentId = m_ExtenCtrl.getAssoAgent(atoi(DestNum));
  202. if(m_AgentOffice.isAgentExisted(DestAgentId) && !m_AgentOffice.lockAgent(DestAgentId)) // 被叫叫座席非空闲
  203. {
  204. a_pCmd->SetToExecReturn();
  205. a_pCmd->SetDataBool(0, false);
  206. // CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  207. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  208. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 座席[%u]请求呼叫失败, 目标座席[%u]非空闲,[%d]"), AgentId, DestAgentId, m_AgentOffice.getAgentState(DestAgentId));
  209. return; // 不再向CTI转发
  210. }
  211. } // end if
  212. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [%s], Agent = %lu, Exten = %lu, Dest Number = %s"),
  213. CmdHint, AgentId, a_pCmd->GetDataUInt(1), DestNum);
  214. CNetworkAcd::GetInstance().send2Cti(a_pCmd);
  215. } // end if
  216. }
  217. /*****************************************************************
  218. **【函数名称】 __onCmdAgentLogin
  219. **【函数功能】 座席签入命令
  220. **【参数】 a_pCmd: PDU命令内容
  221. **【返回值】
  222. ****************************************************************/
  223. void CAcdCore::__onCmdAgentLogin( CPduEntity* a_pCmd )
  224. {
  225. // 得到座席签入信息
  226. UINT ExtId = a_pCmd->GetDataUInt(1);
  227. UINT AgentId = a_pCmd->GetDataUInt(2);
  228. CString Group = a_pCmd->GetDataString(3);
  229. UINT AgentType = a_pCmd->GetDataUInt(4);
  230. UINT TimePostProcessing = a_pCmd->GetDataUInt(5);
  231. // 显示日志
  232. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL,
  233. _T("{Core}: AGENT -> ACD, CMD = [座席签入], Agent = %lu, Exten = %lu, Group = %s, Type = %lu"), AgentId, ExtId, Group, AgentType);
  234. // 校验
  235. bool IsSucceed = false;
  236. if(!CNetworkAcd::GetInstance().isCtiConnected()) // CTI是否已连接
  237. {
  238. a_pCmd->SetDataBool(0, false);
  239. a_pCmd->SetDataUInt(6, LOGIN_ERR_NO_CTI);
  240. }
  241. //#ifndef _DEBUG
  242. else if(m_AgentOffice.getAgentCount() >= m_Auther.GetAgentCount()) //ACD 授权数量验证
  243. {
  244. a_pCmd->SetDataBool(0, false);
  245. a_pCmd->SetDataUInt(6, LOGIN_ERR_AUTH_FAILED);
  246. }
  247. //#endif
  248. else if(!m_ExtenCtrl.isExtenExisted(ExtId)) // 查找要签入的分机是否存在
  249. {
  250. a_pCmd->SetDataBool(0, false);
  251. a_pCmd->SetDataUInt(6, LOGIN_ERR_NO_EXT);
  252. }
  253. else if(m_ExtenCtrl.isExtenUsed(ExtId)) // 分机是否已被占用
  254. {
  255. //a_pCmd->SetDataBool(0, false);
  256. //a_pCmd->SetDataUInt(6, LOGIN_ERR_BIND_EXT);
  257. UINT AgentID = m_ExtenCtrl.getAssoAgent(ExtId);
  258. __removeAgent(AgentID, ExtId, AgentID);
  259. a_pCmd->SetDataBool(0, true);
  260. IsSucceed = true;
  261. }
  262. else // 可以签入
  263. {
  264. a_pCmd->SetDataBool(0, true);
  265. IsSucceed = true;
  266. } // end if
  267. // 如果签入执行成功
  268. if(IsSucceed)
  269. {
  270. // 生成座席实例
  271. INNER_STATE ExtStatus = m_ExtenCtrl.getExtenState(ExtId);
  272. if(!m_AgentOffice.insertAgent(AgentId, ExtId, Group, AgentType, TimePostProcessing, ExtStatus))
  273. {
  274. a_pCmd->SetDataBool(0, false);
  275. a_pCmd->SetDataUInt(6, LOGIN_ERR_BIND_AGENT);
  276. }
  277. else
  278. {
  279. // 通知CTI座席已签入
  280. CNetworkAcd::GetInstance().send2Cti(a_pCmd);
  281. CPduEntity pdu(PDU_CMD_AGENT_RESET);
  282. pdu.SetDataUInt(1,a_pCmd->GetDataUInt(1));
  283. pdu.SetDataUInt(2,a_pCmd->GetDataUInt(2));
  284. CNetworkAcd::GetInstance().send2Cti(&pdu);
  285. // 建立分机与座席的关联
  286. m_ExtenCtrl.setAssoAgent(ExtId, AgentId);
  287. }
  288. } // end if
  289. // 返回签入执行结果
  290. a_pCmd->SetToExecReturn();
  291. //CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  292. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  293. }
  294. /*****************************************************************
  295. **【函数名称】 __onCmdAgentLogout
  296. **【函数功能】 座席签出命令
  297. **【参数】 a_pCmd: PDU命令内容
  298. **【返回值】
  299. ****************************************************************/
  300. void CAcdCore::__onCmdAgentLogout( CPduEntity* a_pCmd )
  301. {
  302. // 得到座席信息
  303. UINT ExtId = a_pCmd->GetDataUInt(1);
  304. UINT AgentId = a_pCmd->GetDataUInt(2);
  305. // 显示日志
  306. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [座席签出], Agent = %lu, Exten = %lu"), AgentId, ExtId);
  307. // ych 2018.5.16
  308. // m_AgentOffice.setAgentState(AgentId, AGENT_STATE_LOGOUT);
  309. if (m_AgentOffice.setAgentState(AgentId, AGENT_STATE_LOGOUT))
  310. {
  311. a_pCmd->SetDataBool(0, true);
  312. }
  313. else
  314. {
  315. a_pCmd->SetDataBool(0, false);
  316. //tj 通知Server
  317. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  318. return;
  319. }
  320. // 通知CTI座席签出
  321. CNetworkAcd::GetInstance().send2Cti(a_pCmd);
  322. //tj 通知Server
  323. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  324. // 清空对应的座席信息
  325. Sleep(100);
  326. __removeAgent(AgentId, ExtId, AgentId);
  327. }
  328. /*****************************************************************
  329. **【函数名称】 __onCmdAgentSetState
  330. **【函数功能】 主动设置座席状态
  331. **【参数】 a_pCmd: PDU命令内容
  332. **【返回值】
  333. ****************************************************************/
  334. void CAcdCore::__onCmdAgentSetState( CPduEntity* a_pCmd )
  335. {
  336. // 得到座席信息
  337. UINT AgentId = a_pCmd->GetDataUInt(2);
  338. AGENT_STATE State = static_cast<AGENT_STATE>(a_pCmd->GetDataUInt(3));
  339. // 显示日志
  340. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [座席状态设置], Agent = %lu, State = %d"), AgentId, State);
  341. // 设置座席逻辑状态
  342. if(m_AgentOffice.setAgentState(AgentId, State))
  343. a_pCmd->SetDataBool(0, true);
  344. else
  345. a_pCmd->SetDataBool(0, false);
  346. // 返回执行结果
  347. a_pCmd->SetToExecReturn();
  348. //CNetworkAcd::GetInstance().send2Agent(a_pCmd->GetLocalDevId(), a_pCmd);
  349. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  350. }
  351. /*****************************************************************
  352. **【函数名称】 __onCmdAgentSubscribe
  353. **【函数功能】 订阅管理
  354. **【参数】 a_pCmd: PDU命令内容
  355. **【返回值】
  356. ****************************************************************/
  357. void CAcdCore::__onCmdAgentSubscribe( CPduEntity* a_pCmd )
  358. {
  359. UINT AgentId = a_pCmd->GetDataUInt(2);
  360. SUBJECT_TYPE Type = static_cast<SUBJECT_TYPE>(a_pCmd->GetDataUInt(4));
  361. int PduType;
  362. // 订阅管理
  363. switch(a_pCmd->GetCmdType())
  364. {
  365. case PDU_CMD_AGENT_SUBSCRIBE: // 事件订阅
  366. PduType = 1;
  367. m_SubjectRepository.registObserver(AgentId, Type, a_pCmd->GetDataInt(3));
  368. break;
  369. case PDU_CMD_AGENT_CANCEL_SUBSCRIBE:// 取消订阅
  370. PduType = 2;
  371. m_SubjectRepository.removeObserver(AgentId, Type, a_pCmd->GetDataInt(3));
  372. break;
  373. } // end switch
  374. // 显示日志
  375. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [座席订阅], Agent = %lu, mode(1-订阅 2-取消) = %d, Type = %d"),
  376. AgentId, PduType, Type);
  377. }
  378. /*****************************************************************
  379. **【函数名称】 __onCmdAgentForceLogout
  380. **【函数功能】 强制签出指定座席
  381. **【参数】 a_pCmd: PDU命令内容
  382. **【返回值】
  383. ****************************************************************/
  384. void CAcdCore::__onCmdAgentForceLogout( CPduEntity* a_pCmd )
  385. {
  386. // 得到主控座席和受控座席信息
  387. UINT HostAgentId = a_pCmd->GetDataUInt(2);
  388. UINT TargetAgentId = a_pCmd->GetDataUInt(4);
  389. // 显示日志
  390. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [座席强制签出], Agent = %lu, TargetAgent = %lu"), HostAgentId, TargetAgentId);
  391. // 座席是否已签入
  392. if(!m_AgentOffice.isAgentExisted(TargetAgentId))
  393. {
  394. a_pCmd->SetDataBool(0, false);
  395. // 坐席不存在的情况下对坐席操作的错误日志
  396. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 强制坐席[%d]签出失败, 坐席[%d]未签入"), TargetAgentId, TargetAgentId);
  397. }
  398. else
  399. {
  400. // 通知被签出座席
  401. //CNetworkAcd::GetInstance().send2Agent(TargetAgentId, a_pCmd);
  402. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  403. UINT TargetExtId = m_AgentOffice.getAgentAssoExten(TargetAgentId);
  404. // 发送重置命令到CTI
  405. CPduEntity cmd(PDU_CMD_AGENT_RESET);
  406. cmd.SetDataUInt(1, TargetExtId);
  407. cmd.SetDataUInt(2, TargetAgentId);
  408. CNetworkAcd::GetInstance().send2Cti(&cmd);
  409. a_pCmd->SetDataBool(0, true);
  410. // 关闭座席
  411. __removeAgent(TargetAgentId, TargetExtId, HostAgentId);
  412. } // end if
  413. // 返回执行结果
  414. a_pCmd->SetToExecReturn();
  415. CNetworkAcd::GetInstance().send2Agent(HostAgentId, a_pCmd);
  416. }
  417. /*****************************************************************
  418. **【函数名称】 __onCmdAgentMonControl
  419. **【函数功能】 班长电话控制
  420. **【参数】 a_pCmd: PDU命令内容
  421. **【返回值】
  422. ****************************************************************/
  423. void CAcdCore::__onCmdAgentMonControl( CPduEntity* a_pCmd )
  424. {
  425. if(!a_pCmd->GetIsExecReturn()) // OCX发出的命令
  426. {
  427. // 得到主控座席和受控座席信息
  428. UINT HostAgentId = a_pCmd->GetDataUInt(2);
  429. UINT TargetAgentId = a_pCmd->GetDataUInt(4);
  430. // 显示日志
  431. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [%d](班长控制), Agent = %lu, TargetAgent = %lu"),
  432. a_pCmd->GetCmdType(), HostAgentId, TargetAgentId);
  433. // 确定目标座席已签入
  434. if(!m_AgentOffice.isAgentExisted(TargetAgentId))
  435. {
  436. // 添加坐席不存在的情况下对坐席操作的错误日志
  437. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 班长[%d]对坐席[%d]执行[%d]控制失败, 目标坐席未签入"),
  438. HostAgentId, TargetAgentId, a_pCmd->GetCmdType());
  439. // 返回执行结果
  440. a_pCmd->SetDataBool(0, false);
  441. a_pCmd->SetToExecReturn();
  442. //CNetworkAcd::GetInstance().send2Agent(HostAgentId, a_pCmd);
  443. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  444. return;
  445. }
  446. // 确保班长座席状态空闲
  447. if (!m_AgentOffice.setAgentState(HostAgentId, AGENT_STATE_FREE))
  448. {
  449. // 添加坐席不存在的情况下对坐席操作的错误日志
  450. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 班长[%d]对坐席[%d]执行[%d]控制失败, 班长状态非空闲"),
  451. HostAgentId, TargetAgentId, a_pCmd->GetCmdType());
  452. a_pCmd->SetDataBool(0, false);
  453. a_pCmd->SetToExecReturn();
  454. // CNetworkAcd::GetInstance().send2Agent(HostAgentId, a_pCmd);
  455. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  456. return;
  457. }
  458. // 转发命令到CTI
  459. a_pCmd->SetDataUInt(3, m_AgentOffice.getAgentAssoExten(TargetAgentId));
  460. CNetworkAcd::GetInstance().send2Cti(a_pCmd);
  461. }
  462. else // CTI的执行结果返回
  463. {
  464. //CNetworkAcd::GetInstance().send2Agent(a_pCmd->GetDataUInt(2), a_pCmd);
  465. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  466. } // end if
  467. }
  468. /*****************************************************************
  469. **【函数名称】 __onCmdAgentForceState
  470. **【函数功能】 强制座席状态控制
  471. **【参数】 a_pCmd PDU命令内容
  472. **【返回值】
  473. ****************************************************************/
  474. void CAcdCore::__onCmdAgentForceState( CPduEntity* a_pCmd )
  475. {
  476. // 得到主控座席和受控座席信息
  477. UINT HostAgentId = a_pCmd->GetDataUInt(2);
  478. UINT TargetAgentId = a_pCmd->GetDataUInt(4);
  479. AGENT_STATE State = static_cast<AGENT_STATE>(a_pCmd->GetDataUInt(5));
  480. // 显示日志
  481. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: AGENT -> ACD, CMD = [座席强制状态转换], Agent = %lu, TargetAgent = %lu, State = %d"),
  482. HostAgentId, TargetAgentId, State);
  483. // 座席是否已签入
  484. if(!m_AgentOffice.isAgentExisted(TargetAgentId))
  485. {
  486. a_pCmd->SetDataBool(0, false);
  487. // 添加坐席不存在的情况下对坐席操作的错误日志
  488. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 对坐席[%d]执行强制状态转换失败, 目标坐席没有签入"), TargetAgentId);
  489. }
  490. else
  491. {
  492. // 改变受控座席状态
  493. if(m_AgentOffice.setAgentState(TargetAgentId, State))
  494. a_pCmd->SetDataBool(0, true);
  495. else
  496. a_pCmd->SetDataBool(0, false);
  497. } // end if
  498. // 返回执行结果
  499. a_pCmd->SetToExecReturn();
  500. //CNetworkAcd::GetInstance().send2Agent(HostAgentId, a_pCmd);
  501. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  502. }
  503. /*****************************************************************
  504. **【函数名称】 __onCmdCtiExtenInfo
  505. **【函数功能】 内线分机状态变化命令
  506. **【参数】 a_pCmd: PDU命令内容
  507. **【返回值】
  508. ****************************************************************/
  509. void CAcdCore::__onCmdCtiExtenInfo( CPduEntity* a_pCmd )
  510. {
  511. UINT ExtID = a_pCmd->GetDataUInt(0);
  512. UINT State = a_pCmd->GetDataUInt(1);
  513. UINT Agentid = m_ExtenCtrl.getAssoAgent(ExtID); // 坐席工号
  514. if(State == INNER_STATE_REMOVE)
  515. {
  516. if (ExtID != 0)
  517. {
  518. if (Agentid != 0)
  519. __removeAgent(Agentid, ExtID, 0); // 迁出坐席
  520. //删除分机
  521. m_ExtenCtrl.removeExten(ExtID);
  522. }
  523. }
  524. else
  525. {
  526. // 显示日志
  527. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: CTI -> ACD, CMD = [线路状态信息], Exten = %lu, State = %lu"), ExtID, State);
  528. // 通知分机管理类
  529. m_ExtenCtrl.onExtenStateUpdated(a_pCmd);
  530. if (Agentid != 0)
  531. {
  532. m_AgentOffice.onExtenStateUpdated(Agentid, a_pCmd); // 通知座席管理类。报坐席和分机状态
  533. }
  534. }
  535. }
  536. /*****************************************************************
  537. **【函数名称】 __onCmdCtiRecord
  538. **【函数功能】 CTI通知座席录音信息
  539. **【参数】 a_pCmd: PDU命令内容
  540. **【返回值】
  541. ****************************************************************/
  542. void CAcdCore::__onCmdCtiRecord( CPduEntity* a_pCmd )
  543. {
  544. UINT Exten = a_pCmd->GetDataUInt(0);
  545. // 显示日志
  546. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: CTI -> ACD, CMD = [录音信息], Exten = %lu, CallId = %lu, FileName = %s"),
  547. Exten, a_pCmd->GetDataULong(1), a_pCmd->GetDataString(2));
  548. // 通过分机号查找对应的座席工号
  549. UINT AgentId = m_ExtenCtrl.getAssoAgent(Exten);
  550. if(AgentId != 0) // 有关联座席
  551. {
  552. //CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  553. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  554. }
  555. else // 录音未通知日志
  556. {
  557. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Core}: 录音信息[%s]未通知到坐席, 座席未签入"), a_pCmd->GetDataString(2));
  558. } // end if
  559. }
  560. /*****************************************************************
  561. **【函数名称】 __onCmdCtiDevCall
  562. **【函数功能】 CTI通知座席物理外呼信息
  563. **【参数】 a_pCmd: PDU命令内容
  564. **【返回值】
  565. ****************************************************************/
  566. void CAcdCore::__onCmdCtiDevCall( CPduEntity* a_pCmd )
  567. {
  568. UINT AgentId = a_pCmd->GetDataUInt(2);
  569. // 显示日志
  570. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: CTI -> ACD, CMD = [外呼信息], Exten = %lu, Agent = %lu, CallId = %lu, Number = %s"),
  571. a_pCmd->GetDataUInt(1), AgentId, a_pCmd->GetDataULong(3), a_pCmd->GetDataString(4));
  572. //CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  573. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  574. }
  575. /*****************************************************************
  576. **【函数名称】 __onCmdCtiTrunkUsage
  577. **【函数功能】 CTI通知呼叫任务中继利用率
  578. **【参数】 a_pCmd: PDU命令内容
  579. **【返回值】
  580. ****************************************************************/
  581. void CAcdCore::__onCmdCtiTrunkUsage( CPduEntity* a_pCmd )
  582. {
  583. UINT TaskId = a_pCmd->GetDataUInt(0);
  584. UINT Usage = a_pCmd->GetDataUInt(1);
  585. m_SubjectRepository.onTrunkUsageUpdated(TaskId, Usage);
  586. }
  587. /*****************************************************************
  588. **【函数名称】 __onCmdIvrQueue
  589. **【函数功能】 排队管理操作
  590. **【参数】 a_pCmd: PDU命令内容
  591. **【返回值】
  592. ****************************************************************/
  593. void CAcdCore::__onCmdIvrQueue( CPduEntity* a_pCmd )
  594. {
  595. PDU_CMD_TYPE CmdType = a_pCmd->GetCmdType();
  596. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Core}: CTI -> ACD, CMD = [%d](来电排队)"), CmdType);
  597. switch(CmdType)
  598. {
  599. case PDU_CMD_IVR_WANT_AGENT: // IVR请求座席
  600. {
  601. m_QueueMgr.onQueueAsking(a_pCmd);
  602. }
  603. break;
  604. case PDU_CMD_IVR_QUEUE_CONTINUE: // IVR通知CTI继续排队
  605. {
  606. m_QueueMgr.onQueueContinue(a_pCmd);
  607. }
  608. break;
  609. case PDU_CMD_IVR_QUEUE_CANCEL: // IVR通知CTI取消排队
  610. {
  611. m_QueueMgr.onQueueCancel(a_pCmd);
  612. }
  613. break;
  614. case PDU_CMD_CTI_ACD_QUEUE_PAUSE: // CTI通知ACD暂停排队
  615. {
  616. m_QueueMgr.onQueuePause(a_pCmd);
  617. }
  618. break;
  619. } // end switch
  620. }
  621. /*****************************************************************
  622. **【函数名称】 __onCmdNeed2Forward
  623. **【函数功能】 处理Agent与CTI相与转发的命令
  624. **【参数】 a_pCmd: PDU命令内容
  625. **【返回值】
  626. ****************************************************************/
  627. void CAcdCore::__onCmdNeed2Forward( CPduEntity* a_pCmd )
  628. {
  629. if(a_pCmd->GetIsExecReturn()) // CTI -> Agent 的返回命令
  630. {
  631. UINT AgentId = a_pCmd->GetDataUInt(2);
  632. //CNetworkAcd::GetInstance().send2Agent(AgentId, a_pCmd);
  633. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  634. }
  635. else // Agent -> CTI 的请求命令
  636. {
  637. CNetworkAcd::GetInstance().send2Cti(a_pCmd);
  638. } // end if
  639. }
  640. void CAcdCore::__onCmdDataSendToAgent(CPduEntity * a_pCmd)
  641. {
  642. int count = a_pCmd->GetDataUInt(0);
  643. if (a_pCmd->GetCmdType() == PDU_CMD_CTI_TRUNKUSE_COUNT)
  644. {
  645. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Core}:收到中继利用数量: %d"),count);
  646. }
  647. else if (a_pCmd->GetCmdType() == PDU_CMD_IVR_WAITER_COUNT)
  648. {
  649. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Core}:收到等待数量: %d"),count);
  650. }
  651. std::vector<int> VecAgentID = m_AgentOffice.getAgentIDAll();
  652. for (auto iter = VecAgentID.begin(); iter != VecAgentID.end(); iter++)
  653. {
  654. bool isSuccess = CNetworkAcd::GetInstance().send2Server(a_pCmd);
  655. if (isSuccess)
  656. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Core}: 通知坐席%d 成功,当前数量:%d"), *iter, count);
  657. else
  658. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Core}: 通知坐席%d 失败,当前数量:%d"), *iter, count);
  659. }
  660. }
  661. void CAcdCore::__onCmdGetAgentList(CPduEntity * a_pCmd)
  662. {
  663. CString str;
  664. m_AgentOffice.getAllAgentStateList(str);
  665. a_pCmd->SetDataString(2, str);
  666. CNetworkAcd::GetInstance().send2Server(a_pCmd);
  667. }
  668. /*****************************************************************
  669. **【函数名称】 stage1Start
  670. **【函数功能】 第一阶段启动
  671. **【参数】
  672. **【返回值】
  673. ****************************************************************/
  674. bool CAcdCore::stage1Start( void )
  675. {
  676. // 连接配置数据库
  677. if(!IOtlConnection::getInstance()->Connect())
  678. {
  679. AfxMessageBox(STR_ERR_CORE_INIT_DB);
  680. return false;
  681. }
  682. // 加载配置
  683. if(!CConfig::load())
  684. {
  685. IOtlConnection::getInstance()->Disconnect();
  686. AfxMessageBox(STR_ERR_CORE_INIT_CFG);
  687. return false;
  688. }
  689. return true;
  690. }
  691. /*****************************************************************
  692. **【函数名称】 stage2Start
  693. **【函数功能】 第二阶段启动
  694. **【参数】 ErrInfo: 出错信息
  695. **【返回值】
  696. ****************************************************************/
  697. bool CAcdCore::stage2Start( void )
  698. {
  699. // 建立网络通讯
  700. if(!CNetworkAcd::GetInstance().init())
  701. {
  702. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_ERROR, _T("%s"), STR_ERR_CORE_INIT_NETWORK);
  703. return false;
  704. }
  705. //#ifndef _DEBUG
  706. m_Auther.InitAutherData("C://Windows//mshy.dll");
  707. // m_Auther.__setTimer(86400000); //一天
  708. m_Auther.__setTimer(10000);
  709. //#endif
  710. CMsgCenter::GetInstance().regist(ACD_MSG_AGENT_STATE_UPDAET, this);
  711. CMsgCenter::GetInstance().regist(ACD_MSG_EXTEN_STATE_UPDATE, this);
  712. CMsgCenter::GetInstance().regist(ACD_MSG_QUEUE_UPDATE, this);
  713. CDaemonClient::GetInstance().doWork();
  714. return true;
  715. }
  716. void CAcdCore::reloadAuther()
  717. {
  718. m_Auther.InitAutherData("C://Windows//mshy.dll");
  719. }
  720. /*****************************************************************
  721. **【函数名称】 exit
  722. **【函数功能】 退出ACD
  723. **【参数】
  724. **【返回值】
  725. ****************************************************************/
  726. void CAcdCore::exit( void )
  727. {
  728. CNetworkAcd::GetInstance().release();
  729. m_QueueMgr.clear();
  730. m_AgentOffice.close();
  731. m_ExtenCtrl.removeExten();
  732. IOtlConnection::getInstance()->Disconnect();
  733. }
  734. /*****************************************************************
  735. **【函数名称】 onNetLinkDown
  736. **【函数功能】 连接断开后续处理
  737. **【参数】
  738. **【返回值】
  739. ****************************************************************/
  740. void CAcdCore::onNetLinkDown( PduLinkContent linkContent )
  741. {
  742. if(linkContent.nFarType == PDU_DEV_TYPE_CTI) // 对CTI的处理
  743. {
  744. m_AgentOffice.clearAgent(); // 清空所有座席信息
  745. m_ExtenCtrl.removeExten(); // 清空所有分机信息
  746. m_QueueMgr.clear(); // 清空所有来电排队信息
  747. }
  748. else if(linkContent.nFarType == PDU_DEV_TYPE_AGENT) // 对Agent的处理
  749. {
  750. // 清空对应的座席信息
  751. UINT AssoExten = m_AgentOffice.getAgentAssoExten(linkContent.nFarId);
  752. __removeAgent(linkContent.nFarId, AssoExten, 0);
  753. } // end if
  754. }
  755. /*****************************************************************
  756. **【函数名称】 onRecvCommand
  757. **【函数功能】 PDU命令到达事件处理
  758. **【参数】
  759. **【返回值】
  760. ****************************************************************/
  761. void CAcdCore::onRecvCommand( CPduEntity* a_pPduEntity )
  762. {
  763. switch(a_pPduEntity->GetCmdType())
  764. {
  765. case PDU_CMD_CTI_LINE_STATE: // CTI通知分机信息
  766. __onCmdCtiExtenInfo(a_pPduEntity);
  767. break;
  768. case PDU_CMD_CTI_ACD_TRUNK_USAGE: // CTI通知呼叫任务中继利用率
  769. __onCmdCtiTrunkUsage(a_pPduEntity);
  770. break;
  771. case PDU_CMD_AGENT_SETSTATE: // 设置座席状态
  772. __onCmdAgentSetState(a_pPduEntity);
  773. break;
  774. case PDU_CMD_IVR_WANT_AGENT: // IVR请求座席
  775. case PDU_CMD_IVR_QUEUE_CONTINUE: // IVR通知CTI继续排队
  776. case PDU_CMD_IVR_QUEUE_CANCEL: // IVR通知CTI取消排队
  777. case PDU_CMD_CTI_ACD_QUEUE_PAUSE: // CTI通知ACD暂停排队
  778. __onCmdIvrQueue(a_pPduEntity);
  779. break;
  780. case PDU_CMD_AGENT_RESET: // 座席重置
  781. case PDU_CMD_AGENT_ANSWER: // 座席应答
  782. case PDU_CMD_AGENT_HOLD: // 保持
  783. case PDU_CMD_AGENT_TAKEBACK: // 接回
  784. case PDU_CMD_AGENT_HANGUP: // 座席挂机
  785. case PDU_CMD_AGENT_CANCEL: // 坐席取消操作
  786. case PDU_CMD_AGENT_FAX: // 收发传真
  787. case PDU_CMD_AGENT_TURN_TO_IVR: // 转IVR
  788. case PDU_CMD_AGENT_CONFIRM_TRANSFER: // 确认转移
  789. case PDU_CMD_AGENT_MUTE: // 静音
  790. __onCmdNeed2Forward(a_pPduEntity);
  791. break;
  792. case PDU_CMD_AGENT_TRANSTALK: // 座席转移
  793. case PDU_CMD_AGENT_THREETALK: // 单步会议
  794. case PDU_CMD_AGENT_MAKECALL: // 坐席外呼
  795. case PDU_CMD_AGENT_CONSULTATION_CALL: // 协商呼叫
  796. __onCmdAgentDial(a_pPduEntity);
  797. break;
  798. case PDU_CMD_AGENT_MONI_LISTEN: // 监听
  799. case PDU_CMD_AGENT_MONI_INSERT: // 强插
  800. case PDU_CMD_AGENT_MONI_CUT: // 强拆
  801. case PDU_CMD_AGENT_MONI_REPLACE: // 代接
  802. case PDU_CMD_AGENT_MONI_INTERCEPT: // 强截
  803. __onCmdAgentMonControl(a_pPduEntity);
  804. break;
  805. case PDU_CMD_AGENT_MONI_FORCE_STATE: // 班长强制状态控制
  806. __onCmdAgentForceState(a_pPduEntity);
  807. break;
  808. case PDU_CMD_AGENT_MONI_FORCE_LOGOUT: // 强制签出
  809. __onCmdAgentForceLogout(a_pPduEntity);
  810. break;
  811. case PDU_CMD_AGENT_SUBSCRIBE: // 事件订阅
  812. case PDU_CMD_AGENT_CANCEL_SUBSCRIBE: // 取消订阅
  813. __onCmdAgentSubscribe(a_pPduEntity);
  814. break;
  815. case PDU_CMD_REG: // 注册命令
  816. __onCmdAgentReg(a_pPduEntity);
  817. break;
  818. case PDU_CMD_AGENT_LOGIN: // 座席签入
  819. __onCmdAgentLogin(a_pPduEntity);
  820. break;
  821. case PDU_CMD_AGENT_LOGOUT: // 座席签出
  822. __onCmdAgentLogout(a_pPduEntity);
  823. break;
  824. case PDU_CMD_CTI_DEV_CALL: // Cti通知物理外呼结果
  825. __onCmdCtiDevCall(a_pPduEntity);
  826. break;
  827. case PDU_CMD_CTI_RECORD: // CTI通知座席录音信息
  828. __onCmdCtiRecord(a_pPduEntity);
  829. break;
  830. case PDU_CMD_IVR_WAITER_COUNT: //向Agent转发的数据
  831. __onCmdDataSendToAgent(a_pPduEntity);
  832. break;
  833. case PDU_CMD_AGENT_GET_AGENTLIST:
  834. __onCmdGetAgentList(a_pPduEntity);
  835. break;
  836. default:
  837. return;
  838. } // end switch
  839. }
  840. /*****************************************************************
  841. **【函数名称】 onMessage
  842. **【函数功能】 系统消息处理
  843. **【参数】
  844. **【返回值】
  845. *****************************************************************/
  846. void CAcdCore::onMessage( UINT MsgType, const PARAM lpContent )
  847. {
  848. switch(MsgType)
  849. {
  850. case ACD_MSG_AGENT_STATE_UPDAET:
  851. __onAgentStateUpdated((UINT)lpContent);
  852. break;
  853. case ACD_MSG_EXTEN_STATE_UPDATE:
  854. __onPhoneStateUpdated((UINT)lpContent);
  855. break;
  856. case ACD_MSG_QUEUE_UPDATE:
  857. __onQueueStateUpdated((UINT)lpContent);
  858. break;
  859. }
  860. }