import type { AuditEventListDTO, AuditOperation, AuditPageQuery } from './types';
|
|
const actionCodeLabels: Record<string, string> = {
|
CREATE: '新增',
|
DELETE: '删除',
|
PRINT: '发起打印',
|
READ: '查询',
|
SIGN: '电子签名',
|
UPDATE: '修改',
|
};
|
|
const eventTypeLabels: Record<string, string> = {
|
BIZ_ACTION: '业务动作',
|
DATA_CHANGE: '数据变更',
|
E_SIGNATURE: '电子签名',
|
PRINT: '打印日志',
|
};
|
|
const sourceLayerLabels: Record<number, string> = {
|
0: '在线表单',
|
1: '数据库变更',
|
2: '业务动作',
|
3: '电子签名',
|
};
|
|
/** Normalize one BUSINESS row and its related physical signature events. */
|
export function normalizeOperation(main: AuditEventListDTO): AuditOperation {
|
const subEvents = Array.isArray(main.subEvents) ? main.subEvents : [];
|
const eventIds = [main.id, ...subEvents.map((event) => event.id)];
|
const layers = [...new Set([main, ...subEvents].flatMap((event) => (typeof event.sourceLayer === 'number' ? [event.sourceLayer] : [])))];
|
const diffCount = toDiffCount(main.diffCount);
|
const hasElectronicSignature = main.eventType === 'E_SIGNATURE' || subEvents.some((event) => event.eventType === 'E_SIGNATURE');
|
|
return {
|
...main,
|
correlationKey: main.operationId ?? main.clientEventId ?? `event:${main.id}`,
|
diffCount,
|
eventIds,
|
layers,
|
sourceSummary: getSourceSummary(layers, diffCount, main.eventType, hasElectronicSignature),
|
subEvents,
|
};
|
}
|
|
/** Timeline uses the same operation-level display contract as the page endpoint. */
|
export function groupTimelineOperations(events: AuditEventListDTO[]): AuditOperation[] {
|
return events.map((event) => normalizeOperation(event));
|
}
|
|
/**
|
* 动作名优先按 actionCode 映射:层 0 的基础三动作有稳定语义,映射后历史数据
|
* (actionLabel 是 "LIMS-请验单 新建" 这种旧格式)也立刻显示对。
|
* 层 2 事件的动作词是业务自定义的("请验单 撤回"),映射表命不中,回落 actionLabel。
|
*/
|
export function getAuditActionLabel(event: Pick<AuditEventListDTO, 'actionCode' | 'actionLabel' | 'bizType'>): string {
|
if (event.bizType === 'DMS_FOLDER' && event.actionLabel) return event.actionLabel;
|
const mapped = event.actionCode ? actionCodeLabels[event.actionCode] : undefined;
|
return mapped || event.actionLabel || event.actionCode || '未标记操作';
|
}
|
|
export function getAuditEventTypeLabel(eventType?: string): string {
|
if (!eventType) return '未标记类型';
|
return eventTypeLabels[eventType] || eventType;
|
}
|
|
export function getSourceLayerLabel(sourceLayer?: number, eventType?: string): string {
|
if (eventType === 'PRINT') return '打印日志';
|
if (sourceLayer === 3 && eventType !== 'E_SIGNATURE') return '业务埋点';
|
if (sourceLayer === undefined) return '未知来源';
|
return sourceLayerLabels[sourceLayer] || `采集层 ${sourceLayer}`;
|
}
|
|
export function getSourceSummary(layers: number[], diffCount: number, eventType?: string, hasElectronicSignature = eventType === 'E_SIGNATURE'): string {
|
if (eventType === 'PRINT') return '打印日志';
|
const hasBusinessAction = layers.includes(2);
|
if (hasBusinessAction) {
|
return ['业务动作', hasElectronicSignature ? '电子签名' : '', diffCount > 0 ? '字段变更' : ''].filter(Boolean).join(' + ');
|
}
|
if (hasElectronicSignature && diffCount > 0) return '电子签名 + 字段变更';
|
if (hasElectronicSignature) return '电子签名';
|
if (layers.includes(3) && diffCount > 0) return '业务埋点 + 字段变更';
|
if (layers.includes(3)) return '业务埋点';
|
if (layers.length === 1 && layers[0] === 0) return '在线表单';
|
if (layers.length === 1 && layers[0] === 1) return '数据库变更';
|
if (layers.includes(0) && layers.includes(1)) return '在线表单 + 数据库变更';
|
return '未知来源';
|
}
|
|
export interface PrintAuditTarget {
|
bizCode?: string;
|
id: string;
|
title?: string;
|
}
|
|
export function parsePrintAuditTargets(extra?: string): { parseError: boolean; targets: PrintAuditTarget[] } {
|
if (!extra) return { parseError: false, targets: [] };
|
try {
|
const parsed = JSON.parse(extra);
|
if (!Array.isArray(parsed?.printTargets)) return { parseError: false, targets: [] };
|
const targets = parsed.printTargets.flatMap((item: unknown) => {
|
if (!item || typeof item !== 'object') return [];
|
const raw = item as Record<string, unknown>;
|
const id = toOptionalText(raw.id);
|
if (!id) return [];
|
return [{ id, bizCode: toOptionalText(raw.bizCode), title: toOptionalText(raw.title) }];
|
});
|
return { parseError: false, targets };
|
} catch {
|
return { parseError: true, targets: [] };
|
}
|
}
|
|
export function normalizeAuditPageQuery(query: Record<string, unknown>): AuditPageQuery {
|
const normalized: Record<string, unknown> = {};
|
for (const [key, value] of Object.entries(query)) {
|
const nextValue = typeof value === 'string' ? value.trim() : value;
|
if (nextValue !== '' && nextValue !== undefined && nextValue !== null) normalized[key] = nextValue;
|
}
|
return normalized as unknown as AuditPageQuery;
|
}
|
|
function toDiffCount(value?: number): number {
|
return Number.isFinite(value) && Number(value) > 0 ? Number(value) : 0;
|
}
|
|
function toOptionalText(value: unknown): string | undefined {
|
if (value === undefined || value === null) return;
|
const text = String(value).trim();
|
return text || undefined;
|
}
|