在 src/locales/lang/
目錄下添加語(yǔ)言文件:
// src/locales/lang/en_US.ts
export default {
common: {
confirm: 'Confirm',
cancel: 'Cancel',
save: 'Save',
delete: 'Delete',
edit: 'Edit',
add: 'Add',
search: 'Search',
reset: 'Reset',
loading: 'Loading...',
noData: 'No Data',
operation: 'Operation',
status: 'Status',
createTime: 'Create Time',
updateTime: 'Update Time',
},
pages: {
login: {
title: 'Login',
username: 'Username',
password: 'Password',
rememberMe: 'Remember me',
forgotPassword: 'Forgot password?',
loginButton: 'Sign In',
registerButton: 'Sign Up',
},
dashboard: {
title: 'Dashboard',
welcome: 'Welcome back!',
totalUsers: 'Total Users',
totalOrders: 'Total Orders',
totalRevenue: 'Total Revenue',
growthRate: 'Growth Rate',
},
user: {
title: 'User Management',
list: 'User List',
detail: 'User Detail',
create: 'Create User',
edit: 'Edit User',
username: 'Username',
email: 'Email',
phone: 'Phone',
role: 'Role',
status: 'Status',
lastLogin: 'Last Login',
},
},
messages: {
success: {
save: 'Saved successfully',
delete: 'Deleted successfully',
update: 'Updated successfully',
create: 'Created successfully',
},
error: {
network: 'Network error',
server: 'Server error',
unauthorized: 'Unauthorized access',
forbidden: 'Access forbidden',
notFound: 'Resource not found',
},
confirm: {
delete: 'Are you sure you want to delete this item?',
logout: 'Are you sure you want to logout?',
},
},
};
編輯 src/locales/index.ts
文件:
import { createI18n } from 'vue-i18n';
import zh_CN from './lang/zh_CN';
import en_US from './lang/en_US';
const messages = {
zh_CN,
en_US,
};
// 獲取瀏覽器語(yǔ)言
function getBrowserLanguage() {
const language = navigator.language.toLowerCase();
if (language.includes('zh')) return 'zh_CN';
if (language.includes('en')) return 'en_US';
return 'zh_CN';
}
// 獲取存儲的語(yǔ)言或瀏覽器語(yǔ)言
function getStoredLanguage() {
return localStorage.getItem('language') || getBrowserLanguage();
}
const i18n = createI18n({
legacy: false,
locale: getStoredLanguage(),
fallbackLocale: 'zh_CN',
messages,
globalInjection: true,
});
export default i18n;
<!-- src/components/LanguageSwitcher.vue -->
<template>
<t-dropdown :options="languageOptions" @click="handleLanguageChange">
<t-button variant="text" :icon="TranslateIcon">
{{ currentLanguageLabel }}
</t-button>
</t-dropdown>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { TranslateIcon } from 'tdesign-icons-vue-next';
const { locale, t } = useI18n();
const languageOptions = [
{ content: '簡(jiǎn)體中文', value: 'zh_CN' },
{ content: 'English', value: 'en_US' },
];
const currentLanguageLabel = computed(() => {
const current = languageOptions.find(item => item.value === locale.value);
return current?.content || '簡(jiǎn)體中文';
});
const handleLanguageChange = (data: any) => {
locale.value = data.value;
localStorage.setItem('language', data.value);
// 刷新頁(yè)面以應用新語(yǔ)言
window.location.reload();
};
</script>
<template>
<div class="user-form">
<t-form :data="formData" :rules="rules">
<t-form-item :label="$t('pages.user.username')" name="username">
<t-input v-model="formData.username" :placeholder="$t('pages.user.username')" />
</t-form-item>
<t-form-item :label="$t('pages.user.email')" name="email">
<t-input v-model="formData.email" :placeholder="$t('pages.user.email')" />
</t-form-item>
<t-form-item>
<t-button theme="primary" @click="handleSubmit">
{{ $t('common.save') }}
</t-button>
<t-button @click="handleCancel">
{{ $t('common.cancel') }}
</t-button>
</t-form-item>
</t-form>
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const formData = reactive({
username: '',
email: '',
});
// 使用國際化的表單驗證規則
const rules = {
username: [
{ required: true, message: t('pages.user.username') + t('common.required'), type: 'error' },
],
email: [
{ required: true, message: t('pages.user.email') + t('common.required'), type: 'error' },
{ email: true, message: t('pages.user.email') + t('common.formatError'), type: 'error' },
],
};
</script>
// src/constants/permission.ts
export const PERMISSIONS = {
// 用戶(hù)管理
USER_VIEW: 'user:view',
USER_CREATE: 'user:create',
USER_EDIT: 'user:edit',
USER_DELETE: 'user:delete',
// 角色管理
ROLE_VIEW: 'role:view',
ROLE_CREATE: 'role:create',
ROLE_EDIT: 'role:edit',
ROLE_DELETE: 'role:delete',
// 系統設置
SYSTEM_CONFIG: 'system:config',
SYSTEM_LOG: 'system:log',
} as const;
export const ROLES = {
ADMIN: 'admin',
USER: 'user',
GUEST: 'guest',
} as const;
// src/utils/permission.ts
import { useUserStore } from '@/store/modules/user';
/**
* 檢查是否有指定權限
*/
export function hasPermission(permission: string | string[]): boolean {
const userStore = useUserStore();
const userPermissions = userStore.permissions;
if (Array.isArray(permission)) {
return permission.some(p => userPermissions.includes(p));
}
return userPermissions.includes(permission);
}
/**
* 檢查是否有指定角色
*/
export function hasRole(role: string | string[]): boolean {
const userStore = useUserStore();
const userRoles = userStore.roles;
if (Array.isArray(role)) {
return role.some(r => userRoles.includes(r));
}
return userRoles.includes(role);
}
/**
* 檢查是否有任意權限
*/
export function hasAnyPermission(permissions: string[]): boolean {
return permissions.some(permission => hasPermission(permission));
}
/**
* 檢查是否有所有權限
*/
export function hasAllPermissions(permissions: string[]): boolean {
return permissions.every(permission => hasPermission(permission));
}
/**
* 是否為管理員
*/
export function isAdmin(): boolean {
return hasRole('admin');
}
// src/directives/permission.ts
import type { App, Directive } from 'vue';
import { hasPermission, hasRole } from '@/utils/permission';
// 權限指令
const permissionDirective: Directive = {
mounted(el, binding) {
const { value } = binding;
if (value && !hasPermission(value)) {
el.style.display = 'none';
}
},
updated(el, binding) {
const { value } = binding;
if (value && !hasPermission(value)) {
el.style.display = 'none';
} else {
el.style.display = '';
}
},
};
// 角色指令
const roleDirective: Directive = {
mounted(el, binding) {
const { value } = binding;
if (value && !hasRole(value)) {
el.style.display = 'none';
}
},
updated(el, binding) {
const { value } = binding;
if (value && !hasRole(value)) {
el.style.display = 'none';
} else {
el.style.display = '';
}
},
};
export function setupPermissionDirectives(app: App) {
app.directive('permission', permissionDirective);
app.directive('role', roleDirective);
}
<template>
<div class="user-management">
<!-- 使用權限指令 -->
<t-button
v-permission="PERMISSIONS.USER_CREATE"
theme="primary"
@click="handleCreate"
>
{{ $t('common.add') }}
</t-button>
<!-- 使用角色指令 -->
<t-button
v-role="ROLES.ADMIN"
theme="danger"
@click="handleDeleteAll"
>
批量刪除
</t-button>
<!-- 使用函數判斷 -->
<t-button
v-if="hasPermission(PERMISSIONS.USER_EDIT)"
@click="handleEdit"
>
{{ $t('common.edit') }}
</t-button>
<t-table :columns="columns" :data="tableData">
<template #operation="{ row }">
<t-button
v-permission="PERMISSIONS.USER_EDIT"
size="small"
@click="handleEdit(row)"
>
編輯
</t-button>
<t-button
v-permission="PERMISSIONS.USER_DELETE"
theme="danger"
size="small"
@click="handleDelete(row)"
>
刪除
</t-button>
</template>
</t-table>
</div>
</template>
<script setup lang="ts">
import { hasPermission, hasRole } from '@/utils/permission';
import { PERMISSIONS, ROLES } from '@/constants/permission';
</script>
// src/permission.ts
import router from '@/router';
import { useUserStore } from '@/store';
import { hasPermission, hasRole } from '@/utils/permission';
import { MessagePlugin } from 'tdesign-vue-next';
// 白名單路由(不需要登錄)
const whiteList = ['/login', '/register', '/404', '/403'];
router.beforeEach(async (to, from, next) => {
const userStore = useUserStore();
// 檢查是否已登錄
if (!userStore.token) {
if (whiteList.includes(to.path)) {
next();
} else {
next('/login');
}
return;
}
// 如果已登錄但沒(méi)有用戶(hù)信息,獲取用戶(hù)信息
if (!userStore.userInfo) {
try {
await userStore.fetchUserInfo();
} catch (error) {
userStore.logout();
next('/login');
return;
}
}
// 檢查路由權限
if (to.meta.roles && !hasRole(to.meta.roles)) {
MessagePlugin.error('您沒(méi)有權限訪(fǎng)問(wèn)該頁(yè)面');
next('/403');
return;
}
if (to.meta.permissions && !hasPermission(to.meta.permissions)) {
MessagePlugin.error('您沒(méi)有權限訪(fǎng)問(wèn)該頁(yè)面');
next('/403');
return;
}
next();
});
<!-- src/pages/system/permission.vue -->
<template>
<div class="permission-management">
<t-card title="權限管理">
<template #actions>
<t-button
v-permission="PERMISSIONS.ROLE_CREATE"
theme="primary"
@click="handleCreateRole"
>
添加角色
</t-button>
</template>
<t-table :columns="columns" :data="roleList" :loading="loading">
<template #permissions="{ row }">
<t-tag
v-for="permission in row.permissions"
:key="permission"
size="small"
style="margin-right: 4px;"
>
{{ getPermissionLabel(permission) }}
</t-tag>
</template>
<template #operation="{ row }">
<t-button
v-permission="PERMISSIONS.ROLE_EDIT"
size="small"
@click="handleEditRole(row)"
>
編輯
</t-button>
<t-button
v-permission="PERMISSIONS.ROLE_DELETE"
theme="danger"
size="small"
@click="handleDeleteRole(row)"
>
刪除
</t-button>
</template>
</t-table>
</t-card>
<!-- 角色編輯對話(huà)框 -->
<t-dialog
v-model:visible="dialogVisible"
:title="isEdit ? '編輯角色' : '添加角色'"
@confirm="handleSaveRole"
>
<t-form :data="roleForm" :rules="rules">
<t-form-item label="角色名稱(chēng)" name="name">
<t-input v-model="roleForm.name" placeholder="請輸入角色名稱(chēng)" />
</t-form-item>
<t-form-item label="角色描述" name="description">
<t-textarea v-model="roleForm.description" placeholder="請輸入角色描述" />
</t-form-item>
<t-form-item label="權限配置" name="permissions">
<t-tree
v-model:checked="roleForm.permissions"
:data="permissionTree"
checkable
expand-all
/>
</t-form-item>
</t-form>
</t-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue';
import { PERMISSIONS } from '@/constants/permission';
import { hasPermission } from '@/utils/permission';
const loading = ref(false);
const dialogVisible = ref(false);
const isEdit = ref(false);
const roleList = ref([]);
const roleForm = reactive({
id: '',
name: '',
description: '',
permissions: [],
});
const columns = [
{ colKey: 'name', title: '角色名稱(chēng)' },
{ colKey: 'description', title: '描述' },
{ colKey: 'permissions', title: '權限', cell: 'permissions' },
{ colKey: 'operation', title: '操作', cell: 'operation' },
];
const permissionTree = [
{
value: 'user',
label: '用戶(hù)管理',
children: [
{ value: 'user:view', label: '查看用戶(hù)' },
{ value: 'user:create', label: '創(chuàng )建用戶(hù)' },
{ value: 'user:edit', label: '編輯用戶(hù)' },
{ value: 'user:delete', label: '刪除用戶(hù)' },
],
},
{
value: 'role',
label: '角色管理',
children: [
{ value: 'role:view', label: '查看角色' },
{ value: 'role:create', label: '創(chuàng )建角色' },
{ value: 'role:edit', label: '編輯角色' },
{ value: 'role:delete', label: '刪除角色' },
],
},
];
const getPermissionLabel = (permission: string) => {
// 根據權限代碼返回中文標簽
const permissionMap: Record<string, string> = {
'user:view': '查看用戶(hù)',
'user:create': '創(chuàng )建用戶(hù)',
'user:edit': '編輯用戶(hù)',
'user:delete': '刪除用戶(hù)',
// ... 更多權限映射
};
return permissionMap[permission] || permission;
};
const handleCreateRole = () => {
isEdit.value = false;
Object.assign(roleForm, {
id: '',
name: '',
description: '',
permissions: [],
});
dialogVisible.value = true;
};
const handleEditRole = (role: any) => {
isEdit.value = true;
Object.assign(roleForm, role);
dialogVisible.value = true;
};
const handleSaveRole = async () => {
// 保存角色邏輯
try {
if (isEdit.value) {
await updateRole(roleForm);
} else {
await createRole(roleForm);
}
dialogVisible.value = false;
fetchRoleList();
} catch (error) {
console.error('保存角色失敗:', error);
}
};
const fetchRoleList = async () => {
loading.value = true;
try {
roleList.value = await getRoleList();
} catch (error) {
console.error('獲取角色列表失敗:', error);
} finally {
loading.value = false;
}
};
onMounted(() => {
fetchRoleList();
});
</script>
這個(gè)權限配置指南涵蓋了完整的國際化和權限管理功能,包括多語(yǔ)言支持、權限檢查、路由守衛和權限管理界面等。