# 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`），现有所有调用方无需修改即可编译通过。只有需要记录设备信息的调用方才需显式传入。
