<!-- 工作台 --> <script lang="ts" setup name="BusinessBench"> import { getCurrentInstance, ref } from 'vue' import type { Ref } from 'vue' import { SCHEDULE } from '@/utils/scheduleDict' import type { pieDataI } from '@/components/Echart/echart-interface' import { getPieData, getSampleMeasureList, getSampleMonitorList, getSamplestatusMonth } from '@/api/business/bench/bench' import { getReportList } from '@/api/business/lab/report' import type { TableColumn } from '@/components/NormalTable/table_interface' import { getJobAccountList } from '@/api/business/board/jobAccount' // 每个展示块高度 const blockHeight = ref(300) const blockWidth = ref(400) const { proxy } = getCurrentInstance() as any // 样品监控表头 const sampleMonitorData = ref([]) // 样品监控表头 const sampleMonitorHead = [ { text: '样品名称', value: 'sampleName' }, { text: '当前检测实验室', value: 'currentSegment', width: '125' }, { text: '下一检测实验室', value: 'nextSegment', width: '125' }, { text: '进度', value: 'progressData', width: '140' }, ] // 样品监控查询条件 const listQuerySampleMonitor = ref({ offset: 1, limit: 10, }) const loadingTableSampleMonitor = ref(false) // 样品监控loading const totalSampleMonitor = ref(0) // 样品监控数据总数 // 样品检测表头 const sampleMeasureHead = [ { text: '样品名称', value: 'sampleName' }, { text: '委托方名称', value: 'customerName', width: '100' }, { text: '检测状态', value: 'measureStatusName' }, ] // 我的检测表格数据 const sampleMeasureData = ref([]) // 进度条添加后缀 % const format = (percentage: number) => (percentage === 100 ? 'Full' : `${percentage}%`) // 证书报告数据 const reportData = ref([]) // 表头 const reportHead = ref<TableColumn[]>([ { text: '名称', value: 'certificateReportName', align: 'center' }, { text: '检定员', value: 'measurePerson', align: 'center' }, { text: '状态', value: 'approvalStatusName', align: 'center', width: '110' }, ]) // 表头 const realTimeWorkStatisticsHead = ref<TableColumn[]>([ { text: '检测实验室', value: 'organizeName', align: 'center' }, { text: '今日检完样品', value: 'samplesCompletedToday', align: 'center' }, { text: '今日出具证书数', value: 'certificatesToday', align: 'center' }, { text: '超期率', value: 'expireRate', align: 'center' }, ]) // 实时工作统计表格数据 const realTimeWorkStatisticsData = ref() // 饼图--图例配置项 const picLegend = ref({ show: false, orient: 'vertical', right: '20%', top: 'center', icon: 'circle', itemWidth: 12, itemHeight: 12, itemStyle: { fontSize: 18, }, }) // 按钮跳转数据 const buttonTypes = ref([ { id: '1', text: '证书打印', url: '/schedule/certPrintList' }, { id: '2', text: '环境记录单', url: '/lab/environmentalList' }, { id: '3', text: '原始记录', url: '/lab/primitiveLogList' }, { id: '4', text: '现场检测申请', url: '/fieldTest/approve' }, { id: '5', text: '分包项目登记', url: '/subpackage/itemApply' }, { id: '6', text: '分包方档案', url: '/subpackage/archives' }, ]) // 当前进行中样品状态数据 const statusData = ref<{ status: string;quantity: string }[]>([]) const router = useRouter() // 点击按钮组 const handleClickButton = (id: string) => { const index = buttonTypes.value.findIndex(item => item.id === id) if (index !== -1 && buttonTypes.value[index].url) { router.push(buttonTypes.value[index].url) } } // 计算工作台区域高度 - 顶部-面包屑-边距 const benchDivHeight = ref() 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) benchDivHeight.value = blockHeight.value - 60 } // ---------------------------------------获取数据------------------------------------ // 样品监控 const fetchSampleMonitorList = (isNowPage = false) => { loadingTableSampleMonitor.value = true if (!isNowPage) { // 是否显示当前页,否则跳转第一页 listQuerySampleMonitor.value.offset = 1 } getSampleMonitorList(listQuerySampleMonitor.value).then((res) => { loadingTableSampleMonitor.value = false sampleMonitorData.value = res.data.rows.map((item: { progress: string; progressData: number }) => { if (item.progress.includes('%')) { item.progressData = Number(item.progress.slice(0, item.progress.indexOf('%'))) } console.log('进度', typeof item.progressData, item.progressData) return item }) totalSampleMonitor.value = parseInt(res.data.total) }).catch(() => { loadingTableSampleMonitor.value = false }) } // 页数发生变化后的操作,可能是页码变化,可能是每页容量变化,此函数必写 const changePage = (val: { size?: number; page?: number }) => { if (val && val.size) { listQuerySampleMonitor.value.limit = val.size } if (val && val.page) { listQuerySampleMonitor.value.offset = val.page } fetchSampleMonitorList(true) } // 证书报告 const listQueryReport = ({ approvalStatus: '0', // 审批状态 -- 全部 certificateReportCode: '', // 证书号 customerName: '', // 委托方名称 measureCategory: '', // 检校类别 orderCode: '', // 委托单编号 sampleName: '', // 样品名称 sampleNo: '', // 样品编号 formId: SCHEDULE.BUSINESS_REPORT_ON_CREDENTIALS, offset: 1, limit: 20, }) // 证书报告获取列表数据 const fetchReportData = () => { getReportList(listQueryReport).then((response) => { reportData.value = response.data.rows.map((item: { approvalStatusName: string }) => { return { ...item, // 已通过-可打印、审批中-审批中、其他所有状态-编制中 approvalStatusName: item.approvalStatusName === '审批中' ? '审批中' : item.approvalStatusName === '已通过' ? '可打印' : '编制中', } }) }).catch((_) => { }) } // 实时工作统计 function fetchJobAccountList() { getJobAccountList().then((response) => { realTimeWorkStatisticsData.value = response.data }) } // 样品检测列表 function fetchSampleMeasureList() { getSampleMeasureList().then((response) => { sampleMeasureData.value = response.data.rows }) } // 本月样品状态 const fetchSamplestatusMonth = () => { getSamplestatusMonth().then((res) => { statusData.value = res.data }) } const totalQuantity = ref(0) // 总数(饼图中间) const pieData = ref() // 饼图数据 // 饼图 const fetchPieData = () => { getPieData().then((res) => { pieData.value = res.data.map((item: { measureQuantity: number; rate: string;measureStatusName: string }) => { return { ...item, name: item.measureStatusName, value: item.measureQuantity, } }) res.data.forEach((item: { totalQuantity: number }) => { totalQuantity.value += item.totalQuantity }) }) } onMounted(() => { calcBlockSize() fetchSampleMonitorList() // 样品监控 fetchReportData() // 证书报告 fetchJobAccountList() // 实时工作统计 fetchSamplestatusMonth() // 本月样品状态 fetchSampleMeasureList() // 样品检测列表 fetchPieData() // 饼图 }) </script> <template> <app-container> <el-row :gutter="10"> <el-col :span="8"> <bench-col icon="icon-file" title="样品监控" :height="blockHeight" :pagination="true" :query="listQuerySampleMonitor" :total="totalSampleMonitor" @change="changePage" > <el-table v-loading="loadingTableSampleMonitor" :data="sampleMonitorData" :height="blockHeight - 90" 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 sampleMonitorHead" :key="item.value" :prop="item.value" align="center" :label="item.text" show-overflow-tooltip :width="item.width" > <template v-if="item.value === 'progressData'" #default="scope"> <el-progress :stroke-width="5" :percentage="scope.row.progressData" /> </template> </el-table-column> </el-table> </bench-col> </el-col> <el-col :span="8"> <bench-col icon="icon-line" title="样品检测" :height="blockHeight" path-url="/lab/myMeasureList"> <div class="my-tests" style="width: 100%;"> <div style="width: 60%;"> <el-table :data="sampleMeasureData" :max-height="blockHeight - 60" 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 sampleMeasureHead" :key="item.value" :prop="item.value" align="center" :label="item.text" :width="item.width" /> </el-table> </div> <div style="width: 40%;"> <pie-chart style="width: 100%;" :data="pieData" :radius="['50%', '70%']" :colors="['#3d7eff', '#caddff', '#1d9cce', '#1D9CAF']" right="0%" :legend="picLegend" :label-formatter="`${totalQuantity}`" /> </div> </div> </bench-col> </el-col> <el-col :span="8"> <bench-col :height="blockHeight"> <div :max-height="blockHeight - 60" style="width: 100%; height: 100%; padding: 32px 0; display: flex;flex-wrap: wrap; justify-content: center; align-items: center;" > <div v-for="(item, index) of buttonTypes" :key="index" class="right-top-box" @click="handleClickButton(item.id)" > {{ item.text }} </div> </div> </bench-col> <!-- <div v-for="item of buttonTypes" :key="item.text" class="right-top-box" > <span> {{ item.text }} </span> </div> --> </el-col> </el-row> <div style="margin-top: 10px;" /> <el-row :gutter="10"> <el-col :span="8"> <bench-col icon="icon-book" title="计量数据" path-url="/lab/measureDataList" :style="{ height: blockHeight }" :height="blockHeight" > <el-table :data="reportData" :max-height="blockHeight - 60" 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 reportHead" :key="item.value" :prop="item.value" align="center" :label="item.text" :width="item.width" show-overflow-tooltip /> </el-table> </bench-col> </el-col> <el-col :span="8"> <bench-col icon="icon-timeTotal" title="实时工作统计" :style="{ height: blockHeight }" path-url="/board/jobAccount" :height="blockHeight" > <el-table :data="realTimeWorkStatisticsData" :max-height="blockHeight - 60" 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 realTimeWorkStatisticsHead" :key="item.value" :prop="item.value" align="center" :label="item.text" :width="item.width" show-overflow-tooltip > <template v-if="item.value === 'schedule'" #default="scope"> <el-progress :stroke-width="5" :percentage="scope.row.schedule" /> </template> </el-table-column> </el-table> </bench-col> </el-col> <el-col :span="8" :style="{ height: blockHeight }" :height="blockHeight"> <bench-col title="本月样品状态" icon="icon-status" :max-height="blockHeight - 60" style="width: 100%; height: 100%;" > <div class="status-box"> <div v-for="(item, index) in statusData" :key="index" class="status-box-item"> <div> {{ item.quantity }} </div> <div style="font-size: 12px;"> {{ item.status }} </div> <div class="status-box-bgc" /> </div> </div> </bench-col> </el-col> </el-row> </app-container> </template> <style lang="scss" scoped> .my-tests { width: 100%; display: flex; justify-content: space-between; } .status-box { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-around; height: 100%; .status-box-item { width: 40%; height: 8vh; display: flex; flex-direction: column; align-items: center; justify-content: space-around; text-align: center; .status-box-bgc { width: 50%; height: 5vh; background: url("../../../assets/images/bench/sampie-status.png") no-repeat center / cover; } } } .right-top-box { width: calc(33% - 20px); height: 20%; padding: 10px; margin: 5px; border-radius: 5px; white-space: nowrap; // 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; } } </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>