From b951f17658816e483219ff5b8651eb5df35aad25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=A4=A9=E9=AA=84?= <5307576@qq.com> Date: Wed, 17 Jun 2026 10:25:23 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E4=BC=98=E5=8C=96=E5=9B=BE=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/styles/main.scss | 29 ++++++++++++++++++++++++++--- src/components/ChartPanel.vue | 7 +++++++ src/views/AiCaseGenerateView.vue | 23 ++++++++++++++++------- src/views/CasesView.vue | 23 ++++++++++++++++------- 4 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/assets/styles/main.scss b/src/assets/styles/main.scss index df2a7ba3..d3ec047b 100644 --- a/src/assets/styles/main.scss +++ b/src/assets/styles/main.scss @@ -596,13 +596,25 @@ p { } .overview-grid { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); + display: flex; + flex-wrap: wrap; + align-items: stretch; gap: 18px; } +.overview-grid > .chart-panel, +.overview-grid > .data-section, +.overview-grid > .stats-grid { + flex: 1 1 calc(33.333% - 12px); + min-width: min(100%, 280px); +} + .wide-chart { - grid-column: span 2; + flex-basis: calc(66.666% - 6px); +} + +.full-width-panel { + flex-basis: 100%; } .tall-chart { @@ -1149,3 +1161,14 @@ p { grid-template-columns: 1fr; } } + +@media (max-width: 768px) { + .overview-grid > .chart-panel, + .overview-grid > .data-section, + .overview-grid > .stats-grid, + .wide-chart, + .full-width-panel { + flex-basis: 100%; + min-width: 0; + } +} diff --git a/src/components/ChartPanel.vue b/src/components/ChartPanel.vue index e9b1889f..4335a723 100644 --- a/src/components/ChartPanel.vue +++ b/src/components/ChartPanel.vue @@ -24,6 +24,7 @@ const props = defineProps<{ const chartRef = ref() let chart: echarts.ECharts | null = null +let resizeObserver: ResizeObserver | null = null const renderOption = computed(() => normalizeChartOption(props.option)) @@ -47,11 +48,17 @@ watch(renderOption, renderChart, { deep: true }) onMounted(() => { renderChart() + if (chartRef.value && 'ResizeObserver' in window) { + resizeObserver = new ResizeObserver(handleResize) + resizeObserver.observe(chartRef.value) + } window.addEventListener('resize', handleResize) }) onBeforeUnmount(() => { window.removeEventListener('resize', handleResize) + resizeObserver?.disconnect() + resizeObserver = null chart?.dispose() chart = null }) diff --git a/src/views/AiCaseGenerateView.vue b/src/views/AiCaseGenerateView.vue index 2f33483f..1abc714a 100644 --- a/src/views/AiCaseGenerateView.vue +++ b/src/views/AiCaseGenerateView.vue @@ -256,6 +256,13 @@ interface ExamItemForm { result_text: string } +const examItemFields: Array<{ key: keyof ExamItemForm; label: string }> = [ + { key: 'item_code', label: '项目编码' }, + { key: 'item_name', label: '项目名称' }, + { key: 'item_type', label: '项目类型' }, + { key: 'result_text', label: '结果文本' } +] + interface CaseDraftForm { title: string case_type: DraftCaseType @@ -552,18 +559,20 @@ function createDefaultScoringRule(): CaseScoringRulePayload { function normalizeExamItems(): CaseExamItemPayload[] { const items = draftForm.exam_items - .map(item => ({ + .map((item, index) => ({ + index, item_code: item.item_code.trim(), item_name: item.item_name.trim(), item_type: item.item_type.trim(), result_text: item.result_text.trim() })) - .filter(item => item.item_code || item.item_name || item.item_type || item.result_text) + .filter(item => examItemFields.some(({ key }) => item[key])) const codes = new Set() for (const item of items) { - if (!item.item_code) { - throw new Error('检查/检验项目编码必填') + const missingLabels = examItemFields.filter(({ key }) => !item[key]).map(({ label }) => label) + if (missingLabels.length) { + throw new Error(`第${item.index + 1}个检查/检验项目需完整填写,缺少:${missingLabels.join('、')}`) } if (codes.has(item.item_code)) { throw new Error(`检查/检验项目编码重复:${item.item_code}`) @@ -573,9 +582,9 @@ function normalizeExamItems(): CaseExamItemPayload[] { return items.map(item => ({ item_code: item.item_code, - ...(item.item_name ? { item_name: item.item_name } : {}), - ...(item.item_type ? { item_type: item.item_type } : {}), - ...(item.result_text ? { result_text: item.result_text } : {}) + item_name: item.item_name, + item_type: item.item_type, + result_text: item.result_text })) } diff --git a/src/views/CasesView.vue b/src/views/CasesView.vue index 8eef782e..40e0dd62 100644 --- a/src/views/CasesView.vue +++ b/src/views/CasesView.vue @@ -634,6 +634,13 @@ interface ExamItemForm { result_text: string } +const examItemFields: Array<{ key: keyof ExamItemForm; label: string }> = [ + { key: 'item_code', label: '项目编码' }, + { key: 'item_name', label: '项目名称' }, + { key: 'item_type', label: '项目类型' }, + { key: 'result_text', label: '结果文本' } +] + interface CaseDraftForm { title: string case_type: DraftCaseType @@ -1201,18 +1208,20 @@ function createDefaultScoringRule(form: CaseDraftForm): CaseScoringRulePayload { function normalizeExamItems(form: CaseDraftForm): CaseExamItemPayload[] { const items = form.exam_items - .map(item => ({ + .map((item, index) => ({ + index, item_code: item.item_code.trim(), item_name: item.item_name.trim(), item_type: item.item_type.trim(), result_text: item.result_text.trim() })) - .filter(item => item.item_code || item.item_name || item.item_type || item.result_text) + .filter(item => examItemFields.some(({ key }) => item[key])) const codes = new Set() for (const item of items) { - if (!item.item_code) { - throw new Error('检查/检验项目编码必填') + const missingLabels = examItemFields.filter(({ key }) => !item[key]).map(({ label }) => label) + if (missingLabels.length) { + throw new Error(`第${item.index + 1}个检查/检验项目需完整填写,缺少:${missingLabels.join('、')}`) } if (codes.has(item.item_code)) { throw new Error(`检查/检验项目编码重复:${item.item_code}`) @@ -1222,9 +1231,9 @@ function normalizeExamItems(form: CaseDraftForm): CaseExamItemPayload[] { return items.map(item => ({ item_code: item.item_code, - ...(item.item_name ? { item_name: item.item_name } : {}), - ...(item.item_type ? { item_type: item.item_type } : {}), - ...(item.result_text ? { result_text: item.result_text } : {}) + item_name: item.item_name, + item_type: item.item_type, + result_text: item.result_text })) }