From cbb00d4729243e4949b3c921fc2f94cb03ca8aaa Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期五, 27 三月 2026 18:47:43 +0800
Subject: [PATCH] #
---
src/main/webapp/static/js/login/login.js | 275 +++++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 245 insertions(+), 30 deletions(-)
diff --git a/src/main/webapp/static/js/login/login.js b/src/main/webapp/static/js/login/login.js
index b12ff13..2fb1a1b 100644
--- a/src/main/webapp/static/js/login/login.js
+++ b/src/main/webapp/static/js/login/login.js
@@ -11,15 +11,25 @@
localeOptions: [],
currentLocale: "zh-CN",
loginLoading: false,
+ passkeyLoading: false,
+ mfaLoading: false,
toolsDialogVisible: false,
textDialogVisible: false,
uploadDialogVisible: false,
+ mfaDialogVisible: false,
licenseBase64: "",
titleClickCount: 0,
titleClickTimer: null,
loginForm: {
mobile: "",
password: ""
+ },
+ mfaForm: {
+ code: ""
+ },
+ mfaPending: {
+ ticket: "",
+ username: ""
},
textDialog: {
title: "",
@@ -34,6 +44,21 @@
password: [
{ required: true, message: "璇疯緭鍏ュ瘑鐮�", trigger: "blur" }
]
+ },
+ mfaRules: {
+ code: [
+ { required: true, message: "璇疯緭鍏�6浣嶉獙璇佺爜", trigger: "blur" },
+ {
+ validator: function (rule, value, callback) {
+ if (!/^\d{6}$/.test(String(value || "").trim())) {
+ callback(new Error("璇疯緭鍏�6浣嶆暟瀛楅獙璇佺爜"));
+ return;
+ }
+ callback();
+ },
+ trigger: "blur"
+ }
+ ]
}
};
},
@@ -45,19 +70,50 @@
var localeTick = this.localeTick;
void localeTick;
if (window.WCS_I18N && typeof window.WCS_I18N.t === "function") {
- return window.WCS_I18N.t(key);
+ var translated = window.WCS_I18N.t(key);
+ if (translated && translated !== key) {
+ return translated;
+ }
}
return fallback || key;
+ },
+ refreshRuleMessages: function () {
+ var vm = this;
+ vm.loginRules = {
+ mobile: [
+ { required: true, message: vm.text("login.validation.usernameRequired", "璇疯緭鍏ヨ处鍙�"), trigger: "blur" }
+ ],
+ password: [
+ { required: true, message: vm.text("login.validation.passwordRequired", "璇疯緭鍏ュ瘑鐮�"), trigger: "blur" }
+ ]
+ };
+ vm.mfaRules = {
+ code: [
+ { required: true, message: vm.text("login.validation.mfaRequired", "璇疯緭鍏�6浣嶉獙璇佺爜"), trigger: "blur" },
+ {
+ validator: function (rule, value, callback) {
+ if (!/^\d{6}$/.test(String(value || "").trim())) {
+ callback(new Error(vm.text("login.validation.mfaInvalid", "璇疯緭鍏�6浣嶆暟瀛楅獙璇佺爜")));
+ return;
+ }
+ callback();
+ },
+ trigger: "blur"
+ }
+ ]
+ };
},
initLanguageSwitch: function () {
var vm = this;
if (!window.WCS_I18N || typeof window.WCS_I18N.onReady !== "function") {
+ vm.refreshRuleMessages();
return;
}
window.WCS_I18N.onReady(function (i18n) {
vm.localeOptions = i18n.getLocaleOptions();
vm.currentLocale = i18n.getLocale();
document.title = i18n.t("login.title");
+ vm.refreshRuleMessages();
vm.localeTick++;
});
},
@@ -97,6 +153,33 @@
return true;
});
},
+ handlePasskeyLogin: function () {
+ var vm = this;
+ if (!window.WCS_WEBAUTHN || !window.WCS_WEBAUTHN.isSupported()) {
+ vm.$message.error(vm.resolvePasskeyErrorMessage({ message: window.isSecureContext ? "not-supported" : "secure-context" }, "login.error.passkeyOptionsFailed", "鑾峰彇閫氳瀵嗛挜鐧诲綍鍙傛暟澶辫触"));
+ return;
+ }
+ vm.passkeyLoading = true;
+ ajaxJson({
+ url: baseUrl + "/login/passkey/options.action",
+ data: {
+ mobile: vm.loginForm.mobile
+ },
+ method: "POST",
+ success: function (res) {
+ if (Number(res.code) !== 200) {
+ vm.passkeyLoading = false;
+ vm.$message.error(res.msg || vm.text("login.error.passkeyOptionsFailed", "鑾峰彇閫氳瀵嗛挜鐧诲綍鍙傛暟澶辫触"));
+ return;
+ }
+ vm.executePasskeyLogin(res.data || {});
+ },
+ error: function () {
+ vm.passkeyLoading = false;
+ vm.$message.error(vm.text("login.error.passkeyOptionsFailed", "鑾峰彇閫氳瀵嗛挜鐧诲綍鍙傛暟澶辫触"));
+ }
+ });
+ },
submitLogin: function () {
var vm = this;
vm.loginLoading = true;
@@ -108,21 +191,143 @@
},
method: "POST",
success: function (res) {
+ var payload = res && res.data ? res.data : {};
if (Number(res.code) === 200) {
- localStorage.setItem("token", res.data.token);
- localStorage.setItem("username", res.data.username);
- window.location.href = "index.html";
- return;
- }
- vm.$message.error(res.msg || "鐧诲綍澶辫触");
+ if (payload.mfaRequired) {
+ vm.openMfaDialog(payload);
+ return;
+ }
+ vm.finishLogin(payload);
+ return;
+ }
+ vm.$message.error(res.msg || vm.text("login.error.loginFailed", "鐧诲綍澶辫触"));
},
error: function () {
- vm.$message.error("鐧诲綍澶辫触");
+ vm.$message.error(vm.text("login.error.loginFailed", "鐧诲綍澶辫触"));
},
complete: function () {
vm.loginLoading = false;
}
});
+ },
+ openMfaDialog: function (payload) {
+ this.mfaPending = {
+ ticket: payload.mfaTicket || "",
+ username: payload.username || this.loginForm.mobile || ""
+ };
+ this.mfaForm.code = "";
+ this.mfaDialogVisible = true;
+ if (this.$refs.mfaForm) {
+ this.$nextTick(function () {
+ this.$refs.mfaForm.clearValidate();
+ });
+ }
+ },
+ closeMfaDialog: function () {
+ this.mfaDialogVisible = false;
+ this.mfaLoading = false;
+ this.mfaPending = {
+ ticket: "",
+ username: ""
+ };
+ this.mfaForm.code = "";
+ if (this.$refs.mfaForm) {
+ this.$refs.mfaForm.clearValidate();
+ }
+ },
+ handleMfaLogin: function () {
+ var vm = this;
+ if (!vm.$refs.mfaForm) {
+ return;
+ }
+ vm.$refs.mfaForm.validate(function (valid) {
+ if (!valid) {
+ return false;
+ }
+ vm.submitMfaLogin();
+ return true;
+ });
+ },
+ submitMfaLogin: function () {
+ var vm = this;
+ if (!vm.mfaPending.ticket) {
+ vm.$message.error(vm.text("login.error.mfaTicketExpired", "鐧诲綍绁ㄦ嵁宸插け鏁堬紝璇烽噸鏂扮櫥褰�"));
+ vm.closeMfaDialog();
+ return;
+ }
+ vm.mfaLoading = true;
+ ajaxJson({
+ url: baseUrl + "/login/mfa.action",
+ data: {
+ ticket: vm.mfaPending.ticket,
+ code: vm.mfaForm.code
+ },
+ method: "POST",
+ success: function (res) {
+ if (Number(res.code) === 200) {
+ vm.finishLogin(res.data || {});
+ return;
+ }
+ vm.$message.error(res.msg || vm.text("login.error.mfaFailed", "楠岃瘉澶辫触"));
+ },
+ error: function () {
+ vm.$message.error(vm.text("login.error.mfaFailed", "楠岃瘉澶辫触"));
+ },
+ complete: function () {
+ vm.mfaLoading = false;
+ }
+ });
+ },
+ executePasskeyLogin: function (payload) {
+ var vm = this;
+ window.WCS_WEBAUTHN.authenticate(payload).then(function (assertion) {
+ ajaxJson({
+ url: baseUrl + "/login/passkey/verify.action",
+ data: {
+ ticket: payload.ticket,
+ credentialId: assertion.credentialId,
+ clientDataJSON: assertion.clientDataJSON,
+ authenticatorData: assertion.authenticatorData,
+ signature: assertion.signature
+ },
+ method: "POST",
+ success: function (res) {
+ if (Number(res.code) === 200) {
+ vm.finishLogin(res.data || {});
+ return;
+ }
+ vm.$message.error(res.msg || vm.text("login.error.passkeyVerifyFailed", "閫氳瀵嗛挜楠岃瘉澶辫触"));
+ },
+ error: function () {
+ vm.$message.error(vm.text("login.error.passkeyVerifyFailed", "閫氳瀵嗛挜楠岃瘉澶辫触"));
+ },
+ complete: function () {
+ vm.passkeyLoading = false;
+ }
+ });
+ }).catch(function (err) {
+ vm.passkeyLoading = false;
+ vm.$message.error(vm.resolvePasskeyErrorMessage(err, "login.error.passkeyVerifyFailed", "閫氳瀵嗛挜楠岃瘉澶辫触"));
+ });
+ },
+ finishLogin: function (payload) {
+ localStorage.setItem("token", payload.token || "");
+ localStorage.setItem("username", payload.username || this.loginForm.mobile || "");
+ this.closeMfaDialog();
+ window.location.href = "index.html";
+ },
+ resolvePasskeyErrorMessage: function (err, fallbackKey, fallbackText) {
+ var message = err && err.message ? String(err.message) : "";
+ if (message === "secure-context") {
+ return this.text("login.passkey.secureContext", "閫氳瀵嗛挜浠呮敮鎸佸湪 HTTPS 鎴� localhost 鐜涓嬩娇鐢�");
+ }
+ if (message === "not-supported" || message === "extension-unsupported" || message === "public-key-missing") {
+ return this.text("login.passkey.browserUnsupported", "褰撳墠娴忚鍣ㄤ笉鏀寔閫氳瀵嗛挜锛岃浣跨敤鏈�鏂扮増 Chrome銆丒dge 鎴� Safari");
+ }
+ if (err && err.name === "NotAllowedError") {
+ return this.text(fallbackKey, fallbackText);
+ }
+ return this.text(fallbackKey, fallbackText);
},
openTextDialog: function (title, label, text, tip) {
var pretty = "";
@@ -149,9 +354,9 @@
textarea.select();
document.execCommand("copy");
document.body.removeChild(textarea);
- this.$message.success("宸插鍒跺埌鍓创鏉�");
+ this.$message.success(this.text("login.dialog.copied", "宸插鍒跺埌鍓创鏉�"));
} catch (err) {
- this.$message.error("澶嶅埗澶辫触");
+ this.$message.error(this.text("login.dialog.copyFailed", "澶嶅埗澶辫触"));
}
},
copyText: function () {
@@ -159,7 +364,7 @@
var text = vm.textDialog.text || "";
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(function () {
- vm.$message.success("宸插鍒跺埌鍓创鏉�");
+ vm.$message.success(vm.text("login.dialog.copied", "宸插鍒跺埌鍓创鏉�"));
}).catch(function () {
vm.fallbackCopy(text);
});
@@ -174,13 +379,18 @@
method: "GET",
success: function (res) {
if (Number(res.code) === 200) {
- vm.openTextDialog("鑾峰彇璇锋眰鐮�", "璇锋眰鐮�", res.msg || "", "璇锋眰鐮佷腑宸插寘鍚」鐩悕绉帮紝鐩存帴鍙戠粰璁稿彲璇佹湇鍔$鍗冲彲銆�");
+ vm.openTextDialog(
+ vm.text("login.requestCode.title", "鑾峰彇璇锋眰鐮�"),
+ vm.text("login.requestCode.label", "璇锋眰鐮�"),
+ res.msg || "",
+ vm.text("login.requestCode.tip", "璇锋眰鐮佷腑宸插寘鍚」鐩悕绉帮紝鐩存帴鍙戠粰璁稿彲璇佹湇鍔$鍗冲彲銆�")
+ );
return;
}
- vm.$message.error(res.msg || "鑾峰彇璇锋眰鐮佸け璐�");
+ vm.$message.error(res.msg || vm.text("login.error.requestCodeFailed", "鑾峰彇璇锋眰鐮佸け璐�"));
},
error: function () {
- vm.$message.error("鑾峰彇璇锋眰鐮佸け璐�");
+ vm.$message.error(vm.text("login.error.requestCodeFailed", "鑾峰彇璇锋眰鐮佸け璐�"));
}
});
},
@@ -190,17 +400,22 @@
url: baseUrl + "/license/getServerInfos",
method: "GET",
success: function (res) {
- vm.openTextDialog("鑾峰彇绯荤粺閰嶇疆", "绯荤粺閰嶇疆淇℃伅", res, "鑰侀」鐩粛鍙户缁娇鐢ㄨ繖浠界‖浠朵俊鎭� JSON 鐢宠璁稿彲璇併��");
+ vm.openTextDialog(
+ vm.text("login.serverInfo.title", "鑾峰彇绯荤粺閰嶇疆"),
+ vm.text("login.serverInfo.label", "绯荤粺閰嶇疆淇℃伅"),
+ res,
+ vm.text("login.serverInfo.tip", "鑰侀」鐩粛鍙户缁娇鐢ㄨ繖浠界‖浠朵俊鎭� JSON 鐢宠璁稿彲璇併��")
+ );
},
error: function () {
- vm.$message.error("鑾峰彇绯荤粺閰嶇疆淇℃伅澶辫触");
+ vm.$message.error(vm.text("login.error.serverInfoFailed", "鑾峰彇绯荤粺閰嶇疆淇℃伅澶辫触"));
}
});
},
submitLicense: function () {
var vm = this;
if (!vm.licenseBase64) {
- vm.$message.warning("璁稿彲璇佸唴瀹逛笉鑳戒负绌�");
+ vm.$message.warning(vm.text("login.error.licenseEmpty", "璁稿彲璇佸唴瀹逛笉鑳戒负绌�"));
return;
}
ajaxJson({
@@ -212,35 +427,35 @@
if (Number(res.code) === 200) {
vm.uploadDialogVisible = false;
vm.licenseBase64 = "";
- vm.$message.success("璁稿彲璇佹洿鏂版垚鍔�");
+ vm.$message.success(vm.text("login.license.success", "璁稿彲璇佹洿鏂版垚鍔�"));
return;
}
- vm.$message.error(res.msg || "璁稿彲璇佹洿鏂板け璐�");
+ vm.$message.error(res.msg || vm.text("login.error.licenseUpdateFailed", "璁稿彲璇佹洿鏂板け璐�"));
},
error: function () {
- vm.$message.error("璁稿彲璇佸綍鍏ュけ璐�");
+ vm.$message.error(vm.text("login.error.licenseImportFailed", "璁稿彲璇佸綍鍏ュけ璐�"));
}
});
},
activateLicense: function () {
var vm = this;
- vm.$confirm("纭畾鎵ц涓�閿縺娲诲悧锛�", "鎻愮ず", {
+ vm.$confirm(vm.text("login.activate.confirm", "纭畾鎵ц涓�閿縺娲诲悧锛�"), vm.text("common.prompt", "鎻愮ず"), {
type: "warning",
- confirmButtonText: "纭畾",
- cancelButtonText: "鍙栨秷"
+ confirmButtonText: vm.text("common.ok", "纭畾"),
+ cancelButtonText: vm.text("login.mfa.cancel", "鍙栨秷")
}).then(function () {
ajaxJson({
url: baseUrl + "/license/activate",
method: "POST",
success: function (res) {
if (Number(res.code) === 200) {
- vm.$message.success("婵�娲绘垚鍔�");
+ vm.$message.success(vm.text("login.activate.success", "婵�娲绘垚鍔�"));
return;
}
- vm.$message.error(res.msg || "婵�娲诲け璐�");
+ vm.$message.error(res.msg || vm.text("login.activate.failed", "婵�娲诲け璐�"));
},
error: function () {
- vm.$message.error("婵�娲诲け璐�");
+ vm.$message.error(vm.text("login.activate.failed", "婵�娲诲け璐�"));
}
});
}).catch(function () {
@@ -253,15 +468,15 @@
method: "GET",
success: function (res) {
if (Number(res.code) === 200) {
- vm.$alert(res.msg || "", "椤圭洰鍚嶇О", {
- confirmButtonText: "纭畾"
+ vm.$alert(res.msg || "", vm.text("login.projectName.title", "椤圭洰鍚嶇О"), {
+ confirmButtonText: vm.text("common.ok", "纭畾")
});
return;
}
- vm.$message.error(res.msg || "鑾峰彇椤圭洰鍚嶇О澶辫触");
+ vm.$message.error(res.msg || vm.text("login.error.projectNameFailed", "鑾峰彇椤圭洰鍚嶇О澶辫触"));
},
error: function () {
- vm.$message.error("鑾峰彇椤圭洰鍚嶇О澶辫触");
+ vm.$message.error(vm.text("login.error.projectNameFailed", "鑾峰彇椤圭洰鍚嶇О澶辫触"));
}
});
}
--
Gitblit v1.9.1