15 KiB
15 KiB
标签模块设计文档
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 | 标签类型列表 |
| GenerateTagRequest | TagType | string | 标签类型 |
| GenerateTagRequest | NeutralWaybillNumber | string | 中性单号 |
| GenerateTagRequest | CustomerId | int | 客户编码 |
| RenderTagRequest | TemplateId | int | 模板ID |
| RenderTagRequest | Data | Dictionary<string, object> | 标签数据 |
4. 业务逻辑设计
4.1 标签模板管理
- 功能:管理标签模板的创建、更新、删除和查询
- 流程:
- 接收模板管理请求
- 验证请求参数
- 执行相应的CRUD操作
- 返回操作结果
4.2 STOP标签触发逻辑
- 功能:根据业务规则自动触发STOP标签
- 流程:
- 接收触发检查请求(中性单号、客户编码)
- 查询第一次扫描时间T(从label_scan_history表)
- 计算T+5截止时间(5天后的23:59:59)
- 检查是否超过截止时间
- 检查是否有尾程标签(FinalMileTrackingNumber不为空)
- 若满足条件,触发STOP标签生成
4.3 标签生成
- 功能:生成标签实例
- 流程:
- 接收标签生成请求
- 检查是否已存在同类型激活标签
- 获取标签模板
- 创建标签实例
- 保存到数据库
- 返回生成结果
4.4 标签渲染
- 功能:将标签模板渲染为HTML(预览)或ZPL(打印)
- 流程:
- 接收渲染请求
- 获取标签模板
- 解析模板配置
- 替换模板变量
- 渲染为目标格式
- 返回渲染结果
5. 数据库设计
5.1 标签模板表(tag_templates)
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)
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 缓存服务接口(预留扩展性)
public interface ICacheService
{
Task<string> GetStringAsync(string key);
Task SetStringAsync(string key, string value, TimeSpan? expiration = null);
Task RemoveAsync(string key);
}
6.2.2 无缓存实现
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标签触发逻辑
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 标签渲染逻辑
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 依赖注入配置
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. 总结
标签模块通过分层架构设计,实现了标签的全生命周期管理和自动触发功能。该模块预留了扩展性,便于后续添加缓存机制和其他功能扩展。同时,通过性能优化措施,确保系统响应迅速,满足业务需求。
- 数据一致性:与系统其他模块保持一致的命名规范和数据结构
- 业务完整性:实现了标签从模板管理到生成、渲染的完整流程
- 系统集成性:与扫描记录系统无缝集成,实现自动触发
- 可扩展性:预留了缓存接口和其他扩展点,便于后续功能扩展
标签模块的实现为变色龙系统中的标签管理提供了一个可靠、高效的解决方案,支持各种业务场景的需求。