左侧菜单以及nav同步

main
许宏杰 2 days ago
parent 0581c54404
commit a1c4878002

@ -49,6 +49,7 @@
"js-beautify": "1.13.0",
"js-cookie": "3.0.1",
"jsencrypt": "3.0.0-rc.1",
"node-forge": "^1.3.1",
"nprogress": "0.2.0",
"quill": "2.0.2",
"screenfull": "5.0.2",

@ -1,4 +1,4 @@
import request from '@/utils/request'
import request from "@/utils/request";
// 登录方法
export function login(username, password, code, uuid) {
@ -6,55 +6,55 @@ export function login(username, password, code, uuid) {
username,
password,
code,
uuid
}
uuid,
};
return request({
url: '/login',
url: "/login",
headers: {
isToken: false,
repeatSubmit: false
repeatSubmit: false,
},
method: 'post',
data: data
})
method: "post",
data: data,
});
}
// 注册方法
export function register(data) {
return request({
url: '/register',
url: "/register",
headers: {
isToken: false
isToken: false,
},
method: 'post',
data: data
})
method: "post",
data: data,
});
}
// 获取用户详细信息
export function getInfo() {
return request({
url: '/getInfo',
method: 'get'
})
url: "/getInfo",
method: "get",
});
}
// 退出方法
export function logout() {
return request({
url: '/logout',
method: 'post'
})
url: "/logout",
method: "post",
});
}
// 获取验证码
export function getCodeImg() {
return request({
url: '/captchaImage',
url: "/captchaImage",
headers: {
isToken: false
isToken: false,
},
method: 'get',
timeout: 20000
})
method: "get",
timeout: 20000,
});
}

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14.58 14.58"><defs></defs><title>icon-dwgl-1</title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M13.38,5.46H9.12V1.2A1.2,1.2,0,0,0,7.92,0H1.2A1.2,1.2,0,0,0,0,1.2V13.38a1.2,1.2,0,0,0,1.2,1.2H7.92a1.2,1.2,0,0,0,.6-.16,1.2,1.2,0,0,0,.6.16h4.26a1.2,1.2,0,0,0,1.2-1.2V6.65a1.2,1.2,0,0,0-1.2-1.2ZM3.93,11.25a.3.3,0,0,1-.3.3H2.43a.3.3,0,0,1-.3-.3v-1.2a.3.3,0,0,1,.3-.3h1.2a.3.3,0,0,1,.3.3Zm0-3.36a.3.3,0,0,1-.3.3H2.43a.3.3,0,0,1-.3-.3V6.69a.3.3,0,0,1,.3-.3h1.2a.3.3,0,0,1,.3.3Zm0-3.36a.3.3,0,0,1-.3.3H2.43a.3.3,0,0,1-.3-.3V3.33a.3.3,0,0,1,.3-.3h1.2a.3.3,0,0,1,.3.3ZM7,11.25a.3.3,0,0,1-.3.3H5.5a.3.3,0,0,1-.3-.3v-1.2a.3.3,0,0,1,.3-.3h1.2a.3.3,0,0,1,.3.3ZM7,7.89a.3.3,0,0,1-.3.3H5.5a.3.3,0,0,1-.3-.3V6.69a.3.3,0,0,1,.3-.3h1.2a.3.3,0,0,1,.3.3ZM7,4.52a.3.3,0,0,1-.3.3H5.5a.3.3,0,0,1-.3-.3V3.33A.3.3,0,0,1,5.5,3h1.2a.3.3,0,0,1,.3.3Zm0,0"/></g></g></svg>

After

Width:  |  Height:  |  Size: 951 B

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13.81 14.71"><defs></defs><title>icon-rwgl</title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M10.07,0H1.6A1.6,1.6,0,0,0,0,1.6V11a3.74,3.74,0,0,0,3.73,3.73H12.2a1.6,1.6,0,0,0,1.6-1.6V3.73A3.74,3.74,0,0,0,10.07,0ZM7.29,10H3.85a.71.71,0,0,1,0-1.41H7.29a.71.71,0,0,1,0,1.41ZM10,6H3.85a.7.7,0,0,1,0-1.41H10A.7.7,0,1,1,10,6Zm0,0"/></g></g></svg>

After

