|
|
@@ -32,6 +32,8 @@
|
|
|
</el-form>
|
|
|
</div>
|
|
|
<div class="btn" @click="login">登 录</div>
|
|
|
+
|
|
|
+ <el-link class="right__sso" :underline="false" :href="ssoUrl">广东省统一身份认证平台登录</el-link>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -40,8 +42,11 @@
|
|
|
<script>
|
|
|
import { encodeStr } from '../utils/pass'
|
|
|
import { Base64 } from 'js-base64'
|
|
|
-import { userLogin } from '@/apis/login'
|
|
|
+import { userLogin, ssoLogin } from '@/apis/login'
|
|
|
import dayjs from 'dayjs'
|
|
|
+
|
|
|
+const ssoUrl = 'https://xtbg.gdzwfw.gov.cn/zwrz/rz/sso/oauth/authorize?response_type=code&scope=all&client_id=zwrz_jmyzt&redirect_uri=' + window.encodeURIComponent(location.href)
|
|
|
+
|
|
|
export default {
|
|
|
name: 'login',
|
|
|
components: {},
|
|
|
@@ -58,15 +63,64 @@ export default {
|
|
|
{ required: true, message: '不能为空', trigger: 'blur' },
|
|
|
{ min: 8, message: '最短8个字符', trigger: 'blur' }
|
|
|
]
|
|
|
- }
|
|
|
+ },
|
|
|
+ ssoUrl
|
|
|
}
|
|
|
},
|
|
|
// 监听属性 类似于data概念
|
|
|
- computed: {},
|
|
|
+ computed: {
|
|
|
+ },
|
|
|
// 监控data中的数据变化
|
|
|
watch: {},
|
|
|
// 方法集合
|
|
|
methods: {
|
|
|
+ async handleSSOLogin (code) {
|
|
|
+ const ssoCode =
|
|
|
+ code || (this.$route && this.$route.query && this.$route.query.code) ||
|
|
|
+ new URLSearchParams(window.location.search).get('code')
|
|
|
+ if (!ssoCode) return
|
|
|
+ const res = await ssoLogin({
|
|
|
+ code: ssoCode
|
|
|
+ })
|
|
|
+ // 清理 URL 中的 code 参数,避免再次使用或泄露
|
|
|
+ try {
|
|
|
+ this.removeCodeFromUrl()
|
|
|
+ } catch (e) {
|
|
|
+ // ignore
|
|
|
+ }
|
|
|
+ if (res.code === 0) {
|
|
|
+ localStorage.setItem('JMYZU_token', res.data.token)
|
|
|
+ localStorage.setItem('JMYZU_userInfo', JSON.stringify(res.data.user))
|
|
|
+ this.$router.replace('/layout/tab1')
|
|
|
+ this.$message.success('登录成功')
|
|
|
+ } else this.$message.warning(res.msg)
|
|
|
+ },
|
|
|
+
|
|
|
+ removeCodeFromUrl () {
|
|
|
+ // 使用 URL API 删除 query 中的 code,并用 history.replaceState 替换当前地址,保留 hash
|
|
|
+ try {
|
|
|
+ const u = new URL(window.location.href)
|
|
|
+ if (!u.searchParams.has('code')) return
|
|
|
+ u.searchParams.delete('code')
|
|
|
+ const newUrl = u.origin + u.pathname + u.search + u.hash
|
|
|
+ history.replaceState(null, '', newUrl)
|
|
|
+ } catch (err) {
|
|
|
+ const href = window.location.href
|
|
|
+ const parts = href.split('#')
|
|
|
+ const beforeHash = parts[0]
|
|
|
+ const hash = parts[1] ? '#' + parts[1] : ''
|
|
|
+ const qIndex = beforeHash.indexOf('?')
|
|
|
+ if (qIndex === -1) return
|
|
|
+ const base = beforeHash.substring(0, qIndex)
|
|
|
+ const query = beforeHash.substring(qIndex + 1)
|
|
|
+ const params = query
|
|
|
+ .split('&')
|
|
|
+ .filter(p => p.split('=')[0] !== 'code')
|
|
|
+ .join('&')
|
|
|
+ const newBefore = params ? base + '?' + params : base
|
|
|
+ history.replaceState(null, '', newBefore + hash)
|
|
|
+ }
|
|
|
+ },
|
|
|
async login () {
|
|
|
try {
|
|
|
await this.$refs.ruleForm.validate()
|
|
|
@@ -103,7 +157,7 @@ export default {
|
|
|
|
|
|
localStorage.setItem('JMYZU_token', res.data.token)
|
|
|
localStorage.setItem('JMYZU_userInfo', JSON.stringify(res.data.user))
|
|
|
- this.$router.push('/layout/tab1')
|
|
|
+ this.$router.replace('/layout/tab1')
|
|
|
this.$message.success('登录成功')
|
|
|
} else this.$message.warning(res.msg)
|
|
|
} catch (error) {
|
|
|
@@ -112,7 +166,14 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
// 生命周期 - 创建完成(可以访问当前this实例)
|
|
|
- created () {},
|
|
|
+ created () {
|
|
|
+ const codeFromRoute = this.$route && this.$route.query && this.$route.query.code
|
|
|
+ const codeFromSearch = new URLSearchParams(window.location.search).get('code')
|
|
|
+ const code = codeFromRoute || codeFromSearch
|
|
|
+ if (code) {
|
|
|
+ this.handleSSOLogin(code)
|
|
|
+ }
|
|
|
+ },
|
|
|
// 生命周期 - 挂载完成(可以访问DOM元素)
|
|
|
mounted () {},
|
|
|
beforeCreate () {}, // 生命周期 - 创建之前
|
|
|
@@ -162,6 +223,11 @@ export default {
|
|
|
.right {
|
|
|
width: 350px;
|
|
|
background-color: rgba(255, 255, 255, 0.8);
|
|
|
+ &__sso {
|
|
|
+ display: block;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
& > p {
|
|
|
font-size: 24px;
|
|
|
text-align: center;
|
|
|
@@ -169,15 +235,17 @@ export default {
|
|
|
}
|
|
|
.input {
|
|
|
width: 90%;
|
|
|
- margin: 50px auto;
|
|
|
+ overflow: hidden;
|
|
|
+ margin: 50px auto 10px;
|
|
|
}
|
|
|
.btn {
|
|
|
cursor: pointer;
|
|
|
width: 90%;
|
|
|
height: 40px;
|
|
|
+ overflow: hidden;
|
|
|
line-height: 40px;
|
|
|
text-align: center;
|
|
|
- margin: 50px auto 0;
|
|
|
+ margin: 20px auto;
|
|
|
background-color: #b9412e;
|
|
|
border-radius: 8px;
|
|
|
color: #fff;
|