|
@@ -12,6 +12,10 @@
|
|
|
:name="item.name"
|
|
:name="item.name"
|
|
|
style="position: relative;"
|
|
style="position: relative;"
|
|
|
>
|
|
>
|
|
|
|
|
+ <SelectDate
|
|
|
|
|
+ v-if="index === 1"
|
|
|
|
|
+ @date-change="selectDatechange"
|
|
|
|
|
+ />
|
|
|
<div
|
|
<div
|
|
|
v-if="item.icon"
|
|
v-if="item.icon"
|
|
|
class="left-top-count"
|
|
class="left-top-count"
|
|
@@ -29,19 +33,6 @@
|
|
|
</div>
|
|
</div>
|
|
|
<div>辆</div>
|
|
<div>辆</div>
|
|
|
</div>
|
|
</div>
|
|
|
- <div
|
|
|
|
|
- v-if="item.btns"
|
|
|
|
|
- class="dateChange"
|
|
|
|
|
- >
|
|
|
|
|
- <div
|
|
|
|
|
- v-for="(itm, index) in item.btns"
|
|
|
|
|
- :key="index"
|
|
|
|
|
- :class="{ active: index === item.checkId }"
|
|
|
|
|
- @click="changeFn(index, item)"
|
|
|
|
|
- >
|
|
|
|
|
- {{ itm }}
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
<Echart
|
|
<Echart
|
|
|
v-if="item.option"
|
|
v-if="item.option"
|
|
|
:option="item.option"
|
|
:option="item.option"
|
|
@@ -54,16 +45,24 @@
|
|
|
:width="1340"
|
|
:width="1340"
|
|
|
:height="420"
|
|
:height="420"
|
|
|
name="维保明细"
|
|
name="维保明细"
|
|
|
|
|
+ class="left-bottom"
|
|
|
>
|
|
>
|
|
|
|
|
+ <n-date-picker
|
|
|
|
|
+ v-model:value="leftContent.bottom.range"
|
|
|
|
|
+ type="daterange"
|
|
|
|
|
+ style="width: 260px;"
|
|
|
|
|
+ />
|
|
|
|
|
+
|
|
|
<n-data-table
|
|
<n-data-table
|
|
|
:columns="leftContent.bottom.head"
|
|
:columns="leftContent.bottom.head"
|
|
|
- :data="leftContent.bottom.body"
|
|
|
|
|
|
|
+ :data="tableData"
|
|
|
:bordered="false"
|
|
:bordered="false"
|
|
|
single-column
|
|
single-column
|
|
|
striped
|
|
striped
|
|
|
size="large"
|
|
size="large"
|
|
|
|
|
+ style="height: 300px;"
|
|
|
/>
|
|
/>
|
|
|
- <div class="left-bottom">
|
|
|
|
|
|
|
+ <div class="page">
|
|
|
<n-pagination
|
|
<n-pagination
|
|
|
v-model:page="leftContent.bottom.page.num"
|
|
v-model:page="leftContent.bottom.page.num"
|
|
|
:page-size="leftContent.bottom.page.size"
|
|
:page-size="leftContent.bottom.page.size"
|
|
@@ -84,7 +83,6 @@
|
|
|
:height="408"
|
|
:height="408"
|
|
|
:name="item.name"
|
|
:name="item.name"
|
|
|
>
|
|
>
|
|
|
- 1111
|
|
|
|
|
<Echart :option="item.option" />
|
|
<Echart :option="item.option" />
|
|
|
</Box>
|
|
</Box>
|
|
|
</template>
|
|
</template>
|
|
@@ -121,12 +119,12 @@
|
|
|
<Box
|
|
<Box
|
|
|
:width="662"
|
|
:width="662"
|
|
|
:height="408"
|
|
:height="408"
|
|
|
- :name="rightContent.bottom.name"
|
|
|
|
|
|
|
+ name="体检问题情况"
|
|
|
>
|
|
>
|
|
|
<div class="checkup">
|
|
<div class="checkup">
|
|
|
<div class="total">
|
|
<div class="total">
|
|
|
<div class="num">
|
|
<div class="num">
|
|
|
- 40
|
|
|
|
|
|
|
+ {{ checkupProblemTotal }}
|
|
|
</div>
|
|
</div>
|
|
|
<div style="font-size: 24px;">
|
|
<div style="font-size: 24px;">
|
|
|
总量
|
|
总量
|
|
@@ -134,15 +132,15 @@
|
|
|
</div>
|
|
</div>
|
|
|
<div class="list">
|
|
<div class="list">
|
|
|
<div
|
|
<div
|
|
|
- v-for="item in 4"
|
|
|
|
|
- :key="item"
|
|
|
|
|
|
|
+ v-for="item,index in checkupProblem"
|
|
|
|
|
+ :key="index"
|
|
|
class="item"
|
|
class="item"
|
|
|
>
|
|
>
|
|
|
<div class="num">
|
|
<div class="num">
|
|
|
- 10
|
|
|
|
|
|
|
+ {{ item.number }}
|
|
|
</div>
|
|
</div>
|
|
|
<div class="label">
|
|
<div class="label">
|
|
|
- 三电故障
|
|
|
|
|
|
|
+ {{ item.problemType }}
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -163,10 +161,16 @@
|
|
|
<script setup lang='ts'>
|
|
<script setup lang='ts'>
|
|
|
import Layout from '@/components/layout.vue'
|
|
import Layout from '@/components/layout.vue'
|
|
|
import Box from '@/components/box.vue'
|
|
import Box from '@/components/box.vue'
|
|
|
-import { ref } from 'vue'
|
|
|
|
|
|
|
+import SelectDate from '@/components/selectDate.vue'
|
|
|
|
|
+
|
|
|
|
|
+import {
|
|
|
|
|
+ Ref, computed, onMounted, ref, watch
|
|
|
|
|
+} from 'vue'
|
|
|
import Echart from '@/components/chart.vue'
|
|
import Echart from '@/components/chart.vue'
|
|
|
|
|
+import MaintenanceDynamicsService from '../services/maintenanceDynamics.Service'
|
|
|
|
|
+import { format, subDays } from 'date-fns'
|
|
|
|
|
|
|
|
-const leftContent = ref({
|
|
|
|
|
|
|
+const leftContent:Ref<any> = ref({
|
|
|
top: [
|
|
top: [
|
|
|
{
|
|
{
|
|
|
name: '车辆总数',
|
|
name: '车辆总数',
|
|
@@ -194,7 +198,7 @@ const leftContent = ref({
|
|
|
fontSize: 18
|
|
fontSize: 18
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
- xAxis: [ {
|
|
|
|
|
|
|
+ xAxis: {
|
|
|
name: '日期',
|
|
name: '日期',
|
|
|
nameLocation: 'center',
|
|
nameLocation: 'center',
|
|
|
nameTextStyle: {
|
|
nameTextStyle: {
|
|
@@ -219,8 +223,8 @@ const leftContent = ref({
|
|
|
alignWithLabel: true
|
|
alignWithLabel: true
|
|
|
},
|
|
},
|
|
|
data: [ '3月26日', '3月27日', '3月28日', '3月29日', '3月30日', '4月1日' ]
|
|
data: [ '3月26日', '3月27日', '3月28日', '3月29日', '3月30日', '4月1日' ]
|
|
|
- } ],
|
|
|
|
|
- yAxis: [ {
|
|
|
|
|
|
|
+ },
|
|
|
|
|
+ yAxis: {
|
|
|
name: '维保量/台',
|
|
name: '维保量/台',
|
|
|
nameLocation: 'center',
|
|
nameLocation: 'center',
|
|
|
nameGap: 50,
|
|
nameGap: 50,
|
|
@@ -245,25 +249,22 @@ const leftContent = ref({
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- ],
|
|
|
|
|
- series: [
|
|
|
|
|
- {
|
|
|
|
|
- name: '维保车辆',
|
|
|
|
|
- type: 'line',
|
|
|
|
|
- symbolSize: 0,
|
|
|
|
|
- itemStyle: {
|
|
|
|
|
- normal: {
|
|
|
|
|
|
|
+ },
|
|
|
|
|
+ series: {
|
|
|
|
|
+ name: '维保车辆',
|
|
|
|
|
+ type: 'line',
|
|
|
|
|
+ symbolSize: 0,
|
|
|
|
|
+ itemStyle: {
|
|
|
|
|
+ normal: {
|
|
|
|
|
+ // color: '#4293FD',
|
|
|
|
|
+ lineStyle: {
|
|
|
// color: '#4293FD',
|
|
// color: '#4293FD',
|
|
|
- lineStyle: {
|
|
|
|
|
- // color: '#4293FD',
|
|
|
|
|
- width: 2
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ width: 2
|
|
|
}
|
|
}
|
|
|
- },
|
|
|
|
|
- data: [ 120, 132, 101, 134, 90, 230 ]
|
|
|
|
|
- }
|
|
|
|
|
- ],
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ data: [ 120, 132, 101, 134, 90, 230 ]
|
|
|
|
|
+ },
|
|
|
dataZoom: {
|
|
dataZoom: {
|
|
|
type: 'slider',
|
|
type: 'slider',
|
|
|
height: 20,
|
|
height: 20,
|
|
@@ -279,9 +280,7 @@ const leftContent = ref({
|
|
|
fillerColor: 'rgba(255,255,255,0.2)',
|
|
fillerColor: 'rgba(255,255,255,0.2)',
|
|
|
borderColor: 'rgba(64,158,225,0.3)'
|
|
borderColor: 'rgba(64,158,225,0.3)'
|
|
|
}
|
|
}
|
|
|
- },
|
|
|
|
|
- btns: [ '总', '年', '月' ],
|
|
|
|
|
- checkId: 0
|
|
|
|
|
|
|
+ }
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
name: '车辆运营状态分布',
|
|
name: '车辆运营状态分布',
|
|
@@ -388,13 +387,13 @@ const leftContent = ref({
|
|
|
],
|
|
],
|
|
|
bottom: {
|
|
bottom: {
|
|
|
head: [
|
|
head: [
|
|
|
- { title: '序号', key: 'num' },
|
|
|
|
|
- { title: '车辆编号', key: 'carNum' },
|
|
|
|
|
- { title: '车牌号', key: 'carNumber' },
|
|
|
|
|
|
|
+ { title: '序号', render: (rowData: object, rowIndex: number) => rowIndex + 1 },
|
|
|
|
|
+ { title: '车辆编号', key: 'code' },
|
|
|
|
|
+ { title: '车牌号', key: 'licensePlate' },
|
|
|
{ title: '线路', key: 'line' },
|
|
{ title: '线路', key: 'line' },
|
|
|
- { title: '维修类型', key: 'type' },
|
|
|
|
|
- { title: '故障原因', key: 'cause' },
|
|
|
|
|
- { title: '维修点位', key: 'postion' },
|
|
|
|
|
|
|
+ { title: '维修类型', key: 'maintenanceType' },
|
|
|
|
|
+ { title: '故障原因', key: 'faultReason' },
|
|
|
|
|
+ { title: '维修点位', key: 'maintenanceLocation' },
|
|
|
{ title: '报修时间', key: 'time' },
|
|
{ title: '报修时间', key: 'time' },
|
|
|
{ title: '维保结果', key: 'result' }
|
|
{ title: '维保结果', key: 'result' }
|
|
|
|
|
|
|
@@ -420,7 +419,8 @@ const leftContent = ref({
|
|
|
size: 5,
|
|
size: 5,
|
|
|
total: 10,
|
|
total: 10,
|
|
|
num: 1
|
|
num: 1
|
|
|
- }
|
|
|
|
|
|
|
+ },
|
|
|
|
|
+ range: [ subDays(Date.now(), 7), Date.now() ]
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
|
|
|
|
@@ -586,32 +586,129 @@ const rightContent = ref({
|
|
|
fontSize: 18
|
|
fontSize: 18
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
- series: [
|
|
|
|
|
- {
|
|
|
|
|
- type: 'pie', // 图表类型为饼图
|
|
|
|
|
- radius: [ '45%', '60%' ], // 控制内外圆环的半径,30%代表内圆,60%代表外圆
|
|
|
|
|
- avoidLabelOverlap: true, // 是否启用防止标签重叠策略
|
|
|
|
|
- showEmptyCircle: true, // 是否在无数据的时候显示一个占位圆
|
|
|
|
|
- label: {
|
|
|
|
|
- show: true,
|
|
|
|
|
- formatter: '{b}: {d}俩',
|
|
|
|
|
- color: 'white',
|
|
|
|
|
- fontSize: 18
|
|
|
|
|
- },
|
|
|
|
|
- data: [
|
|
|
|
|
- { name: '执行', value: 30 },
|
|
|
|
|
- { name: '竣工', value: 20 },
|
|
|
|
|
- { name: '在修', value: 10 }
|
|
|
|
|
- ]
|
|
|
|
|
- }
|
|
|
|
|
- ]
|
|
|
|
|
|
|
+ series: {
|
|
|
|
|
+ type: 'pie', // 图表类型为饼图
|
|
|
|
|
+ radius: [ '45%', '60%' ], // 控制内外圆环的半径,30%代表内圆,60%代表外圆
|
|
|
|
|
+ avoidLabelOverlap: true, // 是否启用防止标签重叠策略
|
|
|
|
|
+ showEmptyCircle: true, // 是否在无数据的时候显示一个占位圆
|
|
|
|
|
+ label: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ formatter: '{b}: {d}俩',
|
|
|
|
|
+ color: 'white',
|
|
|
|
|
+ fontSize: 18
|
|
|
|
|
+ },
|
|
|
|
|
+ data: [
|
|
|
|
|
+ { name: '执行', value: 30 },
|
|
|
|
|
+ { name: '竣工', value: 20 },
|
|
|
|
|
+ { name: '在修', value: 10 }
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
-function changeFn(id: number, item: any) {
|
|
|
|
|
- item.checkId = id
|
|
|
|
|
|
|
+const checkupProblem = ref([] as any[])
|
|
|
|
|
+const checkupProblemTotal = ref(0)
|
|
|
|
|
+
|
|
|
|
|
+const maintenanceDynamicsService = new MaintenanceDynamicsService()
|
|
|
|
|
+
|
|
|
|
|
+async function getMaintenanceCarStatus() {
|
|
|
|
|
+ const res = await maintenanceDynamicsService.getMaintenanceCarStatus()
|
|
|
|
|
+ leftContent.value.top[3].option!.series[0].data = res.map((item: any) => ({
|
|
|
|
|
+ name: item.maintenanceStatus, value: item.number
|
|
|
|
|
+ }))
|
|
|
|
|
+}
|
|
|
|
|
+getMaintenanceCarStatus()
|
|
|
|
|
+async function getMaintenanceCarOperate() {
|
|
|
|
|
+ const res = await maintenanceDynamicsService.getMaintenanceCarOperate()
|
|
|
|
|
+ leftContent.value.top[2].option!.series[0].data = res.map((item: any) => ({
|
|
|
|
|
+ name: item.carStatus, value: item.number
|
|
|
|
|
+ }))
|
|
|
|
|
+}
|
|
|
|
|
+getMaintenanceCarOperate()
|
|
|
|
|
+
|
|
|
|
|
+async function getMaintenanceRidingDistance() {
|
|
|
|
|
+ const res = await maintenanceDynamicsService.getMaintenanceRidingDistance()
|
|
|
|
|
+ rightContent.value.top[2].option!.series.data = res.map((item: any) => ({
|
|
|
|
|
+ name: item.distanceType, value: item.number
|
|
|
|
|
+ }))
|
|
|
|
|
+}
|
|
|
|
|
+getMaintenanceRidingDistance()
|
|
|
|
|
+
|
|
|
|
|
+async function getMaintenanceLocationNum() {
|
|
|
|
|
+ const res = await maintenanceDynamicsService.getMaintenanceLocationNum()
|
|
|
|
|
+ rightContent.value.top[0].option!.series.data = res.map((item: any) => ({
|
|
|
|
|
+ name: item.location, value: item.number
|
|
|
|
|
+ }))
|
|
|
|
|
+}
|
|
|
|
|
+getMaintenanceLocationNum()
|
|
|
|
|
+async function getMaintenanceConsumption() {
|
|
|
|
|
+ const res = await maintenanceDynamicsService.getMaintenanceConsumption()
|
|
|
|
|
+ rightContent.value.top[1].option!.series.data = res.map((item: any) => ({
|
|
|
|
|
+ name: item.consumptionType, value: item.number
|
|
|
|
|
+ }))
|
|
|
|
|
+}
|
|
|
|
|
+getMaintenanceConsumption()
|
|
|
|
|
+
|
|
|
|
|
+async function getMaintenanceImplementation() {
|
|
|
|
|
+ const res = await maintenanceDynamicsService.getMaintenanceImplementation()
|
|
|
|
|
+ rightContent.value.bottom.option!.series.data = res.map((item: any) => ({
|
|
|
|
|
+ name: item.executeType, value: item.number
|
|
|
|
|
+ }))
|
|
|
|
|
+}
|
|
|
|
|
+getMaintenanceImplementation()
|
|
|
|
|
+
|
|
|
|
|
+async function getMaintenanceStatistics(type: number) {
|
|
|
|
|
+ const res = await maintenanceDynamicsService.getMaintenanceStatistics(type)
|
|
|
|
|
+
|
|
|
|
|
+ const xData = res.map((item: any) => item.time)
|
|
|
|
|
+ const carNumberData = res.map((item: any) => item.carNumber)
|
|
|
|
|
+
|
|
|
|
|
+ leftContent.value.top[1].option.xAxis!.data = xData
|
|
|
|
|
+ leftContent.value.top[1].option.series.data = carNumberData
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function getMaintenanceCheckupProblem() {
|
|
|
|
|
+ const res = await maintenanceDynamicsService.getMaintenanceCheckupProblem()
|
|
|
|
|
+ checkupProblem.value = res
|
|
|
|
|
+ checkupProblemTotal.value = res.reduce((prev: any, item: { number: number }) => {
|
|
|
|
|
+ prev += item.number
|
|
|
|
|
+ return prev
|
|
|
|
|
+ }, 0)
|
|
|
|
|
+}
|
|
|
|
|
+getMaintenanceCheckupProblem()
|
|
|
|
|
+async function getBusLineDetailAll() {
|
|
|
|
|
+ const res = await maintenanceDynamicsService.getBusLineDetailAll()
|
|
|
|
|
+ leftContent.value.top[0].num = `${res.reduce((prev: any, item: { totalCar: number }) => {
|
|
|
|
|
+ prev += item.totalCar
|
|
|
|
|
+ return prev
|
|
|
|
|
+ }, 0)}`
|
|
|
|
|
+}
|
|
|
|
|
+getBusLineDetailAll()
|
|
|
|
|
+const tableData = computed(() => {
|
|
|
|
|
+ const { num, size } = leftContent.value.bottom.page
|
|
|
|
|
+ return leftContent.value.bottom.body.slice((num - 1) * size, num * size)
|
|
|
|
|
+})
|
|
|
|
|
+async function getMaintenanceDetail() {
|
|
|
|
|
+ const { range } = leftContent.value.bottom
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ startTime: format(range[0], 'yyyy-MM-dd HH:mm:ss'),
|
|
|
|
|
+ endTime: format(range[1], 'yyyy-MM-dd HH:mm:ss')
|
|
|
|
|
+ }
|
|
|
|
|
+ const res = await maintenanceDynamicsService.getMaintenanceDetail(params)
|
|
|
|
|
+ leftContent.value.bottom.body = res
|
|
|
|
|
+ leftContent.value.bottom.page.total = res.length
|
|
|
|
|
+}
|
|
|
|
|
+getMaintenanceDetail()
|
|
|
|
|
+
|
|
|
|
|
+watch(() => leftContent.value.bottom.range, getMaintenanceDetail)
|
|
|
|
|
+
|
|
|
|
|
+function selectDatechange(type: any) {
|
|
|
|
|
+ getMaintenanceStatistics(type)
|
|
|
}
|
|
}
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ selectDatechange(1)
|
|
|
|
|
+})
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
@@ -649,42 +746,25 @@ function changeFn(id: number, item: any) {
|
|
|
height: 110px;
|
|
height: 110px;
|
|
|
line-height: 145px;
|
|
line-height: 145px;
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- .dateChange {
|
|
|
|
|
- position: absolute;
|
|
|
|
|
- height: 30px;
|
|
|
|
|
- border-radius: 30px;
|
|
|
|
|
- border: solid 1px #2185E8;
|
|
|
|
|
- left: 50%;
|
|
|
|
|
- transform: translate(-50%, 0);
|
|
|
|
|
- top: 50px;
|
|
|
|
|
- z-index: 2;
|
|
|
|
|
- display: flex;
|
|
|
|
|
-
|
|
|
|
|
- &>div {
|
|
|
|
|
- width: 90px;
|
|
|
|
|
- color: white;
|
|
|
|
|
- font-size: 16px;
|
|
|
|
|
- text-align: center;
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
- line-height: 30px;
|
|
|
|
|
-
|
|
|
|
|
- &:not(:first-child) {
|
|
|
|
|
- border-left: solid 1px #2185E8;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- .active {
|
|
|
|
|
- background: #2185e860;
|
|
|
|
|
|
|
+ :deep(.selectDate){
|
|
|
|
|
+ top: 50px;
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
.left-bottom{
|
|
.left-bottom{
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- justify-content: flex-end;
|
|
|
|
|
- margin-top: 20px;
|
|
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ :deep(.n-date-picker){
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ right: 230px;
|
|
|
|
|
+ top: 3px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .page{
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: flex-end;
|
|
|
|
|
+ margin-top: 20px;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
.right-bottom,
|
|
.right-bottom,
|
|
|
.right-top {
|
|
.right-top {
|