diff --git a/5-19泰额版.md b/5-19泰额版.md
deleted file mode 100644
index 3740ee5..0000000
--- a/5-19泰额版.md
+++ /dev/null
@@ -1,381 +0,0 @@
-# 5-19 泰额版 — 多租户(独立库)与接口说明
-
-本文档说明 **泰额版后端**(`泰额版/Food Labeling Management Code/Yi.Abp.Net8`)在 **2026-05-19** 起的多租户改造:**每个租户独立 MySQL 业务库**,平台主库仅存 `yitenant`;以及泰额专用登录、租户开通相关接口。
-
-> 与美国版业务接口(`food-labeling-us`)共用同一宿主时,调用业务 API 须携带租户上下文(见 [租户上下文](#租户上下文))。
-
----
-
-## 目录
-
-- [架构概览](#架构概览)
-- [数据库与 SQL 脚本](#数据库与-sql-脚本)
-- [应用配置](#应用配置)
-- [租户上下文](#租户上下文)
-- [泰额专用接口](#泰额专用接口)
- - [登录](#post-apiappth-app-authlogin)
- - [我的门店](#get-apiappth-app-authmy-locations)
- - [租户下拉 / 当前租户](#thmulti-tenancy)
- - [开通租户独立库](#post-apiappth-tenant-provisioningprovision)
- - [框架租户管理(补充)](#框架租户管理补充)
-- [业务接口联调](#业务接口联调)
-- [代码与脚本路径](#代码与脚本路径)
-- [常见问题](#常见问题)
-
----
-
-## 架构概览
-
-| 库 | 用途 | 连接来源 |
-|----|------|----------|
-| **平台主库** `antis-foodlabeling-host` | 仅 `yitenant`(租户元数据) | `appsettings` → `DbConnOptions.Url` |
-| **租户业务库** 如 `antis-foodlabeling-us` | `fl_*`、`location`、`user` 等 | `yitenant.TenantConnectionString` |
-
-```
-antis-foodlabeling-host (主库)
- └── yitenant
- ├── Default → antis-foodlabeling-us(迁移期默认租户 / 现有数据)
- └── 新租户 → antis-foodlabeling-{tenant}(Provision 自动建库)
-```
-
-- **不做** 业务表 `TenantId` 行级隔离(勿执行给 `fl_*` 加 `TenantId` 的 ALTER)。
-- 切换租户:请求头 `__tenant` 和/或 JWT 中的 `TenantId` Claim。
-- 无租户上下文时:连接**平台主库**(用于租户 CRUD、开通租户等)。
-
-**默认租户(迁移期)**
-
-| 项 | 值 |
-|----|-----|
-| Id | `11111111-1111-1111-1111-111111111111` |
-| Name | `Default` |
-| 业务库 | `antis-foodlabeling-us`(连接串写在 `yitenant.TenantConnectionString`) |
-
----
-
-## 数据库与 SQL 脚本
-
-脚本目录:`泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling/scripts/`
-
-### 执行顺序
-
-| 顺序 | 文件 | 说明 |
-|------|------|------|
-| 1 | `create_platform_host_database.sql` | 创建主库 `antis-foodlabeling-host` 及 `yitenant` 表 |
-| 2 | `migrate_yitenant_to_host.sql` | **可选**:若曾在业务库 `antis-foodlabeling-us` 中写过 `yitenant`,迁移到主库 |
-| 3 | `separate_database_bootstrap.sql` | 在主库登记默认租户,`TenantConnectionString` 指向 `antis-foodlabeling-us` |
-
-### 勿执行
-
-以下 **不要** 在业务库执行(共享库 + 行级 `TenantId` 方案已废弃):
-
-```sql
--- 勿执行
-ALTER TABLE fl_product ADD COLUMN TenantId ...
-UPDATE fl_product SET TenantId = ...
-```
-
-### 自检 SQL
-
-```sql
-USE antis-foodlabeling-host;
-
-SELECT Id, Name, LEFT(TenantConnectionString, 80) AS conn
-FROM yitenant
-WHERE Id = '11111111-1111-1111-1111-111111111111';
-```
-
-应有一条 `Default`,且 `conn` 中含 `database=antis-foodlabeling-us`。
-
----
-
-## 应用配置
-
-文件:`泰额版/.../src/Yi.Abp.Web/appsettings.json`
-
-| 配置项 | 说明 |
-|--------|------|
-| `DbConnOptions.Url` | 平台主库,如 `database=antis-foodlabeling-host` |
-| `DbConnOptions.EnabledSaasMultiTenancy` | `true` |
-| `FoodLabeling:MultiTenancy:Mode` | `SeparateDatabase` |
-| `FoodLabeling:TenantDatabase` | 新租户库名模板、RDS 账号等 |
-| `FoodLabeling:LegacyTenant` | 默认租户 Id / Name |
-
-新租户库名模板示例:`antis-foodlabeling-{tenant}`(`{tenant}` 为规范化后的租户名)。
-
----
-
-## 租户上下文
-
-业务请求须让后端解析到 **租户 Id**,任选其一(推荐登录后仅用 Bearer Token):
-
-| 方式 | 说明 |
-|------|------|
-| 请求头 | `__tenant: {租户Guid}` |
-| JWT | Claim:`TenantId`(`TokenTypeConst.TenantId`)及 `AbpClaimTypes.TenantId` |
-
-泰额登录签发的 Token 已写入上述 Claim;`JwtClaimTenantResolveContributor` 会自动解析。
-
-租户解析顺序(`YiAbpWebModule`):
-
-1. `HeaderTenantResolveContributor`(`__tenant`)
-2. `JwtClaimTenantResolveContributor`(JWT)
-
-> 独立库模式下**不会**自动回落到默认租户;未传租户时走主库连接,业务表可能查不到数据。
-
----
-
-## 泰额专用接口
-
-Swagger 分组:**泰额版-食品标签**(`FoodLabeling.Th.Application`)
-
-基础路径前缀:`/api/app/`(ABP 动态 API 约定,以 Swagger 为准)
-
-### `POST /api/app/th-app-auth/login`
-
-**应用服务**:`ThAppAuthAppService`
-**鉴权**:匿名
-
-**说明**:
-
-1. 在**平台主库**校验 `tenantId` 是否存在且已配置 `TenantConnectionString`。
-2. 切换到该租户业务库,按邮箱 + 密码校验 `user`(盐值哈希与美国版一致)。
-3. 签发 JWT(含 `TenantId`)、RefreshToken,并返回绑定门店列表。
-
-#### 入参 `ThAppLoginInputVo`
-
-| 字段 | 类型 | 必填 | 说明 |
-|------|------|------|------|
-| tenantId | Guid | 是 | 平台主库 `yitenant.Id` |
-| email | string | 是 | 登录邮箱(`user.Email` / 邮箱形 `UserName`) |
-| password | string | 是 | 密码 |
-| uuid | string | 否 | 图形验证码 UUID(系统开启验证码时必填) |
-| code | string | 否 | 图形验证码 |
-
-#### 请求示例
-
-```http
-POST /api/app/th-app-auth/login
-Content-Type: application/json
-```
-
-```json
-{
- "tenantId": "11111111-1111-1111-1111-111111111111",
- "email": "admin@example.com",
- "password": "YourPassword1!"
-}
-```
-
-#### 出参 `ThAppLoginOutputDto`
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| token | string | 访问令牌(含 TenantId Claim) |
-| refreshToken | string | 刷新令牌 |
-| tenantId | Guid | 当前租户 Id |
-| tenantName | string | 租户名称 |
-| locations | array | 绑定门店(结构同美国版 `UsAppBoundLocationDto`) |
-
-#### 出参示例
-
-```json
-{
- "token": "eyJhbGciOiJIUzI1NiIs...",
- "refreshToken": "...",
- "tenantId": "11111111-1111-1111-1111-111111111111",
- "tenantName": "Default",
- "locations": [
- {
- "id": "...",
- "locationCode": "LOC001",
- "locationName": "Store A",
- "fullAddress": "...",
- "state": true
- }
- ]
-}
-```
-
-#### JWT Claims(节选)
-
-| Claim | 说明 |
-|-------|------|
-| `TenantId` / `tenantid` | 租户 Guid 字符串 |
-| `client_kind` | `th_app` |
-| `sub` / `UserId` | 用户 Id |
-
-#### 错误说明
-
-| 提示 | 原因 |
-|------|------|
-| 请输入租户、邮箱与密码 | 参数缺失 |
-| 租户不存在或已停用 | 主库无该 `yitenant` 记录 |
-| 租户未配置业务库连接串 | `TenantConnectionString` 为空 |
-| 登录失败!邮箱不存在 | 租户库中无该用户 |
-| 用户名或密码错误 | 密码校验失败 |
-
----
-
-### `GET /api/app/th-app-auth/my-locations`
-
-**应用服务**:`ThAppAuthAppService`
-**鉴权**:Bearer Token
-
-**说明**:在**当前 JWT 租户上下文**下,查询 `userlocation` + `location` 绑定门店。
-
-```http
-GET /api/app/th-app-auth/my-locations
-Authorization: Bearer {token}
-```
-
-可选同时带:`__tenant: 11111111-1111-1111-1111-111111111111`(与 Token 中租户一致即可)。
-
----
-
-### ThMulti-tenancy
-
-**应用服务**:`ThMultiTenancyAppService`
-
-#### `GET /api/app/th-multi-tenancy/tenant-select`(方法名以 Swagger 为准,一般为 `get-tenant-select`)
-
-租户下拉列表(供登录页选择租户)。
-
-**出参**:`ThTenantSelectDto[]`
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| id | Guid | 租户 Id |
-| name | string | 租户名称 |
-
-#### `GET /api/app/th-multi-tenancy/current-tenant`(`get-current-tenant`)
-
-当前请求解析到的租户(调试用)。
-
-**出参**:`ThCurrentTenantDto`
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| tenantId | Guid? | 当前租户 Id |
-| tenantName | string? | 当前租户名称 |
-
----
-
-### `POST /api/app/th-tenant-provisioning/provision`
-
-**应用服务**:`ThTenantProvisioningAppService`
-**鉴权**:需登录(平台管理员)
-
-**说明**:
-
-1. 在**平台主库**写入 `yitenant`(含 `TenantConnectionString`)。
-2. 若未传连接串,按 `FoodLabeling:TenantDatabase` 生成,如 `antis-foodlabeling-{tenant}`。
-3. `initializeDatabase=true` 时调用 `InitAsync`:建库 + CodeFirst 业务表(**不含** `yitenant`)。
-
-#### 入参 `ThProvisionTenantInputVo`
-
-| 字段 | 类型 | 必填 | 说明 |
-|------|------|------|------|
-| name | string | 是 | 租户名称(用于生成库名) |
-| tenantConnectionString | string | 否 | 自定义连接串;空则按模板生成 |
-| dbType | int | 否 | SqlSugar.DbType,默认 `0` = MySql |
-| initializeDatabase | bool | 否 | 默认 `true`,是否立即建库建表 |
-
-#### 请求示例
-
-```http
-POST /api/app/th-tenant-provisioning/provision
-Content-Type: application/json
-Authorization: Bearer {token}
-```
-
-```json
-{
- "name": "acme",
- "initializeDatabase": true
-}
-```
-
-#### 出参 `ThProvisionTenantOutputDto`
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| tenantId | Guid | 新租户 Id |
-| name | string | 租户名称 |
-| databaseName | string | 业务库名 |
-| tenantConnectionString | string | 完整连接串 |
-| databaseInitialized | bool | 是否已执行 Init |
-
-#### `POST /api/app/th-tenant-provisioning/initialize-tenant-database`
-
-对已有租户补执行建库建表(入参:租户 `tenantId`,以 Swagger 为准)。
-
----
-
-### 框架租户管理(补充)
-
-分组:**租户管理接口**(`Yi.Framework.TenantManagement.Application`)
-
-| 方法 | 路径 | 说明 |
-|------|------|------|
-| POST | `/api/app/tenant` | 创建租户(需 `tenantConnectionString`) |
-| PUT | `/api/app/tenant/init/{id}` | 租户业务库 CodeFirst 初始化 |
-
-泰额推荐使用 `th-tenant-provisioning/provision` 一步完成登记 + 建库。
-
----
-
-## 业务接口联调
-
-宿主同时加载 `FoodLabeling.Application`(美国版业务)与 `FoodLabeling.Th.Application`。
-
-调用任意业务 API(如 `/api/app/product`、`/api/app/location`)时:
-
-```http
-GET /api/app/product?SkipCount=1&MaxResultCount=10
-Authorization: Bearer {泰额登录返回的 token}
-```
-
-或:
-
-```http
-GET /api/app/product?SkipCount=1&MaxResultCount=10
-Authorization: Bearer {token}
-__tenant: 11111111-1111-1111-1111-111111111111
-```
-
-**分页**:`SkipCount` 为 **1-based 页码**(与美国版一致,见 `5-18接口优化.md`)。
-
----
-
-## 代码与脚本路径
-
-| 类型 | 路径 |
-|------|------|
-| 泰额应用层 | `module/food-labeling/FoodLabeling.Th.Application/` |
-| 泰额契约 | `module/food-labeling/FoodLabeling.Th.Application.Contracts/` |
-| 美国版业务(共用) | `module/food-labeling-us/FoodLabeling.Application/` |
-| SQL 脚本 | `module/food-labeling/scripts/` |
-| 多租户常量 | `module/food-labeling-us/FoodLabeling.Domain.Shared/MultiTenancy/FoodLabelingMultiTenancyConsts.cs` |
-| JWT 租户解析 | `module/food-labeling-us/FoodLabeling.Application/MultiTenancy/JwtClaimTenantResolveContributor.cs` |
-| Web 配置 | `src/Yi.Abp.Web/appsettings.json`、`YiAbpWebModule.cs` |
-
----
-
-## 常见问题
-
-| 现象 | 处理 |
-|------|------|
-| 启动报连库失败 | 确认已执行 `create_platform_host_database.sql`,且 `DbConnOptions.Url` 指向 `antis-foodlabeling-host` |
-| 登录报租户不存在 | 在主库执行 `separate_database_bootstrap.sql` |
-| 登录成功但业务列表为空 | 检查 Token 是否带 `TenantId`;或请求头补 `__tenant` |
-| 业务接口查到主库无数据 | 未解析租户,误连主库;须登录泰额接口或传 `__tenant` |
-| 新租户无表 | 调用 `provision` 且 `initializeDatabase=true`,或 `PUT tenant/init/{id}` |
-| 误加了 TenantId 列 | 独立库模式不需要;可保留列但不使用,建议勿加 |
-
----
-
-## 变更记录
-
-| 日期 | 内容 |
-|------|------|
-| 2026-05-19 | 泰额版多租户独立库方案;平台主库分离;`ThAppAuth` 登录写 JWT TenantId;租户开通与 SQL 脚本说明 |
diff --git a/5-26代码优化.md b/5-26代码优化.md
deleted file mode 100644
index ca99bdc..0000000
--- a/5-26代码优化.md
+++ /dev/null
@@ -1,692 +0,0 @@
-# 5-26 代码优化
-
-本文档说明 **2026-05-26** 对美国版接口的变更。
-
-1. **`/api/app/product-category`**:新增/编辑 **`categoryCode` 取消必填**(见 [product-category-categoryCode](#product-category-categorycode-可选))。
-2. **`/api/app/label-template`**:新增/编辑/列表/详情支持 **Region、Location 多选数组**;列表 Query 增加 **Region/Location 筛选**(见 [label-template-regionlocation](#label-template-regionlocation-多选))。
-3. **`/api/app/rbac-role`**:修复 **`accessPermissions` JSON 数组**(如 `manage_labels`)无法绑定菜单(见 [rbac-role-accesspermissions](#rbac-role-accesspermissions-修复))。
-4. **`/api/app/auth-scope`**:管理员(及按数据范围受限账号)登录后 **Company → Region → Location** 级联选店(见 [auth-scope-登录选店](#auth-scope-登录后-company--region--location-级联选店))。
-5. **`/api/app/us-app-auth`**:App 管理员 Token 专用 **Company / Region / 门店筛选** 接口(见 [us-app-auth-管理员选店](#us-app-auth-app-管理员级联选店))。
-
-**应用服务**:`ProductCategoryAppService`、`LabelTemplateAppService`、`RbacRoleAppService`
-**命名约定**(与 5-17 / 5-18 一致):UI **Region** = API **`regionIds` / `groupIds` / `groupId`**(`fl_group.Id`);UI **Location** = **`locationIds` / `locationId`**(`location.Id`)。
-
----
-
-## product-category categoryCode 可选
-
-**影响接口**
-
-| 方法 | 路径 |
-|------|------|
-| POST | `/api/app/product-category` |
-| PUT | `/api/app/product-category/{id}` |
-
-### 变更说明
-
-| 项 | 变更前 | 变更后 |
-|----|--------|--------|
-| **categoryCode** | 必填;空则报「类别编码和名称不能为空」 | **可选**;可不传、传 `null` 或 `""` |
-| **categoryName** | 必填 | 仍必填 |
-| **落库** | — | 未填编码时 `CategoryCode` 存 **空字符串** |
-| **唯一性** | 编码或名称重复即报错 | 有编码:编码 **或** 名称重复报错;**无编码**:仅校验 **名称** 不重复 |
-
-### 入参(节选)
-
-| 字段 | 类型 | 必填 | 说明 |
-|------|------|------|------|
-| categoryCode | string | **否** | 类别编码 |
-| categoryName | string | **是** | 类别名称 |
-| regionIds / groupIds / locationIds | string[] | 否 | Region·Location 范围(规则见 `5-17接口优化.md`) |
-
-### 请求示例(无编码)
-
-```http
-POST /api/app/product-category
-Content-Type: application/json
-Authorization: Bearer {token}
-```
-
-```json
-{
- "categoryName": "Beverages",
- "buttonAppearance": "TEXT",
- "state": true,
- "availabilityType": "ALL",
- "orderNum": 0
-}
-```
-
-### 联调注意
-
-| 现象 | 处理 |
-|------|------|
-| 仍报「类别编码和名称不能为空」 | 确认已部署含本变更的后端;仅需保证 **categoryName** 非空 |
-| 无编码时名称重复 | 正常:仅按 **categoryName** 判重 |
-
-> Region/Location 多选、列表 `region`/`location` 展示等完整说明见 `5-17接口优化.md` → product-category 章节。
-
----
-
-## label-template Region·Location 多选
-
-**应用服务**:`LabelTemplateAppService`
-**存储表**:`fl_label_template_location`(模板 ↔ 门店,**无新表**)
-**主表字段**:`fl_label_template.AppliedLocationType` = `ALL` / `SPECIFIED`
-
-### 变更说明
-
-| 项 | 变更前 | 变更后 |
-|----|--------|--------|
-| **新增/编辑 Body** | 仅 `appliedLocation` + `appliedLocationIds` | 增加 **`regionIds`**、**`groupIds`**、**`locationIds`**(与 `appliedLocationIds` 合并) |
-| **列表 Query** | 仅 `locationId` | 增加 **`groupId`**(Region);`locationId` 优先于 `groupId`(与 product-category 一致) |
-| **列表出参** | 仅 `locationText`(单条展示) | 增加 **`region`**、**`location`** 展示 + **`regionIds`**、**`locationIds`** 数组 |
-| **详情出参** | `appliedLocationIds` | 同上,并保留 **`appliedLocationIds`**(与 `locationIds` 一致,兼容编辑器) |
-| **范围解析** | 仅显式门店 Id | Region 展开为门店后与门店 Id **取并集** 落库 |
-
-### 影响接口
-
-| 方法 | 路径 | 说明 |
-|------|------|------|
-| GET | `/api/app/label-template?SkipCount=1&MaxResultCount=10` | 列表支持 `groupId`/`locationId` 筛选;`items[]` 增加 `region`、`location`、`regionIds`、`locationIds` |
-| GET | `/api/app/label-template/{id}` | 详情增加上述字段 |
-| POST | `/api/app/label-template` | Body 支持 Region/Location 多选 |
-| PUT | `/api/app/label-template/{id}` | 同新增 |
-
-路径参数 **`id`** 仍为模板编码 **`TemplateCode`**(与编辑器 JSON 的 `id` 一致)。
-
-### 新增/编辑入参(Body:`LabelTemplateCreateInputVo`)
-
-| 字段 | JSON 名 | 类型 | 必填 | 说明 |
-|------|---------|------|------|------|
-| TemplateCode | `id` | string | 是 | 模板编码 |
-| TemplateName | `name` | string | 是 | 模板名称 |
-| AppliedLocationType | `appliedLocation` | string | 否 | `ALL` / `SPECIFIED`,默认 `ALL` |
-| RegionIds | `regionIds` | string[] | 否 | Region 多选(`fl_group.Id`) |
-| GroupIds | `groupIds` | string[] | 否 | 与 `regionIds` 等价,合并去重 |
-| LocationIds | `locationIds` | string[] | 否 | 门店多选(`location.Id`) |
-| AppliedLocationIds | `appliedLocationIds` | string[] | 否 | 兼容旧字段,与 `locationIds` 合并 |
-| Elements | `elements` | array | 否 | 模板组件,全量重建 |
-| TemplateProductDefaults | `templateProductDefaults` | array | 否 | 仅 **编辑** 时显式传入才重建 |
-
-**自动规则**
-
-| 入参 | 行为 |
-|------|------|
-| `regionIds` / `groupIds` / `locationIds` / `appliedLocationIds` 任一有有效 Id | `appliedLocation` 按 **`SPECIFIED`** 处理 |
-| 仅传空数组 `[]` 且 `appliedLocation` 为 `ALL` | 不绑定门店(全部门店) |
-| `appliedLocation: "SPECIFIED"` 且合并后无有效门店 | 报错:`指定适用区域或门店时,至少需要匹配到一个有效门店` |
-| `appliedLocation` 非法值 | 报错:`适用门店范围不合法(ALL/SPECIFIED)` |
-
-**合并规则**:每个 `regionIds` 展开为该 Region 下全部门店,再与 `locationIds`、`appliedLocationIds` **取并集** → 写入 `fl_label_template_location`。
-
-### 请求示例(Region + 门店多选)
-
-```http
-POST /api/app/label-template
-Content-Type: application/json
-Authorization: Bearer {token}
-```
-
-```json
-{
- "id": "TPL_TEST_001",
- "name": "Price Tag 4x6",
- "labelType": "PRICE",
- "unit": "inch",
- "width": 4,
- "height": 6,
- "appliedLocation": "SPECIFIED",
- "regionIds": [
- "fl_group_id_east",
- "fl_group_id_west"
- ],
- "locationIds": [
- "11111111-1111-1111-1111-111111111111"
- ],
- "showRuler": true,
- "showGrid": true,
- "state": true,
- "elements": []
-}
-```
-
-### 请求示例(全部门店,兼容旧版)
-
-```json
-{
- "id": "TPL_ALL",
- "name": "Global Template",
- "labelType": "PRICE",
- "unit": "inch",
- "width": 4,
- "height": 6,
- "appliedLocation": "ALL",
- "appliedLocationIds": [],
- "elements": []
-}
-```
-
-### 列表(`GET /api/app/label-template`)
-
-**Query 参数**
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| SkipCount / MaxResultCount | int | 分页(项目约定 SkipCount 从 1 起) |
-| keyword | string | 模板名称/编码模糊 |
-| **groupId** | string | **按 Region 筛选**(`fl_group.Id`):命中 `appliedLocation=ALL` 的模板,或在 `fl_label_template_location` 中绑定了该 Region 下任一门门店的模板 |
-| **locationId** | string | **按门店筛选**(`location.Id`);**优先于 groupId** |
-| labelType | string | 如 `PRICE` |
-| state | bool | 启用状态 |
-| sorting | string | 排序(可选) |
-
-**筛选规则**(与 product-category / label-type 相同,内部 `LocationScopeBindingHelper.ResolveScopedLocationIdsAsync`)
-
-| 入参 | 行为 |
-|------|------|
-| 均未传 `groupId`、`locationId` | 不过滤适用范围 |
-| 仅 `groupId` | 解析该 Region 下全部门店 Id,再筛模板 |
-| 仅 `locationId` | 按该门店 Id 筛模板 |
-| 同时传 | **以 `locationId` 为准**(忽略 `groupId`) |
-| Region/门店无效或解析结果为空 | 仅返回 **`appliedLocation=ALL`** 的模板 |
-
-命中条件(满足其一即可出现在列表):
-
-- `fl_label_template.AppliedLocationType = 'ALL'`
-- `SPECIFIED` 且 `fl_label_template_location` 中存在 `LocationId ∈` 解析得到的门店集合
-
-**请求示例**
-
-```http
-GET /api/app/label-template?SkipCount=1&MaxResultCount=10&groupId=fl_group_id_east HTTP/1.1
-Authorization: Bearer {token}
-```
-
-```http
-GET /api/app/label-template?SkipCount=1&MaxResultCount=10&locationId=11111111-1111-1111-1111-111111111111 HTTP/1.1
-Authorization: Bearer {token}
-```
-
-**命名对照**:UI **Region** → Query **`groupId`**;UI **Location** → Query **`locationId`**。
-
-### 列表出参
-
-**`items[]` 新增/对齐字段**
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| region | string | 适用 Region 展示文案 |
-| location | string | 适用门店展示文案 |
-| regionIds | string[] | Region Id 多选;`ALL` 时为 `[]` |
-| locationIds | string[] | 门店 Id 多选;`ALL` 时为 `[]` |
-| locationText | string | **兼容字段**,与 `location` 相同 |
-
-其它字段不变:`id`(= TemplateCode)、`templateName`、`contentsCount`、`sizeText`、`versionNo`、`lastEdited` 等。
-
-**列表响应示例片段**
-
-```json
-{
- "pageIndex": 1,
- "pageSize": 10,
- "totalCount": 2,
- "items": [
- {
- "id": "TPL_ALL",
- "templateCode": "TPL_ALL",
- "templateName": "Global Template",
- "labelType": "PRICE",
- "region": "All Regions",
- "location": "All Locations",
- "locationText": "All Locations",
- "regionIds": [],
- "locationIds": [],
- "contentsCount": 5,
- "sizeText": "4x6inch",
- "versionNo": 1,
- "lastEdited": "2026-05-26T10:00:00"
- },
- {
- "id": "TPL_TEST_001",
- "templateName": "Price Tag 4x6",
- "region": "East Region, West Region",
- "location": "UNCC store, Central Park Store",
- "locationText": "UNCC store, Central Park Store",
- "regionIds": ["fl_group_id_east", "fl_group_id_west"],
- "locationIds": [
- "11111111-1111-1111-1111-111111111111",
- "22222222-2222-2222-2222-222222222222"
- ],
- "contentsCount": 3,
- "sizeText": "4x6inch",
- "versionNo": 2,
- "lastEdited": "2026-05-26T11:30:00"
- }
- ]
-}
-```
-
-### 详情出参(`GET /api/app/label-template/{id}`)
-
-在原有 `elements`、`templateProductDefaults`、`appliedLocationType` 等基础上增加:
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| region | string | 展示文案 |
-| location | string | 展示文案 |
-| regionIds | string[] | Region Id 多选 |
-| groupIds | string[] | 与 `regionIds` 相同(兼容) |
-| locationIds | string[] | 门店 Id 多选 |
-| appliedLocationIds | string[] | 与 `locationIds` 一致(编辑器回显) |
-
-### 展示规则
-
-| appliedLocation | region | location | regionIds / locationIds |
-|-----------------|--------|----------|-------------------------|
-| **ALL** | `All Regions` | `All Locations` | 空数组 `[]` |
-| **SPECIFIED** | 绑定门店 `location.GroupName` 去重后 `, ` 拼接 | 门店名(优先 `LocationName`,否则 `LocationCode`)拼接 | 由绑定门店反推 / 直接为绑定 Id |
-| **SPECIFIED** 无绑定 | `无` | `无` | `[]` |
-
-`regionIds` 由 `locationIds` 反查 `fl_group` 得到(与 product-category、label-type 一致)。
-
-### 编辑说明
-
-- `PUT` Body 字段与 `POST` 相同;传 `regionIds` / `locationIds` 会 **全量替换** 模板适用门店(先删 `fl_label_template_location` 再插入)。
-- `elements` 仍为全量重建;`templateProductDefaults` 仅当 Body **显式包含** 该字段时才重建,避免普通保存误清空。
-- 编辑成功 **`versionNo` +1**。
-
-### 联调注意
-
-| 现象 | 处理 |
-|------|------|
-| 列表无 `regionIds` | 确认已部署含本变更的后端 |
-| 传 `groupId` 列表仍很多 | 正常:`appliedLocation=ALL` 的模板始终可见 |
-| 传 `groupId` 列表为空 | 检查 Region 是否存在、其下是否有门店;无效 Region 时仅剩 ALL 模板 |
-| 传了 Region 仍显示 All Locations | 检查 Region Id 是否有效、是否能在库中展开到门店 |
-| 仅 `appliedLocationIds` 不传 `locationIds` | 仍支持,与 `locationIds` 合并 |
-| 前端编辑器仍传 `appliedLocation: "ALL"` | 管理端若需多选,须在 Body 增加 `regionIds` / `locationIds`(见 `labelTemplateService.ts`) |
-| 指定范围但 0 门店 | 后端报错,需至少 1 个有效门店 |
-
-### 与 product-category / label-type 的关系
-
-逻辑与 **`5-17接口优化.md`** 中 product-category、label-type 的 Region·Location 绑定一致,差异仅为:
-
-| 模块 | 范围字段名 | 关联表 |
-|------|------------|--------|
-| product-category | `availabilityType` | `fl_product_category_location` |
-| label-type | `availabilityType` | `fl_label_type_location` |
-| **label-template** | **`appliedLocation`** | **`fl_label_template_location`** |
-
----
-
-## rbac-role accessPermissions 修复
-
-**应用服务**:`RbacRoleAppService`
-**影响接口**:`POST` / `PUT /api/app/rbac-role/{id}`、`GET` 列表/详情回显
-
-### 问题与根因
-
-| 现象 | 根因 |
-|------|------|
-| 保存报 `accessPermissions 未匹配到任何菜单` | 前端提交 **JSON 数组字符串**(如 `["manage_labels",...]`),旧逻辑按逗号拆分,解析结果带 `["` 引号,无法匹配 |
-| 传 `manage_labels` 等仍无菜单 | 表单权限码为 **UI 编码**(`manage_labels`),菜单侧为 **`menu.labels`**(由 `Menu.Router` 推导);二者未做映射 |
-| 详情 `accessPermissionCodes` 为空 | 新增/编辑未写入 **`Role.AccessPermissionCodes`**(JSON 列),仅依赖 `RoleMenu` 反查 |
-
-### 变更说明
-
-| 项 | 变更后 |
-|----|--------|
-| **入参解析** | `accessPermissions` 支持 **JSON 数组字符串**、逗号分隔、以及 Body 字段 **`accessPermissionCodes`** 数组 |
-| **菜单绑定** | UI 权限码经 **`RoleAccessPermissionMenuMapping`** 映射到 `Menu.Router`,再写入 **`RoleMenu`** |
-| **落库** | 同时将勾选的 UI 编码写入 **`Role.AccessPermissionCodes`**(JSON 数组),供 GET 回显 |
-| **PermissionCode 为空** | 仍可按 **`Router`** 推导 `menu.xxx`(建议执行 `menu_backfill_permission_code.sql`) |
-
-### UI 权限码 → 菜单 Router 映射(当前库)
-
-| accessPermissions(UI) | 绑定菜单 Router |
-|-------------------------|-----------------|
-| `manage_labels` | `/labeling`、`/labels`、`/label-categories`、`/label-types`、`/label-templates` |
-| `manage_people` | `/account-management` |
-| `edit_settings` | `/menu-management`、`/multiple-options` |
-| `view_reports` | `/reports` |
-| `manage_products` | (当前 `Menu` 表无 Products 路由,勾选不绑定菜单,**不单独报错**) |
-| `approve_batches` | (当前无对应菜单路由,同上) |
-
-> 至少 **1 个** 权限码能匹配到菜单即保存成功;若 **全部** 均无法匹配(例如只勾 `manage_products` 且库中无对应菜单),仍返回业务错误。
-
-### 请求示例(与前端一致)
-
-```http
-PUT /api/app/rbac-role/3a1f077b-3665-63f2-5fea-0fd7e7044b88
-Content-Type: application/json
-Authorization: Bearer {token}
-```
-
-```json
-{
- "roleName": "Partner Admin",
- "roleCode": "admin",
- "remark": "Admin",
- "dataScope": 0,
- "state": true,
- "orderNum": 999,
- "accessPermissions": "[\"manage_labels\",\"edit_settings\",\"view_reports\",\"manage_people\",\"manage_products\",\"approve_batches\"]"
-}
-```
-
-也可使用逗号分隔(旧格式):
-
-```json
-{
- "accessPermissions": "manage_labels, view_reports, manage_people"
-}
-```
-
-或同时传数组字段(与 `accessPermissions` 合并去重):
-
-```json
-{
- "accessPermissionCodes": ["manage_labels", "view_reports"]
-}
-```
-
-### 入参优先级(与 5-18 一致)
-
-| menuIds | accessPermissions / accessPermissionCodes | 行为 |
-|---------|-------------------------------------------|------|
-| 非空数组 | 任意 | **以 menuIds 为准** |
-| 不传 | 非空 | 按 UI 权限码映射菜单并覆盖 `RoleMenu` |
-| 不传 | `""` 或空数组 | 清空 `RoleMenu` 与 `AccessPermissionCodes` |
-| `[]` | 不传 | 清空绑定 |
-
-### 响应回显
-
-| 字段 | 说明 |
-|------|------|
-| `accessPermissionCodes` | 来自 **`Role.AccessPermissionCodes`**,如 `["manage_labels","view_reports"]` |
-| `accessPermissions` | 已绑定菜单的 **`menu.xxx`** 汇总(逗号拼接,只读展示) |
-| `menuIds` | 已绑定菜单 Guid 列表(`RoleMenu`) |
-
-### 数据库准备(推荐)
-
-```bash
-美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/scripts/menu_backfill_permission_code.sql
-```
-
-### 联调注意
-
-| 现象 | 处理 |
-|------|------|
-| 仍报未匹配到菜单 | 确认已部署本修复;检查 `Menu` 是否存在上表 Router |
-| 只勾 Products/Batches 报错 | 当前库无对应菜单属预期;请同时勾选 Labels/Reports 等 |
-| 同时传 `menuIds: []` | **menuIds 优先**,会清空绑定并忽略 accessPermissions |
-
-> 更完整的 RBAC 说明见 **`5-18接口优化.md`** → rbac-role 章节。
-
----
-
-## auth-scope 登录后 Company · Region · Location 级联选店
-
-**应用服务**:`AuthScopeAppService`
-**适用场景**:Web `POST /api/app/account/login` 或 App `POST /api/app/us-app-auth/login` 取得 Token 后,**管理员**无 `userlocation` 绑定时需先选工作门店;亦支持非管理员在数据范围内级联选择(须已绑定该门店)。
-
-**命名约定**(与 5-17 一致):UI **Company** = **`partnerId`**(`fl_partner.Id`);UI **Region** = **`groupId`**(`fl_group.Id`);UI **Location** = **`locationId`**(`location.Id`,Guid 字符串)。
-
-### 接口一览
-
-| 步骤 | 方法 | 路径 | 说明 |
-|------|------|------|------|
-| 1 | GET | `/api/app/auth-scope/companies` | 可选公司列表 |
-| 2 | GET | `/api/app/auth-scope/regions?partnerId={partnerId}` | 指定公司下 Region |
-| 3 | GET | `/api/app/auth-scope/locations?partnerId={partnerId}&groupId={groupId}` | 指定公司+Region 下门店 |
-| 4 | POST | `/api/app/auth-scope/select-location` | 确认当前工作门店 |
-| — | GET | `/api/app/auth-scope/current-scope` | 查询已选工作门店(未选返回 `null`) |
-
-**鉴权**:均需 `Authorization: Bearer {token}`。
-
-### 数据范围
-
-| 角色 | Company | Region | Location |
-|------|---------|--------|----------|
-| **管理员**(`admin` / 用户名 `admin` / 权限 `*:*:*`) | 全部未删除公司 | 该公司下全部 Region | 该 Region 下全部门店(`location.Partner` + `location.GroupName` 与 `fl_group` 一致) |
-| **非管理员** | `userlocation` 绑定门店所属公司 | 绑定门店对应 Region | 上述 Region 内且符合 `LocationRegionScopeHelper` 的门店;**选店时**须已绑定该 `locationId` |
-
-### 1)公司列表
-
-```http
-GET /api/app/auth-scope/companies HTTP/1.1
-Authorization: Bearer {token}
-```
-
-**响应**:`AuthScopeCompanyOptionDto[]`
-
-```json
-[
- { "id": "fl_partner_id_1", "partnerName": "Acme Foods", "state": true }
-]
-```
-
-### 2)Region 列表
-
-```http
-GET /api/app/auth-scope/regions?partnerId=fl_partner_id_1 HTTP/1.1
-Authorization: Bearer {token}
-```
-
-**响应**:`AuthScopeRegionOptionDto[]`
-
-```json
-[
- { "id": "fl_group_id_east", "groupName": "East Region", "partnerId": "fl_partner_id_1", "state": true }
-]
-```
-
-### 3)门店列表
-
-```http
-GET /api/app/auth-scope/locations?partnerId=fl_partner_id_1&groupId=fl_group_id_east HTTP/1.1
-Authorization: Bearer {token}
-```
-
-**响应**:`AuthScopeLocationOptionDto[]`(含 `fullAddress`、`groupName` 等)
-
-### 4)确认选店(与现有 App 逻辑对齐)
-
-```http
-POST /api/app/auth-scope/select-location HTTP/1.1
-Authorization: Bearer {token}
-Content-Type: application/json
-```
-
-```json
-{
- "partnerId": "fl_partner_id_1",
- "groupId": "fl_group_id_east",
- "locationId": "a2696b9e-2277-11f1-b4c6-00163e0c7c4f"
-}
-```
-
-**响应**:`AuthScopeSelectLocationOutputDto`
-
-| 字段 | 说明 |
-|------|------|
-| partnerId / partnerName | 所选公司 |
-| groupId / groupName | 所选 Region |
-| location | 与 **`UsAppBoundLocationDto`** 相同(`id`、`locationCode`、`locationName`、`fullAddress`、`state`) |
-
-**选店后的服务端行为**(无需改前端即可对接 App):
-
-| 能力 | 行为 |
-|------|------|
-| **工作范围缓存** | 写入分布式缓存(24h);退出 `POST /api/app/auth-session/logout` 时清除 |
-| **`GET /api/app/us-app-auth/my-locations`** | 管理员在缓存选店后,列表 **合并** 该门店(与 `userlocation` 并集) |
-| **`GET .../location-detail/{locationId}`** | 管理员可不依赖 `userlocation` 访问已选门店(`UsAppPrintLogScopeHelper.EnsureUserCanAccessLocationAsync`) |
-| **App 打印/报表** | 仍传 `locationId`;权限规则不变(见 `5-18接口优化.md`) |
-
-### 5)当前工作范围
-
-```http
-GET /api/app/auth-scope/current-scope HTTP/1.1
-Authorization: Bearer {token}
-```
-
-未选店时响应体为 **`null`**(HTTP 200)。
-
-### 联调注意
-
-| 现象 | 处理 |
-|------|------|
-| `regions` 为空 | 公司下无 `fl_group` 或当前账号无 Region 数据范围 |
-| `locations` 为空 | 门店 `Partner` / `GroupName` 未与 `fl_partner`、`fl_group` 对齐 |
-| 选店报「门店与所选公司/区域不匹配」 | 检查 `location.Partner`、`location.GroupName` |
-| 非管理员选店报未绑定 | 须在 **Team Member** 中为该账号绑定该门店 |
-| 选店后 `my-locations` 仍为空 | 确认已调 `select-location` 且 Token 为管理员身份 |
-
-> Web 管理端报表等模块仍可按 Query 传 `partnerId` / `groupId` / `locationId` 收窄;本组接口主要解决 **登录后选工作门店** 与 **App 门店列表** 一致性问题。
-
----
-
-## us-app-auth App 管理员级联选店
-
-**应用服务**:`UsAppAuthAppService`
-**适用场景**:App 使用 **`POST /api/app/us-app-auth/login`** 登录后,持 **管理员** 身份(`admin` 角色 / 用户名 `admin` / 权限 `*:*:*`)且 JWT 含 **`client_kind=us-app`**,按 Company → Region 筛选门店。
-
-**与 `auth-scope` 关系**:查询逻辑共用 `AuthScopeQueryHelper`;App 侧路径统一在 **`us-app-auth`** 下,并 **强制 App Token + 管理员**,避免误用 Web Token。
-
-### 接口一览
-
-| 步骤 | 方法 | 路径 | 说明 |
-|------|------|------|------|
-| 0 | POST | `/api/app/us-app-auth/login` | 获取 App Token(须管理员账号) |
-| 1 | GET | `/api/app/us-app-auth/admin-scope-companies` | 公司列表 → 取 `id` 作 `partnerId` |
-| 2 | GET | `/api/app/us-app-auth/admin-scope-regions?partnerId={partnerId}` | Region 列表 → 取 `id` 作 `groupId` |
-| 3 | GET | `/api/app/us-app-auth/admin-scope-locations?partnerId={partnerId}&groupId={groupId}` | **按公司与 Region Id 筛选门店** |
-| 4 | POST | `/api/app/us-app-auth/select-admin-scope-location` | 确认工作门店 |
-| — | GET | `/api/app/us-app-auth/my-locations` | 选店后刷新绑定门店(含缓存门店) |
-
-**鉴权**:步骤 1–4 须 Header `Authorization: Bearer {App登录返回的token}`。
-
-### 前置条件
-
-| 项 | 要求 |
-|----|------|
-| Token 来源 | 必须来自 **`/api/app/us-app-auth/login`**(非 Web `/api/app/account/login`) |
-| JWT 声明 | `client_kind` = `us-app` |
-| 角色 | 平台管理员(`ReportsRoleHelper.IsAdminRole`) |
-| 违反时 | `请使用 App 登录令牌调用该接口` 或 `仅管理员可使用公司/区域/门店筛选接口` |
-
-### 1)公司列表
-
-```http
-GET /api/app/us-app-auth/admin-scope-companies HTTP/1.1
-Authorization: Bearer {app_token}
-```
-
-**响应**:`AuthScopeCompanyOptionDto[]`(与 auth-scope 相同)
-
-```json
-[
- { "id": "fl_partner_id_1", "partnerName": "Acme Foods", "state": true }
-]
-```
-
-### 2)Region 列表
-
-```http
-GET /api/app/us-app-auth/admin-scope-regions?partnerId=fl_partner_id_1 HTTP/1.1
-Authorization: Bearer {app_token}
-```
-
-**响应**:`AuthScopeRegionOptionDto[]`
-
-```json
-[
- { "id": "fl_group_id_east", "groupName": "East Region", "partnerId": "fl_partner_id_1", "state": true }
-]
-```
-
-### 3)门店列表(按 partnerId + groupId 筛选)
-
-```http
-GET /api/app/us-app-auth/admin-scope-locations?partnerId=fl_partner_id_1&groupId=fl_group_id_east HTTP/1.1
-Authorization: Bearer {app_token}
-```
-
-**Query**
-
-| 参数 | 必填 | 说明 |
-|------|------|------|
-| partnerId | 是 | 公司 Id(`fl_partner.Id`) |
-| groupId | 是 | Region Id(`fl_group.Id`) |
-
-**响应**:`AuthScopeLocationOptionDto[]`
-
-```json
-[
- {
- "id": "a2696b9e-2277-11f1-b4c6-00163e0c7c4f",
- "locationCode": "LOC-1",
- "locationName": "Downtown Kitchen",
- "fullAddress": "123 Main St, New York, NY 10001",
- "state": true,
- "partnerId": "fl_partner_id_1",
- "groupId": "fl_group_id_east",
- "groupName": "East Region"
- }
-]
-```
-
-筛选规则:`location.Partner` 匹配该公司(Id 或名称),且 `location.GroupName` 与所选 `fl_group.GroupName` 一致。
-
-### 4)确认选店
-
-```http
-POST /api/app/us-app-auth/select-admin-scope-location HTTP/1.1
-Authorization: Bearer {app_token}
-Content-Type: application/json
-```
-
-```json
-{
- "partnerId": "fl_partner_id_1",
- "groupId": "fl_group_id_east",
- "locationId": "a2696b9e-2277-11f1-b4c6-00163e0c7c4f"
-}
-```
-
-**响应**:`AuthScopeSelectLocationOutputDto`(含 `location` 节点,结构同 `UsAppBoundLocationDto`)
-
-### 推荐调用顺序(App)
-
-```text
-POST /api/app/us-app-auth/login
- → GET admin-scope-companies
- → GET admin-scope-regions?partnerId=...
- → GET admin-scope-locations?partnerId=...&groupId=...
- → POST select-admin-scope-location
- → GET my-locations
- → 后续业务接口传 locationId(打印、报表等,规则不变)
-```
-
-### 联调注意
-
-| 现象 | 处理 |
-|------|------|
-| 报「请使用 App 登录令牌」 | 勿用 Web `account/login` 的 Token;须重新 App 登录 |
-| 报「仅管理员可使用」 | 换管理员账号或绑定 `admin` 角色 |
-| `locations` 为空 | 核对门店 `Partner`、`GroupName` 与 `fl_partner`、`fl_group` |
-| 与 auth-scope 重复 | App 端 **优先** 使用本节前缀;Web 端用 `auth-scope` |
-
----
-
-## 变更记录
-
-| 日期 | 说明 |
-|------|------|
-| 2026-05-26 | us-app-auth:App 管理员 `admin-scope-companies/regions/locations`、`select-admin-scope-location` |
-| 2026-05-26 | auth-scope:登录后 Company/Region/Location 级联选店;选店缓存;`my-locations` / 门店详情与管理员选店对齐 |
-| 2026-05-26 | product-category:`categoryCode` 新增/编辑改为可选 |
-| 2026-05-26 | label-template:新增/编辑/列表/详情支持 `regionIds`、`locationIds` 及 `region`、`location` 展示 |
-| 2026-05-26 | label-template 列表 Query 增加 `groupId`(Region)、`locationId`(门店)筛选 |
-| 2026-05-26 | rbac-role:支持 accessPermissions JSON 数组 + UI 权限码映射 Menu;落库 AccessPermissionCodes |
diff --git a/泰额版/Food Labeling Management App UniApp/nativeplugins/native-fast-printer/android/native_fast_printer-release.aar b/泰额版/Food Labeling Management App UniApp/nativeplugins/native-fast-printer/android/native_fast_printer-release.aar
index 4334e46..d64c21f 100644
--- a/泰额版/Food Labeling Management App UniApp/nativeplugins/native-fast-printer/android/native_fast_printer-release.aar
+++ b/泰额版/Food Labeling Management App UniApp/nativeplugins/native-fast-printer/android/native_fast_printer-release.aar
diff --git a/泰额版/Food Labeling Management App UniApp/nativeplugins/native-fast-printer/package.json b/泰额版/Food Labeling Management App UniApp/nativeplugins/native-fast-printer/package.json
index dc819d1..6e9e837 100644
--- a/泰额版/Food Labeling Management App UniApp/nativeplugins/native-fast-printer/package.json
+++ b/泰额版/Food Labeling Management App UniApp/nativeplugins/native-fast-printer/package.json
@@ -1,7 +1,7 @@
{
"name": "native-fast-printer",
"id": "native-fast-printer",
- "version": "1.2.8",
+ "version": "1.0.3",
"description": "Android高速标签打印原生插件",
"_dp_type": "nativeplugin",
"_dp_nativeplugin": {
@@ -23,8 +23,7 @@
"abis": [
"armeabi-v7a",
"arm64-v8a",
- "x86",
- "x86_64"
+ "x86"
],
"minSdkVersion": "21",
"useAndroidX": true,
diff --git a/泰额版/Food Labeling Management App UniApp/scripts/sync-native-fast-printer.ps1 b/泰额版/Food Labeling Management App UniApp/scripts/sync-native-fast-printer.ps1
index 6969aa1..595025e 100644
--- a/泰额版/Food Labeling Management App UniApp/scripts/sync-native-fast-printer.ps1
+++ b/泰额版/Food Labeling Management App UniApp/scripts/sync-native-fast-printer.ps1
@@ -6,12 +6,17 @@ $dstPluginRoot = Join-Path $appRoot "nativeplugins\native-fast-printer"
$manifestPath = Join-Path $appRoot "src\manifest.json"
Write-Host "[1/4] Validate source plugin files..."
-$sourceAarItem = Get-ChildItem -LiteralPath $repoRoot -Recurse -File -Filter "native_fast_printer-release.aar" |
- Where-Object { $_.FullName -notlike "*\nativeplugins\native-fast-printer\android\*" } |
- Sort-Object LastWriteTime -Descending |
- Select-Object -First 1
+$preferredAar = Join-Path $repoRoot "打印机安卓基座\native-fast-printer\android\native_fast_printer-release.aar"
+$sourceAarItem = $null
+if (Test-Path -LiteralPath $preferredAar) {
+ $sourceAarItem = Get-Item -LiteralPath $preferredAar
+} else {
+ $sourceAarItem = Get-ChildItem -LiteralPath (Join-Path $repoRoot "打印机安卓基座") -Recurse -File -Filter "native_fast_printer-release.aar" -ErrorAction SilentlyContinue |
+ Sort-Object LastWriteTime -Descending |
+ Select-Object -First 1
+}
if ($null -eq $sourceAarItem) {
- throw "AAR not found under repository root: $repoRoot"
+ throw "AAR not found. Build first: 打印机安卓基座/native-fast-printer/android-src/build-aar-windows.bat"
}
$srcPluginRoot = Split-Path -Parent (Split-Path -Parent $sourceAarItem.FullName)
diff --git a/泰额版/Food Labeling Management App UniApp/src/components/AppDatePicker.vue b/泰额版/Food Labeling Management App UniApp/src/components/AppDatePicker.vue
new file mode 100644
index 0000000..76043da
--- /dev/null
+++ b/泰额版/Food Labeling Management App UniApp/src/components/AppDatePicker.vue
@@ -0,0 +1,287 @@
+
+
+
+ {{ displayText }}
+
+
+
+
+ {{ dialogTitle }}
+
+
+ {{ y }}
+
+
+ {{ m }}
+
+
+ {{ d }}
+
+
+
+
+ Cancel
+
+
+ Confirm
+
+
+
+
+
+
+
+
+
+
diff --git a/泰额版/Food Labeling Management App UniApp/src/locales/en.ts b/泰额版/Food Labeling Management App UniApp/src/locales/en.ts
index 64a4095..3f55f9e 100644
--- a/泰额版/Food Labeling Management App UniApp/src/locales/en.ts
+++ b/泰额版/Food Labeling Management App UniApp/src/locales/en.ts
@@ -50,6 +50,14 @@ export default {
selectStoreDesc: 'Select the store where you\'ll be working today',
selectStoreError: 'Please select a store',
storeSelected: 'Store selected successfully',
+ scopeCompany: 'Company',
+ scopeRegion: 'Region',
+ scopeLoading: 'Loading…',
+ scopeNoCompanies: 'No companies available',
+ scopeNoRegions: 'No regions for this company',
+ selectCompanyRegionFirst: 'Select company and region first',
+ scopeLoadFail: 'Could not load options',
+ scopeSelectFail: 'Could not confirm store',
store1: 'Downtown Kitchen', store2: 'Brooklyn Central', store3: 'Queens Food Hub', store4: 'Manhattan Express',
},
dashboard: {
diff --git a/泰额版/Food Labeling Management App UniApp/src/locales/zh.ts b/泰额版/Food Labeling Management App UniApp/src/locales/zh.ts
index f15fd1e..87a55c4 100644
--- a/泰额版/Food Labeling Management App UniApp/src/locales/zh.ts
+++ b/泰额版/Food Labeling Management App UniApp/src/locales/zh.ts
@@ -50,6 +50,14 @@ export default {
selectStoreDesc: '选择您今天工作的店铺',
selectStoreError: '请选择一个店铺',
storeSelected: '店铺选择成功',
+ scopeCompany: '公司',
+ scopeRegion: '区域',
+ scopeLoading: '加载中…',
+ scopeNoCompanies: '暂无可用公司',
+ scopeNoRegions: '该公司下暂无区域',
+ selectCompanyRegionFirst: '请先选择公司与区域',
+ scopeLoadFail: '选项加载失败',
+ scopeSelectFail: '确认门店失败',
store1: '市中心厨房', store2: '布鲁克林中心', store3: '皇后食品中心', store4: '曼哈顿快速店',
},
dashboard: {
diff --git a/泰额版/Food Labeling Management App UniApp/src/pages/labels/bluetooth.vue b/泰额版/Food Labeling Management App UniApp/src/pages/labels/bluetooth.vue
index 50fc183..ba8b132 100644
--- a/泰额版/Food Labeling Management App UniApp/src/pages/labels/bluetooth.vue
+++ b/泰额版/Food Labeling Management App UniApp/src/pages/labels/bluetooth.vue
@@ -225,8 +225,8 @@
1. Ensure the printer is powered on and in pairing mode
2. On Android: enable Location (required for Bluetooth scan)
3. Place the printer within 10 m and tap Scan again
- 4. Devices with no name show as "Unknown Device"—you can still connect
- 5. GP-D320FX (d320fx_xxxx): use Bluetooth mode, tap Scan—shows paired + nearby devices, no filtering
+ 4. Scan list only shows: GP-D320FX-spp_A7FO and Virtual BT Printer
+ 5. Pair the printer in system Bluetooth first if it does not appear after Scan
6. Restart the printer or app if not visible
7. Built-in TSC: defaults to TSPL label commands via UPOS; use Advanced → ESC/POS only if your device is receipt-only.
@@ -290,6 +290,7 @@ import {
setBuiltinPrinter,
} from '../../utils/print/printerConnection'
import { ensureBluetoothPermissions } from '../../utils/print/bluetoothPermissions'
+import { isAllowedBluetoothPrinterName } from '../../utils/print/bluetoothPrinterAllowlist'
import {
getNativeFastPrinterDebugInfo,
getNativeFastPrinterState,
@@ -432,14 +433,12 @@ function handleResetUposOptions () {
}
function hasPreferredClassicDeviceInList () {
- return devices.value.some((item: any) => {
- const name = String(item?.name || '').toLowerCase()
- const driverKey = String(item?.driverKey || '').toLowerCase()
- return name.includes('virtual bt printer') || driverKey === 'd320fax'
- })
+ return devices.value.some((item: any) => isAllowedBluetoothPrinterName(item?.name))
}
function upsertDevice (device: any) {
+ const rawName = (device?.name || device?.localName || '').trim()
+ if (!isAllowedBluetoothPrinterName(rawName)) return
const described = describeDiscoveredPrinter(device)
const existing = devices.value.find(item => item.deviceId === described.deviceId)
if (!existing) {
@@ -573,7 +572,9 @@ function addPairedDevices () {
try {
const paired = classic.getPairedDevices()
debugInfo.value.pairedCount = (paired || []).length
- debugInfo.value.foundVirtualPrinter = (paired || []).some((item: any) => String(item?.name || '').toLowerCase().includes('virtual bt printer'))
+ debugInfo.value.foundVirtualPrinter = (paired || []).some((item: any) =>
+ isAllowedBluetoothPrinterName(item?.name) && String(item?.name || '').toLowerCase().includes('virtual bt'),
+ )
for (const p of paired) {
upsertDevice({
deviceId: p.deviceId,
diff --git a/泰额版/Food Labeling Management App UniApp/src/pages/labels/labels.vue b/泰额版/Food Labeling Management App UniApp/src/pages/labels/labels.vue
index 2d33469..0c0d584 100644
--- a/泰额版/Food Labeling Management App UniApp/src/pages/labels/labels.vue
+++ b/泰额版/Food Labeling Management App UniApp/src/pages/labels/labels.vue
@@ -105,16 +105,20 @@
:key="productCategoryRowKey(pCat, pIdx)"
class="cat-section"
>
-