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

IvrFlow.cpp 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. #include "StdAfx.h"
  2. #include "IvrFlow.h"
  3. #include "CellBase.h"
  4. #include "FlowTemplate.h"
  5. #include "MsgCenter.h"
  6. #include "NetworkIvr.h"
  7. #include "CellTimer.h"
  8. #include "IvrCore.h"
  9. IMPLEMENT_DYNAMIC(CIvrFlow, CWnd)
  10. CIvrFlow::CIvrFlow(int Id) : m_Id(Id), m_State(IVR_FLOW_STATE_FREE), m_IsHangUp(false), m_IsNetLinkUp(false), m_AssoCallId(0), m_pFlowTemplate(NULL), m_pCurrentCell(NULL)
  11. {
  12. CreateEx(0, AfxRegisterWndClass(CS_GLOBALCLASS), "", 0, 0, 0, 0, 0, 0, 0);
  13. }
  14. CIvrFlow::~CIvrFlow(void)
  15. {
  16. __release();
  17. DestroyWindow();
  18. }
  19. BEGIN_MESSAGE_MAP(CIvrFlow, CWnd)
  20. ON_WM_TIMER()
  21. END_MESSAGE_MAP()
  22. /*****************************************************************
  23. **【函数名称】 __release
  24. **【函数功能】 释放资源
  25. **【参数】
  26. **【返回值】
  27. ****************************************************************/
  28. void CIvrFlow::__release( void )
  29. {
  30. if(m_pCurrentCell != NULL)
  31. __deleteCurrentCell();
  32. m_VarTable.RemoveAll();
  33. }
  34. /*****************************************************************
  35. **【函数名称】 __clearFlow
  36. **【函数功能】 流程结束时对流程进行清理
  37. **【参数】
  38. **【返回值】
  39. ****************************************************************/
  40. void CIvrFlow::__clearFlow( void )
  41. {
  42. m_AssoCallId = 0;
  43. m_IsHangUp = false;
  44. m_State = IVR_FLOW_STATE_FREE;
  45. __release();
  46. CMsgCenter::GetInstance().pushMsg(IVR_MSG_FLOW_STATE_UPDAET, reinterpret_cast<const PARAM>(m_Id));
  47. CMsgCenter::GetInstance().pushMsg(IVR_MSG_FLOW_CELL_UPDATE, reinterpret_cast<const PARAM>(m_Id));
  48. if(m_IsNetLinkUp && m_pFlowTemplate != NULL && m_pFlowTemplate->type() == FLOW_AUTO)
  49. start();
  50. }
  51. /*****************************************************************
  52. **【函数名称】 __onTimerTimeOut
  53. **【函数功能】 流程节点最大执行时间超时处理函数
  54. **【参数】
  55. **【返回值】
  56. ****************************************************************/
  57. void CIvrFlow::__onTimerTimeOut( void )
  58. {
  59. ASSERT(m_pCurrentCell != NULL);
  60. ASSERT(m_pFlowTemplate != NULL);
  61. // by 屏蔽流程释放的命令
  62. //if(m_pFlowTemplate->type() != FLOW_SUB) // 执行子流程时不上报流程结束
  63. //{
  64. // CPduEntity cmdFlowEnd(PDU_CMD_IVR_END);
  65. // cmdFlowEnd.SetDataInt(1, m_Id);
  66. // CNetworkIvr::GetInstance().send(cmdFlowEnd);
  67. //}
  68. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{FLow}: 节点[%s]超过最大执行时间, 流程[%d]将被释放"), m_pCurrentCell->name(), m_Id);
  69. // by 屏蔽掉清除掉Flow的函数
  70. //__clearFlow();
  71. }
  72. /*****************************************************************
  73. **【函数名称】 __onNextCellNull
  74. **【函数功能】 当下个节点为空的处理
  75. **【参数】
  76. **【返回值】
  77. ****************************************************************/
  78. void CIvrFlow::__onNextCellNull( int NullCellPos )
  79. {
  80. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{FLow}: 查找节点[%d]失败, 流程[%d]将被释放"), NullCellPos, m_Id);
  81. CPduEntity CmdHangUp(PDU_CMD_IVR_HANGUP);
  82. CmdHangUp.SetDataInt(1, m_Id);
  83. CNetworkIvr::GetInstance().send(CmdHangUp);
  84. __clearFlow();
  85. }
  86. /*****************************************************************
  87. **【函数名称】 __deleteCurrentCell
  88. **【函数功能】 删除当前节点
  89. **【参数】
  90. **【返回值】
  91. ****************************************************************/
  92. void CIvrFlow::__deleteCurrentCell( void )
  93. {
  94. ASSERT(m_pCurrentCell != NULL);
  95. if(m_pCurrentCell->maxWaitingTime() > 0)
  96. KillTimer((long)m_pCurrentCell);
  97. delete m_pCurrentCell;
  98. m_pCurrentCell = NULL;
  99. }
  100. /*****************************************************************
  101. **【函数名称】 start
  102. **【函数功能】 开始执行流程
  103. **【参数】 pFlowTemp: 流程模板
  104. **【返回值】 下一个节点编号
  105. ****************************************************************/
  106. int CIvrFlow::start( CFlowTemplate* pFlowTemp /*= NULL*/, int StartPos/* = 1*/ )
  107. {
  108. if(pFlowTemp != NULL)
  109. m_pFlowTemplate = pFlowTemp;
  110. if(m_pFlowTemplate == NULL)
  111. {
  112. ASSERT(FALSE);
  113. return CELL_OP_ERROR;
  114. }
  115. CString CellName = "";
  116. switch(m_pFlowTemplate->type())
  117. {
  118. case FLOW_NORMAL:
  119. case FLOW_SUB:
  120. CellName = CELL_NAME_START;
  121. break;
  122. case FLOW_AUTO:
  123. CellName = CELL_NAME_TIMER;
  124. break;
  125. }
  126. int Pos = m_pFlowTemplate->getCellPos(CellName);
  127. if(Pos < 1)
  128. {
  129. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Flow}: 执行流程[%d]时未找到起始节点, Template = %s"), m_Id, m_pFlowTemplate->name());
  130. return CELL_OP_ERROR;
  131. }
  132. Pos = (StartPos == 1) ? Pos : StartPos;
  133. m_State = IVR_FLOW_STATE_RUN;
  134. CMsgCenter::GetInstance().pushMsg(IVR_MSG_FLOW_STATE_UPDAET, reinterpret_cast<const PARAM>(m_Id));
  135. // 如果是自动流程,但是还未连接至CTI则等待,直到连至CTI后执行
  136. if(m_pFlowTemplate->type() == FLOW_AUTO && !m_IsNetLinkUp)
  137. {
  138. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL, _T("{Flow}: 自动流程[%d]挂起, 等候与CTI连接, Template = %s"), m_Id, m_pFlowTemplate->name());
  139. return CELL_OP_WAIT_FOR;
  140. }
  141. return next(Pos);
  142. }
  143. /*****************************************************************
  144. **【函数名称】 next
  145. **【函数功能】 执行流程下一结点
  146. **【参数】 NextPos:下一结点编号
  147. **【返回值】 后一个节点编号
  148. ****************************************************************/
  149. int CIvrFlow::next( int NextPos )
  150. {
  151. ASSERT(m_pFlowTemplate != NULL);
  152. if(m_pFlowTemplate == NULL)
  153. {
  154. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Flow}: 执行流程[%d]后续节点时,流程模板为空"), m_Id);
  155. return CELL_OP_ERROR;
  156. }
  157. int NextCellPos = NextPos;
  158. m_pCurrentCell = m_pFlowTemplate->findCell(NextCellPos);
  159. //by 2019-9-6 将播放工号的时间调整至摘机之后
  160. if(m_pCurrentCell == NULL)
  161. {
  162. __onNextCellNull(NextCellPos);
  163. return NextCellPos;
  164. }
  165. while(m_pCurrentCell != NULL)
  166. {
  167. m_pCurrentCell->assoIvrFlow() = this;
  168. CMsgCenter::GetInstance().pushMsg(IVR_MSG_FLOW_CELL_UPDATE, reinterpret_cast<const PARAM>(m_Id));
  169. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]开始执行节点[%s]"), m_Id, m_pCurrentCell->name());
  170. //by 2019-9-6 将播放工号的时间调整至摘机之后
  171. CString n_CellNextName = m_pCurrentCell->name();
  172. if (n_CellNextName == CELL_NAME_HOLD_ON)
  173. {
  174. //主动向ACD发送请求座席状态的消息,如果添加主动返回消息估计会产生问题
  175. CPduEntity cmdhold(PDU_CMD_IVR_TURN_HOLDON);
  176. //cmdhold.SetDataInt(1, /*m_pCurrentCell->assoIvrFlow()->id()*/1017);
  177. cmdhold.SetDataULong(2, m_pCurrentCell->assoIvrFlow()->assoCallId());
  178. CNetworkIvr::GetInstance().send(cmdhold);
  179. }
  180. NextCellPos = m_pCurrentCell->operate();
  181. if(NextCellPos > 0)
  182. {
  183. __deleteCurrentCell();
  184. m_pCurrentCell = m_pFlowTemplate->findCell(NextCellPos);
  185. if(m_pCurrentCell == NULL)
  186. {
  187. __onNextCellNull(NextCellPos);
  188. break;
  189. }
  190. }
  191. else if(NextCellPos == CELL_OP_END)
  192. {
  193. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]执行模板[%s]结束"), m_Id, m_pFlowTemplate->name());
  194. __clearFlow();
  195. break;
  196. }
  197. else if(NextCellPos == CELL_OP_WAIT_FOR)
  198. {
  199. if(m_pCurrentCell->maxWaitingTime() > 0)
  200. SetTimer(reinterpret_cast<long>(m_pCurrentCell), m_pCurrentCell->maxWaitingTime() * 1000, NULL);
  201. break;
  202. }
  203. else if(NextCellPos == CELL_OP_ERROR)
  204. {
  205. CPduEntity cmdIVREnd(PDU_CMD_IVR_END);
  206. cmdIVREnd.SetDataInt(1, m_Id);
  207. if(!CNetworkIvr::GetInstance().send(cmdIVREnd))
  208. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]执行节点[%s]时发生异常, 且通知Cti失败, 流程将被释放"), m_Id, m_pCurrentCell->name());
  209. else
  210. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]执行节点[%s]时发生异常, 已成功通知Cti, 流程将被释放"), m_Id, m_pCurrentCell->name());
  211. __clearFlow();
  212. break;
  213. }
  214. else if(NextCellPos == CELL_OP_SEND_ERROR)
  215. {
  216. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]执行节点[%s]时, 向Cti传送数据失败, 流程将被释放"), m_Id, m_pCurrentCell->name());
  217. __clearFlow();
  218. break;
  219. }
  220. }
  221. return NextCellPos;
  222. }
  223. /*****************************************************************
  224. **【函数名称】 procPdu
  225. **【函数功能】 处理PDU消息
  226. **【参数】 pPduEntity:PDU消息
  227. **【返回值】 下一个节点编号
  228. ****************************************************************/
  229. //2019-09-11 颐和随访
  230. int CIvrFlow::procPdu( CPduEntity* pPduEntity )
  231. {
  232. ASSERT(pPduEntity != NULL);
  233. bool HangupFlag = false;
  234. if(pPduEntity->GetCmdType() == PDU_CMD_CTI_IVR_HANGUP && !pPduEntity->GetIsExecReturn())
  235. HangupFlag = true;
  236. if(m_pCurrentCell != NULL)
  237. {
  238. int NextCellPos = m_pCurrentCell->onOpResultReturn(pPduEntity);
  239. if(HangupFlag)
  240. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]收到挂机消息, 流程当前节点为[%s], Note = %s, 下一节点[%d]"),
  241. m_Id, m_pCurrentCell->name(), m_pCurrentCell->note(), NextCellPos);
  242. else
  243. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]收到节点操作的返回结果, 流程当前节点为[%s], Note = %s, 下一节点[%d]"),
  244. m_Id, m_pCurrentCell->name(), m_pCurrentCell->note(), NextCellPos);
  245. //2019-09-11 颐和随访转分机成功时
  246. if(NextCellPos > 0) // NextCellPos为可用的下一结点编号
  247. {
  248. __deleteCurrentCell();
  249. return next(NextCellPos);
  250. }
  251. else if(NextCellPos == CELL_OP_WAIT_FOR)
  252. {
  253. if(HangupFlag) m_IsHangUp = true;
  254. return CELL_OP_WAIT_FOR;
  255. }
  256. else if(NextCellPos == CELL_OP_END)
  257. {
  258. ASSERT(FALSE);
  259. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_NORMAL, _T("{Flow}: 流程[%d]执行模板[%s]结束"), m_Id, m_pFlowTemplate->name());
  260. __clearFlow();
  261. return CELL_OP_END;
  262. }
  263. else // CELL_OP_ERROR或者CELL_OP_SEND_ERROR的情况
  264. {
  265. __clearFlow();
  266. return CELL_OP_ERROR;
  267. }
  268. }
  269. else
  270. {
  271. if(HangupFlag)
  272. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]收到挂机消息, 但是当前执行节点为空, 流程将被释放"), m_Id);
  273. else
  274. ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING, _T("{Flow}: 流程[%d]收到节点操作的返回结果, 但是执行节点却为空, 流程将被释放"), m_Id);
  275. //__clearFlow();
  276. return CELL_OP_ERROR;
  277. }
  278. }
  279. /*****************************************************************
  280. **【函数名称】 onNetLinkUpdated
  281. **【函数功能】 响应网络链接成功或断开事件
  282. **【参数】 IsConnect:网络链接成功或断开
  283. **【返回值】
  284. ****************************************************************/
  285. void CIvrFlow::onNetLinkUpdated( bool IsConnect )
  286. {
  287. m_IsNetLinkUp = IsConnect;
  288. if(!IsConnect)
  289. {
  290. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 网络中断流程[%d]将被释放"), m_Id);
  291. __clearFlow();
  292. }
  293. else
  294. {
  295. if(m_pFlowTemplate != NULL && m_pFlowTemplate->type() == FLOW_AUTO)
  296. {
  297. ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING, _T("{Flow}: 网络连接成功自动流程[%d]将启动"), m_Id);
  298. start();
  299. }
  300. }
  301. }
  302. /*****************************************************************
  303. **【函数名称】 addVar
  304. **【函数功能】 添加系统变量
  305. **【参数】 VarName: 变量名称
  306. VarValue: 变量值
  307. **【返回值】
  308. ****************************************************************/
  309. void CIvrFlow::addVar( const CString& VarName, const CString& VarValue )
  310. {
  311. m_VarTable.SetAt(VarName, VarValue);
  312. }
  313. /*****************************************************************
  314. **【函数名称】 findVarValue
  315. **【函数功能】 查找系统变量
  316. **【参数】 VarName:变量名称
  317. VarValue:变量值
  318. **【返回值】 true:查找到,false:未查找到
  319. ****************************************************************/
  320. bool CIvrFlow::findVarValue( const CString& VarName, CString& VarValue )
  321. {
  322. if(m_VarTable.Lookup(VarName, VarValue))
  323. return true;
  324. else
  325. return false;
  326. }
  327. /*****************************************************************
  328. **【函数名称】 replaceVar
  329. **【函数功能】 根据流程中的变量对指定字符串进行替换
  330. **【参数】 Src: 要进行替换的字符串
  331. Dst: 替换完成的字符串
  332. **【返回值】 成功true,失败false
  333. ****************************************************************/
  334. bool CIvrFlow::replaceVar( const CString& Src, CString& Dst )
  335. {
  336. Dst = Src;
  337. int Begin = 0;
  338. while( (Begin = Dst.Find(VAR_REF_START_FLAG, Begin)) != -1)
  339. {
  340. int End = Dst.Find(VAR_REF_END_FLAG, Begin);
  341. if(End != -1 && (End - Begin) > 2) // 可以取其中的变量
  342. {
  343. CString ValName = Dst.Mid(Begin + 2, End - Begin - 2);
  344. CString ValValue = _T("");
  345. // 将变量替换为具体值
  346. if( findVarValue(ValName, ValValue))
  347. Dst.Replace((VAR_REF_START_FLAG + ValName + VAR_REF_END_FLAG), ValValue);
  348. else
  349. return false;
  350. } // end if
  351. else
  352. {
  353. return false;
  354. }
  355. } // end while
  356. return true;
  357. }
  358. /*****************************************************************
  359. **【函数名称】 copyVar
  360. **【函数功能】 复制目标流程的系统变量
  361. **【参数】 DestFlow:目标流程
  362. **【返回值】
  363. ****************************************************************/
  364. void CIvrFlow::copyVar( CIvrFlow& DestFlow )
  365. {
  366. const VarTable::CPair* pPair = DestFlow.m_VarTable.PGetFirstAssoc();
  367. while(pPair != NULL)
  368. {
  369. m_VarTable.SetAt(pPair->key, pPair->value);
  370. DestFlow.m_VarTable.PGetNextAssoc(pPair);
  371. }
  372. }
  373. /*****************************************************************
  374. **【函数名称】 setFlowInfo
  375. **【函数功能】 保存流程信息
  376. **【参数】 CallId: 呼叫标识
  377. TrunkId: 外线Id
  378. CallerNum:主叫号码
  379. CalleeNum: 被叫号码
  380. **【返回值】
  381. ****************************************************************/
  382. void CIvrFlow::setFlowInfo( ULONG CallId, UINT TrunkId, const CString& CallerNum, const CString& CalleeNum )
  383. {
  384. m_AssoCallId = CallId;
  385. // 给系统变量呼叫标识赋值
  386. CString Data = "";
  387. Data.Format(_T("%lu"), CallId);
  388. addVar(SYSTEM_VAR_CALLID, Data);
  389. // 给系统变量外线号赋值
  390. Data.Format(_T("%u"), TrunkId);
  391. addVar(SYSTEM_VAR_OUTLINEID, Data);
  392. // 给系统变量主叫号码赋值
  393. addVar(SYSTEM_VAR_CALLER, CallerNum);
  394. // 给系统变量被叫号码赋值
  395. addVar(SYSTEM_VAR_CALLEE, CalleeNum);
  396. }
  397. /*****************************************************************
  398. **【函数名称】 setFlowInfo
  399. **【函数功能】 保存流程信息
  400. **【参数】 CallId: 呼叫标识
  401. TrunkId: 外线Id
  402. TaskId: 预测任务ID
  403. OpType: 操作类型
  404. CallerNum:主叫号码
  405. CalleeNum: 被叫号码
  406. **【返回值】
  407. ****************************************************************/
  408. void CIvrFlow::setFlowInfo( ULONG CallId, UINT TrunkId, int TaskId, UINT OpType, const CString& CallerNum, const CString& CalleeNum )
  409. {
  410. setFlowInfo(CallId, TrunkId, CallerNum, CalleeNum);
  411. CString Data;
  412. Data.Format(_T("%d"), TaskId);
  413. addVar(SYSTEM_VAR_PRE_CALL_ID, Data);
  414. Data.Format(_T("%u"), OpType);
  415. addVar(SYSTEM_VAR_PRE_CALL_TYPE, Data);
  416. }
  417. /*****************************************************************
  418. **【函数名称】 setFlowAssoData
  419. **【函数功能】 设置流程随路数据
  420. **【参数】 AssoData: 随路数据
  421. **【返回值】
  422. ****************************************************************/
  423. void CIvrFlow::setFlowAssoData( CString AssoData )
  424. {
  425. CString DataInfo = "";
  426. CString DataName = "";
  427. CString DataValue = "";
  428. while(!AssoData.IsEmpty())
  429. {
  430. int nIndex = AssoData.Find("|");
  431. if(nIndex == -1)
  432. {
  433. DataInfo = AssoData;
  434. AssoData.Empty();
  435. }
  436. else
  437. {
  438. DataInfo = AssoData.Left(nIndex);
  439. AssoData = AssoData.Right(AssoData.GetLength() - nIndex - 1);
  440. }
  441. // 解析单个随路数据
  442. int Falg = DataInfo.Find(":");
  443. if(Falg == -1)
  444. continue;
  445. // 获取变量名
  446. DataName = DataInfo.Left(Falg);
  447. if(DataName.IsEmpty())
  448. continue;
  449. // 获取变量值
  450. DataValue = DataInfo.Right(DataInfo.GetLength() - Falg - 1);
  451. // 添加进随路数据
  452. this->addVar(DataName, DataValue);
  453. }
  454. }
  455. /*****************************************************************
  456. **【函数名称】 OnTimer
  457. **【函数功能】 定时器响应函数
  458. **【参数】 nIDEvent: 定时器ID
  459. **【返回值】
  460. ****************************************************************/
  461. void CIvrFlow::OnTimer( UINT_PTR nIDEvent )
  462. {
  463. KillTimer(nIDEvent);
  464. if(m_pCurrentCell != NULL && nIDEvent == reinterpret_cast<long>(m_pCurrentCell))
  465. __onTimerTimeOut();
  466. CWnd::OnTimer(nIDEvent);
  467. }
  468. /*****************************************************************
  469. **【函数名称】 onTimeUp
  470. **【函数功能】 定时器节点时间到
  471. **【参数】
  472. **【返回值】
  473. ****************************************************************/
  474. void CIvrFlow::onTimerTimeUp( int NextPos )
  475. {
  476. if(m_pCurrentCell->name() == CELL_NAME_TIMER)
  477. {
  478. __deleteCurrentCell();
  479. next(NextPos);
  480. }
  481. }