From b680585c3a6d43f0c72a83a115ea537ce8c91a07 Mon Sep 17 00:00:00 2001
From: 647556386 <647556386@qq.com>
Date: 星期六, 13 十二月 2025 17:44:10 +0800
Subject: [PATCH] Merge branch 'master' of http://115.159.85.185:8098/r/ZhongRui/ALDbanyunxiangmu

---
 项目资料/数据库字典/ALD_20251212105252.pdf                                                        |    0 
 项目代码/WIDESEA_WMSClient/src/views/stock/stockView.vue                                     |    2 
 项目代码/WIDESEA_WMSClient/src/extension/inbound/extend/EmptyTrayInbound.vue                 |   96 ++++-
 项目代码/WIDESEA_WMSClient/src/views/basic/locationInfo.vue                                  |    4 
 项目代码/WIDESEA_WMSClient/src/views/system/Log.vue                                          |  346 +++++++++++++++++++++
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_LogController.cs |  384 +++++++++++++++++++++++
 项目代码/WIDESEA_WMSClient/src/router/viewGird.js                                            |    8 
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs                    |  118 ++++---
 项目资料/数据库字典/WIDESEAWMS_ALDZhongRui.sql                                                    |    0 
 9 files changed, 880 insertions(+), 78 deletions(-)

diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/extension/inbound/extend/EmptyTrayInbound.vue" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/extension/inbound/extend/EmptyTrayInbound.vue"
index 7105202..d1914ac 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/extension/inbound/extend/EmptyTrayInbound.vue"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/extension/inbound/extend/EmptyTrayInbound.vue"
@@ -1,17 +1,17 @@
 <template>
     <vol-box v-model="show" title="绌烘墭鍏ュ簱" :width="800" :height="1200">
         <template #content>
-            <el-form ref="form" :model="form" label-width="90px">
-                <el-form-item label="鍏ュ簱鍖哄煙:">
+            <el-form ref="form" :model="form" :rules="rules" label-width="90px">
+                <el-form-item label="鍏ュ簱鍖哄煙:" prop="locationType">
                     <el-select v-model="form.locationType" placeholder="璇烽�夋嫨鍏ュ簱鍖哄煙">
                         <el-option v-for="item in locationTypes" :key="item.locationType" :label="item.locationTypeDesc"
                             :value="item.locationType" />
                     </el-select>
                 </el-form-item>
 
-                <el-form-item label="鎵樼洏鏉$爜:">
-                    <el-input v-model="form.palletCode" placeholder="璇锋壂鎻�/杈撳叆鎵樼洏鏉$爜" @keyup.enter="submit" @keyup.13="submit"
-                        clearable maxlength="50" @paste="handlePaste" @input="handleInput" ref="boxCodeInput" />
+                <el-form-item label="鎵樼洏鏉$爜:" prop="palletCode">
+                    <el-input v-model="form.palletCode" placeholder="璇锋壂鎻�/杈撳叆鎵樼洏鏉$爜锛圓寮�澶达紝鍚庤窡鏁板瓧锛�" @keyup.enter="submit" clearable
+                        @paste="handlePaste" @input="handleInput" ref="boxCodeInput" />
                 </el-form-item>
             </el-form>
         </template>
