FoodLabeling.Application
Food Labeling 模块 - 应用层(美国版)
将标签/产品类别的按钮外观与展示字段按「JSON 字符串」落库;兼容历史单行 TEXT/COLOR/IMAGE。
未传按钮外观时的默认 JSON(与前端数组语义一致)。
规范化 /
产品类别同名字段:落库为合法 JSON 文本,不做整串 ToUpper(避免破坏 JSON)。
规范化 /
产品类别同名字段:已是 JSON 则原样落库;否则将整段文本序列化为 JSON 字符串(兼容历史单行色值/URL)。
Location 批量导入/导出 Excel(列名与 Web「Location Manager」表头对齐,兼容中英文表头别名)
导出表头顺序(与模板一致)
将门店列表写入 xlsx 内存流。
从上传的 Excel 解析为创建入参列表(行号从 2 起为数据行)。
与平台端约定:列表接口 Query 的 SkipCount 表示 SqlSugar 分页页码(从 1 起),
不是 0 基 offset。第一页应传 SkipCount=1。
Product 批量导入/导出 Excel(列与「Product-Manager-批量导入模板」一致)
导出表头顺序(与模板一致)
导出数据行
导出数据行
将产品导出数据写入 xlsx 内存流(工作表名 Products)。
从上传的 Excel 解析为原始行(行号从 2 起为数据行)。
Reports — Print Log 全量导出 Excel(列与 Web Print Log 表头对齐)
导出表头(与 UI 一致)
将 Print Log 行写入 xlsx 内存流(工作表名 Print Log)。
Reports 模块角色判断(与 JWT 中角色声明一致)
是否为「可查看全部用户打印数据」的管理员:
- 标准 中含角色码 admin(普通账号绑定 RoleCode=admin 时走此路径);
- 内置超管:用户名 admin 时 JWT 使用自定义 claim Roles,不写多条 role,需单独识别;
- 超管权限 claim Permission 为 *:*:* 时视为管理员。
Team Member 批量导入 Excel(列名与 Account Management 表格对齐,兼容常见别名)
从上传的 Excel 解析为创建入参列表(行号从 2 起为数据行)。
xlsx 流
最多数据行
角色名(忽略大小写、去空白)到角色 Id
未填 Password 列时使用
表头或解析错误
拆分门店单元格为「待解析」片段(后续由服务层解析为 Location Id)。
批量导入模板目录(服务器静态路径)等配置。
模板文件所在目录(Linux 示例:/www/wwwroot/FoodLabelingManagementUs/batchImportOfFiles)
Location Manager 导入模板文件名(与服务器上已上传文件名一致)
Team Member 导入模板文件名(与服务器上已上传文件名一致)
Product(Menu Management)导入模板文件名
Team Member 批量导入时,Excel 未填写「Password」列则使用的默认初始密码
单次导入最多处理的数据行数(不含表头)
上传 Excel 最大体积(字节),默认 10MB
单次「批量编辑」请求最多允许的条数(含空行过滤前的数组长度)
当前登录会话:菜单权限与退出
Dashboard 统计服务(美国版)
依据 PrintInputJson 中的保质期字段与「当前日期」比较得到 active/expired。
组织/分组(Account Management / Group,表 fl_group)
组织名称(Group Name)
所属合作伙伴 Id(fl_partner.Id)
是否启用(对应 UI Active)
按钮展示文案(为空则默认使用 CategoryName)
分类图/展示值:TEXT 可为图或空;COLOR 存色值(如 #409EFF);IMAGE 存图片 URL(与 ButtonAppearance 配合)
按钮外观:TEXT / COLOR / IMAGE(展示数据见 CategoryPhotoUrl)
门店可用范围:ALL / SPECIFIED
标签分类可用门店关联(对应表:fl_label_category_location)
json 字段,直接保存为字符串(入参/出参自行序列化/反序列化)
标签打印数据明细(对应表:fl_label_print_data)
标签打印任务(对应表:fl_label_print_task)
默认值JSON(字符串保存)
门店 Support 联系方式(每个门店仅一条,对 App Support 页展示)
合作伙伴主数据(Account Management / Partner,表 fl_partner)
合作伙伴名称(公司名)
联系邮箱
电话
是否启用(对应 UI Active)
按钮展示文案(为空则默认使用 CategoryName)
分类图/展示值:TEXT 可为图或空;COLOR 存色值;IMAGE 存图片 URL(与 ButtonAppearance 配合)
按钮外观:TEXT / COLOR / IMAGE(展示数据见 CategoryPhotoUrl)
门店可用范围:ALL / SPECIFIED
产品类别可用门店关联(对应表:fl_product_category_location)
menu 表映射(兼容数字/字符串类型的 Id、ParentId)
rolemenu 表映射(兼容字符串类型 RoleId/MenuId)
userlocation 表映射(成员-门店关联)
Food Labeling 示例应用服务实现(美国版)
组织(Group)管理(fl_group)
标签管理(一个产品展示多个标签)
标签预览:不落库,只把 template elements 的 AUTO_DB/PRINT_INPUT 渲染进 config
标签模板管理(Label Templates)
门店管理服务(美国版)
全局 Support 联系方式(全门店共用;Web 可增改查,App JWT 仅可读)
合作伙伴管理(fl_partner)
上传类别图片(保存到 /www/wwwroot/FoodLabelingManagementUs/picture)
返回的 Url 可直接保存到 CategoryPhotoUrl。
产品管理(Products)
生成未删除数据中不重复的 PRD_ 前缀产品编码。
去重、校验门店 Id 格式与存在性。
按产品维度替换 fl_location_product:先删本产品全部关联,再按列表插入(每门店一行)。
产品模块:类别(Categories)服务,对外仅在 food-labeling-us 暴露
类别分页列表
类别详情
新增类别
编辑类别
删除类别(逻辑删除)
产品-门店关联管理(fl_location_product)
权限(Menu)管理(食品标签-美国版对外)
角色管理(食品标签-美国版对外)
角色-权限关联(食品标签-美国版对外)
Reports(Print Log / Label Report)
成员(Team Member)服务,对外仅在 food-labeling-us 暴露
美国版 App 登录:邮箱 + 密码(与 AccountManager 相同盐值哈希)签发 JWT,并返回 userlocation 绑定门店
App 登录:签发 Token / RefreshToken,并返回当前账号绑定的门店列表
行为与系统 AccountService.PostLoginAsync 一致(含验证码、登录日志事件)。
门店数据来自 userlocation 与 location 表。
邮箱、密码;若系统开启验证码则需传 Uuid、Code
Token、RefreshToken 与绑定门店
登录成功
参数或验证码错误
服务器错误
获取当前登录用户已绑定的门店(切换门店时可重新拉取)
查询单个门店详情(Location 页):地址、门店电话、营业时间占位、店长(角色含 manager 的绑定用户)
仅当当前登录用户在 userlocation 中绑定该 locationId 时可查;否则返回业务异常。
店长:在同店绑定用户中,取 Role.RoleCode 或 Role.RoleName(忽略大小写)包含 manager 的第一条;
若无匹配则店长姓名与电话均为「无」。
OperatingHours:当前 location 表无营业时间字段,固定返回「无」。
门店主键(Guid 字符串)
与原型一致的展示字段
成功
未登录、门店标识无效、未绑定或门店不存在
服务器错误
按邮箱或用户名(邮箱形字符串写在 UserName 时)查找未删除且启用的用户;比较忽略大小写,Email 命中优先。
App Labeling:四级列表(标签分类 → 产品分类 → 产品 → 标签种类)
获取当前门店下四级嵌套数据
L1 标签分类 fl_label_category(含 buttonAppearance;COLOR/IMAGE 展示值在 categoryPhotoUrl);仅对当前门店可用:ALL 或 SPECIFIED 且在 fl_label_category_location;
L2 产品分类 fl_product.CategoryId join fl_product_category(同上,展示值在 categoryPhotoUrl);
L3 产品卡片:按「产品 + 标签模板」拆分(同一 productId、不同 fl_label.TemplateId 为多张卡);L4 为该卡下与门店、标签分类、该产品、该模板关联的标签实例(fl_label + fl_label_type)。
L2 仅包含对当前门店可用的类别:AvailabilityType=ALL,或 SPECIFIED 且在 fl_product_category_location 存在该门店记录;
未归类或分类行未关联到 fl_product_category 时仍归入「无」节点。
App 打印预览:按标签编码解析模板并返回顶部展示字段 + 预览模板结构
示例请求:
```json
{
"locationId": "LOC001",
"labelCode": "LBL0001",
"productId": "PROD001",
"baseTime": "2026-03-26T10:30:00",
"printInputJson": {
"price": "12.99"
}
}
```
预览入参
顶部字段 + 预览模板结构
成功
参数错误/数据不存在
服务器错误
App 打印:创建打印任务并落库打印明细(fl_label_print_task / fl_label_print_data)
打印入参
任务Id
App 重新打印:根据历史任务Id重打(创建新任务与明细)
App 打印日志:获取当前登录账号在当前门店打印的记录(分页,时间倒序)
仅返回满足:
- CreatedBy == CurrentUser.Id
- LocationId == input.LocationId
的打印任务记录(fl_label_print_task)。
示例请求:
```json
{
"locationId": "11111111-1111-1111-1111-111111111111",
"skipCount": 1,
"maxResultCount": 20
}
```
参数说明:
- locationId: 当前门店 Id(必填)
- skipCount: 页码(从 1 开始,遵循本项目约定)
- maxResultCount: 每页条数
分页查询入参
分页打印日志
成功
参数错误/未登录
服务器错误
将 App 入参中的 JsonElement(对象或 null)反序列化为 PreviewAsync 所需的扁平字典。