luoyali hace 1 año
padre
commit
06a823f19e

BIN
public/img/auth_banner.png


+ 92 - 0
src/components/scPasswordStrength/index.vue

@@ -0,0 +1,92 @@
+<!--
+ * @Descripttion: 密码强度检测
+ * @version: 1.0
+ * @Author: sakuya
+ * @Date: 2022年6月2日15:36:01
+ * @LastEditors:
+ * @LastEditTime:
+-->
+
+<template>
+	<div class="sc-password-strength">
+		<div class="sc-password-strength-bar" :class="`sc-password-strength-level-${level}`"></div>
+	</div>
+</template>
+
+<script>
+	export default {
+		props: {
+			modelValue: { type: String, default: "" },
+		},
+		data() {
+			return {
+				level: 0
+			}
+		},
+		watch: {
+			modelValue() {
+				this.strength(this.modelValue)
+			}
+		},
+		mounted() {
+			this.strength(this.modelValue)
+		},
+		methods: {
+			strength(v){
+				var _level = 0
+				//长度
+				var has_length = v.length >= 6
+				//包含数字
+				var has_number = /\d/.test(v)
+				//包含小写英文
+				var has_lovercase = /[a-z]/.test(v)
+				//包含大写英文
+				var has_uppercase = /[A-Z]/.test(v)
+				//没有连续的字符3位
+				var no_continuity = !/(\w)\1{2}/.test(v)
+				//包含特殊字符
+				var has_special = /[`~!@#$%^&*()_+<>?:"{},./;'[\]]/.test(v)
+
+				if(v.length <= 0){
+					_level = 0
+					this.level = _level
+					return false
+				}
+				if(!has_length){
+					_level = 1
+					this.level = _level
+					return false
+				}
+				if(has_number){
+					_level += 1
+				}
+				if(has_lovercase){
+					_level += 1
+				}
+				if(has_uppercase){
+					_level += 1
+				}
+				if(no_continuity){
+					_level += 1
+				}
+				if(has_special){
+					_level += 1
+				}
+				this.level = _level
+			}
+		}
+	}
+</script>
+
+<style scoped>
+	.sc-password-strength {height: 5px;width: 100%;background: var(--el-color-info-light-5);border-radius: 5px;position: relative;margin:10px 0;}
+	.sc-password-strength:before {left: 20%;}
+	.sc-password-strength:after {right: 20%;}
+	.sc-password-strength:before, .sc-password-strength:after {position: absolute;content: "";display: block;width: 20%;height: inherit;border: 5px solid var(--el-bg-color-overlay);border-top: 0;border-bottom: 0;z-index: 1;background-color: transparent;box-sizing: border-box;}
+	.sc-password-strength-bar {position: absolute;height: inherit;width: 0%;border-radius: inherit;transition: width .5s ease-in-out,background .25s;background: transparent;}
+	.sc-password-strength-level-1 {width: 20%;background-color: var(--el-color-error);}
+	.sc-password-strength-level-2 {width: 40%;background-color: var(--el-color-error);}
+	.sc-password-strength-level-3 {width: 60%;background-color: var(--el-color-warning);}
+	.sc-password-strength-level-4 {width: 80%;background-color: var(--el-color-success);}
+	.sc-password-strength-level-5 {width: 100%;background-color: var(--el-color-success);}
+</style>

+ 27 - 1
src/lang/en.ts

@@ -24,7 +24,33 @@ export default {
 		username: 'Username',
 		password: 'Password',
 		login: 'Login',
-		code: 'Verification Code'
+		code: 'Verification Code',
+		slogan: 'High performance / delicate / grace',
+		describe: 'Vue3 + element plus based front-end solutions in the background.',
+		signInTitle: 'Sign in',
+		accountLogin: 'Account sign in',
+		mobileLogin: 'Mobile sign in',
+		rememberMe: 'Remember me',
+		forgetPassword: 'Forget password',
+		signIn: 'Sign in',
+		signInOther: 'Sign in with',
+		userPlaceholder: 'user / phone / email',
+		userError: 'Please input a user name',
+		PWPlaceholder: 'Please input a password',
+		PWError: 'Please input a password',
+		admin: 'Administrator',
+		user: 'User',
+		mobilePlaceholder: 'Mobile',
+		mobileError: 'Please input mobile',
+		smsPlaceholder: 'SMS Code',
+		smsError: 'Please input sms code',
+		smsGet: 'Get SMS Code',
+		smsSent: 'SMS sent to mobile number',
+		noAccount: 'No account?',
+		createAccount: 'Create a new account',
+		wechatLoginTitle: 'QR code sign in',
+		wechatLoginMsg: 'Please use wechat to scan and log in | Auto scan after 3 seconds of simulation',
+		wechatLoginResult: 'Scanned | Please click authorize login in the device'
 	},
 	// 导航栏国际化
 	navbar: {

+ 28 - 2
src/lang/zh-cn.ts

@@ -16,7 +16,7 @@ export default {
 		footerSummary: '底部统计',
 		expandTable: '展开行表格',
 		resizeParentHeightTable: '继承父元素高度',
-		profile: '用户中心',
+		profile: '用户中心'
 	},
 	// 登录页面国际化
 	login: {
@@ -24,7 +24,33 @@ export default {
 		username: '用户名',
 		password: '密码',
 		login: '登 录',
-		code: '请输入验证码'
+		code: '请输入验证码',
+		slogan: '快速开发 / 数据安全 / 编码优雅',
+		describe: '爱组搭 ~ 低代码组件化开发平台',
+		signInTitle: '用户登录',
+		accountLogin: '账号登录',
+		mobileLogin: '手机号登录',
+		rememberMe: '24小时免登录',
+		forgetPassword: '忘记密码',
+		signIn: '登录',
+		signInOther: '其他登录方式',
+		userPlaceholder: '用户名 / 手机 / 邮箱',
+		userError: '请输入用户名',
+		PWPlaceholder: '请输入密码',
+		PWError: '请输入密码',
+		admin: '管理员',
+		user: '用户',
+		mobilePlaceholder: '手机号码',
+		mobileError: '请输入手机号码',
+		smsPlaceholder: '短信验证码',
+		smsError: '请输入短信验证码',
+		smsGet: '获取验证码',
+		smsSent: '已发送短信至手机号码',
+		noAccount: '还没有账号?',
+		createAccount: '创建新账号',
+		wechatLoginTitle: '二维码登录',
+		wechatLoginMsg: '请使用微信扫一扫登录 | 模拟3秒后自动扫描',
+		wechatLoginResult: '已扫描 | 请在设备中点击授权登录'
 	},
 	navbar: {
 		dashboard: '首页',

+ 1 - 1
src/permission.ts

@@ -20,7 +20,7 @@ router.beforeEach(async (to, from, next) => {
 	// const hasToken = user.token
 	const hasToken = ls.get('token')
 	// 登录页特殊处理
-	if (to.path === '/login') {
+	if (to.path === '/login1') {
 		// 登录成功,跳转到首页(特)
 		hasToken ? next({ path: '/' }) : next()
 		return NProgress.done()

+ 2 - 2
src/router/index.ts

@@ -10,8 +10,8 @@ const HOME_URL = '/dashboard'
 // 静态路由
 export const sysStaticRouter: Array<AppRouteRecordRaw> = [
 	{
-		path: '/login',
-		component: () => import('@/views/login/index.vue'),
+		path: '/login1',
+		component: () => import('@/views/login1/index.vue'),
 		meta: { hidden: true }
 	},
 	// 主入口

+ 4 - 4
src/styles/element-plus-dark.scss

@@ -12,12 +12,12 @@ html.dark {
     color: #eeeeee;
   }
 
-  /* login */
-  /*.login-container {
+  /* login1 */
+  /*.login1-container {
     background-color: #191919 !important;
-    .login-box {
+    .login1-box {
       background-color: rgb(0 0 0 / 80%) !important;
-      .login-form {
+      .login1-form {
         box-shadow: rgb(255 255 255 / 12%) 0 2px 10px 2px !important;
         .logo-text {
           color: var(--el-text-color-primary) !important;

+ 1 - 1
src/utils/request.ts

@@ -17,7 +17,7 @@ const tokenLoseHandler = debounce(
 	function () {
 		// const { user } = useStore()
 		ls.clear() // 清除浏览器全部缓存
-		router.push('/login')
+		router.push('/login1')
 		ElMessageBox.alert('当前页面已失效,请重新登录', '提示', {})
 	},
 	3000,

+ 35 - 0
src/views/login/components/commonPage.vue

@@ -0,0 +1,35 @@
+<template>
+	<el-container>
+		<el-header style="height:50px;">
+			<div class="common-header-left">
+				<div class="common-header-logo">
+					<img :alt="$CONFIG.APP_NAME" src="img/logo.png">
+					<label>{{$CONFIG.APP_NAME}}</label>
+				</div>
+				<div class="common-header-title">{{title}}</div>
+			</div>
+			<div class="common-header-right">
+				<router-link to="/login">返回登录</router-link>
+			</div>
+		</el-header>
+		<el-main>
+			<div class="common-container">
+				<h2 class="common-title">{{title}}</h2>
+				<div class="common-main el-card">
+					<slot></slot>
+				</div>
+			</div>
+		</el-main>
+	</el-container>
+</template>
+
+<script>
+	export default {
+		props: {
+			title: { type: String, default: "" }
+		}
+	}
+</script>
+
+<style>
+</style>

+ 104 - 0
src/views/login/components/passwordForm.vue

@@ -0,0 +1,104 @@
+<template>
+	<el-form ref="loginForm" :model="form" :rules="rules" label-width="0" size="large" @keyup.enter="login">
+		<el-form-item prop="user">
+			<el-input v-model="form.user" prefix-icon="el-icon-user" clearable :placeholder="$t('login.userPlaceholder')"></el-input>
+		</el-form-item>
+		<el-form-item prop="password">
+			<el-input v-model="form.password" prefix-icon="el-icon-lock" clearable show-password :placeholder="$t('login.PWPlaceholder')"></el-input>
+		</el-form-item>
+		<el-form-item style="margin-bottom: 10px;">
+				<el-col :span="12">
+					<el-checkbox :label="$t('login.rememberMe')" v-model="form.autologin"></el-checkbox>
+				</el-col>
+				<el-col :span="12" class="login-forgot">
+					<router-link to="/reset_password">{{ $t('login.forgetPassword') }}?</router-link>
+				</el-col>
+		</el-form-item>
+		<el-form-item>
+			<el-button type="primary" style="width: 100%;" :loading="islogin" round @click="login">{{ $t('login.signIn') }}</el-button>
+		</el-form-item>
+		<div class="login-reg">
+			{{$t('login.noAccount')}} <router-link to="/user_register">{{$t('login.createAccount')}}</router-link>
+		</div>
+	</el-form>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				form: {
+					user: "admin",
+					password: "100607",
+					autologin: false
+				},
+				rules: {
+					user: [
+						{required: true, message: this.$t('login.userError'), trigger: 'blur'}
+					],
+					password: [
+						{required: true, message: this.$t('login.PWError'), trigger: 'blur'}
+					]
+				},
+				islogin: false,
+			}
+		},
+		mounted() {
+
+		},
+		methods: {
+			async login(){
+
+				let validate = await this.$refs.loginForm.validate().catch(()=>{})
+				if(!validate){ return false }
+
+				this.islogin = true
+				let data = {
+					username: this.form.user,
+					password: this.$TOOL.crypto.MD5(this.form.password)
+				}
+				//获取token
+				let user = await this.$API.user.login(data);
+				if (user.code == 200) {
+					this.$TOOL.cookie.set("TOKEN", user.data.token, {
+						expires: this.form.autologin? 24*60*60 : 0
+					})
+					this.$TOOL.data.set("USER_INFO", user.data.userInfo)
+				} else {
+					this.islogin = false
+					this.$message.warning(user.message)
+					return false
+				}
+				//获取菜单
+				let menu = await this.$API.res.listMenuPermissions()
+				if (menu.code == 200) {
+					let data = menu.data
+					if (data.menu.length == 0) {
+						this.islogin = false
+						await this.$alert("当前用户无任何菜单权限,请联系系统管理员", "无权限访问", {
+							type: 'error',
+							center: true
+						})
+						return false
+					}
+					this.$TOOL.data.set("MENU", data.menu)
+					this.$TOOL.data.set("PERMISSIONS", data.permissions)
+					this.$TOOL.data.set("DASHBOARDGRID", data.dashboardGrid)
+				} else {
+					this.islogin = false
+					this.$message.warning(menu.message)
+					return false
+				}
+
+				this.$router.replace({
+					path: '/'
+				})
+				this.$message.success("Login Success 登录成功")
+				this.islogin = false
+			},
+		}
+	}
+</script>
+
+<style>
+</style>

+ 74 - 0
src/views/login/components/phoneForm.vue

@@ -0,0 +1,74 @@
+<template>
+	<el-form ref="loginForm" :model="form" :rules="rules" label-width="0" size="large" @keyup.enter="login">
+		<el-form-item prop="phone">
+			<el-input v-model="form.phone" prefix-icon="el-icon-iphone" clearable :placeholder="$t('login.mobilePlaceholder')">
+				<template #prepend>+86</template>
+			</el-input>
+		</el-form-item>
+		<el-form-item prop="yzm"  style="margin-bottom: 35px;">
+			<div class="login-msg-yzm">
+				<el-input v-model="form.yzm" prefix-icon="el-icon-unlock" clearable :placeholder="$t('login.smsPlaceholder')"></el-input>
+				<el-button @click="getYzm" :disabled="disabled">{{this.$t('login.smsGet')}}<span v-if="disabled"> ({{time}})</span></el-button>
+			</div>
+		</el-form-item>
+		<el-form-item>
+			<el-button type="primary" style="width: 100%;" :loading="islogin" round @click="login">{{ $t('login.signIn') }}</el-button>
+		</el-form-item>
+		<div class="login-reg">
+			{{$t('login.noAccount')}} <router-link to="/user_register">{{$t('login.createAccount')}}</router-link>
+		</div>
+	</el-form>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				form: {
+					phone: "",
+					yzm: "",
+				},
+				rules: {
+					phone: [
+						{required: true, message: this.$t('login.mobileError')}
+					],
+					yzm: [
+						{required: true, message: this.$t('login.smsError')}
+					]
+				},
+				disabled: false,
+				time: 0,
+				islogin: false,
+			}
+		},
+		mounted() {
+
+		},
+		methods: {
+			async getYzm(){
+				var validate = await this.$refs.loginForm.validateField("phone").catch(()=>{})
+				if(!validate){ return false }
+
+				this.$message.success(this.$t('login.smsSent'))
+				this.disabled = true
+				this.time = 60
+				var t = setInterval(() => {
+					this.time -= 1
+					if(this.time < 1){
+						clearInterval(t)
+						this.disabled = false
+						this.time = 0
+					}
+				},1000)
+			},
+			async login(){
+				var validate = await this.$refs.loginForm.validate().catch(()=>{})
+				if(!validate){ return false }
+			}
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 321 - 335
src/views/login/index.vue

@@ -1,368 +1,354 @@
 <template>
-	<div class="login-container">
-		<div class="login-left">
-			<div class="header">
-				<img class="logo-img" src="@/assets/icons/logo.svg" alt="logo" />
-				{{ title }}
+	<div class="login_bg">
+		<div class="login_adv" style="background-image: url(img/auth_banner.png)">
+			<div class="login_adv__title">
+				<h2>AIZUDA</h2>
+				<h4>{{ $t('login.slogan') }}</h4>
+				<p>{{ $t('login.describe') }}</p>
 			</div>
-			<ServerLogin class="login-left_svg" style="color: var(--el-color-primary)" />
+			<div class="login_adv__mask"></div>
+			<div class="login_adv__bottom">© {{ $CONFIG.APP_NAME }} {{ $CONFIG.APP_VER }}</div>
 		</div>
-		<div class="login-right">
-			<el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
-				<div class="title-container">
-					<h3 class="title">{{ title }}</h3>
-					<lang-select class="set-language" />
+		<div class="login_main">
+			<div class="login_config">
+				<el-button :icon="config.dark ? 'el-icon-sunny' : 'el-icon-moon'" circle type="info" @click="configDark"></el-button>
+				<el-dropdown trigger="click" placement="bottom-end" @command="configLang">
+					<el-button circle>
+						<svg
+							xmlns="http://www.w3.org/2000/svg"
+							xmlns:xlink="http://www.w3.org/1999/xlink"
+							aria-hidden="true"
+							role="img"
+							width="1em"
+							height="1em"
+							preserveAspectRatio="xMidYMid meet"
+							viewBox="0 0 512 512"
+						>
+							<path
+								d="M478.33 433.6l-90-218a22 22 0 0 0-40.67 0l-90 218a22 22 0 1 0 40.67 16.79L316.66 406h102.67l18.33 44.39A22 22 0 0 0 458 464a22 22 0 0 0 20.32-30.4zM334.83 362L368 281.65L401.17 362z"
+								fill="currentColor"
+							></path>
+							<path
+								d="M267.84 342.92a22 22 0 0 0-4.89-30.7c-.2-.15-15-11.13-36.49-34.73c39.65-53.68 62.11-114.75 71.27-143.49H330a22 22 0 0 0 0-44H214V70a22 22 0 0 0-44 0v20H54a22 22 0 0 0 0 44h197.25c-9.52 26.95-27.05 69.5-53.79 108.36c-31.41-41.68-43.08-68.65-43.17-68.87a22 22 0 0 0-40.58 17c.58 1.38 14.55 34.23 52.86 83.93c.92 1.19 1.83 2.35 2.74 3.51c-39.24 44.35-77.74 71.86-93.85 80.74a22 22 0 1 0 21.07 38.63c2.16-1.18 48.6-26.89 101.63-85.59c22.52 24.08 38 35.44 38.93 36.1a22 22 0 0 0 30.75-4.9z"
+								fill="currentColor"
+							></path>
+						</svg>
+					</el-button>
+					<template #dropdown>
+						<el-dropdown-menu>
+							<el-dropdown-item v-for="item in lang" :key="item.value" :command="item" :class="{ selected: config.lang == item.value }">{{
+								item.name
+							}}</el-dropdown-item>
+						</el-dropdown-menu>
+					</template>
+				</el-dropdown>
+			</div>
+			<div class="login-form">
+				<div class="login-header">
+					<div class="logo">
+						<img :alt="$CONFIG.APP_NAME" src="/logo.png" />
+						<label>{{ $CONFIG.APP_NAME }}</label>
+					</div>
 				</div>
-
-				<el-form-item prop="username">
-					<el-input
-						ref="username"
-						v-model="loginForm.username"
-						class="login-input"
-						:placeholder="$t('login.username')"
-						name="username"
-						type="text"
-						tabindex="1"
-						auto-complete="on"
-					>
-						<template #prefix>
-							<span class="svg-container">
-								<svg-icon icon-class="user" />
-							</span>
-						</template>
-					</el-input>
-				</el-form-item>
-
-				<el-form-item prop="password">
-					<el-input
-						ref="passwordRef"
-						v-model="loginForm.password"
-						class="login-input"
-						type="password"
-						:placeholder="$t('login.password')"
-						name="password"
-						tabindex="2"
-						auto-complete="on"
-						:show-password="true"
-						@keyup.enter="handleLogin"
-					>
-						<template #prefix>
-							<span class="svg-container">
-								<svg-icon icon-class="password" />
-							</span>
-						</template>
-					</el-input>
-				</el-form-item>
-
-				<el-button size="default" :loading="loading" type="primary" style="width: 100%; margin-bottom: 30px" @click.prevent="handleLogin"
-				>{{ $t('login.login') }}
-				</el-button>
-			</el-form>
+				<el-tabs>
+					<el-tab-pane :label="$t('login.accountLogin')" lazy>
+						<password-form></password-form>
+					</el-tab-pane>
+					<el-tab-pane :label="$t('login.mobileLogin')" lazy>
+						<phone-form></phone-form>
+					</el-tab-pane>
+				</el-tabs>
+				<template v-if="$CONFIG.MY_SHOW_LOGIN_OAUTH">
+					<el-divider>{{ $t('login.signInOther') }}</el-divider>
+					<div class="login-oauth">
+						<el-button type="success" icon="sc-icon-wechat" circle @click="wechatLogin"></el-button>
+					</div>
+				</template>
+			</div>
 		</div>
 	</div>
+	<el-dialog v-model="showWechatLogin" :title="$t('login.wechatLoginTitle')" :width="400" destroy-on-close>
+		<div class="qrCodeLogin">
+			<!-- <sc-qr-code class="qrCode" :text="WechatLoginCode" :size="200"></sc-qr-code> -->
+			<p class="msg">{{ $tc('login.wechatLoginMsg', 1) }}<br />{{ $tc('login.wechatLoginMsg', 2) }}</p>
+			<div v-if="isWechatLoginResult" class="qrCodeLogin-result">
+				<el-result icon="success" :title="$tc('login.wechatLoginResult', 1)" :sub-title="$tc('login.wechatLoginResult', 2)"></el-result>
+			</div>
+		</div>
+	</el-dialog>
 </template>
 
-<script setup lang="ts">
-import { onMounted, reactive, ref, toRefs, watch, nextTick } from 'vue'
-import ServerLogin from './components/LoginMainSvg.vue'
-// 组件依赖
-import LangSelect from '@/layout/components/Header/components/Language.vue'
+<script>
+import passwordForm from './components/passwordForm'
+import phoneForm from './components/phoneForm'
 
-const title = import.meta.env.VITE_APP_TITLE
-// 状态管理依赖
-import useStore from '@/store'
-// API依赖
-// import { getGeetConfig } from '@/api/login'
-import { useRoute } from 'vue-router'
-
-const { user } = useStore()
-const route = useRoute()
-
-const loginFormRef = ref(/*ElForm*/)
-const passwordRef = ref(/*ElInput*/)
-
-const state = reactive({
-	loginForm: {
-		username: 'admin',
-		password: '100607'
+export default {
+	components: {
+		passwordForm,
+		phoneForm
 	},
-	loginRules: {
-		username: [{ required: true, message: '用户名不能为空', trigger: 'blur' }],
-		password: [{ required: true, message: '密码不能为空', trigger: 'blur' }]
+	data() {
+		return {
+			config: {
+				lang: this.$TOOL.data.get('APP_LANG') || this.$CONFIG.LANG,
+				dark: this.$TOOL.data.get('APP_DARK') || false
+			},
+			lang: [
+				{
+					name: '简体中文',
+					value: 'zh-cn'
+				},
+				{
+					name: 'English',
+					value: 'en'
+				}
+			],
+			WechatLoginCode: '',
+			showWechatLogin: false,
+			isWechatLoginResult: false
+		}
 	},
-	loading: false
-})
-
-const { loginForm, loginRules, loading } = toRefs(state)
-
-function handleLogin() {
-	loginFormRef.value.validate((valid: boolean) => {
-		if (valid) {
-			state.loading = true
-			user.login(state.loginForm).finally(() => {
-				state.loading = false
-			})
+	watch: {
+		// 先不考虑 暗黑模式
+		// 'config.dark'(val) {
+		// 	if (val) {
+		// 		document.documentElement.classList.add('dark')
+		// 		this.$TOOL.data.set('APP_DARK', val)
+		// 	} else {
+		// 		document.documentElement.classList.remove('dark')
+		// 		this.$TOOL.data.remove('APP_DARK')
+		// 	}
+		// },
+		'config.lang'(val) {
+			this.$i18n.locale = val
+			this.$TOOL.data.set('APP_LANG', val)
 		}
-	})
-}
-
-watch(
-	route,
-	() => {
-		const query = route.query
-		user.$patch({
-			loginQuery: query
-		})
 	},
-	{
-		immediate: true
+	created: function () {
+		this.$TOOL.cookie.remove('TOKEN')
+		this.$TOOL.data.remove('USER_INFO')
+		this.$TOOL.data.remove('MENU')
+		this.$TOOL.data.remove('PERMISSIONS')
+		this.$TOOL.data.remove('DASHBOARDGRID')
+		this.$TOOL.data.remove('grid')
+		this.$store.commit('clearViewTags')
+		this.$store.commit('clearKeepLive')
+		this.$store.commit('clearIframeList')
+		console.log('%c SCUI %c Gitee: https://gitee.com/lolicode/scui', 'background:#666;color:#fff;border-radius:3px;', '')
+	},
+	methods: {
+		configDark() {
+			this.config.dark = this.config.dark ? false : true
+		},
+		configLang(command) {
+			this.config.lang = command.value
+		},
+		wechatLogin() {
+			this.showWechatLogin = true
+			this.WechatLoginCode = 'SCUI-823677237287236-' + new Date().getTime()
+			this.isWechatLoginResult = false
+			setTimeout(() => {
+				this.isWechatLoginResult = true
+			}, 3000)
+		}
 	}
-)
+}
 </script>
 
-<style lang="scss" scoped>
-@import '@/styles/mixins.scss';
-//$light_gray: var(--el-input-icon-color);
-//$light_gray: #fff;
-$light_gray: var(--el-color-white);
-.login-container {
-	min-height: 100%;
+<style scoped>
+.login_bg {
 	width: 100%;
-	display: flex;
 	height: 100%;
-	overflow: hidden;
-	.login-left {
-		flex: 1;
-		display: flex;
-		flex-direction: column;
-		background: var(--el-color-primary-light-5);
-		.header {
-			margin-top: 80px;
-			display: flex;
-			align-items: center;
-			height: 78px;
-			padding: 0 20px;
-			color: #fff;
-			font-size: 22px;
-			@include hover-bg-opacity(0, #f00, 0.5);
-			&::before {
-				//background-color: var(--el-color-primary) !important;
-				background: linear-gradient(270deg, var(--el-color-primary-light-5), var(--el-color-primary-light-7));
-			}
-			.logo-img {
-				width: 50px;
-				margin-right: 10px;
-			}
-		}
-		.login-left_svg {
-			margin: 10% auto;
-			max-height: 500px;
-		}
-	}
-	.login-right {
-		width: 660px;
-		max-width: 100%;
-		background: linear-gradient(145deg, var(--el-color-primary-light-5), var(--el-color-white));
-	}
-	.login-form {
-		position: relative;
-		width: 360px;
-		max-width: 100%;
-		padding: 12px 24px;
-		margin: 0 auto;
-		overflow: hidden;
-		top: 30%;
-		//left: 50%;
-		//transform: translate(-50%, -50%);
-		:deep(.el-form-item) {
-			border: 1px solid rgba(255, 255, 255, 0.1);
-			background: rgba(0, 0, 0, 0.1);
-			border-radius: 5px;
-			color: #454545;
-			.el-input {
-				height: 47px;
-				.el-input__wrapper {
-					padding: 0;
-					background: transparent;
-					box-shadow: none;
-					.el-input__inner {
-						background: transparent;
-						border: 0;
-						-webkit-appearance: none;
-						border-radius: 0;
-						padding: 12px 8px;
-						//padding: 12px 0;
-						//padding-right: 8px;
-						color: $light_gray;
-						height: 47px;
-						caret-color: $light_gray;
-						&:-webkit-autofill {
-							box-shadow: 0 0 0px 1000px var(--el-color-primary-light-5) inset !important;
-							-webkit-text-fill-color: $light_gray !important;
-						}
-					}
-					.el-input__prefix-inner > :last-child {
-						margin-right: 0;
-					}
-					/*.el-input__suffix-inner > :first-child {
-						margin-left: 0;
-					}*/
-				}
-			}
-			.el-input__inner {
-				&:hover {
-					border-color: var(--el-input-hover-border, var(--el-border-color-hover));
-					box-shadow: none;
-				}
-
-				box-shadow: none;
-			}
-		}
-		.login-input {
-			//--el-input-icon-color: #fff;
-			--el-input-placeholder-color: #fafafa;
-			:deep(.el-input__suffix) {
-				padding-right: 10px;
-			}
-		}
-	}
-
-	.tips {
-		font-size: 14px;
-		color: #fff;
-		margin-bottom: 10px;
-
-		span {
-			&:first-of-type {
-				margin-right: 16px;
-			}
-		}
-	}
+	background: #fff;
+	display: flex;
+}
+.login_adv {
+	width: 33.33333%;
+	background-color: #555;
+	background-size: cover;
+	background-position: center center;
+	background-repeat: no-repeat;
+	position: relative;
+}
+.login_adv__title {
+	color: #fff;
+	padding: 40px;
+	position: absolute;
+	top: 0px;
+	left: 0px;
+	right: 0px;
+	z-index: 2;
+}
+.login_adv__title h2 {
+	font-size: 40px;
+}
+.login_adv__title h4 {
+	font-size: 18px;
+	margin-top: 10px;
+	font-weight: normal;
+}
+.login_adv__title p {
+	font-size: 14px;
+	margin-top: 10px;
+	line-height: 1.8;
+	color: rgba(255, 255, 255, 0.6);
+}
+.login_adv__title div {
+	margin-top: 10px;
+	display: flex;
+	align-items: center;
+}
+.login_adv__title div span {
+	margin-right: 15px;
+}
+.login_adv__title div i {
+	font-size: 40px;
+}
+.login_adv__title div i.add {
+	font-size: 20px;
+	color: rgba(255, 255, 255, 0.6);
+}
+.login_adv__bottom {
+	position: absolute;
+	left: 0px;
+	right: 0px;
+	bottom: 0px;
+	color: #fff;
+	padding: 40px;
+	background-image: linear-gradient(transparent, #000);
+	z-index: 3;
+}
+.login_adv__mask {
+	position: absolute;
+	top: 0px;
+	left: 0px;
+	right: 0px;
+	bottom: 0px;
+	z-index: 1;
+}
 
-	.svg-container {
-		padding-left: 10px;
-		color: $light_gray;
-		display: inline-block;
-	}
+.login_main {
+	flex: 1;
+	overflow: auto;
+	display: flex;
+}
+.login-form {
+	width: 400px;
+	margin: auto;
+	padding: 20px 0;
+}
+.login-header {
+	margin-bottom: 40px;
+}
+.login-header .logo {
+	display: flex;
+	align-items: center;
+}
+.login-header .logo img {
+	width: 40px;
+	height: 40px;
+	vertical-align: bottom;
+	margin-right: 10px;
+}
+.login-header .logo label {
+	font-size: 26px;
+	font-weight: bold;
+}
+.login-oauth {
+	display: flex;
+	justify-content: space-around;
+}
+.login-form .el-divider {
+	margin-top: 40px;
+}
 
-	.title-container {
-		display: flex;
-		align-items: center;
-		justify-content: space-between;
-		margin-bottom: 36px;
-		.title {
-			font-size: 24px;
-			color: $light_gray;
-			text-align: center;
-			font-weight: bold;
-		}
-		.set-language {
-			color: $light_gray;
-			font-size: 18px;
-			cursor: pointer;
-		}
-	}
+.login-form {
+}
+.login-form:deep(.el-tabs) .el-tabs__header {
+	margin-bottom: 25px;
+}
+.login-form:deep(.el-tabs) .el-tabs__header .el-tabs__item {
+	font-size: 14px;
+}
 
-	/*.captcha {
-		width: 100%;
-		&_placeholder {
-			height: 42px;
-			width: 100%;
-			text-align: center;
-			border-radius: 2px;
-			background-color: #f3f3f3;
-			color: #bbbbbb;
-			font-size: 14px;
-			letter-spacing: 0.1px;
-			line-height: 42px;
-		}
-		&_wait {
-			height: 42px;
-			width: 100%;
-			text-align: center;
-			border-radius: 2px;
-			background-color: #f3f3f3;
-		}
-	}*/
+.login-form:deep(.login-forgot) {
+	text-align: right;
+}
+.login-form:deep(.login-forgot) a {
+	color: var(--el-color-primary);
+}
+.login-form:deep(.login-forgot) a:hover {
+	color: var(--el-color-primary-light-3);
+}
+.login-form:deep(.login-reg) {
+	font-size: 14px;
+	color: var(--el-text-color-primary);
+}
+.login-form:deep(.login-reg) a {
+	color: var(--el-color-primary);
+}
+.login-form:deep(.login-reg) a:hover {
+	color: var(--el-color-primary-light-3);
+}
 
-	.loading {
-		margin: auto;
-		width: 70px;
-		height: 20px;
-		&-dot {
-			&:nth-child(1) {
-				animation-delay: 0s;
-			}
-			&:nth-child(2) {
-				animation-delay: 0.1s;
-			}
+.login_config {
+	position: absolute;
+	top: 20px;
+	right: 20px;
+}
 
-			&:nth-child(3) {
-				animation-delay: 0.2s;
-			}
+.login-form:deep(.login-msg-yzm) {
+	display: flex;
+	width: 100%;
+}
+.login-form:deep(.login-msg-yzm) .el-button {
+	margin-left: 10px;
+	--el-button-size: 42px;
+}
 
-			&:nth-child(4) {
-				animation-delay: 0.3s;
-			}
-			float: left;
-			width: 8px;
-			height: 8px;
-			margin: 18px 4px;
-			background: #ccc;
-			border-radius: 50%;
-			opacity: 0;
-			box-shadow: 0 0 2px black;
-			animation: loadingFade 1s infinite;
-		}
-	}
+.qrCodeLogin {
+	text-align: center;
+	position: relative;
+	padding: 20px 0;
+}
+.qrCodeLogin img.qrCode {
+	background: #fff;
+	padding: 20px;
+	border-radius: 10px;
+}
+.qrCodeLogin p.msg {
+	margin-top: 15px;
+}
+.qrCodeLogin .qrCodeLogin-result {
+	position: absolute;
+	top: 0;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	text-align: center;
+	background: var(--el-mask-color);
+}
 
-	@keyframes loadingFade {
-		0% {
-			opacity: 0;
-		}
-		50% {
-			opacity: 0.8;
-		}
-		100% {
-			opacity: 0;
-		}
+@media (max-width: 1200px) {
+	.login-form {
+		width: 340px;
 	}
 }
-@media screen and (max-width: 1200px) and (min-width: 576px) {
-	.login-container .login-left .login-left_svg {
-		position: absolute;
-		top: 76% !important;
-		left: 0 !important;
-		height: 24% !important;
-		margin: 0;
+@media (max-width: 1000px) {
+	.login_main {
+		display: block;
 	}
-
-	.login-container .login-right {
-		position: absolute;
-		top: 50%;
-		left: 50%;
-		transform: translate(-50%, -50%);
-		padding-top: 20px;
-		background: linear-gradient(145deg, var(--el-color-primary-light-5), var(--el-color-primary-light-7));
+	.login_main .login_config {
+		position: static;
+		padding: 20px 20px 0 20px;
+		text-align: right;
 	}
-}
-
-@media screen and (max-width: 576px) {
-	.login-container .login-left {
-		display: none;
-		/*.header {
-			display: none;
-		}*/
+	.login-form {
+		width: 100%;
+		padding: 20px 40px;
 	}
-	/*.login-container .login-left .login-left_svg {
-		position: absolute;
-		top: 82% !important;
-		left: 0 !important;
-		height: 18% !important;
-		margin: 0;
-	}*/
-	.login-container .title-container .title {
-		font-size: 20px;
+	.login_adv {
+		display: none;
 	}
 }
 </style>

+ 119 - 0
src/views/login/resetPassword.vue

@@ -0,0 +1,119 @@
+<template>
+	<common-page title="重置密码">
+		<el-steps :active="stepActive" simple finish-status="success">
+			<el-step title="填写新密码" />
+			<el-step title="完成重置" />
+		</el-steps>
+		<el-form v-if="stepActive == 0" ref="form" :model="form" :rules="rules" :label-width="120">
+			<el-form-item label="登录账号" prop="user">
+				<el-input v-model="form.user" placeholder="请输入登录账号"></el-input>
+				<div class="el-form-item-msg">请输入注册时填写的登录账号</div>
+			</el-form-item>
+			<el-form-item label="手机号码" prop="phone">
+				<el-input v-model="form.phone" placeholder="请输入手机号码"></el-input>
+			</el-form-item>
+			<el-form-item label="短信验证码" prop="yzm">
+				<div class="yzm">
+					<el-input v-model="form.yzm" placeholder="请输入6位短信验证码"></el-input>
+					<el-button :disabled="disabled" @click="getYzm"
+						>获取验证码<span v-if="disabled"> ({{ time }})</span></el-button
+					>
+				</div>
+			</el-form-item>
+			<el-form-item label="新密码" prop="newpw">
+				<el-input v-model="form.newpw" show-password placeholder="请输入新密码"></el-input>
+				<div class="el-form-item-msg">请输入包含英文、数字的8位以上密码</div>
+			</el-form-item>
+			<el-form-item label="确认新密码" prop="newpw2">
+				<el-input v-model="form.newpw2" show-password placeholder="请再一次输入新密码"></el-input>
+			</el-form-item>
+
+			<el-form-item>
+				<el-button type="primary" @click="save">提交</el-button>
+			</el-form-item>
+		</el-form>
+		<el-result v-if="stepActive == 1" icon="success" title="密码重置成功" sub-title="请牢记自己的新密码,返回登录后使用新密码登录">
+			<template #extra>
+				<el-button type="primary" @click="backLogin">返回登录</el-button>
+			</template>
+		</el-result>
+	</common-page>
+</template>
+
+<script>
+import commonPage from './components/commonPage'
+
+export default {
+	components: {
+		commonPage
+	},
+	data() {
+		return {
+			stepActive: 0,
+			form: {
+				user: '',
+				phone: '',
+				yzm: '',
+				newpw: '',
+				newpw2: ''
+			},
+			rules: {
+				user: [{ required: true, message: '请输入登录账号' }],
+				phone: [{ required: true, message: '请输入手机号' }],
+				yzm: [{ required: true, message: '请输入短信验证码' }],
+				newpw: [{ required: true, message: '请输入新的密码' }],
+				newpw2: [
+					{ required: true, message: '请再次输入新的密码' },
+					{
+						validator: (rule, value, callback) => {
+							if (value !== this.form.newpw) {
+								callback(new Error('两次输入密码不一致'))
+							} else {
+								callback()
+							}
+						}
+					}
+				]
+			},
+			disabled: false,
+			time: 0
+		}
+	},
+	mounted() {},
+	methods: {
+		async getYzm() {
+			var validate = await this.$refs.form.validateField('phone').catch(() => {})
+			if (!validate) {
+				return false
+			}
+
+			this.$message.success('已发送短信至手机号码')
+			this.disabled = true
+			this.time = 60
+			var t = setInterval(() => {
+				this.time -= 1
+				if (this.time < 1) {
+					clearInterval(t)
+					this.disabled = false
+					this.time = 0
+				}
+			}, 1000)
+		},
+		async save() {
+			var validate = await this.$refs.form.validate().catch(() => {})
+			if (!validate) {
+				return false
+			}
+
+			this.stepActive = 1
+		},
+		backLogin() {
+			this.$router.push({
+				path: '/login'
+			})
+		}
+	}
+}
+</script>
+
+<style scoped></style>

+ 165 - 0
src/views/login/userRegister.vue

@@ -0,0 +1,165 @@
+<template>
+	<common-page title="注册新账号">
+		<el-steps :active="stepActive" simple finish-status="success">
+			<el-step title="基础信息" />
+			<el-step title="详细信息" />
+			<el-step title="完成注册" />
+		</el-steps>
+		<el-form v-if="stepActive == 0" ref="stepForm_0" :model="form" :rules="rules" :label-width="120">
+			<el-form-item label="登录账号" prop="user">
+				<el-input v-model="form.user" placeholder="请输入登录账号"></el-input>
+				<div class="el-form-item-msg">登录账号将作为登录时的唯一凭证</div>
+			</el-form-item>
+			<el-form-item label="登录密码" prop="password">
+				<el-input v-model="form.password" type="password" show-password placeholder="请输入登录密码"></el-input>
+				<sc-password-strength v-model="form.password"></sc-password-strength>
+				<div class="el-form-item-msg">请输入包含英文、数字的8位以上密码</div>
+			</el-form-item>
+			<el-form-item label="确认密码" prop="password2">
+				<el-input v-model="form.password2" type="password" show-password placeholder="请再一次输入登录密码"></el-input>
+			</el-form-item>
+			<el-form-item label="" prop="agree">
+				<el-checkbox v-model="form.agree" label="">已阅读并同意</el-checkbox><span class="link" @click="showAgree = true">《平台服务协议》</span>
+			</el-form-item>
+		</el-form>
+		<el-form v-if="stepActive == 1" ref="stepForm_1" :model="form" :rules="rules" :label-width="120">
+			<el-form-item label="真实姓名" prop="userName">
+				<el-input v-model="form.userName" placeholder="请输入真实姓名"></el-input>
+			</el-form-item>
+			<el-form-item label="邮箱" prop="email">
+				<el-input v-model="form.email" placeholder="请输入邮箱地址"></el-input>
+			</el-form-item>
+			<el-form-item label="账号类型" prop="userType">
+				<el-radio-group v-model="form.userType">
+					<el-radio-button label="1">企业开发者</el-radio-button>
+					<el-radio-button label="2">企业开发者</el-radio-button>
+				</el-radio-group>
+			</el-form-item>
+			<el-form-item label="开通类别" prop="open">
+				<el-checkbox-group v-model="form.open">
+					<el-checkbox label="1">云存储API</el-checkbox>
+					<el-checkbox label="2">云检索API</el-checkbox>
+					<el-checkbox label="3">Javescript API</el-checkbox>
+				</el-checkbox-group>
+			</el-form-item>
+		</el-form>
+		<div v-if="stepActive == 2">
+			<el-result icon="success" title="注册成功" sub-title="可以使用登录账号以及手机号登录系统">
+				<template #extra>
+					<el-button type="primary" @click="goLogin">前去登录</el-button>
+				</template>
+			</el-result>
+		</div>
+		<el-form style="text-align: center">
+			<el-button v-if="stepActive > 0 && stepActive < 2" @click="pre">上一步</el-button>
+			<el-button v-if="stepActive < 1" type="primary" @click="next">下一步</el-button>
+			<el-button v-if="stepActive == 1" type="primary" @click="save">提交</el-button>
+		</el-form>
+		<el-dialog v-model="showAgree" title="平台服务协议" :width="800" destroy-on-close>
+			平台服务协议
+			<template #footer>
+				<el-button @click="showAgree = false">取消</el-button>
+				<el-button
+					type="primary"
+					@click="
+						showAgree = false
+						form.agree = true
+					"
+					>我已阅读并同意</el-button
+				>
+			</template>
+		</el-dialog>
+	</common-page>
+</template>
+
+<script>
+import scPasswordStrength from '@/components/scPasswordStrength'
+import commonPage from './components/commonPage'
+
+export default {
+	components: {
+		commonPage,
+		scPasswordStrength
+	},
+	data() {
+		return {
+			stepActive: 0,
+			showAgree: false,
+			form: {
+				user: '',
+				password: '',
+				password2: '',
+				agree: false,
+				userName: '',
+				email: '',
+				userType: '1',
+				open: []
+			},
+			rules: {
+				user: [{ required: true, message: '请输入账号名' }],
+				password: [{ required: true, message: '请输入密码' }],
+				password2: [
+					{ required: true, message: '请再次输入密码' },
+					{
+						validator: (rule, value, callback) => {
+							if (value !== this.form.password) {
+								callback(new Error('两次输入密码不一致'))
+							} else {
+								callback()
+							}
+						}
+					}
+				],
+				agree: [
+					{
+						validator: (rule, value, callback) => {
+							if (!value) {
+								callback(new Error('请阅读并同意协议'))
+							} else {
+								callback()
+							}
+						}
+					}
+				],
+				userName: [{ required: true, message: '请输入真实姓名' }],
+				email: [{ required: true, message: '请输入邮箱地址' }],
+				userType: [{ required: true, message: '请选择账户类型' }],
+				open: [{ required: true, message: '请选择开通类别' }]
+			}
+		}
+	},
+	mounted() {},
+	methods: {
+		pre() {
+			this.stepActive -= 1
+		},
+		next() {
+			const formName = `stepForm_${this.stepActive}`
+			this.$refs[formName].validate(valid => {
+				if (valid) {
+					this.stepActive += 1
+				} else {
+					return false
+				}
+			})
+		},
+		save() {
+			const formName = `stepForm_${this.stepActive}`
+			this.$refs[formName].validate(valid => {
+				if (valid) {
+					this.stepActive += 1
+				} else {
+					return false
+				}
+			})
+		},
+		goLogin() {
+			this.$router.push({
+				path: '/login'
+			})
+		}
+	}
+}
+</script>
+
+<style scoped></style>

+ 0 - 0
src/views/login/components/LoginMainSvg.vue → src/views/login1/components/LoginMainSvg.vue


+ 368 - 0
src/views/login1/index.vue

@@ -0,0 +1,368 @@
+<template>
+	<div class="login-container">
+		<div class="login-left">
+			<div class="header">
+				<img class="logo-img" src="@/assets/icons/logo.svg" alt="logo" />
+				{{ title }}
+			</div>
+			<ServerLogin class="login-left_svg" style="color: var(--el-color-primary)" />
+		</div>
+		<div class="login-right">
+			<el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
+				<div class="title-container">
+					<h3 class="title">{{ title }}</h3>
+					<lang-select class="set-language" />
+				</div>
+
+				<el-form-item prop="username">
+					<el-input
+						ref="username"
+						v-model="loginForm.username"
+						class="login-input"
+						:placeholder="$t('login1.username')"
+						name="username"
+						type="text"
+						tabindex="1"
+						auto-complete="on"
+					>
+						<template #prefix>
+							<span class="svg-container">
+								<svg-icon icon-class="user" />
+							</span>
+						</template>
+					</el-input>
+				</el-form-item>
+
+				<el-form-item prop="password">
+					<el-input
+						ref="passwordRef"
+						v-model="loginForm.password"
+						class="login-input"
+						type="password"
+						:placeholder="$t('login1.password')"
+						name="password"
+						tabindex="2"
+						auto-complete="on"
+						:show-password="true"
+						@keyup.enter="handleLogin"
+					>
+						<template #prefix>
+							<span class="svg-container">
+								<svg-icon icon-class="password" />
+							</span>
+						</template>
+					</el-input>
+				</el-form-item>
+
+				<el-button size="default" :loading="loading" type="primary" style="width: 100%; margin-bottom: 30px" @click.prevent="handleLogin"
+				>{{ $t('login1.login1') }}
+				</el-button>
+			</el-form>
+		</div>
+	</div>
+</template>
+
+<script setup lang="ts">
+import { onMounted, reactive, ref, toRefs, watch, nextTick } from 'vue'
+import ServerLogin from './components/LoginMainSvg.vue'
+// 组件依赖
+import LangSelect from '@/layout/components/Header/components/Language.vue'
+
+const title = import.meta.env.VITE_APP_TITLE
+// 状态管理依赖
+import useStore from '@/store'
+// API依赖
+// import { getGeetConfig } from '@/api/login1'
+import { useRoute } from 'vue-router'
+
+const { user } = useStore()
+const route = useRoute()
+
+const loginFormRef = ref(/*ElForm*/)
+const passwordRef = ref(/*ElInput*/)
+
+const state = reactive({
+	loginForm: {
+		username: 'admin',
+		password: '100607'
+	},
+	loginRules: {
+		username: [{ required: true, message: '用户名不能为空', trigger: 'blur' }],
+		password: [{ required: true, message: '密码不能为空', trigger: 'blur' }]
+	},
+	loading: false
+})
+
+const { loginForm, loginRules, loading } = toRefs(state)
+
+function handleLogin() {
+	loginFormRef.value.validate((valid: boolean) => {
+		if (valid) {
+			state.loading = true
+			user.login(state.loginForm).finally(() => {
+				state.loading = false
+			})
+		}
+	})
+}
+
+watch(
+	route,
+	() => {
+		const query = route.query
+		user.$patch({
+			loginQuery: query
+		})
+	},
+	{
+		immediate: true
+	}
+)
+</script>
+
+<style lang="scss" scoped>
+@import '@/styles/mixins.scss';
+//$light_gray: var(--el-input-icon-color);
+//$light_gray: #fff;
+$light_gray: var(--el-color-white);
+.login-container {
+	min-height: 100%;
+	width: 100%;
+	display: flex;
+	height: 100%;
+	overflow: hidden;
+	.login-left {
+		flex: 1;
+		display: flex;
+		flex-direction: column;
+		background: var(--el-color-primary-light-5);
+		.header {
+			margin-top: 80px;
+			display: flex;
+			align-items: center;
+			height: 78px;
+			padding: 0 20px;
+			color: #fff;
+			font-size: 22px;
+			@include hover-bg-opacity(0, #f00, 0.5);
+			&::before {
+				//background-color: var(--el-color-primary) !important;
+				background: linear-gradient(270deg, var(--el-color-primary-light-5), var(--el-color-primary-light-7));
+			}
+			.logo-img {
+				width: 50px;
+				margin-right: 10px;
+			}
+		}
+		.login-left_svg {
+			margin: 10% auto;
+			max-height: 500px;
+		}
+	}
+	.login-right {
+		width: 660px;
+		max-width: 100%;
+		background: linear-gradient(145deg, var(--el-color-primary-light-5), var(--el-color-white));
+	}
+	.login-form {
+		position: relative;
+		width: 360px;
+		max-width: 100%;
+		padding: 12px 24px;
+		margin: 0 auto;
+		overflow: hidden;
+		top: 30%;
+		//left: 50%;
+		//transform: translate(-50%, -50%);
+		:deep(.el-form-item) {
+			border: 1px solid rgba(255, 255, 255, 0.1);
+			background: rgba(0, 0, 0, 0.1);
+			border-radius: 5px;
+			color: #454545;
+			.el-input {
+				height: 47px;
+				.el-input__wrapper {
+					padding: 0;
+					background: transparent;
+					box-shadow: none;
+					.el-input__inner {
+						background: transparent;
+						border: 0;
+						-webkit-appearance: none;
+						border-radius: 0;
+						padding: 12px 8px;
+						//padding: 12px 0;
+						//padding-right: 8px;
+						color: $light_gray;
+						height: 47px;
+						caret-color: $light_gray;
+						&:-webkit-autofill {
+							box-shadow: 0 0 0px 1000px var(--el-color-primary-light-5) inset !important;
+							-webkit-text-fill-color: $light_gray !important;
+						}
+					}
+					.el-input__prefix-inner > :last-child {
+						margin-right: 0;
+					}
+					/*.el-input__suffix-inner > :first-child {
+						margin-left: 0;
+					}*/
+				}
+			}
+			.el-input__inner {
+				&:hover {
+					border-color: var(--el-input-hover-border, var(--el-border-color-hover));
+					box-shadow: none;
+				}
+
+				box-shadow: none;
+			}
+		}
+		.login-input {
+			//--el-input-icon-color: #fff;
+			--el-input-placeholder-color: #fafafa;
+			:deep(.el-input__suffix) {
+				padding-right: 10px;
+			}
+		}
+	}
+
+	.tips {
+		font-size: 14px;
+		color: #fff;
+		margin-bottom: 10px;
+
+		span {
+			&:first-of-type {
+				margin-right: 16px;
+			}
+		}
+	}
+
+	.svg-container {
+		padding-left: 10px;
+		color: $light_gray;
+		display: inline-block;
+	}
+
+	.title-container {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		margin-bottom: 36px;
+		.title {
+			font-size: 24px;
+			color: $light_gray;
+			text-align: center;
+			font-weight: bold;
+		}
+		.set-language {
+			color: $light_gray;
+			font-size: 18px;
+			cursor: pointer;
+		}
+	}
+
+	/*.captcha {
+		width: 100%;
+		&_placeholder {
+			height: 42px;
+			width: 100%;
+			text-align: center;
+			border-radius: 2px;
+			background-color: #f3f3f3;
+			color: #bbbbbb;
+			font-size: 14px;
+			letter-spacing: 0.1px;
+			line-height: 42px;
+		}
+		&_wait {
+			height: 42px;
+			width: 100%;
+			text-align: center;
+			border-radius: 2px;
+			background-color: #f3f3f3;
+		}
+	}*/
+
+	.loading {
+		margin: auto;
+		width: 70px;
+		height: 20px;
+		&-dot {
+			&:nth-child(1) {
+				animation-delay: 0s;
+			}
+			&:nth-child(2) {
+				animation-delay: 0.1s;
+			}
+
+			&:nth-child(3) {
+				animation-delay: 0.2s;
+			}
+
+			&:nth-child(4) {
+				animation-delay: 0.3s;
+			}
+			float: left;
+			width: 8px;
+			height: 8px;
+			margin: 18px 4px;
+			background: #ccc;
+			border-radius: 50%;
+			opacity: 0;
+			box-shadow: 0 0 2px black;
+			animation: loadingFade 1s infinite;
+		}
+	}
+
+	@keyframes loadingFade {
+		0% {
+			opacity: 0;
+		}
+		50% {
+			opacity: 0.8;
+		}
+		100% {
+			opacity: 0;
+		}
+	}
+}
+@media screen and (max-width: 1200px) and (min-width: 576px) {
+	.login-container .login-left .login-left_svg {
+		position: absolute;
+		top: 76% !important;
+		left: 0 !important;
+		height: 24% !important;
+		margin: 0;
+	}
+
+	.login-container .login-right {
+		position: absolute;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -50%);
+		padding-top: 20px;
+		background: linear-gradient(145deg, var(--el-color-primary-light-5), var(--el-color-primary-light-7));
+	}
+}
+
+@media screen and (max-width: 576px) {
+	.login-container .login-left {
+		display: none;
+		/*.header {
+			display: none;
+		}*/
+	}
+	/*.login1-container .login1-left .login1-left_svg {
+		position: absolute;
+		top: 82% !important;
+		left: 0 !important;
+		height: 18% !important;
+		margin: 0;
+	}*/
+	.login-container .title-container .title {
+		font-size: 20px;
+	}
+}
+</style>