work-order-nine-states-demo.html 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. <!doctype html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="utf-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1" />
  6. <title>Cockpit Work Order Nine States Demo</title>
  7. <style>
  8. body { margin:0; min-height:100vh; background:#08131f; color:#e8f1f8; font:15px/1.5 "Microsoft YaHei",sans-serif; }
  9. main { width:min(1280px,calc(100vw - 32px)); margin:28px auto; display:grid; gap:16px; }
  10. header, section { background:#0e1e2d; border:1px solid #21465f; padding:20px; }
  11. h1,h2,h3 { margin:0 0 10px; } h1 { font-size:22px; } h2 { font-size:17px; } h3 { font-size:15px; }
  12. .endpoint { color:#78a2b8; font-family:Consolas,monospace; margin:0; }
  13. .toolbar { display:flex; gap:8px; flex-wrap:wrap; margin-bottom:14px; }
  14. button { border:1px solid #2f7098; background:#123247; color:#dff2ff; padding:8px 14px; cursor:pointer; }
  15. button.active { outline:2px solid #61c2ff; }
  16. .layout { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:16px; align-items:start; }
  17. .orders { display:grid; gap:12px; }
  18. .order { border:1px solid #275b74; background:#0b1922; padding:12px; }
  19. .order.alarm { border-color:#ff7a7a; } .order.warning { border-color:#f2c94c; }
  20. .title { display:flex; justify-content:space-between; gap:8px; align-items:flex-start; }
  21. .code { color:#78a2b8; font-family:Consolas,monospace; font-size:12px; overflow-wrap:anywhere; }
  22. .badge { font-size:12px; padding:3px 8px; border:1px solid; white-space:nowrap; }
  23. .active { color:#68d095; border-color:#68d095; } .legacy { color:#ff7a7a; border-color:#ff7a7a; } .finished { color:#a9b7c0; border-color:#a9b7c0; }
  24. .timeline { margin-top:10px; display:grid; gap:8px; }
  25. .entry { border-left:3px solid #61c2ff; background:#0e1e2d; padding:8px 10px; }
  26. .entry.legacy { border-left-color:#ff7a7a; } .entry.finished { border-left-color:#a9b7c0; }
  27. .meta { color:#8fb3c7; font-size:13px; margin:6px 0 0; overflow-wrap:anywhere; }
  28. .dictionary { display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:8px; }
  29. .state { border:1px solid #275b74; background:#0b1922; padding:8px; } .state.legacy { border-color:#ff7a7a; }
  30. .mono { font-family:Consolas,monospace; overflow-wrap:anywhere; } pre { max-height:340px; overflow:auto; background:#071019; border:1px solid #275b74; padding:12px; }
  31. .note { color:#8fb3c7; font-size:13px; }
  32. </style>
  33. </head>
  34. <body>
  35. <main>
  36. <header>
  37. <h1>驾驶舱事件关联工单九态演示</h1>
  38. <p class="endpoint">GET /api/cockpit/v1/equipments/{deviceCode}/work-orders</p>
  39. <p class="endpoint">GET /api/cockpit/v1/events/{eventSource}/{eventCode}/work-orders</p>
  40. <p class="endpoint">GET /api/cockpit/v1/work-orders/{workOrderCode}/timeline</p>
  41. </header>
  42. <section>
  43. <div class="toolbar">
  44. <button type="button" data-mode="all" class="active">九态总览</button>
  45. <button type="button" data-mode="multi">同设备多类型报警</button>
  46. </div>
  47. <div class="layout">
  48. <div>
  49. <h2>工单列表</h2>
  50. <div id="orders" class="orders"></div>
  51. </div>
  52. <div>
  53. <h2>状态字典</h2>
  54. <div id="dictionary" class="dictionary"></div>
  55. </div>
  56. </div>
  57. </section>
  58. <section>
  59. <h2>响应契约</h2>
  60. <p class="note">legacyState / legacyName 保留现网九态兼容编码;authoritativeState 是 ADR-0008 七态权威映射,旧 8/9 标记 deprecated,避免新功能依赖已废止状态。</p>
  61. <pre id="payload" class="mono"></pre>
  62. </section>
  63. </main>
  64. <script>
  65. const stateNames = ['待派单','待接单','已接单','处理中','待验收','已结案','已驳回','延期审核','已延期'];
  66. const authoritative = [
  67. {code:1,name:'待派单'}, {code:2,name:'待接单'}, {code:3,name:'已接单'}, {code:4,name:'处理中'},
  68. {code:5,name:'待验收'}, {code:6,name:'已结案'}, {code:7,name:'已取消'}, null, null
  69. ];
  70. const stateDictionary = stateNames.map((name, index) => ({
  71. legacyCode:index + 1, legacyName:name,
  72. authoritativeCode:authoritative[index]?.code ?? null, authoritativeName:authoritative[index]?.name ?? null,
  73. deprecated:index >= 6
  74. }));
  75. const summary = (code, state, source, eventCode, desc) => ({
  76. workOrderCode:code, deviceCode:'TC-PS-WS-202609020012', orderType:1, orderTypeName:'故障维修',
  77. orderLevel:2, orderDesc:desc,
  78. legacyState:state, legacyStateName:stateNames[state - 1],
  79. authoritativeState:authoritative[state - 1]?.code ?? null, authoritativeStateName:authoritative[state - 1]?.name ?? null,
  80. deprecatedState:state >= 7,
  81. createTime:'2026-09-02T09:00:00+08:00', updateTime:'2026-09-02T10:00:00+08:00',
  82. planFinishTime:'2026-09-03T09:00:00+08:00', realFinishTime:state === 6 ? '2026-09-02T10:00:00+08:00' : null,
  83. eventAssociation:{ eventSource:source, eventCode, associatedAt:'2026-09-02T10:00:00+08:00' }
  84. });
  85. const allOrders = stateNames.map((name, index) => summary('WO-202609020000' + (index + 1), index + 1, 'ALARM', 'ALM-20260902-00' + (index + 1), '演示第 ' + (index + 1) + ' 态'));
  86. const multiOrders = [
  87. summary('WO-2026090200101', 4, 'ALARM', 'ALM-WS_ENV_HIGH-001', '污水COD超标维修'),
  88. summary('WO-2026090200102', 5, 'ALARM', 'ALM-WS_ENV_PH-002', '污水pH越界维修')
  89. ];
  90. const timelines = {
  91. 'WO-2026090200101': ['创建:待派单','派单:待接单','开始处置:处理中'],
  92. 'WO-2026090200102': ['创建:待派单','派单:待接单','提交验收:待验收']
  93. };
  94. function renderOrder(order) {
  95. const timeline = timelines[order.workOrderCode] || ['创建:' + order.legacyStateName];
  96. return `<article class="order ${order.eventAssociation.eventSource === 'ALARM' ? 'alarm' : 'warning'}">
  97. <div class="title">
  98. <div><h3>${order.orderDesc}</h3><div class="code">${order.workOrderCode}</div></div>
  99. <span class="badge ${order.deprecatedState ? 'legacy' : order.legacyState === 6 ? 'finished' : 'active'}">${order.legacyState} ${order.legacyStateName}</span>
  100. </div>
  101. <p class="meta">权威状态:${order.authoritativeState ?? '已废止'} ${order.authoritativeStateName ?? ''}<br />事件:${order.eventAssociation.eventSource} ${order.eventAssociation.eventCode}</p>
  102. <div class="timeline">${timeline.map(item => `<div class="entry ${order.deprecatedState ? 'legacy' : order.legacyState === 6 ? 'finished' : ''}">${item}</div>`).join('')}</div>
  103. </article>`;
  104. }
  105. function render(mode) {
  106. document.querySelectorAll('button[data-mode]').forEach(button => button.classList.toggle('active', button.dataset.mode === mode));
  107. const orders = mode === 'all' ? allOrders : multiOrders;
  108. document.getElementById('orders').innerHTML = orders.map(renderOrder).join('');
  109. document.getElementById('dictionary').innerHTML = stateDictionary.map(state => `
  110. <div class="state ${state.deprecated ? 'legacy' : ''}"><strong>${state.legacyCode} ${state.legacyName}</strong>
  111. <p class="meta">${state.authoritativeCode ? '权威:' + state.authoritativeCode + ' ' + state.authoritativeName : '已废止'}</p>
  112. </div>`).join('');
  113. document.getElementById('payload').textContent = JSON.stringify({
  114. code:200, msg:'操作成功', data:{
  115. requestId:'work-order-demo', apiVersion:'v1', readOnly:true,
  116. deviceCode:'TC-PS-WS-202609020012', eventSource:mode === 'all' ? null : 'ALARM',
  117. eventCode:mode === 'all' ? null : 'WS_ENV_MULTI', state:'READY', stateReason:'READY',
  118. stateDictionary, workOrders:orders
  119. }
  120. }, null, 2);
  121. }
  122. document.querySelectorAll('button[data-mode]').forEach(button => button.addEventListener('click', () => render(button.dataset.mode)));
  123. render('all');
  124. </script>
  125. </body>
  126. </html>