211 lines
5.7 KiB
TypeScript
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
|
||
|
|
};
|
||
|
|
});
|