# 标签模块设计文档

## 1. 模块概述

标签模块是变色龙系统中的一个核心组件，用于管理和生成各种类型的标签（如STOP标签）。该模块支持根据业务规则自动触发标签生成，并提供标签预览和打印功能。

### 1.1 设计目标

- 提供统一的标签模板管理能力
- 支持根据业务规则自动触发标签
- 提供标签预览和打印功能
- 确保系统性能高效，响应迅速
- 预留扩展性，便于后续添加缓存机制

### 1.2 适用场景

- 物流分拣中心的标签管理
- 仓库操作中的标签追踪
- 运输过程中的标签标记
- 异常情况的标签提醒（如STOP标签）

## 2. 系统架构

### 2.1 架构层次

标签模块采用分层架构设计，与系统其他模块保持一致：

```
┌─────────────────────┐
│    CONTROLLER层     │  // 控制器层，处理HTTP请求
├─────────────────────┤
│      BLL层          │  // 业务逻辑层，实现核心业务逻辑
├─────────────────────┤
│      DAL层          │  // 数据访问层，处理数据库操作
├─────────────────────┤
│      MDL层          │  // 数据模型层，定义数据结构
└─────────────────────┘
```

### 2.2 核心组件

| 组件名称 | 所在文件 | 功能描述 |
|---------|---------|----------|
| TagTemplateEntity | MDL/Models/TagTemplateEntity.cs | 标签模板实体模型 |
| TagInstanceEntity | MDL/Models/TagInstanceEntity.cs | 标签实例实体模型 |
| ITagRepository | DAL/Interfaces/ITagRepository.cs | 标签数据访问接口 |
| TagRepository | DAL/Repositories/TagRepository.cs | 标签数据访问实现 |
| ITagService | BLL/Interfaces/ITagService.cs | 标签业务逻辑接口 |
| TagService | BLL/Services/TagService.cs | 标签业务逻辑实现 |
| TagController | CONTROLLER/Controllers/TagController.cs | 标签API控制器 |
| ITagRenderer | BLL/Interfaces/ITagRenderer.cs | 标签渲染接口 |
| HtmlTagRenderer | BLL/Services/HtmlTagRenderer.cs | HTML标签渲染实现 |
| ZplTagRenderer | BLL/Services/ZplTagRenderer.cs | ZPL标签渲染实现 |
| ICacheService | BLL/Interfaces/ICacheService.cs | 缓存服务接口（预留） |
| NoCacheService | BLL/Services/NoCacheService.cs | 无缓存实现（当前使用） |
| RedisCacheService | BLL/Services/RedisCacheService.cs | Redis缓存实现（预留） |

## 3. 数据模型设计

### 3.1 标签模板实体（TagTemplateEntity）

| 字段名称 | 数据类型 | 长度 | 约束 | 描述 |
|---------|---------|------|------|------|
| Id | int | - | 主键，自增 | 模板ID |
| TagType | string | 50 | 非空，唯一 | 标签类型（如STOP、暂存） |
| Name | string | 100 | 非空 | 标签名称 |
| TemplateConfig | string | - | 非空 | 模板配置（JSON格式） |
| TriggerRule | string | - | 非空 | 触发规则（JSON格式） |
| IsActive | bool | - | 默认true | 是否启用 |
| CreatedAt | DateTime | - | 默认当前时间 | 创建时间 |
| UpdatedAt | DateTime | - | 默认当前时间 | 更新时间 |

### 3.2 标签实例实体（TagInstanceEntity）

| 字段名称 | 数据类型 | 长度 | 约束 | 描述 |
|---------|---------|------|------|------|
| Id | long | - | 主键，自增 | 实例ID |
| TagType | string | 50 | 非空 | 标签类型 |
| TemplateId | int | - | 非空 | 模板ID |
| NeutralWaybillNumber | string | 100 | 非空 | 中性单号 |
| CustomerId | int | - | 非空 | 客户编码 |
| Status | string | 20 | 默认"ACTIVE" | 状态（ACTIVE/INACTIVE） |
| TriggerTime | DateTime | - | 非空 | 触发时间 |
| CreatedAt | DateTime | - | 默认当前时间 | 创建时间 |
| UpdatedAt | DateTime | - | 默认当前时间 | 更新时间 |

