浏览代码

静态页面国际化基本完成

Huanyi 1 周之前
父节点
当前提交
ee0a43696a
共有 34 个文件被更改,包括 1870 次插入459 次删除
  1. 2 2
      .env.development
  2. 2 2
      .env.production
  3. 7 4
      src/components/RightToolbar/index.vue
  4. 12 1
      src/lang/en_US.ts
  5. 159 0
      src/lang/modules/README.md
  6. 9 0
      src/lang/modules/components/en_US.ts
  7. 9 0
      src/lang/modules/components/zh_CN.ts
  8. 6 0
      src/lang/modules/monitor/index.ts
  9. 6 0
      src/lang/modules/monitor/index_en.ts
  10. 36 0
      src/lang/modules/monitor/online/en_US.ts
  11. 36 0
      src/lang/modules/monitor/online/zh_CN.ts
  12. 72 0
      src/lang/modules/system/dept/en_US.ts
  13. 72 0
      src/lang/modules/system/dept/zh_CN.ts
  14. 16 0
      src/lang/modules/system/index.ts
  15. 16 0
      src/lang/modules/system/index_en.ts
  16. 81 0
      src/lang/modules/system/post/en_US.ts
  17. 81 0
      src/lang/modules/system/post/zh_CN.ts
  18. 94 0
      src/lang/modules/system/role/en_US.ts
  19. 94 0
      src/lang/modules/system/role/zh_CN.ts
  20. 105 0
      src/lang/modules/system/tenant/en_US.ts
  21. 105 0
      src/lang/modules/system/tenant/zh_CN.ts
  22. 64 0
      src/lang/modules/system/tenantPackage/en_US.ts
  23. 64 0
      src/lang/modules/system/tenantPackage/zh_CN.ts
  24. 128 0
      src/lang/modules/system/user/en_US.ts
  25. 128 0
      src/lang/modules/system/user/zh_CN.ts
  26. 12 1
      src/lang/zh_CN.ts
  27. 24 22
      src/views/monitor/online/index.vue
  28. 50 48
      src/views/system/dept/index.vue
  29. 56 54
      src/views/system/post/index.vue
  30. 79 77
      src/views/system/role/index.vue
  31. 85 83
      src/views/system/tenant/index.vue
  32. 45 43
      src/views/system/tenantPackage/index.vue
  33. 15 24
      src/views/system/user/authRole.vue
  34. 100 98
      src/views/system/user/index.vue

+ 2 - 2
.env.development

@@ -1,6 +1,6 @@
 # 页面标题
-VITE_APP_TITLE = 智能eTMF系统
-VITE_APP_LOGO_TITLE = 智能eTMF系统
+VITE_APP_TITLE = eTMF
+VITE_APP_LOGO_TITLE = eTMF
 
 # 开发环境配置
 VITE_APP_ENV = 'development'

+ 2 - 2
.env.production

@@ -1,6 +1,6 @@
 # 页面标题
-VITE_APP_TITLE = 智能eTMF系统
-VITE_APP_LOGO_TITLE = 智能eTMF系统
+VITE_APP_TITLE = eTMF
+VITE_APP_LOGO_TITLE = eTMF
 
 # 生产环境配置
 VITE_APP_ENV = 'production'

+ 7 - 4
src/components/RightToolbar/index.vue

@@ -1,16 +1,16 @@
 <template>
   <div class="top-right-btn" :style="style">
     <el-row>
-      <el-tooltip v-if="search" class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
+      <el-tooltip v-if="search" class="item" effect="dark" :content="showSearch ? t('components.rightToolbar.hideSearch') : t('components.rightToolbar.showSearch')" placement="top">
         <el-button circle icon="Search" @click="toggleSearch()" />
       </el-tooltip>
-      <el-tooltip class="item" effect="dark" content="刷新" placement="top">
+      <el-tooltip class="item" effect="dark" :content="t('components.rightToolbar.refresh')" placement="top">
         <el-button circle icon="Refresh" @click="refresh()" />
       </el-tooltip>
-      <el-tooltip v-if="columns" class="item" effect="dark" content="显示/隐藏列" placement="top">
+      <el-tooltip v-if="columns" class="item" effect="dark" :content="t('components.rightToolbar.columnSetting')" placement="top">
         <div class="show-btn">
           <el-popover placement="bottom" trigger="click">
-            <div class="tree-header">显示/隐藏列</div>
+            <div class="tree-header">{{ t('components.rightToolbar.columnSetting') }}</div>
             <el-tree
               ref="columnRef"
               :data="columns"
@@ -31,6 +31,9 @@
 
 <script setup lang="ts">
 import { propTypes } from '@/utils/propTypes';
