liuyanpeng 5 miesięcy temu
rodzic
commit
4210375bf9

+ 2 - 1
src/api/gate.js

@@ -19,8 +19,9 @@ export function controlGateByBigInv(command) {
 
 // 获取闸机状态
 export function getGateStatus() {
+    const warehouseId = localStorage.getItem('#warehouseId');
     return request({
-        url: '/api/FareGate/api/GetStatus',
+        url: '/api/GateResource/getStatus?warehouseId=' + warehouseId,
         method: 'get',
     });
 }

+ 18 - 1
src/api/login.js

@@ -48,4 +48,21 @@ export function getWarehouseId(deviceId) {
         url: `/api/WarehouseResource/findWarehouseByDeviceId?deviceId=${deviceId}`,
         method: 'get',
     });
-}
+}
+
+// 修改密码
+export function updateUserPassword(data) {
+    const formData = new FormData();
+    formData.append('oldPassword', data.oldPassword);
+    formData.append('newPassword', data.newPassword);
+    formData.append('newPassword2', data.newPassword2);
+    
+    return request({
+        url: '/api/userResource/updateUserPassword',
+        method: 'post',
+        data: formData,
+        headers: {
+            'Content-Type': 'multipart/form-data',
+        },
+    });
+}

+ 4 - 2
src/api/stockIn.js

@@ -2,8 +2,9 @@ import request  from '../util/request.js';
 
 // 闸机外侧扫描查询工装设备信息
 export function cfStockIn() {
+    const warehouseId = localStorage.getItem('#warehouseId');
     return request({
-        url: '/api/stockInResource/queryInventoryByEPC',
+        url: '/api/stockInResource/queryInventoryByEPC?warehouseId=' + warehouseId,
         method: 'get',
     });
 }
