From b9bd29a1a81f6f7de479e3cc3fdfe3d85fc660bf Mon Sep 17 00:00:00 2001
From: he wei <858544502@qq.com>
Date: 星期三, 23 四月 2025 13:35:06 +0800
Subject: [PATCH] UA 整理提交

---
 src/views/login/index.vue |  701 ++++++++++++++++++++++++++++++++--------------------------
 1 files changed, 386 insertions(+), 315 deletions(-)

diff --git a/src/views/login/index.vue b/src/views/login/index.vue
index e028f40..f4e1962 100644
--- a/src/views/login/index.vue
+++ b/src/views/login/index.vue
@@ -1,39 +1,81 @@
 <template>
   <div class="login-container">
-    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on"
-      label-position="left">
-  
-      <div class="title-container">
-        <h3 class="title">楦胯挋鏅鸿兘鐢靛瓙閿佺鐞嗗钩鍙�</h3>
-      </div>
-  
-      <el-form-item prop="username">
-        <span class="svg-container">
-          <svg-icon icon-class="user" />
-        </span>
-        <el-input ref="username" v-model="loginForm.username" placeholder="Username" name="username" type="text"
-          tabindex="1" autocomplete="on" />
-      </el-form-item>
-  
-      <el-tooltip v-model="capsTooltip" :content="passwordType === 'password' ?'鏄剧ず瀵嗙爜':'闅愯棌瀵嗙爜'" placement="right" manual>
-        <el-form-item prop="password">
+    <div class="site-title">
+      <svg-icon icon-class="lock1"></svg-icon>楦胯挋鏅鸿兘鐢靛瓙閿佺鐞嗗钩鍙�
+    </div>
+    <div class="img-hm"></div>
+    <div class="login-wrap">
+      <el-form
+        ref="loginFormRef"
+        :model="loginForm"
+        :rules="loginRules"
+        class="login-form"
+        autocomplete="on"
+        label-position="left"
+      >
+        <div class="title-container">
+          <h3 class="title">鐢ㄦ埛鐧诲綍</h3>
+        </div>
+        <el-form-item class="input-item" prop="username">
           <span class="svg-container">
-            <svg-icon icon-class="password" />
+            <svg-icon icon-class="user" />
           </span>
-          <el-input :key="passwordType" ref="password" v-model="loginForm.password" :type="passwordType"
-            placeholder="Password" name="password" tabindex="2" autocomplete="on" @keyup="checkCapslock"
-            @blur="capsTooltip = false" @keyup.enter="handleLogin" />
-          <span class="show-pwd" @click="showPwd">
-            <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
-          </span>
+          <el-input
+            ref="username"
+            v-model="loginForm.username"
+            placeholder="Username"
+            name="username"
+            type="text"
+            tabindex="1"
+            autocomplete="on"
+          />
         </el-form-item>
-      </el-tooltip>
-  
-      <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:40px;"
-        @click.prevent="handleLogin">鐧诲綍</el-button>
-    </el-form>
+        <el-tooltip
+          v-model="capsTooltip"
+          :content="passwordType === 'password' ?'鏄剧ず瀵嗙爜':'闅愯棌瀵嗙爜'"
+          placement="right"
+          manual
+        >
+          <el-form-item class="input-item" prop="password">
+            <span class="svg-container">
+              <svg-icon icon-class="password" />
+            </span>
+            <el-input
+              :key="passwordType"
+              ref="password"
+              v-model="loginForm.password"
+              :type="passwordType"
+              placeholder="Password"
+              name="password"
+              tabindex="2"
+              autocomplete="on"
+              @keyup="checkCapslock"
+              @blur="capsTooltip = false"
+              @keyup.enter="handleLogin"
+            />
+            <span class="show-pwd" @click="showPwd">
+              <svg-icon
+                :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"
+              />
+            </span>
+          </el-form-item>
+        </el-tooltip>
+        <el-button
+          :loading="loading"
+          type="primary"
+          style="width:100%; height:50px; margin-bottom:40px;"
+          @click.prevent="handleLogin"
+          >鐧诲綍</el-button
+        >
+      </el-form>
+    </div>
     <div class="tools-container">
-      <div class="tools-item" :class="uKeyState" v-if="uKey" @click="uKeyVisible = true">
+      <div
+        class="tools-item"
+        :class="uKeyState"
+        v-if="uKey"
+        @click="uKeyVisible = true"
+      >
         <span class="ukey"></span>
       </div>
       <div class="tools-item" v-if="faceCfg" @click="faceVisible = true">
@@ -41,295 +83,287 @@
       </div>
     </div>
     <!--  uKey鐨勯獙璇� -->
-    <el-dialog title="uKey缁戝畾" width="750px" v-model="uKeyVisible" :close-on-click-modal="false" top="0"
-      class="dialog-center" :modal-append-to-body="false">
+    <el-dialog
+      title="uKey缁戝畾"
+      width="750px"
+      v-model="uKeyVisible"
+      :close-on-click-modal="false"
+      top="0"
+      class="dialog-center"
+      :modal-append-to-body="false"
+    >
       <ukey-bind v-if="uKeyVisible" v-model:visible="uKeyVisible"></ukey-bind>
     </el-dialog>
-  
+
     <!-- 浜鸿劯鐧婚檰 -->
-    <el-dialog title="浜鸿劯鐧婚檰" width="480px" v-model="faceVisible" :close-on-click-modal="false" top="0"
-      class="dialog-center" :modal-append-to-body="false">
-      <face-login v-if="faceVisible" ></face-login>
+    <el-dialog
+      title="浜鸿劯鐧婚檰"
+      width="480px"
+      v-model="faceVisible"
+      :close-on-click-modal="false"
+      top="0"
+      class="dialog-center"
+      :modal-append-to-body="false"
+    >
+      <face-login v-if="faceVisible"></face-login>
     </el-dialog>
   </div>
 </template>
 
-<script lang="ts">
-	import { defineComponent } from 'vue';
-	import { ElMessage, type FormItemRule } from 'element-plus';
-	import type { IForm } from '@/types/element-plus';
-	import store from '@/store';
-	import { mapState } from 'pinia';
-	import config from '@/utils/config.js';
-	import UkeyBind from './components/UKeyBind/index.vue';
-	import useElement from '@/hooks/useElement.js';
-	import { uKeyLogin } from '@/api/user';
-  import FaceLogin from './components/face/FaceLogin.vue';
-	import { getToken, removeToken, setToken, getUname, setUname, removeUname, getUrole, setUrole, removeUrole } from '@/utils/auth';
+<script setup name="Login">
+import { ref, computed, reactive, watch, onMounted, nextTick } from 'vue';
+import { ElMessage } from 'element-plus';
 
-	const { $loading, $confirm, $message } = useElement();
-	const { ukey, face } = config;
+import { mapState } from 'pinia';
+import config from '@/utils/config.js';
+import UkeyBind from './components/UKeyBind/index.vue';
+import useElement from '@/hooks/useElement.js';
+import { uKeyLogin } from '@/api/user';
+import FaceLogin from './components/face/FaceLogin.vue';
+import { getToken, removeToken, setToken, getUname, setUname, removeUname, getUrole, setUrole, removeUrole } from '@/utils/auth';
+import { useUserStore } from '@/store/user';
+import { useSettingsStore } from '@/store/settings';
+import { useUKeyStore } from '@/store/ukey';
+import { storeToRefs } from 'pinia';
+import { useRoute, useRouter } from 'vue-router';
 
-	interface QueryType {
-		// 鑷畾涔塳ey 浠绘剰瀛楃涓�
-		[propname: string]: string
-	}
+const route = useRoute();
+const router = useRouter();
 
