From 54ef52797ea21cc61a372b14e4b1912ae8a87e43 Mon Sep 17 00:00:00 2001 From: yujialong <479214531@qq.com> Date: Tue, 3 Dec 2024 17:49:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AD=A6=E7=94=9F=E5=BE=AE=E4=BF=A1=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/index.js | 1 + src/assets/img/exts/excel.png | Bin 0 -> 432 bytes src/assets/img/wechat.svg | 1 + src/pages/account/login/index.vue | 33 ++- src/pages/account/redirect/index.vue | 289 +++++++++++++++++++++++++++ src/pages/station/preview/index.vue | 2 + src/router/routes.js | 8 + src/setting.js | 2 +- 8 files changed, 334 insertions(+), 2 deletions(-) create mode 100644 src/assets/img/exts/excel.png create mode 100644 src/assets/img/wechat.svg create mode 100644 src/pages/account/redirect/index.vue diff --git a/src/api/index.js b/src/api/index.js index 30efd85..0f5ff99 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -33,6 +33,7 @@ export default { updateRealSchoolId: `competition/competition/registration/updateRealSchoolId`, checkUserNameOrWorkNumber: `users/users/batchProcessing/checkUserNameOrWorkNumber`, updateUserNameOrWorkNumber: `users/users/batchProcessing/updateUserNameOrWorkNumber`, + loginByUnionid: `users/loginByUnionid`, // 阿里云文件/视频管理 getPlayAuth: `nakadai/nakadai/oss/getPlayAuth`, // 获取播放凭证 diff --git a/src/assets/img/exts/excel.png b/src/assets/img/exts/excel.png new file mode 100644 index 0000000000000000000000000000000000000000..6e0482e63d8a90242328abfe200e5853b6e3a72b GIT binary patch literal 432 zcmV;h0Z;ykP)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B00001b5ch_0Itp) z=>Px$YDq*vR5(v#WPpLaWwRI<7*gSUEDTW<`8TiSvqiC~VFU~AE$e4sU?{+62uMy? zNrr)ek@4wUg<KhQwJ?L;GB7X*5n~V=Hy6XNZ{INtgBf(6fq_ARkU>HU(hTgp++bzs zhLL0t8xI$Qup+`&$cB+*5XdELTpSEsLIQBdGqEr~e5ahRK(awty#Ii~xl3^f7-Y#W z&#+J{jN!_c7YrenmoRt=t25-w+Az3Xn8WbYx*F`W!rPk}R=v6e^Cfn#feh+Y_GDP} z;vB=AXQvnr8)q`CeRY{Zl$D#|-JkCa$38v;8*m&-GcYjVHmFkGk-_iM0tOytc7~k> z$qaYDzhyZ8`6+`Ohakg~pC1|iGyG@hdvutvi@H?27+(MS$`F2KDT6+*BtwFP2}9?@ z{R}5ea=@CUkG3L5-XM=PqB1Rxy!ej6xl5R&Vg!dl6BwMk3LyqT$|QmX8y16RGdOpp afy4pgN|h7m@wLPN0000<MNUMnLSTXj8MDX$ literal 0 HcmV?d00001 diff --git a/src/assets/img/wechat.svg b/src/assets/img/wechat.svg new file mode 100644 index 0000000..583d4f8 --- /dev/null +++ b/src/assets/img/wechat.svg @@ -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> \ No newline at end of file diff --git a/src/pages/account/login/index.vue b/src/pages/account/login/index.vue index b767773..e53364a 100644 --- a/src/pages/account/login/index.vue +++ b/src/pages/account/login/index.vue @@ -67,6 +67,11 @@ <!-- 未登录的赛事点击报名进入后的注册 --> <el-link v-else-if="toMatch" :underline="false" type="primary" @click="accountApplyVisible = true">暂无账号?点击申请</el-link> + + <div class="wechat" @click="toWechat"> + <img class="icon" src="@/assets/img/wechat.svg" alt=""> + <span>学生微信登录</span> + </div> </div> <el-button class="submit" type="primary" @click="submit">登录</el-button> </el-form> @@ -298,6 +303,8 @@ export default { rePassword: [{ required: true, message: "请再次输入密码", trigger: "blur" }], code: [{ required: true, message: "请输入验证码", trigger: "blur" }] }, + + qrcode: '', }; }, computed: { @@ -311,6 +318,7 @@ export default { mounted () { localStorage.removeItem('opened') this.getVerImg() + this.getQr() // 页面离开的时候销毁手机和邮箱验证码定时器 this.$once("hook:beforeDestroy", function () { clearInterval(this.phoneTimer) @@ -330,6 +338,11 @@ export default { this.form.random = Math.floor(Math.random() * 999999999); 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 () { this.rules.account[0].message = this.verCodeLogin ? @@ -559,6 +572,11 @@ export default { Util.successMsg(message) this.phoneCountdown() }, + // 微信登录 + toWechat () { + // window.open(this.qrcode) + location.href = this.qrcode + }, // 账号申请 toAccount () { @@ -899,10 +917,23 @@ export default { color: #ffa94e; } + .wechat { + display: flex; + align-items: center; + margin-top: 5px; + font-size: 14px; + color: #333; + cursor: pointer; + + .icon { + margin-right: 5px; + } + } + .submit { width: 100%; height: 48px; - margin-top: 30px; + margin-top: 20px; line-height: 48px; padding: 0; font-size: 20px; diff --git a/src/pages/account/redirect/index.vue b/src/pages/account/redirect/index.vue new file mode 100644 index 0000000..db7e015 --- /dev/null +++ b/src/pages/account/redirect/index.vue @@ -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> \ No newline at end of file diff --git a/src/pages/station/preview/index.vue b/src/pages/station/preview/index.vue index 38f84c5..20a485e 100644 --- a/src/pages/station/preview/index.vue +++ b/src/pages/station/preview/index.vue @@ -76,6 +76,8 @@ <img v-else-if="section.fileType === 'mp4'" src="@/assets/img/exts/video.png" alt=""> <img v-else-if="section.fileType === 'doc' || section.fileType === 'docx'" 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 === 'pdf'" src="@/assets/img/exts/pdf.png" alt=""> <img v-else src="@/assets/img/exts/pic.png" alt=""> diff --git a/src/router/routes.js b/src/router/routes.js index 366924a..980457b 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -28,6 +28,14 @@ const frameOut = [ }, component: () => import("@/pages/account/login") }, + { + path: "/redirect", + name: "redirect", + meta: { + title: "登录" + }, + component: () => import("@/pages/account/redirect") + }, { path: '/join', component: () => import('@/pages/join'), diff --git a/src/setting.js b/src/setting.js index 7828a39..7107741 100644 --- a/src/setting.js +++ b/src/setting.js @@ -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'], /** * 平台列表 * */