@@ -19,8 +20,9 @@ export function createStockIn(params) {
 
 // 闸机内侧扫描查询工装设备信息
 export function cfStockInLeave() {
+    const warehouseId = localStorage.getItem('#warehouseId');
     return request({
-        url: '/api/stockInResource/validationInsideTurnstile',
+        url: '/api/stockInResource/validationInsideTurnstile?warehouseId=' + warehouseId,
         method: 'get',
     });
 }

+ 2 - 1
src/api/stockOut.js

@@ -87,8 +87,9 @@ export function createStockOut(params) {
 
 // 闸机内侧人工领料出库验证工装设备是否一致
 export function cfStockOut() {
+    const warehouseId = localStorage.getItem('#warehouseId');
     return request({
-        url: '/api/StockOutResource/verificationCFStockOut',
+        url: '/api/StockOutResource/verificationCFStockOut?warehouseId=' + warehouseId,
         method: 'get',
     });
 }

+ 11 - 11
src/gate/ControlGate.vue

@@ -94,17 +94,6 @@
             </div>
           </button> -->
 
-          <!-- 重启闸机 -->
-          <button class="control-btn reboot-btn" :disabled="loading" @click="handleControl('REBOOT', '重启闸机', false)">
-            <div class="btn-icon">
-              <i class="fas fa-sync-alt" />
-            </div>
-            <div class="btn-text">
-              <span class="btn-title">重启闸机</span>
-              <span class="btn-desc">重新启动闸机系统</span>
-            </div>
-          </button>
-
           <button class="control-btn big-open-btn" :disabled="loading" @click="handleControl('OPEN', '大件运输常开', true)">
             <div class="btn-icon">
               <i class="fas fa-truck" />
@@ -124,6 +113,17 @@
               <span class="btn-desc">大件运输模式保持关闭</span>
             </div>
           </button>
+
+          <!-- 重启闸机 -->
+          <button class="control-btn reboot-btn" :disabled="loading" @click="handleControl('REBOOT', '重启闸机', false)">
+            <div class="btn-icon">
+              <i class="fas fa-sync-alt" />
+            </div>
+            <div class="btn-text">
+              <span class="btn-title">重启闸机</span>
+              <span class="btn-desc">重新启动闸机系统</span>
+            </div>
+          </button>
         </div>
       </div>
     </main>

+ 17 - 979
src/login/FingerprintLogin.vue

@@ -1,84 +1,8 @@
 <!-- 指纹登录 - 深色科技风格 -->
 <template>
   <div class="fingerprint-login-page">
-    <!-- 指纹主题超炫酷科技背景 -->
-    <div class="bg-layer" />
-    
-    <!-- 指纹扫描环形背景 -->
-    <div class="fingerprint-rings">
-      <div class="fp-ring ring-1" />
-      <div class="fp-ring ring-2" />
-      <div class="fp-ring ring-3" />
-      <div class="fp-ring ring-4" />
-      <div class="fp-ring ring-5" />
-    </div>
-    
-    <!-- 生物识别数据流 -->
-    <div class="biometric-data">
-      <div class="data-stream stream-1" />
-      <div class="data-stream stream-2" />
-      <div class="data-stream stream-3" />
-      <div class="data-stream stream-4" />
-    </div>
-    
-    <!-- 雷达扫描效果 -->
-    <div class="radar-scan">
-      <div class="radar-sweep" />
-      <div class="radar-grid" />
-    </div>
-    
-    <!-- 霓虹指纹脊线装饰 -->
-    <div class="neon-ridges">
-      <div class="neon-ridge ridge-a" />
-      <div class="neon-ridge ridge-b" />
-      <div class="neon-ridge ridge-c" />
-      <div class="neon-ridge ridge-d" />
-    </div>
-    
-    <!-- 数字雨效果(指纹主题) -->
-    <div class="fp-digital-rain">
-      <div class="digital-column" style="left: 8%; animation-delay: 0s;" />
-      <div class="digital-column" style="left: 22%; animation-delay: 0.8s;" />
-      <div class="digital-column" style="left: 38%; animation-delay: 1.6s;" />
-      <div class="digital-column" style="left: 52%; animation-delay: 2.4s;" />
-      <div class="digital-column" style="left: 68%; animation-delay: 3.2s;" />
-      <div class="digital-column" style="left: 84%; animation-delay: 4s;" />
-    </div>
-    
-    <!-- 动态渐变背景 -->
-    <div class="gradient-bg">
-      <div class="gradient-orb gradient-orb-1" />
-      <div class="gradient-orb gradient-orb-2" />
-      <div class="gradient-orb gradient-orb-3" />
-      <div class="gradient-orb gradient-orb-4" />
-    </div>
-    
-    <!-- 指纹主题粒子动画 -->
-    <div class="fingerprint-particles">
-      <div class="fp-particle fp-particle-1" />
-      <div class="fp-particle fp-particle-2" />
-      <div class="fp-particle fp-particle-3" />
-      <div class="fp-particle fp-particle-4" />
-      <div class="fp-particle fp-particle-5" />
-      <div class="fp-particle fp-particle-6" />
-      <div class="fp-particle fp-particle-7" />
-      <div class="fp-particle fp-particle-8" />
-    </div>
-    
-    <!-- 动态扫描线 -->
-    <div class="scan-bg">
-      <div class="scan-wave scan-wave-1" />
-      <div class="scan-wave scan-wave-2" />
-      <div class="scan-wave scan-wave-3" />
-    </div>
-    
-    <!-- 指纹脊线背景装饰 -->
-    <div class="fingerprint-bg-decoration">
-      <div class="ridge-line ridge-1" />
-      <div class="ridge-line ridge-2" />
-      <div class="ridge-line ridge-3" />
-      <div class="ridge-line ridge-4" />
-    </div>
+    <!-- 背景层 -->
+    <div class="bg-layer" :style="{ backgroundImage: `url(${bgImg})` }" />
 
     <!-- 操作按钮 - 右上角 -->
     <div class="action-buttons-top">
@@ -197,7 +121,7 @@ import { showNotify } from 'vant';
 import { queryRemindTime } from '../api/login.js';
 
 // 图片资源
-// import bgImg from '../assets/images/bj.png';
+import bgImg from '../assets/images/bj.png';
 
 const route = useRoute();
 const router = useRouter();
@@ -210,31 +134,6 @@ const isConnected = ref(false);
 // 计算状态类名
 const statusClass = ref('status-waiting');
 
-// 性能释放相关
-const isPageVisible = ref(true);
-let visibilityChangeHandler = null;
-
-// 页面可见性变化处理
-const handleVisibilityChange = () => {
-    isPageVisible.value = !document.hidden;
-    const fingerprintPage = document.querySelector('.fingerprint-login-page');
-    if (fingerprintPage) {
-        if (document.hidden) {
-            // 页面不可见时暂停所有动画
-            fingerprintPage.style.animationPlayState = 'paused';
-            fingerprintPage.querySelectorAll('*').forEach(el => {
-                el.style.animationPlayState = 'paused';
-            });
-        } else {
-            // 页面可见时恢复动画
-            fingerprintPage.style.animationPlayState = 'running';
-            fingerprintPage.querySelectorAll('*').forEach(el => {
-                el.style.animationPlayState = 'running';
-            });
-        }
-    }
-};
-
 // 更新状态
 const updateStatus = (newStatus, text) => {
     status.value = newStatus;
@@ -377,10 +276,6 @@ const checkPasswordReminder = async () => {
 
 // 组件挂载
 onMounted(() => {
-    // 添加页面可见性监听器
-    visibilityChangeHandler = handleVisibilityChange;
-    document.addEventListener('visibilitychange', visibilityChangeHandler);
-    
     // 检查URL参数中是否包含isOut=true,如果有则存储到localStorage
     // const isOutParam = route.query.isOut;
     // if (isOutParam !== undefined) {
@@ -408,21 +303,6 @@ onMounted(() => {
 
 // 组件卸载
 onUnmounted(() => {
-    // 移除页面可见性监听器
-    if (visibilityChangeHandler) {
-        document.removeEventListener('visibilitychange', visibilityChangeHandler);
-        visibilityChangeHandler = null;
-    }
-    
-    // 暂停所有动画以释放性能
-    const fingerprintPage = document.querySelector('.fingerprint-login-page');
-    if (fingerprintPage) {
-        fingerprintPage.style.animationPlayState = 'paused';
-        fingerprintPage.querySelectorAll('*').forEach(el => {
-            el.style.animationPlayState = 'paused';
-        });
-    }
-    
     // 清理响应处理函数
     if (plugin.fingerprintConfig) {
         plugin.fingerprintConfig.receiveFingerprintResponse = () => { };
@@ -444,49 +324,23 @@ onUnmounted(() => {
     flex-direction: column;
     align-items: center;
     justify-content: center;
-    -webkit-user-select: none;
-    -moz-user-select: none;
-    -ms-user-select: none;
-    user-select: none;
 }
 
-/* 指纹主题炫酷科技背景 */
+/* 背景层 */
 .bg-layer {
     position: fixed;
     top: 0;
     left: 0;
     width: 100%;
     height: 100%;
-    background: 
-        radial-gradient(circle at 50% 50%, rgba(0, 255, 255, 0.08) 0%, transparent 40%),
-        radial-gradient(circle at 20% 80%, rgba(0, 180, 255, 0.06) 0%, transparent 50%),
-        radial-gradient(circle at 80% 20%, rgba(0, 220, 255, 0.04) 0%, transparent 60%),
-        conic-gradient(from 0deg at 50% 50%, #0a1a2e 0deg, #0a2a4a 60deg, #0a3a5a 120deg, #0a2a4a 180deg, #0a1a2e 240deg, #0a2a4a 300deg, #0a1a2e 360deg);
-    background-size: 100% 100%, 150% 150%, 120% 120%, 100% 100%;
-    animation: fpBgShift 25s ease-in-out infinite;
+    background-color: #041c3d;
+    background-size: cover;
+    background-position: center;
+    background-repeat: no-repeat;
     z-index: 0;
 }
 
-@keyframes fpBgShift {
-    0%, 100% { 
-        background-position: 50% 50%, 20% 80%, 80% 20%, 0% 0%; 
-        filter: hue-rotate(0deg);
-    }
-    25% { 
-        background-position: 60% 40%, 30% 70%, 70% 30%, 10% 10%; 
-        filter: hue-rotate(30deg);
-    }
-    50% { 
-        background-position: 40% 60%, 10% 90%, 90% 10%, 20% 20%; 
-        filter: hue-rotate(60deg);
-    }
-    75% { 
-        background-position: 55% 45%, 25% 75%, 75% 25%, 15% 15%; 
-        filter: hue-rotate(30deg);
-    }
-}
-
-/* 增强的背景动画网格 */
+/* 背景动画网格 */
 .fingerprint-login-page::before {
     content: '';
     position: absolute;
@@ -495,330 +349,11 @@ onUnmounted(() => {
     width: 100%;
     height: 100%;
     background-image:
-        radial-gradient(circle at 1px 1px, rgba(30, 144, 255, 0.15) 1px, transparent 0),
         linear-gradient(rgba(30, 144, 255, 0.03) 1px, transparent 1px),
         linear-gradient(90deg, rgba(30, 144, 255, 0.03) 1px, transparent 1px);
-    background-size: 60px 60px, 30px 30px, 30px 30px;
+    background-size: 50px 50px;
     z-index: 1;
     pointer-events: none;
-    animation: gridPulse 8s ease-in-out infinite;
-}
-
-@keyframes gridPulse {
-    0%, 100% {
-        opacity: 0.4;
-        transform: scale(1);
-    }
-    50% {
-        opacity: 0.8;
-        transform: scale(1.02);
-    }
-}
-
-/* 动态渐变背景 */
-.gradient-bg {
-    position: fixed;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    z-index: 0;
-    overflow: hidden;
-    pointer-events: none;
-}
-
-.gradient-orb {
-    position: absolute;
-    border-radius: 50%;
-    filter: blur(100px);
-    animation: orbFloat 12s ease-in-out infinite;
-    will-change: transform, opacity;
-    transform: translateZ(0);
-    -webkit-backface-visibility: hidden;
-    backface-visibility: hidden;
-}
-
-.gradient-orb-1 {
-    width: 400px;
-    height: 400px;
-    background: radial-gradient(circle, rgba(30, 144, 255, 0.25) 0%, transparent 70%);
-    top: 15%;
-    left: 25%;
-    animation-delay: 0s;
-}
-
-.gradient-orb-2 {
-    width: 300px;
-    height: 300px;
-    background: radial-gradient(circle, rgba(0, 191, 255, 0.2) 0%, transparent 70%);
-    bottom: 25%;
-    right: 20%;
-    animation-delay: 4s;
-}
-
-.gradient-orb-3 {
-    width: 250px;
-    height: 250px;
-    background: radial-gradient(circle, rgba(135, 206, 250, 0.15) 0%, transparent 70%);
-    top: 50%;
-    left: 70%;
-    animation-delay: 8s;
-}
-
-.gradient-orb-4 {
-    width: 350px;
-    height: 350px;
-    background: radial-gradient(circle, rgba(0, 206, 209, 0.1) 0%, transparent 70%);
-    top: 70%;
-    left: 10%;
-    animation-delay: 6s;
-}
-
-@keyframes orbFloat {
-    0%, 100% {
-        transform: translate(0, 0) scale(1) rotate(0deg);
-        opacity: 0.6;
-    }
-    33% {
-        transform: translate(30px, -40px) scale(1.1) rotate(120deg);
-        opacity: 0.9;
-    }
-    66% {
-        transform: translate(-40px, 30px) scale(0.8) rotate(240deg);
-        opacity: 0.4;
-    }
-}
-
-/* 指纹主题粒子动画 */
-.fingerprint-particles {
-    position: fixed;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    z-index: 2;
-    pointer-events: none;
-    overflow: hidden;
-}
-
-.fp-particle {
-    position: absolute;
-    border-radius: 50%;
-    background: radial-gradient(circle, rgba(30, 144, 255, 0.9) 0%, rgba(30, 144, 255, 0.3) 40%, transparent 100%);
-    animation: fpParticleMove 15s linear infinite;
-    will-change: transform, opacity;
-    transform: translateZ(0);
-    -webkit-backface-visibility: hidden;
-    backface-visibility: hidden;
-}
-
-.fp-particle-1 {
-    width: 8px;
-    height: 8px;
-    left: 20%;
-    animation-delay: 0s;
-    animation-duration: 12s;
-}
-
-.fp-particle-2 {
-    width: 6px;
-    height: 6px;
-    left: 80%;
-    animation-delay: 3s;
-    animation-duration: 14s;
-}
-
-.fp-particle-3 {
-    width: 10px;
-    height: 10px;
-    left: 60%;
-    animation-delay: 6s;
-    animation-duration: 10s;
-}
-
-.fp-particle-4 {
-    width: 5px;
-    height: 5px;
-    left: 40%;
-    animation-delay: 2s;
-    animation-duration: 16s;
-}
-
-.fp-particle-5 {
-    width: 7px;
-    height: 7px;
-    left: 10%;
-    animation-delay: 5s;
-    animation-duration: 13s;
-}
-
-.fp-particle-6 {
-    width: 9px;
-    height: 9px;
-    left: 90%;
-    animation-delay: 8s;
-    animation-duration: 11s;
-}
-
-.fp-particle-7 {
-    width: 4px;
-    height: 4px;
-    left: 70%;
-    animation-delay: 1s;
-    animation-duration: 15s;
-}
-
-.fp-particle-8 {
-    width: 6px;
-    height: 6px;
-    left: 30%;
-    animation-delay: 7s;
-    animation-duration: 9s;
-}
-
-@keyframes fpParticleMove {
-    0% {
-        transform: translateY(110vh) translateX(-20px) rotate(0deg);
-        opacity: 0;
-    }
-    10% {
-        opacity: 1;
-    }
-    50% {
-        opacity: 0.8;
-        transform: translateY(50vh) translateX(20px) rotate(180deg);
-    }
-    90% {
-        opacity: 0.6;
-    }
-    100% {
-        transform: translateY(-10vh) translateX(40px) rotate(360deg);
-        opacity: 0;
-    }
-}
-
-/* 动态扫描线 */
-.scan-bg {
-    position: fixed;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    z-index: 3;
-    pointer-events: none;
-    overflow: hidden;
-}
-
-.scan-wave {
-    position: absolute;
-    width: 100%;
-    height: 2px;
-    background: linear-gradient(90deg, transparent 0%, rgba(0, 191, 255, 0.6) 20%, rgba(30, 144, 255, 0.8) 50%, rgba(0, 191, 255, 0.6) 80%, transparent 100%);
-    animation: scanMove 10s ease-in-out infinite;
-    will-change: transform, opacity;
-    transform: translateZ(0);
-}
-
-.scan-wave-1 {
-    animation-delay: 0s;
-    background: linear-gradient(90deg, transparent 0%, rgba(0, 191, 255, 0.8) 50%, transparent 100%);
-}
-
-.scan-wave-2 {
-    animation-delay: 2s;
-    background: linear-gradient(90deg, transparent 0%, rgba(30, 144, 255, 0.6) 50%, transparent 100%);
-}
-
-.scan-wave-3 {
-    animation-delay: 4s;
-    background: linear-gradient(90deg, transparent 0%, rgba(135, 206, 250, 0.4) 50%, transparent 100%);
-}
-
-@keyframes scanMove {
-    0% {
-        top: -5px;
-        opacity: 0;
-        transform: scaleX(0.5);
-    }
-    20% {
-        opacity: 1;
-        transform: scaleX(1);
-    }
-    80% {
-        opacity: 0.8;
-        transform: scaleX(1.2);
-    }
-    100% {
-        top: 105%;
-        opacity: 0;
-        transform: scaleX(0.3);
-    }
-}
-
-/* 指纹脊线背景装饰 */
-.fingerprint-bg-decoration {
-    position: fixed;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    z-index: 1;
-    pointer-events: none;
-    overflow: hidden;
-}
-
-.ridge-line {
-    position: absolute;
-    border: 1px solid rgba(30, 144, 255, 0.1);
-    border-radius: 50%;
-    animation: ridgeExpand 8s ease-in-out infinite;
-    will-change: transform, opacity;
-    transform: translateZ(0);
-}
-
-.ridge-1 {
-    width: 150px;
-    height: 150px;
-    top: 20%;
-    left: 15%;
-    animation-delay: 0s;
-}
-
-.ridge-2 {
-    width: 200px;
-    height: 200px;
-    bottom: 30%;
-    right: 25%;
-    animation-delay: 2s;
-}
-
-.ridge-3 {
-    width: 100px;
-    height: 100px;
-    top: 60%;
-    left: 70%;
-    animation-delay: 4s;
-}
-
-.ridge-4 {
-    width: 120px;
-    height: 120px;
-    top: 80%;
-    left: 40%;
-    animation-delay: 6s;
-}
-
-@keyframes ridgeExpand {
-    0%, 100% {
-        transform: scale(1) rotate(0deg);
-        opacity: 0.1;
-        border-color: rgba(30, 144, 255, 0.1);
-    }
-    50% {
-        transform: scale(1.5) rotate(180deg);
-        opacity: 0.3;
-        border-color: rgba(30, 144, 255, 0.3);
-    }
 }
 
 .recognize-container {
@@ -1285,517 +820,20 @@ onUnmounted(() => {
     }
 }
 
-/* 性能优化 - 减少动画支持 */
-@media (prefers-reduced-motion: reduce) {
-    *,
-    *::before,
-    *::after {
-        animation-duration: 0.01ms !important;
-        animation-iteration-count: 1 !important;
-        transition-duration: 0.01ms !important;
-        scroll-behavior: auto !important;
-    }
-    
-    .gradient-orb,
-    .fp-particle,
-    .scan-wave,
-    .ridge-line,
-    .status-circle {
-        animation: none !important;
-    }
-}
-
-/* 低性能设备优化 */
-@media (max-width: 768px) {
-    .gradient-orb {
-        filter: blur(60px);
-        animation-duration: 16s;
-    }
-    
-    .fp-particle {
-        animation-duration: 18s;
-    }
-    
-    .fingerprint-particles .fp-particle:nth-child(n+5) {
-        display: none;
-    }
-    
-    .scan-bg .scan-wave:nth-child(n+3) {
-        display: none;
-    }
-}
-
-@media (max-width: 480px) {
-    .gradient-orb-3,
-    .gradient-orb-4,
-    .ridge-line {
-        display: none;
-    }
-    
-    .fingerprint-particles .fp-particle:nth-child(n+4) {
-        display: none;
-    }
-    
-    .scan-bg .scan-wave:nth-child(n+2) {
-        display: none;
-    }
-}
-
 /* 响应式设计 */
 @media (max-width: 768px) {
     .action-buttons {
         display: none;
         padding: 0 1rem;
     }
-    
-    .status-circle {
-        width: clamp(200px, 35vw, 280px);
-        height: clamp(200px, 35vw, 280px);
-    }
-}
-
-/* 高刷新率设备优化 */
-@media (min-resolution: 120dpi) {
-    .fp-particle {
-        animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
-    }
-    
-    .scan-wave {
-        animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
-    }
-}
-
-/* 暗色主题适配 */
-@media (prefers-color-scheme: dark) {
-    .gradient-orb {
-        filter: blur(120px);
-        opacity: 0.9;
-    }
-    
-    .fp-particle {
-        background: radial-gradient(circle, rgba(30, 144, 255, 1) 0%, rgba(30, 144, 255, 0.4) 40%, transparent 100%);
-    }
-}
-
-/* 节能模式适配 */
-@media (prefers-reduced-data) {
-    .gradient-orb,
-    .fingerprint-particles,
-    .scan-bg,
-    .fingerprint-bg-decoration {
-        display: none;
-    }
-}
-
-/* 指纹扫描环形背景 */
-.fingerprint-rings {
-    position: fixed;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    z-index: 1;
-    pointer-events: none;
-    overflow: hidden;
-}
-
-.fp-ring {
-    position: absolute;
-    top: 50%;
-    left: 50%;
-    border: 1px solid rgba(0, 255, 255, 0.3);
-    border-radius: 50%;
-    transform: translate(-50%, -50%);
-    animation: ringExpand 8s ease-in-out infinite;
-}
-
-.ring-1 { width: 100px; height: 100px; animation-delay: 0s; }
-.ring-2 { width: 200px; height: 200px; animation-delay: 1.6s; }
-.ring-3 { width: 300px; height: 300px; animation-delay: 3.2s; }
-.ring-4 { width: 400px; height: 400px; animation-delay: 4.8s; }
-.ring-5 { width: 500px; height: 500px; animation-delay: 6.4s; }
-
-@keyframes ringExpand {
-    0% { 
-        transform: translate(-50%, -50%) scale(0.5);
-        opacity: 0;
-        border-color: rgba(0, 255, 255, 0);
-    }
-    20% {
-        opacity: 0.8;
-        border-color: rgba(0, 255, 255, 0.6);
-    }
-    80% {
-        opacity: 0.4;
-        border-color: rgba(0, 255, 255, 0.3);
-    }
-    100% { 
-        transform: translate(-50%, -50%) scale(1.5);
-        opacity: 0;
-        border-color: rgba(0, 255, 255, 0);
-    }
-}
-
-/* 生物识别数据流 */
-.biometric-data {
-    position: fixed;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    z-index: 2;
-    pointer-events: none;
-    overflow: hidden;
-}
-
-.data-stream {
-    position: absolute;
-    width: 2px;
-    height: 80px;
-    background: linear-gradient(0deg, transparent, #0088ff, #00aaff, transparent);
-    box-shadow: 0 0 10px #0088ff;
-    animation: dataFlow 6s linear infinite;
-}
-
-.stream-1 { 
-    top: 20%; 
-    left: 15%; 
-    animation-delay: 0s; 
-    transform: rotate(45deg);
-}
-.stream-2 { 
-    bottom: 25%; 
-    right: 20%; 
-    animation-delay: 1.5s; 
-    transform: rotate(-30deg);
-}
-.stream-3 { 
-    top: 60%; 
-    left: 70%; 
-    animation-delay: 3s; 
-    transform: rotate(60deg);
-}
-.stream-4 { 
-    top: 80%; 
-    left: 35%; 
-    animation-delay: 4.5s; 
-    transform: rotate(-45deg);
-}
-
-@keyframes dataFlow {
-    0%, 100% { opacity: 0; height: 0; }
-    25% { opacity: 1; height: 80px; }
-    75% { opacity: 0.8; height: 120px; }
-}
-
-/* 雷达扫描效果 */
-.radar-scan {
-    position: fixed;
-    top: 50%;
-    left: 50%;
-    width: 400px;
-    height: 400px;
-    transform: translate(-50%, -50%);
-    z-index: 1;
-    pointer-events: none;
-}
-
-.radar-sweep {
-    position: absolute;
-    top: 0;
-    left: 50%;
-    width: 2px;
-    height: 200px;
-    background: linear-gradient(0deg, transparent, #00ffff, transparent);
-    transform-origin: bottom center;
-    animation: radarSweep 4s linear infinite;
-    box-shadow: 0 0 20px #00ffff;
 }
 
-.radar-grid {
-    position: absolute;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    border: 1px solid rgba(0, 255, 255, 0.1);
-    border-radius: 50%;
-    animation: radarPulse 4s ease-in-out infinite;
-}
-
-.radar-grid::before,
-.radar-grid::after {
-    content: '';
-    position: absolute;
-    top: 50%;
-    left: 50%;
-    border: 1px solid rgba(0, 255, 255, 0.1);
-    border-radius: 50%;
-    transform: translate(-50%, -50%);
-}
-
-.radar-grid::before {
-    width: 66%;
-    height: 66%;
-}
-
-.radar-grid::after {
-    width: 33%;
-    height: 33%;
-}
-
-@keyframes radarSweep {
-    0% { transform: rotate(0deg); opacity: 0; }
-    10% { opacity: 1; }
-    90% { opacity: 0.8; }
-    100% { transform: rotate(360deg); opacity: 0; }
-}
-
-@keyframes radarPulse {
-    0%, 100% { opacity: 0.2; }
-    50% { opacity: 0.6; }
-}
-
-/* 霓虹指纹脊线装饰 */
-.neon-ridges {
-    position: fixed;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    z-index: 1;
-    pointer-events: none;
-    overflow: hidden;
-}
-
-.neon-ridge {
-    position: absolute;
-    border: 2px solid transparent;
-    border-radius: 50%;
-    animation: neonGlow 5s ease-in-out infinite;
-}
-
-.ridge-a {
-    width: 120px;
-    height: 80px;
-    top: 20%;
-    left: 20%;
-    border-color: rgba(0, 160, 255, 0.4);
-    animation-delay: 0s;
-}
-
-.ridge-b {
-    width: 90px;
-    height: 60px;
-    bottom: 30%;
-    right: 25%;
-    border-color: rgba(0, 200, 255, 0.4);
-    animation-delay: 1.25s;
-}
-
-.ridge-c {
-    width: 140px;
-    height: 100px;
-    top: 65%;
-    left: 60%;
-    border-color: rgba(0, 240, 255, 0.4);
-    animation-delay: 2.5s;
-}
-
-.ridge-d {
-    width: 110px;
-    height: 70px;
-    top: 75%;
-    left: 15%;
-    border-color: rgba(0, 180, 240, 0.4);
-    animation-delay: 3.75s;
-}
-
-@keyframes neonGlow {
-    0%, 100% {
-        border-width: 1px;
-        opacity: 0.3;
-        filter: blur(0px);
-        transform: scale(1);
-    }
-    50% {
-        border-width: 3px;
-        opacity: 1;
-        filter: blur(1px);
-        transform: scale(1.1);
-        box-shadow: 0 0 30px currentColor;
-    }
-}
-
-/* 数字雨效果(指纹主题) */
-.fp-digital-rain {
-    position: fixed;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    z-index: 2;
-    pointer-events: none;
-    overflow: hidden;
-}
-
-.digital-column {
-    position: absolute;
-    width: 1px;
-    height: 100%;
-    background: linear-gradient(0deg, 
-        transparent 0%, 
-        rgba(96, 120, 160, 0.15) 20%, 
-        rgba(128, 150, 180, 0.6) 40%, 
-        rgba(160, 180, 210, 0.8) 50%, 
-        rgba(128, 150, 180, 0.6) 60%, 
-        rgba(96, 120, 160, 0.15) 80%, 
-        transparent 100%
-    );
-    animation: digitalFall 22s linear infinite;
-}
-
-/* .digital-column::before {
-    content: 'ABCDEF0123456789';
-    position: absolute;
-    top: 0;
-    left: -5px;
-    font-family: 'Courier New', monospace;
-    font-size: 10px;
-    color: #ff00ff;
-    writing-mode: vertical-rl;
-    opacity: 0.7;
-    animation: digitalText 10s linear infinite;
-    text-shadow: 0 0 5px #ff00ff;
-} */
-
-@keyframes digitalFall {
-    0% { transform: translateY(-100%); opacity: 0; }
-    15% { opacity: 1; }
-    85% { opacity: 0.6; }
-    100% { transform: translateY(100vh); opacity: 0; }
-}
-
-@keyframes digitalText {
-    0% { transform: translateY(-20px); }
-    100% { transform: translateY(100vh); }
-}
-
-/* 硬件加速优化 */
-.fp-ring,
-.data-stream,
-.radar-sweep,
-.radar-grid,
-.neon-ridge,
-.digital-column {
-    will-change: transform, opacity;
-    transform: translateZ(0);
-    -webkit-backface-visibility: hidden;
-    backface-visibility: hidden;
-}
-
-/* 深度性能优化 - 保留所有元素但优化性能 */
-* {
-    -webkit-backface-visibility: hidden;
-    backface-visibility: hidden;
-}
-
-/* CSS Containment 优化 - 限制布局重计算范围 */
-.bg-layer,
-.fingerprint-rings,
-.biometric-data,
-.radar-scan,
-.neon-ridges,
-.fp-digital-rain,
-.gradient-bg,
-.fingerprint-particles,
-.scan-bg,
-.fingerprint-bg-decoration {
-    contain: layout style paint;
-    isolation: isolate;
-}
-
-/* 合成层优化 - 智能GPU加速 */
-.fingerprint-login-page {
-    transform: translateZ(0);
-    will-change: auto;
-}
-
-/* 动画性能优化 - 保持流畅但高效 */
-.fp-ring {
-    animation-timing-function: ease-out;
-}
-
-.neon-ridge {
-    animation-timing-function: ease-in-out;
-}
-
-.radar-sweep {
-    animation-timing-function: linear;
-}
-
-.digital-column {
-    animation-timing-function: linear;
-}
-
-/* 动画性能优化 */
-.gradient-orb {
-    filter: blur(90px);
-    animation-duration: 20s;
-    animation-timing-function: ease-out;
-    animation-fill-mode: both;
-}
-
-.fp-ring {
-    animation-duration: 12s;
-    animation-timing-function: ease-in-out;
-    animation-fill-mode: both;
-}
-
-.data-stream {
-    animation-duration: 10s;
-    animation-timing-function: linear;
-    animation-fill-mode: both;
-}
-
-.radar-sweep {
-    animation-duration: 6s;
-    animation-timing-function: linear;
-    animation-fill-mode: both;
-}
-
-.digital-column {
-    animation-duration: 25s;
-    animation-timing-function: linear;
-    animation-fill-mode: both;
-}
-
-/* 分层优化 */
-.bg-layer {
-    animation-duration: 35s;
-    animation-timing-function: ease-in-out;
-}
-
-/* 响应式性能优化 */
-@media (max-width: 768px) {
-    .gradient-orb {
-        filter: blur(70px);
-        animation-duration: 25s;
-    }
-    
-    .digital-column {
-        animation-duration: 18s;
-    }
-}
-
-@media (max-width: 480px) {
-    .bg-layer {
-        animation-duration: 50s;
-    }
-    
-    .gradient-orb {
-        filter: blur(50px);
-        animation-duration: 30s;
+/* 减少动画(无障碍支持) */
+@media (prefers-reduced-motion: reduce) {
+    * {
+        animation-duration: 0.01ms !important;
+        animation-iteration-count: 1 !important;
+        transition-duration: 0.01ms !important;
     }
 }
-</style>
+</style>

+ 647 - 21
src/login/UserHome.vue

@@ -29,13 +29,21 @@
               <i class="fas fa-fingerprint mr-2" />
               <span>指纹录入</span>
             </div>
-            <div class="dropdown-item" @click="goReturnManagement">
+            <!-- <div class="dropdown-item" @click="goReturnManagement">
               <i class="fas fa-box mr-2" />
               <span>还料区管理</span>
-            </div>
-            <div class="dropdown-item" @click="goDeliveryManagement">
+            </div> -->
+            <!-- <div class="dropdown-item" @click="goDeliveryManagement">
               <i class="fas fa-box mr-2" />
               <span>送料区管理</span>
+            </div> -->
+            <div v-if="isAdmin" class="dropdown-item" @click="goRfidRecord">
+              <i class="fas fa-barcode mr-2" />
+              <span>AGV校验</span>
+            </div>
+            <div v-if="isAdmin" class="dropdown-item" @click="goAbnormalArea">
+              <i class="fas fa-exclamation-triangle mr-2" />
+              <span>异常停泊区</span>
             </div>
             <div v-if="isAdmin" class="dropdown-item" @click="goControlGate">
               <i class="fas fa-door-open mr-2" />
@@ -91,21 +99,19 @@
       </div>
 
       <!-- 操作按钮区域 -->
-      <div class="buttons-section">
+      <div v-if="isOutMenu" class="buttons-section">
         <!-- <template v-if="isOut"> -->
         <!-- 调试使用 -->
-        <template v-if="isOutMenu">
-          <div v-for="action in outButtons" :key="action.label" class="action-btn" @click="handleAction(action.action)">
-            <img :src="buttonBg" alt="" class="btn-bg" />
-            <span class="btn-text">{{ action.label }}</span>
-          </div>
-        </template>
-        <template v-else>
-          <div v-for="action in inButtons" :key="action.label" class="action-btn" @click="handleAction(action.action)">
-            <img :src="buttonBg" alt="" class="btn-bg" />
-            <span class="btn-text">{{ action.label }}</span>
-          </div>
-        </template>
+        <div v-for="action in outButtons" :key="action.label" class="action-btn" @click="handleAction(action.action)">
+          <img :src="buttonBg" alt="" class="btn-bg" />
+          <span class="btn-text">{{ action.label }}</span>
+        </div>
+      </div>
+      <div v-else class="buttons-section buttons-section2">
+        <div v-for="action in inButtons" :key="action.label" class="action-btn" @click="handleAction(action.action)">
+          <img :src="buttonBg" alt="" class="btn-bg" />
+          <span class="btn-text">{{ action.label }}</span>
+        </div>
       </div>
 
 
@@ -140,14 +146,158 @@
         </div>
       </div>
     </div>
+    <div v-if="isUpdatePassword" class="tech-modal-overlay" @click.self="closePasswordModal">
+      <div class="tech-modal result-modal">
+        <!-- 弹窗标题 -->
+        <div class="modal-header">
+          <h3>修改密码</h3>
+          <button class="close-btn" @click="closePasswordModal">
+            <i class="fas fa-times" />
+          </button>
+        </div>
+
+        <div class="dialog-content">
+          <!-- 表单内容 -->
+          <div class="dialog-body">
+            <div class="password-form">
+              <div class="form-group">
+                <label for="oldPassword">原密码</label>
+                <div class="password-input-container">
+                  <input
+                    id="oldPassword" 
+                    v-model="passwordForm.oldPassword" 
+                    :type="passwordVisibility.oldPassword ? 'text' : 'password'" 
+                    class="form-input"
+                    placeholder="请输入原密码"
+                  />
+                  <span class="password-toggle" @click="togglePasswordVisibility('oldPassword')">
+                    <i :class="passwordVisibility.oldPassword ? 'fas fa-eye-slash' : 'fas fa-eye'" />
+                  </span>
+                </div>
+              </div>
+              <div class="form-group">
+                <label for="newPassword">新密码</label>
+                <div class="password-input-container">
+                  <input
+                    id="newPassword" 
+                    v-model="passwordForm.newPassword" 
+                    :type="passwordVisibility.newPassword ? 'text' : 'password'" 
+                    class="form-input"
+                    placeholder="请输入新密码(不少于8位)"
+                    @input="validateNewPassword"
+                  />
+                  <span class="password-toggle" @click="togglePasswordVisibility('newPassword')">
+                    <i :class="passwordVisibility.newPassword ? 'fas fa-eye-slash' : 'fas fa-eye'" />
+                  </span>
+                </div>
+                <div v-if="passwordErrors.newPassword" class="input-error">
+                  {{ passwordErrors.newPassword }}
+                </div>
+              </div>
+              <div class="form-group">
+                <label for="newPassword2">确认密码</label>
+                <div class="password-input-container">
+                  <input
+                    id="newPassword2" 
+                    v-model="passwordForm.newPassword2" 
+                    :type="passwordVisibility.newPassword2 ? 'text' : 'password'" 
+                    class="form-input"
+                    placeholder="请再次输入新密码"
+                    @input="validateConfirmPassword"
+                  />
+                  <span class="password-toggle" @click="togglePasswordVisibility('newPassword2')">
+                    <i :class="passwordVisibility.newPassword2 ? 'fas fa-eye-slash' : 'fas fa-eye'" />
+                  </span>
+                </div>
+                <div v-if="passwordErrors.newPassword2" class="input-error">
+                  {{ passwordErrors.newPassword2 }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+
+        <!-- 底部按钮 -->
+        <div class="dialog-footer">
+          <div class="footer-buttons">
+            <button class="modal-btn close-action-btn" @click="closePasswordModal">
+              取消
+            </button>
+            <button class="modal-btn primary-btn" @click="handleUpdatePassword">
+              <i class="fas fa-key" />
+              确认修改
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+    
+    <!-- 大件运输选项弹窗 -->
+    <div v-if="bigProductTransportVisible" class="tech-modal-overlay" @click.self="closeBigTransportModal">
+      <div class="tech-modal">
+        <div class="modal-content-row">
+          <div class="modal-text">
+            <h3>请选择大件运输操作</h3>
+            <p>请选择您要进行的大件运输操作类型</p>
+          </div>
+          <div class="modal-icon">
+            <div class="icon-box">
+              <i class="fas fa-truck" />
+            </div>
+          </div>
+        </div>
+        <div class="modal-footer">
+          <button class="modal-btn cancel-btn" @click="closeBigTransportModal">取消</button>
+          <button class="modal-btn confirm-btn" @click="selectTransportType('OPEN')">大件运输常开</button>
+          <button class="modal-btn confirm-btn" @click="selectTransportType('CLOSE')">关闭常开</button>
+        </div>
+      </div>
+    </div>
+
+    <!-- 大件运输确认弹窗 -->
+    <div v-if="bigTransportConfirmVisible" class="tech-modal-overlay" @click.self="closeBigTransportConfirmModal">
+      <div class="tech-modal confirmation-modal">
+        <div class="modal-content-row">
+          <div class="modal-text">
+            <h3>大件运输确认</h3>
+            <div class="confirmation-content">
+              <p>尊敬的用户,您好</p>
+              <p>进行大件运输会记录您的信息,请务必遵守管理制度。</p>
+              <p v-if="bigType === 'OPEN'">大件运输完成以后,请务必手工关门。</p>
+              <p v-if="bigType === 'CLOSE'">大件运输关闭常开时,请务必远离闸机。</p>
+              <p class="confirm-text">您同意的话,请点击【确认】按钮,否则点击【取消】按钮。</p>
+            </div>
+          </div>
+          <div class="modal-icon">
+            <div class="icon-box">
+              <i class="fas fa-exclamation-triangle" />
+            </div>
+          </div>
+        </div>
+        <div class="modal-footer">
+          <button class="modal-btn cancel-btn" @click="closeBigTransportConfirmModal">取消</button>
+          <button class="modal-btn confirm-btn" @click="confirmBigTransport">确认</button>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div v-if="loading" class="loading-overlay">
+    <div class="loading-dots">
+      <div class="dot" />
+      <div class="dot" />
+      <div class="dot" />
+    </div>
+    <span class="loading-text">执行中...</span>
   </div>
 </template>
 
 <script setup>
+import { showNotify } from 'vant';
 import { useRouter } from 'vue-router';
 import { getQueryString } from '../util/common.js';
+import { controlGateByBigInv} from '../api/gate.js';
 import { ref, reactive, onMounted, onUnmounted } from 'vue';
-import { getWarehouseId } from '../api/login.js';
+import { getWarehouseId, updateUserPassword, queryRemindTime } from '../api/login.js';
 
 // 图片资源 - 从 assets/images 目录加载
 import cardIcon1 from '../assets/images/card1.png';
@@ -173,6 +323,40 @@ const isOutMenu = ref(true);
 
 // 是否为管理员
 const isAdmin = ref(false);
+const loading = ref(false);
+
+// 是否需要更新密码
+const isUpdatePassword = ref(false);
+
+// 密码表单数据
+const passwordForm = reactive({
+    oldPassword: '',
+    newPassword: '',
+    newPassword2: '',
+});
+
+// 密码表单错误信息
+const passwordErrors = reactive({
+    newPassword: '',
+    newPassword2: '',
+});
+
+// 密码可见性状态
+const passwordVisibility = reactive({
+    oldPassword: false,
+    newPassword: false,
+    newPassword2: false,
+});
+
+// 切换密码可见性
+const togglePasswordVisibility = field => {
+    passwordVisibility[field] = !passwordVisibility[field];
+};
+
+// 大件运输相关状态
+const bigProductTransportVisible = ref(false);
+const bigTransportConfirmVisible = ref(false);
+const bigType = ref('');
 
 // 设置下拉菜单状态
 const showSettings = ref(false);
@@ -212,6 +396,8 @@ onMounted(() => {
     getNowUserRole();
     getWarehouseInfo();
 
+    checkPasswordReminder();
+
     infoTimer = setInterval(() => {
         getInfo();
     }, 1000 * 60);
@@ -288,17 +474,19 @@ const outButtons = reactive([
     { label: '领料', action: 'materialOut' },
     { label: '拣货', action: 'materialReturn' },
     { label: '还料', action: 'materialIn' },
-    { label: 'AGV RFID\n校验', action: 'agvRfidRecognition' },
+    // { label: 'AGV RFID\n校验', action: 'agvRfidRecognition' },
     { label: '成品\n入库', action: 'finishedProductIn' },
+    { label: '大件\n运输', action: 'bigProductTransport' },
 ]);
 
 // 内侧屏幕操作按钮
 const inButtons = reactive([
     { label: '出库\n确认', action: 'materialOutLeave' },
-    { label: '还料\n离开', action: 'materialInLeave' },
+    { label: '入库\n离开', action: 'materialInLeave' },
     { label: '成品\n出库', action: 'finishedProductOut' },
-    { label: '料箱\n上架', action: 'feedingArea' },
-    { label: '异常\n停泊区', action: 'abnormalAnchorageArea' },
+    { label: '大件\n运输', action: 'bigProductTransport' },
+    // { label: '料箱\n上架', action: 'feedingArea' },
+    // { label: '异常\n停泊区', action: 'abnormalAnchorageArea' },
     // { label: '还料区\n管理', action: 'returnManagement' },
     // { label: '取料区\n管理', action: 'deliverManagement' },
 ]);
@@ -341,6 +529,18 @@ const goControlGate = () => {
     router.push('/control-gate');
 };
 
+// 跳转到异常停泊区页面
+const goAbnormalArea = () => {
+    showSettings.value = false;
+    router.push('/abnormal-anchorage-area');
+};
+
+// 跳转到RFID记录页面
+const goRfidRecord = () => {
+    showSettings.value = false;
+    router.push('/agv-rfid-recognition');
+};
+
 // 切换菜单
 const toggleMenu = () => {
     // isOut.value = !isOut.value;
@@ -407,6 +607,9 @@ const handleAction = action => {
     case 'deliverManagement':
         router.push('/delivery-management');
         break;
+    case 'bigProductTransport':
+        bigProductTransportVisible.value = true;
+        break;
     }
 };
 
@@ -497,6 +700,158 @@ const getWarehouseInfo = async () => {
         console.error('获取仓库ID失败:', error);
     }
 };
+
+const handleControl = async (command, actionName) => {
+    console.log('handleControl:', command, actionName);
+    loading.value = true;
+    try {
+        const res = await controlGateByBigInv(command);
+        
+        if (res.errorCode === 0) {
+            showNotify({ type: 'success', message: `${actionName}操作成功`, duration: 2000 });
+            if (actionName.includes('开')) {
+                plugin.soundPlay.playOpen();
+            } else if (actionName.includes('关')) {
+                plugin.soundPlay.playClose();
+            }
+        } else {
+            showNotify({ type: 'danger', message: res.errorMessage || `${actionName}操作失败`, duration: 3000 });
+        }
+    } catch (error) {
+        console.error('闸机控制失败:', error);
+        showNotify({ type: 'danger', message: `${actionName}操作失败`, duration: 3000 });
+    } finally {
+        loading.value = false;
+    }
+};
+
+const checkPasswordReminder = async () => {
+    try {
+        const res = await queryRemindTime();
+        if (res.errorCode === 0) {
+            if (res.data === true) {
+                setTimeout(() => {
+                    showNotify({ type: 'danger', message: res.errorMessage });
+                    // 显示修改密码弹窗
+                    isUpdatePassword.value = true;
+                }, 4000);
+            }
+        } else {
+            showNotify({ type: 'danger', message: res.errorMessage });
+        }
+    } catch (error) {
+        console.error('提示修改密码Api调用失败', error);
+        showNotify({ type: 'danger', message: '修改密码Api调用失败' });
+    }
+};
+
+// 关闭密码修改弹窗
+const closePasswordModal = () => {
+    isUpdatePassword.value = false;
+    // 重置表单
+    passwordForm.oldPassword = '';
+    passwordForm.newPassword = '';
+    passwordForm.newPassword2 = '';
+    passwordErrors.newPassword = '';
+    passwordErrors.newPassword2 = '';
+};
+
+// 验证密码
+const validatePasswordForm = () => {
+    let isValid = true;
+
+    // 重置错误信息
+    passwordErrors.newPassword = '';
+    passwordErrors.newPassword2 = '';
+
+    // 验证新密码长度
+    if (passwordForm.newPassword && passwordForm.newPassword.length < 8) {
+        passwordErrors.newPassword = '新密码长度不得小于8位';
+        isValid = false;
+    }
+
+    // 验证两次密码输入是否一致
+    if (passwordForm.newPassword2 && passwordForm.newPassword !== passwordForm.newPassword2) {
+        passwordErrors.newPassword2 = '两次输入的密码不一致';
+        isValid = false;
+    }
+
+    return isValid;
+};
+
+// 实时验证新密码
+const validateNewPassword = () => {
+    passwordErrors.newPassword = '';
+    if (passwordForm.newPassword && passwordForm.newPassword.length < 8) {
+        passwordErrors.newPassword = '新密码长度不得小于8位';
+    }
+};
+
+// 实时验证确认密码
+const validateConfirmPassword = () => {
+    passwordErrors.newPassword2 = '';
+    if (passwordForm.newPassword2 && passwordForm.newPassword !== passwordForm.newPassword2) {
+        passwordErrors.newPassword2 = '两次输入的密码不一致';
+    }
+};
+
+// 处理密码更新
+const handleUpdatePassword = async () => {
+    // 验证表单
+    if (!validatePasswordForm()) {
+        return;
+    }
+
+    try {
+        const res = await updateUserPassword({
+            oldPassword: passwordForm.oldPassword,
+            newPassword: passwordForm.newPassword,
+            newPassword2: passwordForm.newPassword2,
+        });
+
+        if (res === '修改密码成功') {
+            closePasswordModal();
+            showNotify({ type: 'success', message: '密码修改成功' });
+            router.push('/login');
+        } else {
+            showNotify({ type: 'danger', message: res.errorMessage || '密码修改失败' });
+        }
+    } catch (error) {
+        console.error('密码修改失败:', error);
+        showNotify({ type: 'danger', message: '密码修改失败' });
+    }
+};
+
+// 关闭大件运输选项弹窗
+const closeBigTransportModal = () => {
+    bigProductTransportVisible.value = false;
+    bigType.value = '';
+};
+
+// 关闭大件运输确认弹窗
+const closeBigTransportConfirmModal = () => {
+    bigTransportConfirmVisible.value = false;
+    bigType.value = '';
+};
+
+// 选择运输类型
+const selectTransportType = type => {
+    bigType.value = type;
+    console.log('selectTransportType:', type);
+    bigProductTransportVisible.value = false;
+    bigTransportConfirmVisible.value = true;
+};
+
+// 确认大件运输操作
+const confirmBigTransport = async () => {
+    const actionName = bigType.value === 'OPEN' ? '大件运输常开' : '关闭大件运输常开';
+
+    await handleControl(bigType.value, actionName);
+  
+    // 关闭确认弹窗
+    closeBigTransportConfirmModal();
+
+};
 </script>
 
 <style scoped>
@@ -659,6 +1014,266 @@ const getWarehouseInfo = async () => {
   object-fit: contain;
 }
 
+/* 密码修改弹窗样式 */
+.tech-modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.7);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 10000;
+}
+
+.tech-modal {
+  background: linear-gradient(135deg, rgba(13, 58, 106, 0.95) 0%, rgba(9, 45, 82, 0.95) 100%);
+  border: 1px solid #2a7fff;
+  border-radius: 12px;
+  width: 90%;
+  max-width: 500px !important;
+  box-shadow: 0 0 30px rgba(0, 191, 255, 0.3);
+  overflow: hidden;
+  animation: modalFadeIn 0.3s ease;
+}
+
+.result-modal {
+  width: 90%;
+  max-width: 500px;
+}
+
+@keyframes modalFadeIn {
+  from {
+    opacity: 0;
+    transform: translateY(-20px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+.modal-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 15px 20px;
+  border-bottom: 1px solid rgba(42, 127, 255, 0.3);
+}
+
+.modal-header h3 {
+  margin: 0;
+  color: #ffffff;
+  font-size: 18px;
+  font-weight: 600;
+}
+
+.close-btn {
+  background: transparent;
+  border: none;
+  color: #7ec8ff;
+  font-size: 16px;
+  cursor: pointer;
+  transition: all 0.2s;
+  width: 30px;
+  height: 30px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border-radius: 50%;
+}
+
+.close-btn:hover {
+  background: rgba(126, 200, 255, 0.2);
+  color: #ffffff;
+}
+
+.dialog-content {
+  padding: 20px;
+}
+
+.verification-status {
+  margin-bottom: 15px;
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+
+.status-tag {
+  display: inline-flex;
+  align-items: center;
+  padding: 6px 12px;
+  border-radius: 4px;
+  font-size: 14px;
+  font-weight: 500;
+  gap: 6px;
+}
+
+.status-tag.success {
+  background: rgba(37, 236, 135, 0.2);
+  color: #25EC87;
+  border: 1px solid rgba(37, 236, 135, 0.3);
+}
+
+.status-tag.danger {
+  background: rgba(255, 77, 79, 0.2);
+  color: #FF4D4F;
+  border: 1px solid rgba(255, 77, 79, 0.3);
+}
+
+.dialog-body {
+  display: flex;
+  gap: 20px;
+}
+
+.password-form {
+  width: 100%;
+}
+
+.form-group {
+  margin-bottom: 15px;
+}
+
+.form-group label {
+  display: block;
+  margin-bottom: 6px;
+  font-size: 14px;
+  color: #7ec8ff;
+}
+
+.password-input-container {
+  position: relative;
+  width: 100%;
+}
+
+.form-input {
+  width: 100%;
+  padding: 10px 12px;
+  background: rgba(0, 44, 81, 0.5);
+  border: 1px solid rgba(42, 127, 255, 0.5);
+  border-radius: 4px;
+  color: #ffffff;
+  font-size: 14px;
+  transition: all 0.3s;
+  padding-right: 40px; /* Space for the eye icon */
+}
+
+.form-input:focus {
+  outline: none;
+  border-color: #2a7fff;
+  box-shadow: 0 0 0 2px rgba(42, 127, 255, 0.2);
+}
+
+.form-input::placeholder {
+  color: rgba(126, 200, 255, 0.5);
+}
+
+.password-toggle {
+  position: absolute;
+  right: 12px;
+  top: 50%;
+  transform: translateY(-50%);
+  cursor: pointer;
+  color: #7ec8ff;
+  font-size: 16px;
+  transition: all 0.2s;
+}
+
+.password-toggle:hover {
+  color: #ffffff;
+}
+
+.input-error {
+  color: #FF4D4F;
+  font-size: 12px;
+  margin-top: 4px;
+}
+
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  padding: 15px 20px;
+  border-top: 1px solid rgba(42, 127, 255, 0.3);
+}
+
+.footer-buttons {
+  display: flex;
+  gap: 10px;
+  width: 100%;
+  justify-content: flex-end;
+}
+
+.modal-btn {
+  padding: 8px 16px;
+  border-radius: 4px;
+  font-size: 14px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: all 0.3s;
+  border: none;
+  display: flex;
+  align-items: center;
+  gap: 6px;
+}
+
+.close-action-btn {
+  background: rgba(126, 200, 255, 0.1);
+  color: #7ec8ff;
+  border: 1px solid rgba(126, 200, 255, 0.3);
+}
+
+.close-action-btn:hover {
+  background: rgba(126, 200, 255, 0.2);
+}
+
+.primary-btn {
+  background: linear-gradient(90deg, #1e90ff 0%, #00bfff 100%);
+  color: #ffffff;
+}
+
+.primary-btn:hover {
+  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
+  transform: translateY(-1px);
+}
+
+/* 大件运输弹窗特殊样式 */
+.confirmation-modal .modal-content-row {
+  align-items: flex-start;
+}
+
+.confirmation-content {
+  text-align: left;
+  line-height: 1.6;
+}
+
+.confirmation-content p {
+  margin: 8px 0;
+  color: #ffffff;
+}
+
+.confirm-text {
+  margin-top: 16px !important;
+  font-weight: 500;
+  color: #7ec8ff !important;
+}
+
+/* 大件运输选项按钮布局 */
+.modal-footer {
+  display: flex;
+  justify-content: center;
+  gap: 10px;
+  padding: 20px;
+  flex-wrap: wrap;
+}
+
+.modal-footer .modal-btn {
+  min-width: 120px;
+  padding: 10px 16px;
+}
+
 /* 设置下拉菜单样式 */
 .settings-dropdown {
   position: relative;
@@ -1254,6 +1869,10 @@ const getWarehouseInfo = async () => {
     padding: 15px;
   }
 
+  .buttons-section2 {
+    gap: 86px;
+  }
+
   .action-btn {
     width: 160px;
     height: 160px;
@@ -1352,6 +1971,10 @@ const getWarehouseInfo = async () => {
     padding: 20px;
   }
 
+  .buttons-section2 {
+    gap: 86px;
+  }
+
   .action-btn {
     width: 160px;
     height: 160px;
@@ -1493,6 +2116,9 @@ const getWarehouseInfo = async () => {
   cursor: pointer;
   transition: all 0.3s;
   border: none;
+  display: flex;
+  align-items: center;
+  justify-content: center;
 }
 
 .cancel-btn {

+ 8 - 8
src/login/UserLogin.vue

@@ -269,7 +269,7 @@ const handleLogin = async () => {
             } else {
                 router.push('/home');
             }
-            checkPasswordReminder();
+            // checkPasswordReminder();
             checkAwayAbnormalCar();
         } else {
             showNotify({ type: 'danger', message: res.errorMessage });
@@ -385,7 +385,7 @@ onUnmounted(() => {
     radial-gradient(circle at 40% 60%, rgba(0, 255, 127, 0.05) 0%, transparent 50%),
     linear-gradient(135deg, #0a0a23 0%, #1a1a3a 25%, #194777 50%, #1a1a3a 75%, #0a0a23 100%);
   background-size: 100% 100%, 100% 100%, 100% 100%, 100% 100%;
-  animation: bgShift 20s ease-in-out infinite;
+  /* animation: bgShift 20s ease-in-out infinite; */
   z-index: 0;
 }
 
@@ -514,7 +514,7 @@ onUnmounted(() => {
   position: absolute;
   border-radius: 50%;
   background: radial-gradient(circle, rgba(30, 144, 255, 0.8) 0%, rgba(30, 144, 255, 0.2) 50%, transparent 100%);
-  animation: particleFloat 12s linear infinite;
+  /* animation: particleFloat 12s linear infinite; */
   will-change: transform, opacity;
   transform: translateZ(0);
   -webkit-backface-visibility: hidden;
@@ -643,7 +643,7 @@ onUnmounted(() => {
   height: 2px;
   top: 30%;
   left: 10%;
-  animation: lineSlide 8s linear infinite;
+  /* animation: lineSlide 8s linear infinite; */
 }
 
 .line-2 {
@@ -687,7 +687,7 @@ onUnmounted(() => {
   border-radius: 50%;
   background: rgba(30, 144, 255, 0.6);
   box-shadow: 0 0 20px rgba(30, 144, 255, 0.4);
-  animation: dotPulse 3s ease-in-out infinite;
+  /* animation: dotPulse 3s ease-in-out infinite; */
   will-change: transform, opacity;
   transform: translateZ(0);
 }
@@ -828,7 +828,7 @@ onUnmounted(() => {
     rgba(160, 172, 192, 0.8) 60%, 
     transparent 100%
   );
-  animation: matrixFall 20s linear infinite;
+  /* animation: matrixFall 20s linear infinite; */
 }
 
 /* .matrix-column::before {
@@ -875,7 +875,7 @@ onUnmounted(() => {
   border: 1px solid rgba(0, 255, 255, 0.2);
   background: rgba(0, 255, 255, 0.02);
   clip-path: polygon(30% 0%, 70% 0%, 100% 50%, 70% 100%, 30% 100%, 0% 50%);
-  animation: hexGlow 6s ease-in-out infinite;
+  /* animation: hexGlow 6s ease-in-out infinite; */
 }
 
 .hex-1 { top: 15%; left: 20%; animation-delay: 0s; }
@@ -915,7 +915,7 @@ onUnmounted(() => {
   width: 100%;
   height: 1px;
   background: linear-gradient(90deg, transparent, rgba(0, 255, 255, 0.8), transparent);
-  animation: scanMove 6s linear infinite;
+  /* animation: scanMove 6s linear infinite; */
 }
 
 .scan-1 { animation-delay: 0s; }

+ 2 - 2
src/stock-in/ReturnedLeave.vue

@@ -10,7 +10,7 @@
         <i class="fas fa-home" />
         <span>主页</span>
       </button>
-      <h1 class="page-title">还料离开</h1>
+      <h1 class="page-title">入库离开</h1>
       <!-- 右侧操作按钮 -->
       <div class="header-actions">
         <button class="action-btn refresh-btn" @click="verify">
@@ -84,7 +84,7 @@
     <!-- 底部操作按钮 -->
     <div class="bottom-actions">
       <button class="submit-btn" :disabled="notInStockCount" @click="handleComplete">
-        还料离开
+        入库离开
       </button>
     </div>