Width:  |  Height:  |  Size: 450 B

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13.79 14.76"><defs></defs><title>icon-zcgl-1</title><g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1"><path class="cls-1" d="M13.75,6.26c-1,1.17-3.6,2-6.63,2H6.67c-3,0-5.61-.83-6.63-2l0,0V8.45c1,1.2,3.6,2.05,6.67,2.05h.44c3.07,0,5.68-.86,6.67-2.05V6.3l0,0ZM7.11,0H6.67C3.6,0,1,.86,0,2.05V4.2l0,0c1,1.17,3.6,2,6.63,2h.44c3,0,5.61-.84,6.63-2l0,0V2.05C12.79.86,10.18,0,7.11,0Zm6.63,10.51c-1,1.17-3.6,2-6.63,2H6.67c-3,0-5.61-.83-6.63-2l0,0V12.7c1,1.2,3.6,2.05,6.67,2.05h.44c3.07,0,5.68-.86,6.67-2.05V10.55l0,0Zm0,0"/></g></g></svg>

After

Width:  |  Height:  |  Size: 608 B

@ -1,12 +1,12 @@
// base color
$blue: #324157;
$light-blue:#3A71A8;
$red:#C03639;
$pink: #E65D6E;
$green: #30B08F;
$tiffany: #4AB7BD;
$yellow:#FEC171;
$panGreen: #30B08F;
$light-blue: #3a71a8;
$red: #c03639;
$pink: #e65d6e;
$green: #30b08f;
$tiffany: #4ab7bd;
$yellow: #fec171;
$panGreen: #30b08f;
//
$base-menu-color: #bfcbd9;
@ -14,7 +14,7 @@ $base-menu-color-active:#f4f4f5;
$base-menu-background: #304156;
$base-logo-title-color: #ffffff;
$base-menu-light-color:rgba(0,0,0,.70);
$base-menu-light-color: rgba(0, 0, 0, 0.7);
$base-menu-light-background: #ffffff;
$base-logo-light-title-color: #001529;
@ -36,7 +36,7 @@ $base-sub-menu-background:#000c17;
$base-sub-menu-hover:#001528;
*/
$base-sidebar-width: 200px;
$base-sidebar-width: 260px;
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
@ -50,5 +50,5 @@ $base-sidebar-width: 200px;
subMenuHover: $base-sub-menu-hover;
sideBarWidth: $base-sidebar-width;
logoTitleColor: $base-logo-title-color;
logoLightTitleColor: $base-logo-light-title-color
logoLightTitleColor: $base-logo-light-title-color;
}

@ -2,8 +2,12 @@
<el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
<span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
<span
v-if="item.redirect === 'noRedirect' || index == levelList.length - 1"
class="no-redirect"
>{{ item.meta.title }}</span
>
<!-- <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a> -->
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
@ -13,80 +17,86 @@
export default {
data() {
return {
levelList: null
}
levelList: null,
};
},
watch: {
$route(route) {
// if you go to the redirect page, do not update the breadcrumbs
if (route.path.startsWith('/redirect/')) {
return
}
this.getBreadcrumb()
if (route.path.startsWith("/redirect/")) {
return;
}
this.getBreadcrumb();
},
},
created() {
this.getBreadcrumb()
this.getBreadcrumb();
},
methods: {
getBreadcrumb() {
// only show routes with meta.title
let matched = []
const router = this.$route
const pathNum = this.findPathNum(router.path)
let matched = [];
const router = this.$route;
const pathNum = this.findPathNum(router.path);
// multi-level menu
if (pathNum > 2) {
const reg = /\/\w+/gi
const reg = /\/\w+/gi;
const pathList = router.path.match(reg).map((item, index) => {
if (index !== 0) item = item.slice(1)
return item
})
this.getMatched(pathList, this.$store.getters.defaultRoutes, matched)
if (index !== 0) item = item.slice(1);
return item;
});
this.getMatched(pathList, this.$store.getters.defaultRoutes, matched);
} else {
matched = router.matched.filter(item => item.meta && item.meta.title)
matched = router.matched.filter((item) => item.meta && item.meta.title);
}
//
if (!this.isDashboard(matched[0])) {
matched = [{ path: "/index", meta: { title: "首页" } }].concat(matched)
matched = [{ path: "/index", meta: { title: "首页" } }].concat(matched);
}
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
this.levelList = matched.filter(
(item) => item.meta && item.meta.title && item.meta.breadcrumb !== false
);
},
findPathNum(str, char = "/") {
let index = str.indexOf(char)
let num = 0
let index = str.indexOf(char);
let num = 0;
while (index !== -1) {
num++
index = str.indexOf(char, index + 1)
num++;
index = str.indexOf(char, index + 1);
}
return num
return num;
},
getMatched(pathList, routeList, matched) {
let data = routeList.find(item => item.path == pathList[0] || (item.name += '').toLowerCase() == pathList[0])
let data = routeList.find(
(item) =>
item.path == pathList[0] ||
(item.name += "").toLowerCase() == pathList[0]
);
if (data) {
matched.push(data)
matched.push(data);
if (data.children && pathList.length) {
pathList.shift()
this.getMatched(pathList, data.children, matched)
pathList.shift();
this.getMatched(pathList, data.children, matched);
}
}
},
isDashboard(route) {
const name = route && route.name
const name = route && route.name;
if (!name) {
return false
return false;
}
return name.trim() === 'Index'
return name.trim() === "Index";
},
handleLink(item) {
const { redirect, path } = item
const { redirect, path } = item;
if (redirect) {
this.$router.push(redirect)
return
}
this.$router.push(path)
}
}
this.$router.push(redirect);
return;
}
this.$router.push(path);
},
},
};
</script>
<style lang="scss" scoped>

