import type { StabilityAnalysisRow } from '#/api/x/lims/wendingxing';
|
|
import { formatDisplayNumber, formatPeriodUnit } from './stabilityAnalysis';
|
|
const MIME_TYPE = 'application/vnd.ms-excel;charset=utf-8' as const;
|
const HEADER_CELL_STYLE =
|
'border:1px solid rgb(0, 0, 0);background-color:rgb(38, 183, 255);color:rgb(255, 255, 255);font-weight:700;text-align:center;vertical-align:middle;white-space:nowrap;';
|
|
interface ExportColumn {
|
className?: string;
|
title: string;
|
value: (row: StabilityAnalysisRow, index: number) => string;
|
width: number;
|
}
|
|
export interface StabilityExportFile {
|
fileName: string;
|
html: string;
|
mimeType: typeof MIME_TYPE;
|
}
|
|
const columns: ExportColumn[] = [
|
{ title: '序号', value: (_row, index) => String(index), width: 8 },
|
{ className: 'text', title: '品名', value: (row) => row.yangpin_mingcheng, width: 18 },
|
{ className: 'text', title: '稳定性考察编号', value: (row) => row.jihua_bianhao, width: 28 },
|
{ className: 'text', title: '批号', value: (row) => row.pihao, width: 20 },
|
{ className: 'date', title: '录入日期', value: (row) => formatDate(row.jieguo_luru_riqi), width: 15 },
|
{ title: '考察周期', value: (row) => formatPeriod(row.zhouqi), width: 12 },
|
{ className: 'text', title: '周期单位', value: (row) => formatExportPeriodUnit(row.zhouqi, row.zhouqi_danwei), width: 12 },
|
{ className: 'text', title: '项目名称', value: (row) => row.xiangmu_mingcheng, width: 20 },
|
{ className: 'text', title: '数据', value: (row) => row.raw_result, width: 14 },
|
{ className: 'text', title: '上限', value: (row) => row.shangxian, width: 12 },
|
{ className: 'text', title: '下限', value: (row) => row.xiaxian, width: 12 },
|
{ className: 'text', title: '单位', value: (row) => row.unit, width: 12 },
|
];
|
|
export function buildStabilityExport(rows: StabilityAnalysisRow[], now = new Date()): StabilityExportFile {
|
const columnMarkup = columns.map((column) => `<col style="width:${column.width}ch">`).join('');
|
const headerMarkup = columns.map((column) => `<td style="${HEADER_CELL_STYLE}">${escapeHtml(column.title)}</td>`).join('');
|
const bodyMarkup = rows
|
.map(
|
(row, index) =>
|
`<tr>${columns
|
.map((column) => `<td${column.className ? ` class="${column.className}"` : ''}>${escapeHtml(column.value(row, index) || '')}</td>`)
|
.join('')}</tr>`,
|
)
|
.join('');
|
|
return {
|
fileName: `稳定性数据分析表_${formatTimestamp(now)}.xls`,
|
html: `<!DOCTYPE html>
|
<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">
|
<head>
|
<meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8">
|
<!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>稳定性数据分析表</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->
|
<style>
|
table { border-collapse: collapse; table-layout: fixed; }
|
td { height: 26px; padding: 4px 8px; border: 1px solid #000; font-family: "Microsoft YaHei", sans-serif; font-size: 11pt; text-align: center; vertical-align: middle; white-space: nowrap; }
|
td.text { mso-number-format: "\\@"; }
|
td.date { mso-number-format: "yyyy\\-mm\\-dd"; }
|
</style>
|
</head>
|
<body>
|
<table>${columnMarkup}<tbody><tr>${headerMarkup}</tr>${bodyMarkup}</tbody></table>
|
</body>
|
</html>`,
|
mimeType: MIME_TYPE,
|
};
|
}
|
|
export function downloadStabilityExport(rows: StabilityAnalysisRow[], now = new Date()) {
|
const file = buildStabilityExport(rows, now);
|
const url = URL.createObjectURL(new Blob([`\uFEFF${file.html}`], { type: file.mimeType }));
|
const anchor = document.createElement('a');
|
anchor.download = file.fileName;
|
anchor.href = url;
|
anchor.style.display = 'none';
|
document.body.append(anchor);
|
try {
|
anchor.click();
|
} finally {
|
anchor.remove();
|
URL.revokeObjectURL(url);
|
}
|
}
|
|
function escapeHtml(value: string) {
|
return String(value ?? '')
|
.replaceAll('&', '&')
|
.replaceAll('<', '<')
|
.replaceAll('>', '>')
|
.replaceAll('"', '"')
|
.replaceAll("'", ''');
|
}
|
|
function formatDate(value: string) {
|
return String(value ?? '').match(/\d{4}-\d{2}-\d{2}/)?.[0] || String(value ?? '');
|
}
|
|
function formatExportPeriodUnit(period: string, unit: string) {
|
return Number(period) === 0 ? '/' : formatPeriodUnit(unit);
|
}
|
|
function formatPeriod(value: string) {
|
const normalized = String(value ?? '').trim();
|
return normalized ? formatDisplayNumber(normalized) : '';
|
}
|
|
function formatTimestamp(value: Date) {
|
return [value.getFullYear(), pad(value.getMonth() + 1), pad(value.getDate()), pad(value.getHours()), pad(value.getMinutes()), pad(value.getSeconds())].join(
|
'',
|
);
|
}
|
|
function pad(value: number) {
|
return String(value).padStart(2, '0');
|
}
|