-	export default defineComponent({
-		name: 'Login',
-		data() {
-			const validateUsername: FormItemRule['validator'] = (_rule, value, callback) => {
-				if (!value.trim()) {
-					callback(new Error('璇疯緭鍏ョ敤鎴峰悕'));
-				} else {
-					callback();
-				}
-			};
-			const validatePassword: FormItemRule['validator'] = (_rule, value, callback) => {
-				if (value.length < 1) {
-					callback(new Error('璇疯緭鍏ュ瘑鐮侊紝鑷冲皯1浣�'));
-				} else {
-					callback();
-				}
-			};
-			return {
-				uKey: ukey,
-				faceCfg: face,
-				uKeyVisible: false,
-				faceVisible: false,
-				loginForm: {
-					username: '',
-					password: ''
-				},
-				loginRules: {
-					username: [{ required: true, trigger: 'blur', validator: validateUsername }],
-					password: [{ required: true, trigger: 'blur', validator: validatePassword }]
-				},
-				passwordType: 'password',
-				capsTooltip: false,
-				loading: false,
-				showDialog: false,
-				redirect: undefined,
-				otherQuery: {}
-			};
-		},
-		components: {
-			UkeyBind,
-      FaceLogin,
-		},
-		computed: {
+const userStore = useUserStore();
+const settingsStore = useSettingsStore();
+const ukeyStore = useUKeyStore();
 
-			uKeyState() {
-				let state = -1;
-				let uKey = store.ukey();
-				let cls = "state-error";
-				// 璁剧疆uKey鐨勭姸鎬�
-				if (uKey.connect) {
-					if (uKey.isIn) {
-						state = 1;
-					} else {
-						state = 0;
-					}
-				} else {
-					state = -1;
-				}
-				// 鏍规嵁鐘舵�佺‘瀹歶Key鍥捐〃鐨勯鑹�
-				switch (state) {
-					case 0:
-						cls = "state-default";
-						break;
-					case 1:
-						cls = "";
-						break;
-					default:
-						cls = "state-error";
-						break;
-				}
-				return cls;
-			},
-			...mapState(store.ukey, ['isIn', 'connect', 'id'])
-		},
-		watch: {
-			$route: {
-				handler: function (route) {
-					const query = route.query;
-					if (query) {
-						this.redirect = query.redirect;
-						this.otherQuery = this.getOtherQuery(query);
-					}
-				},
-				immediate: true
-			}
-		},
-		created() {
-			// window.addEventListener('storage', this.afterQRScan)
-		},
-		mounted() {
-			if (this.loginForm.username === '') {
-				(this.$refs.username as HTMLElement).focus();
-			} else if (this.loginForm.password === '') {
-				(this.$refs.password as HTMLElement).focus();
-			}
-			this.themeChange('blue-theme');
-		},
-		unmounted() {
-			// window.removeEventListener('storage', this.afterQRScan)
-		},
-		methods: {
-			themeChange(val) {
-				store.settings().changeSetting({
-					key: 'theme',
-					value: val
-				});
-			},
-			checkCapslock(e) {
-				const { key } = e;
-				this.capsTooltip = key && key.length === 1 && (key >= 'A' && key <= 'Z');
-			},
-			showPwd() {
-				if (this.passwordType === 'password') {
-					this.passwordType = '';
-				} else {
-					this.passwordType = 'password';
-				}
-				this.$nextTick(() => {
-					(this.$refs.password as HTMLElement).focus();
-				});
-			},
-			handleLogin() {
-				if (ukey) {
-					this.uKeyLoginFn();
-				} else {
-					this.normalLogin();
-				}
-			},
-			uKeyLoginFn() {
-				//
-				if (!this.connect) {
-					$message.error("璇峰厛瀹夎uKey瀹㈡埛绔湇鍔�");
-					return;
-				}
-				if (!this.isIn) {
-					$message.warning("璇峰厛鎻掑叆uKey");
-					return;
-				}
+const { isIn, connect, id } = storeToRefs(ukeyStore);
+const { login } = userStore;
+const { changeSetting } = settingsStore;
 
-				// 鏍¢獙鐢ㄦ埛
-				if (this.loginForm.username && this.loginForm.password) {
-					// 寮�鍚瓑寰呮
-					this.loading = true;
-					uKeyLogin(
-						this.loginForm.username,
-						this.loginForm.password,
-						this.id
-					)
-						.then((res) => {
-							// 瀵圭粨鏋滆繘琛屽鐞�
-							console.log('res', res, '=============');
-							let { code, data, data2, msg } = res;
-							this.loading = false;
-							if (code && data) {
-								setUname(data2.uname);
-								setToken('admin');
-								setUrole(data2.urole);
-								ElMessage({
-									message: msg,
-									type: 'success'
-								});
-								this.$router.push({ path: this.redirect || '/', query: this.otherQuery });
-							} else {
-								ElMessage({
-									message: msg,
-									type: 'error'
-								});
-							}
+const { $loading, $confirm, $message } = useElement();
+const { ukey: _ukey, face } = config;
 
-						})
-						.catch((error) => {
-							// 鍏抽棴绛夊緟
-							this.loading = false;
-							console.log(error);
-							$message.error("缃戠粶寮傚父");
-						});
-				} else {
-					$message.error("鐢ㄦ埛鍚嶆垨瀵嗙爜涓嶈兘涓虹┖");
-				}
-			},
-			normalLogin() {
-				(this.$refs.loginForm as IForm).validate(valid => {
-					return new Promise((resolve, reject) => {
-						if (valid) {
-							this.loading = true;
-							store.user().login(this.loginForm)
-								.then((res) => {
-									this.loading = false;
-									let { code, data, msg } = res;
-									if (code && data) {
-										ElMessage({
-											message: msg,
-											type: 'success'
-										});
-										this.$router.push({ path: this.redirect || '/', query: this.otherQuery });
-									} else {
-										ElMessage({
-											message: msg,
-											type: 'error'
-										});
-									}
-								}).catch((error) => {
-									this.loading = false;
-									// 璇锋眰澶辫触锛屽鐞嗛敊璇�
-									if (error.message === 'Network Error') {
-										// 濡傛灉鏄綉缁滈敊璇紝鏄剧ず涓枃娑堟伅
-										ElMessage({
-											message: '缃戠粶閿欒锛岃妫�鏌ユ偍鐨勭綉缁滆繛鎺ユ垨鏈嶅姟鍣ㄧ姸鎬併��',
-											type: 'error'
-										});
-									} else {
-										// 鍏朵粬绫诲瀷鐨勯敊璇紝鍙互鏍规嵁闇�瑕佸鐞�
-										ElMessage({
-											message: error,
-											type: 'warning'
-										});
-									}
-								}).finally(() => {
-									resolve();
-								});
-						} else {
-							console.log('error submit!!');
-							reject();
-						}
-					});
-				});
-			},
-			getOtherQuery(query: QueryType) {
-				return Object.keys(query).reduce((acc: QueryType, cur) => {
-					if (cur !== 'redirect') {
-						acc[cur] = query[cur];
-					}
-					return acc;
-				}, {});
-			}
-			// afterQRScan() {
-			//   if (e.key === 'x-admin-oauth-code') {
-			//     const code = getQueryObject(e.newValue)
-			//     const codeMap = {
-			//       wechat: 'code',
-			//       tencent: 'code'
-			//     }
-			//     const type = codeMap[this.auth_type]
-			//     const codeName = code[type]
-			//     if (codeName) {
-			//       store.user().LoginByThirdparty(codeName).then(() => {
-			//         this.$router.push({ path: this.redirect || '/' })
-			//       })
-			//     } else {
-			//       alert('绗笁鏂圭櫥褰曞け璐�')
-			//     }
-			//   }
-			// }
+const uKeyState = computed(() => {
+	let state = -1;
+	let cls = "state-error";
+	// 璁剧疆uKey鐨勭姸鎬�
+	if (connect.value) {
+		if (isIn.value) {
+			state = 1;
+		} else {
+			state = 0;
 		}
+	} else {
+		state = -1;
+	}
+	// 鏍规嵁鐘舵�佺‘瀹歶Key鍥捐〃鐨勯鑹�
+	switch (state) {
+		case 0:
+			cls = "state-default";
+			break;
+		case 1:
+			cls = "";
+			break;
+		default:
+			cls = "state-error";
+			break;
+	}
+	return cls;
+});
+
+const validateUsername = (_rule, value, callback) => {
+	if (!value.trim()) {
+		callback(new Error('璇疯緭鍏ョ敤鎴峰悕'));
+	} else {
+		callback();
+	}
+};
+const validatePassword = (_rule, value, callback) => {
+	if (value.length < 1) {
+		callback(new Error('璇疯緭鍏ュ瘑鐮侊紝鑷冲皯1浣�'));
+	} else {
+		callback();
+	}
+};
+
+const uKey = ref(_ukey);
+const faceCfg = ref(face);
+
+const uKeyVisible = ref(false);
+const faceVisible = ref(false);
+const loginFormRef = ref();
+const username = ref();
+const password = ref();
+const loginForm = reactive({
+	username: '',
+	password: ''
+});
+const loginRules = reactive({
+	username: [{ required: true, trigger: 'blur', validator: validateUsername }],
+	password: [{ required: true, trigger: 'blur', validator: validatePassword }]
+});
+
+const passwordType = ref('password');
+const capsTooltip = ref(false);
+const loading = ref(false);
+const showDialog = ref(false);
+const redirect = ref(undefined);
+const otherQuery = ref({});
+
+watch(
+	() => route.path,
+	() => {
+		let query = route.query;
+		if (query) {
+			redirect.value = query.redirect;
+			otherQuery.value = getOtherQuery(query);
+		}
+	},
+	{
+		immediate: true
+	}
+);
+
+onMounted(() => {
+	if (loginForm.username === '') {
+		username.value.focus();
+	} else if (loginForm.password === '') {
+		password.value.focus();
+	}
+	themeChange('blue-theme');
+});
+
+function themeChange(val) {
+	changeSetting({
+		key: 'theme',
+		value: val
 	});
+}
+
+function checkCapslock(e) {
+	const { key } = e;
+	capsTooltip.value = key && key.length === 1 && (key >= 'A' && key <= 'Z');
+}
+
+function showPwd() {
+	if (passwordType.value === 'password') {
+		passwordType.value = '';
+	} else {
+		passwordType.value = 'password';
+	}
+	nextTick(() => {
+		password.value.focus();
+	})
+}
+
+function handleLogin() {
+	if (uKey.value) {
+		uKeyLoginFn();
+	} else {
+		normalLogin();
+	}
+}
+
+function uKeyLoginFn() {
+	if (!connect.value) {
+		$message.error("璇峰厛瀹夎uKey瀹㈡埛绔湇鍔�");
+		return;
+	}
+	if (!isIn.value) {
+		$message.warning("璇峰厛鎻掑叆uKey");
+		return;
+	}
+	// 鏍¢獙鐢ㄦ埛
+	if (loginForm.username && loginForm.password) {
+		// 寮�鍚瓑寰呮
+		loading.value = true;
+		uKeyLogin(
+			loginForm.username,
+			loginForm.password,
+			id.value
+		)
+			.then((res) => {
+				let { code, data, data2, msg } = res;
+				loading.value = false;
+				if (code && data) {
+					setUname(data2.uname);
+					setToken('admin');
+					setUrole(data2.urole);
+					ElMessage({
+						message: msg,
+						type: 'success'
+					});
+					router.push({ path: redirect.value || '/', query: otherQuery.value });
+				} else {
+					ElMessage({
+						message: msg,
+						type: 'error'
+					});
+				}
+			}).catch((error) => {
+				loading.value = false;
+				console.log(error);
+				$message.error("缃戠粶寮傚父");
+			})
+	} else {
+		$message.error("鐢ㄦ埛鍚嶆垨瀵嗙爜涓嶈兘涓虹┖");
+	}
+}
+
+function normalLogin() {
+	loginFormRef.value.validate(valid => {
+		return new Promise((resolve, reject) => {
+			if (valid) {
+				loading.value = true;
+				login(loginForm)
+					.then((res) => {
+						loading.value = false;
+						let { code, data, msg } = res;
+						if (code && data) {
+							ElMessage({
+								message: msg,
+								type: 'success'
+							});
+							router.push({ path: redirect.value || '/', query: otherQuery.value });
+						} else {
+							ElMessage({
+								message: msg,
+								type: 'error'
+							});
+						}
+					}).catch((error) => {
+						loading.value = false;
+						console.log('error', error, '=============');
+
+						if (error?.message === 'Network Error') {
+							// 濡傛灉鏄綉缁滈敊璇紝鏄剧ず涓枃娑堟伅
+							ElMessage({
+								message: '缃戠粶閿欒锛岃妫�鏌ユ偍鐨勭綉缁滆繛鎺ユ垨鏈嶅姟鍣ㄧ姸鎬併��',
+								type: 'error'
+							});
+						} else {
+							ElMessage({
+								message: error,
+								type: 'warning'
+							});
+						}
+					}).finally(() => {
+						loading.value = false;
+						resolve();
+					});
+			} else {
+				reject();
+			}
+		})
+	});
+}
+
+function getOtherQuery(query) {
+	return Object.keys(query).reduce((acc, cur) => {
+		if (cur !== 'redirect') {
+			acc[cur] = query[cur];
+		}
+		return acc;
+	}, {});
+}
 </script>
 
 <style lang="scss">
@@ -338,7 +372,9 @@
 
 $bg: #283443;
 $light_gray: #fff;
-$cursor: #fff;
+$cursor: #999;
+$input_bg: rgba(0, 0, 0, 0.1);
+$input_color: #000;
 
 @supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
   .login-container .el-input input {
@@ -363,13 +399,13 @@
 
     input {
       padding: 12px 5px 12px 15px;
-      color: $light_gray;
+      color: $input_color;
       height: 47px;
       caret-color: $cursor;
 
       &:-webkit-autofill {
-        box-shadow: 0 0 0px 1000px $bg inset !important;
-        -webkit-text-fill-color: $cursor !important;
+        box-shadow: 0 0 0px 1000px $input_bg inset !important;
+        -webkit-text-fill-color: $input_color !important;
       }
     }
   }
@@ -391,19 +427,43 @@
 .login-container {
   min-height: 100%;
   width: 100%;
-  background-image: url("./images/login_bg.jpg");
+  background-image: url("@/assets/images/login-bg.jpg");
   background-size: 100% 100%;
   background-repeat: no-repeat;
   overflow: hidden;
 
-  .login-form {
+  .login-wrap {
+    // display: none;
     position: relative;
     width: 520px;
     max-width: 100%;
-    padding: 36px 35px 36px;
+    // margin: 260px 10% 0 auto;
     margin: 260px auto 0;
+    transform: translate(clamp(0px, calc(36vw - 50%), 50vw), 0);
+    padding: 8px;
     overflow: hidden;
-    background-color: #1d4167;
+    // background-color: #1d4167;
+    background: rgba(255, 255, 255, 0.2);
+    border: 2px solid #0d3c68;
+
+    .login-form {
+      background: #fff;
+      padding: 36px 70px 36px;
+      border: 2px solid #064ec3;
+    }
+    .input-item {
+      margin-bottom: 28px;
+    }
+  }
+
+  .site-title {
+    font-size: 30px;
+    font-weight: 700;
+    color: #07fcff;
+    position: absolute;
+    left: 0;
+    top: 12%;
+    transform: translate(clamp(0px, calc(18vw - 50%), 50vw), -50%);
   }
 
   .tips {
@@ -418,6 +478,16 @@
     }
   }
 
+  .img-hm {
+    position: absolute;
+    width: clamp(500px, 50vw, 800px);
+    height: clamp(300px, 80vh, 80vh);
+    background: url(@/assets/images/img-hm.png) center center / contain no-repeat;
+    left: 0;
+    top: 20%;
+    transform: translate(clamp(0px, calc(24vw - 50%), 50vw), 0);
+  }
+
   .svg-container {
     padding: 6px 5px 6px 15px;
     color: $dark_gray;
@@ -430,10 +500,10 @@
     position: relative;
 
     .title {
-      font-size: 26px;
-      color: $light_gray;
+      font-size: 18px;
+      color: #0296f3;
       margin: 0px auto 40px auto;
-      text-align: center;
+      // text-align: center;
       font-weight: bold;
     }
   }
@@ -506,6 +576,7 @@
   .tools-container .state-error .iconfont {
     color: #ff0000;
   }
+
   :deep(.dialog-center) {
     box-sizing: content-box;
   }

--
Gitblit v1.9.1