123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671 |
- <template>
- <div class="flex flex-col">
- <el-row :gutter="16" class="summary">
- <!-- 原有的统计卡片部分保持不变 -->
- <el-col v-loading="loading" :sm="3" :xs="12">
- <SummaryCard
- :value="device.total || 0"
- icon="fa-solid:project-diagram"
- icon-bg-color="text-blue-500"
- icon-color="bg-blue-100"
- title="设备数"
- />
- </el-col>
- <el-col v-loading="loading" :sm="3" :xs="12">
- <SummaryCard
- :value="maintain.total || 0"
- icon="fa-solid:list"
- icon-bg-color="text-pink-500"
- icon-color="bg-blue-100"
- title="维修工单"
- />
- </el-col>
- <el-col v-loading="loading" :sm="3" :xs="12">
- <SummaryCard
- :value="fill.unfilledCount || 0"
- icon="fa-solid:times-circle"
- icon-bg-color="text-purple-500"
- icon-color="bg-purple-100"
- title="运行未填写"
- />
- </el-col>
- <el-col v-loading="loading" :sm="3" :xs="12">
- <SummaryCard
- :value="fill.filledCount || 0"
- icon="fa-solid:award"
- icon-bg-color="text-purple-500"
- icon-color="bg-purple-100"
- title="运行已填写"
- />
- </el-col>
- <el-col v-loading="loading" :sm="3" :xs="12">
- <SummaryCard
- :value="by.todo || 0"
- icon="fa-solid:times-circle"
- icon-bg-color="text-green-500"
- icon-color="bg-green-100"
- title="未执行保养"
- />
- </el-col>
- <el-col v-loading="loading" :sm="3" :xs="12">
- <SummaryCard
- :value="by.finished || 0"
- icon="fa-solid:award"
- icon-bg-color="text-green-500"
- icon-color="bg-green-100"
- title="已执行保养"
- />
- </el-col>
- <el-col v-loading="loading" :sm="3" :xs="12">
- <SummaryCard
- :value="inspect.todo || 0"
- icon="fa-solid:times-circle"
- icon-bg-color="text-yellow-500"
- icon-color="bg-yellow-100"
- title="待填写巡检"
- />
- </el-col>
- <el-col v-loading="loading" :sm="3" :xs="12">
- <SummaryCard
- :value="inspect.finished || 0"
- icon="fa-solid:award"
- icon-bg-color="text-yellow-500"
- icon-color="bg-yellow-100"
- title="已填写巡检"
- />
- </el-col>
- <!-- 其他统计卡片... -->
- </el-row>
- <el-row :gutter="16" class="mb-4">
- <!-- 设备状态统计和工单数量情况图表部分保持不变 -->
- <el-col :span="7">
- <el-card class="chart-card" shadow="never">
- <template #header>
- <div class="flex items-center">
- <span class="text-base font-medium text-gray-600">设备状态统计</span>
- </div>
- </template>
- <div ref="statusChartRef" class="h-[290px]"></div>
- </el-card>
- </el-col>
- <el-col :span="17">
- <el-card class="chart-card" shadow="never">
- <template #header>
- <div class="flex items-center justify-between">
- <span class="text-base font-medium text-gray-600">工单数量情况</span>
- </div>
- </template>
- <div ref="qxRef" class="h-[290px]"></div>
- </el-card>
- </el-col>
- </el-row>
- <el-row :gutter="16" class="mb-4">
- <!-- 备件更换情况部分保持不变 -->
- <el-col :span="7">
- <el-card class="chart-card" shadow="never">
- <template #header>
- <div class="flex items-center justify-between">
- <span class="text-base font-medium text-gray-600">备件更换情况</span>
- </div>
- </template>
- <!-- 添加两个卡片 -->
- <div class="flex justify-between mb-2">
- <el-card class="stat-card " >
- <div class="flex flex-row justify-evenly">
- <div>
- <Icon icon="fa-solid:award" size="30" color="blue"/>
- </div>
- <div class="flex flex-col items-center">
- <span class="text-sm text-gray-600">物料消耗数量</span>
- <span class="text-lg font-bold">{{ totalMaterialCount }}</span>
- </div>
- </div>
- </el-card>
- <el-card class="stat-card">
- <div class="flex flex-row justify-evenly">
- <div>
- <Icon icon="fa-solid:yen-sign" size="30" color="orange"/>
- </div>
- <div class="flex flex-col items-center">
- <span class="text-sm text-gray-600">物料消耗费用</span>
- <span class="text-lg font-bold">{{ totalMaterialCost }}</span>
- </div>
- </div>
- </el-card>
- </div>
- <div ref="sparePartRef" class="h-[330px]"></div>
- </el-card>
- </el-col>
- <el-col :span="17">
- <div class="flex flex-col justify-between">
- <el-card class="chart-card" shadow="never">
- <template #header>
- <div class="flex items-center justify-between" >
- <span class="text-base font-medium text-gray-600">保养情况</span>
- </div>
- </template>
- <div class="flex mr-3">
- <div ref="maintenanceChartRef" class="h-[157px] w-2/5"></div>
- <div class="w-3/5 p-4 flex flex-col mt-5">
- <div class="flex justify-between">
- <div class="flex flex-col items-center">
- <Icon icon="fa-solid:list" size="30" color="blue"/>
- <p style="font-size: 20px;margin-top: 5px">总工单数</p>
- <span style="font-size: 20px">{{ by.finished+by.todo }}</span>
- </div>
- <div class="flex flex-col items-center">
- <Icon icon="fa-solid:check-circle" size="30" color="green"/>
- <p style="font-size: 20px;margin-top: 5px">已执行工单数</p>
- <span style="font-size: 20px">{{ by.finished }}</span>
- </div>
- <div class="flex flex-col items-center">
- <Icon icon="fa-solid:hourglass-half" size="30" color="orange"/>
- <p style="font-size: 20px;margin-top: 5px">待执行工单数 </p>
- <span style="font-size: 20px">{{ by.todo }}</span>
- </div>
- </div>
- </div>
- </div>
- </el-card>
- <el-card class="chart-card mt-2" shadow="never">
- <template #header>
- <div class="flex items-center justify-between">
- <span class="text-base font-medium text-gray-600">巡检情况</span>
- </div>
- </template>
- <div class="flex mr-3">
- <div ref="inspectChartRef" class="h-[157px] w-2/5"></div>
- <div class="w-3/5 p-4 flex flex-col mt-5">
- <div class="flex justify-between">
- <div class="flex flex-col items-center">
- <Icon icon="fa-solid:list" size="30" color="blue"/>
- <p style="font-size: 20px;margin-top: 5px">总工单数</p>
- <span style="font-size: 20px">{{ inspect.todo+inspect.finished }}</span>
- </div>
- <div class="flex flex-col items-center">
- <Icon icon="fa-solid:check-circle" size="30" color="green"/>
- <p style="font-size: 20px;margin-top: 5px">已执行工单数</p>
- <span style="font-size: 20px">{{ inspect.finished }}</span>
- </div>
- <div class="flex flex-col items-center">
- <Icon icon="fa-solid:hourglass-half" size="30" color="orange"/>
- <p style="font-size: 20px;margin-top: 5px">待执行工单数</p>
- <span style="font-size: 20px">{{ inspect.todo }}</span>
- </div>
- </div>
- </div>
- </div>
- </el-card>
- </div>
- </el-col>
- </el-row>
- </div>
- </template>
- <script lang="ts" setup>
- import { MemberSummaryRespVO } from '@/api/mall/statistics/member'
- import SummaryCard from '@/components/SummaryCard/index.vue'
- import { fenToYuan } from '@/utils'
- import * as echarts from 'echarts/core'
- import { BarChart, GaugeChart, LineChart, PieChart } from 'echarts/charts' // 显式导入柱状图模块
- import {
- GridComponent,
- LegendComponent,
- TitleComponent,
- ToolboxComponent,
- TooltipComponent
- } from 'echarts/components'
- import { LabelLayout, UniversalTransition } from 'echarts/features'
- import { CanvasRenderer } from 'echarts/renderers'
- import { IotStatApi } from '@/api/pms/stat'
- import {ref, onMounted, computed, watch, nextTick, reactive} from 'vue';
- import {useUserStore} from "@/store/modules/user";
- /** 会员统计 */
- defineOptions({ name: 'IotRdStat' })
- echarts.use([
- TooltipComponent,
- LegendComponent,
- PieChart,
- CanvasRenderer,
- LabelLayout,
- TitleComponent,
- ToolboxComponent,
- GridComponent,
- LineChart,
- UniversalTransition,
- GaugeChart,
- BarChart
- ])
- const loading = ref(true) // 加载中
- const summary = ref<MemberSummaryRespVO>() // 会员统计数据
- const statusChartRef = ref() // 设备数量统计的图表
- const qxRef = ref(null)
- let qxInstance = null
- const sparePartRef = ref(null)
- let sparePartInstance = null
- const maintenanceChartRef = ref(null)
- let maintenanceChartInstance = null
- const inspectChartRef = ref(null)
- let inspectChartInstance = null
- const inspectionChartRef = ref(null)
- let inspectionChartInstance = null
- const maintenanceChartRef1 = ref(null)
- const typeData = ref({})
- const orderSevenData = ref({})
- const device = ref({
- total: undefined,
- today: undefined
- })
- const maintain = ref({
- total: undefined,
- today: undefined
- })
- const by = ref({
- todo: undefined,
- finished: undefined,
- })
- const fill = ref({
- filledCount: undefined,
- unfilledCount: undefined
- })
- const inspect = ref({
- finished: 0,
- todo: 0
- })
- const sparePartData = ref({
- xAxis: ['扳手', '水杯', '皮带', '螺丝'],
- series: [
- {
- name: '数量',
- type: 'bar',
- data: [10, 20, 15, 25],
- yAxisIndex: 0
- },
- {
- name: '金额',
- type: 'line',
- data: [100, 200, 150, 250],
- yAxisIndex: 1
- }
- ]
- })
- // 模拟保养工单数据
- const totalMaintenanceOrders = ref(100)
- const completedMaintenanceOrders = ref(80)
- const pendingMaintenanceOrders = ref(20)
- // 模拟巡检工单数据
- const totalInspectionOrders = ref(80)
- const completedInspectionOrders = ref(60)
- // 计算物料消耗数量及费用
- const totalMaterialCount = computed(() => {
- const quantitySeries = sparePartData.value.series.find(item => item.name === '数量');
- return quantitySeries ? quantitySeries.data.reduce((sum, val) => sum + val, 0) : 0;
- });
- const totalMaterialCost = computed(() => {
- const costSeries = sparePartData.value.series.find(item => item.name === '金额');
- return costSeries ? costSeries.data.reduce((sum, val) => sum + val, 0) : 0;
- });
- const getStats = () => {
- IotStatApi.getDeviceStatusCount().then((res) => {
- typeData.value = res
- initDeviceStatusCharts()
- })
- IotStatApi.getOrderSeven().then((res) => {
- orderSevenData.value = res
- initQxChart()
- })
- IotStatApi.getDeviceCount().then((res) => {
- device.value = res
- })
- IotStatApi.getMaintainCount().then((res) => {
- maintain.value = res
- })
- IotStatApi.getMaintenanceStatus().then((res) => {
- by.value = res
- initMaintenanceChart()
- })
- const fillQueryParams = reactive({
- startTime: Date.now() - 7 * 24 * 60 * 60 * 1000, // 设置默认开始时间为 7 天前
- endTime: Date.now(), // 设置默认结束时间为当前时间
- createTime: [],
- deptId: null, // 选中的部门ID
- status: null // 填写状态
- })
- IotStatApi.getInspectStatus(fillQueryParams).then((res) => {
- inspect.value = res
- initInspectChart()
- })
- fillQueryParams.deptId = useUserStore().getUser.deptId;
- IotStatApi.getDeptStatistics(fillQueryParams).then((res) => {
- fill.value = res.totalList[0] || [];
- })
- initSparePartChart()
- initInspectionChart()
- }
- const initQxChart = () => {
- if (!qxRef.value) return
- qxInstance = echarts.init(qxRef.value)
- const option = {
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'cross',
- label: {
- backgroundColor: '#6a7985'
- }
- }
- },
- legend: {
- data: orderSevenData.value.series.map((item) => item.name),
- top: 30
- },
- grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- boundaryGap: false,
- data: orderSevenData.value.xAxis,
- axisLabel: {
- formatter: (value) => value.split('-').join('/') // 显示为 2023/01
- }
- },
- yAxis: [
- {
- type: 'value',
- axisLabel: {
- formatter: '{value}'
- },
- position: 'left' // 左侧 Y 轴
- },
- {
- type: 'value',
- axisLabel: {
- formatter: '{value}'
- },
- position: 'right', // 右侧 Y 轴
- splitLine: {
- show: false // 隐藏右侧 Y 轴的分割线
- }
- }
- ],
- series: orderSevenData.value.series.map((item, index) => {
- const yAxisIndex = index < 2 ? 0 : 1
- return {
- name: item.name,
- type: 'line',
- smooth: true,
- symbol: 'circle',
- symbolSize: 8,
- itemStyle: {
- color: ['#5470c6', '#f1d209', '#e14f0f', '#91cc75'][index]
- },
- areaStyle: {
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: 'rgba(84,112,198,0.4)' },
- { offset: 1, color: 'rgba(84,112,198,0.1)' }
- ])
- },
- data: item.data,
- yAxisIndex: yAxisIndex // 指定使用的 Y 轴
- }
- })
- }
- qxInstance.setOption(option)
- }
- const initSparePartChart = () => {
- if (!sparePartRef.value) return
- sparePartInstance = echarts.init(sparePartRef.value)
- const option = {
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'cross',
- crossStyle: {
- color: '#999'
- }
- }
- },
- legend: {
- data: ['数量', '金额']
- },
- grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- data: sparePartData.value.xAxis
- },
- yAxis: [
- {
- type: 'value',
- name: '数量',
- position: 'left',
- axisLabel: {
- formatter: '{value}'
- }
- },
- {
- type: 'value',
- name: '金额',
- position: 'right',
- axisLabel: {
- formatter: '{value}'
- },
- splitLine: {
- show: false
- }
- }
- ],
- series: sparePartData.value.series.map((item, index) => ({
- name: item.name,
- type: item.type,
- data: item.data,
- yAxisIndex: item.yAxisIndex,
- itemStyle: {
- color: ['#6084fb', '#5aef13'][index]
- },
- }))
- }
- sparePartInstance.setOption(option)
- }
- const initInspectChart = () => {
- if (!inspectChartRef.value) return
- inspectChartInstance = echarts.init(inspectChartRef.value)
- const completionRate = (inspect.value.finished / (inspect.value.finished+inspect.value.todo)) * 100
- debugger
- const option = {
- tooltip: {
- trigger: 'item'
- },
- legend: {
- // top: '5%',
- // right: '10%',
- // align: 'center',
- orient: 'horizontal', // 水平排列图例项
- bottom: '0%', // 放置在底部
- icon: 'circle'
- },
- series: [
- {
- type: 'pie',
- radius: ['40%', '70%'],
- label: {
- show: false,
- position: 'outside'
- },
- emphasis: {
- label: {
- show: true,
- fontSize: 15,
- fontWeight: 'bold'
- }
- },
- labelLine: {
- show: true
- },
- // itemStyle: {
- // color: ['#e4a317', '#5aef13']
- // },
- data: [
- { name:'完成率',value: completionRate.toFixed(2) },
- { name:'未完成率',value: 100 - completionRate.toFixed(2) }
- ]
- }
- ]
- }
- inspectChartInstance.setOption(option)
- }
- const initMaintenanceChart = () => {
- if (!maintenanceChartRef.value) return
- maintenanceChartInstance = echarts.init(maintenanceChartRef.value)
- const completionRate = (by.value.finished / (by.value.finished+by.value.todo)) * 100
- debugger
- const option = {
- tooltip: {
- trigger: 'item'
- },
- legend: {
- // top: '5%',
- // right: '10%',
- // align: 'center',
- orient: 'horizontal', // 水平排列图例项
- bottom: '0%', // 放置在底部
- icon: 'circle'
- },
- series: [
- {
- type: 'pie',
- radius: ['40%', '70%'],
- label: {
- show: false,
- position: 'outside'
- },
- emphasis: {
- label: {
- show: true,
- fontSize: 15,
- fontWeight: 'bold'
- }
- },
- labelLine: {
- show: true
- },
- data: [
- { name:'完成率',value: completionRate.toFixed(2) },
- { name:'未完成率',value: 100 - completionRate.toFixed(2) }
- ]
- }
- ]
- }
- maintenanceChartInstance.setOption(option)
- }
- const initInspectionChart = () => {
- if (!inspectionChartRef.value) return
- inspectionChartInstance = echarts.init(inspectionChartRef.value)
- const completionRate = (completedInspectionOrders.value / totalInspectionOrders.value) * 100
- const option = {
- series: [
- {
- type: 'pie',
- radius: ['50%', '80%'],
- data: [
- { value: completionRate, name: '完成率' },
- { value: 100 - completionRate, name: '未完成率' }
- ]
- }
- ]
- }
- inspectionChartInstance.setOption(option)
- }
- /** 初始化图表 */
- const initDeviceStatusCharts = () => {
- // 设备数量统计
- echarts.init(statusChartRef.value).setOption({
- tooltip: {
- trigger: 'item'
- },
- legend: {
- orient: 'horizontal', // 水平排列图例项
- bottom: '0%', // 放置在底部
- icon: 'circle'
- },
- series: [
- {
- name: '',
- type: 'pie',
- radius: ['50%', '80%'],
- avoidLabelOverlap: false,
- center: ['50%', '44%'],
- label: {
- show: false,
- position: 'outside'
- },
- emphasis: {
- label: {
- show: true,
- fontSize: 15,
- fontWeight: 'bold'
- }
- },
- labelLine: {
- show: false
- },
- data: typeData.value
- }
- ]
- })
- }
- /** 初始化 **/
- onMounted(async () => {
- loading.value = true
- await Promise.all([getStats()])
- loading.value = false
- })
- </script>
- <style lang="scss" scoped>
- .summary {
- .el-col {
- margin-bottom: 1rem;
- }
- }
- .stat-card {
- width: 48%;
- }
- .calendar-cell {
- position: relative;
- height: 100%;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- }
- .calendar-pie {
- width: 100%;
- height: 80px;
- }
- </style>
|