+import { useI18n } from 'vue-i18n';
+
+const { t } = useI18n();
 
 const props = defineProps({
   showSearch: propTypes.bool.def(true),

+ 12 - 1
src/lang/en_US.ts

@@ -1,3 +1,8 @@
+// 导入模块化的翻译文件
+import components from './modules/components/en_US';
+import system from './modules/system/index_en';
+import monitor from './modules/monitor/index_en';
+
 export default {
   // 路由国际化
   route: {
@@ -69,6 +74,8 @@ export default {
       }
     }
   },
+  // 公共组件国际化(从模块导入)
+  components,
   // 导航栏国际化
   navbar: {
     full: 'Full Screen',
@@ -81,5 +88,9 @@ export default {
     layoutSetting: 'Layout Setting',
     personalCenter: 'Personal Center',
     logout: 'Logout'
-  }
+  },
+  // 系统管理模块(包含用户、角色等)
+  ...system,
+  // 监控管理模块
+  ...monitor
 };

+ 159 - 0
src/lang/modules/README.md

@@ -0,0 +1,159 @@
+# 国际化翻译模块化管理
+
+## 目录结构
+
+```
+lang/
+├── modules/              # 模块化翻译文件目录
+│   ├── system/          # 系统管理模块
+│   │   ├── user/        # 用户管理翻译
+│   │   │   ├── zh_CN.ts
+│   │   │   └── en_US.ts
+│   │   ├── role/        # 角色管理翻译
+│   │   │   ├── zh_CN.ts
+│   │   │   └── en_US.ts
+│   │   ├── index.ts     # 中文模块索引
+│   │   └── index_en.ts  # 英文模块索引
+│   ├── components/      # 公共组件翻译
+│   │   ├── zh_CN.ts
+│   │   └── en_US.ts
+│   └── ...              # 其他业务模块
+├── zh_CN.ts             # 中文主语言文件
+├── en_US.ts             # 英文主语言文件
+└── index.ts             # i18n 配置入口
+```
+
+## 使用规范
+
+### 1. 创建新模块翻译
+
+#### A. 系统管理模块下的子模块
+
+在 `modules/system/` 目录下创建:
+
+1. 创建子模块文件夹,如 `modules/system/dept/`
+2. 创建语言文件:`zh_CN.ts` 和 `en_US.ts`
+3. 更新 `modules/system/index.ts` 和 `index_en.ts`
+
+**示例:** `modules/system/dept/zh_CN.ts`
+```typescript
+// 部门管理模块 - 中文翻译
+export default {
+  button: {
+    add: '新增部门',
+    edit: '编辑部门',
+    delete: '删除部门'
+  },
+  form: {
+    deptName: '部门名称',
+    leader: '负责人'
+  }
+};
+```
+
+**更新 `modules/system/index.ts`:**
+```typescript
+import user from './user/zh_CN';
+import role from './role/zh_CN';
+import dept from './dept/zh_CN';  // 新增
+
+export default {
+  user,
+  role,
+  dept  // 新增
+};
+```
+
+#### B. 其他业务模块
+
+在 `modules/` 目录下创建独立模块:
+
+1. 创建模块文件夹,如 `modules/setting/`
+2. 创建语言文件和索引文件
+3. 在主语言文件中导入
+
+### 2. 在主语言文件中导入
+
+**当前结构(使用扩展运算符):**
+
+```typescript
+// zh_CN.ts
+import components from './modules/components/zh_CN';
+import system from './modules/system/index';
+
+export default {
+  // ... 其他配置
+  components,
+  ...system  // 展开 system 模块,包含 user、role 等
+};
+```
+
+这样 `user` 和 `role` 会直接暴露在根级别,保持向后兼容。
+
+### 3. 在组件中使用
+
+```vue
+<script setup>
+import { useI18n } from 'vue-i18n';
+const { t } = useI18n();
+</script>
+
+<template>
+  <el-button>{{ t('role.button.add') }}</el-button>
+  <el-form-item :label="t('role.form.roleName')">
+    ...
+  </el-form-item>
+</template>
+```
+
+## 优势
+
+### ✅ 模块化管理
+- 每个功能模块的翻译独立维护
+- 文件结构清晰,易于查找和修改
+
+### ✅ 更好的协作
+- 不同开发人员可以同时修改不同模块的翻译文件
+- 减少 Git 冲突的可能性
+
+### ✅ 按需加载
+- 未来可以实现翻译文件的懒加载
+- 减小初始加载体积
+
+### ✅ 易于维护
+- 翻译内容与业务模块对应
+- 便于新增语言支持
+
+## 注意事项
+
+1. **保持结构一致**:中英文翻译文件的结构必须完全一致
+2. **避免重复键名**:不同模块的键名可以相同,但同一模块内不能重复
+3. **命名规范**:使用小驼峰命名法(camelCase)
+4. **注释说明**:在翻译文件顶部添加模块说明注释
+
+## 现有模块
+
+### 系统管理模块 (system)
+- **user** - 用户管理(用户列表、新增编辑、角色分配等)
+- **role** - 角色管理(角色列表、权限配置、数据权限等)
+
+### 公共模块
+- **components** - 公共组件(RightToolbar 等)
+
+## 待添加模块
+
+根据系统功能,后续可添加:
+
+### system 模块下
+- dept - 部门管理
+- menu - 菜单管理
+- post - 岗位管理
+- dict - 字典管理
+- config - 参数配置
+- notice - 通知公告
+- log - 日志管理
+
+### 其他业务模块
+- monitor - 系统监控
+- tool - 系统工具
+- ...

+ 9 - 0
src/lang/modules/components/en_US.ts

@@ -0,0 +1,9 @@
+// 公共组件 - 英文翻译
+export default {
+  rightToolbar: {
+    hideSearch: 'Hide Search',
+    showSearch: 'Show Search',
+    refresh: 'Refresh',
+    columnSetting: 'Show/Hide Columns'
+  }
+};

+ 9 - 0
src/lang/modules/components/zh_CN.ts

@@ -0,0 +1,9 @@
+// 公共组件 - 中文翻译
+export default {
+  rightToolbar: {
+    hideSearch: '隐藏搜索',
+    showSearch: '显示搜索',
+    refresh: '刷新',
+    columnSetting: '显示/隐藏列'
+  }
+};

+ 6 - 0
src/lang/modules/monitor/index.ts

@@ -0,0 +1,6 @@
+// 监控管理模块 - 统一导出
+import online from './online/zh_CN';
+
+export default {
+  online
+};

+ 6 - 0
src/lang/modules/monitor/index_en.ts

@@ -0,0 +1,6 @@
+// 监控管理模块 - 统一导出 (English)
+import online from './online/en_US';
+
+export default {
+  online
+};

+ 36 - 0
src/lang/modules/monitor/online/en_US.ts

@@ -0,0 +1,36 @@
+// 在线用户监控模块 - 英文翻译
+export default {
+  // 搜索表单
+  search: {
+    ipaddr: 'Login IP Address',
+    ipaddrPlaceholder: 'Please enter login IP address',
+    userName: 'User Name',
+    userNamePlaceholder: 'Please enter user name',
+    search: 'Search',
+    reset: 'Reset'
+  },
+  // 表格列
+  table: {
+    index: 'No.',
+    tokenId: 'Session ID',
+    userName: 'Login Name',
+    clientKey: 'Client',
+    deviceType: 'Device Type',
+    deptName: 'Department',
+    ipaddr: 'Host',
+    loginLocation: 'Login Location',
+    os: 'Operating System',
+    browser: 'Browser',
+    loginTime: 'Login Time',
+    operation: 'Operation'
+  },
+  // 提示信息
+  message: {
+    forceLogoutConfirm: 'Are you sure to force logout user "{userName}"?',
+    forceLogoutSuccess: 'Delete successfully'
+  },
+  // Tooltip 提示
+  tooltip: {
+    forceLogout: 'Force Logout'
+  }
+};

+ 36 - 0
src/lang/modules/monitor/online/zh_CN.ts

@@ -0,0 +1,36 @@
+// 在线用户监控模块 - 中文翻译
+export default {
+  // 搜索表单
+  search: {
+    ipaddr: '登录地址',
+    ipaddrPlaceholder: '请输入登录地址',
+    userName: '用户名称',
+    userNamePlaceholder: '请输入用户名称',
+    search: '搜索',
+    reset: '重置'
+  },
+  // 表格列
+  table: {
+    index: '序号',
+    tokenId: '会话编号',
+    userName: '登录名称',
+    clientKey: '客户端',
+    deviceType: '设备类型',
+    deptName: '所属部门',
+    ipaddr: '主机',
+    loginLocation: '登录地点',
+    os: '操作系统',
+    browser: '浏览器',
+    loginTime: '登录时间',
+    operation: '操作'
+  },
+  // 提示信息
+  message: {
+    forceLogoutConfirm: '是否确认强退名称为"{userName}"的用户?',
+    forceLogoutSuccess: '删除成功'
+  },
+  // Tooltip 提示
+  tooltip: {
+    forceLogout: '强退'
+  }
+};

+ 72 - 0
src/lang/modules/system/dept/en_US.ts

@@ -0,0 +1,72 @@
+// 部门管理模块 - 英文翻译
+export default {
+  // 搜索表单
+  search: {
+    deptName: 'Department Name',
+    deptNamePlaceholder: 'Please enter department name',
+    deptCategory: 'Category Code',
+    deptCategoryPlaceholder: 'Please enter category code',
+    status: 'Status',
+    statusPlaceholder: 'Department status',
+    search: 'Search',
+    reset: 'Reset'
+  },
+  // 按钮操作
+  button: {
+    add: 'Add',
+    expandCollapse: 'Expand/Collapse',
+    submit: 'Submit',
+    cancel: 'Cancel'
+  },
+  // 表格列
+  table: {
+    deptName: 'Department Name',
+    deptCategory: 'Category Code',
+    orderNum: 'Sort',
+    status: 'Status',
+    createTime: 'Create Time',
+    operation: 'Operation'
+  },
+  // 表单
+  form: {
+    parentId: 'Parent Department',
+    parentIdPlaceholder: 'Select parent department',
+    deptName: 'Department Name',
+    deptNamePlaceholder: 'Please enter department name',
+    deptCategory: 'Category Code',
+    deptCategoryPlaceholder: 'Please enter category code',
+    orderNum: 'Display Sort',
+    leader: 'Leader',
+    leaderPlaceholder: 'Please select leader',
+    phone: 'Phone',
+    phonePlaceholder: 'Please enter phone',
+    email: 'Email',
+    emailPlaceholder: 'Please enter email',
+    status: 'Department Status'
+  },
+  // 对话框标题
+  dialog: {
+    add: 'Add Department',
+    edit: 'Edit Department'
+  },
+  // 提示信息
+  message: {
+    deleteConfirm: 'Are you sure to delete the department "{name}"?',
+    deleteSuccess: 'Delete successfully',
+    operationSuccess: 'Operation successful'
+  },
+  // Tooltip 提示
+  tooltip: {
+    edit: 'Edit',
+    add: 'Add',
+    delete: 'Delete'
+  },
+  // 验证规则
+  rule: {
+    parentIdRequired: 'Parent department cannot be empty',
+    deptNameRequired: 'Department name cannot be empty',
+    orderNumRequired: 'Display sort cannot be empty',
+    emailFormat: 'Please enter a valid email address',
+    phoneFormat: 'Please enter a valid phone number'
+  }
+};

+ 72 - 0
src/lang/modules/system/dept/zh_CN.ts

@@ -0,0 +1,72 @@
+// 部门管理模块 - 中文翻译
+export default {
+  // 搜索表单
+  search: {
+    deptName: '部门名称',
+    deptNamePlaceholder: '请输入部门名称',
+    deptCategory: '类别编码',
+    deptCategoryPlaceholder: '请输入类别编码',
+    status: '状态',
+    statusPlaceholder: '部门状态',
+    search: '搜索',
+    reset: '重置'
+  },
+  // 按钮操作
+  button: {
+    add: '新增',
+    expandCollapse: '展开/折叠',
+    submit: '确 定',
+    cancel: '取 消'
+  },
+  // 表格列
+  table: {
+    deptName: '部门名称',
+    deptCategory: '类别编码',
+    orderNum: '排序',
+    status: '状态',
+    createTime: '创建时间',
+    operation: '操作'
+  },
+  // 表单
+  form: {
+    parentId: '上级部门',
+    parentIdPlaceholder: '选择上级部门',
+    deptName: '部门名称',
+    deptNamePlaceholder: '请输入部门名称',
+    deptCategory: '类别编码',
+    deptCategoryPlaceholder: '请输入类别编码',
+    orderNum: '显示排序',
+    leader: '负责人',
+    leaderPlaceholder: '请选择负责人',
+    phone: '联系电话',
+    phonePlaceholder: '请输入联系电话',
+    email: '邮箱',
+    emailPlaceholder: '请输入邮箱',
+    status: '部门状态'
+  },
+  // 对话框标题
+  dialog: {
+    add: '添加部门',
+    edit: '修改部门'
+  },
+  // 提示信息
+  message: {
+    deleteConfirm: '是否确认删除名称为"{name}"的数据项?',
+    deleteSuccess: '删除成功',
+    operationSuccess: '操作成功'
+  },
+  // Tooltip 提示
+  tooltip: {
+    edit: '修改',
+    add: '新增',
+    delete: '删除'
+  },
+  // 验证规则
+  rule: {
+    parentIdRequired: '上级部门不能为空',
+    deptNameRequired: '部门名称不能为空',
+    orderNumRequired: '显示排序不能为空',
+    emailFormat: '请输入正确的邮箱地址',
+    phoneFormat: '请输入正确的手机号码'
+  }
+};

+ 16 - 0
src/lang/modules/system/index.ts

@@ -0,0 +1,16 @@
+// 系统管理模块 - 统一导出
+import user from './user/zh_CN';
+import role from './role/zh_CN';
+import post from './post/zh_CN';
+import dept from './dept/zh_CN';
+import tenant from './tenant/zh_CN';
+import tenantPackage from './tenantPackage/zh_CN';
+
+export default {
+  user,
+  role,
+  post,
+  dept,
+  tenant,
+  tenantPackage
+};

+ 16 - 0
src/lang/modules/system/index_en.ts

@@ -0,0 +1,16 @@
+// 系统管理模块 - 统一导出 (English)
+import user from './user/en_US';
+import role from './role/en_US';
+import post from './post/en_US';
+import dept from './dept/en_US';
+import tenant from './tenant/en_US';
+import tenantPackage from './tenantPackage/en_US';
+
+export default {
+  user,
+  role,
+  post,
+  dept,
+  tenant,
+  tenantPackage
+};

+ 81 - 0
src/lang/modules/system/post/en_US.ts

@@ -0,0 +1,81 @@
+// 岗位管理模块 - 英文翻译
+export default {
+  // 部门树
+  tree: {
+    deptPlaceholder: 'Please enter department name'
+  },
+  // 搜索表单
+  search: {
+    postCode: 'Post Code',
+    postCodePlaceholder: 'Please enter post code',
+    postCategory: 'Category Code',
+    postCategoryPlaceholder: 'Please enter category code',
+    postName: 'Post Name',
+    postNamePlaceholder: 'Please enter post name',
+    deptId: 'Department',
+    deptIdPlaceholder: 'Please select department',
+    status: 'Status',
+    statusPlaceholder: 'Post status',
+    search: 'Search',
+    reset: 'Reset'
+  },
+  // 按钮操作
+  button: {
+    add: 'Add',
+    edit: 'Edit',
+    delete: 'Delete',
+    export: 'Export',
+    submit: 'Submit',
+    cancel: 'Cancel'
+  },
+  // 表格列
+  table: {
+    postId: 'Post ID',
+    postCode: 'Post Code',
+    postCategory: 'Category Code',
+    postName: 'Post Name',
+    deptName: 'Department',
+    postSort: 'Sort',
+    status: 'Status',
+    createTime: 'Create Time',
+    operation: 'Operation'
+  },
+  // 表单
+  form: {
+    postName: 'Post Name',
+    postNamePlaceholder: 'Please enter post name',
+    deptId: 'Department',
+    deptIdPlaceholder: 'Please select department',
+    postCode: 'Post Code',
+    postCodePlaceholder: 'Please enter code name',
+    postCategory: 'Category Code',
+    postCategoryPlaceholder: 'Please enter category code',
+    postSort: 'Post Sort',
+    status: 'Post Status',
+    remark: 'Remark',
+    remarkPlaceholder: 'Please enter content'
+  },
+  // 对话框标题
+  dialog: {
+    add: 'Add Post',
+    edit: 'Edit Post'
+  },
+  // 提示信息
+  message: {
+    deleteConfirm: 'Are you sure to delete the post with ID "{ids}"?',
+    deleteSuccess: 'Delete successfully',
+    operationSuccess: 'Operation successful'
+  },
+  // Tooltip 提示
+  tooltip: {
+    edit: 'Edit',
+    delete: 'Delete'
+  },
+  // 验证规则
+  rule: {
+    postNameRequired: 'Post name cannot be empty',
+    postCodeRequired: 'Post code cannot be empty',
+    deptIdRequired: 'Department cannot be empty',
+    postSortRequired: 'Post sort cannot be empty'
+  }
+};

+ 81 - 0
src/lang/modules/system/post/zh_CN.ts

@@ -0,0 +1,81 @@
+// 岗位管理模块 - 中文翻译
+export default {
+  // 部门树
+  tree: {
+    deptPlaceholder: '请输入部门名称'
+  },
+  // 搜索表单
+  search: {
+    postCode: '岗位编码',
+    postCodePlaceholder: '请输入岗位编码',
+    postCategory: '类别编码',
+    postCategoryPlaceholder: '请输入类别编码',
+    postName: '岗位名称',
+    postNamePlaceholder: '请输入岗位名称',
+    deptId: '部门',
+    deptIdPlaceholder: '请选择部门',
+    status: '状态',
+    statusPlaceholder: '岗位状态',
+    search: '搜索',
+    reset: '重置'
+  },
+  // 按钮操作
+  button: {
+    add: '新增',
+    edit: '修改',
+    delete: '删除',
+    export: '导出',
+    submit: '确 定',
+    cancel: '取 消'
+  },
+  // 表格列
+  table: {
+    postId: '岗位编号',
+    postCode: '岗位编码',
+    postCategory: '类别编码',
+    postName: '岗位名称',
+    deptName: '部门',
+    postSort: '排序',
+    status: '状态',
+    createTime: '创建时间',
+    operation: '操作'
+  },
+  // 表单
+  form: {
+    postName: '岗位名称',
+    postNamePlaceholder: '请输入岗位名称',
+    deptId: '部门',
+    deptIdPlaceholder: '请选择部门',
+    postCode: '岗位编码',
+    postCodePlaceholder: '请输入编码名称',
+    postCategory: '类别编码',
+    postCategoryPlaceholder: '请输入类别编码',
+    postSort: '岗位顺序',
+    status: '岗位状态',
+    remark: '备注',
+    remarkPlaceholder: '请输入内容'
+  },
+  // 对话框标题
+  dialog: {
+    add: '添加岗位',
+    edit: '修改岗位'
+  },
+  // 提示信息
+  message: {
+    deleteConfirm: '是否确认删除岗位编号为"{ids}"的数据项?',
+    deleteSuccess: '删除成功',
+    operationSuccess: '操作成功'
+  },
+  // Tooltip 提示
+  tooltip: {
+    edit: '修改',
+    delete: '删除'
+  },
+  // 验证规则
+  rule: {
+    postNameRequired: '岗位名称不能为空',
+    postCodeRequired: '岗位编码不能为空',
+    deptIdRequired: '部门不能为空',
+    postSortRequired: '岗位顺序不能为空'
+  }
+};

+ 94 - 0
src/lang/modules/system/role/en_US.ts

@@ -0,0 +1,94 @@
+// 角色管理模块 - 英文翻译
+export default {
+  // 搜索表单
+  search: {
+    roleName: 'Role Name',
+    roleNamePlaceholder: 'Please enter role name',
+    roleKey: 'Role Key',
+    roleKeyPlaceholder: 'Please enter role key',
+    status: 'Status',
+    statusPlaceholder: 'Role status',
+    createTime: 'Create Time',
+    startDate: 'Start Date',
+    endDate: 'End Date',
+    search: 'Search',
+    reset: 'Reset'
+  },
+  // 按钮操作
+  button: {
+    add: 'Add',
+    edit: 'Edit',
+    delete: 'Delete',
+    export: 'Export',
+    submit: 'Submit',
+    cancel: 'Cancel'
+  },
+  // 表格列
+  table: {
+    roleId: 'Role ID',
+    roleName: 'Role Name',
+    roleKey: 'Role Key',
+    roleSort: 'Sort Order',
+    status: 'Status',
+    createTime: 'Create Time',
+    operation: 'Operation'
+  },
+  // 表单
+  form: {
+    roleName: 'Role Name',
+    roleNamePlaceholder: 'Please enter role name',
+    roleKey: 'Role Key',
+    roleKeyPlaceholder: 'Please enter role key',
+    roleKeyTooltip: 'Permission character defined in controller, e.g.: @SaCheckRole(\'admin\')',
+    roleSort: 'Sort Order',
+    status: 'Status',
+    menuPermission: 'Menu Permission',
+    expandCollapse: 'Expand/Collapse',
+    selectAll: 'Select All/None',
+    parentChild: 'Parent-Child Link',
+    loading: 'Loading, please wait',
+    remark: 'Remark',
+    remarkPlaceholder: 'Please enter content',
+    dataScope: 'Data Scope',
+    dataPermission: 'Data Permission'
+  },
+  // 对话框标题
+  dialog: {
+    add: 'Add Role',
+    edit: 'Edit Role',
+    dataScope: 'Assign Data Permission'
+  },
+  // 提示信息
+  message: {
+    deleteConfirm: 'Are you sure to delete role with ID {ids}?',
+    deleteSuccess: 'Delete successfully',
+    statusEnable: 'Enable',
+    statusDisable: 'Disable',
+    statusChangeConfirm: 'Are you sure to "{text}" role "{roleName}"?',
+    statusChangeSuccess: '{text} successfully',
+    operationSuccess: 'Operation successful',
+    modifySuccess: 'Modified successfully'
+  },
+  // Tooltip 提示
+  tooltip: {
+    edit: 'Edit',
+    delete: 'Delete',
+    dataScope: 'Data Permission',
+    assignUser: 'Assign User'
+  },
+  // 数据范围选项
+  dataScope: {
+    all: 'All Data Permission',
+    custom: 'Custom Data Permission',
+    dept: 'Department Data Permission',
+    deptAndBelow: 'Department and Below Data Permission',
+    self: 'Self Data Permission Only',
+    deptBelowOrSelf: 'Department Below or Self Data Permission'
+  },
+  // 验证规则
+  rule: {
+    roleNameRequired: 'Role name cannot be empty',
+    roleKeyRequired: 'Role key cannot be empty',
+    roleSortRequired: 'Sort order cannot be empty'
+  }
+};

+ 94 - 0
src/lang/modules/system/role/zh_CN.ts

@@ -0,0 +1,94 @@
+// 角色管理模块 - 中文翻译
+export default {
+  // 搜索表单
+  search: {
+    roleName: '角色名称',
+    roleNamePlaceholder: '请输入角色名称',
+    roleKey: '权限字符',
+    roleKeyPlaceholder: '请输入权限字符',
+    status: '状态',
+    statusPlaceholder: '角色状态',
+    createTime: '创建时间',
+    startDate: '开始日期',
+    endDate: '结束日期',
+    search: '搜索',
+    reset: '重置'
+  },
+  // 按钮操作
+  button: {
+    add: '新增',
+    edit: '修改',
+    delete: '删除',
+    export: '导出',
+    submit: '确 定',
+    cancel: '取 消'
+  },
+  // 表格列
+  table: {
+    roleId: '角色编号',
+    roleName: '角色名称',
+    roleKey: '权限字符',
+    roleSort: '显示顺序',
+    status: '状态',
+    createTime: '创建时间',
+    operation: '操作'
+  },
+  // 表单
+  form: {
+    roleName: '角色名称',
+    roleNamePlaceholder: '请输入角色名称',
+    roleKey: '权限字符',
+    roleKeyPlaceholder: '请输入权限字符',
+    roleKeyTooltip: '控制器中定义的权限字符,如:@SaCheckRole(\'admin\')',
+    roleSort: '角色顺序',
+    status: '状态',
+    menuPermission: '菜单权限',
+    expandCollapse: '展开/折叠',
+    selectAll: '全选/全不选',
+    parentChild: '父子联动',
+    loading: '加载中,请稍候',
+    remark: '备注',
+    remarkPlaceholder: '请输入内容',
+    dataScope: '权限范围',
+    dataPermission: '数据权限'
+  },
+  // 对话框标题
+  dialog: {
+    add: '添加角色',
+    edit: '修改角色',
+    dataScope: '分配数据权限'
+  },
+  // 提示信息
+  message: {
+    deleteConfirm: '是否确认删除角色编号为{ids}数据项目',
+    deleteSuccess: '删除成功',
+    statusEnable: '启用',
+    statusDisable: '停用',
+    statusChangeConfirm: '确认要"{text}""{roleName}"角色吗?',
+    statusChangeSuccess: '{text}成功',
+    operationSuccess: '操作成功',
+    modifySuccess: '修改成功'
+  },
+  // Tooltip 提示
+  tooltip: {
+    edit: '修改',
+    delete: '删除',
+    dataScope: '数据权限',
+    assignUser: '分配用户'
+  },
+  // 数据范围选项
+  dataScope: {
+    all: '全部数据权限',
+    custom: '自定数据权限',
+    dept: '本部门数据权限',
+    deptAndBelow: '本部门及以下数据权限',
+    self: '仅本人数据权限',
+    deptBelowOrSelf: '部门及以下或本人数据权限'
+  },
+  // 验证规则
+  rule: {
+    roleNameRequired: '角色名称不能为空',
+    roleKeyRequired: '权限字符不能为空',
+    roleSortRequired: '角色顺序不能为空'
+  }
+};

+ 105 - 0
src/lang/modules/system/tenant/en_US.ts

@@ -0,0 +1,105 @@
+// 企业管理模块 - 英文翻译
+export default {
+  // 搜索表单
+  search: {
+    tenantId: 'Company ID',
+    tenantIdPlaceholder: 'Please enter company ID',
+    contactUserName: 'Contact Person',
+    contactUserNamePlaceholder: 'Please enter contact person',
+    contactPhone: 'Contact Phone',
+    contactPhonePlaceholder: 'Please enter contact phone',
+    companyName: 'Company Name',
+    companyNamePlaceholder: 'Please enter company name',
+    search: 'Search',
+    reset: 'Reset'
+  },
+  // 按钮操作
+  button: {
+    add: 'Add',
+    edit: 'Edit',
+    delete: 'Delete',
+    export: 'Export',
+    syncDict: 'Sync Company Dictionary',
+    syncConfig: 'Sync Company Config',
+    submit: 'Submit',
+    cancel: 'Cancel'
+  },
+  // 表格列
+  table: {
+    id: 'ID',
+    tenantId: 'Company ID',
+    contactUserName: 'Contact Person',
+    contactPhone: 'Contact Phone',
+    companyName: 'Company Name',
+    licenseNumber: 'Credit Code',
+    expireTime: 'Expire Time',
+    status: 'Company Status',
+    operation: 'Operation'
+  },
+  // 表单
+  form: {
+    companyName: 'Company Name',
+    companyNamePlaceholder: 'Please enter company name',
+    contactUserName: 'Contact Person',
+    contactUserNamePlaceholder: 'Please enter contact person',
+    contactPhone: 'Contact Phone',
+    contactPhonePlaceholder: 'Please enter contact phone',
+    username: 'Username',
+    usernamePlaceholder: 'Please enter system username',
+    password: 'Password',
+    passwordPlaceholder: 'Please enter system password',
+    packageId: 'Company Package',
+    packageIdPlaceholder: 'Please select company package',
+    expireTime: 'Expire Time',
+    expireTimePlaceholder: 'Please select expire time',
+    accountCount: 'User Count',
+    accountCountPlaceholder: 'Please enter user count',
+    domain: 'Domain',
+    domainPlaceholder: 'Please enter domain',
+    address: 'Company Address',
+    addressPlaceholder: 'Please enter company address',
+    licenseNumber: 'License Number',
+    licenseNumberPlaceholder: 'Please enter unified social credit code',
+    intro: 'Company Introduction',
+    introPlaceholder: 'Please enter company introduction',
+    remark: 'Remark',
+    remarkPlaceholder: 'Please enter remark'
+  },
+  // 对话框标题
+  dialog: {
+    add: 'Add Company',
+    edit: 'Edit Company'
+  },
+  // 提示信息
+  message: {
+    deleteConfirm: 'Are you sure to delete the company with ID "{ids}"?',
+    deleteSuccess: 'Delete successfully',
+    statusEnable: 'Enable',
+    statusDisable: 'Disable',
+    statusChangeConfirm: 'Are you sure to "{text}" company "{name}"?',
+    statusChangeSuccess: '{text} successfully',
+    operationSuccess: 'Operation successful',
+    syncPackageConfirm: 'Are you sure to sync company package with company ID "{tenantId}"?',
+    syncSuccess: 'Sync successfully',
+    syncDictConfirm: 'Are you sure to sync all company dictionaries?',
+    syncConfigConfirm: 'Are you sure to sync all company configurations?'
+  },
+  // Tooltip 提示
+  tooltip: {
+    edit: 'Edit',
+    syncPackage: 'Sync Package',
+    delete: 'Delete'
+  },
+  // 验证规则
+  rule: {
+    idRequired: 'ID cannot be empty',
+    tenantIdRequired: 'Company ID cannot be empty',
+    contactUserNameRequired: 'Contact person cannot be empty',
+    contactPhoneRequired: 'Contact phone cannot be empty',
+    companyNameRequired: 'Company name cannot be empty',
+    usernameRequired: 'Username cannot be empty',
+    usernameLength: 'Username length must be between 2 and 20',
+    passwordRequired: 'Password cannot be empty',
+    passwordLength: 'Password length must be between 5 and 20'
+  }
+};

+ 105 - 0
src/lang/modules/system/tenant/zh_CN.ts

@@ -0,0 +1,105 @@
+// 企业管理模块 - 中文翻译
+export default {
+  // 搜索表单
+  search: {
+    tenantId: '企业编号',
+    tenantIdPlaceholder: '请输入企业编号',
+    contactUserName: '联系人',
+    contactUserNamePlaceholder: '请输入联系人',
+    contactPhone: '联系电话',
+    contactPhonePlaceholder: '请输入联系电话',
+    companyName: '企业名称',
+    companyNamePlaceholder: '请输入企业名称',
+    search: '搜索',
+    reset: '重置'
+  },
+  // 按钮操作
+  button: {
+    add: '新增',
+    edit: '修改',
+    delete: '删除',
+    export: '导出',
+    syncDict: '同步企业字典',
+    syncConfig: '同步企业参数配置',
+    submit: '确 定',
+    cancel: '取 消'
+  },
+  // 表格列
+  table: {
+    id: 'id',
+    tenantId: '企业编号',
+    contactUserName: '联系人',
+    contactPhone: '联系电话',
+    companyName: '企业名称',
+    licenseNumber: '社会信用代码',
+    expireTime: '过期时间',
+    status: '企业状态',
+    operation: '操作'
+  },
+  // 表单
+  form: {
+    companyName: '企业名称',
+    companyNamePlaceholder: '请输入企业名称',
+    contactUserName: '联系人',
+    contactUserNamePlaceholder: '请输入联系人',
+    contactPhone: '联系电话',
+    contactPhonePlaceholder: '请输入联系电话',
+    username: '用户名',
+    usernamePlaceholder: '请输入系统用户名',
+    password: '用户密码',
+    passwordPlaceholder: '请输入系统用户密码',
+    packageId: '企业套餐',
+    packageIdPlaceholder: '请选择企业套餐',
+    expireTime: '过期时间',
+    expireTimePlaceholder: '请选择过期时间',
+    accountCount: '用户数量',
+    accountCountPlaceholder: '请输入用户数量',
+    domain: '绑定域名',
+    domainPlaceholder: '请输入绑定域名',
+    address: '企业地址',
+    addressPlaceholder: '请输入企业地址',
+    licenseNumber: '企业代码',
+    licenseNumberPlaceholder: '请输入统一社会信用代码',
+    intro: '企业简介',
+    introPlaceholder: '请输入企业简介',
+    remark: '备注',
+    remarkPlaceholder: '请输入备注'
+  },
+  // 对话框标题
+  dialog: {
+    add: '添加企业',
+    edit: '修改企业'
+  },
+  // 提示信息
+  message: {
+    deleteConfirm: '是否确认删除企业编号为"{ids}"的数据项?',
+    deleteSuccess: '删除成功',
+    statusEnable: '启用',
+    statusDisable: '停用',
+    statusChangeConfirm: '确认要"{text}""{name}"企业吗?',
+    statusChangeSuccess: '{text}成功',
+    operationSuccess: '操作成功',
+    syncPackageConfirm: '是否确认同步企业套餐企业编号为"{tenantId}"的数据项?',
+    syncSuccess: '同步成功',
+    syncDictConfirm: '确认要同步所有企业字典吗?',
+    syncConfigConfirm: '确认要同步所有企业参数配置吗?'
+  },
+  // Tooltip 提示
+  tooltip: {
+    edit: '修改',
+    syncPackage: '同步套餐',
+    delete: '删除'
+  },
+  // 验证规则
+  rule: {
+    idRequired: 'id不能为空',
+    tenantIdRequired: '企业编号不能为空',
+    contactUserNameRequired: '联系人不能为空',
+    contactPhoneRequired: '联系电话不能为空',
+    companyNameRequired: '企业名称不能为空',
+    usernameRequired: '用户名不能为空',
+    usernameLength: '用户名称长度必须介于 2 和 20 之间',
+    passwordRequired: '密码不能为空',
+    passwordLength: '用户密码长度必须介于 5 和 20 之间'
+  }
+};

+ 64 - 0
src/lang/modules/system/tenantPackage/en_US.ts

@@ -0,0 +1,64 @@
+// 企业套餐管理模块 - 英文翻译
+export default {
+  // 搜索表单
+  search: {
+    packageName: 'Package Name',
+    packageNamePlaceholder: 'Please enter package name',
+    search: 'Search',
+    reset: 'Reset'
+  },
+  // 按钮操作
+  button: {
+    add: 'Add',
+    edit: 'Edit',
+    delete: 'Delete',
+    export: 'Export',
+    submit: 'Submit',
+    cancel: 'Cancel'
+  },
+  // 表格列
+  table: {
+    packageId: 'Package ID',
+    packageName: 'Package Name',
+    remark: 'Remark',
+    status: 'Status',
+    operation: 'Operation'
+  },
+  // 表单
+  form: {
+    packageName: 'Package Name',
+    packageNamePlaceholder: 'Please enter package name',
+    relatedMenu: 'Related Menu',
+    expandCollapse: 'Expand/Collapse',
+    selectAll: 'Select All/None',
+    parentChild: 'Parent-Child Link',
+    loading: 'Loading, please wait',
+    remark: 'Remark',
+    remarkPlaceholder: 'Please enter remark'
+  },
+  // 对话框标题
+  dialog: {
+    add: 'Add Company Package',
+    edit: 'Edit Company Package'
+  },
+  // 提示信息
+  message: {
+    deleteConfirm: 'Are you sure to delete the package with ID "{ids}"?',
+    deleteSuccess: 'Delete successfully',
+    statusEnable: 'Enable',
+    statusDisable: 'Disable',
+    statusChangeConfirm: 'Are you sure to "{text}" package "{name}"?',
+    statusChangeSuccess: '{text} successfully',
+    operationSuccess: 'Operation successful'
+  },
+  // Tooltip 提示
+  tooltip: {
+    edit: 'Edit',
+    delete: 'Delete'
+  },
+  // 验证规则
+  rule: {
+    packageIdRequired: 'Package ID cannot be empty',
+    packageNameRequired: 'Package name cannot be empty'
+  }
+};

+ 64 - 0
src/lang/modules/system/tenantPackage/zh_CN.ts

@@ -0,0 +1,64 @@
+// 企业套餐管理模块 - 中文翻译
+export default {
+  // 搜索表单
+  search: {
+    packageName: '套餐名称',
+    packageNamePlaceholder: '请输入套餐名称',
+    search: '搜索',
+    reset: '重置'
+  },
+  // 按钮操作
+  button: {
+    add: '新增',
+    edit: '修改',
+    delete: '删除',
+    export: '导出',
+    submit: '确 定',
+    cancel: '取 消'
+  },
+  // 表格列
+  table: {
+    packageId: '企业套餐id',
+    packageName: '套餐名称',
+    remark: '备注',
+    status: '状态',
+    operation: '操作'
+  },
+  // 表单
+  form: {
+    packageName: '套餐名称',
+    packageNamePlaceholder: '请输入套餐名称',
+    relatedMenu: '关联菜单',
+    expandCollapse: '展开/折叠',
+    selectAll: '全选/全不选',
+    parentChild: '父子联动',
+    loading: '加载中,请稍候',
+    remark: '备注',
+    remarkPlaceholder: '请输入备注'
+  },
+  // 对话框标题
+  dialog: {
+    add: '添加企业套餐',
+    edit: '修改企业套餐'
+  },
+  // 提示信息
+  message: {
+    deleteConfirm: '是否确认删除企业套餐编号为"{ids}"的数据项?',
+    deleteSuccess: '删除成功',
+    statusEnable: '启用',
+    statusDisable: '停用',
+    statusChangeConfirm: '确认要"{text}""{name}"套餐吗?',
+    statusChangeSuccess: '{text}成功',
+    operationSuccess: '操作成功'
+  },
+  // Tooltip 提示
+  tooltip: {
+    edit: '修改',
+    delete: '删除'
+  },
+  // 验证规则
+  rule: {
+    packageIdRequired: '企业套餐id不能为空',
+    packageNameRequired: '套餐名称不能为空'
+  }
+};

+ 128 - 0
src/lang/modules/system/user/en_US.ts

@@ -0,0 +1,128 @@
+// 用户管理模块 - 英文翻译
+export default {
+  // 搜索表单
+  search: {
+    deptPlaceholder: 'Please enter department name',
+    userName: 'User Name',
+    userNamePlaceholder: 'Please enter user name',
+    nickName: 'Nick Name',
+    nickNamePlaceholder: 'Please enter nick name',
+    phonenumber: 'Phone Number',
+    phonenumberPlaceholder: 'Please enter phone number',
+    status: 'Status',
+    statusPlaceholder: 'User status',
+    createTime: 'Create Time',
+    startDate: 'Start Date',
+    endDate: 'End Date',
+    search: 'Search',
+    reset: 'Reset'
+  },
+  // 按钮操作
+  button: {
+    add: 'Add',
+    edit: 'Edit',
+    delete: 'Delete',
+    more: 'More',
+    downloadTemplate: 'Download Template',
+    import: 'Import Data',
+    export: 'Export Data',
+    resetPwd: 'Reset Password',
+    assignRole: 'Assign Role',
+    submit: 'Submit',
+    cancel: 'Cancel',
+    back: 'Back'
+  },
+  // 表格列
+  table: {
+    userId: 'User ID',
+    userName: 'User Name',
+    nickName: 'Nick Name',
+    deptName: 'Department',
+    phonenumber: 'Phone Number',
+    status: 'Status',
+    createTime: 'Create Time',
+    operation: 'Operation'
+  },
+  // 表单
+  form: {
+    nickName: 'Nick Name',
+    nickNamePlaceholder: 'Please enter nick name',
+    deptId: 'Department',
+    deptIdPlaceholder: 'Please select department',
+    phonenumber: 'Phone Number',
+    phonenumberPlaceholder: 'Please enter phone number',
+    email: 'Email',
+    emailPlaceholder: 'Please enter email',
+    userName: 'User Name',
+    userNamePlaceholder: 'Please enter user name',
+    password: 'Password',
+    passwordPlaceholder: 'Please enter password',
+    sex: 'Gender',
+    selectPlaceholder: 'Please select',
+    status: 'Status',
+    postIds: 'Post',
+    postIdsPlaceholder: 'Please select',
+    roleIds: 'Role',
+    roleIdsPlaceholder: 'Please select',
+    remark: 'Remark',
+    remarkPlaceholder: 'Please enter content'
+  },
+  // 对话框标题
+  dialog: {
+    add: 'Add User',
+    edit: 'Edit User',
+    import: 'User Import',
+    importResult: 'Import Result'
+  },
+  // 上传
+  upload: {
+    dragText: 'Drop file here or <em>click to upload</em>',
+    updateSupport: 'Whether to update existing user data',
+    fileType: 'Only xls and xlsx format files are allowed.',
+    downloadTemplate: 'Download Template'
+  },
+  // 验证规则
+  rule: {
+    userNameRequired: 'User name cannot be empty',
+    userNameLength: 'User name length must be between 2 and 20',
+    nickNameRequired: 'Nick name cannot be empty',
+    passwordRequired: 'Password cannot be empty',
+    passwordLength: 'Password length must be between 5 and 20',
+    passwordPattern: "Cannot contain illegal characters: < > \" ' \\ |",
+    emailFormat: 'Please enter a valid email address',
+    phonenumberFormat: 'Please enter a valid phone number',
+    roleIdsRequired: 'User role cannot be empty'
+  },
+  // 提示信息
+  message: {
+    deleteConfirm: 'Are you sure to delete the data item with user ID "{ids}"?',
+    deleteSuccess: 'Delete successfully',
+    statusEnable: 'Enable',
+    statusDisable: 'Disable',
+    statusChangeConfirm: 'Are you sure to "{text}" user "{userName}"?',
+    statusChangeSuccess: '{text} successfully',
+    resetPwdTitle: 'Prompt',
+    resetPwdText: 'Please enter new password for "{userName}"',
+    resetPwdSuccess: 'Modified successfully, new password is: {password}',
+    resetPwdLengthError: 'Password length must be between 5 and 20',
+    resetPwdPatternError: "Cannot contain illegal characters: < > \" ' \\ |",
+    confirmButton: 'Confirm',
+    cancelButton: 'Cancel',
+    operationSuccess: 'Operation successful'
+  },
+  // 角色分配
+  authRole: {
+    basicInfo: 'Basic Information',
+    nickName: 'Nick Name',
+    userName: 'User Name',
+    roleInfo: 'Role Information',
+    serialNumber: 'No.',
+    roleId: 'Role ID',
+    roleName: 'Role Name',
+    roleKey: 'Role Key',
+    createTime: 'Create Time',
+    submit: 'Submit',
+    back: 'Back',
+    authSuccess: 'Authorization successful'
+  }
+};

+ 128 - 0
src/lang/modules/system/user/zh_CN.ts

@@ -0,0 +1,128 @@
+// 用户管理模块 - 中文翻译
+export default {
+  // 搜索表单
+  search: {
+    deptPlaceholder: '请输入部门名称',
+    userName: '用户名称',
+    userNamePlaceholder: '请输入用户名称',
+    nickName: '用户昵称',
+    nickNamePlaceholder: '请输入用户昵称',
+    phonenumber: '手机号码',
+    phonenumberPlaceholder: '请输入手机号码',
+    status: '状态',
+    statusPlaceholder: '用户状态',
+    createTime: '创建时间',
+    startDate: '开始日期',
+    endDate: '结束日期',
+    search: '搜索',
+    reset: '重置'
+  },
+  // 按钮操作
+  button: {
+    add: '新增',
+    edit: '修改',
+    delete: '删除',
+    more: '更多',
+    downloadTemplate: '下载模板',
+    import: '导入数据',
+    export: '导出数据',
+    resetPwd: '重置密码',
+    assignRole: '分配角色',
+    submit: '确 定',
+    cancel: '取 消',
+    back: '返回'
+  },
+  // 表格列
+  table: {
+    userId: '用户编号',
+    userName: '用户名称',
+    nickName: '用户昵称',
+    deptName: '部门',
+    phonenumber: '手机号码',
+    status: '状态',
+    createTime: '创建时间',
+    operation: '操作'
+  },
+  // 表单
+  form: {
+    nickName: '用户昵称',
+    nickNamePlaceholder: '请输入用户昵称',
+    deptId: '归属部门',
+    deptIdPlaceholder: '请选择归属部门',
+    phonenumber: '手机号码',
+    phonenumberPlaceholder: '请输入手机号码',
+    email: '邮箱',
+    emailPlaceholder: '请输入邮箱',
+    userName: '用户名称',
+    userNamePlaceholder: '请输入用户名称',
+    password: '用户密码',
+    passwordPlaceholder: '请输入用户密码',
+    sex: '用户性别',
+    selectPlaceholder: '请选择',
+    status: '状态',
+    postIds: '岗位',
+    postIdsPlaceholder: '请选择',
+    roleIds: '角色',
+    roleIdsPlaceholder: '请选择',
+    remark: '备注',
+    remarkPlaceholder: '请输入内容'
+  },
+  // 对话框标题
+  dialog: {
+    add: '新增用户',
+    edit: '修改用户',
+    import: '用户导入',
+    importResult: '导入结果'
+  },
+  // 上传
+  upload: {
+    dragText: '将文件拖到此处,或<em>点击上传</em>',
+    updateSupport: '是否更新已经存在的用户数据',
+    fileType: '仅允许导入xls、xlsx格式文件。',
+    downloadTemplate: '下载模板'
+  },
+  // 验证规则
+  rule: {
+    userNameRequired: '用户名称不能为空',
+    userNameLength: '用户名称长度必须介于 2 和 20 之间',
+    nickNameRequired: '用户昵称不能为空',
+    passwordRequired: '用户密码不能为空',
+    passwordLength: '用户密码长度必须介于 5 和 20 之间',
+    passwordPattern: '不能包含非法字符:< > " \' \\ |',
+    emailFormat: '请输入正确的邮箱地址',
+    phonenumberFormat: '请输入正确的手机号码',
+    roleIdsRequired: '用户角色不能为空'
+  },
+  // 提示信息
+  message: {
+    deleteConfirm: '是否确认删除用户编号为"{ids}"的数据项?',
+    deleteSuccess: '删除成功',
+    statusEnable: '启用',
+    statusDisable: '停用',
+    statusChangeConfirm: '确认要"{text}""{userName}"用户吗?',
+    statusChangeSuccess: '{text}成功',
+    resetPwdTitle: '提示',
+    resetPwdText: '请输入"{userName}"的新密码',
+    resetPwdSuccess: '修改成功,新密码是:{password}',
+    resetPwdLengthError: '用户密码长度必须介于 5 和 20 之间',
+    resetPwdPatternError: '不能包含非法字符:< > " \' \\ |',
+    confirmButton: '确定',
+    cancelButton: '取消',
+    operationSuccess: '操作成功'
+  },
+  // 角色分配
+  authRole: {
+    basicInfo: '基本信息',
+    nickName: '用户昵称',
+    userName: '登录账号',
+    roleInfo: '角色信息',
+    serialNumber: '序号',
+    roleId: '角色编号',
+    roleName: '角色名称',
+    roleKey: '权限字符',
+    createTime: '创建时间',
+    submit: '提交',
+    back: '返回',
+    authSuccess: '授权成功'
+  }
+};

+ 12 - 1
src/lang/zh_CN.ts

@@ -1,3 +1,8 @@
+// 导入模块化的翻译文件
+import components from './modules/components/zh_CN';
+import system from './modules/system/index';
+import monitor from './modules/monitor/index';
+
 export default {
   // 路由国际化
   route: {
@@ -69,6 +74,8 @@ export default {
       }
     }
   },
+  // 公共组件国际化(从模块导入)
+  components,
   // 导航栏国际化
   navbar: {
     full: '全屏',
@@ -81,5 +88,9 @@ export default {
     layoutSetting: '布局设置',
     personalCenter: '个人中心',
     logout: '退出登录'
-  }
+  },
+  // 系统管理模块(包含用户、角色等)
+  ...system,
+  // 监控管理模块
+  ...monitor
 };

