acf259d5
李曜臣
2026-07-24
|
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
|
# 2026-07-23 美国版:Region / Location / Team Member / Product 在线批量导入
本文档说明 **美国版**(`food-labeling-us`)四个 **JSON 在线批量导入**接口:前端在系统内表格/表单编辑后一次提交,**不再依赖下载 Excel 模板**(Excel 导入接口仍保留,但不推荐)。
> 汇总表与 Excel/导出/批量编辑说明仍见:`项目相关文档/批量导入导出接口说明.md`。
---
## 一、为什么改成在线导入
| 方式 | 问题 / 优势 |
|------|-------------|
| Excel 下载模板再上传 | 表头别名、列顺序、Region 名称 vs Id 等易填错;模板版本与环境不一致 |
| **JSON 在线导入(本文)** | 与单条 `Create` 字段一致;前端下拉选 Company/Region/Location(传 Id);校验即时、失败行可定位 |
---
## 二、公共约定
| 项 | 说明 |
|----|------|
| 宿主 | 美国版 `Yi.Abp.Web`;Swagger 分组「食品标签-美国版接口」 |
| 基址示例 | `http://localhost:19001` / 测试环境 `https://flus-test.3ffoodsafety.com` |
| Content-Type | `application/json` |
| 鉴权 | `Authorization: Bearer {token}`(与其它业务接口相同) |
| 请求体 | `{ "items": [ ... ] }`,每元素字段与对应模块**单条新增**一致 |
| 行语义 | **仅新增**;批量编辑仍用各模块 `*-bulk`(Update) |
| 失败策略 | **逐行**调用现有 `CreateAsync`;部分成功;单行 `UserFriendlyException` 记入 `errors` |
| `index` | 失败行在 `items` 中的下标,**从 0 开始** |
| 上限 | `FoodLabeling:BatchImport:MaxImportRows`(默认 **5000**) |
| Excel 旧接口 | 保留;文档标注不推荐,请优先本文接口 |
### 2.1 接口一览
| 模块 | UI 概念 | HTTP | 路径 |
|------|---------|------|------|
| Group | **Region** | POST | `/api/app/group/batch-import-online` |
| Location | Location | POST | `/api/app/location/batch-import-online` |
| Team Member | Team Member | POST | `/api/app/team-member/batch-import-online` |
| Product | Product | POST | `/api/app/product/batch-import-online` |
### 2.2 统一出参结构
```json
{
"successCount": 2,
"failCount": 1,
"errors": [
{
"index": 2,
"message": "具体业务错误信息",
"groupName": "可选,按模块不同字段名见下表"
}
]
}
```
| 模块 | 失败行业务键字段(camelCase) |
|------|------------------------------|
| Region | `groupName` |
| Location | `locationCode` |
| Team Member | `userName` |
| Product | `productName` |
整单失败(HTTP 400):`items` 为空,或条数超过 `MaxImportRows`。
### 2.3 与批量编辑的区别
| | 在线批量导入(本文) | 批量编辑(已有) |
|--|---------------------|------------------|
| 路径示例 | `.../batch-import-online` | `.../locations-bulk` 等 |
| 行语义 | 新建 | 按 `id` 更新 |
| 典型场景 | 系统内批量录入新数据 | 网格「保存全部」 |
---
## 三、Region(Group)在线导入
| 项 | 值 |
|----|------|
| 路径 | `POST /api/app/group/batch-import-online` |
| 服务 | `GroupAppService.BatchImportOnlineAsync` |
| items 元素 | `GroupCreateInputVo` |
**字段映射**:UI **Region** = 库表 `fl_group.GroupName`(入参字段名仍为 `groupName`)。
| 字段 | 必填 | 说明 |
|------|------|------|
| `groupName` | 是 | Region 名称 |
| `partnerId` | 是 | 所属 Company(`fl_partner.Id`) |
| `state` | 否 | 启用状态,默认 `true` |
```bash
curl -X POST "http://localhost:19001/api/app/group/batch-import-online" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d "{
\"items\": [
{ \"groupName\": \"NC Region\", \"partnerId\": \"<partnerGuid>\", \"state\": true },
{ \"groupName\": \"SC Region\", \"partnerId\": \"<partnerGuid>\", \"state\": true }
]
}"
```
权限与单条 `POST /api/app/group` 相同(含 Company Admin 自动绑定门店等逻辑)。
---
## 四、Location 在线导入
| 项 | 值 |
|----|------|
| 路径 | `POST /api/app/location/batch-import-online` |
| 服务 | `LocationAppService.BatchImportOnlineAsync` |
| items 元素 | `LocationCreateInputVo` |
| 字段 | 必填 | 说明 |
|------|------|------|
| `locationCode` | 是 | Location ID(业务编码) |
| `locationName` | 是 | 门店名称 |
| `partner` | 否 | Company **名称**(与单条新增一致,非 Id) |
| `groupName` | 否 | Region 名称(对应 `location.GroupName`) |
| `street` / `city` / `stateCode` / `country` / `zipCode` | 否 | 地址 |
| `phone` / `email` | 否 | 联系方式 |
| `latitude` / `longitude` | 否 | 坐标 |
| `operatingHours` | 否 | 营业时间文本 |
| `state` | 否 | 启用,默认 `true` |
```bash
curl -X POST "http://localhost:19001/api/app/location/batch-import-online" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d "{
\"items\": [
{
\"locationCode\": \"LOC001\",
\"locationName\": \"UNCC store\",
\"partner\": \"MedVantage Cafe Group\",
\"groupName\": \"NC Region\",
\"city\": \"Charlotte\",
\"stateCode\": \"NC\",
\"country\": \"USA\",
\"state\": true
}
]
}"
```
---
## 五、Team Member 在线导入
| 项 | 值 |
|----|------|
| 路径 | `POST /api/app/team-member/batch-import-online` |
| 服务 | `TeamMemberAppService.BatchImportOnlineAsync` |
| items 元素 | `TeamMemberCreateInputVo` |
| 字段 | 必填 | 说明 |
|------|------|------|
| `fullName` | 是 | 姓名 |
| `userName` | 是 | 登录账号 |
| `password` | 否 | 空则用配置 `TeamMemberImportDefaultPassword` |
| `email` / `phone` | 否 | 联系方式 |
| `roleId` | 否 | 角色 Guid |
| `partnerId` / `partnerIds` | 否 | Company Id |
| `regionIds` / `groupIds` | 否 | Region(`fl_group.Id`),**传 Id 不要传名称** |
| `locationIds` | 否 | 门店 Id 列表 |
| `state` | 否 | 默认 `true` |
与 Excel 导入差异:在线接口的 Region/Location 使用 **Id**,由前端下拉选择,避免名称拼写错误。
```bash
curl -X POST "http://localhost:19001/api/app/team-member/batch-import-online" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d "{
\"items\": [
{
\"fullName\": \"John Doe\",
\"userName\": \"john@example.com\",
\"email\": \"john@example.com\",
\"roleId\": \"<roleGuid>\",
\"locationIds\": [\"<locationGuid>\"],
\"state\": true
}
]
}"
```
---
## 六、Product 在线导入
| 项 | 值 |
|----|------|
| 路径 | `POST /api/app/product/batch-import-online` |
| 服务 | `ProductAppService.BatchImportOnlineAsync` |
| items 元素 | `ProductCreateInputVo` |
| 字段 | 必填 | 说明 |
|------|------|------|
| `productName` | 是 | 产品名称 |
| `productCode` | 否 | 空则后端生成唯一编码 |
| `categoryId` | 否 | 分类 Id |
| `productImageUrl` / `displayText` / `codeValue` | 否 | 展示相关 |
| `buttonAppearance` / `categoryPhotoUrl` | 否 | 按钮外观 |
| `availabilityType` | 否 | `ALL` / `SPECIFIED` |
| `partnerId` | 否 | Company Id,展开门店后写入关联 |
| `groupIds` | 否 | Region Id 列表 |
| `locationIds` | 否 | 门店 Id 列表 |
| `state` | 否 | 默认 `true` |
```bash
curl -X POST "http://localhost:19001/api/app/product/batch-import-online" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d "{
\"items\": [
{
\"productName\": \"Tuna & Bacon Sub\",
\"productCode\": \"40001\",
\"categoryId\": \"<categoryId>\",
\"state\": true,
\"locationIds\": [\"<locationGuid>\"]
}
]
}"
```
---
## 七、配置
`appsettings` 节:`FoodLabeling:BatchImport`
| 配置项 | 与在线导入相关 |
|--------|----------------|
| `MaxImportRows` | 单次 `items` 最大条数(默认 5000) |
| `TeamMemberImportDefaultPassword` | Team Member 未填密码时的默认初始密码 |
---
## 八、前端对接建议
1. 批量录入页用系统内表格 + 下拉(Company / Region / Location / Role),提交 JSON,**不要**再引导用户下载 Excel 模板。
2. 展示返回的 `successCount` / `failCount`,按 `errors[].index` 高亮失败行。
3. Region 展示文案用「Region」,请求字段仍用 `groupName` / `partnerId`。
4. 批量改已有数据继续走各模块 **bulk update**,勿用本导入接口。
5. 部署后需重启后端;Swagger 中确认路径为带模块前缀的 `.../group|location|team-member|product/batch-import-online`。
---
## 九、相关代码
| 类型 | 路径 |
|------|------|
| Group | `FoodLabeling.Application/Services/GroupAppService.cs` |
| Location | `FoodLabeling.Application/Services/LocationAppService.cs` |
| Team Member | `FoodLabeling.Application/Services/TeamMemberAppService.cs` |
| Product | `FoodLabeling.Application/Services/ProductAppService.cs` |
| DTO | `FoodLabeling.Application.Contracts/Dtos/{Group,Location,TeamMember,Product}/*BatchImportOnline*.cs` |
模块根目录:`美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/`。
---
## 十、自检清单
- [ ] 平台/公司账号登录后 Token 可调业务接口
- [ ] Region:合法 `partnerId` + `groupName` 可批量成功
- [ ] Location:重复 `locationCode` 记入 `errors`,其它行仍成功
- [ ] Team Member:不传 `password` 时使用默认密码可登录
- [ ] Product:不传 `productCode` 时后端自动生成
- [ ] `items` 超过 `MaxImportRows` 返回 400
- [ ] 未误用 Excel 导入作为新前端主路径
|