身份跳转后台

This commit is contained in:
熊丽君
2022-02-11 17:36:06 +08:00
parent cff0921b9d
commit d6684a154b
13 changed files with 432 additions and 53 deletions

View File

@ -41,19 +41,42 @@ export function getInfo() {
// 退出方法
export function logout() {
return request({
url: '/logout',
url: '/enterprise/v1/account/logout',
method: 'post'
})
}
// 获取验证码
export function getCodeImg() {
export function getCodeNum(data) {
return request({
url: '/captchaImage',
url: '/enterprise/v1/sms/captcha',
headers: {
isToken: false
},
method: 'get',
method: 'post',
data,
timeout: 20000
})
}
// 验证码验证
export function codeValid(data) {
return request({
url: '/enterprise/v1/sms/captcha/validate',
headers: {
isToken: false
},
method: 'post',
data,
})
}
// 忘记密码/重置密码
export function resetPassword(data) {
return request({
url: '/enterprise/v1/account/reset/password',
headers: {
isToken: false
},
method: 'post',
data,
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -14,11 +14,23 @@
</template>
<script setup>
import { getCodeNum } from "@/api/login";
const props = defineProps({
mobile: String,
});
const disabled = ref(true);
const buttonName = ref("获取验证码");
const isDisabled = ref(false);
const time = ref(60);
const { proxy } = getCurrentInstance();
function getCode() {
const reg = /^1[3|4|5|6|7|8|9][0-9]\d{8}$/;
if (!reg.test(props.mobile))
return proxy.$modal.msgError("请输入正确的手机号码");
isDisabled.value = true;
let interval = setInterval(function () {
buttonName.value = time.value + "后重新发送";
@ -30,15 +42,12 @@ function getCode() {
clearInterval(interval);
}
}, 1000);
console.log(66666);
// getCodeImg().then((res) => {
// captchaOnOff.value =
// res.captchaOnOff === undefined ? true : res.captchaOnOff;
// if (captchaOnOff.value) {
// codeUrl.value = "data:image/gif;base64," + res.img;
// loginForm.value.mode = res.mode;
// }
// });
getCodeNum({ mobile: props.mobile })
.then((res) => {})
.catch(() => {
isDisabled.value = false;
clearInterval(interval);
});
}
</script>

View File

@ -84,14 +84,37 @@
关于我们
</div>
</li>
<li class="menu-item1">
<li class="menu-item1" style="display: flex; justify-content: center">
<div
v-if="!getters.avatar"
class="menu-item-tit"
:class="pagePath == '/login' ? 'active' : ''"
@click="handlePath('/login')"
>
登录注册
</div>
<el-dropdown
v-else
style="margin-top: 20px"
class="avatar-container right-menu-item hover-effect"
trigger="click"
>
<div class="avatar-wrapper">
<img :src="getters.avatar" class="user-avatar" />
<i class="el-icon-caret-bottom" />
</div>
<template #dropdown>
<el-dropdown-menu>
<router-link to="/identity/index">
<el-dropdown-item>个人中心</el-dropdown-item>
</router-link>
<el-dropdown-item divided @click="logout">
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</li>
</ul>
</el-col>
@ -100,8 +123,13 @@
</template>
<script setup>
import { ElMessageBox } from "element-plus";
import { defineComponent, onMounted, reactive, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
const store = useStore();
const getters = computed(() => store.getters);
let state = reactive({});
let pagePath = ref("");
const route = useRoute();
@ -114,10 +142,27 @@ watch(
);
pagePath.value = route.path;
function handlePage() {
router.push("/identity/index");
}
function handlePath(path) {
pagePath.value = path;
router.push(path);
}
function logout() {
ElMessageBox.confirm("确定注销并退出系统吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
store.dispatch("LogOut").then(() => {
location.href = "/";
});
})
.catch(() => {});
}
</script>
<style lang="scss">
@ -202,3 +247,12 @@ dt {
}
}
</style>
<style lang="scss" scoped>
.user-avatar {
cursor: pointer;
width: 40px;
height: 40px;
border-radius: 50%;
}
</style>

View File

@ -14,7 +14,6 @@ router.beforeEach((to, from, next) => {
NProgress.start()
// 跳过登录验证
next();
return;
if (getToken()) {
to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
/* has token*/
@ -27,15 +26,16 @@ router.beforeEach((to, from, next) => {
if (store.getters.roles.length === 0) {
// 判断当前用户是否已拉取完user_info信息
store.dispatch('GetInfo').then(() => {
store.dispatch('GenerateRoutes').then(accessRoutes => {
// 根据roles权限生成可访问的路由表
accessRoutes.forEach(route => {
if (!isHttp(route.path)) {
router.addRoute(route) // 动态添加可访问路由表
}
})
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
})
next({ ...to, replace: true })
// store.dispatch('GenerateRoutes').then(accessRoutes => {
// // 根据roles权限生成可访问的路由表
// accessRoutes.forEach(route => {
// if (!isHttp(route.path)) {
// router.addRoute(route) // 动态添加可访问路由表
// }
// })
// next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
// })
}).catch(err => {
store.dispatch('LogOut').then(() => {
ElMessage.error(err)

View File

@ -194,12 +194,12 @@ export const constantRoutes = [
{
path: '/three',
component: Layout,
redirect: '/three/expert',
redirect: '/three/research',
children: [
{
path: 'expert',
path: 'research',
component: () => import('@/views/admin/three/index'),
name: 'Expert',
name: 'Research',
meta: { title: '首页', icon: 'dashboard', affix: true }
}
]

View File

@ -1,4 +1,5 @@
import { login, logout, getInfo } from '@/api/login'
import { settled } from '@/api/identity'
import { getToken, setToken, removeToken } from '@/utils/auth'
import defAva from '@/assets/images/profile.jpg'
@ -50,9 +51,9 @@ const user = {
// 获取用户信息
GetInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo().then(res => {
const user = res.user
const avatar = user.avatar == "" ? defAva : import.meta.env.VITE_APP_BASE_API + user.avatar;
settled().then(res => {
res.data['avatar'] = ''
const avatar = res.data.avatar == "" ? defAva : import.meta.env.VITE_APP_BASE_API + res.data.avatar;
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
commit('SET_ROLES', res.roles)
@ -60,7 +61,7 @@ const user = {
} else {
commit('SET_ROLES', ['ROLE_DEFAULT'])
}
commit('SET_NAME', user.userName)
commit('SET_NAME', res.data.userName)
commit('SET_AVATAR', avatar)
resolve(res)
}).catch(error => {

View File

@ -77,6 +77,20 @@ service.interceptors.response.use(res => {
error => {
console.log('err' + error)
let { message } = error;
if (message.includes("401")) {
ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
store.dispatch('LogOut').then(() => {
location.href = '/login';
})
}).catch(() => {});
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
}
if (message == "Network Error") {
message = "后端接口连接异常";
}

View File

@ -163,7 +163,7 @@
<el-row>
<el-col :span="24">
<el-form-item label="个人简介" prop="introduce">
<el-form-item label="个人简介:" prop="introduce">
<el-input
v-model="modelValue.introduce"
type="textarea"

View File

@ -53,7 +53,7 @@
v-for="item in levelIII"
:key="item.id"
:label="item.name"
:value="item.id"
:value="item"
>
</el-option>
</el-select>

View File

@ -3,11 +3,11 @@
<div class="content">
<img class="loginImg" src="../assets/images/login.png" alt="" srcset="" />
<div class="login-form">
<el-tabs v-model="loginForm.mode" v-if="isLogin">
<el-tabs v-model="loginForm.mode" v-if="isLogin == 1">
<el-tab-pane label="账号密码登录" name="102"></el-tab-pane>
<el-tab-pane label="手机快捷登录" name="101"></el-tab-pane>
</el-tabs>
<div v-if="isLogin">
<div v-if="isLogin == 1">
<el-form ref="loginRef" :model="loginForm" :rules="loginRules">
<el-form-item prop="username">
<el-input
@ -55,7 +55,7 @@
/>
</template>
</el-input>
<webGetCode />
<WebGetCode v-model:mobile="loginForm.username" />
</el-form-item>
<el-form-item>
<el-checkbox v-model="loginForm.rememberMe">记住账号</el-checkbox>
@ -75,21 +75,20 @@
</el-form-item>
</el-form>
<div style="overflow: hidden">
<div style="float: left" v-if="isLogin">
<span class="text_col pointer" :to="'/login'">忘记密码</span>
<div style="float: left" v-if="isLogin == 1">
<span class="text_col pointer" :to="'/login'" @click="isLogin = 3"
>忘记密码</span
>
</div>
<div style="float: right" v-if="register">
<span
@click="isLogin = false"
style="color: #0054ff"
class="pointer"
<span @click="isLogin = 2" style="color: #0054ff" class="pointer"
>注册</span
>
</div>
</div>
<el-form
v-if="isLogin"
v-if="isLogin == 1"
:model="registerForm"
status-icon
:rules="isCheckRules"
@ -97,7 +96,14 @@
>
<el-form-item prop="isCheck">
<div style="margin-top: 43px">
<div class="text_col">其他登录方式</div>
<div class="text_col">
<div>其他登录方式</div>
<img
class="pointer"
src="@/assets/images/weixin.png"
alt=""
/>
</div>
<el-checkbox
v-model="registerForm.isCheck"
style="margin-top: 43px"
@ -109,7 +115,8 @@
</el-form-item>
</el-form>
</div>
<Register v-model:isLogin="isLogin" v-else />
<Register v-model:isLogin="isLogin" v-else-if="isLogin == 2" />
<Retrieve v-model:isLogin="isLogin" v-else-if="isLogin == 3" />
</div>
</div>
@ -122,13 +129,14 @@
import Cookies from "js-cookie";
import { encrypt, decrypt } from "@/utils/jsencrypt";
import Register from "./register.vue";
import webGetCode from "@/components/webGetCode";
import Retrieve from "./retrieve.vue";
import WebGetCode from "@/components/webGetCode";
const store = useStore();
const router = useRouter();
const { proxy } = getCurrentInstance();
const isLogin = ref(true);
const isLogin = ref(1);
const loginForm = ref({
username: "",
@ -257,7 +265,7 @@ getCookie();
.login-form {
width: 516px;
min-height: 517px;
// height: 517px;
background: #ffffff;
box-sizing: border-box;
padding: 30px 33px;
@ -327,5 +335,9 @@ getCookie();
}
.text_col {
color: #999999;
img {
width: 30px;
margin: 10px 0 0 10px;
}
}
</style>

View File

@ -56,7 +56,7 @@
><svg-icon icon-class="validCode" class="el-input__icon input-icon"
/></template>
</el-input>
<webGetCode />
<webGetCode v-model:mobile="registerForm.mobile" />
</el-form-item>
<el-form-item prop="isCheck" style="margin: 10px 0; height: 28px">
<el-checkbox v-model="registerForm.isCheck">
@ -90,17 +90,17 @@
<script setup>
import { ElMessageBox } from "element-plus";
import { getCodeImg, register } from "@/api/login";
import { getCodeNum, register } from "@/api/login";
import webGetCode from "@/components/webGetCode";
const props = defineProps({
isLogin: Boolean,
isLogin: Number,
});
const emit = defineEmits();
function handleLogin() {
emit("update:isLogin", true);
emit("update:isLogin", 1);
}
const router = useRouter();

266
src/views/retrieve.vue Normal file
View File

@ -0,0 +1,266 @@
<template>
<div>
<el-form
v-if="step == 1"
ref="mobileRef"
:model="retrieveForm"
:rules="mobileRules"
class="retrieve-form"
>
<h3 class="title">
<el-icon
class="pointer"
:size="18"
color="#333333"
@click="handleLogin"
>
<Back />
</el-icon>
<span>找回密码</span>
</h3>
<el-form-item prop="mobile">
<el-input
v-model="retrieveForm.mobile"
type="text"
auto-complete="off"
placeholder="手机号"
>
<template #prefix
><svg-icon icon-class="user" class="el-input__icon input-icon"
/></template>
</el-input>
</el-form-item>
<el-form-item prop="captcha" style="margin-bottom: 0">
<el-input
v-model="retrieveForm.captcha"
auto-complete="off"
placeholder="验证码"
style="width: 65%"
>
<template #prefix
><svg-icon icon-class="validCode" class="el-input__icon input-icon"
/></template>
</el-input>
<WebGetCode v-model:mobile="retrieveForm.mobile" />
<!-- @isSuccess="isSuccess" -->
</el-form-item>
<el-form-item style="width: 100%; margin-top: 35px">
<el-button
class="x_btns"
size="medium"
type="primary"
style="width: 100%"
@click.prevent="handleNext"
>
<span>下一步</span>
</el-button>
</el-form-item>
</el-form>
<el-form
v-else
ref="passRef"
:model="retrieveForm"
:rules="passRules"
class="retrieve-form"
>
<h3 class="title">
<el-icon class="pointer" :size="18" color="#333333" @click="step--">
<Back />
</el-icon>
<span>找回密码</span>
</h3>
<el-form-item prop="password">
<el-input
v-model="retrieveForm.password"
type="password"
auto-complete="off"
placeholder="请输入新密码"
>
<template #prefix
><svg-icon icon-class="password" class="el-input__icon input-icon"
/></template>
</el-input>
</el-form-item>
<el-form-item prop="repeat_pass">
<el-input
v-model="retrieveForm.repeat_pass"
type="password"
auto-complete="off"
placeholder="确认密码"
>
<template #prefix
><svg-icon icon-class="password" class="el-input__icon input-icon"
/></template>
</el-input>
</el-form-item>
<el-form-item style="width: 100%; margin-top: 35px">
<el-button
class="x_btns"
size="medium"
type="primary"
style="width: 100%"
@click.prevent="handleRetrieve"
>
<span> </span>
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { ElMessageBox } from "element-plus";
import { getCodeNum, codeValid, resetPassword } from "@/api/login";
import WebGetCode from "@/components/webGetCode";
const props = defineProps({
isLogin: Number,
});
const emit = defineEmits();
function handleLogin() {
emit("update:isLogin", 1);
}
const router = useRouter();
const { proxy } = getCurrentInstance();
const retrieveForm = ref({
mobile: "",
password: "",
repeat_pass: "",
captcha: "",
token: "",
});
const equalToPassword = (rule, value, callback) => {
if (retrieveForm.value.password !== value) {
callback(new Error("两次输入的密码不一致"));
} else {
callback();
}
};
const mobileRules = {
mobile: [
{ required: true, message: "手机号不能为空", trigger: "blur" },
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur",
},
],
captcha: [{ required: true, trigger: "change", message: "请输入验证码" }],
};
const passRules = {
password: [
{ required: true, trigger: "blur", message: "请输入您的密码" },
{
min: 5,
max: 20,
message: "用户密码长度必须介于 5 和 20 之间",
trigger: "blur",
},
],
repeat_pass: [
{ required: true, trigger: "blur", message: "请再次输入您的新密码" },
{ required: true, validator: equalToPassword, trigger: "blur" },
],
};
const step = ref(1);
function handleNext() {
proxy.$refs.mobileRef.validate((valid) => {
if (valid) {
codeValid(retrieveForm.value).then((res) => {
if (res.code == 200) {
retrieveForm.value.token = res.data.token;
step.value = 2;
}
});
}
});
}
function handleRetrieve() {
proxy.$refs.passRef.validate((valid) => {
if (valid) {
let formData = Object.assign({}, retrieveForm.value);
formData.password = proxy.md5(formData.password);
formData.repeat_pass = proxy.md5(formData.repeat_pass);
resetPassword(formData)
.then((res) => {
const mobile = formData.mobile;
ElMessageBox.alert(
"<font color='red'>恭喜你,您的账号 " +
mobile +
" 修改密码成功!</font>",
"系统提示",
{
dangerouslyUseHTMLString: true,
type: "success",
}
)
.then(() => {
handleLogin();
// router.push("/login");
})
.catch(() => {});
})
.catch(() => {});
}
});
}
</script>
<style lang='scss' scoped>
.title {
display: flex;
align-items: center;
margin: 0px auto 40px auto;
color: #333333;
font-size: 20px;
font-weight: bold;
.el-icon {
text-align: left;
}
span {
flex: 1;
text-align: center;
}
}
.retrieve-form {
.el-input {
height: 38px;
input {
height: 38px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 2px;
}
}
.register-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.el-register-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
</style>