From be1cd9e5b30097ca427a9c2b7b054b28854e410a Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期三, 11 三月 2026 13:21:36 +0800
Subject: [PATCH] #

---
 src/main/webapp/views/detail.html |  217 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 211 insertions(+), 6 deletions(-)

diff --git a/src/main/webapp/views/detail.html b/src/main/webapp/views/detail.html
index 4985baa..301d6b2 100644
--- a/src/main/webapp/views/detail.html
+++ b/src/main/webapp/views/detail.html
@@ -108,6 +108,65 @@
             flex: 0 0 118px;
         }
 
+        .mfa-panel {
+            border: 1px solid rgba(222, 230, 239, 0.92);
+            border-radius: 14px;
+            background: #f8fbff;
+            padding: 14px 16px;
+        }
+
+        .mfa-head {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            gap: 12px;
+            margin-bottom: 10px;
+        }
+
+        .mfa-title {
+            font-size: 14px;
+            font-weight: 700;
+            color: #2f4358;
+        }
+
+        .mfa-actions {
+            display: flex;
+            gap: 10px;
+            flex-wrap: wrap;
+        }
+
+        .mfa-meta {
+            display: grid;
+            grid-template-columns: repeat(3, minmax(0, 1fr));
+            gap: 10px;
+        }
+
+        .mfa-meta-item {
+            padding: 10px 12px;
+            border-radius: 12px;
+            background: rgba(255, 255, 255, 0.95);
+            border: 1px solid rgba(226, 233, 242, 0.96);
+        }
+
+        .mfa-meta-label {
+            font-size: 12px;
+            color: #7b8b9b;
+            margin-bottom: 6px;
+        }
+
+        .mfa-meta-value {
+            font-size: 13px;
+            color: #2f4358;
+            word-break: break-all;
+        }
+
+        .mfa-tip {
+            margin-top: 10px;
+            font-size: 12px;
+            line-height: 1.7;
+            color: #7b8b9b;
+        }
+
         .footer-bar {
             display: flex;
             justify-content: flex-end;
@@ -123,18 +182,21 @@
             overflow: hidden;
         }
 
