lrf há 1 ano atrás
pai
commit
3c466ffc48

+ 1 - 1
index.html

@@ -4,7 +4,7 @@
     <meta charset="UTF-8">
     <link rel="icon" href="/favicon.ico">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Vite App</title>
+    <title>项目名</title>
   </head>
   <body>
     <div id="app" class="app"></div>

+ 3 - 4
src/components/Breadcrumb/index.vue

@@ -3,10 +3,10 @@
     <transition-group name="breadcrumb-transition">
       <el-breadcrumb-item v-for="(item, index) in breadcrumbs" :key="item.path">
         <span v-if="item.redirect === 'noredirect' || index === breadcrumbs.length - 1" class="text-[var(--el-disabled-text-color)]">
-          {{ translateRouteTitle(item.meta.title) }}
+          {{ $t(item.meta.title) }}
         </span>
         <a v-else @click.prevent="handleLink(item)">
-          {{ translateRouteTitle(item.meta.title) }}
+          {{ $t(item.meta.title) }}
         </a>
       </el-breadcrumb-item>
     </transition-group>
@@ -18,7 +18,6 @@ import { onBeforeMount, ref, watch } from 'vue'
 import { useRoute } from 'vue-router'
 import { compile } from 'path-to-regexp'
 import router from '@/router'