+ 24 - 22
src/views/monitor/online/index.vue

@@ -2,16 +2,16 @@
   <div class="p-2">
     <div class="mb-[10px]">
       <el-card shadow="hover">
-        <el-form ref="queryFormRef" :model="queryParams" :inline="true">
-          <el-form-item label="登录地址" prop="ipaddr">
-            <el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable @keyup.enter="handleQuery" />
+        <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="140px">
+          <el-form-item :label="t('online.search.ipaddr')" prop="ipaddr">
+            <el-input v-model="queryParams.ipaddr" :placeholder="t('online.search.ipaddrPlaceholder')" clearable @keyup.enter="handleQuery" />
           </el-form-item>
-          <el-form-item label="用户名称" prop="userName">
-            <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
+          <el-form-item :label="t('online.search.userName')" prop="userName">
+            <el-input v-model="queryParams.userName" :placeholder="t('online.search.userNamePlaceholder')" clearable @keyup.enter="handleQuery" />
           </el-form-item>
           <el-form-item>
-            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            <el-button type="primary" icon="Search" @click="handleQuery">{{ t('online.search.search') }}</el-button>
+            <el-button icon="Refresh" @click="resetQuery">{{ t('online.search.reset') }}</el-button>
           </el-form-item>
         </el-form>
       </el-card>
@@ -23,32 +23,32 @@
         :data="onlineList.slice((queryParams.pageNum - 1) * queryParams.pageSize, queryParams.pageNum * queryParams.pageSize)"
         style="width: 100%"
       >
