1
huangxiaoqiang
2025-12-16 7a7b559723e20de635d3888ea58eb151993c2ca2
1
已添加19个文件
已修改9个文件
2520 ■■■■ 文件已修改
项目代码/WIDESEA_WMSClient/src/api/http.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/inbound/extend/Pallet.vue 465 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/inbound/inboundOrder.js 235 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/extension/inbound/inboundOrder_copy.js 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/views/Login.vue 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WIDESEA_WMSClient/src/views/inbound/inboundOrder.vue 65 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1231.31060/CodeChunks.db 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1231.31060/CodeChunks.db-shm 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1231.31060/CodeChunks.db-wal 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1231.31060/SemanticSymbols.db 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1231.31060/SemanticSymbols.db-shm 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1231.31060/SemanticSymbols.db-wal 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/LogLibrary/Log/FileUtil.cs 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/LogLibrary/Log/ILog.cs 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/LogLibrary/Log/ILogFactory.cs 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/LogLibrary/Log/Level.cs 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/LogLibrary/Log/Log.cs 755 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/LogLibrary/Log/LogFactory.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/LogLibrary/Log/LogUtil.cs 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/LogLibrary/LogLibrary.csproj 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/LogLibrary/Properties/AssemblyInfo.cs 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Common/HttpClient/HttpsClient.cs 195 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_Common/WIDESEA_Common.csproj 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_DTO/Inbound/GroupPalletDto.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_IInboundService/IInboundService.cs 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_InboundService/InboundService.cs 215 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_WMSServer.sln 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Inbound/InboundController.cs 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/api/http.js
@@ -13,7 +13,8 @@
let loadingInstance;
let loadingStatus = false;
if (process.env.NODE_ENV == 'development') {
    axios.defaults.baseURL = window.webConfig.webApiBaseUrl;
    axios.defaults.baseURL = 'http://127.0.0.1:9291/';
    // axios.defaults.baseURL = window.webConfig.webApiBaseUrl;
}
else if (process.env.NODE_ENV == 'debug') {
    axios.defaults.baseURL = 'http://127.0.0.1:8098/';
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/extend/Pallet.vue
@@ -1,12 +1,11 @@
<template>
  <vol-box v-model="groupPalletVisible" :title="'组盘操作 - å•据号:' + currentDocNo" :height="1000" :width="1100" :padding="20"
    :modal="true" @open="handleDialogOpen" @close="handleDialogClose">
  <vol-box v-model="show" :title="'组盘操作 - å•据号:' + orderNo" :height="1000" :width="1100" :padding="20" :modal="true">
    <div class="barcode-scanner-container">
      <!-- ä»“库选择 - ç´§å‡‘布局 -->
      <div class="location-section compact">
        <el-form :model="form" :rules="rules" ref="locationForm" class="compact-form">
          <el-form-item label="仓库" prop="warehouseType" class="location-select compact-item">
          <el-form-item label="入库仓库" prop="warehouseType" class="location-select compact-item">
            <el-select v-model="form.warehouseType" placeholder="请选择仓库" clearable filterable
              @change="handleWarehouseChange" style="width: 100%" :loading="warehouseLoading" size="medium">
              <el-option v-for="item in warehouseTypes" :key="item.warehouseType" :label="item.warehouseTypeDesc"
@@ -53,7 +52,7 @@
          <!-- æ‰˜ç›˜æ¡ç è¾“å…¥ -->
          <div class="input-wrapper custom-input-group compact-input">
            <div class="input-label">料箱码</div>
            <div class="input-label">托盘条码</div>
            <el-input ref="trayInput" v-model="trayBarcode" placeholder="请扫描或输入料箱码后按回车键" clearable
              :disabled="!form.locationType || !form.warehouseType" @keyup.enter.native="handleTraySubmit"
              @clear="handleTrayClear" @input="handleTrayInput" class="custom-input" size="medium">
@@ -113,9 +112,10 @@
            </span>
          </div>
          <div  class="table-container">
            <el-table :data="unpalletMaterials" stripe style="width: 100%" height="100%" size="small" v-loading="unpalletBarcodesLoading">
          <div class="table-container">
            <el-table :data="unpalletMaterials" stripe style="width: 100%" height="100%" size="small"
              v-loading="unpalletBarcodesLoading">
              <el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
              <el-table-column prop="barcode" label="条码" min-width="140" show-overflow-tooltip></el-table-column>
              <el-table-column prop="materielCode" label="物料编码" min-width="150" show-overflow-tooltip></el-table-column>
@@ -126,7 +126,7 @@
            </el-table>
          </div>
        </el-card>
      </div>
      <!-- ç‰©æ–™åˆ—表 - å›ºå®šé«˜åº¦å¸¦æ»šåŠ¨æ¡ -->
@@ -166,35 +166,23 @@
        </el-card>
      </div>
    </div>
    <!--      <div slot="footer" class="dialog-footer">
      <el-button @click="handleCancel">取消</el-button>
      <el-button type="primary" @click="handleConfirm">确认</el-button>
    </div> -->
    <template #footer>
      <el-button type="danger" size="small" @click="handleDialogClose()">关闭</el-button>
    </template>
  </vol-box>
</template>
<script>
import http from '@/api/http.js';
import VolBox from '@/components/basic/VolBox.vue';
import VolForm from '@/components/basic/VolForm.vue';
import VolTable from '@/components/basic/VolTable.vue';
import { ElLoading, ElMessage, ElMessageBox } from 'element-plus';
import { ref, onMounted, onUnmounted } from 'vue'
import InboundOrder from '../../../views/inbound/inboundOrder.vue';
import { th } from 'element-plus/es/locales.mjs';
export default {
  name: 'BarcodeScanner',
  components: { VolBox, VolForm, VolTable },
  props: {
    docNo: { type: String, required: true, default: '' },
    visible: { type: Boolean, required: true, default: false }
  },
  components: { VolBox },
  data() {
    return {
      show: false,
      orderNo: "",
      palletVisible: this.visible,
      trayBarcodeReg:/^[A-Z]\d{9}$/,
      trayBarcodeReg: /^[A-Z]\d{9}$/,
      trayBarcode: '',
      barcode: '',
      materials: [],
@@ -203,7 +191,7 @@
      debugMode: false,
      currentFocus: 'warehouse',
      unpalletBarcodes:[],
      unpalletBarcodes: [],
      unpalletBarcodesLoading: false,
      unpalletMaterials: [], // æœªç»„盘详细数据列表
@@ -239,12 +227,12 @@
            trigger: 'change'
          }
        ],
        trayBarcode:[
        trayBarcode: [
          {
            pattern: this.trayBarcodeReg,
            message: '托盘号格式错误(需为1个大写字母+9个数字,如A000008024)',
            trigger: 'blur'
         }
          }
        ],
        warehouseType: [
          {
@@ -255,12 +243,8 @@
      }
    }
  },
  computed: {
    groupPalletVisible: {
      get() { return this.visible; },
      set(newVal) { this.$emit('update:visible', newVal); }
    },
    currentDocNo() { return this.docNo; },
    // å½“前选择的仓库名称
    currentWarehouseName() {
      const warehouse = this.warehouseTypes.find(item => item.warehouseType === this.form.warehouseType);
@@ -282,9 +266,6 @@
        this.resetData();
        this.$nextTick(() => {
          setTimeout(() => {
            // this.focusTrayInput();
            this.initwarehouseTypes(); // åˆå§‹åŒ–仓库
            this.initLocationTypes(); // åˆå§‹åŒ–仓库区域
            this.fetchStockStatistics(); // åŠ è½½ç»Ÿè®¡æ•°æ®
            this.fetchUnpalletMaterialDetails();
          }, 300);
@@ -310,37 +291,27 @@
      }
    }
  },
  'form.warehouseType'(newVal) {
    if (newVal) {
      this.form.locationType = null;
    } else {
      this.locationTypes = [];
    }
  },
  mounted() {
    // æ·»åŠ å…¨å±€é”®ç›˜ç›‘å¬
    document.addEventListener('keypress', this.handleKeyPress);
    // ä½¿ç”¨setTimeout确保DOM完全渲染后再聚焦
    setTimeout(() => {
      // this.focusTrayInput();
      this.focusLocationSelect();
    }, 300);
  },
  beforeDestroy() {
    // æ¸…理事件监听
    document.removeEventListener('keypress', this.handleKeyPress);
    this.clearAllTimers();
  },
  methods: {
    /**
* è‡ªå®šä¹‰ä»“库区域验证
* å…è®¸å€¼ä¸º0,因为0是合法的locationType
*/
    open() {
      this.show = true;
      this.initLocationTypes();
      this.initwarehouseTypes();
      this.fetchStockStatistics();
      this.fetchUnpalletMaterialDetails();
    },
    validateLocationType(rule, value, callback) {
      // æ£€æŸ¥å€¼æ˜¯å¦ä¸ºnull、undefined或空字符串,但允许数字0
      if (!this.form.warehouseType) {
        callback(new Error('请先选择仓库'));
      } else if (value === null || value === undefined || value === '') {
@@ -349,32 +320,19 @@
        callback();
      }
    },
    // æ ¹æ®æ¡ç åˆ—表获取详细数据
    async fetchUnpalletMaterialDetails() {
      try {
        // å°è¯•调用接口获取详细数据
        // æ³¨æ„ï¼šå¦‚果这个接口不存在,可以注释掉或根据实际API调整
        const response = await http.post('/api/InboundOrder/UnPalletGroupBarcode?orderNo='+this.docNo, {
        });
        console.log('未组盘数据:', response.data);
        const response = await http.post('/api/InboundOrder/UnPalletGroupBarcode?orderNo=' + this.docNo, {});
        if (response.status && Array.isArray(response.data)) {
          this.unpalletMaterials = response.data;
          this.unpalletBarcodes = response.data.map(item => item.barcode || '');
          this.totalStockCount = response.data.length;
        } else {
          // å¦‚果接口返回格式不同,尝试其他方式
          // å¦‚果接口不存在,这里会进入catch,设置为空数组
          this.unpalletMaterials = [];
        }
      } catch (err) {
        console.warn('获取未组盘详细数据接口可能不存在,使用条码列表显示:', err);
        // å¦‚果接口不存在,将条码列表转换为简单的显示格式
        // æˆ–者保持为空,让用户知道需要选择仓库和区域来查看详细数据
        this.unpalletMaterials = this.unpalletBarcodes.map(barcode => ({
          barcode: barcode,
          materielCode: '-',
@@ -386,121 +344,21 @@
        }));
      }
    },
    /**
    * åˆå§‹åŒ–仓库区域数据
    */
    async initLocationTypes() {
      this.locationLoading = true;
      this.error = '';
      try {
        const response = await http.post('/api/LocationInfo/GetLocationTypes');
        if (response.status && Array.isArray(response.data)) {
          this.locationTypes = response.data;
          if (this.locationTypes.length === 0) {
            this.error = '未获取到仓库区域数据';
          } else {
            // å¦‚果有默认区域,可以在这里设置
            // this.form.locationType = this.locationTypes[0].locationType;
          }
        } else {
          this.error = '获取仓库区域数据失败';
        }
      } catch (error) {
        console.error('获取仓库区域失败:', error);
        this.error = `获取仓库区域失败: ${error.message || '网络错误'}`;
      } finally {
        this.locationLoading = false;
        const { data } = await this.http.post("api/LocationInfo/GetLocationTypes")
        this.locationTypes = data
      } catch (e) {
        this.$message.error('获取区域类型失败')
      }
    },
    /**
     * åˆå§‹åŒ–仓库数据
     */
    async initwarehouseTypes() {
      this.warehouseLoading = true;
      this.error = '';
      try {
        const response = await http.post('/api/Warehouse/GetwarehouseTypes');
        if (response.status && Array.isArray(response.data)) {
          this.warehouseTypes = response.data;
          if (this.warehouseTypes.length === 0) {
            this.error = '未获取到仓库数据';
          } else {
            // å¦‚果有默认区域,可以在这里设置
            // this.form.locationType = this.locationTypes[0].locationType;
          }
        } else {
          this.error = '获取仓库数据失败';
        }
      } catch (error) {
        console.error('获取仓库失败:', error);
        this.error = `获取仓库失败: ${error.message || '网络错误'}`;
      } finally {
        this.warehouseLoading = false;
        const { data } = await this.http.post("api/Warehouse/GetwarehouseTypes")
        this.warehouseTypes = data
      } catch (e) {
        this.$message.error('获取区域类型失败')
      }
    },
    /**
    * ä»“库区域变更处理
    */
    handleLocationChange(value) {
      console.log('选择仓库区域:', value, '类型:', typeof value, this.currentLocationDesc);
      // ç«‹å³æ¸…除错误信息
      this.error = '';
      // æ‰‹åŠ¨è§¦å‘è¡¨å•éªŒè¯æ›´æ–°
      this.$nextTick(() => {
        if (this.$refs.locationForm) {
          // æ¸…除该字段的验证状态,然后重新验证
          this.$refs.locationForm.clearValidate('locationType');
          // çŸ­æš‚延迟后重新验证,确保DOM已更新
          setTimeout(() => {
            this.$refs.locationForm.validateField('locationType', (errorMsg) => {
              if (!errorMsg && (value === 0 || value)) {
                console.log('仓库区域验证通过:', value);
                // åŒºåŸŸé€‰æ‹©åŽï¼Œè‡ªåŠ¨èšç„¦åˆ°æ‰˜ç›˜è¾“å…¥æ¡†
                this.focusLocationSelect();
                // åˆ·æ–°æœªç»„盘数据(根据选择的仓库和区域过滤)
              }
            });
          }, 100);
        }
      });
    },
    /**
     * ä»“库变更处理
     */
    handleWarehouseChange(value) {
      console.log('选择仓库:', value, '类型:', typeof value, this.currentWarehouseName);
      // ç«‹å³æ¸…除错误信息
      this.error = '';
      // æ‰‹åŠ¨è§¦å‘è¡¨å•éªŒè¯æ›´æ–°
      this.$nextTick(() => {
        if (this.$refs.locationForm) {
          // æ¸…除该字段的验证状态,然后重新验证
          this.$refs.locationForm.clearValidate('warehouseType');
          // çŸ­æš‚延迟后重新验证,确保DOM已更新
          setTimeout(() => {
            this.$refs.locationForm.validateField('warehouseType', (errorMsg) => {
              if (!errorMsg && (value === 0 || value)) {
                console.log('仓库验证通过:', value);
                this.focusLocationSelect();
              }
            });
          }, 100);
        }
      });
    },
    async fetchStockStatistics() {
@@ -513,29 +371,21 @@
      this.sumLoading = true;
      this.sumError = '';
      try {
        // è°ƒç”¨åŽç«¯ç»Ÿè®¡æŽ¥å£ï¼ˆæ›¿æ¢ä¸ºä½ çš„实际接口路径)
        const response = await http.post('/api/InboundOrder/UnPalletQuantity?orderNo=' + this.docNo, {
        });
        // ç»‘定数据(匹配 PalletSumQuantityDTO ç»“构)
        const response = await http.post('/api/InboundOrder/UnPalletQuantity?orderNo=' + this.docNo, {});
        if (response.data) {
          this.totalStockSum = response.data.stockSumQuantity || 0; // æ€»åº“存数量
          this.totalStockCount = response.data.stockCount || 0;     // æ€»åº“存记录数
          this.uniqueUnit = response.data.uniqueUnit || '';               // è®¡é‡å•位
          this.totalStockSum = response.data.stockSumQuantity || 0;
          this.totalStockCount = response.data.stockCount || 0;
          this.uniqueUnit = response.data.uniqueUnit || '';
        }
      } catch (err) {
        this.sumError = '统计加载失败';
        this.totalStockSum = 0;
        this.totalStockCount = 0;
        console.error('库存统计查询异常:', err);
      } finally {
        this.sumLoading = false;
      }
    },
    /**
     * è¡¨å•验证
     */
    async validateForm() {
      return new Promise((resolve) => {
        if (!this.$refs.locationForm) {
@@ -550,40 +400,18 @@
            this.error = '';
            resolve(true);
          } else {
            // æ‰‹åŠ¨æ£€æŸ¥locationType,正确处理值为0的情况
            if (!this.from.warehouseType) {
              this.error = '请先选择仓库';
            }
            else if (this.form.locationType === null || this.form.locationType === undefined || this.form.locationType === '') {
              this.error = '请先选择仓库区域';
              //this.$message.warning('请先选择仓库区域');
            } else {
              // å¦‚果值存在(包括0),但验证不通过,可能是其他验证错误
              this.error = '请检查表单填写是否正确';
            }
            resolve(false);
          }
        });
      });
    },
    focusWarehouseSelect() {
      if (this.$refs.locationForm) {
        const selectEl = this.$el.querySelector('.location-select:first-child .el-input__inner');
        if (selectEl) {
          selectEl.focus();
          this.currentFocus = 'warehouse';
        }
      }
    },
    // èšç„¦åˆ°ä»“库区域选择
    focusLocationSelect() {
      if (this.$refs.locationForm) {
        const selectEl = this.$el.querySelector('.location-select:nth-child(2) .el-input__inner');
        if (selectEl) {
          selectEl.focus();
          this.currentFocus = 'location';
        }
      }
    },
    // èšç„¦åˆ°æ‰˜ç›˜è¾“入框
    focusTrayInput() {
@@ -606,18 +434,10 @@
          inputEl.focus();
          this.currentFocus = 'material';
          this.scanTarget = 'material';
            inputEl.select();
            console.log('物料输入框内容已选中');
          inputEl.select();
        }
      }
    },
    // é‡ç½®æ‰€æœ‰æ•°æ®
    resetData() {
      console.log('重置弹框数据');
@@ -664,38 +484,9 @@
        this.scanTimer = null;
      }
    },
    // å¼¹æ¡†æ‰“开时重置数据
    handleDialogOpen() {
      console.log('弹框打开,重置数据');
      this.resetData();
      // ä½¿ç”¨setTimeout确保DOM完全渲染后再聚焦
      this.$nextTick(() => {
        setTimeout(() => {
          this.initwarehouseTypes();
          this.initLocationTypes(); // åˆå§‹åŒ–仓库区域
          // ç¡®ä¿è¡¨å•引用存在后再聚焦
          if (this.$refs.locationForm) {
            this.focusWarehouseSelect();
          } else {
            // å¦‚果表单引用还不存在,稍后重试
            setTimeout(() => {
              this.focusWarehouseSelect();
            }, 500);
          }
        }, 300);
      });
    },
    // å¼¹æ¡†å…³é—­æ—¶é‡ç½®æ•°æ®
    handleDialogClose() {
      console.log('弹框关闭,重置数据');
      this.show = false;
      this.resetData();
    },
    // å–消按钮
    handleCancel() {
      this.palletVisible = false;
    },
    // ç¡®è®¤æŒ‰é’®
