kt-template-online-api/src/dict/dict.service.ts
sunlei 7291fed682 feat: 支持数据库字典映射并整理公共能力
- 新增 dict 实体表,字典查询改为从数据库读取
- 使用 childrenKey 实现组件一级类型到二级字典的关系映射
- Component 查询后通过 DecodeDictKey 和 AfterLoad 自动补充翻译字段
- 移除 ComponentDto、本地字典常量和本地 seed 文件
- 将 common 能力按 decorators/interceptors/services/swagger 重新分层
- 使用全局 SaveBodyInterceptor 替代 SaveMiddleware 统一处理 save 请求
- 更新 MinIO、组件、字典接口的 Swagger 响应和少量关键注释
- 重写 README.md 和 API.md,补充项目功能、目录结构和接口说明

BREAKING CHANGE: 字典数据依赖数据库 dict 表维护,不再使用本地字典常量。
2026-05-13 15:33:38 +08:00

68 lines
1.8 KiB
TypeScript

import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { setDictDecodeCache } from '@/common';
import { DictEntity } from './dict.entity';
const COMPONENT_TYPE_DICT_KEY = 'COMPONENT_TYPE';
@Injectable()
export class DictService implements OnApplicationBootstrap {
constructor(
@InjectRepository(DictEntity)
private readonly dictRepository: Repository<DictEntity>,
) {}
async onApplicationBootstrap() {
await this.refreshDecodeCache();
}
async getDictByKey(dictKey: string): Promise<Dict[]> {
const list = await this.dictRepository.find({
where: {
dictKey,
is_deleted: false,
},
order: {
sort: 'ASC',
createTime: 'ASC',
},
});
return list.map(({ label, value }) => ({
label,
value: Number.isNaN(Number(value)) ? value : Number(value),
}));
}
async getComponentDictByType(type: number): Promise<Dict[]> {
// 一级类型的 childrenKey 决定二级字典来源,避免在代码里维护 1 -> CHART 这类关系。
const componentType = await this.dictRepository.findOne({
where: {
dictKey: COMPONENT_TYPE_DICT_KEY,
value: String(type),
is_deleted: false,
},
});
if (!componentType?.childrenKey) return [];
return this.getDictByKey(componentType.childrenKey);
}
async refreshDecodeCache() {
// AfterLoad 字典翻译必须同步完成,所以这里先把数据库字典刷新到进程缓存。
const list = await this.dictRepository.find({
where: {
is_deleted: false,
},
order: {
sort: 'ASC',
createTime: 'ASC',
},
});
setDictDecodeCache(list);
}
}