华辉中间件项目(代码服务器上没有,用杨成电脑的源代码上传的)

AcdCore.cpp 28KB

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