vue版本上线
This commit is contained in:
71
jshERP-web/src/components/menu/Contextmenu.vue
Normal file
71
jshERP-web/src/components/menu/Contextmenu.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<a-menu :style="style" class="contextmenu" v-show="visible" @click="handleClick" :selectedKeys="selectedKeys">
|
||||
<a-menu-item :key="item.key" v-for="item in itemList">
|
||||
<a-icon role="menuitemicon" v-if="item.icon" :type="item.icon" />{{ item.text }}
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Contextmenu',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
itemList: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
left: 0,
|
||||
top: 0,
|
||||
target: null,
|
||||
selectedKeys: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
style () {
|
||||
return {
|
||||
left: this.left + 'px',
|
||||
top: this.top + 'px'
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('mousedown', e => this.closeMenu(e))
|
||||
window.addEventListener('contextmenu', e => this.setPosition(e))
|
||||
},
|
||||
methods: {
|
||||
closeMenu (e) {
|
||||
if (this.visible === true && ['menuitemicon', 'menuitem'].indexOf(e.target.getAttribute('role')) < 0) {
|
||||
this.$emit('update:visible', false)
|
||||
}
|
||||
},
|
||||
setPosition (e) {
|
||||
this.left = e.clientX
|
||||
this.top = e.clientY
|
||||
this.target = e.target
|
||||
},
|
||||
handleClick ({key}) {
|
||||
this.$emit('select', key, this.target)
|
||||
this.$emit('update:visible', false)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.contextmenu{
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
border: 1px solid #9e9e9e;
|
||||
border-radius: 4px;
|
||||
box-shadow: 2px 2px 10px #aaaaaa !important;
|
||||
}
|
||||
</style>
|
||||
177
jshERP-web/src/components/menu/SideMenu.vue
Normal file
177
jshERP-web/src/components/menu/SideMenu.vue
Normal file
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<a-layout-sider
|
||||
:class="['sider', isDesktop() ? null : 'shadow', theme, fixSiderbar ? 'ant-fixed-sidemenu' : null ]"
|
||||
width="200px"
|
||||
:collapsible="collapsible"
|
||||
v-model="collapsed"
|
||||
:trigger="null">
|
||||
<logo />
|
||||
<s-menu
|
||||
:collapsed="collapsed"
|
||||
:menu="menus"
|
||||
:theme="theme"
|
||||
@select="onSelect"
|
||||
:mode="mode"
|
||||
:style="smenuStyle">
|
||||
</s-menu>
|
||||
</a-layout-sider>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ALayoutSider from "ant-design-vue/es/layout/Sider"
|
||||
import Logo from '../tools/Logo'
|
||||
import SMenu from './index'
|
||||
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||
|
||||
export default {
|
||||
name: "SideMenu",
|
||||
components: { ALayoutSider, Logo, SMenu },
|
||||
mixins: [mixin, mixinDevice],
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'inline'
|
||||
},
|
||||
theme: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'dark'
|
||||
},
|
||||
collapsible: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
collapsed: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
menus: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
smenuStyle() {
|
||||
let style = { 'padding': '0' }
|
||||
if (this.fixSiderbar) {
|
||||
style['height'] = 'calc(100% - 59px)'
|
||||
style['overflow'] = 'auto'
|
||||
style['overflow-x'] = 'hidden'
|
||||
}
|
||||
return style
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSelect (obj) {
|
||||
this.$emit('menuSelect', obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
/* update_begin author:sunjianlei date:20190509 for: 修改侧边导航栏滚动条的样式 */
|
||||
.sider {
|
||||
@scrollBarSize: 10px;
|
||||
|
||||
ul.ant-menu {
|
||||
|
||||
/* 定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
|
||||
&::-webkit-scrollbar {
|
||||
width: @scrollBarSize;
|
||||
height: @scrollBarSize;
|
||||
background-color: transparent;
|
||||
display: none;
|
||||
}
|
||||
|
||||
& .-o-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 兼容IE */
|
||||
-ms-overflow-style: none;
|
||||
-ms-scroll-chaining: chained;
|
||||
-ms-content-zooming: zoom;
|
||||
-ms-scroll-rails: none;
|
||||
-ms-content-zoom-limit-min: 100%;
|
||||
-ms-content-zoom-limit-max: 500%;
|
||||
-ms-scroll-snap-type: proximity;
|
||||
-ms-scroll-snap-points-x: snapList(100%, 200%, 300%, 400%, 500%);
|
||||
|
||||
/* 定义滚动条轨道 */
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* 定义滑块 */
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: @scrollBarSize;
|
||||
background-color: #eee;
|
||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
|
||||
|
||||
&:hover {
|
||||
background-color: #dddddd;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: #bbbbbb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 暗色系滚动条样式 */
|
||||
&.dark ul.ant-menu {
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: #666666;
|
||||
|
||||
&:hover {
|
||||
background-color: #808080;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* update_end author:sunjianlei date:20190509 for: 修改侧边导航栏滚动条的样式 */
|
||||
|
||||
</style>
|
||||
|
||||
<!-- update_begin author:sunjianlei date:20190530 for: 选中首页的时候不显示背景颜色 -->
|
||||
<style lang="less">
|
||||
.ant-menu.ant-menu-root {
|
||||
& > .ant-menu-item:first-child {
|
||||
background-color: transparent;
|
||||
|
||||
& > a, & > a:hover {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
|
||||
&.ant-menu-item-selected {
|
||||
& > a, & > a:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.ant-menu-dark > .ant-menu-item:first-child {
|
||||
& > a, & > a:hover {
|
||||
color: rgba(255, 255, 255, 0.65);
|
||||
}
|
||||
|
||||
&.ant-menu-item-selected {
|
||||
& > a, & > a:hover {
|
||||
color: rgba(255, 255, 255, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<!-- update_end author:sunjianlei date:20190530 for: 选中首页的时候不显示背景颜色 -->
|
||||
188
jshERP-web/src/components/menu/index.js
Normal file
188
jshERP-web/src/components/menu/index.js
Normal file
@@ -0,0 +1,188 @@
|
||||
import Menu from 'ant-design-vue/es/menu'
|
||||
import Icon from 'ant-design-vue/es/icon'
|
||||
|
||||
const { Item, SubMenu } = Menu
|
||||
|
||||
export default {
|
||||
name: 'SMenu',
|
||||
props: {
|
||||
menu: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
theme: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'dark'
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'inline'
|
||||
},
|
||||
collapsed: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
openKeys: [],
|
||||
selectedKeys: [],
|
||||
cachedOpenKeys: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
rootSubmenuKeys: vm => {
|
||||
const keys = []
|
||||
vm.menu.forEach(item => keys.push(item.path))
|
||||
return keys
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.updateMenu()
|
||||
},
|
||||
watch: {
|
||||
collapsed (val) {
|
||||
if (val) {
|
||||
this.cachedOpenKeys = this.openKeys.concat()
|
||||
this.openKeys = []
|
||||
} else {
|
||||
this.openKeys = this.cachedOpenKeys
|
||||
}
|
||||
},
|
||||
$route: function () {
|
||||
this.updateMenu()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// select menu item
|
||||
onOpenChange (openKeys) {
|
||||
|
||||
// 在水平模式下时执行,并且不再执行后续
|
||||
if (this.mode === 'horizontal') {
|
||||
this.openKeys = openKeys
|
||||
return
|
||||
}
|
||||
// 非水平模式时
|
||||
const latestOpenKey = openKeys.find(key => !this.openKeys.includes(key))
|
||||
if (!this.rootSubmenuKeys.includes(latestOpenKey)) {
|
||||
this.openKeys = openKeys
|
||||
} else {
|
||||
this.openKeys = latestOpenKey ? [latestOpenKey] : []
|
||||
}
|
||||
},
|
||||
updateMenu () {
|
||||
const routes = this.$route.matched.concat()
|
||||
const { hidden } = this.$route.meta
|
||||
if (routes.length >= 3 && hidden) {
|
||||
routes.pop()
|
||||
this.selectedKeys = [routes[routes.length - 1].path]
|
||||
} else {
|
||||
this.selectedKeys = [routes.pop().path]
|
||||
}
|
||||
const openKeys = []
|
||||
if (this.mode === 'inline') {
|
||||
routes.forEach(item => {
|
||||
openKeys.push(item.path)
|
||||
})
|
||||
}
|
||||
//update-begin-author:taoyan date:20190510 for:online表单菜单点击展开的一级目录不对
|
||||
if(!this.selectedKeys|| this.selectedKeys[0].indexOf(":")<0){
|
||||
this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
|
||||
}
|
||||
//update-end-author:taoyan date:20190510 for:online表单菜单点击展开的一级目录不对
|
||||
},
|
||||
|
||||
// render
|
||||
renderItem (menu) {
|
||||
if (!menu.hidden) {
|
||||
return menu.children && !menu.alwaysShow ? this.renderSubMenu(menu) : this.renderMenuItem(menu)
|
||||
}
|
||||
return null
|
||||
},
|
||||
renderMenuItem (menu) {
|
||||
// const target = menu.meta.target || null
|
||||
// const tag = target && 'a' || 'router-link'
|
||||
let props = { to: { name: menu.name } }
|
||||
if(menu.route && menu.route === '0'){
|
||||
props = { to: { path: menu.path } }
|
||||
}
|
||||
|
||||
const attrs = { href: menu.url, target: menu.text }
|
||||
|
||||
if (menu.children) {
|
||||
// 把有子菜单的 并且 父菜单是要隐藏子菜单的
|
||||
// 都给子菜单增加一个 hidden 属性
|
||||
// 用来给刷新页面时, selectedKeys 做控制用
|
||||
menu.children.forEach(item => {
|
||||
item.meta = Object.assign(item.meta, { hidden: true })
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Item {...{ key: menu.url }}>
|
||||
<tag {...{ props, attrs }}>
|
||||
{this.renderIcon(menu.icon)}
|
||||
<span>{menu.text}</span>
|
||||
</tag>
|
||||
</Item>
|
||||
)
|
||||
},
|
||||
renderSubMenu (menu) {
|
||||
const itemArr = []
|
||||
if (!menu.alwaysShow) {
|
||||
menu.children.forEach(item => itemArr.push(this.renderItem(item)))
|
||||
}
|
||||
return (
|
||||
<SubMenu {...{ key: menu.url }}>
|
||||
<span slot="title">
|
||||
{this.renderIcon(menu.icon)}
|
||||
<span>{menu.text}</span>
|
||||
</span>
|
||||
{itemArr}
|
||||
</SubMenu>
|
||||
)
|
||||
},
|
||||
renderIcon (icon) {
|
||||
if (icon === 'none' || icon === undefined) {
|
||||
return null
|
||||
}
|
||||
const props = {}
|
||||
typeof (icon) === 'object' ? props.component = icon : props.type = icon
|
||||
return (
|
||||
<Icon {... { props } }/>
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
render () {
|
||||
const { mode, theme, menu } = this
|
||||
const props = {
|
||||
mode: mode,
|
||||
theme: theme,
|
||||
openKeys: this.openKeys
|
||||
}
|
||||
const on = {
|
||||
select: obj => {
|
||||
this.selectedKeys = obj.selectedKeys
|
||||
this.$emit('select', obj)
|
||||
},
|
||||
openChange: this.onOpenChange
|
||||
}
|
||||
|
||||
const menuTree = menu.map(item => {
|
||||
if (item.hidden) {
|
||||
return null
|
||||
}
|
||||
return this.renderItem(item)
|
||||
})
|
||||
// {...{ props, on: on }}
|
||||
return (
|
||||
<Menu vModel={this.selectedKeys} {...{ props, on: on }}>
|
||||
{menuTree}
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user