Files
2026-09-12 23:12:15 +08:00

366 lines
9.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 字典数据联调
:::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[Param]):
repo = param_repo
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/utils/string.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[Param]):
repo = param_repo
model = Param
page_like_fields = ('name', 'code')
page_eq_fields = ('type', 'status')
page_order_by = (('sort', 'asc'), ('id', 'desc'))
unique_fields = {'name': '参数名称不能重复', 'code': '参数编码不能重复'}
# 枚举显示名:字段名 → 数据字典编码
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/api/v1/endpoints/dict.py`)。
---
## 值类型处理
字典 value 统一为字符串,但业务字段可能为数字,需要注意转换:
```typescript
// 字典选项值为字符串
const options = [
{ label: '系统', value: '0' },
{ label: '业务', value: '1' },
];
// 业务字段为数字
formData.type = 0;
// el-option 绑定时需要转换
<el-option :value="Number(item.value)" />
```
搜索表单中的 `options` 的 `value` 为字符串 `'0'`/`'1'`,后端 `page_eq_fields` 中的 `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 获取。