diff --git a/public/favicon.ico b/public/favicon.ico
index 91789c8..47bf70b 100644
Binary files a/public/favicon.ico and b/public/favicon.ico differ
diff --git a/src/assets/img/logo.png b/src/assets/img/logo.png
index ce0f22d..62bfe39 100644
Binary files a/src/assets/img/logo.png and b/src/assets/img/logo.png differ
diff --git a/src/assets/img/vue-antd-logo.png b/src/assets/img/vue-antd-logo.png
deleted file mode 100644
index bbdbbfd..0000000
Binary files a/src/assets/img/vue-antd-logo.png and /dev/null differ
diff --git a/src/components/menu/SiderMenu.vue b/src/components/menu/SiderMenu.vue
index 9b0a4e9..a36d5cb 100644
--- a/src/components/menu/SiderMenu.vue
+++ b/src/components/menu/SiderMenu.vue
@@ -6,7 +6,7 @@
{{systemName}}
-
+
@@ -15,6 +15,7 @@ import IMenu from './menu'
export default {
name: 'SiderMenu',
components: {IMenu},
+ inject: ['menuI18n'],
props: {
collapsible: {
type: Boolean,
diff --git a/src/components/menu/menu.js b/src/components/menu/menu.js
index 62b4d90..9bed16e 100644
--- a/src/components/menu/menu.js
+++ b/src/components/menu/menu.js
@@ -1,35 +1,46 @@
/**
* 该插件可根据菜单配置自动生成 ANTD menu组件
- * menuData示例:
+ * menuOptions示例:
* [
* {
* title: '菜单标题',
- * icon: '菜单图标',
* path: '菜单路由',
- * invisible: 'boolean, 是否不可见',
+ * meta: {
+ * icon: '菜单图标',
+ * invisible: 'boolean, 是否不可见, 默认 false',
+ * },
* children: [子菜单配置]
* },
* {
* title: '菜单标题',
- * icon: '菜单图标',
* path: '菜单路由',
- * invisible: 'boolean, 是否不可见',
+ * meta: {
+ * icon: '菜单图标',
+ * invisible: 'boolean, 是否不可见, 默认 false',
+ * },
* children: [子菜单配置]
* }
* ]
+ *
+ * i18n: 国际化配置。组件默认会根据 options route配置的 path 和 name 生成英文以及中文的国际化配置,如需自定义或增加其他语言,配置
+ * 此项即可。如:
+ * i18n: {
+ * CN: {dashboard: {name: '监控中心'}}
+ * HK: {dashboard: {name: '監控中心'}}
+ * }
**/
import Menu from 'ant-design-vue/es/menu'
import Icon from 'ant-design-vue/es/icon'
+import '@/utils/Objects'
const {Item, SubMenu} = Menu
-// 默认菜单图标数组,如果菜单没配置图标,则会设置从该数组随机取一个图标配置
-const iconArr = ['dashboard', 'user', 'form', 'setting', 'message', 'safety', 'bell', 'delete', 'code-o', 'poweroff', 'eye-o', 'hourglass']
-
export default {
name: 'IMenu',
+ i18n: {
+ },
props: {
- menuData: {
+ options: {
type: Array,
required: true
},
@@ -47,7 +58,8 @@ export default {
type: Boolean,
required: false,
default: false
- }
+ },
+ i18n: Object
},
data () {
return {
@@ -59,14 +71,26 @@ export default {
computed: {
rootSubmenuKeys: (vm) => {
let keys = []
- vm.menuData.forEach(item => {
+ vm.options.forEach(item => {
keys.push(item.path)
})
return keys
}
},
+ 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])
+ })
+ }
+ },
created () {
this.updateMenu()
+ this.formatOptions(this.options, '')
},
watch: {
collapsed (val) {
@@ -83,65 +107,72 @@ export default {
},
methods: {
renderIcon: function (h, icon) {
- return icon === 'none' ? null
- : h(
- Icon,
- {
- props: {type: icon !== undefined ? icon : iconArr[Math.floor((Math.random() * iconArr.length))]}
- })
+ return !icon || icon == 'none' ? null : h(Icon, {props: {type: icon}})
},
- renderMenuItem: function (h, menu, pIndex, index) {
+ renderMenuItem: function (h, menu) {
return h(
- Item,
- {
- key: menu.path ? menu.path : 'item_' + pIndex + '_' + index
- },
+ Item, {key: menu.fullPath},
[
- h(
- 'RouterLink',
- // {attrs: {href: '#' + menu.path}},
- {attrs: {to: menu.path}},
+ h('a', {attrs: {href: '#' + menu.fullPath}},
[
- this.renderIcon(h, menu.icon),
- h('span', [menu.name])
+ this.renderIcon(h, menu.meta ? menu.meta.icon : 'none'),
+ h('span', [this.$t(menu.fullPath.substring(1).replace(new RegExp('/', 'g'), '.') + '.name')])
]
)
]
)
},
- renderSubMenu: function (h, menu, pIndex, index) {
- var this2_ = this
- var subItem = [h('span',
- {slot: 'title'},
+ renderSubMenu: function (h, menu) {
+ let this_ = this
+ let subItem = [h('span', {slot: 'title'},
[
- this.renderIcon(h, menu.icon),
- h('span', [menu.name])
+ this.renderIcon(h, menu.meta ? menu.meta.icon : 'none'),
+ h('span', [this.$t(menu.fullPath.substring(1).replace(new RegExp('/', 'g'), '.') + '.name')])
]
)]
- var itemArr = []
- var pIndex_ = pIndex + '_' + index
- menu.children.forEach(function (item, i) {
- itemArr.push(this2_.renderItem(h, item, pIndex_, i))
+ let itemArr = []
+ menu.children.forEach(function (item) {
+ itemArr.push(this_.renderItem(h, item))
})
- return h(
- SubMenu,
- {key: menu.path ? menu.path : 'submenu_' + pIndex + '_' + index},
+ return h(SubMenu, {key: menu.fullPath},
subItem.concat(itemArr)
)
},
- renderItem: function (h, menu, pIndex, index) {
- if (!menu.invisible) {
- return menu.children ? this.renderSubMenu(h, menu, pIndex, index) : this.renderMenuItem(h, menu, pIndex, index)
+ renderItem: function (h, menu) {
+ const meta = menu.meta
+ if (!meta || !meta.invisible) {
+ let renderChildren = false
+ const children = menu.children
+ if (children != undefined) {
+ for (let i = 0; i < children.length; i++) {
+ const childMeta = children[i].meta
+ if (!childMeta || !childMeta.invisible) {
+ renderChildren = true
+ break
+ }
+ }
+ }
+ return (menu.children && renderChildren) ? this.renderSubMenu(h, menu) : this.renderMenuItem(h, menu)
}
},
renderMenu: function (h, menuTree) {
- var this2_ = this
- var menuArr = []
+ let this_ = this
+ let menuArr = []
menuTree.forEach(function (menu, i) {
- menuArr.push(this2_.renderItem(h, menu, '0', i))
+ menuArr.push(this_.renderItem(h, menu, '0', i))
})
return menuArr
},
+ formatOptions(options, parentPath) {
+ let this_ = this
+ options.forEach(route => {
+ let isFullPath = route.path.substring(0, 1) == '/'
+ route.fullPath = isFullPath ? route.path : parentPath + '/' + route.path
+ if (route.children) {
+ this_.formatOptions(route.children, route.fullPath)
+ }
+ })
+ },
onOpenChange (openKeys) {
const latestOpenKey = openKeys.find(key => this.openKeys.indexOf(key) === -1)
if (this.rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
@@ -152,12 +183,29 @@ export default {
},
updateMenu () {
let routes = this.$route.matched.concat()
- this.selectedKeys = [routes.pop().path]
+ const route = routes.pop()
+ this.selectedKeys = [this.getSelectedKey(route)]
let openKeys = []
routes.forEach((item) => {
openKeys.push(item.path)
})
this.collapsed || this.mode === 'horizontal' ? this.cachedOpenKeys = openKeys : this.openKeys = openKeys
+ },
+ getSelectedKey (route) {
+ if (route.meta.invisible && route.parent) {
+ 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) {
@@ -177,7 +225,7 @@ export default {
this.$emit('select', obj)
}
}
- }, this.renderMenu(h, this.menuData)
+ }, this.renderMenu(h, this.options)
)
}
}
diff --git a/src/config/index.js b/src/config/index.js
index 3404910..a3414fb 100644
--- a/src/config/index.js
+++ b/src/config/index.js
@@ -1,5 +1,6 @@
// 系统配置
module.exports = {
+ lang: 'CN',
themeColor: '#1890ff',
theme: 'dark',
layout: 'side',
diff --git a/src/layouts/GlobalHeader.vue b/src/layouts/GlobalHeader.vue
index 203a5cd..0d2f1c6 100644
--- a/src/layouts/GlobalHeader.vue
+++ b/src/layouts/GlobalHeader.vue
@@ -8,7 +8,7 @@
@@ -19,6 +19,16 @@
+
@@ -40,8 +50,9 @@ export default {
headerTheme: this.theme
}
},
+ inject: ['menuI18n'],
computed: {
- ...mapState('setting', ['theme', 'isMobile', 'layout', 'systemName']),
+ ...mapState('setting', ['theme', 'isMobile', 'layout', 'systemName', 'lang']),
headerTheme () {
return (this.layout == 'side' && !this.isMobile) ? 'light' : this.theme
}
@@ -52,6 +63,9 @@ export default {
},
onSelect (obj) {
this.$emit('menuSelect', obj)
+ },
+ changeLang(lang) {
+ this.$store.commit('setting/setLang', lang.key)
}
}
}
@@ -69,7 +83,7 @@ export default {
}
}
.global-header{
- padding: 0 12px 0 0;
+ padding: 0;
-webkit-box-shadow: 0 1px 4px rgba(0,21,41,.08);
box-shadow: 0 1px 4px rgba(0,21,41,.08);
z-index: 1;
@@ -124,11 +138,17 @@ export default {
a, i{
color: #fff !important;
}
+ .header-item:hover{
+ background-color: @primary-color;
+ }
}
.header-item{
padding: 0 12px;
cursor: pointer;
align-self: center;
+ &:hover{
+ background-color: @gray-3;
+ }
i{
font-size: 16px;
color: rgba(0,0,0,.65);
diff --git a/src/layouts/GlobalLayout.vue b/src/layouts/GlobalLayout.vue
index b805765..d8c3b45 100644
--- a/src/layouts/GlobalLayout.vue
+++ b/src/layouts/GlobalLayout.vue
@@ -51,6 +51,7 @@ export default {
provide() {
return{
layoutMinHeight: minHeight,
+ menuI18n: require('@/router/i18n').default
}
},
computed: {
diff --git a/src/layouts/HeaderSearch.vue b/src/layouts/HeaderSearch.vue
index 108d81f..e0b74ea 100644
--- a/src/layouts/HeaderSearch.vue
+++ b/src/layouts/HeaderSearch.vue
@@ -1,5 +1,5 @@
-