@ -0,0 +1,9 @@
<template>
<div>1111</div>
</template>
<script>
export default {};
</script>
<style></style>

@ -10,45 +10,47 @@
</template>
<script>
import iframeToggle from "./IframeToggle/index"
import iframeToggle from "./IframeToggle/index";
export default {
name: 'AppMain',
name: "AppMain",
components: { iframeToggle },
computed: {
cachedViews() {
return this.$store.state.tagsView.cachedViews
return this.$store.state.tagsView.cachedViews;
},
key() {
return this.$route.path
}
return this.$route.path;
},
},
watch: {
$route() {
this.addIframe()
}
this.addIframe();
},
},
mounted() {
this.addIframe()
this.addIframe();
},
methods: {
addIframe() {
const {name} = this.$route
const { name } = this.$route;
if (name && this.$route.meta.link) {
this.$store.dispatch('tagsView/addIframeView', this.$route)
}
}
}
this.$store.dispatch("tagsView/addIframeView", this.$route);
}
},
},
};
</script>
<style lang="scss" scoped>
.app-main {
/* 50= navbar 50 */
min-height: calc(100vh - 50px);
// min-height: calc(100vh - 50px);
min-height: 100%;
width: 100%;
position: relative;
overflow: hidden;
background: #f2f4f6;
}
.fixed-header + .app-main {

@ -1,12 +1,21 @@
<template>
<div class="navbar">
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!topNav"/>
<hamburger
id="hamburger-container"
:is-active="sidebar.opened"
class="hamburger-container"
@toggleClick="toggleSideBar"
/>
<breadcrumb
id="breadcrumb-container"
class="breadcrumb-container"
v-if="!topNav"
/>
<top-nav id="topmenu-container" class="topmenu-container" v-if="topNav" />
<div class="right-menu">
<template v-if="device!=='mobile'">
<!-- <template v-if="device!=='mobile'">
<search id="header-search" class="right-menu-item" />
<el-tooltip content="源码地址" effect="dark" placement="bottom">
@ -23,21 +32,25 @@
<size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip>
</template>
</template> -->
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
<el-dropdown
class="avatar-container right-menu-item hover-effect"
trigger="click"
>
<div class="avatar-wrapper">
<img :src="avatar" class="user-avatar">
<img src="@/assets/images/touxiang.png" class="user-avatar" />
<span class="avatar-userName">{{ name }}</span>
<i class="el-icon-caret-bottom" />
</div>
<el-dropdown-menu slot="dropdown">
<router-link to="/user/profile">
<!-- <router-link to="/user/profile">
<el-dropdown-item>个人中心</el-dropdown-item>
</router-link>
<el-dropdown-item @click.native="setting = true">
<el-dropdown-item @click.native="setting = true" divided>
<span>布局设置</span>
</el-dropdown-item>
<el-dropdown-item divided @click.native="logout">
</el-dropdown-item> -->
<el-dropdown-item @click.native="logout">
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
@ -47,15 +60,15 @@
</template>
<script>
import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import TopNav from '@/components/TopNav'
import Hamburger from '@/components/Hamburger'
import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect'
import Search from '@/components/HeaderSearch'
import RuoYiGit from '@/components/RuoYi/Git'
import RuoYiDoc from '@/components/RuoYi/Doc'
import { mapGetters } from "vuex";
import Breadcrumb from "@/components/Breadcrumb";
import TopNav from "@/components/TopNav";
import Hamburger from "@/components/Hamburger";
import Screenfull from "@/components/Screenfull";
import SizeSelect from "@/components/SizeSelect";
import Search from "@/components/HeaderSearch";
import RuoYiGit from "@/components/RuoYi/Git";
import RuoYiDoc from "@/components/RuoYi/Doc";
export default {
components: {
@ -66,48 +79,46 @@ export default {
SizeSelect,
Search,
RuoYiGit,
RuoYiDoc
RuoYiDoc,
},
computed: {
...mapGetters([
'sidebar',
'avatar',
'device'
]),
...mapGetters(["sidebar", "name", "avatar", "device"]),
setting: {
get() {
return this.$store.state.settings.showSettings
return this.$store.state.settings.showSettings;
},
set(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'showSettings',
value: val
})
}
this.$store.dispatch("settings/changeSetting", {
key: "showSettings",
value: val,
});
},
},
topNav: {
get() {
return this.$store.state.settings.topNav
}
}
return this.$store.state.settings.topNav;
},
},
},
methods: {
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
this.$store.dispatch("app/toggleSideBar");
},
async logout() {
this.$confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$store.dispatch('LogOut').then(() => {
location.href = '/index';
this.$confirm("确定注销并退出系统吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
}).catch(() => {});
}
}
}
.then(() => {
this.$store.dispatch("LogOut").then(() => {
location.href = "/index";
});
})
.catch(() => {});
},
},
};
</script>
<style lang="scss" scoped>
@ -116,18 +127,18 @@ export default {
overflow: hidden;
position: relative;
background: #fff;
box-shadow: 0 1px 4px rgba(0,21,41,.08);
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.hamburger-container {
line-height: 46px;
height: 100%;
float: left;
cursor: pointer;
transition: background .3s;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
&:hover {
background: rgba(0, 0, 0, .025)
background: rgba(0, 0, 0, 0.025);
}
}
@ -164,10 +175,10 @@ export default {
&.hover-effect {
cursor: pointer;
transition: background .3s;
transition: background 0.3s;
&:hover {
background: rgba(0, 0, 0, .025)
background: rgba(0, 0, 0, 0.025);
}
}
}
@ -178,19 +189,27 @@ export default {
.avatar-wrapper {
margin-top: 5px;
position: relative;
display: flex;
align-items: center;
.user-avatar {
cursor: pointer;
width: 40px;
height: 40px;
border-radius: 10px;
width: 30px;
height: 30px;
// border-radius: 10px;
}
.avatar-userName {
font-size: 15px;
color: #192733;
font-family: "Alibaba PuHuiTiR";
font-weight: 400;
margin-left: 5px;
}
.el-icon-caret-bottom {
cursor: pointer;
position: absolute;
right: -20px;
top: 25px;
top: 20px;
font-size: 12px;
}
}

@ -1,45 +1,80 @@
<template>
<div class="sidebar-logo-container" :class="{'collapse':collapse}" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
<div
class="sidebar-logo-container"
:class="{ collapse: collapse }"
:style="{
backgroundColor:
sideTheme === 'theme-dark'
? variables.menuBackground
: variables.menuLightBackground,
}"
>
<transition name="sidebarLogoFade">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<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" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
<h1
v-else
class="sidebar-title"
:style="{
color:
sideTheme === 'theme-dark'
? variables.logoTitleColor
: variables.logoLightTitleColor,
}"
>
{{ 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" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
<!-- <img v-if="logo" :src="logo" class="sidebar-logo" /> -->
<h1
class="sidebar-title"
:style="{
color:
sideTheme === 'theme-dark'
? variables.logoTitleColor
: variables.logoLightTitleColor,
}"
>
{{ title }}
</h1>
</router-link>
</transition>
</div>
</template>
<script>
import logoImg from '@/assets/logo/logo.png'
import variables from '@/assets/styles/variables.scss'
import logoImg from "@/assets/logo/logo.png";
import variables from "@/assets/styles/variables.scss";
export default {
name: 'SidebarLogo',
name: "SidebarLogo",
props: {
collapse: {
type: Boolean,
required: true
}
required: true,
},
},
computed: {
variables() {
return variables;
},
sideTheme() {
return this.$store.state.settings.sideTheme
}
return this.$store.state.settings.sideTheme;
},
},
data() {
return {
title: process.env.VUE_APP_TITLE,
logo: logoImg
}
}
}
logo: logoImg,
};
},
};
</script>
<style lang="scss" scoped>
@ -55,8 +90,8 @@ export default {
.sidebar-logo-container {
position: relative;
width: 100%;
height: 50px;
line-height: 50px;
height: 55px;
line-height: 55px;
background: #2b2f3a;
text-align: center;
overflow: hidden;
@ -76,11 +111,12 @@ export default {
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;
line-height: 25px;
vertical-align: middle;
font-size: 19px;
color: #192734;
font-family: "Alimama ShuHeiTi";
letter-spacing: 1px;
}
}

@ -1,12 +1,29 @@
<template>
<div :class="{'has-logo':showLogo}" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
<div
:class="{ 'has-logo': showLogo }"
:style="{
backgroundColor:
settings.sideTheme === 'theme-dark'
? variables.menuBackground
: variables.menuLightBackground,
}"
>
<logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
:collapse="isCollapse"
:background-color="settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground"
:text-color="settings.sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor"
:background-color="
settings.sideTheme === 'theme-dark'
? variables.menuBackground
: variables.menuLightBackground
"
:text-color="
settings.sideTheme === 'theme-dark'
? variables.menuColor
: variables.menuLightColor
"
:unique-opened="true"
:active-text-color="settings.theme"
:collapse-transition="false"
@ -51,7 +68,7 @@ export default {
},
isCollapse() {
return !this.sidebar.opened;
}
}
},
},
};
</script>

