Просмотр исходного кода

样式优化,修改 agv 校验

liuyanpeng 6 месяцев назад
Родитель
Сommit
7347c66a57

+ 6 - 78
src/Fingerprint/FingerprintEnroll.vue

@@ -144,7 +144,12 @@
 
     <!-- Loading -->
     <div v-if="checking" class="loading-overlay">
-      <div class="loading-spinner" />
+      <div class="loading-dots">
+        <div class="dot" />
+        <div class="dot" />
+        <div class="dot" />
+      </div>
+      <span class="loading-text">加载中...</span>
     </div>
   </div>
 </template>
@@ -360,56 +365,6 @@ onUnmounted(() => {
   z-index: 0;
 }
 
-/* ========== 顶部标题区域 ========== */
-.header-section {
-  position: relative;
-  width: 100%;
-  padding: 20px 30px;
-  box-sizing: border-box;
-  z-index: 10;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.back-btn {
-  position: absolute;
-  left: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 16px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.back-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.back-btn i {
-  font-size: 18px;
-  color: #00bfff;
-}
-
-.page-title {
-  font-size: 28px;
-  font-weight: bold;
-  color: #ffffff;
-  letter-spacing: 2px;
-  margin: 0;
-  text-shadow: 0 0 10px rgba(0, 191, 255, 0.5);
-}
-
 /* ========== 主内容区域 ========== */
 .main-content {
   flex: 1;
@@ -778,33 +733,6 @@ onUnmounted(() => {
   cursor: not-allowed;
 }
 
-/* ========== Loading 遮罩 ========== */
-.loading-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(4, 28, 61, 0.8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.loading-spinner {
-  width: 60px;
-  height: 60px;
-  border: 4px solid rgba(30, 144, 255, 0.3);
-  border-top-color: #00bfff;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
-  to { transform: rotate(360deg); }
-}
-
 /* ========== 响应式 - 横屏 ========== */
 @media screen and (orientation: landscape) {
   .header-section {

+ 6 - 67
src/agv-process/DeliveryManagement.vue

@@ -69,7 +69,12 @@
 
     <!-- Loading -->
     <div v-if="loading" class="loading-overlay">
-      <div class="loading-spinner" />
+      <div class="loading-dots">
+        <div class="dot" />
+        <div class="dot" />
+        <div class="dot" />
+      </div>
+      <span class="loading-text">加载中...</span>
     </div>
   </div>
 </template>
@@ -199,45 +204,6 @@ onMounted(() => {
   z-index: 0;
 }
 
-/* ========== 顶部标题区域 ========== */
-.header-section {
-  position: relative;
-  width: 100%;
-  padding: 20px 30px;
-  z-index: 10;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.back-btn {
-  position: absolute;
-  left: 30px;
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 16px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.back-btn:hover {
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.page-title {
-  font-size: 28px;
-  font-weight: bold;
-  color: #ffffff;
-  text-shadow: 0 0 10px rgba(0, 191, 255, 0.5);
-}
-
 /* ========== 主内容区域 ========== */
 .main-content {
   flex: 1;
@@ -485,33 +451,6 @@ onMounted(() => {
   box-shadow: 0 0 20px rgba(30, 144, 255, 0.5);
 }
 
-/* ========== Loading ========== */
-.loading-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(4, 28, 61, 0.8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.loading-spinner {
-  width: 60px;
-  height: 60px;
-  border: 4px solid rgba(30, 144, 255, 0.3);
-  border-top-color: #00bfff;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
-  to { transform: rotate(360deg); }
-}
-
 /* ========== 响应式 - 横屏 ========== */
 @media screen and (orientation: landscape) {
   .header-section {

+ 11 - 3
src/agv-process/ReturnManagement.vue

@@ -78,7 +78,7 @@
             <div class="tooling-header-row">
               <van-field
                 v-model="toolingSearchKeyword"
-                placeholder="搜索工装..."
+                placeholder="请输入名称..."
                 left-icon="search"
                 class="tooling-input"
                 @update:model-value="handleToolingSearch"
@@ -160,14 +160,22 @@
             <!-- 无数据提示 -->
             <div v-if="toolingDevices.length === 0 && !loading" class="tooling-empty">
               <van-icon name="search" size="24" color="#9ca3af" />
-              <span>输入关键词搜索工装设备</span>
+              <span>输入名称关键词</span>
             </div>
           </div>
         </transition>
       </div>
     </van-dialog>
 
-    <Loading v-if="loading" />
+    <!-- Loading -->
+    <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>
   </div>
 </template>
 

+ 1 - 1
src/api/finishProduct.js

@@ -30,7 +30,7 @@ export function generateStockOut(params) {
 // 获取货位列表
 export function getLocatorList() {
     return request({
-        url: '/api/positionResource/positions',
+        url: '/api/positionResource/queryIdlePositionByFinish',
         method: 'get',
     });
 }

+ 17 - 0
src/api/login.js

@@ -6,4 +6,21 @@ export function loginApi(params) {
         method: 'post',
         data: params,
     });
+}
+
+
+// 闸机侧查询当天出入库数据
+export function getStaticInfo() {
+    return request({
+        url: '/api/StockOutResource/queryInboundAndOutboundData',
+        method: 'get',
+    });
+}
+
+// 登录时查看是否需要修改密码,默认30天后提醒
+export function queryRemindTime() {
+    return request({
+        url: '/api/RemindPasswordTimeResource/queryRemindTime',
+        method: 'get',
+    });
 }

+ 589 - 0
src/assets/css/common.css

@@ -0,0 +1,589 @@
+/**
+ * 智能仓储管理系统 - 通用样式
+ * 包含:Loading、背景层、科技风弹窗、顶部栏、按钮等通用组件样式
+ * 适配 1080x1920 竖屏显示
+ */
+
+/* ========== 顶部标题区域 - 通用样式 ========== */
+.header-section {
+  position: relative;
+  width: 100%;
+  /* padding: 0 30px 25px 30px; 增加顶部padding,避免showNotify遮挡 */
+  box-sizing: border-box;
+  z-index: 10;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+  padding: 24px 20px !important;
+}
+
+.page-title {
+  font-size: 32px;
+  font-weight: bold;
+  color: #ffffff;
+  letter-spacing: 2px;
+  margin: 0;
+  text-shadow: 0 0 10px rgba(0, 191, 255, 0.5);
+}
+
+/* 顶部左侧按钮(返回/主页) */
+.logout-btn,
+.back-btn {
+  position: absolute;
+  left: 30px;
+  top: 50%;
+  transform: translateY(-50%);
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
+  border: 1px solid #2a7fff;
+  border-radius: 10px;
+  padding: 14px 28px;
+  color: #fff;
+  font-size: 18px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: all 0.3s;
+  min-height: 52px;
+}
+
+.logout-btn:hover,
+.back-btn:hover {
+  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
+  box-shadow: 0 0 20px rgba(30, 144, 255, 0.5);
+}
+
+.logout-btn i,
+.back-btn i {
+  font-size: 20px;
+  color: #00bfff;
+}
+
+/* 顶部右侧操作按钮区域 */
+.header-actions {
+  position: absolute;
+  right: 30px;
+  top: 40px;
+  transform: translateY(-50%);
+  display: flex;
+  align-items: center;
+  gap: 20px;
+  padding: 24px 0 !important;
+}
+
+@media screen and (orientation: portrait) and (min-width: 900px) {
+    .header-actions {
+        padding: 44px 0 24px 0 !important;
+    }
+}
+
+/* 顶部操作按钮 - 通用样式 */
+.action-btn {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
+  border: 1px solid #2a7fff;
+  border-radius: 10px;
+  padding: 14px 28px;
+  color: #fff;
+  font-size: 18px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: all 0.3s;
+  min-height: 52px;
+}
+
+.action-btn:hover {
+  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
+  box-shadow: 0 0 20px rgba(30, 144, 255, 0.5);
+}
+
+.action-btn i {
+  font-size: 20px;
+  color: #00bfff;
+}
+
+/* 常用领料按钮 - 紫色主题 */
+.regular-btn {
+  background: linear-gradient(90deg, #5a3a7a 0%, #4a2a6a 100%);
+  border-color: #8a5fff;
+}
+
+.regular-btn:hover {
+  background: linear-gradient(90deg, #6a4a8a 0%, #5a3a7a 100%);
+  box-shadow: 0 0 20px rgba(138, 95, 255, 0.5);
+}
+
+.regular-btn i {
+  color: #d4a5ff;
+}
+
+/* 领料车按钮 - 青色主题 */
+.cart-btn {
+  background: linear-gradient(90deg, #1a6a5a 0%, #0d5a4a 100%);
+  border-color: #2affcf;
+}
+
+.cart-btn:hover {
+  background: linear-gradient(90deg, #2a7a6a 0%, #1d6a5a 100%);
+  box-shadow: 0 0 20px rgba(42, 255, 207, 0.5);
+}
+
+.cart-btn i {
+  color: #2affcf;
+}
+
+/* ========== Loading 遮罩层 - 三点跳动动画 ========== */
+.loading-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(4, 28, 61, 0.85);
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  z-index: 9899999999999;
+}
+
+/* 三点跳动容器 */
+.loading-dots {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 12px;
+}
+
+/* 单个圆点样式 */
+.loading-dots .dot {
+  width: 16px;
+  height: 16px;
+  background: #fff;
+  border-radius: 50%;
+  animation: dotBounce 1.4s ease-in-out infinite both;
+}
+
+.loading-dots .dot:nth-child(1) {
+  animation-delay: -0.32s;
+}
+
+.loading-dots .dot:nth-child(2) {
+  animation-delay: -0.16s;
+}
+
+.loading-dots .dot:nth-child(3) {
+  animation-delay: 0s;
+}
+
+/* 跳动动画 */
+@keyframes dotBounce {
+  0%, 80%, 100% {
+    transform: scale(0.6);
+    opacity: 0.5;
+  }
+  40% {
+    transform: scale(1);
+    opacity: 1;
+  }
+}
+
+/* Loading 文字 */
+.loading-text {
+  margin-top: 20px;
+  color: #7ec8ff;
+  font-size: 16px;
+  letter-spacing: 2px;
+}
+
+/* ========== 旧版 Loading 旋转动画(保留兼容) ========== */
+.loading-spinner {
+  width: 60px;
+  height: 60px;
+  border: 4px solid rgba(30, 144, 255, 0.3);
+  border-top-color: #00bfff;
+  border-radius: 50%;
+  animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+/* ========== 深色科技风背景层 ========== */
+.bg-layer {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: #041c3d;
+  background-size: cover;
+  background-position: center;
+  background-repeat: no-repeat;
+  z-index: 0;
+}
+
+/* ========== 科技感弹窗样式 - 适配1080x1920竖屏 ========== */
+.tech-modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(4, 28, 61, 0.9);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 2000;
+  animation: fadeIn 0.3s ease;
+}
+
+@keyframes fadeIn {
+  from { opacity: 0; }
+  to { opacity: 1; }
+}
+
+.tech-modal {
+  background: linear-gradient(135deg, rgba(9, 45, 82, 0.98) 0%, rgba(5, 30, 60, 0.98) 100%);
+  border: 2px solid #2a7fff;
+  border-radius: 20px;
+  padding: 50px 40px;
+  min-width: 600px;
+  max-width: 90%;
+  box-shadow: 0 0 60px rgba(30, 144, 255, 0.4), 0 30px 80px rgba(0, 0, 0, 0.6);
+  animation: slideIn 0.3s ease;
+}
+
+@keyframes slideIn {
+  from {
+    opacity: 0;
+    transform: translateY(-30px);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+.tech-modal.danger-modal {
+  border-color: #ef4444;
+  box-shadow: 0 0 60px rgba(239, 68, 68, 0.4), 0 30px 80px rgba(0, 0, 0, 0.6);
+}
+
+.modal-content-row {
+  display: flex;
+  align-items: center;
+  gap: 40px;
+  margin-bottom: 40px;
+}
+
+.modal-text {
+  flex: 1;
+}
+
+.modal-text h3 {
+  font-size: 32px;
+  font-weight: 700;
+  color: #fff;
+  margin: 0 0 20px 0;
+  text-shadow: 0 0 15px rgba(0, 191, 255, 0.4);
+}
+
+.modal-text p {
+  font-size: 22px;
+  color: #7ec8ff;
+  margin: 0;
+  line-height: 1.6;
+}
+
+.modal-icon {
+  flex-shrink: 0;
+}
+
+.icon-box {
+  width: 100px;
+  height: 100px;
+  background: linear-gradient(135deg, #1e90ff 0%, #00bfff 100%);
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-shadow: 0 0 40px rgba(30, 144, 255, 0.5);
+}
+
+.icon-box.danger-box {
+  background: linear-gradient(135deg, #dc2626 0%, #ef4444 100%);
+  box-shadow: 0 0 40px rgba(239, 68, 68, 0.5);
+}
+
+.icon-box i {
+  font-size: 48px;
+  color: #fff;
+}
+
+.modal-footer {
+  display: flex;
+  gap: 30px;
+}
+
+.modal-btn {
+  flex: 1;
+  padding: 22px 0;
+  border-radius: 14px;
+  font-size: 24px;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.3s;
+  border: none;
+  min-height: 70px;
+}
+
+.modal-btn.cancel-btn,
+.modal-btn.cancel {
+  background: rgba(13, 58, 106, 0.8);
+  border: 2px solid #2a7fff;
+  color: #7ec8ff;
+}
+
+.modal-btn.cancel-btn:hover,
+.modal-btn.cancel:hover {
+  background: rgba(26, 74, 122, 0.9);
+  box-shadow: 0 0 20px rgba(30, 144, 255, 0.4);
+}
+
+.modal-btn.confirm-btn,
+.modal-btn.confirm {
+  background: linear-gradient(90deg, #10b981 0%, #34d399 100%);
+  color: #fff;
+}
+
+.modal-btn.confirm-btn:hover,
+.modal-btn.confirm:hover {
+  box-shadow: 0 0 30px rgba(16, 185, 129, 0.6);
+  transform: translateY(-3px);
+}
+
+.modal-btn.danger-confirm-btn,
+.modal-btn.confirm.danger {
+  background: linear-gradient(90deg, #dc2626 0%, #ef4444 100%);
+  color: #fff;
+}
+
+.modal-btn.danger-confirm-btn:hover,
+.modal-btn.confirm.danger:hover {
+  box-shadow: 0 0 30px rgba(239, 68, 68, 0.6);
+  transform: translateY(-3px);
+}
+
+/* ========== 通用深色输入框样式 ========== */
+.dark-input {
+  width: 100%;
+  padding: 12px 16px;
+  background: rgba(13, 58, 106, 0.8);
+  border: 1px solid #2a7fff;
+  border-radius: 8px;
+  color: #fff;
+  font-size: 15px;
+  outline: none;
+  transition: all 0.3s ease;
+}
+
+.dark-input::placeholder {
+  color: #7ec8ff;
+  opacity: 0.7;
+}
+
+.dark-input:focus {
+  border-color: #00bfff;
+  box-shadow: 0 0 15px rgba(0, 191, 255, 0.3);
+}
+
+/* ========== Vue-Select 深色主题样式 - 全局统一 ========== */
+/* 适用于所有 v-select,确保下拉框为深色背景 */
+.v-select .vs__dropdown-toggle,
+.dark-select .vs__dropdown-toggle,
+.filter-select .vs__dropdown-toggle,
+.dialog-select .vs__dropdown-toggle {
+  background: rgba(13, 58, 106, 0.9) !important;
+  border: 1px solid #2a7fff !important;
+  border-radius: 8px !important;
+  padding: 8px 12px !important;
+  min-height: 48px !important;
+}
+
+.v-select .vs__selected,
+.dark-select .vs__selected,
+.filter-select .vs__selected,
+.dialog-select .vs__selected {
+  color: #fff !important;
+  font-size: 16px !important;
+}
+
+.v-select .vs__search,
+.dark-select .vs__search,
+.filter-select .vs__search,
+.dialog-select .vs__search {
+  color: #fff !important;
+  font-size: 16px !important;
+}
+
+.v-select .vs__search::placeholder,
+.dark-select .vs__search::placeholder,
+.filter-select .vs__search::placeholder,
+.dialog-select .vs__search::placeholder {
+  color: #7ec8ff !important;
+  opacity: 0.7 !important;
+}
+
+.v-select .vs__actions svg,
+.dark-select .vs__actions svg,
+.filter-select .vs__actions svg,
+.dialog-select .vs__actions svg {
+  fill: #7ec8ff !important;
+}
+
+.v-select .vs__clear svg,
+.dark-select .vs__clear svg,
+.filter-select .vs__clear svg,
+.dialog-select .vs__clear svg {
+  fill: #7ec8ff !important;
+}
+
+/* 下拉菜单样式 - 深色背景 */
+.v-select .vs__dropdown-menu,
+.dark-select .vs__dropdown-menu,
+.filter-select .vs__dropdown-menu,
+.dialog-select .vs__dropdown-menu {
+  background: rgba(9, 45, 82, 0.98) !important;
+  border: 1px solid #2a7fff !important;
+  border-radius: 8px !important;
+  z-index: 99999 !important;
+  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4) !important;
+}
+
+/* 针对 append-to-body 模式的下拉菜单 - 全局样式覆盖 */
+.vs__dropdown-menu {
+  background: rgba(9, 45, 82, 0.98) !important;
+  border: 1px solid #2a7fff !important;
+  border-radius: 8px !important;
+  z-index: 99999 !important;
+  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4) !important;
+}
+
+.vs__dropdown-menu .vs__dropdown-option {
+  color: #fff !important;
+  padding: 14px 18px !important;
+  font-size: 16px !important;
+  background: transparent !important;
+}
+
+.vs__dropdown-menu .vs__dropdown-option:hover,
+.vs__dropdown-menu .vs__dropdown-option--highlight {
+  background: rgba(30, 144, 255, 0.4) !important;
+  color: #fff !important;
+}
+
+.vs__dropdown-menu .vs__no-options {
+  color: #7ec8ff !important;
+  padding: 14px 18px !important;
+  font-size: 16px !important;
+  background: transparent !important;
+}
+
+.v-select .vs__dropdown-option,
+.dark-select .vs__dropdown-option,
+.filter-select .vs__dropdown-option,
+.dialog-select .vs__dropdown-option {
+  color: #fff !important;
+  padding: 14px 18px !important;
+  font-size: 16px !important;
+}
+
+.v-select .vs__dropdown-option--highlight,
+.dark-select .vs__dropdown-option--highlight,
+.filter-select .vs__dropdown-option--highlight,
+.dialog-select .vs__dropdown-option--highlight {
+  background: rgba(30, 144, 255, 0.4) !important;
+}
+
+.v-select .vs__no-options,
+.dark-select .vs__no-options,
+.filter-select .vs__no-options,
+.dialog-select .vs__no-options {
+  color: #7ec8ff !important;
+  padding: 14px 18px !important;
+  font-size: 16px !important;
+}
+
+/* ========== 通用按钮样式 ========== */
+.btn-primary {
+  background: linear-gradient(90deg, #1e90ff 0%, #00bfff 100%);
+  border: none;
+  color: #fff;
+  padding: 12px 30px;
+  border-radius: 8px;
+  font-size: 16px;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.3s;
+}
+
+.btn-primary:hover {
+  box-shadow: 0 0 20px rgba(30, 144, 255, 0.5);
+  transform: translateY(-2px);
+}
+
+.btn-primary:disabled {
+  opacity: 0.5;
+  cursor: not-allowed;
+  transform: none;
+  box-shadow: none;
+}
+
+.btn-secondary {
+  background: rgba(13, 58, 106, 0.8);
+  border: 1px solid #2a7fff;
+  color: #7ec8ff;
+  padding: 12px 30px;
+  border-radius: 8px;
+  font-size: 16px;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.3s;
+}
+
+.btn-secondary:hover {
+  background: rgba(26, 74, 122, 0.9);
+  box-shadow: 0 0 15px rgba(30, 144, 255, 0.3);
+}
+
+.btn-danger {
+  background: linear-gradient(90deg, #dc2626 0%, #ef4444 100%);
+  border: none;
+  color: #fff;
+  padding: 12px 30px;
+  border-radius: 8px;
+  font-size: 16px;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.3s;
+}
+
+.btn-danger:hover {
+  box-shadow: 0 0 20px rgba(239, 68, 68, 0.5);
+  transform: translateY(-2px);
+}
+
+.btn-danger:disabled {
+  opacity: 0.5;
+  cursor: not-allowed;
+  transform: none;
+  box-shadow: none;
+}

+ 0 - 0
src/assets/main.css → src/assets/css/main.css


+ 9 - 1
src/box/FeedingArea.vue

@@ -170,7 +170,15 @@
       <!-- <p>&copy; 2024 智能仓储管理系统. All rights reserved.</p> -->
     </footer>
   </div>
-  <Loading v-if="loading" />
+  <!-- Loading -->
+  <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>

+ 13 - 107
src/finishProduct/FinishProductIn.vue

@@ -174,7 +174,12 @@
 
     <!-- Loading -->
     <div v-if="loading" class="loading-overlay">
-      <div class="loading-spinner" />
+      <div class="loading-dots">
+        <div class="dot" />
+        <div class="dot" />
+        <div class="dot" />
+      </div>
+      <span class="loading-text">加载中...</span>
     </div>
   </div>
 </template>
@@ -249,7 +254,7 @@ const resetForm = () => {
 // 保存成品
 const saveProduct = () => {
     if (!isFormValid.value) {
-        showNotify({ type: 'warning', message: '请完整填写成品信息' });
+        showNotify({ type: 'danger', message: '请完整填写成品信息' });
         return;
     }
 
@@ -273,7 +278,7 @@ const saveProduct = () => {
 // 执行入库
 const handleSubmit = () => {
     if (products.value.length === 0) {
-        showNotify({ type: 'warning', message: '暂无可提交的成品,请添加成品' });
+        showNotify({ type: 'danger', message: '暂无可提交的成品,请添加成品' });
         return;
     }
     showConfirmModal.value = true;
@@ -296,7 +301,7 @@ const executeInbound = async () => {
         if (res.errorCode === 0) {
             showNotify({ type: 'success', message: `已提交 ${count} 条成品入库记录` });
         } else {
-            showNotify({ type: 'warning', message: res.errorMessage || '添加失败' });
+            showNotify({ type: 'danger', message: res.errorMessage || '添加失败' });
         }
         products.value = [];
         showConfirmModal.value = false;
@@ -330,7 +335,7 @@ const getLocators = async () => {
         if (res && res.length > 0) {
             warehouseLocationOptions.value = res;
         } else {
-            showNotify({ type: 'warning', message: '获取货位列表失败' });
+            showNotify({ type: 'danger', message: '获取货位列表失败' });
         }
     } catch (error) {
         console.log(error);
@@ -370,88 +375,18 @@ onMounted(() => {
   z-index: 0;
 }
 
-/* ========== 顶部标题区域 ========== */
-.header-section {
-  position: relative;
-  width: 100%;
-  padding: 20px 30px;
-  box-sizing: border-box;
-  z-index: 10;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.logout-btn {
-  position: absolute;
-  left: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 16px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.logout-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.logout-btn i {
-  font-size: 18px;
-  color: #00bfff;
-}
-
-.page-title {
-  font-size: 28px;
-  font-weight: bold;
-  color: #ffffff;
-  letter-spacing: 2px;
-  margin: 0;
-  text-shadow: 0 0 10px rgba(0, 191, 255, 0.5);
-}
-
-/* 右侧操作按钮 */
-.header-actions {
-  position: absolute;
-  right: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 15px;
-}
-
+/* 成品入库-操作按钮 - 绿色主题 */
 .action-btn {
-  display: flex;
-  align-items: center;
-  gap: 8px;
   background: linear-gradient(90deg, #1a6a5a 0%, #0d5a4a 100%);
-  border: 1px solid #2affcf;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 14px;
-  cursor: pointer;
-  transition: all 0.3s;
+  border-color: #2affcf;
 }
 
 .action-btn:hover {
   background: linear-gradient(90deg, #2a7a6a 0%, #1d6a5a 100%);
-  box-shadow: 0 0 15px rgba(42, 255, 207, 0.4);
+  box-shadow: 0 0 20px rgba(42, 255, 207, 0.5);
 }
 
 .action-btn i {
-  font-size: 16px;
   color: #2affcf;
 }
 
@@ -961,35 +896,6 @@ onMounted(() => {
   background: rgba(30, 144, 255, 0.3);
 }
 
-/* ========== Loading 遮罩 ========== */
-.loading-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(4, 28, 61, 0.8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.loading-spinner {
-  width: 60px;
-  height: 60px;
-  border: 4px solid rgba(30, 144, 255, 0.3);
-  border-top-color: #00bfff;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
-  to {
-    transform: rotate(360deg);
-  }
-}
-
 /* ========== 响应式 - 横屏 ========== */
 @media screen and (orientation: landscape) {
   .header-section {

+ 8 - 82
src/finishProduct/FinishProductOut.vue

@@ -153,7 +153,12 @@
 
     <!-- Loading -->
     <div v-if="loading" class="loading-overlay">
-      <div class="loading-spinner" />
+      <div class="loading-dots">
+        <div class="dot" />
+        <div class="dot" />
+        <div class="dot" />
+      </div>
+      <span class="loading-text">加载中...</span>
     </div>
   </div>
 </template>
@@ -335,7 +340,7 @@ const toggleSelectAll = checked => {
 // 打开发起出库确认
 const confirmOutbound = () => {
     if (selectedProducts.value.length === 0) {
-        showNotify({ type: 'warning', message: '请选择要确认出库的成品' });
+        showNotify({ type: 'danger', message: '请选择要确认出库的成品' });
         return;
     }
     showConfirmModal.value = true;
@@ -354,7 +359,7 @@ const executeOutbound = async () => {
             selectedProducts.value = [];
             getList(); // 重新加载列表
         } else {
-            showNotify({ type: 'warning', message: res.errorMessage });
+            showNotify({ type: 'danger', message: res.errorMessage });
         }
     } catch (error) {
         console.log(error);
@@ -465,56 +470,6 @@ onMounted(() => {
   z-index: 0;
 }
 
-/* ========== 顶部标题区域 ========== */
-.header-section {
-  position: relative;
-  width: 100%;
-  padding: 20px 30px;
-  box-sizing: border-box;
-  z-index: 10;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.logout-btn {
-  position: absolute;
-  left: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 16px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.logout-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.logout-btn i {
-  font-size: 18px;
-  color: #00bfff;
-}
-
-.page-title {
-  font-size: 28px;
-  font-weight: bold;
-  color: #ffffff;
-  letter-spacing: 2px;
-  margin: 0;
-  text-shadow: 0 0 10px rgba(0, 191, 255, 0.5);
-}
-
 /* ========== 主内容区域 ========== */
 .main-content {
   flex: 1;
@@ -1120,35 +1075,6 @@ onMounted(() => {
   box-shadow: 0 0 20px rgba(30, 144, 255, 0.5);
 }
 
-/* ========== Loading 遮罩 ========== */
-.loading-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(4, 28, 61, 0.8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.loading-spinner {
-  width: 60px;
-  height: 60px;
-  border: 4px solid rgba(30, 144, 255, 0.3);
-  border-top-color: #00bfff;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
-  to {
-    transform: rotate(360deg);
-  }
-}
-
 /* ========== 响应式 - 横屏 ========== */
 @media screen and (orientation: landscape) {
   .header-section {

+ 52 - 15
src/login/FingerprintLogin.vue

@@ -118,6 +118,7 @@
 import { useRouter, useRoute } from 'vue-router';
 import { ref, onMounted, onUnmounted } from 'vue';
 import { showNotify } from 'vant';
+import { queryRemindTime } from '../api/login.js';
 
 // 图片资源
 import bgImg from '../assets/images/bj.png';
@@ -192,6 +193,7 @@ const handleFingerprintResponse = data => {
                 } else {
                     router.push('/home');
                 }
+                checkPasswordReminder();
             }, 1000);
         }
     } else {
@@ -227,8 +229,18 @@ const handleRestart = () => {
     updateStatus('waiting', '指纹重启中,请稍后...');
 
     setTimeout(() => {
-        startRecognize();
-        updateStatus('recognizing', '请按下手指');
+        // startRecognize();
+        // updateStatus('recognizing', '请按下手指');
+
+        if (plugin.fingerprintConfig) {
+            plugin.fingerprintConfig.receiveFingerprintResponse = () => { };
+            plugin.fingerprintConfig.disableConnect();
+            plugin.fingerprintConfig.connect();
+            plugin.fingerprintConfig.receiveFingerprintResponse = handleFingerprintResponse;
+            setTimeout(() => {
+                startRecognize();
+            }, 500);
+        }
     }, 1000);
 };
 
@@ -242,6 +254,24 @@ const goToPasswordLogin = () => {
     }
 };
 
+const checkPasswordReminder = async () => {
+    try {
+        const res = await queryRemindTime();
+        if (res.errorCode === 0) {
+            if (res.data === true) {
+                setTimeout(() => {
+                    showNotify({ type: 'danger', message: res.errorMessage });
+                }, 4000);
+            }
+        } else {
+            showNotify({ type: 'danger', message: res.errorMessage });
+        }
+    } catch (error) {
+        console.error('提示修改密码Api调用失败', error);
+        showNotify({ type: 'danger', message: '提示修改密码Api调用失败' });
+    }
+};
+
 // 组件挂载
 onMounted(() => {
     // 检查URL参数中是否包含isOut=true,如果有则存储到localStorage
@@ -316,7 +346,7 @@ onUnmounted(() => {
     left: 0;
     width: 100%;
     height: 100%;
-    background-image: 
+    background-image:
         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: 50px 50px;
@@ -614,16 +644,16 @@ onUnmounted(() => {
 
 /* 状态文本 */
 .status-text {
-    font-size:4rem;
-  color: white;
-  text-align: center;
-  font-weight: 700;
-  max-width: clamp(250px, 50vw, 400px);
-  line-height: 1.6;
-  margin-top: 15px;
-  margin-bottom: 15px;
-  margin-left: 0;
-  margin-right: 0;
+    font-size: 4rem;
+    color: white;
+    text-align: center;
+    font-weight: 700;
+    max-width: clamp(250px, 50vw, 400px);
+    line-height: 1.6;
+    margin-top: 15px;
+    margin-bottom: 15px;
+    margin-left: 0;
+    margin-right: 0;
 }
 
 @keyframes textFadeIn {
@@ -777,8 +807,15 @@ onUnmounted(() => {
 }
 
 @keyframes blink {
-    0%, 100% { opacity: 1; }
-    50% { opacity: 0.5; }
+
+    0%,
+    100% {
+        opacity: 1;
+    }
+
+    50% {
+        opacity: 0.5;
+    }
 }
 
 /* 响应式设计 */

+ 75 - 51
src/login/UserHome.vue

@@ -54,10 +54,10 @@
           <div class="stat-info">
             <div class="stat-label">{{ stat.title }}</div>
             <div class="stat-value">{{ stat.value }}</div>
-            <div class="stat-trend" :class="stat.trend > 0 ? 'up' : 'down'">
+            <!-- <div class="stat-trend" :class="stat.trend > 0 ? 'up' : 'down'">
               <img :src="stat.trend > 0 ? arrowUpIcon : arrowDownIcon" alt="" class="trend-icon" />
               {{ stat.changeText }}
-            </div>
+            </div> -->
           </div>
         </div>
       </div>
@@ -65,19 +65,13 @@
       <!-- 操作按钮区域 -->
       <div class="buttons-section">
         <template v-if="isOut">
-          <div
-            v-for="action in outButtons" :key="action.label" class="action-btn"
-            @click="handleAction(action.action)"
-          >
+          <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)"
-          >
+          <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>
@@ -136,6 +130,8 @@ import arrowDownIcon from '../assets/images/down.png';
 import headerImg from '../assets/images/header.png';
 import bottomImg from '../assets/images/bottom.png';
 
+import { getStaticInfo } from '../api/login.js';
+
 const router = useRouter();
 const username = ref('admin');
 
@@ -149,32 +145,19 @@ const showSettings = ref(false);
 const pickingConfirmVisible = ref(false);
 const settingsDropdown = ref(null);
 
-const config = {
+const config = ref({
     header: ['名称', '图号', '类型', '操作', '时间', '操作人员'],
-    data: [
-        ['我是一个测试名称', '2025001C10', '治物', '出库', '2025-11-26 11:15', '张三'],
-        ['我是一个测试名称', '2025001C10', '治物', '出库', '2025-11-26 11:15', '服务员'],
-        ['测试名称', '2025001C10', '芯角', '出库', '2025-11-26 11:15', '周世豪'],
-        ['测试名称', '2025001C10', '货物', '入库', '2025-11-26 11:15', '管理员'],
-        ['测试名称', '2025001C10', '治物', '入库', '2025-11-26 11:15', '陈静雅'],
-        ['测试名称', '2025001C10', '货物', '入库', '2025-11-26 11:15', '管理员'],
-        ['测试名称', '2025001C10', '治物', '出库', '2025-11-26 11:15', '管理员'],
-        ['测试名称', '2025001C10', '芯角', '出库', '2025-11-26 11:15', '管理员'],
-        ['测试名称', '2025001C10', '货物', '出库', '2025-11-26 11:15', '管理员'],
-        ['测试名称', '2025001C10', '治物', '出库', '2025-11-26 11:15', '周世豪'],
-        ['测试名称', '2025001C10', '货物', '出库', '2025-11-26 11:15', '管理员'],
-        ['测试名称', '2025001C10', '治物', '出库', '2025-11-26 11:15', '管理员'],
-        ['测试名称', '2025001C10', '芯角', '出库', '2025-11-26 11:15', '周世豪'],
-        ['测试名称', '2025001C10', '货物', '出库', '2025-11-26 11:15', '管理员'],
-    ],
+    data: [],
     index: true,
-    columnWidth: [50, 200, 200, 120, 100, 200, 120],
-    align: ['center', 'center', 'center', 'center', 'center','center','center'],
+    columnWidth: [50, 200, 200, 100, 100, 200, 120],
+    align: ['center', 'center', 'center', 'center', 'center', 'center', 'center'],
     rowNum: 14,
-    headerBGC:'#0c5897',
-    oddRowBGC:'#0c3367',
-    evenRowBGC:'#153d75',
-};
+    headerBGC: '#0c5897',
+    oddRowBGC: '#0c3367',
+    evenRowBGC: '#153d75',
+});
+
+let infoTimer = null;
 
 // 从 localStorage 获取用户名和isOut状态
 onMounted(() => {
@@ -182,13 +165,19 @@ onMounted(() => {
     if (storedUser) {
         username.value = storedUser;
     }
-    
+
     // 读取isOut状态
     const storedIsOut = localStorage.getItem('isOut');
     if (storedIsOut !== null) {
         isOut.value = storedIsOut === 'true';
     }
-    
+
+    getInfo();
+
+    infoTimer = setInterval(() => {
+        getInfo();
+    }, 1000 * 60);
+
     // 添加点击外部关闭下拉菜单的事件监听
     document.addEventListener('click', handleClickOutside);
 });
@@ -199,27 +188,27 @@ onUnmounted(() => {
 });
 
 // 统计数据
-const statistics = reactive([
+const statistics = ref([
     {
         title: '总库存量',
-        value: '12,847',
+        value: '-',
         bg: cardIcon1,
         trend: 1,
-        changeText: '较昨日 +2.3%',
+        changeText: '',
     },
     {
         title: '今日入库',
-        value: '1,248',
+        value: '-',
         bg: cardIcon2,
         trend: 1,
-        changeText: '较昨日 +5.7%',
+        changeText: '',
     },
     {
         title: '今日出库',
-        value: '36',
+        value: '-',
         bg: cardIcon3,
         trend: -1,
-        changeText: '较昨日 +2.3%',
+        changeText: '',
     },
 ]);
 
@@ -273,7 +262,7 @@ const handleLogout = () => {
     localStorage.removeItem('#LoginInfo');
     localStorage.removeItem('#token');
     localStorage.removeItem('#accountId');
-    
+
     // 检查localStorage中的isOut值,如果为true则在登录页面添加isOut参数
     const isOutValue = localStorage.getItem('isOut') === 'true';
     if (isOutValue) {
@@ -336,6 +325,33 @@ const handlePickingYes = () => {
     pickingConfirmVisible.value = false;
     router.push('/order-picking');
 };
+
+// 获取数据
+const getInfo = async () => {
+
+    try {
+        const res = await getStaticInfo();
+        if (res.errorCode === 0) {
+            const { inventoryQuantity, stockInQuantity, stockOutQuantity, cfInAndOutResponses } = res.data;
+            console.log(statistics.value[0].value);
+            statistics.value[0].value = inventoryQuantity;
+            statistics.value[1].value = stockInQuantity;
+            statistics.value[2].value = stockOutQuantity;
+            if (cfInAndOutResponses && cfInAndOutResponses.length > 0) {
+                config.value.data = cfInAndOutResponses.map(item => {
+                    const type = item.type === '出库' ? '<span style="color:#FF4D4F;">出库</span>' :
+                        '<span style="color:#25EC87;">入库</span>';
+                    return [item.name, item.no, item.inventoryType, type, item.time, item.userName];
+                });
+            }
+        } else {
+            console.log(res.errorMessage);
+        }
+    } catch (error) {
+        console.error('获取数据API调用失败:', error);
+    }
+
+};
 </script>
 
 <style scoped>
@@ -419,6 +435,7 @@ const handlePickingYes = () => {
   width: 100%;
   flex-shrink: 0;
   z-index: 10;
+  padding: 0 !important
 }
 
 .header-bg {
@@ -466,7 +483,7 @@ const handlePickingYes = () => {
 
 .header-actions {
   position: absolute;
-  top: 62px;
+  top: 74px;
   right: 22px;
   display: flex;
   align-items: center;
@@ -521,6 +538,7 @@ const handlePickingYes = () => {
     opacity: 0;
     transform: translateY(-10px);
   }
+
   to {
     opacity: 1;
     transform: translateY(0);
@@ -946,7 +964,7 @@ const handlePickingYes = () => {
   }
 
   .header-actions {
-    right: calc(50% - 540px + 22px);
+    right: calc(50% - 540px + 6px);
   }
 
   .page-container {
@@ -1051,7 +1069,7 @@ const handlePickingYes = () => {
   }
 
   .header-actions {
-    top: 62px;
+    top: 86px;
     right: 22px;
     gap: 20px;
   }
@@ -1120,12 +1138,12 @@ const handlePickingYes = () => {
 :deep(.dv-scroll-board .header) {
   font-size: 22px !important;
   color: #52dff5 !important;
-  background: linear-gradient(90deg, rgba(4,253,255,0) 0%, rgba(10,115,241,0.5) 50%, rgba(4,244,246,0) 100%)!important
+  background: linear-gradient(90deg, rgba(4, 253, 255, 0) 0%, rgba(10, 115, 241, 0.5) 50%, rgba(4, 244, 246, 0) 100%) !important
 }
 
 :deep(.dv-scroll-board .rows .row-item) {
   font-size: 17px !important;
-  color:#ffffff !important;
+  color: #ffffff !important;
 }
 
 /* ========== 科技感弹窗样式 ========== */
@@ -1144,8 +1162,13 @@ const handlePickingYes = () => {
 }
 
 @keyframes fadeIn {
-  from { opacity: 0; }
-  to { opacity: 1; }
+  from {
+    opacity: 0;
+  }
+
+  to {
+    opacity: 1;
+  }
 }
 
 .tech-modal {
@@ -1153,7 +1176,7 @@ const handlePickingYes = () => {
   border: 1px solid #2a7fff;
   border-radius: 16px;
   padding: 30px;
-  min-width: 450px;
+  min-width: 620px !important;
   max-width: 90%;
   box-shadow: 0 0 40px rgba(30, 144, 255, 0.3), 0 20px 60px rgba(0, 0, 0, 0.5);
   animation: slideIn 0.3s ease;
@@ -1164,6 +1187,7 @@ const handlePickingYes = () => {
     opacity: 0;
     transform: translateY(-20px);
   }
+
   to {
     opacity: 1;
     transform: translateY(0);

+ 43 - 55
src/login/UserLogin.vue

@@ -47,10 +47,7 @@
               <div class="input-wrapper">
                 <i class="fas fa-user input-icon" />
                 <input
-                  v-model="username"
-                  type="text"
-                  placeholder="请输入用户名"
-                  class="dark-input"
+                  v-model="username" type="text" placeholder="请输入用户名" class="dark-input"
                   @keyup.enter="handleLogin"
                 />
               </div>
@@ -62,15 +59,11 @@
               <div class="input-wrapper">
                 <i class="fas fa-lock input-icon" />
                 <input
-                  v-model="password"
-                  :type="showPassword ? 'text' : 'password'"
-                  placeholder="请输入密码"
-                  class="dark-input"
-                  @keyup.enter="handleLogin"
+                  v-model="password" :type="showPassword ? 'text' : 'password'" placeholder="请输入密码"
+                  class="dark-input" @keyup.enter="handleLogin"
                 />
                 <i
-                  :class="showPassword ? 'fas fa-eye-slash' : 'fas fa-eye'"
-                  class="password-toggle"
+                  :class="showPassword ? 'fas fa-eye-slash' : 'fas fa-eye'" class="password-toggle"
                   @click="showPassword = !showPassword"
                 />
               </div>
@@ -91,7 +84,12 @@
 
     <!-- Loading -->
     <div v-if="loading" class="loading-overlay">
-      <div class="loading-spinner" />
+      <div class="loading-dots">
+        <div class="dot" />
+        <div class="dot" />
+        <div class="dot" />
+      </div>
+      <span class="loading-text">加载中...</span>
     </div>
   </div>
 </template>
@@ -99,7 +97,7 @@
 <script setup>
 import { ref, onMounted } from 'vue';
 import { useRouter, useRoute } from 'vue-router';
-import { loginApi } from '../api/login.js';
+import { loginApi, queryRemindTime } from '../api/login.js';
 import { getFormattedDateTime } from '../common/Common.js';
 import { showNotify } from 'vant';
 
@@ -120,7 +118,7 @@ onMounted(() => {
     const isOutParam = route.query.isOut;
     if (isOutParam !== undefined) {
         const isOutValue = String(isOutParam) === 'true' ? 'true' : 'false';
-        if(isOutValue == 'true') {
+        if (isOutValue == 'true') {
             localStorage.setItem('isOut', isOutValue);
         } else {
             localStorage.setItem('isOut', isOutValue);
@@ -133,8 +131,8 @@ onMounted(() => {
 // 登录处理函数
 const handleLogin = async () => {
     if (!username.value || !password.value) {
-        // message.error('请输入完整的登录信息');
-        showNotify({ type: 'warning', message: '请输入完整的登录信息' });
+    // message.error('请输入完整的登录信息');
+        showNotify({ type: 'danger', message: '请输入完整的登录信息' });
         return;
     }
 
@@ -167,16 +165,35 @@ const handleLogin = async () => {
             } else {
                 router.push('/home');
             }
+            checkPasswordReminder();
         } else {
-            showNotify({ type: 'warning', message: res.errorMessage });
+            showNotify({ type: 'danger', message: res.errorMessage });
         }
     } catch (error) {
-        showNotify({ type: 'danger', message: '登录失败' });
+        showNotify({ type: 'danger', message: '登录API调用失败' });
     } 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 });
+                }, 4000);
+            }
+        } else {
+            showNotify({ type: 'danger', message: res.errorMessage });
+        }
+    } catch (error) {
+        console.error('提示修改密码Api调用失败', error);
+        showNotify({ type: 'danger', message: '提示修改密码Api调用失败' });
+    }
+};
+
 const handleFingerprintLogin = () => {
     const isOut = localStorage.getItem('isOut') === 'true';
     if (isOut) {
@@ -188,7 +205,7 @@ const handleFingerprintLogin = () => {
 
 // 忘记密码处理函数
 const handleForgotPassword = () => {
-    showNotify({ type: 'warning', message: '请联系管理员重置密码' });
+    showNotify({ type: 'danger', message: '请联系管理员重置密码' });
 };
 </script>
 
@@ -227,7 +244,7 @@ const handleForgotPassword = () => {
   left: 0;
   width: 100%;
   height: 100%;
-  background-image: 
+  background-image:
     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: 50px 50px;
@@ -286,11 +303,11 @@ const handleForgotPassword = () => {
   flex-direction: column;
 }
 
-.feature-list > * {
+.feature-list>* {
   margin-bottom: 20px;
 }
 
-.feature-list > *:last-child {
+.feature-list>*:last-child {
   margin-bottom: 0;
 }
 
@@ -301,11 +318,11 @@ const handleForgotPassword = () => {
   opacity: 0.95;
 }
 
-.feature-item > * {
+.feature-item>* {
   margin-right: 12px;
 }
 
-.feature-item > *:last-child {
+.feature-item>*:last-child {
   margin-right: 0;
 }
 
@@ -374,11 +391,11 @@ const handleForgotPassword = () => {
   flex-direction: column;
 }
 
-.form-content > * {
+.form-content>* {
   margin-bottom: 20px;
 }
 
-.form-content > *:last-child {
+.form-content>*:last-child {
   margin-bottom: 0;
 }
 
@@ -495,35 +512,6 @@ const handleForgotPassword = () => {
   font-size: 20px;
 }
 
-/* Loading 遮罩 */
-.loading-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(4, 28, 61, 0.8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.loading-spinner {
-  width: 50px;
-  height: 50px;
-  border: 3px solid rgba(30, 144, 255, 0.2);
-  border-top-color: #1e90ff;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
-  to {
-    transform: rotate(360deg);
-  }
-}
-
 .form-footer {
   text-align: center;
   margin-top: 8px;

+ 2 - 1
src/main.js

@@ -8,7 +8,8 @@ import { createRouter, createWebHashHistory } from 'vue-router';
 import * as PcComponentV3 from 'pc-component-v3';
 import 'pc-component-v3/dist/pc-component-v3.css';
 // import 'ant-design-vue/dist/reset.css';
-import './assets/main.css';
+import './assets/css/main.css';
+import './assets/css/common.css';
 import routes from './router/routes.js';
 import $ from 'jquery';
 

+ 9 - 118
src/stock-in/InConfirm.vue

@@ -90,7 +90,12 @@
 
     <!-- Loading -->
     <div v-if="loading" class="loading-overlay">
-      <div class="loading-spinner" />
+      <div class="loading-dots">
+        <div class="dot" />
+        <div class="dot" />
+        <div class="dot" />
+      </div>
+      <span class="loading-text">加载中...</span>
     </div>
   </div>
 </template>
@@ -165,7 +170,7 @@ const handleComplete = async () => {
     const notInStockItems = materialList.value.filter(item => item.remarks === '不在库');
 
     if (notInStockItems.length === 0) {
-        showNotify({ type: 'warning', message: '没有需要入库的物料!' });
+        showNotify({ type: 'danger', message: '没有需要入库的物料!' });
         return;
     }
 
@@ -202,7 +207,7 @@ const getList = async () => {
                 materialList.value = [];
             }
         } else {
-            showNotify({ type: 'warning', message: res.errorMessage });
+            showNotify({ type: 'danger', message: res.errorMessage });
         }
     } catch (error) {
         console.error('获取物料列表API调用失败:', error);
@@ -222,7 +227,7 @@ const generateCFStockIn = async params => {
             showNotify({ type: 'success', message: '入库申请已完成,还料任务已创建!' });
             router.push('/home');
         } else {
-            showNotify({ type: 'warning', message: res.errorMessage });
+            showNotify({ type: 'danger', message: res.errorMessage });
         }
 
     } catch (error) {
@@ -266,91 +271,6 @@ onMounted(() => {
   z-index: 0;
 }
 
-/* ========== 顶部标题区域 ========== */
-.header-section {
-  position: relative;
-  width: 100%;
-  padding: 20px 30px;
-  box-sizing: border-box;
-  z-index: 10;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.logout-btn {
-  position: absolute;
-  left: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 16px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.logout-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.logout-btn i {
-  font-size: 18px;
-  color: #00bfff;
-}
-
-.page-title {
-  font-size: 28px;
-  font-weight: bold;
-  color: #ffffff;
-  letter-spacing: 2px;
-  margin: 0;
-  text-shadow: 0 0 10px rgba(0, 191, 255, 0.5);
-}
-
-/* 右侧操作按钮 */
-.header-actions {
-  position: absolute;
-  right: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 15px;
-}
-
-.action-btn {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 14px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.action-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.action-btn i {
-  font-size: 16px;
-  color: #00bfff;
-}
-
 /* ========== 主内容区域 ========== */
 .main-content {
   flex: 1;
@@ -629,35 +549,6 @@ onMounted(() => {
   background: linear-gradient(90deg, #6b7280 0%, #9ca3af 100%);
 }
 
-/* ========== Loading 遮罩 ========== */
-.loading-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(4, 28, 61, 0.8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.loading-spinner {
-  width: 60px;
-  height: 60px;
-  border: 4px solid rgba(30, 144, 255, 0.3);
-  border-top-color: #00bfff;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
-  to {
-    transform: rotate(360deg);
-  }
-}
-
 /* ========== 响应式 - 横屏 ========== */
 @media screen and (orientation: landscape) {
   .header-section {

+ 9 - 118
src/stock-in/ReturnedLeave.vue

@@ -90,7 +90,12 @@
 
     <!-- Loading -->
     <div v-if="loading" class="loading-overlay">
-      <div class="loading-spinner" />
+      <div class="loading-dots">
+        <div class="dot" />
+        <div class="dot" />
+        <div class="dot" />
+      </div>
+      <span class="loading-text">加载中...</span>
     </div>
   </div>
 </template>
@@ -192,7 +197,7 @@ const getCFStockInByUser = async () => {
                 inList.value = [];
             }
         } else {
-            showNotify({ type: 'warning', message: res.errorMessage,zIndex: 99999999 });
+            showNotify({ type: 'danger', message: res.errorMessage,zIndex: 99999999 });
             getInnerList();
         }
     } catch (error) {
@@ -220,7 +225,7 @@ const getInnerList = async () => {
                 validateList.value = res.datas;
                 showNotify({ type: 'danger', message: '检测到您已携带工装设备,请将工装设备全部还料后,再次点击【重新校验】按钮,待校验通过后,请在闸机开门后离开', duration: 6000 });
             } else {
-                showNotify({ type: 'warning', message: res.errorMessage });
+                showNotify({ type: 'danger', message: res.errorMessage });
             }
         }
     } catch (error) {
@@ -240,7 +245,7 @@ const generateCFStockIn = async params => {
             showNotify({ type: 'success', message: '还料离开已完成!' });
             router.push('/home');
         } else {
-            showNotify({ type: 'warning', message: res.errorMessage });
+            showNotify({ type: 'danger', message: res.errorMessage });
         }
 
     } catch (error) {
@@ -285,91 +290,6 @@ onMounted(() => {
   z-index: 0;
 }
 
-/* ========== 顶部标题区域 ========== */
-.header-section {
-  position: relative;
-  width: 100%;
-  padding: 20px 30px;
-  box-sizing: border-box;
-  z-index: 10;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.logout-btn {
-  position: absolute;
-  left: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 16px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.logout-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.logout-btn i {
-  font-size: 18px;
-  color: #00bfff;
-}
-
-.page-title {
-  font-size: 28px;
-  font-weight: bold;
-  color: #ffffff;
-  letter-spacing: 2px;
-  margin: 0;
-  text-shadow: 0 0 10px rgba(0, 191, 255, 0.5);
-}
-
-/* 右侧操作按钮 */
-.header-actions {
-  position: absolute;
-  right: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 15px;
-}
-
-.action-btn {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 14px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.action-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.action-btn i {
-  font-size: 16px;
-  color: #00bfff;
-}
-
 /* ========== 主内容区域 ========== */
 .main-content {
   flex: 1;
@@ -648,35 +568,6 @@ onMounted(() => {
   background: linear-gradient(90deg, #6b7280 0%, #9ca3af 100%);
 }
 
-/* ========== Loading 遮罩 ========== */
-.loading-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(4, 28, 61, 0.8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.loading-spinner {
-  width: 60px;
-  height: 60px;
-  border: 4px solid rgba(30, 144, 255, 0.3);
-  border-top-color: #00bfff;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
-  to {
-    transform: rotate(360deg);
-  }
-}
-
 /* ========== 响应式 - 横屏 ========== */
 @media screen and (orientation: landscape) {
   .header-section {

+ 305 - 246
src/stock-out/AgvRfidRecognition.vue

@@ -15,7 +15,7 @@
       <div class="header-actions">
         <button class="action-btn refresh-btn" @click="getAgvRfidLog">
           <i class="fas fa-sync-alt" />
-          <span>刷新结果</span>
+          <span>重新校验</span>
         </button>
       </div>
     </div>
@@ -41,7 +41,7 @@
           </div>
           <div class="status-info-item">
             <span class="info-label">执行次数</span>
-            <span class="info-value">{{ taskStatus.success ? `${taskInfo.executionCount} 次` : '-' }}</span>
+            <span class="info-value">{{ `${taskInfo.executionCount} 次` }}</span>
           </div>
           <div class="status-info-item">
             <span class="info-label">信息</span>
@@ -59,24 +59,33 @@
               <i class="fas fa-box-open" />
             </div>
             <div class="card-title">
-              <h3>目标搬运工装</h3>
-              <p>AGV 应当搬运的设备信息</p>
+              <h3>目标搬运</h3>
+              <p>AGV 应当搬运的信息</p>
             </div>
           </div>
           <div class="target-device-list">
-            <div class="target-device-item">
-              <div class="device-info">
-                <span class="device-label">工装名称</span>
-                <span class="device-name">{{ targetDevice.name || '暂无' }}</span>
-              </div>
-              <span class="device-tag target">目标</span>
+            <div v-if="targetDevices.length === 0" class="empty-state-small">
+              <i class="fas fa-inbox" />
+              <p>暂无目标搬运信息</p>
             </div>
-            <div v-if="targetDevice2.name" class="target-device-item">
-              <div class="device-info">
-                <span class="device-label">工装名称</span>
-                <span class="device-name">{{ targetDevice2.name }}</span>
+            <div v-else>
+              <div v-for="(device, index) in targetDevices" :key="device.inventoryNo || index" class="target-device-item">
+                <div class="device-row">
+                  <div class="device-info">
+                    <span class="device-label">编号</span>
+                    <span class="device-code font-mono">{{ device.inventoryNo || '-' }}</span>
+                  </div>
+                  <span class="device-tag target">目标</span>
+                </div>
+                <div class="device-name-row">
+                  <span class="device-label">名称</span>
+                  <span class="device-name">{{ device.inventoryName || '-' }}</span>
+                </div>
+                <div class="device-feedbox-row">
+                  <span class="device-label">料箱</span>
+                  <span class="device-feedbox">{{ device.feedBoxName }}</span>
+                </div>
               </div>
-              <span class="device-tag target">目标</span>
             </div>
           </div>
         </div>
@@ -88,27 +97,31 @@
               <i class="fas fa-tags" />
             </div>
             <div class="card-title">
-              <h3>已识别工装列表</h3>
+              <h3>已识别列表</h3>
               <p>RFID 实际扫描到的设备信息</p>
             </div>
           </div>
           <div class="identified-device-list">
             <div v-if="identifiedDevices.length === 0" class="empty-state-small">
               <i class="fas fa-inbox" />
-              <p>暂无识别到的工装设备</p>
+              <p>暂未识别到的数据</p>
             </div>
             <div v-else>
-              <div v-for="device in identifiedDevices" :key="device.code" class="identified-device-item">
+              <div v-for="device in identifiedDevices" :key="device.inventoryNo" class="identified-device-item">
                 <div class="device-row">
                   <div class="device-info">
-                    <span class="device-label">工装编号</span>
-                    <span class="device-code font-mono">{{ device.code }}</span>
+                    <span class="device-label">编号</span>
+                    <span class="device-code font-mono">{{ device.inventoryNo }}</span>
                   </div>
                   <span class="device-tag identified">已识别</span>
                 </div>
                 <div class="device-name-row">
-                  <span class="device-label">工装名称</span>
-                  <span class="device-name">{{ device.name }}</span>
+                  <span class="device-label">名称</span>
+                  <span class="device-name">{{ device.inventoryName }}</span>
+                </div>
+                <div class="device-feedbox-row">
+                  <span class="device-label">料箱</span>
+                  <span class="device-feedbox">{{ device.feedBoxName || '-' }}</span>
                 </div>
               </div>
             </div>
@@ -119,7 +132,12 @@
 
     <!-- Loading -->
     <div v-if="loading" class="loading-overlay">
-      <div class="loading-spinner" />
+      <div class="loading-dots">
+        <div class="dot" />
+        <div class="dot" />
+        <div class="dot" />
+      </div>
+      <span class="loading-text">加载中...</span>
     </div>
   </div>
 </template>
@@ -152,15 +170,8 @@ const taskStatus = ref({
     text: '待识别',
 });
 
-// 目标设备
-const targetDevice = ref({
-    name: '',
-});
-
-// 目标设备2
-const targetDevice2 = ref({
-    name: '',
-});
+// 目标设备列表(从 inventoryNameResponseList 获取)
+const targetDevices = ref([]);
 
 // 已识别设备列表(支持多个)
 const identifiedDevices = ref([]);
@@ -174,7 +185,7 @@ const getAgvRfidLog = async () => {
         if (res.errorCode === 0 && res.datas && res.datas.length > 0) {
             // 取最后一条数据(最新的记录)
             const latestData = res.datas[res.datas.length - 1];
-
+            console.log(latestData.countExecute);
             // 更新任务信息
             taskInfo.value = {
                 taskId: latestData.scheduleTaskId.toString(),
@@ -182,19 +193,24 @@ const getAgvRfidLog = async () => {
                 message: latestData.message,
             };
 
-            // 更新目标设备
-            targetDevice.value = {
-                name: latestData.inventoryName,
-            };
-            targetDevice2.value = {
-                name: latestData.inventoryName2,
-            };
+            // 更新目标设备列表(从 checkInventoryResponseList 获取)
+            if (latestData.checkInventoryResponseList && latestData.checkInventoryResponseList.length > 0) {
+                targetDevices.value = latestData.checkInventoryResponseList.map(item => ({
+                    inventoryNo: item.inventoryNo,
+                    inventoryName: item.inventoryName,
+                    feedBoxName: item.feedBoxName || '',
+                }));
+              
+            } else {
+                targetDevices.value = [];
+            }
 
-            // 更新已识别设备列表
+            // 更新已识别设备列表(包含料箱信息)
             if (latestData.rfidInventoryResponseList && latestData.rfidInventoryResponseList.length > 0) {
                 identifiedDevices.value = latestData.rfidInventoryResponseList.map(item => ({
-                    code: item.inventoryNo,
-                    name: item.inventoryName,
+                    inventoryNo: item.inventoryNo,
+                    inventoryName: item.inventoryName,
+                    feedBoxName: item.feedBoxName || '',
                 }));
             } else {
                 identifiedDevices.value = [];
@@ -209,11 +225,7 @@ const getAgvRfidLog = async () => {
 
             // message.success('获取识别结果成功');
         } else {
-            showNotify({
-                type: 'warning',
-                message: '暂无识别记录',
-                duration: 3000,
-            });
+            showNotify({ type: 'danger',  message: '暂无识别记录',  duration: 3000 });
         }
     } catch (error) {
         console.error('获取RFID识别记录失败:', error);
@@ -238,11 +250,12 @@ const operationTip = computed(() => {
     }
 
     // 检查是否所有识别的设备都与目标一致
+    const targetNames = targetDevices.value.map(d => d.inventoryName);
     const allMatch = identifiedDevices.value.every(
-        device => device.name === targetDevice.value.name,
+        device => targetNames.includes(device.name),
     );
 
-    if (allMatch && identifiedDevices.value.length === 1) {
+    if (allMatch && identifiedDevices.value.length === targetDevices.value.length) {
         return '当前识别到的工装与目标一致,可以继续执行任务。';
     } else if (!allMatch) {
         return '当前识别到的工装与目标不符,请检查 RFID 标签是否正确贴附,或手动确认后重试任务。';
@@ -259,7 +272,7 @@ const handleBack = () => {
 // 重新识别
 const handleReIdentify = () => {
     showNotify({
-        type: 'warning',
+        type: 'danger',
         message: '正在重新识别 RFID 标签...',
         duration: 3000,
     });
@@ -281,7 +294,7 @@ const handleManualConfirm = () => {
 // 取消任务
 const handleCancelTask = () => {
     showNotify({
-        type: 'warning',
+        type: 'danger',
         message: '任务已取消',
         duration: 3000,
     });
@@ -317,91 +330,6 @@ const handleCancelTask = () => {
   z-index: 0;
 }
 
-/* ========== 顶部标题区域 ========== */
-.header-section {
-  position: relative;
-  width: 100%;
-  padding: 20px 30px;
-  box-sizing: border-box;
-  z-index: 10;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.logout-btn {
-  position: absolute;
-  left: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 16px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.logout-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.logout-btn i {
-  font-size: 18px;
-  color: #00bfff;
-}
-
-.page-title {
-  font-size: 28px;
-  font-weight: bold;
-  color: #ffffff;
-  letter-spacing: 2px;
-  margin: 0;
-  text-shadow: 0 0 10px rgba(0, 191, 255, 0.5);
-}
-
-/* 右侧操作按钮 */
-.header-actions {
-  position: absolute;
-  right: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 15px;
-}
-
-.action-btn {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 14px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.action-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.action-btn i {
-  font-size: 16px;
-  color: #00bfff;
-}
-
 /* ========== 主内容区域 ========== */
 .main-content {
   flex: 1;
@@ -419,8 +347,8 @@ const handleCancelTask = () => {
 .task-status-card {
   background: rgba(9, 61, 140, 0.5);
   border: 1px solid #049FD8;
-  border-radius: 12px;
-  padding: 20px;
+  border-radius: 16px;
+  padding: 30px;
   flex-shrink: 0;
 }
 
@@ -428,30 +356,30 @@ const handleCancelTask = () => {
   display: flex;
   justify-content: space-between;
   align-items: center;
-  margin-bottom: 20px;
+  margin-bottom: 25px;
 }
 
 .status-title {
   display: flex;
   align-items: center;
-  gap: 10px;
-  font-size: 20px;
+  gap: 12px;
+  font-size: 28px;
   font-weight: 600;
   color: #fff;
 }
 
 .status-title i {
   color: #00bfff;
-  font-size: 22px;
+  font-size: 30px;
 }
 
 .status-badge {
   display: flex;
   align-items: center;
-  gap: 8px;
-  padding: 8px 20px;
-  border-radius: 20px;
-  font-size: 14px;
+  gap: 10px;
+  padding: 12px 28px;
+  border-radius: 25px;
+  font-size: 20px;
   font-weight: 500;
 }
 
@@ -470,26 +398,26 @@ const handleCancelTask = () => {
 .status-info-grid {
   display: grid;
   grid-template-columns: repeat(3, 1fr);
-  gap: 15px;
+  gap: 20px;
 }
 
 .status-info-item {
   background: rgba(13, 58, 106, 0.6);
   border: 1px solid rgba(42, 127, 255, 0.3);
-  border-radius: 8px;
-  padding: 15px;
+  border-radius: 12px;
+  padding: 20px;
   display: flex;
   flex-direction: column;
-  gap: 8px;
+  gap: 10px;
 }
 
 .status-info-item .info-label {
-  font-size: 13px;
+  font-size: 18px;
   color: #7ec8ff;
 }
 
 .status-info-item .info-value {
-  font-size: 16px;
+  font-size: 22px;
   color: #fff;
   font-weight: 500;
 }
@@ -510,7 +438,7 @@ const handleCancelTask = () => {
 .device-section {
   display: grid;
   grid-template-columns: 1fr 1fr;
-  gap: 20px;
+  gap: 25px;
   flex: 1;
   min-height: 0;
 }
@@ -518,8 +446,8 @@ const handleCancelTask = () => {
 .device-card {
   background: rgba(9, 61, 140, 0.5);
   border: 1px solid #049FD8;
-  border-radius: 12px;
-  padding: 20px;
+  border-radius: 16px;
+  padding: 25px;
   display: flex;
   flex-direction: column;
   overflow: hidden;
@@ -528,19 +456,19 @@ const handleCancelTask = () => {
 .card-header-icon {
   display: flex;
   align-items: center;
-  gap: 15px;
-  margin-bottom: 20px;
+  gap: 18px;
+  margin-bottom: 25px;
   flex-shrink: 0;
 }
 
 .icon-circle {
-  width: 50px;
-  height: 50px;
+  width: 60px;
+  height: 60px;
   border-radius: 50%;
   display: flex;
   align-items: center;
   justify-content: center;
-  font-size: 22px;
+  font-size: 28px;
 }
 
 .icon-circle.target {
@@ -554,14 +482,14 @@ const handleCancelTask = () => {
 }
 
 .card-title h3 {
-  font-size: 18px;
+  font-size: 26px;
   font-weight: 600;
   color: #fff;
-  margin: 0 0 5px 0;
+  margin: 0 0 8px 0;
 }
 
 .card-title p {
-  font-size: 13px;
+  font-size: 18px;
   color: #7ec8ff;
   margin: 0;
 }
@@ -570,46 +498,45 @@ const handleCancelTask = () => {
 .target-device-list {
   display: flex;
   flex-direction: column;
-  gap: 15px;
+  gap: 18px;
   flex: 1;
+  overflow-y: auto;
 }
 
 .target-device-item {
   background: linear-gradient(135deg, rgba(30, 144, 255, 0.2) 0%, rgba(0, 191, 255, 0.1) 100%);
   border: 1px solid rgba(30, 144, 255, 0.4);
-  border-radius: 10px;
-  padding: 15px 20px;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
+  border-radius: 12px;
+  padding: 20px 25px;
+  margin-bottom: 6px;
 }
 
 .device-info {
   display: flex;
   flex-direction: column;
-  gap: 5px;
+  gap: 6px;
 }
 
 .device-label {
-  font-size: 12px;
+  font-size: 16px;
   color: #7ec8ff;
 }
 
 .device-name {
-  font-size: 18px;
+  font-size: 24px;
   font-weight: 600;
   color: #fff;
 }
 
 .device-code {
-  font-size: 16px;
+  font-size: 20px;
   color: #fff;
 }
 
 .device-tag {
-  padding: 6px 16px;
-  border-radius: 15px;
-  font-size: 12px;
+  padding: 10px 22px;
+  border-radius: 20px;
+  font-size: 16px;
   font-weight: 500;
 }
 
@@ -631,29 +558,55 @@ const handleCancelTask = () => {
   overflow-y: auto;
   display: flex;
   flex-direction: column;
-  gap: 15px;
+  gap: 18px;
 }
 
 .identified-device-item {
   background: linear-gradient(135deg, rgba(139, 92, 246, 0.2) 0%, rgba(167, 139, 250, 0.1) 100%);
   border: 1px solid rgba(139, 92, 246, 0.4);
-  border-radius: 10px;
-  padding: 15px 20px;
+  border-radius: 12px;
+  padding: 8px 25px;
+  margin-bottom: 6px;
 }
 
 .device-row {
   display: flex;
   justify-content: space-between;
   align-items: center;
-  margin-bottom: 10px;
+  /* margin-bottom: 12px; */
 }
 
 .device-name-row {
-  padding-top: 10px;
+  padding-top: 12px;
   border-top: 1px solid rgba(139, 92, 246, 0.3);
   display: flex;
   flex-direction: column;
-  gap: 5px;
+  gap: 6px;
+}
+
+/* 料箱信息行 */
+.device-feedbox-row {
+  padding-top: 12px;
+  border-top: 1px solid rgba(139, 92, 246, 0.2);
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+  margin-top: 6px;
+}
+
+.device-feedbox {
+  font-size: 22px;
+  font-weight: 500;
+  color: #f59e0b;
+}
+
+/* 目标设备的料箱行样式 */
+.target-device-item .device-feedbox-row {
+  border-top: 1px solid rgba(30, 144, 255, 0.2);
+}
+
+.target-device-item .device-feedbox {
+  color: #fbbf24;
 }
 
 /* 空状态 */
@@ -662,139 +615,245 @@ const handleCancelTask = () => {
   flex-direction: column;
   align-items: center;
   justify-content: center;
-  padding: 40px 20px;
+  padding: 50px 20px;
   color: #5a8abf;
 }
 
 .empty-state-small i {
-  font-size: 48px;
-  margin-bottom: 15px;
+  font-size: 60px;
+  margin-bottom: 20px;
   opacity: 0.5;
 }
 
 .empty-state-small p {
-  font-size: 14px;
+  font-size: 20px;
   margin: 0;
 }
 
-/* ========== Loading 遮罩 ========== */
-.loading-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(4, 28, 61, 0.8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
+/* ========== 响应式 - 横屏 1920*1080 ========== */
+@media screen and (orientation: landscape) {
+  .main-content {
+    padding: 0 30px 20px;
+    gap: 20px;
+  }
 
-.loading-spinner {
-  width: 60px;
-  height: 60px;
-  border: 4px solid rgba(30, 144, 255, 0.3);
-  border-top-color: #00bfff;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-}
+  .task-status-card {
+    padding: 25px;
+  }
 
-@keyframes spin {
-  to {
-    transform: rotate(360deg);
+  .status-title {
+    font-size: 24px;
   }
-}
 
-/* ========== 响应式 - 横屏 ========== */
-@media screen and (orientation: landscape) {
-  .header-section {
-    padding: 10px 20px;
+  .status-title i {
+    font-size: 26px;
   }
 
-  .page-title {
+  .status-badge {
+    padding: 10px 24px;
+    font-size: 18px;
+  }
+
+  .status-info-item {
+    padding: 18px;
+  }
+
+  .status-info-item .info-label {
+    font-size: 16px;
+  }
+
+  .status-info-item .info-value {
+    font-size: 20px;
+  }
+
+  .device-section {
+    gap: 20px;
+  }
+
+  .device-card {
+    padding: 20px;
+  }
+
+  .icon-circle {
+    width: 50px;
+    height: 50px;
+    font-size: 24px;
+  }
+
+  .card-title h3 {
     font-size: 22px;
   }
 
-  .logout-btn {
-    padding: 6px 14px;
-    font-size: 13px;
-    left: 20px;
+  .card-title p {
+    font-size: 16px;
   }
 
-  .header-actions {
-    right: 20px;
+  .target-device-item,
+  .identified-device-item {
+    padding: 8px 22px;
   }
 
-  .action-btn {
-    padding: 6px 14px;
-    font-size: 12px;
+  .device-label {
+    font-size: 14px;
   }
 
+  .device-name {
+    font-size: 20px;
+  }
+
+  .device-code {
+    font-size: 22px;
+  }
+
+  .device-feedbox {
+    font-size: 18px;
+  }
+
+  .device-tag {
+    padding: 8px 18px;
+    font-size: 14px;
+  }
+
+  .empty-state-small i {
+    font-size: 48px;
+  }
+
+  .empty-state-small p {
+    font-size: 16px;
+  }
+}
+
+/* ========== 响应式 - 竖屏 1080*1920 ========== */
+@media screen and (orientation: portrait) {
   .main-content {
-    padding: 0 20px 15px;
-    gap: 15px;
+    padding: 0 30px 30px;
+    gap: 25px;
   }
 
   .task-status-card {
-    padding: 15px;
+    padding: 35px;
+  }
+
+  .status-header {
+    margin-bottom: 30px;
   }
 
   .status-title {
-    font-size: 16px;
+    font-size: 32px;
+  }
+
+  .status-title i {
+    font-size: 34px;
   }
 
   .status-badge {
-    padding: 5px 15px;
-    font-size: 12px;
+    padding: 14px 32px;
+    font-size: 22px;
+  }
+
+  .status-info-grid {
+    gap: 25px;
   }
 
   .status-info-item {
-    padding: 10px;
+    padding: 25px;
+    gap: 12px;
   }
 
   .status-info-item .info-label {
-    font-size: 11px;
+    font-size: 20px;
   }
 
   .status-info-item .info-value {
-    font-size: 14px;
+    font-size: 24px;
+  }
+
+   .info-value {
+    font-size: 22px !important;
+  }
+  .text-error {
+    font-size: 19px !important;
+  }
+
+  .device-section {
+    gap: 30px;
   }
 
   .device-card {
-    padding: 15px;
+    padding: 30px;
+  }
+
+  .card-header-icon {
+    gap: 20px;
+    margin-bottom: 30px;
   }
 
   .icon-circle {
-    width: 40px;
-    height: 40px;
-    font-size: 18px;
+    width: 70px;
+    height: 70px;
+    font-size: 32px;
   }
 
   .card-title h3 {
-    font-size: 15px;
+    font-size: 30px;
   }
 
   .card-title p {
-    font-size: 11px;
+    font-size: 20px;
+  }
+
+  .target-device-list,
+  .identified-device-list {
+    gap: 20px;
   }
 
   .target-device-item,
   .identified-device-item {
-    padding: 12px 15px;
+    padding: 8px 14px;
+  }
+
+  .device-label {
+    font-size: 18px;
   }
 
   .device-name {
-    font-size: 15px;
+    font-size: 28px;
   }
 
   .device-code {
-    font-size: 14px;
+    font-size: 22px;
+  }
+
+  .device-feedbox {
+    font-size: 26px;
   }
 
   .device-tag {
-    padding: 4px 12px;
-    font-size: 11px;
+    padding: 12px 26px;
+    font-size: 18px;
+  }
+
+  /* .device-row {
+    margin-bottom: 15px;
+  } */
+
+  .device-name-row,
+  .device-feedbox-row {
+    padding-top: 6px;
+    gap: 4px;
+  }
+
+  .empty-state-small {
+    padding: 60px 20px;
+  }
+
+  .empty-state-small i {
+    font-size: 70px;
+    margin-bottom: 25px;
+  }
+
+  .empty-state-small p {
+    font-size: 24px;
   }
 }
 </style>

+ 11 - 130
src/stock-out/OrderPicking.vue

@@ -201,7 +201,12 @@
 
     <!-- Loading -->
     <div v-if="loading" class="loading-overlay">
-      <div class="loading-spinner" />
+      <div class="loading-dots">
+        <div class="dot" />
+        <div class="dot" />
+        <div class="dot" />
+      </div>
+      <span class="loading-text">加载中...</span>
     </div>
   </div>
 </template>
@@ -426,7 +431,7 @@ const addToRequisition = record => {
 // 领料申请,直接验证并提交
 const handleComplete = async () => {
     if (selectedIds.value.length === 0) {
-        showNotify({ type: 'warning', message: '请至少选择一个物料' });
+        showNotify({ type: 'danger', message: '请至少选择一个物料' });
         return;
     }
 
@@ -435,7 +440,7 @@ const handleComplete = async () => {
     const hasEmptyLocation = agvItems.some(item => !item.selectedLocation);
 
     if (hasEmptyLocation) {
-        showNotify({ type: 'warning', message: '请为所有 AGV 配送的物料选择配送位置' });
+        showNotify({ type: 'danger', message: '请为所有 AGV 配送的物料选择配送位置' });
         return;
     }
 
@@ -608,7 +613,7 @@ const getIdleLocator = async () => {
                 locator.value = [];
             }
         } else {
-            showNotify({ type: 'warning', message: res.errorMessage });
+            showNotify({ type: 'danger', message: res.errorMessage });
         }
     } catch (error) {
         console.error('获取空闲货位API调用失败:', error);
@@ -651,56 +656,6 @@ onMounted(() => {
   z-index: 0;
 }
 
-/* ========== 顶部标题区域 ========== */
-.header-section {
-  position: relative;
-  width: 100%;
-  padding: 20px 30px;
-  box-sizing: border-box;
-  z-index: 10;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.logout-btn {
-  position: absolute;
-  left: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 16px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.logout-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.logout-btn i {
-  font-size: 18px;
-  color: #00bfff;
-}
-
-.page-title {
-  font-size: 28px;
-  font-weight: bold;
-  color: #ffffff;
-  letter-spacing: 2px;
-  margin: 0;
-  text-shadow: 0 0 10px rgba(0, 191, 255, 0.5);
-}
-
 /* ========== 主内容区域 ========== */
 .main-content {
   flex: 1;
@@ -808,52 +763,6 @@ onMounted(() => {
   background: rgba(26, 74, 122, 0.8);
 }
 
-/* Vue Select 深色主题 */
-:deep(.dark-select .vs__dropdown-toggle) {
-  background: rgba(13, 58, 106, 0.8);
-  border: 1px solid #2a7fff;
-  border-radius: 6px;
-  padding: 6px 10px;
-  min-height: 40px;
-}
-
-:deep(.dark-select .vs__selected) {
-  color: #fff;
-}
-
-:deep(.dark-select .vs__search) {
-  color: #fff;
-}
-
-:deep(.dark-select .vs__search::placeholder) {
-  color: #7ec8ff;
-  opacity: 0.7;
-}
-
-:deep(.dark-select .vs__actions svg) {
-  fill: #7ec8ff;
-}
-
-:deep(.dark-select .vs__dropdown-menu) {
-  background: rgba(13, 58, 106, 0.95);
-  border: 1px solid #2a7fff;
-  border-radius: 6px;
-  z-index: 9999;
-}
-
-:deep(.dark-select .vs__dropdown-option) {
-  color: #fff;
-  padding: 10px 15px;
-}
-
-:deep(.dark-select .vs__dropdown-option--highlight) {
-  background: rgba(30, 144, 255, 0.3);
-}
-
-:deep(.dark-select .vs__clear svg) {
-  fill: #7ec8ff;
-}
-
 /* 全选控制栏 */
 .select-all-bar {
   background: rgba(9, 61, 140, 0.3);
@@ -919,7 +828,7 @@ onMounted(() => {
 .card-grid {
   display: grid;
   grid-template-columns: repeat(4, 1fr);
-  gap: 20px;
+  gap: 18px;
 }
 
 /* ========== 设备卡片样式 ========== */
@@ -1077,6 +986,7 @@ onMounted(() => {
   display: flex;
   flex-direction: column;
   justify-content: center;
+  margin-bottom: 6px;
 }
 
 /* 未选中时的占位样式 */
@@ -1239,35 +1149,6 @@ onMounted(() => {
   background: linear-gradient(90deg, #6b7280 0%, #9ca3af 100%);
 }
 
-/* ========== Loading 遮罩 ========== */
-.loading-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(4, 28, 61, 0.8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.loading-spinner {
-  width: 60px;
-  height: 60px;
-  border: 4px solid rgba(30, 144, 255, 0.3);
-  border-top-color: #00bfff;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
-  to {
-    transform: rotate(360deg);
-  }
-}
-
 /* ========== 响应式 - 横屏 ========== */
 @media screen and (orientation: landscape) {
   .header-section {

+ 6 - 115
src/stock-out/OutboundConfirm.vue

@@ -101,7 +101,12 @@
 
       <!-- Loading -->
       <div v-if="loading" class="loading-overlay">
-        <div class="loading-spinner" />
+        <div class="loading-dots">
+          <div class="dot" />
+          <div class="dot" />
+          <div class="dot" />
+        </div>
+        <span class="loading-text">加载中...</span>
       </div>
     </div>
   </dv-border-box-8>
@@ -307,91 +312,6 @@ onMounted(() => {
   z-index: 0;
 }
 
-/* ========== 顶部标题区域 ========== */
-.header-section {
-  position: relative;
-  width: 100%;
-  padding: 30px 30px 20px 30px;
-  box-sizing: border-box;
-  z-index: 10;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.logout-btn {
-  position: absolute;
-  left: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 16px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.logout-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.logout-btn i {
-  font-size: 18px;
-  color: #00bfff;
-}
-
-.page-title {
-  font-size: 28px;
-  font-weight: bold;
-  color: #ffffff;
-  letter-spacing: 2px;
-  margin: 0;
-  text-shadow: 0 0 10px rgba(0, 191, 255, 0.5);
-}
-
-/* 右侧操作按钮 */
-.header-actions {
-  position: absolute;
-  right: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 15px;
-}
-
-.action-btn {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 14px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.action-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.action-btn i {
-  font-size: 16px;
-  color: #00bfff;
-}
-
 /* ========== 主内容区域 ========== */
 .main-content {
   flex: 1;
@@ -674,35 +594,6 @@ onMounted(() => {
   background: linear-gradient(90deg, #6b7280 0%, #9ca3af 100%);
 }
 
-/* ========== Loading 遮罩 ========== */
-.loading-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(4, 28, 61, 0.8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.loading-spinner {
-  width: 60px;
-  height: 60px;
-  border: 4px solid rgba(30, 144, 255, 0.3);
-  border-top-color: #00bfff;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
-  to {
-    transform: rotate(360deg);
-  }
-}
-
 /* ========== 响应式 - 横屏 ========== */
 @media screen and (orientation: landscape) {
   .header-section {

+ 12 - 180
src/stock/RegularRequisition.vue

@@ -108,12 +108,12 @@
                 <span class="info-value">{{ item.inventoryName || '-' }}</span>
               </div>
               <div class="info-row stats-row">
-                <span class="info-label">借用次数:</span>
+                <span class="info-label">次数:</span>
                 <i class="fas fa-history stats-icon" />
                 <span class="info-value">{{ item.borrowTotal || 0 }}次</span>
               </div>
               <div class="info-row stats-row">
-                <span class="info-label">上次借用:</span>
+                <span class="info-label">上次:</span>
                 <i class="fas fa-clock stats-icon" />
                 <span class="info-value"> {{ item.lastBorrowTime }}</span>
               </div>
@@ -154,7 +154,12 @@
 
     <!-- Loading -->
     <div v-if="loading" class="loading-overlay">
-      <div class="loading-spinner" />
+      <div class="loading-dots">
+        <div class="dot" />
+        <div class="dot" />
+        <div class="dot" />
+      </div>
+      <span class="loading-text">加载中...</span>
     </div>
   </div>
 </template>
@@ -193,7 +198,7 @@ const noMoreData = ref(false);
 const inventoryTypeList = ref([
     { value: 'Clamp', label: '工装' },
     { value: 'Instrument', label: '设备' },
-    { value: 'FinishProduct', label: '成品' },
+    // { value: 'FinishProduct', label: '成品' },
 ]);
 
 // 无限滚动参数
@@ -403,7 +408,7 @@ const getDatas = () => {
 // 加入领料车
 const submitStock = async () => {
     if (selectedIds.value.length == 0) {
-        showNotify({ type: 'warning', message: '请至少选择一个物料' });
+        showNotify({ type: 'danger', message: '请至少选择一个物料' });
         return;
     }
     loading.value = true;
@@ -440,7 +445,7 @@ const queryPickingCarCount = async () => {
                 count.value = 0;
             }
         } else {
-            showNotify({ type: 'warning', message: res.errorMessage });
+            showNotify({ type: 'danger', message: res.errorMessage });
         }
 
     } catch (error) {
@@ -483,105 +488,6 @@ onMounted(() => {
   z-index: 0;
 }
 
-/* ========== 顶部标题区域 ========== */
-.header-section {
-  position: relative;
-  width: 100%;
-  padding: 20px 30px;
-  box-sizing: border-box;
-  z-index: 10;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.logout-btn {
-  position: absolute;
-  left: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 16px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.logout-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.logout-btn i {
-  font-size: 18px;
-  color: #00bfff;
-}
-
-.page-title {
-  font-size: 28px;
-  font-weight: bold;
-  color: #ffffff;
-  letter-spacing: 2px;
-  margin: 0;
-  text-shadow: 0 0 10px rgba(0, 191, 255, 0.5);
-}
-
-/* 右侧操作按钮 */
-.header-actions {
-  position: absolute;
-  right: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 15px;
-}
-
-.action-btn {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 14px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.action-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.action-btn i {
-  font-size: 16px;
-  color: #00bfff;
-}
-
-.cart-btn {
-  background: linear-gradient(90deg, #1a6a5a 0%, #0d5a4a 100%);
-  border-color: #2affcf;
-}
-
-.cart-btn:hover {
-  background: linear-gradient(90deg, #2a7a6a 0%, #1d6a5a 100%);
-  box-shadow: 0 0 15px rgba(42, 255, 207, 0.4);
-}
-
-.cart-btn i {
-  color: #2affcf;
-}
-
 /* ========== 主内容区域 ========== */
 .main-content {
   flex: 1;
@@ -688,52 +594,6 @@ onMounted(() => {
   box-shadow: 0 0 10px rgba(30, 144, 255, 0.3);
 }
 
-/* Vue Select 深色主题 */
-:deep(.dark-select .vs__dropdown-toggle) {
-  background: rgba(13, 58, 106, 0.8);
-  border: 1px solid #2a7fff;
-  border-radius: 6px;
-  padding: 6px 10px;
-  min-height: 40px;
-}
-
-:deep(.dark-select .vs__selected) {
-  color: #fff;
-}
-
-:deep(.dark-select .vs__search) {
-  color: #fff;
-}
-
-:deep(.dark-select .vs__search::placeholder) {
-  color: #7ec8ff;
-  opacity: 0.7;
-}
-
-:deep(.dark-select .vs__actions svg) {
-  fill: #7ec8ff;
-}
-
-:deep(.dark-select .vs__dropdown-menu) {
-  background: rgba(13, 58, 106, 0.95);
-  border: 1px solid #2a7fff;
-  border-radius: 6px;
-  z-index: 9999;
-}
-
-:deep(.dark-select .vs__dropdown-option) {
-  color: #fff;
-  padding: 10px 15px;
-}
-
-:deep(.dark-select .vs__dropdown-option--highlight) {
-  background: rgba(30, 144, 255, 0.3);
-}
-
-:deep(.dark-select .vs__clear svg) {
-  fill: #7ec8ff;
-}
-
 /* ========== 全选控制栏 ========== */
 .select-all-bar {
   background: rgba(9, 61, 140, 0.3);
@@ -1016,35 +876,6 @@ onMounted(() => {
   background: linear-gradient(90deg, #6b7280 0%, #9ca3af 100%);
 }
 
-/* ========== Loading 遮罩 ========== */
-.loading-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(4, 28, 61, 0.8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.loading-spinner {
-  width: 60px;
-  height: 60px;
-  border: 4px solid rgba(30, 144, 255, 0.3);
-  border-top-color: #00bfff;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
-  to {
-    transform: rotate(360deg);
-  }
-}
-
 /* ========== 响应式 - 1920x1080 横屏 ========== */
 @media screen and (orientation: landscape) {
   .stock-requisition-page {
@@ -1076,6 +907,7 @@ onMounted(() => {
   .header-actions {
     right: 20px;
     gap: 10px;
+    top: 28px !important;
   }
 
   .action-btn {

+ 10 - 141
src/stock/StockPickingCar.vue

@@ -191,7 +191,12 @@
 
     <!-- Loading -->
     <div v-if="loading" class="loading-overlay">
-      <div class="loading-spinner" />
+      <div class="loading-dots">
+        <div class="dot" />
+        <div class="dot" />
+        <div class="dot" />
+      </div>
+      <span class="loading-text">加载中...</span>
     </div>
   </div>
 </template>
@@ -235,7 +240,7 @@ const isRegular = ref(false);
 const inventoryTypeList = ref([
     { value: 'Clamp', label: '工装' },
     { value: 'Instrument', label: '设备' },
-    { value: 'FinishProduct', label: '成品' },
+    // { value: 'FinishProduct', label: '成品' },
 ]);
 
 // 无限滚动参数
@@ -427,7 +432,7 @@ const handleReset = () => {
 // 从领料车里删除工装设备
 const deleteStock = () => {
     if (selectedIds.value.length == 0) {
-        showNotify({ type: 'warning', message: '请至少选择一个工装设备' });
+        showNotify({ type: 'danger', message: '请至少选择一个工装设备' });
         return;
     }
     // 显示删除确认弹窗
@@ -508,7 +513,7 @@ const getDatas = () => {
 // 领料
 const submitStock = async () => {
     if (selectedIds.value.length == 0) {
-        showNotify({ type: 'warning', message: '请至少选择一个工装设备' });
+        showNotify({ type: 'danger', message: '请至少选择一个工装设备' });
         return;
     }
     loading.value = true;
@@ -525,7 +530,7 @@ const submitStock = async () => {
             getDatas();
             confirmModalVisible.value = true;
         } else {
-            showNotify({ type: 'warning', message: res.errorMessage });
+            showNotify({ type: 'danger', message: res.errorMessage });
         }
     } catch (error) {
         console.log('生成领料单API调用失败', error);
@@ -569,67 +574,6 @@ onMounted(() => {
   z-index: 0;
 }
 
-/* ========== 顶部标题区域 ========== */
-.header-section {
-  position: relative;
-  width: 100%;
-  padding: 20px 30px;
-  box-sizing: border-box;
-  z-index: 10;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.logout-btn {
-  position: absolute;
-  left: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 16px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.logout-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.logout-btn i {
-  font-size: 18px;
-  color: #00bfff;
-}
-
-.page-title {
-  font-size: 28px;
-  font-weight: bold;
-  color: #ffffff;
-  letter-spacing: 2px;
-  margin: 0;
-  text-shadow: 0 0 10px rgba(0, 191, 255, 0.5);
-}
-
-/* 右侧操作按钮 */
-.header-actions {
-  position: absolute;
-  right: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 15px;
-}
-
 /* ========== 主内容区域 ========== */
 .main-content {
   flex: 1;
@@ -736,52 +680,6 @@ onMounted(() => {
   box-shadow: 0 0 10px rgba(30, 144, 255, 0.3);
 }
 
-/* Vue Select 深色主题 */
-:deep(.dark-select .vs__dropdown-toggle) {
-  background: rgba(13, 58, 106, 0.8);
-  border: 1px solid #2a7fff;
-  border-radius: 6px;
-  padding: 6px 10px;
-  min-height: 40px;
-}
-
-:deep(.dark-select .vs__selected) {
-  color: #fff;
-}
-
-:deep(.dark-select .vs__search) {
-  color: #fff;
-}
-
-:deep(.dark-select .vs__search::placeholder) {
-  color: #7ec8ff;
-  opacity: 0.7;
-}
-
-:deep(.dark-select .vs__actions svg) {
-  fill: #7ec8ff;
-}
-
-:deep(.dark-select .vs__dropdown-menu) {
-  background: rgba(13, 58, 106, 0.95);
-  border: 1px solid #2a7fff;
-  border-radius: 6px;
-  z-index: 9999;
-}
-
-:deep(.dark-select .vs__dropdown-option) {
-  color: #fff;
-  padding: 10px 15px;
-}
-
-:deep(.dark-select .vs__dropdown-option--highlight) {
-  background: rgba(30, 144, 255, 0.3);
-}
-
-:deep(.dark-select .vs__clear svg) {
-  fill: #7ec8ff;
-}
-
 /* ========== 全选控制栏 ========== */
 .select-all-bar {
   background: rgba(9, 61, 140, 0.3);
@@ -1065,35 +963,6 @@ onMounted(() => {
   background: linear-gradient(90deg, #6b7280 0%, #9ca3af 100%);
 }
 
-/* ========== Loading 遮罩 ========== */
-.loading-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(4, 28, 61, 0.8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.loading-spinner {
-  width: 60px;
-  height: 60px;
-  border: 4px solid rgba(30, 144, 255, 0.3);
-  border-top-color: #00bfff;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
-  to {
-    transform: rotate(360deg);
-  }
-}
-
 /* 大弹窗样式 */
 :deep(.large-dialog) {
   width: 85vw !important;

+ 9 - 192
src/stock/StockRequisition.vue

@@ -180,7 +180,12 @@
 
     <!-- Loading -->
     <div v-if="loading" class="loading-overlay">
-      <div class="loading-spinner" />
+      <div class="loading-dots">
+        <div class="dot" />
+        <div class="dot" />
+        <div class="dot" />
+      </div>
+      <span class="loading-text">加载中...</span>
     </div>
   </div>
 </template>
@@ -219,7 +224,7 @@ const noMoreData = ref(false);
 const inventoryTypeList = ref([
     { value: 'Clamp', label: '工装' },
     { value: 'Instrument', label: '设备' },
-    { value: 'FinishProduct', label: '成品' },
+    // { value: 'FinishProduct', label: '成品' },
 ]);
 
 // 无限滚动参数
@@ -436,7 +441,7 @@ const getDatas = () => {
 // 加入领料车
 const submitStock = async () => {
     if (selectedIds.value.length == 0) {
-        showNotify({ type: 'warning', message: '请至少选择一个物料' });
+        showNotify({ type: 'danger', message: '请至少选择一个物料' });
         return;
     }
     loading.value = true;
@@ -473,7 +478,7 @@ const queryPickingCarCount = async () => {
                 count.value = 0;
             }
         } else {
-            showNotify({ type: 'warning', message: res.errorMessage });
+            showNotify({ type: 'danger', message: res.errorMessage });
         }
 
     } catch (error) {
@@ -516,119 +521,6 @@ onMounted(() => {
   z-index: 0;
 }
 
-/* ========== 顶部标题区域 ========== */
-.header-section {
-  position: relative;
-  width: 100%;
-  padding: 20px 30px;
-  box-sizing: border-box;
-  z-index: 10;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex-shrink: 0;
-}
-
-.logout-btn {
-  position: absolute;
-  left: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 16px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.logout-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.logout-btn i {
-  font-size: 18px;
-  color: #00bfff;
-}
-
-.page-title {
-  font-size: 28px;
-  font-weight: bold;
-  color: #ffffff;
-  letter-spacing: 2px;
-  margin: 0;
-  text-shadow: 0 0 10px rgba(0, 191, 255, 0.5);
-}
-
-/* 右侧操作按钮 */
-.header-actions {
-  position: absolute;
-  right: 30px;
-  top: 50%;
-  transform: translateY(-50%);
-  display: flex;
-  align-items: center;
-  gap: 15px;
-}
-
-.action-btn {
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  background: linear-gradient(90deg, #1a4a7a 0%, #0d3a6a 100%);
-  border: 1px solid #2a7fff;
-  border-radius: 8px;
-  padding: 10px 20px;
-  color: #fff;
-  font-size: 14px;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-
-.action-btn:hover {
-  background: linear-gradient(90deg, #2a5a8a 0%, #1d4a7a 100%);
-  box-shadow: 0 0 15px rgba(30, 144, 255, 0.4);
-}
-
-.action-btn i {
-  font-size: 16px;
-  color: #00bfff;
-}
-
-.regular-btn {
-  background: linear-gradient(90deg, #5a3a7a 0%, #4a2a6a 100%);
-  border-color: #8a5fff;
-}
-
-.regular-btn:hover {
-  background: linear-gradient(90deg, #6a4a8a 0%, #5a3a7a 100%);
-  box-shadow: 0 0 15px rgba(138, 95, 255, 0.4);
-}
-
-.regular-btn i {
-  color: #d4a5ff;
-}
-
-.cart-btn {
-  background: linear-gradient(90deg, #1a6a5a 0%, #0d5a4a 100%);
-  border-color: #2affcf;
-}
-
-.cart-btn:hover {
-  background: linear-gradient(90deg, #2a7a6a 0%, #1d6a5a 100%);
-  box-shadow: 0 0 15px rgba(42, 255, 207, 0.4);
-}
-
-.cart-btn i {
-  color: #2affcf;
-}
-
 /* ========== 主内容区域 ========== */
 .main-content {
   flex: 1;
@@ -735,52 +627,6 @@ onMounted(() => {
   box-shadow: 0 0 10px rgba(30, 144, 255, 0.3);
 }
 
-/* Vue Select 深色主题 */
-:deep(.dark-select .vs__dropdown-toggle) {
-  background: rgba(13, 58, 106, 0.8);
-  border: 1px solid #2a7fff;
-  border-radius: 6px;
-  padding: 6px 10px;
-  min-height: 40px;
-}
-
-:deep(.dark-select .vs__selected) {
-  color: #fff;
-}
-
-:deep(.dark-select .vs__search) {
-  color: #fff;
-}
-
-:deep(.dark-select .vs__search::placeholder) {
-  color: #7ec8ff;
-  opacity: 0.7;
-}
-
-:deep(.dark-select .vs__actions svg) {
-  fill: #7ec8ff;
-}
-
-:deep(.dark-select .vs__dropdown-menu) {
-  background: rgba(13, 58, 106, 0.95);
-  border: 1px solid #2a7fff;
-  border-radius: 6px;
-  z-index: 9999;
-}
-
-:deep(.dark-select .vs__dropdown-option) {
-  color: #fff;
-  padding: 10px 15px;
-}
-
-:deep(.dark-select .vs__dropdown-option--highlight) {
-  background: rgba(30, 144, 255, 0.3);
-}
-
-:deep(.dark-select .vs__clear svg) {
-  fill: #7ec8ff;
-}
-
 /* ========== 全选控制栏 ========== */
 .select-all-bar {
   background: rgba(9, 61, 140, 0.3);
@@ -1055,35 +901,6 @@ onMounted(() => {
   background: linear-gradient(90deg, #6b7280 0%, #9ca3af 100%);
 }
 
-/* ========== Loading 遮罩 ========== */
-.loading-overlay {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(4, 28, 61, 0.8);
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  z-index: 1000;
-}
-
-.loading-spinner {
-  width: 60px;
-  height: 60px;
-  border: 4px solid rgba(30, 144, 255, 0.3);
-  border-top-color: #00bfff;
-  border-radius: 50%;
-  animation: spin 1s linear infinite;
-}
-
-@keyframes spin {
-  to {
-    transform: rotate(360deg);
-  }
-}
-
 /* ========== 响应式 - 1920x1080 横屏 ========== */
 @media screen and (orientation: landscape) {
   /* 横屏固定布局,不出现页面滚动条 */