index.html 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <!-- 引入 ECharts 文件 -->
  6. <script type="text/javascript" src="static/jquery-3.3.1.min.js"></script>
  7. <script src="static/echarts.min.js"></script>
  8. <script src="static/plug-in.min.js"></script>
  9. <script src="static/jquery.liMarquee.js"></script>
  10. <link rel="stylesheet" href="static/index.css" media="all" />
  11. </head>
  12. <body>
  13. <div class="positon">
  14. <!-- <button class="back-btn" onclick="goBack()">&larr; 返回</button> -->
  15. 底图:<select id="mapName">
  16. </select>
  17. </div>
  18. <div class="title-name">设备运行状态一览图</div>
  19. <div class="title-icon">
  20. <label class="legend-item legend-normal"><input type="checkbox" id="filterNormal" checked> 正常设备</label>
  21. <label class="legend-item legend-yellow"><input type="checkbox" id="filterPlanned" checked> 问题设备</label>
  22. <!-- <label class="legend-item legend-red"><input type="checkbox" id="filterUnplanned" checked> 非计划性维修设备</label>-->
  23. </div>
  24. <div id="echart" class="echart"></div>
  25. <div class="data">
  26. <div>
  27. <span id="monthNum">暂无</span>
  28. </div>
  29. <div>
  30. <span id="waitNum">暂无</span>
  31. <span id="rate">暂无</span>
  32. </div>
  33. <div style="height: 80%;">
  34. <div id="weekJob" class="item title">
  35. <span>设备编号</span>
  36. <span>保养任务</span>
  37. <span>保养计划时间</span>
  38. </div>
  39. <div class="scrollDiv str_wrap str_vertical"></div>
  40. <!-- <div class="item">
  41. <span>设备名称</span>
  42. <span>正常</span>
  43. <span>2021/03/21</span>
  44. </div>-->
  45. </div>
  46. </div>
  47. </body>
  48. <style>
  49. /*Plugin CSS*/
  50. .str_wrap {
  51. overflow: hidden;
  52. height: 56%;
  53. width: 100%;
  54. position: relative;
  55. -moz-user-select: none;
  56. -khtml-user-select: none;
  57. user-select: none;
  58. white-space: nowrap;
  59. }
  60. .positon {
  61. position: absolute;
  62. top: 20px;
  63. left: 30%;
  64. z-index: 1000;
  65. }
  66. .back-btn {
  67. display: inline-block;
  68. margin-right: 15px;
  69. padding: 4px 14px;
  70. background-color: #174FBF;
  71. color: #fff;
  72. border: none;
  73. border-radius: 4px;
  74. font-size: 14px;
  75. cursor: pointer;
  76. vertical-align: middle;
  77. transition: background-color 0.2s;
  78. }
  79. .back-btn:hover {
  80. background-color: #0f3d99;
  81. }
  82. #mapName {
  83. width: 120px;
  84. }
  85. .str_move {
  86. white-space: nowrap;
  87. position: absolute;
  88. top: 0;
  89. left: 0;
  90. cursor: move;
  91. }
  92. .str_move_clone {
  93. display: inline-block;
  94. vertical-align: top;
  95. position: absolute;
  96. left: 100%;
  97. top: 0;
  98. }
  99. .str_vertical .str_move_clone {
  100. left: 0;
  101. top: 100%;
  102. }
  103. .str_down .str_move_clone {
  104. left: 0;
  105. bottom: 100%;
  106. }
  107. .title-name {
  108. position: absolute;
  109. top: 87px;
  110. left: 26%;
  111. font-size: 34px;
  112. color: black;
  113. z-index: 10000;
  114. }
  115. .title-icon {
  116. position: absolute;
  117. top: 130px;
  118. left: 30%;
  119. z-index: 10000;
  120. }
  121. .title-icon label.legend-item {
  122. display: inline-flex;
  123. align-items: center;
  124. margin-right: 24px;
  125. font-size: 14px;
  126. color: #333;
  127. cursor: pointer;
  128. user-select: none;
  129. }
  130. .title-icon label.legend-item::before {
  131. content: '';
  132. display: inline-block;
  133. width: 12px;
  134. height: 12px;
  135. border-radius: 50%;
  136. margin-right: 8px;
  137. }
  138. .title-icon label.legend-normal::before {
  139. background-color: #174FBF;
  140. box-shadow: 0 0 6px #174FBF;
  141. }
  142. .title-icon label.legend-yellow::before {
  143. background-color: yellow;
  144. box-shadow: 0 0 6px yellow;
  145. }
  146. .title-icon label.legend-red::before {
  147. background-color: red;
  148. box-shadow: 0 0 6px red;
  149. }
  150. .title-icon input[type="checkbox"] {
  151. margin-right: 5px;
  152. cursor: pointer;
  153. transform: scale(1.2);
  154. }
  155. </style>
  156. <script>
  157. function getBase64(image) {
  158. var canvas = document.createElement("canvas");
  159. canvas.width = image.width;
  160. canvas.height = image.height;
  161. var context = canvas.getContext("2d");
  162. context.drawImage(image, 0, 0, image.width, image.height);
  163. // 将canvas的内容转换为base64编码的字符串
  164. var base64 = canvas.toDataURL("image/png");// 可以根据需要更改为其他格式,如'image/jpeg'等
  165. return base64;
  166. }
  167. const ACCESS_TOKEN = 'Access-Token'
  168. const VUE_STORE_BASE = 'pro__'
  169. let mapName, mapList, dataList
  170. var tooltip_message = ''
  171. // 基于准备好的dom,初始化echarts实例
  172. var myChart = echarts.init(document.getElementById('echart'))
  173. var img = new Image()
  174. var canvas = document.createElement('canvas')
  175. var ctx = canvas.getContext('2d')
  176. canvas.width = myChart.getWidth() * window.devicePixelRatio
  177. canvas.height = myChart.getHeight() * window.devicePixelRatio
  178. var fullImage = new Image()
  179. img.onload = function () {
  180. ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
  181. fullImage.src = canvas.toDataURL()
  182. setTimeout(function () {
  183. myChart.resize()
  184. }, 100)
  185. }
  186. img.src = './static/03_01.png'
  187. var option = {
  188. // 背景
  189. backgroundColor: {
  190. repeat: 'no-repeat',
  191. image: fullImage
  192. },
  193. // 地图
  194. geo: {
  195. map: 'world',
  196. silent: true,
  197. top: 0,
  198. left: 0,
  199. right: 0,
  200. bottom: 0,
  201. itemStyle: {
  202. normal: {
  203. opacity: 0.8,
  204. borderWidth: 0,
  205. color: '#a53d13'
  206. }
  207. }
  208. },
  209. title: {
  210. text: '',
  211. },
  212. // 开启工具栏
  213. tooltip: {
  214. "trigger": "item",
  215. "confine": true,
  216. "formatter": (params, ticket, callback) => {
  217. // params.data [20, 204, "L-012"],水平位置,垂直位置,设备编号
  218. let sbNo = params.data[2];
  219. getSbDetail(sbNo);
  220. return tooltip_message;
  221. }
  222. },
  223. series: [{
  224. name: '正常点',
  225. type: 'effectScatter',
  226. coordinateSystem: 'geo',
  227. data: [
  228. ],
  229. showEffectOn: 'render',
  230. rippleEffect: {
  231. brushType: 'stroke'
  232. },
  233. hoverAnimation: true,
  234. label: {
  235. normal: {
  236. formatter: '{@value}',
  237. position: 'left',
  238. show: false
  239. }
  240. },
  241. itemStyle: {
  242. normal: {
  243. color: '#174FBF',
  244. shadowBlur: 200,
  245. shadowColor: '#174FBF'
  246. }
  247. },
  248. zlevel: 1
  249. }, {
  250. name: '正常点编号',
  251. type: 'scatter',
  252. coordinateSystem: 'geo',
  253. symbol: 'pin', // 气泡
  254. symbolSize: 50,
  255. label: {
  256. normal: {
  257. show: true,
  258. formatter: '{@value}',
  259. textStyle: {
  260. color: '#000',
  261. fontSize: 11
  262. }
  263. }
  264. },
  265. itemStyle: {
  266. normal: {
  267. color: '#174FBF'
  268. }
  269. },
  270. zlevel: 6,
  271. data: [
  272. ]
  273. }, {
  274. name: '红色非计划性报修异常点',
  275. type: 'effectScatter',
  276. coordinateSystem: 'geo',
  277. data: [
  278. ],
  279. showEffectOn: 'render',
  280. rippleEffect: {
  281. brushType: 'stroke'
  282. },
  283. hoverAnimation: true,
  284. label: {
  285. normal: {
  286. formatter: '{@value}',
  287. position: 'left',
  288. show: false
  289. }
  290. },
  291. itemStyle: {
  292. normal: {
  293. color: 'red',
  294. shadowBlur: 200,
  295. shadowColor: 'red'
  296. }
  297. },
  298. zlevel: 1
  299. }, {
  300. name: '红色非计划性报修异常点编号',
  301. type: 'scatter',
  302. coordinateSystem: 'geo',
  303. symbol: 'pin', // 气泡
  304. symbolSize: 50,
  305. label: {
  306. normal: {
  307. show: true,
  308. formatter: '{@value}',
  309. textStyle: {
  310. color: '#000',
  311. fontSize: 11
  312. }
  313. }
  314. },
  315. itemStyle: {
  316. normal: {
  317. color: 'red'
  318. }
  319. },
  320. zlevel: 6,
  321. data: [
  322. ]
  323. }, {
  324. name: '黄色计划性报修异常点',
  325. type: 'effectScatter',
  326. coordinateSystem: 'geo',
  327. data: [
  328. ],
  329. showEffectOn: 'render',
  330. rippleEffect: {
  331. brushType: 'stroke'
  332. },
  333. hoverAnimation: true,
  334. label: {
  335. normal: {
  336. formatter: '{@value}',
  337. position: 'left',
  338. show: false
  339. }
  340. },
  341. itemStyle: {
  342. normal: {
  343. color: 'yellow',
  344. shadowBlur: 200,
  345. shadowColor: 'yellow'
  346. }
  347. },
  348. zlevel: 1
  349. }, {
  350. name: '黄色计划性报修异常点编号',
  351. type: 'scatter',
  352. coordinateSystem: 'geo',
  353. symbol: 'pin', // 气泡
  354. symbolSize: 50,
  355. label: {
  356. normal: {
  357. show: true,
  358. formatter: '{@value}',
  359. textStyle: {
  360. color: '#000',
  361. fontSize: 11
  362. }
  363. }
  364. },
  365. itemStyle: {
  366. normal: {
  367. color: 'yellow'
  368. }
  369. },
  370. zlevel: 6,
  371. data: [
  372. ]
  373. }]
  374. }
  375. function getMapList() {
  376. $('#mapName').on('change', function (e) {
  377. mapName = e.delegateTarget.value
  378. img.src = mapList.find(item => item.targetId == mapName).url
  379. init()
  380. });
  381. $.ajax({
  382. type: "GET",
  383. url: "/api/upms/files?type=56",
  384. headers: getHeader(),
  385. success: function (res) {
  386. var data = res.data
  387. mapList = data
  388. for (var i = 0; i < data.length; i++) {
  389. var option = '<option value="' + data[i].targetId + '">' + data[i].targetId + '</option>'
  390. $('#mapName').append(option)
  391. }
  392. mapName = mapList[0].targetId
  393. img.src = mapList.find(item => item.targetId == mapName).url
  394. $('#mapName').val(mapName);
  395. }
  396. })
  397. }
  398. getMapList()
  399. //初始化加载数据,定时器只能在定时到了才发生
  400. getData();
  401. getScreenJobData();
  402. // 使用刚指定的配置项和数据显示图表
  403. myChart.setOption(option);
  404. // 设备详情
  405. function getSbDetail(sbNo) {
  406. $.ajax({
  407. type: "get",
  408. url: "/api/sb/infos/no/" + sbNo,
  409. headers: getHeader(),
  410. success: function (response) {
  411. tooltip_message = '<div>设备编号:' + response.data.no +
  412. '<br/>设备名称:' + response.data.name +
  413. '<br/>设备型号:' + response.data.model +
  414. '<br/>使用位置:' + response.data.cph +
  415. '<br/>设备维修员:' + response.data.repairUserName + '</div>';
  416. },
  417. error: function (xhr, textStatus, errorThrown) {
  418. error(xhr, textStatus, errorThrown);
  419. }
  420. });
  421. }
  422. // 任务数据
  423. function getScreenJobData() {
  424. console.log(21);
  425. $.ajax({
  426. type: "get",
  427. url: "/api/check/jobs/screen",
  428. headers: getHeader(),
  429. success: function (response) {
  430. $('#monthNum').text(response.data.finishNum + "/" + response.data.monthNum);
  431. $('#waitNum').text("待完成:" + response.data.waitNum);
  432. $('#rate').text("完成率:" + response.data.rate + "%");
  433. let weekJob = '';
  434. response.data.weekList.forEach(item => {
  435. weekJob = weekJob + ' <div class=\'item\'>\n' +
  436. ' <span>' + item.sbNo + '</span>\n' +
  437. ' <span>' + (item.requirement || '') + '</span>\n' +
  438. ' <span>' + item.startTime + '</span>\n' +
  439. ' </div>'
  440. })
  441. $('.scrollDiv').empty().append(weekJob);
  442. $('.scrollDiv').liMarquee({
  443. direction: 'up',//身上滚动
  444. runshort: false,//内容不足时不滚动
  445. scrollamount: 20//速度
  446. });
  447. },
  448. error: function (xhr, textStatus, errorThrown) {
  449. error(xhr, textStatus, errorThrown);
  450. }
  451. });
  452. }
  453. // setInterval(mockData(), 10000);
  454. setInterval(function () { getData() }, 60000);
  455. // setInterval(function(){ getScreenJobData() }, 60000);
  456. function mockData() {
  457. var data = [
  458. [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000), '正常'],
  459. [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000), '正常'],
  460. [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000), '正常'],
  461. [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000), '正常'],
  462. [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000), '正常'],
  463. [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000), '正常']
  464. ];
  465. var data2 = [
  466. [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000), '不知道', '不知道'],
  467. [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000), '不知道', '不知道'],
  468. [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000), '不知道', '不知道'],
  469. [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000), '不知道', '不知道'],
  470. [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000), '不知道', '不知道'],
  471. [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000), '不知道', '不知道']
  472. ];
  473. option.series[0].data = data;// 正常数据
  474. option.series[1].data = data2;// 异常的红色内容名称
  475. option.series[2].data = data2;// 异常黄点
  476. console.log(data);
  477. console.log(data2);
  478. myChart.setOption(option, true)
  479. }
  480. function getData() {
  481. $.ajax({
  482. type: "get",
  483. url: "/api/sb/infos/screen",
  484. headers: getHeader(),
  485. success: function (response) {
  486. dataList = response.data;
  487. init()
  488. },
  489. error: function (xhr, textStatus, errorThrown) {
  490. error(xhr, textStatus, errorThrown);
  491. }
  492. });
  493. }
  494. function init() {
  495. data = dataList.find(item => item.mapName === mapName)
  496. const normalSbInfoList = [];
  497. const repairSbInfoListRed = [];
  498. const repairSbInfoListYellow = [];
  499. if (data.normalSbInfoList != null) {
  500. for (var i = 0; i < data.normalSbInfoList.length; i++) {
  501. normalSbInfoList.push([data.normalSbInfoList[i].zjm, data.normalSbInfoList[i].jbdh,
  502. data.normalSbInfoList[i].no])
  503. }
  504. }
  505. if (data.repairSbInfoListRed != null) {
  506. for (var i = 0; i < data.repairSbInfoListRed.length; i++) {
  507. repairSbInfoListRed.push([data.repairSbInfoListRed[i].zjm, data.repairSbInfoListRed[i].jbdh,
  508. data.repairSbInfoListRed[i].no])
  509. }
  510. }
  511. if (data.repairSbInfoListYellow != null) {
  512. for (var i = 0; i < data.repairSbInfoListYellow.length; i++) {
  513. repairSbInfoListYellow.push([data.repairSbInfoListYellow[i].zjm, data.repairSbInfoListYellow[i].jbdh,
  514. data.repairSbInfoListYellow[i].no])
  515. }
  516. }
  517. // 保存原始数据副本
  518. option._originalData = {
  519. normal: normalSbInfoList.slice(),
  520. red: repairSbInfoListRed.slice(),
  521. yellow: repairSbInfoListYellow.slice()
  522. };
  523. option.series[0].data = normalSbInfoList;// 正常数据:
  524. option.series[1].data = normalSbInfoList;// 正常数据的编号
  525. option.series[2].data = repairSbInfoListRed;// 非计划性报修 红色编号
  526. option.series[3].data = repairSbInfoListRed;// 非计划性报修 红色
  527. option.series[4].data = repairSbInfoListYellow;// 计划性报修 黃色编号
  528. option.series[5].data = repairSbInfoListYellow;// 计划性报修 黃色
  529. applyFilter();
  530. }
  531. function applyFilter() {
  532. const showNormal = $('#filterNormal').is(':checked');
  533. const showPlanned = $('#filterPlanned').is(':checked');
  534. const showUnplanned = $('#filterUnplanned').is(':checked');
  535. const orig = option._originalData || { normal: [], red: [], yellow: [] };
  536. option.series[0].data = showNormal ? orig.normal : [];
  537. option.series[1].data = showNormal ? orig.normal : [];
  538. option.series[2].data = showUnplanned ? orig.red : [];
  539. option.series[3].data = showUnplanned ? orig.red : [];
  540. option.series[4].data = showPlanned ? orig.yellow : [];
  541. option.series[5].data = showPlanned ? orig.yellow : [];
  542. myChart.setOption(option, true);
  543. }
  544. $('#filterNormal, #filterPlanned, #filterUnplanned').on('change', function () {
  545. applyFilter();
  546. });
  547. function getHeader() {
  548. return {
  549. Authorization: getToken(),
  550. "Cache-Control": "no-cache",
  551. accept: "application/json; charset=utf-8",
  552. 'Content-Type': 'application/json;charset=UTF-8'
  553. // accept: "application/json; charset=utf-8",
  554. // "Access-Control-Allow-Origin": "http://localhost:5000",
  555. // "Access-Control-Allow-Headers":"Origin, X-Requested-With, Content-Type, Accept"
  556. }
  557. }
  558. function getToken() {
  559. const storeTokenJson = JSON.parse(localStorage.getItem(VUE_STORE_BASE + ACCESS_TOKEN))
  560. return 'Bearer ' + storeTokenJson.value
  561. }
  562. function goBack() {
  563. // 优先尝试让父级 Vue 路由跳转到首页
  564. try {
  565. if (window.parent && window.parent !== window) {
  566. // 通知父级 Vue 跳转首页
  567. window.parent.postMessage({ action: 'navigateHome' }, '*')
  568. // 作为兜底:让父级回退
  569. setTimeout(function () {
  570. if (window.parent.history.length > 1) {
  571. window.parent.history.back()
  572. }
  573. }, 100)
  574. } else {
  575. if (window.history.length > 1) {
  576. window.history.back()
  577. }
  578. }
  579. } catch (e) {
  580. if (window.history.length > 1) {
  581. window.history.back()
  582. }
  583. }
  584. }
  585. (function () {
  586. console.log("滚动")
  587. $('.scrollDiv').liMarquee({
  588. direction: 'up',//身上滚动
  589. runshort: false,//内容不足时不滚动
  590. scrollamount: 20//速度
  591. });
  592. });
  593. </script>
  594. </html>