feat: 新增通用导入中心

This commit is contained in:
2026-08-05 17:11:39 +08:00
parent e9c8a1085d
commit 0c94ca54df
20 changed files with 3355 additions and 0 deletions

View File

@@ -0,0 +1,92 @@
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())) {
return value.toISOString().slice(0, 10);
}
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, '""')}"`;
}