Pre Merge pull request !869 from 李家辉/dev-i18n-menu

pull/869/MERGE
李家辉 2026-05-03 01:19:16 +00:00 committed by Gitee
commit d3902dc3dd
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
7 changed files with 51 additions and 6 deletions

View File

@ -3,6 +3,7 @@ import request from '@/config/axios'
export interface MenuVO { export interface MenuVO {
id: number id: number
name: string name: string
nameEn?: string
permission: string permission: string
type: number type: number
sort: number sort: number

View File

@ -141,9 +141,9 @@ export default {
qrcode: 'Scan the QR code to log in', qrcode: 'Scan the QR code to log in',
btnRegister: 'Sign up', btnRegister: 'Sign up',
SmsSendMsg: 'code has been sent', SmsSendMsg: 'code has been sent',
resetPassword: "Reset Password", resetPassword: 'Reset Password',
resetPasswordSuccess: "Reset Password Success", resetPasswordSuccess: 'Reset Password Success',
invalidTenantName:"Invalid Tenant Name" invalidTenantName: 'Invalid Tenant Name'
}, },
captcha: { captcha: {
verify: 'Verify', verify: 'Verify',
@ -156,6 +156,7 @@ export default {
}, },
router: { router: {
login: 'Login', login: 'Login',
socialLogin: 'Social Login',
home: 'Home', home: 'Home',
analysis: 'Analysis', analysis: 'Analysis',
workplace: 'Workplace' workplace: 'Workplace'
@ -459,4 +460,4 @@ export default {
btn_zoom_out: 'Zoom out', btn_zoom_out: 'Zoom out',
preview: 'Preivew' preview: 'Preivew'
} }
} }

View File

@ -3,6 +3,10 @@ import { defineStore } from 'pinia'
import { getAccessToken, removeToken } from '@/utils/auth' import { getAccessToken, removeToken } from '@/utils/auth'
import { CACHE_KEY, useCache, deleteUserCache } from '@/hooks/web/useCache' import { CACHE_KEY, useCache, deleteUserCache } from '@/hooks/web/useCache'
import { getInfo, loginOut } from '@/api/login' import { getInfo, loginOut } from '@/api/login'
import { eachTree } from '@/utils/tree'
import { i18n } from '@/plugins/vueI18n'
import { isNull } from '@/utils/is'
import { LocaleMessages } from 'vue-i18n'
const { wsCache } = useCache() const { wsCache } = useCache()
@ -68,6 +72,23 @@ export const useUserStore = defineStore('admin-user', {
this.isSetUser = true this.isSetUser = true
wsCache.set(CACHE_KEY.USER, userInfo) wsCache.set(CACHE_KEY.USER, userInfo)
wsCache.set(CACHE_KEY.ROLE_ROUTERS, userInfo.menus) wsCache.set(CACHE_KEY.ROLE_ROUTERS, userInfo.menus)
// 设置动态翻译
// 兼容切换语言不刷新页面的情况,所有语言都需要设置
type LocaleMessageMap = LocaleMessages<Record<string, any>>
const routerLocaleMessage =
i18n.global.getLocaleMessage<LocaleMessageMap>('zh-CN')?.router ?? reactive({})
const routerLocaleMessageEn =
i18n.global.getLocaleMessage<LocaleMessageMap>('en')?.router ?? reactive({})
eachTree(userInfo.menus, (menuItem) => {
const key = menuItem.id // 不能用nameOAuth 2.0这种带特殊字符的name会难以识别
const zh = menuItem.name
const en = isNull(menuItem.nameEn) ? zh : menuItem.nameEn
routerLocaleMessage[key] = zh
routerLocaleMessageEn[key] = en
})
i18n.global.setLocaleMessage('zh-CN', { router: routerLocaleMessage })
i18n.global.setLocaleMessage('en', { router: routerLocaleMessageEn })
}, },
async setUserAvatarAction(avatar: string) { async setUserAvatarAction(avatar: string) {
const userInfo = wsCache.get(CACHE_KEY.USER) const userInfo = wsCache.get(CACHE_KEY.USER)

View File

@ -67,7 +67,7 @@ export const generateRoute = (routes: AppCustomRouteRecordRaw[]): AppRouteRecord
for (const route of routes) { for (const route of routes) {
// 1. 生成 meta 菜单元数据 // 1. 生成 meta 菜单元数据
const meta = { const meta = {
title: route.name, title: 'router.' + route.id,
icon: route.icon, icon: route.icon,
hidden: !route.visible, hidden: !route.visible,
noCache: !route.keepAlive, noCache: !route.keepAlive,

View File

@ -20,6 +20,9 @@
<el-form-item label="菜单名称" prop="name"> <el-form-item label="菜单名称" prop="name">
<el-input v-model="formData.name" clearable placeholder="请输入菜单名称" /> <el-input v-model="formData.name" clearable placeholder="请输入菜单名称" />
</el-form-item> </el-form-item>
<el-form-item label="英文名称" prop="nameEn">
<el-input v-model="formData.nameEn" clearable placeholder="请输入英文名称" />
</el-form-item>
<el-form-item label="菜单类型" prop="type"> <el-form-item label="菜单类型" prop="type">
<el-radio-group v-model="formData.type"> <el-radio-group v-model="formData.type">
<el-radio-button <el-radio-button
@ -132,6 +135,7 @@ const formType = ref('') // 表单的类型create - 新增update - 修改
const formData = ref({ const formData = ref({
id: undefined, id: undefined,
name: '', name: '',
nameEn: '',
permission: '', permission: '',
type: SystemMenuTypeEnum.DIR, type: SystemMenuTypeEnum.DIR,
sort: Number(undefined), sort: Number(undefined),
@ -224,7 +228,7 @@ const menuTree = ref<Tree[]>([]) // 树形结构
const getTree = async () => { const getTree = async () => {
menuTree.value = [] menuTree.value = []
const res = await MenuApi.getSimpleMenusList() const res = await MenuApi.getSimpleMenusList()
let menu: Tree = { id: 0, name: '主类目', children: [] } let menu: Tree = { id: 0, name: '主类目', nameEn: 'Root', children: [] }
menu.children = handleTree(res) menu.children = handleTree(res)
menuTree.value.push(menu) menuTree.value.push(menu)
} }
@ -234,6 +238,7 @@ const resetForm = () => {
formData.value = { formData.value = {
id: undefined, id: undefined,
name: '', name: '',
nameEn: '',
permission: '', permission: '',
type: SystemMenuTypeEnum.DIR, type: SystemMenuTypeEnum.DIR,
sort: Number(undefined), sort: Number(undefined),

View File

@ -20,6 +20,15 @@
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="英文名称" prop="nameEn">
<el-input
v-model="queryParams.nameEn"
class="!w-240px"
clearable
placeholder="请输入英文名称"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-select <el-select
v-model="queryParams.status" v-model="queryParams.status"
@ -110,6 +119,12 @@ const columns = [
width: 250, width: 250,
fixed: TableV2FixedDir.LEFT fixed: TableV2FixedDir.LEFT
}, },
{
key: 'nameEn',
title: '英文名称',
dataKey: 'nameEn',
width: 250
},
{ {
key: 'icon', key: 'icon',
title: '图标', title: '图标',
@ -222,6 +237,7 @@ const loading = ref(true) // 列表的加载中
const list = ref<any[]>([]) // const list = ref<any[]>([]) //
const queryParams = reactive({ const queryParams = reactive({
name: undefined, name: undefined,
nameEn: undefined,
status: undefined status: undefined
}) })
const queryFormRef = ref() // const queryFormRef = ref() //

1
types/router.d.ts vendored
View File

@ -68,6 +68,7 @@ declare global {
} }
interface AppCustomRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> { interface AppCustomRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
id: number
icon: any icon: any
name: string name: string
meta: RouteMeta meta: RouteMeta