左侧菜单以及nav同步

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

@ -49,6 +49,7 @@
"js-beautify": "1.13.0", "js-beautify": "1.13.0",
"js-cookie": "3.0.1", "js-cookie": "3.0.1",
"jsencrypt": "3.0.0-rc.1", "jsencrypt": "3.0.0-rc.1",
"node-forge": "^1.3.1",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"quill": "2.0.2", "quill": "2.0.2",
"screenfull": "5.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) { export function login(username, password, code, uuid) {
@ -6,55 +6,55 @@ export function login(username, password, code, uuid) {
username, username,
password, password,
code, code,
uuid uuid,
} };
return request({ return request({
url: '/login', url: "/login",
headers: { headers: {
isToken: false, isToken: false,
repeatSubmit: false repeatSubmit: false,
}, },
method: 'post', method: "post",
data: data data: data,
}) });
} }
// 注册方法 // 注册方法
export function register(data) { export function register(data) {
return request({ return request({
url: '/register', url: "/register",
headers: { headers: {
isToken: false isToken: false,
}, },
method: 'post', method: "post",
data: data data: data,
}) });
} }
// 获取用户详细信息 // 获取用户详细信息
export function getInfo() { export function getInfo() {
return request({ return request({
url: '/getInfo', url: "/getInfo",
method: 'get' method: "get",
}) });
} }
// 退出方法 // 退出方法
export function logout() { export function logout() {
return request({ return request({
url: '/logout', url: "/logout",
method: 'post' method: "post",
}) });
} }
// 获取验证码 // 获取验证码
export function getCodeImg() { export function getCodeImg() {
return request({ return request({
url: '/captchaImage', url: "/captchaImage",
headers: { headers: {
isToken: false isToken: false,
}, },
method: 'get', method: "get",
timeout: 20000 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,25 +1,25 @@
// base color // base color
$blue:#324157; $blue: #324157;
$light-blue:#3A71A8; $light-blue: #3a71a8;
$red:#C03639; $red: #c03639;
$pink: #E65D6E; $pink: #e65d6e;
$green: #30B08F; $green: #30b08f;
$tiffany: #4AB7BD; $tiffany: #4ab7bd;
$yellow:#FEC171; $yellow: #fec171;
$panGreen: #30B08F; $panGreen: #30b08f;
// //
$base-menu-color:#bfcbd9; $base-menu-color: #bfcbd9;
$base-menu-color-active:#f4f4f5; $base-menu-color-active: #f4f4f5;
$base-menu-background:#304156; $base-menu-background: #304156;
$base-logo-title-color: #ffffff; $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-menu-light-background: #ffffff;
$base-logo-light-title-color: #001529; $base-logo-light-title-color: #001529;
$base-sub-menu-background:#1f2d3d; $base-sub-menu-background: #1f2d3d;
$base-sub-menu-hover:#001528; $base-sub-menu-hover: #001528;
// //
/** /**
@ -36,7 +36,7 @@ $base-sub-menu-background:#000c17;
$base-sub-menu-hover:#001528; $base-sub-menu-hover:#001528;
*/ */
$base-sidebar-width: 200px; $base-sidebar-width: 260px;
// the :export directive is the magic sauce for webpack // the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass // 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; subMenuHover: $base-sub-menu-hover;
sideBarWidth: $base-sidebar-width; sideBarWidth: $base-sidebar-width;
logoTitleColor: $base-logo-title-color; 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="/"> <el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb"> <transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path"> <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> <span
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a> 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> </el-breadcrumb-item>
</transition-group> </transition-group>
</el-breadcrumb> </el-breadcrumb>
@ -13,80 +17,86 @@
export default { export default {
data() { data() {
return { return {
levelList: null levelList: null,
} };
}, },
watch: { watch: {
$route(route) { $route(route) {
// if you go to the redirect page, do not update the breadcrumbs // if you go to the redirect page, do not update the breadcrumbs
if (route.path.startsWith('/redirect/')) { if (route.path.startsWith("/redirect/")) {
return return;
}
this.getBreadcrumb()
} }
this.getBreadcrumb();
},
}, },
created() { created() {
this.getBreadcrumb() this.getBreadcrumb();
}, },
methods: { methods: {
getBreadcrumb() { getBreadcrumb() {
// only show routes with meta.title // only show routes with meta.title
let matched = [] let matched = [];
const router = this.$route const router = this.$route;
const pathNum = this.findPathNum(router.path) const pathNum = this.findPathNum(router.path);
// multi-level menu // multi-level menu
if (pathNum > 2) { if (pathNum > 2) {
const reg = /\/\w+/gi const reg = /\/\w+/gi;
const pathList = router.path.match(reg).map((item, index) => { const pathList = router.path.match(reg).map((item, index) => {
if (index !== 0) item = item.slice(1) if (index !== 0) item = item.slice(1);
return item return item;
}) });
this.getMatched(pathList, this.$store.getters.defaultRoutes, matched) this.getMatched(pathList, this.$store.getters.defaultRoutes, matched);
} else { } 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])) { 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 = "/") { findPathNum(str, char = "/") {
let index = str.indexOf(char) let index = str.indexOf(char);
let num = 0 let num = 0;
while (index !== -1) { while (index !== -1) {
num++ num++;
index = str.indexOf(char, index + 1) index = str.indexOf(char, index + 1);
} }
return num return num;
}, },
getMatched(pathList, routeList, matched) { 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) { if (data) {
matched.push(data) matched.push(data);
if (data.children && pathList.length) { if (data.children && pathList.length) {
pathList.shift() pathList.shift();
this.getMatched(pathList, data.children, matched) this.getMatched(pathList, data.children, matched);
} }
} }
}, },
isDashboard(route) { isDashboard(route) {
const name = route && route.name const name = route && route.name;
if (!name) { if (!name) {
return false return false;
} }
return name.trim() === 'Index' return name.trim() === "Index";
}, },
handleLink(item) { handleLink(item) {
const { redirect, path } = item const { redirect, path } = item;
if (redirect) { if (redirect) {
this.$router.push(redirect) this.$router.push(redirect);
return return;
}
this.$router.push(path)
} }
} this.$router.push(path);
} },
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

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

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

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

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

@ -1,12 +1,29 @@
<template> <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" /> <logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper"> <el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
<el-menu <el-menu
:default-active="activeMenu" :default-active="activeMenu"
:collapse="isCollapse" :collapse="isCollapse"
:background-color="settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground" :background-color="
:text-color="settings.sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor" settings.sideTheme === 'theme-dark'
? variables.menuBackground
: variables.menuLightBackground
"
:text-color="
settings.sideTheme === 'theme-dark'
? variables.menuColor
: variables.menuLightColor
"
:unique-opened="true" :unique-opened="true"
:active-text-color="settings.theme" :active-text-color="settings.theme"
:collapse-transition="false" :collapse-transition="false"
@ -51,7 +68,7 @@ export default {
}, },
isCollapse() { isCollapse() {
return !this.sidebar.opened; return !this.sidebar.opened;
} },
} },
}; };
</script> </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 Element from "element-ui";
import './assets/styles/element-variables.scss' import "./assets/styles/element-variables.scss";
import '@/assets/styles/index.scss' // global css import "@/assets/styles/index.scss"; // global css
import '@/assets/styles/ruoyi.scss' // ruoyi css import "@/assets/styles/ruoyi.scss"; // ruoyi css
import App from './App' import App from "./App";
import store from './store' import store from "./store";
import router from './router' import router from "./router";
import directive from './directive' // directive import directive from "./directive"; // directive
import plugins from './plugins' // plugins import plugins from "./plugins"; // plugins
import { download } from '@/utils/request' import { download } from "@/utils/request";
import './assets/icons' // icon import "./assets/icons"; // icon
import './permission' // permission control import "./permission"; // permission control
import { getDicts } from "@/api/system/dict/data"; import { getDicts } from "@/api/system/dict/data";
import { getConfigKey } from "@/api/system/config"; 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 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.getDicts = getDicts;
Vue.prototype.getConfigKey = getConfigKey Vue.prototype.getConfigKey = getConfigKey;
Vue.prototype.parseTime = parseTime Vue.prototype.parseTime = parseTime;
Vue.prototype.resetForm = resetForm Vue.prototype.resetForm = resetForm;
Vue.prototype.addDateRange = addDateRange Vue.prototype.addDateRange = addDateRange;
Vue.prototype.selectDictLabel = selectDictLabel Vue.prototype.selectDictLabel = selectDictLabel;
Vue.prototype.selectDictLabels = selectDictLabels Vue.prototype.selectDictLabels = selectDictLabels;
Vue.prototype.download = download Vue.prototype.download = download;
Vue.prototype.handleTree = handleTree Vue.prototype.handleTree = handleTree;
// 全局组件挂载 // 全局组件挂载
Vue.component('DictTag', DictTag) Vue.component("DictTag", DictTag);
Vue.component('Pagination', Pagination) Vue.component("Pagination", Pagination);
Vue.component('RightToolbar', RightToolbar) Vue.component("RightToolbar", RightToolbar);
Vue.component('Editor', Editor) Vue.component("Editor", Editor);
Vue.component('FileUpload', FileUpload) Vue.component("FileUpload", FileUpload);
Vue.component('ImageUpload', ImageUpload) Vue.component("ImageUpload", ImageUpload);
Vue.component('ImagePreview', ImagePreview) Vue.component("ImagePreview", ImagePreview);
Vue.component("MainApp", MainApp);
Vue.use(directive) Vue.use(directive);
Vue.use(plugins) Vue.use(plugins);
Vue.use(VueMeta) Vue.use(VueMeta);
DictData.install() DictData.install();
/** /**
* If you don't want to use mock-server * If you don't want to use mock-server
@ -73,14 +83,14 @@ DictData.install()
*/ */
Vue.use(Element, { 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({ new Vue({
el: '#app', el: "#app",
router, router,
store, store,
render: h => h(App) render: (h) => h(App),
}) });

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

@ -2,7 +2,7 @@ module.exports = {
/** /**
* 侧边栏主题 深色主题theme-dark浅色主题theme-light * 侧边栏主题 深色主题theme-dark浅色主题theme-light
*/ */
sideTheme: 'theme-dark', sideTheme: "theme-dark",
/** /**
* 是否系统布局配置 * 是否系统布局配置
@ -17,12 +17,12 @@ module.exports = {
/** /**
* 是否显示 tagsView * 是否显示 tagsView
*/ */
tagsView: true, tagsView: false,
/** /**
* 是否固定头部 * 是否固定头部
*/ */
fixedHeader: false, fixedHeader: true,
/** /**
* 是否显示logo * 是否显示logo
@ -40,5 +40,5 @@ module.exports = {
* The default is only used in the production env * The default is only used in the production env
* If you want to also use it in dev, you can pass ['production', 'development'] * 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 { login, logout, getInfo } from "@/api/login";
import { getToken, setToken, removeToken } from '@/utils/auth' import { getToken, setToken, removeToken } from "@/utils/auth";
import { isHttp, isEmpty } from "@/utils/validate" import { isHttp, isEmpty } from "@/utils/validate";
import defAva from '@/assets/images/profile.jpg' import defAva from "@/assets/images/profile.jpg";
const user = { const user = {
state: { state: {
token: getToken(), token: getToken(),
id: '', id: "",
name: '', name: "",
avatar: '', avatar: "",
roles: [], roles: [],
permissions: [] permissions: [],
}, },
mutations: { mutations: {
SET_TOKEN: (state, token) => { SET_TOKEN: (state, token) => {
state.token = token state.token = token;
}, },
SET_ID: (state, id) => { SET_ID: (state, id) => {
state.id = id state.id = id;
}, },
SET_NAME: (state, name) => { SET_NAME: (state, name) => {
state.name = name state.name = name;
}, },
SET_AVATAR: (state, avatar) => { SET_AVATAR: (state, avatar) => {
state.avatar = avatar state.avatar = avatar;
}, },
SET_ROLES: (state, roles) => { SET_ROLES: (state, roles) => {
state.roles = roles state.roles = roles;
}, },
SET_PERMISSIONS: (state, permissions) => { SET_PERMISSIONS: (state, permissions) => {
state.permissions = permissions state.permissions = permissions;
} },
}, },
actions: { actions: {
// 登录 // 登录
Login({ commit }, userInfo) { Login({ commit }, userInfo) {
const username = userInfo.username.trim() const username = userInfo.username.trim();
const password = userInfo.password const password = userInfo.password;
const code = userInfo.code const code = userInfo.code;
const uuid = userInfo.uuid const uuid = userInfo.uuid;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
login(username, password, code, uuid).then(res => { login(username, password, code, uuid)
setToken(res.token) .then((res) => {
commit('SET_TOKEN', res.token) setToken(res.token);
resolve() commit("SET_TOKEN", res.token);
}).catch(error => { resolve();
reject(error)
})
}) })
.catch((error) => {
reject(error);
});
});
}, },
// 获取用户信息 // 获取用户信息
GetInfo({ commit, state }) { GetInfo({ commit, state }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getInfo().then(res => { getInfo()
const user = res.user .then((res) => {
let avatar = user.avatar || "" const user = res.user;
let avatar = user.avatar || "";
if (!isHttp(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是否是一个非空数组 if (res.roles && res.roles.length > 0) {
commit('SET_ROLES', res.roles) // 验证返回的roles是否是一个非空数组
commit('SET_PERMISSIONS', res.permissions) commit("SET_ROLES", res.roles);
commit("SET_PERMISSIONS", res.permissions);
} else { } else {
commit('SET_ROLES', ['ROLE_DEFAULT']) commit("SET_ROLES", ["ROLE_DEFAULT"]);
} }
commit('SET_ID', user.userId) commit("SET_ID", user.userId);
commit('SET_NAME', user.userName) commit("SET_NAME", user.nickName);
commit('SET_AVATAR', avatar) commit("SET_AVATAR", avatar);
resolve(res) resolve(res);
}).catch(error => {
reject(error)
})
}) })
.catch((error) => {
reject(error);
});
});
}, },
// 退出系统 // 退出系统
LogOut({ commit, state }) { LogOut({ commit, state }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
logout(state.token).then(() => { logout(state.token)
commit('SET_TOKEN', '') .then(() => {
commit('SET_ROLES', []) commit("SET_TOKEN", "");
commit('SET_PERMISSIONS', []) commit("SET_ROLES", []);
removeToken() commit("SET_PERMISSIONS", []);
resolve() removeToken();
}).catch(error => { resolve();
reject(error)
})
}) })
.catch((error) => {
reject(error);
});
});
}, },
// 前端 登出 // 前端 登出
FedLogOut({ commit }) { FedLogOut({ commit }) {
return new Promise(resolve => { return new Promise((resolve) => {
commit('SET_TOKEN', '') commit("SET_TOKEN", "");
removeToken() removeToken();
resolve() 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 { getCodeImg } from "@/api/login";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { encrypt, decrypt } from "@/utils/jsencrypt"; import { encrypt, decrypt } from "@/utils/jsencrypt";
import forge from "node-forge";
export default { export default {
name: "Login", name: "Login",
data() { data() {
@ -120,6 +120,7 @@ export default {
// //
register: false, register: false,
redirect: undefined, redirect: undefined,
publicKey: `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl8bS1kYTiMhIS5MZU253bc0ukaxrA1lfCziABFxQrC2c09tMrQGjuH6V1x2ofNBMGhOD9uWN/qkAQy/HwOe/NKUqCw6N0ov6guSrqMDW/BdZ3Bl0rmM1/95jTC1xffFFvej7xWNffIbaPI+bJ4WLX9NViNi9HmT0BRNzJ4d2R86LPPCa+bxLaPjsh2R2tBkbLkUot9769aJaPPiwPCZHMkuQenjHSmpWL0okleqMH8EGX7j6A5A/4IUXPMNKMMzkiSRpsIJ65GJmDAbnR3ZXRfC8MzVBBJB6zr5N0F4N9xZfF+JS/Yx726tCu+rA6GDCyTxtQ/wnKpPdwFP5nUWCWQIDAQAB`,
}; };
}, },
watch: { watch: {
@ -173,8 +174,28 @@ export default {
Cookies.remove("password"); Cookies.remove("password");
Cookies.remove("rememberMe"); 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 this.$store
.dispatch("Login", this.loginForm) .dispatch("Login", { ...this.loginForm, password: encryptedBase64 })
.then(() => { .then(() => {
this.$router.push({ path: this.redirect || "/" }).catch(() => {}); 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