From 1202f64bfc569c3a0ff1344256ff5fee50c78ee4 Mon Sep 17 00:00:00 2001 From: caozehui <2427765068@qq.com> Date: Thu, 28 May 2026 08:44:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A3=80=E6=B5=8B=E8=AE=A1=E5=88=92=E7=BB=9F?= =?UTF-8?q?=E8=AE=A1=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/api/plan/interface/index.ts | 5 +- frontend/src/api/plan/plan.ts | 2 +- frontend/src/views/home/components/table.vue | 23 ++- frontend/src/views/home/components/tree.vue | 2 +- .../components/planStatisticsPopup.vue | 143 +++++++++++++++--- frontend/src/views/plan/planList/index.vue | 2 +- 6 files changed, 147 insertions(+), 30 deletions(-) diff --git a/frontend/src/api/plan/interface/index.ts b/frontend/src/api/plan/interface/index.ts index 4f5297e..0d14acd 100644 --- a/frontend/src/api/plan/interface/index.ts +++ b/frontend/src/api/plan/interface/index.ts @@ -72,10 +72,7 @@ export namespace Plan { export interface PlanStatisticsItem { itemId: string; itemName: string; - totalCount: number; - qualifiedCount: number; unqualifiedCount: number; - passRate: number; } export interface PlanStatistics { @@ -83,9 +80,11 @@ export namespace Plan { planName: string; totalCheckCount: number; checkedDeviceCount: number; + uncheckedDeviceCount: number; firstQualifiedDeviceCount: number; secondQualifiedDeviceCount: number; thirdOrMoreQualifiedDeviceCount: number; + qualifiedDeviceCount: number; unqualifiedDeviceCount: number; unqualifiedItemCount: number; firstPassRate: number; diff --git a/frontend/src/api/plan/plan.ts b/frontend/src/api/plan/plan.ts index 6177e9e..d1c583a 100644 --- a/frontend/src/api/plan/plan.ts +++ b/frontend/src/api/plan/plan.ts @@ -94,7 +94,7 @@ export const staticsAnalyse = (params: { id: string[] }) => { return http.download('/adPlan/analyse', params) } -export const getPlanStatistics = (params: { planId: string }) => { +export const getPlanStatistics = (params: { planId: string; manufacturer?: string; devType?: string }) => { return http.post(`/adPlan/statistics`, params) } diff --git a/frontend/src/views/home/components/table.vue b/frontend/src/views/home/components/table.vue index ab24414..6efd8fe 100644 --- a/frontend/src/views/home/components/table.vue +++ b/frontend/src/views/home/components/table.vue @@ -541,7 +541,6 @@ const columns = reactive[]>([ { prop: 'operation', label: '操作', fixed: 'right', minWidth :200,isShow: operationShow } ]) let testType = 'test' // 检测类型:'test'-检测 'reTest'-复检 -let qualifiedCount = 0 //合格数量 //比对单个报告生成 @@ -577,8 +576,6 @@ const handleSelectionChange = (selection: any[]) => { } else { testType = 'reTest' } - qualifiedCount=selection.filter(item => item.checkResult == 1).length - let devices: CheckData.Device[] = selection.map((item: any) => { return { deviceId: item.id, @@ -601,6 +598,19 @@ const handleSelectionChange = (selection: any[]) => { } } +const isUncheckedDevice = (device: Device.ResPqDev) => Number(device.checkState) === 0 || Number(device.checkResult) === 2 + +const hasCheckedSelectedDevice = () => channelsSelection.value.some(device => !isUncheckedDevice(device)) + +const hasUncheckedSelectedDevice = () => channelsSelection.value.some(device => isUncheckedDevice(device)) + +const hasCheckedUnqualifiedSelectedDevice = () => + channelsSelection.value.some(device => !isUncheckedDevice(device) && Number(device.checkResult) === 0) + +const shouldShowRecheckModeDialog = () => hasCheckedSelectedDevice() + +const canUseUnqualifiedItemRecheck = () => hasCheckedUnqualifiedSelectedDevice() && !hasUncheckedSelectedDevice() + //查询 const handleSearch = () => { proTable.value?.getTableList() @@ -925,12 +935,12 @@ const handleTest = async (val: string) => { dialogTitle.value = val if (val === '手动检测') { checkStore.setShowDetailType(2) - if (testType === 'reTest') { + if (shouldShowRecheckModeDialog()) { ElMessageBox.confirm('请选择复检检测方式', '设备复检', { distinguishCancelAndClose: true, confirmButtonText: '不合格项复检', cancelButtonText: '全部复检', - showConfirmButton:qualifiedCount<=0, + showConfirmButton: canUseUnqualifiedItemRecheck(), type: 'warning' }) .then(() => { @@ -965,11 +975,12 @@ const handleTest = async (val: string) => { checkStore.setCheckType(1) checkStore.initSelectTestItems() // 一键检测 - if (testType === 'reTest' && modeStore.currentMode != '比对式') { + if (shouldShowRecheckModeDialog() && modeStore.currentMode != '比对式') { ElMessageBox.confirm('请选择复检检测方式', '设备复检', { distinguishCancelAndClose: true, confirmButtonText: '不合格项复检', cancelButtonText: '全部复检', + showConfirmButton: canUseUnqualifiedItemRecheck(), type: 'warning' }) .then(() => { diff --git a/frontend/src/views/home/components/tree.vue b/frontend/src/views/home/components/tree.vue index bdad33a..a11f0d6 100644 --- a/frontend/src/views/home/components/tree.vue +++ b/frontend/src/views/home/components/tree.vue @@ -214,7 +214,7 @@ const childDetail = (data: Plan.ResPlan) => { } const isCompletedPlanNode = (data: Partial) => { - return Number(data.testState) === 2 + return [1, 2].includes(Number(data.testState)) } const openStatistics = (data: Partial) => { diff --git a/frontend/src/views/plan/planList/components/planStatisticsPopup.vue b/frontend/src/views/plan/planList/components/planStatisticsPopup.vue index 5d1ed9c..125fdac 100644 --- a/frontend/src/views/plan/planList/components/planStatisticsPopup.vue +++ b/frontend/src/views/plan/planList/components/planStatisticsPopup.vue @@ -11,8 +11,45 @@
@@ -53,16 +81,26 @@ import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue' import * as echarts from 'echarts' import { ElMessage } from 'element-plus' import { getPlanStatistics } from '@/api/plan/plan' +import { getPqDev } from '@/api/device/device' import type { Plan } from '@/api/plan/interface' +import type { Device } from '@/api/device/interface/device' +import { useDictStore } from '@/stores/modules/dict' + +interface SelectOption { + id: string + name: string +} const emptyStatistics = (): Plan.PlanStatistics => ({ planId: '', planName: '', totalCheckCount: 0, checkedDeviceCount: 0, + uncheckedDeviceCount: 0, firstQualifiedDeviceCount: 0, secondQualifiedDeviceCount: 0, thirdOrMoreQualifiedDeviceCount: 0, + qualifiedDeviceCount: 0, unqualifiedDeviceCount: 0, unqualifiedItemCount: 0, firstPassRate: 0, @@ -76,9 +114,17 @@ const dialogVisible = ref(false) const loading = ref(false) const loadFailed = ref(false) const planName = ref('') +const currentPlanId = ref('') const rateChartRef = ref() const itemChartRef = ref() const statisticsData = reactive(emptyStatistics()) +const filters = reactive({ + manufacturer: '', + devType: '' +}) +const dictStore = useDictStore() +const manufacturerOptions = computed(() => dictStore.getDictData('Dev_Manufacturers') as SelectOption[]) +const devTypeOptions = ref([]) let rateChart: echarts.ECharts | null = null let itemChart: echarts.ECharts | null = null @@ -92,13 +138,10 @@ const isEmpty = computed(() => { }) const summaryItems = computed(() => [ - { label: '总次数', value: statisticsData.totalCheckCount }, + { label: '未检设备', value: statisticsData.uncheckedDeviceCount }, { label: '已检设备', value: statisticsData.checkedDeviceCount }, - { label: '一次合格率', value: formatRate(statisticsData.firstPassRate) }, - { label: '二次合格率', value: formatRate(statisticsData.secondPassRate) }, - { label: '3次+合格率', value: formatRate(statisticsData.thirdOrMorePassRate) }, - { label: '不合格率', value: formatRate(statisticsData.unqualifiedRate) }, - { label: '不合格次数', value: statisticsData.unqualifiedItemCount } + { label: '合格设备', value: statisticsData.qualifiedDeviceCount, type: 'is-qualified' }, + { label: '不合格设备', value: statisticsData.unqualifiedDeviceCount, type: 'is-unqualified' } ]) const resetData = () => { @@ -124,12 +167,29 @@ const open = async (row: Partial) => { resetData() disposeCharts() loadFailed.value = false + currentPlanId.value = row.id + filters.manufacturer = '' + filters.devType = '' planName.value = row.name || '' dialogVisible.value = true + await loadFilterOptions() + await loadStatistics() +} + +const reloadStatistics = async () => { + if (!dialogVisible.value || !currentPlanId.value) return + await loadStatistics() +} + +const loadStatistics = async () => { loading.value = true try { - const { data } = await getPlanStatistics({ planId: row.id }) + const { data } = await getPlanStatistics({ + planId: currentPlanId.value, + manufacturer: filters.manufacturer || undefined, + devType: filters.devType || undefined + }) Object.assign(statisticsData, { ...emptyStatistics(), ...data, @@ -145,6 +205,19 @@ const open = async (row: Partial) => { } } +const loadFilterOptions = async () => { + if (devTypeOptions.value.length) return + try { + const { data } = await getPqDev() + devTypeOptions.value = ((data || []) as Device.ResDev[]).map(item => ({ + id: item.id, + name: item.name + })) + } catch (error) { + devTypeOptions.value = [] + } +} + const renderCharts = () => { if (!dialogVisible.value || loadFailed.value || isEmpty.value) return renderRateChart() @@ -247,6 +320,7 @@ const handleClosed = () => { disposeCharts() resetData() loadFailed.value = false + currentPlanId.value = '' } onMounted(() => { @@ -274,9 +348,20 @@ defineExpose({ open }) min-height: 0; } +.filter-bar { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-bottom: 12px; +} + +.filter-select { + width: 220px; +} + .summary-grid { display: grid; - grid-template-columns: repeat(7, minmax(0, 1fr)); + grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; margin-bottom: 12px; } @@ -305,6 +390,24 @@ defineExpose({ open }) line-height: 28px; } +.summary-item.is-qualified { + border-color: var(--el-color-success-light-5); + background: var(--el-color-success-light-9); +} + +.summary-item.is-qualified .summary-value { + color: var(--el-color-success); +} + +.summary-item.is-unqualified { + border-color: var(--el-color-danger-light-5); + background: var(--el-color-danger-light-9); +} + +.summary-item.is-unqualified .summary-value { + color: var(--el-color-danger); +} + .chart-grid { display: grid; grid-template-columns: 1fr 1fr; @@ -373,6 +476,10 @@ defineExpose({ open }) gap: 8px; } + .filter-select { + width: 100%; + } + .summary-item { padding: 10px; } diff --git a/frontend/src/views/plan/planList/index.vue b/frontend/src/views/plan/planList/index.vue index cc1fba9..e3c7160 100644 --- a/frontend/src/views/plan/planList/index.vue +++ b/frontend/src/views/plan/planList/index.vue @@ -104,7 +104,7 @@ v-auth.plan="'analysis'" link icon="PieChart" - v-if="scope.row.testState == '2' && modeStore.currentMode != '比对式'" + v-if="(scope.row.testState == '1' || scope.row.testState == '2') && modeStore.currentMode != '比对式'" @click="openStatistics(scope.row)" > 统计