master
xy 1 year ago
parent cf79667321
commit fecb68bf4d

@ -3,7 +3,7 @@ import request from "@/utils/request";
export function getBudget(params){
return request({
method:'get',
url:'/api/admin/plan/index',
url:'/api/ht/plan/index',
params
})
}
@ -11,7 +11,7 @@ export function getBudget(params){
export function addBudget(data){
return request({
method:'post',
url:'/api/admin/plan/store',
url:'/api/ht/plan/store',
data
})
}
@ -19,7 +19,7 @@ export function addBudget(data){
export function delBudget(params){
return request({
method:'get',
url:'/api/admin/plan/destroy',
url:'/api/ht/plan/destroy',
params
})
}
@ -27,7 +27,7 @@ export function delBudget(params){
export function editorBudget(data){
return request({
method:'post',
url:'/api/admin/plan/save',
url:'/api/ht/plan/save',
data
})
}
@ -35,7 +35,7 @@ export function editorBudget(data){
export function detailBudget(params){
return request({
method:'get',
url:"/api/admin/plan/show",
url:"/api/ht/plan/show",
params
})
}

@ -6,7 +6,7 @@ import request from '@/utils/request'
export function listCommondepartment(params) {
return request({
url: '/api/admin/other/admin-department-list',
url: '/api/ht/other/admin-department-list',
method: 'get',
params:params,
noloading: true
@ -16,7 +16,7 @@ export function listCommondepartment(params) {
export function listCommonuser(params) {
return request({
url: '/api/admin/other/admin-user-list',
url: '/api/ht/other/admin-user-list',
method: 'get',
params:params,
noloading: true

@ -2,10 +2,10 @@ import request from '@/utils/request'
export function login(data) {
return request({
url: '/api/admin/auth/login',
url: '/api/auth/login',
method: 'post',
data,
noloading: true
isLoading: false
})
}
@ -29,25 +29,27 @@ export function loginOssV2 (data) {
export function getInfo(token) {
return request({
url: '/api/admin/auth/me',
url: '/api/auth/me',
method: 'post',
params: { token },
noloading: true
isLoading: false
})
}
export function logout() {
return request({
url: '/api/admin/auth/logout',
url: '/api/auth/logout',
method: 'post'
})
}
export function getAuthMenu(token) {
export function permissions() {
return request({
url: '/api/admin/auth/permissions',
method: 'get',
params: { token },
noloading: true
url: `/api/auth/module-permissions/${window.MODULE_NAME||window.location.pathname.replaceAll(/\//g,"")||process.env.VUE_APP_MODULE_NAME}`,
method: "get",
isLoading: false,
params: {
module: window.MODULE_NAME||window.location.pathname.replaceAll(/\//g,"")||process.env.VUE_APP_MODULE_NAME
}
})
}

@ -17,7 +17,7 @@ export function listdept() {
export function listdeptNoAuth(params = {show_tree:1}){
return request({
url:'/api/admin/other/admin-department-list',
url:'/api/ht/other/admin-department-list',
method:'get',
params
})
@ -33,7 +33,7 @@ export function del(data) {
export function adminDepartmentList(data) {
return request({
url: '/api/admin/other/admin-department-list',
url: '/api/ht/other/admin-department-list',
method: 'get',
params: data
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

@ -5,7 +5,7 @@
<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 menuComputed" :key="route.path" :item="route" :base-path="route.path" />
<sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
</el-menu>
</el-scrollbar>

@ -1,345 +1,76 @@
<template>
<div :class="classObj" class="app-wrapper">
<!-- 最顶部导航栏-->
<div class="top-head-bar" v-if="(!$store.state.app.isInIframe && !$store.state.app.isInElectron) && isShowTopBar">
<div class="top-head-bar__logo">
<img style="height: 20px" src="../assets/logo.png" alt="logo" />
</div>
<ul>
<li
v-for="item in $store.state.permission.rootMenu"
:class="{
'li-active':
new RegExp(`^${item.path}`).test($route.path)
}"
@click="menuClick(item)"
>
{{ item.name }}
</li>
</ul>
<div class="top-head-bar__user">
<el-dropdown class="avatar-container" trigger="click">
<div class="avatar-wrapper">
<div class="avatar-wrapper__name">{{ $store.state.user.name }}</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>
<router-link to="/info/password">
<el-dropdown-item>
个人信息
</el-dropdown-item>
</router-link>
<router-link to="/install" target="_blank">
<el-dropdown-item>
软件安装
</el-dropdown-item>
</router-link>
<el-dropdown-item v-if="!$store.state.app.isInElectron" class="user-logout" divided @click.native="logout">
<span style="display: block">退出</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar class="sidebar-container" />
<div class="mobile-sidebar-button" v-show="device==='mobile' && !sidebar.opened" @click="toggleSideBar">
<el-button type="primary" circle>
<SvgIcon icon-class="menu"></SvgIcon>
</el-button>
</div>
<div
v-if="device === 'mobile' && sidebar.opened"
class="drawer-bg"
@click="handleClickOutside"
/>
<div class="app-view-container">
<template v-if="$route.path === '/worker'">
<el-scrollbar style="height: 100%">
<worker></worker>
</el-scrollbar>
</template>
<template v-else-if="/^\/asset/.test($route.path)">
<sidebar class="sidebar-container" />
<div class="main-container">
<iframe ref="bookIframe" :src="iframeUrl"
>你的浏览器不支持该iframe</iframe
>
</div>
</template>
<template v-else-if="$route.path === '/oaOld'">
<div
style="width: 100%; height: 100%; overflow-x: hidden"
>
<iframe ref="oldIframe" style="width: 100%;" :src="oldOaUrl">你的浏览器不支持该iframe</iframe>
</div>
</template>
<template v-else-if="$route.path === '/old'">
<div
style="width: 100%; height: 100%; overflow-x: hidden"
>
<iframe ref="oldIframe" style="width: 100%;" :src="oldUrl">你的浏览器不支持该iframe</iframe>
</div>
</template>
<template v-else>
<sidebar class="sidebar-container" />
<div class="main-container">
<div :class="{ 'fixed-header': fixedHeader }" v-if="false">
<navbar />
</div>
<el-scrollbar style="height: 100%">
<app-main :is-show-top-bar="isShowTopBar"/>
</el-scrollbar>
</div>
</template>
<div class="main-container">
<app-main />
</div>
</div>
</template>
<script>
import { getOatoken } from "@/api/oatoken"
import { ossLogin } from "@/api/system/ossLogin";
import { Navbar, Sidebar, AppMain } from "./components";
import ResizeMixin from "./mixin/ResizeHandler";
import worker from "./components/worker/index.vue";
import axios from "axios";
window.$isShowTopBar = true;
window.hideTopBar = () => {
window.$isShowTopBar = false
}
import SvgIcon from '@/components/SvgIcon'
import { Navbar, Sidebar, AppMain } from './components'
import ResizeMixin from './mixin/ResizeHandler'
export default {
name: "Layout",
name: 'Layout',
components: {
Navbar,
Sidebar,
AppMain,
worker,
SvgIcon
},
mixins: [ResizeMixin],
data() {
return {
isShowTopBar: window.$isShowTopBar,
isIframe: false,
active: 0,
bookUrl: process.env.VUE_APP_OUT_Book,
gdzcUrl: `${process.env.VUE_APP_OUT_GDZC}/member/oss_login?id=${this.$store.state.user.userId}&username=${this.$store.state.user.username}`,
oldUrl: `${process.env.VUE_APP_OUT_OLD}?auth_token=${this.$store.getters.oa_token}`,
goodsUrl: `${process.env.VUE_APP_OUT_GOODS}/admin/oss-login?id=${this.$store.state.user.userId}&username=${this.$store.state.user.username}`,
oldOaUrl: `${process.env.VUE_APP_OLD_OA}/login/oss_login?auth_token=${this.$store.getters.oa_token}`
};
},
computed: {
sidebar() {
return this.$store.state.app.sidebar;
return this.$store.state.app.sidebar
},
device() {
return this.$store.state.app.device;
return this.$store.state.app.device
},
fixedHeader() {
return this.$store.state.settings.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",
};
},
iframeUrl() {
let urlMap = new Map([
['/bookmanage', this.bookUrl],
['/gdzc', this.gdzcUrl],
['/goods', this.goodsUrl]
])
return urlMap.get(this.$route.path.substring(this.$route.path.lastIndexOf('/')))
mobile: this.device === 'mobile'
}
}
},
methods: {
async logout() {
if (this.$store.state.app.isInElectron) {
return
}
await this.$store.dispatch('app/clearLayout')
await this.$store.dispatch("user/logout");
this.$router.push(`/login`);
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
handleClickOutside() {
this.$store.dispatch("app/closeSideBar", {
withoutAnimation: false,
});
},
menuClick(item) {
this.$router.push(item.path);
},
},
created() {
window.routerTo = {};
for (let key in this.$store.state.permission.rootMenu) {
let item = this.$store.state.permission.rootMenu[key]
window.routerTo[item.path] = () => this.$router.push(item.path)
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
}
},
mounted() {
},
watch: {
"$route.path": {
handler: function (url) {
if(/^\/asset/.test(url)) {
if(this.$store.state.app.sidebar.opened) {
this.$store.commit('app/TOGGLE_SIDEBAR')
}
}
if (/\/bookmanage/.test(url)) {
this.$nextTick(() => {
this.$refs['bookIframe'].onload = () => {
this.$refs["bookIframe"].contentWindow.postMessage(
{
key: "login",
data: {
authToken: this.$store.state.user.authToken
},
},
"*"
);
}
})
return;
}
},
immediate: true,
},
},
beforeRouteEnter(to,from,next){
document.getElementsByTagName('iframe').forEach(dom => {
dom.onload = null;
})
next()
}
};
}
</script>
<style lang="scss" scoped>
@import "~@/styles/mixin.scss";
@import "~@/styles/variables.scss";
.app-view-container {
height: 100%;
padding-top: $topbarHeight;
&:has(.main-container) {
padding-top: 0;
}
}
.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
width: 100%;
&.mobile.openSidebar {
position: fixed;
&.mobile.openSidebar{
z-index: 1000;
top: 0;
}
}
.top-head-bar {
background: #338de3ff;
height: $topbarHeight;
filter: drop-shadow(0 1px 1px #49a0f3);
display: grid;
-webkit-app-region: drag;
grid-template-columns: auto 0.5fr 6fr 0.2fr 1fr;
grid-template-rows: $topbarHeight;
grid-template-areas: "logo . menu . user";
z-index: 2000;
position: fixed;
top: 0;
left: 0;
right: 0;
&__logo {
-webkit-app-region: no-drag;
height: $topbarHeight;
grid-area: logo;
display: flex;
align-items: center;
padding: 0 20px;
}
@media screen and (max-width: 1000px) {
&__logo {
display: none;
}
}
&__user {
-webkit-app-region: no-drag;
grid-area: user;
}
ul {
grid-area: menu;
height: 100%;
display: flex;
justify-self: flex-end;
align-items: flex-end;
li {
-webkit-app-region: no-drag;
color: #fff;
height: 40px;
line-height: 40px;
list-style: none;
transition: all 300ms ease-out;
border-top-right-radius: 6px;
border-top-left-radius: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
padding: 0 20px;
position: relative;
&::after {
content: "";
background: #338de3ff;
height: 3px;
width: 0;
border-radius: 1px;
transition: all 300ms ease-out;
position: absolute;
left: 6px;
bottom: 2px;
}
& + li {
margin-left: 20px;
}
&:hover {
background: #fff;
color: rgb(100, 100, 100);
&::after {
width: calc(100% - 12px);
}
}
}
.li-active {
background: #fff;
color: rgb(100, 100, 100);
&::after {
width: calc(100% - 12px);
}
}
}
}
.drawer-bg {
background: #000;
opacity: 0.3;
@ -360,80 +91,20 @@ export default {
}
.hideSidebar .fixed-header {
width: calc(100% - 54px);
width: calc(100% - 54px)
}
.mobile .fixed-header {
width: 100%;
}
.avatar-container {
height: 100%;
margin-right: 30px;
.avatar-wrapper {
height: 100%;
display: flex;
align-items: center;
.user-avatar {
cursor: pointer;
width: 40px;
height: 40px;
border-radius: 10px;
}
&__name {
color: #fff;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 0 6px;
}
.el-icon-caret-bottom {
cursor: pointer;
color: #fff;
position: absolute;
right: -20px;
font-size: 12px;
}
}
}
div:has(iframe) {
overflow: hidden;
}
iframe {
height: calc(100vh - #{$topbarHeight});
width: calc(100% + 12px);
border: none;
position: relative;
top: 0;
left: 0;
bottom: 0;
}
</style>
<style lang="scss">
.app-wrapper:not(:has(.top-head-bar)) {
.app-view-container {
padding-top: 0!important;
}
.main-container {
top: 0!important;
}
.sidebar-container {
top: 0!important;
}
.app-view-container iframe {
height: 100vh;
}
::v-deep .el-button.is-circle {
padding: 8px;
}
@media (max-width: 960px) {
.top-head-bar {
display: none !important;
}
.main-container {
top: 0 !important;
}
.mobile-sidebar-button {
position: fixed;
z-index: 998;
right: 16px;
bottom: 16px;
}
</style>

@ -0,0 +1,16 @@
<template>
<router-view />
</template>
<script>
export default {
data() {
return {}
},
methods: {},
computed: {}
}
</script>
<style scoped lang="scss">
</style>

@ -57,28 +57,37 @@ Vue.prototype.$integrateData = (target,value) => {
}
window.$router = router;
// if (window.__POWERED_BY_WUJIE__) {
// let instance;
// window.__WUJIE_MOUNT = () => {
// instance = new Vue({
// router,
// store,
// render: h => h(App)
// }).$mount("#app")
// };
// window.__WUJIE_UNMOUNT = () => {
// instance.$destroy();
// };
// } else {
// new Vue({
// router,
// store,
// render: h => h(App)
// }).$mount("#app")
// }
new Vue({
el: '#app',
router,
store,
render: h => h(App)
})
if (window.__POWERED_BY_WUJIE__) {
let instance;
window.__WUJIE_MOUNT = () => {
instance = new Vue({
router,
store,
render: h => h(App)
}).$mount("#app")
window.MODULE_NAME = window.$wujie?.props?.module_name;
console.log('token-wujie',window.MODULE_NAME)
setToken(window.$wujie?.props?.auth_token)
router.push('/')
};
window.__WUJIE_UNMOUNT = () => {
instance.$destroy();
};
} else {
if (window.top !== window.self) {
// 当前页面在iframe中
window._IN_IFRAME = true;
window.addEventListener("message",function (e) {
const { module_name, auth_token } = e.data;
window.MODULE_NAME = module_name;
console.log('token',auth_token)
setToken(auth_token)
router.push('/')
})
}
new Vue({
router,
store,
render: h => h(App)
}).$mount("#app")
}

@ -1,91 +1,46 @@
import router from './router'
import store from './store'
import {
Message
} from 'element-ui'
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 { getToken } from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
import { loginOssV2, loginOss } from "@/api/user"
import { setToken, removeToken } from "@/utils/auth";
NProgress.configure({
showSpinner: false
}) // NProgress Configuration
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login','/preview'] // no redirect whitelist
const whiteList = ['/login'] // no redirect whitelist
router.beforeEach(async (to, from, next) => {
router.beforeEach(async(to, from, next) => {
// start progress bar
NProgress.start()
store.commit('app/SET_ISINIFRAME')
// set page title
document.title = getPageTitle(to.meta.title)
if (to.query.token) {
removeToken()
const res = await loginOss({
auth_token: to.query.token
})
setToken(res.access_token)
store.commit('user/SET_TOKEN',res.access_token)
const {
roles
} = await store.dispatch('user/getInfo')
// generate accessible routes map based on roles
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
// dynamically add accessible routes
router.addRoutes(accessRoutes)
delete to.query.token
next({
...to,
replace: true
})
return
}
// determine whether the user has logged in
const hasToken = getToken()
console.log(4444,hasToken)
if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page
next({ path: '/' })
NProgress.done()
} else {
// determine whether the user has obtained his permission roles through getInfo
const hasRoles = store.getters.roles && store.getters.roles.length > 0
if (hasRoles) {
if (store.state.permission.addRoutes && store.state.permission.addRoutes instanceof Array && store.state.permission.addRoutes.length > 0) {
next()
} else {
try {
// get user info
// note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
const {
roles
} = await store.dispatch('user/getInfo')
// generate accessible routes map based on roles
const { roles } = await store.dispatch('user/getInfo')
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
})
next({ ...to, replace: true })
} catch (error) {
console.log(error)
// remove token and go to login page to re-login
await store.dispatch('user/resetToken')
Message.error(error || 'Has Error')

@ -45,9 +45,9 @@ export const constantRoutes = [{
{
path: '/',
component: Layout,
redirect: '/worker',
redirect: '/dashboard',
children: [{
path: 'contract/dashboard',
path: 'dashboard',
name: '系统首页',
component: () => import('@/views/dashboard/index'),
meta: {

@ -1,83 +1,45 @@
import {
asyncRoutes,
constantRoutes
} from '@/router'
import Layout from '@/layout'
import {
getAuthMenu
} from '@/api/user.js'
const pathHandler = (item) => {
if(!item.path || item.path?.includes('#') || item.path == ''){
return item.id + '_key'
}
if(/^\^/.test(item.path)){
return item.path.replace(/^\^+/g,"")
}
if(/^\$/.test(item.path)){
return item.path.replace(/^\$+/g,"")
}
return item.path
// if(path.includes('$')){
// return path.replace(/^\$+/g,"")
// }
// if(path.includes('^')){
// return path.replace(/^\^+/g,"")
// }
// if(path.includes('#') || path == ''){
// return id + '_key'
// }
// return path
import { asyncRoutes, constantRoutes } from '@/router'
import { permissions } from "@/api/me"
import path from "path"
import Layout from "@/layout"
import Nested from "@/layout/nested.vue"
const loadView = (view) => {
return (resolve) => require([`@/views${view}`], resolve);
}
const componentHandler = (path) => {
//return path === '#'|| path == '' ? Layout : loadView(path)
if(path === '#' || path === ''){
const componentHandle = (url, route)=> {
if (/^#+/.test(route.path)) {
return Layout
}
if(path.includes('#') && path !== '#'){
return ()=>import('@/layout/noLayout')
}
return loadView(path)
}
/**
* 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 if (/^#+/.test(route.path) && route.pid !== 0) {
return Nested
} else {
return true
return loadView(url)
}
}
/**
* 静态路由懒加载
* @param view 格式必须为 xxx/xxx 开头不要加斜杠
* @returns
*/
export const loadView = (view) => {
return (resolve) => require([`@/views${view}`], resolve);
}
/**
* Filter asynchronous routing tables by recursion
* @param routes asyncRoutes
* @param roles
*/
export function filterAsyncRoutes(routes, roles) {
export function filterAsyncRoutes(routes) {
const res = []
routes.forEach(route => {
const tmp = {
...route
}
if (hasPermission(roles, tmp)) {
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles)
if (!route.visible) return
let tmp= {
key: `key-${route.id}`,
path: route.path === '#' ? '' : route.path,
component: componentHandle(route.url, route),
name: route.name,
hidden: !route.visible,
meta: {
title: route.title,
icon: route.icon,
guard: route.guard_name,
folder: route.folder,
}
res.push(tmp)
}
if (route.children && route.children instanceof Array && route.children.length > 0) {
tmp.children = filterAsyncRoutes(route.children)
}
res.push(tmp)
})
return res
@ -85,176 +47,34 @@ export function filterAsyncRoutes(routes, roles) {
const state = {
routes: [],
rootMenu:[],
systemMenu:[],
addRoutes: [],
sidebarMenuMap: new Map()
}
/**
* 后台查询的菜单数据拼装成路由格式的数据
* @param routes
*/
export function generaMenu(routes, data) {
data.forEach(item => {
let params = {};
if(item.path?.includes('?')){
let flag = item.path.split('?')
item.path = flag[0]
if(flag[1]){
let list = flag[1].split('&')
list.forEach(item => {
let kv = item.split('=')
Object.defineProperty(params,kv[0],{
value:kv[1],
writable:true,
enumerable:true,
configurable:false
})
})
}
}
if (item.url === "/") {
routes.push({
path: '/',
component: Layout,
redirect: '/worker',
children: [{
path: 'dashboard',
name: '系统首页',
component: () => import('@/views/dashboard/index'),
meta: {
title: '系统首页',
icon: 'dashboard',
params
}
}]
})
}else if(/^\^/.test(item.path)){
const menu = {
path: pathHandler(item),
component: Layout,
children: [{
path: "",
name: 'menu_' + item.id,
component: (item.url.includes('#')||item.path == '') ? Layout : loadView(item.url),
meta: {
title: item.name,
id: item.id,
roles: ['admin'],
auths:item.has_auth_node_tags,
params,
icon: item.icon
}
}, ]
}
if (item.children) {
generaMenu(menu.children, item.children)
}
routes.push(menu)
} else {
var path = item.url;
if (item.path != "null" && item.path != null && item.path != "") {
path = item.path
}
const menu = {
path: (path.includes('#') ? item.id + '_key' : path),
redirect: item.redirect || '',
component: componentHandler(item.url),
hidden: item.hidden ?? false,
children: [],
name: 'menu_' + item.id,
meta: {
title: item.name,
id: item.id,
roles: ['admin'],
params,
icon: item.icon
}
}
if (item.children) {
generaMenu(menu.children, item.children)
}
routes.push(menu)
}
})
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
},
SET_ROOTMENU:(state,menu) => {
state.rootMenu = menu
},
SET_SYSTEMMENU:(state,menu) => {
state.systemMenu = menu
},
SET_SIDEBARMENUMAP: (state,{ k,v }) => {
state.sidebarMenuMap.set(k,v)
}
}
const actions = {
generateRoutes({
commit
}, roles) {
return new Promise(resolve => {
const loadMenuData = []
// 先查询后台并返回左侧菜单数据并把数据添加到路由
getAuthMenu(state.token).then(response => {
let data = response
commit('SET_ROOTMENU',data)
let routes = data?.find(item => item.path === '/contract').children
let root = data?.map(item => {
let menu = []
generaMenu(menu,item.children)
commit('SET_SIDEBARMENUMAP', { k: item.path, v: menu })
if(item.children.length > 0){
item.redirect = item.children[0]?.path
}
if(item.path === '/contract') {
item.redirect = '/contract/dashboard'
}
item.hidden = true
return item
})
Object.assign(loadMenuData, [...routes,...root])
asyncRoutes.length=0;
generaMenu(asyncRoutes, loadMenuData)
//console.log(asyncRoutes)
generateRoutes({ commit }, roles) {
return new Promise(async (resolve, reject) => {
try {
const routes = await permissions()
let accessedRoutes
if (roles.includes('admin')) {
accessedRoutes = asyncRoutes || []
} else {
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
}
accessedRoutes.push({
path: '*',
redirect: '/404',
hidden: true
})
accessedRoutes = filterAsyncRoutes(routes)
//把404拦截放在最后匹配
accessedRoutes.push({ path: '*', redirect: '/404', hidden: true })
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
// generaMenu(asyncRoutes, data)
}).catch(error => {
console.log(error)
})
} catch (err) {
reject(err)
}
})
}
}
export default {
namespaced: true,
state,

@ -3,7 +3,7 @@ import {
logout,
getInfo,
loginOss
} from '@/api/user'
} from '@/api/me'
import { getOaToken } from "@/api/out"
import {
getToken,
@ -17,14 +17,11 @@ import {
const getDefaultState = () => {
return {
token: getToken(),
userId:'',
name: '',
username:'',
avatar: '',
min_allow_level: 2,
adminId: '',
department: {},
roles: [],
authToken: ''
role: [],
}
}
@ -37,29 +34,20 @@ const mutations = {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_LEVEL: (state, level=2) => {
state.min_allow_level = level
},
SET_NAME: (state, name) => {
state.name = name
},
SET_USERNAME:(state,username) => {
state.username = username
},
SET_USERID:(state,id) => {
state.userId = id
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_ROLES: (state, roles) => {
state.roles = roles
SET_ROLE: (state, role) => {
state.role = role
},
SET_ADMIN_ID: (state, id) => {
state.adminId = id
},
SET_DEPARTMENT: (state, department) => {
state.department = department
},
SET_AUTHTOKEN: (state, token) => {
state.authToken = token
}
}
@ -105,11 +93,6 @@ const actions = {
username: username.trim(),
password: password
}).then(response => {
console.log(response)
const {
data
} = response;
console.log(response.access_token)
commit('SET_TOKEN', response.access_token)
setToken(response.access_token)
@ -126,34 +109,18 @@ const actions = {
state
}) {
return new Promise((resolve, reject) => {
getOaToken().then(res => {
commit('SET_AUTHTOKEN',res.auth_token)
})
getInfo(state.token).then(response => {
getInfo().then(response => {
if (!response) {
reject('身份验证失败请重新登录')
}
response["roles"] = ["admin"];
const {
id,
roles,
name,
username,
avatar,
department,
min_allow_level
} = response
const { name, avatar, id, role, department } = response
commit('SET_USERNAME',username)
commit('SET_USERID',id)
commit('SET_ROLES', roles)
commit('SET_DEPARTMENT',department)
commit('SET_NAME', name)
commit('SET_AVATAR', avatar)
commit('SET_DEPARTMENT', department)
commit('SET_LEVEL', min_allow_level)
commit('SET_ADMIN_ID', id)
commit('SET_ROLE', role)
resolve(response)
}).catch(error => {
reject(error)

@ -5,7 +5,6 @@
transition: margin-left .28s;
margin-left: $sideBarWidth;
position: relative;
top: 50px;
}
.sidebar-container {
@ -15,7 +14,7 @@
height: 100%;
position: fixed;
font-size: 0px;
top: 50px;
top: 0;
bottom: 0;
left: 0;
z-index: 1001;

@ -29,7 +29,7 @@ service.interceptors.request.use(
text: "正在加载中..."
})
}
if (store.getters.token) {
if (getToken()) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
@ -59,49 +59,47 @@ service.interceptors.response.use(
* You can also judge the status by HTTP Status Code
*/
response => {
if (loading) {
loading.close()
loading?.close()
if (response.status !== 200) {
return Promise.reject("系统错误")
}
const res = response.data
// if the custom code is not 20000, it is judged as an error.
if (res.errcode) {
if (res.code !== 0) {
Message({
message: res.errmsg || 'Error',
message: res.msg || '系统错误',
type: 'error',
duration: 5 * 1000,
offset:50
duration: 5 * 1000
})
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
if (res.errcode === 50008 || res.errcode === 50012 || res.errcode === 50014) {
if (res.code === 20001) {
// to re-login
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again',
'Confirm logout', {
confirmButtonText: 'Re-Login',
cancelButtonText: 'Cancel',
type: 'warning'
MessageBox.alert('您的登录状态已过期,需重新登录',
'登录已过期', {
confirmButtonText: '确定',
type: 'warning',
closeOnClickModal: false,
showClose: false
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
}
return Promise.reject(new Error(res.errmsg || 'Error'))
return Promise.reject(new Error(res.msg || 'Error'))
} else {
return res
return res.data
}
},
error => {
if (loading) {
loading.close()
}
console.log('err' + error) // for debug
loading?.close()
console.error('err' + error) // for debug
Message({
message: error.message,
message: /Network Error/g.test(error) ? "网络错误" : "系统错误",
type: 'error',
duration: 5 * 1000,
offset: 50
duration: 5 * 1000
})
return Promise.reject(error)
}

@ -359,7 +359,7 @@ import {
import {
getInfo
} from '@/api/user.js'
} from '@/api/me.js'
import {
Message
} from 'element-ui'

@ -860,7 +860,7 @@ import {
} from "@/api/contract/contract";
import { getBudget } from "@/api/budget/budget";
import { getInfo } from "@/api/user.js";
import { getInfo } from "@/api/me.js";
import { listdeptNoAuth } from '@/api/system/department'
import {deepCopy} from "@/utils";
export default {

@ -997,7 +997,7 @@ import { getBudget } from "@/api/budget/budget";
import { getOatoken } from "@/api/oatoken";
import { deepCopy, parseTime, resetSelect,moneyFormatter } from '@/utils'
import { Message } from "element-ui";
import { getInfo } from "@/api/user.js";
import { getInfo } from "@/api/me.js";
import { getToken } from "@/utils/auth";
import { getOutDetail, httpCurl, updateFlow } from "@/api/out";
import editor from "./components/editorContract";

@ -1193,7 +1193,7 @@ import { getBudget } from "@/api/budget/budget";
import { getOatoken } from "@/api/oatoken";
import { deepCopy, parseTime, resetSelect, moneyFormatter, throttle } from '@/utils'
import { Message } from "element-ui";
import { getInfo } from "@/api/user.js";
import { getInfo } from "@/api/me.js";
import { getToken } from "@/utils/auth";
import { getOaToken, getOutDetail, httpCurl, updateFlow } from "@/api/out";
import editor from "./components/editorContract";

@ -309,7 +309,7 @@ import { getBudget } from "@/api/budget/budget";
import { getOatoken } from "@/api/oatoken";
import { parseTime, deepCopy } from "@/utils";
import { Message } from "element-ui";
import { getInfo } from "@/api/user.js";
import { getInfo } from "@/api/me.js";
import detail from "./components/detailContract";
import paymentRegistration from "./components/paymentRegistration";

@ -415,7 +415,7 @@
} from "element-ui";
import {
getInfo
} from '@/api/user.js'
} from '@/api/me.js'
import editor from "./components/editorContract"
import detail from "./components/detailContract"

@ -311,7 +311,7 @@ import LxHeader from "@/components/LxHeader/index.vue";
import Pagination from "@/components/Pagination";
import PieChart from "./components/PieChart.vue";
import { adminDepartmentList } from '@/api/system/department';
import { adminUserList, getInfo } from '@/api/user';
import { adminUserList, getInfo } from '@/api/me';
import { getNotice, readNotice, statistic, carry } from "@/api/dashboard/notice";
import { parseTime, moneyFormatter } from '@/utils';
import { Message } from "element-ui";

@ -1,233 +1,221 @@
<template>
<div class="login-container" v-if="showLogin">
<div ref="formContainer" class="form-container">
<div class="login-container">
<img class="build-img" src="~@/assets/login/build.png" alt="">
<!-- <vue-particles color="#ffffff" :particleOpacity="0.7" :particlesNumber="80" shapeType="circle" :particleSize="4"-->
<!-- linesColor="#ffffff" :linesWidth="1" :lineLinked="true" :lineOpacity="0.4" :linesDistance="150" :moveSpeed="3"-->
<!-- :hoverEffect="true" hoverMode="grab" :clickEffect="true" clickMode="push"> </vue-particles>-->
<!-- <img class="title-img" src="~@/assets/login/title.png" alt="">-->
<el-form size="small" ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on"
label-position="left">
<div class="title-container">
<img :src="require('@/assets/imgs/login-title.png')" alt="" />
<h3 class="title">欢迎登录</h3>
</div>
<div class="login-pannel">
<div class="left">
<img :src="require('@/assets/imgs/login-img1.png')" alt="" />
<el-form-item prop="username">
<div class="form-item">
<span class="svg-container">
<svg-icon icon-class="user" />
</span>
<el-input ref="username" v-model="loginForm.username" placeholder="请输入登录名" name="username" type="text"
tabindex="1" auto-complete="on" />
</div>
<div class="right">
<el-form
ref="loginForm"
:model="loginForm"
:rules="loginRules"
class="login-form"
auto-complete="on"
label-position="left"
>
<el-form-item class="form-item" prop="username">
<span class="svg-container">
<svg-icon icon-class="user" />
</span>
<el-input
ref="username"
v-model="loginForm.username"
placeholder="请输入账号"
:autofocus="true"
name="username"
type="text"
tabindex="1"
auto-complete="true"
/>
</el-form-item>
<el-form-item class="form-item" prop="password">
<span class="svg-container">
<svg-icon icon-class="password" />
</span>
<el-input
:key="passwordType"
ref="password"
:autofocus="true"
v-model="loginForm.password"
:type="passwordType"
placeholder="请输入密码"
name="password"
tabindex="2"
auto-complete="true"
@keyup.enter.native="handleLogin"
/>
</el-form-item>
<el-checkbox size="large" style="margin-top: 18px;zoom: 1.3;" v-model="isRemember"></el-checkbox>
<el-button
:loading="loading"
type="primary"
round
style="
margin-top: 35px;
font-size: 18px;
letter-spacing: 3px;
border-radius: 50px;
height: 50px;
width: 100%;
background-color: #3d7af6;
filter: drop-shadow(0px 4px 9px rgba(72, 93, 237, 0.63));
"
@click.native.prevent="handleLogin"
>登录</el-button
>
</el-form>
</el-form-item>
<el-form-item prop="password">
<div class="form-item">
<span class="svg-container">
<svg-icon icon-class="password" />
</span>
<el-input :key="passwordType" ref="password" v-model="loginForm.password" :type="passwordType"
placeholder="请输入密码" name="password" tabindex="2" auto-complete="on" @keyup.enter.native="handleLogin" />
<span class="show-pwd" @click="showPwd">
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
</span>
</div>
</div>
</div>
</el-form-item>
<!-- <el-form-item prop="code">-->
<!-- <div class="form-item">-->
<!-- <span class="svg-container">-->
<!-- <svg-icon icon-class="message" />-->
<!-- </span>-->
<!-- <el-input ref="username" v-model="loginForm.code" placeholder="请输入验证码" name="username" type="text"-->
<!-- tabindex="1" auto-complete="on" />-->
<!-- <el-button class="msg-btn" :loading="msgLoading" type="primary" size="small" :disabled="isVer" @click="sendSms">{{ isVer ? (''+verTime+'') : '' }}</el-button>-->
<!-- </div>-->
<!-- </el-form-item>-->
<el-button :loading="loading" type="primary" class="login-btn"
@click.native.prevent="handleLogin">登录</el-button>
</el-form>
<footer class="copyright">
版权所有{{ copyright }}
</footer>
</div>
<div v-else class="login-container-w"></div>
</template>
<script>
import drawMixin from "@/views/login/mixin/drawMixin";
import { validUsername } from "@/utils/validate";
import Cookies from "js-cookie";
import {
validUsername
} from '@/utils/validate'
import { login, getInfo } from "@/api/me";
const defaultSettings = require('../../../src/settings.js')
export default {
mixins: [drawMixin],
name: "Login",
name: 'Login',
data() {
const validateUsername = (rule, value, callback) => {
if (false) {
callback(new Error("请正确输入登录名"));
} else {
callback();
}
};
const validatePassword = (rule, value, callback) => {
if (false) {
callback(new Error("请正确输入密码"));
if (value.length < 6) {
callback(new Error('密码输入错误'))
} else {
callback();
callback()
}
};
}
return {
isRemember: false,
showLogin: false,
title: "",
loginForm: {
username: "",
password: "",
username: '',
password: '',
//code: ''
},
loginRules: {
username: [
{
required: true,
trigger: "blur",
validator: validateUsername,
},
],
password: [
{
required: true,
trigger: "blur",
validator: validatePassword,
},
],
username: [{
required: true,
trigger: 'blur'
}],
password: [{
required: true,
trigger: 'blur',
validator: validatePassword
}],
// code: [
// {
// required: true,
// trigger: 'blur',
// message: '',
// validator: (rule, value, callback) => {
// if (value.length !== 4) {
// callback(new Error(''))
// } else {
// callback()
// }
// }
// }
// ]
},
msgLoading: false,
loading: false,
passwordType: "password",
passwordType: 'password',
redirect: undefined,
};
},
beforeCreate() {},
created() {
var query = this.$route.query;
if (query.tp) {
this.showLogin = false;
} else {
this.showLogin = true;
}
if (query.token && query.userid && query.tp) {
this.loading = true;
this.$store
.dispatch("user/loginskip", {
token: query.token,
tp: query.tp,
})
.then(() => {
this.$router.push({
path: "/",
});
this.loading = false;
})
.catch((error) => {
console.log(error);
this.loading = false;
});
}
let lgifStr = Cookies.get('lgif')
if (lgifStr) {
try {
this.isRemember = true;
this.loginForm = JSON.parse(window.atob(lgifStr))
} catch (e) {
this.loginForm = {
username: "",
password: "",
}
verTime: 60,
isVer: false,
temp: {
mobile: "",
token: ""
}
}
},
watch: {
$route: {
handler: function (route) {
this.redirect = route.query && route.query.redirect;
handler: function(route) {
this.redirect = route.query && route.query.redirect
},
immediate: true,
},
immediate: true
}
},
created() {
this.title = defaultSettings.title;
this.copyright = defaultSettings.copyright;
},
methods: {
async sendSms () {
if (this.isVer) return;
if (this.loginForm.username) {
this.msgLoading = true;
try {
await sendSms({
username: this.loginForm.username
})
this.isVer = true;
this.verTime = 60;
this.$message({
message: '验证码已发送',
type:'success'
})
let timer = setInterval(() => {
this.verTime--;
if (this.verTime <= 0) {
this.isVer = false;
clearInterval(timer);
}
}, 1000);
this.msgLoading = false;
} catch (e) {
this.msgLoading = false;
}
} else {
this.$message({
message: '请输入登录名',
type: 'warning'
})
}
},
showPwd() {
if (this.passwordType === "password") {
this.passwordType = "";
if (this.passwordType === 'password') {
this.passwordType = ''
} else {
this.passwordType = "password";
this.passwordType = 'password'
}
this.$nextTick(() => {
this.$refs.password.focus();
});
this.$refs.password.focus()
})
},
handleLogin() {
this.$refs.loginForm.validate((valid) => {
//
async handleLogin() {
this.$refs.loginForm.validate(async(valid) => {
if (valid) {
this.loading = true;
this.$store
.dispatch("user/login", this.loginForm)
.then(() => {
console.log(this.redirect);
if (this.isRemember) {
Cookies.set('lgif',window.btoa(JSON.stringify(this.loginForm)))
} else {
Cookies.remove('lgif')
}
this.$router.push({
path: this.redirect || "/",
});
this.loading = false;
this.loading = true
this.$store.dispatch('user/login', this.loginForm).then(() => {
this.$router.push({
path: this.redirect || '/'
})
.catch(() => {
this.loading = false;
});
this.loading = false
}).catch(() => {
this.loading = false
})
} else {
console.log("error submit!!");
return false;
console.log('error submit!!')
return false
}
});
},
},
};
})
}
}
}
</script>
<style lang="scss">
#particles-js {
width: 100%;
height: 99%;
position: absolute;
}
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
$bg: #283443;
$light_gray: #fff;
$cursor: #fff;
$bg:#122583;
$light_gray:#122583;
$cursor: #122583;
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
.login-container .el-input input {
@ -236,84 +224,76 @@ $cursor: #fff;
}
/* reset element-ui css */
.login-container {
.el-input {
flex: 1;
display: inline-block;
height: 47px;
width: 70%;
input {
background: transparent;
border: 0px;
-webkit-appearance: none;
border-radius: 0px;
padding: 12px 5px 12px 15px;
color: #666;
height: 47px;
caret-color: #000;
padding: 4px 5px 4px 15px;
color: $light_gray;
caret-color: $cursor;
&:-webkit-autofill {
box-shadow: 0 0 0px 1000px $bg inset !important;
-webkit-text-fill-color: $cursor !important;
//box-shadow: 0 0 0px 1000px $bg inset !important;
//-webkit-text-fill-color: $cursor !important;
}
}
}
.el-form-item {
color: #0003;
font-size: 16px;
line-height: 24px;
border-radius: 6px;
background-color: #ffffff;
border: 1px solid #d9d9d9;
}
}
</style>
<style lang="scss" scoped>
::v-deep .el-checkbox__inner {}
$bg: #2d3a4b;
$dark_gray: #889aa4;
$light_gray: #eee;
.login-container-w {
min-height: 100%;
width: 100%;
background-color: #ffffff;
overflow: hidden;
$bg:#122583;
$dark_gray:#122583;
$light_gray:#122583;
.build-img {
position: absolute;
width: 36.5vw;
object-fit: contain;
top: 50%;
transform: translateY(-50%);
left: 10.2%;
}
.title-img {
display: block;
width: 44.64vw;
object-fit: contain;
margin: 16.11vh auto 0;
}
.form-item {
height: 3vw;
width: 86.4%;
margin: auto;
border-radius: 8px;
background-color: #f4f4f4;
filter: drop-shadow(0 0 1px #cdcdcd);
display: flex;
align-items: center;
}
.login-container {
min-height: 100%;
height: 100%;
width: 100%;
background: url("../../assets/imgs/login-bkg.png") no-repeat;
background: url("~@/assets/login/bkg.png") no-repeat;
background-size: cover;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
.form-container {
width: 930px;
max-width: 100vw;
background: #fff;
border-radius: 14px;
padding-bottom: 53px;
filter: drop-shadow(0px 5px 24.5px rgba(74, 113, 240, 0.23));
.login-pannel {
display: flex;
justify-content: space-between;
padding: 0 41px 0 104px;
margin-top: 57px;
}
.left {
img {
width: 310px;
}
}
.login-form {
position: relative;
width: 28.7vw;
margin: 50vh 10.2vw 0 auto;
transform: translateY(-50%);
overflow: hidden;
border-radius: 10px;
box-shadow: inset 0 0 4px rgb(255,255,255,0.8);
filter: drop-shadow(0 0 7px rgba(0,0,0,0.2));
background-color: rgba(255,255,255,0.2);
}
.tips {
@ -328,76 +308,112 @@ $light_gray: #eee;
}
}
.form-item {
width: 361px;
height: 51px;
margin-bottom: 0;
}
.svg-container {
padding: 6px 0;
padding: 6px 5px 6px 15px;
color: $dark_gray;
vertical-align: middle;
width: 25px;
width: 30px;
display: inline-block;
margin-left: 15px;
}
.title-container {
display: flex;
justify-content: center;
position: relative;
margin-top: 85px;
img {
width: 754px;
margin-bottom: 2vw;
.title {
text-align: center;
font-size: 1.7vw;
letter-spacing: 4px;
color: #ffffff;
padding: 1.41vw 0 1.2vw;
position: relative;
&::after {
content: "";
width: 100%;
height: 1px;
background: linear-gradient(to right, #fff0 20%, #fff, #fff0 80%);
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
}
}
.show-pwd {
position: absolute;
right: 10px;
top: 7px;
right: 8%;
top: 50%;
transform: translate(0, -50%);
font-size: 16px;
color: $dark_gray;
cursor: pointer;
user-select: none;
}
.msg-btn {
border-radius: 0 8px 8px 0;
height: 100%;
background-image: linear-gradient(90deg, #1d57da 0%, #1d57da 0%, #4185c5 100%);
}
.login-btn {
width: 86.4%;
height: 3vw;
border-radius: 8px;
padding: 0;
background-image: linear-gradient(90deg, #1d57da 0%, #1d57da 0%, #05a658 100%);
display: block;
margin: auto auto 3.2vw;
font-size: 1.21vw;
letter-spacing: 3px;
color: #ffffff;
}
}
::v-deep .el-form-item--small.el-form-item {
margin-bottom: 1.5vw;
}
.form-item + .form-item {
margin-top: 18px;
.copyright {
width: 100%;
text-align: center;
color: #fff;
line-height: 16px;
font-size: 16px;
position: absolute;
left: 0;
bottom: 6vh;
}
::v-deep .el-form-item__error {
left: 6.8%;
}
@media (max-width: 960px) {
.form-container {
width: 90% !important;
height: 70% !important;
padding: 20px;
.title-container {
margin-top: 0;
& > img {
width: 100%;
object-fit: contain;
display: block;
margin: auto;
}
}
.left {
display: none;
}
.right {
width: 100%;
}
.login-pannel {
margin-top: 10% !important;
padding: 0 20px !important;
}
.title-img {
display: none;
}
.login-container .login-form {
max-width: 420px;
width: 78%;
margin: auto;
position: relative;
top: 50%;
transform: translateY(-50%);
}
.login-container .title-container .title {
font-size: 15px;
}
.form-item {
height: 40px;
margin-bottom: 12px;
}
.login-container .login-btn {
height: 40px;
font-size: 14px;
}
::v-deep .el-form-item__error {
bottom: 0;
top: auto;
}
}
.login-container .el-form-item {
width: 100% !important;
}
</style>

@ -18,7 +18,7 @@
} from '@/api/system/user.js'
import {
getInfo
} from '@/api/user.js'
} from '@/api/me.js'
export default {
data() {

@ -35,7 +35,7 @@
import {
getInfo
} from '@/api/user'
} from '@/api/me'
export default {
name: 'Profile',

@ -136,7 +136,7 @@
import { index, show, save, destroy } from "@/api/system/diyMenu";
import { listmenu } from "@/api/system/menu";
import { deepCopy } from '@/utils';
import { getAuthMenu } from "@/api/user"
import { getAuthMenu } from "@/api/me"
import SvgIcon from "@/components/SvgIcon/index.vue";
export default {
components: {

@ -25,8 +25,8 @@ module.exports = {
* In most cases please use '/' !!!
* Detail: https://cli.vuejs.org/config/#publicpath
*/
publicPath: process.env.ENV === "staging" ? "/admin_test" : '/admin',
outputDir: './dist',
publicPath: `/${process.env.VUE_APP_MODULE_NAME}`,
outputDir: `../cz_hjjc/public/${process.env.VUE_APP_MODULE_NAME}`,
assetsDir: 'static',
lintOnSave: false,
productionSourceMap: false,

Loading…
Cancel
Save