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

---
 src/main/webapp/views/login.html |  150 +++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 118 insertions(+), 32 deletions(-)

diff --git a/src/main/webapp/views/login.html b/src/main/webapp/views/login.html
index 01e5ad2..0bc4ab7 100644
--- a/src/main/webapp/views/login.html
+++ b/src/main/webapp/views/login.html
@@ -260,27 +260,57 @@
         }
 
         .login-submit {
-            width: 100%;
             display: inline-flex;
             align-items: center;
             justify-content: center;
             font-size: 16px;
             font-weight: 600;
             border-radius: 16px;
-            margin-top: 6px;
             box-shadow: 0 14px 24px rgba(46, 115, 223, 0.28);
+        }
+
+        .login-actions {
+            display: flex;
+            flex-direction: column;
+            gap: 12px;
+            margin-top: 6px;
+        }
+
+        .login-actions .el-button {
+            width: 100%;
+            margin-left: 0;
+            box-sizing: border-box;
+        }
+
+        .login-passkey {
+            display: inline-flex;
+            align-items: center;
+            justify-content: center;
+            border-radius: 16px;
+            border-color: rgba(71, 110, 162, 0.24);
+            color: #26496a;
+            background: rgba(245, 249, 255, 0.96);
+        }
+
+        .login-passkey-tip {
+            margin-top: 12px;
+            color: #7b8c9d;
+            font-size: 12px;
+            line-height: 1.7;
         }
 
         .tools-dialog .el-dialog,
         .text-dialog .el-dialog,
