学生微信登录等

dev_202412
yujialong 4 months ago
parent 5638089fc9
commit 54ef52797e
  1. 1
      src/api/index.js
  2. BIN
      src/assets/img/exts/excel.png
  3. 1
      src/assets/img/wechat.svg
  4. 33
      src/pages/account/login/index.vue
  5. 289
      src/pages/account/redirect/index.vue
  6. 2
      src/pages/station/preview/index.vue
  7. 8
      src/router/routes.js
  8. 2
      src/setting.js

@ -33,6 +33,7 @@ export default {
updateRealSchoolId: `competition/competition/registration/updateRealSchoolId`, updateRealSchoolId: `competition/competition/registration/updateRealSchoolId`,
checkUserNameOrWorkNumber: `users/users/batchProcessing/checkUserNameOrWorkNumber`, checkUserNameOrWorkNumber: `users/users/batchProcessing/checkUserNameOrWorkNumber`,
updateUserNameOrWorkNumber: `users/users/batchProcessing/updateUserNameOrWorkNumber`, updateUserNameOrWorkNumber: `users/users/batchProcessing/updateUserNameOrWorkNumber`,
loginByUnionid: `users/loginByUnionid`,
// 阿里云文件/视频管理 // 阿里云文件/视频管理
getPlayAuth: `nakadai/nakadai/oss/getPlayAuth`, // 获取播放凭证 getPlayAuth: `nakadai/nakadai/oss/getPlayAuth`, // 获取播放凭证

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1733123764466" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5187" width="20" height="20" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M683.058 364.695c11 0 22 1.016 32.943 1.976C686.564 230.064 538.896 128 370.681 128c-188.104 0.66-342.237 127.793-342.237 289.226 0 93.068 51.379 169.827 136.725 229.256L130.72 748.43l119.796-59.368c42.918 8.395 77.37 16.79 119.742 16.79 11 0 21.46-0.48 31.914-1.442a259.168 259.168 0 0 1-10.455-71.358c0.485-148.002 128.744-268.297 291.403-268.297l-0.06-0.06z m-184.113-91.992c25.99 0 42.913 16.79 42.913 42.575 0 25.188-16.923 42.579-42.913 42.579-25.45 0-51.38-16.85-51.38-42.58 0-25.784 25.93-42.574 51.38-42.574z m-239.544 85.154c-25.384 0-51.374-16.85-51.374-42.58 0-25.784 25.99-42.574 51.374-42.574 25.45 0 42.918 16.79 42.918 42.575 0 25.188-16.924 42.579-42.918 42.579z m736.155 271.655c0-135.647-136.725-246.527-290.983-246.527-162.655 0-290.918 110.88-290.918 246.527 0 136.128 128.263 246.587 290.918 246.587 33.972 0 68.423-8.395 102.818-16.85l93.809 50.973-25.93-84.677c68.907-51.93 120.286-119.815 120.286-196.033z m-385.275-42.58c-16.923 0-34.452-16.79-34.452-34.179 0-16.79 17.529-34.18 34.452-34.18 25.99 0 42.918 16.85 42.918 34.18 0 17.39-16.928 34.18-42.918 34.18z m188.165 0c-16.984 0-33.972-16.79-33.972-34.179 0-16.79 16.927-34.18 33.972-34.18 25.93 0 42.913 16.85 42.913 34.18 0 17.39-16.983 34.18-42.913 34.18z" fill="#09BB07" p-id="5188"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -67,6 +67,11 @@
<!-- 未登录的赛事点击报名进入后的注册 --> <!-- 未登录的赛事点击报名进入后的注册 -->
<el-link v-else-if="toMatch" :underline="false" type="primary" <el-link v-else-if="toMatch" :underline="false" type="primary"
@click="accountApplyVisible = true">暂无账号点击申请</el-link> @click="accountApplyVisible = true">暂无账号点击申请</el-link>
<div class="wechat" @click="toWechat">
<img class="icon" src="@/assets/img/wechat.svg" alt="">
<span>学生微信登录</span>
</div>
</div> </div>
<el-button class="submit" type="primary" @click="submit">登录</el-button> <el-button class="submit" type="primary" @click="submit">登录</el-button>
</el-form> </el-form>
@ -298,6 +303,8 @@ export default {
rePassword: [{ required: true, message: "请再次输入密码", trigger: "blur" }], rePassword: [{ required: true, message: "请再次输入密码", trigger: "blur" }],
code: [{ required: true, message: "请输入验证码", trigger: "blur" }] code: [{ required: true, message: "请输入验证码", trigger: "blur" }]
}, },
qrcode: '',
}; };
}, },
computed: { computed: {
@ -311,6 +318,7 @@ export default {
mounted () { mounted () {
localStorage.removeItem('opened') localStorage.removeItem('opened')
this.getVerImg() this.getVerImg()
this.getQr()
// //
this.$once("hook:beforeDestroy", function () { this.$once("hook:beforeDestroy", function () {
clearInterval(this.phoneTimer) clearInterval(this.phoneTimer)
@ -330,6 +338,11 @@ export default {
this.form.random = Math.floor(Math.random() * 999999999); this.form.random = Math.floor(Math.random() * 999999999);
this.verificationIMG = this.api.verification + "?random=" + `${this.form.random}`; this.verificationIMG = this.api.verification + "?random=" + `${this.form.random}`;
}, },
//
async getQr () {
const res = await this.$get(`https://edu.occupationlab.com/users/getQRCodeUrl`)
this.qrcode = res.message
},
// //
handleRule () { handleRule () {
this.rules.account[0].message = this.verCodeLogin ? this.rules.account[0].message = this.verCodeLogin ?
@ -559,6 +572,11 @@ export default {
Util.successMsg(message) Util.successMsg(message)
this.phoneCountdown() this.phoneCountdown()
}, },
//
toWechat () {
// window.open(this.qrcode)
location.href = this.qrcode
},
// //
toAccount () { toAccount () {
@ -899,10 +917,23 @@ export default {
color: #ffa94e; color: #ffa94e;
} }
.wechat {
display: flex;
align-items: center;
margin-top: 5px;
font-size: 14px;
color: #333;
cursor: pointer;
.icon {
margin-right: 5px;
}
}
.submit { .submit {
width: 100%; width: 100%;
height: 48px; height: 48px;
margin-top: 30px; margin-top: 20px;
line-height: 48px; line-height: 48px;
padding: 0; padding: 0;
font-size: 20px; font-size: 20px;

@ -0,0 +1,289 @@
<template>
<div>
<!-- 多个账号 -->
<el-dialog title="请选择您要登录的用户" :visible.sync="userVisible" :close-on-click-modal="false" :show-close="false"
custom-class="user-dia" width="500px">
<p class="tips">已为你展示该微信关联的账号</p>
<ul class="users">
<li :class="{ isEnable: !user.isEnable }" v-for="(user, i) in users" :key="i" @click="chooseUser(user)">
<span>{{ user.typeName }}{{ user.schoolName }}{{ user.userName }}{{ user.workNumber }}{{
user.isEnable
? ''
: '(已禁用)' }}</span>
<i class="el-icon-right"></i>
</li>
</ul>
</el-dialog>
<!-- 新用户 -->
<el-dialog title="" :visible.sync="newVisible" :close-on-click-modal="false" :show-close="false"
custom-class="new-dia" width="400px">
<el-form v-if="addAccount" :model="form" :rules="rules" ref="form">
<h2 class="bind-tips">绑定账号</h2>
<el-form-item class="flex-1" prop="account">
<label class="label account"></label>
<el-input v-model.trim="form.account" placeholder="请输入账号" autocomplete="new-password"
@keyup.enter.native="bindSubmit"></el-input>
</el-form-item>
<el-form-item class="relative" prop="password">
<label class="password label"></label>
<el-input type="password" placeholder="请输入密码" v-model.trim="form.password" autocomplete="new-password"
@keyup.enter.native="bindSubmit" />
</el-form-item>
<el-button class="submit" type="primary" @click="bindSubmit">绑定</el-button>
</el-form>
<div v-else>
<p class="suc">微信授权成功</p>
<i class="el-icon-success icon"></i>
<p class="tips">您的微信暂时没有已绑定的账号</p>
<p class="bind">
<el-link :underline="false" type="primary" @click="addAccount = true">绑定已有学生账号</el-link>
</p>
<el-link :underline="false" type="primary" @click="toLogin">返回账号登录</el-link>
</div>
</el-dialog>
</div>
</template>
<script>
import { mapActions, mapMutations } from 'vuex'
import Util from '@/libs/util'
import Setting from '@/setting'
import CryptoJS from 'crypto-js'
import JSEncrypt from 'jsencrypt'
export default {
data: function () {
return {
token: this.$route.query.token || '',
unionid: this.$route.query.unionid,
curUser: {},
userVisible: false,
users: [],
newVisible: true,
addAccount: false,
form: {
account: '',
password: '',
},
rules: {
account: [{ required: true, message: "请输入账号", trigger: "blur" }],
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
},
};
},
mounted () {
localStorage.removeItem('opened')
// this.setLogin()
},
methods: {
async setLogin () {
const res = await this.$post(this.api.loginByUnionid)
return
Util.local.set(Setting.tokenKey, this.token, Setting.tokenExpires)
this.getOss()
Util.cookies.remove('serverLogin')
this.reloadIndex()
Util.successMsg('登录成功')
},
//
reloadIndex () {
try {
window.opener && window.opener.location.reload()
} catch (e) { }
},
//
toLogin () {
this.$router.replace('/login')
},
//
bindSubmit () {
this.$refs.form.validate(valid => {
if (valid) {
const form = JSON.parse(JSON.stringify(this.form))
if (this.verCodeLogin) form.distinguish = 2
this.$post(this.api.logins, form).then(({ status, data, message }) => {
//
if (status == 30001) {
this.phoneVisible = true
this.getVerImg()
form.code = ''
} else if (status == 200) {
const accounts = data.userAccounts
//
if (accounts instanceof Array) {
this.users = accounts
this.userVisible = true
} else {
this.token = data.token
//
if (data.customer) {
Util.cookies.set('customerName', data.customerName)
this.SET_CUSTOMERNAME(data.customerName)
this.selectVisible = true
} else {
data.typeName === '学生端' ? this.setLogin() : this.toMang()
}
}
} else {
form.code = ''
Util.errorMsg(message)
}
}).catch(res => {
form.code = ''
this.getVerImg()
})
}
});
},
async getOss () {
const A = (key, encryptedData) => {
const keyHex = CryptoJS.enc.Base64.parse(key)
const decrypted = CryptoJS.AES.decrypt(encryptedData, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
return decrypted.toString(CryptoJS.enc.Utf8)
}
const R = (encryptedKey, privateKey) => {
const decrypt = new JSEncrypt()
decrypt.setPrivateKey(privateKey)
const decryptedKey = decrypt.decrypt(encryptedKey)
return decryptedKey
}
const res = await this.$get(this.api.encrypt)
const RE = A(R(res.encryptedKey, res.privateKey), res.encryptedData).split('/')
localStorage.setItem('osc', JSON.stringify(RE))
},
}
};
</script>
<style lang="scss" scoped>
/deep/.user-dia {
.tips {
margin-bottom: 20px;
text-align: center;
color: #666;
}
.users {
li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 15px;
margin-bottom: 10px;
line-height: 40px;
font-size: 14px;
background-color: #ebeef5;
cursor: pointer;
&.isEnable {
color: #c0c4cc;
background-color: #f5f7fa;
cursor: not-allowed;
}
&:last-child {
margin-bottom: 0;
}
&:hover {
background-color: #d3e0ff;
}
i {
font-size: 16px;
}
}
}
}
/deep/.new-dia {
text-align: center;
.el-dialog__header {
display: none;
}
.suc {
font-size: 16px;
font-weight: 600;
color: #333;
}
.icon {
margin: 30px 0;
font-size: 50px;
color: #52c41a;
}
.tips {
color: #8f8f8f;
}
.bind {
margin: 30px 0 10px;
}
.bind-tips {
margin-bottom: 20px;
font-size: 20px;
font-weight: 600;
color: #333;
text-align: left;
}
.el-form-item {
margin-bottom: 20px;
}
.el-input__inner {
position: relative;
height: 40px;
padding: 0 20px 0 34px;
line-height: 40px;
background-color: #fbfbfb;
border-color: #e1e6f2;
border-radius: 4px !important;
&:focus {
border-color: $main-color;
box-shadow: 0 0 2px #4486e9;
}
}
.label {
z-index: 1;
position: absolute;
top: 11px;
left: 11px;
width: 18px;
height: 18px;
background: url(../../../assets/img/login/account.png) 0 0/100% 100% no-repeat;
}
.password {
background-image: url(../../../assets/img/login/password.png);
}
.submit {
width: 100%;
height: 40px;
margin-top: 20px;
line-height: 40px;
padding: 0;
font-size: 16px;
background-color: $main-color;
border-radius: 4px;
border: 0;
}
}
</style>

@ -76,6 +76,8 @@
<img v-else-if="section.fileType === 'mp4'" src="@/assets/img/exts/video.png" alt=""> <img v-else-if="section.fileType === 'mp4'" src="@/assets/img/exts/video.png" alt="">
<img v-else-if="section.fileType === 'doc' || section.fileType === 'docx'" <img v-else-if="section.fileType === 'doc' || section.fileType === 'docx'"
src="@/assets/img/exts/word.png" alt=""> src="@/assets/img/exts/word.png" alt="">
<img v-else-if="section.fileType === 'xlsx' || section.fileType === 'xls'"
src="@/assets/img/exts/excel.png" alt="">
<img v-else-if="section.fileType === 'txt'" src="@/assets/img/exts/txt.png" alt=""> <img v-else-if="section.fileType === 'txt'" src="@/assets/img/exts/txt.png" alt="">
<img v-else-if="section.fileType === 'pdf'" src="@/assets/img/exts/pdf.png" alt=""> <img v-else-if="section.fileType === 'pdf'" src="@/assets/img/exts/pdf.png" alt="">
<img v-else src="@/assets/img/exts/pic.png" alt=""> <img v-else src="@/assets/img/exts/pic.png" alt="">

@ -28,6 +28,14 @@ const frameOut = [
}, },
component: () => import("@/pages/account/login") component: () => import("@/pages/account/login")
}, },
{
path: "/redirect",
name: "redirect",
meta: {
title: "登录"
},
component: () => import("@/pages/account/redirect")
},
{ {
path: '/join', path: '/join',
component: () => import('@/pages/join'), component: () => import('@/pages/join'),

@ -67,7 +67,7 @@ const Setting = {
/** /**
* 路由白名单 * 路由白名单
* */ * */
whiteList: ['/login', '/index/list', '/index/zxy', '/product/list', '/cityPartner/list', '/devPlatform/list', '/log/list', '/touristMatch/list', '/touristMatch/details', '/touristMatch/noticeDetail', '/preCourse/list', '/preCourse/details', '/preInfo/list', '/preInfo/details', '/screen', '/screenShow', '/screenShowPro', '/join', '/join/success'], whiteList: ['/login', '/redirect', '/index/list', '/index/zxy', '/product/list', '/cityPartner/list', '/devPlatform/list', '/log/list', '/touristMatch/list', '/touristMatch/details', '/touristMatch/noticeDetail', '/preCourse/list', '/preCourse/details', '/preInfo/list', '/preInfo/details', '/screen', '/screenShow', '/screenShowPro', '/join', '/join/success'],
/** /**
* 平台列表 * 平台列表
* */ * */

Loading…
Cancel
Save