262 lines
8.1 KiB
Markdown
262 lines
8.1 KiB
Markdown
# DeviceCode / DeviceName Header 接收及 label_scan_history 表扩展计划
|
||
|
||
## 概述
|
||
|
||
更新后的文档新增了 2 个 Header:
|
||
- `DeviceCode` — 设备唯一编码(GUID,32位无横线)
|
||
- `DeviceName` — 设备名称(计算机名)
|
||
|
||
要求在扫描记录表 `label_scan_history` 中增加设备信息字段,用于跟踪每条记录是哪个设备产生的。
|
||
|
||
---
|
||
|
||
## 涉及修改的文件
|
||
|
||
| # | 文件 | 操作 | 说明 |
|
||
|---|------|------|------|
|
||
| 1 | `src/CONTROLLER/Models/RequestTrackingContext.cs` | 修改 | 加 `DeviceCode`、`DeviceName` |
|
||
| 2 | `src/CONTROLLER/Middleware/RequestTrackingMiddleware.cs` | 修改 | 读取 `DeviceCode`、`DeviceName` Header |
|
||
| 3 | `src/CONTROLLER/Extensions/HttpContextExtensions.cs` | 修改 | 加便捷访问方法 |
|
||
| 4 | `src/MDL/Models/LabelScanEntity.cs` | 修改 | 加 `DeviceCode`、`DeviceName` 属性 |
|
||
| 5 | `src/BLL/Interfaces/ILabelScanService.cs` | 修改 | `RecordScanAsync` 加 2 个可选参数 |
|
||
| 6 | `src/BLL/Services/LabelScanService.cs` | 修改 | 实现层写入新字段 |
|
||
| 7 | `src/MDL/DTOs/LabelScanWithCustomerDto.cs` | 修改 | 加 `DeviceCode`、`DeviceName` |
|
||
| 8 | `src/DAL/repositories/LabelScanRepository.cs` | 修改 | DTO 映射加设备字段 |
|
||
| 9 | `src/CONTROLLER/Controllers/LabelController.cs` | 修改 | 3 个 download 端点传设备信息 |
|
||
| 10 | `database/004_add_device_fields.sql` | **新建** | 数据库 DDL 迁移脚本 |
|
||
|
||
---
|
||
|
||
## 实施步骤
|
||
|
||
### 步骤 1:扩展 `RequestTrackingContext` 模型
|
||
|
||
文件:`src/CONTROLLER/Models/RequestTrackingContext.cs`
|
||
|
||
```csharp
|
||
namespace CONTROLLER.Models
|
||
{
|
||
public class RequestTrackingContext
|
||
{
|
||
public string Caller { get; set; } = "system";
|
||
public string? DeviceCode { get; set; }
|
||
public string? DeviceName { get; set; }
|
||
}
|
||
}
|
||
```
|
||
|
||
`DeviceCode` 和 `DeviceName` 为可空,未传 Header 时为 `null`。
|
||
|
||
---
|
||
|
||
### 步骤 2:扩展 `RequestTrackingMiddleware`
|
||
|
||
文件:`src/CONTROLLER/Middleware/RequestTrackingMiddleware.cs`
|
||
|
||
```csharp
|
||
var deviceCode = context.Request.Headers["DeviceCode"].FirstOrDefault();
|
||
if (!string.IsNullOrWhiteSpace(deviceCode))
|
||
trackingContext.DeviceCode = deviceCode;
|
||
|
||
var deviceName = context.Request.Headers["DeviceName"].FirstOrDefault();
|
||
if (!string.IsNullOrWhiteSpace(deviceName))
|
||
trackingContext.DeviceName = deviceName;
|
||
```
|
||
|
||
在 `Caller` 读取之后、`context.Items` 赋值之前加入。
|
||
|
||
---
|
||
|
||
### 步骤 3:扩展 `HttpContextExtensions`
|
||
|
||
文件:`src/CONTROLLER/Extensions/HttpContextExtensions.cs`
|
||
|
||
新增便捷方法:
|
||
```csharp
|
||
public static string? GetDeviceCode(this HttpContext context)
|
||
=> context.GetRequestTrackingContext().DeviceCode;
|
||
|
||
public static string? GetDeviceName(this HttpContext context)
|
||
=> context.GetRequestTrackingContext().DeviceName;
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 4:扩展 `LabelScanEntity` 模型
|
||
|
||
文件:`src/MDL/Models/LabelScanEntity.cs`
|
||
|
||
在 `CreatedBy` 属性之后新增:
|
||
```csharp
|
||
[SugarColumn(Length = 64)]
|
||
public string? DeviceCode { get; set; }
|
||
|
||
[SugarColumn(Length = 100)]
|
||
public string? DeviceName { get; set; }
|
||
```
|
||
|
||
- `DeviceCode`: VARCHAR(64),GUID 去除横线后 32 位
|
||
- `DeviceName`: VARCHAR(100),计算机名
|
||
|
||
---
|
||
|
||
### 步骤 5:扩展 `ILabelScanService` 接口
|
||
|
||
文件:`src/BLL/Interfaces/ILabelScanService.cs`
|
||
|
||
`RecordScanAsync` 方法签名追加 2 个可选参数(放在末尾,兼容现有调用):
|
||
|
||
```csharp
|
||
Task<LabelScanEntity> RecordScanAsync(int customerId, string neutralWaybillNumber,
|
||
ScanResult result, string createdBy,
|
||
string? referenceNumber = null, string? finalMileTrackingNumber = null,
|
||
string? description = null,
|
||
string? deviceCode = null, string? deviceName = null);
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 6:扩展 `LabelScanService` 实现
|
||
|
||
文件:`src/BLL/Services/LabelScanService.cs`
|
||
|
||
- 方法签名同步更新
|
||
- 创建 `LabelScanEntity` 时赋值:
|
||
```csharp
|
||
var scanRecord = new LabelScanEntity
|
||
{
|
||
// ... existing fields ...
|
||
DeviceCode = deviceCode,
|
||
DeviceName = deviceName
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 7:扩展 `LabelScanWithCustomerDto`
|
||
|
||
文件:`src/MDL/DTOs/LabelScanWithCustomerDto.cs`
|
||
|
||
新增:
|
||
```csharp
|
||
public string? DeviceCode { get; set; }
|
||
public string? DeviceName { get; set; }
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 8:更新 `LabelScanRepository` DTO 映射
|
||
|
||
文件:`src/DAL/repositories/LabelScanRepository.cs`
|
||
|
||
在 `GetByPageAsync` 方法的 DTO 构建(第 306-318 行)中增加:
|
||
```csharp
|
||
DeviceCode = l.DeviceCode,
|
||
DeviceName = l.DeviceName,
|
||
```
|
||
|
||
---
|
||
|
||
### 步骤 9:改造 `LabelController` 下载端点传设备信息
|
||
|
||
文件:`src/CONTROLLER/Controllers/LabelController.cs`
|
||
|
||
涉及 3 个方法的 `RecordScanAsync` 调用(第 721、1306、1714 行附近),各增加 2 个参数。
|
||
|
||
**具体改动方案:**
|
||
|
||
在每个方法的**变量声明区**新增 `deviceCode` 和 `deviceName`:
|
||
```csharp
|
||
string? deviceCode = HttpContext.GetDeviceCode();
|
||
string? deviceName = HttpContext.GetDeviceName();
|
||
```
|
||
|
||
对于使用 `Task.Run` 异步捕获的方法(download, download/v2),在 finally 块中增加捕获变量:
|
||
```csharp
|
||
var capturedDeviceCode = deviceCode;
|
||
var capturedDeviceName = deviceName;
|
||
```
|
||
|
||
然后在 `RecordScanAsync` 调用中添加:
|
||
```csharp
|
||
deviceCode: capturedDeviceCode,
|
||
deviceName: capturedDeviceName,
|
||
```
|
||
|
||
对于 NoTrigger 方法(直接 await,无需捕获),直接在调用中添加:
|
||
```csharp
|
||
deviceCode: deviceCode,
|
||
deviceName: deviceName,
|
||
```
|
||
|
||
**注意**:`deviceCode` 的声明位置需要与 `caller` 一样,放在方法级别的变量初始化区(`try` 块之前),以便 `finally` 块可以访问。
|
||
|
||
---
|
||
|
||
### 步骤 10:创建数据库 DDL 迁移脚本
|
||
|
||
文件:`database/004_add_device_fields.sql`
|
||
|
||
```sql
|
||
-- 为 label_scan_history 表添加设备信息字段
|
||
-- 用于跟踪每条扫描记录是哪个设备产生的
|
||
|
||
ALTER TABLE `label_scan_history`
|
||
ADD COLUMN `DeviceCode` VARCHAR(64) NULL COMMENT '设备唯一编码(GUID)' AFTER `CreatedBy`,
|
||
ADD COLUMN `DeviceName` VARCHAR(100) NULL COMMENT '设备名称(计算机名)' AFTER `DeviceCode`;
|
||
|
||
-- 为设备编码添加索引,方便按设备查询/统计
|
||
ALTER TABLE `label_scan_history`
|
||
ADD INDEX `IX_DeviceCode` (`DeviceCode`);
|
||
```
|
||
|
||
由于 SqlSugar 的 `CodeFirst.InitTables` 在 `LabelScanRepository.CreateAsync` 中会自动建表(首次),新增字段后可能需要手动执行此 SQL(或依赖 CodeFirst 的自动列添加行为,取决于 SqlSugar 配置)。
|
||
|
||
---
|
||
|
||
## 调用链路总结
|
||
|
||
```
|
||
HTTP Request
|
||
├── Header: Caller, DeviceCode, DeviceName
|
||
│
|
||
▼
|
||
RequestTrackingMiddleware
|
||
└── 提取所有 Header → RequestTrackingContext → HttpContext.Items
|
||
│
|
||
▼
|
||
LabelController.DownloadLabelByWaybillNumber (及另 2 个)
|
||
├── var caller = HttpContext.GetCaller();
|
||
├── var deviceCode = HttpContext.GetDeviceCode();
|
||
├── var deviceName = HttpContext.GetDeviceName();
|
||
│
|
||
▼ finally
|
||
RecordScanAsync(..., createdBy: caller, deviceCode: deviceCode, deviceName: deviceName)
|
||
│
|
||
▼
|
||
LabelScanService.RecordScanAsync
|
||
└── LabelScanEntity { DeviceCode = deviceCode, DeviceName = deviceName }
|
||
│
|
||
▼
|
||
LabelScanRepository.CreateAsync → INSERT INTO label_scan_history
|
||
```
|
||
|
||
---
|
||
|
||
## 改造汇总
|
||
|
||
| 步骤 | 文件 | 操作 | 涉及行数 |
|
||
|------|------|------|---------|
|
||
| 1 | `Models/RequestTrackingContext.cs` | 加 2 属性 | ~3 行 |
|
||
| 2 | `Middleware/RequestTrackingMiddleware.cs` | 加 2 段读取 | ~6 行 |
|
||
| 3 | `Extensions/HttpContextExtensions.cs` | 加 2 方法 | ~6 行 |
|
||
| 4 | `MDL/Models/LabelScanEntity.cs` | 加 2 属性 | ~6 行 |
|
||
| 5 | `BLL/Interfaces/ILabelScanService.cs` | 接口加 2 参数 | ~2 行 |
|
||
| 6 | `BLL/Services/LabelScanService.cs` | 实现加赋值 | ~3 行 |
|
||
| 7 | `MDL/DTOs/LabelScanWithCustomerDto.cs` | 加 2 属性 | ~2 行 |
|
||
| 8 | `DAL/repositories/LabelScanRepository.cs` | DTO 映射加 2 行 | ~2 行 |
|
||
| 9 | `CONTROLLER/LabelController.cs` | 3 个方法各加声明+传参 | ~15 行 |
|
||
| 10 | `database/004_add_device_fields.sql` | **新建** | ~8 行 |
|
||
|
||
> **向后兼容**:`RecordScanAsync` 追加的是可选参数(带默认值 `null`),现有所有调用方无需修改即可编译通过。只有需要记录设备信息的调用方才需显式传入。
|