<script lang="ts" setup name="MeasureBench"> import { getCurrentInstance, ref } from 'vue' import type { Ref } from 'vue' import type { trainLogStatistic } from './bench-interface' import { getCertificateStatistic, getStaffSStatistic, getStatistic, getTrainLogSStatistic } from '@/api/system/bench' import { getPlanList } from '@/api/system/plan' import { listPageApi } from '@/api/measure/file' import BenchCol from '@/components/benchCol/index.vue' import type { lineDataI, pieDataI } from '@/components/Echart/echart-interface' import { SCHEDULE } from '@/utils/scheduleDict' import useUserStore from '@/store/modules/user' // 每个展示块高度 const blockHeight = ref(300) const blockWidth = ref(400) const { username } = useUserStore() const buttomTypes = ref([ { id: '1', text: '培训记录', url: '/train/trainLog' }, { id: '2', text: '证书到期提醒', url: '/person/remind' }, { id: '3', text: '溯源供方', url: '/source/list' }, { id: '4', text: '实验室', url: '/measureDept/ks' }, { id: '5', text: '工程组', url: '/measureDept/gcz' }, { id: '6', text: '计量人员', url: '/person/list' }, ]) const tableData = ref([]) const meterageTableData = ref([]) const columns = ref([ { text: '培训名称', value: 'planName' }, { text: '负责人', value: 'director', width: '120' }, { text: '培训时间', value: 'trainTime', width: '180' }, ]) const meterageColumns = ref([ { text: '文件名称', value: 'fileName' }, { text: '类别', value: 'fileTypeName', width: '110' }, { text: '发布时间', value: 'publishTime', width: '180' }, ]) const CertificateColumns = ref([ { text: '证书名称', value: 'certificateName' }, { text: '到期时间', value: 'validDate', width: '180' }, ]) const CertificatesColumns = ref([ { text: '证书名称', value: 'certificateName' }, { text: '人员名称', value: 'name', width: '110' }, { text: '到期时间', value: 'validDate', width: '180' }, ]) const StatisticxAxis: Ref<string[]> = ref([]) const StatisticData: Ref<lineDataI[]> = ref([]) const StaffSStatisticData: Ref<lineDataI[]> = ref([]) const maxStaffCount = ref(10) const StaffSStatisticxAxis: Ref<string[]> = ref([]) const TrainLogSList: Ref<pieDataI[]> = ref([]) const TrainLogTitle = ref(0) const CertificateList = ref([]) // 我的证书返回值 interface validReturn { certificateName: string count: string date: string lastValidDate: number name: string notQualified: number qualified: number qualifiedCount: number trainCount: number validDate: string } // 培训计划统计返回值 interface planReturn { date: string count: string | number } const CertificateObject = ref<validReturn>({ certificateName: '', count: '', date: '', lastValidDate: 0, name: '', notQualified: 0, qualified: 0, qualifiedCount: 0, trainCount: 0, validDate: '', }) // 获得权限 const { proxy } = getCurrentInstance() as any // 培训计划列表 const getStatisticList = () => { const params = { createStartTime: '', // 创建开始时间 createEndTime: '', // 创建结束时间 trainStartTime: '', // 培训开始时间 trainEndTime: '', // 培训结束时间 deptId: '', // 部门id formId: SCHEDULE.TRAIN_APPROVAL, // 表单id director: '', // 负责人 effectiveCompany: '', // 实施单位 offset: 1, limit: 20, } getPlanList(params).then((res) => { tableData.value = res.data.rows }) getStatistic().then((res) => { StatisticxAxis.value = res.data.map((item: planReturn) => { return item.date }) const yValue = res.data.map((item: planReturn) => { return Number(item.count) }) StatisticData.value = [{ name: '培训计划', data: yValue }] }) } function fetchStaffStatistic() { // 计量人员统计 getStaffSStatistic().then((res) => { StaffSStatisticxAxis.value = res.data.map((item: planReturn) => item.date) const yValue = res.data.map((item: planReturn) => Number(item.count)) maxStaffCount.value = Math.max(yValue) > 10 ? Math.max(yValue) : 10 StaffSStatisticData.value = [{ name: '人数', data: yValue }] }) } function fetchCertificates() { // 返回值 interface CertificatReturn { lastValidDate: number } const param = { account: username, } getCertificateStatistic(param).then((res) => { CertificateList.value = res.data CertificateObject.value = res.data.sort((nex: CertificatReturn, max: CertificatReturn) => { return nex.lastValidDate - max.lastValidDate })[0] }) } // 我的培训考核 function fetchMyTrainLog() { const param = { account: username, } getTrainLogSStatistic(param).then((res) => { const result: trainLogStatistic = res.data const notQualified: number = Number(result.trainCount) - result.qualifiedCount const qualifiedRate = ((result.qualifiedCount / result.trainCount) * 100).toFixed(2) // 合格率 const notQualifiedRate = ((notQualified / result.trainCount) * 100).toFixed(2) // 不合格率 TrainLogSList.value = [ { name: `合 格 ${result.qualifiedCount}-${qualifiedRate}%`, value: result.qualifiedCount }, { name: `不合格 ${notQualified}- ${notQualifiedRate}%`, value: notQualified }, ] TrainLogTitle.value = res.data.trainCount }).catch((_) => { // 处理异常 TrainLogSList.value = [ { name: '合 格 0 - 50%', value: 0 }, { name: '不合格 0 - 50%', value: 0 }, ] TrainLogTitle.value = 0 }) } // 计量文件列表 const getFileList = () => { const params = { ids: [], fileNo: '', // 编号 fileName: '', // 名称 formId: SCHEDULE.FILE_APPROVAL, // 表单id publishStartTime: '', // 发布时间 publishEndTime: '', // 发布时间 fileCode: '', // 文件号 effectiveStartTime: '', // 实施时间 effectiveEndTime: '', // 实施时间 effectiveStatus: '', // 实施状态 limit: 20, offset: 1, } listPageApi(params).then((res) => { meterageTableData.value = res.data.rows }) } function calcBlockSize() { // 计算工作台区域高度 - 顶部-面包屑-边距 const bodyHeight = document.body.clientHeight - 60 - 50 - 20 blockHeight.value = bodyHeight > 610 ? (bodyHeight - 10) / 2 : 300 blockWidth.value = (document.body.clientWidth - 180 - 20 - 20) / 3 console.log(blockHeight.value, blockWidth.value - 20) } window.addEventListener('resize', () => { calcBlockSize() }) onMounted(() => { calcBlockSize() // 计算各区域宽高 fetchMyTrainLog() // 获取我的培训考核 getFileList() // 计量文件 getStatisticList() // 培训计划列表 fetchCertificates() // 证书列表 fetchStaffStatistic() // 计量人员统计 }) </script> <template> <app-container> <div class="bench"> <el-row :gutter="10"> <el-col :span="8"> <bench-col v-if="proxy.hasPerm('/workbench/meterTrainStatistic')" icon="icon-book" title="培训计划" path-url="/train/plan" :style="{ height: blockHeight }" :height="blockHeight" > <el-table :data="tableData" style="width: 100%; height: 100%;" stripe header-row-class-name="bench-table-header" row-class-name="bench-table-row" class="bench-table" > <el-table-column v-for="item in columns" :key="item.value" :prop="item.value" align="center" :label="item.text" :width="item.width" /> </el-table> </bench-col> </el-col> <el-col :span="8"> <bench-col v-if="proxy.hasPerm('/workbench/meterTrain/line')" icon="icon-line" title="培训计划" :height="blockHeight" > <line-chart :x-axis-data="StatisticxAxis" :data="StatisticData" :width="`${blockWidth - 20}px`" unit="个" /> </bench-col> </el-col> <el-col :span="8"> <div class="bench-right block" :style="{ height: `${blockHeight}px` }" > <bench-col height="40%"> <div class="bench-right-top"> <div v-for="item of buttomTypes" :key="item.text" class="right-top-box" @click="$router.push(item.url)" > {{ item.text }} </div> </div> </bench-col> <div style="flex: 1; margin-top: 10px;"> <bench-col v-if="proxy.hasPerm('/workbench/meterTrain/train')" title="我的培训考核" icon="icon-book" height="100%" > <div class="pie-chart"> <div class="pie-chart-info"> <pie-chart :data="TrainLogSList" :radius="['50%', '70%']" right="40%" :width="`${blockWidth - 20}px`" :label-formatter="`${TrainLogTitle}`" /> </div> </div> </bench-col> </div> </div> </el-col> </el-row> </div> <div class="bench"> <el-row :gutter="10"> <el-col :span="8"> <bench-col v-if="proxy.hasPerm('/measure/file/quality')" title="计量文件" icon="icon-file" path-url="/file/quality" :height="blockHeight" class="flex-full block" > <el-table :data="meterageTableData" style="width: 100%; height: 100%;" stripe header-row-class-name="bench-table-header" row-class-name="bench-table-row" class="bench-table" > <el-table-column v-for="item in meterageColumns" :key="item.value" :prop="item.value" align="center" :label="item.text" :width="item.width" /> </el-table> </bench-col> </el-col> <el-col :span="8"> <bench-col v-if="proxy.hasPerm('/workbench/person/remind')" title="我的证书" icon="icon-certi" :height="blockHeight" path-url="/person/remind" class="flex-full block" > <div style="display: flex;"> <el-table :data="CertificateList" style="width: 65%; height: 100%;" stripe header-row-class-name="bench-table-header" row-class-name="bench-table-row" class="bench-table" > <el-table-column v-for="item in CertificateColumns" :key="item.value" :prop="item.value" align="center" :label="item.text" :width="item.width" /> </el-table> <div class="validDate"> <div class="validDate-top"> <span class="validate-text">{{ CertificateObject.lastValidDate }}<span style="font-size: 12px;">天</span></span> </div> <div class="validDate-bottom"> 最近到期时间 <br> <span>{{ CertificateObject.validDate || '无' }}</span> </div> </div> </div> </bench-col> <bench-col v-if=" proxy.hasPerm('/workbench/person/certificate') && !proxy.hasPerm('/workbench/person/remind') " title="证书预警" icon="icon-certi" path-url="/person/remind" :height="blockHeight" class="flex-full block" > <el-table :data="CertificateList" style="width: 100%; height: 100%;" stripe header-row-class-name="bench-table-header" row-class-name="bench-table-row" class="bench-table" > <el-table-column v-for="item in CertificatesColumns" :key="item.value" :prop="item.value" align="center" :label="item.text" :width="item.width" /> </el-table> </bench-col> </el-col> <el-col :span="8"> <bench-col v-if="proxy.hasPerm('/workbench/person/list')" title="计量人员" icon="icon-line" :height="blockHeight" class="flex-full block" > <line-chart :x-axis-data="StaffSStatisticxAxis" :width="`${blockWidth - 20}px`" :max="maxStaffCount" :data="StaffSStatisticData" unit="人" /> </bench-col> </el-col> </el-row> </div> </app-container> </template> <style lang="scss" scoped> .bench { // display: flex; // justify-content: flex-start; width: 100%; box-sizing: border-box; .flex-full { flex: 1; } .block + .block { margin-left: 10px; } .bench-right { flex: 1; display: flex; flex-direction: column; height: 40vh; .bench-right-top { width: 100%; height: 100%; padding: 0 10px; display: flex; flex-wrap: wrap; align-items: center; box-sizing: border-box; .right-top-box { width: calc(33% - 10px); height: calc(50% - 10px); padding: 10px; margin: 5px; border-radius: 5px; text-align: center; font-size: 14px; color: #fff; cursor: pointer; background-color: #3d7eff; display: flex; justify-content: center; align-items: center; &:hover { background-color: #286ffd; } } } } } .bench + .bench { margin-top: 10px; } .validDate { width: 35%; height: 100%; display: flex; flex-direction: column; align-items: center; text-align: center; .validDate-top { position: relative; width: 100px; height: 100px; margin-bottom: 20px; background: url("../../../assets/images/bench/clock.png") no-repeat center / cover; .validate-text { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 20px; } } .validDate-bottom { font-size: 16px; font-weight: 500; span { font-size: 14px; line-height: 2; font-weight: 400; } } } .pie-chart { display: flex; align-items: center; width: 100%; height: 100%; .pie-chart-info { flex: 1; font-size: 12px; height: 100%; .chart-info-title { display: flex; align-items: center; margin-top: 10px; .chart-info-bg { width: 10px; height: 10px; border-radius: 50%; margin-right: 8px; background-color: #3d7eff; } } } } </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; } </style>