feat: Excel 导入预检与动态问答,AI 聊天/文件解析体验修复
- imports: 新增 preflight_import 预检报告(判定/分阶段统计/阻断归因/问题/下一步/错误示例),导入任务 settings 落库(映射/校区/更新/重复/未匹配策略),预览应用策略,向导提交写操作日志 - ai-chat: 新增 excel_analyze(ExcelJS)工具,移除附件/上下文截断,start_import_wizard 支持确认参数,ui.import_preflight SSE,预览确认写操作日志 - admin: ImportPreflightCard 渲染与持久化,聊天抽屉布局/侧边栏修复,考勤页 CSS 引入,费用/学生页接口 schema 校验修复
This commit is contained in:
@@ -8,6 +8,7 @@ import { IMPORT_STEP_LABELS } from './imports.types';
|
||||
import type {
|
||||
CellValue,
|
||||
ColumnMapping,
|
||||
ImportRunSettings,
|
||||
ImportStepKey,
|
||||
StepPreviewSummary,
|
||||
} from './imports.types';
|
||||
@@ -16,6 +17,7 @@ import { assertMapping, suggestMapping } from './imports.mapping';
|
||||
import { buildLookups } from './imports.lookups';
|
||||
import { validateRow } from './imports.rows';
|
||||
import type { ImportBatchState } from './imports.rows';
|
||||
import { applyPreviewPolicies } from './imports.policies';
|
||||
import { findOwnedRun, findStep } from './imports.access';
|
||||
import type { ImportPrincipal } from './imports.access';
|
||||
|
||||
@@ -55,6 +57,7 @@ export class ImportPreviewService {
|
||||
const sheetsData =
|
||||
parseJson<Array<{ name: string; headers: string[]; rows: CellValue[][] }>>(run.sheetsJson) ??
|
||||
[];
|
||||
const settings = parseJson<ImportRunSettings>(run.settingsJson) ?? {};
|
||||
const sheetNames = body.sheets?.length
|
||||
? body.sheets
|
||||
: (parseJson<string[]>(step.sheetsJson) ?? []);
|
||||
@@ -106,20 +109,22 @@ export class ImportPreviewService {
|
||||
fields[field] = rawValues[sheet.headers.indexOf(header)] ?? null;
|
||||
}
|
||||
const result = validateRow(stepKey, fields, lookups, batchState);
|
||||
const policy = applyPreviewPolicies(result, settings);
|
||||
const normalized = { ...result.normalized, ...result.resolvedIds };
|
||||
summary.total += 1;
|
||||
if (result.errors.length > 0) {
|
||||
if (policy.status === 'error') {
|
||||
summary.error += 1;
|
||||
} else {
|
||||
summary.valid += 1;
|
||||
if (result.action === 'create') summary.create += 1;
|
||||
if (result.action === 'update') summary.update += 1;
|
||||
if (result.action === 'create') {
|
||||
const studentId = result.resolvedIds._studentId;
|
||||
if (studentId !== undefined) {
|
||||
if (stepKey === 'checkins') batchState.checkinStudentIds.add(studentId);
|
||||
if (stepKey === 'transfers') batchState.transferStudentIds.add(studentId);
|
||||
}
|
||||
if (policy.action === 'create') summary.create += 1;
|
||||
if (policy.action === 'update') summary.update += 1;
|
||||
if (policy.action === 'skip') summary.skip += 1;
|
||||
}
|
||||
if (policy.status === 'valid' && policy.action === 'create') {
|
||||
const studentId = result.resolvedIds._studentId;
|
||||
if (studentId !== undefined) {
|
||||
if (stepKey === 'checkins') batchState.checkinStudentIds.add(studentId);
|
||||
if (stepKey === 'transfers') batchState.transferStudentIds.add(studentId);
|
||||
}
|
||||
}
|
||||
rowEntities.push(
|
||||
@@ -131,9 +136,9 @@ export class ImportPreviewService {
|
||||
rawJson: JSON.stringify(raw),
|
||||
normalizedJson: JSON.stringify(normalized),
|
||||
matchKey: result.matchKey,
|
||||
action: result.action,
|
||||
status: result.errors.length > 0 ? 'error' : 'valid',
|
||||
errorsJson: result.errors.length > 0 ? JSON.stringify(result.errors) : null,
|
||||
action: policy.action,
|
||||
status: policy.status,
|
||||
errorsJson: policy.errors.length > 0 ? JSON.stringify(policy.errors) : null,
|
||||
targetId: result.targetId ?? null,
|
||||
}),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user