签入版本

This commit is contained in:
2026-10-08 17:50:29 +08:00
parent 809750b47e
commit e213a9b31d
444 changed files with 39366 additions and 37533 deletions
@@ -1,7 +1,7 @@
# 8.5 字典数据接口
:::tip 概述
字典数据接口分为两组:字典管理(DictController)和字典项管理(DictItemController)。前端通过字典编码获取字典项列表用于下拉框,后台通过管理接口维护字典数据。
字典数据接口分为两组:字典管理(DictController)和字典项管理(DictItemController)。前端通过字典编码获取字典项列表用于下拉框,后台通过管理接口维护字典数据。字典项变更时 `DictItemObserver` **自动失效缓存**。
:::
## 接口总览
@@ -16,7 +16,7 @@
| PUT | `/api/dict/update` | sys:dict:update | 修改字典 |
| DELETE | `/api/dict/delete/{id}` | sys:dict:delete | 删除字典 |
| DELETE | `/api/dict/batchDelete` | sys:dict:batchDelete | 批量删除字典 |
| GET | `/api/dict/refreshCache` | sys:dict:update | 刷新字典缓存 |
| GET | `/api/dict/refreshCache` | sys:dict:update | 刷新字典缓存(`#[DemoAllow]` 演示环境放行) |
### 字典项管理(DictItemController)
@@ -30,6 +30,10 @@
| DELETE | `/api/dict/item/batchDelete` | sys:dict:batchDelete | 批量删除字典项 |
| GET | `/api/dict/item/getDictItemList/{code}` | — | 按编码获取字典项列表 |
:::tip 批量删除为 DELETE
本项目 `batchDelete` 系列接口统一为 **DELETE** 方法(请求体传 `ids` 数组——DELETE 方法携带 body)。
:::
## 按编码获取字典项(最常用)
### 接口信息
@@ -37,7 +41,7 @@
| 项目 | 说明 |
|------|------|
| URL | `GET /api/dict/item/getDictItemList/{code}` |
| 权限 | 无需额外权限(已登录即可) |
| 权限 | 无需额外权限注解(已登录即可,位于 `auth.jwt` 组内) |
| 用途 | 前端下拉框数据源 |
### 请求示例
@@ -56,7 +60,8 @@ Authorization: Bearer <token>
"msg": "操作成功",
"data": [
{ "id": 1, "name": "男", "value": "1", "sort": 1, "note": "" },
{ "id": 2, "name": "女", "value": "2", "sort": 2, "note": "" }
{ "id": 2, "name": "女", "value": "2", "sort": 2, "note": "" },
{ "id": 3, "name": "保密", "value": "3", "sort": 3, "note": "" }
]
}
```
@@ -71,18 +76,17 @@ Authorization: Bearer <token>
| `sort` | number | 排序 |
| `note` | string | 备注 |
### 常用字典编码
### 常用字典编码(以初始化脚本为准)
| 编码 | 说明 | 字典项 |
|------|------|--------|
| `gender` | 性别 | 1=男, 2=女 |
| `user_status` | 用户状态 | 0=禁用, 1=启用 |
| `article_status` | 文章状态 | 0=草稿, 1=已发布 |
| `tenant_status` | 租户状态 | 0=禁用, 1=启用 |
| `notice_type` | 通知类型 | 1=通知, 2=公告 |
| `example_type` | 案例类型 | 1=基础, 2=进阶, 3=高级 |
| `example_status` | 案例状态 | 0=禁用, 1=启用 |
| `data_scope` | 数据权限 | 1=全部, 2=本部门, 3=仅本人 |
| `gender` | 性别 | 1=男, 2=女, 3=保密 |
| `user_status` | 用户状态 | 1=正常, 2=禁用 |
| `tenant_status` | 租户状态 | 1=启用, 0=禁用 |
| `example_type` | 案例类型 | 1=类型1, 2=类型2, 3=类型3, 4=类型4 |
| `example_status` | 案例状态 | 1=在用, 2=停用 |
(完整字典可在「数据管理 → 字典管理」中查看。)
## 刷新字典缓存
@@ -92,7 +96,9 @@ Authorization: Bearer <token>
| 权限 | `sys:dict:update` |
| 演示环境 | 允许执行(标注 `#[DemoAllow]`) |
修改字典数据后需调用此接口刷新缓存,否则新数据不会立即生效。
:::tip 正常情况无需手动刷新
字典项通过后台接口增删改时,`DictItemObserver` **自动清除**对应字典缓存。本接口用于**绕过模型直接改库**后的手动兜底,或运维批量刷新。
:::
```bash
GET /api/dict/refreshCache
@@ -105,18 +111,25 @@ Authorization: Bearer <token>
{
"code": 0,
"ok": true,
"msg": "缓存已刷新",
"msg": "缓存刷新成功",
"data": null
}
```
命令行兜底:`php artisan dict:clear-cache`。
## 前端使用
### 获取字典项
```typescript
// ui/src/api/common/index.ts
export function getDictItemList(code: string) {
// ui/src/api/common/index.ts(实际代码)
/**
* 根据字典编码查询字典项数据
* @param code 字典编码
* @returns 返回结果
*/
export function getDictItemByCode(code) {
return http.request({
url: '/dict/item/getDictItemList/' + code,
method: 'GET',
@@ -140,12 +153,12 @@ export function getDictItemList(code: string) {
<script setup>
import { ref, onMounted } from 'vue';
import { getDictItemList } from '@/api/common/index';
import { getDictItemByCode } from '@/api/common/index';
const statusOptions = ref([]);
onMounted(async () => {
statusOptions.value = await getDictItemList('example_status');
statusOptions.value = await getDictItemByCode('example_status');
});
</script>
```
@@ -154,51 +167,16 @@ onMounted(async () => {
```typescript
const [genderOptions, statusOptions] = await Promise.all([
getDictItemList('gender'),
getDictItemList('user_status'),
getDictItemByCode('gender'),
getDictItemByCode('user_status'),
]);
```
### 封装为通用 Hook
```typescript
// ui/src/hooks/web/useDict.ts
import { ref, onMounted } from 'vue';
import { getDictItemList } from '@/api/common/index';
export function useDict(code: string) {
const options = ref([]);
const loading = ref(false);
const load = async () => {
loading.value = true;
try {
options.value = await getDictItemList(code);
} finally {
loading.value = false;
}
};
onMounted(() => load());
return { options, loading, reload: load };
}
// 使用
const { options: genderOptions } = useDict('gender');
const { options: statusOptions } = useDict('user_status');
```
### 枚举显示名自动翻译
Logic 中配置 `serializeMaps` 后,查询数据自动补全 `{字段名}Text`:
Service 中配置 `serializeMaps`(需 `use HasSerializeMaps`)后,查询数据自动补全 `{字段名}Text`:
```php
/**
* 枚举显示名映射
*
* @var array
*/
protected array $serializeMaps = [
'status' => 'example_status',
];
@@ -206,32 +184,32 @@ protected array $serializeMaps = [
```json
// API 响应自动包含 statusText
{ "id": 1, "name": "测试", "status": 1, "statusText": "启用" }
{ "id": 1, "name": "测试", "status": 1, "statusText": "在用" }
```
:::tip 缓存机制
DictService 采用两级缓存(请求级 + 持久缓存,1小时过期)。修改字典数据后需调用刷新缓存接口,否则新数据不会立即生效。
`DictCacheService` 采用两级缓存(请求级 + Redis 持久缓存)。变更一致性由 Observer 保证;详见 [4.8 缓存架构设计](/zh/architecture/cache.html) 与 [5.10 字典模块](/zh/core/dict.html)。
:::
## 后端 DictService 调用
## 后端 DictCacheService 调用
```php
use app\service\DictService;
use App\Services\DictCacheService;
// 根据值获取名称
$text = DictService::getText('gender', 1); // '男'
$text = DictCacheService::getText('gender', 1); // '男'
// 根据名称反向获取值
$value = DictService::getValue('gender', '男'); // '1'
$value = DictCacheService::getValue('gender', '男'); // '1'
// 获取下拉框选项
$options = DictService::getOptions('gender');
// [['label'=>'男','value'=>'1'], ['label'=>'女','value'=>'2']]
$options = DictCacheService::getOptions('gender');
// [['label'=>'男','value'=>'1'], ['label'=>'女','value'=>'2'], ...]
// 获取完整字典项(含 id、sort、note)
$items = DictService::getFullItems('gender');
// 批量获取多个字典映射(列表翻译一次取词)
$maps = DictCacheService::getBatchTextMaps(['gender', 'user_status']);
// 清除缓存
DictService::clearCache('gender'); // 清除指定字典
DictService::clearAllCache(); // 清除所有字典
DictCacheService::clearCache('gender'); // 清除指定字典
DictCacheService::clearAllCache(); // 清除所有字典
```