Files
gongxue-base/apps/server/src/imports/imports.helpers.ts
wangziqi 7f09d5271e feat(imports): 导入向导兼容旧版工作簿并完善执行/预览
- 新增 xls 工作簿回退解析与测试
- 执行/预览/权限校验逻辑完善
2026-08-06 11:59:51 +08:00

96 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as ExcelJS from 'exceljs';
import type { CellValue } from './imports.types';
export function parseJson<T>(raw: string | null | undefined): T | null {
if (!raw) return null;
try {
return JSON.parse(raw) as T;
} catch {
return null;
}
}
export function textValue(value: CellValue): string {
if (value === null || value === undefined) return '';
return String(value).trim();
}
export function normalizeHeader(value: string): string {
return value
.trim()
.toLowerCase()
.replace(/[\s()]/g, '');
}
export function headerMatches(header: string, alias: string): boolean {
const h = normalizeHeader(header);
const a = normalizeHeader(alias);
if (!h || !a) return false;
return h === a || h.includes(a) || a.includes(h);
}
export function cellValue(cell: ExcelJS.Cell | undefined): CellValue {
if (!cell) return null;
const value = cell.value;
if (value === null || value === undefined) return null;
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
return value;
}
if (value instanceof Date) return value;
if (typeof value === 'object') {
const candidate = value as { text?: unknown; result?: unknown };
if (typeof candidate.text === 'string') return candidate.text;
if (typeof candidate.result === 'string' || typeof candidate.result === 'number') {
return candidate.result;
}
if (candidate.result instanceof Date) return candidate.result;
}
return null;
}
export function parseDateValue(value: CellValue): string | null {
if (value instanceof Date && !Number.isNaN(value.getTime())) {
const year = value.getFullYear();
const month = String(value.getMonth() + 1).padStart(2, '0');
const day = String(value.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
const raw = textValue(value);
if (!raw) return null;
const match = /^(\d{4})[-/](\d{1,2})[-/](\d{1,2})/.exec(raw);
if (!match) return null;
const year = Number(match[1]);
const month = Number(match[2]);
const day = Number(match[3]);
const date = new Date(Date.UTC(year, month - 1, day));
if (
date.getUTCFullYear() !== year ||
date.getUTCMonth() !== month - 1 ||
date.getUTCDate() !== day
) {
return null;
}
return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
}
export function safeError(error: unknown): string {
if (error instanceof Error) return error.message.slice(0, 120);
return '未知错误';
}
export function applyString(target: object, key: string, value: CellValue): void {
const text = textValue(value);
if (text) (target as Record<string, unknown>)[key] = text;
}
export function optionalNumber(value: CellValue): number | null {
const text = textValue(value);
if (!text) return null;
const parsed = Number(text);
return Number.isFinite(parsed) ? parsed : null;
}
export function csvCell(value: string): string {
return `"${value.replace(/"/g, '""')}"`;
}