研发图纸文件管理系统-前端项目
chenghongxing
2020-07-20 d21a2ab0620c0b9117bf6d60154bf919535d5739
chore: optimize the i18n code of router; :star2:
11个文件已修改
1个文件已添加
254 ■■■■■ 已修改文件
src/components/menu/SideMenu.vue 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/menu/menu.js 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/AdminLayout.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/PageLayout.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/PageView.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/header/AdminHeader.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/tabs/TabsView.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mock/extend/index.js 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/i18n.js 100 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/setting.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/i18n.js 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/menu/SideMenu.vue
@@ -6,17 +6,16 @@
        <h1>{{systemName}}</h1>
      </router-link>
    </div>
    <i-menu @i18nComplete="setRoutesI18n" :i18n="menuI18n" :theme="theme" :collapsed="collapsed" :options="menuData" @select="onSelect" class="menu"/>
    <i-menu :theme="theme" :collapsed="collapsed" :options="menuData" @select="onSelect" class="menu"/>
  </a-layout-sider>
</template>
<script>
import IMenu from './menu'
import {mapState, mapMutations} from 'vuex'
import {mapState} from 'vuex'
export default {
  name: 'SideMenu',
  components: {IMenu},
  inject: ['menuI18n'],
  props: {
    collapsible: {
      type: Boolean,
@@ -47,8 +46,7 @@
  methods: {
    onSelect (obj) {
      this.$emit('menuSelect', obj)
    },
    ...mapMutations('setting', ['setRoutesI18n'])
    }
  }
}
</script>
src/components/menu/menu.js
@@ -31,7 +31,6 @@
 **/
import Menu from 'ant-design-vue/es/menu'
import Icon from 'ant-design-vue/es/icon'
import '@/utils/Objects'
const {Item, SubMenu} = Menu
@@ -78,21 +77,15 @@
      return this.theme == 'light' ? this.theme : 'dark'
    }
  },
  beforeMount() {
    let CN = this.generateI18n(new Object(), this.options, 'name')
    let US = this.generateI18n(new Object(), this.options, 'path')
    this.$i18n.setLocaleMessage('CN', CN)
    this.$i18n.setLocaleMessage('US', US)
    if(this.i18n) {
      Object.keys(this.i18n).forEach(key => {
        this.$i18n.mergeLocaleMessage(key, this.i18n[key])
      })
    }
    this.$emit('i18nComplete', this.$i18n._getMessages())
  },
  created () {
    this.updateMenu()
    this.formatOptions(this.options, '')
    // 自定义国际化配置
    if(this.i18n && this.i18n.messages) {
      const messages = this.i18n.messages
      Object.keys(messages).forEach(key => {
        this.$i18n.mergeLocaleMessage(key, messages[key])
      })
    }
  },
  watch: {
    collapsed (val) {
@@ -198,16 +191,6 @@
        return this.getSelectedKey(route.parent)
      }
      return route.path
    },
    generateI18n(lang, options, valueKey) {
      options.forEach(menu => {
        let keys = menu.fullPath.substring(1).split('/').concat('name')
        lang.assignProps(keys, menu[valueKey])
        if (menu.children) {
          this.generateI18n(lang, menu.children, valueKey)
        }
      })
      return lang
    }
  },
  render (h) {
src/layouts/AdminLayout.vue
@@ -50,8 +50,7 @@
  },
  provide() {
    return{
      layoutMinHeight: minHeight,
      menuI18n: require('@/router/i18n').default
      layoutMinHeight: minHeight
    }
  },
  computed: {
src/layouts/PageLayout.vue
@@ -1,6 +1,6 @@
<template>
  <div class="page-layout">
    <page-header :i18n="routesI18n" :breadcrumb="breadcrumb" :title="pageTitle" :logo="logo" :avatar="avatar">
    <page-header :breadcrumb="breadcrumb" :title="pageTitle" :logo="logo" :avatar="avatar">
      <slot name="action"  slot="action"></slot>
      <slot slot="content" name="headerContent"></slot>
      <div slot="content" v-if="!this.$slots.headerContent && desc">
@@ -37,14 +37,10 @@
    }
  },
  created() {
    let i18n = this.routesI18n
    Object.keys(i18n).forEach(key => {
      this.$i18n.mergeLocaleMessage(key, i18n[key])
    })
    this.page = this.$route.meta.page
  },
  computed: {
    ...mapState('setting', ['layout', 'routesI18n']),
    ...mapState('setting', ['layout']),
    pageTitle() {
      let pageTitle = this.page && this.page.title
      return this.title || this.$t(pageTitle) || this.routeName
src/layouts/PageView.vue
@@ -26,7 +26,7 @@
    }
  },
  computed: {
    ...mapState('setting', ['isMobile', 'multiPage', 'animate', 'routesI18n', 'dustbins']),
    ...mapState('setting', ['isMobile', 'multiPage', 'animate', 'dustbins']),
    desc() {
      return this.page.desc
    },
src/layouts/header/AdminHeader.vue
@@ -8,7 +8,7 @@
      <a-divider v-if="isMobile" type="vertical" />
      <a-icon v-if="layout === 'side'" class="trigger" :type="collapsed ? 'menu-unfold' : 'menu-fold'" @click="toggleCollapse"/>
      <div v-if="layout == 'head' && !isMobile" class="admin-header-menu">
        <i-menu class="head-menu" style="height: 64px; line-height: 64px;box-shadow: none" @i18nComplete="setRoutesI18n" :i18n="menuI18n" :theme="headerTheme" mode="horizontal" :options="menuData" @select="onSelect"/>
        <i-menu class="head-menu" style="height: 64px; line-height: 64px;box-shadow: none" :theme="headerTheme" mode="horizontal" :options="menuData" @select="onSelect"/>
      </div>
      <div :class="['admin-header-right', headerTheme]">
          <header-search class="header-item" />
@@ -43,7 +43,6 @@
  name: 'AdminHeader',
  components: {IMenu, HeaderAvatar, HeaderNotice, HeaderSearch},
  props: ['collapsed', 'menuData'],
  inject: ['menuI18n'],
  data() {
    return {
      langList: [
@@ -73,7 +72,7 @@
    onSelect (obj) {
      this.$emit('menuSelect', obj)
    },
    ...mapMutations('setting', ['setLang', 'setRoutesI18n'])
    ...mapMutations('setting', ['setLang'])
  }
}
</script>
src/layouts/tabs/TabsView.vue
@@ -44,7 +44,7 @@
    }
  },
  computed: {
    ...mapState('setting', ['multiPage', 'animate', 'layout', 'dustbins', 'routesI18n']),
    ...mapState('setting', ['multiPage', 'animate', 'layout', 'dustbins']),
    menuItemList() {
      return [
        { key: '1', icon: 'vertical-right', text: this.$t('closeLeft') },
@@ -57,10 +57,6 @@
    const route = this.$route
    this.pageList.push(route)
    this.activePage = route.fullPath
    let i18n = this.routesI18n
    Object.keys(i18n).forEach(key => {
      this.$i18n.mergeLocaleMessage(key, i18n[key])
    })
  },
  watch: {
    '$route': function (newRoute) {
src/main.js
@@ -7,22 +7,15 @@
import '@/mock'
import store from './store'
import 'animate.css/source/animate.css'
import VueI18n from 'vue-i18n'
import Plugins from '@/plugins'
import {initI18n} from '@/utils/i18n'
Vue.config.productionTip = false
Vue.use(Viser)
Vue.use(Antd)
Vue.use(VueI18n)
Vue.use(Plugins)
const i18n = new VueI18n({
  locale: 'CN',
  fallbackLocale: 'US',
  silentFallbackWarn: true
})
const i18n = initI18n(router, 'CN', 'US')
new Vue({
  router,
src/mock/extend/index.js
@@ -17,10 +17,14 @@
    HK: '中午好',
    US: 'Good afternoon',
  },{
    CN: '下午好',
    HK: '下午好',
    US: 'Good afternoon',
  },{
    CN: '晚上好',
    HK: '晚上好',
    US: 'Good evening',
  },
  }
]
const welcomeMessages = [
@@ -56,7 +60,8 @@
  timeFix () {
    const time = new Date()
    const hour = time.getHours()
    return hour < 9 ? timeList[0] : (hour <= 11 ? timeList[1] : (hour <= 13 ? timeList[2] : (hour <= 20 ? timeList[3] : timeList[4])))
    return hour < 9
      ? timeList[0] : (hour <= 11 ? timeList[1] : (hour <= 13 ? timeList[2] : (hour <= 20 ? timeList[3] : timeList[4])))
  },
  avatar () {
    return this.pick(avatars)
src/router/i18n.js
@@ -1,55 +1,57 @@
export default {
  CN: {
    home: {name: '首页'},
  },
  US: {
    home: {name: 'home'},
  },
  HK: {
    home: {name: '首頁'},
    dashboard: {
      name: 'Dashboard',
      workplace: {name: '工作台'},
      analysis: {name: '分析頁'}
module.exports = {
  messages: {
    CN: {
      home: {name: '首页'},
    },
    form: {
      name: '表單頁',
      basic: {name: '基礎表單'},
      step: {name: '分步表單'},
      advance: {name: '分步表單'}
    US: {
      home: {name: 'home'},
    },
    list: {
      name: '列表頁',
      query: {name: '查詢表格'},
      primary: {name: '標準列表'},
      card: {name: '卡片列表'},
      search: {
        name: '搜索列表',
        article: {name: '文章'},
        application: {name: '應用'},
        project: {name: '項目'}
    HK: {
      home: {name: '首頁'},
      dashboard: {
        name: 'Dashboard',
        workplace: {name: '工作台'},
        analysis: {name: '分析頁'}
      },
      form: {
        name: '表單頁',
        basic: {name: '基礎表單'},
        step: {name: '分步表單'},
        advance: {name: '分步表單'}
      },
      list: {
        name: '列表頁',
        query: {name: '查詢表格'},
        primary: {name: '標準列表'},
        card: {name: '卡片列表'},
        search: {
          name: '搜索列表',
          article: {name: '文章'},
          application: {name: '應用'},
          project: {name: '項目'}
        }
      },
      details: {
        name: '詳情頁',
        basic: {name: '基礎詳情頁'},
        advance: {name: '高級詳情頁'}
      },
      result: {
        name: '結果頁',
        success: {name: '成功'},
        error: {name: '失敗'}
      },
      exception: {
        name: '異常頁',
        404: {name: '404'},
        403: {name: '403'},
        500: {name: '500'}
      },
      components: {
        name: '小組件',
        taskCard: {name: '任務卡片'},
        palette: {name: '顏色複選框'}
      }
    },
    details: {
      name: '詳情頁',
      basic: {name: '基礎詳情頁'},
      advance: {name: '高級詳情頁'}
    },
    result: {
      name: '結果頁',
      success: {name: '成功'},
      error: {name: '失敗'}
    },
    exception: {
      name: '異常頁',
      404: {name: '404'},
      403: {name: '403'},
      500: {name: '500'}
    },
    components: {
      name: '小組件',
      taskCard: {name: '任務卡片'},
      palette: {name: '顏色複選框'}
    }
  }
}
src/store/modules/setting.js
@@ -6,7 +6,6 @@
    isMobile: false,
    animates: ADMIN.animates,
    palettes: ADMIN.palettes,
    routesI18n: {},
    dustbins: [],
    ...config,
  },
@@ -37,9 +36,6 @@
    },
    setLang(state, lang) {
      state.lang = lang
    },
    setRoutesI18n(state, i18n) {
      state.routesI18n = i18n
    },
    setHideSetting(state, hideSetting) {
      state.hideSetting = hideSetting
src/utils/i18n.js
New file
@@ -0,0 +1,67 @@
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import routesI18n from '@/router/i18n'
import './Objects'
/**
 * 创建 i18n 配置
 * @param router 路由
 * @param locale 本地化语言
 * @param fallback 回退语言
 * @returns {VueI18n}
 */
function initI18n(router, locale, fallback) {
  Vue.use(VueI18n)
  const options = router.options.routes.find(item => item.path === '/').children
  formatOptions(options, '')
  const CN = generateI18n(new Object(), options, 'name')
  const US = generateI18n(new Object(), options, 'path')
  const i18n = new VueI18n({
    locale,
    fallbackLocale: fallback,
    silentFallbackWarn: true,
    messages: {CN, US}
  })
  const messages = routesI18n.messages
  Object.keys(messages).forEach(key => {
    i18n.mergeLocaleMessage(key, messages[key])
  })
  return i18n
}
/**
 * 根据 router options 配置生成 国际化语言
 * @param lang
 * @param options
 * @param valueKey
 * @returns {*}
 */
function generateI18n(lang, options, valueKey) {
  options.forEach(menu => {
    let keys = menu.fullPath.substring(1).split('/').concat('name')
    lang.assignProps(keys, menu[valueKey])
    if (menu.children) {
      generateI18n(lang, menu.children, valueKey)
    }
  })
  return lang
}
/**
 * 格式化 router options,生成 fullPath
 * @param options
 * @param parentPath
 */
function formatOptions(options, parentPath) {
  options.forEach(route => {
    let isFullPath = route.path.substring(0, 1) === '/'
    route.fullPath = isFullPath ? route.path : parentPath + '/' + route.path
    if (route.children) {
      formatOptions(route.children, route.fullPath)
    }
  })
}
export {
  initI18n
}