6-17 代码优化
本文档说明 2026-06-17 对美国版的两项后端改造:
GET /api/app/label-template列表 500 修复(scope 库结构兼容)POST /api/app/us-app-labeling/get-print-log-list增加 按自然日 的打印时间筛选
测试环境:http://flus-test.3ffoodsafety.com
一、label-template 列表修复
Web 管理端 Label Templates 页加载失败,Network 中:
GET /api/app/label-template?SkipCount=1&MaxResultCount=10 返回错误,页面提示 Failed to load label templates。
根因
6-4 改造引入 Company / Region / Location 三维适用范围后,代码会:
- 查询
fl_label_template.AppliedPartnerType/AppliedRegionType - 关联
fl_label_template_partner/fl_label_template_region
测试库若尚未执行迁移脚本 fl_label_template_scope.sql,上述列/表不存在,SqlSugar 生成 SQL 时报 Unknown column / Table doesn't exist,接口 500。
SkipCount=1表示第 1 页(页码从 1 起),不是报错原因。
修复说明
1. 库结构兼容(未迁移仍可列表)
| 改动 | 说明 |
|---|---|
LabelTemplateScopeSchemaHelper |
启动后首次请求检测 partner/region 关联表是否存在 |
FlLabelTemplateDbEntity |
AppliedPartnerType / AppliedRegionType 标记 IsIgnore,避免 SELECT 不存在列 |
LabelTemplateScopeHelper |
未迁移时列表/详情 仅 Location 维度 过滤与展示;Company/Region 显示 All Companies / All Regions |
| 已迁移库 | 行为与 6-4 一致,按关联表判断 ALL/SPECIFIED |
2. 列表筛选补全
LabelTemplateGetListInputVo 增加 partnerId(Company),与 groupId、locationId 按「门店优先」解析(ResolveFilteredLocationIdsForListAsync)。
3. Items 列
LabelTemplateListItemsHelper 补全 ElementKey 查询字段,控件名称排序稳定。
接口说明(label-template)
| 项目 | 内容 |
|---|---|
| 方法 | GET |
| 路径 | /api/app/label-template |
| 鉴权 | Bearer Token |
入参(Query)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
SkipCount |
int | 否 | 页码,从 1 起;第一页传 1(与全平台列表约定一致) |
MaxResultCount |
int | 否 | 每页条数,默认 10 |
Keyword |
string | 否 | 模板名称 / 编码模糊搜索 |
PartnerId |
string | 否 | 按 Company(fl_partner.Id)筛选 |
GroupId |
string | 否 | 按 Region(fl_group.Id)筛选 |
LocationId |
string | 否 | 按门店(location.Id)筛选;优先于 Partner/Region |
LabelType |
string | 否 | 如 PRICE / NUTRITION |
State |
bool | 否 | 启用状态 |
Sorting |
string | 否 | 排序字段 |
筛选解析顺序:LocationId → GroupId → PartnerId;均未传则不按门店范围收窄(仍受登录账号数据权限约束)。
出参(PagedResultWithPageDto<LabelTemplateGetListOutputDto>)
| 字段 | 说明 |
|---|---|
pageIndex |
当前页码 |
pageSize |
每页条数 |
totalCount |
总条数 |
totalPages |
总页数 |
items[] |
模板列表 |
items[] 主要字段
| 字段 | 说明 |
|---|---|
id / templateCode |
模板编码(前端主键) |
templateName |
模板名称 |
company / region / location |
三维适用范围展示文案 |
partnerIds / regionIds / locationIds |
对应 Id 数组(ALL 时为空) |
items / itemNames |
模板内控件名称(逗号拼接 / 数组) |
contentsCount |
控件数量 |
sizeText |
如 4x2inch |
lastEdited |
最近编辑时间 |
请求示例(label-template)
curl -G "http://flus-test.3ffoodsafety.com/api/app/label-template" \
-H "Authorization: Bearer {token}" \
--data-urlencode "SkipCount=1" \
--data-urlencode "MaxResultCount=10"
带筛选:
curl -G "http://flus-test.3ffoodsafety.com/api/app/label-template" \
-H "Authorization: Bearer {token}" \
--data-urlencode "SkipCount=1" \
--data-urlencode "MaxResultCount=10" \
--data-urlencode "PartnerId=1234567890123456789" \
--data-urlencode "Keyword=Price"
响应片段(示例)
{
"pageIndex": 1,
"pageSize": 10,
"totalCount": 2,
"totalPages": 1,
"items": [
{
"id": "TPL-PRICE-01",
"templateCode": "TPL-PRICE-01",
"templateName": "Standard Price Label",
"company": "All Companies",
"region": "All Regions",
"location": "All Locations",
"items": "Label Name, Price, Barcode",
"itemNames": ["Label Name", "Price", "Barcode"],
"contentsCount": 3,
"sizeText": "2x2inch",
"lastEdited": "2026-06-04T10:00:00"
}
]
}
数据库迁移(启用完整三维 scope)
未执行前:列表可正常返回,但 无法 保存 Company/Region 多选明细。
脚本(可重复执行):
美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/scripts/fl_label_template_scope.sql
| 对象 | 说明 |
|---|---|
fl_label_template.AppliedPartnerType |
Company:ALL / SPECIFIED |
fl_label_template.AppliedRegionType |
Region:ALL / SPECIFIED |
fl_label_template_partner |
Company 多选明细 |
fl_label_template_region |
Region 多选明细 |
执行后重启应用,新建/编辑模板即可写入 Company/Region 范围。
SQL 检查是否已迁移
SELECT COLUMN_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'fl_label_template'
AND COLUMN_NAME IN ('AppliedPartnerType', 'AppliedRegionType');
SELECT TABLE_NAME
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME IN ('fl_label_template_partner', 'fl_label_template_region');
涉及代码(label-template)
| 文件 | 说明 |
|---|---|
Helpers/LabelTemplateScopeSchemaHelper.cs |
检测 scope 表是否已迁移 |
Helpers/LabelTemplateScopeHelper.cs |
兼容未迁移库的过滤/展示/保存 |
Helpers/LabelTemplateListItemsHelper.cs |
Items 列 ElementKey |
Services/DbModels/FlLabelTemplateDbEntity.cs |
Partner/Region 列 IsIgnore |
Services/LabelTemplateAppService.cs |
列表筛选支持 partnerId |
Dtos/LabelTemplate/LabelTemplateGetListInputVo.cs |
新增 PartnerId |
IServices/ILabelTemplateAppService.cs |
接口注释 |
验证步骤(label-template)
- 未迁移库:仅执行后端部署,调用
GET /api/app/label-template?SkipCount=1&MaxResultCount=10应 200,Web 列表可加载。 - 已迁移库:列表
company/region展示与 6-4 一致;指定 Company 保存后再查列表 Id 数组正确。 - 分页:第 1 页
SkipCount=1,第 2 页SkipCount=2,totalCount与 UI 分页一致。 - 筛选:传
LocationId后仅返回该门店可见模板 + 全范围模板。
二、App Print Log 按日筛选(get-print-log-list)
背景
App Print Log 页增加 Date 选择器(及 Today 快捷按钮),需按所选自然日只展示该门店当日的打印记录;无记录时提示如 No print records for 06/16/2026。
改造前接口仅按门店 + 权限分页,无日期条件,无法与 UI 日期筛选对齐。
接口说明
| 项目 | 内容 |
|---|---|
| 方法 | POST |
| 路径 | /api/app/us-app-labeling/get-print-log-list |
| 鉴权 | App Bearer Token |
入参(Body:PrintLogGetListInputVo)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
locationId |
string | 是 | 当前门店 Id(location.Id) |
printDate |
DateTime | 否 | 打印日期(自然日);按 PrintedAt ?? CreationTime 落在该日的任务筛选 |
skipCount |
int | 否 | 页码,从 1 起 |
maxResultCount |
int | 否 | 每页条数 |
printDate 规则
- 未传 → 默认 服务器当天(与 App 默认选中 Today 一致)。
- 传入任意时刻 → 仅取 日期部分(
Date),区间为[当天 00:00:00, 次日 00:00:00)。 - 有效时间字段:
fl_label_print_task.PrintedAt优先,为空则用CreationTime(与 Label ID 序号、6-2/6-11一致)。 - 权限不变:管理员 / Partner 看门店全部;其它角色仅本人(
CreatedBy)。
出参
仍为 PagedResultWithPageDto<PrintLogItemDto>;items[] 字段不变。totalCount 为该日符合条件的总数。
| 字段 | 说明 |
|---|---|
labelId |
门店当日打印序号 yyyyMMdd-n(与 preview / 报表一致) |
printedAt |
打印时间 |
| 其它 | 与改造前一致 |
请求示例
查询当天(显式传 printDate)
curl -X POST "http://flus-test.3ffoodsafety.com/api/app/us-app-labeling/get-print-log-list" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"locationId": "550e8400-e29b-41d4-a716-446655440000",
"printDate": "2026-06-16T00:00:00",
"skipCount": 1,
"maxResultCount": 20
}'
Today 按钮(不传 printDate,后端默认当天)
{
"locationId": "550e8400-e29b-41d4-a716-446655440000",
"skipCount": 1,
"maxResultCount": 20
}
响应片段(示例)
{
"pageIndex": 1,
"pageSize": 20,
"totalCount": 2,
"totalPages": 1,
"items": [
{
"taskId": "1234567890123456789",
"labelId": "20260616-1",
"productName": "Organic Milk",
"printedAt": "2026-06-16T09:15:00",
"operatorName": "Alice",
"locationName": "Ordos Airport"
},
{
"taskId": "1234567890123456788",
"labelId": "20260616-2",
"printedAt": "2026-06-16T14:30:00"
}
]
}
若 totalCount = 0,App 可展示 No print records for MM/DD/YYYY。
涉及代码(get-print-log-list)
| 文件 | 说明 |
|---|---|
Dtos/UsAppLabeling/PrintLogGetListInputVo.cs |
新增 PrintDate |
Services/UsAppLabelingAppService.cs |
GetPrintLogListAsync 增加日期 Where |
Helpers/ReportsPrintLogDailyLabelIdHelper.cs |
新增 ResolvePrintLogFilterDayRange |
IServices/IUsAppLabelingAppService.cs |
接口注释 |
验证步骤(get-print-log-list)
- 门店在
2026-06-16有 N 条打印任务,传printDate=2026-06-16→totalCount=N,且每条printedAt落在该日。 - 传
printDate=2026-06-15且无记录 →totalCount=0,items=[]。 - 不传
printDate→ 等价于查询服务器当天。 - 同一
printDate下labelId序号与6-2规则一致(-1、-2… 按当日时间升序)。
SQL 抽查
SELECT Id, LocationId, PrintedAt, CreationTime
FROM fl_label_print_task
WHERE LocationId = '{locationId}'
AND IFNULL(PrintedAt, CreationTime) >= '2026-06-16'
AND IFNULL(PrintedAt, CreationTime) < '2026-06-17'
ORDER BY IFNULL(PrintedAt, CreationTime), Id;
行数应与接口 totalCount(该日、该门店、权限范围内)一致。
关联文档
- 三维 scope 业务规则:
项目相关文档/6-4代码优化.md - App Print Log Label ID:
项目相关文档/6-2代码优化.md - Preview 当日序号:
项目相关文档/6-11代码优化.md - 分页约定(SkipCount = 页码):
Helpers/PagedQueryConvention.cs