| | |
| | | import { compareSelectionKey, createCompareReport, editCompareReport, getCompareReport, getCompareSources, previewCompareReport, refreshCompareSource, |
| | | type CompareCandidate, type CompareItem, type SavedCompareReport } from '@/api/compareReports' |
| | | import { compareMetricDefinitions as metricDefinitions, openCompareReportPrint } from '@/utils/compareReportPrint' |
| | | import { compareChartOption } from '@/utils/compareReportChart' |
| | | import { compareChartOption, compareSeriesName } from '@/utils/compareReportChart' |
| | | import { compareDetailSources } from '@/utils/compareSourceDetails' |
| | | import ReportTestDetail from '@/components/ReportTestDetail.vue' |
| | | import { reportDetailColumn, snapshotReportDetails } from '@/utils/reportTestDetails' |
| | |
| | | const changeSummary = ref('') |
| | | const loadError = ref('') |
| | | const previewLoading = ref(false) |
| | | let previewRequest = 0 |
| | | const previewError = ref('') |
| | | const reportLoading = ref(false) |
| | | const saving = ref(false) |
| | |
| | | }, { immediate: true }) |
| | | |
| | | async function refreshPreview() { |
| | | const current = ++previewRequest |
| | | const selections = selectedTests.value.map(item => item.selection) |
| | | previewLoading.value = true |
| | | previewError.value = '' |
| | | sourceItems.value = [] |
| | | try { |
| | | const items = await previewCompareReport(selections) |
| | | if (editingId.value) return |
| | | if (editingId.value || current !== previewRequest) return |
| | | sourceItems.value = items |
| | | } catch (error) { previewError.value = error instanceof Error ? error.message : '曲线预览失败' } |
| | | finally { previewLoading.value = false } |
| | | } catch (error) { if (current === previewRequest) previewError.value = error instanceof Error ? error.message : '曲线预览失败' } |
| | | finally { if (current === previewRequest) previewLoading.value = false } |
| | | } |
| | | |
| | | function openAddTest() { |
| | | void loadCandidates() |
| | | selectedCandidateId.value = null |
| | | selectedBatteryNo.value = '' |
| | | selectedCycle.value = null |
| | |
| | | <div v-if="chartSeries.length" class="chart-legend-bar"><strong>对比图例</strong><div v-for="(item, index) in chartSeries" :key="compareSelectionKey(item.selection)" class="chart-legend-item"><el-color-picker v-if="!readonly" class="legend-color-picker" :model-value="seriesColors[index]" :show-alpha="false" popper-class="legend-color-popper" :aria-label="`修改${item.name}颜色`" @change="updateSeriesColor(index, $event)" /><i v-else class="series-swatch" :style="{ background: seriesColors[index] }" /><button type="button" class="legend-name" :class="{ 'is-hidden': hiddenSeriesKeys.includes(compareSelectionKey(item.selection)) }" :aria-pressed="!hiddenSeriesKeys.includes(compareSelectionKey(item.selection))" :disabled="readonly" @click="toggleSeries(item)">{{ item.name }} (#{{ item.id }}) · {{ item.batteryGroup }} · {{ item.batteryNo }} · 循环{{ item.cycle }} · {{ item.process }}</button></div></div> |
| | | <!-- 报表切换和比对项移除时完整替换配置,避免图表库将颜色数组缩短误判为组件合并。 --> |
| | | <div v-if="!visibleMetrics.length" class="chart-empty">当前未启用曲线指标</div> |
| | | <div class="charts-grid"><article v-for="metric in visibleMetrics" :key="metric.key" class="chart-card"><header><strong>{{ metric.title }}</strong></header><VChart class="metric-chart" :option="compareChartOption(metric, sourceItems, seriesColors, hiddenSeriesKeys)" :update-options="{ notMerge: true }" autoresize /><div v-if="!sourceItems.some(item => !hiddenSeriesKeys.includes(compareSelectionKey(item.source.selection)) && item.records.some(row => (metric.key === 'voltage' || metric.key === 'current' ? row.deviceTime : row.collectorDeviceTime) != null && (metric.key === 'positiveVoltage' ? row.positivePotential : metric.key === 'negativeVoltage' ? row.negativePotential : row[metric.key]) != null))" class="chart-empty">{{ sourceItems.length && hiddenSeriesKeys.length === sourceItems.length ? '当前全部曲线已隐藏' : '所选范围暂无该指标数据' }}</div></article></div> |
| | | <div class="charts-grid"><article v-for="metric in visibleMetrics" :key="metric.key" class="chart-card"><header><strong>{{ metric.title }}</strong></header><VChart class="metric-chart" :option="compareChartOption(metric, sourceItems, seriesColors, hiddenSeriesKeys)" :update-options="{ notMerge: true }" autoresize @legendselectchanged="!readonly && (hiddenSeriesKeys = sourceItems.filter(item => !$event.selected[compareSeriesName(item)]).map(item => compareSelectionKey(item.source.selection)))" /><div v-if="!sourceItems.some(item => !hiddenSeriesKeys.includes(compareSelectionKey(item.source.selection)) && item.records.some(row => (metric.key === 'voltage' || metric.key === 'current' ? row.deviceTime : row.collectorDeviceTime) != null && (metric.key === 'positiveVoltage' ? row.positivePotential : metric.key === 'negativeVoltage' ? row.negativePotential : row[metric.key]) != null))" class="chart-empty">{{ sourceItems.length && hiddenSeriesKeys.length === sourceItems.length ? '当前全部曲线已隐藏' : '所选范围暂无该指标数据' }}</div></article></div> |
| | | </section> |
| | | |
| | | <footer class="form-actions"> |
| | |
| | | .chart-card { min-width: 0; border: 1px solid #edf1f5; background: #fff; } |
| | | .chart-card header { height: 38px; display: flex; align-items: center; gap: 18px; padding: 0 14px; color: #52606d; font-size: 11px; } |
| | | .chart-card header strong { margin-right: auto; color: #26333f; font-size: 13px; } |
| | | .metric-chart { width: 100%; height: 210px; } |
| | | .metric-chart { width: 100%; height: 230px; } |
| | | .form-actions { position: sticky; bottom: 0; z-index: 20; min-height: 62px; display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 10px; margin-top: 16px; padding: 10px 16px; background: rgba(234, 240, 246, .96); border-top: 1px solid #cbd9e5; } |
| | | .form-actions .primary-button, .form-actions .secondary-button { min-width: 110px; } |
| | | .save-button { min-width: 110px; } |