gaoluyang
16 小时以前 6f35f9dc767e99ad701f7f6e2f5d4c52b6cc1d0f
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
import type { VNodeChild } from 'vue';
 
import { h } from 'vue';
 
import { message, notification } from 'ant-design-vue';
 
export interface ImportResultNotifyOptions {
  /** 业务主体,用于拼标题与建议,如「设备」「客户」 */
  subject: string;
  /** 新增成功的条数 */
  createCount?: number;
  /** 更新成功的条数 */
  updateCount?: number;
  /** 失败明细:key 为编码/名称,value 为后端失败原因 */
  failures?: null | Record<string, string>;
  /** 「不存在」类失败的落点提示,如「【设备类型】【车间】【工作站】中的对应编码」 */
  masterDataHint?: string;
}
 
/**
 * 统一展示 Excel 导入结果。
 *
 * 只要后端返回了失败明细,就绝不能再提示「操作成功」——改为常驻通知逐行列出失败原因,
 * 并按失败原因给出下一步动作;全部成功时才提示成功。
 *
 * @returns 实际写入的条数(新增 + 更新),供调用方决定是否需要刷新列表
 */
export function notifyImportResult(
  options: ImportResultNotifyOptions,
): number {
  const {
    subject,
    createCount = 0,
    updateCount = 0,
    failures,
    masterDataHint,
  } = options;
  const failureEntries = Object.entries(failures ?? {});
  const importedCount = createCount + updateCount;
 
  if (failureEntries.length === 0) {
    message.success(`导入成功:新增 ${createCount} 条,更新 ${updateCount} 条`);
    return importedCount;
  }
 
  const nodes: VNodeChild[] = [
    h(
      'div',
      `新增成功 ${createCount} 条,更新成功 ${updateCount} 条,失败 ${failureEntries.length} 条:`,
    ),
    ...failureEntries.map(([name, reason]) => h('div', `${name}:${reason}`)),
    ...buildFailureHints(failureEntries.map(([, reason]) => reason), {
      subject,
      masterDataHint,
    }).map((hint) => h('div', { class: 'mt-2 text-red-500' }, hint)),
  ];
 
  const notify = importedCount === 0 ? notification.error : notification.warning;
  notify({
    message:
      importedCount === 0
        ? `${subject}导入失败:${failureEntries.length} 行全部未导入`
        : `导入完成,部分${subject}导入失败(成功 ${importedCount} 条 / 失败 ${failureEntries.length} 条)`,
    description: () => h('div', nodes),
    duration: null,
  });
  return importedCount;
}
 
/** 按失败原因归纳下一步动作,避免用户只看到「失败」却不知道改哪里 */
function buildFailureHints(
  reasons: string[],
  { subject, masterDataHint }: Pick<ImportResultNotifyOptions, 'masterDataHint' | 'subject'>,
): string[] {
  const hints = new Set<string>();
  for (const reason of reasons) {
    if (reason.includes('不存在')) {
      hints.add(
        `提示「不存在」的:请先维护好${masterDataHint ?? '对应主数据'},或把 Excel 中的值改成已存在的,再重新导入。`,
      );
    } else if (reason.includes('已经存在') || reason.includes('已存在')) {
      hints.add(
        `提示「已存在」的:请修改 Excel 中的${subject}名称或编码,或勾选「支持更新」后重新导入以覆盖已有数据。`,
      );
    } else if (reason.includes('不能为空') || reason.includes('为空')) {
      hints.add('提示「不能为空」的:请补齐 Excel 中对应列的内容后重新导入。');
    }
  }
  return [...hints];
}