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

fix: 补货完成自动完结补货单 + 仅看补货单开关 + 日志目录修正

【后端】
- ReplenishDTO新增orderId字段
- replenishStock补货完成后自动将关联补货单状态→已完成(3)
- getDeviceList新增pendingOrderId/pendingOrderNo
- application.yml: logging.file.path ./logs/admin→./logs/haha-admin

【补货操作页】
- 有补货单时默认仅显示补货单商品(开关), 可切换显示全部
- 一键补满=标准库存-剩余库存, 剩余≥标准则跳过

【前端修复】
- CustomTabBar: isReplenisher()从模块顶层移至onMounted, 修复too early错误
- 有补货单设备点击→自动拉详情→预填数量→关联orderId

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline 8 часов назад
Родитель
Сommit
f7e9b1ecf1

+ 2 - 1
haha-admin-mp/src/components/CustomTabBar.vue

@@ -42,7 +42,7 @@ import { ref, onMounted } from 'vue';
 import { logger } from '@/utils/logger';
 import { isReplenisher } from '@/utils/auth';
 
-const visible = !isReplenisher();
+const visible = ref(true);
 
 const tabPages = [
   '/pages/index/index',
@@ -54,6 +54,7 @@ const tabPages = [
 const currentIndex = ref(0);
 
 onMounted(() => {
+  visible.value = !isReplenisher();
   const pages = getCurrentPages();
   const currentPage = pages[pages.length - 1];
   const currentPath = '/' + currentPage.route;

+ 20 - 3
haha-admin-mp/src/pages/replenish/operation.vue

@@ -22,6 +22,10 @@
       <view class="inventory-section">
         <view class="section-head">
           <text class="section-title">商品库存清单</text>
+          <view class="order-toggle" v-if="orderNo" @click="showOrderOnly = !showOrderOnly">
+            <text class="toggle-label">仅看补货单</text>
+            <view class="toggle-switch" :class="{ on: showOrderOnly }"><view class="toggle-knob"></view></view>
+          </view>
         </view>
 
         <view class="empty-state" v-if="inventoryList.length === 0">
@@ -29,7 +33,7 @@
           <text class="empty-text">暂无商品库存数据</text>
         </view>
 
-        <view class="inventory-card" v-for="(item, index) in inventoryList" :key="index">
+        <view class="inventory-card" v-for="(item, index) in inventoryList" :key="index" v-show="!showOrderOnly || isInOrder(item)">
           <view class="item-top">
             <image v-if="item.product_image" :src="item.product_image" class="item-img" mode="aspectFill" />
             <view v-else class="item-img-placeholder"><text>无图</text></view>
@@ -90,6 +94,13 @@ const loading = ref(true);
 const submitting = ref(false);
 const orderId = ref('');
 const orderNo = ref('');
+const showOrderOnly = ref(false);
+const orderItemCodes = ref<Set<string>>(new Set());
+
+const isInOrder = (item: any) => {
+  const code = item.product_code || item.productCode || '';
+  return orderItemCodes.value.has(code);
+};
 
 const totalReplenishCount = computed(() => replenishItems.value.reduce((s, i) => s + (i.quantity || 0), 0));
 
@@ -144,7 +155,7 @@ onMounted(async () => {
     let orderItems: any[] = [];
     const orderStr = uni.getStorageSync('pendingReplenishOrder');
     if (orderStr) {
-      try { const od = JSON.parse(orderStr); if (od.orderId === orderId.value) { orderNo.value = od.orderNo || ''; orderItems = od.items || []; } } catch { }
+      try { const od = JSON.parse(orderStr); if (od.orderId === orderId.value) { orderNo.value = od.orderNo || ''; orderItems = od.items || []; orderItemCodes.value = new Set(orderItems.map((oi: any) => oi.productCode)); showOrderOnly.value = true; } } catch { }
     }
 
     replenishItems.value = list.filter((it: any) => it.product_id || it.productId).map((it: any) => {
@@ -188,8 +199,14 @@ onMounted(async () => {
 
 // ====== Inventory ======
 .inventory-section { padding: 0 24rpx; flex: 1; height: 0; overflow-y: auto; }
-.section-head { padding: $spacing-3 0 $spacing-2; }
+.section-head { display: flex; align-items: center; justify-content: space-between; padding: $spacing-3 0 $spacing-2; }
 .section-title { font-size: $font-size-md; font-weight: 700; color: $text-color-primary; }
+.order-toggle { display: flex; align-items: center; gap: 8rpx; }
+.toggle-label { font-size: 20rpx; color: $text-color-muted; }
+.toggle-switch { width: 56rpx; height: 32rpx; border-radius: 16rpx; background: $border-color; position: relative; transition: background 0.2s;
+  .toggle-knob { width: 26rpx; height: 26rpx; border-radius: 50%; background: $bg-color-card; position: absolute; top: 3rpx; left: 3rpx; transition: left 0.2s; box-shadow: 0 1rpx 4rpx rgba(0,0,0,0.1); }
+  &.on { background: $primary-color; .toggle-knob { left: 27rpx; } }
+}
 
 .empty-state { display: flex; flex-direction: column; align-items: center; padding: 80rpx 0; }
 .empty-icon-box { width: 96rpx; height: 96rpx; background: $bg-color-secondary; border-radius: $radius-lg; display: flex; align-items: center; justify-content: center; margin-bottom: $spacing-2; }

+ 15 - 0
haha-admin/src/main/java/com/haha/admin/controller/ReplenisherOperationController.java

@@ -289,6 +289,21 @@ public class ReplenisherOperationController {
             }
         }
 
+        // 如果关联了补货单,自动完成
+        if (dto.getOrderId() != null && successCount > 0) {
+            try {
+                ReplenishmentOrder order = replenishmentOrderService.getById(dto.getOrderId());
+                if (order != null && order.getStatus() != 3 && order.getStatus() != 4) {
+                    order.setStatus(3);
+                    order.setUpdateTime(java.time.LocalDateTime.now());
+                    replenishmentOrderService.updateById(order);
+                    log.info("[补货操作] 自动完成补货单: orderId={}", dto.getOrderId());
+                }
+            } catch (Exception e) {
+                log.warn("[补货操作] 自动完成补货单失败: orderId={}, error={}", dto.getOrderId(), e.getMessage());
+            }
+        }
+
         Map<String, Object> result = new HashMap<>();
         result.put("total", dto.getItems().size());
         result.put("success", successCount);

+ 1 - 1
haha-admin/src/main/resources/application.yml

@@ -156,4 +156,4 @@ logging:
     com.haha.admin: debug
   file:
     # 日志文件路径(相对于项目启动目录) - 按应用隔离子目录,避免 admin/miniapp 互相覆盖
-    path: ./logs/admin
+    path: ./logs/haha-admin

+ 5 - 0
haha-entity/src/main/java/com/haha/entity/dto/ReplenishDTO.java

@@ -23,6 +23,11 @@ public class ReplenishDTO {
     /**
      * 补货商品列表
      */
+    /**
+     * 关联补货单ID(可选,补货完成后自动完成该补货单)
+     */
+    private Long orderId;
+
     @NotNull(message = "补货商品列表不能为空")
     @Valid
     private List<ReplenishItem> items;