@@ -785,12 +576,13 @@
      this.error = '';
      if(!this.trayBarcodeReg.test(currentTrayBarcode)){
        ElMessage.warning({
          message: '托盘号格式错误',
          type: 'warning',
          duration: 3000
        })
      if (!this.trayBarcodeReg.test(currentTrayBarcode)) {
        // ElMessage.warning({
        //   message: '托盘号格式错误',
        //   type: 'warning',
        //   duration: 3000
        // })
        this.$message("托盘号格式错误");
        this.focusTrayInput();
        return;
      }
@@ -798,11 +590,12 @@
      // è®¾ç½®æ‰˜ç›˜æ¡ç åŽï¼Œè‡ªåŠ¨èšç„¦åˆ°ç‰©æ–™è¾“å…¥æ¡†
      this.focusBarcodeInput();
      this.$message({
        message: `托盘条码已设置: ${currentTrayBarcode}`,
        type: 'success',
        duration: 2000
      });
      // this.$message({
      //   message: `托盘条码已设置: ${currentTrayBarcode}`,
      //   type: 'success',
      //   duration: 2000
      // });
      this.$message.success(`托盘条码已设置: ${currentTrayBarcode}`);
    },
    // æ¸…除托盘
@@ -829,7 +622,7 @@
      this.isManualInput = false;
      this.isScanning = false;
    },
    // å¤„理物料条码提交
    async handleBarcodeSubmit() {
@@ -851,71 +644,43 @@
      this.error = '';
      this.loading = true;
      console.log(currentBarcode);
      try {
        // è°ƒç”¨API查询物料信息
        const materialData = await this.fetchMaterialData(currentBarcode);
        if (!materialData || materialData.length === 0) {
          return;
        }
        // æ£€æŸ¥æ˜¯å¦å·²å­˜åœ¨ç›¸åŒç‰©æ–™ç¼–码的记录
        const exists = this.materials.some(item =>
          item.barcode === this.trayBarcode
        );
        console.log('API:', materialData)
        if (exists) {
          this.$message({
            message: '该条码已存在当前托盘的列表中',
            type: 'warning',
            duration: 2000
        this.materials = [];
        materialData.forEach(item => {
          this.materials.push({
            ...item,
            trayCode: this.trayBarcode,
            locationType: this.form.locationType,
            locationDesc: this.currentLocationDesc,
            scanTime: this.formatTime(new Date())
          });
        } else {
        });
        this.orderNo = materialData[0].orderNo;
          materialData.forEach(item => {
        this.fetchStockStatistics();
        // æ¸…空物料输入框并保持聚焦
        this.barcode = '';
        this.scanCode = ''; // æ¸…空扫码缓存
        this.isScanning = false;
            // å¦‚果不存在,添加新物料
            this.materials.push({
              ...item,
              trayCode: this.trayBarcode,
              locationType: this.form.locationType,
              locationDesc: this.currentLocationDesc,
              scanTime: this.formatTime(new Date())
            });
          });
          const removeIndex = this.unpalletMaterials.findIndex(item => item.barcode === currentBarcode);
          if (removeIndex > -1) {
            this.unpalletMaterials.splice(removeIndex, 1); // åˆ é™¤æœªç»„盘对应数据
            this.unpalletBarcodes = this.unpalletMaterials.map(item => item.barcode || ''); // æ›´æ–°æ¡ç æ•°ç»„
            this.totalStockCount = Math.max(0, this.totalStockCount - 1);
          }
          this.$message({
            message: `成功添加条码: ${currentBarcode}`,
            type: 'success',
            duration: 2000
          });
          this.fetchStockStatistics();
          // æ¸…空物料输入框并保持聚焦
          this.barcode = '';
          this.scanCode = ''; // æ¸…空扫码缓存
          this.isScanning = false;
          setTimeout(() => {
            this.focusBarcodeInput();
          }, 100);
        }
        setTimeout(() => {
          this.focusBarcodeInput();
        }, 100);
      } catch (err) {
        this.error = err.message || '查询条码信息失败,请重试';
        this.focusBarcodeInput();
        setTimeout(() => {
      // é€‰ä¸­è¾“入框内的错误内容(确保focus完成后执行)
      const inputEl = this.$refs.barcodeInput?.$el?.querySelector('input');
      if (inputEl) inputEl.select();
    }, 100);
          // é€‰ä¸­è¾“入框内的错误内容(确保focus完成后执行)
          const inputEl = this.$refs.barcodeInput?.$el?.querySelector('input');
          if (inputEl) inputEl.select();
        }, 100);
      } finally {
        this.loading = false;
      }
@@ -924,18 +689,15 @@
    // API请求 - æ›¿æ¢ä¸ºå®žé™…çš„API调用
    async fetchMaterialData(barcode) {
      try {
        const response = await http.post('/api/InboundOrder/BarcodeMaterielGroup',
        const response = await http.post('/api/Inbound/GroupPallet',
          {
            palletCode: this.trayBarcode,
            orderNo: this.docNo,
            barcodes: barcode,
            barcode: barcode,
            locationTypeDesc: this.currentLocationDesc,
            locationType: this.form.locationType, // æ·»åŠ ä»“åº“åŒºåŸŸä¿¡æ¯
            warehouseType: this.form.warehouseType
          }
        );
        let materialData;
        if (typeof response.data === 'string') {
@@ -946,7 +708,6 @@
          }
        } else {
          // å¦‚果返回的是JSON对象,直接使用
          materialData = response.data;
        }
        if (!response.status) {
@@ -957,8 +718,6 @@
      } catch (error) {
        console.error('API调用失败:', error);
      }
    },
@@ -1377,35 +1136,35 @@
  }
  .unpallet-section.compact {
  margin-bottom: 8px;
  flex-shrink: 0;
}
.unpallet-card {
  flex-shrink: 0;
}
.unpallet-barcode-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 8px 0;
  max-height: 180px;
  overflow-y: auto;
}
.unpallet-barcode-list>>>.el-tag {
  cursor: pointer;
  max-width: calc(33.333% - 4px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (max-width: 768px) {
  .unpallet-barcode-list>>>.el-tag {
    max-width: calc(50% - 4px);
    margin-bottom: 8px;
    flex-shrink: 0;
  }
}
  .unpallet-card {
    flex-shrink: 0;
  }
  .unpallet-barcode-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 8px 0;
    max-height: 180px;
    overflow-y: auto;
  }
  .unpallet-barcode-list>>>.el-tag {
    cursor: pointer;
    max-width: calc(33.333% - 4px);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  @media (max-width: 768px) {
    .unpallet-barcode-list>>>.el-tag {
      max-width: calc(50% - 4px);
    }
  }
}
</style>
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/inboundOrder.js
@@ -1,13 +1,11 @@
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
import http from '@/api/http.js'
import { h, createVNode, render, reactive, ref } from 'vue';
import { ElDialog, ElForm, ElFormItem, ElInput, ElButton, ElMessage, ElSelect, ElOption } from 'element-plus'; // å¼•å…¥ElMessage,解决提示无反应
import gridHeader from './extend/EmptyTrayInbound.vue'
import gridBody from '../inbound/extend/Pallet.vue'
let extension = {
  components: {
    //查询界面扩展组件
    gridHeader: gridHeader,
    gridBody: '',
    gridBody: gridBody,
    gridFooter: '',
    //新建、编辑弹出框扩展组件
    modelHeader: '',
@@ -17,32 +15,30 @@
  tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
  buttons: {
    view: [
      {
        name: '组盘',
        type: 'primary',
        value: '组盘',
        onClick: function () { // ä¿®å¤1:移除无用row参数,加日志调试
          console.log('组盘按钮被点击,开始校验');
          const selectedRows = this.$refs.table.getSelected();
      // {
      //   name: '组盘',
      //   type: 'primary',
      //   value: '组盘',
      //   onClick: function () { // ä¿®å¤1:移除无用row参数,加日志调试
      //     const selectedRows = this.$refs.table.getSelected();
      //     // æ ¡éªŒ1:是否选中行
      //     if (selectedRows.length === 0) {
      //       console.log('校验不通过:未选中任何单据');
      //       ElMessage.warning('请选择一条单据');
      //       return;
      //     }
      //     // æ ¡éªŒ2:是否选中单行
      //     if (selectedRows.length > 1) {
      //       console.log('校验不通过:选中多行单据');
      //       ElMessage.warning('只能选择一条单据');
      //       return;
      //     }
          // æ ¡éªŒ1:是否选中行
          if (selectedRows.length === 0) {
            console.log('校验不通过:未选中任何单据');
            ElMessage.warning('请选择一条单据');
            return;
          }
          // æ ¡éªŒ2:是否选中单行
          if (selectedRows.length > 1) {
            console.log('校验不通过:选中多行单据');
            ElMessage.warning('只能选择一条单据');
            return;
          }
      //     const targetRow = selectedRows[0];
          const targetRow = selectedRows[0];
          this.$emit('openPalletDialog', targetRow.inboundOrderNo);
        }
      },
      //     this.$emit('openPalletDialog', targetRow.inboundOrderNo);
      //   }
      // },
      {
        name: '撤销组盘',
        type: 'primary',
@@ -245,181 +241,6 @@
          }
        }
      },
      // {
      //   name: '空托盘入库',
      //   type: 'primary',
      //   value: '空托盘入库',
      //   onClick: function () {
      //     const mountNode = document.createElement('div');
      //     document.body.appendChild(mountNode);
      //     // å“åº”式表单数据:料箱码(必填,扫码枪/手动输入)
      //     const formData = reactive({
      //       boxCode: '',
      //       warehouseCode: ''
      //     });
      //     const warehouses = ref([]);
      //     const isLoadingWarehouses = ref(false);
      //     const getWarehouseList = async () => {
      //       isLoadingWarehouses.value = true;
      //       try {
      //         const { data, status } = await http.post('/api/LocationInfo/GetLocationTypes');
      //         if (status && Array.isArray(data)) {
      //           // æ ¼å¼åŒ–仓库选项:适配ElSelect的label-value格式
      //           warehouses.value = data.map(item => ({
      //             label: item.locationTypeDesc,
      //             value: item.locationType
      //           }));
      //         } else {
      //           ElMessage.error('获取区域列表失败');
      //           warehouses.value = [];
      //         }
      //       } catch (err) {
      //         ElMessage.error('区域数据请求异常,请稍后重试');
      //         warehouses.value = [];
      //       } finally {
      //         isLoadingWarehouses.value = false;
      //       }
      //     };
      //     // æäº¤è¡¨å•的统一逻辑(供回车触发和按钮点击共用)
      //     const submitForm = async () => {
      //       const formRef = vnode.component.refs.batchInForm;
      //       try {
      //         // æ‰§è¡Œè¡¨å•校验(料箱码必填)
      //         await formRef.validate();
      //       } catch (err) {
      //         ElMessage.warning('请输入有效的料箱码');
      //         return;
      //       }
      //       http.post('/api/InboundOrder/EmptyMaterielGroup', {
      //         palletCode: formData.boxCode.trim(),
      //         warehouseCode: formData.warehouseCode
      //       }).then(({ data, status, message }) => {
      //         if (status) {
      //           ElMessage.success(`入库成功,料箱码:${formData.boxCode.trim()}`);
      //           this.refresh();
      //           formData.boxCode = '';
      //           setTimeout(() => {
      //             const inputRef = vnode.component.refs.boxCodeInput;
      //             inputRef?.focus();
      //           }, 100);
      //         } else {
      //           ElMessage.error(message || data?.message || '入库失败');
      //           selectBoxCodeInput();
      //         }
      //       }).catch(() => {
      //         ElMessage.error('请求失败,请稍后重试');
      //         selectBoxCodeInput();
      //       });
      //     };
      //     const selectBoxCodeInput = () => {
      //       setTimeout(() => {
      //         const inputRef = vnode.component.refs.boxCodeInput;
      //         if (inputRef) {
      //           const targetInput = inputRef.$el?.querySelector('input') || inputRef;
      //           targetInput?.focus();
      //           targetInput?.select();
      //         }
      //       }, 100);
      //     }
      //     const vnode = createVNode(ElDialog, {
      //       title: '空托盘入库',
      //       width: '400px',
      //       modelValue: true,
      //       appendToBody: true,
      //       onOpened: async () => {
      //         await getWarehouseList();
      //         const inputRef = vnode.component.refs.boxCodeInput;
      //         inputRef?.focus();
      //       },
      //       'onUpdate:modelValue': (isVisible) => {
      //         if (!isVisible) {
      //           render(null, mountNode);
      //           document.body.removeChild(mountNode);
      //         }
      //       }
      //     }, {
      //       default: () => h(ElForm, {
      //         model: formData,
      //         rules: {
      //           boxCode: [
      //             { required: true, message: '请输入料箱码', trigger: ['blur', 'enter'] }
      //           ],
      //           warehouseCode: [
      //             { required: true, message: '请选择区域', trigger: ['change', 'blur'] }
      //           ]
      //         },
      //         ref: 'batchInForm'
      //       }, [
      //         //仓库数据
      //         h(ElFormItem, { label: '区域', prop: 'warehouseCode', required: true }, [
      //           h(ElSelect, {
      //             modelValue: formData.warehouseCode,
      //             'onUpdate:modelValue': (val) => {
      //               formData.warehouseCode = val;
      //             },
      //             placeholder: '请选择入库区域',
      //             filterable: true, // æ”¯æŒæœç´¢ä»“库
      //             loading: isLoadingWarehouses.value, // åŠ è½½çŠ¶æ€
      //             style: { width: '100%' }
      //           }, [
      //             // æ¸²æŸ“仓库下拉选项
      //             warehouses.value.map(item => h(ElOption, {
      //               label: item.label,
      //               value: item.value
      //             }))
      //           ])
      //         ]),
      //         // æ–™ç®±ç è¾“入项(支持聚焦、回车提交)
      //         h(ElFormItem, { label: '料箱码', prop: 'boxCode', required: true }, [
      //           h(ElInput, {
      //             type: 'text',
      //             modelValue: formData.boxCode,
      //             'onUpdate:modelValue': (val) => {
      //               formData.boxCode = val;
      //             },
      //             ref: 'boxCodeInput',
      //             placeholder: '扫码输入或手动输入料箱码',
      //             // ç›‘听回车事件(扫码枪默认会发送回车)
      //             onKeydown: (e) => {
      //               if (e.key === 'Enter') {
      //                 e.preventDefault();
      //                 submitForm();
      //               }
      //             }
      //           })
      //         ]),
      //         // åº•部按钮区
      //         h('div', { style: { textAlign: 'right', marginTop: '16px' } }, [
      //           h(ElButton, {
      //             type: 'text',
      //             onClick: () => {
      //               render(null, mountNode);
      //               document.body.removeChild(mountNode);
      //               ElMessage.info('取消入库任务');
      //             }
      //           }, '取消'),
      //           h(ElButton, {
      //             type: 'primary',
      //             onClick: submitForm
      //           }, '确定')
      //         ])
      //       ])
      //     });
      //     vnode.appContext = this.$.appContext;
      //     render(vnode, mountNode);
      //   }
      // }
    ], box: [], detail: []
  },
  methods: {
@@ -431,7 +252,13 @@
               this.$refs.gridHeader.open();
            }
        }
        var GroupPalletBtn = this.buttons.find(x => x.value == "GroupPallet");
        if (GroupPalletBtn != null) {
          GroupPalletBtn.onClick = () => {
              // console.log(this.$refs)
               this.$refs.gridBody.open();
            }
        }
      this.columns.forEach(column => {
        if (column.field === 'orderStatistics') {
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/extension/inbound/inboundOrder_copy.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,105 @@
//此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码
import gridHeader from './extend/EmptyTrayInbound.vue'
import gridBody from './extend/Pallet.vue'
let extension = {
  components: {
    //查询界面扩展组件
    gridHeader: gridHeader,
    gridBody: gridBody,
    gridFooter: '',
    //新建、编辑弹出框扩展组件
    modelHeader: '',
    modelBody: '',
    modelFooter: ''
  },
  tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
  buttons: { view: [], box: [], detail: [] },
  methods: {
    //下面这些方法可以保留也可以删除
    onInit() {
      var EmptyTrayInboundBtn = this.buttons.find(x => x.value == "EmptyTrayInbound");
        if (EmptyTrayInboundBtn != null) {
          EmptyTrayInboundBtn.onClick = () => {
               this.$refs.gridHeader.open();
            }
        }
        var GroupPalletBtn = this.buttons.find(x => x.value == "GroupPallet");
        if (GroupPalletBtn != null) {
          GroupPalletBtn.onClick = () => {
              // console.log(this.$refs)
               this.$refs.gridBody.open();
            }
        }
      this.columns.forEach(column => {
        if (column.field === 'orderStatistics') {
          column.formatter = (row) => {
            // æ ¡éªŒdetails是否存在且有数据
            if (row.details && row.details.length > 0) {
              //按materielCode分组统计orderQuantity总和
              const materielSumMap = row.details.reduce((acc, item) => {
                const materielCode = item.materielCode || '未知物料';
                const quantity = Number(item.orderQuantity) || 0;
                acc[materielCode] = (acc[materielCode] || 0) + quantity;
                return acc;
              }, {});
              //每个物料项生成独立div,跨行显示
              const displayItems = Object.entries(materielSumMap).map(([code, total]) => {
                return `<div style="line-height: 1.5; white-space: normal;">${code}:${total}个</div>`;
              });
              const displayContent = displayItems.join('');
              return `<div style="color: #F56C6C; white-space: normal; word-break: break-all;">${displayContent}</div>`;
            } else {
              return '<span style="color: #F56C6C">无入库明细</span>';
            }
          };
        }
      });
    },
    onInited() {
      //框架初始化配置后
      //如果要配置明细表,在此方法操作
      //this.detailOptions.columns.forEach(column=>{ });
    },
    searchBefore(param) {
      //界面查询前,可以给param.wheres添加查询参数
      //返回false,则不会执行查询
      // this.searchFormFields.orderType=[0]
      let wheres = [{
        'name': 'orderType',
        'value': '0',
        'displayType': 'text'
      }];
      param.wheres.push(...wheres);
      return true;
    },
    searchAfter(result) {
      return true;
    },
    addBefore(formData) {
      //新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
      return true;
    },
    updateBefore(formData) {
      //编辑保存前formData为对象,包括明细表、删除行的Id
      return true;
    },
    rowClick({ row, column, event }) {
      //查询界面点击行事件
      this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
    },
    modelOpenAfter(row) {
      //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
      //(1)判断是编辑还是新建操作: this.currentAction=='Add';
      //(2)给弹出框设置默认值
      //(3)this.editFormFields.字段='xxx';
      //如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值
      //看不懂就把输出看:console.log(this.editFormOptions)
    }
  }
};
export default extension;
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/Login.vue
@@ -13,63 +13,31 @@
        <div class="login-text-small">WELCOME TO LOGIN</div>
        <div class="item">
          <div class="input-icon el-icon-user"></div>
          <input
            type="text"
            v-focus
            v-model="userInfo.userName"
            placeholder="请输入账号"
          />
          <input type="text" v-focus v-model="userInfo.userName" placeholder="请输入账号" />
        </div>
        <div class="item">
          <div class="input-icon el-icon-lock"></div>
          <input
            type="password"
            v-focus
            v-model="userInfo.password"
            placeholder="请输入密码"
          />
          <input type="password" v-focus v-model="userInfo.password" placeholder="请输入密码" />
        </div>
         <div class="item station-select-item">
        <div class="item station-select-item">
          <div class="input-icon el-icon-lock"></div>
          <el-select
            v-model="stationValue"
            placeholder="选择站台"
            class="station-select"
            @change="handleStationChange"
          >
            <el-option
              v-for="item in stationOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          <el-select v-model="stationValue" placeholder="选择站台" class="station-select" @change="handleStationChange">
            <el-option v-for="item in stationOptions" :key="item.value" :label="item.label" :value="item.value" />
          </el-select>
        </div>
        <div class="item">
          <div class="input-icon el-icon-mobile"></div>
          <input
            v-focus
            type="text"
            v-model="userInfo.verificationCode"
            placeholder="输入验证码"
          />
          <input v-focus type="text" v-model="userInfo.verificationCode" placeholder="输入验证码" />
          <div class="code" @click="getVierificationCode">
            <img v-show="codeImgSrc != ''" :src="codeImgSrc" />
          </div>
        </div>
      </div>
      <div class="loging-btn">
        <el-button
          size="large"
          :loading="loading"
          color="#3a6cd1"
          :dark="true"
          @click="login"
          long
        >
        <el-button size="large" :loading="loading" color="#3a6cd1" :dark="true" @click="login" long>
          <span v-if="!loading">登录</span>
          <span v-else>正在登录...</span>
        </el-button>
@@ -100,17 +68,17 @@
    const codeImgSrc = ref("");
    const value = ref("");
    const userInfo = reactive({
      userName: "",
      password: "",
      verificationCode: "",
      userName: "admin",
      password: "123456",
      verificationCode: "1234",
      UUID: undefined,
    });
     const stationValue = ref("");
   const stationOptions = reactive([
    const stationValue = ref("");
    const stationOptions = reactive([
      { label: "站台2", value: "2-1" },
      { label: "站台3", value: "3-1" },
    ]);
     // åˆå§‹åŒ–站台值
    // åˆå§‹åŒ–站台值
    onMounted(() => {
      // ä»Žæœ¬åœ°å­˜å‚¨åŠ è½½ä¿å­˜çš„ç«™å°å€¼
      const savedStation = stationManager.getStation();
@@ -149,7 +117,7 @@
        return $message.error("请输入验证码");
      }
          // ç¡®ä¿ç«™å°å€¼å·²ä¿å­˜
      // ç¡®ä¿ç«™å°å€¼å·²ä¿å­˜
      if (stationValue.value) {
        stationManager.saveStation(stationValue.value);
        store.commit("setStation", stationValue.value);
@@ -184,7 +152,7 @@
      userInfo,
      loginPress,
      openUrl,
     stationOptions,
      stationOptions,
      stationValue,
      handleStationChange,
    };
@@ -228,7 +196,7 @@
      &.station-select-item {
        padding-left: 0;
        .input-icon {
          margin-left: 20px;
          min-width: 20px;
@@ -367,9 +335,11 @@
    border: none;
    padding: 0;
    background: transparent;
    // ç§»é™¤æ‰€æœ‰hover、focus效果
    &:hover, &:focus, &.is-focus {
    &:hover,
    &:focus,
    &.is-focus {
      box-shadow: none !important;
      outline: none !important;
      border: none !important;
@@ -383,7 +353,7 @@
    font-size: 16px;
    color: #323233;
    cursor: pointer; // æ·»åŠ æŒ‡é’ˆæ˜¾ç¤ºä¸ºå¯ç‚¹å‡»
    &::placeholder {
      color: #c0c4cc;
    }
@@ -403,7 +373,9 @@
  }
  // ç§»é™¤æ•´ä¸ªç»„件上的任何hover和focus样式
  &:hover, &:focus, &.is-focus {
  &:hover,
  &:focus,
  &.is-focus {
    :deep(.el-input__wrapper) {
      box-shadow: none !important;
      outline: none !important;
@@ -417,35 +389,35 @@
  border: 1px solid #ececec;
  border-radius: 5px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  .el-select-dropdown__item {
    height: 45px;
    line-height: 45px;
    font-size: 16px;
    color: #323233;
    padding: 0 20px;
    &:hover {
      background-color: #f5f7fa;
    }
    &.selected {
      color: #3a6cd1;
      font-weight: normal;
      background-color: #f0f7ff;
    }
  }
  // éšè—æ»šåŠ¨æ¡æˆ–è°ƒæ•´æ»šåŠ¨æ¡æ ·å¼
  &::-webkit-scrollbar {
    width: 6px;
  }
  &::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 3px;
  }
  &::-webkit-scrollbar-thumb {
    background: #c1c1c1;
    border-radius: 3px;
@@ -454,7 +426,9 @@
// ç§»é™¤æ‰€æœ‰input的focus和hover样式
input {
  &:hover, &:focus {
  &:hover,
  &:focus {
    border: none !important;
    outline: none !important;
    box-shadow: none !important;
@@ -532,6 +506,7 @@
<style lang="less" scoped>
@media screen and (max-width: 700px) {
  .login-bg,
  .account-info,
  .app-link,
ÏîÄ¿´úÂë/WIDESEA_WMSClient/src/views/inbound/inboundOrder.vue
@@ -1,38 +1,14 @@
<template>
  <view-grid
    ref="grid"
    @openPalletDialog="handleOpenPalletDialog"
    :columns="columns"
    :detail="detail"
    :editFormFields="editFormFields"
    :editFormOptions="editFormOptions"
    :searchFormFields="searchFormFields"
    :searchFormOptions="searchFormOptions"
    :table="table"
    :extend="extend"
  >
  <view-grid ref="grid" @openPalletDialog="handleOpenPalletDialog" :columns="columns" :detail="detail"
    :editFormFields="editFormFields" :editFormOptions="editFormOptions" :searchFormFields="searchFormFields"
    :searchFormOptions="searchFormOptions" :table="table" :extend="extend">
  </view-grid>
      <!-- 2. ç»„盘弹窗:确保props和事件绑定正确 -->
    <PalletDialog
      v-model:visible="palletVisible"
      :docNo="currentPalletDocNo"
      @back-success="handlePalletBackSuccess"
    ></PalletDialog>
</template>
    <script>
import extend from "@/extension/inbound/inboundOrder.js";
import ViewGrid from '@/components/basic/ViewGrid/ViewGrid.vue';
<script>
import extend from "@/extension/inbound/inboundOrder_copy.js";
import { ref, defineComponent } from "vue";
import PalletDialog from "@/extension/inbound/extend/Pallet.vue";
export default defineComponent({
   components: {
    // å…³é”®ä¿®å¤2:组件注册名与模板标签名适配(kebab-case对应view-grid)
    viewGrid: ViewGrid,  // æ³¨å†Œä¸ºkebab-case,模板用<view-grid>
    PalletDialog      // æ³¨å†Œç»„盘弹窗
  },
  setup() {
    const table = ref({
      key: "id",
@@ -57,7 +33,7 @@
          type: "select",
          dataKey: "inOrderType",
          data: [],
          hidden:true
          hidden: true
        },
        {
          field: "inboundOrderNo",
@@ -149,7 +125,7 @@
        width: 150,
        align: "left",
        bind: { key: "inOrderType", data: [] },
        hidden:true
        hidden: true
      },
      {
        field: "businessType",
@@ -193,7 +169,7 @@
        field: "returnToMESStatus",
        title: "回传MES状态",
        width: 120,
        bind: { key: "createType", data:[{key:0, value:"未回传"},{key:1, value:"已回传成功"},{key:2, value:"回传失败"}]},
        bind: { key: "createType", data: [{ key: 0, value: "未回传" }, { key: 1, value: "已回传成功" }, { key: 2, value: "回传失败" }] },
      },
      {
        field: "factoryArea",
@@ -375,20 +351,7 @@
      sortName: "id",
      key: "id",
    });
     // 6. ç»„盘弹窗联动(所有变量必须返回)
    const palletVisible = ref(false);
    const currentPalletDocNo = ref("");
    const handleOpenPalletDialog = (docNo) => {
      console.log('主组件收到组盘事件,单据号:', docNo);
      currentPalletDocNo.value = docNo;
      palletVisible.value = true;
    };
    const handlePalletBackSuccess = () => {
      console.log('组盘回传成功,刷新表格');
      grid.value?.refresh();  // æ­¤æ—¶gridRef已挂载,可调用方法
    };
    return {
      table,
@@ -399,12 +362,12 @@
      searchFormOptions,
      columns,
      detail,
       // ç»„盘弹窗相关
      PalletDialog,    // å¼¹çª—组件(无需返回,注册即可,但变量需返回)
      palletVisible,
      currentPalletDocNo,
      handleOpenPalletDialog,
      handlePalletBackSuccess
      //  // ç»„盘弹窗相关
      // PalletDialog,    // å¼¹çª—组件(无需返回,注册即可,但变量需返回)
      // palletVisible,
      // currentPalletDocNo,
      // handleOpenPalletDialog,
      // handlePalletBackSuccess
    };
  },
});
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1231.31060/CodeChunks.db
Binary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1231.31060/CodeChunks.db-shm
Binary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1231.31060/CodeChunks.db-wal
Binary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1231.31060/SemanticSymbols.db
Binary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1231.31060/SemanticSymbols.db-shm
Binary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/.vs/WIDESEA_WMSServer/CopilotIndices/17.14.1231.31060/SemanticSymbols.db-wal
Binary files differ
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/LogLibrary/Log/FileUtil.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
using System;
using System.IO;
using System.Threading;
namespace LogLibrary.Log
{
    public static class FileUtil
    {
        /// <summary>
        /// è¿½åŠ å†…å®¹åˆ°æŒ‡å®šæ–‡ä»¶ä¸­
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="content"></param>
        public static void WriteAppend(string filePath, string content)
        {
            WriteAppend(filePath, new string[] { content });
        }
        public static void WriteAppend(string filePath, string[] contents)
        {
            using (FileStream fs = new(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
            {
                fs.Seek(fs.Length, SeekOrigin.Current);
                string content = string.Join(Environment.NewLine, contents) + Environment.NewLine;
                //byte[] data = System.Text.Encoding.GetEncoding("GB2312").GetBytes(content);
                byte[] data = System.Text.Encoding.Default.GetBytes(content);
                fs.Write(data, 0, data.Length);
                fs.Close();
                fs.Dispose();
            }
        }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/LogLibrary/Log/ILog.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,89 @@
using System;
namespace LogLibrary.Log
{
    public unsafe interface ILog
    {
        bool* IsCryto { set; }
        bool IsDebugEnabled { get; }
        bool IsErrorEnabled { get; }
        bool IsFatalEnabled { get; }
        bool IsInfoEnabled { get; }
        bool IsWarnEnabled { get; }
        void Debug(bool isWriteFile, object message);
        void Debug(bool isWriteFile, object message, Exception exception);
        void DebugFormat(bool isWriteFile, string format, object arg0);
        void DebugFormat(bool isWriteFile, string format, params object[] args);
        void DebugFormat(bool isWriteFile, IFormatProvider provider, string format, params object[] args);
        void DebugFormat(bool isWriteFile, string format, object arg0, object arg1);
        void DebugFormat(bool isWriteFile, string format, object arg0, object arg1, object arg2);
        void Error(bool isWriteFile, object message);
        void Error(bool isWriteFile, object message, Exception exception);
        void ErrorFormat(bool isWriteFile, string format, object arg0);
        void ErrorFormat(bool isWriteFile, string format, params object[] args);
        void ErrorFormat(bool isWriteFile, IFormatProvider provider, string format, params object[] args);
        void ErrorFormat(bool isWriteFile, string format, object arg0, object arg1);
        void ErrorFormat(bool isWriteFile, string format, object arg0, object arg1, object arg2);
        void Fatal(bool isWriteFile, object message);
        void Fatal(bool isWriteFile, object message, Exception exception);
        void FatalFormat(bool isWriteFile, string format, object arg0);
        void FatalFormat(bool isWriteFile, string format, params object[] args);
        void FatalFormat(bool isWriteFile, IFormatProvider provider, string format, params object[] args);
        void FatalFormat(bool isWriteFile, string format, object arg0, object arg1);
        void FatalFormat(bool isWriteFile, string format, object arg0, object arg1, object arg2);
        void Info(bool isWriteFile, object message);
        void Info(bool isWriteFile, object message, Exception exception);
        //void InfoFormat(bool isWriteFile, string format, object arg0);
        //void InfoFormat(bool isWriteFile, string format, params object[] args);
        //void InfoFormat(bool isWriteFile, IFormatProvider provider, string format, params object[] args);
        //void InfoFormat(bool isWriteFile, string format, object arg0, object arg1);
        void InfoFormat(bool isWriteFile, object arg0, object arg1, object arg2);
        void Warn(bool isWriteFile, object message);
        void Warn(bool isWriteFile, object message, Exception exception);
        void WarnFormat(bool isWriteFile, string format, object arg0);
        void WarnFormat(bool isWriteFile, string format, params object[] args);
        void WarnFormat(bool isWriteFile, IFormatProvider provider, string format, params object[] args);
        void WarnFormat(bool isWriteFile, string format, object arg0, object arg1);
        void WarnFormat(bool isWriteFile, string format, object arg0, object arg1, object arg2);
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/LogLibrary/Log/ILogFactory.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
namespace LogLibrary.Log
{
    public interface ILogFactory
    {
        ILog GetLog(string name);
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/LogLibrary/Log/Level.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LogLibrary.Log
{
        public enum Level : int
        {
            Debug,
            Info,
            Warning,
            Error
        }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/LogLibrary/Log/Log.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,755 @@
using System;
using System.Text.RegularExpressions;
namespace LogLibrary.Log
{
    public unsafe class Log
    {
        private string m_Name;
        private const string m_MessageTemplate = "{0}-{1}: {2}";
        private const string m_Debug = "DEBUG";
        private const string m_Error = "ERROR";
        private const string m_Fatal = "FATAL";
        private const string m_Info = "INFO";
        private const string m_Warn = "WARN";
        /// <summary>
        /// Initializes a new instance of the <see cref="Log"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        public Log(string name)
        {
            m_Name = name;
        }
        public Log()
        {
            m_Name = "NaN";
        }
        /// <summary>
        /// Gets a value indicating whether this instance is debug enabled.
        /// </summary>
        /// <value>
        ///     <c>true</c> if this instance is debug enabled; otherwise, <c>false</c>.
        /// </value>
        public bool IsDebugEnabled
        {
            get { return true; }
        }
        /// <summary>
        /// Gets a value indicating whether this instance is error enabled.
        /// </summary>
        /// <value>
        ///     <c>true</c> if this instance is error enabled; otherwise, <c>false</c>.
        /// </value>
        public bool IsErrorEnabled
        {
            get { return true; }
        }
        /// <summary>
        /// Gets a value indicating whether this instance is fatal enabled.
        /// </summary>
        /// <value>
        ///     <c>true</c> if this instance is fatal enabled; otherwise, <c>false</c>.
        /// </value>
        public bool IsFatalEnabled
        {
            get { return true; }
        }
        /// <summary>
        /// Gets a value indicating whether this instance is info enabled.
        /// </summary>
        /// <value>
        ///     <c>true</c> if this instance is info enabled; otherwise, <c>false</c>.
        /// </value>
        public bool IsInfoEnabled
        {
            get { return true; }
        }
        /// <summary>
        /// Gets a value indicating whether this instance is warn enabled.
        /// </summary>
        /// <value>
        ///     <c>true</c> if this instance is warn enabled; otherwise, <c>false</c>.
        /// </value>
        public bool IsWarnEnabled
        {
            get { return true; }
        }
        public string GetDataTimeLog(string log)
        {
            return string.Format("[{0}] >>  {1}", DateTime.Now.ToString("yy-MM-dd HH:mm:ss"), log);
        }
        /// <summary>
        /// Logs the debug message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="message">The message.</param>
        public void Debug(bool isWriteFile, object message)
        {
            string log = GetDataTimeLog(message.ToString());
            Console.WriteLine(m_MessageTemplate, m_Name, m_Debug, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Debug, log);
            }
        }
        /// <summary>
        /// Logs the debug message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="message">The message.</param>
        /// <param name="exception">The exception.</param>
        public void Debug(bool isWriteFile, object message, Exception exception)
        {
            string log = GetDataTimeLog(message + Environment.NewLine + exception.Message + exception.StackTrace);
            Console.WriteLine(m_MessageTemplate, m_Name, m_Debug, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Debug, log);
            }
        }
        /// <summary>
        /// Logs the debug message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        public void DebugFormat(bool isWriteFile, string format, object arg0)
        {
            string log = GetDataTimeLog(string.Format(format, arg0));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Debug, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Debug, log);
            }
        }
        /// <summary>
        /// Logs the debug message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="args">The args.</param>
        public void DebugFormat(bool isWriteFile, string format, params object[] args)
        {
            string log = GetDataTimeLog(string.Format(format, args));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Debug, string.Format(format, args));
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Debug, log);
            }
        }
        /// <summary>
        /// Logs the debug message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="provider">The provider.</param>
        /// <param name="format">The format.</param>
        /// <param name="args">The args.</param>
        public void DebugFormat(bool isWriteFile, IFormatProvider provider, string format, params object[] args)
        {
            string log = GetDataTimeLog(string.Format(format, args));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Debug, string.Format(provider, format, args));
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Debug, log);
            }
        }
        /// <summary>
        /// Logs the debug message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        /// <param name="arg1">The arg1.</param>
        public void DebugFormat(bool isWriteFile, string format, object arg0, object arg1)
        {
            string log = GetDataTimeLog(string.Format(format, arg0, arg1));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Debug, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Debug, log);
            }
        }
        /// <summary>
        /// Logs the debug message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        public void DebugFormat(bool isWriteFile, string format, object arg0, object arg1, object arg2)
        {
            string log = GetDataTimeLog(string.Format(format, arg0, arg1, arg2));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Debug, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Debug, log);
            }
        }
        /// <summary>
        /// Logs the error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="message">The message.</param>
        public void Error(bool isWriteFile, object message)
        {
            string log = GetDataTimeLog(message.ToString());
            Console.WriteLine(m_MessageTemplate, m_Name, m_Error, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Error, log);
            }
        }
        /// <summary>
        /// Logs the error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="message">The message.</param>
        /// <param name="exception">The exception.</param>
        public void Error(bool isWriteFile, object message, Exception exception)
        {
            //string log = GetDataTimeLog(message + Environment.NewLine + exception.Message + exception.StackTrace);
            string log = GetDataTimeLog(message + Environment.NewLine + exception.Message );
            Console.WriteLine(m_MessageTemplate, m_Name, m_Error, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Error, log);
            }
        }
        /// <summary>
        /// Logs the error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        public void ErrorFormat(bool isWriteFile, string format, object arg0)
        {
            string log = GetDataTimeLog(string.Format(format, arg0));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Error, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Error, log);
            }
        }
        /// <summary>
        /// Logs the error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="args">The args.</param>
        public void ErrorFormat(bool isWriteFile, string format, params object[] args)
        {
            string log = GetDataTimeLog(string.Format(format, args));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Error, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Error, log);
            }
        }
        /// <summary>
        /// Logs the error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="provider">The provider.</param>
        /// <param name="format">The format.</param>
        /// <param name="args">The args.</param>
        public void ErrorFormat(bool isWriteFile, IFormatProvider provider, string format, params object[] args)
        {
            string log = GetDataTimeLog(string.Format(provider, format, args));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Error, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Error, log);
            }
        }
        /// <summary>
        /// Logs the error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        /// <param name="arg1">The arg1.</param>
        public void ErrorFormat(bool isWriteFile, string format, object arg0, object arg1)
        {
            string log = GetDataTimeLog(string.Format(format, arg0, arg1));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Error, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Error, log);
            }
        }
        /// <summary>
        /// Logs the error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        public void ErrorFormat(bool isWriteFile, string format, object arg0, object arg1, object arg2)
        {
            string log = GetDataTimeLog(string.Format(format, arg0, arg2));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Error, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Error, log);
            }
        }
        /// <summary>
        /// Logs the fatal error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="message">The message.</param>
        public void Fatal(bool isWriteFile, object message)
        {
            string log = GetDataTimeLog(message.ToString());
            Console.WriteLine(m_MessageTemplate, m_Name, m_Fatal, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Fatal, log);
            }
        }
        /// <summary>
        /// Logs the fatal error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="message">The message.</param>
        /// <param name="exception">The exception.</param>
        public void Fatal(bool isWriteFile, object message, Exception exception)
        {
            string log = GetDataTimeLog(message + Environment.NewLine + exception.Message + exception.StackTrace);
            Console.WriteLine(m_MessageTemplate, m_Name, m_Fatal, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Fatal, log);
            }
        }
        /// <summary>
        /// Logs the fatal error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        public void FatalFormat(bool isWriteFile, string format, object arg0)
        {
            string log = GetDataTimeLog(string.Format(format, arg0));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Fatal, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Fatal, log);
            }
        }
        /// <summary>
        /// Logs the fatal error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="args">The args.</param>
        public void FatalFormat(bool isWriteFile, string format, params object[] args)
        {
            string log = GetDataTimeLog(string.Format(format, args));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Fatal, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Fatal, log);
            }
        }
        /// <summary>
        /// Logs the fatal error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="provider">The provider.</param>
        /// <param name="format">The format.</param>
        /// <param name="args">The args.</param>
        public void FatalFormat(bool isWriteFile, IFormatProvider provider, string format, params object[] args)
        {
            string log = GetDataTimeLog(string.Format(provider, format, args));
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Fatal, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Fatal, log);
            }
        }
        /// <summary>
        /// Logs the fatal error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        /// <param name="arg1">The arg1.</param>
        public void FatalFormat(bool isWriteFile, string format, object arg0, object arg1)
        {
            string log = GetDataTimeLog(string.Format(format, arg0, arg1));
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Fatal, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Fatal, log);
            }
        }
        /// <summary>
        /// Logs the fatal error message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        public void FatalFormat(bool isWriteFile, string format, object arg0, object arg1, object arg2)
        {
            string log = GetDataTimeLog(string.Format(format, arg0, arg1, arg2));
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Fatal, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Fatal, log);
            }
        }
        /// <summary>
        /// Logs the info message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="message">The message.</param>
        public void Info(bool isWriteFile, object message)
        {
            string log = GetDataTimeLog(message.ToString());
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Info, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Info, log);
            }
        }
        /// <summary>
        /// Logs the info message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="message">The message.</param>
        /// <param name="exception">The exception.</param>
        public void Info(bool isWriteFile, object message, Exception exception)
        {
            string log = GetDataTimeLog(message + Environment.NewLine + exception.Message + exception.StackTrace);
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Info, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Info, log);
            }
        }
        /// <summary>
        /// Logs the info message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        public void InfoFormat(bool isWriteFile, string format, object arg0)
        {
            string log = GetDataTimeLog(string.Format("\n{0}\n{1}\n-----------------------------------------------------------\n\n", format, arg0));
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Info, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Info, log);
            }
        }
        /// <summary>
        /// Logs the info message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="args">The args.</param>
        //public void InfoFormat(bool isWriteFile, string format, params object[] args)
        //{
        //    string log = GetDataTimeLog(string.Format(format, args));
        //    Console.WriteLine(m_MessageTemplate, m_Name, m_Info, log);
        //    if (isWriteFile)
        //    {
        //        LogUtil.WriteLogFile(m_Name, m_Info, log);
        //    }
        //}
        /// <summary>
        /// Logs the info message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="provider">The provider.</param>
        /// <param name="format">The format.</param>
        /// <param name="args">The args.</param>
        //public void InfoFormat(bool isWriteFile, IFormatProvider provider, string format, params object[] args)
        //{
        //    string log = GetDataTimeLog(string.Format(provider, format, args));
        //    Console.WriteLine(m_MessageTemplate, m_Name, m_Info, log);
        //    if (isWriteFile)
        //    {
        //        LogUtil.WriteLogFile(m_Name, m_Info, log);
        //    }
        //}
        /// <summary>
        /// Logs the info message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        /// <param name="arg1">The arg1.</param>
        //public void InfoFormat(bool isWriteFile, string format, object arg0, object arg1)
        //{
        //    string log = GetDataTimeLog(string.Format(format, arg0, arg1));
        //    Console.WriteLine(m_MessageTemplate, m_Name, m_Info, log);
        //    if (isWriteFile)
        //    {
        //        LogUtil.WriteLogFile(m_Name, m_Info, log);
        //    }
        //}
        /// <summary>
        /// Logs the info message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        public void InfoFormat(bool isWriteFile, object arg0, object arg1, object arg2)
        {
            string func(string str, int len)
            {
                var strSLen = Regex.Replace(str, @"[^\x00-\xff]", "aa").Length;
                var strLen = str.Length;
                return str.PadLeft(len - strSLen + strLen);
            }
            string log = GetDataTimeLog(string.Format("[{0}]\t[{1}]\t{2}", arg0?.ToString(), arg1?.ToString(), arg2));
            //string log = GetDataTimeLog(string.Format("[{0}]  [{1}]  {2}", func(arg0?.ToString(), 13), func(arg1?.ToString(), 16), arg2));
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Info, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Info, log);
            }
        }
        /// <summary>
        /// Logs the warning message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="message">The message.</param>
        public void Warn(bool isWriteFile, object message)
        {
            string log = GetDataTimeLog(message.ToString());
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Warn, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Warn, log);
            }
        }
        /// <summary>
        /// Logs the warning message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="message">The message.</param>
        /// <param name="exception">The exception.</param>
        public void Warn(bool isWriteFile, object message, Exception exception)
        {
            string log = GetDataTimeLog(message + Environment.NewLine + exception.Message + exception.StackTrace);
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Warn, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Warn, log);
            }
        }
        /// <summary>
        /// Logs the warning message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        public void WarnFormat(bool isWriteFile, string format, object arg0)
        {
            string log = GetDataTimeLog(string.Format(format, arg0));
            //Console.WriteLine(m_MessageTemplate, m_Name, m_Warn, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Warn, log);
            }
        }
        /// <summary>
        /// Logs the warning message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="args">The args.</param>
        public void WarnFormat(bool isWriteFile, string format, params object[] args)
        {
            string log = GetDataTimeLog(string.Format(format, args));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Warn, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Warn, log);
            }
        }
        /// <summary>
        /// Logs the warning message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="provider">The provider.</param>
        /// <param name="format">The format.</param>
        /// <param name="args">The args.</param>
        public void WarnFormat(bool isWriteFile, IFormatProvider provider, string format, params object[] args)
        {
            string log = GetDataTimeLog(string.Format(provider, format, args));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Warn, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Warn, log);
            }
        }
        /// <summary>
        /// Logs the warning message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        /// <param name="arg1">The arg1.</param>
        public void WarnFormat(bool isWriteFile, string format, object arg0, object arg1)
        {
            string log = GetDataTimeLog(string.Format(format, arg0, arg1));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Warn, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Warn, log);
            }
        }
        /// <summary>
        /// Logs the warning message.
        /// </summary>
        /// <param name="isWriteFile"></param>
        /// <param name="format">The format.</param>
        /// <param name="arg0">The arg0.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        public void WarnFormat(bool isWriteFile, string format, object arg0, object arg1, object arg2)
        {
            string log = GetDataTimeLog(string.Format(format, arg0, arg1, arg2));
            Console.WriteLine(m_MessageTemplate, m_Name, m_Warn, log);
            if (isWriteFile)
            {
                LogUtil.WriteLogFile(m_Name, m_Warn, log);
            }
        }
        //public void Behavior(string logMsg, Level level)
        //{
        //    lock (this)
        //    {
        //        m_Name = "行为";
        //        switch (level)
        //        {
        //            case Level.Debug:
        //                Debug(true, logMsg);
        //                break;
        //            case Level.Info:
        //                Info(true, logMsg);
        //                break;
        //            case Level.Warning:
        //                Warn(true, logMsg);
        //                break;
        //            case Level.Error:
        //                Error(true, logMsg);
        //                break;
        //            default:
        //                break;
        //        }
        //    }
        //}
        //public void Interface(string logMsg, Level level)
        //{
        //    lock (this)
        //    {
        //        m_Name = "接口";
        //        switch (level)
        //        {
        //            case Level.Debug:
        //                Debug(true, logMsg);
        //                break;
        //            case Level.Info:
        //                Info(true, logMsg);
        //                break;
        //            case Level.Warning:
        //                Warn(true, logMsg);
        //                break;
        //            case Level.Error:
        //                Error(true, logMsg);
        //                break;
        //            default:
        //                break;
        //        }
        //    }
        //}
        //public void Hardware(string logMsg, Level level)
        //{
        //    lock (this)
        //    {
        //        m_Name = "硬件";
        //        switch (level)
        //        {
        //            case Level.Debug:
        //                Debug(true, logMsg);
        //                break;
        //            case Level.Info:
        //                Info(true, logMsg);
        //                break;
        //            case Level.Warning:
        //                Warn(true, logMsg);
        //                break;
        //            case Level.Error:
        //                Error(true, logMsg);
        //                break;
        //            default:
        //                break;
        //        }
        //    }
        //}
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/LogLibrary/Log/LogFactory.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@

