warehouseTwo.html 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8" />
  5. <meta name="viewport" content="width=1920" />
  6. <title>无人线边仓库看板</title>
  7. <link rel="stylesheet" href="./css/common.css" />
  8. <link rel="stylesheet" href="./css/board2.css" />
  9. <script type="text/javascript" src="./plugin/jquery.min.js"></script>
  10. <script type="text/javascript" src="./plugin/echarts.min.js"></script>
  11. <script type="text/javascript" src="./plugin/vue.min.js"></script>
  12. <script type="text/javascript" src="./js/util.js"></script>
  13. <script type="text/javascript" src="./js/common.js"></script>
  14. <script src="./plugin/datav.min.js"></script>
  15. <script type="text/javascript" src="./js/chart.js"></script>
  16. <script type="text/javascript" src="./js/testDatas.js"></script>
  17. </head>
  18. <script>
  19. $(window).load(function () {
  20. $(".loading").fadeOut();
  21. });
  22. //动态设置视口
  23. const setSize = () => {
  24. // 获取html元素
  25. const html = document.getElementsByTagName("html")[0];
  26. // 获取屏幕宽度
  27. const pageWidth = html.getBoundingClientRect().width;
  28. // 动态计算字体大小(rem)
  29. html.style.fontSize = pageWidth / 20 + "px";
  30. };
  31. setSize();
  32. window.addEventListener("resize", setSize, false);
  33. </script>
  34. <body>
  35. <div class="loading">
  36. <div class="load_box">
  37. <img src="./images/loading.gif" /> 看板加载中,请稍等...
  38. </div>
  39. </div>
  40. <div id="app" class="container">
  41. <div class="head">
  42. <h1>无人线边仓库看板</h1>
  43. <span id="showTime"></span>
  44. </div>
  45. <div class="box">
  46. <span class="title maintain-title">工装设备维修记录</span>
  47. <span class="maintain maintain-all"
  48. >当月维修总数:{{repairDatas.repairQuantity}}</span
  49. >
  50. <span class="maintain maintain-complete"
  51. >已维修数:{{repairDatas.repairCompletedQuantity}}</span
  52. >
  53. <span class="maintain maintain-incomplete"
  54. >待维修数:{{repairDatas.repairUncompletedQuantity}}</span
  55. >
  56. <div>
  57. <dv-scroll-board
  58. ref="scrollBoard1"
  59. style="
  60. height: 2.2rem;
  61. position: absolute;
  62. width: 5.2rem;
  63. top: 1.06rem;
  64. left: 0.3rem;
  65. "
  66. :config="maintainConfig"
  67. />
  68. </div>
  69. </div>
  70. <div class="box">
  71. <span class="title checkout-title">工装设备检验记录</span>
  72. <span class="checkout checkout-all"
  73. >当月检验总数:{{checkoutDatas.inspectionQuantity}}</span
  74. >
  75. <span class="checkout checkout-complete"
  76. >已检验数:{{checkoutDatas.inspectionCompletedQuantity}}</span
  77. >
  78. <span class="checkout checkout-incomplete"
  79. >待检验数:{{checkoutDatas.inspectionUncompletedQuantity}}</span
  80. >
  81. <div>
  82. <dv-scroll-board
  83. ref="scrollBoard2"
  84. style="
  85. height: 2.2rem;
  86. position: absolute;
  87. width: 5.2rem;
  88. top: 4.7rem;
  89. left: 0.3rem;
  90. "
  91. :config="checkoutConfig"
  92. />
  93. </div>
  94. </div>
  95. <div class="box">
  96. <span class="title check-title">工装设备检验图表</span>
  97. <div
  98. style="
  99. height: 2.5rem;
  100. position: absolute;
  101. width: 4.86rem;
  102. top: 7.9rem;
  103. left: 0.44rem;
  104. "
  105. id="checkoutChart"
  106. ></div>
  107. </div>
  108. <div class="box">
  109. <span class="title inventory-name">{{ inventoryDatas.name }}</span>
  110. <span class="inventory clamp-all">工装总数</span>
  111. <span class="inventory clamp-all-count"
  112. >{{ inventoryDatas.clampQuantity }}</span
  113. >
  114. <span class="inventory clamp-complete">已盘数</span>
  115. <span class="inventory clamp-complete-count"
  116. >{{ inventoryDatas.clampInventoriedQuantity }}</span
  117. >
  118. <span class="inventory clamp-incomplete">未盘数</span>
  119. <span class="inventory clamp-incomplete-count"
  120. >{{ inventoryDatas.clampNotInventoriedQuantity }}</span
  121. >
  122. <span class="inventory device-all">设备总数</span>
  123. <span class="inventory device-all-count"
  124. >{{ inventoryDatas.instrumentQuantity }}</span
  125. >
  126. <span class="inventory device-complete">已盘数</span>
  127. <span class="inventory device-complete-count"
  128. >{{ inventoryDatas.instrumentInventoriedQuantity }}</span
  129. >
  130. <span class="inventory device-incomplete">未盘数</span>
  131. <span class="inventory device-incomplete-count"
  132. >{{ inventoryDatas.instrumentNotInventoriedQuantity }}</span
  133. >
  134. </div>
  135. <div class="box">
  136. <span class="title agv-task-title">AGV 任务执行记录</span>
  137. <div>
  138. <dv-scroll-board
  139. ref="scrollBoard3"
  140. style="
  141. height: 2.8rem;
  142. position: absolute;
  143. width: 7.8rem;
  144. top: 7.4rem;
  145. left: 6rem;
  146. "
  147. :config="agvTaskConfig"
  148. />
  149. </div>
  150. </div>
  151. <div class="box">
  152. <span class="title agv-year-title">AGV 年任务统计</span>
  153. <div
  154. style="
  155. height: 3rem;
  156. position: absolute;
  157. width: 5.6rem;
  158. top: 0.82rem;
  159. right: 0.1rem;
  160. "
  161. id="agvYearChart"
  162. ></div>
  163. </div>
  164. <div class="box">
  165. <span class="title agv-record-title">AGV 任务执行统计</span>
  166. <div
  167. style="
  168. height: 2.5rem;
  169. position: absolute;
  170. width: 4.86rem;
  171. top: 4.3rem;
  172. right: 0.44rem;
  173. "
  174. id="agvTotalChart"
  175. ></div>
  176. </div>
  177. <div class="box">
  178. <span class="title device-time-title">设备使用时长</span>
  179. <div>
  180. <dv-scroll-board
  181. ref="scrollBoard4"
  182. style="
  183. height: 2.3rem;
  184. position: absolute;
  185. width: 5rem;
  186. top: 7.86rem;
  187. right: 0.4rem;
  188. "
  189. :config="deviceTimeConfig"
  190. />
  191. </div>
  192. </div>
  193. </div>
  194. <div class="back"></div>
  195. <script>
  196. var app = new Vue({
  197. el: "#app",
  198. data() {
  199. return {
  200. timer: null,
  201. checkoutChart: null,
  202. agvYearChart: null,
  203. agvTotalChart: null,
  204. chartDatas: null,
  205. maintainConfig: {
  206. header: [
  207. // '<span style="color:#ffffff;font-size:0.14rem">序号</span>',
  208. '<span style="color:#ffffff;font-size:0.14rem">名称</span>',
  209. '<span style="color:#ffffff;font-size:0.14rem">类型</span>',
  210. '<span style="color:#ffffff;font-size:0.14rem">维修原因</span>',
  211. '<span style="color:#ffffff;font-size:0.14rem">维修时间</span>',
  212. ],
  213. columnWidth: [140, 80, 120, 140],
  214. data: [],
  215. align: ["center", "center", "center", "center"],
  216. headerBGC: "transparent",
  217. oddRowBGC: "transparent",
  218. evenRowBGC: "transparent",
  219. },
  220. checkoutConfig: {
  221. header: [
  222. // '<span style="color:#ffffff;font-size:0.14rem">序号</span>',
  223. '<span style="color:#ffffff;font-size:0.14rem">名称</span>',
  224. '<span style="color:#ffffff;font-size:0.14rem">类型</span>',
  225. '<span style="color:#ffffff;font-size:0.14rem">送检时间</span>',
  226. '<span style="color:#ffffff;font-size:0.14rem">返回时间</span>',
  227. ],
  228. columnWidth: [140, 80, 120, 140],
  229. data: [],
  230. align: ["center", "center", "center", "center"],
  231. headerBGC: "transparent",
  232. oddRowBGC: "transparent",
  233. evenRowBGC: "transparent",
  234. },
  235. agvTaskConfig: {
  236. header: [
  237. // '<span style="color:#ffffff;font-size:0.14rem">序号</span>',
  238. '<span style="color:#ffffff;font-size:0.14rem">名称</span>',
  239. '<span style="color:#ffffff;font-size:0.14rem">类型</span>',
  240. // '<span style="color:#ffffff;font-size:0.14rem">状态</span>',
  241. '<span style="color:#ffffff;font-size:0.14rem">起点位置</span>',
  242. '<span style="color:#ffffff;font-size:0.14rem">终点位置</span>',
  243. '<span style="color:#ffffff;font-size:0.14rem">下达时间</span>',
  244. // '<span style="color:#ffffff;font-size:0.14rem">执行时间</span>',
  245. '<span style="color:#ffffff;font-size:0.14rem">完成时间</span>',
  246. ],
  247. columnWidth: [120, 110, 90, 90, 160, 160],
  248. data: [],
  249. align: [
  250. "center",
  251. "center",
  252. "center",
  253. "center",
  254. "center",
  255. "center",
  256. // "center",
  257. ],
  258. headerBGC: "transparent",
  259. oddRowBGC: "transparent",
  260. evenRowBGC: "transparent",
  261. },
  262. deviceTimeConfig: {
  263. header: [
  264. // '<span style="color:#ffffff;font-size:0.14rem">序号</span>',
  265. '<span style="color:#ffffff;font-size:0.14rem">名称</span>',
  266. '<span style="color:#ffffff;font-size:0.14rem">编号</span>',
  267. '<span style="color:#ffffff;font-size:0.14rem">类型</span>',
  268. '<span style="color:#ffffff;font-size:0.14rem">使用时长</span>',
  269. ],
  270. columnWidth: [140, 160, 70, 126],
  271. data: [],
  272. align: ["center", "center", "center", "center"],
  273. headerBGC: "transparent",
  274. oddRowBGC: "transparent",
  275. evenRowBGC: "transparent",
  276. },
  277. tableDatas: [],
  278. repairDatas: {},
  279. repairLineDatas: [],
  280. checkoutDatas: {},
  281. checkoutLineDatas: [],
  282. inventoryDatas: {},
  283. chartDatas: [],
  284. agvTaskDatas: [],
  285. agvMonthDatas: [],
  286. useTimeData: [],
  287. agvComplete: 0,
  288. agvUnComplete: 0,
  289. };
  290. },
  291. methods: {
  292. // 获取当前展示的仓库id
  293. getWarehouseId() {
  294. const _self = this;
  295. const params = getQueryString();
  296. _self.warehouseId = params.warehouseId;
  297. },
  298. // 绘制工装设备检验图
  299. createCheckoutChart() {
  300. const _self = this;
  301. const checkoutOption = drawCheckoutChart();
  302. initChart(_self.checkoutChart, checkoutOption);
  303. },
  304. // 绘制Agv年任务统计图
  305. createAgvYearChart() {
  306. const _self = this;
  307. const agvYearOption = drawAgvYearChart();
  308. initChart(_self.agvYearChart, agvYearOption);
  309. },
  310. // 绘制AGV任务执行统计图
  311. createAgvTotalChart() {
  312. const _self = this;
  313. const agvTotalOption = drawAgvTotalChart();
  314. initChart(_self.agvTotalChart, agvTotalOption);
  315. },
  316. // 获取看板信息
  317. getWarehouseInfo() {
  318. const _self = this;
  319. const url = "/api/InventoryRepairResource/queryBoardData";
  320. const params = [["warehouseId", _self.warehouseId]];
  321. // const success = twoDatas // 测试数据
  322. ajaxGet(url, params).then((success) => {
  323. if (success.errorCode === 0) {
  324. const {
  325. cfCheckVouchBoardResponse,
  326. cfInventoryRepairBoardResponse,
  327. } = success.data;
  328. const {
  329. cfInventoryInspectionBoardResponse,
  330. cfInventoryChartBoardResponse,
  331. cfInventoryAgvBoardResponse,
  332. cfInventoryUseTimeBoardResponse,
  333. } = success.data;
  334. _self.updateInventory(cfCheckVouchBoardResponse);
  335. _self.updateRepair(
  336. cfInventoryRepairBoardResponse.cfInventoryRepairLineBoardResponses,
  337. );
  338. _self.updateCheck(
  339. cfInventoryInspectionBoardResponse.cfInventoryInspectionLineBoardResponses,
  340. );
  341. _self.updateCount(
  342. cfInventoryRepairBoardResponse,
  343. cfInventoryInspectionBoardResponse,
  344. );
  345. _self.updateChart(cfInventoryChartBoardResponse);
  346. _self.updateAgvTask(cfInventoryAgvBoardResponse.agvTaskList);
  347. _self.updateAgvMonthTask(
  348. cfInventoryAgvBoardResponse.agvMonthTaskList,
  349. );
  350. _self.updateAgvTotalTask(
  351. cfInventoryAgvBoardResponse.completeQuantity,
  352. cfInventoryAgvBoardResponse.incompleteQuantity,
  353. );
  354. _self.updateUseTime(cfInventoryUseTimeBoardResponse);
  355. } else {
  356. console.log(success.errorMessage);
  357. }
  358. });
  359. },
  360. // 更新盘点单信息
  361. updateInventory(dtos) {
  362. const _self = this;
  363. if (!isObjectEqual(dtos, _self.inventoryDatas)) {
  364. _self.inventoryDatas = dtos;
  365. }
  366. },
  367. // 更新维修单信息
  368. updateRepair(dtos) {
  369. const _self = this;
  370. if (!isObjectEqual(dtos, _self.repairLineDatas)) {
  371. const processedData = dtos.map((item, index) => {
  372. return [
  373. // index + 1,
  374. item.name || "",
  375. item.type || "",
  376. item.repairReason || "",
  377. item.completeRepairTime
  378. ? item.completeRepairTime.substring(0, 10)
  379. : "",
  380. ];
  381. });
  382. _self.maintainConfig.data = JSON.parse(
  383. JSON.stringify(processedData),
  384. );
  385. // 强制更新组件
  386. _self.$nextTick(() => {
  387. if (_self.$refs.scrollBoard1) {
  388. _self.$refs.scrollBoard1.updateRows(
  389. _self.maintainConfig.data,
  390. );
  391. }
  392. });
  393. _self.repairLineDatas = dtos;
  394. }
  395. },
  396. // 更新检验单信息
  397. updateCheck(dtos) {
  398. const _self = this;
  399. if (!isObjectEqual(dtos, _self.checkoutLineDatas)) {
  400. const processedData = dtos.map((item, index) => {
  401. return [
  402. // index + 1,
  403. item.name || "",
  404. item.type || "",
  405. item.inspectionTime
  406. ? item.inspectionTime.substring(0, 10)
  407. : "",
  408. item.completeInspectionTime
  409. ? item.completeInspectionTime.substring(0, 10)
  410. : "",
  411. ];
  412. });
  413. _self.checkoutConfig.data = JSON.parse(
  414. JSON.stringify(processedData),
  415. );
  416. // 强制更新组件
  417. _self.$nextTick(() => {
  418. if (_self.$refs.scrollBoard2) {
  419. _self.$refs.scrollBoard2.updateRows(
  420. _self.checkoutConfig.data,
  421. );
  422. }
  423. });
  424. _self.checkoutLineDatas = dtos;
  425. }
  426. },
  427. // 更新维修检查数量
  428. updateCount(repair, checkout) {
  429. const _self = this;
  430. const repairCount = {
  431. repairQuantity: repair.repairQuantity,
  432. repairCompletedQuantity: repair.repairCompletedQuantity,
  433. repairUncompletedQuantity: repair.repairUncompletedQuantity,
  434. };
  435. const checkoutCount = {
  436. inspectionQuantity: checkout.inspectionQuantity,
  437. inspectionCompletedQuantity: checkout.inspectionCompletedQuantity,
  438. inspectionUncompletedQuantity:
  439. checkout.inspectionUncompletedQuantity,
  440. };
  441. if (!isObjectEqual(repairCount, _self.repairDatas)) {
  442. _self.repairDatas = repairCount;
  443. }
  444. if (!isObjectEqual(checkoutCount, _self.checkoutDatas)) {
  445. _self.checkoutDatas = checkoutCount;
  446. }
  447. },
  448. // 更新agv任务列表
  449. updateAgvTask(dtos) {
  450. const _self = this;
  451. if (!isObjectEqual(dtos, _self.agvTaskDatas)) {
  452. const processedData = dtos.map((item, index) => {
  453. return [
  454. // index + 1,
  455. item.agvName || "",
  456. item.type || "",
  457. item.positionNo || "",
  458. item.positionEndNo || "",
  459. item.createTime || "",
  460. // item.executeTime || "",
  461. item.endTime || "",
  462. ];
  463. });
  464. _self.agvTaskConfig.data = JSON.parse(
  465. JSON.stringify(processedData),
  466. );
  467. // 强制更新组件
  468. _self.$nextTick(() => {
  469. if (_self.$refs.scrollBoard3) {
  470. _self.$refs.scrollBoard3.updateRows(_self.agvTaskConfig.data);
  471. }
  472. });
  473. _self.agvTaskDatas = dtos;
  474. }
  475. },
  476. // 更新工装设备检验表数据
  477. updateChart(dtos) {
  478. const _self = this;
  479. if (!isObjectEqual(dtos, _self.chartDatas)) {
  480. // 工装数据
  481. const clampData =
  482. dtos.cfInventoryChartClampLineBoardResponses || [];
  483. // 设备数据
  484. const instrumentData =
  485. dtos.cfInventoryChartInstrumentLineBoardResponses || [];
  486. // 按日期排序(日期小的在前)
  487. const sortedClampData = [...clampData].sort((a, b) => {
  488. return new Date(a.monthName) - new Date(b.monthName);
  489. });
  490. const sortedInstrumentData = [...instrumentData].sort((a, b) => {
  491. return new Date(a.monthName) - new Date(b.monthName);
  492. });
  493. // 排序后的月份
  494. const xDatas =
  495. sortedClampData.map((item) => item.monthName) || [];
  496. // 创建月份到数量的映射,确保日期对应
  497. const clampMap = new Map();
  498. sortedClampData.forEach((item) => {
  499. clampMap.set(item.monthName, item.quantity);
  500. });
  501. const instrumentMap = new Map();
  502. sortedInstrumentData.forEach((item) => {
  503. instrumentMap.set(item.monthName, item.quantity);
  504. });
  505. // 根据x轴数据顺序提取对应的数量数据
  506. const clampQuantities = xDatas.map(
  507. (month) => clampMap.get(month) || 0,
  508. );
  509. const instrumentQuantities = xDatas.map(
  510. (month) => instrumentMap.get(month) || 0,
  511. );
  512. // 更新图表
  513. if (_self.checkoutChart) {
  514. _self.checkoutChart.setOption({
  515. xAxis: {
  516. data: xDatas,
  517. },
  518. series: [
  519. { name: "工装", data: clampQuantities },
  520. { name: "设备", data: instrumentQuantities },
  521. ],
  522. });
  523. }
  524. _self.chartDatas = dtos;
  525. }
  526. },
  527. // 更新agv年任务统计(地面库、立体库)
  528. updateAgvMonthTask(dto) {
  529. const _self = this;
  530. if (!isObjectEqual(dto, _self.agvMonthDatas)) {
  531. const newData = dto.reverse();
  532. const xDatas = newData.map((item) => item.monthName);
  533. const groundCount = dto.map((item) => item.groundCount);
  534. const stereoscopicCount = dto.map(
  535. (item) => item.stereoscopicCount,
  536. );
  537. _self.agvYearChart.setOption({
  538. xAxis: { data: xDatas },
  539. series: [
  540. { name: "地面库", data: groundCount },
  541. { name: "立体库", data: stereoscopicCount },
  542. ],
  543. });
  544. _self.agvMonthDatas = dto;
  545. }
  546. },
  547. // 更新agv任务统计(已完成、未完成)
  548. updateAgvTotalTask(completeQuantity, incompleteQuantity) {
  549. const _self = this;
  550. if (
  551. completeQuantity !== _self.agvComplete ||
  552. incompleteQuantity !== _self.agvUnComplete
  553. ) {
  554. const countData = [
  555. { name: "已完成", value: completeQuantity },
  556. { name: "未完成", value: incompleteQuantity },
  557. ];
  558. _self.agvTotalChart.setOption({
  559. series: [{ name: "任务统计", data: countData }],
  560. });
  561. _self.agvComplete = completeQuantity;
  562. _self.agvUnComplete = incompleteQuantity;
  563. }
  564. },
  565. // 更新设备使用时长
  566. updateUseTime(dtos) {
  567. const _self = this;
  568. if (!isObjectEqual(dtos, _self.useTimeData)) {
  569. const processedData = dtos.map((item, index) => {
  570. return [
  571. // index + 1,
  572. item.invName || "",
  573. item.invNo || "",
  574. item.type || "",
  575. item.useTime || "",
  576. ];
  577. });
  578. _self.deviceTimeConfig.data = JSON.parse(
  579. JSON.stringify(processedData),
  580. );
  581. // 强制更新组件
  582. _self.$nextTick(() => {
  583. if (_self.$refs.scrollBoard4) {
  584. _self.$refs.scrollBoard4.updateRows(
  585. _self.deviceTimeConfig.data,
  586. );
  587. }
  588. });
  589. _self.useTimeData = dtos;
  590. }
  591. },
  592. // 屏幕自适应
  593. resizeChart() {
  594. const _self = this;
  595. _self.checkoutChart && _self.checkoutChart.resize();
  596. _self.agvYearChart && _self.agvYearChart.resize();
  597. _self.agvTotalChart && _self.agvTotalChart.resize();
  598. },
  599. cancalDebounce: debounce(function () {
  600. this.resizeChart();
  601. }, 200),
  602. },
  603. mounted() {
  604. const _self = this;
  605. _self.getWarehouseId();
  606. _self.checkoutChart = getElement("checkoutChart");
  607. _self.agvYearChart = getElement("agvYearChart");
  608. _self.agvTotalChart = getElement("agvTotalChart");
  609. _self.$nextTick(() => {
  610. _self.createCheckoutChart();
  611. _self.createAgvYearChart();
  612. _self.createAgvTotalChart();
  613. _self.getWarehouseInfo();
  614. window.addEventListener("resize", _self.cancalDebounce);
  615. });
  616. _self.timer = setInterval(() => {
  617. _self.getWarehouseInfo();
  618. }, 3000);
  619. },
  620. beforeUnmount() {
  621. const _self = this;
  622. clearInterval(_self.timer);
  623. _self.timer = null;
  624. },
  625. });
  626. </script>
  627. </body>
  628. </html>