364 lines
9.6 KiB
Markdown
364 lines
9.6 KiB
Markdown
# 字典数据联调
|
||
|
||
:::tip 说明
|
||
字典数据通过后端字典 API 获取,前端在下拉选择器中渲染选项。字典项的 `value` 字段统一为字符串类型,前端使用时需要注意类型转换。
|
||
:::
|
||
|
||
## 后端字典 API
|
||
|
||
### 获取字典数据
|
||
|
||
```
|
||
GET /api/v1/dict/data/{code}
|
||
```
|
||
|
||
返回:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": [
|
||
{ "id": 1, "label": "系统", "value": "0" },
|
||
{ "id": 2, "label": "业务", "value": "1" }
|
||
],
|
||
"msg": "操作成功",
|
||
"ok": true
|
||
}
|
||
```
|
||
|
||
### 字典数据结构
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `id` | number | 字典项 ID |
|
||
| `label` | string | 显示文本 |
|
||
| `value` | string | 值(注意:统一为字符串) |
|
||
|
||
:::warning 值类型注意
|
||
字典项的 `value` 字段统一为字符串类型,即使存储的是数字。前端使用时需要注意类型转换。
|
||
:::
|
||
|
||
---
|
||
|
||
## 序列化映射
|
||
|
||
BaseService 的 `serialize_maps` 自动将字典值映射为显示名,列表和详情接口均生效。
|
||
|
||
### 基本用法(以 param 模块为例)
|
||
|
||
```python
|
||
# src/modules/param/service.py
|
||
class ParamService(BaseService):
|
||
repository = ParamRepository
|
||
model = Param
|
||
# 字段名 → 数据字典编码
|
||
serialize_maps = {'type': 'param_type', 'status': 'param_status'}
|
||
```
|
||
|
||
`serialize_maps` 的 key 是模型字段名,value 是数据字典编码。BaseService 序列化时自动:
|
||
|
||
1. 取出模型字段的原始值(如 `type=0`)
|
||
2. 从数据字典查询对应的 label(如 `param_type` 字典中 `value='0'` 的 `label='系统'`)
|
||
3. 以 `字段名驼峰 + Text` 为 key 写入响应(如 `type` → `typeText`)
|
||
|
||
### 响应示例
|
||
|
||
模型原始数据:
|
||
|
||
```
|
||
Param(id=1, name="默认密码", code="DEFAULT_PASSWORD", value="123456", type=0, status=1, sort=1)
|
||
```
|
||
|
||
列表/详情接口返回:
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"name": "默认密码",
|
||
"code": "DEFAULT_PASSWORD",
|
||
"value": "123456",
|
||
"type": 0,
|
||
"typeText": "系统",
|
||
"status": 1,
|
||
"statusText": "正常",
|
||
"sort": 1,
|
||
"note": null,
|
||
"createUser": "管理员",
|
||
"createTime": "2025-03-06 14:30:25"
|
||
}
|
||
```
|
||
|
||
### 字段命名规则
|
||
|
||
| 模型字段 | serialize_maps key | 响应字段 | 说明 |
|
||
|----------|-------------------|----------|------|
|
||
| `type` | `'type'` | `typeText` | snake_case → camelCase + `Text` |
|
||
| `status` | `'status'` | `statusText` | 同上 |
|
||
| `log_type` | `'log_type'` | `logTypeText` | 下划线也转驼峰 |
|
||
| `source` | `'source'` | `sourceText` | 同上 |
|
||
|
||
转换逻辑(`src/common/utils/case_converter.py`):
|
||
|
||
```python
|
||
def convert_camel_case(name: str) -> str:
|
||
"""snake_case → camelCase(log_type → logType)"""
|
||
parts = name.split('_')
|
||
return parts[0] + ''.join(word.capitalize() for word in parts[1:])
|
||
```
|
||
|
||
### 数据字典编码
|
||
|
||
`serialize_maps` 的 value 必须是已配置的数据字典编码。常用编码:
|
||
|
||
| 字典编码 | 说明 | 字典项示例 |
|
||
|----------|------|-----------|
|
||
| `param_type` | 参数类型 | 0-系统, 1-业务 |
|
||
| `param_status` | 参数状态 | 1-正常, 2-禁用 |
|
||
| `operation_type` | 操作类型 | 0-其他, 1-新增, 2-修改, 3-删除 |
|
||
| `operation_source` | 操作来源 | 0-后台, 1-前台 |
|
||
| `operation_status` | 操作状态 | 0-正常, 1-异常 |
|
||
| `log_type` | 日志类型 | 1-登录, 2-退出 |
|
||
| `login_source` | 登录来源 | 0-后台, 1-前台 |
|
||
| `login_status` | 登录状态 | 0-成功, 1-失败 |
|
||
|
||
字典编码在后台「字典管理」中配置,或通过 `scripts/seed_dict.py` 初始化。
|
||
|
||
### 完整示例:param 模块
|
||
|
||
**后端 Service**:
|
||
|
||
```python
|
||
# src/modules/param/service.py
|
||
class ParamService(BaseService):
|
||
repository = ParamRepository
|
||
form = ParamForm
|
||
status_form = ParamStatusForm
|
||
model_name = "参数"
|
||
# 枚举显示名:字段名 → 数据字典编码
|
||
serialize_maps = {'type': 'param_type', 'status': 'param_status'}
|
||
```
|
||
|
||
**前端 columns.ts**:
|
||
|
||
```typescript
|
||
// src/views/system/param/columns.ts
|
||
{
|
||
label: '参数类型',
|
||
prop: 'type',
|
||
width: 100,
|
||
// 方式一:直接使用后端返回的 typeText 字段
|
||
render(record) {
|
||
return h(ElTag,
|
||
{ type: record.row.type == 0 ? 'primary' : 'warning' },
|
||
{ default: () => record.row.typeText });
|
||
},
|
||
},
|
||
{
|
||
label: '状态',
|
||
prop: 'status',
|
||
width: 100,
|
||
// 方式二:直接使用后端返回的 statusText 字段
|
||
render(record) {
|
||
return h(ElTag,
|
||
{ type: record.row.status == 1 ? 'success' : 'danger' },
|
||
{ default: () => record.row.statusText });
|
||
},
|
||
},
|
||
```
|
||
|
||
### 其他模块示例
|
||
|
||
```python
|
||
# src/modules/operation_log/service.py
|
||
serialize_maps = {
|
||
'type': 'operation_type', # typeText: "新增"/"修改"/"删除"
|
||
'source': 'operation_source', # sourceText: "后台"/"前台"
|
||
'status': 'operation_status', # statusText: "正常"/"异常"
|
||
}
|
||
|
||
# src/modules/login_log/service.py
|
||
serialize_maps = {
|
||
'log_type': 'log_type', # logTypeText: "登录"/"退出"
|
||
'source': 'login_source', # sourceText: "后台"/"前台"
|
||
'status': 'login_status', # statusText: "成功"/"失败"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 前端字典管理
|
||
|
||
### 搜索表单中的字典选项
|
||
|
||
搜索表单中直接硬编码选项(简单场景)或通过 API 获取(动态场景):
|
||
|
||
**硬编码选项(简单场景)**
|
||
|
||
```typescript
|
||
// src/views/system/param/querySchemas.ts
|
||
export const schemas: FormSchema[] = [
|
||
{
|
||
field: 'type',
|
||
component: 'Select',
|
||
label: '参数类型',
|
||
componentProps: {
|
||
placeholder: '请选择参数类型',
|
||
clearable: true,
|
||
options: [
|
||
{ label: '系统', value: 0 },
|
||
{ label: '业务', value: 1 },
|
||
],
|
||
},
|
||
},
|
||
{
|
||
field: 'status',
|
||
component: 'Select',
|
||
label: '状态',
|
||
componentProps: {
|
||
placeholder: '请选择状态',
|
||
clearable: true,
|
||
options: [
|
||
{ label: '正常', value: 1 },
|
||
{ label: '禁用', value: 2 },
|
||
],
|
||
},
|
||
},
|
||
];
|
||
```
|
||
|
||
**API 获取选项(动态场景)**
|
||
|
||
```typescript
|
||
import { getDictItemByCode } from '@/api/common';
|
||
|
||
const typeOptions = ref([]);
|
||
const statusOptions = ref([]);
|
||
|
||
onMounted(async () => {
|
||
const res1 = await getDictItemByCode('param_type');
|
||
typeOptions.value = res1.data; // [{ label: '系统', value: '0' }, ...]
|
||
|
||
const res2 = await getDictItemByCode('param_status');
|
||
statusOptions.value = res2.data;
|
||
});
|
||
|
||
const schemas: FormSchema[] = [
|
||
{
|
||
field: 'type',
|
||
component: 'Select',
|
||
label: '参数类型',
|
||
componentProps: { options: typeOptions },
|
||
},
|
||
{
|
||
field: 'status',
|
||
component: 'Select',
|
||
label: '状态',
|
||
componentProps: { options: statusOptions },
|
||
},
|
||
];
|
||
```
|
||
|
||
### 前端字典 API
|
||
|
||
字典相关 API 位于 `src/api/data/dictionary.ts`:
|
||
|
||
```typescript
|
||
// src/api/data/dictionary.ts
|
||
import { http } from '@/utils/http/axios';
|
||
|
||
// 字典列表(分页)
|
||
export function getDictList(params?) {
|
||
return http.request({ url: '/dict/page', method: 'GET', params });
|
||
}
|
||
|
||
// 字典项列表(分页)
|
||
export function getDictItemList(params?) {
|
||
return http.request({ url: '/dict/item/page', method: 'GET', params });
|
||
}
|
||
```
|
||
|
||
按字典编码获取字典项(下拉框用)位于 `src/api/common/index.ts`:
|
||
|
||
```typescript
|
||
// src/api/common/index.ts
|
||
export function getDictItemByCode(code) {
|
||
return http.request({
|
||
url: '/dict/item/getDictItemList/' + code,
|
||
method: 'GET',
|
||
});
|
||
}
|
||
```
|
||
|
||
后端对应接口:`GET /api/v1/dict/data/{code}`(`src/modules/dictionary/dict/router.py`)。
|
||
|
||
---
|
||
|
||
## 值类型处理
|
||
|
||
字典 value 统一为字符串,但业务字段可能为数字,需要注意转换:
|
||
|
||
```typescript
|
||
// 字典选项值为字符串
|
||
const options = [
|
||
{ label: '系统', value: '0' },
|
||
{ label: '业务', value: '1' },
|
||
];
|
||
|
||
// 业务字段为数字
|
||
formData.type = 0;
|
||
|
||
// Select 绑定时需要转换
|
||
<a-select-option :value="Number(item.value)" />
|
||
```
|
||
|
||
搜索表单中的 `options` 的 `value` 为字符串 `'0'`/`'1'`,后端 `filters` 中的 `type` 字段期望数字。前端 API 传参时自动转换。
|
||
|
||
---
|
||
|
||
## 字典管理
|
||
|
||
### 配置字典
|
||
|
||
在后台「字典管理」中配置字典类型和字典项:
|
||
|
||
```
|
||
字典类型: param_type(参数类型)
|
||
字典项:
|
||
- label: 系统, value: 0
|
||
- label: 业务, value: 1
|
||
|
||
字典类型: param_status(参数状态)
|
||
字典项:
|
||
- label: 正常, value: 1
|
||
- label: 禁用, value: 2
|
||
```
|
||
|
||
### 字典类型命名规范
|
||
|
||
```
|
||
sys_ —— 系统类字典(sys_status, sys_gender 等)
|
||
param_ —— 参数类字典(param_type, param_status 等)
|
||
operation_ —— 操作日志类字典(operation_type, operation_status 等)
|
||
login_ —— 登录日志类字典(log_type, login_source, login_status 等)
|
||
cms_ —— 内容类字典(cms_article_status 等)
|
||
biz_ —— 业务类字典
|
||
```
|
||
|
||
---
|
||
|
||
## 联调流程
|
||
|
||
```
|
||
1. 后台「字典管理」中新增字典类型和字典项
|
||
2. 后端 service 设置 serialize_maps(字段名 → 字典编码)
|
||
3. 前端 columns.ts 使用 render 函数渲染状态标签(直接用 xxxText 字段)
|
||
4. 前端 querySchemas.ts 中配置搜索选项(硬编码或 API 获取)
|
||
5. 表单提交时 value 为字符串,后端存储时注意类型处理
|
||
```
|
||
|
||
---
|
||
|
||
## 总结
|
||
|
||
字典数据联调通过后端字典 API + `serialize_maps` 映射显示名 + 前端 `render` 函数渲染标签实现。`serialize_maps` 的 value 为数据字典编码,BaseService 自动查询字典并以 `xxxText` 格式输出。字典值统一为字符串,前端使用时注意类型转换。简单场景硬编码选项,动态场景通过 API 获取。
|