@ -1,67 +1,77 @@
import Vue from 'vue'
import Vue from "vue";
import Cookies from 'js-cookie'
import Cookies from "js-cookie";
import Element from 'element-ui'
import './assets/styles/element-variables.scss'
import Element from "element-ui";
import "./assets/styles/element-variables.scss";
import '@/assets/styles/index.scss' // global css
import '@/assets/styles/ruoyi.scss' // ruoyi css
import App from './App'
import store from './store'
import router from './router'
import directive from './directive' // directive
import plugins from './plugins' // plugins
import { download } from '@/utils/request'
import "@/assets/styles/index.scss"; // global css
import "@/assets/styles/ruoyi.scss"; // ruoyi css
import App from "./App";
import store from "./store";
import router from "./router";
import directive from "./directive"; // directive
import plugins from "./plugins"; // plugins
import { download } from "@/utils/request";
import './assets/icons' // icon
import './permission' // permission control
import "./assets/icons"; // icon
import "./permission"; // permission control
import { getDicts } from "@/api/system/dict/data";
import { getConfigKey } from "@/api/system/config";
import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi";
import {
parseTime,
resetForm,
addDateRange,
selectDictLabel,
selectDictLabels,
handleTree,
} from "@/utils/ruoyi";
// 分页组件
import Pagination from "@/components/Pagination";
// 自定义表格工具组件
import RightToolbar from "@/components/RightToolbar"
import RightToolbar from "@/components/RightToolbar";
// 富文本组件
import Editor from "@/components/Editor"
import Editor from "@/components/Editor";
// 文件上传组件
import FileUpload from "@/components/FileUpload"
import FileUpload from "@/components/FileUpload";
// 图片上传组件
import ImageUpload from "@/components/ImageUpload"
import ImageUpload from "@/components/ImageUpload";
// 图片预览组件
import ImagePreview from "@/components/ImagePreview"
import ImagePreview from "@/components/ImagePreview";
// 字典标签组件
import DictTag from '@/components/DictTag'
import DictTag from "@/components/DictTag";
// 头部标签组件
import VueMeta from 'vue-meta'
import VueMeta from "vue-meta";
// 字典数据组件
import DictData from '@/components/DictData'
import DictData from "@/components/DictData";
//通用表格页面
import MainApp from "@/components/MainApp";
// 全局方法挂载
Vue.prototype.getDicts = getDicts
Vue.prototype.getConfigKey = getConfigKey
Vue.prototype.parseTime = parseTime
Vue.prototype.resetForm = resetForm
Vue.prototype.addDateRange = addDateRange
Vue.prototype.selectDictLabel = selectDictLabel
Vue.prototype.selectDictLabels = selectDictLabels
Vue.prototype.download = download
Vue.prototype.handleTree = handleTree
Vue.prototype.getDicts = getDicts;
Vue.prototype.getConfigKey = getConfigKey;
Vue.prototype.parseTime = parseTime;
Vue.prototype.resetForm = resetForm;
Vue.prototype.addDateRange = addDateRange;
Vue.prototype.selectDictLabel = selectDictLabel;
Vue.prototype.selectDictLabels = selectDictLabels;
Vue.prototype.download = download;
Vue.prototype.handleTree = handleTree;
// 全局组件挂载
Vue.component('DictTag', DictTag)
Vue.component('Pagination', Pagination)
Vue.component('RightToolbar', RightToolbar)
Vue.component('Editor', Editor)
Vue.component('FileUpload', FileUpload)
Vue.component('ImageUpload', ImageUpload)
Vue.component('ImagePreview', ImagePreview)
Vue.component("DictTag", DictTag);
Vue.component("Pagination", Pagination);
Vue.component("RightToolbar", RightToolbar);
Vue.component("Editor", Editor);
Vue.component("FileUpload", FileUpload);
Vue.component("ImageUpload", ImageUpload);
Vue.component("ImagePreview", ImagePreview);
Vue.component("MainApp", MainApp);
Vue.use(directive)
Vue.use(plugins)
Vue.use(VueMeta)
DictData.install()
Vue.use(directive);
Vue.use(plugins);
Vue.use(VueMeta);
DictData.install();
/**
* If you don't want to use mock-server
@ -73,14 +83,14 @@ DictData.install()
*/
Vue.use(Element, {
size: Cookies.get('size') || 'medium' // set element-ui default size
})
size: Cookies.get("size") || "medium", // set element-ui default size
});
Vue.config.productionTip = false
Vue.config.productionTip = false;
new Vue({
el: '#app',
el: "#app",
router,
store,
render: h => h(App)
})
render: (h) => h(App),
});

