"...contract/git@gitlab.aishuhong.com:liujiale/finance.git" did not exist on "01e9384f2462ac1961ddbb0839799ecd63b6f762"
Commit 6e137f66 authored by 柳 佳乐's avatar 柳 佳乐
Browse files

first

parents
Pipeline #20 failed with stages
in 0 seconds
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)
}
}
}
}
}
<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>
<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) {
if (this.isExternal) {
return {
href: to,
target: '_blank',
rel: 'noopener'
}
}
return {
to: to
}
}
}
}
</script>
<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: '财务管理系统',
logo: 'favicon.ico'
}
}
}
</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>
<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() {
this.onlyOneChild = null;
return {};
},
methods: {
hasOneShowingChild(children = [], parent) {
//过滤子菜单(看是否有要显示的子菜单)
const showingChildren = children.filter((item) => {
//子菜单是否时显示 0为false
if (item.hidden) {
return false;
} else {
//赋值子菜单
this.onlyOneChild = item;
return true;
}
});
// 当只有一个子路由器时,默认显示子路由器
if (showingChildren.length === 1) {
return true;
}
// 如果没有要显示的子路由器,则显示父路由器
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>
<template>
<div :class="{'has-logo':showLogo}">
<logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
ref="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"
menu-trigger="click"
mode="vertical"
>
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
</el-menu>
</el-scrollbar>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import Logo from './Logo'
import SidebarItem from './SidebarItem'
import variables from '@/styles/variables.scss'
export default {
components: { SidebarItem, Logo },
computed: {
...mapGetters([
'permission_routes',
'sidebar'
]),
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>
<template>
<el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
<slot />
</el-scrollbar>
</template>
<script>
const tagAndTagSpacing = 4 // tagAndTagSpacing
export default {
name: 'ScrollPane',
data() {
return {
left: 0
}
},
computed: {
scrollWrapper() {
return this.$refs.scrollContainer.$refs.wrap
}
},
mounted() {
this.scrollWrapper.addEventListener('scroll', this.emitScroll, true)
},
beforeDestroy() {
this.scrollWrapper.removeEventListener('scroll', this.emitScroll)
},
methods: {
handleScroll(e) {
const eventDelta = e.wheelDelta || -e.deltaY * 40
const $scrollWrapper = this.scrollWrapper
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
},
emitScroll() {
this.$emit('scroll')
},
moveToTarget(currentTag) {
const $container = this.$refs.scrollContainer.$el
const $containerWidth = $container.offsetWidth
const $scrollWrapper = this.scrollWrapper
const tagList = this.$parent.$refs.tag
let firstTag = null
let lastTag = null
// find first tag and last tag
if (tagList.length > 0) {
firstTag = tagList[0]
lastTag = tagList[tagList.length - 1]
}
if (firstTag === currentTag) {
$scrollWrapper.scrollLeft = 0
} else if (lastTag === currentTag) {
$scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
} else {
// find preTag and nextTag
const currentIndex = tagList.findIndex(item => item === currentTag)
const prevTag = tagList[currentIndex - 1]
const nextTag = tagList[currentIndex + 1]
// the tag's offsetLeft after of nextTag
const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
// the tag's offsetLeft before of prevTag
const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
$scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
} else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
$scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
}
}
}
}
}
</script>
<style lang="scss" scoped>
.scroll-container {
white-space: nowrap;
position: relative;
overflow: hidden;
width: 100%;
::v-deep {
.el-scrollbar__bar {
bottom: 0px;
}
.el-scrollbar__wrap {
height: 49px;
}
}
}
</style>
<template>
<div id="tags-view-container" class="tags-view-container">
<scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
<router-link
v-for="tag in visitedViews"
ref="tag"
:key="tag.path"
:class="isActive(tag)?'active':''"
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
tag="span"
class="tags-view-item"
@click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
@contextmenu.prevent.native="openMenu(tag,$event)"
>
{{ tag.title }}
<span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
</router-link>
</scroll-pane>
<ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
<li @click="refreshSelectedTag(selectedTag)">Refresh</li>
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">Close</li>
<li @click="closeOthersTags">Close Others</li>
<li @click="closeAllTags(selectedTag)">Close All</li>
</ul>
</div>
</template>
<script>
import ScrollPane from './ScrollPane'
import path from 'path'
export default {
components: { ScrollPane },
data() {
return {
visible: false,
top: 0,
left: 0,
selectedTag: {},
affixTags: []
}
},
computed: {
visitedViews() {
return this.$store.state.tagsView.visitedViews
},
routes() {
return this.$store.state.permission.routes
}
},
watch: {
$route() {
this.addTags()
this.moveToCurrentTag()
},
visible(value) {
if (value) {
document.body.addEventListener('click', this.closeMenu)
} else {
document.body.removeEventListener('click', this.closeMenu)
}
}
},
mounted() {
this.initTags()
this.addTags()
},
methods: {
isActive(route) {
return route.path === this.$route.path
},
isAffix(tag) {
return tag.meta && tag.meta.affix
},
filterAffixTags(routes, basePath = '/') {
let tags = []
routes.forEach(route => {
if (route.meta && route.meta.affix) {
const tagPath = path.resolve(basePath, route.path)
tags.push({
fullPath: tagPath,
path: tagPath,
name: route.name,
meta: { ...route.meta }
})
}
if (route.children) {
const tempTags = this.filterAffixTags(route.children, route.path)
if (tempTags.length >= 1) {
tags = [...tags, ...tempTags]
}
}
})
return tags
},
initTags() {
const affixTags = this.affixTags = this.filterAffixTags(this.routes)
for (const tag of affixTags) {
// Must have tag name
if (tag.name) {
this.$store.dispatch('tagsView/addVisitedView', tag)
}
}
},
addTags() {
const { name } = this.$route
if (name) {
this.$store.dispatch('tagsView/addView', this.$route)
}
return false
},
moveToCurrentTag() {
const tags = this.$refs.tag
this.$nextTick(() => {
for (const tag of tags) {
if (tag.to.path === this.$route.path) {
this.$refs.scrollPane.moveToTarget(tag)
// when query is different then update
if (tag.to.fullPath !== this.$route.fullPath) {
this.$store.dispatch('tagsView/updateVisitedView', this.$route)
}
break
}
}
})
},
refreshSelectedTag(view) {
this.$store.dispatch('tagsView/delCachedView', view).then(() => {
const { fullPath } = view
this.$nextTick(() => {
this.$router.replace({
path: '/redirect' + fullPath
})
})
})
},
closeSelectedTag(view) {
this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
if (this.isActive(view)) {
this.toLastView(visitedViews, view)
}
})
},
closeOthersTags() {
this.$router.push(this.selectedTag)
this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
this.moveToCurrentTag()
})
},
closeAllTags(view) {
this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
if (this.affixTags.some(tag => tag.path === view.path)) {
return
}
this.toLastView(visitedViews, view)
})
},
toLastView(visitedViews, view) {
const latestView = visitedViews.slice(-1)[0]
if (latestView) {
this.$router.push(latestView.fullPath)
} else {
// now the default is to redirect to the home page if there is no tags-view,
// you can adjust it according to your needs.
if (view.name === 'Dashboard') {
// to reload home page
this.$router.replace({ path: '/redirect' + view.fullPath })
} else {
this.$router.push('/')
}
}
},
openMenu(tag, e) {
const menuMinWidth = 105
const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
const offsetWidth = this.$el.offsetWidth // container width
const maxLeft = offsetWidth - menuMinWidth // left boundary
const left = e.clientX - offsetLeft + 15 // 15: margin right
if (left > maxLeft) {
this.left = maxLeft
} else {
this.left = left
}
this.top = e.clientY
this.visible = true
this.selectedTag = tag
},
closeMenu() {
this.visible = false
},
handleScroll() {
this.closeMenu()
}
}
}
</script>
<style lang="scss" scoped>
.tags-view-container {
height: 34px;
width: 100%;
background: #fff;
border-bottom: 1px solid #d8dce5;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
.tags-view-wrapper {
.tags-view-item {
display: inline-block;
position: relative;
cursor: pointer;
height: 26px;
line-height: 26px;
border: 1px solid #d8dce5;
color: #495060;
background: #fff;
padding: 0 8px;
font-size: 12px;
margin-left: 5px;
margin-top: 4px;
&:first-of-type {
margin-left: 15px;
}
&:last-of-type {
margin-right: 15px;
}
&.active {
background-color: #42b983;
color: #fff;
border-color: #42b983;
&::before {
content: '';
background: #fff;
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
position: relative;
margin-right: 2px;
}
}
}
}
.contextmenu {
margin: 0;
background: #fff;
z-index: 3000;
position: absolute;
list-style-type: none;
padding: 5px 0;
border-radius: 4px;
font-size: 12px;
font-weight: 400;
color: #333;
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
li {
margin: 0;
padding: 7px 16px;
cursor: pointer;
&:hover {
background: #eee;
}
}
}
}
</style>
<style lang="scss">
//reset element css of el-icon-close
.tags-view-wrapper {
.tags-view-item {
.el-icon-close {
width: 16px;
height: 16px;
vertical-align: 2px;
border-radius: 50%;
text-align: center;
transition: all .3s cubic-bezier(.645, .045, .355, 1);
transform-origin: 100% 50%;
&:before {
transform: scale(.6);
display: inline-block;
vertical-align: -3px;
}
&:hover {
background-color: #b4bccc;
color: #fff;
}
}
}
}
</style>
export { default as AppMain } from './AppMain'
export { default as Navbar } from './Navbar'
export { default as Sidebar } from './Sidebar/index.vue'
export { default as TagsView } from './TagsView/index.vue'
<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="{hasTagsView:needTagsView}" class="main-container">
<div :class="{'fixed-header':fixedHeader}">
<navbar />
<tags-view v-if="needTagsView" />
</div>
<app-main />
</div>
</div>
</template>
<script>
import { AppMain, Navbar, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'
export default {
name: 'Layout',
components: {
AppMain,
Navbar,
Sidebar,
TagsView
},
mixins: [ResizeMixin],
computed: {
...mapState({
sidebar: state => state.app.sidebar,
device: state => state.app.device,
showSettings: state => state.settings.showSettings,
needTagsView: state => state.settings.tagsView,
fixedHeader: state => 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>
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 })
}
}
}
}
}
import Vue from 'vue'
import 'normalize.css/normalize.css' // a modern alternative to CSS resets
import Element from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import '@/styles/element-variables.scss'
import '@/styles/index.scss' // global css
import App from './App' // 导入App第一个组件
import store from './store'
import router from './router'
import './icons' // icon
import './permission' // 导入权限控制脚本
import './utils/error-log' // error log
//import print from "print-js"//引入打印插件
import * as filters from './filters' // global filters
Vue.use(Element)
// if (process.env.NODE_ENV === 'production') {
// const { mockXHR } = require('../mock')
// mockXHR()
// }
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
})
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})
import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login'] // no redirect whitelist
// 路由拦截器
router.beforeEach(async(to, from, next) => {
// start progress bar
NProgress.start()
// set page title
// 设置目标页面的title(从目标路由的meta中获取title)
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
// 获取store里面的登录令牌,有令牌,表示有登录
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page
// 如果有登录,并且目标路径是/login,路由到首页
next({ path: '/' })
NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
} else {
// determine whether the user has obtained his permission roles through getInfo
// 获取登录用户的角色,能获取到,表示有角色信息,否则就调用getInfo,获取当前登录用户的角色信息
const hasRoles = store.getters.roles && store.getters.roles.length > 0
if (hasRoles) {
//判断前往的路由是否有
let routes = store.getters.permission_routes
let tpath = to.path
let a = 0
routes.forEach(e => {
if(e.path == tpath){
a++;
next()
}
if(e.children){
e.children.forEach(c => {
if(c.path == tpath){
a++;
next()
}
})
}
});
if(a == 0){
Message.warning("你没有权限")
}
NProgress.done()
// next({path:from.fullPath})
} else {
try {
// get user info
// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
// 派发user/getInfo action,获取当前用户的角色信息
const { roles } = await store.dispatch('user/getInfo')
// generate accessible routes map based on roles
// 根据用户的角色信息,派发到permission/generateRoutes action,生成动态路由表
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
// dynamically add accessible routes
// 挂载动态路由
router.addRoutes(accessRoutes)
// hack method to ensure that addRoutes is complete
// set the replace: true, so the navigation will not leave a history record
next({ ...to, replace: true })
} catch (error) {
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next()
} else {
// other pages that do not have permission to access are redirected to the login page.
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
})
router.afterEach(() => {
// finish progress bar
NProgress.done()
})
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
import Layout from '@/layout'
/**
* 定义组件名称和组件对象的map对象
*/
export const componentMap = {
'layout': require('@/layout').default,
'permission_menu': () => import('@/views/permission/menu').then(m=>m.default),
'permission_role': () => import('@/views/permission/role').then(m=>m.default),
'company_list':()=>import('@/views/company/index').then(m=>m.default),
'company_add':()=>import('@/views/company/addcompany').then(m=>m.default),
'personal_vue': ()=>import('@/views/personal/personal').then(m=>m.default),
'staff_list':()=>import('@/views/staff/staffList').then(m=>m.default),
'staff_add':()=>import('@/views/staff/addStaff').then(m=>m.default),
'staff_updata':()=>import('@/views/staff/updataStaff').then(m=>m.default),
'type_list':()=>import('@/views/type/typeList').then(m=>m.default),
'type_add':()=>import('@/views/type/typeAdd').then(m=>m.default),
'type_updata':()=>import('@/views/type/typeUpdata').then(m=>m.default),
'project_list':()=>import('@/views/project/projectList').then(m=>m.default),
'project_add':()=>import('@/views/project/projectAdd').then(m=>m.default),
'project_updata':()=>import('@/views/project/projectUpdata').then(m=>m.default),
'project_member_list':()=>import('@/views/project/member/memberList').then(m=>m.default),
'project_member_updata':()=>import('@/views/project/member/memberUpdata').then(m=>m.default),
'project_income_list':()=>import('@/views/project/income/incomeList').then(m=>m.default),
'project_income_add':()=>import('@/views/project/income/incomeAdd').then(m=>m.default),
'project_income_updata':()=>import('@/views/project/income/incomeUpdata').then(m=>m.default),
'project_expend_list':()=>import('@/views/project/expend/expendList').then(m=>m.default),
'project_expend_add':()=>import('@/views/project/expend/expendAdd').then(m=>m.default),
'project_expend_updata':()=>import('@/views/project/expend/expendUpdata').then(m=>m.default),
//报销单
//'expense_list': () => import('@/views/expense/expenseList.vue').then(m => m.default),
//负责项目列表
'beresponsiblefor_List':()=>import('@/views/project/beresponsiblefor/beresponsibleforList').then(m => m.default),
//参与项目列表
'participatein_List':()=>import('@/views/project/participatein/participateinList').then(m => m.default),
'reimbursement_list':()=>import('@/views/reimbursement/reimbursementList').then(m=>m.default),
'reimbursement_add':()=>import('@/views/reimbursement/reimbursementAdd').then(m=>m.default),
'reimbursement_updata':()=>import('@/views/reimbursement/reimbursementUpdata').then(m=>m.default),
//'reimbursement_print':()=>import('@/views/reimbursement/reimbursementPrint').then(m=>m.default),
'reimbursement_finance_list':()=>import('@/views/reimbursement/finance/financeList').then(m=>m.default),
'reimbursement_headman_list':()=>import('@/views/reimbursement/headman/headmanList').then(m=>m.default),
'businessTravel_list':()=>import('@/views/businessTravel/businessTravelList').then(m=>m.default),
'businessTravel_add':()=>import('@/views/businessTravel/businessTravelAdd').then(m=>m.default),
'businessTravel_updata':()=>import('@/views/businessTravel/businessTravelUpdata').then(m=>m.default),
'businessTravel_finance_list':()=>import('@/views/businessTravel/finance/financeList').then(m=>m.default),
'businessTravel_headman_list':()=>import('@/views/businessTravel/headman/headmanList').then(m=>m.default),
'reimburtype_list': () => import('@/views/reimebursementItem/reimebursementItemList.vue').then(m => m.default),
'reimebursementItem_Add': () => import('@/views/reimebursementItem/reimebursementItemAdd.vue').then(m => m.default),
'reimebursementItem_Update': () => import('@/views/reimebursementItem/reimebursementItemUpdate.vue').then(m => m.default),
'apply_businessTravel_list':()=>import('@/views/businessTravel/apply/applyBusinessTravelList').then(m=>m.default),
'apply_businessTravel_add':()=>import('@/views/businessTravel/apply/applyBusinessTravelAdd').then(m=>m.default),
'apply_businessTravel_updata':()=>import('@/views/businessTravel/apply/applyBusinessTravelUpdata').then(m=>m.default),
'apply_businessTravel_finance_list':()=>import('@/views/businessTravel/apply/finance/financeList').then(m=>m.default),
'apply_businessTravel_headman_list':()=>import('@/views/businessTravel/apply/headman/headmanList').then(m=>m.default),
}
/**
* Note: sub-menu only appear when route children.length >= 1
* Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
*
* hidden: true 设置菜单是否隐藏(不显示在左边菜单,缺省false)
* alwaysShow: true 设置在一级菜单上,是否总是显示,true表示总是显示
* 如果为false,一级菜单只会在有多个子菜单情况下才显示
* redirect: noRedirect 如果设置成noRedirect,面包屑不会重定向
* name:'router-name' 路由名称,必须设置,且唯一
* meta : {
roles: ['admin','editor'] 允许路由的角色列表
title: 'title' 显示在左边导航栏和面包屑上的名称
icon: 'svg-name'/'el-icon-x' 图标名称
noCache: true 页面是否不要缓存,缺省为false
affix: true 标签页面是否总是显示(不能关闭)
breadcrumb: false 缺省true,是否以面包屑显示页面
activeMenu: '/example/list' 在左边菜单上高亮显示
}
*/
export const asyncRoutes=[
]
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/error-page/404'),
hidden: true
},
{
path: '/401',
component: () => import('@/views/error-page/401'),
hidden: true
},
//登录首页修改
{
path: '/',
// hidden: true,
component: Layout,
redirect: '/personal',
},
]
const createRouter = () => new Router({
// mode: 'history', // require service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes,asyncRoutes
})
const router = createRouter()
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
export default router
module.exports = {
title: 'Vue Element Admin',
/**
* @type {boolean} true | false
* @description Whether show the settings right-panel
*/
showSettings: true,
/**
* @type {boolean} true | false
* @description Whether need tagsView
*/
tagsView: true,
/**
* @type {boolean} true | false
* @description Whether fix the header
*/
fixedHeader: false,
/**
* @type {boolean} true | false
* @description Whether show the logo in sidebar
*/
sidebarLogo: true, // false,
/**
* @type {string | array} 'production' | ['production', 'development']
* @description Need show err logs component.
* The default is only used in the production env
* If you want to also use it in dev, you can pass ['production', 'development']
*/
errorLog: 'production'
}
const getters = {
sidebar: state => state.app.sidebar,
size: state => state.app.size,
device: state => state.app.device,
visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews,
token: state => state.user.token,
urId: state => state.user.urId,
avatar: state => state.user.avatar,
name: state => state.user.name,
introduction: state => state.user.introduction,
roles: state => state.user.roles,
permission_routes: state => state.permission.routes,
errorLogs: state => state.errorLog.logs,
info: state=>state.user.info,
companyId: state=>state.user.companyId,
memberId:state=>state.settings.memberId,
}
export default getters
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
Vue.use(Vuex)
// https://webpack.js.org/guides/dependency-management/#requirecontext
const modulesFiles = require.context('./modules', true, /\.js$/)
// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './app.js' => 'app'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
const store = new Vuex.Store({
modules,
getters
})
export default store
import Cookies from 'js-cookie'
const state = {
sidebar: {
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
withoutAnimation: false
},
device: 'desktop',
size: Cookies.get('size') || 'medium'
}
const mutations = {
TOGGLE_SIDEBAR: state => {
state.sidebar.opened = !state.sidebar.opened
state.sidebar.withoutAnimation = false
if (state.sidebar.opened) {
Cookies.set('sidebarStatus', 1)
} else {
Cookies.set('sidebarStatus', 0)
}
},
CLOSE_SIDEBAR: (state, withoutAnimation) => {
Cookies.set('sidebarStatus', 0)
state.sidebar.opened = false
state.sidebar.withoutAnimation = withoutAnimation
},
TOGGLE_DEVICE: (state, device) => {
state.device = device
},
SET_SIZE: (state, size) => {
state.size = size
Cookies.set('size', size)
}
}
const actions = {
toggleSideBar({ commit }) {
commit('TOGGLE_SIDEBAR')
},
closeSideBar({ commit }, { withoutAnimation }) {
commit('CLOSE_SIDEBAR', withoutAnimation)
},
toggleDevice({ commit }, device) {
commit('TOGGLE_DEVICE', device)
},
setSize({ commit }, size) {
commit('SET_SIZE', size)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
const state = {
logs: []
}
const mutations = {
ADD_ERROR_LOG: (state, log) => {
state.logs.push(log)
},
CLEAR_ERROR_LOG: (state) => {
state.logs.splice(0)
}
}
const actions = {
addErrorLog({ commit }, log) {
commit('ADD_ERROR_LOG', log)
},
clearErrorLog({ commit }) {
commit('CLEAR_ERROR_LOG')
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
import { constantRoutes, componentMap } from '@/router'
import { getRoutes } from '@/api/auth'
/**
* Use meta.role to determine if the current user has permission
* @param roles
* @param route
*/
function hasPermission(roles, route) {
if (route.meta && route.meta.roles) {
return roles.some(role => route.meta.roles.includes(role))
} else {
return true
}
}
export function filterAsyncRoutes(routes, roles) {
const res = []
routes.forEach(route => {
const tmp = { ...route }
if (hasPermission(roles, tmp)) {
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
res.push(tmp)
}
})
return res
}
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
}
}
// 替换route对象中的component
function replaceComponent(comp){
if(comp.component && typeof(comp.component)=='string'){
comp.component = componentMap[comp.component];
}
if(comp.children && comp.children.length>0){
for(let i=0;i<comp.children.length;i++){
comp.children[i] = replaceComponent(comp.children[i]);
}
}
return comp
}
const actions = {
generateRoutes: async function({ commit }, roles) {
// console.log(routes)
// 从后台请求所有的路由信息
let res = await getRoutes()
// 定义一个变量,用来存放可以访问的路由表
let dbAsyncRoutes = res.data;
let myAsyncRoutes = dbAsyncRoutes.filter(curr => {
if(curr.children == null || curr.children.length === 0){
delete curr.children
}
return replaceComponent(curr);
})
let accessedRoutes
// 判断当前的角色列表中,是否有包含admin
// if (roles == 1) {
// // 所有路由都可以被访问,将ansyncRoutes改造成从数据库中获取
// accessedRoutes = myAsyncRoutes || []
// console.log(accessedRoutes)
// } else {
// 根据角色,过滤掉不能访问的路由表
accessedRoutes = filterAsyncRoutes(myAsyncRoutes, roles)
//}
// commit
commit('SET_ROUTES', accessedRoutes)
// 成功返回
// console.log(accessedRoutes)
return accessedRoutes
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment