6-2代码优化.md 15.2 KB

6-2 代码优化

本文档说明 2026-06-02 对美国版 /api/app/label 列表接口报错修复,以及 适用 Region 字段的接口约定。


标签列表接口报错修复

现象

GET http://flus-test.3ffoodsafety.com/api/app/label?SkipCount=1&MaxResultCount=10 返回 500,典型错误为 MySQL:

  • Unknown column 'AppliedRegionType' in 'field list'
  • Table 'xxx.fl_label_region' doesn't exist

根因

后端已上线「适用 Region」逻辑,但测试库 尚未执行 DDL

  • fl_label 缺少列 AppliedRegionType
  • 缺少表 fl_label_region

ORM 在列表/筛选 SQL 中引用上述结构即失败。

修复方式(代码 + 库)

层级 处理
代码 新增 LabelRegionSchemaHelper:启动后首次访问探测 information_schema,无列/无表时走 兼容路径(仅按 LocationId、门店反推 Region 展示),列表不再因缺列 500
实体 FlLabelDbEntity.AppliedRegionType 标记 IsIgnore,读写经 Helper 的原始 SQL(列存在时)
数据库 须在环境执行 DDL,才能持久化 ALL/多选 Region(见下节脚本)

DDL 脚本(可重复执行)

美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/scripts/fl_label_region_scope.sql

验证步骤

  1. 未执行 DDL:部署含本修复的后端 → GET /api/app/label?SkipCount=1&MaxResultCount=10200region 可由门店反推或显示「无」。
  2. 执行 DDL 后:重启应用(或等待 schema 缓存失效;生产建议重启)→ 新增/编辑可落库 regionIdsAppliedRegionType=ALL
  3. 库内确认:
SELECT COLUMN_NAME FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'fl_label' AND COLUMN_NAME = 'AppliedRegionType';

SELECT TABLE_NAME FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'fl_label_region';

涉及文件(本次修复)

文件 说明
Helpers/LabelRegionSchemaHelper.cs 探测 schema、批量读 AppliedRegionType、按列更新
Helpers/LabelRegionScopeHelper.cs 列表筛选/App 校验按 schema 分支
Services/LabelAppService.cs 列表不再 SELECT 缺列;创建/更新后 SetAppliedRegionTypeAsync
Services/UsAppLabelingAppService.cs labeling-tree 按 schema 拼接条件
Services/DbModels/FlLabelDbEntity.cs AppliedRegionType ORM 忽略
scripts/fl_label_region_scope.sql 幂等 DDL

标签 /api/app/label 适用 Region(接口说明)

背景

标签除 locationId 外,支持显式配置适用 Regionfl_group.Id),模式与 label-type / label-multiple-option 一致:

  • ALL:全选 Region
  • SPECIFIEDregionIds / groupIds 单选或多选

存储

位置 字段 说明
fl_label AppliedRegionType ALL / SPECIFIED(需 DDL)
fl_label_region LabelId + GroupId Region 多选明细
fl_label LocationId 兼容 App;多 Region 未指定门店时取合并门店第一家

接口一览

方法 路径 说明
GET /api/app/label 分页列表;GroupId 按 Region 筛选
GET /api/app/label/{id} 详情(id = LabelCode
POST /api/app/label 新增
PUT /api/app/label/{id} 编辑
DELETE /api/app/label/{id} 逻辑删除

测试环境列表示例

http://flus-test.3ffoodsafety.com/api/app/label?SkipCount=1&MaxResultCount=10

鉴权Authorization: {登录返回的 data.token}(已含 Bearer 前缀)

列表请求参数

参数 类型 说明
SkipCount int 跳过条数(分页)
MaxResultCount int 每页条数
Keyword string 模糊:标签名、类别、类型、模板、产品名
GroupId string Region(fl_group.Id)筛选
LocationId string 门店筛选
ProductId string 产品筛选
LabelCategoryId string 标签类别
LabelTypeId string 标签类型
TemplateCode string 模板编码
State bool 启用状态
Sorting string 排序(可选)

请求示例

GET /api/app/label?SkipCount=1&MaxResultCount=10 HTTP/1.1
Host: flus-test.3ffoodsafety.com
Authorization: Bearer {access_token}

列表响应(主要字段)

字段 说明
totalCount 总条数
items 行数组
items[].id 标签 Code(LabelCode
items[].labelName 名称
items[].region Region 展示名;ALL 为 All Regions
items[].regionIds / groupIds Region Id 数组
items[].appliedRegionType ALL / SPECIFIED
items[].locationName 门店名
items[].products 关联产品名(逗号拼接)
items[].lastEdited 最后编辑时间

新增 / 编辑 Body(JSON)

字段 类型 必填 说明
appliedRegionType string ALL / SPECIFIED;有 regionIds 时按 SPECIFIED
regionIds string[] 条件 fl_group.Id,与 groupIds 合并去重
groupIds string[] regionIds
locationId string 条件 门店;须在 Region 内(SPECIFIED)
labelName string 标签名称
templateCode string 模板编码
labelCategoryId string 标签类别 Id
labelTypeId string 标签类型 Id
productIds string[] 至少 1 个
labelInfoJson object 模板数据
state bool 默认 true

全选 Region

{
  "labelName": "Demo",
  "templateCode": "TPL001",
  "appliedRegionType": "ALL",
  "regionIds": [],
  "labelCategoryId": "...",
  "labelTypeId": "...",
  "productIds": ["..."]
}

单选 Region

{
  "appliedRegionType": "SPECIFIED",
  "regionIds": ["{fl_group.Id}"],
  "locationId": "{location.Id}",
  "labelName": "...",
  "templateCode": "...",
  "labelCategoryId": "...",
  "labelTypeId": "...",
  "productIds": ["..."]
}

联调注意

现象 处理
列表仍 500 确认已部署含 LabelRegionSchemaHelper 的版本
regionIds 保存不上 执行 fl_label_region_scope.sql 并重启
ALL 不生效 AppliedRegionType 列;执行 DDL
未执行 DDL 时新增带 regionIds 关联表不存在则仅更新 locationId,Region 关联不落库

与 6-1 文档关系

  • 6-1代码优化.md:首版 Region 功能说明(含 my-menus、team-member 等其它优化)。
  • 本节(6-2):列表 500 根因与兼容修复 + 接口速查;以 6-2 为准处理 label 列表报错与 DDL 要求。

Reports Print Log 日期格式统一(print-log-list

背景

GET /api/app/reports/print-log-list 返回的 printedAt 原为 DateTime JSON(ISO / 客户端 en-US 再格式化),与 expiryDateText(来自 PrintInputJson 原始模板文案,如 MM/dd/yyyy)展示顺序不一致。要求两列统一为 年月日在前,且 Expiration(expiryDateText)精确到分钟

目标格式

字段 格式 示例
printedAt yyyy-MM-dd HH:mm 2026-05-19 14:30
expiryDateText yyyy-MM-dd HH:mm(可解析时) 2026-06-02 18:00
无数据 固定文案

仅日期、无时分的数据解析后时间为 00:00

接口

说明
方法 GET
路径 /api/app/reports/print-log-list
鉴权 Bearer Token
测试示例 http://flus-test.3ffoodsafety.com/api/app/reports/print-log-list?Sorting=PrintedAt+desc&StartDate=2026-05-04&EndDate=2026-06-02&SkipCount=1&MaxResultCount=10

请求参数(常用)

参数 说明
SkipCount / MaxResultCount 分页
Sorting PrintedAt desc / PrintedAt asc
StartDate / EndDate 区间(yyyy-MM-dd,含起止日)
PartnerId / GroupId / LocationId 组织筛选
Keyword 产品名等模糊

响应 items[](与本次相关)

字段 类型 说明
printedAt string 打印时间,yyyy-MM-dd HH:mm
expiryDateText string 保质期(Expiration),同上;无法解析时保留原文或
taskId string 任务 Id(重打)
labelCode string 门店当日序号 Label ID
productName string 产品名
templateText string 模板展示
printedByName string 打印人
locationText string 门店

响应片段示例

{
  "totalCount": 42,
  "items": [
    {
      "taskId": "…",
      "labelCode": "20260519-1",
      "printedAt": "2026-05-19 14:30",
      "expiryDateText": "2026-06-02 18:00",
      "productName": "Chicken Breast",
      "printedByName": "John",
      "locationText": "Store A (001)"
    }
  ]
}

实现说明

组件 说明
ReportsDateTimeDisplayHelper FormatPrintedAt / FormatExpiryDisplay,统一 yyyy-MM-dd HH:mm
ReportsPrintLogExpiryHelper.ExtractFormattedExpiryText PrintInputJson 解析并格式化 Expiration
ReportsPrintLogListItemDto.PrintedAt DateTime 改为 string 出参
PDF / Excel 导出 与列表相同格式
Web ReportsView.tsx 直接展示接口字符串,不再 en-US 二次格式化

App get-print-log-list 的 Label ID(labelId

背景

POST /api/app/us-app-labeling/get-print-log-list 原先 labelId 返回 fl_label.Id(或界面误用 labelCode / batchId),与业务要求的 门店当日打印序号 不一致。管理端 Print Log 已使用 ReportsPrintLogDailyLabelIdHelperyyyyMMdd-n),App 需对齐。

规则

说明
范围 同一 门店 + 同一 自然日(按 PrintedAt,无则 CreationTime
排序 当日任务按打印时间升序,再按任务 Id 升序
格式 {yyyyMMdd}-{n},如 20260513-120260513-2
不是 fl_label.LabelCode,也不是标签主键本身

接口

说明
方法 POST
路径 /api/app/us-app-labeling/get-print-log-list
鉴权 App 登录 Bearer Token

请求 Body 示例

{
  "locationId": "{门店Guid}",
  "skipCount": 1,
  "maxResultCount": 10
}

响应 items[](与 Label ID 相关)

字段 说明
labelId 门店当日打印序号yyyyMMdd-n),列表 Ref / Label ID 展示用
labelEntityId fl_label.Id(内部、重打关联)
labelCode fl_label.LabelCode(重打/预览入参,勿与 labelId 混用)
taskId fl_label_print_task.Id(重打主键)

响应片段

{
  "totalCount": 3,
  "items": [
    {
      "taskId": "…",
      "labelId": "20260513-1",
      "labelEntityId": "…",
      "labelCode": "LBL_xxx",
      "productName": "Chicken",
      "printedAt": "2026-05-13T10:30:00"
    },
    {
      "taskId": "…",
      "labelId": "20260513-2",
      "labelEntityId": "…",
      "labelCode": "LBL_yyy"
    }
  ]
}

验证步骤

  1. 同一门店当日连续打印多条 → labelIdyyyyMMdd-1yyyyMMdd-2 … 递增。
  2. 跨日:次日首条从 yyyyMMdd-1 重新计数(日期段为当日 yyyyMMdd)。
  3. 跨门店:各门店各自从 -1 计数(请求已限定 locationId)。
  4. 重打仍用 taskId + labelCode,不依赖 labelId 序号。

涉及文件

文件 说明
Helpers/ReportsPrintLogDailyLabelIdHelper.cs 序号计算(与 Web Print Log 共用)
Services/UsAppLabelingAppService.cs GetPrintLogListAsync
Contracts/Dtos/UsAppLabeling/PrintLogItemDto.cs labelId / labelEntityId / labelCode 注释
App print-log.vue Ref 列展示 labelId
App types/usAppLabeling.ts 类型补充

验证步骤

  1. 调用上述 print-log-list,检查 printedAtexpiryDateText 均为 yyyy-MM-dd HH:mm
  2. 对比改前:不应再出现 05/19/20262026-05-19T… 混用。
  3. 导出 Excel/PDF 的 Printed at、Expiration 列与列表一致。

涉及文件

文件 说明
Helpers/ReportsDateTimeDisplayHelper.cs 统一格式化
Helpers/ReportsPrintLogExpiryHelper.cs ExtractFormattedExpiryText
Services/ReportsAppService.cs 列表 / 导出映射
Contracts/Dtos/Reports/ReportsPrintLogListItemDto.cs printedAt 类型与注释
Web ReportsView.tsx 列表展示

标签模板列表 Items 列(控件名称)

说明

标签模板列表需展示 Items 列:该模板画布上每个控件的名称,逗号拼接(如图:Barcode, Print Time, Print Date, …)。

接口路径GET /api/app/label-template(标签模板分页列表)。
若写成 /api/app/location 则为门店列表,不含模板 Items;请以本节路径为准。

接口

说明
方法 GET
路径 /api/app/label-template
鉴权 Web 登录 Bearer Token
示例 http://flus-test.3ffoodsafety.com/api/app/label-template?SkipCount=1&MaxResultCount=500

请求参数(常用)

参数 说明
SkipCount / MaxResultCount 分页
Keyword 模板名/编码模糊
GroupId / LocationId Region / 门店范围筛选
LabelType 标签类型
State 启用状态
Sorting 排序(可选)

响应 items[](本次新增)

字段 类型 说明
items string 控件名称逗号拼接(按 OrderNum 排序),无控件时为
itemNames string[] items 相同内容的数组
contentsCount int 控件数量(Contents 列)
templateName / templateCode string 模板名 / 编码
locationText / region string 适用范围展示

展示名解析顺序

  1. fl_label_template_element.ElementName(非空优先)
  2. TypeAdd 中下划线后缀(如 print_Print TimePrint Time
  3. ElementType 映射(如 BARCODEBarcode

响应片段

{
  "totalCount": 12,
  "items": [
    {
      "id": "TPL001",
      "templateName": "G'n'G 2x6",
      "contentsCount": 8,
      "items": "Barcode, Print Time, Print Date, Text Field, Duration Date, Label Name, Employee",
      "itemNames": ["Barcode", "Print Time", "Print Date", "Text Field", "Duration Date", "Label Name", "Employee"],
      "sizeText": "2x6inch"
    }
  ]
}

验证步骤

  1. 打开 Web Label Templates 列表,Items 列与接口 items 一致。
  2. 编辑模板增删控件后刷新列表,items / contentsCount 同步更新。
  3. 无元素的模板:itemscontentsCount 为 0。

涉及文件

文件 说明
Helpers/LabelTemplateListItemsHelper.cs 批量汇总控件名
Services/LabelTemplateAppService.cs GetListAsync 出参
Contracts/Dtos/LabelTemplate/LabelTemplateGetListOutputDto.cs items / itemNames
Web labelTemplateService.ts / LabelTemplatesView.tsx 列表 Items 列展示