<!-- 设备分析 --数据看板 --> <script name="deviceTrend" lang="ts" setup> import dayjs from 'dayjs' import draggable from 'vuedraggable' import { colors } from '../environment/colors' import { device } from './img' import { getRangeAllTime } from '@/utils/date' import { getBaseInfo, getDeptExpire, getDeviceMaintain, getDeviceStatus, getDeviceType, getStandardDeviceType, getTraceAnalyse, } from '@/api/dataManagement/data/device' const props = defineProps({ lab: { type: String, default: '', }, }) // 查询条件 const searchQueryResult = ref({ groupCode: '', labCode: '', timeStart: '', timeEnd: '', }) const year = ref('') // 年度 const yearList = ref<string[]>([]) watch( () => props.lab, (newVal) => { if (newVal) { searchQueryResult.value.labCode = props.lab fetchData() } }, ) // 基础信息展示数据 const baseInfo = ref([ { name: '在用设备总量', value: 'equipmentAmount', data: '', icon: device['在用设备总量'], color: '#1AAF8B', }, { name: '在用标准设备总量', value: 'standardAmount', data: '', icon: device['在用标准设备总量'], color: '#1AAF8B', }, { name: '本年度到期设备总量', value: 'expireAmount', data: '', icon: device['本年度到期设备总量'], color: '#1AAF8B', }, { name: '应溯源总数量', value: 'shouldTraceAmount', data: '', icon: device['应溯源总数量'], color: '#1AAF8B', }, { name: '实际溯源总数量', value: 'tracedAmount', data: '', icon: device['实际溯源总数量'], color: '#1AAF8B', }, ]) const showChart = ref<any[]>([ { name: '近一年部门设备到期趋势', type: 'line', source: 'system', xAxisData: [], data: [], smooth: false, gradient: true, }, { name: '设备类型分析', type: 'pie', source: 'system', center: ['50%', '60%'], labelPosition: 'outside', radius: '70%', data: [], }, { name: '标准设备种类分析', type: 'rank-table', source: 'system', data: [], columns: [ { text: '标准设备名称', value: 'name', align: 'center', }, { text: '数量', value: 'count', align: 'center', }, ], }, { name: '设备状态分析', type: 'bar-vertical', source: 'system', }, { name: '设备维护保养情况', type: 'rank-table', source: 'system', data: [], columns: [ { text: '实验室', value: 'labCodeName', align: 'center', width: '75', }, { text: '部门', value: 'groupCodeName', align: 'center', }, { text: '设备名称', value: 'equipmentName', align: 'center', }, { text: '规格型号', value: 'model', align: 'center', }, { text: '月保养次数', value: 'monthAmount', align: 'center', width: '95', }, { text: '周维护次数', value: 'weekAmount', align: 'center', width: '95', }, ], }, { name: '设备溯源分析', type: 'bar-horizontal', source: 'system', }, ]) watch( () => showChart.value.length, () => { setTimeout(() => { const resize = new Event('resize') window.dispatchEvent(resize) }) }, ) // 模拟数据 const loading = ref(false) function fetchData() { // 获取基础数据 getBaseInfo(searchQueryResult.value).then((res) => { baseInfo.value.forEach((item) => { item.data = res.data[item.value] }) }) // 近一年部门设备到期趋势 getDeptExpire(searchQueryResult.value).then((res) => { console.log(res.data, '近一年部门设备到期趋势') const current = showChart.value.filter( item => item.name === '近一年部门设备到期趋势', )[0] current.xAxisData = res.data.map((item: any) => item.dimension) const data = [ { name: '电学电源组', value: 'ddAmount', }, { name: '热工压力组', value: 'rlAmount', }, { name: '无线脉冲组', value: 'wmAmount', }, { name: '综合管理组', value: 'glAmount', }, ] current.data = data.map((item: any) => ({ name: item.name, symbol: 'emptyCircle', data: res.data.map((citem: any) => String(citem[item.value])), })) }) // 设备类型分析 getDeviceType(searchQueryResult.value).then((res) => { console.log(res.data, '设备类型分析') const data = [ { name: '标准设备', value: 'standardAmount', data: '', }, { name: '配套设备', value: 'equipmentAmount', data: '', }, { name: '其他设备', value: 'otherAmount', data: '', }, ] const current = showChart.value.filter( item => item.name === '设备类型分析', )[0] data.forEach((item) => { item.data = res.data[item.value] }) current.data = data.map(item => ({ name: item.name, value: String(item.data) })) }) // 设备状态分析 getDeviceStatus(searchQueryResult.value).then((res) => { console.log(res.data, '设备状态分析') const current = showChart.value.filter( item => item.name === '设备状态分析', )[0] 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] }) current.xAxisData = data.map((item: any) => item.name) current.data = [ { name: '数量', data: data.map((item: any) => String(item.data)), }, ] }) // 设备溯源分析 getTraceAnalyse(searchQueryResult.value).then((res) => { console.log(res.data, '设备溯源分析') const current = showChart.value.filter( item => item.name === '设备溯源分析', )[0] const data = [ { name: '合格', value: 'qualifiedAmount', data: '', }, { name: '限用', value: 'restrictAmount', data: '', }, { name: '停用', value: 'stopAmount', data: '', }, ] data.forEach((item) => { item.data = res.data[item.value] }) current.xAxisData = data.map((item: any) => item.name) current.data = [ { name: '数量', data: data.map((item: any) => String(item.data)), }, ] }) // 标准设备种类分析 getStandardDeviceType(searchQueryResult.value).then((res) => { console.log(res.data, '标准设备种类分析') const current = showChart.value.filter( item => item.name === '标准设备种类分析', )[0] current.data = [] for (const i in res.data) { current.data.push({ name: i, count: res.data[i] }) } current.data.reverse() }) // 设备维护保养情况 getDeviceMaintain({ ...searchQueryResult.value, offset: 1, limit: 9999 }).then((res) => { console.log(res.data, '设备维护保养情况') const current = showChart.value.filter( item => item.name === '设备维护保养情况', )[0] current.data = [] current.data = res.data.rows }) // loading.value = true // // 近一年部门设备到期趋势 // const name1 = ['电学电源组', '热工压力组', '无线脉冲组', '综合管理组'] // const timeList = getRangeAllTime(dayjs().subtract(14, 'day').format('YYYY-MM-DD'), dayjs().format('YYYY-MM-DD')) // showChart.value.filter((item: any) => item.name === '近一年部门设备到期趋势')[0].data = name1.map(item => ({ // name: item, // data: timeList.map(item => Math.floor(Math.random() * 100) + 1), // symbol: 'emptyCircle', // })) // showChart.value.filter((item: any) => item.name === '近一年部门设备到期趋势')[0].xAxisData = timeList // // 设备类型分析 // const name2 = ['标准设备', '配套设备', '其他'] // showChart.value.filter((item: any) => item.name === '设备类型分析')[0].data = name2.map(item => ({ // name: item, // value: Math.floor(Math.random() * 100) + 1, // })) // // 设备状态分析 // const name3 = ['在用', '禁用', '报废', '延用', '封存'] // showChart.value.filter((item: any) => item.name === '设备状态分析')[0].data = [{ // name: '数量', // data: name3.map(item => Math.floor(Math.random() * 100) + 1), // }] // showChart.value.filter((item: any) => item.name === '设备状态分析')[0].xAxisData = name3 // // 设备溯源分析 // const name4 = ['校准', '测试', '合格', '限用', '禁用', '停用', '封存'] // showChart.value.filter((item: any) => item.name === '设备溯源分析')[0].data = [{ // name: '数量', // data: name4.map(item => Math.floor(Math.random() * 100) + 1), // }] // showChart.value.filter((item: any) => item.name === '设备溯源分析')[0].xAxisData = name4 // setTimeout(() => { // const resize = new Event('resize') // window.dispatchEvent(resize) // }) // setTimeout(() => { // loading.value = false // }, 3000) } defineExpose({ showChart, }) // 拖拽结束 const onEnd = () => { console.log('拖拽结束') const resize = new Event('resize') window.dispatchEvent(resize) } // 整理最近五年年度 const currentYear = new Date().getFullYear() yearList.value = [] for (let i = 0; i < 5; i++) { yearList.value.push(String(currentYear - i)) } watch( () => year.value, (newVal) => { if (newVal) { console.log(newVal, '当前年度') searchQueryResult.value.timeStart = `${newVal}-01-01` searchQueryResult.value.timeEnd = `${newVal}-12-31` setTimeout(() => { fetchData() }) } }, ) onMounted(() => { year.value = String(currentYear) if (props.lab) { searchQueryResult.value.labCode = props.lab setTimeout(() => { fetchData() }) } }) </script> <template> <div class="container"> <div class="btns"> <div /> <!-- 部门 --> <el-select v-model="year" style="width: 130px;" class="short-input" placeholder="年度" > <el-option v-for="item in yearList" :key="item" :label="item" :value="item" /> </el-select> </div> <!-- 展示内容 --> <div class="content-count"> <!-- 统计数据 --> <div class="count"> <div v-for="item in baseInfo" :key="item.value" class="count-item"> <div class="header-icon"> <img :src="item.icon"> </div> <div class="header-content"> <div class="content-title"> {{ item.name }} </div> <div class="content-count" :style="{ color: item.color }"> {{ item.data }} </div> </div> </div> </div> <!-- 图表区域 --> <!-- <div class="chart"> --> <draggable v-model="showChart" item-key="name" class="chart" animation="300" drag-class="dragClass" ghost-class="ghostClass" chosen-class="chosenClass" @end="onEnd" > <template #item="{ element, index }"> <div :style="{ width: `${ '31.5%' }`, }" class="chart-item" > <div class="chart-name"> <!-- {{ element.name }} --> </div> <div v-loading="loading" class="chart-page"> <div style="width: 100%; height: 100%;"> <div class="chart-name" style="width: 100%; height: 10%; display: flex;" > {{ element.name }} <div v-if="element.name === '人员持证到期趋势'" style="width: 350px; margin-left: 40px;" > <el-date-picker v-model="datetimerange" type="daterange" value-format="YYYY-MM-DD" format="YYYY-MM-DD" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" /> </div> </div> <div style="width: 100%; height: 90%;"> <pie-chart v-if="element.type === 'pie'" :title="element.title" :show-total="element.showTotal" :data="element.data" :colors="colors" :center="element.center" label-formatter="{style1|{c}}" :label-position="element.labelPosition" :radius="element.radius" :grid="{ top: 50, left: 15, right: 15, bottom: 10, containLabel: true, }" :legend="{ itemWidth: 8, itemHeight: 8, type: 'scroll', orient: 'horizontal', icon: 'roundRect', left: '0', top: '10', }" /> <line-chart v-if="element.type === 'line'" :colors="colors" :gradient="element.gradient" :x-axis-data="element.xAxisData" :data="element.data" :smooth="element.smooth" :grid="{ top: 47, left: 5, right: 5, bottom: 10, containLabel: true, }" :legend="{ itemWidth: 8, itemHeight: 2, type: 'scroll', orient: 'horizontal', icon: 'roundRect', left: '0', top: '5', }" /> <bar-chart-double v-if="element.type === 'bar-double'" :legend-data="element.legendData" :data1="element.data1" :data2="element.data2" :x-axis-data="element.xAxisData" :legend="{ itemWidth: 8, itemHeight: 8, type: 'scroll', orient: 'horizontal', icon: 'roundRect', left: '0', top: '10', }" /> <bar-chart-vertical v-if="element.type === 'bar-vertical'" :bar-coner="0" :data="element.data" :x-axis-data="element.xAxisData" :legend="{ itemWidth: 8, itemHeight: 8, type: 'scroll', orient: 'horizontal', icon: 'roundRect', left: '0', top: '10', }" /> <bar-chart-horizontal v-if="element.type === 'bar-horizontal'" bar-width="10" :bar-coner="0" :data="element.data" :x-axis-data="element.xAxisData" :legend="{ itemWidth: 8, itemHeight: 8, type: 'scroll', orient: 'horizontal', icon: 'roundRect', left: '0', top: '10', }" /> <scroll-table v-if="element.type === 'rank-table'" style="width: 100%;" :height="300" :data="element.data" :columns="element.columns" /> </div> </div> </div> </div> </template> </draggable> <!-- </div> --> </div> </div> </template> <style lang="scss" scoped> .dragClass { /* background-color: blueviolet !important; */ opacity: 1 !important; box-shadow: none !important; outline: none !important; background-image: none !important; color: #6ff !important; } .ghostClass { /* background-color: blue !important; */ } .chosenClass { color: #6ff !important; /* background-color: #ccc !important; */ /* opacity: 1 !important; */ /* width: 32.5% !important; */ } .icon-button-icon { width: 50px; height: 50px; } .container { position: relative; .btns { width: 100%; position: absolute; top: -36px; right: 50%; // left: 50%; display: flex; justify-content: space-between; padding: 0 120px; } .count { display: flex; width: 60%; margin: 0 auto; position: absolute; top: -40px; left: 50%; transform: translateX(-50%); justify-content: space-around; .count-item { // margin-left: 20px; width: 22%; height: 75px; display: flex; justify-content: space-around; // padding: 0 10px; .header-icon { width: 20%; display: flex; flex-direction: column; justify-content: center; } .header-content { // width: 60%; padding: 10px; display: flex; flex-direction: column; justify-content: space-around; .content-title { font-weight: 700; } .content-count { font-weight: 700; font-size: 24px; color: #1aaf8b; text-align: center; } } } } .chart { display: flex; flex-wrap: wrap; justify-content: space-around; // margin-top: 15px; padding-top: 20px; .chart-item { width: 33%; height: 348px; // border: 1px solid red; margin-top: 10px; .chart-name { color: #3d6fb6; font-size: 18px; font-weight: 700; } .chart-page { height: 330px; } } } } </style>