| | |
| | | import { LineChart } from 'echarts/charts' |
| | | import { GridComponent } from 'echarts/components' |
| | | import { SVGRenderer } from 'echarts/renderers' |
| | | import { compareSelectionKey, getComparePrintVersion, type CompareItem, type SavedCompareReport } from '@/api/compareReports' |
| | | import { compareSelectionKey, getComparePrintVersion, type SavedCompareReport } from '@/api/compareReports' |
| | | import type { CompareMetricKey } from '@/stores/compareReports' |
| | | import { compareChartOption, compareSeriesName } from './compareReportChart' |
| | | import { compareFields, compareFieldLabel, compareBusinessFieldValue } from './compareReportFields' |
| | | import { openSavedReportPrint } from './savedReportPrint' |
| | | import { compareSourceKey, compareDetailSources, compareSourceFields, compareSourceValue, compareHasRangeDetailValues } from './compareSourceDetails' |
| | | import { compareDetailSources } from './compareSourceDetails' |
| | | import { reportDetailColumn, reportDetailsHtml } from './reportTestDetails' |
| | | |
| | | use([LineChart, GridComponent, SVGRenderer]) |
| | | |
| | |
| | | |
| | | function printHtml(record: SavedCompareReport) { |
| | | const cell = (value: unknown) => `<td>${escapeHtml(value === '' || value == null ? '-' : value)}</td>` |
| | | const fields = compareFields(record.settings) |
| | | const showSource = record.settings.sourceDetailOverrides !== undefined |
| | | const bySource = !compareHasRangeDetailValues(record.settings) |
| | | const detailSources = bySource ? compareDetailSources(record.items) : record.items.map(item => item.source) |
| | | const sources = compareDetailSources(record.items) |
| | | const sourceFields = compareSourceFields(sources, record.settings.sourceDetailOverrides) |
| | | const detailTables = reportDetailsHtml(compareDetailSources(record.items).map(reportDetailColumn), record.settings.sourceDetailOverrides) |
| | | const compareRows = record.items.map(item => { |
| | | const source = item.source |
| | | return `<tr>${[source.name, source.type, source.batteryGroup, source.batteryNo, source.process, source.selection.cycleNo].map(cell).join('')}</tr>` |
| | | }).join('') |
| | | const fieldValue = (field: typeof fields[number], item: CompareItem) => { |
| | | const value = record.settings.detailFieldValues[field.name]?.[bySource ? compareSourceKey(item.source) : compareSelectionKey(item.source.selection)] |
| | | // 与重开表单相同:未填写才使用冻结业务字段,显式清空仍为空。 |
| | | return value === undefined ? compareBusinessFieldValue(field, item) : value |
| | | } |
| | | // 横向每组最多四项,所有组顺序输出,长表可跨页并重复列头。 |
| | | const detailTables: string[] = [] |
| | | if (showSource) for (let start = 0; start < sources.length; start += 4) { |
| | | const columns = sources.slice(start, start + 4) |
| | | const rows = [ |
| | | ['测试', ...columns.map(source => source.name)], |
| | | ['电池组', ...columns.map(source => source.batteryGroup)], |
| | | ['电池号', ...columns.map(source => source.batteryNo)], |
| | | ['实验', ...columns.map(source => compareSourceValue(source, record.settings.sourceDetailOverrides))], |
| | | ...sourceFields.map(field => [`${field.name}(${field.category === 'battery' ? '电池组详情' : '特殊详情'})`, ...columns.map(source => compareSourceValue(source, record.settings.sourceDetailOverrides, field))]), |
| | | ] |
| | | detailTables.push(`<table class="detail-table source-detail-table"><thead><tr><th>字段</th>${columns.map((_, index) => `<th>来源电池 ${start + index + 1}</th>`).join('')}</tr></thead><tbody>${rows.map(row => `<tr>${row.map(cell).join('')}</tr>`).join('')}</tbody></table>`) |
| | | } |
| | | for (let start = 0; (fields.length || !showSource) && start < detailSources.length; start += 4) { |
| | | const items = detailSources.slice(start, start + 4).map(source => record.items.find(item => compareSelectionKey(item.source.selection) === compareSelectionKey(source.selection))!) |
| | | const rows = [ |
| | | ['测试', ...items.map(item => item.source.name)], |
| | | ['电池组', ...items.map(item => item.source.batteryGroup)], |
| | | ['电池号', ...items.map(item => item.source.batteryNo)], |
| | | ...(!bySource ? [['循环 / 工步', ...items.map(item => `${item.source.selection.cycleNo} / ${item.source.process}`)]] : []), |
| | | ...fields.map(field => [compareFieldLabel(field), ...items.map(item => fieldValue(field, item))]), |
| | | ] |
| | | detailTables.push(`<table class="detail-table"><thead><tr><th>字段</th>${items.map((_, index) => `<th>${bySource ? '来源电池' : '对比项'} ${start + index + 1}</th>`).join('')}</tr></thead><tbody>${rows.map(row => `<tr>${row.map(cell).join('')}</tr>`).join('')}</tbody></table>`) |
| | | } |
| | | const legend = record.items.map((item, index) => { |
| | | const color = record.settings.seriesColors[index % record.settings.seriesColors.length] |
| | | const safeColor = color && /^#[0-9a-f]{6}$/i.test(color) ? color : '#52606d' |
| | |
| | | </style></head><body> |
| | | <header class="report-header"><div><h1>${escapeHtml(record.name)}</h1><p>检测室数据可视化系统 · 对比报表</p></div><div class="saved-meta"><span>报表ID <strong>#${record.id}</strong></span><span>版本 <strong>V${record.versionNo}</strong></span><span>创建人 <strong>${escapeHtml(record.creator)}</strong></span><span>创建时间 <strong>${date(record.createdAt)}</strong></span><span>版本操作人 <strong>${escapeHtml(record.operatorName)}</strong></span><span>版本时间 <strong>${date(record.versionCreatedAt)}</strong></span><span>修改说明 <strong>${escapeHtml(record.changeSummary)}</strong></span></div></header> |
| | | <section class="section"><h2 class="section-title">对比信息</h2><table class="compare-table"><thead><tr><th>测试名称</th><th>测试类型</th><th>电池组</th><th>电池号</th><th>工步</th><th>循环</th></tr></thead><tbody>${compareRows}</tbody></table></section> |
| | | <section class="section"><h2 class="section-title">测试详情</h2>${!showSource || record.experimentName ? `<div class="experiment">实验<strong>${escapeHtml(record.experimentName || '-')}</strong></div>` : ''}${detailTables.join('')}</section> |
| | | <section class="section"><h2 class="section-title">测试详情</h2>${detailTables}</section> |
| | | <section class="section"><h2 class="section-title">对比曲线</h2><div class="legend">${legend}</div><div class="charts">${charts || '<div class="empty">当前未启用曲线指标</div>'}</div></section> |
| | | <section class="section"><h2 class="section-title">报表说明</h2><div class="note">${escapeHtml(record.description || '-')}</div></section> |
| | | </body></html>` |