刘光辉
6 小时以前 cf11e63b659afcc9792ab3e395f1b45d844431a8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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;
}