feat: 菜单名称国际化
This commit is contained in:
@@ -5,6 +5,7 @@ export namespace SystemMenuApi {
|
|||||||
export interface Menu {
|
export interface Menu {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
i18nKey: string;
|
||||||
permission: string;
|
permission: string;
|
||||||
type: number;
|
type: number;
|
||||||
sort: 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';
|
} from '@vben/types';
|
||||||
|
|
||||||
import { generateAccessible } from '@vben/access';
|
import { generateAccessible } from '@vben/access';
|
||||||
|
import { $te } from '@vben/locales';
|
||||||
import { preferences } from '@vben/preferences';
|
import { preferences } from '@vben/preferences';
|
||||||
import { useAccessStore } from '@vben/stores';
|
import { useAccessStore } from '@vben/stores';
|
||||||
import { convertServerMenuToRouteRecordStringComponent } from '@vben/utils';
|
import { convertServerMenuToRouteRecordStringComponent } from '@vben/utils';
|
||||||
@@ -28,7 +29,10 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) {
|
|||||||
// 由于 yudao 通过 accessStore 读取,所以不在进行 message.loading 提示
|
// 由于 yudao 通过 accessStore 读取,所以不在进行 message.loading 提示
|
||||||
// 补充说明:accessStore.accessMenus 一开始是 AppRouteRecordRaw 类型(后端加载),后面被赋值成 MenuRecordRaw 类型(前端转换)
|
// 补充说明:accessStore.accessMenus 一开始是 AppRouteRecordRaw 类型(后端加载),后面被赋值成 MenuRecordRaw 类型(前端转换)
|
||||||
const accessMenus = accessStore.accessMenus as AppRouteRecordRaw[];
|
const accessMenus = accessStore.accessMenus as AppRouteRecordRaw[];
|
||||||
return convertServerMenuToRouteRecordStringComponent(accessMenus);
|
|
||||||
|
return convertServerMenuToRouteRecordStringComponent(
|
||||||
|
convertMenuToI18nKey(accessMenus),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
// 可以指定没有权限跳转403页面
|
// 可以指定没有权限跳转403页面
|
||||||
forbiddenComponent,
|
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 };
|
export { generateAccess };
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
|
import type { ChangeEvent } from 'ant-design-vue/es/_util/EventInterface';
|
||||||
|
|
||||||
import type { Recordable } from '@vben/types';
|
import type { Recordable } from '@vben/types';
|
||||||
|
|
||||||
import type { VbenFormSchema } from '#/adapter/form';
|
import type { VbenFormSchema } from '#/adapter/form';
|
||||||
import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { SystemMenuApi } from '#/api/system/menu';
|
import type { SystemMenuApi } from '#/api/system/menu';
|
||||||
|
|
||||||
import { h } from 'vue';
|
import { h, ref } from 'vue';
|
||||||
|
|
||||||
import { useAccess } from '@vben/access';
|
import { useAccess } from '@vben/access';
|
||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
|
import { $te } from '@vben/locales';
|
||||||
import { handleTree, isHttpUrl } from '@vben/utils';
|
import { handleTree, isHttpUrl } from '@vben/utils';
|
||||||
|
|
||||||
import { z } from '#/adapter/form';
|
import { z } from '#/adapter/form';
|
||||||
@@ -23,6 +26,8 @@ import {
|
|||||||
|
|
||||||
const { hasAccessByCodes } = useAccess();
|
const { hasAccessByCodes } = useAccess();
|
||||||
|
|
||||||
|
export const titleSuffix = ref<string>();
|
||||||
|
|
||||||
/** 新增/修改的表单 */
|
/** 新增/修改的表单 */
|
||||||
export function useFormSchema(): VbenFormSchema[] {
|
export function useFormSchema(): VbenFormSchema[] {
|
||||||
return [
|
return [
|
||||||
@@ -87,6 +92,20 @@ export function useFormSchema(): VbenFormSchema[] {
|
|||||||
},
|
},
|
||||||
rules: 'required',
|
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',
|
fieldName: 'type',
|
||||||
label: '菜单类型',
|
label: '菜单类型',
|
||||||
|
|||||||
@@ -157,7 +157,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
class="size-full"
|
class="size-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</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 class="items-center justify-end"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type { SystemMenuApi } from '#/api/system/menu';
|
|||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
import { useVbenModal } from '@vben/common-ui';
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
import { $te } from '@vben/locales';
|
||||||
|
|
||||||
import { message } from 'ant-design-vue';
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@ import { useVbenForm } from '#/adapter/form';
|
|||||||
import { createMenu, getMenu, updateMenu } from '#/api/system/menu';
|
import { createMenu, getMenu, updateMenu } from '#/api/system/menu';
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
import { useFormSchema } from '../data';
|
import { titleSuffix, useFormSchema } from '../data';
|
||||||
|
|
||||||
const emit = defineEmits(['success']);
|
const emit = defineEmits(['success']);
|
||||||
const formData = ref<SystemMenuApi.Menu>();
|
const formData = ref<SystemMenuApi.Menu>();
|
||||||
@@ -67,6 +68,12 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
modalApi.lock();
|
modalApi.lock();
|
||||||
try {
|
try {
|
||||||
data = await getMenu(data.id as number);
|
data = await getMenu(data.id as number);
|
||||||
|
if (data) {
|
||||||
|
titleSuffix.value =
|
||||||
|
data?.i18nKey && $te(data.i18nKey) ? $t(data.i18nKey) : '';
|
||||||
|
} else {
|
||||||
|
titleSuffix.value = '';
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
modalApi.unlock();
|
modalApi.unlock();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
|
|||||||
componentName?: string;
|
componentName?: string;
|
||||||
components?: any;
|
components?: any;
|
||||||
fullPath?: string;
|
fullPath?: string;
|
||||||
|
i18nKey: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
id?: any;
|
id?: any;
|
||||||
keepAlive?: boolean;
|
keepAlive?: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user