namespace LogLibrary.Log
{
    public unsafe class LogFactory
    {
        public Log GetLog(string name)
        {
            return new Log(name);
        }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/LogLibrary/Log/LogUtil.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
using System;
using System.Diagnostics;
using System.Threading;
namespace LogLibrary.Log
{
    internal unsafe class LogUtil
    {
        static ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim();
        /// <summary>
        /// æ ¼å¼å¼åŒ–Log信息
        /// </summary>
        /// <param name="format"></param>
        /// <param name="name"></param>
        /// <param name="logType"></param>
        /// <param name="log"></param>
        /// <returns></returns>
        private static string GetLogString(string name, string logType, string log)
        {
            return string.Format("[{0}]{1}-{2}: {3}", DateTime.Now.ToString("HH:mm:ss"), name, logType, log);
        }
        /// <summary>
        /// èŽ·å¾—æ—¥å¿—è¦ä¿å­˜çš„è·¯å¾„
        /// </summary>
        /// <param name="name"></param>
        /// <param name="logType"></param>
        /// <returns></returns>
        private static string GetLogPath(string name, string logType)
        {
            string path = AppDomain.CurrentDomain.BaseDirectory + $"Logs/{DateTime.Now:yyyyMM}";
            if (!System.IO.Directory.Exists(path))
            {
                System.IO.Directory.CreateDirectory(path);
            }
            return System.IO.Path.Combine(path, string.Format("{0}_{1}_{2}.log", DateTime.Now.ToString("yyyy-MM-dd"), name, logType));
        }
        public static void WriteLogFile(string name, string logType, string log)
        {
            string logPath = GetLogPath(name, logType);
            Trace.WriteLine(log);
            lockSlim.EnterWriteLock();//打开写操作锁
            try
            {
                FileUtil.WriteAppend(logPath, log);
            }
            finally
            {
                lockSlim.ExitWriteLock();
            }
        }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/LogLibrary/LogLibrary.csproj
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <OutputType>Library</OutputType>
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <Configurations>Debug;Release;Dev</Configurations>
    <Platforms>AnyCPU;x86</Platforms>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
    <OutputPath>bin\x86\Debug\</OutputPath>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <DebugType>embedded</DebugType>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Dev|x86'">
    <OutputPath>bin\x86\Debug\</OutputPath>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
    <OutputPath>bin\x86\Release\</OutputPath>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <DebugType>embedded</DebugType>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Dev|AnyCPU'">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\Dev\</OutputPath>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <DebugType>embedded</DebugType>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Dev|x86'">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\Dev\</OutputPath>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Dev|x86'">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\x86\Dev\</OutputPath>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <DebugType>embedded</DebugType>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DebugType>embedded</DebugType>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <DebugType>embedded</DebugType>
  </PropertyGroup>
</Project>
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/LogLibrary/Properties/AssemblyInfo.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// æœ‰å…³ç¨‹åºé›†çš„一般信息由以下
// æŽ§åˆ¶ã€‚更改这些特性值可修改
// ä¸Žç¨‹åºé›†å…³è”的信息。
[assembly: AssemblyTitle("LogLibrary")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LogLibrary")]
[assembly: AssemblyCopyright("Copyright Â©  2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// å°† ComVisible è®¾ç½®ä¸º false ä¼šä½¿æ­¤ç¨‹åºé›†ä¸­çš„类型
//对 COM ç»„件不可见。如果需要从 COM è®¿é—®æ­¤ç¨‹åºé›†ä¸­çš„类型
//请将此类型的 ComVisible ç‰¹æ€§è®¾ç½®ä¸º true。
[assembly: ComVisible(false)]
// å¦‚果此项目向 COM å…¬å¼€ï¼Œåˆ™ä¸‹åˆ— GUID ç”¨äºŽç±»åž‹åº“çš„ ID
[assembly: Guid("2e0d9770-ab36-4811-a0d0-05b98093b92d")]
// ç¨‹åºé›†çš„版本信息由下列四个值组成:
//
//      ä¸»ç‰ˆæœ¬
//      æ¬¡ç‰ˆæœ¬
//      ç”Ÿæˆå·
//      ä¿®è®¢å·
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Common/HttpClient/HttpsClient.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,195 @@
using LogLibrary.Log;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEA_Common;
public class HttpsClient
{
    private static readonly LogFactory LogFactory = new LogFactory();
    // å°è£…一个用HttpClient发送GET请求的方法有参数
    public static async Task<string> GetAsync(string url, Dictionary<string, object> parameters)
    {
        try
        {
            // è®°å½•请求参数
            LogRequestParameters(parameters, url);
            // å°†å‚数拼接到URL中
            string queryString = string.Join("&", parameters.Select(x => $"{x.Key}={x.Value}"));
            url += "?" + queryString;
            // åˆ›å»ºHttpClient实例
            using (HttpClient client = new HttpClient())
            {
                // å‘送GET请求并获取响应
                HttpResponseMessage response = await client.GetAsync(url);
                // ç¡®ä¿å“åº”成功
                response.EnsureSuccessStatusCode();
                // è¯»å–响应内容
                string responseBody = await response.Content.ReadAsStringAsync();
                // è®°å½•响应参数
                LogResponseParameters(responseBody, url);
                // è¿”回响应内容
                return responseBody;
            }
        }
        catch (Exception ex)
        {
            LogErrorParameters(ex.StackTrace, ex.Message, url);
            return ex.Message;
        }
    }
    // ç”¨äºŽè¿½è¸ªæ¯ä¸ªè¯·æ±‚的调用次数和最后请求时间。
    //private static readonly Dictionary<string, (int Count, DateTime LastRequestTime)> requestTracker = new();
    // å°è£…一个用HttpClient发送Post请求的方法有参数
    public static async Task<string> PostAsync(string url, Dictionary<string, object> parameters)
    {
        try
        {
            //// åˆ›å»ºä¸€ä¸ªæ–°çš„字典,排除 RequestTime å’Œ SessionId
            //var filteredParameters = parameters.Where(p => p.Key != "RequestTime" && p.Key != "SessionId").ToDictionary(p => p.Key, p => p.Value);
            //string requestKey = $"{url}:{JsonConvert.SerializeObject(filteredParameters)}";
            //// æ£€æŸ¥è¯·æ±‚次数和时间限制
            //if (requestTracker.TryGetValue(requestKey, out var requestInfo))
            //{
            //    if (requestInfo.Count >= 5 && DateTime.Now < requestInfo.LastRequestTime.AddMinutes(3))
            //    {
            //        // å¦‚果请求次数超过限制且未超过10分钟,抛出异常
            //        throw new InvalidOperationException("请求次数已达到限制,请稍后再试。");
            //    }
            //}
            //// æ›´æ–°è¯·æ±‚跟踪信息
            //if (requestTracker.ContainsKey(requestKey))
            //{
            //    requestTracker[requestKey] = (requestInfo.Count + 1, DateTime.Now);
            //}
            //else
            //{
            //    requestTracker[requestKey] = (1, DateTime.Now);
            //}
            // è®°å½•请求参数
            LogRequestParameters(parameters, url);
            // åˆ›å»ºHttpClient实例
            using (HttpClient client = new HttpClient())
            {
                // å°†å‚数转换为FormUrlEncodedContent
                string content = JsonConvert.SerializeObject(parameters);
                var request = new HttpRequestMessage(HttpMethod.Post, url);
                request.Content = new StringContent(content, Encoding.UTF8, "application/json");
                HttpResponseMessage response = await client.SendAsync(request);
                // ç¡®ä¿å“åº”成功
                response.EnsureSuccessStatusCode();
                // è¯»å–响应内容
                string responseBody = await response.Content.ReadAsStringAsync();
                // è®°å½•响应参数
                LogResponseParameters(responseBody, url);
                // è¿”回响应内容
                return responseBody;
            }
        }
        catch (Exception ex)
        {
            LogErrorParameters(ex.StackTrace,ex.Message, url);
            return ex.Message;
        }
    }
    public static async Task<string> PostAsync(string url, string requestJson = null, string contentType = "application/json", Dictionary<string, string>? headers = null)
    {
        try
        {
            LogRequestParameters(requestJson, url);
            string result = string.Empty;
            using (HttpContent httpContent = new StringContent(requestJson))
            {
                httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                using HttpClient httpClient = new HttpClient();
                httpClient.Timeout = new TimeSpan(0, 0, 60);
                if (headers != null)
                {
                    foreach (var header in headers)
                        httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
                result = await httpClient.PostAsync(url, httpContent).Result.Content.ReadAsStringAsync();
            }
            LogResponseParameters(result, url);
            return result;
        }
        catch (Exception ex)
        {
            LogErrorParameters(ex.StackTrace, ex.Message, url);
            Console.WriteLine(ex.Message);
        }
        return null;
    }
    private static void LogErrorParameters(string errordetail, string error, string url = "")
    {
        StringBuilder builder = new StringBuilder();
        builder.Append(Environment.NewLine);
        builder.Append("---------------------------------------------");
        builder.Append(Environment.NewLine);
        builder.Append("url:" + url + "异常详细信息: " + JsonConvert.SerializeObject(error));
        builder.Append("url:" + url + "异常信息: " + JsonConvert.SerializeObject(error));
        LogFactory.GetLog("API接口异常").Error(true, builder);
    }
    private static void LogRequestParameters(Dictionary<string, object> parameters, string url = "")
    {
        StringBuilder builder = new StringBuilder();
        builder.Append(Environment.NewLine);
        builder.Append("---------------------------------------------");
        builder.Append(Environment.NewLine);
        builder.Append("url:" + url + "请求参数: " + JsonConvert.SerializeObject(parameters));
        LogFactory.GetLog("API接口").Info(true, builder);
    }
    private static void LogRequestParameters(string parameters, string url = "")
    {
        StringBuilder builder = new StringBuilder();
        builder.Append(Environment.NewLine);
        builder.Append("---------------------------------------------");
        builder.Append(Environment.NewLine);
        builder.Append("url:" + url + "请求参数: " + JsonConvert.SerializeObject(parameters));
        LogFactory.GetLog("API接口").Info(true, builder);
    }
    private static void LogResponseParameters(string responseBody, string url = "")
    {
        StringBuilder builder = new StringBuilder();
        builder.Append(Environment.NewLine);
        builder.Append("url:" + url + "响应参数: " + responseBody);
        builder.Append(Environment.NewLine);
        builder.Append("---------------------------------------------");
        builder.Append(Environment.NewLine);
        LogFactory.GetLog("API接口").Info(true, builder);
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_Common/WIDESEA_Common.csproj
@@ -12,4 +12,12 @@
    <None Remove="Location\**" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\LogLibrary\LogLibrary.csproj" />
  </ItemGroup>
</Project>
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_DTO/Inbound/GroupPalletDto.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core.Attributes;
namespace WIDESEA_DTO.Inbound
{
    [ModelValidate]
    public class GroupPalletDto
    {
        [PropertyValidate("托盘编号", NotNullAndEmpty = true)]
        public string PalletCode { get; set; }
        [PropertyValidate("序列号条码", NotNullAndEmpty = true)]
        public string Barcode { get; set; }
        public string locationType { get; set; }
        public string WarehouseType { get; set; }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_IInboundService/IInboundService.cs
@@ -4,6 +4,7 @@
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core;
using WIDESEA_DTO.Inbound;
namespace WIDESEA_IInboundService
{
@@ -12,5 +13,12 @@
        IInboundOrderDetailService InboundOrderDetailService { get; }
        IInboundOrderService InbounOrderService { get; }
        /// <summary>
        /// ç»„盘
        /// </summary>
        /// <param name="palletDto"></param>
        /// <returns></returns>
        Task<WebResponseContent> GroupPallet(GroupPalletDto palletDto);
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_InboundService/InboundService.cs
@@ -1,22 +1,233 @@
using System;
using LogLibrary.Log;
using MailKit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Common.CommonEnum;
using WIDESEA_Common.OrderEnum;
using WIDESEA_Common.StockEnum;
using WIDESEA_Core;
using WIDESEA_Core.BaseRepository;
using WIDESEA_Core.Helper;
using WIDESEA_Core.Utilities;
using WIDESEA_DTO.Inbound;
using WIDESEA_IInboundService;
using WIDESEA_IStockService;
using WIDESEA_Model.Models;
using WIDESEA_Model.Models.Basic;
namespace WIDESEA_InboundService
{
    public class InboundService : IInboundService
    {
        LogFactory LogFactory = new LogFactory();
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        public IInboundOrderDetailService InboundOrderDetailService { get; }
        public IInboundOrderService InbounOrderService { get; }
        private readonly IRepository<Dt_InboundOrder> _inboundOrderRepository;
        private readonly IRepository<Dt_WarehouseArea> _warehouseAreaRepository;
        private readonly IRepository<Dt_LocationType> _locationTypeRepository;
        private readonly IRepository<Dt_StockInfo> _stockInfoRepository;
        private readonly IRepository<Dt_InboundOrderDetail> _inboundOrderDetailRepository;
        private readonly IRepository<Dt_Task> _taskRepository;
        private IStockService _stockService;
        public InboundService(IInboundOrderDetailService inboundOrderDetailService, IInboundOrderService inbounOrderService)
        public InboundService(IUnitOfWorkManage unitOfWorkManage, IInboundOrderDetailService inboundOrderDetailService, IInboundOrderService inbounOrderService, IRepository<Dt_InboundOrder> inboundOrderRepository, IRepository<Dt_WarehouseArea> warehouseAreaRepository, IRepository<Dt_LocationType> locationTypeRepository, IRepository<Dt_StockInfo> stockInfoRepository, IRepository<Dt_InboundOrderDetail> inboundOrderDetailRepository, IStockService stockService, IRepository<Dt_Task> taskRepository)
        {
            _unitOfWorkManage = unitOfWorkManage;
            InboundOrderDetailService = inboundOrderDetailService;
            InbounOrderService = inbounOrderService;
            _inboundOrderRepository = inboundOrderRepository;
            _warehouseAreaRepository = warehouseAreaRepository;
            _locationTypeRepository = locationTypeRepository;
            _stockInfoRepository = stockInfoRepository;
            _inboundOrderDetailRepository = inboundOrderDetailRepository;
            _stockService = stockService;
            _taskRepository = taskRepository;
        }
        public async Task<WebResponseContent> GroupPallet(GroupPalletDto palletDto)
        {
            WebResponseContent content = new WebResponseContent();
            try
            {
                (bool, string, object?) result2 = ModelValidate.ValidateModelData(palletDto);
                if (!result2.Item1) return content.Error(result2.Item2);
                var code = _warehouseAreaRepository.Db.Queryable<Dt_WarehouseArea>().Where(x => x.Code == palletDto.WarehouseType).Select(x => x.Code).First();
                if (string.IsNullOrEmpty(code))
                {
                    return content.Error($"仓库中没有该{palletDto.WarehouseType}编号。");
                }
                List<Dt_InboundOrderDetail> details = new List<Dt_InboundOrderDetail>();
                Dt_InboundOrder inboundOrder = new Dt_InboundOrder();
                details = _inboundOrderDetailRepository.QueryData(x => x.OutBoxbarcodes == palletDto.Barcode && x.OrderDetailStatus == (int)InOrderStatusEnum.未开始);
                if (details.Count <= 0)
                {
                    details = _inboundOrderDetailRepository.QueryData(x => x.Barcode == palletDto.Barcode && x.OrderDetailStatus == (int)InOrderStatusEnum.未开始);
                }
                if (details.Count() <= 0)
                {
                    return content.Error("未找到该条码单据信息请确认是否已经组盘完成");
                }
                inboundOrder = _inboundOrderRepository.Db.Queryable<Dt_InboundOrder>().Includes(x=>x.Details).Where(x => x.Id == details.First().OrderId).First();
                if (inboundOrder == null)
                {
                    return content.Error("未找到该条码主单信息");
                }
                Dt_StockInfo? stockInfo = await _stockInfoRepository.Db.Queryable<Dt_StockInfo>().Includes(x => x.Details).Where(x => x.PalletCode == palletDto.PalletCode).FirstAsync();
                List<string?> materielCodes = details.GroupBy(x => x.Barcode).Select(x => x.Key).ToList();
                (bool, string, object?) result = CheckMaterielGroupParam(palletDto, materielCodes, inboundOrder, stockInfo);
                if (!result.Item1) return content = WebResponseContent.Instance.Error(result.Item2);
                if (stockInfo == null)
                {
                    stockInfo = new Dt_StockInfo() { PalletType = (int)PalletTypeEnum.None, LocationType = Convert.ToInt32(palletDto.locationType) };
                    stockInfo.Details = new List<Dt_StockInfoDetail>();
                }
                foreach (var item in details)
                {
                    stockInfo.Details.Add(new Dt_StockInfoDetail
                    {
                        StockId = stockInfo == null ? 0 : stockInfo.Id,
                        Barcode = item.Barcode,
                        MaterielCode = item.MaterielCode,
                        BatchNo = item.BatchNo,
                        Unit = item.Unit,
                        InboundOrderRowNo = item.lineNo,
                        SupplyCode = item.SupplyCode,
                        WarehouseCode = palletDto.WarehouseType,
                        StockQuantity = item.OrderQuantity,
                        BarcodeQty = item.BarcodeQty,
                        BarcodeUnit = item.BarcodeUnit,
                        FactoryArea = inboundOrder.FactoryArea,
                        Status = 0,
                        OrderNo = inboundOrder.InboundOrderNo,
                        BusinessType = inboundOrder.BusinessType,
                    });
                    item.ReceiptQuantity = item.BarcodeQty;
                    item.OrderDetailStatus = (int)OrderDetailStatusEnum.Over;
                    item.WarehouseCode = palletDto.WarehouseType;
                    item.ReturnToMESStatus = 0;
                }
                if (stockInfo.Id == 0)
                {
                    stockInfo.PalletCode = palletDto.PalletCode;
                    stockInfo.StockStatus = (int)StockStatusEmun.组盘暂存;
                }
                stockInfo.PalletType = (int)PalletTypeEnum.None;
                List<int> updateDetailIds = details.Select(x => x.Id).ToList();
                if (inboundOrder.OrderStatus == (int)InOrderStatusEnum.未开始)
                {
                    inboundOrder.OrderStatus = (int)InOrderStatusEnum.入库中;
                }
                inboundOrder.Operator = App.User.UserName;
                content = MaterielGroupUpdateData(inboundOrder, details, stockInfo).Result;
                if (content.Status)
                {
                    Dt_StockInfo? NewstockInfo = await _stockInfoRepository.Db.Queryable<Dt_StockInfo>().Includes(x => x.Details).Where(x => x.PalletCode == palletDto.PalletCode).FirstAsync();
                    return WebResponseContent.Instance.OK(data: NewstockInfo.Details);
                }
                else
                {
                    content = WebResponseContent.Instance.Error(content.Message);
                }
            }
            catch (Exception ex)
            {
                LogFactory.GetLog($"组盘信息").Info(true, $"【异常】:【{ex.Message}】{Environment.NewLine}【{ex.StackTrace}】{Environment.NewLine}{Environment.NewLine}");
                return content.Error(ex.Message);
            }
            return content;
        }
        /// <summary>
        /// éªŒè¯ç»„盘数据
        /// </summary>
        /// <param name="materielGroupDTO">物料组盘DTO</param>
        /// <param name="matSerialNumberDTOs">扫码序列号</param>
        /// <param name="materielInfos">物料信息</param>
        /// <param name="materielCodes">物料编号</param>
        /// <param name="inboundOrder">入库单据</param>
        /// <param name="stockInfo">组盘信息</param>
        /// <returns></returns>
        public (bool, string, object?) CheckMaterielGroupParam(GroupPalletDto materielGroupDTO, List<string> barcodeCodes, Dt_InboundOrder inboundOrder, Dt_StockInfo stockInfo)
        {
            (bool, string, object?) result = ModelValidate.ValidateModelData(materielGroupDTO);
            if (!result.Item1) return result;
            if (_taskRepository.QueryFirst(x => x.PalletCode == materielGroupDTO.PalletCode) != null)
            {
                return (false, "该托盘号已有任务", materielGroupDTO);
            }
            if (stockInfo != null && !string.IsNullOrEmpty(stockInfo.LocationCode) && stockInfo.StockStatus != (int)StockStatusEmun.组盘暂存)
            {
                return (false, "已上架的托盘不能再次组盘", materielGroupDTO);
            }
            if (_stockService.StockInfoDetailService.ExistBarcodes(barcodeCodes))
            {
                return (false, $"{barcodeCodes[0]} æ¡ç åœ¨åº“存中已存在", materielGroupDTO);
            }
            if (inboundOrder == null)
            {
                return (false, "单据不存在", materielGroupDTO);
            }
            if (inboundOrder.Details == null || inboundOrder.Details.Count == 0)
            {
                return (false, "无单据明细信息", materielGroupDTO);
            }
            if (inboundOrder.OrderStatus != (int)InOrderStatusEnum.未开始 && inboundOrder.OrderStatus != (int)InOrderStatusEnum.入库中)
            {
                return (false, "该单据不可再组盘", materielGroupDTO);
            }
            List<Dt_InboundOrderDetail> inboundOrderDetails = inboundOrder.Details.Where(x => barcodeCodes.Contains(x.Barcode)).ToList();
            if (inboundOrderDetails.GroupBy(x => x.Barcode).Count() != barcodeCodes.Count)
            {
                return (false, "有物料不在单据内", materielGroupDTO);
            }
            return (true, "成功", materielGroupDTO);
        }
        public async Task<WebResponseContent> MaterielGroupUpdateData(Dt_InboundOrder inboundOrder, List<Dt_InboundOrderDetail> inboundOrderDetails, Dt_StockInfo stockInfo)
        {
            try
            {
                _unitOfWorkManage.BeginTran();
                //await _inboundOrderRepository.Db.UpdateNav(inboundOrder).Include(x=>x.Details).ExecuteCommandAsync();
                _inboundOrderRepository.UpdateData(inboundOrder);
                _inboundOrderDetailRepository.UpdateData(inboundOrderDetails);
                _stockService.StockInfoService.AddMaterielGroup(stockInfo);
                _unitOfWorkManage.CommitTran();
                return WebResponseContent.Instance.OK();
            }
            catch (Exception ex)
            {
                _unitOfWorkManage.RollbackTran();
                return WebResponseContent.Instance.Error(ex.Message);
            }
        }
    }
}
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer.sln
@@ -74,6 +74,8 @@
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WIDESEA_IAllocateService", "WIDESEA_IAllocateService\WIDESEA_IAllocateService.csproj", "{A6E822A3-5A09-4B18-BEE6-57CC7D7B8BEC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogLibrary", "LogLibrary\LogLibrary.csproj", "{A7C339A4-CC00-2872-6005-A272626BC5F1}"
EndProject
Global
    GlobalSection(SolutionConfigurationPlatforms) = preSolution
        Debug|Any CPU = Debug|Any CPU
@@ -360,6 +362,18 @@
        {A6E822A3-5A09-4B18-BEE6-57CC7D7B8BEC}.Release|Any CPU.Build.0 = Release|Any CPU
        {A6E822A3-5A09-4B18-BEE6-57CC7D7B8BEC}.Release|x86.ActiveCfg = Release|Any CPU
        {A6E822A3-5A09-4B18-BEE6-57CC7D7B8BEC}.Release|x86.Build.0 = Release|Any CPU
        {A7C339A4-CC00-2872-6005-A272626BC5F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {A7C339A4-CC00-2872-6005-A272626BC5F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {A7C339A4-CC00-2872-6005-A272626BC5F1}.Debug|x86.ActiveCfg = Debug|x86
        {A7C339A4-CC00-2872-6005-A272626BC5F1}.Debug|x86.Build.0 = Debug|x86
        {A7C339A4-CC00-2872-6005-A272626BC5F1}.Dev|Any CPU.ActiveCfg = Dev|Any CPU
        {A7C339A4-CC00-2872-6005-A272626BC5F1}.Dev|Any CPU.Build.0 = Dev|Any CPU
        {A7C339A4-CC00-2872-6005-A272626BC5F1}.Dev|x86.ActiveCfg = Dev|x86
        {A7C339A4-CC00-2872-6005-A272626BC5F1}.Dev|x86.Build.0 = Dev|x86
        {A7C339A4-CC00-2872-6005-A272626BC5F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {A7C339A4-CC00-2872-6005-A272626BC5F1}.Release|Any CPU.Build.0 = Release|Any CPU
        {A7C339A4-CC00-2872-6005-A272626BC5F1}.Release|x86.ActiveCfg = Release|x86
        {A7C339A4-CC00-2872-6005-A272626BC5F1}.Release|x86.Build.0 = Release|x86
    EndGlobalSection
    GlobalSection(SolutionProperties) = preSolution
        HideSolutionNode = FALSE
ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Inbound/InboundController.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using WIDESEA_Core;
using WIDESEA_DTO.CalcOut;
using WIDESEA_DTO.Inbound;
namespace WIDESEA_WMSServer.Controllers.Outbound
{
    [Route("api/[controller]")]
    [ApiController]
    public class InboundController : ControllerBase
    {
        private readonly WIDESEA_IInboundService.IInboundService Service;
        public InboundController(WIDESEA_IInboundService.IInboundService inboundService)
        {
            Service = inboundService;
        }
        /// <summary>
        /// ç»„盘
        /// </summary>
        /// <param name="palletDto"></param>
        /// <returns></returns>
        [HttpPost, Route("GroupPallet"), AllowAnonymous]
        public async Task<WebResponseContent> GroupPallet([FromBody]GroupPalletDto palletDto)
        {
            return await Service.GroupPallet(palletDto);
        }
    }
}