-        .password-dialog .el-dialog__header {
+        .password-dialog .el-dialog__header,
+        .mfa-dialog .el-dialog__header {
             padding: 18px 20px 12px;
             border-bottom: 1px solid rgba(222, 230, 239, 0.92);
             background: #f8fbff;
         }
 
-        .password-dialog .el-dialog__title {
+        .password-dialog .el-dialog__title,
+        .mfa-dialog .el-dialog__title {
             font-weight: 700;
             color: var(--text-main);
         }
 
-        .password-dialog .el-dialog__body {
+        .password-dialog .el-dialog__body,
+        .mfa-dialog .el-dialog__body {
             padding: 18px 20px 12px;
         }
 
@@ -169,18 +231,77 @@
             padding-top: 4px;
         }
 
+        .mfa-setup {
+            margin-bottom: 16px;
+            padding: 14px;
+            border-radius: 14px;
+            background: rgba(248, 251, 255, 0.92);
+            border: 1px solid rgba(226, 233, 242, 0.96);
+        }
+
+        .mfa-setup-tip {
+            font-size: 12px;
+            line-height: 1.7;
+            color: #738396;
+            margin-bottom: 12px;
+        }
+
+        .mfa-qr-wrap {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            min-height: 220px;
+            margin-bottom: 14px;
+            background: #fff;
+            border-radius: 14px;
+            border: 1px dashed rgba(210, 220, 233, 0.96);
+        }
+
+        .mfa-qr-wrap img {
+            width: 220px;
+            height: 220px;
+            object-fit: contain;
+        }
+
+        .mfa-secret-row {
+            display: flex;
+            gap: 10px;
+            align-items: center;
+        }
+
+        .mfa-secret-row .el-input {
+            flex: 1;
+        }
+
+        .mfa-footer {
+            display: flex;
+            justify-content: center;
+            gap: 12px;
+            padding-top: 6px;
+        }
+
         @media (max-width: 768px) {
             .page-shell {
                 padding: 10px;
             }
 
-            .password-row {
+            .password-row,
+            .mfa-secret-row {
                 flex-direction: column;
                 align-items: stretch;
             }
 
             .form-shell {
                 max-width: none;
+            }
+
+            .mfa-head {
+                flex-direction: column;
+                align-items: stretch;
+            }
+
+            .mfa-meta {
+                grid-template-columns: 1fr;
             }
         }
     </style>
@@ -194,7 +315,6 @@
         <div class="card-body">
             <div class="form-shell">
                 <input id="id" type="hidden" v-model="form.id">
-                <input id="password" type="hidden" v-model="form.password">
                 <el-form
                     ref="profileForm"
                     class="profile-form"
@@ -229,6 +349,48 @@
                                 <div class="password-row">
                                     <el-input class="password-mask" value="宸茶缃瘑鐮�" disabled></el-input>
                                     <el-button type="primary" plain icon="el-icon-lock" @click="openPasswordDialog">淇敼瀵嗙爜</el-button>
+                                </div>
+                            </el-form-item>
+                        </el-col>
+                        <el-col :xs="24">
+                            <el-form-item label="MFA">
+                                <div class="mfa-panel">
+                                    <div class="mfa-head">
+                                        <div class="mfa-title">澶氬洜瀛愮櫥褰曢獙璇�</div>
+                                        <div class="mfa-actions">
+                                            <el-button
+                                                v-if="Number(form.mfaAllow) === 1 && Number(form.mfaEnabled) !== 1"
+                                                type="primary"
+                                                plain
+                                                icon="el-icon-key"
+                                                @click="openMfaEnableDialog">鍚敤 MFA</el-button>
+                                            <el-button
+                                                v-if="Number(form.mfaEnabled) === 1"
+                                                type="danger"
+                                                plain
+                                                icon="el-icon-switch-button"
+                                                @click="openMfaDisableDialog">鍋滅敤 MFA</el-button>
+                                        </div>
+                                    </div>
+                                    <div class="mfa-meta">
+                                        <div class="mfa-meta-item">
+                                            <div class="mfa-meta-label">璐﹀彿鎺堟潈</div>
+                                            <div class="mfa-meta-value">{{ form.mfaAllow$ || '--' }}</div>
+                                        </div>
+                                        <div class="mfa-meta-item">
+                                            <div class="mfa-meta-label">鍚敤鐘舵��</div>
+                                            <div class="mfa-meta-value">{{ form.mfaEnabled$ || '--' }}</div>
+                                        </div>
+                                        <div class="mfa-meta-item">
+                                            <div class="mfa-meta-label">缁戝畾鏃堕棿</div>
+                                            <div class="mfa-meta-value">{{ form.mfaBoundTime$ || '--' }}</div>
+                                        </div>
+                                    </div>
+                                    <div class="mfa-tip">
+                                        <span v-if="Number(form.mfaAllow) !== 1">褰撳墠璐﹀彿鏈紑閫� MFA 浣跨敤鏉冮檺锛岃鑱旂郴绠$悊鍛樻巿鏉冦��</span>
+                                        <span v-else-if="Number(form.mfaEnabled) === 1">宸茬粦瀹氬瘑閽ワ細{{ form.mfaMaskedSecret || '--' }}銆傜櫥褰曟椂闇�瑕佸啀杈撳叆涓�娆″姩鎬侀獙璇佺爜銆�</span>
+                                        <span v-else>褰撳墠璐﹀彿宸插厑璁镐娇鐢� MFA锛屽惎鐢ㄥ悗鐧诲綍浼氬鍔犱竴娆� 6 浣嶅姩鎬侀獙璇佺爜鏍¢獙銆�</span>
+                                    </div>
                                 </div>
                             </el-form-item>
                         </el-col>
@@ -271,6 +433,49 @@
             </div>
         </el-form>
     </el-dialog>
+
+    <el-dialog
+        class="mfa-dialog"
+        :title="mfaDialogMode === 'enable' ? '鍚敤 MFA' : '鍋滅敤 MFA'"
+        :visible.sync="mfaDialogVisible"
+        width="520px"
+        :close-on-click-modal="false"
+        @close="closeMfaDialog"
+        append-to-body>
+        <div v-if="mfaDialogMode === 'enable'" class="mfa-setup">
+            <div class="mfa-setup-tip">璇峰厛浣跨敤 Google Authenticator銆丮icrosoft Authenticator 绛夎韩浠介獙璇佸櫒鎵弿浜岀淮鐮侊紝鍐嶈緭鍏ュ綋鍓嶅瘑鐮佸拰 6 浣嶅姩鎬佺爜瀹屾垚缁戝畾銆�</div>
+            <div class="mfa-qr-wrap" v-loading="mfaSetupLoading">
+                <img v-if="mfaSetup.qrCode" :src="mfaSetup.qrCode" alt="MFA QR Code">
+                <span v-else>浜岀淮鐮佺敓鎴愪腑...</span>
+            </div>
+            <div class="mfa-secret-row">
+                <el-input :value="mfaSetup.secret" readonly placeholder="MFA瀵嗛挜"></el-input>
+                <el-button plain @click="copySecret">澶嶅埗瀵嗛挜</el-button>
+            </div>
+        </div>
+        <div v-else class="mfa-setup">
+            <div class="mfa-setup-tip">鍋滅敤 MFA 鍓嶏紝璇疯緭鍏ュ綋鍓嶅瘑鐮佸拰韬唤楠岃瘉鍣ㄤ腑鐨� 6 浣嶅姩鎬佺爜杩涜纭銆�</div>
+        </div>
+        <el-form
+            ref="mfaForm"
+            class="password-form"
+            :model="mfaForm"
+            :rules="mfaRules"
+            label-width="112px"
+            size="small"
+            @submit.native.prevent>
+            <el-form-item label="褰撳墠瀵嗙爜" prop="currentPassword">
+                <el-input v-model="mfaForm.currentPassword" type="password" show-password autocomplete="off"></el-input>
+            </el-form-item>
+            <el-form-item label="鍔ㄦ�侀獙璇佺爜" prop="code">
+                <el-input v-model.trim="mfaForm.code" maxlength="6" autocomplete="off" placeholder="璇疯緭鍏�6浣嶉獙璇佺爜"></el-input>
+            </el-form-item>
+            <div class="mfa-footer">
+                <el-button @click="closeMfaDialog">鍏抽棴</el-button>
+                <el-button type="primary" :loading="mfaSubmitting" @click="handleMfaSubmit">淇濆瓨</el-button>
+            </div>
+        </el-form>
+    </el-dialog>
 </div>
 </body>
 <script type="text/javascript" src="../static/js/jquery/jquery-3.3.1.min.js"></script>
@@ -278,5 +483,5 @@
 <script type="text/javascript" src="../static/js/common.js"></script>
 <script type="text/javascript" src="../static/vue/js/vue.min.js"></script>
 <script type="text/javascript" src="../static/vue/element/element.js"></script>
-<script type="text/javascript" src="../static/js/detail/detail.js?v=20260310_detail_vue3"></script>
+<script type="text/javascript" src="../static/js/detail/detail.js?v=20260311_detail_mfa"></script>
 </html>

--
Gitblit v1.9.1