### 3.3 请求模型（TagRequest）

| 模型名称 | 字段名称 | 数据类型 | 描述 |
|---------|---------|---------|------|
| CreateTagTemplateRequest | TagType | string | 标签类型 |
| CreateTagTemplateRequest | Name | string | 标签名称 |
| CreateTagTemplateRequest | TemplateConfig | string | 模板配置（JSON格式） |
| CreateTagTemplateRequest | TriggerRule | string | 触发规则（JSON格式） |
| CheckTriggerRequest | NeutralWaybillNumber | string | 中性单号 |
| CheckTriggerRequest | CustomerId | int | 客户编码 |
| CheckTriggerRequest | TagTypes | List<string> | 标签类型列表 |
| GenerateTagRequest | TagType | string | 标签类型 |
| GenerateTagRequest | NeutralWaybillNumber | string | 中性单号 |
| GenerateTagRequest | CustomerId | int | 客户编码 |
| RenderTagRequest | TemplateId | int | 模板ID |
| RenderTagRequest | Data | Dictionary<string, object> | 标签数据 |

## 4. 业务逻辑设计

### 4.1 标签模板管理

- **功能**：管理标签模板的创建、更新、删除和查询
- **流程**：
  1. 接收模板管理请求
  2. 验证请求参数
  3. 执行相应的CRUD操作
  4. 返回操作结果

### 4.2 STOP标签触发逻辑

- **功能**：根据业务规则自动触发STOP标签
- **流程**：
  1. 接收触发检查请求（中性单号、客户编码）
  2. 查询第一次扫描时间T（从label_scan_history表）
  3. 计算T+5截止时间（5天后的23:59:59）
  4. 检查是否超过截止时间
  5. 检查是否有尾程标签（FinalMileTrackingNumber不为空）
  6. 若满足条件，触发STOP标签生成

### 4.3 标签生成

- **功能**：生成标签实例
- **流程**：
  1. 接收标签生成请求
  2. 检查是否已存在同类型激活标签
  3. 获取标签模板
  4. 创建标签实例
  5. 保存到数据库
  6. 返回生成结果

### 4.4 标签渲染

- **功能**：将标签模板渲染为HTML（预览）或ZPL（打印）
- **流程**：
  1. 接收渲染请求
  2. 获取标签模板
  3. 解析模板配置
  4. 替换模板变量
  5. 渲染为目标格式
  6. 返回渲染结果

## 5. 数据库设计

### 5.1 标签模板表（tag_templates）