@@ -34,13 +34,37 @@
         value: { type: Boolean, default: false }
     },
     data() {
+        // 鑷畾涔夋潯鐮侀獙璇佽鍒�
+        const validatePalletCode = (rule, value, callback) => {
+            if (!value) {
+                return callback(new Error('璇疯緭鍏ユ墭鐩樻潯鐮�'));
+            }
+
+            // 楠岃瘉鏉$爜鏍煎紡锛欰寮�澶达紝鍚庨潰鑷冲皯1浣嶆暟瀛楋紙涓嶉檺鍒跺叿浣撻暱搴︼級
+            const codePattern = /^A\d+$/;
+            if (!codePattern.test(value)) {
+                return callback(new Error('鏉$爜鏍煎紡涓嶆纭紒姝g‘鏍煎紡锛欰寮�澶达紝鍚庤窡鏁板瓧锛屽锛欰000008080'));
+            }
+
+            callback();
+        };
+
         return {
             show: false,
             form: {
                 palletCode: '',
                 locationType: ''
             },
-            locationTypes: []
+            locationTypes: [],
+            // 琛ㄥ崟楠岃瘉瑙勫垯
+            rules: {
+                locationType: [
+                    { required: true, message: '璇烽�夋嫨鍏ュ簱鍖哄煙', trigger: 'change' }
+                ],
+                palletCode: [
+                    { validator: validatePalletCode, trigger: ['blur', 'change'] }
+                ]
+            }
         }
     },
     methods: {
@@ -62,15 +86,13 @@
         },
 
         async submit() {
-            if (!this.form.palletCode) {
-                this.$message.warning('璇疯緭鍏ユ墭鐩樻潯鐮�')
-                this.focusInput()
-                return
-            }
-
-            if (!this.form.locationType) {
-                this.$message.warning('璇烽�夋嫨鍏ュ簱鍖哄煙')
-                return
+            // 琛ㄥ崟楠岃瘉
+            try {
+                await this.$refs.form.validate();
+            } catch (error) {
+                // 楠岃瘉澶辫触锛岃仛鐒﹁緭鍏ユ
+                this.focusAndSelectInput();
+                return;
             }
 
             try {
@@ -88,6 +110,8 @@
                     this.$message.success("缁勭洏鎴愬姛");
                     // 娓呯┖杈撳叆妗嗘暟鎹�
                     this.form.palletCode = '';
+                    // 閲嶇疆楠岃瘉鐘舵��
+                    this.$refs.form.clearValidate('palletCode');
                     // 鑱氱劍骞堕�変腑杈撳叆妗�
                     this.focusAndSelectInput();
                 } else {
@@ -104,15 +128,39 @@
 
         // 鎵弿鏋紭鍖栧鐞�
         handleInput(value) {
-            // 杩囨护闈炴暟瀛楀拰鏉$爜甯哥敤瀛楃
-            this.form.palletCode = value.replace(/[^a-zA-Z0-9\-]/g, '')
+            // 杩囨护闈炴暟瀛楀拰鏉$爜甯哥敤瀛楃锛屽厑璁窤寮�澶�
+            this.form.palletCode = value.replace(/[^a-zA-Z0-9]/g, '')
+
+            // 鑷姩杞崲涓哄ぇ鍐欙紙鏉$爜閫氬父涓哄ぇ鍐欙級
+            this.form.palletCode = this.form.palletCode.toUpperCase();
+
+            // 鑷姩瑙﹀彂楠岃瘉
+            this.$nextTick(() => {
+                this.$refs.form.validateField('palletCode');
+            });
         },
 
         handlePaste(e) {
-            // 绮樿创鏃惰嚜鍔ㄦ彁浜�
-            setTimeout(this.submit, 100)
+            // 鑾峰彇绮樿创鐨勫唴瀹�
+            const clipboardData = e.clipboardData || window.clipboardData;
+            const pastedText = clipboardData.getData('text');
+
+            // 澶勭悊绮樿创鍐呭
+            const cleanedText = pastedText.replace(/[^a-zA-Z0-9]/g, '').toUpperCase();
+
+            // 濡傛灉绮樿创鍐呭绗﹀悎鏉$爜鏍煎紡锛岃嚜鍔ㄥ~鍏呭苟鎻愪氦
+            if (cleanedText.startsWith('A')) {
+                this.form.palletCode = cleanedText;
+                // 寤惰繜鎻愪氦锛岀‘淇濊〃鍗曞凡鏇存柊
+                setTimeout(() => {
+                    this.submit();
+                }, 50);
+            }
+
+            // 闃绘榛樿绮樿创琛屼负锛屼娇鐢ㄦ垜浠鐞嗗悗鐨勫��
+            e.preventDefault();
         },
-        
+
         // 鑱氱劍骞堕�変腑杈撳叆妗�
         focusAndSelectInput() {
             this.$nextTick(() => {
@@ -129,7 +177,7 @@
                 }, 100);
             });
         },
-        
+
         // 鍙仛鐒﹁緭鍏ユ锛堜笉娓呯┖鏁版嵁锛�
         focusInput() {
             this.$nextTick(() => {
@@ -140,10 +188,14 @@
                 }
             });
         },
-        
+
         // 娓呯┖琛ㄥ崟鏁版嵁
         clearForm() {
             this.form.palletCode = '';
+            // 閲嶇疆楠岃瘉鐘舵��
+            if (this.$refs.form) {
+                this.$refs.form.clearValidate();
+            }
             // 涓嶆竻绌� locationType锛屼繚鎸佸尯鍩熼�夋嫨
         }
     },
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/router/viewGird.js" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/router/viewGird.js"
index e4c2aca..5f34601 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/router/viewGird.js"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/router/viewGird.js"
@@ -227,7 +227,13 @@
     path:'/printForm',
     name: 'printForm',
     component: () => import('@/views/outbound/printForm.vue') 
