严飞永 1 month ago
parent a6049d585e
commit d2a44e5fb3

@ -26,76 +26,54 @@ router.beforeEach((to, from, next) => {
NProgress.start() NProgress.start()
//政务登录 const { userToken, signature, timespan } = to.query
const url = window.location.href console.log(userToken, signature, timespan, '参数')
// 检查是否包含政务平台返回的关键参数
const hasUserToken = url.includes('userToken=') if (userToken && signature && timespan) {
const hasSignature = url.includes('signature=') // 政务登录
const hasTimespan = url.includes('timespan=') governmentGetInfo({
userToken,
if (hasUserToken && hasSignature && hasTimespan) { signature,
const regUserToken = /[?&]userToken=([^&#]+)/ timespan
const regSignature = /[?&]signature=([^&#]+)/ }).then(res => {
const regTimespan = /[?&]timespan=([^&#]+)/ const token = res.token
if (token) {
const userTokenMatch = url.match(regUserToken) setToken(token)
const signatureMatch = url.match(regSignature) localStorage.setItem('otherToken', userToken)
const timespanMatch = url.match(regTimespan)
const newQuery = { ...to.query }
const userToken = userTokenMatch ? userTokenMatch[1] : null delete newQuery.userToken
const signature = signatureMatch ? signatureMatch[1] : null delete newQuery.signature
const timespan = timespanMatch ? timespanMatch[1] : null delete newQuery.timespan
const newPath = to.path + '?' + new URLSearchParams(newQuery).toString()
if (userToken && signature && timespan) { window.history.replaceState({}, '', newPath)
// 调用政务系统登录接口
governmentGetInfo({ if (store.getters.roles.length === 0) {
userToken, isRelogin.show = true
signature, store.dispatch('GetInfo').then(() => {
timespan isRelogin.show = false
}).then(res => { store.dispatch('GenerateRoutes').then(accessRoutes => {
const token = res.token router.addRoutes(accessRoutes)
if (token) { next({ ...to, replace: true })
setToken(token) })
localStorage.setItem('otherToken', userToken) }).catch(err => {
store.dispatch('LogOut').then(() => {
const cleanUrl = url Message.error(err)
.replace(regUserToken, '') next({ path: '/' })
.replace(regSignature, '') })
.replace(regTimespan, '') })
.replace(/^&/, '?') } else {
next()
window.history.replaceState({}, '', cleanUrl) }
// 继续路由守卫流程
if (store.getters.roles.length === 0) {
isRelogin.show = true
store.dispatch('GetInfo').then(() => {
isRelogin.show = false
store.dispatch('GenerateRoutes').then(accessRoutes => {
router.addRoutes(accessRoutes)
next({ ...to, replace: true })
})
}).catch(err => {
store.dispatch('LogOut').then(() => {
Message.error(err)
next({ path: '/' })
})
})
} else {
next()
}
}
}).catch(err => {
console.error('政务系统登录失败:', err)
Message.error('政务系统登录失败,请重新登录')
})
} else {
Message.error('缺少必要的登录参数')
next(`/login?redirect=${encodeURIComponent(to.fullPath)}`)
} }
return }).catch(err => {
} console.error('政务系统登录失败:', err)
Message.error('政务系统登录失败,请重新登录')
})
return
}

@ -43,7 +43,10 @@ export const constantRoutes = [
}, },
{ {
path: "/login", path: "/login",
component: () => import("@/views/login"), // 正式环境登录页
// component: () => import("@/views/login"),
// 测试
component: () => import("@/views/login_v1"),
hidden: true, hidden: true,
}, },
{ {
@ -77,7 +80,7 @@ export const constantRoutes = [
component: () => import("@/views/index"), component: () => import("@/views/index"),
name: "Index", name: "Index",
meta: { title: "角色判断", icon: "icon-tjfx-1" }, meta: { title: "角色判断", icon: "icon-tjfx-1" },
hidden:true hidden: true,
}, },
{ {
path: "/user", path: "/user",

@ -203,7 +203,7 @@ export default {
window.location.href = 'https://qyt.sipac.gov.cn/sipsg-enterprise-mobile-manage/#/login' window.location.href = 'https://qyt.sipac.gov.cn/sipsg-enterprise-mobile-manage/#/login'
}, },
handleEnterpriseLogin() { handleEnterpriseLogin() {
window.location.href = 'https://gysl.sipac.gov.cn'; // window.location.href = 'https://gysl.sipac.gov.cn';
} }
} }
} }

@ -1,335 +1,356 @@
<template> <template>
<div class="login"> <div class="login">
<div class="loginleft"> <div class="loginleft">
</div>
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<img src="@/assets/images/logo@2x.png" alt="">
<div class="title">苏州工业园区工业上楼管理系统</div>
<div class="logintabs">
<el-tabs v-model="activeName" :stretch="true" color="#216CDC">
<el-tab-pane label="企业用户登录" name="first"></el-tab-pane>
<el-tab-pane label="政务人员登录" name="second"></el-tab-pane>
</el-tabs>
</div> </div>
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form"> <el-form-item prop="username" class="loginitem" style="margin-top: 1rem;">
<img src="@/assets/images/logo@2x.png" alt=""> <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
<div class="title">苏州工业园区工业上楼管理系统</div> <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
<div class="logintabs"> </el-input>
<el-tabs v-model="activeName" :stretch="true" color="#216CDC"> </el-form-item>
<el-tab-pane label="企业用户登录" name="first"></el-tab-pane> <el-form-item prop="password" class="loginitem">
<el-tab-pane label="政务人员登录" name="second"></el-tab-pane> <el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码"
</el-tabs> @keyup.enter.native="handleLogin">
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled" class="loginitem">
<el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码" style="width: 63%"
@keyup.enter.native="handleLogin">
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img" style="width: 8.56rem;" />
</div> </div>
<el-form-item prop="username" class="loginitem" style="margin-top: 1rem;"> </el-form-item>
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号"> <el-checkbox v-model="loginForm.rememberMe" style="margin:1rem 18.6rem 25px 0px;"></el-checkbox>
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" /> <el-form-item style="width:24rem;;margin-top: 1rem;">
</el-input> <el-button :loading="loading" size="medium" type="primary" style="width:100%;background: #2B62F1;"
</el-form-item> @click.native.prevent="handleLogin">
<el-form-item prop="password" class="loginitem"> <span v-if="!loading"> </span>
<el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码" <span v-else> ...</span>
@keyup.enter.native="handleLogin"> </el-button>
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" /> <el-button v-if="showGovernmentLoginButton" size="medium" type="primary" class="tongyidenglu"
</el-input> style="width:100%;background: #2B62F1;" @click.native.prevent="handleGovernmentLogin">
</el-form-item> <span>政务统一身份认证登录</span>
<el-form-item prop="code" v-if="captchaEnabled" class="loginitem"> </el-button>
<el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" <el-button v-if="showEnterpriseLoginButton" size="medium" type="primary" class="tongyidenglu"
@keyup.enter.native="handleLogin"> style="width:100%;background: #2B62F1;" @click.native.prevent="handleEnterpriseLogin">
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" /> <span>企业统一身份认证登录</span>
</el-input> </el-button>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img" style="width: 8.56rem;" />
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:1rem 18.6rem 25px 0px;"></el-checkbox>
<el-form-item style="width:24rem;;margin-top: 1rem;">
<el-button :loading="loading" size="medium" type="primary" style="width:100%;background: #2B62F1;"
@click.native.prevent="handleLogin">
<span v-if="!loading"> </span>
<span v-else> ...</span>
</el-button>
<el-button v-if="showGovernmentLoginButton" size="medium" type="primary" class="tongyidenglu"
style="width:100%;background: #2B62F1;" @click.native.prevent="handleGovernmentLogin">
<span>政务统一身份认证登录</span>
</el-button>
<el-button v-if="showEnterpriseLoginButton" size="medium" type="primary" class="tongyidenglu"
style="width:100%;background: #2B62F1;" @click.native.prevent="handleEnterpriseLogin">
<span>企业统一身份认证登录</span>
</el-button>
</el-form-item> </el-form-item>
<div style="font-size: 0.88rem;color: #333;">主办单位苏州工业园区经济发展委员会</div> <div style="font-size: 0.88rem;color: #333;">主办单位苏州工业园区经济发展委员会</div>
</el-form> </el-form>
<!-- 底部 --> <!-- 底部 -->
<div class="el-login-footer"> <div class="el-login-footer">
<span></span> <span></span>
</div>
</div> </div>
</template> </div>
</template>
<script> <script>
import { getCodeImg } from '@/api/login' import { getCodeImg } from '@/api/login'
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import { encrypt, decrypt } from '@/utils/jsencrypt' import { encrypt, decrypt } from '@/utils/jsencrypt'
import forge from 'node-forge'
export default {
export default { name: 'Login',
name: 'Login', data() {
data() { return {
return { codeUrl: '',
codeUrl: '', activeName: 'second',
activeName: 'second', loginForm: {
loginForm: { username: '',
username: '', password: '',
password: '', rememberMe: false,
rememberMe: false, code: '',
code: '', uuid: '',
uuid: '', loginRole: 2
loginRole: 2 },
}, loginRules: {
loginRules: { username: [
username: [ { required: true, trigger: 'blur', message: '请输入您的账号' }
{ required: true, trigger: 'blur', message: '请输入您的账号' } ],
], password: [
password: [ { required: true, trigger: 'blur', message: '请输入您的密码' }
{ required: true, trigger: 'blur', message: '请输入您的密码' } ],
], code: [{ required: true, trigger: 'change', message: '请输入验证码' }]
code: [{ required: true, trigger: 'change', message: '请输入验证码' }] },
}, loading: false,
loading: false, captchaEnabled: true,
// register: false,
captchaEnabled: true, redirect: undefined,
// a1: `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl8bS1kYTiMhIS5MZU253bc0ukaxrA1lfCziABFxQrC2c09tMrQGjuH6V1x2ofNBMGhOD9uWN/qkAQy/HwOe/NKUqCw6N0ov6guSrqMDW/BdZ3Bl0rmM1/95jTC1xffFFvej7xWNffIbaPI+bJ4WLX9NViNi9HmT0BRNzJ4d2R86LPPCa+bxLaPjsh2R2tBkbLkUot9769aJaPPiwPCZHMkuQenjHSmpWL0okleqMH8EGX7j6A5A/4IUXPMNKMMzkiSRpsIJ65GJmDAbnR3ZXRfC8MzVBBJB6zr5N0F4N9xZfF+JS/Yx726tCu+rA6GDCyTxtQ/wnKpPdwFP5nUWCWQIDAQAB`
register: false, }
redirect: undefined },
watch: {
$route: {
handler: function (route) {
this.redirect = route.query && route.query.redirect;
},
immediate: true
},
activeName(newVal) {
if (newVal === 'first') {
this.loginForm.loginRole = 2
} else if (newVal === 'second') {
this.loginForm.loginRole = 1
} }
}
},
computed: {
showGovernmentLoginButton() {
return this.activeName === 'second'
}, },
watch: { showEnterpriseLoginButton() {
$route(route) { return this.activeName === 'first'
this.redirect = route.query && route.query.redirect }
}, },
activeName(newVal) { created() {
if (newVal === 'first') { this.getCode()
this.loginForm.loginRole = 2; this.getCookie()
} else if (newVal === 'second') { },
this.loginForm.loginRole = 1; methods: {
getCode() {
getCodeImg().then(res => {
this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled;
if (this.captchaEnabled) {
this.codeUrl = "data:image/gif;base64," + res.img;
this.loginForm.uuid = res.uuid;
} }
} });
}, },
computed: { getCookie() {
showGovernmentLoginButton() { const username = Cookies.get('username')
return this.activeName === 'second'; const password = Cookies.get('password')
}, const rememberMe = Cookies.get('rememberMe')
showEnterpriseLoginButton() { this.loginForm = {
return this.activeName === 'first'; username: username === undefined ? this.loginForm.username : username,
password: password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
} }
}, },
created() { handleLogin() {
this.getCode() this.$refs.loginForm.validate(valid => {
this.getCookie()
}, if (valid) {
methods: { this.loading = true;
getCode() { if (this.loginForm.rememberMe) {
getCodeImg().then((res) => { Cookies.set("username", this.loginForm.username, { expires: 30 });
this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
if (this.captchaEnabled) { Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
this.codeUrl = `data:image/gif;base64,${res.img}` } else {
this.loginForm.uuid = res.uuid Cookies.remove("username");
Cookies.remove("password");
Cookies.remove('rememberMe');
} }
}).catch((error) => { // 2048 RSA
console.error('获取验证码失败:', error) const lines = [];
}) lines.push('-----BEGIN PUBLIC KEY-----');
}, for (let i = 0; i < this.a1.length; i += 64) {
getCookie() { lines.push(this.a1.slice(i, i + 64));
const username = Cookies.get('username') }
const password = Cookies.get('password') lines.push('-----END PUBLIC KEY-----');
const rememberMe = Cookies.get('rememberMe') lines.join('\n')
this.loginForm = { const publicKey = forge.pki.publicKeyFromPem(lines.join('\n'));
username: username === undefined ? this.loginForm.username : username, //
password: password === undefined ? this.loginForm.password : decrypt(password), var dataBytes = forge.util.encodeUtf8(this.loginForm.password);
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe) //
} var encryptedBytes = publicKey.encrypt(dataBytes, 'RSA-OAEP', {
}, md: forge.md.sha256.create(),
handleLogin() { mgf1: {
this.$refs.loginForm.validate((valid) => { md: forge.md.sha1.create()
if (valid) {
this.loading = true;
if (this.loginForm.rememberMe) {
Cookies.set('username', this.loginForm.username, { expires: 30 });
Cookies.set('password', encrypt(this.loginForm.password), { expires: 30 });
Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
} else {
Cookies.remove('username');
Cookies.remove('password');
Cookies.remove('rememberMe');
} }
});
// Base64
var encryptedBase64 = forge.util.encode64(encryptedBytes);
const loginData = { //
username: this.loginForm.username, const loginData = {
password: this.loginForm.password, username: this.loginForm.username,
code: this.loginForm.code, password: encryptedBase64,
uuid: this.loginForm.uuid, code: this.loginForm.code,
loginRole: this.activeName === 'first' ? 2 : 1 uuid: this.loginForm.uuid,
}; loginRole: this.activeName === 'first' ? 2 : 1
};
this.$store.dispatch('Login', loginData) this.$store.dispatch('Login', loginData)
.then(() => { .then(() => {
this.$router.push({ path: this.redirect || '/' }).catch(() => { }); this.$router.push({ path: this.redirect || '/' }).catch(() => { });
}) })
.catch((error) => { .catch((error) => {
this.loading = false; this.loading = false;
if (this.captchaEnabled) { if (this.captchaEnabled) {
this.getCode(); this.getCode();
} }
console.error('登录失败:', error); console.error('登录失败:', error);
}); });
}
});
},
handleGovernmentLogin() {
//
window.location.href = 'https://qyt.sipac.gov.cn/';
},
handleEnterpriseLogin() {
//
// window.location.href = 'https://example.com/enterprise-login';
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped> }
::v-deep .el-tabs__active-bar { });
width: 2rem !important; },
margin-left: 3rem; handleGovernmentLogin() {
background-color: #216CDC; window.location.href = 'https://qyt.sipac.gov.cn/sipsg-enterprise-mobile-manage/#/login'
height: 0.21rem; },
border-radius: 0.16rem; handleEnterpriseLogin() {
window.location.href = 'https://gysl.sipac.gov.cn';
}
} }
}
</script>
::v-deep .el-tabs__header { <style rel="stylesheet/scss" lang="scss" scoped>
border-bottom: none !important; ::v-deep .el-tabs__active-bar {
} width: 2rem !important;
margin-left: 3rem;
background-color: #216CDC;
height: 0.21rem;
border-radius: 0.16rem;
}
::v-deep .el-tabs__item { ::v-deep .el-tabs__header {
font-size: 1rem; border-bottom: none !important;
padding: 0 20px; }
color: #3D424C;
font-family: Alibaba PuHuiTi;
font-weight: 400;
color: #3D424C;
}
::v-deep .el-tabs__item.is-active { ::v-deep .el-tabs__item {
color: #216CDC; font-size: 1rem;
} padding: 0 20px;
color: #3D424C;
font-family: Alibaba PuHuiTi;
font-weight: 400;
color: #3D424C;
}
::v-deep .el-tabs__nav-wrap::after { ::v-deep .el-tabs__item.is-active {
display: none !important; color: #216CDC;
} }
.tongyidenglu { ::v-deep .el-tabs__nav-wrap::after {
margin-top: 1rem; display: none !important;
margin-left: 0rem; }
}
.login { .tongyidenglu {
display: flex; margin-top: 1rem;
justify-content: center; margin-left: 0rem;
align-items: center; }
border-radius: 6px 0 0 6px;
height: 100%;
background-image: url('../assets/images/loginbackground.png');
background-size: cover;
}
.loginleft { .login {
width: 35rem; display: flex;
height: 40rem; justify-content: center;
background-image: url('../assets/images/loginleft.png'); align-items: center;
background-size: 100% 100%; border-radius: 6px 0 0 6px;
background-repeat: no-repeat; height: 100%;
} background-image: url('../assets/images/loginbackground.png');
background-size: cover;
}
.title { .loginleft {
width: 29.13rem; width: 35rem;
height: 1.94rem; height: 40rem;
font-family: Alibaba PuHuiTi; background-image: url('../assets/images/loginleft.png');
font-weight: 500; background-size: 100% 100%;
font-size: 2rem; background-repeat: no-repeat;
color: #292C33; }
line-height: 3.5rem;
text-align: center;
margin-top: 1rem;
}
.loginitem { .title {
width: 24rem; width: 29.13rem;
} height: 1.94rem;
font-family: Alibaba PuHuiTi;
font-weight: 500;
font-size: 2rem;
color: #292C33;
line-height: 3.5rem;
text-align: center;
margin-top: 1rem;
}
.login-form { .loginitem {
border-radius: 0 6px 6px 0; width: 24rem;
background: #ffffff; }
width: 50rem;
height: 40rem;
padding: 25px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
img { .login-form {
width: 6.56rem; border-radius: 0 6px 6px 0;
height: 3.56rem; background: #ffffff;
} width: 50rem;
height: 40rem;
padding: 25px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.el-input { img {
height: 38px; width: 6.56rem;
height: 3.56rem;
}
input { .el-input {
height: 38px; height: 38px;
}
}
.input-icon { input {
height: 39px; height: 38px;
width: 14px;
margin-left: 2px;
} }
} }
.login-tip { .input-icon {
font-size: 13px; height: 39px;
text-align: center; width: 14px;
color: #bfbfbf; margin-left: 2px;
} }
}
.logintabs { .login-tip {
margin-top: 2.88rem; font-size: 13px;
width: 18rem; text-align: center;
} color: #bfbfbf;
}
.login-code { .logintabs {
width: 35%; margin-top: 2.88rem;
height: 1.8rem; width: 18rem;
float: right; }
img { .login-code {
cursor: pointer; width: 35%;
vertical-align: middle; height: 1.8rem;
} float: right;
}
.el-login-footer { img {
height: 40px; cursor: pointer;
line-height: 40px; vertical-align: middle;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #333;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
} }
}
.login-code-img { .el-login-footer {
height: 38px; height: 40px;
} line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #333;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.el-tabs__item.is-active { .login-code-img {
color: #216CDC; height: 38px;
position: relative; }
padding-bottom: 0.5rem;
} .el-tabs__item.is-active {
</style> color: #216CDC;
position: relative;
padding-bottom: 0.5rem;
}
</style>
Loading…
Cancel
Save