From 9ce02d17cafc6b8dab49b16fa20fdca4c978bb5b Mon Sep 17 00:00:00 2001
From: huangxiaoqiang <huangxiaoqiang@hnkhzn.com>
Date: 星期六, 13 十二月 2025 09:33:30 +0800
Subject: [PATCH] 新增文本日志Web端显示

---
 项目代码/WIDESEA_WMSClient/src/views/system/Log.vue                                          |  346 ++++++++++++++++++++++++++++++++++++++
 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_LogController.cs |  178 +++++++++++++++++++
 项目代码/WIDESEA_WMSClient/src/router/viewGird.js                                            |    8 
 3 files changed, 530 insertions(+), 2 deletions(-)

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/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_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..3a72445 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;
@@ -16,5 +19,178 @@
         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();
+                    using StreamReader stream = new StreamReader(file.FullName);
+                    StringBuilder text = new StringBuilder();
+                    List<string> lines = new List<string>();
+                    int i = 0;
+                    while (stream.Peek() >= 0)
+                    {
+                        var line = stream.ReadLine();
+                        lines.Add(line);
+                    }
+
+                    content = WebResponseContent.Instance.OK(data: lines);
+                }
+                else
+                {
+                    content = WebResponseContent.Instance.Error($"鏈壘鍒版棩蹇楁枃浠�,銆恵fileName}銆�");
+                }
+            }
+            catch (Exception ex)
+            {
+                content = WebResponseContent.Instance.Error($"鎵撳紑鏃ュ織鏂囦欢閿欒,{ex.Message}");
+            }
+            return content;
+        }
+        [HttpPost, HttpGet, Route("DownLoadLog"), AllowAnonymous]
+        public virtual ActionResult DownLoadLog(string fileName)
+        {
+            try
+            {
+                // 1. 鍙傛暟楠岃瘉
+                if (string.IsNullOrWhiteSpace(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 > 50 * 1024 * 1024) // 50MB闄愬埗
+                {
+                    return BadRequest("鏂囦欢杩囧ぇ锛屾棤娉曚笅杞�");
+                }
+
+                byte[] fileBytes;
+                using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
+                {
+                    using (MemoryStream memoryStream = new MemoryStream())
+                    {
+                        fileStream.CopyTo(memoryStream);
+                        fileBytes = memoryStream.ToArray();
+                    }
+                }
+
+                string contentType = GetContentType(extension);
+
+                return File(fileBytes, contentType, fileName);
+            }
+            catch (UnauthorizedAccessException)
+            {
+                return StatusCode(403, "娌℃湁璁块棶璇ユ枃浠剁殑鏉冮檺");
+            }
+            catch (PathTooLongException)
+            {
+                return BadRequest("鏂囦欢璺緞杩囬暱");
+            }
+            catch (IOException ex)
+            {
+                return StatusCode(500, "鏂囦欢璇诲彇澶辫触锛屽彲鑳芥鍦ㄨ鍏朵粬杩涚▼浣跨敤");
+            }
+            catch (Exception ex)
+            {
+                return StatusCode(500, $"鏈嶅姟鍣ㄥ唴閮ㄩ敊璇�: {ex.Message}");
+            }
+        }
+        private bool IsAllowedFileType(string extension)
+        {
+            var allowedTypes = new[] { ".txt", ".log", ".csv", ".json", ".xml" };
+            return allowedTypes.Contains(extension);
+        }
+
+        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"
+            };
+        }
     }
 }

--
Gitblit v1.9.3