# 合作伙伴(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`) ```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`) ```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 节**,查询参数与当前列表筛选一致。