Skip to content

19:附件、变更日志、Excel 导入与导入记录

1. 这些不是边缘功能

在当前 CRM 中,附件、变更日志和 Excel 导入都直接参与主业务:

text
客户新增 -> 附件跟随跟进记录保存
客户编辑 -> 记录基础资料/地区/工商/发票/银行变更
项目评估/合同 -> 按附件来源类型保存文件
批量导入 -> 校验、异步处理、落库、生成结果文件

2. 附件:统一的 sys_file 模型

核心代码:

text
SysFileController
SysFileServiceImpl
SysFileForm
FileSourceTypeEnum

核心表:sys_file

业务代码一般不直接“保存一个文件对象”,而是构造:

java
Map<FileSourceTypeEnum, List<SysFileForm>> fileMap = new HashMap<>();
fileMap.put(FileSourceTypeEnum.PROJECT_QUOTATION, dto.getQuotationFileList());
sysFileService.batchInsertFilesByTypes(sourceId, fileMap);

统一参数含义:

text
sourceId          附件属于哪一条业务记录
sourceType        附件业务来源,例如合同、跟进记录、项目评估
file metadata     上传路径、文件名、上传 id 等

这样一个附件表可以服务客户跟进、项目评估、合同、导入结果等多个领域。

3. 客户变更日志:记录“变化”,不是记录快照

核心代码:

text
CustomerInfoChangeLogServiceImpl
CustomerInfoChangeLogController
CustomerInfoChangeLog

表:customer_info_change_log

提供的方法:

text
recordCreate(customerId, newData, changeType, sourceId)
recordCreateBatch(...)
recordUpdate(customerId, oldData, newData, changeType, sourceId)
recordDelete(customerId, oldData, changeType)

调用点:

text
新增客户基础、地区、工商、跟进、发票、银行资料
编辑客户主表、地区、工商资料
删除客户或子资料
产品跟进转移、到期、公海等状态改变

正确顺序是:先读取 oldData,再执行更新,用 oldData 和 newData 计算变化,最后写审计日志。否则日志无法知道“从什么值变成什么值”。

4. Excel 导入是异步业务

相关代码:

text
imports/dto/CustomerInfoImportDto
imports/dto/CustomerBankInfoImportDto
imports/processor/AbstractImportProcessor
imports/processor/CustomerInfoImportProcessor
CustomerInfoServiceImpl.saveBatchByImport
CustomerBankInfoServiceImpl.saveBatchByImport
CustomerInvoiceServiceImpl.saveBatchByImport
ImportRecordServiceImpl

导入链路:

mermaid
flowchart LR
    A["上传 Excel"] --> B["读取行并映射 ImportDto"]
    B --> C["字段/字典/地区/重复校验"]
    C --> D["异步 Processor"]
    D --> E["按批写入业务表"]
    E --> F["记录 ImportRecord"]
    F --> G["生成成功/失败结果文件"]

AbstractImportProcessor 用模板方法模式固定导入流程,具体客户、发票、银行导入只实现不同字段校验和批量保存逻辑。

5. 导入与普通保存的区别

场景普通新增Excel 导入
单次数据量一条或少量成百上千条
返回方式立即返回结果返回任务或记录,异步处理
错误处理整体失败或直接提示每一行记录错误,生成失败文件
上下文当前请求线程异步线程,需要传递用户/租户信息
幂等前端避免重复点必须处理重复行和重复导入

6. Demo 的最小版本

不要先做真正 Excel 解析。先练两件事:

text
1. demo_operation_log
   - 客户新增、编辑、删除写一条日志

2. demo_file
   - 先把“附件”当作文件 URL + sourceType + sourceId 写入
   - 客户详情按 sourceId 查询附件

接着再做 CSV 导入:

text
读取 CSV
  -> 校验每行 customerName 是否为空/重复
  -> 成功行批量插入
  -> 失败行收集到结果列表
  -> 写 demo_import_record

理解这个过程后,再学习 EasyExcel、异步任务和文件导出。

7. 必测用例

  • 同一个业务来源 id 的不同附件类型能正确查询;
  • 修改前后日志能显示旧值和新值;
  • 100 行导入中 3 行非法时,结果能定位到这 3 行;
  • 异步导入执行时保留正确的用户和租户上下文;
  • 导入重复数据时遵循明确策略:跳过、更新或报错。

8. 源码阅读顺序

text
SysFileServiceImpl.batchInsertFilesByTypes
CustomerInfoChangeLogServiceImpl.recordCreate / recordUpdate / recordDelete
CustomerInfoImportDto
AbstractImportProcessor
CustomerInfoImportProcessor
CustomerInfoServiceImpl.saveBatchByImport
ImportRecordServiceImpl
pginit.sql 中 sys_file、customer_info_change_log、import_record

Lucking