647556386
2026-01-19 c36c6a8236689fb3704a2d7722c39bb2c4bf7aa0
Merge branch 'htq20251215' of http://115.159.85.185:8098/r/ZhongRui/ALDbanyunxiangmu into htq20251215
已修改6个文件
622 ■■■■ 文件已修改
项目代码/WIDESEA_WMSClient/src/extension/inbound/extend/Pallet.vue 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/views/Home.vue 487 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/views/inbound/inboundOrder.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/BigGreenService/BigGreenService.cs 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_InboundService/InboundOrderService.cs 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_InboundService/InboundService.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/extend/Pallet.vue
@@ -203,6 +203,8 @@
      scanTimer: null,
      manualInputTimer: null,
      scanTarget: 'tray', // å½“前扫码目标: tray æˆ– material
      isSubmitting: false, // æ–°å¢žï¼šæäº¤é”å®šï¼Œé˜²æ­¢é‡å¤è¯·æ±‚
      groupedBarcodes: [],
      // åº“存统计相关变量
      totalStockSum: 0,
@@ -434,6 +436,8 @@
    },
    // é‡ç½®æ‰€æœ‰æ•°æ®
    resetData() {
      this.groupedBarcodes = []; // æ¸…空已组盘条码
      this.isSubmitting = false; // é‡ç½®æäº¤é”
      this.trayBarcode = '';
      this.barcode = '';
      this.materials = [];
@@ -619,6 +623,10 @@
    // å¤„理物料条码提交
    async handleBarcodeSubmit() {
      if (this.isSubmitting) {
    this.$message.warning('正在处理中,请稍候');
    return;
  }
      if (!await this.validateForm()) return;
      const currentBarcode = this.barcode.trim();
@@ -636,6 +644,7 @@
      this.focusBarcodeInput();
      this.error = '';
      this.loading = true;
      this.isSubmitting = true; // å¼€å¯æäº¤é”
      try {
        // è°ƒç”¨API查询物料信息
@@ -645,6 +654,7 @@
        }
        this.materials = [];
        const newBarcodes = []; // ä¸´æ—¶å­˜å‚¨æœ¬æ¬¡æ–°å¢žçš„æ¡ç 
        materialData.forEach(item => {
          this.materials.push({
            ...item,
@@ -653,7 +663,11 @@
            locationDesc: this.currentLocationDesc,
            scanTime: this.formatTime(new Date())
          });
          newBarcodes.push(item.barcode); // æ”¶é›†æœ¬æ¬¡ç»„盘的条码
        });
         // å°†æœ¬æ¬¡ç»„盘的条码加入已组盘列表
        this.groupedBarcodes = [...new Set([...this.groupedBarcodes, ...newBarcodes])];
        this.orderNo = materialData[0].orderNo;
        await this.fetchStockStatistics(materialData[0].orderNo);
        await this.fetchUnpalletMaterialDetails();
@@ -675,6 +689,7 @@
        }, 100);
      } finally {
        this.loading = false;
        this.isSubmitting = false; // å…³é—­æäº¤é”
      }
    },