-  },
+  },{
+    path: '/Log',
+    name: 'Log',
+    component: () => import('@/views/system/Log.vue'),
+    meta: {
+    }
+  }
 ]
 
 export default viewgird   
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/basic/locationInfo.vue" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/basic/locationInfo.vue"
index b6a588f..6237c87 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/basic/locationInfo.vue"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/basic/locationInfo.vue"
@@ -48,7 +48,7 @@
       [
         { title: "璐т綅缂栧彿", field: "locationCode", type: "like" },
         { title: "宸烽亾缂栧彿", field: "roadwayNo",type:"like" },
-        { title: "璐т綅绫诲瀷", field: "locationType",type: "select",dataKey: "locationTypeEnum",data: [], },
+        { title: "璐т綅鍖哄煙", field: "locationType",type: "select",dataKey: "locationTypeEnum",data: [], },
         { title: "绂佺敤鐘舵��", field: "enableStatus" ,type: "select",dataKey: "enableStatusEnum",data: [],},
       ],
       [
@@ -132,7 +132,7 @@
       },
       {
         field: "locationType",
-        title: "璐т綅绫诲瀷",
+        title: "璐т綅鍖哄煙",
         type: "string",
         width: 120,
         align: "left",
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/stock/stockView.vue" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/stock/stockView.vue"
index f208fc2..fe81dcc 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/stock/stockView.vue"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/stock/stockView.vue"
@@ -158,7 +158,7 @@
       },
       {
         field: "locationType",
-        title: "璐т綅绫诲瀷",
+        title: "璐т綅鍖哄煙",
         type: "string",
         width: 140,
         align: "left",
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/system/Log.vue" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/system/Log.vue"
new file mode 100644
index 0000000..1766626
--- /dev/null
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WIDESEA_WMSClient/src/views/system/Log.vue"
@@ -0,0 +1,346 @@
+<template>
+  <div class="tree-container">
+    <el-input placeholder="杈撳叆鍏抽敭瀛楄繘琛岃繃婊�" v-model="filterText" class="filter-input">
+    </el-input>
+    <div class="custom-tree-wrapper">
+      <el-tree ref="tree" class="filter-tree" :filter-node-method="filterNode" :data="data" node-key="id" accordion>
+        <template #default="{ node, data }">
+          <div class="custom-tree-node">
+            <span class="node-label">{{ node.label }}</span>
+            <span v-if="data.hidden" class="node-actions">
+              <el-button type="text" size="mini" @click="() => view(data)" class="action-btn">
+                鏌ョ湅
+              </el-button>
+              <el-button type="text" size="mini" @click="() => dowmload(node, data)" class="action-btn">
+                涓嬭浇
+              </el-button>
+            </span>
+          </div>
+        </template>
+      </el-tree>
+    </div>
+  </div>
+  <div class="log-container">
+    <el-card shadow="always" v-if="logName" class="log-card">
+      <template #header>
+        <div class="card-header">
+          <el-tag type="info" size="small">鏃ュ織鏂囦欢</el-tag>
+          <span class="log-title">{{ logName }}</span>
+        </div>
+      </template>
+      <div class="log-content">
+        <div v-for="(item, index) in log" :key="index" class="log-line">
+          <span class="line-number">{{ index + 1 }}</span>
+          <span class="line-content">{{ item }}</span>
+        </div>
+      </div>
+    </el-card>
+    <div v-else class="empty-log">
+      <el-empty description="璇烽�夋嫨鏃ュ織鏂囦欢杩涜鏌ョ湅" />
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      data: [],
+      defaultProps: {
+        children: "children",
+        label: "label",
+      },
+      filterText: "",
+      logName: "",
+      log: [],
+    };
+  },
+  watch: {
+    filterText(val) {
+      this.$refs.tree.filter(val);
+    },
+  },
+  created() {
+    this.getLogName();
+  },
+
+  methods: {
+    filterNode(value, data) {
+      if (!value) return true;
+      return data.label.indexOf(value) !== -1;
+    },
+    getLogName() {
+      this.http
+        .post("/api/Sys_Log/GetLogName", null, "姝e湪鎵ц涓�...")
+        .then((x) => {
+          if (x.status) {
+            this.data = x.data;
+          }
+        });
+    },
+
+    view(data) {
+      // var params = {
+      //   MainData: { fileName: data.label },
+      // };
+      this.http
+        .post("/api/Sys_Log/GetLog?fileName=" + data.label, "姝e湪鏌ヨ涓�...")
+        .then((x) => {
+          if (x.status) {
+            this.logName = data.label;
+            this.log = x.data;
+          }
+        });
+    },
+
+    dowmload(node, data) {
+      let ipAddress = this.http.ipAddress;
+      let url =
+        "api/Sys_Log/DownLoadLog?fileName=" +
+        data.fatherNode +
+        "\\" +
+        data.label;
+      let fileName = data.label;
+      let xmlResquest = new XMLHttpRequest();
+      xmlResquest.open("GET", ipAddress + url, true);
+      xmlResquest.setRequestHeader("Content-type", "application/json");
+      xmlResquest.setRequestHeader(
+        "Authorization",
+        this.$store.getters.getToken()
+      );
+      let elink = this.$refs.template;
+      xmlResquest.responseType = "blob";
+      let $_vue = this;
+      this.loadingStatus = true;
+      xmlResquest.onload = function (e) {
+        // 璇锋眰鎴愬姛
+        if (this.status == 200) {
+          let blob = this.response;
+          let a = document.createElement("a");
+          //window.URL.createObjectURL() 闈欐�佹柟娉曚細鍒涘缓涓�涓� DOMString锛屽叾涓寘鍚竴涓〃绀哄弬鏁颁腑缁欏嚭鐨勫璞$殑URL銆傝繖涓� URL 鐨勭敓鍛藉懆鏈熷拰鍒涘缓瀹冪殑绐楀彛涓殑 document 缁戝畾銆傝繖涓柊鐨刄RL 瀵硅薄琛ㄧず鎸囧畾鐨� File 瀵硅薄鎴� Blob 瀵硅薄銆�
+          let url = window.URL.createObjectURL(blob);
+          a.href = url;
+          a.download = fileName;
+          a.click();
+          //URL.revokeObjectURL() 闈欐�佹柟娉曠敤鏉ラ噴鏀句竴涓箣鍓嶅凡缁忓瓨鍦ㄧ殑銆侀�氳繃璋冪敤 URL.createObjectURL() 鍒涘缓鐨� URL 瀵硅薄銆傚綋浣犵粨鏉熶娇鐢ㄦ煇涓� URL 瀵硅薄涔嬪悗锛屽簲璇ラ�氳繃璋冪敤杩欎釜鏂规硶鏉ヨ娴忚鍣ㄧ煡閬撲笉鐢ㄥ湪鍐呭瓨涓户缁繚鐣欏杩欎釜鏂囦欢鐨勫紩鐢ㄤ簡銆�
+          window.URL.revokeObjectURL(url);
+
+        } else {
+          //涓嬭浇澶辫触澶勭悊
+
+        }
+      };
+      xmlResquest.send();
+    },
+  },
+};
+</script>
+
+<style scoped>
+.tree-container {
+  width: 30%;
+  float: left;
+  padding: 16px;
+  background: #f8f9fa;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.filter-input {
+  margin-bottom: 16px;
+}
+
+.filter-input :deep(.el-input__inner) {
+  border-radius: 20px;
+  border-color: #dcdfe6;
+  transition: all 0.3s;
+}
+
+.filter-input :deep(.el-input__inner):focus {
+  border-color: #409eff;
+  box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1);
+}
+
+.custom-tree-wrapper {
+  height: 760px;
+  overflow-y: auto;
+  padding: 8px;
+  background: white;
+  border-radius: 6px;
+  border: 1px solid #ebeef5;
+}
+
+.filter-tree :deep(.el-tree-node__content) {
+  height: 40px;
+  margin: 2px 0;
+  border-radius: 4px;
+  transition: all 0.2s;
+}
+
+.filter-tree :deep(.el-tree-node__content:hover) {
+  background-color: #f0f9ff;
+}
+
+.filter-tree :deep(.el-tree-node.is-current > .el-tree-node__content) {
+  background-color: #ecf5ff;
+  font-weight: 600;
+}
+
+.custom-tree-node {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  padding: 0 8px;
+}
+
+.node-label {
+  font-size: 14px;
+  color: #606266;
+  flex: 1;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.node-actions {
+  display: flex;
+  gap: 8px;
+  margin-left: 12px;
+}
+
+.action-btn {
+  padding: 4px 8px;
+  font-size: 12px;
+  color: #409eff;
+  border-radius: 3px;
+}
+
+.action-btn:hover {
+  background-color: rgba(64, 158, 255, 0.1);
+}
+
+.log-container {
+  width: 68%;
+  float: right;
+  padding: 16px;
+}
+
+.log-card {
+  height: 800px;
+  border-radius: 8px;
+  border: 1px solid #ebeef5;
+}
+
+.log-card :deep(.el-card__header) {
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  border-bottom: 1px solid #ebeef5;
+  padding: 16px 20px;
+}
+
+.card-header {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.log-title {
+  font-size: 16px;
+  font-weight: 600;
+  color: white;
+  flex: 1;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.log-content {
+  height: 700px;
+  overflow-y: auto;
+  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
+  background: #f8f9fa;
+  padding: 12px;
+  border-radius: 4px;
+}
+
+.log-line {
+  display: flex;
+  align-items: flex-start;
+  margin-bottom: 4px;
+  line-height: 1.5;
+  background: white;
+  padding: 8px 12px;
+  border-radius: 4px;
+  border-left: 3px solid #409eff;
+  transition: all 0.2s;
+}
+
+.log-line:hover {
+  background: #f0f9ff;
+  transform: translateX(2px);
+}
+
+.line-number {
+  display: inline-block;
+  min-width: 40px;
+  padding-right: 12px;
+  text-align: right;
+  color: #909399;
+  font-size: 12px;
+  user-select: none;
+}
+
+.line-content {
+  flex: 1;
+  color: #303133;
+  font-size: 13px;
+  word-break: break-all;
+  white-space: pre-wrap;
+}
+
+.empty-log {
+  height: 800px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: white;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.empty-log :deep(.el-empty__description) {
+  margin-top: 8px;
+}
+
+/* 婊氬姩鏉℃牱寮� */
+.custom-tree-wrapper::-webkit-scrollbar,
+.log-content::-webkit-scrollbar {
+  width: 6px;
+  height: 6px;
+}
+
+.custom-tree-wrapper::-webkit-scrollbar-track,
+.log-content::-webkit-scrollbar-track {
+  background: #f1f1f1;
+  border-radius: 3px;
+}
+
+.custom-tree-wrapper::-webkit-scrollbar-thumb,
+.log-content::-webkit-scrollbar-thumb {
+  background: #c1c1c1;
+  border-radius: 3px;
+}
+
+.custom-tree-wrapper::-webkit-scrollbar-thumb:hover,
+.log-content::-webkit-scrollbar-thumb:hover {
+  background: #a8a8a8;
+}
+
+/* 娓呴櫎娴姩 */
+.tree-container::after,
+.log-container::after {
+  content: "";
+  display: table;
+  clear: both;
+}
+</style>
\ No newline at end of file
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs"
index b65d4c3..eb77ed2 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs"
@@ -714,7 +714,7 @@
                     _logger.LogInformation($"InPickTaskCompleted AddLocationStatusChangeRecord : {ex.Message} ");
                 }
 
-                _logger.LogInformation($"鎵樼洏鍥炲簱瀹屾垚澶勭悊鎴愬姛 - 浠诲姟鍙�: {task.TaskNum}, 鎵樼洏: {task.PalletCode}, 璁㈠崟: {task.OrderNo}");
+                _logger.LogInformation($"鎵樼洏鍥炲簱瀹屾垚澶勭悊鎴愬姛 - 浠诲姟鍙�: {task.TaskNum}, 鎵樼洏: {task.PalletCode}, 璁㈠崟: {task.OrderNo} 璐т綅鐘舵�侊細{locationInfo.LocationStatus}");
                 _ = Task.Run(async () =>
                 {
                     try
@@ -1136,33 +1136,36 @@
 
                                 allocatefeedmodel.Details.Add(detailModel);
                             }
-                            var groupedResult = allocatefeedmodel.Details.GroupBy(item => new
-                            {
-                                item.WarehouseCode,
-                                item.MaterialCode,
-                                item.Unit,
-                                item.LineNo
-                            }).Select(group => new AllocateDtoDetail
-                            {
-                                 WarehouseCode = group.Key.WarehouseCode,
-                                 MaterialCode = group.Key.MaterialCode,
-                                 LineNo = group.Key.LineNo,                              
-                                 Qty = group.Sum(x => x.Qty),  
-                                 Unit = group.Key.Unit, 
-                                 Barcodes = group.SelectMany(x => x.Barcodes) 
-                                                       .GroupBy(b => b.Barcode) 
-                                                       .Select(b => new BarcodeInfo
-                                                       {
-                                                           Barcode = b.Key,
-                                                           BatchNo = b.First().BatchNo,
-                                                           SupplyCode = b.First().SupplyCode,
-                                                           Qty = b.Max(x => x.Qty), 
-                                                           Unit = b.First().Unit
-                                                       }) .ToList()
-                             }) .ToList();
+                            var groupedResult = allocatefeedmodel.Details
+                                .GroupBy(item => new { item.WarehouseCode, item.MaterialCode, item.Unit, item.LineNo })
+                                .Select(group =>
+                                {
+
+                                    var deduplicatedBarcodes = group.SelectMany(x => x.Barcodes)
+                                                                   .GroupBy(b => b.Barcode)
+                                                                   .Select(b => new BarcodeInfo
+                                                                   {
+                                                                       Barcode = b.Key,
+                                                                       BatchNo = b.First().BatchNo,
+                                                                       SupplyCode = b.First().SupplyCode,
+                                                                       Qty = b.Max(x => x.Qty),
+                                                                       Unit = b.First().Unit
+                                                                   }).ToList();
+                                    return new AllocateDtoDetail
+                                    {
+                                        WarehouseCode = group.Key.WarehouseCode,
+                                        MaterialCode = group.Key.MaterialCode,
+                                        LineNo = group.Key.LineNo,
+                                        Qty = deduplicatedBarcodes.Sum(b => b.Qty),
+                                        Unit = group.Key.Unit,
+                                        Barcodes = deduplicatedBarcodes
+                                    };
+                                }).ToList();
+
                             allocatefeedmodel.Details = groupedResult;
 
-                          var result = await _invokeMESService.FeedbackAllocate(allocatefeedmodel);
+
+                            var result = await _invokeMESService.FeedbackAllocate(allocatefeedmodel);
                             if (result != null && result.code == 200)
                             {
                                 await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
@@ -1175,6 +1178,19 @@
                                           ReturnToMESStatus = 1,
                                       }).Where(x => x.OrderNo == orderNo).ExecuteCommandAsync();
                             }
+                            else
+                            {
+                                await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>()
+                                 .SetColumns(x => x.ReturnToMESStatus == 2)
+                                 .Where(x => x.OrderId == outboundOrder.Id)
+                                 .ExecuteCommandAsync();
+
+                                await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>()
+                                    .SetColumns(it => new Dt_OutboundOrder { ReturnToMESStatus = 2, Remark = result.message })
+                                     .Where(x => x.OrderNo == orderNo)
+                                    .ExecuteCommandAsync();
+                            }
+
                         }
                     }
                     else if (outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt())
