feat: 菜单名称国际化
This commit is contained in:
@@ -5,6 +5,7 @@ export namespace SystemMenuApi {
|
||||
export interface Menu {
|
||||
id: number;
|
||||
name: string;
|
||||
i18nKey: string;
|
||||
permission: string;
|
||||
type: number;
|
||||
sort: number;
|
||||
|
||||
85
apps/web-antd/src/locales/langs/en-US/menu.json
Normal file
85
apps/web-antd/src/locales/langs/en-US/menu.json
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"system": {
|
||||
"base": "System Management",
|
||||
"tenant": {
|
||||
"base": "Tenant Management",
|
||||
"list": "Tenant List",
|
||||
"package": "Tenant Package"
|
||||
},
|
||||
"user": "User Management",
|
||||
"role": "Role Management",
|
||||
"menu": "Menu Management",
|
||||
"dept": "Department Management",
|
||||
"post": "Post Management",
|
||||
"dict": "Dictionary Management",
|
||||
"msg": {
|
||||
"base": "Message Center",
|
||||
"sms": {
|
||||
"base": "SMS Management",
|
||||
"channel": "SMS Channel",
|
||||
"template": "SMS Template",
|
||||
"log": "SMS Log"
|
||||
},
|
||||
"mail": {
|
||||
"base": "Email Management",
|
||||
"account": "Email Account",
|
||||
"template": "Email Template",
|
||||
"log": "Email Log"
|
||||
},
|
||||
"notify": {
|
||||
"base": "Internal Message Management",
|
||||
"template": "Template Management",
|
||||
"log": "Message Log"
|
||||
},
|
||||
"notice": "Notice Announcement"
|
||||
},
|
||||
"notice": {
|
||||
"base": "Notice Announcement",
|
||||
"list": "Notice List",
|
||||
"template": "Notice Template"
|
||||
},
|
||||
"log": {
|
||||
"base": "Audit Log",
|
||||
"operation": "Operation Log",
|
||||
"login": "Login Log"
|
||||
},
|
||||
"oauth": {
|
||||
"base": "OAuth 2.0",
|
||||
"client": "Application Management",
|
||||
"token": "Token Management"
|
||||
},
|
||||
"social": {
|
||||
"base": "Third Party Login",
|
||||
"client": "Third Party Application",
|
||||
"user": "Third Party User"
|
||||
},
|
||||
"area": "Area Management"
|
||||
},
|
||||
"infra": {
|
||||
"base": "Infrastructure",
|
||||
"codegen": "Code Generation",
|
||||
"datasource": "Data Source Configuration",
|
||||
"formConstruction": "Form Construction",
|
||||
"api": "API Management",
|
||||
"apiLog": {
|
||||
"base": "API Log",
|
||||
"access": "Access Log",
|
||||
"error": "Error Log"
|
||||
},
|
||||
"webSocket": "WebSocket",
|
||||
"file": {
|
||||
"base": "File Management",
|
||||
"config": "File Configuration",
|
||||
"list": "File List"
|
||||
},
|
||||
"job": "Scheduled Tasks",
|
||||
"config": "Config Management",
|
||||
"monitor": {
|
||||
"base": "Monitoring Center",
|
||||
"mysql": "MySQL Monitoring",
|
||||
"redis": "Redis Monitoring",
|
||||
"java": "Java Monitoring",
|
||||
"track": "Link Tracking"
|
||||
}
|
||||
}
|
||||
}
|
||||
85
apps/web-antd/src/locales/langs/zh-CN/menu.json
Normal file
85
apps/web-antd/src/locales/langs/zh-CN/menu.json
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"system": {
|
||||
"base": "系统管理",
|
||||
"tenant": {
|
||||
"base": "租户管理",
|
||||
"list": "租户列表",
|
||||
"package": "租户套餐"
|
||||
},
|
||||
"user": "用户管理",
|
||||
"role": "角色管理",
|
||||
"menu": "菜单管理",
|
||||
"dept": "部门管理",
|
||||
"post": "岗位管理",
|
||||
"dict": "字典管理",
|
||||
"msg": {
|
||||
"base": "消息中心",
|
||||
"sms": {
|
||||
"base": "短信管理",
|
||||
"channel": "短信渠道",
|
||||
"template": "短信模板",
|
||||
"log": "短信日志"
|
||||
},
|
||||
"mail": {
|
||||
"base": "邮件管理",
|
||||
"account": "邮箱账号",
|
||||
"template": "邮件模板",
|
||||
"log": "邮件记录"
|
||||
},
|
||||
"notify": {
|
||||
"base": "站内信管理",
|
||||
"template": "模板管理",
|
||||
"log": "消息记录"
|
||||
},
|
||||
"notice": "通知公告"
|
||||
},
|
||||
"notice": {
|
||||
"base": "通知公告",
|
||||
"list": "通知公告列表",
|
||||
"template": "通知公告模板"
|
||||
},
|
||||
"log": {
|
||||
"base": "审计日志",
|
||||
"operation": "操作日志",
|
||||
"login": "登录日志"
|
||||
},
|
||||
"oauth": {
|
||||
"base": "OAuth 2.0",
|
||||
"client": "应用管理",
|
||||
"token": "令牌管理"
|
||||
},
|
||||
"social": {
|
||||
"base": "三方登录",
|
||||
"client": "三方应用",
|
||||
"user": "三方用户"
|
||||
},
|
||||
"area": "地区管理"
|
||||
},
|
||||
"infra": {
|
||||
"base": "基础设施",
|
||||
"codegen": "代码生成",
|
||||
"datasource": "数据源配置",
|
||||
"formConstruction": "表单构建",
|
||||
"api": "API接口",
|
||||
"apiLog": {
|
||||
"base": "API日志",
|
||||
"access": "访问日志",
|
||||
"error": "错误日志"
|
||||
},
|
||||
"webSocket": "WebSocket",
|
||||
"file": {
|
||||
"base": "文件管理",
|
||||
"config": "文件配置",
|
||||
"list": "文件列表"
|
||||
},
|
||||
"job": "定时任务",
|
||||
"config": "配置管理",
|
||||
"monitor": {
|
||||
"base": "监控中心",
|
||||
"mysql": "MySQL 监控",
|
||||
"redis": "Redis 监控",
|
||||
"java": "Java 监控",
|
||||
"track": "链路追踪"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
} from '@vben/types';
|
||||
|
||||
import { generateAccessible } from '@vben/access';
|
||||
import { $te } from '@vben/locales';
|
||||
import { preferences } from '@vben/preferences';
|
||||
import { useAccessStore } from '@vben/stores';
|
||||
import { convertServerMenuToRouteRecordStringComponent } from '@vben/utils';
|
||||
@@ -28,7 +29,10 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) {
|
||||
// 由于 yudao 通过 accessStore 读取,所以不在进行 message.loading 提示
|
||||
// 补充说明:accessStore.accessMenus 一开始是 AppRouteRecordRaw 类型(后端加载),后面被赋值成 MenuRecordRaw 类型(前端转换)
|
||||
const accessMenus = accessStore.accessMenus as AppRouteRecordRaw[];
|
||||
return convertServerMenuToRouteRecordStringComponent(accessMenus);
|
||||
|
||||
return convertServerMenuToRouteRecordStringComponent(
|
||||
convertMenuToI18nKey(accessMenus),
|
||||
);
|
||||
},
|
||||
// 可以指定没有权限跳转403页面
|
||||
forbiddenComponent,
|
||||
@@ -38,4 +42,24 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将菜单名称转换为国际化键
|
||||
* @param menuList 菜单列表
|
||||
* @returns 转换后的菜单列表
|
||||
*/
|
||||
function convertMenuToI18nKey(
|
||||
menuList: AppRouteRecordRaw[],
|
||||
): AppRouteRecordRaw[] {
|
||||
return menuList.map((menu) => {
|
||||
const { i18nKey } = menu;
|
||||
if (i18nKey) {
|
||||
menu.name = $te(i18nKey) ? i18nKey : menu.name;
|
||||
}
|
||||
if (menu.children) {
|
||||
menu.children = convertMenuToI18nKey(menu.children);
|
||||
}
|
||||
return menu;
|
||||
});
|
||||
}
|
||||
|
||||
export { generateAccess };
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import type { ChangeEvent } from 'ant-design-vue/es/_util/EventInterface';
|
||||
|
||||
import type { Recordable } from '@vben/types';
|
||||
|
||||
import type { VbenFormSchema } from '#/adapter/form';
|
||||
import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { SystemMenuApi } from '#/api/system/menu';
|
||||
|
||||
import { h } from 'vue';
|
||||
import { h, ref } from 'vue';
|
||||
|
||||
import { useAccess } from '@vben/access';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
import { $te } from '@vben/locales';
|
||||
import { handleTree, isHttpUrl } from '@vben/utils';
|
||||
|
||||
import { z } from '#/adapter/form';
|
||||
@@ -23,6 +26,8 @@ import {
|
||||
|
||||
const { hasAccessByCodes } = useAccess();
|
||||
|
||||
export const titleSuffix = ref<string>();
|
||||
|
||||
/** 新增/修改的表单 */
|
||||
export function useFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
@@ -87,6 +92,20 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||
},
|
||||
rules: 'required',
|
||||
},
|
||||
{
|
||||
fieldName: 'i18nKey',
|
||||
label: $t('common.i18nKey'),
|
||||
component: 'Input',
|
||||
componentProps() {
|
||||
// 不需要处理多语言时就无需这么做
|
||||
return {
|
||||
addonAfter: titleSuffix.value,
|
||||
onChange({ target: { value } }: ChangeEvent) {
|
||||
titleSuffix.value = value && $te(value) ? $t(value) : undefined;
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'type',
|
||||
label: '菜单类型',
|
||||
|
||||
@@ -157,7 +157,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
class="size-full"
|
||||
/>
|
||||
</div>
|
||||
<span class="flex-auto">{{ $t(row.name) }}</span>
|
||||
<span class="flex-auto">{{
|
||||
$te(row.i18nKey) ? $t(row.i18nKey) : $t(row.name)
|
||||
}}</span>
|
||||
<div class="items-center justify-end"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { SystemMenuApi } from '#/api/system/menu';
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
import { $te } from '@vben/locales';
|
||||
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
@@ -11,7 +12,7 @@ import { useVbenForm } from '#/adapter/form';
|
||||
import { createMenu, getMenu, updateMenu } from '#/api/system/menu';
|
||||
import { $t } from '#/locales';
|
||||
|
||||
import { useFormSchema } from '../data';
|
||||
import { titleSuffix, useFormSchema } from '../data';
|
||||
|
||||
const emit = defineEmits(['success']);
|
||||
const formData = ref<SystemMenuApi.Menu>();
|
||||
@@ -67,6 +68,12 @@ const [Modal, modalApi] = useVbenModal({
|
||||
modalApi.lock();
|
||||
try {
|
||||
data = await getMenu(data.id as number);
|
||||
if (data) {
|
||||
titleSuffix.value =
|
||||
data?.i18nKey && $te(data.i18nKey) ? $t(data.i18nKey) : '';
|
||||
} else {
|
||||
titleSuffix.value = '';
|
||||
}
|
||||
} finally {
|
||||
modalApi.unlock();
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
|
||||
componentName?: string;
|
||||
components?: any;
|
||||
fullPath?: string;
|
||||
i18nKey: string;
|
||||
icon?: string;
|
||||
id?: any;
|
||||
keepAlive?: boolean;
|
||||
|
||||
Reference in New Issue
Block a user