27 changed files with 2138 additions and 45 deletions
@ -0,0 +1,48 @@ |
|||
<template> |
|||
<section class="app-main"> |
|||
<transition name="fade-transform" mode="out-in"> |
|||
<router-view :key="key" /> |
|||
</transition> |
|||
<!-- <router-view /> --> |
|||
<!-- <router-view :key="key" /> --> |
|||
</section> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'AppMain', |
|||
computed: { |
|||
key() { |
|||
console.log("AppMain") |
|||
console.log("AppMain") |
|||
console.log(this.$route.path) |
|||
console.log(this.$route.fullPath) |
|||
return this.$route.fullPath |
|||
|
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.app-main { |
|||
/*50 = navbar */ |
|||
min-height: calc(100vh - 50px); |
|||
width: 100%; |
|||
position: relative; |
|||
overflow: hidden; |
|||
padding: 10px; |
|||
} |
|||
.fixed-header+.app-main { |
|||
padding-top: 50px; |
|||
} |
|||
</style> |
|||
|
|||
<style lang="scss"> |
|||
// fix css style bug in open el-dialog |
|||
.el-popup-parent--hidden { |
|||
.fixed-header { |
|||
padding-right: 15px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,152 @@ |
|||
<template> |
|||
<div class="navbar"> |
|||
<hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> |
|||
|
|||
<breadcrumb class="breadcrumb-container" /> |
|||
|
|||
<div class="right-menu"> |
|||
<el-dropdown class="avatar-container" trigger="click"> |
|||
<div class="avatar-wrapper"> |
|||
<!-- <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar"> --> |
|||
<div> |
|||
{{userInfo.groupName}}{{userInfo.roleName}} |
|||
</div> |
|||
<i class="el-icon-caret-bottom" /> |
|||
</div> |
|||
<el-dropdown-menu slot="dropdown" class="user-dropdown"> |
|||
<router-link to="/"> |
|||
<el-dropdown-item> |
|||
个人信息 |
|||
</el-dropdown-item> |
|||
</router-link> |
|||
<!-- <a target="_blank" href="https://github.com/PanJiaChen/vue-admin-template/"> |
|||
<el-dropdown-item>Github</el-dropdown-item> |
|||
</a> |
|||
<a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/"> |
|||
<el-dropdown-item>Docs</el-dropdown-item> |
|||
</a> --> |
|||
<el-dropdown-item divided @click.native="logout"> |
|||
<span style="display:block;">退 出</span> |
|||
</el-dropdown-item> |
|||
</el-dropdown-menu> |
|||
</el-dropdown> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex' |
|||
import Breadcrumb from '@/components/Breadcrumb' |
|||
import Hamburger from '@/components/Hamburger' |
|||
|
|||
export default { |
|||
data () { |
|||
return { |
|||
userInfo:{} |
|||
} |
|||
}, |
|||
components: { |
|||
Breadcrumb, |
|||
Hamburger |
|||
}, |
|||
computed: { |
|||
...mapGetters([ |
|||
'sidebar', |
|||
'avatar' |
|||
]) |
|||
}, |
|||
created () { |
|||
if (JSON.parse(sessionStorage.getItem('userinfo'))==null) { |
|||
this.$router.push('/login') |
|||
} |
|||
this.userInfo=JSON.parse(sessionStorage.getItem('userinfo')); |
|||
}, |
|||
methods: { |
|||
toggleSideBar() { |
|||
this.$store.dispatch('app/toggleSideBar') |
|||
}, |
|||
logout() { |
|||
this.$store.commit('user/loginOut') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.navbar { |
|||
height: 50px; |
|||
overflow: hidden; |
|||
position: relative; |
|||
background: #fff; |
|||
box-shadow: 0 1px 4px rgba(0,21,41,.08); |
|||
|
|||
.hamburger-container { |
|||
line-height: 46px; |
|||
height: 100%; |
|||
float: left; |
|||
cursor: pointer; |
|||
transition: background .3s; |
|||
-webkit-tap-highlight-color:transparent; |
|||
|
|||
&:hover { |
|||
background: rgba(0, 0, 0, .025) |
|||
} |
|||
} |
|||
|
|||
.breadcrumb-container { |
|||
float: left; |
|||
} |
|||
|
|||
.right-menu { |
|||
float: right; |
|||
height: 100%; |
|||
line-height: 50px; |
|||
|
|||
&:focus { |
|||
outline: none; |
|||
} |
|||
|
|||
.right-menu-item { |
|||
display: inline-block; |
|||
padding: 0 8px; |
|||
height: 100%; |
|||
font-size: 18px; |
|||
color: #5a5e66; |
|||
vertical-align: text-bottom; |
|||
|
|||
&.hover-effect { |
|||
cursor: pointer; |
|||
transition: background .3s; |
|||
|
|||
&:hover { |
|||
background: rgba(0, 0, 0, .025) |
|||
} |
|||
} |
|||
} |
|||
|
|||
.avatar-container { |
|||
margin-right: 30px; |
|||
|
|||
.avatar-wrapper { |
|||
margin-top: 5px; |
|||
position: relative; |
|||
|
|||
.user-avatar { |
|||
cursor: pointer; |
|||
width: 40px; |
|||
height: 40px; |
|||
border-radius: 10px; |
|||
} |
|||
|
|||
.el-icon-caret-bottom { |
|||
cursor: pointer; |
|||
position: absolute; |
|||
right: -20px; |
|||
top: 25px; |
|||
font-size: 12px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,26 @@ |
|||
export default { |
|||
computed: { |
|||
device() { |
|||
return this.$store.state.app.device |
|||
} |
|||
}, |
|||
mounted() { |
|||
// In order to fix the click on menu on the ios device will trigger the mouseleave bug
|
|||
// https://github.com/PanJiaChen/vue-element-admin/issues/1135
|
|||
this.fixBugIniOS() |
|||
}, |
|||
methods: { |
|||
fixBugIniOS() { |
|||
const $subMenu = this.$refs.subMenu |
|||
if ($subMenu) { |
|||
const handleMouseleave = $subMenu.handleMouseleave |
|||
$subMenu.handleMouseleave = (e) => { |
|||
if (this.device === 'mobile') { |
|||
return |
|||
} |
|||
handleMouseleave(e) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
<script> |
|||
export default { |
|||
name: 'MenuItem', |
|||
functional: true, |
|||
props: { |
|||
icon: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
title: { |
|||
type: String, |
|||
default: '' |
|||
} |
|||
}, |
|||
render(h, context) { |
|||
const { icon, title } = context.props |
|||
const vnodes = [] |
|||
|
|||
if (icon) { |
|||
if (icon.includes('el-icon')) { |
|||
vnodes.push(<i class={[icon, 'sub-el-icon']} />) |
|||
} else { |
|||
vnodes.push(<svg-icon icon-class={icon}/>) |
|||
} |
|||
} |
|||
|
|||
if (title) { |
|||
vnodes.push(<span slot='title'>{(title)}</span>) |
|||
} |
|||
return vnodes |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.sub-el-icon { |
|||
color: currentColor; |
|||
width: 1em; |
|||
height: 1em; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,49 @@ |
|||
<template> |
|||
<component :is="type" v-bind="linkProps(to)"> |
|||
<slot /> |
|||
</component> |
|||
</template> |
|||
|
|||
<script> |
|||
import { isExternal } from '@/utils/validate' |
|||
|
|||
export default { |
|||
props: { |
|||
to: { |
|||
type: String, |
|||
required: true |
|||
} |
|||
}, |
|||
computed: { |
|||
isExternal() { |
|||
return isExternal(this.to) |
|||
}, |
|||
type() { |
|||
if (this.isExternal) { |
|||
return 'a' |
|||
} |
|||
return 'router-link' |
|||
} |
|||
}, |
|||
methods: { |
|||
linkProps(to) { |
|||
console.log("to") |
|||
console.log(to) |
|||
console.log("this.isExternal") |
|||
console.log(this.isExternal) |
|||
console.log("this.type") |
|||
console.log(this.type) |
|||
if (this.isExternal) { |
|||
return { |
|||
href: to, |
|||
target: '_blank', |
|||
rel: 'noopener' |
|||
} |
|||
} |
|||
return { |
|||
to: to |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,82 @@ |
|||
<template> |
|||
<div class="sidebar-logo-container" :class="{'collapse':collapse}"> |
|||
<transition name="sidebarLogoFade"> |
|||
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/"> |
|||
<img v-if="logo" :src="logo" class="sidebar-logo"> |
|||
<h1 v-else class="sidebar-title">{{ title }} </h1> |
|||
</router-link> |
|||
<router-link v-else key="expand" class="sidebar-logo-link" to="/"> |
|||
<img v-if="logo" :src="logo" class="sidebar-logo"> |
|||
<h1 class="sidebar-title">{{ title }} </h1> |
|||
</router-link> |
|||
</transition> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'SidebarLogo', |
|||
props: { |
|||
collapse: { |
|||
type: Boolean, |
|||
required: true |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
title: 'Vue Admin Template', |
|||
logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png' |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.sidebarLogoFade-enter-active { |
|||
transition: opacity 1.5s; |
|||
} |
|||
|
|||
.sidebarLogoFade-enter, |
|||
.sidebarLogoFade-leave-to { |
|||
opacity: 0; |
|||
} |
|||
|
|||
.sidebar-logo-container { |
|||
position: relative; |
|||
width: 100%; |
|||
height: 50px; |
|||
line-height: 50px; |
|||
background: #2b2f3a; |
|||
text-align: center; |
|||
overflow: hidden; |
|||
|
|||
& .sidebar-logo-link { |
|||
height: 100%; |
|||
width: 100%; |
|||
|
|||
& .sidebar-logo { |
|||
width: 32px; |
|||
height: 32px; |
|||
vertical-align: middle; |
|||
margin-right: 12px; |
|||
} |
|||
|
|||
& .sidebar-title { |
|||
display: inline-block; |
|||
margin: 0; |
|||
color: #fff; |
|||
font-weight: 600; |
|||
line-height: 50px; |
|||
font-size: 14px; |
|||
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; |
|||
vertical-align: middle; |
|||
} |
|||
} |
|||
|
|||
&.collapse { |
|||
.sidebar-logo { |
|||
margin-right: 0px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,95 @@ |
|||
<template> |
|||
<div v-if="!item.hidden"> |
|||
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"> |
|||
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)"> |
|||
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}"> |
|||
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" /> |
|||
</el-menu-item> |
|||
</app-link> |
|||
</template> |
|||
|
|||
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body> |
|||
<template slot="title"> |
|||
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" /> |
|||
</template> |
|||
<sidebar-item |
|||
v-for="child in item.children" |
|||
:key="child.path" |
|||
:is-nest="true" |
|||
:item="child" |
|||
:base-path="resolvePath(child.path)" |
|||
class="nest-menu" |
|||
/> |
|||
</el-submenu> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import path from 'path' |
|||
import { isExternal } from '@/utils/validate' |
|||
import Item from './Item' |
|||
import AppLink from './Link' |
|||
import FixiOSBug from './FixiOSBug' |
|||
|
|||
export default { |
|||
name: 'SidebarItem', |
|||
components: { Item, AppLink }, |
|||
mixins: [FixiOSBug], |
|||
props: { |
|||
// route object |
|||
item: { |
|||
type: Object, |
|||
required: true |
|||
}, |
|||
isNest: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
basePath: { |
|||
type: String, |
|||
default: '' |
|||
} |
|||
}, |
|||
data() { |
|||
// To fix https://github.com/PanJiaChen/vue-admin-template/issues/237 |
|||
// TODO: refactor with render function |
|||
this.onlyOneChild = null |
|||
return {} |
|||
}, |
|||
methods: { |
|||
hasOneShowingChild(children = [], parent) { |
|||
const showingChildren = children.filter(item => { |
|||
if (item.hidden) { |
|||
return false |
|||
} else { |
|||
// Temp set(will be used if only has one showing child) |
|||
this.onlyOneChild = item |
|||
return true |
|||
} |
|||
}) |
|||
|
|||
// When there is only one child router, the child router is displayed by default |
|||
if (showingChildren.length === 1) { |
|||
return true |
|||
} |
|||
|
|||
// Show parent if there are no child router to display |
|||
if (showingChildren.length === 0) { |
|||
this.onlyOneChild = { ... parent, path: '', noShowingChildren: true } |
|||
return true |
|||
} |
|||
|
|||
return false |
|||
}, |
|||
resolvePath(routePath) { |
|||
if (isExternal(routePath)) { |
|||
return routePath |
|||
} |
|||
if (isExternal(this.basePath)) { |
|||
return this.basePath |
|||
} |
|||
return path.resolve(this.basePath, routePath) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,95 @@ |
|||
<template> |
|||
<div> |
|||
<template v-if="hasOneShowingChild(item.child,item) && (!onlyOneChild.child||onlyOneChild.noShowingChildren)&&!item.alwaysShow"> |
|||
<app-link v-if="onlyOneChild.title" :to="resolvePath(onlyOneChild.apiUrl)"> |
|||
<el-menu-item :index="resolvePath(onlyOneChild.apiUrl)" :class="{'submenu-title-noDropdown':!isNest}"> |
|||
<item :title="onlyOneChild.title" /> |
|||
</el-menu-item> |
|||
</app-link> |
|||
</template> |
|||
|
|||
<el-submenu v-else ref="subMenu" :index="resolvePath(item.apiUrl)" popper-append-to-body> |
|||
<template slot="title"> |
|||
<item v-if="item.title" :title="item.title" /> |
|||
</template> |
|||
<sidebar-item |
|||
v-for="child in item.child" |
|||
:key="child.id" |
|||
:is-nest="true" |
|||
:item="child" |
|||
:base-path="resolvePath(child.apiUrl)" |
|||
class="nest-menu" |
|||
/> |
|||
</el-submenu> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import path from 'path' |
|||
import { isExternal } from '@/utils/validate' |
|||
import Item from './Item' |
|||
import AppLink from './Link' |
|||
import FixiOSBug from './FixiOSBug' |
|||
|
|||
export default { |
|||
name: 'SidebarItem', |
|||
components: { Item, AppLink }, |
|||
mixins: [FixiOSBug], |
|||
props: { |
|||
// route object |
|||
item: { |
|||
type: Object, |
|||
required: true |
|||
}, |
|||
isNest: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
basePath: { |
|||
type: String, |
|||
default: '' |
|||
} |
|||
}, |
|||
data() { |
|||
// To fix https://github.com/PanJiaChen/vue-admin-template/issues/237 |
|||
// TODO: refactor with render function |
|||
this.onlyOneChild = null |
|||
return {} |
|||
}, |
|||
methods: { |
|||
hasOneShowingChild(children = [], parent) { |
|||
const showingChildren = children.filter(item => { |
|||
if (item.hidden) { |
|||
return false |
|||
} else { |
|||
// Temp set(will be used if only has one showing child) |
|||
this.onlyOneChild = item |
|||
return true |
|||
} |
|||
}) |
|||
|
|||
// When there is only one child router, the child router is displayed by default |
|||
if (showingChildren.length === 1) { |
|||
return true |
|||
} |
|||
|
|||
// Show parent if there are no child router to display |
|||
if (showingChildren.length === 0) { |
|||
this.onlyOneChild = { ... parent, path: '', noShowingChildren: true } |
|||
return true |
|||
} |
|||
|
|||
return false |
|||
}, |
|||
resolvePath(routePath) { |
|||
if (isExternal(routePath)) { |
|||
return routePath |
|||
} |
|||
if (isExternal(this.basePath)) { |
|||
return this.basePath |
|||
} |
|||
return path.resolve(this.basePath, routePath) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,95 @@ |
|||
<template> |
|||
<div :class="{'has-logo':showLogo}"> |
|||
<logo v-if="showLogo" :collapse="isCollapse" /> |
|||
<el-scrollbar wrap-class="scrollbar-wrapper"> |
|||
<!-- <el-menu |
|||
:default-active="activeMenu" |
|||
:collapse="isCollapse" |
|||
:background-color="variables.menuBg" |
|||
:text-color="variables.menuText" |
|||
:unique-opened="false" |
|||
:active-text-color="variables.menuActiveText" |
|||
:collapse-transition="false" |
|||
mode="vertical" |
|||
> |
|||
<sidebar-item v-for="route in menu" :key="route.path" :item="route" :base-path="route.path" /> |
|||
</el-menu> --> |
|||
<!-- <el-menu |
|||
:default-active="activeMenu" |
|||
:collapse="isCollapse" |
|||
:background-color="variables.menuBg" |
|||
:text-color="variables.menuText" |
|||
:unique-opened="false" |
|||
:active-text-color="variables.menuActiveText" |
|||
:collapse-transition="false" |
|||
mode="vertical" |
|||
> |
|||
<sidebar-item v-for="route in menu" :key="route.id" :item="route" :base-path="route.apiUrl" /> |
|||
</el-menu> --> |
|||
<el-menu |
|||
:background-color="variables.menuBg" |
|||
:text-color="variables.menuText" |
|||
:default-active="$route.meta.pageId" |
|||
> |
|||
<template v-for="item in menu"> |
|||
<router-link :to="item.apiUrl" :key="item.id" v-if="item.child.length===0"> |
|||
<el-menu-item :index="item.id.toString()"> |
|||
<i :class="item.icon"></i> |
|||
<span slot="title">{{item.title}}</span> |
|||
</el-menu-item> |
|||
</router-link> |
|||
<subMenu v-else :data="item" :key="item.id"></subMenu> |
|||
</template> |
|||
</el-menu> |
|||
</el-scrollbar> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import subMenu from "./subMenu"; |
|||
import { mapGetters } from 'vuex' |
|||
import Logo from './Logo' |
|||
import SidebarItem from './SidebarItem' |
|||
import variables from '@/styles/variables.scss' |
|||
import { getmenu } from '@/api/user' |
|||
export default { |
|||
components: { SidebarItem, Logo,subMenu }, |
|||
data () { |
|||
return { |
|||
menu:[], |
|||
} |
|||
}, |
|||
async created () { |
|||
console.log(this.$router.options.routes) |
|||
const res = await getmenu() |
|||
this.menu=res.data.list |
|||
}, |
|||
computed: { |
|||
...mapGetters([ |
|||
'sidebar' |
|||
]), |
|||
// routes() { |
|||
// return this.$router.options.routes |
|||
|
|||
// }, |
|||
activeMenu() { |
|||
const route = this.$route |
|||
const { meta, path } = route |
|||
// if set path, the sidebar will highlight the path you set |
|||
if (meta.activeMenu) { |
|||
return meta.activeMenu |
|||
} |
|||
return path |
|||
}, |
|||
showLogo() { |
|||
return this.$store.state.settings.sidebarLogo |
|||
}, |
|||
variables() { |
|||
return variables |
|||
}, |
|||
isCollapse() { |
|||
return !this.sidebar.opened |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,42 @@ |
|||
<template functional> |
|||
<el-submenu :index="props.data.id.toString()"> |
|||
<template slot="title"> |
|||
<i :class="props.data.icon"></i> |
|||
<span>{{props.data.title}}</span> |
|||
</template> |
|||
<template v-for="item in props.data.child"> |
|||
<app-link :to="item.apiUrl" v-if="item.child.length===0" :key="item.id"> |
|||
<el-menu-item class="subitem" :index="item.id.toString()"> |
|||
<i :class="item.icon"></i> |
|||
<span slot="title">{{item.title}}</span> |
|||
</el-menu-item> |
|||
</app-link> |
|||
<!-- <router-link :to="item.apiUrl" :key="item.id" v-if="item.child.length===0"> |
|||
<el-menu-item class="subitem" :index="item.id.toString()"> |
|||
<i :class="item.icon"></i> |
|||
<span slot="title">{{item.title}}</span> |
|||
</el-menu-item> |
|||
</router-link> --> |
|||
<sub-menu v-else :data="item" :key="item.id"></sub-menu> |
|||
</template> |
|||
</el-submenu> |
|||
</template> |
|||
|
|||
<script> |
|||
import AppLink from './Link' |
|||
export default { |
|||
name: "submenu", |
|||
components: { AppLink }, |
|||
props: { |
|||
data: [Array, Object] |
|||
} |
|||
}; |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.el-submenu { |
|||
.el-menu-item { |
|||
padding: 0; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,43 @@ |
|||
<template functional> |
|||
<el-submenu :index="props.data.id.toString()"> |
|||
<template slot="title"> |
|||
<i :class="props.data.icon"></i> |
|||
<span>{{props.data.title}}</span> |
|||
</template> |
|||
<template v-for="item in props.data.child"> |
|||
|
|||
<!-- <router-link :to="item.apiUrl" v-if="item.child.length===0" :key="item.id"> --> |
|||
<router-link :to="{ path: item.apiUrl }" v-if="item.child.length===0" :key="item.id"> |
|||
<el-menu-item class="subitem" :index="item.id.toString()"> |
|||
<i :class="item.icon"></i> |
|||
<span slot="title">{{item.title}}</span> |
|||
</el-menu-item> |
|||
</router-link> |
|||
<!-- <component :is="type" v-bind="linkProps(to)"> |
|||
<slot /> |
|||
</component> --> |
|||
<!-- <applink :to="item.apiUrl" v-if="item.child.length===0" :key="item.id"> |
|||
<el-menu-item class="subitem" :index="item.id.toString()"> |
|||
<i :class="item.icon"></i> |
|||
<span slot="title">{{item.title}}</span> |
|||
</el-menu-item> |
|||
</applink> --> |
|||
<sub-menu v-else :data="item" :key="item.id"></sub-menu> |
|||
</template> |
|||
</el-submenu> |
|||
</template> |
|||
|
|||
<script> |
|||
import applink from '../Sidebar/Link.vue' |
|||
export default { |
|||
name: "submenu", |
|||
components: { applink }, |
|||
props: { |
|||
data: [Array, Object] |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
|
|||
</style> |
|||
@ -0,0 +1,3 @@ |
|||
export { default as Navbar } from './Navbar' |
|||
export { default as Sidebar } from './Sidebar' |
|||
export { default as AppMain } from './AppMain' |
|||
@ -0,0 +1,103 @@ |
|||
<template> |
|||
<div :class="classObj" class="app-wrapper"> |
|||
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" /> |
|||
<sidebar class="sidebar-container" /> |
|||
<div class="main-container"> |
|||
<div :class="{'fixed-header':fixedHeader}"> |
|||
<navbar /> |
|||
</div> |
|||
<router-view key="/characterlist/index"/> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { Navbar, Sidebar, AppMain } from './components' |
|||
import ResizeMixin from './mixin/ResizeHandler' |
|||
|
|||
export default { |
|||
name: 'Layout', |
|||
components: { |
|||
Navbar, |
|||
Sidebar, |
|||
AppMain |
|||
}, |
|||
mixins: [ResizeMixin], |
|||
computed: { |
|||
|
|||
key() { |
|||
console.log("AppMain") |
|||
console.log("AppMain") |
|||
console.log(this.$route.path) |
|||
console.log(this.$route.fullPath) |
|||
return this.$route.fullPath |
|||
|
|||
}, |
|||
|
|||
sidebar() { |
|||
return this.$store.state.app.sidebar |
|||
}, |
|||
device() { |
|||
return this.$store.state.app.device |
|||
}, |
|||
fixedHeader() { |
|||
return this.$store.state.settings.fixedHeader |
|||
}, |
|||
classObj() { |
|||
return { |
|||
hideSidebar: !this.sidebar.opened, |
|||
openSidebar: this.sidebar.opened, |
|||
withoutAnimation: this.sidebar.withoutAnimation, |
|||
mobile: this.device === 'mobile' |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
handleClickOutside() { |
|||
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false }) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
@import "~@/styles/mixin.scss"; |
|||
@import "~@/styles/variables.scss"; |
|||
|
|||
.app-wrapper { |
|||
@include clearfix; |
|||
position: relative; |
|||
height: 100%; |
|||
width: 100%; |
|||
&.mobile.openSidebar{ |
|||
position: fixed; |
|||
top: 0; |
|||
} |
|||
} |
|||
.drawer-bg { |
|||
background: #000; |
|||
opacity: 0.3; |
|||
width: 100%; |
|||
top: 0; |
|||
height: 100%; |
|||
position: absolute; |
|||
z-index: 999; |
|||
} |
|||
|
|||
.fixed-header { |
|||
position: fixed; |
|||
top: 0; |
|||
right: 0; |
|||
z-index: 9; |
|||
width: calc(100% - #{$sideBarWidth}); |
|||
transition: width 0.28s; |
|||
} |
|||
|
|||
.hideSidebar .fixed-header { |
|||
width: calc(100% - 54px) |
|||
} |
|||
|
|||
.mobile .fixed-header { |
|||
width: 100%; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,45 @@ |
|||
import store from '@/store' |
|||
|
|||
const { body } = document |
|||
const WIDTH = 992 // refer to Bootstrap's responsive design
|
|||
|
|||
export default { |
|||
watch: { |
|||
$route(route) { |
|||
if (this.device === 'mobile' && this.sidebar.opened) { |
|||
store.dispatch('app/closeSideBar', { withoutAnimation: false }) |
|||
} |
|||
} |
|||
}, |
|||
beforeMount() { |
|||
window.addEventListener('resize', this.$_resizeHandler) |
|||
}, |
|||
beforeDestroy() { |
|||
window.removeEventListener('resize', this.$_resizeHandler) |
|||
}, |
|||
mounted() { |
|||
const isMobile = this.$_isMobile() |
|||
if (isMobile) { |
|||
store.dispatch('app/toggleDevice', 'mobile') |
|||
store.dispatch('app/closeSideBar', { withoutAnimation: true }) |
|||
} |
|||
}, |
|||
methods: { |
|||
// use $_ for mixins properties
|
|||
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
|
|||
$_isMobile() { |
|||
const rect = body.getBoundingClientRect() |
|||
return rect.width - 1 < WIDTH |
|||
}, |
|||
$_resizeHandler() { |
|||
if (!document.hidden) { |
|||
const isMobile = this.$_isMobile() |
|||
store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop') |
|||
|
|||
if (isMobile) { |
|||
store.dispatch('app/closeSideBar', { withoutAnimation: true }) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
import store from '@/store' |
|||
|
|||
const { body } = document |
|||
const WIDTH = 992 // refer to Bootstrap's responsive design
|
|||
|
|||
export default { |
|||
watch: { |
|||
$route(route) { |
|||
if (this.device === 'mobile' && this.sidebar.opened) { |
|||
store.dispatch('app/closeSideBar', { withoutAnimation: false }) |
|||
} |
|||
} |
|||
}, |
|||
beforeMount() { |
|||
window.addEventListener('resize', this.$_resizeHandler) |
|||
}, |
|||
beforeDestroy() { |
|||
window.removeEventListener('resize', this.$_resizeHandler) |
|||
}, |
|||
mounted() { |
|||
const isMobile = this.$_isMobile() |
|||
if (isMobile) { |
|||
store.dispatch('app/toggleDevice', 'mobile') |
|||
store.dispatch('app/closeSideBar', { withoutAnimation: true }) |
|||
} |
|||
}, |
|||
methods: { |
|||
// use $_ for mixins properties
|
|||
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
|
|||
$_isMobile() { |
|||
const rect = body.getBoundingClientRect() |
|||
return rect.width - 1 < WIDTH |
|||
}, |
|||
$_resizeHandler() { |
|||
if (!document.hidden) { |
|||
const isMobile = this.$_isMobile() |
|||
store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop') |
|||
|
|||
if (isMobile) { |
|||
store.dispatch('app/closeSideBar', { withoutAnimation: true }) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<template> |
|||
<div> |
|||
|
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { getToken, setToken, removeToken,setKey } from '@/utils/auth' |
|||
import { scancode } from '@/api/user' |
|||
export default { |
|||
data () { |
|||
return { |
|||
|
|||
} |
|||
}, |
|||
async created () { |
|||
console.log(this.$route.query) |
|||
setToken(this.$route.query.token) |
|||
setKey(this.$route.query.key) |
|||
this.$store.commit('user/setToken', this.$route.query.token) |
|||
this.$store.commit('user/setKey', this.$route.query.key) |
|||
const from = { |
|||
userkey: this.$route.query.key.toString(), |
|||
usertoken:this.$route.query.token.toString() |
|||
} |
|||
const res = await scancode(from) |
|||
if (res.code === 0) { |
|||
console.log("scancode_res") |
|||
console.log(res) |
|||
setToken(res.data.token) |
|||
setKey(res.data.key) |
|||
console.log("getToken") |
|||
console.log(getToken) |
|||
sessionStorage.setItem('userinfo',JSON.stringify(res.data.userinfo)); |
|||
this.$store.commit('user/setUserInfo', res.data.userinfo) |
|||
this.$store.commit('user/setToken', res.data.token) |
|||
this.$store.commit('user/setKey', res.data.key) |
|||
console.log(JSON.parse(sessionStorage.getItem('userinfo'))) |
|||
// this.$store.state.变量名 |
|||
this.$router.push('/') |
|||
// this.$router.push('/') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
|
|||
</style> |
|||
@ -0,0 +1,378 @@ |
|||
<template> |
|||
<div id="userLayout"> |
|||
<div class="login_panle"> |
|||
<div class="login_panle_form" v-show="loginCard==1"> |
|||
<div class="login_panle_form_title"> |
|||
<!-- <img |
|||
class="login_panle_form_title_logo" |
|||
:src="$GIN_VUE_ADMIN.appLogo" |
|||
alt |
|||
/> --> |
|||
<p class="login_panle_form_title_p">恒信高科后台管理系统</p> |
|||
</div> |
|||
<el-form |
|||
ref="loginForm" |
|||
:model="loginForm" |
|||
:rules="rules" |
|||
@keyup.native.enter="submitForm" |
|||
> |
|||
<el-form-item prop="username"> |
|||
<el-input v-model="loginForm.username" placeholder="请输入用户名"> |
|||
<template #suffix> |
|||
<i class="el-input__icon el-icon-user" /> |
|||
</template> |
|||
</el-input> |
|||
</el-form-item> |
|||
<el-form-item prop="password"> |
|||
<el-input |
|||
v-model="loginForm.password" |
|||
:type="lock === 'lock' ? 'password' : 'text'" |
|||
placeholder="请输入密码" |
|||
> |
|||
<template #suffix> |
|||
<i |
|||
:class="'el-input__icon el-icon-' + lock" |
|||
@click="changeLock" |
|||
/> |
|||
</template> |
|||
</el-input> |
|||
</el-form-item> |
|||
<el-form-item style="position: relative" prop="captcha"> |
|||
<el-input |
|||
v-model="loginForm.captcha" |
|||
name="logVerify" |
|||
placeholder="请输入验证码" |
|||
style="width: 60%" |
|||
/> |
|||
<div class="vPic"> |
|||
<img |
|||
v-if="picPath" |
|||
:src="picPath" |
|||
alt="请输入验证码" |
|||
@click="loginVerify()" |
|||
/> |
|||
</div> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button |
|||
type="primary" |
|||
style="width: 46%; margin-left: 25%" |
|||
@click="submitForm" |
|||
>登 录</el-button |
|||
> |
|||
</el-form-item> |
|||
<el-row :gutter="20"> |
|||
<el-col :span="12" style="text-align: center;color: #0082EF;" @click.native="loginType(1)"> |
|||
账号登录 |
|||
</el-col> |
|||
<el-col :span="12" style="text-align: center;color: #0082EF;" @click.native="loginType(2)"> |
|||
扫码登录 |
|||
</el-col> |
|||
</el-row> |
|||
</el-form> |
|||
</div> |
|||
<div class="login_panle_form" v-show="loginCard==2"> |
|||
<div class="login_panle_form_title"> |
|||
<!-- <img |
|||
class="login_panle_form_title_logo" |
|||
:src="$GIN_VUE_ADMIN.appLogo" |
|||
alt |
|||
/> --> |
|||
<p class="login_panle_form_title_p">恒信高科后台管理系统</p> |
|||
|
|||
</div> |
|||
|
|||
<div id="weChat" style="margin-left: 13px;"></div> |
|||
<el-row :gutter="20"> |
|||
<el-col :span="12" style="text-align: center;color: #0082EF;" @click.native="loginType(1)"> |
|||
账号登录 |
|||
</el-col> |
|||
<el-col :span="12" style="text-align: center;color: #0082EF;" @click.native="loginType(2)"> |
|||
扫码登录 |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
<div class="login_panle_right" /> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
import { getToken, setToken, removeToken,setKey } from '@/utils/auth' |
|||
import { mapActions } from 'vuex' |
|||
import { captcha,mylogin,mysystemlogin,scancodelogin } from '@/api/user' |
|||
export default { |
|||
name: 'Login', |
|||
data() { |
|||
const checkUsername = (rule, value, callback) => { |
|||
if (value.length < 5) { |
|||
return callback(new Error('请输入正确的用户名')) |
|||
} else { |
|||
callback() |
|||
} |
|||
} |
|||
const checkPassword = (rule, value, callback) => { |
|||
if (value.length < 6) { |
|||
return callback(new Error('请输入正确的密码')) |
|||
} else { |
|||
callback() |
|||
} |
|||
} |
|||
return { |
|||
loginCard:2, |
|||
redirect: undefined, |
|||
curYear: 0, |
|||
lock: 'lock', |
|||
loginForm: { |
|||
username: '', |
|||
password: '', |
|||
captcha: '', |
|||
captchaId: '' |
|||
}, |
|||
rules: { |
|||
username: [{ required: true, message: '请输入工号',trigger: 'blur' }], |
|||
password: [{ validator: checkPassword, trigger: 'blur' }], |
|||
captcha: [{ required: true, message: '请输入验证码', trigger: 'blur' }, |
|||
{ |
|||
min: 5, |
|||
max: 6, |
|||
message: '验证码格式不正确', |
|||
trigger: 'blur', |
|||
}] |
|||
}, |
|||
logVerify: '', |
|||
picPath: '' |
|||
} |
|||
}, |
|||
created() { |
|||
this.getWeChat() |
|||
this.loginVerify() |
|||
this.curYear = new Date().getFullYear() |
|||
}, |
|||
watch: { |
|||
$route: { |
|||
handler: function(route) { |
|||
const query = route.query |
|||
if (query) { |
|||
this.redirect = query.redirect |
|||
this.otherQuery = this.getOtherQuery(query) |
|||
} |
|||
}, |
|||
immediate: true |
|||
} |
|||
}, |
|||
methods: { |
|||
...mapActions('user', ['myLoginIn']), |
|||
getWeChat () { |
|||
// 动态引入企业微信js文件 |
|||
const s = document.createElement('script') |
|||
s.type = 'text/javascript' |
|||
s.src = 'http://rescdn.qqmail.com/node/ww/wwopenmng/js/sso/wwLogin-1.0.0.js' |
|||
const wxElement = document.body.appendChild(s) |
|||
// 调用企业微信二维码方法 |
|||
wxElement.onload = function () { |
|||
window.WwLogin({ |
|||
id: 'weChat', // 需要显示的容器id |
|||
appid: 'ww02f310301953277a', // 公众号appid wx******* |
|||
agentid: '1000008', // 公众号agentid wx******* |
|||
scope: 'snsapi_login', // 网页默认即可 |
|||
redirect_uri: 'https%3A%2F%2Fwww.hxgk.group%2Fjumpapiurl%2Fscancode', // 授权成功后回调的url,需要在企业微信配置,我的方法是回调到自己的weChatBack页面 |
|||
state: Math.ceil(Math.random() * 1000), // 可设置为简单的随机数加session用来校验 |
|||
style: 'black', // 提供"black"、"white"可选。二维码的样式 |
|||
href: '' // 外部css文件url,需要https |
|||
}) |
|||
} |
|||
}, |
|||
loginType(a){ |
|||
console.log("aaa") |
|||
if (a==1) { |
|||
this.loginCard=1 |
|||
} |
|||
if (a==2) { |
|||
this.loginCard=2 |
|||
} |
|||
}, |
|||
async checkInit() { |
|||
const res = await checkDB() |
|||
if (res.code === 0) { |
|||
if (res.data?.needInit) { |
|||
this.$store.commit('user/NeedInit') |
|||
this.$router.push({ name: 'Init' }) |
|||
} else { |
|||
this.$message({ |
|||
type: 'info', |
|||
message: '已配置数据库信息,无法初始化' |
|||
}) |
|||
} |
|||
} |
|||
}, |
|||
// async login() { |
|||
// return await this.myLoginIn(this.loginForm) |
|||
// }, |
|||
async submitForm() { |
|||
this.$refs.loginForm.validate(async(v) => { |
|||
if (v) { |
|||
// const flag = await this.login() |
|||
const res = await scancodelogin(this.loginForm) |
|||
if (res.code === 0) { |
|||
setToken(res.data.token) |
|||
setKey(res.data.key) |
|||
console.log("res.data.userinfo") |
|||
console.log(res.data.userinfo) |
|||
// this.$store.commit('saveCurrDbSource',this.db) |
|||
sessionStorage.setItem('userinfo',JSON.stringify(res.data.userinfo)); |
|||
this.$store.commit('user/setUserInfo', res.data.userinfo) |
|||
this.$store.commit('user/setToken', res.data.token) |
|||
this.$store.commit('user/setKey', res.data.key) |
|||
console.log("this.$store.state.user.token") |
|||
console.log(this.$store.state.user.token) |
|||
console.log("this.$store.state.user.userInfo") |
|||
console.log(this.$store.state.user.userInfo) |
|||
console.log("this.$store.state.user.key") |
|||
console.log(this.$store.state.user.key) |
|||
// this.$store.state.变量名 |
|||
this.$router.push('/') |
|||
// this.$router.push('/') |
|||
this.loading = false |
|||
} |
|||
|
|||
} else { |
|||
this.$message({ |
|||
type: 'error', |
|||
message: '请正确填写登录信息', |
|||
showClose: true |
|||
}) |
|||
this.loginVerify() |
|||
return false |
|||
} |
|||
}) |
|||
}, |
|||
getOtherQuery(query) { |
|||
return Object.keys(query).reduce((acc, cur) => { |
|||
if (cur !== 'redirect') { |
|||
acc[cur] = query[cur] |
|||
} |
|||
return acc |
|||
}, {}) |
|||
}, |
|||
changeLock() { |
|||
this.lock = this.lock === 'lock' ? 'unlock' : 'lock' |
|||
}, |
|||
loginVerify() { |
|||
|
|||
captcha({}).then((ele) => { |
|||
this.picPath = ele.data.picPath |
|||
this.loginForm.captchaId = ele.data.captchaId |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
|
|||
</script> |
|||
|
|||
|
|||
|
|||
|
|||
<style lang="scss" scoped> |
|||
#userLayout { |
|||
margin: 0; |
|||
padding: 0; |
|||
//background-image: url("@/assets/login_background.jpg"); |
|||
// background-image: url("../assets/login_background.jpg"); |
|||
background-image: url("../../assets/404_images/login_background.jpg"); |
|||
background-size: cover; |
|||
width: 100%; |
|||
height: 100%; |
|||
position: relative; |
|||
.login_panle { |
|||
position: absolute; |
|||
top: 3vh; |
|||
left: 2vw; |
|||
width: 96vw; |
|||
height: 94vh; |
|||
background-color: rgba(255, 255, 255, .8); |
|||
backdrop-filter: blur(5px); |
|||
border-radius: 10px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-evenly; |
|||
.login_panle_right { |
|||
// background-image: url("../assets/login_left.svg"); |
|||
background-image: url("../../assets/404_images/login_left.svg"); |
|||
background-size: cover; |
|||
width: 40%; |
|||
height: 60%; |
|||
float: right !important; |
|||
} |
|||
.login_panle_form { |
|||
width: 420px; |
|||
background-color: #fff; |
|||
padding: 40px 40px 40px 40px; |
|||
border-radius: 10px; |
|||
box-shadow: 2px 3px 7px rgba(0, 0, 0, .2); |
|||
.login_panle_form_title { |
|||
display: flex; |
|||
align-items: center; |
|||
margin: 30px 0; |
|||
.login_panle_form_title_logo { |
|||
width: 90px; |
|||
height: 72px; |
|||
} |
|||
.login_panle_form_title_p { |
|||
font-size: 30px; |
|||
padding-left: 20px; |
|||
} |
|||
} |
|||
.vPic { |
|||
width: 33%; |
|||
height: 38px; |
|||
float: right !important; |
|||
background: #ccc; |
|||
img { |
|||
width: 100%; |
|||
height: 100%; |
|||
cursor: pointer; |
|||
vertical-align: middle; |
|||
} |
|||
} |
|||
} |
|||
.login_panle_foot { |
|||
position: absolute; |
|||
bottom: 20px; |
|||
.links { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
.link-icon { |
|||
width: 30px; |
|||
height: 30px; |
|||
} |
|||
} |
|||
.copyright { |
|||
color: #777777; |
|||
margin-top: 5px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
//小屏幕不显示右侧,将登陆框居中 |
|||
@media (max-width: 750px) { |
|||
.login_panle_right { |
|||
display: none; |
|||
} |
|||
.login_panle { |
|||
width: 100vw; |
|||
height: 100vh; |
|||
top: 0; |
|||
left: 0; |
|||
} |
|||
.login_panle_form { |
|||
width: 100%; |
|||
} |
|||
} |
|||
|
|||
|
|||
/* |
|||
powerBy : bypanghu@163.com |
|||
*/ |
|||
</style> |
|||
@ -0,0 +1,378 @@ |
|||
<template> |
|||
<!-- 菜单 --> |
|||
<div class="dashboard-container"> |
|||
<!-- <div class="gva-search-box"> |
|||
<el-form ref="searchForm" :inline="true" :model="searchInfo"> |
|||
<el-form-item label="考核维度名称"> |
|||
<el-input |
|||
placeholder="请输入名称" |
|||
v-model="searchInfo.title" |
|||
clearable> |
|||
</el-input> |
|||
</el-form-item> |
|||
<el-form-item label="考核维度状态"> |
|||
<el-select v-model="searchInfo.state" clearable placeholder="请选择状态"> |
|||
<el-option :value=1 label="正常">正常</el-option> |
|||
<el-option :value=2 label="禁止">禁止</el-option> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button size="mini" type="primary" icon="el-icon-search" @click="onSubmit">查询</el-button> |
|||
<el-button size="mini" icon="el-icon-refresh" @click="onReset">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> --> |
|||
<div class="gva-table-box"> |
|||
<div class="gva-btn-list"> |
|||
<el-button size="mini" type="primary" icon="el-icon-plus" @click="showAdd()">新增根目录</el-button> |
|||
</div> |
|||
<el-table :data="tableData" row-key="id" :tree-props="{children: 'child'}"> |
|||
<el-table-column align="left" label="ID" min-width="100" prop="id" /> |
|||
<el-table-column align="left" label="名称" show-overflow-tooltip min-width="160" prop="title" /> |
|||
<el-table-column align="left" label="路由Path" prop="apiUrl" /> |
|||
<el-table-column align="left" label="状态" min-width="140" prop="authorityName"> |
|||
<template #default="scope"> |
|||
<el-switch |
|||
inline-prompt |
|||
active-text="正常" |
|||
inactive-text="禁止" |
|||
v-model="scope.row.state" |
|||
active-color="#13ce66" |
|||
inactive-color="#ff4949" |
|||
:active-value=1 |
|||
:inactive-value=2 |
|||
@change="changeVal($event,scope.row.outId)" |
|||
/> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column align="left" fixed="right" label="操作" width="300"> |
|||
<template #default="scope"> |
|||
<!-- <el-button |
|||
size="mini" |
|||
type="text" |
|||
icon="el-icon-plus" |
|||
@click="addMenu(scope.row.ID)" |
|||
>添加子菜单</el-button> --> |
|||
<el-button |
|||
size="mini" |
|||
type="text" |
|||
icon="el-icon-edit" |
|||
@click="editMenu(scope.row.ID)" |
|||
>编辑</el-button> |
|||
<el-button |
|||
size="mini" |
|||
type="text" |
|||
icon="el-icon-delete" |
|||
@click="deleteMenu(scope.row.ID)" |
|||
>删除</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<!-- <div class="gva-pagination"> |
|||
<el-pagination |
|||
@size-change="handleSizeChange" |
|||
@current-change="handleCurrentChange" |
|||
:page-sizes="[10, 30, 50, 100]" |
|||
:page-size="searchInfo.pagesize" |
|||
layout="total, sizes, prev, pager, next, jumper" |
|||
:total="total"> |
|||
</el-pagination> |
|||
</div> --> |
|||
</div> |
|||
<!-- 新增弹框 --> |
|||
<el-dialog :visible.sync="dialogFormVisible" :before-close="closeDialog" title="新增根目录" width="20%"> |
|||
<el-form ref="addForm" :model="form" :rules="rules" label-width="150px"> |
|||
<el-form-item label="栏目名称"> |
|||
<el-input v-model="form.title"/> |
|||
</el-form-item> |
|||
<!-- <el-form-item label="所属栏目"> |
|||
<el-cascader |
|||
:options="options" |
|||
:props="{ checkStrictly: true }" |
|||
clearable></el-cascader> |
|||
</el-form-item> --> |
|||
|
|||
<el-form-item label="栏目路径"> |
|||
<el-input v-model="form.menuurl"/> |
|||
</el-form-item> |
|||
<el-form-item label="排序"> |
|||
<el-input v-model="form.sort"/> |
|||
</el-form-item> |
|||
</el-form> |
|||
<template #footer> |
|||
<div class="dialog-footer"> |
|||
<el-button size="small" @click="closeDialog">取 消</el-button> |
|||
<el-button size="small" type="primary" @click="enterDialog">确 定</el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
<!-- 新增子菜单弹框 --> |
|||
<el-dialog :visible.sync="dialogFormVisible" :before-close="closeDialog" title="新增" width="20%"> |
|||
<el-form ref="addForm" :model="form" :rules="rules" label-width="150px"> |
|||
<el-form-item label="栏目名称"> |
|||
<el-input v-model="form.title"/> |
|||
</el-form-item> |
|||
<!-- <el-form-item label="所属栏目"> |
|||
<el-cascader |
|||
:options="options" |
|||
:props="{ checkStrictly: true }" |
|||
clearable></el-cascader> |
|||
</el-form-item> --> |
|||
|
|||
<el-form-item label="栏目路径"> |
|||
<el-input v-model="form.menuurl"/> |
|||
</el-form-item> |
|||
<el-form-item label="排序"> |
|||
<el-input v-model="form.sort"/> |
|||
</el-form-item> |
|||
</el-form> |
|||
<template #footer> |
|||
<div class="dialog-footer"> |
|||
<el-button size="small" @click="closeDialog">取 消</el-button> |
|||
<el-button size="small" type="primary" @click="enterDialog">确 定</el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
<!-- 编辑弹框 --> |
|||
<el-dialog :visible.sync="editDialogFormVisible" :before-close="editCloseDialog" title="修改" width="20%"> |
|||
<el-form ref="editForm" :model="editAdd" :rules="editRules" label-width="150px"> |
|||
<el-form-item label="考核维度名称" prop="title"> |
|||
<el-input v-model="editAdd.title" autocomplete="off" /> |
|||
</el-form-item> |
|||
<el-form-item label="排序" prop="sort"> |
|||
<el-input v-model.number="editAdd.sort" autocomplete="off" /> |
|||
</el-form-item> |
|||
</el-form> |
|||
<template #footer> |
|||
<div class="dialog-footer"> |
|||
<el-button size="small" @click="editCloseDialog">取 消</el-button> |
|||
<el-button size="small" type="primary" @click="editEnterDialog">确 定</el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { dutyclasslist,statedutyclass,eitedutyclassinfo,getdutyclassinfo,adddutyclass } from '@/api/duty/dimension' |
|||
import { systemmenulist,addmenu,eitemenu,delmenu,addmenuoperation,delmenuperation } from '@/api/user' |
|||
export default { |
|||
name: 'Dashboard', |
|||
data() { |
|||
return { |
|||
// 查询详情的数据 |
|||
editFrom:{}, |
|||
// 修改状态提交数据 |
|||
switchFrom:{}, |
|||
// 删除数据提交 |
|||
deleFrom:{}, |
|||
// 编辑时数据 |
|||
editAdd:{}, |
|||
assessList:{}, |
|||
// 添加数据 |
|||
form:{ |
|||
type:1, |
|||
}, |
|||
// 弹窗变量 |
|||
dialogFormVisible:false, |
|||
// 修改弹窗 |
|||
editDialogFormVisible:false, |
|||
total: 0, |
|||
tableData:[], |
|||
// 条件查询变量 |
|||
searchInfo: { |
|||
page: 1, |
|||
pagesize: 10 |
|||
}, |
|||
// 条件查询变量 |
|||
abc:{ |
|||
aaa:"111", |
|||
bbb:"222" |
|||
}, |
|||
// 添加时验证规则 |
|||
rules: { |
|||
title: [{ required: true, message: '请输入名称', trigger: 'blur' }], |
|||
}, |
|||
editRules:{ |
|||
title: [{ required: true, message: '请输入名称', trigger: 'blur' }], |
|||
} |
|||
} |
|||
}, |
|||
created() { |
|||
console.log(this.$store.state.user.token) |
|||
if (this.$store.state.user.token=='') { |
|||
this.$router.push('/login') |
|||
} |
|||
// 页面渲染时获取初始数据 |
|||
this.getDataList() |
|||
}, |
|||
methods: { |
|||
// 删除操作 |
|||
//删除操作 |
|||
async deleteMenu(row) { |
|||
this.$confirm('此操作将永久删除, 是否继续?', '提示', { |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
type: 'warning' |
|||
}) |
|||
.then(async() => { |
|||
this.deleFrom.state=3; |
|||
this.deleFrom.outid=row.outId; |
|||
const res = await delmenu(this.deleFrom) |
|||
if (res.code === 0) { |
|||
this.$message({ |
|||
type: 'success', |
|||
message: '删除成功!' |
|||
}) |
|||
|
|||
this.getDataList() |
|||
} |
|||
}) |
|||
}, |
|||
// 新增按钮 |
|||
showAdd(){ |
|||
this.dialogFormVisible=true; |
|||
console.log(this.dialogFormVisible) |
|||
}, |
|||
// 编辑按钮 |
|||
async showEdit(row){ |
|||
this.editFrom.outid=row.outId |
|||
const res = await getdutyclassinfo(this.editFrom) |
|||
this.editAdd = res.data |
|||
this.editDialogFormVisible=true; |
|||
|
|||
}, |
|||
// 开关状态监听 |
|||
async changeVal(val,id){ |
|||
console.log(val) |
|||
this.switchFrom.outid=id |
|||
if (val==1) { |
|||
this.switchFrom.state=1; |
|||
const res = await delmenu(this.switchFrom) |
|||
if (res.code === 0) { |
|||
this.$message({ |
|||
type: 'success', |
|||
message: '修改状态成功', |
|||
showClose: true |
|||
}) |
|||
this.getDataList() |
|||
} |
|||
} else { |
|||
this.switchFrom.state=2; |
|||
const res = await delmenu(this.switchFrom) |
|||
if (res.code === 0) { |
|||
this.$message({ |
|||
type: 'success', |
|||
message: '修改状态成功', |
|||
showClose: true |
|||
}) |
|||
this.getDataList() |
|||
} |
|||
} |
|||
}, |
|||
// 重置搜索条件 |
|||
onReset() { |
|||
this.searchInfo = {} |
|||
}, |
|||
// 条件搜索 |
|||
onSubmit() { |
|||
this.page = 1 |
|||
this.pageSize = 10 |
|||
this.getDataList() |
|||
}, |
|||
// 日期时间戳转日期格式 |
|||
formatDate(nS) { |
|||
return new Date(parseInt(nS) * 1000).toLocaleString().replace(/:\d{1,2}$/,' '); |
|||
}, |
|||
|
|||
// 提交按钮 |
|||
async enterDialog(){ |
|||
|
|||
this.form.parentId=0 |
|||
this.form.sort=parseInt(this.form.sort) |
|||
const res = await addmenu(this.form) |
|||
if (res.code === 0) { |
|||
this.$message({ |
|||
type: 'success', |
|||
message: '添加成功', |
|||
showClose: true |
|||
}) |
|||
} |
|||
this.getDataList(); |
|||
this.closeDialog(); |
|||
|
|||
}, |
|||
|
|||
// 编辑提交按钮 |
|||
async editEnterDialog(){ |
|||
this.$refs.editForm.validate(async valid => { |
|||
if (valid) { |
|||
const res = await eitedutyclassinfo(this.editAdd) |
|||
if (res.code === 0) { |
|||
this.$message({ |
|||
type: 'success', |
|||
message: '编辑成功', |
|||
showClose: true |
|||
}) |
|||
} |
|||
this.getDataList(); |
|||
this.editCloseDialog(); |
|||
} |
|||
}) |
|||
}, |
|||
// 添加框关闭 |
|||
closeDialog() { |
|||
console.log("closeDialog") |
|||
this.initForm() |
|||
this.dialogFormVisible = false |
|||
}, |
|||
// 修改框关闭 |
|||
editCloseDialog() { |
|||
this.editInitForm() |
|||
this.editDialogFormVisible = false |
|||
}, |
|||
// 添加重置表单 |
|||
initForm() { |
|||
console.log("initForm") |
|||
this.$refs.addForm.resetFields() |
|||
this.form = {} |
|||
console.log(this.form) |
|||
}, |
|||
// 修改重置表单 |
|||
editInitForm() { |
|||
this.$refs.editForm.resetFields() |
|||
this.editAdd = {} |
|||
}, |
|||
// 改变pageSize |
|||
handleSizeChange(val) { |
|||
this.searchInfo.pagesize=val |
|||
this.getDataList(this.searchInfo) |
|||
}, |
|||
// 改变page |
|||
handleCurrentChange(val) { |
|||
this.searchInfo.page=val |
|||
this.getDataList(this.searchInfo) |
|||
}, |
|||
// 获取初始数据 |
|||
async getDataList() { |
|||
const res = await systemmenulist(this.searchInfo) |
|||
this.tableData = res.data.list |
|||
this.total = res.data.total |
|||
this.searchInfo.page = res.data.page |
|||
this.searchInfo.pagesize = res.data.pageSize |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.dashboard { |
|||
&-container { |
|||
margin: 30px; |
|||
} |
|||
&-text { |
|||
font-size: 30px; |
|||
line-height: 46px; |
|||
} |
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue