<script lang="ts" setup name="Statistics"> import { getCurrentInstance, ref } from 'vue' import type { Ref } from 'vue' import { type DateModelType, ElMessage } from 'element-plus' import dayjs from 'dayjs' import { getDeptExpireTrend, getEquipmentAmount, getEquipmentStatus, getEquipmentType, getStandardDeviceType, getTestEquipmentAmount, getTestEquipmentMeasuredTrend, getTestEquipmentNoMeasureAmount, getTestEquipmentShouldMeasuredTrend, } from '@/api/workBench/workBench' // import groupPng from '@/assets/images/dashboard/group.png' // import devicePng from '@/assets/images/dashboard/device.png' // import productPng from '@/assets/images/dashboard/product.png' // import dataPng from '@/assets/images/dashboard/data.png' import { getDictByCode } from '@/api/system/dict' import useUserStore from '@/store/modules/user' // import { getGroupListPage } from '@/api/basic/group' // import { getDeviceListPage } from '@/api/basic/device' const router = useRouter() const user = useUserStore()// 用户信息 const checkedPng = new URL('@/assets/images/workBench/checked.png', import.meta.url) const equipmentPng = new URL('@/assets/images/workBench/equipment.png', import.meta.url) const standardPng = new URL('@/assets/images/workBench/standard.png', import.meta.url) const notCheckPng = new URL('@/assets/images/workBench/not-check.png', import.meta.url) const orderPng = new URL('@/assets/images/workBench/order.png', import.meta.url) // 每个展示块高度 const blockHeight = ref(300) const deptId = ref('') // ---------------------------------标准设备种类分析----------------------------------------------- // 默认查询条件 const standardDeviceTypeListQuery = ref({ deptId: '', }) const standardDeviceTypeList: any = ref([]) const standardDeviceTypeColumn: any = [ { text: '标准设备名称', value: 'name', align: 'center' }, { text: '数量', value: 'count', align: 'center' }, ] const standardDeviceTypeLoadingTable = ref(false) // 标准设备种类分析 function fetchStandardDeviceType() { standardDeviceTypeLoadingTable.value = true const params = { ...standardDeviceTypeListQuery.value, deptId: deptId.value, } getStandardDeviceType(params).then((res) => { standardDeviceTypeList.value = [] for (const i in res.data) { standardDeviceTypeList.value.push({ name: i, count: res.data[i] }) } standardDeviceTypeList.value.reverse() standardDeviceTypeLoadingTable.value = false }).catch(() => { standardDeviceTypeLoadingTable.value = false }) } // ---------------------------------设备类型分析----------------------------------------------- const equipmentTypeListQuery = ref({ deptId: '', }) const equipmentType: any = ref([]) const equipmentTypeLoading = ref(false) // 设备类型分析 const fetchEquipmentType = () => { equipmentTypeLoading.value = true const params = { ...equipmentTypeListQuery.value, deptId: deptId.value, } getEquipmentType(params).then((res) => { if (res.data) { const tempData = [ { name: '标准设备', value: 'standardAmount', data: '', }, { name: '配套设备', value: 'equipmentAmount', data: '', }, { name: '其他设备', value: 'otherAmount', data: '', }, ] tempData.forEach((item) => { item.data = res.data[item.value] }) equipmentType.value = tempData.map(item => ({ name: item.name, value: String(item.data) })) } equipmentTypeLoading.value = false }) } // ---------------------------------设备状态分析----------------------------------------------- const equipmentStatusListQuery = ref({ deptId: '', }) const equipmentStatusX: any = ref([]) const equipmentStatusY: any = ref([]) const equipmentStatusLoading = ref(false) // 设备类型分析 const fetchequipmentStatus = () => { equipmentStatusLoading.value = true const params = { ...equipmentStatusListQuery.value, deptId: deptId.value, } getEquipmentStatus(params).then((res) => { if (res.data) { const data = [ { name: '在用', value: 'onUseAmount', data: '', }, { name: '禁用', value: 'disableAmount', data: '', }, { name: '报废', value: 'scrapAmount', data: '', }, { name: '延用', value: 'delayAmount', data: '', }, { name: '封存', value: 'sealAmount', data: '', }, ] data.forEach((item) => { item.data = res.data[item.value] }) equipmentStatusX.value = data.map((item: any) => item.name) equipmentStatusY.value = [ { name: '数量', data: data.map((item: any) => String(item.data)), }, ] equipmentStatusLoading.value = false } }).catch(() => { equipmentStatusLoading.value = false }) } // ---------------------------------受检设备未检设备分析----------------------------------------------- // 默认查询条件 const testEquipmentNoMeasureListQuery = ref({ deptId: '', timeEnd: dayjs().subtract(5, 'year').format('YYYY-MM-DD HH:mm:ss'), timeStart: dayjs().format('YYYY-MM-DD HH:mm:ss'), }) const dateRangeTestEquipmentNoMeasure = ref<[DateModelType, DateModelType]>(['', ''])// 筛选时间段数据 const testEquipmentNoMeasureList: any = ref([]) const testEquipmentNoMeasureColumn: any = [ { text: '部门', value: 'dept', align: 'center' }, { text: '数量', value: 'count', align: 'center' }, ] const testEquipmentNoMeasureLoadingTable = ref(false) // 受检设备未检设备分析 function fetchTestEquipmentNoMeasureAmount() { testEquipmentNoMeasureLoadingTable.value = true const params = { ...testEquipmentNoMeasureListQuery.value, deptId: deptId.value, timeEnd: dayjs(testEquipmentNoMeasureListQuery.value.timeEnd).endOf('month').format('YYYY-MM-DD HH:mm:ss'), timeStart: dayjs(testEquipmentNoMeasureListQuery.value.timeStart).startOf('month').format('YYYY-MM-DD HH:mm:ss'), } getTestEquipmentNoMeasureAmount(params).then((response: any) => { if (response.code === 200) { const tempData = [] for (const i in response.data) { tempData.push({ dept: i, count: response.data[i], }) } testEquipmentNoMeasureList.value = tempData } testEquipmentNoMeasureLoadingTable.value = false }).catch(() => { testEquipmentNoMeasureLoadingTable.value = false }) } // ---------------------------------受检设备已检、应检设备趋势----------------------------------------------- const measuredLineX = ref([]) // 受检设备已检设备趋势x轴 const measuredLineY: any = ref([]) // 受检设备已检设备趋势Y轴 const measuredLoading = ref(false) const shouldMeasuredLineX = ref([]) // 受检设备应检设备趋势x轴 const shouldMeasuredLineY: any = ref([]) // 受检设备应检设备趋势Y轴 const shouldMeasuredLoading = ref(false) const dateRangeMeasured = ref<[DateModelType, DateModelType]>(['', ''])// 筛选时间段数据 const dateRangeShouldMeasured = ref<[DateModelType, DateModelType]>(['', ''])// 筛选时间段数据 const measuredListQuery = ref({ checkDestination: '', contentType: 0, customerId: 0, deptId: '', helpInstruction: '', manufacturer: '', model: '', sampleName: '', timeEnd: dayjs().format('YYYY-MM'), timeStart: dayjs().subtract(6, 'month').format('YYYY-MM'), }) const shouldMeasuredListQuery = ref({ checkDestination: '', contentType: 0, customerId: 0, deptId: '', helpInstruction: '', manufacturer: '', model: '', sampleName: '', timeEnd: dayjs().format('YYYY-MM'), timeStart: dayjs().subtract(6, 'month').format('YYYY-MM'), }) // 受检设备已检设备趋势 const fetchMeasuredLine = () => { measuredLoading.value = true const params = { ...measuredListQuery.value, deptId: deptId.value, timeEnd: dayjs(measuredListQuery.value.timeEnd).endOf('month').format('YYYY-MM-DD HH:mm:ss'), timeStart: dayjs(measuredListQuery.value.timeStart).startOf('month').format('YYYY-MM-DD HH:mm:ss'), } getTestEquipmentMeasuredTrend(params).then((res) => { const tempData = res.data.map((item: { aAmount: any }) => item.aAmount) measuredLineY.value = [{ name: '受检设备已检设备趋势', color: '#17d46b', data: [...tempData] }] measuredLineX.value = res.data.map((item: { dimension: any }) => item.dimension) measuredLoading.value = false }) } // 受检设备应检设备趋势 const fetchshouldMeasuredLine = () => { shouldMeasuredLoading.value = true const params = { ...shouldMeasuredListQuery.value, deptId: deptId.value, timeEnd: dayjs(shouldMeasuredListQuery.value.timeEnd).endOf('month').format('YYYY-MM-DD HH:mm:ss'), timeStart: dayjs(shouldMeasuredListQuery.value.timeStart).startOf('month').format('YYYY-MM-DD HH:mm:ss'), } getTestEquipmentShouldMeasuredTrend(params).then((res) => { const tempData = res.data.map((item: { aAmount: any }) => item.aAmount) shouldMeasuredLineY.value = [{ name: '受检设备未检设备趋势', color: '#9A66E4', data: [...tempData] }] shouldMeasuredLineX.value = res.data.map((item: { dimension: any }) => item.dimension) shouldMeasuredLoading.value = false }) } // ----------------------------------------------------------------------------------- // 点击标题跳转页面 const handleClickTitle = (title = '') => { console.log('点击的title', title) switch (title) { case '分组管理': router.push('/basic/group/list') break case '低电量设备(低于10%)': router.push({ path: '/basic/device/list', query: { fromPage: 'dashboard', queryType: 'lowBattery', }, }) break } } // ------------------------------------数量------------------------------------------------------------------- const testEquipmentcount = ref({ expireAmount: '****', // 受检设备年度到期应检总量 measuredAmount: '****', // 受检设备已检总量 modelAmount: '****', // 受检设备规格型号总量 orderAmount: '****', // 任务单总量 sampleAmount: '****', // 受检设备总量 }) const equipmentcount = ref({ equipmentAmount: '****', // 在用设备总量 expireAmount: '****', // 本年度到期设备总量 shouldTraceAmount: '****', // 应溯源总数量 standardAmount: '****', // 在用标准设备总量 }) // 获取受检设备分析 const fetchTestEquipmentAmount = () => { const params = { checkDestination: '', contentType: 0, customerId: 0, deptId: deptId.value, helpInstruction: '', manufacturer: '', model: '', sampleName: '', timeEnd: '', timeStart: '', } getTestEquipmentAmount(params).then((res) => { testEquipmentcount.value.expireAmount = res.data.expireAmount // 受检设备年度到期应检总量 testEquipmentcount.value.measuredAmount = res.data.measuredAmount // 受检设备已检总量 testEquipmentcount.value.modelAmount = res.data.modelAmount // 受检设备规格型号总量 testEquipmentcount.value.orderAmount = res.data.orderAmount // 任务单总量 testEquipmentcount.value.sampleAmount = res.data.sampleAmount // 受检设备总量 }) } // 获取实验室设备分析 const fetchEquipmentAmount = () => { const params = { checkDestination: '', contentType: 0, customerId: 0, deptId: deptId.value, helpInstruction: '', manufacturer: '', model: '', sampleName: '', timeEnd: '', timeStart: '', } getEquipmentAmount(params).then((res) => { equipmentcount.value.equipmentAmount = res.data.equipmentAmount // 在用设备总量 equipmentcount.value.expireAmount = res.data.expireAmount // 本年度到期设备总量 equipmentcount.value.shouldTraceAmount = res.data.shouldTraceAmount // 应溯源总数量 equipmentcount.value.standardAmount = res.data.standardAmount // 在用标准设备总量 }) } // ----------------------------------------------------------------------------------------------------- watch(dateRangeMeasured, (val) => { if (val) { measuredListQuery.value.timeStart = `${val[0]}` measuredListQuery.value.timeEnd = `${val[1]}` } else { measuredListQuery.value.timeStart = dayjs().subtract(6, 'month').format('YYYY-MM') measuredListQuery.value.timeEnd = dayjs().format('YYYY-MM') } fetchMeasuredLine() }) watch(dateRangeShouldMeasured, (val) => { if (val) { shouldMeasuredListQuery.value.timeStart = `${val[0]}` shouldMeasuredListQuery.value.timeEnd = `${val[1]}` } else { shouldMeasuredListQuery.value.timeStart = dayjs().subtract(6, 'month').format('YYYY-MM') shouldMeasuredListQuery.value.timeEnd = dayjs().format('YYYY-MM') } fetchshouldMeasuredLine() }) watch(dateRangeTestEquipmentNoMeasure, (val) => { if (val) { shouldMeasuredListQuery.value.timeStart = `${val[0]}` shouldMeasuredListQuery.value.timeEnd = `${val[1]}` } else { shouldMeasuredListQuery.value.timeStart = dayjs().subtract(5, 'year').format('YYYY') shouldMeasuredListQuery.value.timeEnd = dayjs().format('YYYY') } fetchTestEquipmentNoMeasureAmount() }) function calcBlockSize() { // 计算工作台区域高度 - 顶部-面包屑-边距 const bodyHeight = document.body.clientHeight - 50 - 80 blockHeight.value = (bodyHeight - 100) / 2 // 左侧菜单使用 } watch(() => deptId.value, (newValue) => { fetchTestEquipmentAmount() fetchEquipmentAmount() fetchMeasuredLine() // 受检设备已检设备趋势 fetchshouldMeasuredLine() // 受检设备应检设备趋势 fetchTestEquipmentNoMeasureAmount() // 受检设备未检定设备数量分析 fetchEquipmentType() // 设备类型分析 fetchequipmentStatus() // 设备状态分析 fetchStandardDeviceType() // 标准设备种类分析 }) window.addEventListener('resize', () => { calcBlockSize() }) onBeforeMount(() => { calcBlockSize() }) onMounted(() => { deptId.value = user.deptId }) </script> <template> <dept-select ref="deptSelect" v-model="deptId" style="position: absolute; right: 10px;top: -40px;z-index: 999;width: 220px;" placeholder="实验室" :dept-show="true" /> <app-container style="overflow: hidden;padding-top: 10px;"> <!-- <div class="card"> --> <div style="display: flex;height: 90px;text-align: center;width: 100%;justify-content: space-between;" > <div class="item"> <el-image :src="equipmentPng" class="base-map-image" mode="fill" /> <div class="item-text"> <div style="color: #0f67e7;"> 在用设备总量 </div> <div class="num"> {{ equipmentcount.equipmentAmount }} </div> </div> </div> <div class="item"> <el-image :src="standardPng" class="base-map-image" mode="fill" /> <div class="item-text"> <div style="color: #0f67e7;"> 在用标准装置总量 </div> <div class="num"> {{ equipmentcount.standardAmount }} <!-- <span class="unit">台</span> --> </div> </div> </div> <div class="item"> <el-image :src="orderPng" class="base-map-image" mode="fill" /> <div class="item-text"> <div style="color: #0f67e7;"> 委托单总量 </div> <div class="num"> {{ testEquipmentcount.orderAmount }} <!-- <span class="unit">%</span> --> </div> </div> </div> <div class="item"> <el-image :src="equipmentPng" class="base-map-image" mode="fill" /> <div class="item-text"> <div style="color: #0f67e7;"> 受检设备总量 </div> <div class="num"> {{ testEquipmentcount.sampleAmount }} <!-- <span class="unit">%</span> --> </div> </div> </div> <div class="item"> <el-image :src="notCheckPng" class="base-map-image" mode="fill" /> <div class="item-text"> <div style="color: #0f67e7;"> 受检设备年度到期应检总量 </div> <div class="num"> {{ testEquipmentcount.expireAmount }} </div> </div> </div> <div class="item"> <el-image :src="checkedPng" class="base-map-image" mode="fill" /> <div class="item-text"> <div style="color: #0f67e7;"> 受检设备已检总量 </div> <div class="num"> {{ testEquipmentcount.measuredAmount }} </div> </div> </div> </div> <!-- </div> --> <div class="device-bench"> <el-row :gutter="10"> <el-col :span="8"> <bench-col v-loading="measuredLoading" style="position: relative;" icon="icon-line1" title="受检设备已检设备趋势" :height="blockHeight" @handleClickTitle="handleClickTitle"> <div style="position: absolute;right: 10px;top: 10px;"> <el-date-picker v-model="dateRangeMeasured" class="short-input" type="monthrange" range-separator="至" format="YYYY-MM" value-format="YYYY-MM" start-placeholder="开始日期" end-placeholder="结束日期" size="small" style="width: 220px;float: right;" /> </div> <line-chart :x-axis-data="measuredLineX" :data="measuredLineY" :legend="{ show: false }" /> </bench-col> </el-col> <el-col :span="8"> <bench-col v-loading="shouldMeasuredLoading" style="position: relative;" icon="icon-line1" title="受检设备应检设备趋势" :height="blockHeight" @handleClickTitle="handleClickTitle"> <div style="position: absolute;right: 10px;top: 10px;"> <el-date-picker v-model="dateRangeShouldMeasured" class="short-input" type="monthrange" range-separator="至" format="YYYY-MM" value-format="YYYY-MM" start-placeholder="开始日期" end-placeholder="结束日期" size="small" style="width: 220px;float: right;" /> </div> <line-chart :x-axis-data="shouldMeasuredLineX" :data="shouldMeasuredLineY" :legend="{ show: false }" /> </bench-col> </el-col> <el-col :span="8"> <bench-col v-loading="testEquipmentNoMeasureLoadingTable" style="position: relative;" icon="icon-table" title="受检设备未检设备分析" :height="blockHeight" @handleClickTitle="handleClickTitle"> <div style="position: absolute;right: 10px;top: 10px;"> <el-date-picker v-model="dateRangeTestEquipmentNoMeasure" class="short-input" type="monthrange" range-separator="至" format="YYYY-MM" value-format="YYYY-MM" start-placeholder="开始日期" end-placeholder="结束日期" size="small" style="width: 220px;float: right;" /> </div> <normal-table :data="testEquipmentNoMeasureList" :height="blockHeight - 60" :columns="testEquipmentNoMeasureColumn" :pagination="false" :query="testEquipmentNoMeasureListQuery" :list-loading="testEquipmentNoMeasureLoadingTable" > <template #preColumns> <el-table-column label="序号" width="55" align="center"> <template #default="scope"> {{ scope.$index + 1 }} </template> </el-table-column> </template> </normal-table> </bench-col> </el-col> </el-row> </div> <div class="device-bench" style="margin-top: 10px;"> <el-row :gutter="10"> <el-col :span="8"> <bench-col v-loading="equipmentTypeLoading" style="position: relative;" icon="icon-pie" title="设备类型分析" :height="blockHeight" @handleClickTitle="handleClickTitle"> <pie-chart v-if="equipmentType.length" style="flex: 1;margin-left: 10px;" :data="equipmentType" :radius="['70%']" :label-show="false" title="设备类型分析" :emphasis="{ show: false }" /> <el-empty v-if="!equipmentType.length" :image-size="100" style="margin: 0 auto;" description="暂无数据" /> </bench-col> </el-col> <el-col :span="8"> <bench-col v-loading="equipmentStatusLoading" style="position: relative;" icon="icon-bar" title="设备状态分析" :height="blockHeight" @handleClickTitle="handleClickTitle"> <bar-chart-vertical v-if="equipmentStatusY.length" :x-axis-data="equipmentStatusX" :data="equipmentStatusY" :legend="{ show: false }" :bar-coner="0" :gradient="false" /> <el-empty v-if="!equipmentStatusY.length" :image-size="100" style="margin: 0 auto;" description="暂无数据" /> </bench-col> </el-col> <el-col :span="8"> <bench-col v-loading="standardDeviceTypeLoadingTable" style="position: relative;" icon="icon-table" title="标准设备种类分析" :height="blockHeight" @handleClickTitle="handleClickTitle"> <normal-table :data="standardDeviceTypeList" :height="blockHeight - 60" :columns="standardDeviceTypeColumn" :pagination="false" :query="standardDeviceTypeListQuery" > <template #preColumns> <el-table-column label="序号" width="55" align="center"> <template #default="scope"> {{ scope.$index + 1 }} </template> </el-table-column> </template> </normal-table> </bench-col> </el-col> </el-row> </div> </app-container> </template> <style lang="scss" scoped> .card { background-color: #fff; border-radius: 8px; box-shadow: 0 0 12px rgb(0 0 0 / 12%); padding-top: 8px; margin-bottom: 10px; } .device-bench { width: 100%; height: 100%; box-sizing: border-box; .the-month-total-Data { width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: space-around; padding: 0 20px; .title { display: flex; justify-content: space-between; font-weight: 500; margin-bottom: 3px; } .content { width: 100%; .item { display: flex; flex-direction: column; flex: 1; margin-right: 10px; padding: 3px 0; justify-content: center; align-items: center; background-image: linear-gradient(to bottom, #e9f5ff, #3d7eff); border-radius: 8px; &:last-child { margin-right: 0; } } } } .my-equipment { height: 100%; display: flex; flex-direction: column; justify-content: space-around; padding: 20px; .item { height: 40%; display: flex; flex-direction: column; justify-content: center; align-items: center; background-image: linear-gradient(to right, #caddff, #3d7eff); border-radius: 16px; } } } .item { // width: 300px; padding-right: 20px; padding-left: 20px; display: flex; justify-content: left; align-items: center; height: 80px; border-radius: 10px; border: 2px solid #398bff; &:hover { background-color: #e7f1fd; cursor: pointer; color: #398bff; } } </style> <style lang="scss"> .bench-table { .el-table__header-wrapper { border-radius: 8px; } } .bench-table-header { th { font-weight: normal; font-size: 14px; } } .bench-table-row { border-radius: 8px; } .num { text-shadow: 0 0 5px #0f67e7; color: #0f67e7; font-size: 30px; padding-top: 2px; font-weight: bold; } .unit { color: #0f67e7; font-size: 14px; margin-left: 3px; } .item-text { text-shadow: 0 0 2px #0f67e7; flex: 1; text-align: center; font-size: 18px; } .base-map-image { width: 50px; height: 50px; // margin-left: 20px; margin-right: 20px; } </style>