-        <el-table-column label="序号" width="50" type="index" align="center">
+        <el-table-column :label="t('online.table.index')" width="80" type="index" align="center">
           <template #default="scope">
             <span>{{ (queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1 }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="会话编号" align="center" prop="tokenId" :show-overflow-tooltip="true" />
-        <el-table-column label="登录名称" align="center" prop="userName" :show-overflow-tooltip="true" />
-        <el-table-column label="客户端" align="center" prop="clientKey" :show-overflow-tooltip="true" />
-        <el-table-column label="设备类型" align="center">
+        <el-table-column :label="t('online.table.tokenId')" align="center" prop="tokenId" :show-overflow-tooltip="true" width="180" />
+        <el-table-column :label="t('online.table.userName')" align="center" prop="userName" :show-overflow-tooltip="true" width="150" />
+        <el-table-column :label="t('online.table.clientKey')" align="center" prop="clientKey" :show-overflow-tooltip="true" width="150" />
+        <el-table-column :label="t('online.table.deviceType')" align="center" width="150">
           <template #default="scope">
             <dict-tag :options="sys_device_type" :value="scope.row.deviceType" />
           </template>
         </el-table-column>
-        <el-table-column label="所属部门" align="center" prop="deptName" :show-overflow-tooltip="true" />
-        <el-table-column label="主机" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
-        <el-table-column label="登录地点" align="center" prop="loginLocation" :show-overflow-tooltip="true" />
-        <el-table-column label="操作系统" align="center" prop="os" :show-overflow-tooltip="true" />
-        <el-table-column label="浏览器" align="center" prop="browser" :show-overflow-tooltip="true" />
-        <el-table-column label="登录时间" align="center" prop="loginTime" width="180">
+        <el-table-column :label="t('online.table.deptName')" align="center" prop="deptName" :show-overflow-tooltip="true" width="180" />
+        <el-table-column :label="t('online.table.ipaddr')" align="center" prop="ipaddr" :show-overflow-tooltip="true" width="150" />
+        <el-table-column :label="t('online.table.loginLocation')" align="center" prop="loginLocation" :show-overflow-tooltip="true" width="180" />
+        <el-table-column :label="t('online.table.os')" align="center" prop="os" :show-overflow-tooltip="true" width="180" />
+        <el-table-column :label="t('online.table.browser')" align="center" prop="browser" :show-overflow-tooltip="true" width="150" />
+        <el-table-column :label="t('online.table.loginTime')" align="center" prop="loginTime" width="180">
           <template #default="scope">
             <span>{{ proxy.parseTime(scope.row.loginTime) }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <el-table-column :label="t('online.table.operation')" align="center" fixed="right" class-name="small-padding fixed-width" width="120">
           <template #default="scope">
-            <el-tooltip content="强退" placement="top">
+            <el-tooltip :content="t('online.tooltip.forceLogout')" placement="top">
               <el-button v-hasPermi="['monitor:online:forceLogout']" link type="primary" icon="Delete" @click="handleForceLogout(scope.row)">
               </el-button>
             </el-tooltip>
@@ -66,7 +66,9 @@ import { forceLogout, list as initData } from '@/api/monitor/online';
 import { OnlineQuery, OnlineVO } from '@/api/monitor/online/types';
 import api from '@/api/system/user';
 import { to } from 'await-to-js';
+import { useI18n } from 'vue-i18n';
 
+const { t } = useI18n();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_device_type } = toRefs<any>(proxy?.useDict('sys_device_type'));
 
@@ -103,11 +105,11 @@ const resetQuery = () => {
 };
 /** 强退按钮操作 */
 const handleForceLogout = async (row: OnlineVO) => {
-  const [err] = await to(proxy?.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?') as any);
+  const [err] = await to(proxy?.$modal.confirm(t('online.message.forceLogoutConfirm', { userName: row.userName })) as any);
   if (!err) {
     await forceLogout(row.tokenId);
     await getList();
-    proxy?.$modal.msgSuccess('删除成功');
+    proxy?.$modal.msgSuccess(t('online.message.forceLogoutSuccess'));
   }
 };
 

+ 50 - 48
src/views/system/dept/index.vue

@@ -3,21 +3,21 @@
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
       <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
-            <el-form-item label="部门名称" prop="deptName">
-              <el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="140px">
+            <el-form-item :label="t('dept.search.deptName')" prop="deptName">
+              <el-input v-model="queryParams.deptName" :placeholder="t('dept.search.deptNamePlaceholder')" clearable @keyup.enter="handleQuery" />
             </el-form-item>
-            <el-form-item label="类别编码" prop="deptCategory">
-              <el-input v-model="queryParams.deptCategory" placeholder="请输入类别编码" clearable style="width: 240px" @keyup.enter="handleQuery" />
+            <el-form-item :label="t('dept.search.deptCategory')" prop="deptCategory">
+              <el-input v-model="queryParams.deptCategory" :placeholder="t('dept.search.deptCategoryPlaceholder')" clearable style="width: 240px" @keyup.enter="handleQuery" />
             </el-form-item>
-            <el-form-item label="状态" prop="status">
-              <el-select v-model="queryParams.status" placeholder="部门状态" clearable>
+            <el-form-item :label="t('dept.search.status')" prop="status">
+              <el-select v-model="queryParams.status" :placeholder="t('dept.search.statusPlaceholder')" clearable>
                 <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
               </el-select>
             </el-form-item>
             <el-form-item>
-              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+              <el-button type="primary" icon="Search" @click="handleQuery">{{ t('dept.search.search') }}</el-button>
+              <el-button icon="Refresh" @click="resetQuery">{{ t('dept.search.reset') }}</el-button>
             </el-form-item>
           </el-form>
         </el-card>
@@ -28,10 +28,10 @@
       <template #header>
         <el-row :gutter="10">
           <el-col :span="1.5">
-            <el-button v-hasPermi="['system:dept:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增 </el-button>
+            <el-button v-hasPermi="['system:dept:add']" type="primary" plain icon="Plus" @click="handleAdd()">{{ t('dept.button.add') }} </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
+            <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">{{ t('dept.button.expandCollapse') }}</el-button>
           </el-col>
           <right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
@@ -46,28 +46,28 @@
         :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
         :default-expand-all="isExpandAll"
       >
-        <el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
-        <el-table-column prop="deptCategory" align="center" label="类别编码" width="200"></el-table-column>
-        <el-table-column prop="orderNum" align="center" label="排序" width="200"></el-table-column>
-        <el-table-column prop="status" align="center" label="状态" width="100">
+        <el-table-column prop="deptName" :label="t('dept.table.deptName')" width="260"></el-table-column>
+        <el-table-column prop="deptCategory" align="center" :label="t('dept.table.deptCategory')" width="200"></el-table-column>
+        <el-table-column prop="orderNum" align="center" :label="t('dept.table.orderNum')" width="200"></el-table-column>
+        <el-table-column prop="status" align="center" :label="t('dept.table.status')" width="100">
           <template #default="scope">
             <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
           </template>
         </el-table-column>
-        <el-table-column label="创建时间" align="center" prop="createTime" width="200">
+        <el-table-column :label="t('dept.table.createTime')" align="center" prop="createTime" width="200">
           <template #default="scope">
             <span>{{ proxy.parseTime(scope.row.createTime) }}</span>
           </template>
         </el-table-column>
-        <el-table-column fixed="right" align="center" label="操作">
+        <el-table-column fixed="right" align="center" :label="t('dept.table.operation')">
           <template #default="scope">
-            <el-tooltip content="修改" placement="top">
+            <el-tooltip :content="t('dept.tooltip.edit')" placement="top">
               <el-button v-hasPermi="['system:dept:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)" />
             </el-tooltip>
-            <el-tooltip content="新增" placement="top">
+            <el-tooltip :content="t('dept.tooltip.add')" placement="top">
               <el-button v-hasPermi="['system:dept:add']" link type="primary" icon="Plus" @click="handleAdd(scope.row)" />
             </el-tooltip>
-            <el-tooltip content="删除" placement="top">
+            <el-tooltip :content="t('dept.tooltip.delete')" placement="top">
               <el-button v-hasPermi="['system:dept:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)" />
             </el-tooltip>
           </template>
@@ -75,55 +75,55 @@
       </el-table>
     </el-card>
 
-    <el-dialog v-model="dialog.visible" :title="dialog.title" destroy-on-close append-to-body width="600px">
-      <el-form ref="deptFormRef" :model="form" :rules="rules" label-width="80px">
+    <el-dialog v-model="dialog.visible" :title="dialog.title" destroy-on-close append-to-body width="900px">
+      <el-form ref="deptFormRef" :model="form" :rules="rules" label-width="180px">
         <el-row>
           <el-col v-if="form.parentId !== 0" :span="24">
-            <el-form-item label="上级部门" prop="parentId">
+            <el-form-item :label="t('dept.form.parentId')" prop="parentId">
               <el-tree-select
                 v-model="form.parentId"
                 :data="deptOptions"
                 :props="{ value: 'deptId', label: 'deptName', children: 'children' } as any"
                 value-key="deptId"
-                placeholder="选择上级部门"
+                :placeholder="t('dept.form.parentIdPlaceholder')"
                 check-strictly
               />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="部门名称" prop="deptName">
-              <el-input v-model="form.deptName" placeholder="请输入部门名称" />
+            <el-form-item :label="t('dept.form.deptName')" prop="deptName">
+              <el-input v-model="form.deptName" :placeholder="t('dept.form.deptNamePlaceholder')" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="类别编码" prop="deptCategory">
-              <el-input v-model="form.deptCategory" placeholder="请输入类别编码" />
+            <el-form-item :label="t('dept.form.deptCategory')" prop="deptCategory">
+              <el-input v-model="form.deptCategory" :placeholder="t('dept.form.deptCategoryPlaceholder')" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="显示排序" prop="orderNum">
+            <el-form-item :label="t('dept.form.orderNum')" prop="orderNum">
               <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="负责人" prop="leader">
-              <el-select v-model="form.leader" placeholder="请选择负责人">
+            <el-form-item :label="t('dept.form.leader')" prop="leader">
+              <el-select v-model="form.leader" :placeholder="t('dept.form.leaderPlaceholder')">
                 <el-option v-for="item in deptUserList" :key="item.userId" :label="item.userName" :value="item.userId" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="联系电话" prop="phone">
-              <el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
+            <el-form-item :label="t('dept.form.phone')" prop="phone">
+              <el-input v-model="form.phone" :placeholder="t('dept.form.phonePlaceholder')" maxlength="11" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="邮箱" prop="email">
-              <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
+            <el-form-item :label="t('dept.form.email')" prop="email">
+              <el-input v-model="form.email" :placeholder="t('dept.form.emailPlaceholder')" maxlength="50" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="部门状态">
+            <el-form-item :label="t('dept.form.status')">
               <el-radio-group v-model="form.status">
                 <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
               </el-radio-group>
@@ -133,8 +133,8 @@
       </el-form>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">确 定</el-button>
-          <el-button @click="cancel">取 消</el-button>
+          <el-button type="primary" @click="submitForm">{{ t('dept.button.submit') }}</el-button>
+          <el-button @click="cancel">{{ t('dept.button.cancel') }}</el-button>
         </div>
       </template>
     </el-dialog>
@@ -146,6 +146,7 @@ import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild }
 import { DeptForm, DeptQuery, DeptVO } from '@/api/system/dept/types';
 import { UserVO } from '@/api/system/user/types';
 import { listUserByDeptId } from '@/api/system/user';
+import { useI18n } from 'vue-i18n';
 
 interface DeptOptionsType {
   deptId: number | string;
@@ -153,6 +154,7 @@ interface DeptOptionsType {
   children: DeptOptionsType[];
 }
 
+const { t } = useI18n();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
 
@@ -193,11 +195,11 @@ const initData: PageData<DeptForm, DeptQuery> = {
     status: undefined
   },
   rules: {
-    parentId: [{ required: true, message: '上级部门不能为空', trigger: 'blur' }],
-    deptName: [{ required: true, message: '部门名称不能为空', trigger: 'blur' }],
-    orderNum: [{ required: true, message: '显示排序不能为空', trigger: 'blur' }],
-    email: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }],
-    phone: [{ pattern: /^1[3456789][0-9]\d{8}$/, message: '请输入正确的手机号码', trigger: 'blur' }]
+    parentId: [{ required: true, message: t('dept.rule.parentIdRequired'), trigger: 'blur' }],
+    deptName: [{ required: true, message: t('dept.rule.deptNameRequired'), trigger: 'blur' }],
+    orderNum: [{ required: true, message: t('dept.rule.orderNumRequired'), trigger: 'blur' }],
+    email: [{ type: 'email', message: t('dept.rule.emailFormat'), trigger: ['blur', 'change'] }],
+    phone: [{ pattern: /^1[3456789][0-9]\d{8}$/, message: t('dept.rule.phoneFormat'), trigger: 'blur' }]
   }
 };
 const data = reactive<PageData<DeptForm, DeptQuery>>(initData);
@@ -268,7 +270,7 @@ const handleAdd = async (row?: DeptVO) => {
       form.value.parentId = row?.deptId;
     }
     dialog.visible = true;
-    dialog.title = '添加部门';
+    dialog.title = t('dept.dialog.add');
   }
 };
 
@@ -293,14 +295,14 @@ const handleUpdate = async (row: DeptVO) => {
     }
   }
   dialog.visible = true;
-  dialog.title = '修改部门';
+  dialog.title = t('dept.dialog.edit');
 };
 /** 提交按钮 */
 const submitForm = () => {
   deptFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       form.value.deptId ? await updateDept(form.value) : await addDept(form.value);
-      proxy?.$modal.msgSuccess('操作成功');
+      proxy?.$modal.msgSuccess(t('dept.message.operationSuccess'));
       dialog.visible = false;
       await getList();
     }
