equipment-archive-demo.html 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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 Equipment Archive 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(1180px,calc(100vw - 32px)); margin:28px auto; display:grid; gap:16px; }
  10. header, section { background:#0e1e2d; border:1px solid #21465f; padding:20px; }
  11. h1,h2 { margin:0 0 10px; } h1 { font-size:22px; } h2 { font-size:17px; }
  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) 340px; gap:18px; align-items:start; }
  17. table { width:100%; border-collapse:collapse; }
  18. th,td { border:1px solid #275b74; padding:8px; text-align:left; vertical-align:top; }
  19. th { background:#123247; width:180px; }
  20. td.mono { font-family:Consolas,monospace; }
  21. .image-panel, .missing { background:#0b1922; border:1px solid #275b74; padding:12px; }
  22. img { display:block; width:100%; height:180px; object-fit:cover; border:1px solid #2f7098; background:#071019; }
  23. .image-meta { margin:10px 0 0; color:#8fb3c7; font-size:13px; overflow-wrap:anywhere; }
  24. .missing { display:grid; place-items:center; min-height:180px; color:#a9b7c0; text-align:center; }
  25. .note { color:#8fb3c7; font-size:13px; }
  26. pre { max-height:300px; overflow:auto; background:#071019; border:1px solid #275b74; padding:12px; }
  27. </style>
  28. </head>
  29. <body>
  30. <main>
  31. <header>
  32. <h1>驾驶舱设备基础档案演示</h1>
  33. <p class="endpoint">GET /api/cockpit/v1/equipments/{deviceCode}/archive</p>
  34. </header>
  35. <section>
  36. <div class="toolbar">
  37. <button type="button" data-mode="full" class="active">完整档案</button>
  38. <button type="button" data-mode="partial">部分档案</button>
  39. <button type="button" data-mode="noImage">无图片</button>
  40. <button type="button" data-mode="loadFailure">加载失败</button>
  41. </div>
  42. <div id="detail">
  43. <div class="layout">
  44. <div><h2>基础档案</h2><table><tbody id="archive"></tbody></table></div>
  45. <div><h2>最新图片</h2><div id="image"></div></div>
  46. </div>
  47. </div>
  48. <div id="error" hidden>
  49. <h2 id="error-title"></h2>
  50. <pre id="error-payload"></pre>
  51. </div>
  52. </section>
  53. <section>
  54. <h2>响应契约</h2>
  55. <p class="note">坐标字段以 WGS84 发布;缺失档案字段显示“未提供”,无图片返回 latestImage 空值,加载失败使用 typed error。</p>
  56. <pre id="payload"></pre>
  57. </section>
  58. </main>
  59. <script>
  60. var fields = [
  61. ['deviceCode','设备编码'],['deviceName','设备名称'],['deviceModel','设备型号'],['deviceSpec','设备规格参数'],
  62. ['manufacturer','设备制造商'],['productionDate','设备生产日期'],['deviceType','设备类别'],['deviceTypeName','类别名称'],
  63. ['assetValue','设备资产价值(元)'],['expectedServiceYears','预计使用年限(年)'],
  64. ['longitude','经度'],['latitude','纬度'],['coordinateSystem','坐标系'],
  65. ['equipmentLocation','设备位置描述'],['installTime','安装时间'],
  66. ['maintainer','设备维护人员'],['maintainerPhone','联系方式'],
  67. ['ownershipUnit','权属单位'],['remark','备注信息']
  68. ];
  69. var image = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="320" height="180"><rect width="100%" height="100%" fill="#123247"/><text x="50%" y="50%" fill="#dff2ff" text-anchor="middle" font-family="sans-serif">设备现场图</text></svg>';
  70. var responses = {
  71. full: response('TC-PS-YS-202609020012', {
  72. deviceName:'污水管网环境监测设备', deviceModel:'WS-PRO-2000',
  73. deviceSpec:'悬浮物/COD/氨氮/电导率/PH', manufacturer:'沅陵专用仪表厂',
  74. productionDate:'2025-12-01', deviceType:'ws_sewage_environment', deviceTypeName:'污水环境监测设备',
  75. assetValue:128000, expectedServiceYears:10, longitude:110.141, latitude:28.452, coordinateSystem:'WGS84',
  76. equipmentLocation:'沅陵县太常片区污水干管检查井', installTime:'2026-01-10 09:30:00',
  77. maintainer:'张维护', maintainerPhone:'13800000000', ownershipUnit:'沅陵县排水管理所',
  78. remark:'监测点首选查看设备',
  79. latestImage:{ url:image, capturedAt:'2026-08-30T10:20:00+08:00' }
  80. }),
  81. partial: response('TC-GS-202609020015', {
  82. deviceName:'燃气压力监测设备', deviceModel:null, deviceSpec:'压力',
  83. manufacturer:'沅陵专用仪表厂', productionDate:'2025-11-10', deviceType:'gs_pressure', deviceTypeName:'燃气压力设备',
  84. assetValue:null, expectedServiceYears:8, longitude:110.151, latitude:28.462, coordinateSystem:'WGS84',
  85. equipmentLocation:'沅陵县太常片区燃气中压管线', installTime:'2026-02-01 14:00:00',
  86. maintainer:null, maintainerPhone:null, ownershipUnit:'沅陵县燃气公司', remark:null,
  87. latestImage:{ url:image, capturedAt:'2026-08-29T16:40:00+08:00' }
  88. }),
  89. noImage: response('TC-PS-WS-202609020016', {
  90. deviceName:'泵站液位监测设备', deviceModel:'LEVEL-300', deviceSpec:'液位/温度',
  91. manufacturer:'沅陵专用仪表厂', productionDate:'2025-10-01', deviceType:'ps_level', deviceTypeName:'泵站液位设备',
  92. assetValue:66000, expectedServiceYears:10, longitude:110.161, latitude:28.472, coordinateSystem:'WGS84',
  93. equipmentLocation:'沅陵县太常片区泵站', installTime:'2026-03-01 08:00:00',
  94. maintainer:'李巡检', maintainerPhone:'13900000000', ownershipUnit:'沅陵县排水管理所', remark:'演示无图片状态',
  95. latestImage:null
  96. }),
  97. loadFailure: {
  98. code:500, msg:'驾驶舱设备档案数据暂不可用',
  99. data:{ category:'SERVER_ERROR', message:'驾驶舱设备档案数据暂不可用', requestId:'equipment-archive-demo-500', serverTime:'2026-09-02T10:00:00+08:00' }
  100. }
  101. };
  102. function response(code, archive) {
  103. return { code:200, msg:'操作成功', data:Object.assign({
  104. requestId:'equipment-archive-demo-' + code, apiVersion:'v1', readOnly:true
  105. }, archive) };
  106. }
  107. function render(mode) {
  108. document.querySelectorAll('button[data-mode]').forEach(function(button) {
  109. button.classList.toggle('active', button.dataset.mode === mode);
  110. });
  111. var payload = responses[mode];
  112. var success = payload.code === 200;
  113. document.getElementById('detail').hidden = !success;
  114. document.getElementById('error').hidden = success;
  115. if (success) {
  116. var data = payload.data;
  117. document.getElementById('archive').innerHTML = fields.map(function(field) {
  118. var value = data[field[0]];
  119. return '<tr><th>' + field[1] + '</th><td class="mono">' + (value === null || value === undefined ? '<span class="note">未提供</span>' : value) + '</td></tr>';
  120. }).join('');
  121. var latest = data.latestImage;
  122. document.getElementById('image').innerHTML = latest
  123. ? '<div class="image-panel"><img alt="设备最新图片" src="' + latest.url + '" /><p class="image-meta">' + latest.capturedAt + '<br />' + latest.url + '</p></div>'
  124. : '<div class="missing">无设备图片</div>';
  125. } else {
  126. document.getElementById('error-title').textContent = 'HTTP ' + payload.code + ':' + payload.msg;
  127. document.getElementById('error-payload').textContent = JSON.stringify(payload, null, 2);
  128. }
  129. document.getElementById('payload').textContent = JSON.stringify(payload, null, 2);
  130. }
  131. document.querySelectorAll('button[data-mode]').forEach(function(button) {
  132. button.addEventListener('click', function() { render(button.dataset.mode); });
  133. });
  134. render('full');
  135. </script>
  136. </body>
  137. </html>