-        .upload-dialog .el-dialog {
+        .upload-dialog .el-dialog,
+        .mfa-dialog .el-dialog {
             border-radius: 20px;
             overflow: hidden;
         }
 
         .tools-dialog .el-dialog__header,
         .text-dialog .el-dialog__header,
-        .upload-dialog .el-dialog__header {
+        .upload-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;
@@ -288,14 +318,16 @@
 
         .tools-dialog .el-dialog__title,
         .text-dialog .el-dialog__title,
-        .upload-dialog .el-dialog__title {
+        .upload-dialog .el-dialog__title,
+        .mfa-dialog .el-dialog__title {
             font-weight: 700;
             color: #243447;
         }
 
         .tools-dialog .el-dialog__body,
         .text-dialog .el-dialog__body,
-        .upload-dialog .el-dialog__body {
+        .upload-dialog .el-dialog__body,
+        .mfa-dialog .el-dialog__body {
             padding: 18px 20px 20px;
         }
 
@@ -357,6 +389,33 @@
             display: inline-flex;
             align-items: center;
             justify-content: center;
+        }
+
+        .mfa-tip {
+            color: #6f7f92;
+            font-size: 13px;
+            line-height: 1.7;
+            margin-bottom: 12px;
+        }
+
+        .mfa-account {
+            margin-bottom: 14px;
+            padding: 12px 14px;
+            border-radius: 14px;
+            background: rgba(244, 248, 253, 0.92);
+            color: #42576d;
+            font-size: 13px;
+        }
+
+        .mfa-account strong {
+            color: #1e3956;
+        }
+
+        .mfa-footer {
+            display: flex;
+            justify-content: flex-end;
+            gap: 10px;
+            margin-top: 14px;
         }
 
         @media (max-width: 640px) {
@@ -423,37 +482,34 @@
     <div class="login-layout">
         <section class="hero-panel animate__animated animate__fadeInLeft">
             <div class="brand-chip">Zoneyung WCS</div>
-            <div class="hero-title">WCS绯荤粺璁╄澶囪皟搴︺�佷换鍔℃墽琛屼笌鐜板満鐩戞帶淇濇寔鍦ㄥ悓涓�濂椾笟鍔¢摼璺腑銆�</div>
+            <div class="hero-title">{{ text('login.hero.title', 'WCS绯荤粺璁╄澶囪皟搴︺�佷换鍔℃墽琛屼笌鐜板満鐩戞帶淇濇寔鍦ㄥ悓涓�濂椾笟鍔¢摼璺腑銆�') }}</div>
             <div class="hero-subtitle">
-                Warehouse Control System 闈㈠悜鑷姩鍖栫珛浣撲粨搴撶幇鍦烘墽琛屽眰锛屽洿缁曞爢鍨涙満銆丷GV銆佽緭閫佺珯鍙般�佷换鍔℃寚浠ゃ��
-                搴撲綅鐘舵�佸拰鏃ュ織杩借釜杩涜缁熶竴璋冨害涓庡彲瑙嗗寲绠$悊锛屽府鍔╀粨鍌ㄧ郴缁熷疄鐜扮ǔ瀹氥�佸彲杩芥函銆佸彲鑱斿姩鐨勪綔涓氭帶鍒躲��
-                娴欐睙涓壃绔嬪簱鎶�鏈湁闄愬叕鍙搁暱鏈熶笓娉ㄤ簬鑷姩鍖栫珛浣撲粨搴撲笌鏅鸿兘鐗╂祦绯荤粺寤鸿锛岃鐩栨柟妗堣璁°�佽蒋浠舵帶鍒躲��
-                璁惧闆嗘垚涓庨」鐩疄鏂戒氦浠樸��
+                {{ text('login.hero.subtitle', 'Warehouse Control System 闈㈠悜鑷姩鍖栫珛浣撲粨搴撶幇鍦烘墽琛屽眰锛屽洿缁曞爢鍨涙満銆丷GV銆佽緭閫佺珯鍙般�佷换鍔℃寚浠ゃ�佸簱浣嶇姸鎬佸拰鏃ュ織杩借釜杩涜缁熶竴璋冨害涓庡彲瑙嗗寲绠$悊锛屽府鍔╀粨鍌ㄧ郴缁熷疄鐜扮ǔ瀹氥�佸彲杩芥函銆佸彲鑱斿姩鐨勪綔涓氭帶鍒躲�傛禉姹熶腑鎵珛搴撴妧鏈湁闄愬叕鍙搁暱鏈熶笓娉ㄤ簬鑷姩鍖栫珛浣撲粨搴撲笌鏅鸿兘鐗╂祦绯荤粺寤鸿锛岃鐩栨柟妗堣璁°�佽蒋浠舵帶鍒躲�佽澶囬泦鎴愪笌椤圭洰瀹炴柦浜や粯銆�') }}
             </div>
             <div class="hero-metrics">
                 <div class="metric-card">
-                    <div class="metric-value">璋冨害</div>
-                    <div class="metric-label">缁熶竴缂栨帓鐜板満鎵ц浠诲姟</div>
+                    <div class="metric-value">{{ text('login.hero.metric.dispatch.title', '璋冨害') }}</div>
+                    <div class="metric-label">{{ text('login.hero.metric.dispatch.desc', '缁熶竴缂栨帓鐜板満鎵ц浠诲姟') }}</div>
                 </div>
                 <div class="metric-card">
-                    <div class="metric-value">杩芥函</div>
-                    <div class="metric-label">浣滀笟銆佽澶囥�佹棩蹇楀叏閾捐矾鐣欑棔</div>
+                    <div class="metric-value">{{ text('login.hero.metric.trace.title', '杩芥函') }}</div>
+                    <div class="metric-label">{{ text('login.hero.metric.trace.desc', '浣滀笟銆佽澶囥�佹棩蹇楀叏閾捐矾鐣欑棔') }}</div>
                 </div>
                 <div class="metric-card">
-                    <div class="metric-value">闆嗘垚</div>
-                    <div class="metric-label">瀵规帴WMS銆佽澶囦笌涓氬姟瑙勫垯</div>
+                    <div class="metric-value">{{ text('login.hero.metric.integration.title', '闆嗘垚') }}</div>
+                    <div class="metric-label">{{ text('login.hero.metric.integration.desc', '瀵规帴WMS銆佽澶囦笌涓氬姟瑙勫垯') }}</div>
                 </div>
             </div>
             <div class="hero-footer">
-                <span>娴欐睙涓壃绔嬪簱鎶�鏈湁闄愬叕鍙�</span>
-                <span>鑷姩鍖栫珛浣撲粨搴撲笌鏅鸿兘鐗╂祦绯荤粺瑙e喅鏂规</span>
+                <span>{{ text('login.hero.company.name', '娴欐睙涓壃绔嬪簱鎶�鏈湁闄愬叕鍙�') }}</span>
+                <span>{{ text('login.hero.company.solution', '鑷姩鍖栫珛浣撲粨搴撲笌鏅鸿兘鐗╂祦绯荤粺瑙e喅鏂规') }}</span>
             </div>
         </section>
 
         <section class="login-card animate__animated animate__fadeInUp">
             <div class="login-head">
                 <h1 class="login-title" @click="handleTitleClick">{{ text('login.title', 'WCS绯荤粺V3.0') }}</h1>
-                <div class="login-subtitle">璇疯緭鍏ヨ处鍙峰拰瀵嗙爜杩涘叆绯荤粺銆�</div>
+                <div class="login-subtitle">{{ text('login.subtitle', '璇疯緭鍏ヨ处鍙峰拰瀵嗙爜杩涘叆绯荤粺銆�') }}</div>
             </div>
             <div class="login-body">
                 <el-form ref="loginForm" class="login-form" :model="loginForm" :rules="loginRules" @submit.native.prevent>
@@ -467,15 +523,23 @@
                             <i slot="prefix" class="el-input__icon el-icon-lock"></i>
                         </el-input>
                     </el-form-item>
-                    <el-button class="login-submit" type="primary" :loading="loginLoading" @click="handleLogin">
-                        {{ text('login.submit', '鐧诲綍') }}
-                    </el-button>
+                    <div class="login-actions">
+                        <el-button class="login-submit" type="primary" :loading="loginLoading" @click="handleLogin">
+                            {{ text('login.submit', '鐧诲綍') }}
+                        </el-button>
+                        <el-button class="login-passkey" plain :loading="passkeyLoading" @click="handlePasskeyLogin">
+                            {{ text('login.passkey.submit', '閫氳瀵嗛挜鐧诲綍') }}
+                        </el-button>
+                    </div>
+                    <div class="login-passkey-tip">
+                        {{ text('login.passkey.tip', '鏀寔浣跨敤璁惧鐢熺墿璇嗗埆鎴栧畨鍏ㄥ瘑閽ョ櫥褰曘�傚彲鍏堣緭鍏ヨ处鍙风缉灏忓嚟璇佽寖鍥达紝鐣欑┖鍒欏皾璇曞彂鐜板紡鐧诲綍銆�') }}
+                    </div>
                 </el-form>
             </div>
         </section>
     </div>
 
-    <el-dialog class="tools-dialog" title="绯荤粺宸ュ叿" :visible.sync="toolsDialogVisible" width="560px" :close-on-click-modal="true" append-to-body>
+    <el-dialog class="tools-dialog" :title="text('login.tools.title', '绯荤粺宸ュ叿')" :visible.sync="toolsDialogVisible" width="560px" :close-on-click-modal="true" append-to-body>
         <div class="tool-group">
             <div class="tool-title">{{ text('login.tools.recommended', '鎺ㄨ崘鎿嶄綔') }}</div>
             <div class="tool-actions">
@@ -494,31 +558,53 @@
         </div>
     </el-dialog>
 
+    <el-dialog
+        class="mfa-dialog"
+        :title="text('login.mfa.title', 'MFA浜屾楠岃瘉')"
+        :visible.sync="mfaDialogVisible"
+        width="420px"
+        :close-on-click-modal="false"
+        @close="closeMfaDialog"
+        append-to-body>
+        <div class="mfa-tip">{{ text('login.mfa.tip', '璐﹀彿瀵嗙爜宸查�氳繃锛岃杈撳叆韬唤楠岃瘉鍣ㄤ腑鐨� 6 浣嶅姩鎬侀獙璇佺爜鍚庣户缁櫥褰曘��') }}</div>
+        <div class="mfa-account">{{ text('login.mfa.currentAccount', '褰撳墠璐﹀彿锛�') }}<strong>{{ mfaPending.username || loginForm.mobile || '--' }}</strong></div>
+        <el-form ref="mfaForm" :model="mfaForm" :rules="mfaRules" label-width="82px" size="small" @submit.native.prevent>
+            <el-form-item :label="text('login.mfa.codeLabel', '楠岃瘉鐮�')" prop="code">
+                <el-input v-model.trim="mfaForm.code" maxlength="6" :placeholder="text('login.mfa.codePlaceholder', '璇疯緭鍏�6浣嶅姩鎬佺爜')" @keyup.enter.native="handleMfaLogin"></el-input>
+            </el-form-item>
+        </el-form>
+        <div class="mfa-footer">
+            <el-button @click="closeMfaDialog">{{ text('login.mfa.cancel', '鍙栨秷') }}</el-button>
+            <el-button type="primary" :loading="mfaLoading" @click="handleMfaLogin">{{ text('login.mfa.submit', '楠岃瘉骞剁櫥褰�') }}</el-button>
+        </div>
+    </el-dialog>
+
     <el-dialog class="text-dialog" :title="textDialog.title" :visible.sync="textDialogVisible" width="720px" append-to-body>
         <div class="dialog-text-label">{{ textDialog.label }}</div>
         <div v-if="textDialog.tip" class="dialog-text-tip">{{ textDialog.tip }}</div>
         <el-input v-model="textDialog.text" type="textarea" :rows="10" readonly></el-input>
         <div class="text-footer">
-            <el-button @click="textDialogVisible = false">鍏抽棴</el-button>
+            <el-button @click="textDialogVisible = false">{{ text('login.dialog.close', '鍏抽棴') }}</el-button>
             <el-button type="primary" @click="copyText">{{ text('copy', '澶嶅埗') }}</el-button>
         </div>
     </el-dialog>
 
-    <el-dialog class="upload-dialog" title="褰曞叆璁稿彲璇�" :visible.sync="uploadDialogVisible" width="760px" append-to-body>
-        <div class="dialog-text-label">璁稿彲璇� Base64</div>
-        <div class="dialog-text-tip">灏嗚鍙瘉鏈嶅姟绔繑鍥炵殑 license 瀛楁瀹屾暣绮樿创鍒拌繖閲屻��</div>
+    <el-dialog class="upload-dialog" :title="text('login.tools.uploadLicense', '褰曞叆璁稿彲璇�')" :visible.sync="uploadDialogVisible" width="760px" append-to-body>
+        <div class="dialog-text-label">{{ text('login.license.label', '璁稿彲璇� Base64') }}</div>
+        <div class="dialog-text-tip">{{ text('login.license.tip', '灏嗚鍙瘉鏈嶅姟绔繑鍥炵殑 license 瀛楁瀹屾暣绮樿创鍒拌繖閲屻��') }}</div>
         <el-input v-model.trim="licenseBase64" type="textarea" :rows="10"></el-input>
         <div class="upload-footer">
-            <el-button @click="uploadDialogVisible = false">鍙栨秷</el-button>
-            <el-button type="primary" @click="submitLicense">鎻愪氦</el-button>
+            <el-button @click="uploadDialogVisible = false">{{ text('login.mfa.cancel', '鍙栨秷') }}</el-button>
+            <el-button type="primary" @click="submitLicense">{{ text('login.license.submit', '鎻愪氦') }}</el-button>
         </div>
     </el-dialog>
 </div>
 </body>
 <script type="text/javascript" src="../static/js/jquery/jquery-3.3.1.min.js"></script>
 <script type="text/javascript" src="../static/js/tools/md5.js"></script>
-<script type="text/javascript" src="../static/js/common.js?v=20260309_i18n_fix1"></script>
+<script type="text/javascript" src="../static/js/common.js"></script>
+<script type="text/javascript" src="../static/js/webauthn-utils.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/login/login.js?v=20260310_login_vue"></script>
+<script type="text/javascript" src="../static/js/login/login.js?v=20260311_login_passkey"></script>
 </html>

--
Gitblit v1.9.1