You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
10 KiB

# 数据字典 — 前端对接文档
> 遵循《业务中台产品接口说明书》全局契约
> 接口基础路径:`/api/dict`
> 权限控制:纯 `hasAuthority`,权限码 `dict:*` 由初始化器种子化到权限资源树
> 需求来源:蓝湖原型「itc信息化业务中台 web端」页面 `A7-4-1 数据字典`
> 架构决策:见 `docs/adr/0015-data-dictionary-crm-dict-two-level.md`;领域术语见 `crm-dict/CONTEXT.md`
本文档供前端**做原型**与**联调**使用。字典是两级结构:**字典分组**(第一级容器)→ **字典项**(第二级键值条目)。页面有两个页签:字典分组、字典列表。
---
## 1. 接口总览
| 方法 | 路径 | 用途 | 权限码 |
|------|------|------|--------|
| `POST` | `/api/dict/group/page` | 分组分页查询 | `dict:group:list` |
| `POST` | `/api/dict/group/saveOrUpdate` | 新增/编辑分组 | `dict:group:save` |
| `POST` | `/api/dict/group/delete` | 删除分组 | `dict:group:delete` |
| `POST` | `/api/dict/group/status` | 启用/停用分组 | `dict:group:status` |
| `GET` | `/api/dict/group/enabled-list` | 启用分组列表(选分组用) | `dict:group:list` |
| `POST` | `/api/dict/item/page` | 字典项分页查询 | `dict:item:list` |
| `POST` | `/api/dict/item/saveOrUpdate` | 新增/编辑字典项 | `dict:item:save` |
| `POST` | `/api/dict/item/delete` | 删除字典项 | `dict:item:delete` |
| `POST` | `/api/dict/item/force-delete` | 强制删除字典项 | `dict:item:force-delete` |
| `POST` | `/api/dict/item/status` | 启用/停用字典项 | `dict:item:status` |
| `POST` | `/api/dict/item/set-default` | 设为分组默认项 | `dict:item:default` |
| `GET` | `/api/dict/item/enabled-list` | 某分组启用项列表(业务选择器) | `dict:item:list` |
**认证**:所有接口请求头携带 `Authorization: Bearer {token}`,token 对应用户须持有对应权限码。
**请求格式**:GET 参数走 URL query;POST 用 `Content-Type: application/x-www-form-urlencoded`,参数为表单字段(不是 JSON body)。
**ID**:所有 id 按**字符串**收发(雪花 ID 超出 JS Number 安全范围),前端回传原样传字符串,不要转 Number。
---
## 2. 数据模型
### 2.1 DictGroup(字典分组)
```typescript
interface DictGroup {
id: string; // 分组 ID
name: string; // 分组名称(必填)
code: string; // 分组编码(全局唯一,创建后不可改;新建必填)
itemCount: number; // 字典数量(该分组下未删除字典项数,含启用+停用)
sortNo: number | null; // 排序号(可空,非负整数,值越小越靠前,空排最后)
status: number; // 状态:1=启用 0=停用
description: string | null; // 描述
builtin: boolean; // 是否内置分组(true=平台内置,不可删除,可改名/描述/排序/启停)
}
```
### 2.2 DictItem(字典项)
```typescript
interface DictItem {
id: string; // 字典项 ID
groupId: string; // 所属分组 ID(创建后不可改)
groupName: string; // 所属分组名称(列表展示用)
name: string; // 字典名称(必填,展示文案,改名后历史数据展示最新名)
code: string; // 字典编码(分组内唯一,创建后不可改;未填自动生成 dict_+32位hex)
value: string | null; // 字典值(同组唯一,空值不校验;被引用后只读)
sortNo: number | null; // 排序号(同 DictGroup)
status: number; // 状态:1=启用 0=停用
isDefault: boolean; // 是否分组默认项(派生字段,非独立存储)
referenced: boolean; // 是否被业务数据引用(true 时不可删、分组/值只读)
effectiveSelectable: boolean; // 有效可选 = 分组启用 且 本项启用
builtin: boolean; // 是否内置字典项
description: string | null;
}
```
> **失活标记**:当 `status===1`(自身启用)但 `effectiveSelectable===false`(因所属分组已停用)时,列表行应加**视觉标记**(角标/灰化)并提示"所属分组已停用,当前字典暂不可用"。
### 2.3 状态枚举
| 值 | 含义 |
|----|------|
| 1 | 启用 |
| 0 | 停用 |
---
## 3. 统一响应结构
```typescript
interface Result<T> {
code: number; // 200 成功,其余为业务错误码
message: string;
data: T;
}
interface PageResult<T> {
records: T[];
total: number;
current: number;
size: number;
}
```
---
## 4. 字典分组接口
### 4.1 分组分页 `POST /api/dict/group/page`
请求(表单):`current`、`size`、`keyword`(可选,匹配名称/编码)、`status`(可选,1/0)
响应:`Result<PageResult<DictGroup>>`
### 4.2 分组保存 `POST /api/dict/group/saveOrUpdate`
请求(表单):
| 字段 | 必填 | 说明 |
|------|------|------|
| `id` | 编辑必填 | 新建不传 |
| `name` | 是 | 去首尾空格 |
| `code` | 是 | **仅新建可传**;仅字母/数字/下划线。**编辑时忽略/只读** |
| `sortNo` | 否 | 非负整数 |
| `description` | 否 | |
错误:`name` 空 → 提示必填;`code` 格式非法 → 提示;`code` 全局重复 → "分组编码已存在"。
### 4.3 分组删除 `POST /api/dict/group/delete`
请求(表单):`id`
规则:分组下**存在任何未删除字典项**→ 阻断,提示"该分组下仍有字典,无法删除";`builtin=true` → 阻断"内置分组不可删除"。
### 4.4 分组启停 `POST /api/dict/group/status`
请求(表单):`id`、`status`(1/0)
前端**二次确认**后调用。停用后该分组下所有字典项都不进入业务选择器(即使项自身启用);默认项关系保留(休眠),重新启用后原默认项继续生效(若其自身启用)。
### 4.5 启用分组列表 `GET /api/dict/group/enabled-list`
无参。返回所有启用状态分组(`Result<DictGroup[]>`),供"新建字典项"时选择所属分组——**只能选启用分组**。
---
## 5. 字典项接口
### 5.1 字典项分页 `POST /api/dict/item/page`
请求(表单):`current`、`size`、`groupId`(可选,按分组筛选)、`keyword`(可选,匹配名称/编码/值)、`status`(可选)
响应:`Result<PageResult<DictItem>>`
### 5.2 字典项保存 `POST /api/dict/item/saveOrUpdate`
请求(表单):
| 字段 | 必填 | 说明 |
|------|------|------|
| `id` | 编辑必填 | |
| `groupId` | 新建必填 | **仅新建可传**;只能选启用分组。**编辑时只读**(分组创建后不可改) |
| `name` | 是 | 去首尾空格;被引用后**仍可改** |
| `code` | 否 | **仅新建可传**;仅字母/数字/下划线;未填自动生成。编辑只读 |
| `value` | 否 | 同组唯一(空不校验);**被引用后只读** |
| `sortNo` | 否 | 非负整数 |
| `description` | 否 | |
错误:`name` 空 → 必填;`code` 非法/组内重复 → 提示;`value` 组内重复 → "字典值已存在";被引用后传了 `groupId`/`code`/`value` 改动 → 拒绝并提示只读。
> 前端编辑态:`referenced===true` 时,把「分组」「编码」「字典值」置灰只读;「名称」「排序」「描述」仍可编辑。`referenced===false` 时「字典值」可编辑,「分组」「编码」始终只读。
### 5.3 字典项删除 `POST /api/dict/item/delete`
请求(表单):`id`
规则:`referenced===true` → 阻断,提示"该字典已被引用,无法删除";`builtin=true` → 阻断;未被引用可直接删(不要求先停用)。
### 5.4 强制删除 `POST /api/dict/item/force-delete`
请求(表单):`id`
用途:引用计数因故飘高、实际已无引用但常规删除被阻断时的**管理员兜底**。前端需**强二次确认**("确认强制删除?此操作绕过引用校验")。需 `dict:item:force-delete` 权限,界面上仅对有此权限者显示。
### 5.5 字典项启停 `POST /api/dict/item/status`
请求(表单):`id`、`status`(1/0)
前端二次确认。停用时若该项是默认项 → 后端自动取消其默认状态(不自动补新默认)。
### 5.6 设为默认项 `POST /api/dict/item/set-default`
请求(表单):`id`
后端一次事务内:清除同分组原默认项 + 将本项设为默认。每组至多一个默认项。仅用于新建业务数据的初始选择,不改已有业务数据。
### 5.7 分组启用项列表 `GET /api/dict/item/enabled-list`
请求(query):`groupCode`(或 `groupId`,二选一,建议 `groupCode`
返回该分组下**有效可选**(分组启用且项启用)的字典项列表,供业务页面的**业务选择器**(下拉)渲染。分组停用 → 返回空列表。
---
## 6. 业务侧取值约定(供其他业务页面开发者)
- 业务数据**只保存字典编码**(`code`),不保存 id、不保存名称。
- 每个业务字段在设计期**固定绑定一个字典分组**(如客户「行业」字段永远读 `industry` 分组)。禁止一个字段跨多个分组取值。
- 展示业务数据时,用 `(该字段绑定的分组编码, 存的字典编码)` 反查字典项,显示其**最新名称**。
- 渲染新建/编辑业务表单的下拉时,调 `enabled-list` 拿有效选项。
- 编辑历史业务数据时:若原选中的字典项已停用,仍需**回显**该值并标注"已停用";用户清除后该项不可再选。
---
## 7. 排序规则
列表排序:有排序号的按号升序 → 无排序号的排在后面 → 排序号相同或都为空的按创建时间升序。字典项分页先按分组、再按项排序。前端**不做拖拽重排**(后端只接受手填 `sortNo`);如需拖拽体验,前端可在保存时重算该组所有项的 `sortNo` 逐条提交。
---
## 8. 权限码一览
| 权限码 | 控制 |
|--------|------|
| `dict:group:list` | 分组查询、启用分组列表 |
| `dict:group:save` | 分组新增/编辑 |
| `dict:group:delete` | 分组删除 |
| `dict:group:status` | 分组启停 |
| `dict:item:list` | 字典项查询、启用项列表 |
| `dict:item:save` | 字典项新增/编辑 |
| `dict:item:delete` | 字典项删除 |
| `dict:item:force-delete` | 字典项强制删除 |
| `dict:item:status` | 字典项启停 |
| `dict:item:default` | 设默认项 |
无对应权限 → 后端返回无权限错误码;前端应据登录用户权限码隐藏对应入口/按钮(但服务端强制校验为准,前端隐藏不可替代)。