-import { translateRouteTitle } from '@/utils/i18n'
 
 const currentRoute = useRoute()
 const pathCompile = (path) => {
@@ -33,7 +32,7 @@ function getBreadcrumb() {
   let matched = currentRoute.matched.filter((item) => item.meta && item.meta.title)
   const first = matched[0]
   if (!isDashboard(first)) {
-    matched = [{ path: '/', meta: { title: 'dashboard' } }].concat(matched)
+    matched = [{ path: '/', meta: { title: 'menus.home' } }].concat(matched)
   }
   breadcrumbs.value = matched.filter((item) => {
     return item.meta && item.meta.title && item.meta.breadcrumb !== false

+ 5 - 1
src/lang/package/zh-cn/common.js

@@ -5,6 +5,10 @@ export default {
   delete: '删除',
   search: '查询',
   view: '查看',
+  save: '保存',
+  submit: '提交',
   is_use_use: '启用',
-  is_use_notUse: '禁用'
+  is_use_notUse: '禁用',
+  yes: '是',
+  no: '否'
 }

+ 9 - 0
src/lang/package/zh-cn/menus.js

@@ -0,0 +1,9 @@
+export default {
+  home: '首页',
+  system: '系统设置',
+  system_menus: '菜单设置',
+  system_role: '角色设置',
+  system_parameter: '系统参数',
+  system_dict: '字典管理',
+  system_dict_data: '字典数据'
+}

+ 12 - 1
src/lang/package/zh-cn/pages.js

@@ -2,14 +2,25 @@ export default {
   menus: {
     dialogTitle: '菜单信息',
     name: '菜单名称',
+    namePh: '请填写菜单名称',
+    route_name: '路由名称',
+    route_namePh: '请填写路由名称',
+    i18n_code: '国际化编码',
+    i18n_codePh: '请填写国际化编码并确保与国际化文件中的编码一致',
     parentName: '父级菜单',
     icon: '图标',
+    iconPh: '请选择图标',
     order_num: '顺序',
     path: '路由地址',
+    pathPh: '请填写路由地址',
     component: '组件地址',
+    componentPh: '请填写组件地址',
     type: '菜单类型',
+    typePh: '请选择菜单类型',
     is_use: '状态',
     remark: '备注',
-    addNext: '添加下一级'
+    remarkPh: '请输入备注',
+    addNext: '添加下一级',
+    baseInfo: '基本信息'
   }
 }

+ 3 - 3
src/layout/parts/breadcrumb.vue

@@ -64,7 +64,7 @@ const appStore = useAppStore()
 const { visitedViews } = storeToRefs(tagsViewStore)
 const settingsStore = useSettingsStore()
 const layout = computed(() => settingsStore.layout)
-
+const { t } = useI18n()
 const selectedTag = ref({
   path: '',
   fullPath: '',
@@ -140,7 +140,7 @@ function addTags() {
   if (route.meta.title) {
     tagsViewStore.addView({
       name: route.name,
-      title: route.meta.title,
+      title: t(route.meta.title),
       path: route.path,
       fullPath: route.fullPath,
       affix: route.meta?.affix,
@@ -391,7 +391,7 @@ onMounted(() => {
         width: 8px;
         height: 8px;
         margin-right: 5px;
-        content: "";
+        content: '';
         background: #fff;
         border-radius: 50%;
       }

+ 2 - 2
src/layout/parts/sidebar/items.vue

@@ -4,7 +4,7 @@
       <el-sub-menu :index="item._id" :key="item._id">
         <template #title>
           <i :class="['iconfont', item.icon]"></i>
-          <span>{{ item.name }}</span>
+          <span>{{ $t(item.i18n_code) }}</span>
         </template>
         <menu-item :items="item.children"></menu-item>
       </el-sub-menu>
@@ -12,7 +12,7 @@
     <template v-else-if="item.type === '1'">
       <el-menu-item :index="item.path" :key="item.path">
         <i :class="['iconfont', item.icon]"></i>
-        <span>{{ item.name }}</span>
+        <span>{{ $t(item.i18n_code) }}</span>
       </el-menu-item>
     </template>
   </template>

+ 1 - 1
src/main.js

@@ -21,5 +21,5 @@ setupStore(app)
 for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
   app.component(key, component)
 }
-app.use(router).use(i18n).mount('#app')
+app.use(i18n).use(router).mount('#app')
 InitCheckResult(app)

+ 46 - 26
src/router/guard.js

@@ -3,6 +3,7 @@ import { checkResult } from '@/utils/checkResult'
 import { UserStore } from '@/store/user'
 import { cloneDeep, omit } from 'lodash-es'
 import { translateRouteTitle } from '@/utils/i18n'
+import i18n from '@/lang/index'
 // 检查路由是否存在
 const hasNecessaryRoute = (to, router) => {
   // 将默认注册的路由平铺成一维数组
@@ -31,7 +32,6 @@ const getUserMeta = async (token) => {
 // 注册前置守卫
 export const registerBeforeRouter = async (router) => {
   router.beforeEach(async (to, from, next) => {
-    document.title = `${translateRouteTitle(to.meta.title)} `
     const token = localStorage.getItem('token')
     if (to.path === '/login') {
       next()
@@ -70,42 +70,62 @@ const toOneDimensional = (routes) => {
   return result
 }
 // 添加路由
-export const addUserRoutes = async (menus, router) => {
+const addUserRoutes = async (menus, router) => {
   return new Promise((resolve, reject) => {
     // 将用户菜单转换成普通对象
     const menuArr = toRaw(menus)
     // 将用户菜单平铺成一维数组,并将目录过滤出去.目录不需要注册,不是组件
-    const menuOneDimensional = toOneDimensional(menuArr).filter((f) => f.type !== '0')
+    const menuOneDimensional = toOneDimensional(menuArr)
     // 将默认注册的路由平铺成一维数组
     const routesOneDimensional = toOneDimensional(router.getRoutes())
-    // 过滤出需要注册的路由数据
-    const needRegistRoute = menuOneDimensional.filter((f) => !routesOneDimensional.find((od) => od.path === f.path))
-    const loadComponent = import.meta.glob('../views/**/*.vue')
-    // 注册路由
-    for (const r of needRegistRoute) {
-      let { path, component, route_name: name, name: title, in_admin_frame } = r
-      // 判断有没有route_name,没有就用component地址最后两个拼一起
-      if (!name) {
-        const list = component.split('/')
-        name = list.shift().join('')
+    routesRegister(menuOneDimensional, routesOneDimensional, router)
+    resolve()
+  })
+}
+/**
+ * 注册路由
+ * @param {Array} menus 一维数组菜单
+ * @param {Array} defaultRoutes 默认路由一维数组
+ * @param {*} router 路由实例
+ */
+const routesRegister = (menus, defaultRoutes, router) => {
+  // 默认注册位置
+  const __def = 'Layout'
+  const loadComponent = import.meta.glob('../views/**/*.vue')
+  for (const route of menus) {
+    const { type, route_name, path, component, parent_id, i18n_code } = route
+    // 检查路由是否已存在,存在跳过
+    const hasRoute = defaultRoutes.find((f) => f.path === path)
+    if (hasRoute) continue
+    if (type === '0') {
+      // 目录, 默认使用 `/${路由名称}`
+      const route = {
+        path: `/${route_name}`,
+        name: route_name
       }
-      const c = {
-        path,
-        name,
-        component: loadComponent[`../views${component}.vue`],
+      router.addRoute(__def, route)
+    } else if (type === '1' || type === '2') {
+      // 菜单 或 子菜单
+      const route = {
+        path: path,
+        name: route_name,
         meta: {
-          title,
-          affix: false,
-          keepAlive: false,
-          alwaysShow: false
-        }
+          title: i18n_code
+        },
+        component: loadComponent[`../views${component}.vue`]
+      }
+      if (parent_id) {
+        const parent = menus.find((f) => f._id === parent_id)
+        if (!parent) continue
+        const pos = parent.route_name
+        router.addRoute(pos, route)
+      } else {
+        router.addRoute(__def, route)
       }
-      if (in_admin_frame === '0') router.addRoute('system', c)
-      else router.addRoute(c)
     }
-    resolve()
-  })
+  }
 }
+
 const resetMenus = (menus) => {
   const cMenus = cloneDeep(menus)
   const result = []

+ 1 - 32
src/router/index.js

@@ -24,6 +24,7 @@ export const constantRoutes = [
   },
   {
     path: '/',
+    name: 'Layout',
     component: Layout,
     children: [
       {
@@ -40,38 +41,6 @@ export const constantRoutes = [
       {
         path: '/system',
         name: 'system'
-        //   children: [
-        //     {
-        //       path: '/system/menus',
-        //       meta: { title: 'menus' },
-        //       component: () => import('@/views/system/menus/index.vue')
-        //     },
-        //     {
-        //       path: '/system/role',
-        //       meta: { title: 'role' },
-        //       component: () => import('@/views/system/role/index.vue')
-        //     },
-        //     {
-        //       path: '/system/dict',
-        //       meta: { title: 'dict' },
-        //       component: () => import('@/views/system/dict/index.vue')
-        //     },
-        //     {
-        //       path: '/system/dictData',
-        //       meta: { title: 'dictData' },
-        //       component: () => import('@/views/system/dictData/index.vue')
-        //     },
-        //     {
-        //       path: '/system/config',
-        //       meta: { title: 'config' },
-        //       component: () => import('@/views/system/config/index.vue')
-        //     },
-        //     {
-        //       path: '/system/module',
-        //       meta: { title: 'module' },
-        //       component: () => import('@/views/system/module/index.vue')
-        //     }
-        //   ]
       },
       {
         path: '401',

+ 1 - 1
src/views/system/menus/index.vue

@@ -1,7 +1,7 @@
 <template>
   <el-row>
     <el-col :span="24" style="text-align: right; padding: 10px">
-      <el-button type="primary" size="small" @click="toAdd()">添加</el-button>
+      <el-button type="primary" size="small" @click="toAdd()">{{ $t('common.add') }}</el-button>
     </el-col>
     <el-col :span="24">
       <menu-table></menu-table>

+ 3 - 6
src/views/system/menus/parts/menu-info.vue

@@ -1,6 +1,6 @@
 <template>
   <el-tabs v-model="tab" type="card">
-    <el-tab-pane label="基本信息" name="basic">
+    <el-tab-pane :label="$t('pages.menus.baseInfo')" name="basic">
       <info v-bind="$attrs"></info>
     </el-tab-pane>
 
@@ -33,7 +33,7 @@
   </el-tabs>
   <el-row type="flex" justify="space-around" style="margin-top: 10px">
     <el-col :span="6">
-      <el-button @click="toSave" size="small" type="primary">保存</el-button>
+      <el-button @click="toSave" size="small" type="primary">{{ $t('common.save') }}</el-button>
     </el-col>
   </el-row>
 </template>
@@ -41,10 +41,7 @@
 <script setup>
 import info from './parts/info.vue'
 const tab = ref('basic')
-const emits = defineEmits(['toSave'])
-const toSave = () => {
-  emits('toSave')
-}
+const toSave = inject('toSave')
 </script>
 
 <style scoped></style>

+ 8 - 5
src/views/system/menus/parts/menu-table.vue

@@ -1,21 +1,24 @@
 <template>
   <div id="menu-table">
     <el-table :data="data" row-key="_id" border>
-      <el-table-column align="center" :label="$t('pages.menus.name')" prop="name"></el-table-column>
-      <el-table-column align="center" :label="$t('pages.menus.parentName')" prop="parent_name"></el-table-column>
+      <el-table-column align="center" :label="$t('pages.menus.order_num')" sortable prop="order_num" width="80"></el-table-column>
       <el-table-column align="center" :label="$t('pages.menus.icon')" width="80">
         <template #default="{ row }"><span :class="['iconfont', row.icon]"></span></template>
       </el-table-column>
-      <el-table-column align="center" :label="$t('pages.menus.order_num')" sortable prop="order_num" width="80"></el-table-column>
+      <el-table-column align="center" :label="$t('pages.menus.name')" prop="name"></el-table-column>
+      <el-table-column align="center" :label="$t('pages.menus.route_name')" prop="route_name"></el-table-column>
+      <el-table-column align="center" :label="$t('pages.menus.i18n_code')" prop="i18n_code"></el-table-column>
+      <el-table-column align="center" :label="$t('pages.menus.parentName')" prop="parent_name"></el-table-column>
+
       <el-table-column align="center" :label="$t('pages.menus.path')" prop="path"></el-table-column>
       <el-table-column align="center" :label="$t('pages.menus.component')" prop="component"></el-table-column>
-      <el-table-column align="center" :label="$t('pages.menus.parentName')" prop="type">
+      <el-table-column align="center" :label="$t('pages.menus.type')" prop="type" width="100">
         <template #default="{ row }">{{ getType(row) }} </template>
       </el-table-column>
       <el-table-column align="center" :label="$t('pages.menus.is_use')" prop="is_use" width="80">
         <template #default="{ row }">{{ getStatus(row) }} </template>
       </el-table-column>
-      <el-table-column align="center" :label="$t('pages.menus.remark')" prop="remark"> </el-table-column>
+      <el-table-column align="center" :label="$t('pages.menus.remark')" prop="remark" width="100"> </el-table-column>
       <el-table-column align="center" :label="$t('common.opera')">
         <template #default="{ row }">
           <el-link :underline="false" type="primary" size="mini" @click="toUpdate(row)" style="margin-right: 10px">{{ $t('common.update') }}</el-link>

+ 26 - 34
src/views/system/menus/parts/parts/info.vue

@@ -1,45 +1,52 @@
 <template>
-  <el-form label-position="left" label-width="80px">
+  <el-form label-position="left" label-width="100px">
     <el-form-item :label="$t('pages.menus.name')">
-      <el-input v-model="form.name" placeholder="请填写菜单名称"></el-input>
+      <el-input v-model="form.name" :placeholder="$t('pages.menus.namePh')"></el-input>
     </el-form-item>
-    <el-form-item label="菜单类型">
-      <el-select v-model="form.type" placeholder="请选择菜单类型">
+    <el-form-item :label="$t('pages.menus.route_name')">
+      <el-input v-model="form.route_name" :placeholder="$t('pages.menus.route_namePh')"></el-input>
+    </el-form-item>
+    <el-form-item :label="$t('pages.menus.i18n_code')">
+      <el-input v-model="form.i18n_code" :placeholder="$t('pages.menus.i18n_codePh')"></el-input>
+    </el-form-item>
+
+    <el-form-item :label="$t('pages.menus.type')">
+      <el-select v-model="form.type" :placeholder="$t('pages.menus.typePh')">
         <el-option v-for="(i, index) in typeList" :key="`t${index}`" :label="i.label" :value="i.value"></el-option>
       </el-select>
     </el-form-item>
-    <el-form-item label="父级菜单">
+    <el-form-item :label="$t('pages.menus.parentName')">
       <el-select v-model="form.parent_id" placeholder="" :disabled="true">
         <el-option v-for="(i, index) in getOneDimensionList()" :key="`m${index}`" :label="i.name" :value="i._id"></el-option>
       </el-select>
     </el-form-item>
     <template v-if="form.type === '1' || form.type === '2'">
-      <el-form-item label="路由地址">
-        <el-input v-model="form.path" placeholder="请填写路由地址"></el-input>
+      <el-form-item :label="$t('pages.menus.path')">
+        <el-input v-model="form.path" :placeholder="$t('pages.menus.pathPh')"></el-input>
       </el-form-item>
-      <el-form-item label="组件地址">
-        <el-input v-model="form.component" placeholder="请填写组件地址"></el-input>
+      <el-form-item :label="$t('pages.menus.component')">
+        <el-input v-model="form.component" :placeholder="$t('pages.menus.componentPh')"></el-input>
       </el-form-item>
     </template>
-    <el-form-item label="顺序">
+    <el-form-item :label="$t('pages.menus.order_num')">
       <el-input-number v-model="form.order_num"></el-input-number>
     </el-form-item>
-    <el-form-item label="图标">
-      <el-select v-model="form.icon" clearable filterable placeholder="请选择图标">
-        <el-option v-for="item in iconList" :key="item.dict_label" :label="item.dict_label" :value="item.dict_label">
+    <el-form-item :label="$t('pages.menus.icon')">
+      <el-select v-model="form.icon" clearable filterable :placeholder="$t('pages.menus.iconPh')">
+        <!-- <el-option v-for="item in iconList" :key="item.dict_label" :label="item.dict_label" :value="item.dict_label">
           <span style="float: left" :class="['iconfont', item.dict_label]"></span>
           <span style="float: right; color: #8492a6; font-size: 13px">{{ item.dict_label }}</span>
-        </el-option>
+        </el-option> -->
       </el-select>
     </el-form-item>
-    <el-form-item label="状态">
+    <el-form-item :label="$t('pages.menus.is_use')">
       <el-radio-group v-model="form.is_use">
-        <el-radio label="0">使用</el-radio>
-        <el-radio label="1">禁用</el-radio>
+        <el-radio label="0">{{ $t('common.is_use_use') }}</el-radio>
+        <el-radio label="1">{{ $t('common.is_use_notUse') }}</el-radio>
       </el-radio-group>
     </el-form-item>
-    <el-form-item label="备注">
-      <el-input v-model="form.remark" placeholder="请输入备注" type="textarea" :autosize="{ minRows: 5, maxRows: 5 }"></el-input>
+    <el-form-item :label="$t('pages.menus.remark')">
+      <el-input v-model="form.remark" :placeholder="$t('pages.menus.remarkPh')" type="textarea" :autosize="{ minRows: 5, maxRows: 5 }"></el-input>
     </el-form-item>
   </el-form>
 </template>
@@ -50,21 +57,6 @@ const menuTree = inject('menuTree')
 const typeList = inject('typeList')
 const form = inject('form')
 
-// const props = defineProps({
-//   menuTree: { type: Array, default: () => [] },
-//   data: { type: Object, default: () => {} }
-// })
-// const emits = defineEmits(['update:form'])
-// // v-model
-// const form = computed({
-//   get() {
-//     return props.data
-//   },
-//   set(value) {
-//     emits('update:form', value)
-//   }
-// })
-
 // #region 整理数组
 const getOneDimensionList = () => {
   let dup = cloneDeep(menuTree.value)