From 2d87b60a58734fd5ecbd1496bf250aaa1fefea29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A7=8B=E7=94=B0=E5=BC=98?= <1240092443@qq.com> Date: Fri, 10 Jan 2025 11:37:12 +0800 Subject: [PATCH] =?UTF-8?q?add=EF=BC=9Athirdlogin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/assets/login/email.png | Bin 0 -> 2574 bytes frontend/src/assets/login/login.png | Bin 0 -> 4793 bytes .../src/components/desktop/LockDesktop.vue | 305 ++++++++++++++++-- frontend/src/stores/login.ts | 3 + frontend/src/system/dinglogin.ts | 8 +- frontend/src/system/index.ts | 14 +- frontend/src/system/qiyeweixinlogin.ts | 3 +- frontend/src/system/third_login.ts | 62 ++++ go.mod | 2 +- go.sum | 1 + 10 files changed, 355 insertions(+), 43 deletions(-) create mode 100644 frontend/src/assets/login/email.png create mode 100644 frontend/src/assets/login/login.png create mode 100644 frontend/src/system/third_login.ts diff --git a/frontend/src/assets/login/email.png b/frontend/src/assets/login/email.png new file mode 100644 index 0000000000000000000000000000000000000000..b61d780d4e6aa1ef9c8396033e1935aa6fbcbf08 GIT binary patch literal 2574 zcmdUx`9G9<8^>p+Tkg@~#u!t?Z8w+^hr~G@Gt*ecGCgkF%t&bxc~UZ^BbAsaOKHLx zQBn+9G9k-oQHjZNqRo;>)(Ry@vduGi=DN%&$HBM&^mh;2mN@Mt>Tqyg98ml`&LS!RHd4^CPqH4z8=@1vH1@>2XjzhxzjS# za_ieHBV{Fex=j+lM*yU=s!hRT=>li|L^ZJXBWnR@P$-^d2btX3dQ~T(S5cm#k-2=e z);xd|x@l|heC)~SJKQHsNU9r}+RRW9SbD4bUghu<~B&YGI{yy}w?MPws;W z^J-$ED&Wz3>ib7ElGNZ7JiTSw?~JCVX(cgnp)5w96Yq_ydZJPj;8OmmI#nY%Uux(! zYg37N1o#hsnsGgzl^3~ky;R-90$qaCYhfen!PUag(|&7;_~)EK*iCKPleY>Blola3 zZh=^UEX-r=Lzk%5H#M4w(z)`Na0&oP#O_s{1}MQJCKX8-;Y)k{HAEbUcocEM)KCJyX7(`RtvtKY_YJlQ^W_7ZZpmkg|HvQo(ren*NUJ?e zx!46J)Do_p?7wS2Ha4X?^6;)+v)c!b3l&#x##|luevf0=&_+#Vx!w_)c>BEm0W9tm z;oTdmU3e9um10>c+1v>w-0LAn?`H*wc0cT^m+&WKIDlQpE}d#{6AiLtw>p_fg{hJS03DE>GBB%s`7AP5rm81OlRF->TEFJx_*ijMXSIaK7 zMY}zHN10uoZH=4!uu&m1DY_W(+GCuU?&VK`+iTgUfI^Fws{1w0PKwcD z&3%e;IhA+)$)EiCX!nnNrqGj0|G7Z1tLIZCB;NHEiWFZmlj4sY3{!~RdDixdlwtD= zeU8R?U9+a~$XB=&8?+;6x|ZL#pn*SzZ~LzOI7AcRO7`SzN$&~YR9%Bj!`pB>11u)q z&xv&uMEi;tpVRV95405LO;#7SgVneE59pg}b)6$PENHZ4xhm&EiT=|eANsbrbw(6f zPXJNmjxW!&7Bt*V>s?4MggX88G2d)=7FH5>N9bZ+Hfmn_r8gFcx*gfZT{PxL7PZD$ zYzouuRvD?%>^N$$x20#15V+4PyE&Wzg*1#2WXB`geX6p%5EI5BVPzzDf>{>jq_6*? z4nDI$S=$JiIH)1=myP*uZBbuI0m7%LPkwdgz25d$N8E{;K>FHReudMI41q8vJP+Z( zt@`fiy03;LGgZ+HkuNSRec$Zs%o_FwQ)P<3W4SbxyEiYC5PR4R)z;`BrSsE<)r9^~&zX?vJc13cDKkg~)1b)~87Iah75M`1<| zRhHyAO>uSw{J#S#ifEXbf$hRUZ;eOp})MKUTKU2pCfi{&UqMNiJ@_@2dV=_ z|ISEr!~))~?hnMMigF?Jx0gvLk}4 zV`AvMGLwc94H^_J0U}Z`!Wv&MfwyTqJn4q-Q^x|~rMY7T|1X1wKYbsqn7X4q-wGts zJ^~|CGBwG9dG*f-05a0%;p}Os`}lmDA5!erYudWvy9fvP;%_J&jl2Ir@ws??PB64L zo(3-MPd+-ZwDexP^$Y>N>i%~Ar}+(~VYb+uBkbM=*9BOel2-9mtSo8tSU8_*UDP`1&omDYS3k=@3AJxJwPs)#y9PdylJWyY{1R-eCn8) z>Ne@GYw54!9Y0vIHP@_Lt?yp!bP!!6xt&`bY>YcIw%Ht1s2NWtmI@zOJFr!323{2m zmK8j(MA&b$bi$PA>JBk3{iX-m=|*%>bKEuVuqSTzm~POrZDU}xWz(CW8$LeI1Wzo1 zGnWiSf^L#ktQZ~`w+VuYC(Y-X5j1B0&eBUKoBFi>gX`b21*AhNc<5A18Ai4&)aTESn9m zKov)`C*(9nc#*8Ms>%&RxAaf4%Ry}`)cqmDQk@2+`R(!wMYBr|QVIRn<%_D)9qfpN S<#l8<;9*$KY^IbEEc^#5i(p3p literal 0 HcmV?d00001 diff --git a/frontend/src/assets/login/login.png b/frontend/src/assets/login/login.png new file mode 100644 index 0000000000000000000000000000000000000000..6b5509f473d89d3f97a40d8b5ff8692d086a7963 GIT binary patch literal 4793 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 @@ -175,10 +172,7 @@ - 返回 + 返回 @@ -186,21 +180,26 @@
- - + + - - + @@ -208,7 +207,7 @@
+
+ + + + + + + + + + + + + + + + + + + + + + + + + 返回 + + 登录 + + +
+
+ + + + + + + + + + 返回 + + + 登录 @@ -246,7 +327,7 @@ import router from "@/system/router"; import { RestartApp } from "@/util/goutil"; import { notifyError } from "@/util/msg"; - import { onMounted, ref, watchEffect } from "vue"; + import { computed, onMounted, ref, watchEffect } from "vue"; import { useRoute } from "vue-router"; const route = useRoute(); const store = useLoginStore(); @@ -255,11 +336,31 @@ const config = getSystemConfig(); const lockClassName = ref("screen-show"); + const backToLogin = () => { + store.ThirdPartyLoginMethod = "login"; + localStorage.removeItem("ThirdPartyPlatform"); + }; + const phoneForm = ref({ phone: "", code: "", }); + const emailForm = ref({ + email: "", + code: "", + }); + + const thirdpartyCode = ref(""); + + const validateAndLoginByThirdparty = () => { + if (thirdpartyCode.value === "") { + notifyError("请输入第三方登录码"); + return; + } + onLogin(thirdpartyCode.value); + }; + // 声明 DTFrameLogin 和 WwLogin 方法 declare global { interface Window { @@ -303,8 +404,8 @@ state?: string; // 登录成功后获取到的state } - onMounted(() => { - getThirdpartyList(); + onMounted(async () => { + await getThirdpartyList(); }); const getThirdpartyList = async () => { @@ -312,10 +413,20 @@ config.userInfo.url + "/user/thirdparty/list" ); if (result.ok) { - await result.json(); + const data = await result.json(); + store.thirdpartyList = data.data.list; + console.log(data); + } + }; + + const isPlatformAvailable = (platform: string) => { + for (let i = 0; i < store.thirdpartyList.length; i++) { + if (store.thirdpartyList[i] === platform) { + return true; + } } + return false; }; - const onDingDingScan = () => { store.ThirdPartyLoginMethod = "dingding"; @@ -375,9 +486,34 @@ const sendCodeButtonText = ref("发送验证码"); const isSendCodeButtonDisabled = ref(false); - const onSendCode = () => { - console.log("发送验证码"); - startCountdown(); + const onSendCode = async () => { + try { + const response = await fetch( + config.userInfo.url + "/user/emailcode", + { + method: "POST", + body: JSON.stringify({ email: emailForm.value.email }), + } + ); + + console.log(response); + + if (!response.ok) { + notifyError("发送验证码失败,请重试"); + return; + } + + const result = await response.json(); + if (result.success) { + console.log("验证码发送成功"); + startEmailCountdown(); + } else { + notifyError(result.message || "发送验证码失败,请重试"); + } + } catch (error) { + console.error("发送验证码时发生错误", error); + notifyError("发送验证码时发生错误,请重试"); + } }; const startCountdown = () => { @@ -397,6 +533,26 @@ }, 1000); }; + const sendEmailCodeButtonText = ref("发送验证码"); + const isSendEmailCodeButtonDisabled = ref(false); + + const startEmailCountdown = () => { + let countdown = 2; + isSendEmailCodeButtonDisabled.value = true; + sendEmailCodeButtonText.value = `${countdown}秒后重试`; + + const interval = setInterval(() => { + countdown--; + if (countdown > 0) { + sendEmailCodeButtonText.value = `${countdown}秒后重试`; + } else { + clearInterval(interval); + sendEmailCodeButtonText.value = "发送验证码"; + isSendEmailCodeButtonDisabled.value = false; + } + }, 1000); + }; + const thirdPartyPlatforms = [ { name: "qyweixin", @@ -418,8 +574,22 @@ name: "gitee", icon: new URL("@/assets/login/gitee.png", import.meta.url).href, }, + { + name: "email", + icon: new URL("@/assets/login/email.png", import.meta.url).href, + }, + { + name: "thirdparty", + icon: new URL("@/assets/login/login.png", import.meta.url).href, + }, ]; + const availablePlatforms = computed(() => { + return thirdPartyPlatforms.filter((platform) => + isPlatformAvailable(platform.name) + ); + }); + function loginSuccess() { lockClassName.value = "screen-hidean"; setTimeout(() => { @@ -436,7 +606,7 @@ userPassword.value = sys._options.login?.password || ""; } else { userName.value = config.userInfo.username; - userPassword.value = config.userInfo.password; + // userPassword.value = config.userInfo.password; } }); @@ -463,8 +633,9 @@ qq: "qq", dingding: "dingtalk_scan", phone: "sms_code", + email: "email", + thirdparty: "third_api", }; - // 获取对应的参数名称 const codeParam = platform ? platformCodeMap[platform] : null; @@ -472,12 +643,27 @@ let param; if (codeParam) { if (platform === "phone") { - param = { phone: phoneForm.value.phone, sms_code: code }; + param = { + phone: phoneForm.value.phone, + sms_code: phoneForm.value.code, + }; + } else if (platform === "email") { + param = { + email: emailForm.value.email, + code: emailForm.value.code, + }; + } else if (platform === "thirdparty") { + param = { + unionid: thirdpartyCode.value, + }; } else { param = { code: code }; } } else { - param = { username: userName.value, password: userPassword.value }; + param = { + username: userName.value, + password: userPassword.value, + }; } const login_type = codeParam ? codeParam : "password"; @@ -488,7 +674,7 @@ localStorage.removeItem("ThirdPartyPlatform"); loginSuccess(); } else { - notifyError("登录失败,请重试"); + console.log("登录失败"); } } } @@ -510,6 +696,11 @@ message: "用户名长度应在3到20个字符之间", trigger: "blur", }, + { + pattern: /^[a-zA-Z0-9]+$/, + message: "用户名只能包含英文和数字", + trigger: "blur", + }, ], password: [ { required: true, message: "密码不能为空", trigger: "blur" }, @@ -635,6 +826,16 @@ return await authWithPhone(); }; break; + case "email": + loginFunction = async function () { + return await authWithEmail(); + }; + break; + case "thirdparty": + loginFunction = async function () { + return await authWithThirdParty(); + }; + break; default: notifyError("不支持的第三方登录平台"); return; @@ -648,13 +849,14 @@ } }; - const authWithPhone = async (): Promise => { - store.ThirdPartyLoginMethod = "phone"; + const authWithThirdParty = async (): Promise => { + store.ThirdPartyLoginMethod = "thirdparty"; return true; }; - const loginByPhone = async () => { - await onLogin(); + const authWithPhone = async (): Promise => { + store.ThirdPartyLoginMethod = "phone"; + return true; }; const authWithDingDing = async (): Promise => { @@ -762,6 +964,41 @@ // store.page = "phone"; // return true; }; + + const authWithEmail = async (): Promise => { + store.ThirdPartyLoginMethod = "email"; + return true; + }; + + const loginByEmail = async () => { + await onLogin(); + }; + + const phoneLoginFormRef: any = ref(null); + + const phoneLoginRules = { + phone: [ + { required: true, message: "手机号不能为空", trigger: "blur" }, + { + pattern: /^\d{11}$/, + message: "手机号格式不正确,必须为11位有效数字", + trigger: "blur", + }, + ], + code: [ + { required: true, message: "验证码不能为空", trigger: "blur" }, + { + pattern: /^\d{4,6}$/, + message: "验证码必须为4到6位数字", + trigger: "blur", + }, + ], + }; + + const validateAndLoginByPhone = async () => { + await phoneLoginFormRef.value.validate(); + onLogin(); + };