yeg
2026-09-08 cfd4511378aefa04d4e06058cee628b6edd8e9c1
src/utils/compareReportPrint.ts
@@ -2,12 +2,12 @@
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])
@@ -42,45 +42,11 @@
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'
@@ -103,7 +69,7 @@
  </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>`