From 1a3f0ed6b7f6d4112069a3c8679e7192365d5eef Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期二, 31 三月 2026 12:38:44 +0800
Subject: [PATCH] #电视机退回时入库站点也显示信息

---
 src/main/webapp/static/js/detail/detail.js |  382 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 357 insertions(+), 25 deletions(-)

diff --git a/src/main/webapp/static/js/detail/detail.js b/src/main/webapp/static/js/detail/detail.js
index 2c4c7d5..5a80ca2 100644
--- a/src/main/webapp/static/js/detail/detail.js
+++ b/src/main/webapp/static/js/detail/detail.js
@@ -15,18 +15,48 @@
                 saving: false,
                 passwordDialogVisible: false,
                 passwordSaving: false,
+                mfaDialogVisible: false,
+                mfaDialogMode: "enable",
+                mfaSetupLoading: false,
+                mfaSubmitting: false,
+                passkeyDialogVisible: false,
+                passkeyDialogMode: "register",
+                passkeySubmitting: false,
                 form: {
                     id: "",
                     roleName: "",
                     username: "",
                     mobile: "",
-                    password: "",
-                    createTime$: ""
+                    createTime$: "",
+                    mfaAllow: 0,
+                    mfaAllow$: "鍚�",
+                    mfaEnabled: 0,
+                    mfaEnabled$: "鍚�",
+                    mfaBoundTime$: "",
+                    mfaMaskedSecret: "",
+                    passkeyBound: false,
+                    passkeyName: "",
+                    passkeyBoundTime$: "",
+                    passkeyLastUsedTime$: "",
+                    passkeyTransports: ""
                 },
                 passwordForm: {
                     oldPassword: "",
                     password: "",
                     rePassword: ""
+                },
+                mfaForm: {
+                    currentPassword: "",
+                    code: ""
+                },
+                mfaSetup: {
+                    secret: "",
+                    qrCode: "",
+                    otpAuth: ""
+                },
+                passkeyForm: {
+                    name: "",
+                    currentPassword: ""
                 },
                 rules: {
                     username: [
@@ -38,25 +68,7 @@
                 },
                 passwordRules: {
                     oldPassword: [
-                        { required: true, message: "璇疯緭鍏ュ綋鍓嶅瘑鐮�", trigger: "blur" },
-                        {
-                            validator: function (rule, value, callback) {
-                                if (!value) {
-                                    callback(new Error("璇疯緭鍏ュ綋鍓嶅瘑鐮�"));
-                                    return;
-                                }
-                                if (!this.form.password) {
-                                    callback(new Error("鏈鍙栧埌褰撳墠鐢ㄦ埛瀵嗙爜"));
-                                    return;
-                                }
-                                if (hex_md5(value) !== this.form.password) {
-                                    callback(new Error("瀵嗙爜涓嶅尮閰�"));
-                                    return;
-                                }
-                                callback();
-                            }.bind(this),
-                            trigger: "blur"
-                        }
+                        { required: true, message: "璇疯緭鍏ュ綋鍓嶅瘑鐮�", trigger: "blur" }
                     ],
                     password: [
                         { required: true, message: "璇疯緭鍏ユ柊瀵嗙爜", trigger: "blur" },
@@ -70,7 +82,7 @@
                                     callback(new Error("涓嶈兘灏戜簬4涓瓧绗�"));
                                     return;
                                 }
-                                if (this.form.password && hex_md5(value) === this.form.password) {
+                                if (value === this.passwordForm.oldPassword) {
                                     callback(new Error("涓庢棫瀵嗙爜涓嶈兘鐩稿悓"));
                                     return;
                                 }
@@ -91,6 +103,29 @@
                             }.bind(this),
                             trigger: "blur"
                         }
+                    ]
+                },
+                mfaRules: {
+                    currentPassword: [
+                        { required: true, message: "璇疯緭鍏ュ綋鍓嶅瘑鐮�", trigger: "blur" }
+                    ],
+                    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"
+                        }
+                    ]
+                },
+                passkeyRules: {
+                    currentPassword: [
+                        { required: true, message: "璇疯緭鍏ュ綋鍓嶅瘑鐮�", trigger: "blur" }
                     ]
                 }
             };
