中间件底层,websocket

IvrFlow.cpp 16KB

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