@@ -308,10 +310,10 @@ const submitForm = () => {
 };
 /** 删除按钮操作 */
 const handleDelete = async (row: DeptVO) => {
-  await proxy?.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?');
+  await proxy?.$modal.confirm(t('dept.message.deleteConfirm', { name: row.deptName }));
   await delDept(row.deptId);
   await getList();
-  proxy?.$modal.msgSuccess('删除成功');
+  proxy?.$modal.msgSuccess(t('dept.message.deleteSuccess'));
 };
 
 onMounted(() => {

+ 56 - 54
src/views/system/post/index.vue

@@ -4,7 +4,7 @@
       <!-- 部门树 -->
       <el-col :lg="4" :xs="24" style="">
         <el-card shadow="hover">
-          <el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
+          <el-input v-model="deptName" :placeholder="t('post.tree.deptPlaceholder')" prefix-icon="Search" clearable />
           <el-tree
             ref="deptTreeRef"
             class="mt-2"
@@ -23,40 +23,40 @@
         <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
           <div v-show="showSearch" class="mb-[10px]">
             <el-card shadow="hover">
-              <el-form ref="queryFormRef" :model="queryParams" :inline="true">
-                <el-form-item label="岗位编码" prop="postCode">
-                  <el-input v-model="queryParams.postCode" placeholder="请输入岗位编码" clearable @keyup.enter="handleQuery" />
+              <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="140px">
+                <el-form-item :label="t('post.search.postCode')" prop="postCode">
+                  <el-input v-model="queryParams.postCode" :placeholder="t('post.search.postCodePlaceholder')" clearable @keyup.enter="handleQuery" />
                 </el-form-item>
-                <el-form-item label="类别编码" prop="postCategory">
+                <el-form-item :label="t('post.search.postCategory')" prop="postCategory">
                   <el-input
                     v-model="queryParams.postCategory"
-                    placeholder="请输入类别编码"
+                    :placeholder="t('post.search.postCategoryPlaceholder')"
                     clearable
                     style="width: 200px"
                     @keyup.enter="handleQuery"
                   />
                 </el-form-item>
-                <el-form-item label="岗位名称" prop="postName">
-                  <el-input v-model="queryParams.postName" placeholder="请输入岗位名称" clearable @keyup.enter="handleQuery" />
+                <el-form-item :label="t('post.search.postName')" prop="postName">
+                  <el-input v-model="queryParams.postName" :placeholder="t('post.search.postNamePlaceholder')" clearable @keyup.enter="handleQuery" />
                 </el-form-item>
-                <el-form-item label="部门" prop="deptId">
+                <el-form-item :label="t('post.search.deptId')" prop="deptId">
                   <el-tree-select
                     v-model="queryParams.deptId"
                     :data="deptOptions"
                     :props="{ value: 'id', label: 'label', children: 'children' } as any"
                     value-key="id"
-                    placeholder="请选择部门"
+                    :placeholder="t('post.search.deptIdPlaceholder')"
                     check-strictly
                   />
                 </el-form-item>
-                <el-form-item label="状态" prop="status">
-                  <el-select v-model="queryParams.status" placeholder="岗位状态" clearable>
+                <el-form-item :label="t('post.search.status')" prop="status">
+                  <el-select v-model="queryParams.status" :placeholder="t('post.search.statusPlaceholder')" clearable>
                     <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
                   </el-select>
                 </el-form-item>
                 <el-form-item>
-                  <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-                  <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+                  <el-button type="primary" icon="Search" @click="handleQuery">{{ t('post.search.search') }}</el-button>
+                  <el-button icon="Refresh" @click="resetQuery">{{ t('post.search.reset') }}</el-button>
                 </el-form-item>
               </el-form>
             </el-card>
@@ -66,48 +66,48 @@
           <template #header>
             <el-row :gutter="10" class="mb8">
               <el-col :span="1.5">
-                <el-button v-hasPermi="['system:post:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
+                <el-button v-hasPermi="['system:post:add']" type="primary" plain icon="Plus" @click="handleAdd">{{ t('post.button.add') }}</el-button>
               </el-col>
               <el-col :span="1.5">
                 <el-button v-hasPermi="['system:post:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
-                  >修改</el-button
+                  >{{ t('post.button.edit') }}</el-button
                 >
               </el-col>
               <el-col :span="1.5">
                 <el-button v-hasPermi="['system:post:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
-                  删除
+                  {{ t('post.button.delete') }}
                 </el-button>
               </el-col>
               <el-col :span="1.5">
-                <el-button v-hasPermi="['system:post:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
+                <el-button v-hasPermi="['system:post:export']" type="warning" plain icon="Download" @click="handleExport">{{ t('post.button.export') }}</el-button>
               </el-col>
               <right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
             </el-row>
           </template>
           <el-table v-loading="loading" border :data="postList" @selection-change="handleSelectionChange">
             <el-table-column type="selection" width="55" align="center" />
-            <el-table-column v-if="false" label="岗位编号" align="center" prop="postId" />
-            <el-table-column label="岗位编码" align="center" prop="postCode" />
-            <el-table-column label="类别编码" align="center" prop="postCategory" />
-            <el-table-column label="岗位名称" align="center" prop="postName" />
-            <el-table-column label="部门" align="center" prop="deptName" />
-            <el-table-column label="排序" align="center" prop="postSort" />
-            <el-table-column label="状态" align="center" prop="status">
+            <el-table-column v-if="false" :label="t('post.table.postId')" align="center" prop="postId" />
+            <el-table-column :label="t('post.table.postCode')" align="center" prop="postCode" />
+            <el-table-column :label="t('post.table.postCategory')" align="center" prop="postCategory" />
+            <el-table-column :label="t('post.table.postName')" align="center" prop="postName" />
+            <el-table-column :label="t('post.table.deptName')" align="center" prop="deptName" />
+            <el-table-column :label="t('post.table.postSort')" align="center" prop="postSort" />
+            <el-table-column :label="t('post.table.status')" align="center" prop="status">
               <template #default="scope">
                 <dict-tag :options="sys_normal_disable" :value="scope.row.status" />
               </template>
             </el-table-column>
-            <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+            <el-table-column :label="t('post.table.createTime')" align="center" prop="createTime" width="180">
               <template #default="scope">
                 <span>{{ proxy.parseTime(scope.row.createTime) }}</span>
               </template>
             </el-table-column>
-            <el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
+            <el-table-column :label="t('post.table.operation')" width="180" align="center" class-name="small-padding fixed-width">
               <template #default="scope">
-                <el-tooltip content="修改" placement="top">
+                <el-tooltip :content="t('post.tooltip.edit')" placement="top">
                   <el-button v-hasPermi="['system:post:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
                 </el-tooltip>
-                <el-tooltip content="删除" placement="top">
+                <el-tooltip :content="t('post.tooltip.delete')" placement="top">
                   <el-button v-hasPermi="['system:post:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
                 </el-tooltip>
               </template>
@@ -124,43 +124,43 @@
         </el-card>
 
         <!-- 添加或修改岗位对话框 -->
-        <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
-          <el-form ref="postFormRef" :model="form" :rules="rules" label-width="80px">
-            <el-form-item label="岗位名称" prop="postName">
-              <el-input v-model="form.postName" placeholder="请输入岗位名称" />
+        <el-dialog v-model="dialog.visible" :title="dialog.title" width="900px" append-to-body>
+          <el-form ref="postFormRef" :model="form" :rules="rules" label-width="180px">
+            <el-form-item :label="t('post.form.postName')" prop="postName">
+              <el-input v-model="form.postName" :placeholder="t('post.form.postNamePlaceholder')" />
             </el-form-item>
-            <el-form-item label="部门" prop="deptId">
+            <el-form-item :label="t('post.form.deptId')" prop="deptId">
               <el-tree-select
                 v-model="form.deptId"
                 :data="deptOptions"
                 :props="{ value: 'id', label: 'label', children: 'children' } as any"
                 value-key="id"
-                placeholder="请选择部门"
+                :placeholder="t('post.form.deptIdPlaceholder')"
                 check-strictly
               />
             </el-form-item>
-            <el-form-item label="岗位编码" prop="postCode">
-              <el-input v-model="form.postCode" placeholder="请输入编码名称" />
+            <el-form-item :label="t('post.form.postCode')" prop="postCode">
+              <el-input v-model="form.postCode" :placeholder="t('post.form.postCodePlaceholder')" />
             </el-form-item>
-            <el-form-item label="类别编码" prop="postCategory">
-              <el-input v-model="form.postCategory" placeholder="请输入类别编码" />
+            <el-form-item :label="t('post.form.postCategory')" prop="postCategory">
+              <el-input v-model="form.postCategory" :placeholder="t('post.form.postCategoryPlaceholder')" />
             </el-form-item>
-            <el-form-item label="岗位顺序" prop="postSort">
+            <el-form-item :label="t('post.form.postSort')" prop="postSort">
               <el-input-number v-model="form.postSort" controls-position="right" :min="0" />
             </el-form-item>
-            <el-form-item label="岗位状态" prop="status">
+            <el-form-item :label="t('post.form.status')" prop="status">
               <el-radio-group v-model="form.status">
                 <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
               </el-radio-group>
             </el-form-item>
-            <el-form-item label="备注" prop="remark">
-              <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+            <el-form-item :label="t('post.form.remark')" prop="remark">
+              <el-input v-model="form.remark" type="textarea" :placeholder="t('post.form.remarkPlaceholder')" />
             </el-form-item>
           </el-form>
           <template #footer>
             <div class="dialog-footer">
-              <el-button type="primary" @click="submitForm">确 定</el-button>
-              <el-button @click="cancel">取 消</el-button>
+              <el-button type="primary" @click="submitForm">{{ t('post.button.submit') }}</el-button>
+              <el-button @click="cancel">{{ t('post.button.cancel') }}</el-button>
             </div>
           </template>
         </el-dialog>
@@ -173,7 +173,9 @@
 import { listPost, addPost, delPost, getPost, updatePost, deptTreeSelect } from '@/api/system/post';
 import { PostForm, PostQuery, PostVO } from '@/api/system/post/types';
 import { DeptTreeVO, DeptVO } from '@/api/system/dept/types';
+import { useI18n } from 'vue-i18n';
 
+const { t } = useI18n();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
 
@@ -219,10 +221,10 @@ const data = reactive<PageData<PostForm, PostQuery>>({
     status: ''
   },
   rules: {
-    postName: [{ required: true, message: '岗位名称不能为空', trigger: 'blur' }],
-    postCode: [{ required: true, message: '岗位编码不能为空', trigger: 'blur' }],
-    deptId: [{ required: true, message: '部门不能为空', trigger: 'blur' }],
-    postSort: [{ required: true, message: '岗位顺序不能为空', trigger: 'blur' }]
+    postName: [{ required: true, message: t('post.rule.postNameRequired'), trigger: 'blur' }],
+    postCode: [{ required: true, message: t('post.rule.postCodeRequired'), trigger: 'blur' }],
+    deptId: [{ required: true, message: t('post.rule.deptIdRequired'), trigger: 'blur' }],
+    postSort: [{ required: true, message: t('post.rule.postSortRequired'), trigger: 'blur' }]
   }
 });
 
@@ -309,7 +311,7 @@ const handleSelectionChange = (selection: PostVO[]) => {
 const handleAdd = () => {
   reset();
   dialog.visible = true;
-  dialog.title = '添加岗位';
+  dialog.title = t('post.dialog.add');
 };
 
 /** 修改按钮操作 */
@@ -319,7 +321,7 @@ const handleUpdate = async (row?: PostVO) => {
   const res = await getPost(postId);
   Object.assign(form.value, res.data);
   dialog.visible = true;
-  dialog.title = '修改岗位';
+  dialog.title = t('post.dialog.edit');
 };
 
 /** 提交按钮 */
@@ -327,7 +329,7 @@ const submitForm = () => {
   postFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
       form.value.postId ? await updatePost(form.value) : await addPost(form.value);
-      proxy?.$modal.msgSuccess('操作成功');
+      proxy?.$modal.msgSuccess(t('post.message.operationSuccess'));
       dialog.visible = false;
       await getList();
     }
@@ -337,10 +339,10 @@ const submitForm = () => {
 /** 删除按钮操作 */
 const handleDelete = async (row?: PostVO) => {
   const postIds = row?.postId || ids.value;
-  await proxy?.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?');
+  await proxy?.$modal.confirm(t('post.message.deleteConfirm', { ids: postIds }));
   await delPost(postIds);
   await getList();
-  proxy?.$modal.msgSuccess('删除成功');
+  proxy?.$modal.msgSuccess(t('post.message.deleteSuccess'));
 };
 
 /** 导出按钮操作 */

+ 79 - 77
src/views/system/role/index.vue

@@ -3,33 +3,33 @@
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
       <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
-            <el-form-item label="角色名称" prop="roleName">
-              <el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable @keyup.enter="handleQuery" />
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="140px">
+            <el-form-item :label="t('role.search.roleName')" prop="roleName">
+              <el-input v-model="queryParams.roleName" :placeholder="t('role.search.roleNamePlaceholder')" clearable @keyup.enter="handleQuery" />
             </el-form-item>
-            <el-form-item label="权限字符" prop="roleKey">
-              <el-input v-model="queryParams.roleKey" placeholder="请输入权限字符" clearable @keyup.enter="handleQuery" />
+            <el-form-item :label="t('role.search.roleKey')" prop="roleKey">
+              <el-input v-model="queryParams.roleKey" :placeholder="t('role.search.roleKeyPlaceholder')" clearable @keyup.enter="handleQuery" />
             </el-form-item>
-            <el-form-item label="状态" prop="status">
-              <el-select v-model="queryParams.status" placeholder="角色状态" clearable>
+            <el-form-item :label="t('role.search.status')" prop="status">
+              <el-select v-model="queryParams.status" :placeholder="t('role.search.statusPlaceholder')" clearable>
                 <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
               </el-select>
             </el-form-item>
-            <el-form-item label="创建时间" style="width: 308px">
+            <el-form-item :label="t('role.search.createTime')" style="width: 308px">
               <el-date-picker
                 v-model="dateRange"
                 value-format="YYYY-MM-DD HH:mm:ss"
                 type="daterange"
                 range-separator="-"
-                start-placeholder="开始日期"
-                end-placeholder="结束日期"
+                :start-placeholder="t('role.search.startDate')"
+                :end-placeholder="t('role.search.endDate')"
                 :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
               ></el-date-picker>
             </el-form-item>
 
             <el-form-item>
-              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+              <el-button type="primary" icon="Search" @click="handleQuery">{{ t('role.search.search') }}</el-button>
+              <el-button icon="Refresh" @click="resetQuery">{{ t('role.search.reset') }}</el-button>
             </el-form-item>
           </el-form>
         </el-card>
@@ -40,16 +40,16 @@
       <template #header>
         <el-row :gutter="10">
           <el-col :span="1.5">
-            <el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
+            <el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="handleAdd()">{{ t('role.button.add') }}</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button v-hasPermi="['system:role:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">修改</el-button>
+            <el-button v-hasPermi="['system:role:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">{{ t('role.button.edit') }}</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button v-hasPermi="['system:role:delete']" type="danger" plain :disabled="ids.length === 0" @click="handleDelete()">删除</el-button>
+            <el-button v-hasPermi="['system:role:delete']" type="danger" plain :disabled="ids.length === 0" @click="handleDelete()">{{ t('role.button.delete') }}</el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button v-hasPermi="['system:role:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
+            <el-button v-hasPermi="['system:role:export']" type="warning" plain icon="Download" @click="handleExport">{{ t('role.button.export') }}</el-button>
           </el-col>
           <right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
@@ -57,33 +57,33 @@
 
       <el-table ref="roleTableRef" border v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column v-if="false" label="角色编号" prop="roleId" width="120" />
-        <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
-        <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="200" />
-        <el-table-column label="显示顺序" prop="roleSort" width="100" />
-        <el-table-column label="状态" align="center" width="100">
+        <el-table-column v-if="false" :label="t('role.table.roleId')" prop="roleId" width="120" />
+        <el-table-column :label="t('role.table.roleName')" prop="roleName" :show-overflow-tooltip="true" width="150" />
+        <el-table-column :label="t('role.table.roleKey')" prop="roleKey" :show-overflow-tooltip="true" width="200" />
+        <el-table-column :label="t('role.table.roleSort')" prop="roleSort" width="100" />
+        <el-table-column :label="t('role.table.status')" align="center" width="100">
           <template #default="scope">
             <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
           </template>
         </el-table-column>
-        <el-table-column label="创建时间" align="center" prop="createTime">
+        <el-table-column :label="t('role.table.createTime')" align="center" prop="createTime">
           <template #default="scope">
             <span>{{ proxy.parseTime(scope.row.createTime) }}</span>
           </template>
         </el-table-column>
 
-        <el-table-column fixed="right" label="操作" width="180">
+        <el-table-column fixed="right" :label="t('role.table.operation')" width="180">
           <template #default="scope">
-            <el-tooltip v-if="scope.row.roleId !== 1" content="修改" placement="top">
+            <el-tooltip v-if="scope.row.roleId !== 1" :content="t('role.tooltip.edit')" placement="top">
               <el-button v-hasPermi="['system:role:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
             </el-tooltip>
-            <el-tooltip v-if="scope.row.roleId !== 1" content="删除" placement="top">
+            <el-tooltip v-if="scope.row.roleId !== 1" :content="t('role.tooltip.delete')" placement="top">
               <el-button v-hasPermi="['system:role:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
-            <el-tooltip v-if="scope.row.roleId !== 1" content="数据权限" placement="top">
+            <el-tooltip v-if="scope.row.roleId !== 1" :content="t('role.tooltip.dataScope')" placement="top">
               <el-button v-hasPermi="['system:role:edit']" link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)"></el-button>
             </el-tooltip>
-            <el-tooltip v-if="scope.row.roleId !== 1" content="分配用户" placement="top">
+            <el-tooltip v-if="scope.row.roleId !== 1" :content="t('role.tooltip.assignUser')" placement="top">
               <el-button v-hasPermi="['system:role:edit']" link type="primary" icon="User" @click="handleAuthUser(scope.row)"></el-button>
             </el-tooltip>
           </template>
@@ -99,34 +99,34 @@
       />
     </el-card>
 
-    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
-      <el-form ref="roleFormRef" :model="form" :rules="rules" label-width="100px">
-        <el-form-item label="角色名称" prop="roleName">
-          <el-input v-model="form.roleName" placeholder="请输入角色名称" />
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="900px" append-to-body>
+      <el-form ref="roleFormRef" :model="form" :rules="rules" label-width="180px">
+        <el-form-item :label="t('role.form.roleName')" prop="roleName">
+          <el-input v-model="form.roleName" :placeholder="t('role.form.roleNamePlaceholder')" />
         </el-form-item>
         <el-form-item prop="roleKey">
           <template #label>
             <span>
-              <el-tooltip content="控制器中定义的权限字符,如:@SaCheckRole('admin')" placement="top">
+              <el-tooltip :content="t('role.form.roleKeyTooltip')" placement="top">
                 <el-icon><question-filled /></el-icon>
               </el-tooltip>
-              权限字符
+              {{ t('role.form.roleKey') }}
             </span>
           </template>
-          <el-input v-model="form.roleKey" placeholder="请输入权限字符" />
+          <el-input v-model="form.roleKey" :placeholder="t('role.form.roleKeyPlaceholder')" />
         </el-form-item>
-        <el-form-item label="角色顺序" prop="roleSort">
+        <el-form-item :label="t('role.form.roleSort')" prop="roleSort">
           <el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
         </el-form-item>
-        <el-form-item label="状态">
+        <el-form-item :label="t('role.form.status')">
           <el-radio-group v-model="form.status">
             <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
           </el-radio-group>
         </el-form-item>
-        <el-form-item label="菜单权限">
-          <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
-          <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
-          <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
+        <el-form-item :label="t('role.form.menuPermission')">
+          <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">{{ t('role.form.expandCollapse') }}</el-checkbox>
+          <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">{{ t('role.form.selectAll') }}</el-checkbox>
+          <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">{{ t('role.form.parentChild') }}</el-checkbox>
           <el-tree
             ref="menuRef"
             class="tree-border"
@@ -134,40 +134,40 @@
             show-checkbox
             node-key="id"
             :check-strictly="!form.menuCheckStrictly"
-            empty-text="加载中,请稍候"
+            :empty-text="t('role.form.loading')"
             :props="{ label: 'label', children: 'children' } as any"
           ></el-tree>
         </el-form-item>
-        <el-form-item label="备注">
-          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
+        <el-form-item :label="t('role.form.remark')">
+          <el-input v-model="form.remark" type="textarea" :placeholder="t('role.form.remarkPlaceholder')"></el-input>
         </el-form-item>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">确 定</el-button>
-          <el-button @click="cancel">取 消</el-button>
+          <el-button type="primary" @click="submitForm">{{ t('role.button.submit') }}</el-button>
+          <el-button @click="cancel">{{ t('role.button.cancel') }}</el-button>
         </div>
       </template>
     </el-dialog>
 
     <!-- 分配角色数据权限对话框 -->
-    <el-dialog v-model="openDataScope" :title="dialog.title" width="500px" append-to-body>
-      <el-form ref="dataScopeRef" :model="form" label-width="80px">
-        <el-form-item label="角色名称">
+    <el-dialog v-model="openDataScope" :title="dialog.title" width="900px" append-to-body>
+      <el-form ref="dataScopeRef" :model="form" label-width="180px">
+        <el-form-item :label="t('role.form.roleName')">
           <el-input v-model="form.roleName" :disabled="true" />
         </el-form-item>
-        <el-form-item label="权限字符">
+        <el-form-item :label="t('role.form.roleKey')">
           <el-input v-model="form.roleKey" :disabled="true" />
         </el-form-item>
-        <el-form-item label="权限范围">
+        <el-form-item :label="t('role.form.dataScope')">
           <el-select v-model="form.dataScope" @change="dataScopeSelectChange">
             <el-option v-for="item in dataScopeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
           </el-select>
         </el-form-item>
-        <el-form-item v-show="form.dataScope === '2'" label="数据权限">
-          <el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
-          <el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
-          <el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
+        <el-form-item v-show="form.dataScope === '2'" :label="t('role.form.dataPermission')">
+          <el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">{{ t('role.form.expandCollapse') }}</el-checkbox>
+          <el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">{{ t('role.form.selectAll') }}</el-checkbox>
+          <el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">{{ t('role.form.parentChild') }}</el-checkbox>
           <el-tree
             ref="deptRef"
             class="tree-border"
@@ -176,15 +176,15 @@
             default-expand-all
             node-key="id"
             :check-strictly="!form.deptCheckStrictly"
-            empty-text="加载中,请稍候"
+            :empty-text="t('role.form.loading')"
             :props="{ label: 'label', children: 'children' } as any"
           ></el-tree>
         </el-form-item>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitDataScope">确 定</el-button>
-          <el-button @click="cancelDataScope">取 消</el-button>
+          <el-button type="primary" @click="submitDataScope">{{ t('role.button.submit') }}</el-button>
+          <el-button @click="cancelDataScope">{{ t('role.button.cancel') }}</el-button>
         </div>
       </template>
     </el-dialog>
@@ -196,7 +196,9 @@ import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updat
 import { roleMenuTreeselect, treeselect as menuTreeselect } from '@/api/system/menu/index';
 import { RoleVO, RoleForm, RoleQuery, DeptTreeOption } from '@/api/system/role/types';
 import { MenuTreeOption, RoleMenuTree } from '@/api/system/menu/types';
+import { useI18n } from 'vue-i18n';
 
+const { t } = useI18n();
 const router = useRouter();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));
@@ -218,13 +220,13 @@ const deptOptions = ref<DeptTreeOption[]>([]);
 const openDataScope = ref(false);
 
 /** 数据范围选项*/
