浏览代码

部分登录替换

CzRger 8 月之前
父节点
当前提交
6f7a915201

+ 1 - 1
snowy-admin-web/src/router/systemRouter.js

@@ -23,7 +23,7 @@ const routes = [
 	},
 	{
 		path: '/login',
-		component: () => import('@/views/auth/login/login.vue'),
+		component: () => import('@/views/auth/login/single-window-login.vue'),
 		meta: {
 			title: '登录'
 		}

+ 9 - 0
snowy-admin-web/src/style/cus.less

@@ -0,0 +1,9 @@
+@import './realdark';
+@import './default';
+
+.__hover {
+	&:hover {
+		opacity: 0.75;
+		cursor: pointer;
+	}
+}

+ 1 - 0
snowy-admin-web/src/style/index.less

@@ -1,5 +1,6 @@
 @import './realdark';
 @import './default';
+@import './cus';
 
 .body, html {
 	width: 100%;

+ 358 - 0
snowy-admin-web/src/views/auth/login/single-window-login.vue

@@ -0,0 +1,358 @@
+<template>
+	<div class="single-window-login">
+		<div class="swl-head">
+			<div class="swl-head-center">
+				<a href="https://www.singlewindow.cn"><img src="https://update.singlewindow.cn/images/swLogo.png"></a>
+				<div class="swl-head-lang">
+					<div class="__hover" :class="{ active: config.lang === 'zh-cn' }" @click="configLang('zh-cn')">简体中文</div>
+					<div>/</div>
+					<div class="__hover" :class="{ active: config.lang === 'en' }" @click="configLang('en')">English</div>
+				</div>
+			</div>
+		</div>
+		<div class="swl-content">
+			<div class="swl-content-login">
+				<div class="swl-content-login-left"/>
+				<div class="swl-content-login-right">
+					<div class="swlclr-login">
+						<div class="swlclr-login-div">
+							<div class="swlclr-login-div-title">账号登录</div>
+							<a-form class="login-form" ref="loginForm" :model="ruleForm" :rules="rules">
+								<a-form-item name="account">
+									<a-input
+										v-model:value="ruleForm.account"
+										:placeholder="$t('login.accountPlaceholder')"
+										size="large"
+										@keyup.enter="login"
+									>
+										<template #prefix>
+											<UserOutlined class="login-icon-gray" />
+										</template>
+									</a-input>
+								</a-form-item>
+								<a-form-item name="password">
+									<a-input-password
+										v-model:value="ruleForm.password"
+										:placeholder="$t('login.PWPlaceholder')"
+										size="large"
+										autocomplete="off"
+										@keyup.enter="login"
+									>
+										<template #prefix>
+											<LockOutlined class="login-icon-gray" />
+										</template>
+									</a-input-password>
+								</a-form-item>
+								<a-form-item name="validCode" v-if="captchaOpen === 'true'">
+									<a-row :gutter="8">
+										<a-col :span="17">
+											<a-input
+												v-model:value="ruleForm.validCode"
+												:placeholder="$t('login.validLaceholder')"
+												size="large"
+												@keyup.enter="login"
+											>
+												<template #prefix>
+													<verified-outlined class="login-icon-gray" />
+												</template>
+											</a-input>
+										</a-col>
+										<a-col :span="7">
+											<img :src="validCodeBase64" class="login-validCode-img" @click="loginCaptcha" />
+										</a-col>
+									</a-row>
+								</a-form-item>
+								<div class="agree">
+									<a-checkbox v-model:checked="loginAgree"/>
+									<span style="color:#222222">已阅读并同意</span>
+									<span style="color: #096ac6;text-decoration:underline dotted; cursor:pointer;" onclick="userNameProtocolAgree()">《用户服务协议》</span>
+									<span>和</span>
+									<span style="color: #096ac6;text-decoration:underline dotted; cursor:pointer;" onclick="userNameProtocolPrivacy()">《用户隐私政策》</span>
+								</div>
+								<a-button type="primary" class="w-full mt-4" :loading="loading" round size="large" @click="login"
+								>{{ $t('login.signIn') }}
+								</a-button>
+							</a-form>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+		<div class="swl-foot" v-if="config.lang === 'zh-cn'"></div>
+	</div>
+</template>
+<script setup>
+	import loginApi from '@/api/auth/loginApi'
+	import smCrypto from '@/utils/smCrypto'
+	import { required } from '@/utils/formRules'
+	import { afterLogin } from './util'
+	import configData from '@/config'
+	import configApi from '@/api/dev/configApi'
+	import tool from '@/utils/tool'
+	import { globalStore, iframeStore, keepAliveStore, viewTagsStore } from '@/store'
+	import {message, Modal} from "ant-design-vue";
+	import {createVNode} from "vue";
+	import {ExclamationCircleOutlined} from "@ant-design/icons-vue";
+	import router from "@/router";
+	const { proxy } = getCurrentInstance()
+
+	const activeKey = ref('userAccount')
+	const captchaOpen = ref(configData.SYS_BASE_CONFIG.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN)
+	const validCodeBase64 = ref('')
+	const loading = ref(false)
+	const loginAgree = ref(false)
+
+	const ruleForm = reactive({
+		account: 'superAdmin',
+		password: '123456',
+		validCode: '',
+		validCodeReqNo: '',
+		autologin: false
+	})
+
+	const rules = reactive({
+		account: [required(proxy.$t('login.accountError'), 'blur')],
+		password: [required(proxy.$t('login.PWError'), 'blur')]
+	})
+	const lang = ref([
+		{
+			name: '简体中文',
+			value: 'zh-cn'
+		},
+		{
+			name: 'English',
+			value: 'en'
+		}
+	])
+	const config = ref({
+		lang: tool.data.get('APP_LANG') || proxy.$CONFIG.LANG,
+		theme: tool.data.get('APP_THEME') || 'default'
+	})
+
+	const store = globalStore()
+	const kStore = keepAliveStore()
+	const iStore = iframeStore()
+	const vStore = viewTagsStore()
+
+	const setSysBaseConfig = store.setSysBaseConfig
+	const clearKeepLive = kStore.clearKeepLive
+	const clearIframeList = iStore.clearIframeList
+	const clearViewTags = vStore.clearViewTags
+
+	const sysBaseConfig = computed(() => {
+		return store.sysBaseConfig
+	})
+
+	onMounted(() => {
+		let formData = ref(configData.SYS_BASE_CONFIG)
+		configApi.configSysBaseList().then((data) => {
+			if (data) {
+				data.forEach((item) => {
+					formData.value[item.configKey] = item.configValue
+				})
+				captchaOpen.value = formData.value.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN
+				tool.data.set('SNOWY_SYS_BASE_CONFIG', formData.value)
+				setSysBaseConfig(formData.value)
+				refreshSwitch()
+			}
+		})
+	})
+
+	onBeforeMount(() => {
+		clearViewTags()
+		clearKeepLive()
+		clearIframeList()
+	})
+
+	// 监听语言
+	watch(
+		() => config.value.lang,
+		(newValue) => {
+			proxy.$i18n.locale = newValue
+			tool.data.set('APP_LANG', newValue)
+		}
+	)
+	// 主题
+	watch(
+		() => config.value.theme,
+		(newValue) => {
+			document.body.setAttribute('data-theme', newValue)
+		}
+	)
+	// 通过开关加载内容
+	const refreshSwitch = () => {
+		// 判断是否开启验证码
+		if (captchaOpen.value === 'true') {
+			// 加载验证码
+			loginCaptcha()
+			// 加入校验
+			rules.validCode = [required(proxy.$t('login.validError'), 'blur')]
+		}
+	}
+
+	// 获取验证码
+	const loginCaptcha = () => {
+		loginApi.getPicCaptcha().then((data) => {
+			validCodeBase64.value = data.validCodeBase64
+			ruleForm.validCodeReqNo = data.validCodeReqNo
+		})
+	}
+	//登陆
+	const loginForm = ref()
+	const login = async () => {
+		if (loginAgree.value) {
+			loginForm.value
+			.validate()
+			.then(async () => {
+				loading.value = true
+				const loginData = {
+					account: ruleForm.account,
+					// 密码进行SM2加密,传输过程中看到的只有密文,后端存储使用hash
+					password: smCrypto.doSm2Encrypt(ruleForm.password),
+					validCode: ruleForm.validCode,
+					validCodeReqNo: ruleForm.validCodeReqNo
+				}
+
+				// 获取token
+				// loginApi.login(loginData).then((loginToken) => {
+				// 	afterLogin(loginToken)
+				// }).catch(() => {
+				// 	loading.value = false
+				// 	loginCaptcha()
+				// })
+
+				// 获取token
+				try {
+					const loginToken = await loginApi.login(loginData)
+					const loginAfter = afterLogin(loginToken)
+				} catch (err) {
+					loading.value = false
+					loginCaptcha()
+				}
+			})
+			.catch(() => {})
+		} else {
+			Modal.confirm({
+				title: '提示',
+				content: '请阅读并勾选《用户服务协议》和《用户隐私政策》!',
+				centered: true,
+				width: 420,
+				icon: createVNode(ExclamationCircleOutlined),
+				maskClosable: false,
+				onOk() {},
+				onCancel() {}
+			})
+		}
+	}
+	const configLang = (key) => {
+		config.value.lang = key
+	}
+</script>
+<style lang="less" scoped>
+.single-window-login {
+	display: flex;
+	flex-direction: column;
+	width: 100%;
+	height: 100%;
+	.swl-head {
+		background-color: #ffffff;
+		min-width: 1200px;
+		height: 90px;
+		line-height: 90px;
+		display: flex;
+		.swl-head-center {
+			width: 1200px;
+			display: flex;
+			align-items: center;
+			margin: 0 auto;
+			.swl-head-lang {
+				margin-left: auto;
+				display: flex;
+				align-items: center;
+				gap: 10px;
+				color: #00599C;
+				font-size: 15px;
+				&:nth-child(2) {
+					font-size: 12px;
+					color: #00599C;
+				}
+				.active {
+					color: #00599C;
+					font-weight: bold;
+					font-size: 16px;
+				}
+			}
+		}
+	}
+	.swl-content {
+		flex: 1;
+		background-image: url('https://app.singlewindow.cn/cas/images/newLogin/icon_bgNew.png');
+		background-repeat: no-repeat;
+		background-size: 100% 100%;
+		.swl-content-login {
+			height: 659px;
+			max-width: 1200px;
+			display: flex;
+			flex-direction: row;
+			align-items: center;
+			justify-content: center;
+			margin: 0 auto;
+			.swl-content-login-left {
+				width: 553px;
+				height: 478px;
+				background-image: url('https://app.singlewindow.cn/cas/images/leftimg_04.png');
+				background-repeat: no-repeat;
+				background-position: center;
+			}
+			.swl-content-login-right {
+				width: 600px;
+				height: 478px;
+				.swlclr-login {
+					width: 412px;
+					height: auto;
+					background-color: #FFFFFF;
+					border: solid #ccc 0px;
+					border-radius: 8px;
+					margin: 0px auto;
+					color: #666666;
+					padding-bottom: 12px;
+					.swlclr-login-div {
+						width: 410px;
+						height: 420px;
+						background: #ffffff;
+						border-radius: 10px;
+						margin: 20px auto;
+						padding: 26px 41px 0 39px;
+						box-sizing: border-box;
+						position: relative;
+						.swlclr-login-div-title {
+							font-weight: 700;
+							color: #00599c;
+							font-size: 18px;
+							margin-top: 18px;
+							margin-bottom: 28px;
+							text-align: center;
+						}
+						:deep(.login-form) {
+							.ant-form-item-control-input-content {
+								border-bottom: 1px solid #e5e5e5;
+								.ant-input-affix-wrapper {
+									border: none;
+									box-shadow: none;
+								}
+							}
+						}
+						.agree {
+							font-size: 12px;
+						}
+					}
+				}
+			}
+		}
+	}
+	.swl-foot {
+		height: 160px;
+		background-color: rgba(230, 230, 230, 1);
+	}
+}
+</style>