@ -1,10 +1,10 @@
import Vue from 'vue'
import Router from 'vue-router'
import Vue from "vue";
import Router from "vue-router";
Vue.use(Router)
Vue.use(Router);
/* Layout */
import Layout from '@/layout'
import Layout from "@/layout";
/**
* Note: 路由配置项
@ -31,153 +31,160 @@ import Layout from '@/layout'
// 公共路由
export const constantRoutes = [
{
path: '/redirect',
path: "/redirect",
component: Layout,
hidden: true,
children: [
{
path: '/redirect/:path(.*)',
component: () => import('@/views/redirect')
}
]
path: "/redirect/:path(.*)",
component: () => import("@/views/redirect"),
},
],
},
{
path: '/login',
component: () => import('@/views/login'),
hidden: true
path: "/login",
component: () => import("@/views/login"),
hidden: true,
},
{
path: '/register',
component: () => import('@/views/register'),
hidden: true
path: "/register",
component: () => import("@/views/register"),
hidden: true,
},
{
path: '/404',
component: () => import('@/views/error/404'),
hidden: true
path: "/404",
component: () => import("@/views/error/404"),
hidden: true,
},
{
path: '/401',
component: () => import('@/views/error/401'),
hidden: true
path: "/401",
component: () => import("@/views/error/401"),
hidden: true,
},
{
path: '',
path: "",
component: Layout,
redirect: 'index',
redirect: "index",
children: [
// {
// path: 'index',
// component: () => import('@/views/index'),
// name: 'Index',
// meta: { title: '首页', icon: 'dashboard', affix: true }
// }
],
},
{
path: 'index',
component: () => import('@/views/index'),
name: 'Index',
meta: { title: '首页', icon: 'dashboard', affix: true }
}
]
path: "/index",
component: () => import("@/views/index"),
name: "Index",
meta: { title: "首页", icon: "dashboard", affix: true },
hidden: true,
},
{
path: '/user',
path: "/user",
component: Layout,
hidden: true,
redirect: 'noredirect',
redirect: "noredirect",
children: [
{
path: 'profile',
component: () => import('@/views/system/user/profile/index'),
name: 'Profile',
meta: { title: '个人中心', icon: 'user' }
}
]
}
]
path: "profile",
component: () => import("@/views/system/user/profile/index"),
name: "Profile",
meta: { title: "个人中心", icon: "user" },
},
],
},
];
// 动态路由,基于用户权限动态去加载
export const dynamicRoutes = [
{
path: '/system/user-auth',
path: "/system/user-auth",
component: Layout,
hidden: true,
permissions: ['system:user:edit'],
permissions: ["system:user:edit"],
children: [
{
path: 'role/:userId(\\d+)',
component: () => import('@/views/system/user/authRole'),
name: 'AuthRole',
meta: { title: '分配角色', activeMenu: '/system/user' }
}
]
path: "role/:userId(\\d+)",
component: () => import("@/views/system/user/authRole"),
name: "AuthRole",
meta: { title: "分配角色", activeMenu: "/system/user" },
},
],
},
{
path: '/system/role-auth',
path: "/system/role-auth",
component: Layout,
hidden: true,
permissions: ['system:role:edit'],
permissions: ["system:role:edit"],
children: [
{
path: 'user/:roleId(\\d+)',
component: () => import('@/views/system/role/authUser'),
name: 'AuthUser',
meta: { title: '分配用户', activeMenu: '/system/role' }
}
]
path: "user/:roleId(\\d+)",
component: () => import("@/views/system/role/authUser"),
name: "AuthUser",
meta: { title: "分配用户", activeMenu: "/system/role" },
},
],
},
{
path: '/system/dict-data',
path: "/system/dict-data",
component: Layout,
hidden: true,
permissions: ['system:dict:list'],
permissions: ["system:dict:list"],
children: [
{
path: 'index/:dictId(\\d+)',
component: () => import('@/views/system/dict/data'),
name: 'Data',
meta: { title: '字典数据', activeMenu: '/system/dict' }
}
]
path: "index/:dictId(\\d+)",
component: () => import("@/views/system/dict/data"),
name: "Data",
meta: { title: "字典数据", activeMenu: "/system/dict" },
},
],
},
{
path: '/monitor/job-log',
path: "/monitor/job-log",
component: Layout,
hidden: true,
permissions: ['monitor:job:list'],
permissions: ["monitor:job:list"],
children: [
{
path: 'index/:jobId(\\d+)',
component: () => import('@/views/monitor/job/log'),
name: 'JobLog',
meta: { title: '调度日志', activeMenu: '/monitor/job' }
}
]
path: "index/:jobId(\\d+)",
component: () => import("@/views/monitor/job/log"),
name: "JobLog",
meta: { title: "调度日志", activeMenu: "/monitor/job" },
},
],
},
{
path: '/tool/gen-edit',
path: "/tool/gen-edit",
component: Layout,
hidden: true,
permissions: ['tool:gen:edit'],
permissions: ["tool:gen:edit"],
children: [
{
path: 'index/:tableId(\\d+)',
component: () => import('@/views/tool/gen/editTable'),
name: 'GenEdit',
meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
}
]
}
]
path: "index/:tableId(\\d+)",
component: () => import("@/views/tool/gen/editTable"),
name: "GenEdit",
meta: { title: "修改生成配置", activeMenu: "/tool/gen" },
},
],
},
];
// 防止连续点击多次路由报错
let routerPush = Router.prototype.push;
let routerReplace = Router.prototype.replace;
// push
Router.prototype.push = function push(location) {
return routerPush.call(this, location).catch(err => err)
}
return routerPush.call(this, location).catch((err) => err);
};
// replace
Router.prototype.replace = function push(location) {
return routerReplace.call(this, location).catch(err => err)
}
return routerReplace.call(this, location).catch((err) => err);
};
export default new Router({
mode: 'history', // 去掉url中的#
mode: "history", // 去掉url中的#
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
routes: constantRoutes,
});

@ -2,7 +2,7 @@ module.exports = {
/**
* 侧边栏主题 深色主题theme-dark浅色主题theme-light
*/
sideTheme: 'theme-dark',
sideTheme: "theme-dark",
/**
* 是否系统布局配置
@ -17,12 +17,12 @@ module.exports = {
/**
* 是否显示 tagsView
*/
tagsView: true,
tagsView: false,
/**
* 是否固定头部
*/
fixedHeader: false,
fixedHeader: true,
/**
* 是否显示logo
@ -40,5 +40,5 @@ module.exports = {
* 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'
}
errorLog: "production",
};

@ -1,106 +1,115 @@
import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { isHttp, isEmpty } from "@/utils/validate"
import defAva from '@/assets/images/profile.jpg'
import { login, logout, getInfo } from "@/api/login";
import { getToken, setToken, removeToken } from "@/utils/auth";
import { isHttp, isEmpty } from "@/utils/validate";
import defAva from "@/assets/images/profile.jpg";
const user = {
state: {
token: getToken(),
id: '',
name: '',
avatar: '',
id: "",
name: "",
avatar: "",
roles: [],
permissions: []
permissions: [],
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
state.token = token;
},
SET_ID: (state, id) => {
state.id = id
state.id = id;
},
SET_NAME: (state, name) => {
state.name = name
state.name = name;
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
state.avatar = avatar;
},
SET_ROLES: (state, roles) => {
state.roles = roles
state.roles = roles;
},
SET_PERMISSIONS: (state, permissions) => {
state.permissions = permissions
}
state.permissions = permissions;
},
},
actions: {
// 登录
Login({ commit }, userInfo) {
const username = userInfo.username.trim()
const password = userInfo.password
const code = userInfo.code
const uuid = userInfo.uuid
const username = userInfo.username.trim();
const password = userInfo.password;
const code = userInfo.code;
const uuid = userInfo.uuid;
return new Promise((resolve, reject) => {
login(username, password, code, uuid).then(res => {
setToken(res.token)
commit('SET_TOKEN', res.token)
resolve()
}).catch(error => {
reject(error)
})
login(username, password, code, uuid)
.then((res) => {
setToken(res.token);
commit("SET_TOKEN", res.token);
resolve();
})
.catch((error) => {
reject(error);
});
});
},
// 获取用户信息
GetInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo().then(res => {
const user = res.user
let avatar = user.avatar || ""
getInfo()
.then((res) => {
const user = res.user;
let avatar = user.avatar || "";
if (!isHttp(avatar)) {
avatar = (isEmpty(avatar)) ? defAva : process.env.VUE_APP_BASE_API + avatar
avatar = isEmpty(avatar)
? defAva
: process.env.VUE_APP_BASE_API + avatar;
}
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
commit('SET_ROLES', res.roles)
commit('SET_PERMISSIONS', res.permissions)
if (res.roles && res.roles.length > 0) {
// 验证返回的roles是否是一个非空数组
commit("SET_ROLES", res.roles);
commit("SET_PERMISSIONS", res.permissions);
} else {
commit('SET_ROLES', ['ROLE_DEFAULT'])
commit("SET_ROLES", ["ROLE_DEFAULT"]);
}
commit('SET_ID', user.userId)
commit('SET_NAME', user.userName)
commit('SET_AVATAR', avatar)
resolve(res)
}).catch(error => {
reject(error)
})
commit("SET_ID", user.userId);
commit("SET_NAME", user.nickName);
commit("SET_AVATAR", avatar);
resolve(res);
})
.catch((error) => {
reject(error);
});
});
},
// 退出系统
LogOut({ commit, state }) {
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
commit('SET_PERMISSIONS', [])
removeToken()
resolve()
}).catch(error => {
reject(error)
})
logout(state.token)
.then(() => {
commit("SET_TOKEN", "");
commit("SET_ROLES", []);
commit("SET_PERMISSIONS", []);
removeToken();
resolve();
})
.catch((error) => {
reject(error);
});
});
},
// 前端 登出
FedLogOut({ commit }) {
return new Promise(resolve => {
commit('SET_TOKEN', '')
removeToken()
resolve()
})
}
}
}
return new Promise((resolve) => {
commit("SET_TOKEN", "");
removeToken();
resolve();
});
},
},
};
export default user
export default user;

@ -0,0 +1,9 @@
<template>
<main-app></main-app>
</template>
<script>
export default {};
</script>
<style></style>

File diff suppressed because it is too large Load Diff

@ -91,7 +91,7 @@
import { getCodeImg } from "@/api/login";
import Cookies from "js-cookie";
import { encrypt, decrypt } from "@/utils/jsencrypt";
import forge from "node-forge";
export default {
name: "Login",
data() {
@ -120,6 +120,7 @@ export default {
//
register: false,
redirect: undefined,
publicKey: `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl8bS1kYTiMhIS5MZU253bc0ukaxrA1lfCziABFxQrC2c09tMrQGjuH6V1x2ofNBMGhOD9uWN/qkAQy/HwOe/NKUqCw6N0ov6guSrqMDW/BdZ3Bl0rmM1/95jTC1xffFFvej7xWNffIbaPI+bJ4WLX9NViNi9HmT0BRNzJ4d2R86LPPCa+bxLaPjsh2R2tBkbLkUot9769aJaPPiwPCZHMkuQenjHSmpWL0okleqMH8EGX7j6A5A/4IUXPMNKMMzkiSRpsIJ65GJmDAbnR3ZXRfC8MzVBBJB6zr5N0F4N9xZfF+JS/Yx726tCu+rA6GDCyTxtQ/wnKpPdwFP5nUWCWQIDAQAB`,
};
},
watch: {
@ -173,8 +174,28 @@ export default {
Cookies.remove("password");
Cookies.remove("rememberMe");
}
// 2048 RSA
const lines = [];
lines.push("-----BEGIN PUBLIC KEY-----");
for (let i = 0; i < this.publicKey.length; i += 64) {
lines.push(this.publicKey.slice(i, i + 64));
}
lines.push("-----END PUBLIC KEY-----");
lines.join("\n");
const publicKey = forge.pki.publicKeyFromPem(lines.join("\n"));
//
var dataBytes = forge.util.encodeUtf8(this.loginForm.password);
//
var encryptedBytes = publicKey.encrypt(dataBytes, "RSA-OAEP", {
md: forge.md.sha256.create(),
mgf1: {
md: forge.md.sha1.create(),
},
});
// Base64
var encryptedBase64 = forge.util.encode64(encryptedBytes);
this.$store
.dispatch("Login", this.loginForm)
.dispatch("Login", { ...this.loginForm, password: encryptedBase64 })
.then(() => {
this.$router.push({ path: this.redirect || "/" }).catch(() => {});
})

@ -0,0 +1,9 @@
<template>
<div>2222</div>
</template>
<script>
export default {};
</script>
<style></style>
Loading…
Cancel
Save