Files
cn-rdms-web/src/store/modules/dict/index.ts
hongawen 4122dfa50d feat(product): 新增产品管理模块与字典组件功能
- 新增产品管理相关路由和页面(dashboard、list、requirement、setting)
- 实现产品基础信息编辑弹窗组件(base-info-dialog.vue)
- 添加运行时字典功能(dict-select、dict-text、dict-tag组件)
- 集成字典管理store和API调用
- 规范ID类型定义为string避免精度丢失问题
- 完善国际化资源文件支持中英文对照
- 新增对象上下文业务域入口页导航实现说明
- 添加Vue DevTools浮动入口注释说明
- 统一权限控制支持全局和对象作用域区分
- 规范分页查询参数类型定义与使用方式
2026-04-23 09:05:55 +08:00

211 lines
5.7 KiB
TypeScript

import { ref } from 'vue';
import { defineStore } from 'pinia';
import { RDMS_OBJECT_DIRECTION_DICT_CODE, RDMS_OBJECT_DIRECTION_LEGACY_DICT_CODE } from '@/constants/dict';
import { fetchGetFrontendDictCache } from '@/service/api';
import { SetupStoreId } from '@/enum';
type DictValue = string | number | null | undefined;
type DictFilterOptions = {
onlyEnabled?: boolean;
};
type DictLabelOptions = DictFilterOptions & {
fallback?: string;
};
type DictLabelsOptions = DictLabelOptions & {
separator?: string;
};
function sortDictData(list: Api.Dict.DictData[]) {
return list.slice().sort((left, right) => left.sort - right.sort || left.label.localeCompare(right.label, 'zh-CN'));
}
function normalizeFrontendDictData(
dictType: string,
list: Api.Dict.FrontendDictData[],
dictIndex: number
): Api.Dict.DictData[] {
const normalizedList = list.map((item, itemIndex) => ({
id: -((dictIndex + 1) * 100000 + itemIndex + 1),
label: item.label,
value: item.value,
dictType: item.dictType || dictType,
sort: item.sort,
status: item.status ?? 0,
remark: null,
createTime: 0
}));
return sortDictData(normalizedList);
}
function normalizeFrontendDictCache(cache: Api.Dict.FrontendDictCache) {
const entries = Object.entries(cache);
return Object.fromEntries(
entries.map(([dictType, list], index) => [dictType, normalizeFrontendDictData(dictType, list, index)])
);
}
function applyDictTypeAliases(dictDataMap: Record<string, Api.Dict.DictData[]>) {
const nextDictDataMap = { ...dictDataMap };
// 兼容后端尚未切换完成的过渡期:旧编码仍返回时,前端统一映射到新编码。
if (!nextDictDataMap[RDMS_OBJECT_DIRECTION_DICT_CODE] && nextDictDataMap[RDMS_OBJECT_DIRECTION_LEGACY_DICT_CODE]) {
nextDictDataMap[RDMS_OBJECT_DIRECTION_DICT_CODE] = nextDictDataMap[RDMS_OBJECT_DIRECTION_LEGACY_DICT_CODE].map(
item => ({
...item,
dictType: RDMS_OBJECT_DIRECTION_DICT_CODE
})
);
}
return nextDictDataMap;
}
function createRuntimeDictTypes(dictDataMap: Record<string, Api.Dict.DictData[]>) {
return Object.keys(dictDataMap).map((dictType, index) => ({
id: -(index + 1),
name: dictType,
type: dictType,
status: 0 as const,
remark: null,
createTime: 0
}));
}
function findDictItem(list: Api.Dict.DictData[], value?: DictValue) {
if (value === null || value === undefined || value === '') {
return undefined;
}
return list.find(item => item.value === String(value));
}
export const useDictStore = defineStore(SetupStoreId.Dict, () => {
const loading = ref(false);
const initialized = ref(false);
const dictTypes = ref<Api.Dict.DictType[]>([]);
const dictDataMap = ref<Record<string, Api.Dict.DictData[]>>({});
const loadedAt = ref<number | null>(null);
let initPromise: Promise<boolean> | null = null;
function resetDictCache() {
dictTypes.value = [];
dictDataMap.value = {};
loadedAt.value = null;
initialized.value = false;
initPromise = null;
}
async function initDictCache(force = false) {
if (initialized.value && !force) {
return true;
}
if (initPromise && !force) {
return initPromise;
}
if (force) {
resetDictCache();
}
initPromise = (async () => {
loading.value = true;
const result = await fetchGetFrontendDictCache();
loading.value = false;
if (result.error) {
initPromise = null;
return false;
}
const normalizedDictDataMap = applyDictTypeAliases(normalizeFrontendDictCache(result.data || {}));
dictTypes.value = createRuntimeDictTypes(normalizedDictDataMap);
dictDataMap.value = normalizedDictDataMap;
loadedAt.value = Date.now();
initialized.value = true;
initPromise = null;
return true;
})();
return initPromise;
}
function getDictData(dictType: string, onlyEnabled = false) {
if (!dictType) {
return [];
}
const list = dictDataMap.value[dictType] || [];
if (!onlyEnabled) {
return list;
}
return list.filter(item => item.status === 0);
}
function getDictOptions(dictType: string, onlyEnabled = true) {
return getDictData(dictType, onlyEnabled).map(item => ({
label: item.label,
value: item.value
}));
}
function getDictItem(dictType: string, value?: DictValue, options: DictFilterOptions = {}) {
return findDictItem(getDictData(dictType, options.onlyEnabled), value);
}
function getDictLabel(dictType: string, value?: DictValue, options: DictLabelOptions = {}) {
const { fallback = '--', onlyEnabled = false } = options;
if (value === null || value === undefined || value === '') {
return fallback;
}
const matched = getDictItem(dictType, value, { onlyEnabled });
return matched?.label || String(value);
}
function getDictLabels(dictType: string, values?: Array<DictValue> | null, options: DictLabelsOptions = {}) {
const { fallback = '--', separator = ' / ', onlyEnabled = false } = options;
if (!values?.length) {
return fallback;
}
const labels = values
.filter(value => value !== null && value !== undefined && value !== '')
.map(value => getDictLabel(dictType, value, { fallback: String(value), onlyEnabled }));
return labels.length ? labels.join(separator) : fallback;
}
function hasDictValue(dictType: string, value?: DictValue, options: DictFilterOptions = {}) {
return Boolean(getDictItem(dictType, value, options));
}
return {
loading,
initialized,
dictTypes,
dictDataMap,
loadedAt,
initDictCache,
resetDictCache,
getDictData,
getDictOptions,
getDictItem,
getDictLabel,
getDictLabels,
hasDictValue
};
});