Przeglądaj źródła

中英文切换翻译

pm 5 miesięcy temu
rodzic
commit
3f6d4d063e

+ 1 - 0
package.json

@@ -66,6 +66,7 @@
     "vue-count-to": "1.0.13",
     "vue-count-to": "1.0.13",
     "vue-cropper": "0.5.5",
     "vue-cropper": "0.5.5",
     "vue-form-generator": "^2.3.4",
     "vue-form-generator": "^2.3.4",
+    "vue-i18n": "^8.28.2",
     "vue-meta": "2.4.0",
     "vue-meta": "2.4.0",
     "vue-plugin-hiprint": "^0.0.54-fix",
     "vue-plugin-hiprint": "^0.0.54-fix",
     "vue-router": "3.4.9",
     "vue-router": "3.4.9",

+ 56 - 0
src/components/LangSelect/index.vue

@@ -0,0 +1,56 @@
+<template>
+  <el-dropdown class="international right-menu-item hover-effect" trigger="click" @command="handleSetLanguage">
+    <div>
+      <svg-icon class-name="international-icon" icon-class="language" />
+    </div>
+    <el-dropdown-menu slot="dropdown">
+      <el-dropdown-item :disabled="language === 'zh'" command="zh">
+        <span>中文</span>
+      </el-dropdown-item>
+      <el-dropdown-item :disabled="language === 'en'" command="en">
+        <span>English</span>
+      </el-dropdown-item>
+    </el-dropdown-menu>
+  </el-dropdown>
+</template>
+
+<script>
+export default {
+  name: 'LangSelect',
+  computed: {
+    language() {
+      return this.$store.getters.language
+    }
+  },
+  methods: {
+    handleSetLanguage(lang) {
+      this.$store.dispatch('i18n/setLanguage', lang)
+      this.$i18n.locale = lang
+      // 如果是登录页面,不需要刷新,直接更新即可
+      if (this.$route.path === '/login' || this.$route.path === '/register') {
+        // 登录页面直接更新,不刷新
+        this.$message({
+          message: lang === 'zh' ? '切换语言成功' : 'Switch Language Success',
+          type: 'success'
+        })
+      } else {
+        // 其他页面刷新以应用语言更改
+        this.$message({
+          message: lang === 'zh' ? '切换语言成功' : 'Switch Language Success',
+          type: 'success'
+        })
+        this.$router.go(0)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.international-icon {
+  font-size: 20px;
+  cursor: pointer;
+  vertical-align: -5px!important;
+}
+</style>
+

+ 86 - 0
src/components/LangSwitch/index.vue

@@ -0,0 +1,86 @@
+<template>
+  <div class="lang-switch">
+    <span class="lang-text" :class="{ active: language === 'zh' }">中</span>
+    <el-switch
+      v-model="switchValue"
+      :active-text="''"
+      :inactive-text="''"
+      active-color="#409EFF"
+      inactive-color="#C0CCDA"
+      @change="handleLanguageChange"
+    />
+    <span class="lang-text" :class="{ active: language === 'en' }">EN</span>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'LangSwitch',
+  computed: {
+    language() {
+      return this.$store.getters.language
+    },
+    switchValue: {
+      get() {
+        return this.language === 'en'
+      },
+      set(val) {
+        // 这个 setter 不会被直接调用,因为我们在 @change 中处理
+      }
+    }
+  },
+  methods: {
+    handleLanguageChange(val) {
+      const lang = val ? 'en' : 'zh'
+      this.$store.dispatch('i18n/setLanguage', lang)
+      this.$i18n.locale = lang
+      // 如果是登录页面,不需要刷新,直接更新即可
+      if (this.$route.path === '/login' || this.$route.path === '/register') {
+        // 登录页面直接更新,不刷新
+      } else {
+        // 其他页面刷新以应用语言更改
+        this.$router.go(0)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.lang-switch {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  background: rgba(255, 255, 255, 0.95);
+  padding: 6px 12px;
+  border-radius: 20px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+  
+  .lang-text {
+    font-size: 14px;
+    font-weight: 500;
+    color: #909399;
+    transition: color 0.3s;
+    min-width: 20px;
+    text-align: center;
+    
+    &.active {
+      color: #409EFF;
+      font-weight: 600;
+    }
+  }
+  
+  ::v-deep .el-switch {
+    .el-switch__core {
+      width: 44px;
+      height: 22px;
+      
+      &::after {
+        width: 18px;
+        height: 18px;
+      }
+    }
+  }
+}
+</style>
+

+ 38 - 0
src/i18n/index.js

@@ -0,0 +1,38 @@
+import Vue from 'vue'
+import VueI18n from 'vue-i18n'
+import Cookies from 'js-cookie'
+import elementEnLocale from 'element-ui/lib/locale/lang/en' // element-ui 英文包
+import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN' // element-ui 中文包
+import zhLocale from './lang/zh'
+import enLocale from './lang/en'
+
+Vue.use(VueI18n)
+
+const messages = {
+  zh: {
+    ...zhLocale,
+    ...elementZhLocale
+  },
+  en: {
+    ...enLocale,
+    ...elementEnLocale
+  }
+}
+
+// 从 cookie 中获取语言设置,默认为中文
+const getLocale = () => {
+  const cookieLanguage = Cookies.get('language')
+  if (cookieLanguage) {
+    return cookieLanguage
+  }
+  // 默认返回中文
+  return 'zh'
+}
+
+const i18n = new VueI18n({
+  locale: getLocale(),
+  messages
+})
+
+export default i18n
+

+ 291 - 0
src/i18n/lang/en.js

@@ -0,0 +1,291 @@
+export default {
+  common: {
+    search: 'Search',
+    reset: 'Reset',
+    add: 'Add',
+    edit: 'Edit',
+    delete: 'Delete',
+    confirm: 'Confirm',
+    cancel: 'Cancel',
+    submit: 'Submit',
+    save: 'Save',
+    export: 'Export',
+    import: 'Import',
+    operation: 'Operation',
+    status: 'Status',
+    createTime: 'Create Time',
+    updateTime: 'Update Time',
+    remark: 'Remark',
+    pleaseSelect: 'Please Select',
+    pleaseInput: 'Please Input',
+    success: 'Success',
+    failed: 'Failed',
+    loading: 'Loading...',
+    noData: 'No Data'
+  },
+  login: {
+    title: 'System Login',
+    systemTitle: 'Intelligent Lock Control Material Management System',
+    username: 'Account',
+    password: 'Password',
+    code: 'Verification Code',
+    rememberMe: 'Remember Me',
+    login: 'Login',
+    logging: 'Logging in...',
+    register: 'Register Now',
+    forgotPassword: 'Forgot Password',
+    usernamePlaceholder: 'Account',
+    passwordPlaceholder: 'Password',
+    codePlaceholder: 'Verification Code',
+    usernameRequired: 'Please enter your account',
+    passwordRequired: 'Please enter your password',
+    codeRequired: 'Please enter the verification code'
+  },
+  navbar: {
+    profile: 'Profile',
+    layoutSettings: 'Layout Settings',
+    logout: 'Logout',
+    logoutConfirm: 'Are you sure you want to log out?',
+    tip: 'Tip',
+    language: 'Language'
+  },
+  dashboard: {
+    materialsTotal: 'Total Materials',
+    cabinetMaterials: 'Materials in Cabinet',
+    loanMaterials: 'Loaned Materials',
+    exceptionCount: 'Exception Count',
+    ongoingJobs: 'Ongoing Jobs',
+    ticketName: 'Job Ticket Name',
+    workstation: 'Workstation',
+    machinery: 'Equipment/Process',
+    jobType: 'Job Type',
+    startTime: 'Start Time',
+    loan: 'Loan',
+    return: 'Return'
+  },
+  register: {
+    systemName: 'Guoruan MES',
+    username: 'Account',
+    password: 'Password',
+    confirmPassword: 'Confirm Password',
+    code: 'Verification Code',
+    register: 'Register',
+    registering: 'Registering...',
+    loginWithExisting: 'Login with Existing Account',
+    passwordMismatch: 'The two passwords do not match',
+    usernameRequired: 'Please enter your account',
+    usernameLength: 'Account length must be between 2 and 20',
+    passwordRequired: 'Please enter your password',
+    passwordLength: 'Password length must be between 5 and 20',
+    confirmPasswordRequired: 'Please enter your password again',
+    codeRequired: 'Please enter the verification code',
+    registerSuccess: 'Congratulations! Your account {username} has been registered successfully!',
+    systemTip: 'System Tip'
+  },
+  system: {
+    user: {
+      userNo: 'User No.',
+      userNoPlaceholder: 'Please enter user number',
+      name: 'Name',
+      namePlaceholder: 'Please enter name',
+      phone: 'Phone Number',
+      phonePlaceholder: 'Please enter phone number',
+      unit: 'Unit',
+      unitPlaceholder: 'Please select unit',
+      role: 'Role',
+      rolePlaceholder: 'Please select role',
+      post: 'Post',
+      postPlaceholder: 'Select post',
+      status: 'Status',
+      userStatus: 'User Status',
+      employeeNo: 'Employee No.',
+      email: 'Email',
+      view: 'View',
+      fingerprint: 'Fingerprint',
+      face: 'Face',
+      more: 'More',
+      resetPassword: 'Reset Password',
+      resetKey: 'Reset Key',
+      assignRole: 'Assign Role',
+      dialogTitle: 'Add or Modify User Configuration Dialog',
+      namePlaceholder2: 'Please enter name',
+      phonePlaceholder2: 'Please enter phone number',
+      employeeNoPlaceholder: 'Please enter employee number',
+      unitPlaceholder2: 'Please select unit',
+      rolePlaceholder2: 'Please select role',
+      emailPlaceholder: 'Please enter email',
+      marsPost: 'Mars Post',
+      postPlaceholder2: 'Please select post',
+      filterKeyword: 'Enter keyword to filter',
+      gender: 'User Gender',
+      genderPlaceholder: 'Please select gender',
+      userPassword: 'User Password',
+      userPasswordPlaceholder: 'Please enter user password',
+      keyPassword: 'Key Password',
+      keyPasswordPlaceholder: 'Please enter key password',
+      remarkPlaceholder: 'Please enter content',
+      importDialog: 'User Import Dialog',
+      uploadTip: 'Drag file here or click to upload',
+      fileFormat: 'Only xls and xlsx format files are allowed.',
+      downloadTemplate: 'Download Template',
+      viewDialog: 'View User Face and Fingerprint Dialog',
+      serialNo: 'Serial No.',
+      group: 'Group',
+      fingerprintData: 'User Fingerprint Data'
+    },
+    dept: {
+      deptName: 'Department Name',
+      deptNamePlaceholder: 'Please enter department name',
+      status: 'Status',
+      deptStatus: 'Department Status',
+      expandCollapse: 'Expand/Collapse',
+      sort: 'Sort',
+      createTime: 'Create Time',
+      parentDept: 'Parent Department',
+      parentDeptPlaceholder: 'Select parent department',
+      displaySort: 'Display Sort',
+      leader: 'Leader',
+      leaderPlaceholder: 'Please enter leader',
+      phone: 'Contact Phone',
+      phonePlaceholder: 'Please enter contact phone',
+      email: 'Email',
+      emailPlaceholder: 'Please enter email',
+      dialogTitle: 'Add or Modify Department Dialog',
+      parentDeptRequired: 'Parent department cannot be empty',
+      deptNameRequired: 'Department name cannot be empty',
+      displaySortRequired: 'Display sort cannot be empty',
+      emailFormat: 'Please enter a valid email address',
+      phoneFormat: 'Please enter a valid phone number',
+      addDept: 'Add Department',
+      editDept: 'Modify Department',
+      editSuccess: 'Modify Success',
+      addSuccess: 'Add Success',
+      deleteConfirm: 'Are you sure to delete the item with name?',
+      deleteSuccess: 'Delete Success'
+    },
+    post: {
+      postCode: 'Post Code',
+      postCodePlaceholder: 'Please enter post code',
+      postName: 'Post Name',
+      postNamePlaceholder: 'Please enter post name',
+      status: 'Status',
+      postStatus: 'Post Status',
+      postNo: 'Post No.',
+      postSort: 'Post Sort',
+      createTime: 'Create Time',
+      dialogTitle: 'Add or Modify Post Dialog',
+      codeNamePlaceholder: 'Please enter code name',
+      postOrder: 'Post Order',
+      dialogTitle2: 'Add or Modify Post Dialog',
+      addPost: 'Add Post',
+      editPost: 'Modify Post',
+      postNameRequired: 'Post name cannot be empty',
+      postCodeRequired: 'Post code cannot be empty',
+      postOrderRequired: 'Post order cannot be empty',
+      editSuccess: 'Modify Success',
+      addSuccess: 'Add Success',
+      deleteConfirm: 'Are you sure to delete the post with number?',
+      deleteSuccess: 'Delete Success'
+    },
+    unit: {
+      unitNo: 'Unit No.',
+      unitNoPlaceholder: 'Please enter unit number',
+      unitName: 'Unit Name',
+      unitNamePlaceholder: 'Please enter unit name',
+      status: 'Status',
+      unitType: 'Unit Type',
+      sort: 'Sort',
+      createTime: 'Create Time',
+      dialogTitle: 'Add or Modify Unit Dialog',
+      internal: 'Internal',
+      external: 'External',
+      remarkPlaceholder: 'Please enter remark',
+      unitNameRequired: 'Unit name cannot be empty',
+      enable: 'Enable',
+      disable: 'Disable',
+      confirmPost: 'Confirm post?',
+      success: 'Success',
+      addUnit: 'Add Unit',
+      editUnit: 'Modify Unit',
+      editSuccess: 'Modify Success',
+      addSuccess: 'Add Success',
+      deleteConfirm: 'Are you sure to delete the selected items?',
+      deleteSuccess: 'Delete Success'
+    },
+    role: {
+      roleName: 'Role Name',
+      roleNamePlaceholder: 'Please enter role name',
+      roleKey: 'Permission Key',
+      roleKeyPlaceholder: 'Please enter permission key',
+      status: 'Status',
+      roleStatus: 'Role Status',
+      roleNo: 'Role No.',
+      displayOrder: 'Display Order',
+      more: 'More',
+      dataPermission: 'Data Permission',
+      assignUser: 'Assign User',
+      menuPermission: 'Menu Permission',
+      expandCollapse: 'Expand/Collapse',
+      selectAll: 'Select All/None',
+      parentChildLink: 'Parent-Child Link',
+      loading: 'Loading, please wait',
+      dataPermissionDialog: 'Assign Role Data Permission Dialog',
+      permissionScope: 'Permission Scope',
+      postPermission: 'Post Permission',
+      allDataPermission: 'All Data Permission',
+      customDataPermission: 'Custom Data Permission',
+      deptDataPermission: 'Department Data Permission',
+      deptAndBelowDataPermission: 'Department and Below Data Permission',
+      onlySelfDataPermission: 'Only Self Data Permission',
+      roleNameRequired: 'Role name cannot be empty',
+      roleKeyRequired: 'Permission key cannot be empty',
+      roleOrderRequired: 'Role order cannot be empty'
+    }
+  },
+  commonComponents: {
+    navbar: {
+      layoutSize: 'Layout Size'
+    },
+    sidebar: {
+      logo: 'Doctor Safety'
+    },
+    modal: {
+      systemTip: 'System Tip'
+    },
+    imageUpload: {
+      uploadTip: 'Upload Tip',
+      pleaseUpload: 'Please upload',
+      sizeLimit: 'Size not exceeding',
+      mb: 'MB',
+      format: 'Format',
+      file: 'file',
+      preview: 'Preview',
+      loading: 'Loading',
+      formatError: 'File format is incorrect, please upload image format file!',
+      sizeError: 'Uploaded avatar image size cannot exceed MB!',
+      uploading: 'Uploading image, please wait...',
+      countError: 'Upload file count cannot exceed!',
+      uploadFailed: 'Upload image failed, please try again'
+    }
+  },
+  router: {
+    home: 'Home',
+    profile: 'Profile',
+    assignRole: 'Assign Role',
+    sopNew: 'SOP Management - New SOP',
+    sopEdit: 'SOP Management - Edit SOP',
+    sopView: 'SOP Management - View SOP',
+    jobNew: 'Job Management - New Job Ticket',
+    jobExecute: 'Job Execution - Job Status',
+    preview: 'Preview',
+    craftDetail: 'Craft Detail',
+    materialInstructionDetail: 'Material Instruction Detail',
+    deviceDetail: 'Device Detail',
+    detail: 'Detail',
+    materialSpec: 'Material Specification',
+    assignUser: 'Assign User',
+    dictData: 'Dictionary Data',
+    ruleComposition: 'Rule Composition'
+  }
+}
+

+ 1517 - 0
src/i18n/lang/zh.js

@@ -0,0 +1,1517 @@
+export default {
+  common: {
+    search: '搜索',
+    reset: '重置',
+    add: '新增',
+    edit: '修改',
+    delete: '删除',
+    confirm: '确定',
+    cancel: '取消',
+    submit: '提交',
+    save: '保存',
+    export: '导出',
+    import: '导入',
+    operation: '操作',
+    status: '状态',
+    createTime: '创建时间',
+    updateTime: '更新时间',
+    remark: '备注',
+    pleaseSelect: '请选择',
+    pleaseInput: '请输入',
+    success: '成功',
+    failed: '失败',
+    loading: '加载中...',
+    noData: '暂无数据'
+  },
+  login: {
+    title: '系统登录',
+    systemTitle: '智能锁控物资管理系统',
+    username: '账号',
+    password: '密码',
+    code: '验证码',
+    rememberMe: '记住密码',
+    login: '登 录',
+    logging: '登 录 中...',
+    register: '立即注册',
+    forgotPassword: '忘记密码',
+    usernamePlaceholder: '账号',
+    passwordPlaceholder: '密码',
+    codePlaceholder: '验证码',
+    usernameRequired: '请输入您的账号',
+    passwordRequired: '请输入您的密码',
+    codeRequired: '请输入验证码'
+  },
+  navbar: {
+    profile: '个人中心',
+    layoutSettings: '布局设置',
+    logout: '退出登录',
+    logoutConfirm: '确定注销并退出系统吗?',
+    tip: '提示',
+    language: '语言切换'
+  },
+  dashboard: {
+    materialsTotal: '物资总数',
+    cabinetMaterials: '柜中物资',
+    loanMaterials: '借出物资',
+    exceptionCount: '异常数量',
+    ongoingJobs: '进行中的作业',
+    ticketName: '作业票名称',
+    workstation: '岗位',
+    machinery: '设备工艺',
+    jobType: '作业类型',
+    startTime: '启动时间',
+    loan: '领取',
+    return: '归还'
+  },
+  register: {
+    systemName: '国软MES',
+    username: '账号',
+    password: '密码',
+    confirmPassword: '确认密码',
+    code: '验证码',
+    register: '注 册',
+    registering: '注 册 中...',
+    loginWithExisting: '使用已有账户登录',
+    passwordMismatch: '两次输入的密码不一致',
+    usernameRequired: '请输入您的账号',
+    usernameLength: '用户账号长度必须介于 2 和 20 之间',
+    passwordRequired: '请输入您的密码',
+    passwordLength: '用户密码长度必须介于 5 和 20 之间',
+    confirmPasswordRequired: '请再次输入您的密码',
+    codeRequired: '请输入验证码',
+    registerSuccess: '恭喜你,您的账号 {username} 注册成功!',
+    systemTip: '系统提示'
+  },
+  system: {
+    user: {
+      userNo: '人员编号',
+      userNoPlaceholder: '请输入人员编号',
+      name: '姓名',
+      namePlaceholder: '请输入姓名',
+      phone: '手机号码',
+      phonePlaceholder: '请输入手机号码',
+      unit: '单位',
+      unitPlaceholder: '请选择单位',
+      role: '角色',
+      rolePlaceholder: '请选择角色',
+      post: '岗位',
+      postPlaceholder: '选择岗位',
+      status: '状态',
+      userStatus: '用户状态',
+      employeeNo: '工号',
+      email: '邮件',
+      view: '查看',
+      fingerprint: '指纹',
+      face: '人脸',
+      more: '更多',
+      resetPassword: '重置密码',
+      resetKey: '重置钥匙',
+      assignRole: '分配角色',
+      dialogTitle: '添加或修改用户配置对话框',
+      namePlaceholder2: '请输入姓名',
+      phonePlaceholder2: '请输入手机号码',
+      employeeNoPlaceholder: '请输入工号',
+      unitPlaceholder2: '请选择单位',
+      rolePlaceholder2: '请选择角色',
+      emailPlaceholder: '请输入邮件',
+      marsPost: '玛氏岗位',
+      postPlaceholder2: '请选择岗位',
+      filterKeyword: '输入关键字进行过滤',
+      gender: '用户性别',
+      genderPlaceholder: '请选择性别',
+      userPassword: '用户密码',
+      userPasswordPlaceholder: '请输入用户密码',
+      keyPassword: '钥匙密码',
+      keyPasswordPlaceholder: '请输入钥匙密码',
+      remarkPlaceholder: '请输入内容',
+      importDialog: '用户导入对话框',
+      uploadTip: '将文件拖到此处,或点击上传',
+      fileFormat: '仅允许导入xls、xlsx格式文件。',
+      downloadTemplate: '下载模板',
+      viewDialog: '查看用户人脸和指纹弹窗',
+      serialNo: '序号',
+      group: '分组',
+      fingerprintData: '人员指纹数据'
+    },
+    dept: {
+      deptName: '部门名称',
+      deptNamePlaceholder: '请输入部门名称',
+      status: '状态',
+      deptStatus: '部门状态',
+      expandCollapse: '展开/折叠',
+      sort: '排序',
+      createTime: '创建时间',
+      parentDept: '上级部门',
+      parentDeptPlaceholder: '选择上级部门',
+      displaySort: '显示排序',
+      leader: '负责人',
+      leaderPlaceholder: '请输入负责人',
+      phone: '联系电话',
+      phonePlaceholder: '请输入联系电话',
+      email: '邮箱',
+      emailPlaceholder: '请输入邮箱',
+      dialogTitle: '添加或修改部门对话框',
+      parentDeptRequired: '上级部门不能为空',
+      deptNameRequired: '部门名称不能为空',
+      displaySortRequired: '显示排序不能为空',
+      emailFormat: '请输入正确的邮箱地址',
+      phoneFormat: '请输入正确的手机号码',
+      addDept: '添加部门',
+      editDept: '修改部门',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除名称为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    post: {
+      postCode: '岗位编码',
+      postCodePlaceholder: '请输入岗位编码',
+      postName: '岗位名称',
+      postNamePlaceholder: '请输入岗位名称',
+      status: '状态',
+      postStatus: '岗位状态',
+      postNo: '岗位编号',
+      postSort: '岗位排序',
+      createTime: '创建时间',
+      dialogTitle: '添加或修改岗位对话框',
+      codeNamePlaceholder: '请输入编码名称',
+      postOrder: '岗位顺序',
+      dialogTitle2: '添加或修改岗位对话框',
+      addPost: '添加岗位',
+      editPost: '修改岗位',
+      postNameRequired: '岗位名称不能为空',
+      postCodeRequired: '岗位编码不能为空',
+      postOrderRequired: '岗位顺序不能为空',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除岗位编号为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    unit: {
+      unitNo: '单位编号',
+      unitNoPlaceholder: '请输入单位编号',
+      unitName: '单位名称',
+      unitNamePlaceholder: '请输入单位名称',
+      status: '状态',
+      unitType: '单位类型',
+      sort: '排序',
+      createTime: '创建时间',
+      dialogTitle: '添加或修改单位对话框',
+      internal: '内部',
+      external: '外部',
+      remarkPlaceholder: '请输入备注',
+      unitNameRequired: '单位名称不能为空',
+      enable: '启用',
+      disable: '停用',
+      confirmPost: '确认要岗位吗?',
+      success: '成功',
+      addUnit: '新增单位',
+      editUnit: '修改单位',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除所选数据项?',
+      deleteSuccess: '删除成功'
+    },
+    role: {
+      roleName: '角色名称',
+      roleNamePlaceholder: '请输入角色名称',
+      roleKey: '权限字符',
+      roleKeyPlaceholder: '请输入权限字符',
+      status: '状态',
+      roleStatus: '角色状态',
+      roleNo: '角色编号',
+      displayOrder: '显示顺序',
+      more: '更多',
+      dataPermission: '数据权限',
+      assignUser: '分配用户',
+      menuPermission: '菜单权限',
+      expandCollapse: '展开/折叠',
+      selectAll: '全选/全不选',
+      parentChildLink: '父子联动',
+      loading: '加载中,请稍候',
+      dataPermissionDialog: '分配角色数据权限对话框',
+      permissionScope: '权限范围',
+      postPermission: '岗位权限',
+      allDataPermission: '全部数据权限',
+      customDataPermission: '自定数据权限',
+      deptDataPermission: '本部门数据权限',
+      deptAndBelowDataPermission: '本部门及以下数据权限',
+      onlySelfDataPermission: '仅本人数据权限',
+      roleNameRequired: '角色名称不能为空',
+      roleKeyRequired: '权限字符不能为空',
+      roleOrderRequired: '角色顺序不能为空'
+    }
+  },
+  commonComponents: {
+    navbar: {
+      layoutSize: '布局大小'
+    },
+    sidebar: {
+      logo: '博士安全'
+    },
+    modal: {
+      systemTip: '系统提示'
+    },
+    imageUpload: {
+      uploadTip: '上传提示',
+      pleaseUpload: '请上传',
+      sizeLimit: '大小不超过',
+      mb: 'MB',
+      format: '格式为',
+      file: '的文件',
+      preview: '预览',
+      loading: '加载中',
+      formatError: '文件格式不正确, 请上传图片格式文件!',
+      sizeError: '上传头像图片大小不能超过 MB!',
+      uploading: '正在上传图片,请稍候...',
+      countError: '上传文件数量不能超过 个!',
+      uploadFailed: '上传图片失败,请重试'
+    }
+  },
+  router: {
+    home: '首页',
+    profile: '个人中心',
+    assignRole: '分配角色',
+    sopNew: 'SOP管理-新建SOP',
+    sopEdit: 'SOP管理-编辑SOP',
+    sopView: 'SOP管理-查看SOP',
+    jobNew: '作业管理-新建作业票',
+    jobExecute: '作业执行-作业状态',
+    preview: '预览',
+    craftDetail: '工艺详情',
+    materialInstructionDetail: '物资使用说明详情',
+    deviceDetail: '设备详情',
+    detail: '详情',
+    materialSpec: '物资规格',
+    assignUser: '分配用户',
+    dictData: '字典数据',
+    ruleComposition: '规则组成'
+  },
+  mes: {
+    hardwareType: {
+      hardwareTypeCode: '硬件类型编号',
+      hardwareTypeCodePlaceholder: '请输入硬件类型编号',
+      typeName: '类型名称',
+      typeNamePlaceholder: '请输入类型名称',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      enable: '启用',
+      disable: '禁用',
+      hardwareTypeNo: '硬件类型编号',
+      dialogTitle: '添加或修改设备类型对话框',
+      parentType: '父类型',
+      parentTypePlaceholder: '请选择父类型',
+      autoGenerate: '自动生成',
+      hardwareCodeRequired: '硬件编号不能为空',
+      hardwareNameRequired: '硬件名称不能为空',
+      addHardwareType: '新增硬件类型',
+      editHardwareType: '编辑硬件类型',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否删除硬件编号为的硬件类型?',
+      deleteSuccess: '删除成功'
+    },
+    rfid: {
+      rfidCode: 'RFID编码',
+      rfidCodePlaceholder: '请输入RFID编码',
+      rfidContent: 'RFID内容',
+      rfidContentPlaceholder: '请输入锁柜名称',
+      rfidType: 'RFID类型',
+      rfidTypePlaceholder: '请选择RFID类型',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      batchDelete: '批量删除',
+      rifidCode: 'RIFID编码',
+      createTime: '创建时间',
+      dialogTitle: '添加或修改设备维修单对话框',
+      autoGenerate: '自动生成',
+      rfidContentPlaceholder2: '请输入RFID内容',
+      remarkPlaceholder: '请输入备注',
+      rfidCodeRequired: 'RFID编码不能为空',
+      rfidContentRequired: 'RFID内容不能为空',
+      rfidTypeRequired: 'RFID类型不能为空',
+      addRfid: '添加RFID信息',
+      editRfid: '编辑RFID信息',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除所选数据项?',
+      deleteSuccess: '删除成功'
+    },
+    workCard: {
+      workCardCode: '工卡编码',
+      workCardCodePlaceholder: '请输入工卡编码',
+      workCardType: '工卡类型',
+      workCardTypePlaceholder: '请选择工卡类型',
+      userName: '用户名称',
+      userPlaceholder: '请选择工卡用户',
+      workCardNFC: '工卡NFC',
+      status: '状态',
+      dialogTitle: '添加或修改设备维修单对话框',
+      keyCodePlaceholder: '请输入钥匙编码',
+      autoGenerate: '自动生成',
+      nfcPlaceholder: '请输入工卡Nfc',
+      remarkPlaceholder: '请输入备注',
+      workCardCodeRequired: '工卡编码不能为空',
+      userNameRequired: '用户名称不能为空',
+      nfcRequired: '工卡NFC不能为空',
+      workCardTypeRequired: '工卡类型不能为空',
+      addWorkCard: '添加工卡信息',
+      editWorkCard: '编辑工卡信息',
+      employeeCard: '员工卡',
+      tempCard: '临时卡',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除编码为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    lockCabinet: {
+      lockCabinetName: '锁柜名称',
+      lockCabinetNamePlaceholder: '请输入锁柜名称',
+      isOnline: '是否在线',
+      isOnlinePlaceholder: '请选择是否在线',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      batchDelete: '批量删除',
+      lockCabinetCode: '锁柜编码',
+      hardwareId: '硬件ID',
+      hardwareSerialNo: '硬件序列号',
+      post: '岗位',
+      image: '图片',
+      icon: '图标',
+      detail: '详情',
+      view: '查看',
+      test: '测试',
+      dialogTitle: '添加或修改设备维修单对话框',
+      lockCabinetNo: '锁柜编号',
+      lockCabinetNoPlaceholder: '请输入锁柜编号',
+      autoGenerate: '自动生成',
+      postNo: '岗位序号',
+      postPlaceholder: '选择岗位',
+      hardwareIdPlaceholder: '请选择硬件ID',
+      remarkPlaceholder: '请输入备注',
+      testType: '类型',
+      typePlaceholder: '请输入type',
+      serialNo: '序列号',
+      serialNoPlaceholder: '请输入lotoSerialNumber',
+      content: '内容',
+      contentPlaceholder: '请输入content',
+      lockCabinetCodeRequired: '锁柜编码不能为空',
+      lockCabinetNameRequired: '锁柜名称不能为空',
+      hardwareIdRequired: '硬件ID不能为空',
+      postNoRequired: '岗位序号不能为空',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      testSuccess: '测试成功',
+      deleteConfirm: '是否确认删除所选数据项?',
+      deleteSuccess: '删除成功',
+      lockCabinetView: '锁柜视图',
+      listView: '列表视图',
+      slotCode: '仓位编码',
+      slotCodePlaceholder: '请输入仓位编码',
+      slotType: '仓位类型',
+      slotTypePlaceholder: '请选择仓位类型',
+      row: '行',
+      col: '列',
+      isOccupied: '是否被占用',
+      occupiedHardwareId: '占用仓位的硬件ID',
+      lockCabinetNo2: '锁柜序号',
+      slotNo: '仓位编号',
+      slotNoPlaceholder: '请输入仓位编号',
+      rowPlaceholder: '请输入行',
+      colPlaceholder: '请输入列',
+      occupiedHardwareIdPlaceholder: '请选择硬件ID',
+      addSlot: '添加仓位数据信息',
+      editSlot: '编辑仓位数据信息'
+    },
+    hardwareInfo: {
+      hardwareCode: '硬件编码',
+      hardwareCodePlaceholder: '请输入硬件编码',
+      hardwareName: '硬件名称',
+      hardwareNamePlaceholder: '请输入硬件名称',
+      status: '状态',
+      statusPlaceholder: '请选择硬件状态',
+      hardwareType: '硬件类型',
+      hardwareTypePlaceholder: '请选择硬件类型',
+      specModel: '规格型号',
+      specModelPlaceholder: '请输入规格型号',
+      createTime: '创建时间',
+      startDate: '开始日期',
+      endDate: '结束日期',
+      batchDelete: '批量删除',
+      hardwareNo: '硬件编码',
+      serialNo: '序列号',
+      hardwareStatus: '硬件状态',
+      enableTime: '启用时间',
+      availableCount: '可用次数',
+      usedCount: '已用次数',
+      availableLifespan: '可用寿命',
+      usedLifespan: '已用寿命',
+      dialogTitle: '添加或修改设备维修单对话框',
+      autoGenerate: '自动生成',
+      hardwareTypePlaceholder2: '请选择硬件类型',
+      serialNoPlaceholder: '请输入序列号',
+      availableCountPlaceholder: '请输入可用次数',
+      usedCountPlaceholder: '请输入已用次数',
+      availableLifespanPlaceholder: '请输入可用寿命',
+      usedLifespanPlaceholder: '请输入已用寿命',
+      enableDate: '启用日期',
+      enableDatePlaceholder: '请选择启用日期',
+      online: '在线',
+      offline: '离线',
+      exception: '异常',
+      hardwareCodeRequired: '硬件编码不能为空',
+      hardwareNameRequired: '硬件名称不能为空',
+      hardwareTypeRequired: '硬件类型不能为空',
+      lastWeek: '最近一周',
+      lastMonth: '最近一个月',
+      lastThreeMonths: '最近三个月',
+      addHardwareInfo: '新增硬件信息',
+      editHardwareInfo: '编辑硬件信息',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除硬件编码为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    mapData: {
+      close: '关闭',
+      save: '保存',
+      reset: '重置',
+      saveConfirm: '请确认是否保存修改内容',
+      tip: '提示'
+    }
+  },
+  device: {
+    machineryType: {
+      typeName: '类型名称',
+      typeNamePlaceholder: '请输入设备类型名称',
+      isEnable: '是否启用',
+      isEnablePlaceholder: '选择是或否',
+      machineryTypeCode: '设备类型编码',
+      machineryTypeName: '设备类型名称',
+      dialogTitle: '添加或修改设备类型对话框',
+      parentType: '父类型',
+      parentTypePlaceholder: '请选择父类型',
+      remarkPlaceholder: '请输入内容',
+      parentTypeRequired: '父类型不能为空',
+      machineryTypeNameRequired: '设备类型名称不能为空',
+      isEnableRequired: '是否启用不能为空',
+      addMachineryType: '添加设备类型',
+      editMachineryType: '修改设备类型',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除设备类型编号为"的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    machinery: {
+      categoryNamePlaceholder: '请输入分类名称',
+      machineryCode: '设备编码',
+      machineryCodePlaceholder: '请输入设备编码',
+      machineryName: '设备名称',
+      machineryNamePlaceholder: '请输入设备名称',
+      brand: '品牌',
+      specModel: '规格型号',
+      workshop: '所属车间',
+      machineryStatus: '设备状态',
+      dialogTitle: '添加或修改设备对话框',
+      autoGenerate: '自动生成',
+      brandPlaceholder: '请输入品牌',
+      category: '设备分类',
+      categoryPlaceholder: '请选择所属分类',
+      specModelPlaceholder: '请输入规格型号',
+      workshopPlaceholder: '请选择车间',
+      remarkPlaceholder: '请输入内容',
+      back: '返回',
+      machineryCodeRequired: '设备编码不能为空',
+      machineryCodeLength: '设备编码长度必须小于64个字符',
+      machineryNameRequired: '设备名称不能为空',
+      workshopRequired: '车间不能为空',
+      categoryRequired: '设备分类不能为空',
+      importDialog: '物料导入对话框',
+      uploadTip: '将文件拖到此处,或点击上传',
+      updateExisting: '是否更新已经存在的设备数据',
+      fileFormat: '仅允许导入xls、xlsx格式文件。',
+      downloadTemplate: '下载模板'
+    },
+    segregationPoint: {
+      pointName: '隔离点名称',
+      pointNamePlaceholder: '请输入隔离点名称',
+      pointType: '隔离点类型',
+      pointTypePlaceholder: '请选择隔离点类型',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      batchDelete: '批量删除',
+      pointNo: '隔离点编号',
+      dangerEnergyType: '危险能量类型',
+      dialogTitle: '添加或修改隔离点对话框',
+      dangerEnergyTypePlaceholder: '请选择危险能量类型',
+      remarkPlaceholder: '请输入备注',
+      pointNameRequired: '隔离点名称不能为空',
+      pointTypeRequired: '隔离点类型不能为空',
+      dangerEnergyTypeRequired: '危险能量类型不能为空',
+      addPoint: '添加隔离点',
+      editPoint: '修改隔离点',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除隔离点编号为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    switchManagement: {
+      switchName: '开关名称',
+      switchNamePlaceholder: '请输入开关名称',
+      switchType: '开关类型',
+      switchTypePlaceholder: '请选择开关类型',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      batchDelete: '批量删除',
+      switchNo: '开关编号',
+      dialogTitle: '添加或修改开关对话框',
+      remarkPlaceholder: '请输入备注',
+      switchNameRequired: '开关名称不能为空',
+      switchTypeRequired: '开关类型不能为空',
+      addSwitch: '添加开关',
+      editSwitch: '修改开关',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除开关编号为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    lotoStation: {
+      stationName: '锁定站名称',
+      stationNamePlaceholder: '请输入锁定站名称',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      batchDelete: '批量删除',
+      stationNo: '锁定站编号',
+      dialogTitle: '添加或修改锁定站对话框',
+      remarkPlaceholder: '请输入备注',
+      stationNameRequired: '锁定站名称不能为空',
+      addStation: '添加锁定站',
+      editStation: '修改锁定站',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除锁定站编号为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    switchMotor: {
+      motorName: '电机名称',
+      motorNamePlaceholder: '请输入电机名称',
+      motorType: '电机类型',
+      motorTypePlaceholder: '请选择电机类型',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      batchDelete: '批量删除',
+      motorNo: '电机编号',
+      dialogTitle: '添加或修改电机对话框',
+      remarkPlaceholder: '请输入备注',
+      motorNameRequired: '电机名称不能为空',
+      motorTypeRequired: '电机类型不能为空',
+      addMotor: '添加电机',
+      editMotor: '修改电机',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除电机编号为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    technology: {
+      selectPostTip: '请在下方选择岗位名称',
+      craft: '工艺',
+      device: '设备',
+      craftName: '工艺名称',
+      craftNamePlaceholder: '请输入工艺名称',
+      deviceName: '设备名称',
+      deviceNamePlaceholder: '请输入设备名称',
+      craftNo: '工艺编号',
+      deviceNo: '设备编号',
+      craftImage: '工艺图',
+      deviceImage: '设备图',
+      dialogTitle: '添加或修改部门对话框',
+      namePlaceholder: '请输入名称',
+      postPlaceholder: '请选择岗位',
+      cabinetPlaceholder: '请选择所属电柜',
+      deviceInfo: '设备信息',
+      lotoStation: '锁定站',
+      deviceCraftName: '设备/工艺名称',
+      deviceCraftNamePlaceholder: '请输入设备/工艺名称',
+      deviceCraftCode: '设备/工艺编号',
+      deviceCraftCodePlaceholder: '请输入设备/工艺编号',
+      autoGenerate: '自动生成',
+      deviceCraftType: '设备/工艺类型',
+      deviceCraftTypePlaceholder: '请输入设备/工艺类型',
+      craftImage2: '工艺图',
+      deviceCraftCodeRequired: '设备/工艺编码不能为空',
+      deviceCraftNameRequired: '设备/工艺名称不能为空',
+      postRequired: '岗位不能为空',
+      cabinetRequired: '电柜不能为空',
+      craftInfo: '工艺信息',
+      deviceList: '设备列表',
+      sopList: 'SOP列表',
+      deviceCraftImage: '工艺/设备 工艺图',
+      lotoStationInfo: 'LOTO站信息',
+      lockStationInfo: '锁定站信息',
+      eightSteps: '八大步骤',
+      deviceCode: '设备编码',
+      deviceName2: '设备名称',
+      deviceImage2: '设备图',
+      sopName: 'sop名称',
+      workContent: '工作内容',
+      deviceListDialog: '添加或修改设备列表对话框',
+      deviceNamePlaceholder2: '请输入设备名称',
+      deviceCodePlaceholder: '请输入设备编号'
+    }
+  },
+  sop: {
+    sopName: 'SOP名称',
+    sopNamePlaceholder: '请输入SOP名称',
+    sopType: 'SOP类型',
+    sopTypePlaceholder: '请选择SOP类型',
+    status: '状态',
+    statusPlaceholder: '请选择状态',
+    batchDelete: '批量删除',
+    sopNo: 'SOP编号',
+    view: '查看',
+    dialogTitle: '添加或修改SOP对话框',
+    sopNoPlaceholder: '请输入SOP编号',
+    autoGenerate: '自动生成',
+    sopContent: 'SOP内容',
+    isolationPointInfo: '隔离点信息',
+    isolationPoint: '隔离点',
+    isolationPointType: '隔离点类型',
+    dangerEnergyType: '危险能量类型',
+    preIsolationPoint: '前置隔离点',
+    personnelInfo: '人员信息',
+    locker: '上锁人',
+    coLocker: '共锁人',
+    addInternalPerson: '添加内部人员',
+    addExternalPerson: '添加外部人员',
+    sopNameRequired: 'SOP名称不能为空',
+    sopNoRequired: 'SOP编号不能为空',
+    sopTypeRequired: 'SOP类型不能为空',
+    addSop: '添加SOP',
+    editSop: '修改SOP',
+    editSuccess: '修改成功',
+    addSuccess: '新增成功',
+    deleteConfirm: '是否确认删除SOP编号为的数据项?',
+    deleteSuccess: '删除成功',
+    newSop: {
+      title: 'LD-R&R SOP',
+      selectCraftDevice: '选择 工艺/设备',
+      deviceCraftName: '设备/工艺名称',
+      post: '所属岗位',
+      deviceCraftType: '设备/工艺类型',
+      postType: '岗位类型',
+      sopType: 'sop类型',
+      shiftChange: '开收班',
+      cleaning: '清洁',
+      changeover: '换产',
+      repair: '维修',
+      pm: 'PM',
+      startExecute: '开始执行',
+      previousStep: '上一步',
+      craftImage: '工艺/设备 工艺图',
+      lotoStationInfo: 'LOTO站信息',
+      eightSteps: '八大步骤',
+      step1: '第1步',
+      step2: '第2步',
+      step3: '第3步',
+      step4: '第4步',
+      step5: '第5步',
+      step6: '第6步',
+      step7: '第7步',
+      step8: '第8步',
+      executed: '已执行',
+      assign: '分配',
+      execute: '执行',
+      step1Content: '识别所要完成的工作内容',
+      step2Content: '判断工作中锁设计的能量源及隔离方式',
+      step3Content: '通知所有受影响的人',
+      step4Content: '如果设备正在运行,按正常操作停机',
+      step5Content: '上锁并挂牌',
+      step6Content: '能量隔离证实',
+      step7Content: '取锁前的检查',
+      step8Content: '拆除锁具,并把隔离开关恢复到正常位置',
+      addPersonnel: '添加人员',
+      selectInternalPerson: '选择内部人员',
+      personPlaceholder: '请选择人员',
+      selectExternalPerson: '选择外部人员'
+    },
+    viewSop: {
+      basicInfo: '基本信息',
+      sopName: 'SOP名称',
+      sopNamePlaceholder: '请输入SOP名称',
+      sopNo: 'SOP编号',
+      sopNoPlaceholder: '请输入SOP编号',
+      autoGenerate: '自动生成',
+      sopType: 'SOP类型',
+      sopTypePlaceholder: '请选择SOP类型',
+      sopContent: 'SOP内容',
+      isolationPointInfo: '隔离点信息',
+      isolationPoint: '隔离点',
+      isolationPointType: '隔离点类型',
+      dangerEnergyType: '危险能量类型',
+      preIsolationPoint: '前置隔离点',
+      personnelInfo: '人员信息',
+      locker: '上锁人',
+      coLocker: '共锁人',
+      addInternalPerson: '添加内部人员',
+      addExternalPerson: '添加外部人员'
+    }
+  },
+  job: {
+    jobList: {
+      ticketName: '作业票名称',
+      ticketNamePlaceholder: '请输入作业票名称',
+      jobType: '作业类型',
+      jobTypePlaceholder: '请选择作业类型',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      batchDelete: '批量删除',
+      ticketNo: '作业票编号',
+      dialogTitle: '添加或修改作业票对话框',
+      ticketNoPlaceholder: '请输入作业票编号',
+      autoGenerate: '自动生成',
+      remarkPlaceholder: '请输入备注',
+      ticketNameRequired: '作业票名称不能为空',
+      ticketNoRequired: '作业票编号不能为空',
+      jobTypeRequired: '作业类型不能为空',
+      addTicket: '添加作业票',
+      editTicket: '修改作业票',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除作业票编号为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    jobManagement: {
+      selectPost: '选择岗位',
+      selectSop: '选择SOP',
+      jobDetail: '作业详情',
+      selectCraftDevice: '选择 工艺/设备',
+      deviceCraftName: '设备/工艺名称',
+      sopType: 'sop类型',
+      startExecute: '开始执行',
+      craftImage: '工艺/设备 工艺图',
+      lockStationInfo: '锁定站信息',
+      eightSteps: '八大步骤',
+      step: '第步',
+      stepLabel: '步骤',
+      status: '状态',
+      assign: '分配',
+      executed: '已执行',
+      execute: '执行',
+      content: '内容',
+      detail: '详情',
+      view: '查看',
+      jobLog: '作业日志',
+      all: '全部',
+      finishJob: '结束作业',
+      cancelJob: '取消作业',
+      newLogAlert: '新日志提醒',
+      addPersonnel: '添加人员',
+      locker: '上锁人',
+      selectedPersonList: '选中人员列表',
+      name: '姓名',
+      source: '来源',
+      internal: '内部',
+      external: '外部',
+      internalCoLockerList: '内部共锁人列表',
+      internalPersonId: '内部人员Id',
+      searchName: '搜索姓名',
+      externalCoLockerList: '外部共锁人列表',
+      externalPersonId: '外部人员Id',
+      lockerRequired: '上锁人不能为空',
+      jobStatus: '作业状态',
+      jobNo: '作业编号',
+      jobName: '作业名称',
+      lockKey: '上锁钥匙',
+      unlockKey: '解锁钥匙',
+      personnelStatus: '人员状态',
+      coLocker: '共锁人',
+      isolationPointStatus: '隔离点状态',
+      isolationPoint: '隔离点',
+      padlockName: '挂锁名称',
+      lockMechanism: '锁具机构',
+      close: '关 闭',
+      affectedTickets: '受影响作业票',
+      ticketNo: '作业票编号',
+      ticketName: '作业票名称',
+      ticketStatus: '作业票状态',
+      ticketType: '作业票类型',
+      lockStationInfo2: '锁定站信息',
+      isolationPointName: '隔离点名称',
+      function: '作用',
+      ongoingJobs: '进行中的作业',
+      post: '岗位',
+      no: '编号',
+      icon: '图标',
+      operation: '操作'
+    },
+    jobExecution: {
+      selectPost: '选择岗位',
+      selectSop: '选择SOP',
+      jobDetail: '作业详情',
+      selectCraftDevice: '选择 工艺/设备',
+      deviceCraftName: '设备/工艺名称',
+      sopType: 'sop类型',
+      startExecute: '开始执行',
+      craftImage: '工艺/设备 工艺图',
+      lockStationInfo: '锁定站信息',
+      eightSteps: '八大步骤',
+      step1: '第1步',
+      step2: '第2步',
+      step3: '第3步',
+      step4: '第4步',
+      step5: '第5步',
+      step6: '第6步',
+      step7: '第7步',
+      step8: '第8步',
+      executed: '已执行',
+      assign: '分配',
+      execute: '执行',
+      view: '查看',
+      step1Content: '识别所要完成的工作内容',
+      step2Content: '判断工作中锁设计的能量源及隔离方式',
+      step3Content: '通知所有受影响的人',
+      step4Content: '如果设备正在运行,按正常操作停机',
+      step5Content: '上锁并挂牌',
+      step6Content: '能量隔离证实',
+      step7Content: '取锁前的检查',
+      step8Content: '拆除锁具,并把隔离开关恢复到正常位置'
+    },
+    jobDetail: {
+      jobStatus: '作业状态',
+      jobName: '作业名称',
+      status: '状态',
+      lockKey: '上锁钥匙',
+      unlockKey: '解锁钥匙',
+      personnelStatus: '人员状态',
+      locker: '上锁人',
+      coLocker: '共锁人',
+      isolationPointStatus: '隔离点状态',
+      isolationPoint: '隔离点',
+      switchStatus: '开关状态',
+      padlockName: '挂锁名称',
+      lockMechanism: '锁具机构'
+    }
+  },
+  statistics: {
+    lockerDaily: {
+      dailyLoanReturn: '每日领取归还统计',
+      totalLoanCount: '累计领取次数',
+      totalNormalReturnCount: '累计正常归还次数',
+      totalTimeoutReturnCount: '累计超时归还次数',
+      count: '次数',
+      times: '次'
+    },
+    lockerLending: {
+      avgLoanDuration: '物资借出平均时长',
+      avgLoanHours: '平均借出时长(小时)',
+      hours: '小时'
+    },
+    lockerCollection: {
+      materialLoan: '物资领取统计',
+      loanCount: '领取次数',
+      count: '次数',
+      times: '次'
+    },
+    lockerReturn: {
+      materialReturn: '物资归还统计',
+      normalReturnCount: '正常归还次数',
+      timeoutReturnCount: '超时归还次数',
+      count: '次数'
+    },
+    lockerOpen: {
+      cabinetOpenClose: '物资柜开关次数',
+      openCloseCount: '开关次数',
+      count: '次数',
+      times: '次'
+    },
+    lockerMistake: {
+      cabinetException: '物资柜异常统计',
+      wrongPlacement: '物资错放',
+      timeoutNotClosed: '超时未关',
+      count: '次数'
+    },
+    lockerChange: {
+      materialReplacement: '物资更换统计',
+      normalReplacementCount: '正常更换次数',
+      expiredReplacementCount: '过期更换次数',
+      damagedReplacementCount: '损坏更换次数',
+      count: '次数'
+    },
+    lockerSpeciality: {
+      specialStatus: '特殊状态物资统计(当前时刻)',
+      aboutToExpire: '即将过期',
+      expired: '已过期',
+      damaged: '损坏数',
+      unit: '个'
+    }
+  },
+  material: {
+    materialInfo: {
+      materialCode: '物资编码',
+      materialCodePlaceholder: '请输入物资编码',
+      materialName: '物资名称',
+      materialNamePlaceholder: '请输入物资名称',
+      materialType: '物资类型',
+      materialTypePlaceholder: '请选择物资类型',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      batchDelete: '批量删除',
+      materialNo: '物资编号',
+      dialogTitle: '添加或修改物资对话框',
+      autoGenerate: '自动生成',
+      materialTypePlaceholder2: '请选择物资类型',
+      statusPlaceholder2: '请选择状态',
+      remarkPlaceholder: '请输入备注',
+      materialCodeRequired: '物资编码不能为空',
+      materialNameRequired: '物资名称不能为空',
+      materialTypeRequired: '物资类型不能为空',
+      addMaterial: '添加物资',
+      editMaterial: '修改物资',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除物资编号为的数据项?',
+      deleteSuccess: '删除成功',
+      cabinet: '物资柜',
+      cabinetPlaceholder: '请选择物资柜',
+      bindCabinet: '绑定物资柜',
+      bindCabinetPlaceholder: '请选择绑定物资柜',
+      rfid: 'RFID',
+      rfidPlaceholder: '请输入物资RFID',
+      supplier: '供应商',
+      supplierPlaceholder: '请输入供应商',
+      expirationDate: '有效期截止',
+      selectDate: '选择日期',
+      materialSpec: '物资规格',
+      materialSpecType: '物资规格种类',
+      materialSpecTypePlaceholder: '请选择物资规格种类',
+      materialSpecPlaceholder: '请输入物资规格',
+      isInCabinet: '是否在柜中',
+      materialStatus: '物资状态'
+    },
+    materialType: {
+      typeName: '类型名称',
+      typeNamePlaceholder: '请输入类型名称',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      batchDelete: '批量删除',
+      typeNo: '类型编号',
+      dialogTitle: '添加或修改物资类型对话框',
+      remarkPlaceholder: '请输入备注',
+      typeNameRequired: '类型名称不能为空',
+      addMaterialType: '添加物资类型',
+      editMaterialType: '修改物资类型',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除类型编号为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    materialStandard: {
+      materialSpecType: '物资规格种类',
+      materialSpecTypePlaceholder: '请输入物资规格种类',
+      batchDelete: '批量删除',
+      no: '编号',
+      createTime: '创建时间',
+      specSettings: '规格设置',
+      remarkPlaceholder: '请输入内容',
+      nameRequired: '名称不能为空',
+      addMaterialSpecType: '新增物资规格种类',
+      editMaterialSpecType: '修改物资规格种类',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除所选数据项?',
+      deleteSuccess: '删除成功',
+      propertyForm: {
+        materialSpecTypeNo: '物资规格种类编号',
+        materialSpecTypePlaceholder: '请输入物资规格种类',
+        materialSpec: '物资规格',
+        materialSpecPlaceholder: '请输入物资规格',
+        back: '返回',
+        materialSpecRequired: '物资规格不能为空',
+        addMaterialSpec: '新增物资规格',
+        editMaterialSpec: '修改物资规格'
+      }
+    },
+    collectionManagement: {
+      cabinet: '物资柜',
+      cabinetPlaceholder: '请选择物资柜',
+      materialName: '物资名称',
+      materialNamePlaceholder: '请输入物资名称',
+      materialType: '物资类型',
+      materialTypePlaceholder: '请选择物资类型',
+      loanPerson: '领取人',
+      loanPersonPlaceholder: '请输入领取人',
+      loanTime: '领取时间',
+      startDate: '开始日期',
+      endDate: '结束日期',
+      returnPerson: '归还人',
+      returnPersonPlaceholder: '请输入归还人',
+      returnTime: '归还时间',
+      status: '状态',
+      timeoutNotReturned: '超时未还',
+      materialNo: '物资编号',
+      materialImage: '物资图片',
+      loanDuration: '借出时长',
+      lastWeek: '最近一周',
+      lastMonth: '最近一个月',
+      lastThreeMonths: '最近三个月'
+    },
+    inventory: {
+      materialType: '物资类型',
+      overview: '总览',
+      inCabinet: '柜中',
+      loaned: '借出',
+      normal: '正常',
+      expired: '过期',
+      damaged: '损坏'
+    },
+    instructions: {
+      title: '标题',
+      titlePlaceholder: '请输入标题',
+      materialType: '物资类型',
+      materialTypePlaceholder: '请选择物资类型',
+      type: '类型',
+      batchDelete: '批量删除',
+      instructionNo: '说明编号',
+      sort: '排序',
+      file: '文件',
+      view: '查看',
+      detail: '详情',
+      addTime: '添加时间',
+      dialogTitle: '添加或修改物资对话框',
+      displaySort: '显示排序',
+      selectMaterialType: '选择物资类型',
+      fileType: '文件类型',
+      delete: '删除',
+      import: '导入',
+      uploadTip: '将文件拖到此处,或点击上传',
+      fileFormat: 'mp4、pdf格式文件。',
+      confirm: '确认',
+      uploading: '正在上传',
+      deleteSuccess: '删除成功'
+    },
+    blacklist: {
+      employeeNo: '工号',
+      employeeNoPlaceholder: '请输入工号',
+      name: '姓名',
+      namePlaceholder: '请输入姓名',
+      batchDelete: '批量删除',
+      userNo: '用户编号',
+      createTime: '创建时间',
+      dialogTitle: '添加或修改设备维修单对话框',
+      namePlaceholder2: '请输入姓名',
+      type: '类型',
+      loginName: '登录名'
+    },
+    inspectionPlan: {
+      planName: '计划名称',
+      planNamePlaceholder: '请输入计划名称',
+      cabinet: '物资柜',
+      cabinetPlaceholder: '请选择检查的物资柜',
+      planDate: '计划日期',
+      startDate: '开始日期',
+      endDate: '结束日期',
+      inspector: '检察员',
+      inspectorPlaceholder: '请选择检察员',
+      status: '状态',
+      startAutoCreate: '启动自动创建',
+      planFrequency: '计划频率',
+      planFrequencyPlaceholder: '请选择计划频率',
+      month: '月',
+      week: '周',
+      planDatePlaceholder: '请选择计划日期',
+      autoCreateNote: '(*自动创建的检查计划,覆盖所有物资柜)',
+      planNo: '计划编号',
+      inspectionRecord: '检查记录',
+      view: '查看',
+      dialogTitle: '添加或修改班组对话框',
+      area: '所属区域',
+      areaPlaceholder: '选择所属区域',
+      cabinetPlaceholder2: '请选择需要检查的物资柜',
+      datePlaceholder: '请选择日期',
+      inspectionCabinetDetail: '巡检物资柜详情',
+      planName2: '计划名称',
+      inspectionCabinet: '巡检物资柜',
+      signature: '签名',
+      detail: '详情',
+      close: '关 闭',
+      cabinetInspectionRecord: '物资柜检查记录',
+      materialNo: '物资编号',
+      materialName: '物资名称',
+      materialType: '物资类型',
+      materialImage: '物资图片',
+      rfid: 'RFID',
+      inspectionTime: '检查时间',
+      inspectionResult: '检查结果',
+      exceptionReason: '异常原因',
+      measure: '措施',
+      replacementRecord: '更换记录'
+    },
+    inspectionRecord: {
+      planName: '计划名称',
+      planNamePlaceholder: '请输入计划名称',
+      cabinet: '物资柜',
+      cabinetPlaceholder: '请选择物资柜',
+      materialName: '物资名称',
+      materialNamePlaceholder: '请输入物资名称',
+      materialType: '物资类型',
+      materialTypePlaceholder: '请选择物资类型',
+      rfid: 'RFID',
+      rfidPlaceholder: '请输入RFID',
+      inspectionTime: '检查时间',
+      startDate: '开始日期',
+      endDate: '结束日期',
+      inspectionResult: '检查结果',
+      exceptionReason: '异常原因',
+      status: '状态',
+      planName2: '计划名称',
+      materialNo: '物资编号',
+      measure: '措施'
+    },
+    replacementRecord: {
+      cabinet: '物资柜',
+      cabinetPlaceholder: '请选择物资柜',
+      materialType: '物资类型',
+      materialTypePlaceholder: '请选择物资类型',
+      originalMaterialNo: '原物资编号',
+      originalMaterialNoPlaceholder: '请输入原物资编号',
+      originalRfid: '原RFID',
+      originalRfidPlaceholder: '请输入原RFID',
+      newMaterialNo: '新物资编号',
+      newMaterialNoPlaceholder: '请输入新物资编号',
+      newRfid: '新RFID',
+      newRfidPlaceholder: '请输入新RFID',
+      replacer: '更换人',
+      replacerPlaceholder: '请输入更换人',
+      replacementTime: '更换时间',
+      startDate: '开始日期',
+      endDate: '结束日期',
+      operationType: '操作类型',
+      operationTypePlaceholder: '请选择操作类型',
+      materialImage: '物资图片',
+      originalMaterialName: '原物资名称',
+      newMaterialName: '新物资名称',
+      repair: '维修',
+      replacement: '更换'
+    },
+    lockers: {
+      cabinetLocation: '物资柜位置',
+      cabinetList: '物资柜列表',
+      noDataTip: '暂无数据,请到基础数据菜单进行配置',
+      areaNamePlaceholder: '请输入区域名称',
+      cabinetNo: '物资柜编号',
+      cabinetNoPlaceholder: '请输入物资柜编号',
+      cabinetName: '物资柜名称',
+      cabinetNamePlaceholder: '请输入物资柜名称',
+      cabinetImage: '物资柜图片',
+      cabinetStatus: '物资柜状态',
+      exceptionType: '异常类型',
+      cabinetDetail: '物资柜详情',
+      view: '查看',
+      exceptionInfo: '异常信息'
+    }
+  },
+  exception: {
+    manual: {
+      exceptionName: '异常名称',
+      exceptionNamePlaceholder: '请输入异常名称',
+      exceptionType: '异常类型',
+      exceptionTypePlaceholder: '请选择异常类型',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      batchDelete: '批量删除',
+      exceptionNo: '异常编号',
+      dialogTitle: '添加或修改异常对话框',
+      remarkPlaceholder: '请输入备注',
+      exceptionNameRequired: '异常名称不能为空',
+      exceptionTypeRequired: '异常类型不能为空',
+      addException: '添加异常',
+      editException: '修改异常',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除异常编号为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    management: {
+      cabinet: '物资柜',
+      cabinetPlaceholder: '请选择物资柜',
+      materialName: '物资名称',
+      materialNamePlaceholder: '请输入物资名称',
+      returnPerson: '归还人',
+      returnPersonPlaceholder: '请输入归还人',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      exceptionTime: '异常发生时间',
+      startDate: '开始日期',
+      endDate: '结束日期',
+      exceptionResolveTime: '异常解除时间',
+      no: '编号',
+      returnCabinet: '归还柜',
+      rfid: 'rfid'
+    },
+    doorException: {
+      cabinet: '物资柜',
+      cabinetPlaceholder: '请选择物资柜',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      exceptionTime: '异常发生时间',
+      startDate: '开始日期',
+      endDate: '结束日期',
+      exceptionResolveTime: '异常解除时间',
+      no: '编号'
+    }
+  },
+  email: {
+    template: {
+      templateName: '模板名称',
+      templateNamePlaceholder: '请输入模板名称',
+      templateType: '模板类型',
+      templateTypePlaceholder: '请选择模板类型',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      batchDelete: '批量删除',
+      templateNo: '模板编号',
+      dialogTitle: '添加或修改邮件模板对话框',
+      remarkPlaceholder: '请输入备注',
+      templateNameRequired: '模板名称不能为空',
+      templateTypeRequired: '模板类型不能为空',
+      addTemplate: '添加邮件模板',
+      editTemplate: '修改邮件模板',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除模板编号为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    notify: {
+      notifyName: '通知名称',
+      notifyNamePlaceholder: '请输入通知名称',
+      notifyType: '通知类型',
+      notifyTypePlaceholder: '请选择通知类型',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      batchDelete: '批量删除',
+      notifyNo: '通知编号',
+      dialogTitle: '添加或修改邮件通知对话框',
+      remarkPlaceholder: '请输入备注',
+      notifyNameRequired: '通知名称不能为空',
+      notifyTypeRequired: '通知类型不能为空',
+      addNotify: '添加邮件通知',
+      editNotify: '修改邮件通知',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除通知编号为的数据项?',
+      deleteSuccess: '删除成功'
+    }
+  },
+  systemOther: {
+    menu: {
+      menuName: '菜单名称',
+      menuNamePlaceholder: '请输入菜单名称',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      menuNo: '菜单编号',
+      icon: '图标',
+      sort: '排序',
+      dialogTitle: '添加或修改菜单对话框',
+      parentMenu: '上级菜单',
+      parentMenuPlaceholder: '选择上级菜单',
+      menuType: '菜单类型',
+      directory: '目录',
+      menu: '菜单',
+      button: '按钮',
+      routePath: '路由地址',
+      routePathPlaceholder: '请输入路由地址',
+      componentPath: '组件路径',
+      componentPathPlaceholder: '请输入组件路径',
+      permissionKey: '权限标识',
+      permissionKeyPlaceholder: '请输入权限标识',
+      menuIcon: '菜单图标',
+      displaySort: '显示排序',
+      isExternal: '是否外链',
+      isCache: '是否缓存',
+      isShow: '是否显示',
+      parentMenuRequired: '上级菜单不能为空',
+      menuNameRequired: '菜单名称不能为空',
+      routePathRequired: '路由地址不能为空',
+      addMenu: '添加菜单',
+      editMenu: '修改菜单',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除菜单编号为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    dict: {
+      dictName: '字典名称',
+      dictNamePlaceholder: '请输入字典名称',
+      dictType: '字典类型',
+      dictTypePlaceholder: '请输入字典类型',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      dictNo: '字典编号',
+      createTime: '创建时间',
+      dictData: '字典数据',
+      dialogTitle: '添加或修改字典类型对话框',
+      remarkPlaceholder: '请输入备注',
+      dictNameRequired: '字典名称不能为空',
+      dictTypeRequired: '字典类型不能为空',
+      addDictType: '添加字典类型',
+      editDictType: '修改字典类型',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除字典编号为的数据项?',
+      deleteSuccess: '删除成功',
+      data: {
+        dictLabel: '字典标签',
+        dictLabelPlaceholder: '请输入字典标签',
+        dataStatus: '数据状态',
+        dictCode: '字典编码',
+        dictKey: '字典键值',
+        dictSort: '字典排序',
+        dialogTitle: '添加或修改参数配置对话框',
+        dictType: '字典类型',
+        dataLabel: '数据标签',
+        dataLabelPlaceholder: '请输入数据标签',
+        dataKey: '数据键值',
+        dataKeyPlaceholder: '请输入数据键值',
+        styleAttr: '样式属性',
+        styleAttrPlaceholder: '请输入样式属性',
+        displaySort: '显示排序',
+        echoStyle: '回显样式',
+        default: '默认',
+        primary: '主要',
+        success: '成功',
+        info: '信息',
+        warning: '警告',
+        danger: '危险',
+        dataLabelRequired: '数据标签不能为空',
+        dataKeyRequired: '数据键值不能为空',
+        dataSortRequired: '数据顺序不能为空'
+      }
+    },
+    notice: {
+      noticeTitle: '公告标题',
+      noticeTitlePlaceholder: '请输入公告标题',
+      noticeType: '公告类型',
+      noticeTypePlaceholder: '请选择公告类型',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      noticeNo: '公告编号',
+      createTime: '创建时间',
+      dialogTitle: '添加或修改公告对话框',
+      noticeContent: '公告内容',
+      noticeTitleRequired: '公告标题不能为空',
+      noticeTypeRequired: '公告类型不能为空',
+      addNotice: '添加公告',
+      editNotice: '修改公告',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除公告编号为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    config: {
+      paramName: '参数名称',
+      paramNamePlaceholder: '请输入参数名称',
+      paramKey: '参数键名',
+      paramKeyPlaceholder: '请输入参数键名',
+      paramType: '参数类型',
+      paramTypePlaceholder: '请选择参数类型',
+      refreshCache: '刷新缓存',
+      paramNo: '参数编号',
+      paramValue: '参数键值',
+      dialogTitle: '添加或修改参数配置对话框',
+      paramValuePlaceholder: '请输入参数键值',
+      remarkPlaceholder: '请输入备注',
+      paramNameRequired: '参数名称不能为空',
+      paramKeyRequired: '参数键名不能为空',
+      paramValueRequired: '参数键值不能为空',
+      addParam: '添加参数',
+      editParam: '修改参数',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除参数编号为的数据项?',
+      deleteSuccess: '删除成功',
+      refreshSuccess: '刷新成功'
+    },
+    autocode: {
+      ruleName: '规则名称',
+      ruleNamePlaceholder: '请输入规则名称',
+      ruleType: '规则类型',
+      ruleTypePlaceholder: '请选择规则类型',
+      status: '状态',
+      statusPlaceholder: '请选择状态',
+      ruleNo: '规则编号',
+      ruleComposition: '规则组成',
+      dialogTitle: '添加或修改自动编码规则对话框',
+      remarkPlaceholder: '请输入备注',
+      ruleNameRequired: '规则名称不能为空',
+      ruleTypeRequired: '规则类型不能为空',
+      addRule: '添加规则',
+      editRule: '修改规则',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除规则编号为的数据项?',
+      deleteSuccess: '删除成功'
+    },
+    configuration: {
+      paramName: '参数名称',
+      paramNamePlaceholder: '请输入参数名称',
+      paramKey: '参数键名',
+      paramKeyPlaceholder: '请输入参数键名',
+      paramValue: '参数键值',
+      paramValuePlaceholder: '请输入参数键值',
+      refreshCache: '刷新缓存',
+      paramType: '参数类型',
+      dialogTitle: '添加或修改基础数据配置对话框',
+      paramTypePlaceholder: '请选择参数类型',
+      valueType: '键值类型',
+      text: '文字',
+      image: '图片',
+      remarkPlaceholder: '请输入备注',
+      refreshSuccess: '刷新成功'
+    },
+    mapConfig: {
+      mapName: '地图名称',
+      mapNamePlaceholder: '请输入地图名称',
+      fingerprintFaceImport: '指纹人脸导入',
+      mapNo: '地图编号',
+      mapShortName: '地图简称',
+      mapImage: '地图图片',
+      mapWidth: '地图宽度',
+      mapHeight: '地图高度',
+      xCoordinate: '横坐标',
+      yCoordinate: '纵坐标',
+      createTime: '创建时间',
+      detail: '详情',
+      dialogTitle: '添加或修改参数配置对话框',
+      mapWidthPlaceholder: '请输入图片宽度',
+      mapHeightPlaceholder: '请输入图片高度',
+      xCoordinatePlaceholder: '请输入横坐标',
+      yCoordinatePlaceholder: '请输入纵坐标',
+      userNamePlaceholder: '请输入userName',
+      fingerprintImport: '指纹导入',
+      faceImport: '人脸导入',
+      fingerprintLogin: '指纹登录',
+      faceLogin: '人脸登录',
+      uploadTip: '将文件拖到此处,或点击上传',
+      updateExisting: '是否更新已经存在的设备数据',
+      fileFormat: '仅允许导入xls、xlsx格式文件。',
+      editSuccess: '修改成功',
+      addSuccess: '新增成功',
+      deleteConfirm: '是否确认删除所选数据项?',
+      deleteSuccess: '删除成功'
+    },
+    mapPoint: {
+      mapName: '地图名称',
+      import: '导入',
+      mapPointNo: '地图点位编号',
+      mapType: '地图类型',
+      entityName: '实体名称',
+      xCoordinate: '横坐标',
+      yCoordinate: '纵坐标',
+      createTime: '创建时间',
+      dialogTitle: '添加或修改参数配置对话框',
+      entity: '实体',
+      entityPlaceholder: '选择实体'
+    }
+  }
+}
+

+ 19 - 13
src/layout/components/Navbar.vue

@@ -9,13 +9,13 @@
       <template v-if="device!=='mobile'">
       <template v-if="device!=='mobile'">
         <search id="header-search" class="right-menu-item" />
         <search id="header-search" class="right-menu-item" />
 
 
-        <el-tooltip content="源码地址" effect="dark" placement="bottom">
-          <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
-        </el-tooltip>
+<!--        <el-tooltip content="源码地址" effect="dark" placement="bottom">-->
+<!--          <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />-->
+<!--        </el-tooltip>-->
 
 
-        <el-tooltip content="文档地址" effect="dark" placement="bottom">
-          <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
-        </el-tooltip>
+<!--        <el-tooltip content="文档地址" effect="dark" placement="bottom">-->
+<!--          <ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />-->
+<!--        </el-tooltip>-->
 
 
         <screenfull id="screenfull" class="right-menu-item hover-effect" />
         <screenfull id="screenfull" class="right-menu-item hover-effect" />
 
 
@@ -23,6 +23,10 @@
           <size-select id="size-select" class="right-menu-item hover-effect" />
           <size-select id="size-select" class="right-menu-item hover-effect" />
         </el-tooltip>
         </el-tooltip>
 
 
+        <el-tooltip :content="$t('navbar.language') || '语言切换'" effect="dark" placement="bottom">
+          <lang-select id="lang-select" class="right-menu-item hover-effect" />
+        </el-tooltip>
+
       </template>
       </template>
 
 
       <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
       <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
@@ -32,13 +36,13 @@
         </div>
         </div>
         <el-dropdown-menu slot="dropdown">
         <el-dropdown-menu slot="dropdown">
           <router-link to="/user/profile">
           <router-link to="/user/profile">
-            <el-dropdown-item>个人中心</el-dropdown-item>
+            <el-dropdown-item>{{ $t('navbar.profile') }}</el-dropdown-item>
           </router-link>
           </router-link>
           <el-dropdown-item @click.native="setting = true">
           <el-dropdown-item @click.native="setting = true">
-            <span>布局设置</span>
+            <span>{{ $t('navbar.layoutSettings') }}</span>
           </el-dropdown-item>
           </el-dropdown-item>
           <el-dropdown-item divided @click.native="logout">
           <el-dropdown-item divided @click.native="logout">
-            <span>退出登录</span>
+            <span>{{ $t('navbar.logout') }}</span>
           </el-dropdown-item>
           </el-dropdown-item>
         </el-dropdown-menu>
         </el-dropdown-menu>
       </el-dropdown>
       </el-dropdown>
@@ -56,6 +60,7 @@ import SizeSelect from '@/components/SizeSelect'
 import Search from '@/components/HeaderSearch'
 import Search from '@/components/HeaderSearch'
 import RuoYiGit from '@/components/RuoYi/Git'
 import RuoYiGit from '@/components/RuoYi/Git'
 import RuoYiDoc from '@/components/RuoYi/Doc'
 import RuoYiDoc from '@/components/RuoYi/Doc'
+import LangSelect from '@/components/LangSelect'
 
 
 export default {
 export default {
   components: {
   components: {
@@ -66,7 +71,8 @@ export default {
     SizeSelect,
     SizeSelect,
     Search,
     Search,
     RuoYiGit,
     RuoYiGit,
-    RuoYiDoc
+    RuoYiDoc,
+    LangSelect
   },
   },
   computed: {
   computed: {
     ...mapGetters([
     ...mapGetters([
@@ -96,9 +102,9 @@ export default {
       this.$store.dispatch('app/toggleSideBar')
       this.$store.dispatch('app/toggleSideBar')
     },
     },
     async logout() {
     async logout() {
-      this.$confirm('确定注销并退出系统吗?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
+      this.$confirm(this.$t('navbar.logoutConfirm'), this.$t('navbar.tip'), {
+        confirmButtonText: this.$t('common.confirm'),
+        cancelButtonText: this.$t('common.cancel'),
         type: 'warning'
         type: 'warning'
       }).then(() => {
       }).then(() => {
         this.$store.dispatch('LogOut').then(() => {
         this.$store.dispatch('LogOut').then(() => {

+ 4 - 1
src/main.js

@@ -15,6 +15,7 @@ import router from './router'
 import directive from './directive' // directive
 import directive from './directive' // directive
 import plugins from './plugins' // plugins
 import plugins from './plugins' // plugins
 import { download } from '@/utils/request'
 import { download } from '@/utils/request'
+import i18n from './i18n' // 国际化
 
 
 import './assets/icons' // icon
 import './assets/icons' // icon
 import './permission' // permission control
 import './permission' // permission control
@@ -114,7 +115,8 @@ Vue.directive('noMoreClick', {
   }
   }
 })
 })
 Vue.use(Element, {
 Vue.use(Element, {
-  size: Cookies.get('size') || 'medium' // set element-ui default size
+  size: Cookies.get('size') || 'medium', // set element-ui default size
+  i18n: (key, value) => i18n.t(key, value) // element-ui 国际化
 })
 })
 
 
 Vue.config.productionTip = false
 Vue.config.productionTip = false
@@ -123,5 +125,6 @@ new Vue({
   el: '#app',
   el: '#app',
   router,
   router,
   store,
   store,
+  i18n,
   render: h => h(App)
   render: h => h(App)
 })
 })

+ 1 - 0
src/store/getters.js

@@ -14,5 +14,6 @@ const getters = {
   topbarRouters:state => state.permission.topbarRouters,
   topbarRouters:state => state.permission.topbarRouters,
   defaultRoutes:state => state.permission.defaultRoutes,
   defaultRoutes:state => state.permission.defaultRoutes,
   sidebarRouters:state => state.permission.sidebarRouters,
   sidebarRouters:state => state.permission.sidebarRouters,
+  language: state => state.i18n.language,
 }
 }
 export default getters
 export default getters

+ 3 - 1
src/store/index.js

@@ -7,6 +7,7 @@ import permission from './modules/permission'
 import settings from './modules/settings'
 import settings from './modules/settings'
 import getters from './getters'
 import getters from './getters'
 import sopSelectPoints from './modules/sopSelectPoints'
 import sopSelectPoints from './modules/sopSelectPoints'
+import i18n from './modules/i18n'
 Vue.use(Vuex)
 Vue.use(Vuex)
 
 
 const store = new Vuex.Store({
 const store = new Vuex.Store({
@@ -16,7 +17,8 @@ const store = new Vuex.Store({
     tagsView,
     tagsView,
     permission,
     permission,
     settings,
     settings,
-    sopSelectPoints
+    sopSelectPoints,
+    i18n
   },
   },
   getters
   getters
 })
 })

+ 26 - 0
src/store/modules/i18n.js

@@ -0,0 +1,26 @@
+import Cookies from 'js-cookie'
+
+const state = {
+  language: Cookies.get('language') || 'zh'
+}
+
+const mutations = {
+  SET_LANGUAGE: (state, language) => {
+    state.language = language
+    Cookies.set('language', language)
+  }
+}
+
+const actions = {
+  setLanguage({ commit }, language) {
+    commit('SET_LANGUAGE', language)
+  }
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}
+

+ 5 - 0
src/utils/request.js

@@ -32,6 +32,11 @@ window.addEventListener('online', () => {
 
 
 // request拦截器
 // request拦截器
 service.interceptors.request.use(config => {
 service.interceptors.request.use(config => {
+  // 设置 Accept-Language 请求头
+  const language = store.getters.language || 'zh'
+  const acceptLanguage = language === 'en' ? 'en-US' : 'zh-CN'
+  config.headers['Accept-Language'] = acceptLanguage
+  
   // 检查网络状态
   // 检查网络状态
   if (!navigator.onLine) {
   if (!navigator.onLine) {
     // 如果还未显示网络错误提示,则显示一次
     // 如果还未显示网络错误提示,则显示一次

+ 9 - 3
src/views/dashboard/LineChart.vue

@@ -43,6 +43,12 @@ export default {
       handler(val) {
       handler(val) {
         this.setOptions(val);
         this.setOptions(val);
       }
       }
+    },
+    '$i18n.locale'() {
+      // 语言切换时重新设置图表选项
+      if (this.chartData) {
+        this.setOptions(this.chartData);
+      }
     }
     }
   },
   },
   mounted() {
   mounted() {
@@ -99,11 +105,11 @@ export default {
             }
             }
           },
           },
           legend: {
           legend: {
-            data: ['领取', '归还']
+            data: [this.$t('dashboard.loan'), this.$t('dashboard.return')]
           },
           },
           series: [
           series: [
             {
             {
-              name: '领取',
+              name: this.$t('dashboard.loan'),
               itemStyle: {
               itemStyle: {
                 normal: {
                 normal: {
                   color: '#FF005A',
                   color: '#FF005A',
@@ -121,7 +127,7 @@ export default {
               animationEasing: 'cubicInOut'
               animationEasing: 'cubicInOut'
             },
             },
             {
             {
-              name: '归还',
+              name: this.$t('dashboard.return'),
               smooth: true,
               smooth: true,
               type: 'bar',
               type: 'bar',
 
 

+ 4 - 4
src/views/dashboard/PanelGroup.vue

@@ -7,7 +7,7 @@
         </div>
         </div>
         <div class="card-panel-description">
         <div class="card-panel-description">
           <div class="card-panel-text">
           <div class="card-panel-text">
-            物资总数
+            {{ $t('dashboard.materialsTotal') }}
           </div>
           </div>
           <count-to :start-val="0" :end-val="materialsCount" :duration="2600" class="card-panel-num" />
           <count-to :start-val="0" :end-val="materialsCount" :duration="2600" class="card-panel-num" />
         </div>
         </div>
@@ -20,7 +20,7 @@
         </div>
         </div>
         <div class="card-panel-description">
         <div class="card-panel-description">
           <div class="card-panel-text">
           <div class="card-panel-text">
-            柜中物资
+            {{ $t('dashboard.cabinetMaterials') }}
           </div>
           </div>
           <count-to :start-val="0" :end-val="cabinetMaterialsCount" :duration="3000" class="card-panel-num" />
           <count-to :start-val="0" :end-val="cabinetMaterialsCount" :duration="3000" class="card-panel-num" />
         </div>
         </div>
@@ -33,7 +33,7 @@
         </div>
         </div>
         <div class="card-panel-description">
         <div class="card-panel-description">
           <div class="card-panel-text">
           <div class="card-panel-text">
-            借出物资
+            {{ $t('dashboard.loanMaterials') }}
           </div>
           </div>
           <count-to :start-val="0" :end-val="loanMaterialsCount" :duration="3200" class="card-panel-num" />
           <count-to :start-val="0" :end-val="loanMaterialsCount" :duration="3200" class="card-panel-num" />
         </div>
         </div>
@@ -46,7 +46,7 @@
         </div>
         </div>
         <div class="card-panel-description">
         <div class="card-panel-description">
           <div class="card-panel-text">
           <div class="card-panel-text">
-            异常数量
+            {{ $t('dashboard.exceptionCount') }}
           </div>
           </div>
           <count-to :start-val="0" :end-val="exceptionMaterialsCount" :duration="3600" class="card-panel-num" />
           <count-to :start-val="0" :end-val="exceptionMaterialsCount" :duration="3600" class="card-panel-num" />
         </div>
         </div>

+ 6 - 6
src/views/index.vue

@@ -6,7 +6,7 @@
     <el-row :gutter="32" style="padding:0px 16px 0;margin-bottom:32px;">
     <el-row :gutter="32" style="padding:0px 16px 0;margin-bottom:32px;">
       <el-card>
       <el-card>
         <div slot="header" class="clearfix">
         <div slot="header" class="clearfix">
-          <span>进行中的作业</span>
+          <span>{{ $t('dashboard.ongoingJobs') }}</span>
         </div>
         </div>
         <el-table
         <el-table
           height="260"
           height="260"
@@ -26,15 +26,15 @@
           <!--                    >{{scope.row.workorderCode}}</el-button>-->
           <!--                    >{{scope.row.workorderCode}}</el-button>-->
           <!--                    </template>-->
           <!--                    </template>-->
           <!--                </el-table-column>-->
           <!--                </el-table-column>-->
-          <el-table-column label="作业票名称" width="370" align="center" prop="ticketName"/>
-          <el-table-column label="岗位" align="center" prop="workstationName" :show-overflow-tooltip="true"/>
-          <el-table-column label="设备工艺" align="center" prop="machineryName"/>
-          <el-table-column label="作业类型" align="center" prop="ticketType" :show-overflow-tooltip="true">
+          <el-table-column :label="$t('dashboard.ticketName')" width="370" align="center" prop="ticketName"/>
+          <el-table-column :label="$t('dashboard.workstation')" align="center" prop="workstationName" :show-overflow-tooltip="true"/>
+          <el-table-column :label="$t('dashboard.machinery')" align="center" prop="machineryName"/>
+          <el-table-column :label="$t('dashboard.jobType')" align="center" prop="ticketType" :show-overflow-tooltip="true">
             <template slot-scope="scope">
             <template slot-scope="scope">
               <dict-tag :options="dict.type.ticket_type" :value="scope.row.ticketType"/>
               <dict-tag :options="dict.type.ticket_type" :value="scope.row.ticketType"/>
             </template>
             </template>
           </el-table-column>
           </el-table-column>
-          <el-table-column label="启动时间" align="center" prop="ticketStartTime" :show-overflow-tooltip="true"/>
+          <el-table-column :label="$t('dashboard.startTime')" align="center" prop="ticketStartTime" :show-overflow-tooltip="true"/>
 
 
         </el-table>
         </el-table>
       </el-card>
       </el-card>

+ 38 - 17
src/views/login.vue

@@ -1,13 +1,17 @@
 <template>
 <template>
   <div class="login">
   <div class="login">
+    <!-- 右上角语言切换 -->
+    <div class="login-lang-select">
+      <lang-switch />
+    </div>
     <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
     <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
-      <h3 class="title">智能锁控物资管理系统</h3>
+      <h3 class="title">{{ $t('login.systemTitle') }}</h3>
       <el-form-item prop="username">
       <el-form-item prop="username">
         <el-input
         <el-input
           v-model="loginForm.username"
           v-model="loginForm.username"
           type="text"
           type="text"
           auto-complete="off"
           auto-complete="off"
-          placeholder="账号"
+          :placeholder="$t('login.usernamePlaceholder')"
         >
         >
           <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
           <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
         </el-input>
         </el-input>
@@ -17,7 +21,7 @@
           v-model="loginForm.password"
           v-model="loginForm.password"
           type="password"
           type="password"
           auto-complete="off"
           auto-complete="off"
-          placeholder="密码"
+          :placeholder="$t('login.passwordPlaceholder')"
           @keyup.enter.native="handleLogin"
           @keyup.enter.native="handleLogin"
         >
         >
           <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
           <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
@@ -27,7 +31,7 @@
         <el-input
         <el-input
           v-model="loginForm.code"
           v-model="loginForm.code"
           auto-complete="off"
           auto-complete="off"
-          placeholder="验证码"
+          :placeholder="$t('login.codePlaceholder')"
           style="width: 63%"
           style="width: 63%"
           @keyup.enter.native="handleLogin"
           @keyup.enter.native="handleLogin"
         >
         >
@@ -37,7 +41,7 @@
           <img :src="codeUrl" @click="getCode" class="login-code-img"/>
           <img :src="codeUrl" @click="getCode" class="login-code-img"/>
         </div>
         </div>
       </el-form-item>
       </el-form-item>
-      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
+      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">{{ $t('login.rememberMe') }}</el-checkbox>
       <el-form-item style="width:100%;">
       <el-form-item style="width:100%;">
         <el-button v-no-more-click
         <el-button v-no-more-click
           :loading="loading"
           :loading="loading"
@@ -46,11 +50,11 @@
           style="width:100%;"
           style="width:100%;"
           @click.native.prevent="handleLogin"
           @click.native.prevent="handleLogin"
         >
         >
-          <span v-if="!loading">登 录</span>
-          <span v-else>登 录 中...</span>
+          <span v-if="!loading">{{ $t('login.login') }}</span>
+          <span v-else>{{ $t('login.logging') }}</span>
         </el-button>
         </el-button>
         <div style="float: right;" v-if="register">
         <div style="float: right;" v-if="register">
-          <router-link class="link-type" :to="'/register'">立即注册</router-link>
+          <router-link class="link-type" :to="'/register'">{{ $t('login.register') }}</router-link>
         </div>
         </div>
       </el-form-item>
       </el-form-item>
     </el-form>
     </el-form>
@@ -65,9 +69,13 @@
 import { getCodeImg } from "@/api/login";
 import { getCodeImg } from "@/api/login";
 import Cookies from "js-cookie";
 import Cookies from "js-cookie";
 import { encrypt, decrypt } from '@/utils/jsencrypt'
 import { encrypt, decrypt } from '@/utils/jsencrypt'
+import LangSwitch from '@/components/LangSwitch'
 
 
 export default {
 export default {
   name: "Login",
   name: "Login",
+  components: {
+    LangSwitch
+  },
   data() {
   data() {
     return {
     return {
       codeUrl: "",
       codeUrl: "",
@@ -78,15 +86,6 @@ export default {
         code: "",
         code: "",
         uuid: ""
         uuid: ""
       },
       },
-      loginRules: {
-        username: [
-          { required: true, trigger: "blur", message: "请输入您的账号" }
-        ],
-        password: [
-          { required: true, trigger: "blur", message: "请输入您的密码" }
-        ],
-        code: [{ required: true, trigger: "change", message: "请输入验证码" }]
-      },
       loading: false,
       loading: false,
       // 验证码开关
       // 验证码开关
       captchaOnOff: true,
       captchaOnOff: true,
@@ -95,6 +94,19 @@ export default {
       redirect: undefined
       redirect: undefined
     };
     };
   },
   },
+  computed: {
+    loginRules() {
+      return {
+        username: [
+          { required: true, trigger: "blur", message: this.$t('login.usernameRequired') }
+        ],
+        password: [
+          { required: true, trigger: "blur", message: this.$t('login.passwordRequired') }
+        ],
+        code: [{ required: true, trigger: "change", message: this.$t('login.codeRequired') }]
+      }
+    }
+  },
   watch: {
   watch: {
     $route: {
     $route: {
       handler: function(route) {
       handler: function(route) {
@@ -131,6 +143,7 @@ export default {
       };
       };
     },
     },
     handleLogin() {
     handleLogin() {
+  
       this.$refs.loginForm.validate(valid => {
       this.$refs.loginForm.validate(valid => {
         if (valid) {
         if (valid) {
           this.loading = true;
           this.loading = true;
@@ -166,6 +179,14 @@ export default {
   height: 100%;
   height: 100%;
   background-image: url("../assets/images/login-background.jpg");
   background-image: url("../assets/images/login-background.jpg");
   background-size: cover;
   background-size: cover;
+  position: relative;
+}
+
+.login-lang-select {
+  position: absolute;
+  top: 20px;
+  right: 20px;
+  z-index: 1000;
 }
 }
 .title {
 .title {
   margin: 0px auto 30px auto;
   margin: 0px auto 30px auto;

+ 1 - 1
vue.config.js

@@ -36,7 +36,7 @@ module.exports = {
       // detail: https://cli.vuejs.org/config/#devserver-proxy
       // detail: https://cli.vuejs.org/config/#devserver-proxy
       [process.env.VUE_APP_BASE_API]: {
       [process.env.VUE_APP_BASE_API]: {
         // http://36.133.174.236:9090  http://192.168.0.10:9190 http://192.168.31.110:9090(动感光波) 192.168.28.97:9090(车总GRKJ) 120.27.232.27:9190(东上阿里云)
         // http://36.133.174.236:9090  http://192.168.0.10:9190 http://192.168.31.110:9090(动感光波) 192.168.28.97:9090(车总GRKJ) 120.27.232.27:9190(东上阿里云)
-        target: `http://120.27.232.27:9190`,
+        target: `http://192.168.0.10:9190`,
         changeOrigin: true,
         changeOrigin: true,
         pathRewrite: {
         pathRewrite: {
           ['^' + process.env.VUE_APP_BASE_API]: ''
           ['^' + process.env.VUE_APP_BASE_API]: ''