a7684ddb
李曜臣
批量导入导出,批量编辑
|
1
2
3
4
5
6
7
8
9
10
11
12
|
# 美国版 · 批量导入 / 批量导出(Excel·PDF)/ 下载模板 / 批量编辑 — 接口汇总
本文档集中维护 **Account Management**、**Reports** 及相关模块的「下载 Excel 模板」「批量导出(Excel 或 PDF)」「批量导入 Excel」以及 **网格「保存全部」式批量编辑(JSON)** 等接口。**单条 CRUD、分页列表**仍以各业务模块说明为准(如门店见 `门店(Location)接口对接说明.md`)。
---
## 目录
| 章节 | 内容 |
|------|------|
| [公共约定](#公共约定) | 基址、鉴权、Swagger、通用注意事项 |
| [共享配置](#共享配置) | `appsettings` 中 `FoodLabeling:BatchImport` |
|
acf259d5
李曜臣
2026-07-24
|
13
|
| [在线批量导入(JSON,推荐)](#在线批量导入json推荐) | Region / Location / Team Member / Product 四模块 JSON 逐行导入 |
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
| [1 Location Manager(门店)](#1-location-manager门店) | 下载模板 / Excel 导出 / 导入 / 批量编辑 |
| [2 Team Member(成员)](#2-team-member成员) | 下载模板 / **PDF 全量导出** / Excel 导入 / 批量编辑 |
| [3 Products(菜单-产品)](#3-products菜单-产品) | 下载模板 / Excel 全量导出 / Excel 导入 / 批量编辑 |
| [4 后续模块(预留)](#4-后续模块预留) | 新接口在此追加小节 |
| [5 Account Management(Company / Region)](#5-account-managementcompany-region) | **PDF 全量导出**(Company、Region 页签) |
| [6 Reports — Print Log(Excel)](#6-reports--print-logexcel) | **Excel 全量导出**(Print Log 页签) |
| [附录 curl 模板](#附录-curl-模板) | 登录、Location / Team Member / Products / Company / Region / Reports 调用示例 |
---
## 公共约定
- **宿主**:美国版后端 `Yi.Abp.Web`;本地 Swagger 示例:`http://localhost:19001/swagger`。
- **路由前缀**:约定式控制器 `RootPath` 为 **`api/app`**(与 ABP 实际配置一致)。
- **Swagger 分组**:**「食品标签-美国版接口」**;具体路径以 Swagger 展示为准(下表为常见命名,联调时请以 Swagger 为准)。
- **鉴权**:与其它业务接口相同,请求头携带登录接口返回的 **`data.token` 完整值**(已含 `Bearer ` 前缀),示例:`Authorization: {data.token}`。
- **文件类响应**:`Content-Type` 多为 `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`(`.xlsx`)。
|
acf259d5
李曜臣
2026-07-24
|
31
|
- **导入类请求**:Excel 导入统一使用 **`multipart/form-data`**,文件字段名以各接口说明为准(Location 为 **`file`**);**推荐**使用下文 [在线批量导入(JSON)](#在线批量导入json推荐) 替代 Excel 上传。
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
- **批量编辑类请求**:使用 **`application/json`**,一次提交多行(与前端表格「保存全部」对齐)。
- **导出类响应**:Location 与 **Products(菜单-产品)**、**Reports — Print Log** 为 **Excel 全量**;**Team Member**、**Account Management 的 Company / Region**、**Reports — Label Report** 等为 **PDF**(见各小节);数据量极大时请注意服务端内存与响应耗时。
---
## 共享配置
配置节全名:`FoodLabeling:BatchImport`(绑定类:`FoodLabelingBatchImportOptions`,在 `FoodLabelingApplicationModule` 中注册)。
| 配置项 | 说明 |
|--------|------|
| `TemplateDirectory` | 服务器上存放**批量导入模板**的目录(生产示例:`/www/wwwroot/FoodLabelingManagementUs/batchImportOfFiles`) |
| `LocationTemplateFileName` | Location 模板文件名(默认:`Location-Manager-批量导入模板.xlsx`) |
| `TeamMemberTemplateFileName` | Team Member 模板文件名(默认:`Team-Member-批量导入模板.xlsx`) |
| `ProductTemplateFileName` | Product(菜单-产品)模板文件名(默认:`Product-Manager-批量导入模板.xlsx`) |
| `TeamMemberImportDefaultPassword` | Team Member 批量导入时,Excel 未填 Password 列则使用的默认初始密码 |
| `MaxImportRows` | 单次导入最多数据行数(默认 5000) |
| `MaxUploadBytes` | 上传 Excel 最大字节数(默认 10MB) |
| `MaxBulkUpdateItems` | 单次「批量编辑」请求中 **`items` 数组最大长度**(默认 500;含占位空行,与前端网格行数一致) |
后续若增加其它模块模板文件名等,可在此表同一节下扩展配置项说明(并与 `appsettings`、Options 类保持一致)。
---
|
acf259d5
李曜臣
2026-07-24
|
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
|
## 在线批量导入(JSON,推荐)
四个 Account Management / 业务模块均提供 **JSON 在线批量导入** 接口:请求体 `{ "items": [ ...CreateInputVo ] }`,**逐行调用现有 `CreateAsync`**,**部分成功**(单行失败不影响其它行)。`errors` 中 **`index` 从 0 起**(与 `items` 数组下标一致)。单次条数上限为 **`MaxImportRows`**(默认 5000)。
| 模块 | 方法 | HTTP | 路径 | 失败行 key 字段 |
|------|------|------|------|-----------------|
| Region(Group) | `BatchImportOnlineAsync` | `POST` | `/api/app/group/batch-import-online` | `groupName` |
| Location | `BatchImportOnlineAsync` | `POST` | `/api/app/location/batch-import-online` | `locationCode` |
| Team Member | `BatchImportOnlineAsync` | `POST` | `/api/app/team-member/batch-import-online` | `userName` |
| Product | `BatchImportOnlineAsync` | `POST` | `/api/app/product/batch-import-online` | `productName` |
**公共返回字段**(各模块 `*BatchImportOnlineResultDto`):`successCount`、`failCount`、`errors[{ index, message, key? }]`(JSON 命名一般为 camelCase)。
**Team Member 特殊规则**:`password` 为空或仅空白时,使用配置 **`TeamMemberImportDefaultPassword`**;若配置亦为空则该行失败。
**与 Excel 导入关系**:Excel 导入接口(`import-*-batch`)**保留但不推荐**,新前端与联调请优先 **`batch-import-online`**;Excel 仍适用于离线模板填写后上传的旧流程。
### Region(Group)在线导入
| 项目 | 说明 |
|------|------|
| Body | `GroupBatchImportOnlineInputVo`:`items` 为 `GroupCreateInputVo` 数组(`groupName`、`partnerId`、`state`) |
| 业务 | 与单条 `POST /api/app/group` 一致;ID 由现有 `CreateAsync` 生成 |
```bash
curl -X POST "$BASE/api/app/group/batch-import-online" \
-H "Authorization: TOKEN" \
-H "Content-Type: application/json" \
-d "{\"items\":[{\"groupName\":\"NC Region\",\"partnerId\":\"PARTNER_ID\",\"state\":true}]}"
```
### Location 在线导入
| 项目 | 说明 |
|------|------|
| Body | `LocationBatchImportOnlineInputVo`:`items` 为 `LocationCreateInputVo` 数组 |
| 业务 | 与单条 `POST /api/app/location` 一致 |
```bash
curl -X POST "$BASE/api/app/location/batch-import-online" \
-H "Authorization: TOKEN" \
-H "Content-Type: application/json" \
-d "{\"items\":[{\"locationCode\":\"LOC001\",\"locationName\":\"UNCC store\",\"partner\":\"MedVantage Cafe Group\",\"groupName\":\"NC Region\",\"state\":true}]}"
```
### Team Member 在线导入
| 项目 | 说明 |
|------|------|
| Body | `TeamMemberBatchImportOnlineInputVo`:`items` 为 `TeamMemberCreateInputVo` 数组 |
| 密码 | 未填 `password` 时使用 `TeamMemberImportDefaultPassword` |
```bash
curl -X POST "$BASE/api/app/team-member/batch-import-online" \
-H "Authorization: TOKEN" \
-H "Content-Type: application/json" \
-d "{\"items\":[{\"fullName\":\"John Doe\",\"userName\":\"john@example.com\",\"email\":\"john@example.com\",\"roleId\":\"ROLE_GUID\",\"locationIds\":[\"LOCATION_GUID\"],\"state\":true}]}"
```
### Product 在线导入
| 项目 | 说明 |
|------|------|
| Body | `ProductBatchImportOnlineInputVo`:`items` 为 `ProductCreateInputVo` 数组 |
| 业务 | 与单条 `POST /api/app/product` 一致 |
```bash
curl -X POST "$BASE/api/app/product/batch-import-online" \
-H "Authorization: TOKEN" \
-H "Content-Type: application/json" \
-d "{\"items\":[{\"productName\":\"Tuna & Bacon Sub\",\"categoryId\":\"CATEGORY_ID\",\"productCode\":\"40001\",\"state\":true,\"locationIds\":[\"LOCATION_GUID\"]}]}"
```
---
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
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
|
## 1 Location Manager(门店)
**应用服务**:`LocationAppService`(模块 `food-labeling-us`)。
**列表筛选字段**(导出与列表对齐时):`Sorting`、`Keyword`、`Partner`、`GroupName`、`State` — 含义与分页列表一致,详见 `门店(Location)接口对接说明.md` 接口 1。
### 1.1 下载批量导入模板
| 项目 | 说明 |
|------|------|
| 方法 | `DownloadLocationImportTemplateAsync` |
| HTTP | `GET` |
| 常见路径 | `/api/app/location/download-location-import-template` |
| 作用 | 从 `TemplateDirectory` 读取 `LocationTemplateFileName` 指向的文件并作为附件下载 |
| 失败常见原因 | 未配置目录、文件名、或服务器上文件不存在 |
### 1.2 批量导出 Excel
| 项目 | 说明 |
|------|------|
| 方法 | `ExportLocationsExcelAsync` |
| HTTP | `GET` |
| 常见路径 | `/api/app/location/export-locations-excel` |
| Query | 与门店列表筛选一致:`Sorting`、`Keyword`、`Partner`、`GroupName`、`State` |
| 数据范围 | **全量**:符合筛选条件的全部记录;**不使用**请求中的 `SkipCount` / `MaxResultCount`(与列表分页无关) |
| 排序 | 与列表一致:有 `Sorting` 则按其排序,否则默认 `CreationTime` 降序 |
| 响应文件名示例 | `locations-export-yyyyMMdd-HHmmss.xlsx` |
|
acf259d5
李曜臣
2026-07-24
|
159
|
### 1.3 批量导入 Excel(不推荐,请优先 [batch-import-online](#在线批量导入json推荐))
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
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
|
| 项目 | 说明 |
|------|------|
| 方法 | `ImportLocationsBatchAsync` |
| HTTP | `POST` |
| Content-Type | `multipart/form-data` |
| 常见路径 | `/api/app/location/import-locations-batch` |
| 表单字段 | **`file`**:仅支持 `.xlsx` |
| 返回类型 | `LocationBatchImportResultDto`(JSON) |
**`LocationBatchImportResultDto` 字段**
| 字段 | 说明 |
|------|------|
| `SuccessCount` | 成功新增条数 |
| `FailCount` | 失败条数(含解析错误与逐行业务校验失败) |
| `SkippedEmptyRows` | 预留,当前一般为 `0` |
| `Errors` | `RowNumber`、`LocationCode`、`Message` |
**解析与业务摘要**
- 表头须能识别 **Location ID**(或同义列);建议使用官方模板。
- **必填**:Location ID(`LocationCode`)、Location Name(与单条新增一致)。
- **可选**:Company/Region、地址、电话、邮箱、经纬度、`Active` 等;经纬度为空则 `null`,有值则校验格式。
### 1.4 批量编辑(网格「保存全部」)
对应前端在 **Location Manager** 进入批量编辑页后,将多行修改一次性提交;**每行通过主键 `id` 定位记录**,可编辑字段与单条 **`PUT /api/app/location/{id}`** 的 body(`LocationUpdateInputVo`)一致。**不修改 Location ID(`LocationCode`)**(与单条更新接口一致)。
| 项目 | 说明 |
|------|------|
| 方法 | `UpdateLocationsBulkAsync` |
|
6ce07406
杨鑫
提交
|
192
|
| HTTP | `PUT` |
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
193
|
| Content-Type | `application/json` |
|
6ce07406
杨鑫
提交
|
194
|
| 常见路径 | `/api/app/location/locations-bulk`(ABP 会去掉方法名中的 `Update` 前缀,不是 `update-locations-bulk`) |
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
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
|
| Body | `LocationBulkUpdateInputVo` |
**请求体 `LocationBulkUpdateInputVo`**
| 字段 | 类型 | 说明 |
|------|------|------|
| `items` | 数组 | 每一元素为 `LocationBulkUpdateItemVo` |
**`LocationBulkUpdateItemVo`(单行)**
| 字段 | 说明 |
|------|------|
| `id` | **Guid**,列表接口返回的门店主键;为 **`00000000-0000-0000-0000-000000000000`** 或未填写的占位行将被**忽略**(便于与「至少 10 行空行」类 UI 对齐) |
| `partner` | 可选,Company |
| `groupName` | 可选,Region |
| `locationName` | **必填**(与单条更新校验一致) |
| `street` / `city` / `stateCode` / `country` / `zipCode` / `phone` / `email` | 可选 |
| `latitude` / `longitude` | 可选,decimal |
| `state` | 是否启用,默认 `true` |
**返回 `LocationBulkUpdateResultDto`**
| 字段 | 说明 |
|------|------|
| `SuccessCount` | 成功更新条数 |
| `FailCount` | 失败条数 |
| `Errors` | `LocationBulkUpdateErrorDto`:`rowNumber`(在 **`items` 数组中的序号,从 1 开始**)、`id`、`message` |
**行为说明**
- **逐条提交**:内部对每一有效行调用与单条更新相同的业务逻辑;**一行失败不影响其它行**。
- **整单校验**:`items` 为空、超过 `MaxBulkUpdateItems`、或没有任何有效 `id` 时返回 **400** 类业务错误(`UserFriendlyException`)。
- **JSON 命名**:与项目其它接口一致,一般为 **camelCase**(以实际 JSON 序列化配置为准)。
---
## 2 Team Member(成员)
**应用服务**:`TeamMemberAppService`(模块 `food-labeling-us`;前端常见路径前缀 **`/team-member`**)。
**列表筛选字段**(导出与列表对齐):`Keyword`、`RoleId`、`LocationId`、`State`、`Sorting` — 与成员分页列表一致(`LocationId` 为门店主键字符串,与 `UserLocation.LocationId` 一致)。
### 2.1 下载批量导入模板
| 项目 | 说明 |
|------|------|
| 方法 | `DownloadTeamMemberImportTemplateAsync` |
| HTTP | `GET` |
| 常见路径 | `/api/app/team-member/download-team-member-import-template` |
| 作用 | 从 `TemplateDirectory` 读取 `TeamMemberTemplateFileName` 指向的 xlsx 并下载 |
### 2.2 批量导出 PDF(全量)
| 项目 | 说明 |
|------|------|
| 方法 | `ExportTeamMembersPdfAsync` |
| HTTP | `GET` |
| 常见路径 | `/api/app/team-member/export-team-members-pdf` |
| Query | 与成员列表筛选一致:`Keyword`、`RoleId`、`LocationId`、`State`、`Sorting` |
| 数据范围 | **全量**:符合筛选条件的全部成员;**不使用** `SkipCount` / `MaxResultCount` |
| 排序 | 有 `Sorting` 则按其排序,否则按创建时间降序 |
| 响应 | `Content-Type: application/pdf`,文件名示例 `team-members_yyyy-MM-dd_HH-mm-ss.pdf` |
|
14afbc16
李曜臣
2026-6-22
|
257
|
| PDF 列 | Name、Email、Phone、Role、**Region**、Assigned Locations(多门店以分号拼接)、Status(Active/Inactive) |
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
258
259
260
|
**说明**:PDF 中「Assigned Locations」展示该成员**全部**已分配门店(不受列表按门店筛选时「仅显示命中门店」的收缩影响),便于导出后审阅完整权限。
|
acf259d5
李曜臣
2026-07-24
|
261
|
### 2.3 批量导入 Excel(不推荐,请优先 [batch-import-online](#在线批量导入json推荐))
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
262
263
264
265
266
267
268
269
270
271
272
273
|
| 项目 | 说明 |
|------|------|
| 方法 | `ImportTeamMembersBatchAsync` |
| HTTP | `POST` |
| Content-Type | `multipart/form-data` |
| 常见路径 | `/api/app/team-member/import-team-members-batch` |
| 表单字段 | **`file`**,仅 `.xlsx` |
| 返回 | `TeamMemberBatchImportResultDto`:`successCount`、`failCount`、`errors`(`rowNumber`、`userName`、`message`) |
**表头识别(摘要)**
|
14afbc16
李曜臣
2026-6-22
|
274
275
276
277
278
279
280
281
|
- **必填列**:`Name`(或 FullName)、`Email`;**Role Name**(或 **Role Id** Guid);**Region** 与 **Assigned Location Ids** **至少填一项**(均可留空仅适用于 Web 已支持的 Company Admin + Company 场景)。
- **可选列**:`User Name` / `Login`(不填则登录账号用 Email)、`Password`(不填则用配置 **`TeamMemberImportDefaultPassword`**)、`Phone`、`Status`、**`Region`**(可留空)。
- **Region**:多个可用 **`;`**、`|`, 换行分隔;支持 **`fl_group.Id`(Guid)** 或 **Region 名称(GroupName)**;仅填 Region 时会绑定该区域下全部门店。
- **Assigned Location Ids**:多个可用 **`;`**、`|`, 换行、中文 **`,`** 分隔;支持 **`location.LocationCode`(门店编码,推荐)** 或 **`location.Id`(Guid)**;亦支持 `LOC001 - Store Name`(取 **` -`** 前为编码或 Guid)。
- **Role**:与系统 **`Role.RoleName`** 一致(忽略大小写与中间空格);或填 **Role Id**(Guid)。
- 下载模板由服务端 **动态生成**(含 **Region** 列),不再依赖服务器目录中的静态 xlsx。
**PDF 导出列**:Name、Email、Phone、Role、**Region**、Assigned Locations、Status。
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
282
283
284
285
286
287
288
289
|
内部对每行调用与单条创建相同的业务逻辑;**单行失败不影响其它行**。
### 2.4 批量编辑(网格「保存全部」)
| 项目 | 说明 |
|------|------|
| 方法 | `UpdateTeamMembersBulkAsync` |
|
6ce07406
杨鑫
提交
|
290
|
| HTTP | `PUT` |
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
291
|
| Content-Type | `application/json` |
|
6ce07406
杨鑫
提交
|
292
|
| 常见路径 | `/api/app/team-member/team-members-bulk`(勿写 `update-team-members-bulk`,否则易命中 `PUT …/{id}` 导致 Guid 校验错误) |
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
293
294
295
296
297
298
299
300
301
302
303
304
305
306
|
| Body | `TeamMemberBulkUpdateInputVo`:`items` 为 `TeamMemberBulkUpdateItemVo` 数组 |
每行含 **`id`(成员 Guid)** 及与单条 **`PUT /api/app/team-member/{id}`** 相同的字段(`password` 可空表示不改密码)。`id` 为全零 GUID 的项忽略。整单规则与 Location 批量编辑相同(`MaxBulkUpdateItems`、至少一条有效 `id` 等)。
**返回** `TeamMemberBulkUpdateResultDto`:`successCount`、`failCount`、`errors`(`rowNumber`、`id`、`message`)。
---
## 3 Products(菜单-产品)
**应用服务**:`ProductAppService`(模块 `food-labeling-us`;前端常见路径前缀 **`/product`**)。
**列表筛选字段**(导出与列表对齐):`Keyword`、`State`、`Sorting` — 与产品分页列表一致(`Keyword` 匹配产品编码、名称、分类名称)。
|
10fd1324
李曜臣
5-17接口优化
|
307
308
|
**路由说明**:单条 **GET/PUT/DELETE** 的 `{id}` 为 **`Guid` 类型**(与 `fl_product.Id` 的 Guid 字符串一致),约定路由会带 **`{id:guid}`** 约束,因此 **`export-products-excel`、`download-product-import-template`、`import-products-batch`、`update-products-bulk`** 等字面路径不会被误判为产品 Id。
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
309
310
311
312
313
|
### 3.1 下载批量导入模板
| 项目 | 说明 |
|------|------|
| 方法 | `DownloadProductImportTemplateAsync` |
|
10fd1324
李曜臣
5-17接口优化
|
314
|
| HTTP | `GET`(已标 `[HttpGet]`,与约定 `Download*` 可能判为 `POST` 的情况区分) |
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
315
316
317
318
319
320
321
322
|
| 常见路径 | `/api/app/product/download-product-import-template` |
| 作用 | 从 `TemplateDirectory` 读取 `ProductTemplateFileName` 指向的 xlsx 并下载(工作表名一般为 `Products`) |
### 3.2 批量导出 Excel(全量)
| 项目 | 说明 |
|------|------|
| 方法 | `ExportProductsExcelAsync` |
|
10fd1324
李曜臣
5-17接口优化
|
323
|
| HTTP | `GET`(应用服务方法上已标 `[HttpGet]`;ABP 对 `Export*` 默认易判成 `POST`,用 GET 否则会 **405**) |
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
324
|
| 常见路径 | `/api/app/product/export-products-excel` |
|
10fd1324
李曜臣
5-17接口优化
|
325
|
| Postman | **不要** 填 Body;筛选用 **Params**(Query)或拼在 URL 上;导出**不需要**上传 `file`(上传文件是 **3.3 导入**) |
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
326
327
328
329
330
331
|
| Query | 与产品列表筛选一致:`Keyword`、`State`、`Sorting` |
| 数据范围 | **全量**:符合筛选条件的全部产品;**不使用** `SkipCount` / `MaxResultCount` |
| 排序 | 有 `Sorting` 则按其排序,否则默认按 `ProductName` 降序 |
| 响应文件名示例 | `products-export-yyyyMMdd-HHmmss.xlsx` |
| 列(与导入模板一致) | **Location**(多门店英文逗号拼接门店名称)、**Product Category**(分类名称)、**Product**(产品名称)、**Product Code**(产品编码;可为空则导出为空单元格) |
|
10fd1324
李曜臣
5-17接口优化
|
332
333
|
**部署**:须使用 **`dotnet publish` 后的完整输出目录**(含 `ClosedXML.dll`、`DocumentFormat.OpenXml.dll`、`Yi.Abp.Web.deps.json` 等)部署;**不要用 `bin/Debug`(或 `bin/Release`)里挑文件当上线包**。也**禁止**「本地跑起来后只把若干 dll / 自己改过的文件」覆盖到线上(极易漏掉第三方依赖)。上线建议整包替换发布目录,或在服务器上 `git pull` + `dotnet publish`;发布时若输出里缺少 `ClosedXML.dll`,当前 `Yi.Abp.Web` 工程会在 `dotnet publish` 结束时报错提示。
|
acf259d5
李曜臣
2026-07-24
|
334
|
### 3.3 批量导入 Excel(不推荐,请优先 [batch-import-online](#在线批量导入json推荐))
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
|
| 项目 | 说明 |
|------|------|
| 方法 | `ImportProductsBatchAsync` |
| HTTP | `POST` |
| Content-Type | `multipart/form-data` |
| 常见路径 | `/api/app/product/import-products-batch` |
| 表单字段 | **`file`**,仅 `.xlsx` |
| 返回 | `ProductBatchImportResultDto`:`successCount`、`failCount`、`errors`(`rowNumber`、`productName`、`message`) |
**表头识别(摘要)**
- **必填列**:`Product Category`(分类**名称**,与 `fl_product_category.CategoryName` 匹配,忽略大小写;若同名多条则该行失败)、`Product`(产品名称)。
- **可选列**:`Location`(多门店可用英文逗号 **`,`**、中文逗号、分号、竖线、换行分隔;每个片段:若为 **Guid** 则按门店主键;否则按 **Location Code** 精确匹配,或按 **Location Name** 不区分大小写匹配;**同一片段匹配到多条门店**则该行失败)、`Product Code`(可空,空则创建时由后端生成唯一编码,与单条创建一致)。
- **不在模板中的字段**:产品主键、启用状态由后端处理;导入创建的产品 **`state` 恒为 `true`(启用)**;`productImageUrl` 不通过本导入写入。
内部对每行调用与单条 **`POST` 创建产品** 相同的业务逻辑(含门店关联写入);**单行失败不影响其它行**。
### 3.4 批量编辑(网格「保存全部」)
| 项目 | 说明 |
|------|------|
| 方法 | `UpdateProductsBulkAsync` |
|
6ce07406
杨鑫
提交
|
358
|
| HTTP | `PUT` |
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
359
|
| Content-Type | `application/json` |
|
6ce07406
杨鑫
提交
|
360
|
| 常见路径 | `/api/app/product/products-bulk` |
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
|
| Body | `ProductBulkUpdateInputVo`:`items` 为 `ProductBulkUpdateItemVo` 数组 |
每行含 **`id`(产品主键字符串,与列表/详情返回的 `id` 一致)** 及与单条 **`PUT /api/app/product/{id}`** 相同的 body 字段(`ProductUpdateInputVo` / `ProductCreateInputVo` 形状:`productCode`、`productName`、`categoryId`、`productImageUrl`、`state`、`locationIds`)。`id` 为空或仅空白的项**忽略**。整单规则与 Location / Team Member 批量编辑相同(`MaxBulkUpdateItems`、至少一条有效 `id` 等)。
**返回** `ProductBulkUpdateResultDto`:`successCount`、`failCount`、`errors`(`rowNumber`、`id`、`message`)。
---
## 4 后续模块(预留)
> 新模块的批量能力可在此追加 **## 7 xxx** 等章节,并更新文首 **目录** 与 **共享配置** 表(本节为占位,章节号可按实际顺延)。
---
## 5 Account Management(Company / Region)
|
10fd1324
李曜臣
5-17接口优化
|
377
|
前端 **Account Management** 菜单中 **Company**、**Region** 两个页签的「Bulk Export (PDF)」对应后端已有接口:数据模型分别为 **`fl_partner`**(合作伙伴 / 公司)、**`fl_group`**(组织 / 大区);应用服务为 **`PartnerAppService`**、**`GroupAppService`**。导出为 **QuestPDF** 生成的 **PDF**,筛选条件与各自**分页列表**一致,**不使用** `SkipCount` / `MaxResultCount`(全量导出)。单次导出超过 **5000** 条时返回业务错误,需缩小筛选范围。单条 **GET/PUT/DELETE** 的 `{id}` 为 **`Guid`**(与 `fl_partner.Id` / `fl_group.Id` 的 Guid 字符串一致),约定路由 **`{id:guid}`**,**`export-pdf`** 等字面路径不会误判为资源 Id;`ExportPdfAsync` 已标 **`[HttpGet]`**。
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
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
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
|
### 5.1 Company(合作伙伴 / `PartnerAppService`)
| 项目 | 说明 |
|------|------|
| 方法 | `ExportPdfAsync` |
| HTTP | `GET` |
| 常见路径 | `/api/app/partner/export-pdf` |
| Query | 与 Company 列表一致:`Keyword`、`State`、`Sorting` |
| 数据范围 | 符合筛选条件的**全部**记录(全量) |
| 排序 | 与列表 `GetListAsync` 内 `BuildPartnerListQuery` 一致(含 `Sorting` 各分支;无则 `CreationTime` 降序) |
| 响应 | `Content-Type: application/pdf`,文件名示例 `companies_yyyy-MM-dd_HH-mm-ss.pdf` |
| PDF 列 | Company(公司名称)、Contact(邮箱)、Phone、Status(active/inactive)、Created |
### 5.2 Region(组织 / `GroupAppService`)
| 项目 | 说明 |
|------|------|
| 方法 | `ExportPdfAsync` |
| HTTP | `GET` |
| 常见路径 | `/api/app/group/export-pdf` |
| Query | 与 Region 列表一致:`Keyword`、`PartnerId`(下拉「所属公司」对应 `fl_partner.Id`)、`State`、`Sorting` |
| 数据范围 | 符合筛选条件的**全部**记录(全量) |
| 排序 | 与列表 `GetListAsync` 内 `BuildGroupJoinedQuery` 一致 |
| 响应 | `Content-Type: application/pdf`,文件名示例 `regions_yyyy-MM-dd_HH-mm-ss.pdf` |
| PDF 列 | Region Name、Parent company、Status(active/inactive)、Created |
**说明**:前端 `partnerService.exportPartnersPdf` / `groupService.exportGroupsPdf` 已按上述路径封装;鉴权与其它 `GET` 一致。
---
## 6 Reports — Print Log(Excel)
**应用服务**:`ReportsAppService`(模块 `food-labeling-us`)。前端 **Reports** 菜单 **Print Log** 页签的「Export Report」在实现上调用 **Excel 全量导出**(与列表同一套筛选;**不使用**分页参数参与数据范围,仅可选用 `Sorting` 与列表对齐)。
### 6.1 Print Log 批量导出 Excel
| 项目 | 说明 |
|------|------|
| 方法 | `ExportPrintLogExcelAsync` |
| HTTP | `GET` |
| 常见路径 | `/api/app/reports/export-print-log-excel` |
| Query | 与 Print Log 分页列表一致:`PartnerId`、`GroupId`、`LocationId`、`StartDate`、`EndDate`、`Keyword`、`Sorting`(**不传** `SkipCount` / `MaxResultCount` 或传了也会被后端忽略;全量以筛选为准) |
| 数据范围 | 符合筛选条件的**全部**打印任务行(上限 **5000** 条;超出则 `UserFriendlyException`) |
| 排序 | 与列表一致:`Sorting` 为 `PrintedAt asc` 时按打印时间升序,否则按打印时间降序 |
| 响应 | `Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`,文件名示例 `print-log_yyyyMMdd-HHmmss.xlsx` |
| Excel 列(工作表名 `Print Log`) | Label ID、Product Name、Category、Template、Printed At、Printed By、Location、Expiry Date(空值语义与列表「无」一致) |
| 权限 | 与 `GetPrintLogListAsync` 相同:**admin** 可查全部;非 admin 仅导出本人打印记录 |
**说明**:同模块另有 **`GET .../export-print-log-pdf`**(PDF);**Label Report** 页签仍使用 **`export-label-report-pdf`**。前端 `reportsService.exportPrintLogExcel` 已封装本接口。
---
## 附录 curl 模板
将 `TOKEN` 替换为登录响应中的 `data.token` 整段;将 `BASE` 替换为实际基址(如 `http://localhost:19001`)。
```bash
# 登录
curl -X POST "$BASE/api/oauth/Login" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "userName=admin&password=123456"
# --- Location Manager ---
curl -X GET "$BASE/api/app/location/download-location-import-template" \
-H "Authorization: TOKEN" \
-o "Location-Manager-template.xlsx"
curl -X GET "$BASE/api/app/location/export-locations-excel?Partner=&GroupName=&State=&Keyword=&Sorting=" \
-H "Authorization: TOKEN" \
-o "locations-export.xlsx"
curl -X POST "$BASE/api/app/location/import-locations-batch" \
-H "Authorization: TOKEN" \
-F "file=@./Location-Manager-template.xlsx"
|
6ce07406
杨鑫
提交
|
454
|
curl -X PUT "$BASE/api/app/location/locations-bulk" \
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
|
-H "Authorization: TOKEN" \
-H "Content-Type: application/json" \
-d "{\"items\":[{\"id\":\"YOUR_LOCATION_ID\",\"locationName\":\"UNCC store\",\"state\":true}]}"
# --- Team Member ---
curl -X GET "$BASE/api/app/team-member/download-team-member-import-template" \
-H "Authorization: TOKEN" \
-o "Team-Member-template.xlsx"
curl -X GET "$BASE/api/app/team-member/export-team-members-pdf?Keyword=&RoleId=&LocationId=&State=&Sorting=" \
-H "Authorization: TOKEN" \
-o "team-members.pdf"
curl -X POST "$BASE/api/app/team-member/import-team-members-batch" \
-H "Authorization: TOKEN" \
-F "file=@./Team-Member-template.xlsx"
|
6ce07406
杨鑫
提交
|
472
|
curl -X PUT "$BASE/api/app/team-member/team-members-bulk" \
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
|
-H "Authorization: TOKEN" \
-H "Content-Type: application/json" \
-d "{\"items\":[{\"id\":\"YOUR_USER_GUID\",\"fullName\":\"John\",\"userName\":\"john@example.com\",\"email\":\"john@example.com\",\"phone\":789654444,\"roleId\":\"ROLE_GUID\",\"locationIds\":[\"LOCATION_GUID\"],\"state\":true}]}"
# --- Account Management:Company / Region(PDF 全量)---
curl -X GET "$BASE/api/app/partner/export-pdf?Keyword=&State=&Sorting=" \
-H "Authorization: TOKEN" \
-o "companies-export.pdf"
curl -X GET "$BASE/api/app/group/export-pdf?Keyword=&PartnerId=&State=&Sorting=" \
-H "Authorization: TOKEN" \
-o "regions-export.pdf"
# --- Reports:Print Log(Excel 全量)---
curl -X GET "$BASE/api/app/reports/export-print-log-excel?PartnerId=&GroupId=&LocationId=&StartDate=&EndDate=&Keyword=&Sorting=PrintedAt%20desc" \
-H "Authorization: TOKEN" \
-o "print-log-export.xlsx"
# --- Products(菜单-产品)---
curl -X GET "$BASE/api/app/product/download-product-import-template" \
-H "Authorization: TOKEN" \
-o "Product-Manager-template.xlsx"
curl -X GET "$BASE/api/app/product/export-products-excel?Keyword=&State=&Sorting=" \
-H "Authorization: TOKEN" \
-o "products-export.xlsx"
curl -X POST "$BASE/api/app/product/import-products-batch" \
-H "Authorization: TOKEN" \
-F "file=@./Product-Manager-template.xlsx"
|
6ce07406
杨鑫
提交
|
504
|
curl -X PUT "$BASE/api/app/product/products-bulk" \
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
505
506
507
|
-H "Authorization: TOKEN" \
-H "Content-Type: application/json" \
-d "{\"items\":[{\"id\":\"YOUR_PRODUCT_ID\",\"productName\":\"Tuna & Bacon Sub\",\"categoryId\":\"CATEGORY_ID\",\"productCode\":\"40001\",\"state\":true,\"locationIds\":[\"LOCATION_GUID_1\",\"LOCATION_GUID_2\"]}]}"
|
acf259d5
李曜臣
2026-07-24
|
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
|
# --- 在线批量导入(JSON,推荐)---
curl -X POST "$BASE/api/app/group/batch-import-online" \
-H "Authorization: TOKEN" \
-H "Content-Type: application/json" \
-d "{\"items\":[{\"groupName\":\"NC Region\",\"partnerId\":\"PARTNER_ID\",\"state\":true}]}"
curl -X POST "$BASE/api/app/location/batch-import-online" \
-H "Authorization: TOKEN" \
-H "Content-Type: application/json" \
-d "{\"items\":[{\"locationCode\":\"LOC001\",\"locationName\":\"UNCC store\",\"state\":true}]}"
curl -X POST "$BASE/api/app/team-member/batch-import-online" \
-H "Authorization: TOKEN" \
-H "Content-Type: application/json" \
-d "{\"items\":[{\"fullName\":\"John\",\"userName\":\"john@example.com\",\"email\":\"john@example.com\",\"roleId\":\"ROLE_GUID\",\"state\":true}]}"
curl -X POST "$BASE/api/app/product/batch-import-online" \
-H "Authorization: TOKEN" \
-H "Content-Type: application/json" \
-d "{\"items\":[{\"productName\":\"Tuna Sub\",\"categoryId\":\"CATEGORY_ID\",\"state\":true}]}"
|
a7684ddb
李曜臣
批量导入导出,批量编辑
|
529
530
531
532
533
534
535
536
537
538
|
```
更完整的接口测试流程见仓库内 `.codex/skills/api-interface-testing/SKILL.md`。
---
## 文档维护说明
- **新增**某模块的导入/导出/下载模板/**批量编辑**接口时:在本文件 **目录** 表增加一行锚点,新增 **## n 模块名** 章节,并同步 **共享配置** 表(若有新配置项)。
- **避免**在多个 Markdown 中重复粘贴大段相同表格;门店分页与单条接口仍以 `门店(Location)接口对接说明.md` 为准;本文侧重「批量」与「多行一次提交」类接口。
|