MaintenanceDynamics.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  1. <template>
  2. <Layout>
  3. <template #left>
  4. <div class="left-top">
  5. <template
  6. v-for="(item, index) in leftContent.top"
  7. :key="index"
  8. >
  9. <Box
  10. :width="662"
  11. :height="408"
  12. :name="item.name"
  13. style="position: relative;"
  14. >
  15. <SelectDate
  16. v-if="index === 1"
  17. @date-change="selectDatechange"
  18. />
  19. <div
  20. v-if="item.icon"
  21. class="left-top-count"
  22. >
  23. <Icon
  24. :name="item.icon"
  25. :size="81"
  26. style="margin-right: 20px;"
  27. />
  28. <div
  29. v-for="(itm, id) in item.num"
  30. :key="id"
  31. >
  32. {{ itm }}
  33. </div>
  34. <div>辆</div>
  35. </div>
  36. <Echart
  37. v-if="item.option"
  38. :option="item.option"
  39. />
  40. </Box>
  41. </template>
  42. </div>
  43. <Box
  44. :width="1340"
  45. :height="420"
  46. name="维保明细"
  47. class="left-bottom"
  48. >
  49. <n-date-picker
  50. v-model:value="leftContent.bottom.range"
  51. type="daterange"
  52. :separator="'至'"
  53. :bordered="false"
  54. style="width: 260px;"
  55. />
  56. <n-data-table
  57. :columns="leftContent.bottom.head"
  58. :data="tableData"
  59. :bordered="false"
  60. single-column
  61. striped
  62. size="large"
  63. style="height: 300px;"
  64. />
  65. <div class="page">
  66. <n-pagination
  67. v-model:page="leftContent.bottom.page.num"
  68. :page-size="leftContent.bottom.page.size"
  69. :item-count="leftContent.bottom.page.total"
  70. size="large"
  71. />
  72. </div>
  73. </Box>
  74. </template>
  75. <template #right>
  76. <div class="right-top">
  77. <template
  78. v-for="(item, index) in rightContent.top"
  79. :key="index"
  80. >
  81. <Box
  82. :width="438"
  83. :height="408"
  84. :name="item.name"
  85. >
  86. <Echart :option="item.option" />
  87. </Box>
  88. </template>
  89. </div>
  90. <Box
  91. :width="1340"
  92. :height="408"
  93. name="线路运行速度"
  94. class="right-center"
  95. >
  96. <div class="lineSpeed">
  97. <div class="img">
  98. <img
  99. src="../../../../assets/img/1-2.png"
  100. alt="car"
  101. >
  102. </div>
  103. <div class="control">
  104. <n-select
  105. size="large"
  106. :bordered="false"
  107. :options="[{label:'车型',value:1}]"
  108. placeholder="车型选择"
  109. />
  110. <div class="btn">
  111. 一键体检
  112. </div>
  113. </div>
  114. </div>
  115. </Box>
  116. <div class="right-bottom">
  117. <Box
  118. :width="662"
  119. :height="408"
  120. name="体检问题情况"
  121. >
  122. <div class="checkup">
  123. <div class="total">
  124. <div class="num">
  125. {{ checkupProblemTotal }}
  126. </div>
  127. <div style="font-size: 24px;">
  128. 总量
  129. </div>
  130. </div>
  131. <div class="list">
  132. <div
  133. v-for="item,index in checkupProblem"
  134. :key="index"
  135. class="item"
  136. >
  137. <div class="num">
  138. {{ item.number }}
  139. </div>
  140. <div class="label">
  141. {{ item.problemType }}
  142. </div>
  143. </div>
  144. </div>
  145. </div>
  146. </Box>
  147. <Box
  148. :width="662"
  149. :height="408"
  150. :name="rightContent.bottom.name"
  151. >
  152. <Echart :option="rightContent.bottom.option" />
  153. </Box>
  154. </div>
  155. </template>
  156. </Layout>
  157. </template>
  158. <script setup lang='ts'>
  159. import Layout from '@/components/layout.vue'
  160. import Box from '@/components/box.vue'
  161. import SelectDate from '@/components/selectDate.vue'
  162. import {
  163. Ref, computed, onMounted, onUnmounted, ref, watch
  164. } from 'vue'
  165. import Echart from '@/components/chart.vue'
  166. import MaintenanceDynamicsService from '../services/maintenanceDynamics.Service'
  167. import { format, subDays } from 'date-fns'
  168. const leftContent:Ref<any> = ref({
  169. top: [
  170. {
  171. name: '车辆总数',
  172. num: '166',
  173. icon: '30'
  174. },
  175. {
  176. name: '维修保养统计',
  177. option: {
  178. grid: {
  179. containLabel: true,
  180. right: 30,
  181. left: 50,
  182. bottom: '25%',
  183. top: '20%'
  184. },
  185. legend: {
  186. show: true,
  187. left: 'center',
  188. bottom: 30,
  189. itemWidth: 15,
  190. itemHeight: 10,
  191. textStyle: {
  192. color: '#646464',
  193. fontSize: 18
  194. }
  195. },
  196. xAxis: {
  197. name: '日期',
  198. nameLocation: 'center',
  199. nameTextStyle: {
  200. fontSize: 16,
  201. color: 'white',
  202. padding: [ 20, 0 ]
  203. },
  204. type: 'category',
  205. axisLine: {
  206. show: false
  207. },
  208. axisLabel: {
  209. color: '#fff',
  210. fontSize: 18
  211. // formatter: (value: number) => format( 1'时')
  212. },
  213. splitLine: {
  214. show: false
  215. },
  216. axisTick: {
  217. show: true,
  218. alignWithLabel: true
  219. },
  220. data: [ '3月26日', '3月27日', '3月28日', '3月29日', '3月30日', '4月1日' ]
  221. },
  222. yAxis: {
  223. name: '维保量/台',
  224. nameLocation: 'center',
  225. nameGap: 50,
  226. nameTextStyle: {
  227. color: '#fff',
  228. fontSize: 18
  229. },
  230. padding: 5,
  231. // max: 1000,
  232. splitLine: {
  233. show: true,
  234. lineStyle: {
  235. color: '#A1A7B3'
  236. // type: 'dashed'
  237. }
  238. },
  239. axisLabel: {
  240. show: true,
  241. margin: 10,
  242. textStyle: {
  243. color: '#fff'
  244. }
  245. }
  246. },
  247. series: {
  248. name: '维保车辆',
  249. type: 'line',
  250. symbolSize: 0,
  251. itemStyle: {
  252. normal: {
  253. // color: '#4293FD',
  254. lineStyle: {
  255. // color: '#4293FD',
  256. width: 2
  257. }
  258. }
  259. },
  260. data: [ 120, 132, 101, 134, 90, 230 ]
  261. },
  262. dataZoom: {
  263. type: 'slider',
  264. height: 20,
  265. bottom: 8,
  266. handleIcon: 'path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z',
  267. handleSize: '140%',
  268. handleStyle: {
  269. color: '#fff'
  270. },
  271. moveHandleSize: 0,
  272. textStyle: {
  273. color: '#666'
  274. },
  275. fillerColor: 'rgba(24,38,73,.3)',
  276. borderColor: 'none'
  277. }
  278. }
  279. },
  280. {
  281. name: '车辆运营状态分布',
  282. option: {
  283. title: {
  284. text: '总166', // 图标内容文本
  285. left: 'center', // 图标内容水平居中
  286. top: 'center', // 图标内容垂直居中
  287. // 文本样式
  288. textStyle: {
  289. color: '#fff', // 图标内容文字颜色
  290. fontSize: '18px', // 图标内容文字大小
  291. fontWeight: 'normal'
  292. }
  293. },
  294. grid: {
  295. containLabel: true
  296. },
  297. tooltip: {
  298. formatter: '{b}: {c}辆 ,占比: {d}%'
  299. },
  300. // 图表图例
  301. legend: {
  302. type: 'scroll',
  303. orient: 'horizontal', // 图例排列方向
  304. icon: 'circle', // 图例样式为圆形
  305. itemWidth: 10, // 图例图形的宽度
  306. itemHeight: 16, // 图例图形的高度
  307. itemGap: 10, // 图例项之间的间隔
  308. left: 'center', // 图例距离容器右侧的距离
  309. bottom: 0, // 图例垂直居中
  310. textStyle: {
  311. color: 'white', // 图例文字颜色
  312. fontSize: 18
  313. }
  314. },
  315. series: [
  316. {
  317. type: 'pie', // 图表类型为饼图
  318. radius: [ '45%', '60%' ], // 控制内外圆环的半径,30%代表内圆,60%代表外圆
  319. avoidLabelOverlap: true, // 是否启用防止标签重叠策略
  320. showEmptyCircle: true, // 是否在无数据的时候显示一个占位圆
  321. label: {
  322. formatter: '{b} {d}%',
  323. color: 'white',
  324. fontSize: 18
  325. },
  326. data: [
  327. { name: '运营中', value: 30619 },
  328. { name: '维保中', value: 5921 },
  329. { name: '报废', value: 1153 }
  330. ]
  331. }
  332. ]
  333. }
  334. },
  335. {
  336. name: '车辆维保状态分别',
  337. option: {
  338. title: {
  339. text: '总166', // 图标内容文本
  340. left: 'center', // 图标内容水平居中
  341. top: 'center', // 图标内容垂直居中
  342. // 文本样式
  343. textStyle: {
  344. color: '#fff', // 图标内容文字颜色
  345. fontSize: '18px', // 图标内容文字大小
  346. fontWeight: 'normal'
  347. }
  348. },
  349. grid: {
  350. containLabel: true
  351. },
  352. tooltip: {
  353. formatter: '{b}: {c}辆 ,占比: {d}%'
  354. },
  355. // 图表图例
  356. legend: {
  357. type: 'scroll',
  358. orient: 'horizontal', // 图例排列方向
  359. icon: 'circle', // 图例样式为圆形
  360. itemWidth: 10, // 图例图形的宽度
  361. itemHeight: 16, // 图例图形的高度
  362. itemGap: 10, // 图例项之间的间隔
  363. left: 'center', // 图例距离容器右侧的距离
  364. bottom: 0, // 图例垂直居中
  365. textStyle: {
  366. color: 'white', // 图例文字颜色
  367. fontSize: 18
  368. }
  369. },
  370. series: [
  371. {
  372. type: 'pie', // 图表类型为饼图
  373. radius: [ '45%', '60%' ], // 控制内外圆环的半径,30%代表内圆,60%代表外圆
  374. avoidLabelOverlap: true, // 是否启用防止标签重叠策略
  375. showEmptyCircle: true, // 是否在无数据的时候显示一个占位圆
  376. label: {
  377. formatter: '{b} {d}%',
  378. color: 'white',
  379. fontSize: 18
  380. },
  381. data: [
  382. { name: '隔日留交车辆', value: 30619 },
  383. { name: '保养中车辆', value: 5921 },
  384. { name: '维修中车辆', value: 1153 }
  385. ]
  386. }
  387. ]
  388. }
  389. }
  390. ],
  391. bottom: {
  392. head: [
  393. { title: '序号', render: (rowData: object, rowIndex: number) => rowIndex + 1 },
  394. { title: '车辆编号', key: 'code' },
  395. { title: '车牌号', key: 'licensePlate' },
  396. { title: '线路', key: 'line' },
  397. { title: '维修类型', key: 'maintenanceType' },
  398. { title: '故障原因', key: 'faultReason' },
  399. { title: '维修点位', key: 'maintenanceLocation' },
  400. { title: '报修时间', key: 'time' },
  401. { title: '维保结果', key: 'result' }
  402. ],
  403. body: [
  404. {
  405. num: 1, carNum: 1, carNumber: 1, line: '1路', type: '小修', cause: '测试', postion: 'tess', time: '2023-01-01 12:00', result: '已处理'
  406. },
  407. {
  408. num: 1, carNum: 1, carNumber: 1, line: '1路', type: '小修', cause: '测试', postion: 'tess', time: '2023-01-01 12:00', result: '已处理'
  409. },
  410. {
  411. num: 1, carNum: 1, carNumber: 1, line: '1路', type: '小修', cause: '测试', postion: 'tess', time: '2023-01-01 12:00', result: '已处理'
  412. },
  413. {
  414. num: 1, carNum: 1, carNumber: 1, line: '1路', type: '小修', cause: '测试', postion: 'tess', time: '2023-01-01 12:00', result: '已处理'
  415. },
  416. {
  417. num: 1, carNum: 1, carNumber: 1, line: '1路', type: '小修', cause: '测试', postion: 'tess', time: '2023-01-01 12:00', result: '已处理'
  418. }
  419. ],
  420. page: {
  421. size: 5,
  422. total: 10,
  423. num: 1
  424. },
  425. range: [ subDays(Date.now(), 7), Date.now() ]
  426. }
  427. })
  428. const rightContent = ref({
  429. top: [
  430. {
  431. name: '客流线路分布',
  432. option: {
  433. // 图表图例
  434. legend: {
  435. show: true,
  436. type: 'scroll',
  437. orient: 'horizontal', // 图例排列方向
  438. icon: 'circle', // 图例样式为圆形
  439. itemWidth: 10, // 图例图形的宽度
  440. itemHeight: 16, // 图例图形的高度
  441. itemGap: 10, // 图例项之间的间隔
  442. left: 'center', // 图例距离容器右侧的距离
  443. bottom: 50, // 图例垂直居中
  444. textStyle: {
  445. color: 'white', // 图例文字颜色
  446. fontSize: 18
  447. }
  448. },
  449. tooltip: {
  450. formatter: '{b}: {c}个 , {d}%'
  451. },
  452. series: {
  453. bottom: 50,
  454. type: 'pie', // 图表类型为饼图
  455. radius: '50%', // 控制内外圆环的半径,30%代表内圆,60%代表外圆
  456. avoidLabelOverlap: true, // 是否启用防止标签重叠策略
  457. showEmptyCircle: true, // 是否在无数据的时候显示一个占位圆
  458. label: {
  459. show: true,
  460. fontSize: 16,
  461. formatter: '{b}: {c}个',
  462. color: 'white'
  463. },
  464. data: [
  465. { name: '维保场', value: 10 },
  466. { name: '运维驿站', value: 2 }
  467. ]
  468. }
  469. }
  470. },
  471. {
  472. name: '消费类型',
  473. option: {
  474. // 图表图例
  475. legend: {
  476. show: true,
  477. type: 'scroll',
  478. orient: 'horizontal', // 图例排列方向
  479. icon: 'circle', // 图例样式为圆形
  480. itemWidth: 10, // 图例图形的宽度
  481. itemHeight: 16, // 图例图形的高度
  482. itemGap: 10, // 图例项之间的间隔
  483. left: 'center', // 图例距离容器右侧的距离
  484. bottom: 50, // 图例垂直居中
  485. textStyle: {
  486. color: 'white', // 图例文字颜色
  487. fontSize: 18
  488. }
  489. },
  490. tooltip: {
  491. formatter: '{b}: {c}个 , {d}%'
  492. },
  493. series: {
  494. bottom: 50,
  495. type: 'pie', // 图表类型为饼图
  496. radius: '50%', // 控制内外圆环的半径,30%代表内圆,60%代表外圆
  497. avoidLabelOverlap: true, // 是否启用防止标签重叠策略
  498. showEmptyCircle: true, // 是否在无数据的时候显示一个占位圆
  499. label: {
  500. show: true,
  501. fontSize: 16,
  502. formatter: '{b}: {c}辆',
  503. color: 'white'
  504. },
  505. data: [
  506. { name: '一保', value: 100 },
  507. { name: '二保', value: 50 },
  508. { name: '三保', value: 16 }
  509. ]
  510. }
  511. }
  512. },
  513. {
  514. name: '乘距分布',
  515. option: {
  516. // 图表图例
  517. legend: {
  518. show: true,
  519. type: 'scroll',
  520. orient: 'horizontal', // 图例排列方向
  521. icon: 'circle', // 图例样式为圆形
  522. itemWidth: 10, // 图例图形的宽度
  523. itemHeight: 16, // 图例图形的高度
  524. itemGap: 10, // 图例项之间的间隔
  525. left: 'center', // 图例距离容器右侧的距离
  526. bottom: 50, // 图例垂直居中
  527. textStyle: {
  528. color: 'white', // 图例文字颜色
  529. fontSize: 18
  530. }
  531. },
  532. tooltip: {
  533. formatter: '{b}: {c}个 , {d}%'
  534. },
  535. series: {
  536. bottom: 50,
  537. type: 'pie', // 图表类型为饼图
  538. radius: '50%', // 控制内外圆环的半径,30%代表内圆,60%代表外圆
  539. avoidLabelOverlap: true, // 是否启用防止标签重叠策略
  540. showEmptyCircle: true, // 是否在无数据的时候显示一个占位圆
  541. label: {
  542. show: true,
  543. fontSize: 16,
  544. formatter: '{b}: {c}万元',
  545. color: 'white'
  546. },
  547. data: [
  548. { name: '保养', value: 60 },
  549. { name: '维修', value: 100 }
  550. ]
  551. }
  552. }
  553. }
  554. ],
  555. bottom: {
  556. name: '维保执行情况',
  557. option: {
  558. title: {
  559. text: '总报修', // 图标内容文本
  560. subtext: '60',
  561. left: 'center', // 图标内容水平居中
  562. top: 'center', // 图标内容垂直居中
  563. // 文本样式
  564. textStyle: {
  565. color: '#fff', // 图标内容文字颜色
  566. fontSize: '18px', // 图标内容文字大小
  567. fontWeight: 'normal'
  568. },
  569. subtextStyle: {
  570. color: '#fff', // 图标内容文字颜色
  571. fontSize: '18px', // 图标内容文字大小
  572. fontWeight: 'normal'
  573. }
  574. },
  575. tooltip: {
  576. formatter: '{b}: {c}辆 ,占比: {d}%'
  577. },
  578. grid: {
  579. containLabel: true,
  580. top: 0,
  581. bottom: 0
  582. },
  583. // 图表图例
  584. legend: {
  585. show: true,
  586. type: 'scroll',
  587. orient: 'horizontal', // 图例排列方向
  588. icon: 'circle', // 图例样式为圆形
  589. itemWidth: 10, // 图例图形的宽度
  590. itemHeight: 16, // 图例图形的高度
  591. itemGap: 10, // 图例项之间的间隔
  592. left: 'center', // 图例距离容器右侧的距离
  593. bottom: 0, // 图例垂直居中
  594. textStyle: {
  595. color: 'white', // 图例文字颜色
  596. fontSize: 18
  597. }
  598. },
  599. series: {
  600. type: 'pie', // 图表类型为饼图
  601. radius: [ '45%', '60%' ], // 控制内外圆环的半径,30%代表内圆,60%代表外圆
  602. avoidLabelOverlap: true, // 是否启用防止标签重叠策略
  603. showEmptyCircle: true, // 是否在无数据的时候显示一个占位圆
  604. label: {
  605. show: true,
  606. formatter: '{b}: {d}辆',
  607. color: 'white',
  608. fontSize: 18
  609. },
  610. data: [
  611. { name: '执行', value: 30 },
  612. { name: '竣工', value: 20 },
  613. { name: '在修', value: 10 }
  614. ]
  615. }
  616. }
  617. }
  618. })
  619. const checkupProblem = ref([] as any[])
  620. const checkupProblemTotal = ref(0)
  621. const maintenanceDynamicsService = new MaintenanceDynamicsService()
  622. async function getMaintenanceCarStatus() {
  623. const res = await maintenanceDynamicsService.getMaintenanceCarStatus()
  624. leftContent.value.top[3].option!.series[0].data = res.map((item: any) => ({
  625. name: item.maintenanceStatus, value: item.number
  626. }))
  627. }
  628. getMaintenanceCarStatus()
  629. async function getMaintenanceCarOperate() {
  630. const res = await maintenanceDynamicsService.getMaintenanceCarOperate()
  631. leftContent.value.top[2].option!.series[0].data = res.map((item: any) => ({
  632. name: item.carStatus, value: item.number
  633. }))
  634. }
  635. getMaintenanceCarOperate()
  636. async function getMaintenanceRidingDistance() {
  637. const res = await maintenanceDynamicsService.getMaintenanceRidingDistance()
  638. rightContent.value.top[2].option!.series.data = res.map((item: any) => ({
  639. name: item.distanceType, value: item.number
  640. }))
  641. }
  642. getMaintenanceRidingDistance()
  643. async function getMaintenanceLocationNum() {
  644. const res = await maintenanceDynamicsService.getMaintenanceLocationNum()
  645. rightContent.value.top[0].option!.series.data = res.map((item: any) => ({
  646. name: item.location, value: item.number
  647. }))
  648. }
  649. getMaintenanceLocationNum()
  650. async function getMaintenanceConsumption() {
  651. const res = await maintenanceDynamicsService.getMaintenanceConsumption()
  652. rightContent.value.top[1].option!.series.data = res.map((item: any) => ({
  653. name: item.consumptionType, value: item.number
  654. }))
  655. }
  656. getMaintenanceConsumption()
  657. async function getMaintenanceImplementation() {
  658. const res = await maintenanceDynamicsService.getMaintenanceImplementation()
  659. rightContent.value.bottom.option!.series.data = res.map((item: any) => ({
  660. name: item.executeType, value: item.number
  661. }))
  662. }
  663. getMaintenanceImplementation()
  664. async function getMaintenanceStatistics(type: number) {
  665. const res = await maintenanceDynamicsService.getMaintenanceStatistics(type)
  666. const xData = res.map((item: any) => item.time)
  667. const carNumberData = res.map((item: any) => item.carNumber)
  668. leftContent.value.top[1].option.xAxis!.data = xData
  669. leftContent.value.top[1].option.series.data = carNumberData
  670. }
  671. async function getMaintenanceCheckupProblem() {
  672. const res = await maintenanceDynamicsService.getMaintenanceCheckupProblem()
  673. checkupProblem.value = res
  674. checkupProblemTotal.value = res.reduce((prev: any, item: { number: number }) => {
  675. prev += item.number
  676. return prev
  677. }, 0)
  678. }
  679. getMaintenanceCheckupProblem()
  680. async function getBusLineDetailAll() {
  681. const res = await maintenanceDynamicsService.getBusLineDetailAll()
  682. leftContent.value.top[0].num = `${res.reduce((prev: any, item: { totalCar: number }) => {
  683. prev += item.totalCar
  684. return prev
  685. }, 0)}`
  686. }
  687. getBusLineDetailAll()
  688. const tableData = computed(() => {
  689. const { num, size } = leftContent.value.bottom.page
  690. return leftContent.value.bottom.body.slice((num - 1) * size, num * size)
  691. })
  692. async function getMaintenanceDetail() {
  693. const { range } = leftContent.value.bottom
  694. const params = {
  695. startTime: format(range[0], 'yyyy-MM-dd HH:mm:ss'),
  696. endTime: format(range[1], 'yyyy-MM-dd HH:mm:ss')
  697. }
  698. const res = await maintenanceDynamicsService.getMaintenanceDetail(params)
  699. leftContent.value.bottom.body = res
  700. leftContent.value.bottom.page.total = res.length
  701. }
  702. getMaintenanceDetail()
  703. watch(() => leftContent.value.bottom.range, getMaintenanceDetail)
  704. const statisticsType = ref(1)
  705. function selectDatechange(type: any) {
  706. statisticsType.value = type
  707. getMaintenanceStatistics(type)
  708. }
  709. onMounted(() => {
  710. selectDatechange(1)
  711. })
  712. const timer = setInterval(() => {
  713. getBusLineDetailAll()
  714. getMaintenanceStatistics(statisticsType.value)
  715. getMaintenanceCarOperate()
  716. getMaintenanceCarStatus()
  717. getMaintenanceRidingDistance()
  718. getMaintenanceLocationNum()
  719. getMaintenanceConsumption()
  720. getMaintenanceCheckupProblem()
  721. getMaintenanceImplementation()
  722. }, 5 * 1000)
  723. onUnmounted(() => {
  724. clearInterval(timer)
  725. })
  726. </script>
  727. <style lang="scss" scoped>
  728. .left-top {
  729. display: flex;
  730. flex-wrap: wrap;
  731. justify-content: space-between;
  732. &-count {
  733. display: flex;
  734. font-family: 'Impact Normal', 'Impact', sans-serif;
  735. font-weight: 408;
  736. font-style: normal;
  737. text-align: center;
  738. align-items: center;
  739. width: 100%;
  740. height: 100%;
  741. justify-content: center;
  742. &>div:not(:last-child) {
  743. width: 84px;
  744. height: 110px;
  745. background-color: rgba(33, 133, 232, 0.298039215686275);
  746. border: solid 2px rgba(33, 133, 232, 1);
  747. border-radius: 10px;
  748. line-height: 110px;
  749. font-size: 70px;
  750. color: #FFFFFF;
  751. margin-right: 16px;
  752. }
  753. &>div:last-child {
  754. font-size: 24px;
  755. color: #80FFFF;
  756. height: 110px;
  757. line-height: 145px;
  758. }
  759. }
  760. :deep(.selectDate){
  761. top: 50px;
  762. }
  763. }
  764. .left-bottom{
  765. position: relative;
  766. :deep(.n-date-picker){
  767. position: absolute;
  768. right: 230px;
  769. top: 3px;
  770. }
  771. .page{
  772. display: flex;
  773. justify-content: flex-end;
  774. margin-top: 20px;
  775. }
  776. }
  777. .right-bottom,
  778. .right-top {
  779. display: flex;
  780. justify-content: space-between;
  781. }
  782. .right-center{
  783. .lineSpeed{
  784. display: flex;
  785. align-items: center;
  786. height: 100%;
  787. >div{
  788. width: 50%;
  789. }
  790. .img{
  791. text-align: center;
  792. img{
  793. height: 262px;
  794. }
  795. }
  796. .control{
  797. width: 300px;
  798. margin: auto;
  799. display: flex;
  800. flex-wrap: wrap;
  801. justify-content: center;
  802. :deep(.n-select){
  803. .n-base-selection{
  804. border: 1px solid #5689F0;
  805. height: 50px;
  806. .n-base-selection-label{
  807. height: 100%;
  808. background: rgba(86, 137, 240, 0.298);
  809. }
  810. }
  811. }
  812. .btn{
  813. width: 173px;
  814. height: 71px;
  815. line-height: 71px;
  816. border-radius: 5px;
  817. background: rgba(24, 145, 255, 0.298);
  818. border: 1px solid #1891FF;
  819. color: #FFFFFF;
  820. font-size: 24px;
  821. text-align: center;
  822. margin-top: 53px;
  823. }
  824. }
  825. }
  826. }
  827. .right-bottom{
  828. .checkup{
  829. display: flex;
  830. height: 100%;
  831. .total{
  832. width: 30%;
  833. color: #FFFFFF;
  834. text-align: center;
  835. height: fit-content;
  836. margin: auto;
  837. >div{
  838. width: 100%;
  839. }
  840. .num{
  841. font-size: 60px;
  842. text-shadow: 1px 1px 10px rgba(0, 255, 255, 0.698);
  843. }
  844. }
  845. .list{
  846. flex: 1;
  847. display: flex;
  848. align-items: center;
  849. flex-wrap: wrap;
  850. padding-right: 40px;
  851. .item{
  852. width: 50%;
  853. height: 115px;
  854. background: url('../../../../assets/img/1-3.png') no-repeat;
  855. background-size: contain;
  856. text-align: center;
  857. background-position-y: 13px;
  858. .num{
  859. font-size: 50px;
  860. text-shadow: 1px 1px 10px rgba(0, 255, 255, 0.698);
  861. color: #00FFFF;
  862. font-family: Impact Normal;
  863. }
  864. .label{
  865. font-size: 24px;
  866. color: #FFFFFF;
  867. text-shadow: 1px 1px 10px rgba(0, 255, 255, 0.698);
  868. }
  869. }
  870. }
  871. }
  872. }
  873. </style>