feat(projects): 菜单字典适配 i18n

This commit is contained in:
xlsea 2025-06-11 20:36:53 +08:00
parent d141ed5bef
commit 39dd9acca9
8 changed files with 52 additions and 10 deletions

View File

@ -3,6 +3,7 @@ import { computed, useAttrs } from 'vue';
import type { TagProps } from 'naive-ui';
import { useDict } from '@/hooks/business/dict';
import { isNotNull } from '@/utils/common';
import { $t } from '@/locales';
defineOptions({ name: 'DictTag' });
@ -23,13 +24,18 @@ const props = withDefaults(defineProps<Props>(), {
const attrs = useAttrs() as TagProps;
const { transformDictData } = useDict(props.dictCode, props.immediate);
const dictTagData = computed<Api.System.DictData[]>(() => {
if (props.dictData) {
return [props.dictData];
const dictData = props.dictData;
if (dictData.dictLabel?.startsWith(`dict.${dictData.dictType}.`)) {
dictData.dictLabel = $t(dictData.dictLabel as App.I18n.I18nKey);
}
return [dictData];
}
// props.value 0
if (props.dictCode && isNotNull(props.value)) {
const { transformDictData } = useDict(props.dictCode, props.immediate);
return transformDictData(props.value) || [];
}

View File

@ -3,6 +3,8 @@ import { storeToRefs } from 'pinia';
import { fetchGetDictDataByType } from '@/service/api/system';
import { useDictStore } from '@/store/modules/dict';
import { isNull } from '@/utils/common';
import { $t } from '@/locales';
export function useDict(dictType: string, immediate: boolean = true) {
const dictStore = useDictStore();
const { dictData: dictList } = storeToRefs(dictStore);
@ -19,6 +21,11 @@ export function useDict(dictType: string, immediate: boolean = true) {
}
const { data: dictData, error } = await fetchGetDictDataByType(dictType);
if (error) return;
dictData.forEach(dict => {
if (dict.dictLabel?.startsWith(`dict.${dictType}.`)) {
dict.dictLabel = $t(dict.dictLabel as App.I18n.I18nKey);
}
});
dictStore.setDict(dictType, dictData);
data.value = dictData;
}

View File

@ -234,6 +234,13 @@ const local: App.I18n.Schema = {
exception_404: '404',
exception_500: '500'
},
dict: {
sys_user_sex: {
male: 'Male',
female: 'Female',
unknown: 'Unknown'
}
},
page: {
login: {
common: {

View File

@ -234,6 +234,13 @@ const local: App.I18n.Schema = {
exception_404: '404',
exception_500: '500'
},
dict: {
sys_user_sex: {
male: '男',
female: '女',
unknown: '未知'
}
},
page: {
login: {
common: {

View File

@ -1,11 +1,17 @@
import { ref } from 'vue';
import { defineStore } from 'pinia';
import { $t } from '@/locales';
export const useDictStore = defineStore('dict', () => {
const dictData = ref<{ [key: string]: Api.System.DictData[] }>({});
const getDict = (key: string) => {
return dictData.value[key];
return dictData.value[key]?.map(item => ({
...item,
dictLabel: item.dictLabel?.startsWith(`dict.${item.dictType}.`)
? $t(item.dictLabel as App.I18n.I18nKey)
: item.dictLabel
}));
};
const setDict = (key: string, dict: Api.System.DictData[]) => {

View File

@ -103,6 +103,9 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
// eslint-disable-next-line complexity
function parseRouter(route: ElegantConstRoute, parent?: ElegantConstRoute) {
route.meta = route.meta ? route.meta : { title: route.name };
if (route.meta.title.startsWith('route.')) {
route.meta.i18nKey = route.meta.title as App.I18n.I18nKey;
}
const isLayout = route.component === 'Layout';
const isFramePage = route.component === 'FrameView';
const isParentLayout = route.component === 'ParentView';

View File

@ -467,6 +467,7 @@ declare namespace App {
};
};
route: Record<I18nRouteKey, string>;
dict: Record<string, Record<string, string>>;
page: {
common: {
id: string;

View File

@ -44,13 +44,15 @@ type Model = Api.System.DictDataOperateParams;
const model: Model = reactive(createDefaultModel());
const listClassOptions = [
{ label: 'primary', value: 'primary' },
{ label: 'success', value: 'success' },
{ label: 'info', value: 'info' },
{ label: 'warning', value: 'warning' },
{ label: 'error', value: 'error' },
{ label: 'default', value: 'default' }
const listClassOptions: Record<string, string>[] = [
{ label: 'Text', value: 'text' },
{ label: 'Default', value: 'default' },
{ label: 'Tertiary', value: 'tertiary' },
{ label: 'Primary', value: 'primary' },
{ label: 'Info', value: 'info' },
{ label: 'Success', value: 'success' },
{ label: 'Warning', value: 'warning' },
{ label: 'Error', value: 'error' }
];
function createDefaultModel(): Model {
@ -134,6 +136,9 @@ watch(visible, () => {
});
function renderTagLabel(option: { label: string; value: string }) {
if (option.value === 'text') {
return option.label;
}
return (
<NTag size="small" type={option.value as any}>
{option.label}