@@ -716,7 +731,7 @@
    // å¤„理扫码枪输入
    handleKeyPress(event) {
      // å¦‚果是手动输入模式,不处理扫码枪逻辑
      if (this.isManualInput) {
      if (this.isManualInput || this.isSubmitting) {
        return;
      }
@@ -725,6 +740,7 @@
      // å¿½ç•¥ç›´æŽ¥æŒ‰ä¸‹çš„回车键(由handleBarcodeSubmit处理)
      if (key === 'Enter') {
        event.preventDefault(); // å¼ºåˆ¶é˜»æ­¢é»˜è®¤è¡Œä¸ºï¼Œé¿å…é‡å¤è§¦å‘
        if (this.scanCode.length > 0) {
          // é˜»æ­¢é»˜è®¤å›žè½¦è¡Œä¸ºï¼Œé¿å…è¡¨å•提交
          event.preventDefault();
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/Home.vue
@@ -1,6 +1,6 @@
<template>
  <div class="wms-dashboard">
    <!-- ç»Ÿè®¡å¡ç‰‡åŒºåŸŸ - ç»‘定响应式数据 -->
    <!-- ç»Ÿè®¡å¡ç‰‡åŒºåŸŸ -->
    <el-row :gutter="20" class="stats-card-row">
      <el-col :span="4">
        <div class="stats-card">
@@ -9,8 +9,8 @@
              <Box />
            </el-icon>
          </div>
          <div class="card-title">总库存</div>
          <div class="card-value">{{ formatNumber(bigscreendata.totalStockQuantity) }}</div>
          <div class="card-title">待入库订单</div>
          <div class="card-value">{{ bigscreendata.unInBoundOrderCount }}</div>
        </div>
      </el-col>
      <el-col :span="4">
@@ -78,11 +78,9 @@
          <div ref="locationRateRef" class="chart-container"></div>
        </div>
      </el-col>
      <!-- ä¸´æœŸä¿¡æ¯æ”¹ä¸ºè¡¨æ ¼ -->
      <el-col :span="8">
        <div class="chart-card">
          <div class="chart-title">物料临期信息</div>
          <!-- ä¸´æœŸç‰©æ–™è¡¨æ ¼ -->
          <div class="expiration-table-container">
            <el-table 
              :data="expirationTableData" 
@@ -107,7 +105,6 @@
                  </span>
                </template>
              </el-table-column>
              <!-- <el-table-column prop="barcode" label="条码" align="center" /> -->
              <el-table-column prop="stockQuantity" label="库存数量" align="center" />
              <el-table-column prop="locationCode" label="库位" align="center" />
              <el-table-column prop="palletCode" label="托盘编号" align="center" />
@@ -127,30 +124,46 @@
    <el-row :gutter="20" class="chart-row">
    </el-row>
    <!-- è¡¨æ ¼åŒºåŸŸ - ç»‘定后端作业数据 -->
    <!-- è¡¨æ ¼åŒºåŸŸ - å®žæ—¶ä½œä¸šç›‘控 -->
    <el-row :gutter="20" class="table-row" width="100%">
      <el-col :span="24">
        <div class="table-card">
          <div class="table-title">实时作业监控</div>
          <el-table :data="showTaskList" border style="width: 100%;">
            <el-table-column prop="taskNum" label="任务号" />
            <el-table-column prop="taskStatus" label="任务状态" >
          <el-table
            :data="showTaskList"
            border
            style="width: 100%;"
            :empty-text="showTaskList.length === 0 ? '暂无作业数据' : ''"
          >
            <el-table-column prop="upperOrderNo" label="单据编号" />
            <el-table-column label="单据状态" >
              <template #default="{ row }">
                <span class="task-status" :class="getStatusClass(row.taskStatus)">{{ getTaskStatusText(row.taskStatus) }}</span>
                <span class="task-status" :class="getStatusClass(row.taskStatus)">
                  {{ getTaskStatusText(row.taskStatus) }}
                </span>
              </template>
            </el-table-column>
            <el-table-column prop="taskType" label="任务类型" >
            <el-table-column label="单据类型" >
              <template #default="{ row }">
                <span class="task-type" :class="getTypeClass(row.taskType)">{{ getTaskTypeText(row.taskType) }}</span>
                <span class="task-type" :class="getTypeClass(row.taskType)">
                  {{ getTaskTypeText(row) }}
                </span>
              </template>
            </el-table-column>
            <el-table-column prop="palletCode" label="托盘编号" />
            <el-table-column prop="sourceAddress" label="起点位置"/>
            <el-table-column prop="targetAddress" label="终点位置"/>
            <el-table-column label="回传MES状态" >
              <template #default="{ row }">
                <span class="task-status" :class="getMESStatusClass(row.returnToMESStatus)">
                  {{ getMESStatusText(row.returnToMESStatus) }}
                </span>
              </template>
            </el-table-column>
            <el-table-column prop="factoryArea" label="厂区" />
            <el-table-column prop="modifier" label="修改人" />
            <el-table-column prop="createDate" label="创建时间"/>
            <el-table-column prop="modifyDate" label="修改时间"/>
          </el-table>
          <div class="table-pagination">
            <el-pagination layout="prev, pager, next, jumper" :current-page="1" :total="50" />
            <el-pagination layout="prev, pager, next, jumper" :current-page="1" :total="mergedTaskList.length" />
          </div>
        </div>
      </el-col>
@@ -162,62 +175,45 @@
import { ref, onMounted, onUnmounted, nextTick, computed } from 'vue';
import * as echarts from 'echarts';
import http from "@/api/http.js";
// è¡¥å……缺失的图标导入
import { Box, Document, Download, Upload } from '@element-plus/icons-vue';
// è¡¥å……ElMessage导入
import { ElMessage } from 'element-plus';
// å“åº”式数据
const month = ref('month');
const orderType = ref('return');
// åŽç«¯è¿”回数据(响应式)
// å“åº”式数据 - æ–°å¢ž completeTask å­—段
const bigscreendata = ref({
  totalStockQuantity: 0,
  unOutBoundOrderCount: 0,
  unInBoundOrderCount:0,
  dailyCompletionRate: 0,
  unhandledExceptionCount: 0,
  locationUtilizationRate: 0,
  inStockPallet: 0,
  freeStockPallet: 0,
  dailyInOutBoundList: [],
  taskList: [],
  completeTask: [], // æ–°å¢žï¼šåŽç«¯è¿”回的嵌套任务数据
  inboundCount: 0,
  outboundCount: 0,
  inventoryLocationDist: [], 
  exceptionTypeTrend: [],    
  nearExpirationList: []      // æ”¹ä¸ºæ•°ç»„类型,匹配新数据结构
  nearExpirationList: []
});
// ä¸´æœŸè¡¨æ ¼æ•°æ®ï¼ˆè®¡ç®—属性:适配新的数组数据结构)
// ä¸´æœŸè¡¨æ ¼æ•°æ®ï¼ˆä¿æŒä¸å˜ï¼‰
const expirationTableData = computed(() => {
  // æ–°æ•°æ®ç»“构是数组,直接取数组并处理空值
  const expirationList = bigscreendata.value.nearExpirationList || [];
  // ç¬¬ä¸€æ­¥ï¼šåŽ»é‡ - æŒ‰ ç‰©æ–™ç¼–码+批次号+托盘编号+有效期 å”¯ä¸€æ ‡è¯†åŽ»é‡
  const uniqueMap = new Map();
  expirationList.forEach(item => {
    // æ‹¼æŽ¥å”¯ä¸€æ ‡è¯†ï¼ˆå¤„理空值,避免因空值导致重复判断错误)
    const uniqueKey = [
      item.materielCode || '未知编码',
      item.batchNo || '未知批次',
      item.palletCode || '未知托盘',
    ].join('|'); // ç”¨ç‰¹æ®Šå­—符分隔,避免字段值拼接后混淆
    // åªä¿ç•™ç¬¬ä¸€æ¬¡å‡ºçŽ°çš„è®°å½•
    ].join('|');
    if (!uniqueMap.has(uniqueKey)) {
      uniqueMap.set(uniqueKey, item);
    }
  });
  // æå–去重后的数组
  const uniqueExpirationList = Array.from(uniqueMap.values());
  // ç¬¬äºŒæ­¥ï¼šéåŽ†åŽ»é‡åŽçš„æ•°æ®ï¼Œè¡¥å……ä¸´æœŸç­‰çº§å’Œé»˜è®¤å€¼
  return uniqueExpirationList.map(item => {
    // æå–当前物料的临期天数(核心字段)
    const daysToExpiration = item.daysToExpiration || 0;
    // è®¡ç®—临期等级
    let expireLevel = '';
    if (daysToExpiration < 0) {
      expireLevel = '已过期';
@@ -230,7 +226,6 @@
    } else {
      expireLevel = '30天以上';
    }
    return {
      materielCode: item.materielCode || '未知编码',
      materielName: item.materielName || '未知名称',
@@ -246,14 +241,13 @@
  });
});
// ç©ºæ•°æ®æç¤ºæ–‡æœ¬ï¼ˆä¿®æ­£åˆ¤æ–­é€»è¾‘)
// ç©ºæ•°æ®æç¤ºæ–‡æœ¬ï¼ˆä¿æŒä¸å˜ï¼‰
const emptyText = computed(() => {
  const expirationList = bigscreendata.value.nearExpirationList || [];
  // æ•°ç»„长度为0时显示空提示,否则不显示(原逻辑写反了)
  return expirationList.length === 0 ? '暂无临期物料数据' : '';
});
// èŽ·å–ä¸´æœŸç­‰çº§æ ·å¼ç±»
// èŽ·å–ä¸´æœŸç­‰çº§æ ·å¼ç±»ï¼ˆä¿æŒä¸å˜ï¼‰
const getExpireLevelClass = (level) => {
  switch(level) {
    case '已过期': return 'expire-level expired';
@@ -265,75 +259,131 @@
  }
};
const taskStatusMap = {
  100: "新建",
  105: "已发送",
  200: "堆垛机待执行",
  210: "堆垛机执行中",
  220: "堆垛机完成",
  400: "输送线待执行",
  410: "输送线执行中",
  420: "输送线完成",
  300: "AGV待执行",
  310: "AGV执行中",
  315: "AGV取货中",
  320: "AGV待继续执行",
  325: "AGV放货中",
  330: "AGV完成",
  900: "任务完成",
  970: "任务挂起",
  980: "任务取消",
  990: "任务异常",
  110: "提升机执行中"
// æ ¸å¿ƒï¼šå…¥åº“/出库业务类型枚举映射
const inboundBusinessTypeMap = {
  11: "采购入库",
  12: "杂收单",
  13: "生产退料单",
  14: "外协退料单",
  15: "销售退库单",
  3: "调拨入库单"
};
// èŽ·å–ä»»åŠ¡çŠ¶æ€æ–‡æœ¬
const outboundBusinessTypeMap = {
  21: "工单领料出库单",
  22: "杂发单",
  23: "退货单",
  24: "销售出库单",
  25: "外协领料申请单",
  2: "调拨出库单",
};
// æ ¸å¿ƒä¿®æ”¹ï¼šä»Ž completeTask ä¸­æå–订单数据
const mergedTaskList = computed(() => {
  // 1. èŽ·å– completeTask æ•°ç»„,处理空值
  const completeTaskList = bigscreendata.value.completeTask || [];
  // 2. å–第一个元素(后端返回数组长度为1)
  const taskData = completeTaskList[0] || {};
  // 3. æå–入库/出库订单,处理空值
  const inboundOrders = taskData.inboundOrders || [];
  const outboundOrders = taskData.outboundOrders || [];
  console.log('从completeTask提取的入库订单:', inboundOrders);
  console.log('从completeTask提取的出库订单:', outboundOrders);
  // æ ¼å¼åŒ–入库订单
  const formattedInbound = inboundOrders.map(item => ({
    upperOrderNo: item.upperOrderNo || item.inboundOrderNo || '未知单号',
    taskStatus: item.orderStatus || 0,
    taskType: 'inbound',
    businessType: item.businessType || '',
    returnToMESStatus: item.returnToMESStatus || 0,
    factoryArea: item.factoryArea || '未知厂区',
    modifier: item.modifier || '未知修改人',
    createDate: item.createDate || '未知时间',
    modifyDate: item.modifyDate || '未知时间'
  }));
  // æ ¼å¼åŒ–出库订单
  const formattedOutbound = outboundOrders.map(item => ({
    upperOrderNo: item.upperOrderNo || item.orderNo || '未知单号',
    taskStatus: item.orderStatus || 0,
    taskType: 'outbound',
    businessType: item.businessType || '',
    returnToMESStatus: item.returnToMESStatus || 0,
    factoryArea: item.factoryArea || '未知厂区',
    modifier: item.modifier || '未知修改人',
    createDate: item.createDate || '未知时间',
    modifyDate: item.modifyDate || '未知时间'
  }));
  const merged = [...formattedInbound, ...formattedOutbound];
  console.log('最终合并的作业列表:', merged);
  return merged;
});
// è®¢å•状态映射
const orderStatusMap = {
  0: "未开始",
};
// èŽ·å–è®¢å•çŠ¶æ€æ–‡æœ¬
const getTaskStatusText = (statusNum) => {
  if (statusNum === 1) {
    if (statusNum.taskType === 'inbound') {
      return "入库中";
    } else if (statusNum.taskType === 'outbound') {
      return "出库中";
    } else {
      return "处理中";
    }
  }
  return orderStatusMap[statusNum];
};
// MES回传状态映射
const mesStatusMap = {
  0: "未回传",
  1: "回传成功",
  2: "回传失败",
  3: "部分回传成功",
  4: "部分回传失败",
};
// èŽ·å–MES回传状态文本
const getMESStatusText = (statusNum) => {
  if (statusNum === undefined || statusNum === null || isNaN(statusNum)) {
    return "未知状态";
  }
  return taskStatusMap[statusNum] || "未知状态";
  return mesStatusMap[statusNum] || `未知状态(${statusNum})`;
};
// è¡¨æ ¼æ˜¾ç¤ºçš„任务列表(轮播用)
const showTaskList = ref([]);
const currentTaskIndex = ref(5);
let taskCarouselTimer = null;
// æ•°å­—格式化(千分位分隔)
const formatNumber = (num) => {
  if (!num) return '0';
  return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};
// ä»»åŠ¡åˆ—è¡¨è½®æ’­é€»è¾‘
const startTaskCarousel = () => {
  if (taskCarouselTimer) clearInterval(taskCarouselTimer);
  const totalTask = bigscreendata.value.taskList.length;
  if (totalTask <= 5) {
    showTaskList.value = [...bigscreendata.value.taskList];
    return;
// èŽ·å–MES回传状态样式类
const getMESStatusClass = (statusNum) => {
  if (statusNum === undefined || statusNum === null || isNaN(statusNum)) {
    return "status-unknown";
  }
  taskCarouselTimer = setInterval(() => {
    showTaskList.value.push(bigscreendata.value.taskList[currentTaskIndex.value]);
    showTaskList.value.shift();
    currentTaskIndex.value++;
    if (currentTaskIndex.value >= totalTask) {
      currentTaskIndex.value = 0;
    }
  }, 5000);
  if (statusNum === 0) return "status-pending";
  if (statusNum === 1) return "status-completed";
  if (statusNum === 2) return "status-error";
  if (statusNum === 3) return "status-processing";
  if (statusNum === 4) return "status-error";
  return "status-unknown";
};
// èŽ·å–ä»»åŠ¡ç±»åž‹æ–‡æœ¬
const getTaskTypeText = (taskTypeNum) => {
  if (!taskTypeNum || isNaN(taskTypeNum)) return "未知类型";
// èŽ·å–å•æ®ç±»åž‹æ–‡æœ¬
const getTaskTypeText = (row) => {
  const businessType = Number(row.businessType) || 0;
  
  if (taskTypeNum >= 500 && taskTypeNum < 900) return "入库";
  if (taskTypeNum >= 100 && taskTypeNum < 500) return "出库";
  if (taskTypeNum >= 900 && taskTypeNum < 1000) return "移库";
  return "其他作业";
  if (row.taskType === 'inbound') {
    const typeName = inboundBusinessTypeMap[businessType] || `未知类型(${businessType})`;
    return `${typeName}`;
  } else if (row.taskType === 'outbound') {
    const typeName = outboundBusinessTypeMap[businessType] || `未知类型(${businessType})`;
    return `${typeName}`;
  } else {
    return "其他作业";
  }
};
// èŽ·å–ä»»åŠ¡çŠ¶æ€æ ·å¼ç±»
@@ -341,43 +391,67 @@
  if (statusNum === undefined || statusNum === null || isNaN(statusNum)) {
    return "status-unknown";
  }
  if (statusNum >= 900) return "status-completed";
  if (statusNum >= 400) return "status-processing";
  if (statusNum >= 300) return "status-processing";
  if (statusNum >= 200) return "status-processing";
  if (statusNum >= 100) return "status-pending";
  if (statusNum === 970) return "status-suspended";
  if (statusNum === 980) return "status-canceled";
  if (statusNum === 990) return "status-error";
  if (statusNum === 3) return "status-completed";
  if (statusNum === 2) return "status-processing";
  if (statusNum === 0) return "status-pending";
  if (statusNum === 4) return "status-canceled";
  if (statusNum === 5) return "status-error";
  if (statusNum === 1) return "status-completed";
  return "status-unknown";
};
// èŽ·å–ä»»åŠ¡ç±»åž‹æ ·å¼ç±»
const getTypeClass = (taskTypeNum) => {
  if (!taskTypeNum || isNaN(taskTypeNum)) return "type-unknown";
  if (taskTypeNum >= 500 && taskTypeNum < 900) return "type-inbound";
  if (taskTypeNum >= 100 && taskTypeNum < 500) return "type-outbound";
  if (taskTypeNum >= 900 && taskTypeNum < 1000) return "type-transfer";
const getTypeClass = (taskType) => {
  if (taskType === 'inbound') return "type-inbound";
  if (taskType === 'outbound') return "type-outbound";
  return "type-other";
};
// èŽ·å–åŽç«¯å¤§å±æ•°æ®
// è¡¨æ ¼æ˜¾ç¤ºçš„任务列表(轮播用)
const showTaskList = ref([]);
const currentTaskIndex = ref(0);
let taskCarouselTimer = null;
// æ•°å­—格式化
const formatNumber = (num) => {
  if (!num) return '0';
  return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};
// è½®æ’­é€»è¾‘
const startTaskCarousel = () => {
  if (taskCarouselTimer) clearInterval(taskCarouselTimer);
  const totalTask = mergedTaskList.value.length;
  console.log('作业列表总数:', totalTask);
  if (totalTask <= 5) {
    showTaskList.value = [...mergedTaskList.value];
  } else {
    showTaskList.value = mergedTaskList.value.slice(0, 5);
    currentTaskIndex.value = 5;
  }
  if (totalTask > 5) {
    taskCarouselTimer = setInterval(() => {
      showTaskList.value.shift();
      showTaskList.value.push(mergedTaskList.value[currentTaskIndex.value]);
      currentTaskIndex.value++;
      if (currentTaskIndex.value >= totalTask) {
        currentTaskIndex.value = 0;
      }
    }, 5000);
  }
};
// èŽ·å–åŽç«¯æ•°æ®
const fetchBigGreenData = async () => {
  try {
    const res = await http.get('/api/BigScreen/GetBigGreenData');
    console.log('大屏数据', res);
    console.log('后端原始数据:', res.data);
    
    bigscreendata.value = res.data || res;
    // æ•°æ®æ›´æ–°åŽåˆ·æ–°å›¾è¡¨å’Œè¡¨æ ¼
    nextTick(() => {
      const total = bigscreendata.value.taskList.length;
      showTaskList.value = total >=5
        ? [...bigscreendata.value.taskList.slice(0,5)]
        : [...bigscreendata.value.taskList];
      startTaskCarousel();
      refreshCharts();
    });
@@ -395,26 +469,22 @@
  { opNo: 'SC251224005', opType: '上架', operator: '孙七', startTime: '15:10:18', status: '异常' }
]);
// å›¾è¡¨å®¹å™¨Ref
// å›¾è¡¨ç›¸å…³æ–¹æ³•(保持不变)
const inventoryPieRef = ref(null);
const stockTrendRef = ref(null);
const locationRateRef = ref(null);
const exceptionTrendRef = ref(null);
// å›¾è¡¨å®žä¾‹ï¼ˆå…¨å±€ç®¡ç†ï¼‰
let inventoryPieChart = null;
let stockTrendChart = null;
let locationRateChart = null;
let exceptionTrendChart = null;
// åˆå§‹åŒ–库存库位分布饼图
const initInventoryPie= () => {
  if (!inventoryPieRef.value) return;
  if (inventoryPieChart) {
    inventoryPieChart.dispose();
  }
  inventoryPieChart = echarts.init(inventoryPieRef.value);
  const locationData = bigscreendata.value.inventoryLocationDist.length 
    ? bigscreendata.value.inventoryLocationDist
@@ -424,7 +494,6 @@
        { value: 21.9, name: '保税区C区', itemStyle: { color: '#fac858' } },
        { value: 2.2, name: '残次品区D区', itemStyle: { color: '#ee6666' } }
      ];
  const option = {
    tooltip: {
      trigger: 'item',
@@ -463,26 +532,20 @@
      data: locationData
    }]
  };
  inventoryPieChart.setOption(option);
  return inventoryPieChart;
};
// åˆå§‹åŒ–è¿‘7日出入库趋势图
const initStockTrend = () => {
  if (!stockTrendRef.value) return;
  if (stockTrendChart) {
    stockTrendChart.dispose();
  }
  stockTrendChart = echarts.init(stockTrendRef.value);
  const trendData = bigscreendata.value.dailyInOutBoundList;
  const maxInbound = trendData.length ? Math.max(...trendData.map(item => item.dailyInboundQuantity || 0)) : 0;
  const maxOutbound = trendData.length ? Math.max(...trendData.map(item => item.dailyOutboundQuantity || 0)) : 0;
  const maxValue = Math.max(maxInbound, maxOutbound);
  const option = {
    tooltip: {
      trigger: 'axis',
@@ -535,23 +598,18 @@
      }
    ]
  };
  stockTrendChart.setOption(option);
  return stockTrendChart;
};
// åˆå§‹åŒ–库位利用率环形图
const initLocationRate = () => {
  if (!locationRateRef.value) return;
  if (locationRateChart) {
    locationRateChart.dispose();
  }
  locationRateChart = echarts.init(locationRateRef.value);
  const utilizationRate = bigscreendata.value.locationUtilizationRate || 0;
  const freeRate = 100 - utilizationRate;
  const option = {
    tooltip: {
      trigger: 'item',
@@ -601,19 +659,15 @@
      }
    ]
  };
  locationRateChart.setOption(option);
  return locationRateChart;
};
// åˆå§‹åŒ–异常类型统计趋势图
const initExceptionTrend = () => {
  if (!exceptionTrendRef.value) return;
  if (exceptionTrendChart) {
    exceptionTrendChart.dispose();
  }
  exceptionTrendChart = echarts.init(exceptionTrendRef.value);
  const exceptionData = bigscreendata.value.exceptionTypeTrend.length
    ? bigscreendata.value.exceptionTypeTrend
@@ -624,7 +678,6 @@
        locationException: [4, 5, 2, 4, 3, 5, 4],
        checkDiff: [2, 3, 1, 2, 1, 3, 2]
      };
  const option = {
    tooltip: {
      trigger: 'axis',
@@ -695,18 +748,15 @@
      }
    ]
  };
  exceptionTrendChart.setOption(option);
  return exceptionTrendChart;
};
// åˆ·æ–°æ‰€æœ‰å›¾è¡¨
const refreshCharts = () => {
  const charts = [
    initStockTrend,
    initLocationRate
  ];
  charts.forEach(initFunc => {
    const chart = initFunc();
    if (chart) {
@@ -715,7 +765,6 @@
  });
};
// çª—口大小变化监听
const handleResize = () => {
  const charts = [
    inventoryPieChart,
@@ -723,7 +772,6 @@
    locationRateChart,
    exceptionTrendChart
  ];
  charts.forEach(chart => {
    if (chart) {
      chart.resize();
@@ -731,11 +779,9 @@
  });
};
// ç»„件挂载时
// ç»„件生命周期
onMounted(() => {
  // å…ˆèŽ·å–åŽç«¯æ•°æ®
  fetchBigGreenData();
  // åˆå§‹åŒ–图表(确保DOM已渲染)
  nextTick(() => {
    initInventoryPie();
    initStockTrend();
@@ -745,7 +791,6 @@
  });
});
// ç»„件卸载时
onUnmounted(() => {
  const charts = [
    inventoryPieChart,
@@ -753,7 +798,6 @@
    locationRateChart,
    exceptionTrendChart
  ];
  charts.forEach(chart => {
    if (chart) {
      chart.dispose();
@@ -790,7 +834,6 @@
  margin-bottom: 20px;
}
/* æ ¸å¿ƒæ ·å¼ï¼šå¡ç‰‡åŸºç¡€æ ·å¼ */
.stats-card, .chart-card, .table-card {
  background: #fff;
  border-radius: 8px;
@@ -888,7 +931,6 @@
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.03);
}
/* ä¸´æœŸç‰©æ–™è¡¨æ ¼å®¹å™¨æ ·å¼ */
.expiration-table-container {
  width: 100%;
  height: 100%;
@@ -897,7 +939,6 @@
  overflow-y: auto;
}
/* ä¸´æœŸç­‰çº§æ ‡ç­¾æ ·å¼ */
.expire-level {
  padding: 2px 8px;
  border-radius: 4px;
@@ -935,7 +976,6 @@
  border: 1px solid #e8e8e8;
}
/* å·²è¿‡æœŸæ–‡å­—红色 */
.text-red {
  color: #ff4d4f;
  font-weight: 500;
@@ -984,7 +1024,6 @@
  border-top: 1px solid #ebeef5;
}
/* è¡¨æ ¼æ ·å¼ä¼˜åŒ– */
:deep(.el-table) {
  border-radius: 6px;
  overflow: hidden;
@@ -1026,7 +1065,6 @@
  display: none;
}
/* åˆ†é¡µå™¨æ ·å¼ä¼˜åŒ– */
:deep(.el-pagination) {
  margin-top: 10px;
}
@@ -1051,7 +1089,6 @@
  color: #fff;
}
/* ä»»åŠ¡çŠ¶æ€æ ·å¼ */
.task-status {
  display: inline-block;
  padding: 6px 12px;
@@ -1107,127 +1144,49 @@
  border: 1px solid rgba(144, 147, 153, 0.2);
}
/* ä»»åŠ¡ç±»åž‹æ ·å¼ */
.task-type {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 5px 12px;
  border-radius: 16px;
  display: inline-block;
  padding: 6px 12px;
  border-radius: 20px;
  font-size: 13px;
  font-weight: 600;
  font-weight: 500;
  text-align: center;
  min-width: 70px;
  position: relative;
  overflow: hidden;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  min-width: 80px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
  transition: all 0.2s ease;
  letter-spacing: 0.5px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
@keyframes pulse {
  0% {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  }
  50% {
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.12);
  }
  100% {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  }
}
.task-type::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
  transform: translateX(-100%);
  transition: transform 0.8s cubic-bezier(0.19, 1, 0.22, 1);
}
.task-type:hover::before {
  transform: translateX(0);
}
.task-type:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
}
.task-type::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 3px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.7), transparent);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.5s cubic-bezier(0.19, 1, 0.22, 1);
}
.task-type:hover::after {
  transform: scaleX(1);
}
.type-inbound:hover {
  box-shadow: 0 5px 15px rgba(19, 194, 194, 0.4);
}
.type-outbound:hover {
  box-shadow: 0 5px 15px rgba(47, 84, 235, 0.4);
}
.type-transfer:hover {
  box-shadow: 0 5px 15px rgba(250, 140, 22, 0.4);
}
.type-other:hover {
  box-shadow: 0 5px 15px rgba(114, 46, 209, 0.4);
}
.type-unknown:hover {
  box-shadow: 0 5px 15px rgba(89, 89, 89, 0.4);
}
.type-inbound {
  background: linear-gradient(135deg, #13c2c2 0%, #36cfc9 100%);
  color: white;
  box-shadow: 0 3px 5px rgba(19, 194, 194, 0.3);
  animation: pulse 2s infinite;
  background-color: rgba(64, 158, 255, 0.1);
  color: #409eff;
  border: 1px solid rgba(64, 158, 255, 0.2);
}
.type-outbound {
  background: linear-gradient(135deg, #2f54eb 0%, #597ef7 100%);
  color: white;
  box-shadow: 0 3px 5px rgba(47, 84, 235, 0.3);
  animation: pulse 2.5s infinite;
  background-color: rgba(103, 194, 58, 0.1);
  color: #67c23a;
  border: 1px solid rgba(103, 194, 58, 0.2);
}
.type-transfer {
  background: linear-gradient(135deg, #fa8c16 0%, #ffc53d 100%);
  color: white;
  box-shadow: 0 3px 5px rgba(250, 140, 22, 0.3);
  animation: pulse 3s infinite;
  background-color: rgba(230, 162, 60, 0.1);
  color: #e6a23c;
  border: 1px solid rgba(230, 162, 60, 0.2);
}
.type-other {
  background: linear-gradient(135deg, #722ed1 0%, #b37feb 100%);
  color: white;
  box-shadow: 0 3px 5px rgba(114, 46, 209, 0.3);
  animation: pulse 2.2s infinite;
  background-color: rgba(144, 147, 153, 0.1);
  color: #909399;
  border: 1px solid rgba(144, 147, 153, 0.2);
}
.type-unknown {
  background: linear-gradient(135deg, #595959 0%, #8c8c8c 100%);
  color: white;
  box-shadow: 0 3px 5px rgba(89, 89, 89, 0.3);
  animation: pulse 2.8s infinite;
  background-color: rgba(144, 147, 153, 0.1);
  color: #909399;
  border: 1px solid rgba(144, 147, 153, 0.2);
}
.btn-group {
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/inbound/inboundOrder.vue
@@ -60,6 +60,7 @@
      createType: "",
      creater: "",
      createDate: "",
      materielCode: "",
    });
    const searchFormOptions = ref([
      [
@@ -90,6 +91,7 @@
        },
        { title: "创建者", field: "creater", type: "like" },
        { title: "创建时间", field: "createDate", type: "datetime" },
        { title: "物料编号", field: "materielCode", type: "like" },
      ],
    ]);
    const columns = ref([
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/BigGreenService/BigGreenService.cs
@@ -30,8 +30,9 @@
        private readonly IRepository<Dt_Task> _taskRepository;
        private readonly IRepository<Dt_StockInfo> _stockInfoRepository;
        private readonly IRepository<Dt_MaterialExpirationDate> _materialExpirationDateRepository;
        private readonly IRepository<Dt_InboundOrder> _inboundRepository;
        public BigGreenService(IRepository<Dt_StockInfoDetail> stockInfoDetailRepository, IRepository<Dt_OutboundOrder> outBoundOrderRepository, IRepository<Dt_LocationInfo> locationInfoRepository, IRepository<Dt_OutboundOrderDetail> outBoundOrderDetailRepository, IRepository<Dt_InboundOrderDetail> inboundOrderDetailRepository, IRepository<Dt_Task> taskRepository, IRepository<Dt_Task_Hty> taskHtyRepository, IRepository<Dt_StockInfo> stockInfoRepository, IRepository<Dt_MaterialExpirationDate> materialExpirationDateRepository)
        public BigGreenService(IRepository<Dt_StockInfoDetail> stockInfoDetailRepository, IRepository<Dt_OutboundOrder> outBoundOrderRepository, IRepository<Dt_LocationInfo> locationInfoRepository, IRepository<Dt_OutboundOrderDetail> outBoundOrderDetailRepository, IRepository<Dt_InboundOrderDetail> inboundOrderDetailRepository, IRepository<Dt_Task> taskRepository, IRepository<Dt_Task_Hty> taskHtyRepository, IRepository<Dt_StockInfo> stockInfoRepository, IRepository<Dt_MaterialExpirationDate> materialExpirationDateRepository,IRepository<Dt_InboundOrder> inboundRepository)
        {
            _stockInfoDetailRepository = stockInfoDetailRepository;
            _outBoundOrderRepository = outBoundOrderRepository;
@@ -42,6 +43,7 @@
            _taskHtyRepository = taskHtyRepository;
            _stockInfoRepository = stockInfoRepository;
            _materialExpirationDateRepository = materialExpirationDateRepository;
            _inboundRepository = inboundRepository;
        }
        public WebResponseContent GetBigGreenData()
        {
@@ -54,11 +56,17 @@
                (int)OutOrderStatusEnum.出库中,
                (int)OutOrderStatusEnum.未开始
            };
            var unOutBound = _outBoundOrderRepository.Db.Queryable<Dt_OutboundOrder>().Where(x => targetStatus.Contains(x.OrderStatus)).Count();
            var targetInStatus = new List<int>
            {
                (int)InOrderStatusEnum.入库中,
                (int)InOrderStatusEnum.未开始
            };
            var unOutBound = _outBoundOrderRepository.Db.Queryable<Dt_OutboundOrder>().Where(x => targetStatus.Contains(x.OrderStatus) && x.CreateDate.ToString("MM-dd") == DateTime.Now.ToString("MM-dd")).Count();
            var unInBound = _inboundRepository.Db.Queryable<Dt_InboundOrder>().Where(x => targetInStatus.Contains(x.OrderStatus) && x.CreateDate.ToString("MM-dd") == DateTime.Now.ToString("MM-dd")).Count();
            //计算库位利用率
            var freeLocation = _locationInfoRepository.Db.Queryable<Dt_LocationInfo>().Where(x => x.LocationStatus == (int)LocationStatusEnum.Free).Count();
            var inStockLocation = _locationInfoRepository.Db.Queryable<Dt_LocationInfo>().Where(x => x.LocationStatus != (int)LocationStatusEnum.Free).Count();
            var freeLocation = _locationInfoRepository.Db.Queryable<Dt_LocationInfo>().Select(x=>x.Id).Count();
            var inStockLocation = _locationInfoRepository.Db.Queryable<Dt_LocationInfo>().Where(x => x.LocationStatus == (int)LocationStatusEnum.InStock).Count();
            int totalLocation = freeLocation + inStockLocation;
            decimal locationUtilizationRate = totalLocation == 0
                ? 0
@@ -93,7 +101,8 @@
                InStockPallet = inStockPallet,
                FreeStockPallet = freeStockPallet,
                CompleteTask = completeTask,
                NearExpirationList = nearExpirationList
                NearExpirationList = nearExpirationList,
                UnInBoundOrderCount = unInBound
            };
            return WebResponseContent.Instance.OK(data: bigGreenData);
        }
@@ -114,33 +123,33 @@
                .ToList();
            // 2. æŸ¥è¯¢æ¯æ—¥å‡ºåº“明细(按日期分组)
            var dailyOutboundList = _outBoundOrderDetailRepository.Db
                .Queryable<Dt_OutboundOrderDetail>()
            var dailyOutboundList = _outBoundOrderRepository.Db
                .Queryable<Dt_OutboundOrder>()
                .Where(x => x.CreateDate >= startDate
                         && x.CreateDate < endDate.AddDays(1))
                .Select(x => new
                {
                    Date = x.CreateDate.ToString("MM-dd"),
                    x.OverOutQuantity
                    x.OrderStatus
                })
                .ToList()
                .GroupBy(x => x.Date)
                .ToDictionary(k => k.Key, g => g.Sum(x => (decimal?)x.OverOutQuantity) ?? 0); // è½¬ä¸ºå­—典方便匹配
                .ToDictionary(k => k.Key, g => g.Count(x => x.OrderStatus == (int)OutOrderStatusEnum.出库完成)); // è½¬ä¸ºå­—典方便匹配
            // 3. æŸ¥è¯¢æ¯æ—¥å…¥åº“明细(按日期分组)
            var dailyInboundList = _inboundOrderDetailRepository.Db
                .Queryable<Dt_InboundOrderDetail>()
            var dailyInboundList = _inboundRepository.Db
                .Queryable<Dt_InboundOrder>()
                .Where(x => x.CreateDate >= startDate
                         && x.CreateDate < endDate.AddDays(1))
                .Select(x => new
                {
                    Date = x.CreateDate.ToString("MM-dd"),
                    x.OverInQuantity
                    x.OrderStatus
                })
                .ToList()
                .GroupBy(x => x.Date)
                .ToDictionary(k => k.Key, g => g.Sum(x => (decimal?)x.OverInQuantity) ?? 0); // è½¬ä¸ºå­—典方便匹配
                .ToDictionary(k => k.Key, g => g.Count(x => x.OrderStatus == (int)InOrderStatusEnum.入库完成)); // è½¬ä¸ºå­—典方便匹配
            // 4. åˆå¹¶æ¯æ—¥æ•°æ®ï¼ˆç¡®ä¿7天日期完整,无数据补0)
            var dailyInOutBoundList = all7Days.Select(date => new DailyInOutBoundDto
@@ -156,22 +165,21 @@
        public List<SimpleStatisticsDTO> SimpleStatistics()
        {
            DateTime sevenDaysAgo = DateTime.Now.AddDays(-7);
            var targetStatuses = new List<int>
            {
                (int)InOrderStatusEnum.入库中,
                (int)InOrderStatusEnum.未开始,
                (int)OutOrderStatusEnum.未开始,
                (int)OutOrderStatusEnum.出库中
            };
            var inboundList = _inboundRepository.QueryData(x => x.CreateDate.ToString("MM-dd") == DateTime.Now.ToString("MM-dd") && targetStatuses.Contains(x.OrderStatus)).ToList();
            var outboundList = _outBoundOrderRepository.QueryData(x => x.CreateDate.ToString("MM-dd") == DateTime.Now.ToString("MM-dd") && targetStatuses.Contains(x.OrderStatus)).ToList();
            var stats = _taskHtyRepository
                .QueryData(x => x.TaskStatus == (int)TaskStatusEnum.Finish && x.CreateDate >= sevenDaysAgo)
                .GroupBy(t =>
                    (int)t.TaskType >= 100 && (int)t.TaskType <= 299 ? "出库" :
                    (int)t.TaskType >= 500 && (int)t.TaskType <= 699 ? "入库" : "其他"
                )
                .Where(g => g.Key == "出库" || g.Key == "入库")
                .Select(g => new SimpleStatisticsDTO
                {
                    TaskType = g.Key,
                    Count = g.Count()
                })
                .ToList();
            var stats = new List<SimpleStatisticsDTO> { new SimpleStatisticsDTO
            {
                inboundOrders =inboundList,
                outboundOrders = outboundList
            } };
            return stats;
        }
@@ -197,6 +205,8 @@
            /// å¾…出库订单数量(出库中+未开始)
            /// </summary>
            public int UnOutBoundOrderCount { get; set; }
            public int UnInBoundOrderCount { get; set; }
            /// <summary>
            /// ç©ºé—²åº“位数量
@@ -266,8 +276,8 @@
        public class SimpleStatisticsDTO
        {
            public string TaskType { get; set; }
            public int Count { get; set; }
            public List<Dt_InboundOrder> inboundOrders { get; set; }
            public List<Dt_OutboundOrder> outboundOrders { get; set; }
        }
        
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_InboundService/InboundOrderService.cs
@@ -910,6 +910,14 @@
                        {
                            sugarQueryable1 = sugarQueryable1.Where(x => x.OrderType.Equals(searchParameters.Value.ToString()));
                        }
                        var detailMaterielCode = searchParametersList.FirstOrDefault(x => x.Name == "materielCode");
                        if(detailMaterielCode!=null && !string.IsNullOrEmpty(detailMaterielCode.Value?.ToString()))
                        {
                            string materielCode = detailMaterielCode.Value.ToString().Trim();
                            sugarQueryable1 = sugarQueryable1.Where(x => x.Details.Any(d => d.MaterielCode.Contains(materielCode)));
                        }
                        //var dataList = sugarQueryable1.ToPageList(options.Page, options.Rows, ref totalCount);
                        //return new PageGridData<Dt_InboundOrder>(totalCount, dataList);
                    }
@@ -980,11 +988,7 @@
                {
                    var inbound = _inboundOrderRepository.QueryFirst(x => x.InboundOrderNo == orderNo);
                    var outbound = _outboundOrderRepository.QueryFirst(x=>x.OrderNo == orderNo);
                    if(inbound == null && outbound == null)
                    {
                        return WebResponseContent.Instance.Error($"该单据不存在,无法进行关闭");
                    }
                    if (inbound != null)
                    {
                        if (inbound.OrderStatus != (int)InOrderStatusEnum.未开始 && inbound.OrderStatus != (int)InOrderStatusEnum.入库中)
@@ -994,7 +998,19 @@
                        inbound.OrderStatus = (int)InOrderStatusEnum.手动关闭;
                        inbound.Operator = App.User.UserName;
                        _inboundOrderRepository.UpdateData(inbound);
                    }else if (outbound != null)
                        var inboundItems = _inboundOrderDetailRepository.QueryData(x => x.OrderId == inbound.Id);
                        if(inboundItems.FirstOrDefault().OrderDetailStatus == (int)OrderDetailStatusEnum.New)
                        {
                            foreach (var item in inboundItems)
                            {
                                item.OrderDetailStatus = (int)InOrderStatusEnum.手动关闭;
                                item.Modifier = App.User.UserName;
                                BaseDal.Db.Updateable<Dt_InboundOrderDetail>(item).ExecuteCommand();
                            }
                        }
                    }
                    else if (outbound != null)
                    {
                        if(outbound.OrderStatus !=(int)OutOrderStatusEnum.未开始 && outbound.OrderStatus != (int)OutOrderStatusEnum.出库中)
                        {
@@ -1003,6 +1019,15 @@
                        outbound.OrderStatus = (int)OutOrderStatusEnum.关闭;
                        outbound.Operator = App.User.UserName;
                        _outboundOrderRepository.UpdateData(outbound);
                        var outboundItems = BaseDal.Db.Queryable<Dt_OutboundOrderDetail>().Where(x => x.OrderId == outbound.Id).ToList();
                        if(outboundItems.FirstOrDefault().OrderDetailStatus == (int)OrderDetailStatusEnum.New)
                        foreach(var item in outboundItems)
                        {
                            item.OrderDetailStatus = (int)OutOrderStatusEnum.关闭;
                            item.Modifier = App.User.UserName;
                            BaseDal.Db.Updateable<Dt_OutboundOrderDetail>(item).ExecuteCommand();
                        }
                    }
                    
                }
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_InboundService/InboundService.cs
@@ -93,7 +93,11 @@
                if (details.Count() <= 0)
                {
                    var inbounddetail =_inboundOrderDetailRepository.QueryFirst(x => x.Barcode == palletDto.Barcode);
                    var inbounddetail =_inboundOrderDetailRepository.QueryFirst(x => x.Barcode == palletDto.Barcode || x.OutBoxbarcodes == palletDto.Barcode);
                    if(inbounddetail == null)
                    {
                        return content.Error($"条码{palletDto.Barcode}不存在");
                    }
                    var inbound = _inboundOrderRepository.Db.Queryable<Dt_InboundOrder>().Where(x => x.Id == inbounddetail.OrderId).First();
                    if (inbound == null)
                    {
@@ -113,7 +117,7 @@
                    d.SupplyCode,
                    d.WarehouseCode
                }).ToList();
                    return content.Error("请确认是否已经组盘",detail);
                    return content.Error($"请确认条码{palletDto.Barcode}是否已经组盘",detail);
                }
                inboundOrder = _inboundOrderRepository.Db.Queryable<Dt_InboundOrder>().Includes(x=>x.Details).Where(x => x.Id == details.First().OrderId).First();