```sql
CREATE TABLE IF NOT EXISTS `tag_templates` (
  `Id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '模板ID',
  `TagType` VARCHAR(50) NOT NULL COMMENT '标签类型',
  `Name` VARCHAR(100) NOT NULL COMMENT '标签名称',
  `TemplateConfig` TEXT NOT NULL COMMENT '模板配置（JSON格式）',
  `TriggerRule` TEXT NOT NULL COMMENT '触发规则（JSON格式）',
  `IsActive` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
  `CreatedAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `UpdatedAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`Id`),
  UNIQUE KEY `UK_TagType` (`TagType`),
  KEY `IX_IsActive` (`IsActive`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='标签模板表';
```

### 5.2 标签实例表（tag_instances）

```sql
CREATE TABLE IF NOT EXISTS `tag_instances` (
  `Id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '实例ID',
  `TagType` VARCHAR(50) NOT NULL COMMENT '标签类型',
  `TemplateId` INT(11) NOT NULL COMMENT '模板ID',
  `NeutralWaybillNumber` VARCHAR(100) NOT NULL COMMENT '中性单号',
  `CustomerId` INT(11) NOT NULL COMMENT '客户编码',
  `Status` VARCHAR(20) DEFAULT 'ACTIVE' COMMENT '状态（ACTIVE/INACTIVE）',
  `TriggerTime` DATETIME NOT NULL COMMENT '触发时间',
  `CreatedAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `UpdatedAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`Id`),
  KEY `IX_NeutralWaybillNumber` (`NeutralWaybillNumber`),
  KEY `IX_CustomerId` (`CustomerId`),
  KEY `IX_TagType` (`TagType`),
  KEY `IX_Status` (`Status`),
  CONSTRAINT `FK_TagInstances_TagTemplates` FOREIGN KEY (`TemplateId`) REFERENCES `tag_templates` (`Id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='标签实例表';
```

## 6. 实现细节

### 6.1 技术栈

- 语言：C#
- 框架：ASP.NET Core
- 数据库：MySQL
- ORM：SqlSugar
- 依赖注入：Microsoft.Extensions.DependencyInjection

### 6.2 核心实现

#### 6.2.1 缓存服务接口（预留扩展性）

```csharp
public interface ICacheService
{
    Task<string> GetStringAsync(string key);
    Task SetStringAsync(string key, string value, TimeSpan? expiration = null);
    Task RemoveAsync(string key);
}
```

#### 6.2.2 无缓存实现

```csharp
public class NoCacheService : ICacheService
{
    public Task<string> GetStringAsync(string key)
    {
        return Task.FromResult<string>(null);
    }

    public Task SetStringAsync(string key, string value, TimeSpan? expiration = null)
    {
        return Task.CompletedTask;
    }

    public Task RemoveAsync(string key)
    {
        return Task.CompletedTask;
    }
}
```

#### 6.2.3 STOP标签触发逻辑

```csharp
public async Task<bool> CheckStopTagTriggerAsync(string neutralWaybillNumber, int customerId)
{
    // 1. 查询第一次扫描时间T
    var firstScan = await _scanRepository.GetFirstScanAsync(neutralWaybillNumber, customerId);
    if (firstScan == null)
    {
        return false;
    }

    // 2. 计算T+5截止时间
    var tPlus5 = firstScan.CreatedAt.AddDays(5).Date.AddHours(23).AddMinutes(59).AddSeconds(59);
    
    // 3. 检查是否超过截止时间
    if (DateTime.Now <= tPlus5)
    {
        return false;
    }

    // 4. 检查是否有尾程标签
    var hasLastMileTag = await _scanRepository.HasLastMileTrackingAsync(neutralWaybillNumber, customerId);
    return !hasLastMileTag;
}
```

#### 6.2.4 标签渲染逻辑

```csharp
public async Task<string> RenderHtmlAsync(int templateId, Dictionary<string, object> data)
{
    var template = await _tagRepository.GetTemplateByIdAsync(templateId);
    if (template == null)
    {
        throw new Exception("Template not found");
    }

    var config = JsonSerializer.Deserialize<TagTemplateConfig>(template.TemplateConfig);
    var html = new StringBuilder();

    // 生成HTML结构
    html.AppendLine($"<div style='width:{config.Width}in; height:{config.Height}in; border:1px solid black; padding:0.25in;'>");

    foreach (var element in config.Elements)
    {
        if (element.Type == "text")
        {
            var content = ReplaceVariables(element.Content, data);
            html.AppendLine($"<div style='position:absolute; left:{element.X}in; top:{element.Y}in; font-size:{element.FontSize}pt; {(element.Bold ? "font-weight:bold;" : "")}'>{content}</div>");
        }
        else if (element.Type == "barcode")
        {
            var content = ReplaceVariables(element.Content, data);
            // 生成条形码的HTML表示
            html.AppendLine($"<div style='position:absolute; left:{element.X}in; top:{element.Y}in; width:{element.Width}in; height:{element.Height}in;'>");
            html.AppendLine($"<img src='data:image/png;base64,{GenerateBarcode(content)}' style='width:100%; height:100%;' />");
            html.AppendLine($"</div>");
        }
    }

    html.AppendLine($"</div>");
    return html.ToString();
}
```

### 6.3 依赖注入配置

```csharp
builder.Services.AddScoped<ITagRepository, TagRepository>();
builder.Services.AddScoped<ITagService, TagService>();
builder.Services.AddScoped<IScanRepository, ScanRepository>();
builder.Services.AddScoped<ITagRenderer, HtmlTagRenderer>();
builder.Services.AddScoped<ITagRenderer, ZplTagRenderer>();
builder.Services.AddScoped<ICacheService, NoCacheService>(); // 当前使用无缓存实现
// 后续可切换为Redis缓存实现：
// builder.Services.AddScoped<ICacheService, RedisCacheService>();
```

## 7. 扩展性设计

### 7.1 缓存扩展

- 预留了ICacheService接口，可无缝切换为RedisCacheService
- 所有缓存操作通过接口调用，实现与具体缓存实现解耦

### 7.2 标签类型扩展

- 采用模板化设计，支持添加新的标签类型
- 触发规则通过JSON配置，可灵活定义

### 7.3 渲染格式扩展

- 预留了ITagRenderer接口，可添加新的渲染格式（如PDF）
- 渲染逻辑与业务逻辑解耦，便于扩展

### 7.4 API扩展

- 采用RESTful API设计，支持版本控制
- 接口设计遵循REST原则，便于扩展新功能

## 8. 代码结构

```
src/
├── MDL/
│   └── Models/
│       ├── TagTemplateEntity.cs          // 标签模板实体
│       ├── TagInstanceEntity.cs           // 标签实例实体
│       └── TagRequest.cs                  // 标签相关请求模型
├── DAL/
│   ├── Interfaces/
│   │   ├── ITagRepository.cs              // 标签数据访问接口
│   │   └── IScanRepository.cs             // 扫描记录数据访问接口
│   └── Repositories/
│       ├── TagRepository.cs               // 标签数据访问实现
│       └── ScanRepository.cs              // 扫描记录数据访问实现
├── BLL/
│   ├── Interfaces/
│   │   ├── ITagService.cs                 // 标签业务逻辑接口
│   │   ├── ITagRenderer.cs                // 标签渲染接口
│   │   └── ICacheService.cs               // 缓存服务接口
│   └── Services/
│       ├── TagService.cs                  // 标签业务逻辑实现
│       ├── HtmlTagRenderer.cs             // HTML标签渲染实现
│       ├── ZplTagRenderer.cs              // ZPL标签渲染实现
│       ├── NoCacheService.cs              // 无缓存实现
│       └── RedisCacheService.cs           // Redis缓存实现（预留）
└── CONTROLLER/
    └── Controllers/
        └── TagController.cs               // 标签API控制器
```

## 9. 性能优化

### 9.1 数据库优化

- 为关键表添加索引，加速查询
- 使用合适的数据类型，减少存储空间
- 优化SQL查询，避免全表扫描

### 9.2 代码优化

- 使用异步编程，提高并发性能
- 减少数据库查询次数，采用批量操作
- 优化时间计算逻辑，减少CPU开销

### 9.3 内存优化

- 合理使用对象池，减少GC压力
- 避免内存泄漏，及时释放资源
- 优化大对象处理，减少内存占用

## 10. 总结

标签模块通过分层架构设计，实现了标签的全生命周期管理和自动触发功能。该模块预留了扩展性，便于后续添加缓存机制和其他功能扩展。同时，通过性能优化措施，确保系统响应迅速，满足业务需求。

- **数据一致性**：与系统其他模块保持一致的命名规范和数据结构
- **业务完整性**：实现了标签从模板管理到生成、渲染的完整流程
- **系统集成性**：与扫描记录系统无缝集成，实现自动触发
- **可扩展性**：预留了缓存接口和其他扩展点，便于后续功能扩展

标签模块的实现为变色龙系统中的标签管理提供了一个可靠、高效的解决方案，支持各种业务场景的需求。