| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- <!doctype html>
- <html lang="zh-CN">
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <title>Cockpit Monitoring Point Detail Demo</title>
- <style>
- body { margin:0; min-height:100vh; background:#08131f; color:#e8f1f8; font:15px/1.5 "Microsoft YaHei",sans-serif; }
- main { width:min(1180px,calc(100vw - 32px)); margin:28px auto; display:grid; gap:16px; }
- header, section { background:#0e1e2d; border:1px solid #21465f; padding:20px; }
- h1,h2 { margin:0 0 10px; } h1 { font-size:22px; } h2 { font-size:17px; }
- .endpoint { color:#78a2b8; font-family:Consolas,monospace; margin:0; }
- .toolbar { display:flex; gap:8px; flex-wrap:wrap; margin-bottom:14px; }
- button { border:1px solid #2f7098; background:#123247; color:#dff2ff; padding:8px 14px; cursor:pointer; }
- button.active { outline:2px solid #61c2ff; }
- .summary { display:grid; grid-template-columns:repeat(6,1fr); gap:8px; margin-bottom:14px; }
- .summary div { background:#0b1922; border:1px solid #275b74; padding:10px; text-align:center; }
- .summary strong { display:block; font-size:20px; }
- .summary span { color:#8fb3c7; font-size:12px; }
- .status { display:inline-block; padding:3px 9px; border-radius:12px; background:#20415a; }
- .alarm { background:#8b2020; } .warning { background:#8a6510; } .work-order { background:#1f5e91; }
- .normal { background:#197343; } .offline { color:#a9b7c0; background:#38424a; } .empty { background:#48515a; }
- table { width:100%; border-collapse:collapse; }
- th,td { border:1px solid #275b74; padding:8px; text-align:left; }
- th { background:#123247; } td.mono { font-family:Consolas,monospace; }
- .reasons { margin:0; padding-left:18px; } .note { color:#8fb3c7; font-size:13px; }
- pre { max-height:260px; overflow:auto; background:#071019; border:1px solid #275b74; padding:12px; }
- </style>
- </head>
- <body>
- <main>
- <header>
- <h1>驾驶舱监测点状态与详情演示</h1>
- <p class="endpoint">GET /api/cockpit/v1/monitoring-points/{monitoringPointCode}</p>
- </header>
- <section>
- <div class="toolbar">
- <button type="button" data-mode="alarm" class="active">报警优先</button>
- <button type="button" data-mode="workOrder">工单处置</button>
- <button type="button" data-mode="offline">离线</button>
- <button type="button" data-mode="empty">无设备</button>
- <button type="button" data-mode="notFound">404</button>
- </div>
- <div id="detail">
- <div class="summary" id="statistics"></div>
- <h2>设备卡片(后端排序)</h2>
- <table>
- <thead><tr><th>设备编码</th><th>设备名称</th><th>类型</th><th>状态</th><th>状态时间</th></tr></thead>
- <tbody id="devices"></tbody>
- </table>
- </div>
- <div id="error" hidden>
- <h2 id="error-title"></h2>
- <pre id="error-payload"></pre>
- </div>
- </section>
- <section>
- <h2>状态原因与状态字典</h2>
- <p class="note">监测点状态由后端按 ALARM > WARNING > WORK_ORDER > NORMAL > OFFLINE > EMPTY 解析。</p>
- <ul id="reasons" class="reasons"></ul>
- <pre id="payload"></pre>
- </section>
- </main>
- <script>
- var statusClass = {
- ALARM: 'alarm', WARNING: 'warning', WORK_ORDER: 'work-order',
- NORMAL: 'normal', OFFLINE: 'offline', EMPTY: 'empty'
- };
- var responses = {
- alarm: response('MP-001', '供水干管监测点', 'ALARM', [
- device('EQ-001', '供水压力计-001', '压力计', 'ALARM', '2026-09-02T09:59:00+08:00', ['压力超高']),
- device('EQ-003', '燃气浓度计-003', '气体检测仪', 'ALARM', '2026-09-02T09:59:10+08:00', ['浓度超限']),
- device('EQ-005', '污水环境监测仪-005', '环境监测仪', 'WARNING', '2026-09-02T09:59:20+08:00', ['氨氮波动']),
- device('EQ-002', '智能井盖-002', '智能井盖', 'NORMAL', '2026-09-02T09:59:30+08:00', []),
- device('EQ-004', '供水流量计-004', '流量计', 'OFFLINE', '2026-09-02T09:59:40+08:00', [])
- ]),
- workOrder: response('MP-WORK', '泵站监测点', 'WORK_ORDER', [
- device('EQ-WORK', '泵站振动监测器', '振动监测器', 'WORK_ORDER', '2026-09-02T09:58:00+08:00', ['维修处置中'])
- ]),
- offline: response('MP-OFFLINE', '排口监测点', 'OFFLINE', [
- device('EQ-OFFLINE', '污水液位计', '液位计', 'OFFLINE', '2026-09-02T09:57:00+08:00', ['连接超时'])
- ]),
- empty: response('MP-EMPTY', '预留监测点', 'EMPTY', []),
- notFound: {
- code: 404, msg: '监测点不存在',
- data: { category: 'NOT_FOUND', message: '监测点不存在', requestId: 'point-detail-demo-404', serverTime: '2026-09-02T10:00:00+08:00' }
- }
- };
- function device(code, name, type, status, time, reasons) {
- return { deviceCode: code, deviceName: name, deviceTypeName: type, deviceStatus: status,
- statusLabel: label(status), statusReasons: reasons, statusTime: time };
- }
- function label(status) {
- return { ALARM:'报警', WARNING:'预警', WORK_ORDER:'工单处置', NORMAL:'正常', OFFLINE:'离线', EMPTY:'无设备' }[status];
- }
- function response(code, name, status, devices) {
- return {
- code: 200, msg: '操作成功',
- data: {
- requestId: 'point-detail-demo-' + status.toLowerCase(), apiVersion: 'v1', readOnly: true,
- monitoringPointCode: code, monitoringPointName: name, pointStatus: status, statusLabel: label(status),
- statusReasons: devices.filter(function (item) { return item.deviceStatus === status; })
- .flatMap(function (item) { return item.statusReasons.map(function (reason) { return { status: status, deviceCode: item.deviceCode, reason: reason }; }); }),
- deviceStatistics: {
- totalDeviceCount: devices.length,
- alarmDeviceCount: count(devices, 'ALARM'), warningDeviceCount: count(devices, 'WARNING'),
- workOrderDeviceCount: count(devices, 'WORK_ORDER'), normalDeviceCount: count(devices, 'NORMAL'),
- offlineDeviceCount: count(devices, 'OFFLINE')
- },
- devices: devices,
- coordinateValidation: { state: 'VALID', reason: null, renderable: true, crs: 'WGS84' },
- statusDictionary: ['ALARM','WARNING','WORK_ORDER','NORMAL','OFFLINE','EMPTY'].map(function (item, index) {
- return { status: item, label: label(item), priority: index + 1 };
- })
- }
- };
- }
- function count(devices, status) { return devices.filter(function (item) { return item.deviceStatus === status; }).length; }
- function render(mode) {
- document.querySelectorAll('button[data-mode]').forEach(function (button) { button.classList.toggle('active', button.dataset.mode === mode); });
- var payload = responses[mode];
- var success = payload.code === 200;
- document.getElementById('detail').hidden = !success;
- document.getElementById('error').hidden = success;
- if (success) {
- var data = payload.data;
- var stats = data.deviceStatistics;
- document.getElementById('statistics').innerHTML = [
- ['总设备', stats.totalDeviceCount], ['报警', stats.alarmDeviceCount], ['预警', stats.warningDeviceCount],
- ['工单', stats.workOrderDeviceCount], ['正常', stats.normalDeviceCount], ['离线', stats.offlineDeviceCount]
- ].map(function (item) { return '<div><strong>' + item[1] + '</strong><span>' + item[0] + '</span></div>'; }).join('');
- document.getElementById('devices').innerHTML = data.devices.map(function (item) {
- return '<tr><td class="mono">' + item.deviceCode + '</td><td>' + item.deviceName + '</td><td>' + item.deviceTypeName +
- '</td><td><span class="status ' + statusClass[item.deviceStatus] + '">' + item.statusLabel + '</span></td><td class="mono">' + item.statusTime + '</td></tr>';
- }).join('');
- document.getElementById('reasons').innerHTML = data.statusReasons.length
- ? data.statusReasons.map(function (item) { return '<li><strong>' + item.deviceCode + '</strong>:' + item.reason + '</li>'; }).join('')
- : '<li>无对应状态原因</li>';
- } else {
- document.getElementById('error-title').textContent = 'HTTP ' + payload.code + ':' + payload.msg;
- document.getElementById('error-payload').textContent = JSON.stringify(payload, null, 2);
- }
- document.getElementById('payload').textContent = JSON.stringify(payload, null, 2);
- }
- document.querySelectorAll('button[data-mode]').forEach(function (button) {
- button.addEventListener('click', function () { render(button.dataset.mode); });
- });
- render('alarm');
- </script>
- </body>
- </html>
|