6.3 KiB
收货扫描记录表(arrival_scan_records)设计与实现计划
一、背景分析
当前 ArrivalHandoverFormController 的 /api/arrival-handover/receipt-query 接口(ArrivalHandoverFormController.cs:L447-L495)用于 PDA 收货扫描查询。
ArrivalHandoverFormService.GetReceiptInfoAsync 方法(ArrivalHandoverFormService.cs:L181-L281)的核心逻辑:
- 接收
arrivalNumber(大箱号或提单号) - 在
label_replace_requests表中按BillOfLadingNumber或MasterPackageNumber匹配 - 返回
(packageCount, labelRate, arrivalTime, billOfLadingNumber, masterPackageNumber) - 同时自动创建/更新
arrival_handover_forms记录
需要新增:PDA 每次扫描收货时,将扫描记录持久化到一张独立的记录表中,便于后续追溯和统计。
二、表结构设计
表名:arrival_scan_records
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
Id |
INT UNSIGNED | PK, AUTO_INCREMENT | 主键 |
ArrivalNumber |
VARCHAR(100) | NOT NULL | PDA扫描的大箱号(即 request.ArrivalNumber) |
CustomerId |
INT | NULL | 客户ID(冗余字段,关联 customers 表) |
BillOfLadingNumber |
VARCHAR(100) | NULL | 提单号 |
MasterPackageNumber |
VARCHAR(100) | NULL | 大箱号 |
CreatedAt |
DATETIME | NOT NULL | PDA收货扫描时间(创建时间) |
UpdatedAt |
DATETIME | NOT NULL | 更新时间 |
索引设计
| 索引名 | 字段 | 用途 |
|---|---|---|
idx_arrival_number |
ArrivalNumber | 按扫描号查询历史记录 |
idx_created_at |
CreatedAt | 按时间范围统计查询 |
idx_customer_id |
CustomerId | 按客户维度查询 |
设计说明
- ArrivalNumber 对应 PDA 扫描时传入的
request.ArrivalNumber,是本次扫描的核心标识 - CustomerId 为冗余字段,从
label_replace_requests表中获取,便于按客户维度查询,避免每次查询都要 JOIN - BillOfLadingNumber / MasterPackageNumber 从
GetReceiptInfoAsync返回值中获取 - CreatedAt 即为 PDA 收货扫描时间
- 遵循项目现有的命名规范和注解风格(PascalCase 属性名 +
[SugarColumn]注解)
三、实现步骤
步骤 1:创建 SQL 建表脚本
文件:src/DB/Scripts/CreateArrivalScanRecordTable.sql
参考 CreateLabelReplaceTable.sql 的格式:
- InnoDB 引擎
- utf8mb4 字符集
- 包含中文注释
- 创建必要索引
步骤 2:创建 Entity 实体类
文件:src/MDL/Models/ArrivalScanRecordEntity.cs
参考 LabelScanEntity.cs 和 LabelReplaceEntity.cs 的写法:
[SugarTable("arrival_scan_records")][SugarColumn(IsPrimaryKey = true, IsIdentity = true)]主键- 时间字段默认值
DateTime.UtcNow - 完整的中文 XML 注释
步骤 3:创建 Repository 仓库层
文件:
src/DAL/Interfaces/IArrivalScanRecordRepository.cs— 接口定义src/DAL/Repositories/ArrivalScanRecordRepository.cs— 实现
参考 CustomerRepository.cs 的模式:
- 通过
ISqlSugarProvider操作数据库 - 至少需要
InsertAsync方法
步骤 4:修改 ArrivalHandoverFormService
文件:src/BLL/Services/ArrivalHandoverFormService.cs
在 GetReceiptInfoAsync 方法中,查询完成后插入一条扫描记录到 arrival_scan_records 表:
// 在 return 之前插入扫描记录
var scanRecord = new ArrivalScanRecordEntity
{
ArrivalNumber = arrivalNumber,
CustomerId = labelReplaceEntities.FirstOrDefault()?.CustomerId,
BillOfLadingNumber = billOfLadingNumber,
MasterPackageNumber = masterPackageNumber,
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow
};
await db.Insertable(scanRecord).ExecuteCommandAsync();
关键点:
CustomerId从label_replace_entities的第一个匹配记录中获取(冗余存储)- 插入操作应在 try-catch 内部,且不应影响主流程(即使插入失败也不应阻止接口正常返回)
- 建议用独立的 try-catch 包裹插入逻辑,避免扫描记录入库失败导致接口报错
步骤 5:注册依赖注入
文件:src/CONTROLLER/Program.cs(或对应的 DI 注册文件)
- 注册
IArrivalScanRecordRepository→ArrivalScanRecordRepository - 在
ArrivalHandoverFormService构造函数中注入(如需要)
可选简化方案:由于
ArrivalHandoverFormService已经持有ISqlSugarProvider,可以直接通过_provider.GetClient()操作数据库,无需单独创建 Repository。是否需要独立 Repository 取决于项目的分层规范。
四、文件清单
| 文件 | 操作 | 说明 |
|---|---|---|
src/DB/Scripts/CreateArrivalScanRecordTable.sql |
新增 | 建表 SQL 脚本 |
src/MDL/Models/ArrivalScanRecordEntity.cs |
新增 | 实体类 |
src/DAL/Interfaces/IArrivalScanRecordRepository.cs |
新增 | 仓库接口 |
src/DAL/Repositories/ArrivalScanRecordRepository.cs |
新增 | 仓库实现 |
src/BLL/Services/ArrivalHandoverFormService.cs |
修改 | 在 GetReceiptInfoAsync 中插入扫描记录 |
src/CONTROLLER/Program.cs |
修改 | 注册 DI(如需独立 Repository) |
五、待确认事项
- Repository 分层:是否需要创建独立的 Repository,还是直接在 Service 中通过
ISqlSugarProvider操作?(推荐后者,与现有模式一致,因为ArrivalHandoverFormService已经直接使用_provider.GetClient()操作数据库) - 插入时机:是否仅在 Mock 数据分支(TEST 开头的 arrivalNumber)不插入?建议仅在实际数据库查询成功后插入。
- 错误处理策略:扫描记录插入失败时,是静默忽略(不影响接口返回)还是抛出异常?建议静默忽略,确保核心业务不受影响。