@@ -155,10 +190,10 @@
                 var vm = this;
                 vm.passwordSaving = true;
                 $.ajax({
-                    url: baseUrl + "/user/update/auth",
+                    url: baseUrl + "/user/password/update/auth",
                     headers: { token: localStorage.getItem("token") },
                     data: {
-                        id: vm.form.id,
+                        oldPassword: hex_md5(vm.passwordForm.oldPassword),
                         password: hex_md5(vm.passwordForm.password)
                     },
                     method: "POST",
@@ -170,7 +205,6 @@
                             vm.$message.error(res.msg || "瀵嗙爜淇敼澶辫触");
                             return;
                         }
-                        vm.form.password = hex_md5(vm.passwordForm.password);
                         vm.passwordDialogVisible = false;
                         vm.$alert("瀵嗙爜淇敼鎴愬姛锛岃閲嶆柊鐧诲綍", "鎻愮ず", {
                             confirmButtonText: "纭畾",
@@ -188,6 +222,304 @@
                     }
                 });
             },
+            openMfaEnableDialog: function () {
+                if (Number(this.form.mfaAllow) !== 1) {
+                    this.$message.warning("褰撳墠璐﹀彿鏈紑閫歁FA浣跨敤鏉冮檺");
+                    return;
+                }
+                this.mfaDialogMode = "enable";
+                this.resetMfaDialogState();
+                this.mfaDialogVisible = true;
+                this.loadMfaSetup();
+            },
+            openMfaDisableDialog: function () {
+                this.mfaDialogMode = "disable";
+                this.resetMfaDialogState();
+                this.mfaDialogVisible = true;
+            },
+            closeMfaDialog: function () {
+                this.mfaDialogVisible = false;
+                this.resetMfaDialogState();
+            },
+            resetMfaDialogState: function () {
+                this.mfaSubmitting = false;
+                this.mfaSetupLoading = false;
+                this.mfaForm = {
+                    currentPassword: "",
+                    code: ""
+                };
+                this.mfaSetup = {
+                    secret: "",
+                    qrCode: "",
+                    otpAuth: ""
+                };
+                if (this.$refs.mfaForm) {
+                    this.$refs.mfaForm.clearValidate();
+                }
+            },
+            loadMfaSetup: function () {
+                var vm = this;
+                vm.mfaSetupLoading = true;
+                $.ajax({
+                    url: baseUrl + "/user/mfa/setup/auth",
+                    headers: { token: localStorage.getItem("token") },
+                    method: "POST",
+                    success: function (res) {
+                        if (handleForbidden(res)) {
+                            return;
+                        }
+                        if (Number(res.code) !== 200) {
+                            vm.$message.error(res.msg || "MFA閰嶇疆鍔犺浇澶辫触");
+                            return;
+                        }
+                        vm.mfaSetup = Object.assign({}, vm.mfaSetup, res.data || {});
+                    },
+                    error: function () {
+                        vm.$message.error("MFA閰嶇疆鍔犺浇澶辫触");
+                    },
+                    complete: function () {
+                        vm.mfaSetupLoading = false;
+                    }
+                });
+            },
+            handleMfaSubmit: function () {
+                var vm = this;
+                if (!vm.$refs.mfaForm) {
+                    return;
+                }
+                vm.$refs.mfaForm.validate(function (valid) {
+                    if (!valid) {
+                        return false;
+                    }
+                    if (vm.mfaDialogMode === "enable" && !vm.mfaSetup.secret) {
+                        vm.$message.error("MFA瀵嗛挜灏氭湭鐢熸垚锛岃绋嶅悗閲嶈瘯");
+                        return false;
+                    }
+                    vm.submitMfaAction();
+                    return true;
+                });
+            },
+            submitMfaAction: function () {
+                var vm = this;
+                vm.mfaSubmitting = true;
+                $.ajax({
+                    url: baseUrl + (vm.mfaDialogMode === "enable" ? "/user/mfa/enable/auth" : "/user/mfa/disable/auth"),
+                    headers: { token: localStorage.getItem("token") },
+                    data: {
+                        currentPassword: hex_md5(vm.mfaForm.currentPassword),
+                        code: vm.mfaForm.code,
+                        secret: vm.mfaSetup.secret
+                    },
+                    method: "POST",
+                    success: function (res) {
+                        if (handleForbidden(res)) {
+                            return;
+                        }
+                        if (Number(res.code) !== 200) {
+                            vm.$message.error(res.msg || "MFA鎿嶄綔澶辫触");
+                            return;
+                        }
+                        vm.$message.success(vm.mfaDialogMode === "enable" ? "MFA宸插惎鐢�" : "MFA宸插仠鐢�");
+                        vm.closeMfaDialog();
+                        vm.loadDetail();
+                    },
+                    error: function () {
+                        vm.$message.error("MFA鎿嶄綔澶辫触");
+                    },
+                    complete: function () {
+                        vm.mfaSubmitting = false;
+                    }
+                });
+            },
+            openPasskeyRegisterDialog: function () {
+                if (!window.WCS_WEBAUTHN || !window.WCS_WEBAUTHN.isSupported()) {
+                    this.$message.error(this.resolvePasskeyErrorMessage({ message: window.isSecureContext ? "not-supported" : "secure-context" }, "褰撳墠鐜涓嶆敮鎸侀�氳瀵嗛挜"));
+                    return;
+                }
+                this.passkeyDialogMode = "register";
+                this.resetPasskeyDialogState();
+                this.passkeyDialogVisible = true;
+            },
+            openPasskeyRemoveDialog: function () {
+                this.passkeyDialogMode = "remove";
+                this.resetPasskeyDialogState();
+                this.passkeyDialogVisible = true;
+            },
+            closePasskeyDialog: function () {
+                this.passkeyDialogVisible = false;
+                this.resetPasskeyDialogState();
+            },
+            resetPasskeyDialogState: function () {
+                this.passkeySubmitting = false;
+                this.passkeyForm = {
+                    name: "",
+                    currentPassword: ""
+                };
+                if (this.$refs.passkeyForm) {
+                    this.$refs.passkeyForm.clearValidate();
+                }
+            },
+            handlePasskeySubmit: function () {
+                var vm = this;
+                if (!vm.$refs.passkeyForm) {
+                    return;
+                }
+                vm.$refs.passkeyForm.validate(function (valid) {
+                    if (!valid) {
+                        return false;
+                    }
+                    if (vm.passkeyDialogMode === "register") {
+                        vm.submitPasskeyRegister();
+                    } else {
+                        vm.submitPasskeyRemove();
+                    }
+                    return true;
+                });
+            },
+            submitPasskeyRegister: function () {
+                var vm = this;
+                if (!window.WCS_WEBAUTHN || !window.WCS_WEBAUTHN.isSupported()) {
+                    vm.$message.error(vm.resolvePasskeyErrorMessage({ message: window.isSecureContext ? "not-supported" : "secure-context" }, "褰撳墠鐜涓嶆敮鎸侀�氳瀵嗛挜"));
+                    return;
+                }
+                vm.passkeySubmitting = true;
+                $.ajax({
+                    url: baseUrl + "/user/passkey/register/options/auth",
+                    headers: { token: localStorage.getItem("token") },
+                    method: "POST",
+                    success: function (res) {
+                        if (handleForbidden(res)) {
+                            return;
+                        }
+                        if (Number(res.code) !== 200) {
+                            vm.passkeySubmitting = false;
+                            vm.$message.error(res.msg || "閫氳瀵嗛挜閰嶇疆鍔犺浇澶辫触");
+                            return;
+                        }
+                        vm.executePasskeyRegister(res.data || {});
+                    },
+                    error: function () {
+                        vm.passkeySubmitting = false;
+                        vm.$message.error("閫氳瀵嗛挜閰嶇疆鍔犺浇澶辫触");
+                    }
+                });
+            },
+            executePasskeyRegister: function (optionsPayload) {
+                var vm = this;
+                window.WCS_WEBAUTHN.register(optionsPayload).then(function (credential) {
+                    $.ajax({
+                        url: baseUrl + "/user/passkey/register/finish/auth",
+                        headers: { token: localStorage.getItem("token") },
+                        data: {
+                            ticket: optionsPayload.ticket,
+                            currentPassword: hex_md5(vm.passkeyForm.currentPassword),
+                            name: vm.passkeyForm.name,
+                            credentialId: credential.credentialId,
+                            clientDataJSON: credential.clientDataJSON,
+                            authenticatorData: credential.authenticatorData,
+                            publicKey: credential.publicKey,
+                            publicKeyAlgorithm: credential.publicKeyAlgorithm,
+                            transports: credential.transports
+                        },
+                        method: "POST",
+                        success: function (res) {
+                            if (handleForbidden(res)) {
+                                return;
+                            }
+                            if (Number(res.code) !== 200) {
+                                vm.$message.error(res.msg || "閫氳瀵嗛挜缁戝畾澶辫触");
+                                return;
+                            }
+                            vm.$message.success("閫氳瀵嗛挜宸茬粦瀹�");
+                            vm.closePasskeyDialog();
+                            vm.loadDetail();
+                        },
+                        error: function () {
+                            vm.$message.error("閫氳瀵嗛挜缁戝畾澶辫触");
+                        },
+                        complete: function () {
+                            vm.passkeySubmitting = false;
+                        }
+                    });
+                }).catch(function (err) {
+                    vm.passkeySubmitting = false;
+                    vm.$message.error(vm.resolvePasskeyErrorMessage(err, "閫氳瀵嗛挜缁戝畾澶辫触"));
+                });
+            },
+            submitPasskeyRemove: function () {
+                var vm = this;
+                vm.passkeySubmitting = true;
+                $.ajax({
+                    url: baseUrl + "/user/passkey/remove/auth",
+                    headers: { token: localStorage.getItem("token") },
+                    data: {
+                        currentPassword: hex_md5(vm.passkeyForm.currentPassword)
+                    },
+                    method: "POST",
+                    success: function (res) {
+                        if (handleForbidden(res)) {
+                            return;
+                        }
+                        if (Number(res.code) !== 200) {
+                            vm.$message.error(res.msg || "閫氳瀵嗛挜瑙g粦澶辫触");
+                            return;
+                        }
+                        vm.$message.success("閫氳瀵嗛挜宸茶В缁�");
+                        vm.closePasskeyDialog();
+                        vm.loadDetail();
+                    },
+                    error: function () {
+                        vm.$message.error("閫氳瀵嗛挜瑙g粦澶辫触");
+                    },
+                    complete: function () {
+                        vm.passkeySubmitting = false;
+                    }
+                });
+            },
+            resolvePasskeyErrorMessage: function (err, fallback) {
+                var message = err && err.message ? String(err.message) : "";
+                if (message === "secure-context") {
+                    return "閫氳瀵嗛挜浠呮敮鎸佸湪 HTTPS 鎴� localhost 鐜涓嬩娇鐢�";
+                }
+                if (message === "not-supported" || message === "extension-unsupported" || message === "public-key-missing") {
+                    return "褰撳墠娴忚鍣ㄤ笉鏀寔閫氳瀵嗛挜锛岃浣跨敤鏈�鏂扮増 Chrome銆丒dge 鎴� Safari";
+                }
+                if (err && err.name === "NotAllowedError") {
+                    return "宸插彇娑堥�氳瀵嗛挜鎿嶄綔鎴栭獙璇佽秴鏃�";
+                }
+                return fallback || "閫氳瀵嗛挜鎿嶄綔澶辫触";
+            },
+            copySecret: function () {
+                var vm = this;
+                var text = vm.mfaSetup.secret || "";
+                if (!text) {
+                    return;
+                }
+                if (navigator.clipboard && navigator.clipboard.writeText) {
+                    navigator.clipboard.writeText(text).then(function () {
+                        vm.$message.success("瀵嗛挜宸插鍒�");
+                    }).catch(function () {
+                        vm.fallbackCopy(text);
+                    });
+                    return;
+                }
+                vm.fallbackCopy(text);
+            },
+            fallbackCopy: function (text) {
+                try {
+                    var textarea = document.createElement("textarea");
+                    textarea.value = text;
+                    textarea.style.position = "fixed";
+                    textarea.style.opacity = "0";
+                    document.body.appendChild(textarea);
+                    textarea.select();
+                    document.execCommand("copy");
+                    document.body.removeChild(textarea);
+                    this.$message.success("瀵嗛挜宸插鍒�");
+                } catch (err) {
+                    this.$message.error("澶嶅埗澶辫触");
+                }
+            },
             handleSave: function () {
                 var vm = this;
                 vm.$refs.profileForm.validate(function (valid) {

--
Gitblit v1.9.1