chore: 优化图表
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ const props = defineProps<{
|
||||
|
||||
const chartRef = ref<HTMLDivElement>()
|
||||
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
|
||||
})
|
||||
|
||||
@@ -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<string>()
|
||||
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
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
+16
-7
@@ -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<string>()
|
||||
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
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user