4d328ec2
李曜臣
平台端报表reports,仪表盘D...
|
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
|
# 合作伙伴(Partner)与组织(Group)接口对接说明
> 适用范围:美国版 Web 管理端「Account Management」下的 **Partner**、**Group** 主数据
> **Partner** 表:`fl_partner`,接口:`IPartnerAppService` / `PartnerAppService`
> **Group** 表:`fl_group`(`PartnerId` 关联 `fl_partner.Id`),接口:`IGroupAppService` / `GroupAppService`
> 宿主路由前缀:`/api/app`(与 `YiAbpWebModule` 中 `RootPath = api/app` 一致)
---
## 0. 通用说明
- **鉴权**:需要登录(`Authorization: Bearer {token}`),与其它 `/api/app/*` 接口一致。
- **Content-Type**:`POST` / `PUT` 使用 `application/json`。
- **分页约定(美国版食品标签模块)**:`skipCount` 表示**页码(从 1 起)**,不是 0 基 offset;第一页请传 `skipCount=1`。与 `PagedQueryConvention` 及 SqlSugar `ToPageListAsync` 用法一致。
- **逻辑删除**:`DELETE` 将对应表的 `IsDeleted` 置为 `true`(`fl_partner` / `fl_group`),不物理删行。
- **列表与导出筛选一致**:各模块列表的筛选字段与对应 **export-pdf** 接口一致,便于数据对齐。
- **Group 与 Partner**:新建/编辑 Group 时 `partnerId` 必须指向**未逻辑删除**的 `fl_partner`;列表左联 Partner 时仅展示未删除合作伙伴名称,已删 Partner 在列表中显示为 **`无`**。
---
# 第一部分:Partner(合作伙伴)
## 1. 分页列表
- **方法**:`GET`
- **路径**:`/api/app/partner`
### 1.1 查询参数(`PartnerGetListInputVo`)
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `skipCount` | int | 是 | 页码,从 **1** 开始 |
| `maxResultCount` | int | 是 | 每页条数 |
| `sorting` | string | 否 | 排序,仅支持白名单(见下) |
| `keyword` | string | 否 | 模糊匹配 `PartnerName`、`ContactEmail`、`PhoneNumber` |
| `state` | bool | 否 | 按启用状态筛选;不传则不过滤 |
**排序白名单**(大小写不敏感):
- `PartnerName asc` / `PartnerName desc`
- `CreationTime asc` / `CreationTime desc`
- `State asc` / `State desc`
其它值将回退为默认:**按 `CreationTime` 降序**。
### 1.2 请求示例
```http
GET /api/app/partner?skipCount=1&maxResultCount=10&keyword=Global&state=true&sorting=CreationTime%20desc HTTP/1.1
Authorization: Bearer {token}
```
### 1.3 响应结构(`PagedResultWithPageDto<PartnerGetListOutputDto>`)
```json
{
"pageIndex": 1,
"pageSize": 10,
"totalCount": 2,
"totalPages": 1,
"items": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"partnerName": "Global Foods Inc.",
"contactEmail": "admin@globalfoods.com",
"phoneNumber": "+1 (555) 100-2000",
"state": true,
"creationTime": "2026-04-27T10:00:00"
}
]
}
```
### 1.4 列表项字段(`PartnerGetListOutputDto`)
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | string | 主键 |
| `partnerName` | string | 合作伙伴名称 |
| `contactEmail` | string \| null | 联系邮箱 |
| `phoneNumber` | string \| null | 电话 |
| `state` | bool | 是否启用(UI Active 开关) |
| `creationTime` | string (datetime) | 创建时间 |
---
## 2. 详情
- **方法**:`GET`
- **路径**:`/api/app/partner/{id}`
### 2.1 路径参数
| 参数 | 说明 |
|------|------|
| `id` | `fl_partner.Id` |
### 2.2 响应结构(`PartnerGetOutputDto`)
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | string | 主键 |
| `partnerName` | string | 合作伙伴名称 |
| `contactEmail` | string \| null | 联系邮箱 |
| `phoneNumber` | string \| null | 电话 |
| `state` | bool | 是否启用 |
| `creationTime` | string (datetime) | 创建时间 |
| `lastModificationTime` | string (datetime) \| null | 最后修改时间 |
### 2.3 错误说明
- `id` 为空或记录不存在(含已逻辑删除):业务错误提示「合作伙伴不存在」等。
---
## 3. 新增
- **方法**:`POST`
- **路径**:`/api/app/partner`
### 3.1 Body(`PartnerCreateInputVo`)
```json
{
"partnerName": "Global Foods Inc.",
"contactEmail": "admin@globalfoods.com",
"phoneNumber": "+1 (555) 100-2000",
"state": true
}
```
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `partnerName` | string | 是 | 合作伙伴名称,去首尾空格后不能为空 |
| `contactEmail` | string | 否 | 若填写则做简单格式校验(含 `@` 等) |
| `phoneNumber` | string | 否 | 电话 |
| `state` | bool | 否 | 默认 `true` |
### 3.2 响应
- 成功:返回 `PartnerGetOutputDto`(与详情结构一致)。
---
## 4. 编辑
- **方法**:`PUT`
- **路径**:`/api/app/partner/{id}`
### 4.1 参数
- **Path**:`id` 为当前合作伙伴主键。
- **Body**:`PartnerUpdateInputVo`,字段与新增相同。
```json
{
"partnerName": "Global Foods Inc.",
"contactEmail": "admin@globalfoods.com",
"phoneNumber": "+1 (555) 100-2000",
"state": false
}
```
### 4.2 响应
- 成功:返回更新后的 `PartnerGetOutputDto`。
---
## 5. 删除(逻辑删除)
- **方法**:`DELETE`
- **路径**:`/api/app/partner/{id}`
### 5.1 路径参数
| 参数 | 说明 |
|------|------|
| `id` | `fl_partner.Id` |
### 5.2 行为
- 将 `IsDeleted` 置为 `true`,并更新 `LastModificationTime` / `LastModifierId`(若当前用户存在)。
---
## 6. 批量导出 PDF
- **方法**:`GET`
- **路径**:`/api/app/partner/export-pdf`
- **响应**:`Content-Type: application/pdf`,附件名形如 `partners_yyyy-MM-dd_HH-mm-ss.pdf`
### 6.1 查询参数
与列表接口相同的筛选字段(分页字段可忽略):
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `keyword` | string | 否 | 与列表 `keyword` 一致 |
| `state` | bool | 否 | 与列表 `state` 一致 |
| `sorting` | string | 否 | 与列表白名单一致,用于导出行顺序 |
### 6.2 限制
- 命中行数 **超过 5000** 时接口返回业务错误,需缩小筛选范围后再导出。
- 导出最多取 **5000** 条,排序与列表查询逻辑一致。
### 6.3 请求示例
```http
GET /api/app/partner/export-pdf?keyword=Global&state=true HTTP/1.1
Authorization: Bearer {token}
```
### 6.4 PDF 内容说明
- 表头列:**Partner**、**Contact**、**Phone**、**Status**、**Created**。
- `Status` 文本:`state === true` 时为 `active`,否则 `inactive`。
- 空邮箱、空电话在 PDF 中显示为 **`无`**(与项目列表空值展示约定一致)。
---
## 7. 数据库与建表(Partner)
- 建表脚本:`美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/scripts/fl_partner_create.sql`
- 主要字段:`Id`、`IsDeleted`、`CreationTime`、`CreatorId`、`LastModificationTime`、`LastModifierId`、`PartnerName`、`ContactEmail`、`PhoneNumber`、`State`
---
## 8. 与门店字段的关系说明
- 门店(`location`)上可能存在 **`Partner` 字符串字段**(原型/筛选用),与本文 **`fl_partner` 主数据表** 无强制外键关联。
- 若后续要将门店关联到合作伙伴主数据,需单独产品方案(例如增加 `PartnerId` 或同步名称)。
---
## 9. 前端对接提示(Partner)
- 列表「Search」对应 `keyword`;「Active」筛选对应 `state`。
- 「Bulk Export (PDF)」调用 **第 6 节** 导出接口,查询参数与当前列表筛选保持一致即可。
---
# 第二部分:Group(组织 / Group)
> UI:**Group Name**、**Parent Partner**(下拉绑定合作伙伴)、**Status**、**Bulk Export (PDF)**、**New+** 弹窗(Group Name、Assign to Partner、Active)。
## 10. 数据库与建表(Group)
- 库中原先**无**独立 Group 业务表;新建表名:`fl_group`。
- 建表脚本:`美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/scripts/fl_group_create.sql`
- **须先存在 `fl_partner` 表**(脚本内含外键 `FK_fl_group_partner` → `fl_partner(Id)`)。
- 主要字段:`Id`、`IsDeleted`、`CreationTime`、`CreatorId`、`LastModificationTime`、`LastModifierId`、`GroupName`、`PartnerId`、`State`
**建表 SQL(与脚本文件一致,便于直接执行):**
```sql
CREATE TABLE IF NOT EXISTS `fl_group` (
`Id` varchar(64) NOT NULL COMMENT '主键',
`IsDeleted` tinyint(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除',
`CreationTime` datetime(6) NOT NULL COMMENT '创建时间',
`CreatorId` varchar(64) DEFAULT NULL COMMENT '创建人',
`LastModificationTime` datetime(6) DEFAULT NULL COMMENT '最后修改时间',
`LastModifierId` varchar(64) DEFAULT NULL COMMENT '最后修改人',
`GroupName` varchar(256) NOT NULL COMMENT '组织名称',
`PartnerId` varchar(64) NOT NULL COMMENT '所属合作伙伴 fl_partner.Id',
`State` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
PRIMARY KEY (`Id`),
KEY `IX_fl_group_IsDeleted` (`IsDeleted`),
KEY `IX_fl_group_State` (`State`),
KEY `IX_fl_group_PartnerId` (`PartnerId`),
KEY `IX_fl_group_GroupName` (`GroupName`(128)),
KEY `IX_fl_group_CreationTime` (`CreationTime`),
CONSTRAINT `FK_fl_group_partner` FOREIGN KEY (`PartnerId`) REFERENCES `fl_partner` (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='组织(Group)';
```
---
## 11. Group — 分页列表
- **方法**:`GET`
- **路径**:`/api/app/group`
### 11.1 查询参数(`GroupGetListInputVo`)
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `skipCount` | int | 是 | 页码,从 **1** 开始 |
| `maxResultCount` | int | 是 | 每页条数 |
| `sorting` | string | 否 | 排序白名单(见下) |
| `keyword` | string | 否 | 模糊匹配 `GroupName`、所属 **未删除** Partner 的 `PartnerName` |
| `partnerId` | string | 否 | 仅查看某合作伙伴下的组织(`fl_partner.Id`) |
| `state` | bool | 否 | 按启用状态筛选;不传则不过滤 |
**排序白名单**(大小写不敏感):
- `GroupName asc` / `GroupName desc`
- `CreationTime asc` / `CreationTime desc`
- `State asc` / `State desc`
- `PartnerName asc` / `PartnerName desc`(按关联合作伙伴名称)
其它值回退为默认:**按 `CreationTime` 降序**。
### 11.2 请求示例
```http
GET /api/app/group?skipCount=1&maxResultCount=10&keyword=West&partnerId={partnerGuid}&state=true HTTP/1.1
Authorization: Bearer {token}
```
### 11.3 响应结构(`PagedResultWithPageDto<GroupGetListOutputDto>`)
```json
{
"pageIndex": 1,
"pageSize": 10,
"totalCount": 2,
"totalPages": 1,
"items": [
{
"id": "…",
"groupName": "West Coast Region",
"partnerId": "…",
"partnerName": "Global Foods Inc.",
"state": true,
"creationTime": "2026-04-27T10:00:00"
}
]
}
```
### 11.4 列表项字段
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | string | 主键 |
| `groupName` | string | 组织名称 |
| `partnerId` | string | 所属合作伙伴 Id |
| `partnerName` | string | 父级合作伙伴名称(UI「Parent Partner」) |
| `state` | bool | 是否启用 |
| `creationTime` | string (datetime) | 创建时间 |
---
## 12. Group — 详情
- **方法**:`GET`
- **路径**:`/api/app/group/{id}`
路径参数 `id`:`fl_group.Id`。响应为 `GroupGetOutputDto`(在列表字段基础上增加 `lastModificationTime`)。
---
## 13. Group — 新增
- **方法**:`POST`
- **路径**:`/api/app/group`
### Body(`GroupCreateInputVo`)
```json
{
"groupName": "West Coast Region",
"partnerId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"state": true
}
```
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `groupName` | string | 是 | 组织名称 |
| `partnerId` | string | 是 | Assign to Partner,须为未删除的 `fl_partner.Id` |
| `state` | bool | 否 | 默认 `true` |
---
## 14. Group — 编辑
- **方法**:`PUT`
- **路径**:`/api/app/group/{id}`
- **Body**:`GroupUpdateInputVo`(字段同新增)
---
## 15. Group — 删除(逻辑删除)
- **方法**:`DELETE`
- **路径**:`/api/app/group/{id}`
---
## 16. Group — 批量导出 PDF
- **方法**:`GET`
- **路径**:`/api/app/group/export-pdf`
- **响应**:`application/pdf`,附件名形如 `groups_yyyy-MM-dd_HH-mm-ss.pdf`
### 16.1 查询参数
与列表一致(分页可忽略):`keyword`、`partnerId`、`state`、`sorting`。
### 16.2 限制
- 命中行数 **超过 5000** 返回业务错误;导出最多 **5000** 条。
### 16.3 PDF 列
**Group Name**、**Parent Partner**、**Status**(`active` / `inactive`)、**Created**。
---
## 17. 前端对接提示(Group)
- 「Search」→ `keyword`;按父级合作伙伴筛选 → `partnerId`(下拉选中项的 `id`);「Active」→ `state`。
- 「Assign to Partner」下拉数据来自 **Partner 列表接口**(`/api/app/partner`)。
- 「Bulk Export (PDF)」→ **第 16 节**,查询参数与当前列表筛选一致。
|