@@ -1247,30 +1263,32 @@
                                 }
                                 feedmodel.details.Add(detailModel);
                             }
-                            var groupedResult = feedmodel.details.GroupBy(item => new
-                            {
-                                item.warehouseCode,
-                                item.materialCode,
-                                item.unit,
-                                item.lineNo
-                            }).Select(group => new FeedbackOutboundDetailsModel
-                            {
-                                warehouseCode = group.Key.warehouseCode,
-                                materialCode = group.Key.materialCode,
-                                lineNo = group.Key.lineNo,
-                                qty = group.Sum(x => x.qty),
-                                unit = group.Key.unit,
-                                barcodes = group.SelectMany(x => x.barcodes)
-                                                       .GroupBy(b => b.barcode)
-                                                       .Select(b => new WIDESEA_DTO.Outbound.BarcodesModel
-                                                       {
-                                                           barcode = b.Key,
-                                                           batchNo = b.First().batchNo,
-                                                           supplyCode = b.First().supplyCode,
-                                                           qty = b.Max(x => x.qty),
-                                                           unit = b.First().unit
-                                                       }).ToList()
-                            }).ToList();
+
+                            var groupedResult = feedmodel.details
+                               .GroupBy(item => new { item.warehouseCode, item.materialCode, item.unit, item.lineNo })
+                               .Select(group =>
+                               {
+                                   var deduplicatedBarcodes = group.SelectMany(x => x.barcodes)
+                                                                  .GroupBy(b => b.barcode)
+                                                                  .Select(b => new WIDESEA_DTO.Outbound.BarcodesModel
+                                                                  {
+                                                                      barcode = b.Key,
+                                                                      batchNo = b.First().batchNo,
+                                                                      supplyCode = b.First().supplyCode,
+                                                                      qty = b.Max(x => x.qty),
+                                                                      unit = b.First().unit
+                                                                  }).ToList();
+                                   return new FeedbackOutboundDetailsModel
+                                   {
+                                       warehouseCode = group.Key.warehouseCode,
+                                       materialCode = group.Key.materialCode,
+                                       lineNo = group.Key.lineNo,
+                                       qty = deduplicatedBarcodes.Sum(b => b.qty),
+                                       unit = group.Key.unit,
+                                       barcodes = deduplicatedBarcodes
+                                   };
+                               }).ToList();
+
                             feedmodel.details = groupedResult;
 
                             var result = await _invokeMESService.FeedbackOutbound(feedmodel);