-const dataScopeOptions = ref([
-  { value: '1', label: '全部数据权限' },
-  { value: '2', label: '自定数据权限' },
-  { value: '3', label: '本部门数据权限' },
-  { value: '4', label: '本部门及以下数据权限' },
-  { value: '5', label: '仅本人数据权限' },
-  { value: '6', label: '部门及以下或本人数据权限' }
+const dataScopeOptions = computed(() => [
+  { value: '1', label: t('role.dataScope.all') },
+  { value: '2', label: t('role.dataScope.custom') },
+  { value: '3', label: t('role.dataScope.dept') },
+  { value: '4', label: t('role.dataScope.deptAndBelow') },
+  { value: '5', label: t('role.dataScope.self') },
+  { value: '6', label: t('role.dataScope.deptBelowOrSelf') }
 ]);
 
 const queryFormRef = ref<ElFormInstance>();
@@ -257,9 +259,9 @@ const data = reactive<PageData<RoleForm, RoleQuery>>({
     status: ''
   },
   rules: {
-    roleName: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
-    roleKey: [{ required: true, message: '权限字符不能为空', trigger: 'blur' }],
-    roleSort: [{ required: true, message: '角色顺序不能为空', trigger: 'blur' }]
+    roleName: [{ required: true, message: t('role.rule.roleNameRequired'), trigger: 'blur' }],
+    roleKey: [{ required: true, message: t('role.rule.roleKeyRequired'), trigger: 'blur' }],
+    roleSort: [{ required: true, message: t('role.rule.roleSortRequired'), trigger: 'blur' }]
   }
 });
 const { form, queryParams, rules } = toRefs(data);
@@ -298,10 +300,10 @@ const resetQuery = () => {
 /**删除按钮操作 */
 const handleDelete = async (row?: RoleVO) => {
   const roleids = row?.roleId || ids.value;
-  await proxy?.$modal.confirm('是否确认删除角色编号为' + roleids + '数据项目');
+  await proxy?.$modal.confirm(t('role.message.deleteConfirm', { ids: roleids }));
   await delRole(roleids);
   getList();
-  proxy?.$modal.msgSuccess('删除成功');
+  proxy?.$modal.msgSuccess(t('role.message.deleteSuccess'));
 };
 
 /** 导出按钮操作 */
@@ -323,11 +325,11 @@ const handleSelectionChange = (selection: RoleVO[]) => {
 
 /** 角色状态修改 */
 const handleStatusChange = async (row: RoleVO) => {
-  const text = row.status === '0' ? '启用' : '停用';
+  const text = row.status === '0' ? t('role.message.statusEnable') : t('role.message.statusDisable');
   try {
-    await proxy?.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?');
+    await proxy?.$modal.confirm(t('role.message.statusChangeConfirm', { text, roleName: row.roleName }));
     await changeRoleStatus(row.roleId, row.status);
-    proxy?.$modal.msgSuccess(text + '成功');
+    proxy?.$modal.msgSuccess(t('role.message.statusChangeSuccess', { text }));
   } catch {
     row.status = row.status === '0' ? '1' : '0';
   }
@@ -370,7 +372,7 @@ const handleAdd = () => {
   reset();
   getMenuTreeselect();
   dialog.visible = true;
-  dialog.title = '添加角色';
+  dialog.title = t('role.dialog.add');
 };
 /** 修改角色 */
 const handleUpdate = async (row?: RoleVO) => {
@@ -380,7 +382,7 @@ const handleUpdate = async (row?: RoleVO) => {
   Object.assign(form.value, data);
   form.value.roleSort = Number(form.value.roleSort);
   const res = await getRoleMenuTreeselect(roleId);
-  dialog.title = '修改角色';
+  dialog.title = t('role.dialog.edit');
   dialog.visible = true;
   res.checkedKeys.forEach((v) => {
     nextTick(() => {
@@ -452,7 +454,7 @@ const submitForm = () => {
     if (valid) {
       form.value.menuIds = getMenuAllCheckedKeys();
       form.value.roleId ? await updateRole(form.value) : await addRole(form.value);
-      proxy?.$modal.msgSuccess('操作成功');
+      proxy?.$modal.msgSuccess(t('role.message.operationSuccess'));
       dialog.visible = false;
       getList();
     }
@@ -475,7 +477,7 @@ const handleDataScope = async (row: RoleVO) => {
   Object.assign(form.value, response.data);
   const res = await getRoleDeptTreeSelect(row.roleId);
   openDataScope.value = true;
-  dialog.title = '分配数据权限';
+  dialog.title = t('role.dialog.dataScope');
   await nextTick(() => {
     deptRef.value?.setCheckedKeys(res.checkedKeys);
   });
@@ -485,7 +487,7 @@ const submitDataScope = async () => {
   if (form.value.roleId) {
     form.value.deptIds = getDeptAllCheckedKeys();
     await dataScope(form.value);
-    proxy?.$modal.msgSuccess('修改成功');
+    proxy?.$modal.msgSuccess(t('role.message.modifySuccess'));
     openDataScope.value = false;
     getList();
   }

+ 85 - 83
src/views/system/tenant/index.vue

@@ -3,22 +3,22 @@
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
       <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
-            <el-form-item label="租户编号" prop="tenantId">
-              <el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable @keyup.enter="handleQuery" />
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="140px">
+            <el-form-item :label="t('tenant.search.tenantId')" prop="tenantId">
+              <el-input v-model="queryParams.tenantId" :placeholder="t('tenant.search.tenantIdPlaceholder')" clearable @keyup.enter="handleQuery" />
             </el-form-item>
-            <el-form-item label="联系人" prop="contactUserName">
-              <el-input v-model="queryParams.contactUserName" placeholder="请输入联系人" clearable @keyup.enter="handleQuery" />
+            <el-form-item :label="t('tenant.search.contactUserName')" prop="contactUserName">
+              <el-input v-model="queryParams.contactUserName" :placeholder="t('tenant.search.contactUserNamePlaceholder')" clearable @keyup.enter="handleQuery" />
             </el-form-item>
-            <el-form-item label="联系电话" prop="contactPhone">
-              <el-input v-model="queryParams.contactPhone" placeholder="请输入联系电话" clearable @keyup.enter="handleQuery" />
+            <el-form-item :label="t('tenant.search.contactPhone')" prop="contactPhone">
+              <el-input v-model="queryParams.contactPhone" :placeholder="t('tenant.search.contactPhonePlaceholder')" clearable @keyup.enter="handleQuery" />
             </el-form-item>
-            <el-form-item label="企业名称" prop="companyName">
-              <el-input v-model="queryParams.companyName" placeholder="请输入企业名称" clearable @keyup.enter="handleQuery" />
+            <el-form-item :label="t('tenant.search.companyName')" prop="companyName">
+              <el-input v-model="queryParams.companyName" :placeholder="t('tenant.search.companyNamePlaceholder')" clearable @keyup.enter="handleQuery" />
             </el-form-item>
             <el-form-item>
-              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+              <el-button type="primary" icon="Search" @click="handleQuery">{{ t('tenant.search.search') }}</el-button>
+              <el-button icon="Refresh" @click="resetQuery">{{ t('tenant.search.reset') }}</el-button>
             </el-form-item>
           </el-form>
         </el-card>
@@ -29,20 +29,20 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button v-hasPermi="['system:tenant:add']" type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
+            <el-button v-hasPermi="['system:tenant:add']" type="primary" plain icon="Plus" @click="handleAdd">{{ t('tenant.button.add') }}</el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button v-hasPermi="['system:tenant:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()"
-              >修改</el-button
+              >{{ t('tenant.button.edit') }}</el-button
             >
           </el-col>
           <el-col :span="1.5">
             <el-button v-hasPermi="['system:tenant:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
-              删除
+              {{ t('tenant.button.delete') }}
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button v-hasPermi="['system:tenant:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
+            <el-button v-hasPermi="['system:tenant:export']" type="warning" plain icon="Download" @click="handleExport">{{ t('tenant.button.export') }}</el-button>
           </el-col>
 <!--          <el-col :span="1.5">-->
 <!--            <el-button v-if="userId === 1" type="success" plain icon="Refresh" @click="handleSyncTenantDict">同步租户字典</el-button>-->
@@ -56,32 +56,32 @@
 
       <el-table v-loading="loading" border :data="tenantList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column v-if="false" label="id" align="center" prop="id" />
-        <el-table-column label="租户编号" align="center" prop="tenantId" />
-        <el-table-column label="联系人" align="center" prop="contactUserName" />
-        <el-table-column label="联系电话" align="center" prop="contactPhone" />
-        <el-table-column label="企业名称" align="center" prop="companyName" />
-        <el-table-column label="社会信用代码" align="center" prop="licenseNumber" />
-        <el-table-column label="过期时间" align="center" prop="expireTime" width="180">
+        <el-table-column v-if="false" :label="t('tenant.table.id')" align="center" prop="id" />
+        <el-table-column :label="t('tenant.table.tenantId')" align="center" prop="tenantId" />
+        <el-table-column :label="t('tenant.table.contactUserName')" align="center" prop="contactUserName" />
+        <el-table-column :label="t('tenant.table.contactPhone')" align="center" prop="contactPhone" />
+        <el-table-column :label="t('tenant.table.companyName')" align="center" prop="companyName" />
+        <el-table-column :label="t('tenant.table.licenseNumber')" align="center" prop="licenseNumber" />
+        <el-table-column :label="t('tenant.table.expireTime')" align="center" prop="expireTime" width="180">
           <template #default="scope">
             <span>{{ proxy.parseTime(scope.row.expireTime, '{y}-{m}-{d}') }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="租户状态" align="center" prop="status">
+        <el-table-column :label="t('tenant.table.status')" align="center" prop="status">
           <template #default="scope">
             <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
           </template>
         </el-table-column>
-        <el-table-column width="150" label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
+        <el-table-column width="150" :label="t('tenant.table.operation')" align="center" fixed="right" class-name="small-padding fixed-width">
           <template #default="scope">
-            <el-tooltip content="修改" placement="top">
+            <el-tooltip :content="t('tenant.tooltip.edit')" placement="top">
               <el-button v-hasPermi="['system:tenant:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
             </el-tooltip>
-            <el-tooltip content="同步套餐" placement="top">
+            <el-tooltip :content="t('tenant.tooltip.syncPackage')" placement="top">
               <el-button v-hasPermi="['system:tenant:edit']" link type="primary" icon="Refresh" @click="handleSyncTenantPackage(scope.row)">
               </el-button>
             </el-tooltip>
-            <el-tooltip content="删除" placement="top">
+            <el-tooltip :content="t('tenant.tooltip.delete')" placement="top">
               <el-button v-hasPermi="['system:tenant:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
           </template>
@@ -90,56 +90,56 @@
 
       <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
-    <!-- 添加或修改租户对话框 -->
-    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
-      <el-form ref="tenantFormRef" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="企业名称" prop="companyName">
-          <el-input v-model="form.companyName" placeholder="请输入企业名称" />
+    <!-- 添加或修改企业对话框 -->
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="900px" append-to-body>
+      <el-form ref="tenantFormRef" :model="form" :rules="rules" label-width="180px">
+        <el-form-item :label="t('tenant.form.companyName')" prop="companyName">
+          <el-input v-model="form.companyName" :placeholder="t('tenant.form.companyNamePlaceholder')" />
         </el-form-item>
-        <el-form-item label="联系人" prop="contactUserName">
-          <el-input v-model="form.contactUserName" placeholder="请输入联系人" />
+        <el-form-item :label="t('tenant.form.contactUserName')" prop="contactUserName">
+          <el-input v-model="form.contactUserName" :placeholder="t('tenant.form.contactUserNamePlaceholder')" />
         </el-form-item>
-        <el-form-item label="联系电话" prop="contactPhone">
-          <el-input v-model="form.contactPhone" placeholder="请输入联系电话" />
+        <el-form-item :label="t('tenant.form.contactPhone')" prop="contactPhone">
+          <el-input v-model="form.contactPhone" :placeholder="t('tenant.form.contactPhonePlaceholder')" />
         </el-form-item>
-        <el-form-item v-if="!form.id" label="用户名" prop="username">
-          <el-input v-model="form.username" placeholder="请输入系统用户名" maxlength="30" />
+        <el-form-item v-if="!form.id" :label="t('tenant.form.username')" prop="username">
+          <el-input v-model="form.username" :placeholder="t('tenant.form.usernamePlaceholder')" maxlength="30" />
         </el-form-item>
-        <el-form-item v-if="!form.id" label="用户密码" prop="password">
-          <el-input v-model="form.password" type="password" placeholder="请输入系统用户密码" maxlength="20" />
+        <el-form-item v-if="!form.id" :label="t('tenant.form.password')" prop="password">
+          <el-input v-model="form.password" type="password" :placeholder="t('tenant.form.passwordPlaceholder')" maxlength="20" />
         </el-form-item>
-        <el-form-item label="租户套餐" prop="packageId">
-          <el-select v-model="form.packageId" :disabled="!!form.tenantId" placeholder="请选择租户套餐" clearable style="width: 100%">
+        <el-form-item :label="t('tenant.form.packageId')" prop="packageId">
+          <el-select v-model="form.packageId" :disabled="!!form.tenantId" :placeholder="t('tenant.form.packageIdPlaceholder')" clearable style="width: 100%">
             <el-option v-for="item in packageList" :key="item.packageId" :label="item.packageName" :value="item.packageId" />
           </el-select>
         </el-form-item>
-        <el-form-item label="过期时间" prop="expireTime">
-          <el-date-picker v-model="form.expireTime" clearable type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择过期时间">
+        <el-form-item :label="t('tenant.form.expireTime')" prop="expireTime">
+          <el-date-picker v-model="form.expireTime" clearable type="datetime" value-format="YYYY-MM-DD HH:mm:ss" :placeholder="t('tenant.form.expireTimePlaceholder')">
           </el-date-picker>
         </el-form-item>
-        <el-form-item label="用户数量" prop="accountCount">
-          <el-input v-model="form.accountCount" placeholder="请输入用户数量" />
+        <el-form-item :label="t('tenant.form.accountCount')" prop="accountCount">
+          <el-input v-model="form.accountCount" :placeholder="t('tenant.form.accountCountPlaceholder')" />
         </el-form-item>
-        <el-form-item label="绑定域名" prop="domain">
-          <el-input v-model="form.domain" placeholder="请输入绑定域名" />
+        <el-form-item :label="t('tenant.form.domain')" prop="domain">
+          <el-input v-model="form.domain" :placeholder="t('tenant.form.domainPlaceholder')" />
         </el-form-item>
-        <el-form-item label="企业地址" prop="address">
-          <el-input v-model="form.address" placeholder="请输入企业地址" />
+        <el-form-item :label="t('tenant.form.address')" prop="address">
+          <el-input v-model="form.address" :placeholder="t('tenant.form.addressPlaceholder')" />
         </el-form-item>
-        <el-form-item label="企业代码" prop="licenseNumber">
-          <el-input v-model="form.licenseNumber" placeholder="请输入统一社会信用代码" />
+        <el-form-item :label="t('tenant.form.licenseNumber')" prop="licenseNumber">
+          <el-input v-model="form.licenseNumber" :placeholder="t('tenant.form.licenseNumberPlaceholder')" />
         </el-form-item>
-        <el-form-item label="企业简介" prop="intro">
-          <el-input v-model="form.intro" type="textarea" placeholder="请输入企业简介" />
+        <el-form-item :label="t('tenant.form.intro')" prop="intro">
+          <el-input v-model="form.intro" type="textarea" :placeholder="t('tenant.form.introPlaceholder')" />
         </el-form-item>
-        <el-form-item label="备注" prop="remark">
-          <el-input v-model="form.remark" placeholder="请输入备注" />
+        <el-form-item :label="t('tenant.form.remark')" prop="remark">
+          <el-input v-model="form.remark" :placeholder="t('tenant.form.remarkPlaceholder')" />
         </el-form-item>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
-          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
-          <el-button @click="cancel">取 消</el-button>
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">{{ t('tenant.button.submit') }}</el-button>
+          <el-button @click="cancel">{{ t('tenant.button.cancel') }}</el-button>
         </div>
       </template>
     </el-dialog>
@@ -162,7 +162,9 @@ import { selectTenantPackage } from '@/api/system/tenantPackage';
 import { useUserStore } from '@/store/modules/user';
 import { TenantForm, TenantQuery, TenantVO } from '@/api/system/tenant/types';
 import { TenantPkgVO } from '@/api/system/tenantPackage/types';
+import { useI18n } from 'vue-i18n';
 
+const { t } = useI18n();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
 const userStore = useUserStore();
@@ -214,18 +216,18 @@ const data = reactive<PageData<TenantForm, TenantQuery>>({
     companyName: ''
   },
   rules: {
-    id: [{ required: true, message: 'id不能为空', trigger: 'blur' }],
-    tenantId: [{ required: true, message: '租户编号不能为空', trigger: 'blur' }],
-    contactUserName: [{ required: true, message: '联系人不能为空', trigger: 'blur' }],
-    contactPhone: [{ required: true, message: '联系电话不能为空', trigger: 'blur' }],
-    companyName: [{ required: true, message: '企业名称不能为空', trigger: 'blur' }],
+    id: [{ required: true, message: t('tenant.rule.idRequired'), trigger: 'blur' }],
+    tenantId: [{ required: true, message: t('tenant.rule.tenantIdRequired'), trigger: 'blur' }],
+    contactUserName: [{ required: true, message: t('tenant.rule.contactUserNameRequired'), trigger: 'blur' }],
+    contactPhone: [{ required: true, message: t('tenant.rule.contactPhoneRequired'), trigger: 'blur' }],
+    companyName: [{ required: true, message: t('tenant.rule.companyNameRequired'), trigger: 'blur' }],
     username: [
-      { required: true, message: '用户名不能为空', trigger: 'blur' },
-      { min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
+      { required: true, message: t('tenant.rule.usernameRequired'), trigger: 'blur' },
+      { min: 2, max: 20, message: t('tenant.rule.usernameLength'), trigger: 'blur' }
     ],
     password: [
-      { required: true, message: '密码不能为空', trigger: 'blur' },
-      { min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
+      { required: true, message: t('tenant.rule.passwordRequired'), trigger: 'blur' },
+      { min: 5, max: 20, message: t('tenant.rule.passwordLength'), trigger: 'blur' }
     ]
   }
 });
@@ -247,13 +249,13 @@ const getList = async () => {
   loading.value = false;
 };
 
-// 租户套餐状态修改
+// 企业状态修改
 const handleStatusChange = async (row: TenantVO) => {
-  const text = row.status === '0' ? '启用' : '停用';
+  const text = row.status === '0' ? t('tenant.message.statusEnable') : t('tenant.message.statusDisable');
   try {
-    await proxy?.$modal.confirm('确认要"' + text + '""' + row.companyName + '"租户吗?');
+    await proxy?.$modal.confirm(t('tenant.message.statusChangeConfirm', { text, name: row.companyName }));
     await changeTenantStatus(row.id, row.tenantId, row.status);
-    proxy?.$modal.msgSuccess(text + '成功');
+    proxy?.$modal.msgSuccess(t('tenant.message.statusChangeSuccess', { text }));
   } catch {
     row.status = row.status === '0' ? '1' : '0';
   }
@@ -295,7 +297,7 @@ const handleAdd = () => {
   reset();
   getTenantPackage();
   dialog.visible = true;
-  dialog.title = '添加租户';
+  dialog.title = t('tenant.dialog.add');
 };
 
 /** 修改按钮操作 */
@@ -306,7 +308,7 @@ const handleUpdate = async (row?: TenantVO) => {
   const res = await getTenant(_id);
   Object.assign(form.value, res.data);
   dialog.visible = true;
-  dialog.title = '修改租户';
+  dialog.title = t('tenant.dialog.edit');
 };
 
 /** 提交按钮 */
@@ -319,7 +321,7 @@ const submitForm = () => {
       } else {
         await addTenant(form.value).finally(() => (buttonLoading.value = false));
       }
-      proxy?.$modal.msgSuccess('操作成功');
+      proxy?.$modal.msgSuccess(t('tenant.message.operationSuccess'));
       dialog.visible = false;
       await getList();
     }
@@ -329,21 +331,21 @@ const submitForm = () => {
 /** 删除按钮操作 */
 const handleDelete = async (row?: TenantVO) => {
   const _ids = row?.id || ids.value;
-  await proxy?.$modal.confirm('是否确认删除租户编号为"' + _ids + '"的数据项?');
+  await proxy?.$modal.confirm(t('tenant.message.deleteConfirm', { ids: _ids }));
   loading.value = true;
   await delTenant(_ids).finally(() => (loading.value = false));
   await getList();
-  proxy?.$modal.msgSuccess('删除成功');
+  proxy?.$modal.msgSuccess(t('tenant.message.deleteSuccess'));
 };
 
-/** 同步租户套餐按钮操作 */
+/** 同步企业套餐按钮操作 */
 const handleSyncTenantPackage = async (row: TenantVO) => {
   try {
-    await proxy?.$modal.confirm('是否确认同步租户套餐租户编号为"' + row.tenantId + '"的数据项?');
+    await proxy?.$modal.confirm(t('tenant.message.syncPackageConfirm', { tenantId: row.tenantId }));
     loading.value = true;
     await syncTenantPackage(row.tenantId, row.packageId);
     await getList();
-    proxy?.$modal.msgSuccess('同步成功');
+    proxy?.$modal.msgSuccess(t('tenant.message.syncSuccess'));
   } catch {
     return;
   } finally {
@@ -362,16 +364,16 @@ const handleExport = () => {
   );
 };
 
-/**同步租户字典*/
+/**同步企业字典*/
 const handleSyncTenantDict = async () => {
-  await proxy?.$modal.confirm('确认要同步所有租户字典吗?');
+  await proxy?.$modal.confirm(t('tenant.message.syncDictConfirm'));
   const res = await syncTenantDict();
   proxy?.$modal.msgSuccess(res.msg);
 };
 
-/**同步租户参数配置*/
+/**同步企业参数配置*/
 const handleSyncTenantConfig = async () => {
-  await proxy?.$modal.confirm('确认要同步所有租户参数配置吗?');
+  await proxy?.$modal.confirm(t('tenant.message.syncConfigConfirm'));
   const res = await syncTenantConfig();
   proxy?.$modal.msgSuccess(res.msg);
 };

+ 45 - 43
src/views/system/tenantPackage/index.vue

@@ -3,13 +3,13 @@
     <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
       <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
-          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
-            <el-form-item label="套餐名称" prop="packageName">
-              <el-input v-model="queryParams.packageName" placeholder="请输入套餐名称" clearable @keyup.enter="handleQuery" />
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="140px">
+            <el-form-item :label="t('tenantPackage.search.packageName')" prop="packageName">
+              <el-input v-model="queryParams.packageName" :placeholder="t('tenantPackage.search.packageNamePlaceholder')" clearable @keyup.enter="handleQuery" />
             </el-form-item>
             <el-form-item>
-              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+              <el-button type="primary" icon="Search" @click="handleQuery">{{ t('tenantPackage.search.search') }}</el-button>
+              <el-button icon="Refresh" @click="resetQuery">{{ t('tenantPackage.search.reset') }}</el-button>
             </el-form-item>
           </el-form>
         </el-card>
@@ -20,20 +20,20 @@
       <template #header>
         <el-row :gutter="10" class="mb8">
           <el-col :span="1.5">
-            <el-button v-hasPermi="['system:tenantPackage:add']" type="primary" plain icon="Plus" @click="handleAdd"> 新增 </el-button>
+            <el-button v-hasPermi="['system:tenantPackage:add']" type="primary" plain icon="Plus" @click="handleAdd"> {{ t('tenantPackage.button.add') }} </el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button v-hasPermi="['system:tenantPackage:edit']" type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()">
-              修改
+              {{ t('tenantPackage.button.edit') }}
             </el-button>
           </el-col>
           <el-col :span="1.5">
             <el-button v-hasPermi="['system:tenantPackage:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
-              删除
+              {{ t('tenantPackage.button.delete') }}
             </el-button>
           </el-col>
           <el-col :span="1.5">
-            <el-button v-hasPermi="['system:tenantPackage:export']" type="warning" plain icon="Download" @click="handleExport">导出 </el-button>
+            <el-button v-hasPermi="['system:tenantPackage:export']" type="warning" plain icon="Download" @click="handleExport">{{ t('tenantPackage.button.export') }} </el-button>
           </el-col>
           <right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
         </el-row>
@@ -41,20 +41,20 @@
 
       <el-table v-loading="loading" border :data="tenantPackageList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column v-if="false" label="租户套餐id" align="center" prop="packageId" />
-        <el-table-column label="套餐名称" align="center" prop="packageName" />
-        <el-table-column label="备注" align="center" prop="remark" />
-        <el-table-column label="状态" align="center" prop="status">
+        <el-table-column v-if="false" :label="t('tenantPackage.table.packageId')" align="center" prop="packageId" />
+        <el-table-column :label="t('tenantPackage.table.packageName')" align="center" prop="packageName" />
+        <el-table-column :label="t('tenantPackage.table.remark')" align="center" prop="remark" />
+        <el-table-column :label="t('tenantPackage.table.status')" align="center" prop="status">
           <template #default="scope">
             <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @click="handleStatusChange(scope.row)"></el-switch>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <el-table-column :label="t('tenantPackage.table.operation')" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
-            <el-tooltip content="修改" placement="top">
+            <el-tooltip :content="t('tenantPackage.tooltip.edit')" placement="top">
               <el-button v-hasPermi="['system:tenantPackage:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
             </el-tooltip>
-            <el-tooltip content="删除" placement="top">
+            <el-tooltip :content="t('tenantPackage.tooltip.delete')" placement="top">
               <el-button v-hasPermi="['system:tenantPackage:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
             </el-tooltip>
           </template>
@@ -64,16 +64,16 @@
       <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
     </el-card>
 
-    <!-- 添加或修改租户套餐对话框 -->
-    <el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
-      <el-form ref="tenantPackageFormRef" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="套餐名称" prop="packageName">
-          <el-input v-model="form.packageName" placeholder="请输入套餐名称" />
+    <!-- 添加或修改企业套餐对话框 -->
+    <el-dialog v-model="dialog.visible" :title="dialog.title" width="900px" append-to-body>
+      <el-form ref="tenantPackageFormRef" :model="form" :rules="rules" label-width="180px">
+        <el-form-item :label="t('tenantPackage.form.packageName')" prop="packageName">
+          <el-input v-model="form.packageName" :placeholder="t('tenantPackage.form.packageNamePlaceholder')" />
         </el-form-item>
-        <el-form-item label="关联菜单">
-          <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
-          <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选 </el-checkbox>
-          <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动 </el-checkbox>
+        <el-form-item :label="t('tenantPackage.form.relatedMenu')">
+          <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">{{ t('tenantPackage.form.expandCollapse') }}</el-checkbox>
+          <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">{{ t('tenantPackage.form.selectAll') }} </el-checkbox>
+          <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">{{ t('tenantPackage.form.parentChild') }} </el-checkbox>
           <el-tree
             ref="menuTreeRef"
             class="tree-border"
@@ -81,18 +81,18 @@
             show-checkbox
             node-key="id"
             :check-strictly="!form.menuCheckStrictly"
-            empty-text="加载中,请稍候"
+            :empty-text="t('tenantPackage.form.loading')"
             :props="{ label: 'label', children: 'children' } as any"
           ></el-tree>
         </el-form-item>
-        <el-form-item label="备注" prop="remark">
-          <el-input v-model="form.remark" placeholder="请输入备注" />
+        <el-form-item :label="t('tenantPackage.form.remark')" prop="remark">
+          <el-input v-model="form.remark" :placeholder="t('tenantPackage.form.remarkPlaceholder')" />
         </el-form-item>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
-          <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
-          <el-button @click="cancel">取 消</el-button>
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">{{ t('tenantPackage.button.submit') }}</el-button>
+          <el-button @click="cancel">{{ t('tenantPackage.button.cancel') }}</el-button>
         </div>
       </template>
     </el-dialog>
@@ -112,7 +112,9 @@ import { tenantPackageMenuTreeselect } from '@/api/system/menu';
 import { TenantPkgForm, TenantPkgQuery, TenantPkgVO } from '@/api/system/tenantPackage/types';
 import { MenuTreeOption } from '@/api/system/menu/types';
 import to from 'await-to-js';
+import { useI18n } from 'vue-i18n';
 
+const { t } = useI18n();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
 const tenantPackageList = ref<TenantPkgVO[]>([]);
@@ -151,8 +153,8 @@ const data = reactive<PageData<TenantPkgForm, TenantPkgQuery>>({
     packageName: ''
   },
   rules: {
-    packageId: [{ required: true, message: '租户套餐id不能为空', trigger: 'blur' }],
-    packageName: [{ required: true, message: '套餐名称不能为空', trigger: 'blur' }]
+    packageId: [{ required: true, message: t('tenantPackage.rule.packageIdRequired'), trigger: 'blur' }],
+    packageName: [{ required: true, message: t('tenantPackage.rule.packageNameRequired'), trigger: 'blur' }]
   }
 });
 
@@ -170,14 +172,14 @@ const getMenuAllCheckedKeys = (): any => {
   return checkedKeys;
 };
 
-/** 根据租户套餐ID查询菜单树结构 */
+/** 根据企业套餐ID查询菜单树结构 */
 const getPackageMenuTreeselect = async (packageId: string | number) => {
   const res = await tenantPackageMenuTreeselect(packageId);
   menuOptions.value = res.data.menus;
   return Promise.resolve(res);
 };
 
-/** 查询租户套餐列表 */
+/** 查询企业套餐列表 */
 const getList = async () => {
   loading.value = true;
   const res = await listTenantPackage(queryParams.value);
@@ -186,15 +188,15 @@ const getList = async () => {
   loading.value = false;
 };
 
-// 租户套餐状态修改
+// 企业套餐状态修改
 const handleStatusChange = async (row: TenantPkgVO) => {
-  const text = row.status === '0' ? '启用' : '停用';
-  const [err] = await to(proxy?.$modal.confirm('确认要"' + text + '""' + row.packageName + '"套餐吗?') as Promise<any>);
+  const text = row.status === '0' ? t('tenantPackage.message.statusEnable') : t('tenantPackage.message.statusDisable');
+  const [err] = await to(proxy?.$modal.confirm(t('tenantPackage.message.statusChangeConfirm', { text, name: row.packageName })) as Promise<any>);
   if (err) {
     row.status = row.status === '0' ? '1' : '0';
   } else {
     await changePackageStatus(row.packageId, row.status);
-    proxy?.$modal.msgSuccess(text + '成功');
+    proxy?.$modal.msgSuccess(t('tenantPackage.message.statusChangeSuccess', { text }));
   }
 };
 
@@ -263,7 +265,7 @@ const handleAdd = async () => {
   reset();
   await getPackageMenuTreeselect(0);
   dialog.visible = true;
-  dialog.title = '添加租户套餐';
+  dialog.title = t('tenantPackage.dialog.add');
 };
 
 /** 修改按钮操作 */
@@ -274,7 +276,7 @@ const handleUpdate = async (row?: TenantPkgVO) => {
   form.value = response.data;
   const res = await getPackageMenuTreeselect(_packageId);
   dialog.visible = true;
-  dialog.title = '修改租户套餐';
+  dialog.title = t('tenantPackage.dialog.edit');
   res.data.checkedKeys.forEach((v) => {
     nextTick(() => {
       menuTreeRef.value?.setChecked(v, true, false);
@@ -293,7 +295,7 @@ const submitForm = () => {
       } else {
         await addTenantPackage(form.value).finally(() => (buttonLoading.value = false));
       }
-      proxy?.$modal.msgSuccess('操作成功');
+      proxy?.$modal.msgSuccess(t('tenantPackage.message.operationSuccess'));
       dialog.visible = false;
       await getList();
     }
@@ -303,13 +305,13 @@ const submitForm = () => {
 /** 删除按钮操作 */
 const handleDelete = async (row?: TenantPkgVO) => {
   const _packageIds = row?.packageId || ids.value;
-  await proxy?.$modal.confirm('是否确认删除租户套餐编号为"' + _packageIds + '"的数据项?').finally(() => {
+  await proxy?.$modal.confirm(t('tenantPackage.message.deleteConfirm', { ids: _packageIds })).finally(() => {
     loading.value = false;
   });
   await delTenantPackage(_packageIds);
   loading.value = true;
   await getList();
-  proxy?.$modal.msgSuccess('删除成功');
+  proxy?.$modal.msgSuccess(t('tenantPackage.message.deleteSuccess'));
 };
 
 /** 导出按钮操作 */

+ 15 - 24
src/views/system/user/authRole.vue

@@ -1,16 +1,16 @@
 <template>
   <div class="p-2">
     <div class="panel">
-      <h4 class="panel-title">基本信息</h4>
+      <h4 class="panel-title">{{ t('user.authRole.basicInfo') }}</h4>
       <el-form :model="form" :inline="true">
         <el-row :gutter="10">
           <el-col :span="2.5">
-            <el-form-item label="用户昵称" prop="nickName">
+            <el-form-item :label="t('user.authRole.nickName')" prop="nickName">
               <el-input v-model="form.nickName" disabled />
             </el-form-item>
           </el-col>
           <el-col :span="2.5">
-            <el-form-item label="登录账号" prop="userName">
+            <el-form-item :label="t('user.authRole.userName')" prop="userName">
               <el-input v-model="form.userName" disabled />
             </el-form-item>
           </el-col>
@@ -18,7 +18,7 @@
       </el-form>
     </div>
     <div class="panel">
-      <h4 class="panel-title">角色信息</h4>
+      <h4 class="panel-title">{{ t('user.authRole.roleInfo') }}</h4>
       <div>
         <el-table
           ref="tableRef"
@@ -29,16 +29,16 @@
           @row-click="clickRow"
           @selection-change="handleSelectionChange"
         >
-          <el-table-column label="序号" width="55" type="index" align="center">
+          <el-table-column :label="t('user.authRole.serialNumber')" width="55" type="index" align="center">
             <template #default="scope">
               <span>{{ (pageNum - 1) * pageSize + scope.$index + 1 }}</span>
             </template>
           </el-table-column>
           <el-table-column type="selection" :reserve-selection="true" :selectable="checkSelectable" width="55"></el-table-column>
-          <el-table-column label="角色编号" align="center" prop="roleId" />
-          <el-table-column label="角色名称" align="center" prop="roleName" />
-          <el-table-column label="权限字符" align="center" prop="roleKey" />
-          <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+          <el-table-column :label="t('user.authRole.roleId')" align="center" prop="roleId" />
+          <el-table-column :label="t('user.authRole.roleName')" align="center" prop="roleName" />
+          <el-table-column :label="t('user.authRole.roleKey')" align="center" prop="roleKey" />
+          <el-table-column :label="t('user.authRole.createTime')" align="center" prop="createTime" width="180">
             <template #default="scope">
               <span>{{ proxy.parseTime(scope.row.createTime) }}</span>
             </template>
@@ -46,8 +46,8 @@
         </el-table>
         <pagination v-show="total > 0" v-model:page="pageNum" v-model:limit="pageSize" :total="total" />
         <div style="text-align: center; margin-left: -120px; margin-top: 30px">
-          <el-button type="primary" @click="submitForm()">提交</el-button>
-          <el-button @click="close()">返回</el-button>
+          <el-button type="primary" @click="submitForm()">{{ t('user.authRole.submit') }}</el-button>
+          <el-button @click="close()">{{ t('user.authRole.back') }}</el-button>
         </div>
         <div></div>
       </div>
@@ -61,9 +61,11 @@ import { getAuthRole, updateAuthRole } from '@/api/system/user';
 import { UserForm } from '@/api/system/user/types';
 import { RouteLocationNormalized } from 'vue-router';
 import { parseTime } from '@/utils/ruoyi';
+import { useI18n } from 'vue-i18n';
 
 const route = useRoute();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { t } = useI18n();
 
 const loading = ref(true);
 const total = ref(0);
@@ -100,25 +102,14 @@ const checkSelectable = (row: RoleVO): boolean => {
 };
 /** 关闭按钮 */
 const close = () => {
-  const obj: RouteLocationNormalized = {
-    fullPath: '',
-    hash: '',
-    matched: [],
-    meta: undefined,
-    name: undefined,
-    params: undefined,
-    query: undefined,
-    redirectedFrom: undefined,
-    path: '/system/user'
-  };
-  proxy?.$tab.closeOpenPage(obj);
+  proxy?.$tab.closeOpenPage({ path: '/system/user' });
 };
 /** 提交按钮 */
 const submitForm = async () => {
   const userId = form.value.userId;
   const rIds = roleIds.value.join(',');
   await updateAuthRole({ userId: userId as string, roleIds: rIds });
-  proxy?.$modal.msgSuccess('授权成功');
+  proxy?.$modal.msgSuccess(t('user.authRole.authSuccess'));
   close();
 };
 

+ 100 - 98
src/views/system/user/index.vue

@@ -4,7 +4,7 @@
       <!-- 部门树 -->
       <el-col :lg="4" :xs="24" style="">
         <el-card shadow="hover">
-          <el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
+          <el-input v-model="deptName" :placeholder="t('user.search.deptPlaceholder')" prefix-icon="Search" clearable />
           <el-tree
             ref="deptTreeRef"
             class="mt-2"
@@ -23,36 +23,36 @@
         <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
           <div v-show="showSearch" class="mb-[10px]">
             <el-card shadow="hover">
-              <el-form ref="queryFormRef" :model="queryParams" :inline="true">
-                <el-form-item label="用户名称" prop="userName">
-                  <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
+              <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="140px">
+                <el-form-item :label="t('user.search.userName')" prop="userName">
+                  <el-input v-model="queryParams.userName" :placeholder="t('user.search.userNamePlaceholder')" clearable @keyup.enter="handleQuery" />
                 </el-form-item>
-                <el-form-item label="用户昵称" prop="nickName">
-                  <el-input v-model="queryParams.nickName" placeholder="请输入用户昵称" clearable @keyup.enter="handleQuery" />
+                <el-form-item :label="t('user.search.nickName')" prop="nickName">
+                  <el-input v-model="queryParams.nickName" :placeholder="t('user.search.nickNamePlaceholder')" clearable @keyup.enter="handleQuery" />
                 </el-form-item>
-                <el-form-item label="手机号码" prop="phonenumber">
-                  <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" />
+                <el-form-item :label="t('user.search.phonenumber')" prop="phonenumber">
+                  <el-input v-model="queryParams.phonenumber" :placeholder="t('user.search.phonenumberPlaceholder')" clearable @keyup.enter="handleQuery" />
                 </el-form-item>
 
-                <el-form-item label="状态" prop="status">
-                  <el-select v-model="queryParams.status" placeholder="用户状态" clearable>
+                <el-form-item :label="t('user.search.status')" prop="status">
+                  <el-select v-model="queryParams.status" :placeholder="t('user.search.statusPlaceholder')" clearable>
                     <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
                   </el-select>
                 </el-form-item>
-                <el-form-item label="创建时间" style="width: 308px">
+                <el-form-item :label="t('user.search.createTime')" style="width: 308px">
                   <el-date-picker
                     v-model="dateRange"
                     value-format="YYYY-MM-DD HH:mm:ss"
                     type="daterange"
                     range-separator="-"
-                    start-placeholder="开始日期"
-                    end-placeholder="结束日期"
+                    :start-placeholder="t('user.search.startDate')"
+                    :end-placeholder="t('user.search.endDate')"
                     :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
                   ></el-date-picker>
                 </el-form-item>
                 <el-form-item>
-                  <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
-                  <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+                  <el-button type="primary" icon="Search" @click="handleQuery">{{ t('user.search.search') }}</el-button>
+                  <el-button icon="Refresh" @click="resetQuery">{{ t('user.search.reset') }}</el-button>
                 </el-form-item>
               </el-form>
             </el-card>
@@ -63,30 +63,30 @@
           <template #header>
             <el-row :gutter="10">
               <el-col :span="1.5">
-                <el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
+                <el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()">{{ t('user.button.add') }}</el-button>
               </el-col>
               <el-col :span="1.5">
                 <el-button v-has-permi="['system:user:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
-                  修改
+                  {{ t('user.button.edit') }}
                 </el-button>
               </el-col>
               <el-col :span="1.5">
                 <el-button v-has-permi="['system:user:remove']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
-                  删除
+                  {{ t('user.button.delete') }}
                 </el-button>
               </el-col>
               <el-col :span="1.5">
                 <el-dropdown class="mt-[1px]">
                   <el-button plain type="info">
-                    更多
+                    {{ t('user.button.more') }}
                     <el-icon class="el-icon--right"><arrow-down /></el-icon
                   ></el-button>
                   <template #dropdown>
                     <el-dropdown-menu>
-                      <el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item>
+                      <el-dropdown-item icon="Download" @click="importTemplate">{{ t('user.button.downloadTemplate') }}</el-dropdown-item>
                       <!-- 注意 由于el-dropdown-item标签是延迟加载的 所以v-has-permi自定义标签不生效 需要使用v-if调用方法执行 -->
-                      <el-dropdown-item v-if="checkPermi(['system:user:import'])" icon="Top" @click="handleImport">导入数据</el-dropdown-item>
-                      <el-dropdown-item v-if="checkPermi(['system:user:export'])" icon="Download" @click="handleExport">导出数据</el-dropdown-item>
+                      <el-dropdown-item v-if="checkPermi(['system:user:import'])" icon="Top" @click="handleImport">{{ t('user.button.import') }}</el-dropdown-item>
+                      <el-dropdown-item v-if="checkPermi(['system:user:export'])" icon="Download" @click="handleExport">{{ t('user.button.export') }}</el-dropdown-item>
                     </el-dropdown-menu>
                   </template>
                 </el-dropdown>
@@ -97,37 +97,37 @@
 
           <el-table v-loading="loading" border :data="userList" @selection-change="handleSelectionChange">
             <el-table-column type="selection" width="50" align="center" />
-            <el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" />
-            <el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
-            <el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" />
-            <el-table-column v-if="columns[3].visible" key="deptName" label="部门" align="center" prop="deptName" :show-overflow-tooltip="true" />
-            <el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center" prop="phonenumber" width="120" />
-            <el-table-column v-if="columns[5].visible" key="status" label="状态" align="center">
+            <el-table-column v-if="columns[0].visible" key="userId" :label="t('user.table.userId')" align="center" prop="userId" />
+            <el-table-column v-if="columns[1].visible" key="userName" :label="t('user.table.userName')" align="center" prop="userName" :show-overflow-tooltip="true" />
+            <el-table-column v-if="columns[2].visible" key="nickName" :label="t('user.table.nickName')" align="center" prop="nickName" :show-overflow-tooltip="true" />
+            <el-table-column v-if="columns[3].visible" key="deptName" :label="t('user.table.deptName')" align="center" prop="deptName" :show-overflow-tooltip="true" />
+            <el-table-column v-if="columns[4].visible" key="phonenumber" :label="t('user.table.phonenumber')" align="center" prop="phonenumber" width="120" />
+            <el-table-column v-if="columns[5].visible" key="status" :label="t('user.table.status')" align="center">
               <template #default="scope">
                 <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
               </template>
             </el-table-column>
 
-            <el-table-column v-if="columns[6].visible" label="创建时间" align="center" prop="createTime" width="160">
+            <el-table-column v-if="columns[6].visible" :label="t('user.table.createTime')" align="center" prop="createTime" width="160">
               <template #default="scope">
                 <span>{{ scope.row.createTime }}</span>
               </template>
             </el-table-column>
 
-            <el-table-column label="操作" fixed="right" width="180" class-name="small-padding fixed-width">
+            <el-table-column :label="t('user.table.operation')" fixed="right" width="180" class-name="small-padding fixed-width">
               <template #default="scope">
-                <el-tooltip v-if="scope.row.userId !== 1" content="修改" placement="top">
+                <el-tooltip v-if="scope.row.userId !== 1" :content="t('user.button.edit')" placement="top">
                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
                 </el-tooltip>
-                <el-tooltip v-if="scope.row.userId !== 1" content="删除" placement="top">
+                <el-tooltip v-if="scope.row.userId !== 1" :content="t('user.button.delete')" placement="top">
                   <el-button v-hasPermi="['system:user:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
                 </el-tooltip>
 
-                <el-tooltip v-if="scope.row.userId !== 1" content="重置密码" placement="top">
+                <el-tooltip v-if="scope.row.userId !== 1" :content="t('user.button.resetPwd')" placement="top">
                   <el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key" @click="handleResetPwd(scope.row)"></el-button>
                 </el-tooltip>
 
-                <el-tooltip v-if="scope.row.userId !== 1" content="分配角色" placement="top">
+                <el-tooltip v-if="scope.row.userId !== 1" :content="t('user.button.assignRole')" placement="top">
                   <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)"></el-button>
                 </el-tooltip>
               </template>
@@ -146,22 +146,22 @@
     </el-row>
 
     <!-- 添加或修改用户配置对话框 -->
-    <el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="600px" append-to-body @close="closeDialog">
-      <el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
+    <el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="900px" append-to-body @close="closeDialog">
+      <el-form ref="userFormRef" :model="form" :rules="rules" label-width="180px">
         <el-row>
           <el-col :span="12">
-            <el-form-item label="用户昵称" prop="nickName">
-              <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
+            <el-form-item :label="t('user.form.nickName')" prop="nickName">
+              <el-input v-model="form.nickName" :placeholder="t('user.form.nickNamePlaceholder')" maxlength="30" />
             </el-form-item>
           </el-col>
           <el-col :span="12" v-if="form.userId == null || form.userId != useUserStore().userId">
-            <el-form-item label="归属部门" prop="deptId">
+            <el-form-item :label="t('user.form.deptId')" prop="deptId">
               <el-tree-select
                 v-model="form.deptId"
                 :data="enabledDeptOptions"
                 :props="{ value: 'id', label: 'label', children: 'children' } as any"
                 value-key="id"
-                placeholder="请选择归属部门"
+                :placeholder="t('user.form.deptIdPlaceholder')"
                 check-strictly
                 @change="handleDeptChange"
               />
@@ -170,38 +170,38 @@
         </el-row>
         <el-row>
           <el-col :span="12">
-            <el-form-item label="手机号码" prop="phonenumber">
-              <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
+            <el-form-item :label="t('user.form.phonenumber')" prop="phonenumber">
+              <el-input v-model="form.phonenumber" :placeholder="t('user.form.phonenumberPlaceholder')" maxlength="11" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="邮箱" prop="email">
-              <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
+            <el-form-item :label="t('user.form.email')" prop="email">
+              <el-input v-model="form.email" :placeholder="t('user.form.emailPlaceholder')" maxlength="50" />
             </el-form-item>
           </el-col>
         </el-row>
         <el-row>
           <el-col :span="12">
-            <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
-              <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
+            <el-form-item v-if="form.userId == undefined" :label="t('user.form.userName')" prop="userName">
+              <el-input v-model="form.userName" :placeholder="t('user.form.userNamePlaceholder')" maxlength="30" />
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
-              <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
+            <el-form-item v-if="form.userId == undefined" :label="t('user.form.password')" prop="password">
+              <el-input v-model="form.password" :placeholder="t('user.form.passwordPlaceholder')" type="password" maxlength="20" show-password />
             </el-form-item>
           </el-col>
         </el-row>
         <el-row>
           <el-col :span="12">
-            <el-form-item label="用户性别">
-              <el-select v-model="form.sex" placeholder="请选择">
+            <el-form-item :label="t('user.form.sex')">
+              <el-select v-model="form.sex" :placeholder="t('user.form.selectPlaceholder')">
                 <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="状态">
+            <el-form-item :label="t('user.form.status')">
               <el-radio-group v-model="form.status">
                 <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
               </el-radio-group>
@@ -210,8 +210,8 @@
         </el-row>
         <el-row>
           <el-col :span="12" v-if="form.userId == null || form.userId != useUserStore().userId">
-            <el-form-item label="岗位">
-              <el-select v-model="form.postIds" multiple placeholder="请选择">
+            <el-form-item :label="t('user.form.postIds')">
+              <el-select v-model="form.postIds" multiple :placeholder="t('user.form.postIdsPlaceholder')">
                 <el-option
                   v-for="item in postOptions"
                   :key="item.postId"
@@ -223,8 +223,8 @@
             </el-form-item>
           </el-col>
           <el-col :span="12" v-if="form.userId == null || form.userId != useUserStore().userId">
-            <el-form-item label="角色" prop="roleIds">
-              <el-select v-model="form.roleIds" filterable multiple placeholder="请选择">
+            <el-form-item :label="t('user.form.roleIds')" prop="roleIds">
+              <el-select v-model="form.roleIds" filterable multiple :placeholder="t('user.form.roleIdsPlaceholder')">
                 <el-option
                   v-for="item in roleOptions"
                   :key="item.roleId"
@@ -238,22 +238,22 @@
         </el-row>
         <el-row>
           <el-col :span="24">
-            <el-form-item label="备注">
-              <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
+            <el-form-item :label="t('user.form.remark')">
+              <el-input v-model="form.remark" type="textarea" :placeholder="t('user.form.remarkPlaceholder')"></el-input>
             </el-form-item>
           </el-col>
         </el-row>
       </el-form>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">确 定</el-button>
-          <el-button @click="cancel()">取 消</el-button>
+          <el-button type="primary" @click="submitForm">{{ t('user.button.submit') }}</el-button>
+          <el-button @click="cancel()">{{ t('user.button.cancel') }}</el-button>
         </div>
       </template>
     </el-dialog>
 
     <!-- 用户导入对话框 -->
-    <el-dialog v-model="upload.open" :title="upload.title" width="400px" append-to-body>
+    <el-dialog v-model="upload.open" :title="upload.title" width="550px" append-to-body>
       <el-upload
         ref="uploadRef"
         :limit="1"
@@ -269,19 +269,19 @@
         <el-icon class="el-icon--upload">
           <i-ep-upload-filled />
         </el-icon>
-        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+        <div class="el-upload__text" v-html="t('user.upload.dragText')"></div>
         <template #tip>
           <div class="text-center el-upload__tip">
-            <div class="el-upload__tip"><el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据</div>
-            <span>仅允许导入xls、xlsx格式文件。</span>
-            <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
+            <div class="el-upload__tip"><el-checkbox v-model="upload.updateSupport" />{{ t('user.upload.updateSupport') }}</div>
+            <span>{{ t('user.upload.fileType') }}</span>
+            <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">{{ t('user.upload.downloadTemplate') }}</el-link>
           </div>
         </template>
       </el-upload>
       <template #footer>
         <div class="dialog-footer">
-          <el-button type="primary" @click="submitFileForm">确 定</el-button>
-          <el-button @click="upload.open = false">取 消</el-button>
+          <el-button type="primary" @click="submitFileForm">{{ t('user.button.submit') }}</el-button>
+          <el-button @click="upload.open = false">{{ t('user.button.cancel') }}</el-button>
         </div>
       </template>
     </el-dialog>
@@ -299,9 +299,11 @@ import { to } from 'await-to-js';
 import { optionselect } from '@/api/system/post';
 import { checkPermi } from '@/utils/permission';
 import { useUserStore } from '@/store/modules/user';
+import { useI18n } from 'vue-i18n';
 
 const router = useRouter();
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { t } = useI18n();
 const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex'));
 const userList = ref<UserVO[]>();
 const loading = ref(true);
@@ -334,13 +336,13 @@ const upload = reactive<ImportOption>({
 });
 // 列显隐信息
 const columns = ref<FieldOption[]>([
-  { key: 0, label: `用户编号`, visible: false, children: [] },
-  { key: 1, label: `用户名称`, visible: true, children: [] },
-  { key: 2, label: `用户昵称`, visible: true, children: [] },
-  { key: 3, label: `部门`, visible: true, children: [] },
-  { key: 4, label: `手机号码`, visible: true, children: [] },
-  { key: 5, label: `状态`, visible: true, children: [] },
-  { key: 6, label: `创建时间`, visible: true, children: [] }
+  { key: 0, label: t('user.table.userId'), visible: false, children: [] },
+  { key: 1, label: t('user.table.userName'), visible: true, children: [] },
+  { key: 2, label: t('user.table.nickName'), visible: true, children: [] },
+  { key: 3, label: t('user.table.deptName'), visible: true, children: [] },
+  { key: 4, label: t('user.table.phonenumber'), visible: true, children: [] },
+  { key: 5, label: t('user.table.status'), visible: true, children: [] },
+  { key: 6, label: t('user.table.createTime'), visible: true, children: [] }
 ]);
 
 const deptTreeRef = ref<ElTreeInstance>();
@@ -382,40 +384,40 @@ const initData: PageData<UserForm, UserQuery> = {
   },
   rules: {
     userName: [
-      { required: true, message: '用户名称不能为空', trigger: 'blur' },
+      { required: true, message: t('user.rule.userNameRequired'), trigger: 'blur' },
       {
         min: 2,
         max: 20,
-        message: '用户名称长度必须介于 2 和 20 之间',
+        message: t('user.rule.userNameLength'),
         trigger: 'blur'
       }
     ],
-    nickName: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
+    nickName: [{ required: true, message: t('user.rule.nickNameRequired'), trigger: 'blur' }],
     password: [
-      { required: true, message: '用户密码不能为空', trigger: 'blur' },
+      { required: true, message: t('user.rule.passwordRequired'), trigger: 'blur' },
       {
         min: 5,
         max: 20,
-        message: '用户密码长度必须介于 5 和 20 之间',
+        message: t('user.rule.passwordLength'),
         trigger: 'blur'
       },
-      { pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\ |', trigger: 'blur' }
+      { pattern: /^[^<>"'|\\]+$/, message: t('user.rule.passwordPattern'), trigger: 'blur' }
     ],
     email: [
       {
         type: 'email',
-        message: '请输入正确的邮箱地址',
+        message: t('user.rule.emailFormat'),
         trigger: ['blur', 'change']
       }
     ],
     phonenumber: [
       {
         pattern: /^1[3456789][0-9]\d{8}$/,
-        message: '请输入正确的手机号码',
+        message: t('user.rule.phonenumberFormat'),
         trigger: 'blur'
       }
     ],
-    roleIds: [{ required: true, message: '用户角色不能为空', trigger: 'blur' }]
+    roleIds: [{ required: true, message: t('user.rule.roleIdsRequired'), trigger: 'blur' }]
   }
 };
 const data = reactive<PageData<UserForm, UserQuery>>(initData);
@@ -490,21 +492,21 @@ const resetQuery = () => {
 /** 删除按钮操作 */
 const handleDelete = async (row?: UserVO) => {
   const userIds = row?.userId || ids.value;
-  const [err] = await to(proxy?.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?') as any);
+  const [err] = await to(proxy?.$modal.confirm(t('user.message.deleteConfirm', { ids: userIds })) as any);
   if (!err) {
     await api.delUser(userIds);
     await getList();
-    proxy?.$modal.msgSuccess('删除成功');
+    proxy?.$modal.msgSuccess(t('user.message.deleteSuccess'));
   }
 };
 
 /** 用户状态修改  */
 const handleStatusChange = async (row: UserVO) => {
-  const text = row.status === '0' ? '启用' : '停用';
+  const text = row.status === '0' ? t('user.message.statusEnable') : t('user.message.statusDisable');
   try {
-    await proxy?.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?');
+    await proxy?.$modal.confirm(t('user.message.statusChangeConfirm', { text, userName: row.userName }));
     await api.changeUserStatus(row.userId, row.status);
-    proxy?.$modal.msgSuccess(text + '成功');
+    proxy?.$modal.msgSuccess(t('user.message.statusChangeSuccess', { text }));
   } catch (err) {
     row.status = row.status === '0' ? '1' : '0';
   }
@@ -518,22 +520,22 @@ const handleAuthRole = (row: UserVO) => {
 /** 重置密码按钮操作 */
 const handleResetPwd = async (row: UserVO) => {
   const [err, res] = await to(
-    ElMessageBox.prompt('请输入"' + row.userName + '"的新密码', '提示', {
-      confirmButtonText: '确定',
-      cancelButtonText: '取消',
+    ElMessageBox.prompt(t('user.message.resetPwdText', { userName: row.userName }), t('user.message.resetPwdTitle'), {
+      confirmButtonText: t('user.message.confirmButton'),
+      cancelButtonText: t('user.message.cancelButton'),
       closeOnClickModal: false,
       inputPattern: /^.{5,20}$/,
-      inputErrorMessage: '用户密码长度必须介于 5 和 20 之间',
+      inputErrorMessage: t('user.message.resetPwdLengthError'),
       inputValidator: (value) => {
         if (/<|>|"|'|\||\\/.test(value)) {
-          return '不能包含非法字符:< > " \' \\ |';
+          return t('user.message.resetPwdPatternError');
         }
       }
     })
   );
   if (!err && res) {
     await api.resetUserPwd(row.userId, res.value);
-    proxy?.$modal.msgSuccess('修改成功,新密码是:' + res.value);
+    proxy?.$modal.msgSuccess(t('user.message.resetPwdSuccess', { password: res.value }));
   }
 };
 
@@ -546,7 +548,7 @@ const handleSelectionChange = (selection: UserVO[]) => {
 
 /** 导入按钮操作 */
 const handleImport = () => {
-  upload.title = '用户导入';
+  upload.title = t('user.dialog.import');
   upload.open = true;
 };
 /** 导出按钮操作 */
@@ -573,7 +575,7 @@ const handleFileSuccess = (response: any, file: UploadFile) => {
   upload.open = false;
   upload.isUploading = false;
   uploadRef.value?.handleRemove(file);
-  ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + '</div>', '导入结果', {
+  ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + '</div>', t('user.dialog.importResult'), {
     dangerouslyUseHTMLString: true
   });
   getList();
@@ -600,7 +602,7 @@ const handleAdd = async () => {
   reset();
   const { data } = await api.getUser();
   dialog.visible = true;
-  dialog.title = '新增用户';
+  dialog.title = t('user.dialog.add');
   postOptions.value = data.posts;
   roleOptions.value = data.roles;
   form.value.password = initPassword.value.toString();
@@ -612,7 +614,7 @@ const handleUpdate = async (row?: UserForm) => {
   const userId = row?.userId || ids.value[0];
   const { data } = await api.getUser(userId);
   dialog.visible = true;
-  dialog.title = '修改用户';
+  dialog.title = t('user.dialog.edit');
   Object.assign(form.value, data.user);
   postOptions.value = data.posts;
   roleOptions.value = Array.from(
@@ -638,7 +640,7 @@ const submitForm = () => {
       } else {
         await api.addUser(form.value);
       }
-      proxy?.$modal.msgSuccess('操作成功');
+      proxy?.$modal.msgSuccess(t('user.message.operationSuccess'));
       dialog.visible = false;
       await getList();
     }