mesEnergyScreen.html 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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.0">
  6. <title>能耗监控大屏</title>
  7. <style>
  8. * { box-sizing: border-box; }
  9. body {
  10. margin: 0;
  11. width: 100vw;
  12. height: 100vh;
  13. overflow: hidden;
  14. color: #e9f7ff;
  15. font-family: "Microsoft YaHei", Arial, sans-serif;
  16. background: #07121f;
  17. }
  18. .screen {
  19. width: 100vw;
  20. height: 100vh;
  21. padding: 18px 22px;
  22. display: grid;
  23. grid-template-rows: 74px 118px 280px 1fr;
  24. gap: 14px;
  25. background: linear-gradient(135deg, #07121f 0%, #102234 48%, #081522 100%);
  26. }
  27. .header {
  28. display: flex;
  29. align-items: center;
  30. justify-content: space-between;
  31. border-bottom: 1px solid rgba(108, 214, 255, .28);
  32. }
  33. .title { font-size: 30px; font-weight: 700; letter-spacing: 0; }
  34. .time { text-align: right; color: #9fd8ff; font-size: 16px; line-height: 26px; }
  35. .summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
  36. .metric, .panel, .device-card {
  37. border: 1px solid rgba(95, 201, 255, .28);
  38. background: rgba(7, 25, 41, .76);
  39. box-shadow: inset 0 0 22px rgba(49, 163, 220, .08);
  40. border-radius: 6px;
  41. }
  42. .metric { padding: 14px 20px; display: flex; flex-direction: column; justify-content: center; }
  43. .metric-label { color: #9fb6c7; font-size: 15px; }
  44. .metric-value { margin-top: 6px; font-size: 32px; font-weight: 700; color: #44e0c2; }
  45. .metric-unit { margin-left: 6px; font-size: 16px; color: #a8cfe7; }
  46. .metric-sub { margin-top: 6px; color: #8fb3ca; font-size: 14px; }
  47. .metric-sub strong { color: #79d9ff; font-size: 16px; }
  48. .main { min-height: 0; }
  49. .device-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; min-height: 0; }
  50. .device-card { padding: 16px; min-height: 0; }
  51. .device-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
  52. .device-name { font-size: 20px; font-weight: 700; }
  53. .badge { padding: 4px 10px; border-radius: 4px; font-size: 13px; background: rgba(68, 224, 194, .18); color: #44e0c2; }
  54. .badge.offline { background: rgba(255, 103, 103, .14); color: #ff8686; }
  55. .device-sn { margin-left: 10px; color: #8fb3ca; font-size: 13px; font-weight: 400; }
  56. .kv-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
  57. .kv { padding: 10px; border-radius: 4px; background: rgba(255,255,255,.04); }
  58. .kv span { display: block; color: #92a9bb; font-size: 13px; margin-bottom: 5px; }
  59. .kv strong {
  60. display: block;
  61. width: 100%;
  62. font-size: 20px;
  63. color: #ffffff;
  64. line-height: 1.25;
  65. white-space: normal;
  66. overflow-wrap: anywhere;
  67. }
  68. .kv strong.small { font-size: 16px; }
  69. .chart-wrap { display: grid; grid-template-columns: 1fr 1.2fr 0.8fr; gap: 14px; min-height: 0; }
  70. .panel { min-height: 0; padding: 14px; display: flex; flex-direction: column; }
  71. .panel-title { height: 30px; line-height: 30px; font-size: 18px; font-weight: 700; color: #79d9ff; }
  72. .chart { flex: 1; min-height: 0; }
  73. </style>
  74. </head>
  75. <body>
  76. <div class="screen">
  77. <div class="header">
  78. <div class="title">能源消耗监控大屏</div>
  79. <div class="time"><div id="dateText">--</div><div id="timeText">--</div></div>
  80. </div>
  81. <div class="summary">
  82. <div class="metric"><div class="metric-label" id="meter1PowerLabel">电表1 当前功率</div><div class="metric-value"><span id="meter1Power">0</span><span class="metric-unit">kW</span></div></div>
  83. <div class="metric">
  84. <div class="metric-label" id="meter1EnergyLabel">电表1 今日用电</div>
  85. <div class="metric-value"><span id="meter1Energy">0</span><span class="metric-unit">kWh</span></div>
  86. <div class="metric-sub">本月 <strong><span id="meter1MonthEnergy">0</span></strong> kWh</div>
  87. </div>
  88. <div class="metric"><div class="metric-label" id="meter2PowerLabel">电表2 当前功率</div><div class="metric-value"><span id="meter2Power">0</span><span class="metric-unit">kW</span></div></div>
  89. <div class="metric">
  90. <div class="metric-label" id="meter2EnergyLabel">电表2 今日用电</div>
  91. <div class="metric-value"><span id="meter2Energy">0</span><span class="metric-unit">kWh</span></div>
  92. <div class="metric-sub">本月 <strong><span id="meter2MonthEnergy">0</span></strong> kWh</div>
  93. </div>
  94. </div>
  95. <div class="main">
  96. <div class="device-list" id="deviceList"></div>
  97. </div>
  98. <div class="chart-wrap">
  99. <div class="panel"><div class="panel-title">今日累计用电趋势</div><div id="trendChart" class="chart"></div></div>
  100. <div class="panel"><div class="panel-title">本月每日用电</div><div id="monthChart" class="chart"></div></div>
  101. <div class="panel"><div class="panel-title">实时功率对比</div><div id="powerChart" class="chart"></div></div>
  102. </div>
  103. </div>
  104. <script src="${ctxStatic}/jquery-1.11.3.min.js"></script>
  105. <script src="${ctxStatic}/echarts/4.2/echarts.min.js"></script>
  106. <script>
  107. var trendChart = echarts.init(document.getElementById('trendChart'));
  108. var monthChart = echarts.init(document.getElementById('monthChart'));
  109. var powerChart = echarts.init(document.getElementById('powerChart'));
  110. function fmt(value) {
  111. var num = Number(value || 0);
  112. return Number.isFinite(num) ? num.toFixed(2) : '0.00';
  113. }
  114. function deviceTitle(device, index) {
  115. return device.deviceName || device.deviceSn || ('电表' + (index + 1));
  116. }
  117. function formatTime(value) {
  118. if (!value) {
  119. return '-';
  120. }
  121. if (typeof value === 'string') {
  122. return value.replace('T', ' ').replace(/\.\d+.*$/, '');
  123. }
  124. return value;
  125. }
  126. function updateClock() {
  127. var now = new Date();
  128. $('#dateText').text(now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0'));
  129. $('#timeText').text(String(now.getHours()).padStart(2, '0') + ':' + String(now.getMinutes()).padStart(2, '0') + ':' + String(now.getSeconds()).padStart(2, '0'));
  130. }
  131. function renderDevices(devices) {
  132. var html = '';
  133. devices.forEach(function (d, index) {
  134. var title = deviceTitle(d, index);
  135. html += '<div class="device-card">' +
  136. '<div class="device-head"><div class="device-name">' + title + '<span class="device-sn">' + (d.deviceSn || '-') + '</span></div>' +
  137. '<div class="badge ' + (d.online ? '' : 'offline') + '">' + (d.online ? '在线' : '离线') + '</div></div>' +
  138. '<div class="kv-grid">' +
  139. '<div class="kv"><span>当前功率</span><strong>' + fmt(d.power) + ' kW</strong></div>' +
  140. '<div class="kv"><span>今日用电</span><strong>' + fmt(d.todayEnergy) + ' kWh</strong></div>' +
  141. '<div class="kv"><span>本月用电</span><strong>' + fmt(d.monthEnergy) + ' kWh</strong></div>' +
  142. '<div class="kv"><span>A/B/C电压</span><strong class="small">' + fmt(d.ua) + ' / ' + fmt(d.ub) + ' / ' + fmt(d.uc) + ' V</strong></div>' +
  143. '<div class="kv"><span>A/B/C电流</span><strong class="small">' + fmt(d.ia) + ' / ' + fmt(d.ib) + ' / ' + fmt(d.ic) + ' A</strong></div>' +
  144. '<div class="kv"><span>上报时间</span><strong class="small">' + formatTime(d.reportTimeText || d.reportTime) + '</strong></div>' +
  145. '</div></div>';
  146. });
  147. $('#deviceList').html(html || '<div class="device-card"><div class="device-name">暂无电表数据</div></div>');
  148. }
  149. function renderTopMeters(devices) {
  150. for (var i = 0; i < 2; i++) {
  151. var device = devices[i] || {};
  152. var title = deviceTitle(device, i);
  153. $('#meter' + (i + 1) + 'PowerLabel').text(title + ' 当前功率');
  154. $('#meter' + (i + 1) + 'EnergyLabel').text(title + ' 今日用电');
  155. $('#meter' + (i + 1) + 'Power').text(fmt(device.power));
  156. $('#meter' + (i + 1) + 'Energy').text(fmt(device.todayEnergy));
  157. $('#meter' + (i + 1) + 'MonthEnergy').text(fmt(device.monthEnergy));
  158. }
  159. }
  160. function renderCharts(data) {
  161. var devices = data.devices || [];
  162. trendChart.setOption({
  163. color: ['#44e0c2', '#79d9ff', '#ffcc66'],
  164. tooltip: { trigger: 'axis' },
  165. legend: { top: 0, right: 10, textStyle: { color: '#b8d9ee' } },
  166. grid: { left: 45, right: 25, bottom: 34, top: 42 },
  167. xAxis: { type: 'category', data: data.hours || [], axisLabel: { color: '#9fb6c7' }, axisLine: { lineStyle: { color: '#31536a' } } },
  168. yAxis: { type: 'value', name: 'kWh', nameTextStyle: { color: '#9fb6c7' }, axisLabel: { color: '#9fb6c7' }, splitLine: { lineStyle: { color: 'rgba(100,160,190,.16)' } } },
  169. series: (data.hourlySeries || []).map(function (item) {
  170. return { name: item.name, type: 'line', smooth: true, symbol: 'circle', symbolSize: 5, data: item.data || [] };
  171. })
  172. });
  173. monthChart.setOption({
  174. color: ['#44e0c2', '#79d9ff', '#ffcc66'],
  175. tooltip: { trigger: 'axis' },
  176. legend: { top: 0, right: 10, textStyle: { color: '#b8d9ee' } },
  177. grid: { left: 50, right: 20, bottom: 34, top: 42 },
  178. xAxis: {
  179. type: 'category',
  180. data: data.days || [],
  181. axisLabel: { color: '#9fb6c7', interval: 0, rotate: 40 },
  182. axisLine: { lineStyle: { color: '#31536a' } }
  183. },
  184. yAxis: {
  185. type: 'value',
  186. name: 'kWh',
  187. nameTextStyle: { color: '#9fb6c7' },
  188. axisLabel: { color: '#9fb6c7' },
  189. splitLine: { lineStyle: { color: 'rgba(100,160,190,.16)' } }
  190. },
  191. series: (data.dailySeries || []).map(function (item) {
  192. return { name: item.name, type: 'bar', barMaxWidth: 14, data: item.data || [] };
  193. })
  194. });
  195. powerChart.setOption({
  196. color: ['#44e0c2'],
  197. tooltip: {},
  198. grid: { left: 45, right: 25, bottom: 34, top: 20 },
  199. xAxis: { type: 'category', data: devices.map(function (d, index) { return deviceTitle(d, index); }), axisLabel: { color: '#9fb6c7' }, axisLine: { lineStyle: { color: '#31536a' } } },
  200. yAxis: { type: 'value', name: 'kW', nameTextStyle: { color: '#9fb6c7' }, axisLabel: { color: '#9fb6c7' }, splitLine: { lineStyle: { color: 'rgba(100,160,190,.16)' } } },
  201. series: [{ type: 'bar', barWidth: 36, data: devices.map(function (d) { return Number(d.power || 0); }) }]
  202. });
  203. }
  204. function loadData() {
  205. $.get('${ctx}/mes/mesProduct/energyScreenData', function (resp) {
  206. if (!resp || resp.result !== 'true') { return; }
  207. var data = resp.data || {};
  208. var devices = data.devices || [];
  209. renderTopMeters(devices);
  210. renderDevices(devices);
  211. renderCharts(data);
  212. });
  213. }
  214. updateClock();
  215. loadData();
  216. setInterval(updateClock, 1000);
  217. setInterval(loadData, 10000);
  218. window.addEventListener('resize', function () {
  219. trendChart.resize();
  220. monthChart.resize();
  221. powerChart.resize();
  222. });
  223. </script>
  224. </body>
  225. </html>