diff --git "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_LogController.cs" "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_LogController.cs"
index 3cd2f46..8fd6406 100644
--- "a/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_LogController.cs"
+++ "b/\351\241\271\347\233\256\344\273\243\347\240\201/WMS\346\227\240\344\273\223\345\202\250\347\211\210/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_LogController.cs"
@@ -1,5 +1,8 @@
-锘縰sing Microsoft.AspNetCore.Http;
+锘縰sing Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
+using System.Text;
+using WIDESEA_Core;
 using WIDESEA_Core.BaseController;
 using WIDESEA_ISystemService;
 using WIDESEA_Model.Models;
@@ -13,8 +16,385 @@
     [ApiController]
     public class Sys_LogController : ApiBaseController<ISys_LogService, Sys_Log>
     {
+        // 閰嶇疆甯搁噺
+        private const int MAX_FILE_SIZE_MB = 50;
+        private const int MAX_RETRY_COUNT = 3;
+        private const int RETRY_DELAY_MS = 100;
+        private static readonly string[] ALLOWED_FILE_TYPES = { ".txt", ".log", ".csv", ".json", ".xml" };
+
         public Sys_LogController(ISys_LogService service) : base(service)
         {
         }
+
+        [HttpPost, Route("GetLogName"), AllowAnonymous]
+        public WebResponseContent GetLogName()
+        {
+            WebResponseContent content = new WebResponseContent();
+            try
+            {
+                List<object> data = new List<object>();
+                DirectoryInfo folder = new DirectoryInfo(AppContext.BaseDirectory + "\\logs\\");
+                DirectoryInfo[] firstDirectoryInfos = folder.GetDirectories().OrderByDescending(x => x.CreationTime).ToArray();
+                int k = 2020;
+                for (int i = 0; i < firstDirectoryInfos.Length; i++)
+                {
+                    if (firstDirectoryInfos[i].Name != "Info")
+                    {
+                        FileInfo[] nextFileInfos = firstDirectoryInfos[i].GetFiles();
+                        List<object> values = new List<object>();
+                        for (int j = 0; j < nextFileInfos.Length; j++)
+                        {
+                            values.Add(new { label = nextFileInfos[j].Name, id = k, hidden = true, fatherNode = firstDirectoryInfos[i].Name });
+                            k++;
+                        }
+                        data.Add(new { label = firstDirectoryInfos[i].Name, children = values, id = i, hidden = false });
+                    }
+                }
+
+                FileInfo[] nextFileInfo = folder.GetFiles();
+                List<object> value = new List<object>();
+                for (int j = 0; j < nextFileInfo.Length; j++)
+                {
+                    value.Add(new { label = nextFileInfo[j].Name, id = k, hidden = true, fatherNode = folder.Name });
+                    k++;
+                }
+                data.Add(new { label = folder.Name, children = value, id = 1, hidden = false });
+
+                return WebResponseContent.Instance.OK(data: data);
+            }
+            catch (Exception ex)
+            {
+                return WebResponseContent.Instance.Error(ex.Message);
+            }
+        }
+
+        [HttpPost, Route("GetLog"), AllowAnonymous]
+        public WebResponseContent GetLog(string fileName)
+        {
+            WebResponseContent content = new WebResponseContent();
+            try
+            {
+                List<FileInfo> files = new List<FileInfo>();
+                DirectoryInfo folder = new DirectoryInfo(AppContext.BaseDirectory + "\\logs\\");
+                DirectoryInfo[] firstDirectoryInfos = folder.GetDirectories();
+                for (int i = 0; i < firstDirectoryInfos.Length; i++)
+                {
+                    FileInfo[] nextFileInfos = firstDirectoryInfos[i].GetFiles();
+                    files.AddRange(nextFileInfos);
+                }
+
+                FileInfo[] nextFileInfo = folder.GetFiles();
+                files.AddRange(nextFileInfo);
+                if (files.Count > 0)
+                {
+                    FileInfo file = files.Where(x => x.Name == fileName).FirstOrDefault();
+                    if (file == null)
+                    {
+                        return WebResponseContent.Instance.Error($"鏈壘鍒版棩蹇楁枃浠�: {fileName}");
+                    }
+
+                    // 浣跨敤鍏变韩璇诲彇妯″紡
+                    using (FileStream stream = new FileStream(
+                        file.FullName,
+                        FileMode.Open,
+                        FileAccess.Read,
+                        FileShare.ReadWrite))
+                    using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
+                    {
+                        StringBuilder text = new StringBuilder();
+                        List<string> lines = new List<string>();
+                        while (!reader.EndOfStream)
+                        {
+                            var line = reader.ReadLine();
+                            lines.Add(line);
+                        }
+
+                        content = WebResponseContent.Instance.OK(data: lines);
+                    }
+                }
+                else
+                {
+                    content = WebResponseContent.Instance.Error($"鏈壘鍒版棩蹇楁枃浠�,銆恵fileName}銆�");
+                }
+            }
+            catch (IOException ex)
+            {
+                if (IsFileLockedException(ex))
+                {
+                    content = WebResponseContent.Instance.Error($"鏃ュ織鏂囦欢姝e湪琚郴缁熷啓鍏ワ紝璇风◢鍚庡啀璇�");
+                }
+                else
+                {
+                    content = WebResponseContent.Instance.Error($"鎵撳紑鏃ュ織鏂囦欢閿欒,{ex.Message}");
+                }
+            }
+            catch (Exception ex)
+            {
+                content = WebResponseContent.Instance.Error($"鎵撳紑鏃ュ織鏂囦欢閿欒,{ex.Message}");
+            }
+            return content;
+        }
+
+        [HttpPost, HttpGet, Route("DownLoadLog"), AllowAnonymous]
+        public virtual async Task<ActionResult> DownLoadLog(string fileName)
+        {
+            try
+            {
+                // 1. 鍙傛暟楠岃瘉
+                if (string.IsNullOrWhiteSpace(fileName))
+                {
+                    return BadRequest("鏂囦欢鍚嶄笉鑳戒负绌�");
+                }
+
+                // 瀹夊叏鎬ф鏌ワ細闃叉璺緞閬嶅巻鏀诲嚮
+                if (fileName.Contains("..") || Path.IsPathRooted(fileName))
+                {
+                    return BadRequest("鏃犳晥鐨勬枃浠跺悕");
+                }
+
+                //string logDirectory = Path.Combine(AppContext.BaseDirectory, "logs");
+                string logDirectory = Path.Combine(AppContext.BaseDirectory);
+
+                if (!Directory.Exists(logDirectory))
+                {
+                    Directory.CreateDirectory(logDirectory);
+                }
+
+                string filePath = Path.Combine(logDirectory, fileName);
+
+                if (Directory.Exists(filePath))
+                {
+                    return NotFound($"鏂囦欢 {fileName} 涓嶅瓨鍦�");
+                }
+
+                string extension = Path.GetExtension(fileName).ToLowerInvariant();
+                if (!IsAllowedFileType(extension))
+                {
+                    return BadRequest($"涓嶆敮鎸佺殑鏂囦欢绫诲瀷: {extension}");
+                }
+
+                FileInfo fileInfo = new FileInfo(filePath);
+
+                if (fileInfo.Length > MAX_FILE_SIZE_MB * 1024 * 1024)
+                {
+                    return BadRequest($"鏂囦欢杩囧ぇ锛岃秴杩噞MAX_FILE_SIZE_MB}MB闄愬埗");
+                }
+
+                // 鏂规1锛氫娇鐢ㄩ噸璇曟満鍒� + 鍏变韩璇诲彇锛堟帹鑽愶級
+                byte[] fileBytes = await ReadFileWithRetryAsync(filePath);
+
+                if (fileBytes == null)
+                {
+                    return StatusCode(500, "鏂囦欢琚崰鐢紝鏃犳硶涓嬭浇锛岃绋嶅悗閲嶈瘯");
+                }
+
+                string contentType = GetContentType(extension);
+
+                // 璁剧疆涓嬭浇澶�
+                Response.Headers.Add("Content-Disposition", $"attachment; filename=\"{System.Web.HttpUtility.UrlEncode(fileName, Encoding.UTF8)}\"");
+                Response.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate");
+                Response.Headers.Add("Pragma", "no-cache");
+                Response.Headers.Add("Expires", "0");
+
+                return File(fileBytes, contentType, fileName);
+            }
+            catch (UnauthorizedAccessException)
+            {
+                return StatusCode(403, "娌℃湁璁块棶璇ユ枃浠剁殑鏉冮檺");
+            }
+            catch (PathTooLongException)
+            {
+                return BadRequest("鏂囦欢璺緞杩囬暱");
+            }
+            catch (IOException ex)
+            {
+                if (IsFileLockedException(ex))
+                {
+                    return StatusCode(500, "鏂囦欢琚攣瀹氾紝鍙兘姝e湪琚郴缁熷啓鍏ワ紝璇风◢鍚庡啀璇�");
+                }
+                return StatusCode(500, $"鏂囦欢璇诲彇澶辫触: {ex.Message}");
+            }
+            catch (Exception ex)
+            {
+                // 璁板綍寮傚父鏃ュ織锛堣繖閲岀畝鍖栦负杩斿洖锛屽疄闄呴」鐩腑搴旇璁板綍鍒版棩蹇楃郴缁燂級
+                return StatusCode(500, $"鏈嶅姟鍣ㄥ唴閮ㄩ敊璇�: {ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 甯﹂噸璇曟満鍒剁殑鏂囦欢璇诲彇鏂规硶
+        /// </summary>
+        private async Task<byte[]> ReadFileWithRetryAsync(string filePath)
+        {
+            for (int attempt = 0; attempt < MAX_RETRY_COUNT; attempt++)
+            {
+                try
+                {
+                    // 浣跨敤 FileShare.ReadWrite 鍏佽鍏朵粬杩涚▼鍚屾椂璇诲彇鍜屽啓鍏�
+                    // 浣跨敤寮傛璇诲彇鎻愰珮鎬ц兘
+                    using (var fileStream = new FileStream(
+                        filePath,
+                        FileMode.Open,
+                        FileAccess.Read,
+                        FileShare.ReadWrite | FileShare.Delete, // 鍏佽鍒犻櫎鎿嶄綔
+                        bufferSize: 4096,
+                        useAsync: true))
+                    {
+                        using (var memoryStream = new MemoryStream())
+                        {
+                            await fileStream.CopyToAsync(memoryStream);
+                            return memoryStream.ToArray();
+                        }
+                    }
+                }
+                catch (IOException) when (attempt < MAX_RETRY_COUNT - 1)
+                {
+                    // 濡傛灉涓嶆槸鏈�鍚庝竴娆¢噸璇曪紝绛夊緟涓�娈垫椂闂�
+                    await Task.Delay(RETRY_DELAY_MS * (attempt + 1));
+                }
+                catch (IOException ex)
+                {
+                    // 鏈�鍚庝竴娆″皾璇曚篃澶辫触浜�
+                    throw;
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// 鍒ゆ柇鏄惁涓烘枃浠惰閿佸畾鐨勫紓甯�
+        /// </summary>
+        private bool IsFileLockedException(IOException ex)
+        {
+            int errorCode = ex.HResult & 0xFFFF;
+            return errorCode == 32 || errorCode == 33; // ERROR_SHARING_VIOLATION or ERROR_LOCK_VIOLATION
+        }
+
+        /// <summary>
+        /// 妫�鏌ユ枃浠剁被鍨嬫槸鍚﹀厑璁�
+        /// </summary>
+        private bool IsAllowedFileType(string extension)
+        {
+            return ALLOWED_FILE_TYPES.Contains(extension);
+        }
+
+        /// <summary>
+        /// 鑾峰彇Content-Type
+        /// </summary>
+        private string GetContentType(string extension)
+        {
+            return extension.ToLowerInvariant() switch
+            {
+                ".txt" => "text/plain; charset=utf-8",
+                ".log" => "text/plain; charset=utf-8",
+                ".csv" => "text/csv; charset=utf-8",
+                ".json" => "application/json; charset=utf-8",
+                ".xml" => "application/xml; charset=utf-8",
+                _ => "application/octet-stream"
+            };
+        }
+
+        /// <summary>
+        /// 澶囬�夋柟妗堬細鍒涘缓涓存椂鍓湰涓嬭浇锛堟渶瀹夊叏锛屼絾鎬ц兘绋嶅樊锛�
+        /// </summary>
+        [HttpPost, HttpGet, Route("DownLoadLogCopy"), AllowAnonymous]
+        public virtual async Task<ActionResult> DownLoadLogCopy(string fileName)
+        {
+            try
+            {
+                // 鍙傛暟楠岃瘉锛堝悓涓婏級
+                if (string.IsNullOrWhiteSpace(fileName))
+                {
+                    return BadRequest("鏂囦欢鍚嶄笉鑳戒负绌�");
+                }
+
+                string logDirectory = Path.Combine(AppContext.BaseDirectory, "logs");
+                string filePath = Path.Combine(logDirectory, fileName);
+
+                if (Directory.Exists(filePath))
+                {
+                    return NotFound($"鏂囦欢 {fileName} 涓嶅瓨鍦�");
+                }
+
+                // 鐢熸垚涓存椂鏂囦欢鍚�
+                string tempFileName = $"{Path.GetFileNameWithoutExtension(fileName)}_{Guid.NewGuid():N}{Path.GetExtension(fileName)}";
+                string tempFilePath = Path.Combine(Path.GetTempPath(), tempFileName);
+
+                try
+                {
+                    // 灏濊瘯澶嶅埗鏂囦欢鍒颁复鏃朵綅缃紙浣跨敤閲嶈瘯鏈哄埗锛�
+                    bool copySuccess = false;
+                    for (int attempt = 0; attempt < MAX_RETRY_COUNT; attempt++)
+                    {
+                        try
+                        {
+                            //Directory.GetFiles.Copy(filePath, tempFilePath, false);
+                            copySuccess = true;
+                            break;
+                        }
+                        catch (IOException) when (attempt < MAX_RETRY_COUNT - 1)
+                        {
+                            await Task.Delay(RETRY_DELAY_MS * (attempt + 1));
+                        }
+                    }
+
+                    if (!copySuccess)
+                    {
+                        return StatusCode(500, "鏃犳硶澶嶅埗鏂囦欢锛屽彲鑳借鍏朵粬杩涚▼鍗犵敤");
+                    }
+
+                    // 浠庝复鏃舵枃浠惰鍙�
+                    byte[] fileBytes;
+                    using (FileStream tempStream = new FileStream(tempFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
+                    {
+                        using (MemoryStream memoryStream = new MemoryStream())
+                        {
+                            await tempStream.CopyToAsync(memoryStream);
+                            fileBytes = memoryStream.ToArray();
+                        }
+                    }
+
+                    string extension = Path.GetExtension(fileName).ToLowerInvariant();
+                    string contentType = GetContentType(extension);
+
+                    // 杩斿洖鏂囦欢鍚庢竻鐞嗕复鏃舵枃浠�
+                    var result = File(fileBytes, contentType, fileName);
+
+                    // 寮傛娓呯悊涓存椂鏂囦欢
+                    _ = Task.Run(() =>
+                    {
+                        try
+                        {
+                            Directory.Delete(tempFilePath);
+                        }
+                        catch
+                        {
+                            // 蹇界暐鍒犻櫎澶辫触
+                        }
+                    });
+
+                    return result;
+                }
+                finally
+                {
+                    // 纭繚涓存椂鏂囦欢琚竻鐞�
+                    if (Directory.Exists(tempFilePath))
+                    {
+                        try
+                        {
+                            Directory.Delete(tempFilePath);
+                        }
+                        catch
+                        {
+                            // 蹇界暐鍒犻櫎澶辫触
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                return StatusCode(500, $"鏈嶅姟鍣ㄥ唴閮ㄩ敊璇�: {ex.Message}");
+            }
+        }
     }
-}
+}
\ No newline at end of file
diff --git "a/\351\241\271\347\233\256\350\265\204\346\226\231/\346\225\260\346\215\256\345\272\223\345\255\227\345\205\270/ALD_20251212105252.pdf" "b/\351\241\271\347\233\256\350\265\204\346\226\231/\346\225\260\346\215\256\345\272\223\345\255\227\345\205\270/ALD_20251212105252.pdf"
new file mode 100644
index 0000000..87a9c8e
--- /dev/null
+++ "b/\351\241\271\347\233\256\350\265\204\346\226\231/\346\225\260\346\215\256\345\272\223\345\255\227\345\205\270/ALD_20251212105252.pdf"
Binary files differ
diff --git "a/\351\241\271\347\233\256\350\265\204\346\226\231/\346\225\260\346\215\256\345\272\223\345\255\227\345\205\270/WIDESEAWMS_ALDZhongRui.sql" "b/\351\241\271\347\233\256\350\265\204\346\226\231/\346\225\260\346\215\256\345\272\223\345\255\227\345\205\270/WIDESEAWMS_ALDZhongRui.sql"
new file mode 100644
index 0000000..ce7350c
--- /dev/null
+++ "b/\351\241\271\347\233\256\350\265\204\346\226\231/\346\225\260\346\215\256\345\272\223\345\255\227\345\205\270/WIDESEAWMS_ALDZhongRui.sql"
Binary files differ

--
Gitblit v1.9.3