mirror of
https://github.com/chillzhuang/Saber.git
synced 2024-11-24 19:39:28 +08:00
🎉 2.7.2.RELEASE 集成JustAuth支持第三方登录
This commit is contained in:
parent
e4d39096f6
commit
9c8a04763e
@ -59,7 +59,8 @@ SpringBlade
|
||||
* 交流一群:`477853168`(满)
|
||||
* 交流二群:`751253339`(满)
|
||||
* 交流三群:`784729540`(满)
|
||||
* 交流四群:`1034621754`
|
||||
* 交流四群:`1034621754`(满)
|
||||
* 交流五群:`946350912`
|
||||
|
||||
## 在线演示
|
||||
* Saber-基于Vue:[https://saber.bladex.vip](https://saber.bladex.vip)
|
||||
|
@ -82,7 +82,7 @@
|
||||
<div id="app">
|
||||
<div class="avue-home">
|
||||
<div class="avue-home__main">
|
||||
<img class="avue-home__loading" src="./svg/loading-spin.svg" alt="loading">
|
||||
<img class="avue-home__loading" src="<%= BASE_URL %>svg/loading-spin.svg" alt="loading">
|
||||
<div class="avue-home__title">
|
||||
正在加载资源
|
||||
</div>
|
||||
|
@ -22,7 +22,7 @@ export const grant = (roleIds, menuIds) => {
|
||||
return request({
|
||||
url: '/api/blade-system/role/grant',
|
||||
method: 'post',
|
||||
params: {
|
||||
data: {
|
||||
roleIds,
|
||||
menuIds
|
||||
}
|
||||
|
@ -18,6 +18,22 @@ export const loginByUsername = (tenantId, account, password, type, key, code) =>
|
||||
}
|
||||
});
|
||||
|
||||
export const loginBySocial = (tenantId, source, code, state) => request({
|
||||
url: '/api/blade-auth/token',
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Tenant-Id': tenantId
|
||||
},
|
||||
params: {
|
||||
tenantId,
|
||||
source,
|
||||
code,
|
||||
state,
|
||||
grantType: "social",
|
||||
scope: "all",
|
||||
}
|
||||
});
|
||||
|
||||
export const getButtons = () => request({
|
||||
url: '/api/blade-system/menu/buttons',
|
||||
method: 'get'
|
||||
@ -28,11 +44,23 @@ export const getUserInfo = () => request({
|
||||
method: 'get'
|
||||
});
|
||||
|
||||
export const refeshToken = () => request({
|
||||
export const refreshToken = () => request({
|
||||
url: baseUrl + '/user/refesh',
|
||||
method: 'post'
|
||||
})
|
||||
|
||||
export const registerGuest = (form, oauthId) => request({
|
||||
url: '/api/blade-user/register-guest',
|
||||
method: 'post',
|
||||
params: {
|
||||
tenantId: form.tenantId,
|
||||
name: form.name,
|
||||
account: form.account,
|
||||
password: form.password,
|
||||
oauthId
|
||||
}
|
||||
});
|
||||
|
||||
export const getMenu = () => request({
|
||||
url: '/api/blade-system/menu/routes',
|
||||
method: 'get'
|
||||
|
106
src/components/third-register/main.vue
Normal file
106
src/components/third-register/main.vue
Normal file
@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<el-dialog title="账号注册"
|
||||
append-to-body
|
||||
:visible.sync="accountBox"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:show-close="false"
|
||||
width="20%">
|
||||
<el-form :model="form" ref="form" label-width="80px">
|
||||
<el-form-item label="租户编号">
|
||||
<el-input v-model="form.tenantId" placeholder="请输入租户编号"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户姓名">
|
||||
<el-input v-model="form.name" placeholder="请输入用户姓名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="账号名称">
|
||||
<el-input v-model="form.account" placeholder="请输入账号名称"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="账号密码">
|
||||
<el-input v-model="form.password" placeholder="请输入账号密码"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码">
|
||||
<el-input v-model="form.password2" placeholder="请输入确认密码"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" :loading="loading" @click="handleRegister">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapGetters} from "vuex";
|
||||
import {validatenull} from "@/util/validate";
|
||||
import {registerGuest} from "@/api/user";
|
||||
|
||||
export default {
|
||||
name: "thirdRegister",
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
tenantId: '',
|
||||
name: '',
|
||||
account: '',
|
||||
password: '',
|
||||
password2: '',
|
||||
},
|
||||
loading: false,
|
||||
accountBox: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["userInfo"]),
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.userInfo)
|
||||
// 若未登录则弹出框进行绑定
|
||||
if (validatenull(this.userInfo.userId) || this.userInfo.userId < 0) {
|
||||
this.form.name = this.userInfo.account;
|
||||
this.form.account = this.userInfo.account;
|
||||
this.accountBox = true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleRegister() {
|
||||
if (this.form.tenantId === '') {
|
||||
this.$message.warning("请先输入租户编号");
|
||||
return;
|
||||
}
|
||||
if (this.form.account === '') {
|
||||
this.$message.warning("请先输入账号名称");
|
||||
return;
|
||||
}
|
||||
if (this.form.password === '' || this.form.password2 === '') {
|
||||
this.$message.warning("请先输入密码");
|
||||
return;
|
||||
}
|
||||
if (this.form.password !== this.form.password2) {
|
||||
this.$message.warning("两次密码输入不一致");
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
registerGuest(this.form, this.userInfo.oauthId).then(res => {
|
||||
this.loading = false;
|
||||
const data = res.data;
|
||||
if (data.success) {
|
||||
this.accountBox = false;
|
||||
this.$alert("注册申请已提交,请耐心等待管理员通过!", '注册提示').then(() => {
|
||||
this.$store.dispatch("LogOut").then(() => {
|
||||
this.$router.push({path: "/login"});
|
||||
});
|
||||
})
|
||||
} else {
|
||||
this.$message.error(data.msg || '提交失败');
|
||||
}
|
||||
}, error => {
|
||||
window.console.log(error);
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
@ -1,7 +1,7 @@
|
||||
// 配置编译环境和线上环境之间的切换
|
||||
|
||||
let baseUrl = '';
|
||||
let iconfontVersion = ['567566_pwc3oottzol', '1066523_v8rsbcusj5q'];
|
||||
let iconfontVersion = ['567566_pwc3oottzol', '1066523_6bvkeuqao36'];
|
||||
let iconfontUrl = `//at.alicdn.com/t/font_$key.css`;
|
||||
let codeUrl = `${baseUrl}/code`
|
||||
const env = process.env
|
||||
|
@ -64,6 +64,8 @@ export default [
|
||||
"iconfont iconicon_addmessage",
|
||||
"iconfont iconicon_addresslist",
|
||||
"iconfont iconicon_add",
|
||||
"iconfont icongithub",
|
||||
"iconfont icongitee2",
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -36,5 +36,7 @@ export default {
|
||||
icon: 'source',
|
||||
children: 'children'
|
||||
}
|
||||
}
|
||||
},
|
||||
// 授权地址
|
||||
authUrl: 'http://localhost/blade-auth/oauth/render'
|
||||
}
|
||||
|
@ -71,6 +71,8 @@ export default {
|
||||
password: 'Please input a password',
|
||||
wechat: 'Wechat',
|
||||
qq: 'QQ',
|
||||
github: 'github',
|
||||
gitee: 'gitee',
|
||||
phone: 'Please input a phone',
|
||||
code: 'Please input a code',
|
||||
submit: 'Login',
|
||||
|
@ -71,6 +71,8 @@ export default {
|
||||
password: '请输入密码',
|
||||
wechat: '微信',
|
||||
qq: 'QQ',
|
||||
github: 'github',
|
||||
gitee: '码云',
|
||||
phone: '请输入手机号',
|
||||
code: '请输入验证码',
|
||||
submit: '登录',
|
||||
|
@ -17,6 +17,7 @@ import i18n from './lang' // Internationalization
|
||||
import './styles/common.scss';
|
||||
|
||||
import basicContainer from './components/basic-container/main'
|
||||
import thirdRegister from './components/third-register/main'
|
||||
|
||||
Vue.use(router)
|
||||
Vue.use(VueAxios, axios)
|
||||
@ -28,6 +29,7 @@ Vue.use(window.AVUE, {
|
||||
})
|
||||
//注册全局容器
|
||||
Vue.component('basicContainer', basicContainer)
|
||||
Vue.component('thirdRegister', thirdRegister);
|
||||
// 加载相关url地址
|
||||
Object.keys(urls).forEach(key => {
|
||||
Vue.prototype[key] = urls[key];
|
||||
@ -45,4 +47,4 @@ new Vue({
|
||||
store,
|
||||
i18n,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
}).$mount('#app')
|
||||
|
@ -95,7 +95,7 @@ export default {
|
||||
if (!(date.seconds >= this.website.tokenTime) && !this.refreshLock) {
|
||||
this.refreshLock = true;
|
||||
this.$store
|
||||
.dispatch("RefeshToken")
|
||||
.dispatch("RefreshToken")
|
||||
.then(() => {
|
||||
this.refreshLock = false;
|
||||
})
|
||||
|
@ -22,12 +22,9 @@
|
||||
<codeLogin v-else-if="activeName==='code'"></codeLogin>
|
||||
<thirdLogin v-else-if="activeName==='third'"></thirdLogin>
|
||||
<div class="login-menu">
|
||||
<a href="#"
|
||||
@click.stop="activeName='user'">{{ $t('login.userLogin') }}</a>
|
||||
<a href="#"
|
||||
@click.stop="activeName='code'">{{ $t('login.phoneLogin') }}</a>
|
||||
<a href="#"
|
||||
@click.stop="activeName='third'">{{ $t('login.thirdLogin') }}</a>
|
||||
<a href="#" @click.stop="activeName='user'">{{ $t('login.userLogin') }}</a>
|
||||
<!--<a href="#" @click.stop="activeName='code'">{{ $t('login.phoneLogin') }}</a>-->
|
||||
<a href="#" @click.stop="activeName='third'">{{ $t('login.thirdLogin') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -44,6 +41,7 @@ import { dateFormat } from "@/util/date";
|
||||
import { validatenull } from "@/util/validate";
|
||||
import topLang from "@/page/index/top/top-lang";
|
||||
import topColor from "@/page/index/top/top-color";
|
||||
import {getQueryString, getTopUrl} from "@/util/util";
|
||||
export default {
|
||||
name: "login",
|
||||
components: {
|
||||
@ -56,42 +54,61 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
time: "",
|
||||
activeName: "user"
|
||||
activeName: "user",
|
||||
socialForm: {
|
||||
tenantId: "000000",
|
||||
source: "",
|
||||
code: "",
|
||||
state: "",
|
||||
}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
const params = this.$route.query;
|
||||
this.socialForm.state = params.state;
|
||||
this.socialForm.code = params.code;
|
||||
if (!validatenull(this.socialForm.state)) {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: `${
|
||||
this.socialForm.state === "WX" ? "微信" : "QQ"
|
||||
}登录中,请稍后。。。`,
|
||||
spinner: "el-icon-loading"
|
||||
});
|
||||
setTimeout(() => {
|
||||
loading.close();
|
||||
}, 2000);
|
||||
}
|
||||
this.handleLogin();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.handleLogin();
|
||||
this.getTime();
|
||||
setInterval(() => {
|
||||
this.getTime();
|
||||
}, 1000);
|
||||
},
|
||||
mounted() {},
|
||||
mounted() {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["website"])
|
||||
...mapGetters(["website", "tagWel"])
|
||||
},
|
||||
props: [],
|
||||
methods: {
|
||||
getTime() {
|
||||
this.time = dateFormat(new Date());
|
||||
setInterval(() => {
|
||||
this.time = dateFormat(new Date());
|
||||
}, 1000);
|
||||
},
|
||||
handleLogin() {
|
||||
const topUrl = getTopUrl();
|
||||
const redirectUrl = "/oauth/redirect/";
|
||||
this.socialForm.source = getQueryString("source");
|
||||
this.socialForm.code = getQueryString("code");
|
||||
this.socialForm.state = getQueryString("state");
|
||||
if (validatenull(this.socialForm.source) && topUrl.includes(redirectUrl)) {
|
||||
let source = topUrl.split("?")[0];
|
||||
source = source.split(redirectUrl)[1];
|
||||
this.socialForm.source = source;
|
||||
}
|
||||
if (!validatenull(this.socialForm.source) && !validatenull(this.socialForm.code) && !validatenull(this.socialForm.state)) {
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: '第三方系统登录中,请稍后。。。',
|
||||
spinner: "el-icon-loading"
|
||||
});
|
||||
this.$store.dispatch("LoginBySocial", this.socialForm).then(() => {
|
||||
window.location.href = topUrl.split(redirectUrl)[0];
|
||||
this.$router.push({path: this.tagWel.value});
|
||||
loading.close();
|
||||
}).catch(() => {
|
||||
loading.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -99,4 +116,4 @@ export default {
|
||||
|
||||
<style lang="scss">
|
||||
@import "@/styles/login.scss";
|
||||
</style>
|
||||
</style>
|
||||
|
@ -1,20 +1,26 @@
|
||||
<template>
|
||||
<div class="social-container">
|
||||
<div class="box"
|
||||
@click="handleClick('wechat')">
|
||||
<span class="container"
|
||||
:style="{backgroundColor:'#6ba2d6'}">
|
||||
<i icon-class="wechat"
|
||||
class="iconfont icon-weixin"></i>
|
||||
<div @click="handleClick('github')">
|
||||
<span class="container" :style="{backgroundColor:'#61676D'}">
|
||||
<i icon-class="github" class="iconfont icongithub"></i>
|
||||
</span>
|
||||
<p class="title">{{$t('login.github')}}</p>
|
||||
</div>
|
||||
<div @click="handleClick('gitee')">
|
||||
<span class="container" :style="{backgroundColor:'#c35152'}">
|
||||
<i icon-class="gitee" class="iconfont icongitee2"></i>
|
||||
</span>
|
||||
<p class="title">{{$t('login.gitee')}}</p>
|
||||
</div>
|
||||
<div @click="handleClick('wechat_open')">
|
||||
<span class="container" :style="{backgroundColor:'#8dc349'}">
|
||||
<i icon-class="wechat" class="iconfont icon-weixin"/>
|
||||
</span>
|
||||
<p class="title">{{$t('login.wechat')}}</p>
|
||||
</div>
|
||||
<div class="box"
|
||||
@click="handleClick('tencent')">
|
||||
<span class="container"
|
||||
:style="{backgroundColor:'#8dc349'}">
|
||||
<i icon-class="qq"
|
||||
class="iconfont icon-qq"></i>
|
||||
<div @click="handleClick('qq')">
|
||||
<span class="container" :style="{backgroundColor:'#6ba2d6'}">
|
||||
<i icon-class="qq" class="iconfont icon-qq"/>
|
||||
</span>
|
||||
<p class="title">{{$t('login.qq')}}</p>
|
||||
</div>
|
||||
@ -22,33 +28,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { openWindow } from "@/util/util";
|
||||
import website from '@/config/website';
|
||||
|
||||
export default {
|
||||
name: "thirdLogin",
|
||||
methods: {
|
||||
handleClick(thirdpart) {
|
||||
let appid, client_id, redirect_uri, url;
|
||||
redirect_uri = encodeURIComponent(
|
||||
window.location.origin + "/#/authredirect"
|
||||
);
|
||||
if (thirdpart === "wechat") {
|
||||
appid = "xxxx";
|
||||
url =
|
||||
"https://open.weixin.qq.com/connect/qrconnect?appid=" +
|
||||
appid +
|
||||
"&redirect_uri=" +
|
||||
redirect_uri +
|
||||
"&state=WX&response_type=code&scope=snsapi_login#wechat_redirect";
|
||||
} else if (thirdpart === "tencent") {
|
||||
client_id = "xxxx";
|
||||
url =
|
||||
"https://graph.qq.com/oauth2.0/authorize?response_type=code&state=QQ&client_id=" +
|
||||
client_id +
|
||||
"&redirect_uri=" +
|
||||
redirect_uri;
|
||||
}
|
||||
openWindow(url, thirdpart, 540, 540);
|
||||
handleClick(source) {
|
||||
window.location.href = `${website.authUrl}/${source}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -60,15 +46,14 @@ export default {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
.box {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
color: #fff;
|
||||
font-size: 30px;
|
||||
}
|
||||
.container {
|
||||
$height: 50px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
width: $height;
|
||||
height: $height;
|
||||
|
@ -11,26 +11,9 @@ import 'nprogress/nprogress.css' // progress bar style
|
||||
NProgress.configure({showSpinner: false});
|
||||
const lockPage = store.getters.website.lockPage; //锁屏页
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (to.matched.length === 0 && to.fullPath.indexOf("?sec") === -1) {
|
||||
next(to.path + "?sec");
|
||||
window.location.reload();
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
//缓冲设置
|
||||
if (to.meta.keepAlive === true && store.state.tags.tagList.some(ele => {
|
||||
return ele.value === to.fullPath;
|
||||
})) {
|
||||
to.meta.$keepAlive = true;
|
||||
} else {
|
||||
NProgress.start()
|
||||
if (to.meta.keepAlive === true && validatenull(to.meta.$keepAlive)) {
|
||||
to.meta.$keepAlive = true;
|
||||
} else {
|
||||
to.meta.$keepAlive = false;
|
||||
}
|
||||
}
|
||||
const meta = to.meta || {};
|
||||
const isMenu = meta.menu === undefined ? to.query.menu : meta.menu;
|
||||
store.commit('SET_IS_MENU', isMenu === undefined);
|
||||
if (getToken()) {
|
||||
if (store.getters.isLock && to.path !== lockPage) { //如果系统激活锁屏,全部跳转到锁屏页
|
||||
next({path: lockPage})
|
||||
|
@ -1,41 +1,51 @@
|
||||
import Layout from '@/page/index/'
|
||||
|
||||
export default [{
|
||||
path: '/wel',
|
||||
component: Layout,
|
||||
redirect: '/wel/index',
|
||||
children: [{
|
||||
path: 'index',
|
||||
name: '首页',
|
||||
meta: {
|
||||
i18n: 'dashboard'
|
||||
},
|
||||
component: () =>
|
||||
import( /* webpackChunkName: "views" */ '@/views/wel')
|
||||
}]
|
||||
path: '/wel',
|
||||
component: Layout,
|
||||
redirect: '/wel/index',
|
||||
children: [{
|
||||
path: 'index',
|
||||
name: '首页',
|
||||
meta: {
|
||||
i18n: 'dashboard'
|
||||
},
|
||||
component: () =>
|
||||
import( /* webpackChunkName: "views" */ '@/views/wel/index')
|
||||
}, {
|
||||
path: 'dashboard',
|
||||
name: '控制台',
|
||||
meta: {
|
||||
i18n: 'dashboard',
|
||||
menu: false,
|
||||
},
|
||||
component: () =>
|
||||
import( /* webpackChunkName: "views" */ '@/views/wel/dashboard')
|
||||
}]
|
||||
}, {
|
||||
path: '/test',
|
||||
component: Layout,
|
||||
redirect: '/test/index',
|
||||
children: [{
|
||||
path: 'index',
|
||||
name: '测试页',
|
||||
meta: {
|
||||
i18n: 'test'
|
||||
},
|
||||
component: () =>
|
||||
import( /* webpackChunkName: "views" */ '@/views/util/test')
|
||||
}]
|
||||
path: '/test',
|
||||
component: Layout,
|
||||
redirect: '/test/index',
|
||||
children: [{
|
||||
path: 'index',
|
||||
name: '测试页',
|
||||
meta: {
|
||||
i18n: 'test'
|
||||
},
|
||||
component: () =>
|
||||
import( /* webpackChunkName: "views" */ '@/views/util/test')
|
||||
}]
|
||||
}, {
|
||||
path: '/info',
|
||||
component: Layout,
|
||||
redirect: '/info/index',
|
||||
children: [{
|
||||
path: 'index',
|
||||
name: '个人信息',
|
||||
meta: {
|
||||
i18n: 'info'
|
||||
},
|
||||
component: () =>
|
||||
import( /* webpackChunkName: "views" */ '@/views/user/info')
|
||||
}]
|
||||
}]
|
||||
path: '/info',
|
||||
component: Layout,
|
||||
redirect: '/info/index',
|
||||
children: [{
|
||||
path: 'index',
|
||||
name: '个人信息',
|
||||
meta: {
|
||||
i18n: 'info'
|
||||
},
|
||||
component: () =>
|
||||
import( /* webpackChunkName: "views" */ '@/views/user/info')
|
||||
}]
|
||||
}]
|
||||
|
@ -1,26 +1,27 @@
|
||||
const getters = {
|
||||
tag: state => state.tags.tag,
|
||||
language: state => state.common.language,
|
||||
website: state => state.common.website,
|
||||
userInfo: state => state.user.userInfo,
|
||||
colorName: state => state.common.colorName,
|
||||
themeName: state => state.common.themeName,
|
||||
isShade: state => state.common.isShade,
|
||||
isCollapse: state => state.common.isCollapse,
|
||||
keyCollapse: (state, getters) => getters.screen > 1 ? getters.isCollapse : false,
|
||||
screen: state => state.common.screen,
|
||||
isLock: state => state.common.isLock,
|
||||
isFullScren: state => state.common.isFullScren,
|
||||
lockPasswd: state => state.common.lockPasswd,
|
||||
tagList: state => state.tags.tagList,
|
||||
tagWel: state => state.tags.tagWel,
|
||||
token: state => state.user.token,
|
||||
roles: state => state.user.roles,
|
||||
permission: state => state.user.permission,
|
||||
menu: state => state.user.menu,
|
||||
menuAll: state => state.user.menuAll,
|
||||
logsList: state => state.logs.logsList,
|
||||
logsLen: state => state.logs.logsList.length || 0,
|
||||
logsFlag: (state, getters) => getters.logsLen === 0
|
||||
tag: state => state.tags.tag,
|
||||
language: state => state.common.language,
|
||||
website: state => state.common.website,
|
||||
userInfo: state => state.user.userInfo,
|
||||
colorName: state => state.common.colorName,
|
||||
themeName: state => state.common.themeName,
|
||||
isShade: state => state.common.isShade,
|
||||
isCollapse: state => state.common.isCollapse,
|
||||
keyCollapse: (state, getters) => getters.screen > 1 ? getters.isCollapse : false,
|
||||
screen: state => state.common.screen,
|
||||
isLock: state => state.common.isLock,
|
||||
isFullScren: state => state.common.isFullScren,
|
||||
isMenu: state => state.common.isMenu,
|
||||
lockPasswd: state => state.common.lockPasswd,
|
||||
tagList: state => state.tags.tagList,
|
||||
tagWel: state => state.tags.tagWel,
|
||||
token: state => state.user.token,
|
||||
roles: state => state.user.roles,
|
||||
permission: state => state.user.permission,
|
||||
menu: state => state.user.menu,
|
||||
menuAll: state => state.user.menuAll,
|
||||
logsList: state => state.logs.logsList,
|
||||
logsLen: state => state.logs.logsList.length || 0,
|
||||
logsFlag: (state, getters) => getters.logsLen === 0
|
||||
}
|
||||
export default getters
|
||||
export default getters
|
||||
|
@ -1,94 +1,99 @@
|
||||
import {
|
||||
setStore,
|
||||
getStore,
|
||||
removeStore
|
||||
setStore,
|
||||
getStore,
|
||||
removeStore
|
||||
} from '@/util/store'
|
||||
import website from '@/config/website'
|
||||
|
||||
const common = {
|
||||
|
||||
state: {
|
||||
language: getStore({ name: 'language' }) || 'zh',
|
||||
isCollapse: false,
|
||||
isFullScren: false,
|
||||
isShade: false,
|
||||
screen: -1,
|
||||
isLock: getStore({ name: 'isLock' }) || false,
|
||||
showTag: true,
|
||||
showDebug: true,
|
||||
showCollapse: true,
|
||||
showSearch: true,
|
||||
showLock: true,
|
||||
showFullScren: true,
|
||||
showTheme: true,
|
||||
showMenu: true,
|
||||
showColor: true,
|
||||
colorName: getStore({ name: 'colorName' }) || '#409EFF',
|
||||
themeName: getStore({ name: 'themeName' }) || 'theme-default',
|
||||
lockPasswd: getStore({ name: 'lockPasswd' }) || '',
|
||||
website: website,
|
||||
state: {
|
||||
language: getStore({name: 'language'}) || 'zh',
|
||||
isCollapse: false,
|
||||
isFullScren: false,
|
||||
isMenu: true,
|
||||
isShade: false,
|
||||
screen: -1,
|
||||
isLock: getStore({name: 'isLock'}) || false,
|
||||
showTag: true,
|
||||
showDebug: true,
|
||||
showCollapse: true,
|
||||
showSearch: true,
|
||||
showLock: true,
|
||||
showFullScren: true,
|
||||
showTheme: true,
|
||||
showMenu: true,
|
||||
showColor: true,
|
||||
colorName: getStore({name: 'colorName'}) || '#409EFF',
|
||||
themeName: getStore({name: 'themeName'}) || 'theme-default',
|
||||
lockPasswd: getStore({name: 'lockPasswd'}) || '',
|
||||
website: website,
|
||||
},
|
||||
mutations: {
|
||||
SET_LANGUAGE: (state, language) => {
|
||||
state.language = language
|
||||
setStore({
|
||||
name: 'language',
|
||||
content: state.language
|
||||
})
|
||||
},
|
||||
mutations: {
|
||||
SET_LANGUAGE: (state, language) => {
|
||||
state.language = language
|
||||
setStore({
|
||||
name: 'language',
|
||||
content: state.language
|
||||
})
|
||||
},
|
||||
SET_SHADE: (state, active) => {
|
||||
state.isShade = active;
|
||||
},
|
||||
SET_COLLAPSE: (state) => {
|
||||
state.isCollapse = !state.isCollapse;
|
||||
},
|
||||
SET_FULLSCREN: (state) => {
|
||||
state.isFullScren = !state.isFullScren;
|
||||
},
|
||||
SET_LOCK: (state) => {
|
||||
state.isLock = true;
|
||||
setStore({
|
||||
name: 'isLock',
|
||||
content: state.isLock,
|
||||
type: 'session'
|
||||
})
|
||||
},
|
||||
SET_SCREEN: (state, screen) => {
|
||||
state.screen = screen;
|
||||
},
|
||||
SET_COLOR_NAME: (state, colorName) => {
|
||||
state.colorName = colorName;
|
||||
setStore({
|
||||
name: 'colorName',
|
||||
content: state.colorName,
|
||||
})
|
||||
},
|
||||
SET_THEME_NAME: (state, themeName) => {
|
||||
state.themeName = themeName;
|
||||
setStore({
|
||||
name: 'themeName',
|
||||
content: state.themeName,
|
||||
})
|
||||
},
|
||||
SET_LOCK_PASSWD: (state, lockPasswd) => {
|
||||
state.lockPasswd = lockPasswd;
|
||||
setStore({
|
||||
name: 'lockPasswd',
|
||||
content: state.lockPasswd,
|
||||
type: 'session'
|
||||
})
|
||||
},
|
||||
CLEAR_LOCK: (state) => {
|
||||
state.isLock = false;
|
||||
state.lockPasswd = '';
|
||||
removeStore({
|
||||
name: 'lockPasswd',
|
||||
type: 'session'
|
||||
});
|
||||
removeStore({
|
||||
name: 'isLock',
|
||||
type: 'session'
|
||||
});
|
||||
},
|
||||
}
|
||||
SET_SHADE: (state, active) => {
|
||||
state.isShade = active;
|
||||
},
|
||||
SET_COLLAPSE: (state) => {
|
||||
state.isCollapse = !state.isCollapse;
|
||||
},
|
||||
SET_FULLSCREN: (state) => {
|
||||
state.isFullScren = !state.isFullScren;
|
||||
},
|
||||
SET_IS_MENU: (state, menu) => {
|
||||
state.isMenu = menu;
|
||||
},
|
||||
SET_LOCK: (state) => {
|
||||
state.isLock = true;
|
||||
setStore({
|
||||
name: 'isLock',
|
||||
content: state.isLock,
|
||||
type: 'session'
|
||||
})
|
||||
},
|
||||
SET_SCREEN: (state, screen) => {
|
||||
state.screen = screen;
|
||||
},
|
||||
SET_COLOR_NAME: (state, colorName) => {
|
||||
state.colorName = colorName;
|
||||
setStore({
|
||||
name: 'colorName',
|
||||
content: state.colorName,
|
||||
})
|
||||
},
|
||||
SET_THEME_NAME: (state, themeName) => {
|
||||
state.themeName = themeName;
|
||||
setStore({
|
||||
name: 'themeName',
|
||||
content: state.themeName,
|
||||
})
|
||||
},
|
||||
SET_LOCK_PASSWD: (state, lockPasswd) => {
|
||||
state.lockPasswd = lockPasswd;
|
||||
setStore({
|
||||
name: 'lockPasswd',
|
||||
content: state.lockPasswd,
|
||||
type: 'session'
|
||||
})
|
||||
},
|
||||
CLEAR_LOCK: (state) => {
|
||||
state.isLock = false;
|
||||
state.lockPasswd = '';
|
||||
removeStore({
|
||||
name: 'lockPasswd',
|
||||
type: 'session'
|
||||
});
|
||||
removeStore({
|
||||
name: 'isLock',
|
||||
type: 'session'
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
export default common
|
||||
export default common
|
||||
|
@ -3,7 +3,8 @@ import {setStore, getStore} from '@/util/store'
|
||||
import {isURL, validatenull} from '@/util/validate'
|
||||
import {deepClone} from '@/util/util'
|
||||
import webiste from '@/config/website'
|
||||
import {loginByUsername, getUserInfo, getMenu, getTopMenu, logout, refeshToken, getButtons} from '@/api/user'
|
||||
import {Message} from 'element-ui'
|
||||
import {loginByUsername, loginBySocial, getUserInfo, getMenu, getTopMenu, logout, refreshToken, getButtons} from '@/api/user'
|
||||
|
||||
|
||||
function addPath(ele, first) {
|
||||
@ -45,7 +46,7 @@ const user = {
|
||||
loginByUsername(userInfo.tenantId, userInfo.username, userInfo.password, userInfo.type, userInfo.key, userInfo.code).then(res => {
|
||||
const data = res.data.data;
|
||||
commit('SET_TOKEN', data.accessToken);
|
||||
commit('SET_USERIFNO', data);
|
||||
commit('SET_USER_INFO', data);
|
||||
commit('DEL_ALL_TAG');
|
||||
commit('CLEAR_LOCK');
|
||||
resolve();
|
||||
@ -54,11 +55,23 @@ const user = {
|
||||
})
|
||||
})
|
||||
},
|
||||
GetButtons({commit}) {
|
||||
//根据第三方信息登录
|
||||
LoginBySocial({ commit }, userInfo) {
|
||||
return new Promise((resolve) => {
|
||||
getButtons().then(res => {
|
||||
const data = res.data.data;
|
||||
commit('SET_PERMISSION', data);
|
||||
loginBySocial(userInfo.tenantId, userInfo.source, userInfo.code, userInfo.state).then(res => {
|
||||
const data = res.data;
|
||||
if (data.success) {
|
||||
commit('SET_TOKEN', data.data.accessToken);
|
||||
commit('SET_REFRESH_TOKEN', data.data.refreshToken);
|
||||
commit('SET_USER_INFO', data.data);
|
||||
commit('DEL_ALL_TAG');
|
||||
commit('CLEAR_LOCK');
|
||||
} else {
|
||||
Message({
|
||||
message: data.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
resolve();
|
||||
})
|
||||
})
|
||||
@ -87,9 +100,9 @@ const user = {
|
||||
})
|
||||
},
|
||||
//刷新token
|
||||
RefeshToken({state, commit}) {
|
||||
RefreshToken({state, commit}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
refeshToken(state.refeshToken).then(res => {
|
||||
refreshToken(state.refreshToken).then(res => {
|
||||
const data = res.data.data;
|
||||
commit('SET_TOKEN', data);
|
||||
resolve(data);
|
||||
@ -102,9 +115,10 @@ const user = {
|
||||
LogOut({commit}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
logout().then(() => {
|
||||
commit('SET_TOKEN', '')
|
||||
commit('SET_TOKEN', '');
|
||||
commit('SET_MENU', [])
|
||||
commit('SET_ROLES', [])
|
||||
commit('SET_MENU_ALL', []);
|
||||
commit('SET_ROLES', []);
|
||||
commit('DEL_ALL_TAG');
|
||||
commit('CLEAR_LOCK');
|
||||
removeToken()
|
||||
@ -117,9 +131,10 @@ const user = {
|
||||
//注销session
|
||||
FedLogOut({commit}) {
|
||||
return new Promise(resolve => {
|
||||
commit('SET_TOKEN', '')
|
||||
commit('SET_MENU', [])
|
||||
commit('SET_ROLES', [])
|
||||
commit('SET_TOKEN', '');
|
||||
commit('SET_MENU', []);
|
||||
commit('SET_MENU_ALL', []);
|
||||
commit('SET_ROLES', []);
|
||||
commit('DEL_ALL_TAG');
|
||||
commit('CLEAR_LOCK');
|
||||
removeToken()
|
||||
@ -143,12 +158,22 @@ const user = {
|
||||
menu.forEach(ele => {
|
||||
addPath(ele, true);
|
||||
})
|
||||
commit('SET_MENU', menu)
|
||||
commit('SET_MENU', menu);
|
||||
commit('SET_MENU_ALL', menu);
|
||||
dispatch('GetButtons');
|
||||
resolve(menu)
|
||||
})
|
||||
})
|
||||
},
|
||||
GetButtons({commit}) {
|
||||
return new Promise((resolve) => {
|
||||
getButtons().then(res => {
|
||||
const data = res.data.data;
|
||||
commit('SET_PERMISSION', data);
|
||||
resolve();
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
SET_TOKEN: (state, token) => {
|
||||
@ -156,16 +181,33 @@ const user = {
|
||||
state.token = token;
|
||||
setStore({name: 'token', content: state.token, type: 'session'})
|
||||
},
|
||||
SET_USERIFNO: (state, userInfo) => {
|
||||
SET_USER_INFO: (state, userInfo) => {
|
||||
state.userInfo = userInfo;
|
||||
setStore({name: 'userInfo', content: state.userInfo})
|
||||
},
|
||||
SET_MENU_ALL: (state, menuAll) => {
|
||||
state.menuAll = menuAll
|
||||
setStore({name: 'menuAll', content: state.menuAll, type: 'session'})
|
||||
},
|
||||
SET_MENU: (state, menu) => {
|
||||
state.menu = menu
|
||||
setStore({name: 'menu', content: state.menu, type: 'session'})
|
||||
},
|
||||
SET_MENU_ALL: (state, menuAll) => {
|
||||
state.menuAll = menuAll;
|
||||
if (validatenull(menu)) return;
|
||||
//合并动态路由去重
|
||||
let menuAll = state.menuAll;
|
||||
menuAll = menuAll.concat(menu).reverse();
|
||||
let newMenu = [];
|
||||
for (let item1 of menuAll) {
|
||||
let flag = true;
|
||||
for (let item2 of newMenu) {
|
||||
if (item1.name === item2.name || item1.path === item2.path) {
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
if (flag) newMenu.push(item1);
|
||||
}
|
||||
state.menuAll = newMenu;
|
||||
setStore({name: 'menuAll', content: state.menuAll, type: 'session'})
|
||||
},
|
||||
SET_ROLES: (state, roles) => {
|
||||
state.roles = roles;
|
||||
|
@ -26,6 +26,7 @@ export const getObjType = obj => {
|
||||
}
|
||||
return map[toString.call(obj)];
|
||||
};
|
||||
|
||||
/**
|
||||
* 对象深拷贝
|
||||
*/
|
||||
@ -285,4 +286,22 @@ export const openWindow = (url, title, w, h) => {
|
||||
if (window.focus) {
|
||||
newWindow.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取顶部地址栏地址
|
||||
*/
|
||||
export const getTopUrl = () => {
|
||||
return window.location.href.split("/#/")[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取url参数
|
||||
* @param name 参数名
|
||||
*/
|
||||
export const getQueryString = (name) => {
|
||||
let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
|
||||
let r = window.location.search.substr(1).match(reg);
|
||||
if (r != null) return unescape(decodeURI(r[2]));
|
||||
return null;
|
||||
}
|
||||
|
@ -180,15 +180,15 @@
|
||||
dicData: [
|
||||
{
|
||||
label: "工具栏",
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
label: "操作栏",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: "工具操作栏",
|
||||
label: "操作栏",
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
label: "工具操作栏",
|
||||
value: 3
|
||||
}
|
||||
],
|
||||
hide: true,
|
||||
|
@ -183,12 +183,19 @@
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids.join(",");
|
||||
},
|
||||
idsArray() {
|
||||
let ids = [];
|
||||
this.selectionList.forEach(ele => {
|
||||
ids.push(ele.id);
|
||||
});
|
||||
return ids;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
const menuLIst = this.$refs.tree.getCheckedKeys().join(",");
|
||||
grant(this.ids, menuLIst).then(() => {
|
||||
const menuLIst = this.$refs.tree.getCheckedKeys();
|
||||
grant(this.idsArray, menuLIst).then(() => {
|
||||
this.box = false;
|
||||
this.$message({
|
||||
type: "success",
|
||||
|
@ -102,6 +102,7 @@
|
||||
<script>
|
||||
import {
|
||||
getList,
|
||||
getUser,
|
||||
remove,
|
||||
update,
|
||||
add,
|
||||
@ -555,7 +556,18 @@
|
||||
},
|
||||
beforeOpen(done, type) {
|
||||
if (["edit", "view"].includes(type)) {
|
||||
// 预留
|
||||
getUser(this.form.id).then(res => {
|
||||
this.form = res.data.data;
|
||||
if(this.form.hasOwnProperty("deptId")){
|
||||
this.form.deptId = this.form.deptId.split(",");
|
||||
}
|
||||
if(this.form.hasOwnProperty("roleId")){
|
||||
this.form.roleId = this.form.roleId.split(",");
|
||||
}
|
||||
if(this.form.hasOwnProperty("postId")){
|
||||
this.form.postId = this.form.postId.split(",");
|
||||
}
|
||||
});
|
||||
}
|
||||
done();
|
||||
},
|
||||
|
156
src/views/wel/dashboard.vue
Normal file
156
src/views/wel/dashboard.vue
Normal file
@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<basic-container>
|
||||
<div class="wel">
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-platform-eleme"
|
||||
text="开始菜单1"
|
||||
time="1"
|
||||
background="/img/bg/bg3.jpg"
|
||||
color="#d56259"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-eleme"
|
||||
text="开始菜单2"
|
||||
time="2"
|
||||
background="/img/bg/bg2.jpg"
|
||||
color="#419ce7"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-delete-solid"
|
||||
text="开始菜单3"
|
||||
time="3"
|
||||
color="#56b69b"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-delete"
|
||||
text="开始菜单4"
|
||||
time="4"
|
||||
color="#d44858"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-s-tools"
|
||||
text="开始菜单5"
|
||||
time="5"
|
||||
color="#3a1f7e"></basic-block>
|
||||
<basic-block :width="410"
|
||||
:height="height"
|
||||
icon="el-icon-setting"
|
||||
text="开始菜单6"
|
||||
time="6"
|
||||
background="/img/bg/bg1.jpg"
|
||||
dept="这是一段很长的很长很长很长的描述这是一段很长的很长很长很长的描述"
|
||||
color="#422829"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-user-solid"
|
||||
text="开始菜单7"
|
||||
time="7"
|
||||
color="#613cbd"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-star-off"
|
||||
text="开始菜单8"
|
||||
time="8"
|
||||
color="#da542e"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-goods"
|
||||
text="开始菜单9"
|
||||
time="9"
|
||||
color="#2e8aef"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-circle-check"
|
||||
text="开始菜单10"
|
||||
time="10"
|
||||
color="#3d17b8"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-s-platform"
|
||||
text="开始菜单11"
|
||||
time="11"
|
||||
color="#e31462"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-s-fold"
|
||||
text="开始菜单12"
|
||||
time="12"
|
||||
color="#d9532d"></basic-block>
|
||||
<basic-block :width="410"
|
||||
:height="height"
|
||||
icon="el-icon-s-open"
|
||||
text="开始菜单13"
|
||||
time="13"
|
||||
dept="这是一段很长的很长很长很长的描述这是一段很长的很长很长很长的描述"
|
||||
color="#b72147"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-s-flag"
|
||||
text="开始菜单14"
|
||||
time="14"
|
||||
color="#01a100"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-s-data"
|
||||
text="开始菜单15"
|
||||
time="15"
|
||||
color="#0c56bf"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-s-grid"
|
||||
text="开始菜单16"
|
||||
time="16"
|
||||
color="#0098a9"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-s-release"
|
||||
text="开始菜单17"
|
||||
time="17"
|
||||
background="/img/bg/bg2.jpg"
|
||||
color="#209bdf"></basic-block>
|
||||
<basic-block :width="width"
|
||||
:height="height"
|
||||
icon="el-icon-s-home"
|
||||
text="开始菜单18"
|
||||
time="18"
|
||||
background="/img/bg/bg3.jpg"
|
||||
color="#603bbc"></basic-block>
|
||||
<basic-block :width="515"
|
||||
:height="height"
|
||||
icon="el-icon-s-promotion"
|
||||
text="开始菜单19"
|
||||
time="19"
|
||||
dept="这是一段很长的很长很长很长的描述这是一段很长的很长很长很长的描述"
|
||||
color="#009bad"></basic-block>
|
||||
<basic-block :width="515"
|
||||
:height="height"
|
||||
icon="el-icon-s-custom"
|
||||
text="开始菜单20"
|
||||
time="20"
|
||||
background="/img/bg/bg4.jpg"
|
||||
dept="这是一段很长的很长很长很长的描述这是一段很长的很长很长很长的描述"
|
||||
color="#d74e2a"></basic-block>
|
||||
</div>
|
||||
</basic-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
width: 200,
|
||||
height: 120,
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.wel {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 1100px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
@ -1,11 +1,12 @@
|
||||
<template>
|
||||
<div>
|
||||
<basic-container>
|
||||
<third-register></third-register>
|
||||
<p style="text-align: center;">
|
||||
<img src="https://img.shields.io/badge/Release-V2.7.0-green.svg" alt="Downloads"/>
|
||||
<img src="https://img.shields.io/badge/Release-V2.7.2-green.svg" alt="Downloads"/>
|
||||
<img src="https://img.shields.io/badge/JDK-1.8+-green.svg" alt="Build Status"/>
|
||||
<img src="https://img.shields.io/badge/Spring%20Cloud-Hoxton.SR3-blue.svg" alt="Coverage Status"/>
|
||||
<img src="https://img.shields.io/badge/Spring%20Boot-2.2.6.RELEASE-blue.svg" alt="Downloads"/>
|
||||
<img src="https://img.shields.io/badge/Spring%20Cloud-Hoxton.SR7-blue.svg" alt="Coverage Status"/>
|
||||
<img src="https://img.shields.io/badge/Spring%20Boot-2.2.9.RELEASE-blue.svg" alt="Downloads"/>
|
||||
<a target="_blank" href="https://bladex.vip">
|
||||
<img src="https://img.shields.io/badge/Saber%20Author-Small%20Chill-ff69b4.svg" alt="Downloads"/>
|
||||
</a>
|
||||
@ -124,17 +125,32 @@
|
||||
<el-row>
|
||||
<basic-container>
|
||||
<el-collapse v-model="logActiveNames" @change="handleChange">
|
||||
<el-collapse-item title="2.7.2发布 集成JustAuth支持第三方登录" name="19">
|
||||
<div>1.升级至 SpringCloud Hoxton.SR7</div>
|
||||
<div>2.升级至 SpringBoot 2.2.9.RELEASE</div>
|
||||
<div>4.升级至 SpringBootAdmin 2.3.0</div>
|
||||
<div>3.升级至 Seata 1.3.0</div>
|
||||
<div>5.升级至 Kinfe4j 2.0.4</div>
|
||||
<div>6.升级至 FastJson 1.2.73</div>
|
||||
<div>8.集成JustAuth支持第三方登录</div>
|
||||
<div>9.优化请求日志打印工具</div>
|
||||
<div>10.优化Token返回字段集合</div>
|
||||
<div>11.修复菜单列表API报空指针的问题</div>
|
||||
<div>12.修复角色配置数据量较大导致失败的问题</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="2.7.1发布 增加行政区划管理,支持seata1.2" name="18">
|
||||
<div>1.升级至 SpringCloud Hoxton.SR5</div>
|
||||
<div>2.升级至 SpringBoot 2.2.7.RELEASE</div>
|
||||
<div>3.升级至 Seata 1.2.0</div>
|
||||
<div>4.升级至 FastJson 1.2.70</div>
|
||||
<div>5.升级至 Avue 2.5.3</div>
|
||||
<div>6.新增行政区划管理模块</div>
|
||||
<div>7.优化用户导入的密码配置逻辑</div>
|
||||
<div>8.优化INode结构支持懒加载数据格式</div>
|
||||
<div>9.优化代码生成模板,支持最新版Saber结构</div>
|
||||
<div>10.修复Log模块在多线程、异步场景下报错的问题</div>
|
||||
<div>4.升级至 MybatisPlus 3.3.2</div>
|
||||
<div>5.升级至 Kinfe4j 2.0.3</div>
|
||||
<div>6.升级至 FastJson 1.2.70</div>
|
||||
<div>7.升级至 Avue 2.5.3</div>
|
||||
<div>8.新增行政区划管理模块</div>
|
||||
<div>9.优化用户导入的密码配置逻辑</div>
|
||||
<div>10.优化INode结构支持懒加载数据格式</div>
|
||||
<div>11.优化代码生成模板,支持最新版Saber结构</div>
|
||||
<div>12.修复Log模块在多线程、异步场景下报错的问题</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="2.7.0发布 内核全面升级,增加岗位管理,用户导入导出" name="17">
|
||||
<div>1.升级至 SpringCloud Hoxton.SR3</div>
|
Loading…
Reference in New Issue
Block a user