MiddleWares_YiHe 郑州颐和医院随访系统中间件

AcdCore.cpp 29KB

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