49755ef0
李曜臣
6-12代码优化
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
|
# 6-4 代码优化
本文档说明 **2026-06-04** 对美国版 **`/api/app/label-template`** 新增/编辑接口的 **Company / Region / Location** 三维适用范围改造。
---
## 背景
标签模板除画布与控件外,需按 **Company(Partner)**、**Region(Group)**、**Location(门店)** 三个维度配置可见范围:
- 各维度支持 **全选(ALL)** 或 **指定(SPECIFIED + Id 数组)**
- 支持 **单选 / 多选**
- 新增与编辑使用同一套 Body 字段
测试环境基址:`http://flus-test.3ffoodsafety.com`
---
## 接口一览
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/app/label-template` | 分页列表(含 `company` / `region` / `location` 展示与 Id 数组) |
| GET | `/api/app/label-template/{templateCode}` | 详情 |
| POST | `/api/app/label-template` | 新增 |
| PUT | `/api/app/label-template/{templateCode}` | 编辑(版本号 +1,全量重建 elements) |
| DELETE | `/api/app/label-template/{templateCode}` | 逻辑删除 |
---
## 适用范围字段(POST / PUT Body)
三个维度 **相互独立**,列表/详情筛选时按 **AND** 组合(某维度为 ALL 表示该维度不限制)。
| 字段 | 类型 | 说明 |
|------|------|------|
| `appliedPartnerType` | `ALL` \| `SPECIFIED` | 适用 **Company**;默认 `ALL` |
| `partnerIds` | `string[]` | Company Id(`fl_partner.Id`);与 `companyIds` 合并去重 |
| `companyIds` | `string[]` | 与 `partnerIds` 相同(兼容别名) |
| `appliedRegionType` | `ALL` \| `SPECIFIED` | 适用 **Region**;默认 `ALL` |
| `regionIds` | `string[]` | Region Id(`fl_group.Id`);与 `groupIds` 合并去重 |
| `groupIds` | `string[]` | 与 `regionIds` 相同(兼容别名) |
| `appliedLocation` | `ALL` \| `SPECIFIED` | 适用 **Location**(与历史字段一致);默认 `ALL` |
| `locationIds` | `string[]` | 门店 Id(`location.Id`) |
| `appliedLocationIds` | `string[]` | 与 `locationIds` 合并去重(兼容旧前端) |
### 解析规则
1. 某维度 Id 数组 **非空** → 该维度自动视为 `SPECIFIED`(即使未传 `applied*Type`)。
2. 传了空数组 `[]` 且对应 `applied*Type=ALL` → 该维度 **全选**。
3. `applied*Type=SPECIFIED` 且对应 Id 数组为空 → 返回 **400** 友好错误。
4. 任一维度为 `SPECIFIED` 时,合并后的有效门店集合不能为空(至少匹配到一个门店)。
### 示例
**全选(默认,三维度均 ALL)**
```json
{
"id": "tpl-price-001",
"name": "Price Label",
"labelType": "PRICE",
"unit": "inch",
"width": 4,
"height": 2,
"appliedPartnerType": "ALL",
"appliedRegionType": "ALL",
"appliedLocation": "ALL",
"partnerIds": [],
"regionIds": [],
"locationIds": [],
"elements": []
}
```
**指定 Company + Region 多选**
```json
{
"appliedPartnerType": "SPECIFIED",
"partnerIds": ["1234567890123456789"],
"appliedRegionType": "SPECIFIED",
"regionIds": ["9876543210987654321", "9876543210987654322"],
"appliedLocation": "ALL",
"locationIds": []
}
```
**仅指定门店多选**
```json
{
"appliedPartnerType": "ALL",
"appliedRegionType": "ALL",
"appliedLocation": "SPECIFIED",
"locationIds": ["550e8400-e29b-41d4-a716-446655440000"]
}
```
---
## 出参(详情 GET / 列表 Items)
除原有 `templateCode`、`elements`、`items` 等外,增加:
| 字段 | 说明 |
|------|------|
| `company` | 展示文案:`All Companies` 或 Partner 名称逗号拼接 |
| `region` | `All Regions` 或 Region 名称拼接 |
| `location` | `All Locations` 或门店名称拼接 |
| `appliedPartnerType` / `appliedRegionType` / `appliedLocationType` | 各维度类型 |
| `partnerIds` / `companyIds` | Company Id 数组(ALL 时 `[]`) |
| `regionIds` / `groupIds` | Region Id 数组 |
| `locationIds` / `appliedLocationIds` | 门店 Id 数组 |
---
## 数据库存储
**DDL 脚本(可重复执行)**:
`美国版/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.AppliedLocationType` | Location:`ALL` / `SPECIFIED`(原有列,语义收窄为 Location 维度) |
| `fl_label_template_partner` | `TemplateId` + `PartnerId` 多选明细 |
| `fl_label_template_region` | `TemplateId` + `GroupId` 多选明细 |
| `fl_label_template_location` | `TemplateId` + `LocationId`(仅 Location 维度 SPECIFIED 时写入) |
> **部署注意**:测试/生产库须先执行 DDL,再部署含本改动的后端,否则写入新字段可能失败。
### 兼容旧数据
- 历史仅配置 `AppliedLocationType=SPECIFIED` + `fl_label_template_location` 的模板:Partner/Region 默认为 `ALL`,Location 仍按 junction 表回读。
- 列表权限筛选:三维度 AND;旧「仅门店 junction」数据行为保持不变。
---
## 列表筛选
`GET /api/app/label-template` 仍支持 Query:
- `groupId`(Region)
- `locationId`(门店)
按当前用户 Token 可见门店范围过滤模板(与 Team Member / Label 列表一致)。
---
## 涉及代码文件
| 层级 | 文件 |
|------|------|
| DDL | `scripts/fl_label_template_scope.sql` |
| Helper | `Helpers/LabelTemplateScopeHelper.cs` |
| 实体 | `FlLabelTemplateDbEntity.cs`、`FlLabelTemplatePartnerDbEntity.cs`、`FlLabelTemplateRegionDbEntity.cs` |
| DTO | `LabelTemplateCreateInputVo.cs`、`LabelTemplateGetOutputDto.cs`、`LabelTemplateGetListOutputDto.cs` |
| 服务 | `LabelTemplateAppService.cs` |
| 前端类型 | `src/types/labelTemplate.ts`(`buildLabelTemplateScopePayload`) |
| 前端 API | `src/services/labelTemplateService.ts` |
| 前端页面 | `LabelTemplatesView.tsx`、`LabelTemplateEditor/index.tsx` |
---
## 验证步骤
1. 在目标库执行 `fl_label_template_scope.sql`。
2. 部署后端并重启。
3. **POST** 创建模板:`appliedRegionType=SPECIFIED` + `regionIds`,详情应回显 `regionIds` 与 `region` 文案。
4. **PUT** 编辑为全选:三维度 `ALL` + 空数组,junction 表对应记录应清空。
5. **GET** 列表:新列 `company` / `region` / `location` 与 Id 数组一致。
6. 库内抽查:
```sql
SELECT AppliedPartnerType, AppliedRegionType, AppliedLocationType
FROM fl_label_template WHERE TemplateCode = '你的模板编码';
SELECT * FROM fl_label_template_partner WHERE TemplateId = (
SELECT Id FROM fl_label_template WHERE TemplateCode = '你的模板编码' LIMIT 1
);
```
---
## curl 示例(需先登录取 Token)
```bash
# 新增:指定 Region
curl -X POST "http://flus-test.3ffoodsafety.com/api/app/label-template" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"id": "test-scope-tpl",
"name": "Scope Test",
"labelType": "PRICE",
"unit": "inch",
"width": 4,
"height": 2,
"appliedRegionType": "SPECIFIED",
"regionIds": ["{fl_group.Id}"],
"appliedPartnerType": "ALL",
"appliedLocation": "ALL",
"elements": []
}'
```
|