| 项目代码/WIDESEA_WMSClient/src/router/viewGird.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| 项目代码/WIDESEA_WMSClient/src/views/system/Log.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| 项目代码/WMS无仓储版/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_LogController.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
ÏîÄ¿´úÂë/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 ÏîÄ¿´úÂë/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, "æ£å¨æ§è¡ä¸...") .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, "æ£å¨æ¥è¯¢ä¸...") .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 ç»å®ãè¿ä¸ªæ°çURL 对象表示æå®ç 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> ÏîÄ¿´úÂë/WMSÎÞ²Ö´¢°æ/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/System/Sys_LogController.cs
@@ -1,5 +1,8 @@ using Microsoft.AspNetCore.Http; using 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" }; } } }