|
@@ -18,43 +18,42 @@
|
|
|
|
|
|
|
|
<div class="input_tips">请输入验证码</div>
|
|
<div class="input_tips">请输入验证码</div>
|
|
|
|
|
|
|
|
- <!-- <div class="login_info_message">校本选课系统登录</div> -->
|
|
|
|
|
-<!--
|
|
|
|
|
- <div class="tab">
|
|
|
|
|
- <span :class="!isStudentLogin ? 'selected': 'un_selected' " @click="HandleLoginChange(false)">教师</span>
|
|
|
|
|
- <span :class="isStudentLogin ? 'selected': 'un_selected' " @click="HandleLoginChange(true)">学生</span>
|
|
|
|
|
- </div> -->
|
|
|
|
|
-
|
|
|
|
|
<div class="login_info_input">
|
|
<div class="login_info_input">
|
|
|
- <el-form ref="userInfoForm" @submit.prevent="SubmitLogin">
|
|
|
|
|
- <el-form-item :rules="phoneRules" prop="userName">
|
|
|
|
|
- <el-input v-model="userName" placeholder="请输入手机号" @keyup.enter="SubmitLogin">
|
|
|
|
|
|
|
+ <el-form :rules="formRules"
|
|
|
|
|
+ ref="userInfoForm"
|
|
|
|
|
+ :model="formData" >
|
|
|
|
|
+ <!-- :rules="phoneRules" -->
|
|
|
|
|
+ <el-form-item prop="phone">
|
|
|
|
|
+ <el-input :disabled="true" v-model="formData.phone" placeholder="请输入手机号" @keyup.enter="SubmitLogin()">
|
|
|
<template #prefix>
|
|
<template #prefix>
|
|
|
<i class="iconfont icon_zhanghao" />
|
|
<i class="iconfont icon_zhanghao" />
|
|
|
</template>
|
|
</template>
|
|
|
- <template #suffix>
|
|
|
|
|
- <img @click.stop="ClearInput" :src="lineCloseIcon" alt="Clear Icon" style="width: 18px;height: 18px;cursor: pointer;">
|
|
|
|
|
- </template>
|
|
|
|
|
</el-input>
|
|
</el-input>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
- <el-form-item prop="passWord">
|
|
|
|
|
- <el-input v-model="passWord" :type="'text'" placeholder="请输入验证码" @keyup.enter="SubmitLogin">
|
|
|
|
|
|
|
+ <el-form-item prop="phoneVerificationCode">
|
|
|
|
|
+ <el-input v-model="formData.phoneVerificationCode" placeholder="请输入验证码" @keyup.enter="SubmitLogin()">
|
|
|
<template #prefix>
|
|
<template #prefix>
|
|
|
<img :src="validateCodeIcon" alt="" style="width: 18px;height: 18px;">
|
|
<img :src="validateCodeIcon" alt="" style="width: 18px;height: 18px;">
|
|
|
</template>
|
|
</template>
|
|
|
<template #suffix>
|
|
<template #suffix>
|
|
|
- <span style="z-index: 10 !important;" class="valid_code" >
|
|
|
|
|
|
|
+ <span v-if="timeCountDown<=0" style="z-index: 10 !important;"
|
|
|
|
|
+ class="valid_code" @click="sendVerificationCode" >
|
|
|
获取验证码
|
|
获取验证码
|
|
|
- <!-- <i @click.down="showPass = !showPass" :class="['iconfont', {'icon_xianshimima':showPass},{'icon_buxianshimima':!showPass}]"></i> -->
|
|
|
|
|
</span>
|
|
</span>
|
|
|
|
|
+ <span v-else>重新发送 {{ timeCountDown }}s</span>
|
|
|
</template>
|
|
</template>
|
|
|
</el-input>
|
|
</el-input>
|
|
|
- <!-- <el-input v-model="passWord" placeholder="请输入密码" :type="!showPass ? 'password' : 'text'">
|
|
|
|
|
- <template #prefix>
|
|
|
|
|
- <i class="iconfont icon_mima" />
|
|
|
|
|
- </template>
|
|
|
|
|
- </el-input> -->
|
|
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 验证码 -->
|
|
|
|
|
+ <el-form-item v-if="showCaptchaCode" prop="captchaCode">
|
|
|
|
|
+ <div class="captcha_code">
|
|
|
|
|
+ <el-input v-model="formData.captchaCode" placeholder="请输入验证码" @keyup.enter="SubmitLogin">
|
|
|
|
|
+ </el-input>
|
|
|
|
|
+ <img class="captcha_code" :src="graphCaptchaCode.img" alt="验证码图片" @click="ReplaceGraphCode">
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+
|
|
|
</el-form>
|
|
</el-form>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
@@ -67,60 +66,60 @@
|
|
|
<div class="login_info_button">
|
|
<div class="login_info_button">
|
|
|
<el-button style="width:100%;" @click="SubmitLogin()" :loading="loadingLogin">登 录</el-button>
|
|
<el-button style="width:100%;" @click="SubmitLogin()" :loading="loadingLogin">登 录</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- <!-- <div class="login_other_type"> -->
|
|
|
|
|
- <!-- <div class="other_login_line">
|
|
|
|
|
- <span class="line"></span>
|
|
|
|
|
- <span class="text">其他登录方式</span>
|
|
|
|
|
- <span class="line"></span>
|
|
|
|
|
- </div> -->
|
|
|
|
|
- <!-- <div class="other_login_icon"> -->
|
|
|
|
|
- <!-- <div class="icon_item">
|
|
|
|
|
- <img src="../../assets/login/login_wechat.webp" alt=""></img>
|
|
|
|
|
- <p>微信</p>
|
|
|
|
|
- </div> -->
|
|
|
|
|
- <!--
|
|
|
|
|
- <div class="icon_item">
|
|
|
|
|
- <img src="../../assets/login/login_feishu.webp" alt=""></img>
|
|
|
|
|
- <p>钉钉</p>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="icon_item">
|
|
|
|
|
- <img src="../../assets/login/login_email.webp" alt=""></img>
|
|
|
|
|
- <p>邮箱</p>
|
|
|
|
|
- </div>
|
|
|
|
|
- -->
|
|
|
|
|
- <!-- </div> -->
|
|
|
|
|
- <!-- </div> -->
|
|
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { ref, onMounted, computed, watch } from 'vue'
|
|
|
|
|
|
|
+import { ref, reactive, onMounted, computed, watch, onUnmounted } from 'vue'
|
|
|
// import particles from 'particles.js'
|
|
// import particles from 'particles.js'
|
|
|
-import { login,getUserInfo} from '@/api/login.ts'
|
|
|
|
|
|
|
+import {
|
|
|
|
|
+ login,getUserInfo,sendSMSVerificationLogin,
|
|
|
|
|
+ smsCodeLoginApi, replaceGraphValidateCodeApi
|
|
|
|
|
+} from '@/api/login.ts'
|
|
|
|
|
|
|
|
import { ElMessage } from 'element-plus' //
|
|
import { ElMessage } from 'element-plus' //
|
|
|
import { useRouter } from 'vue-router'
|
|
import { useRouter } from 'vue-router'
|
|
|
import { encrypt } from "@/utils/jsencrypt";
|
|
import { encrypt } from "@/utils/jsencrypt";
|
|
|
-import passwordIcon from '@/assets/icon/password.svg'
|
|
|
|
|
-import lineCloseIcon from '@/assets/icon/line_close_icon.webp'
|
|
|
|
|
import validateCodeIcon from '@/assets/login/validate_code.png'
|
|
import validateCodeIcon from '@/assets/login/validate_code.png'
|
|
|
|
|
|
|
|
const router = useRouter() // 获取路由实例
|
|
const router = useRouter() // 获取路由实例
|
|
|
-// 响应式数据
|
|
|
|
|
-const userName = ref('')
|
|
|
|
|
-const passWord = ref('')
|
|
|
|
|
|
|
+
|
|
|
|
|
+// 手机验证码表单登录数据
|
|
|
|
|
+const userInfoForm = ref()
|
|
|
|
|
+const formData = ref({
|
|
|
|
|
+ phone:'', //手机号
|
|
|
|
|
+ phoneVerificationCode:'', //手机验证码
|
|
|
|
|
+ captchaCode:'', // 图形验证码
|
|
|
|
|
+})
|
|
|
|
|
+const formRules = ref({
|
|
|
|
|
+ phone: [
|
|
|
|
|
+ { required:true,trigger:'blur',message:'请输入手机号'},
|
|
|
|
|
+ ],
|
|
|
|
|
+ phoneVerificationCode:[
|
|
|
|
|
+ { required:true,trigger:'blur',message:'请输入验证码'},
|
|
|
|
|
+ ],
|
|
|
|
|
+ captchaCode:[
|
|
|
|
|
+ { required:true,trigger:'blur',message:'请输入图形验证码'},
|
|
|
|
|
+ ]
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const sendMsgInfo = ref({}) //上一步传过来的用户名/密码/账号绑定的手机号
|
|
|
|
|
+
|
|
|
|
|
+const showCaptchaCode = ref(false) //是否展示图形验证码
|
|
|
|
|
+const graphCaptchaCode = reactive({
|
|
|
|
|
+ img:'', //验证码图片
|
|
|
|
|
+ id:'' //图形验证码id
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
const remeberPassWord = ref(false)
|
|
const remeberPassWord = ref(false)
|
|
|
const loadingLogin = ref(false)
|
|
const loadingLogin = ref(false)
|
|
|
-const showPass = ref(false)
|
|
|
|
|
-
|
|
|
|
|
-const isStudentLogin = ref(true)
|
|
|
|
|
|
|
|
|
|
|
|
+// 验证码发送倒计时数据
|
|
|
|
|
+const timeCountDown = ref(0)
|
|
|
|
|
+const timeoutFlag = ref()
|
|
|
|
|
|
|
|
-const userInfoForm = ref()
|
|
|
|
|
|
|
|
|
|
// 粒子动画初始化
|
|
// 粒子动画初始化
|
|
|
const InitParticles = () => {
|
|
const InitParticles = () => {
|
|
@@ -240,104 +239,140 @@ const InitParticles = () => {
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const phoneValidatePass = (rule,value, callback) => {
|
|
|
|
|
- if (value === '') {
|
|
|
|
|
- callback(new Error('Please input the password again'))
|
|
|
|
|
- } else {
|
|
|
|
|
- callback()
|
|
|
|
|
|
|
+
|
|
|
|
|
+// 发送验证码
|
|
|
|
|
+const sendVerificationCode = async ()=>{
|
|
|
|
|
+ let params = {
|
|
|
|
|
+ username: sendMsgInfo.value.userName,
|
|
|
|
|
+ password: sendMsgInfo.value.passWord,
|
|
|
|
|
+ mobile: formData.value.phone,
|
|
|
|
|
+ captchaId: graphCaptchaCode.id,
|
|
|
|
|
+ captchaAnswer: formData.value.captchaCode,
|
|
|
|
|
+ "userType": ""
|
|
|
|
|
+ }
|
|
|
|
|
+ let res = await sendSMSVerificationLogin(params)
|
|
|
|
|
+ if(res?.code == 200){
|
|
|
|
|
+ ElMessage.success(res.msg)
|
|
|
|
|
+ timeCountDown.value = 60
|
|
|
|
|
+ // 开始验证码倒计时
|
|
|
|
|
+ timeoutFlag.value = setInterval(()=>{
|
|
|
|
|
+ if(timeCountDown.value > 0){
|
|
|
|
|
+ console.log('倒计时进行中')
|
|
|
|
|
+ timeCountDown.value -= 1
|
|
|
|
|
+ }else{
|
|
|
|
|
+ console.log('倒计时结束')
|
|
|
|
|
+ clearInterval(timeoutFlag.value)
|
|
|
|
|
+ timeoutFlag.value = null
|
|
|
|
|
+ timeCountDown.value = 0
|
|
|
|
|
+ }
|
|
|
|
|
+ },1000)
|
|
|
|
|
+ }else{
|
|
|
|
|
+ ElMessage.warning(res.msg)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-const phoneRules = [
|
|
|
|
|
- { required:true,trigger:'blur',message:'请输入手机号'},
|
|
|
|
|
- // 动态提示
|
|
|
|
|
- { validator: phoneValidatePass, trigger: 'blur' }
|
|
|
|
|
-]
|
|
|
|
|
-onMounted(() => {
|
|
|
|
|
-// InitParticles()
|
|
|
|
|
- const storedUsername = localStorage.getItem('userName')
|
|
|
|
|
- const storedPassword = localStorage.getItem('passWord')
|
|
|
|
|
- const storedRememberMe = localStorage.getItem('rememberMe')
|
|
|
|
|
|
|
|
|
|
- if (storedRememberMe === 'true') {
|
|
|
|
|
- userName.value = storedUsername
|
|
|
|
|
- passWord.value = storedPassword
|
|
|
|
|
- remeberPassWord.value = true
|
|
|
|
|
- }
|
|
|
|
|
-})
|
|
|
|
|
|
|
|
|
|
-const HandleLoginChange = (val)=>{
|
|
|
|
|
- isStudentLogin.value = val
|
|
|
|
|
|
|
+// 重新生成图形验证码
|
|
|
|
|
+const ReplaceGraphCode = async ()=>{
|
|
|
|
|
+ let res = await replaceGraphValidateCodeApi()
|
|
|
|
|
+ if(res?.code == 200){
|
|
|
|
|
+ graphCaptchaCode.img = res.data.captchaImage
|
|
|
|
|
+ graphCaptchaCode.id = res.data.captchaId
|
|
|
|
|
+ }else{
|
|
|
|
|
+ ElMessage.warning(res.msg)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// 清空输入框
|
|
|
|
|
-const ClearInput = (event) => {
|
|
|
|
|
- userName.value = ''
|
|
|
|
|
-}
|
|
|
|
|
- const menuList = ref([])
|
|
|
|
|
|
|
+
|
|
|
// 登录提交
|
|
// 登录提交
|
|
|
const SubmitLogin = async () => {
|
|
const SubmitLogin = async () => {
|
|
|
- if(!userName.value || !passWord.value) {
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- if (remeberPassWord.value) {
|
|
|
|
|
- localStorage.setItem('userName', userName.value)
|
|
|
|
|
- localStorage.setItem('passWord', passWord.value)
|
|
|
|
|
- localStorage.setItem('rememberMe', 'true')
|
|
|
|
|
- } else {
|
|
|
|
|
- localStorage.removeItem('userName')
|
|
|
|
|
- localStorage.removeItem('passWord')
|
|
|
|
|
- localStorage.setItem('rememberMe', 'false')
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /*
|
|
|
|
|
- const params = {
|
|
|
|
|
- username: userName.value.trim(),
|
|
|
|
|
- password: encrypt(passWord.value.trim()),
|
|
|
|
|
- deviceType:'PC',
|
|
|
|
|
- }
|
|
|
|
|
- loadingLogin.value = true
|
|
|
|
|
- let res = undefined
|
|
|
|
|
- try{
|
|
|
|
|
- res = await login(params)
|
|
|
|
|
- loadingLogin.value = false
|
|
|
|
|
- if (res.code === 200) {
|
|
|
|
|
- console.log("登录成功返回",res)
|
|
|
|
|
- localStorage.setItem('token', res.data.tokenValue)
|
|
|
|
|
- menuList.value = res.data.pcMenuVOS
|
|
|
|
|
- localStorage.setItem('menuList', JSON.stringify(res.data.pcMenuVOS))
|
|
|
|
|
- localStorage.setItem('permissions', JSON.stringify(res.data.permissions))
|
|
|
|
|
-
|
|
|
|
|
- // 登录成功后调用获取用户信息接口
|
|
|
|
|
- let userInfoRes = undefined
|
|
|
|
|
- userInfoRes = await getUserInfo(res.data.token)
|
|
|
|
|
- console.log("获取用户信息返回",userInfoRes)
|
|
|
|
|
- if (userInfoRes?.code === 200) {
|
|
|
|
|
- // 存储用户信息到 localStorage 或 Pinia
|
|
|
|
|
- localStorage.setItem('userInfo', JSON.stringify(userInfoRes.data))
|
|
|
|
|
- ElMessage.success('登录成功');
|
|
|
|
|
-
|
|
|
|
|
- //根据不同的角色跳转不同的页面
|
|
|
|
|
- // 管理员跳转
|
|
|
|
|
- if(userInfoRes.data?.roleCodes?.includes('SCHOOL_MANAGER')){
|
|
|
|
|
- router.push('/main')
|
|
|
|
|
- }else{
|
|
|
|
|
- router.push('/main/personalCenter')
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ let formEl = userInfoForm.value
|
|
|
|
|
+ if (!formEl) return
|
|
|
|
|
+
|
|
|
|
|
+ await formEl.validate(async(valid) => {
|
|
|
|
|
+ if(!valid) return
|
|
|
|
|
+
|
|
|
|
|
+ let params = {
|
|
|
|
|
+ username: sendMsgInfo.value.userName,
|
|
|
|
|
+ password: sendMsgInfo.value.passWord,
|
|
|
|
|
+ mobile: formData.value.phone,
|
|
|
|
|
+ rememberMe: remeberPassWord.value,
|
|
|
|
|
+ smsCode: formData.value.phoneVerificationCode,
|
|
|
|
|
+ captchaId: graphCaptchaCode.id,
|
|
|
|
|
+ captchaAnswer: formData.value.captchaCode,
|
|
|
|
|
+ "userType": ""
|
|
|
}
|
|
}
|
|
|
- }catch(err){
|
|
|
|
|
- loadingLogin.value = false
|
|
|
|
|
- console.error(err)
|
|
|
|
|
- }
|
|
|
|
|
- */
|
|
|
|
|
|
|
+ let res = await smsCodeLoginApi(params)
|
|
|
|
|
+
|
|
|
|
|
+ // 登录失败处理
|
|
|
|
|
+ if(res?.code !== 200){
|
|
|
|
|
+ ElMessage.warning(res.msg)
|
|
|
|
|
+ formData.value.captchaCode = ''
|
|
|
|
|
|
|
|
- router.push('/main')
|
|
|
|
|
|
|
+ const {
|
|
|
|
|
+ captchaVO, //图形验证码数据
|
|
|
|
|
+ showPicCode, //是否需要图形验证码
|
|
|
|
|
+ commitCount, //当前提交次数
|
|
|
|
|
+ commitTopCount //最多提交次数
|
|
|
|
|
+ } = res?.data
|
|
|
|
|
+
|
|
|
|
|
+ showCaptchaCode.value = showPicCode
|
|
|
|
|
+ if(showPicCode){
|
|
|
|
|
+ // 需要显示 图形验证码数据
|
|
|
|
|
+ graphCaptchaCode.img = captchaVO.captchaImage
|
|
|
|
|
+ graphCaptchaCode.id = captchaVO.captchaId
|
|
|
|
|
+ }else{
|
|
|
|
|
+ graphCaptchaCode.img = ''
|
|
|
|
|
+ graphCaptchaCode.id = ''
|
|
|
|
|
+ formData.value.captchaCode = ''
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 登录成功处理
|
|
|
|
|
+ }else{
|
|
|
|
|
+ let token = res.data.tokenInfo.tokenValue
|
|
|
|
|
+ localStorage.setItem('token',token)
|
|
|
|
|
+ sessionStorage.removeItem('sendMsgInfo')
|
|
|
|
|
+
|
|
|
|
|
+ if (!(remeberPassWord.value)) {
|
|
|
|
|
+ localStorage.removeItem('userName')
|
|
|
|
|
+ localStorage.removeItem('passWord')
|
|
|
|
|
+ localStorage.setItem('rememberMe', 'false')
|
|
|
|
|
+ }
|
|
|
|
|
+ router.push('/main')
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(err=>{
|
|
|
|
|
+ console.log('报错信息',err)
|
|
|
|
|
+ })
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 去往官网
|
|
// 去往官网
|
|
|
const GoWebsite = () => {
|
|
const GoWebsite = () => {
|
|
|
window.open('https://www.k12100.com/website')
|
|
window.open('https://www.k12100.com/website')
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ // InitParticles()
|
|
|
|
|
+ let sendMsgInfoStorage = sessionStorage.getItem('sendMsgInfo')
|
|
|
|
|
+ if(!sendMsgInfoStorage){
|
|
|
|
|
+ router.replace('/phone')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ sendMsgInfo.value = JSON.parse(sendMsgInfoStorage || '{}')
|
|
|
|
|
+ formData.value.phone = sendMsgInfo.value.phone
|
|
|
|
|
+
|
|
|
|
|
+ const storedRememberMe = localStorage.getItem('rememberMe')
|
|
|
|
|
+ if (storedRememberMe === 'true') {
|
|
|
|
|
+ remeberPassWord.value = true
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+onUnmounted(()=>{
|
|
|
|
|
+ console.log('清除倒计时')
|
|
|
|
|
+ clearInterval(timeoutFlag.value)
|
|
|
|
|
+ sessionStorage.removeItem('sendMsgInfo')
|
|
|
|
|
+ timeoutFlag.value = null
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
@@ -372,6 +407,7 @@ const GoWebsite = () => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.valid_code{
|
|
.valid_code{
|
|
|
|
|
+ cursor: pointer;
|
|
|
font-size: 12px;
|
|
font-size: 12px;
|
|
|
color: #2E64FA;
|
|
color: #2E64FA;
|
|
|
}
|
|
}
|
|
@@ -431,6 +467,19 @@ const GoWebsite = () => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ .captcha_code{
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ gap:10px;
|
|
|
|
|
+ img{
|
|
|
|
|
+ height: 48px;
|
|
|
|
|
+ width: calc(50% - 10px);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|