overview-warning-settings-demo.html 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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>总体概览 / 预警设置 Demo</title>
  7. <style>
  8. :root { color-scheme:dark; --panel:#0c1a2c; --line:#22486a; --cyan:#45d6ff; --green:#49d17c; --red:#ff5f6d; --yellow:#ffd166; --muted:#8ba7bd; }
  9. * { box-sizing:border-box; }
  10. body { margin:0; font-family:"Microsoft YaHei",Arial,sans-serif; background:#071322; color:#eaf5ff; }
  11. header { display:flex; justify-content:space-between; align-items:center; padding:18px 24px; border-bottom:1px solid var(--line); }
  12. h1 { margin:0; font-size:22px; letter-spacing:2px; }
  13. h1 small { margin-left:10px; font-size:12px; color:var(--muted); }
  14. main { display:grid; grid-template-columns:minmax(320px,440px) 1fr; gap:18px; padding:20px; }
  15. .panel { background:var(--panel); border:1px solid var(--line); border-radius:8px; overflow:hidden; }
  16. .panel h2 { margin:0; padding:12px 14px; font-size:15px; border-bottom:1px solid var(--line); }
  17. .body { padding:14px; }
  18. .seg { display:flex; gap:8px; margin-bottom:14px; }
  19. button { cursor:pointer; padding:8px 14px; border:1px solid var(--line); background:#102c44; color:#eaf5ff; border-radius:4px; }
  20. button.active { border-color:var(--cyan); background:#1a5f83; }
  21. .cards { display:grid; grid-template-columns:repeat(3,1fr); gap:10px; }
  22. .card { background:#08182b; border:1px solid var(--line); border-radius:6px; padding:12px; }
  23. .card b { display:block; font-size:25px; color:var(--cyan); }
  24. .card span { color:var(--muted); font-size:12px; }
  25. .meta { margin:14px 0 8px; font-size:13px; color:#d3e9f8; }
  26. .states { display:grid; grid-template-columns:repeat(7,1fr); gap:6px; }
  27. .states div { text-align:center; padding:8px 2px; background:#08182b; border:1px solid var(--line); border-radius:4px; }
  28. .states b { display:block; }
  29. ul { padding-left:20px; margin:8px 0; }
  30. .bar { height:10px; background:#12324c; border-radius:5px; overflow:hidden; margin:5px 0 12px; }
  31. .bar i { display:block; height:100%; background:linear-gradient(90deg,#1a8ec7,var(--cyan)); }
  32. .map { position:relative; min-height:470px; background:#020b16; }
  33. .grid { position:absolute; inset:0; opacity:.4; background-image:linear-gradient(#12324c 1px,transparent 1px),linear-gradient(90deg,#12324c 1px,transparent 1px); background-size:50px 50px; }
  34. .point { position:absolute; width:25px; height:25px; margin:-12px; border-radius:50%; border:2px solid #ffffff22; display:flex; align-items:center; justify-content:center; cursor:pointer; }
  35. .point.WARNING { background:#55431a; border-color:var(--yellow); }
  36. .point.ALARM { background:#57232a; border-color:var(--red); }
  37. .point small { font-size:10px; font-weight:700; }
  38. .legend { padding:10px 14px; border-top:1px solid var(--line); color:var(--muted); font-size:12px; }
  39. .map-title { position:absolute; top:14px; left:14px; z-index:2; padding:7px 11px; background:#08182bcc; border:1px solid var(--cyan); border-radius:4px; }
  40. </style>
  41. </head>
  42. <body>
  43. <header>
  44. <h1>总体概览 / 预警设置 <small>合同固定名称 · 只读展示</small></h1>
  45. <div>更新时间:<span id="updatedAt">2026-09-02 09:59:50</span></div>
  46. </header>
  47. <main>
  48. <section class="panel">
  49. <h2>预警 / 报警处置态势</h2>
  50. <div class="body">
  51. <div class="seg">
  52. <button id="btn-WARNING" class="active">预警</button>
  53. <button id="btn-ALARM">报警</button>
  54. </div>
  55. <div class="cards">
  56. <div class="card"><b id="total">--</b><span>事件总数</span></div>
  57. <div class="card"><b id="handled">--</b><span>已处置</span></div>
  58. <div class="card"><b id="pending">--</b><span>未处置</span></div>
  59. <div class="card"><b id="efficiency">--</b><span>处置效率</span></div>
  60. <div class="card"><b id="unlinked">--</b><span>未关联工单</span></div>
  61. <div class="card"><b id="invalid">--</b><span>异常工单状态</span></div>
  62. </div>
  63. <div class="meta">近两日趋势</div>
  64. <div id="trend"></div>
  65. <div class="meta">七态工单分布</div>
  66. <div class="states" id="states"></div>
  67. </div>
  68. </section>
  69. <section class="panel">
  70. <h2>中央一张图联动</h2>
  71. <div class="map">
  72. <div class="grid"></div>
  73. <div class="map-title" id="mapTitle">筛选:预警</div>
  74. </div>
  75. <div class="legend">黄点=预警事件;红点=报警事件;切换模式只过滤当前事件族,不合并 warning / alarm 统计。</div>
  76. </section>
  77. </main>
  78. <script>
  79. const data = {
  80. updatedAt: '2026-09-02T09:59:50+08:00',
  81. WARNING: {
  82. total: 3, handled: 1, pending: 2, efficiency: '0.3333', unlinked: 0, invalid: 0,
  83. trend: [{ bucket:'09-01', total:2, handled:1 }, { bucket:'09-02', total:1, handled:0 }],
  84. states: { 1:1, 2:0, 3:0, 4:0, 5:1, 6:1, 7:0 },
  85. points: [
  86. { code:'WRN-001', x:20, y:27 }, { code:'WRN-002', x:35, y:45 }, { code:'WRN-003', x:48, y:30 }
  87. ]
  88. },
  89. ALARM: {
  90. total: 2, handled: 0, pending: 2, efficiency: '0.0000', unlinked: 0, invalid: 0,
  91. trend: [{ bucket:'09-01', total:1, handled:0 }, { bucket:'09-02', total:1, handled:0 }],
  92. states: { 1:0, 2:0, 3:0, 4:2, 5:0, 6:0, 7:0 },
  93. points: [
  94. { code:'ALM-001', x:64, y:36 }, { code:'ALM-002', x:82, y:58 }
  95. ]
  96. }
  97. };
  98. const labels = { 1:'待派单', 2:'待接单', 3:'已接单', 4:'处理中', 5:'待验收', 6:'已结案', 7:'已取消' };
  99. let mode = 'WARNING';
  100. function render() {
  101. const item = data[mode];
  102. document.getElementById('total').textContent = item.total;
  103. document.getElementById('handled').textContent = item.handled;
  104. document.getElementById('pending').textContent = item.pending;
  105. document.getElementById('efficiency').textContent = item.efficiency;
  106. document.getElementById('unlinked').textContent = item.unlinked;
  107. document.getElementById('invalid').textContent = item.invalid;
  108. document.getElementById('mapTitle').textContent = '筛选:' + (mode === 'WARNING' ? '预警' : '报警');
  109. document.getElementById('btn-WARNING').classList.toggle('active', mode === 'WARNING');
  110. document.getElementById('btn-ALARM').classList.toggle('active', mode === 'ALARM');
  111. const trend = document.getElementById('trend');
  112. trend.innerHTML = item.trend.map(point => `
  113. <div>
  114. <div style="display:flex;justify-content:space-between;font-size:12px;color:#8ba7bd;">
  115. <span>${point.bucket}</span><span>${point.handled}/${point.total}</span>
  116. </div>
  117. <div class="bar"><i style="width:${point.total ? point.handled / point.total * 100 : 0}%"></i></div>
  118. </div>
  119. `).join('');
  120. const states = document.getElementById('states');
  121. states.innerHTML = Object.entries(labels).map(([code, label]) => `
  122. <div><b>${item.states[code] || 0}</b><span>${label}</span></div>
  123. `).join('');
  124. const map = document.querySelector('.map');
  125. map.querySelectorAll('.point').forEach(node => node.remove());
  126. item.points.forEach(point => {
  127. const node = document.createElement('div');
  128. node.className = 'point ' + mode;
  129. node.style.left = point.x + '%';
  130. node.style.top = point.y + '%';
  131. node.title = point.code;
  132. node.innerHTML = '<small>' + point.code.slice(0, 3) + '</small>';
  133. node.onclick = () => alert(point.code + ' / ' + mode);
  134. map.appendChild(node);
  135. });
  136. }
  137. document.getElementById('btn-WARNING').onclick = () => { mode = 'WARNING'; render(); };
  138. document.getElementById('btn-ALARM').onclick = () => { mode = 'ALARM'; render(); };
  139. render();
  140. </script>
  141. </body>
  142. </html>