diff --git a/Controllers/LogsController.cs b/Controllers/LogsController.cs index cb2a0ae..2ad199a 100644 --- a/Controllers/LogsController.cs +++ b/Controllers/LogsController.cs @@ -12,12 +12,12 @@ namespace dy.net.Controllers public class LogsController : ControllerBase { private readonly IWebHostEnvironment webHostEnvironment; - private readonly DouyinHttpClientService douyinHttpClientService; + private readonly LogInfoService logInfoService; - public LogsController(IWebHostEnvironment webHostEnvironment,DouyinHttpClientService douyinHttpClientService) + public LogsController(IWebHostEnvironment webHostEnvironment,LogInfoService logInfoService) { this.webHostEnvironment = webHostEnvironment; - this.douyinHttpClientService = douyinHttpClientService; + this.logInfoService = logInfoService; } [HttpGet] @@ -38,5 +38,59 @@ namespace dy.net.Controllers //var fileContent = encoding.GetString(fileBytes); //return Content (fileContent, "text/plain", encoding); } + + + + + /// + /// 获取最近10天的日志文件列表 + /// + [HttpGet("/api/logs/list")] + public IActionResult GetLogFiles() + { + try + { + var _logDirectory = Path.Combine(Directory.GetCurrentDirectory(), "logs"); + var files = logInfoService.GetLogFiles(_logDirectory); + return Ok(new {code=0,data=files}); + } + catch (Exception ex) + { + return StatusCode(500, new { message = "获取日志列表失败", error = ex.Message }); + } + } + + + + /// + /// 获取日志文件内容流 + /// + [HttpGet("/api/logs/content")] + public IActionResult GetLogContent([FromQuery] LogContentRequest request) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + try + { + var _logDirectory = Path.Combine(Directory.GetCurrentDirectory(), "logs"); + var stream = logInfoService.GetLogFileStream(_logDirectory, request.Type, request.Date); + // 返回文件流,指定MIME类型为文本 + return File(stream, "text/plain", $"log-{request.Type}-{request.Date}.txt"); + } + catch (FileNotFoundException ex) + { + return NotFound(new { message = ex.Message }); + } + catch (ArgumentException ex) + { + return BadRequest(new { message = ex.Message }); + } + catch (Exception ex) + { + return StatusCode(500, new { message = "读取日志文件失败", error = ex.Message }); + } + } } } diff --git a/Properties/PublishProfiles/FolderProfile.pubxml.user b/Properties/PublishProfiles/FolderProfile.pubxml.user index 3509475..cd69bc6 100644 --- a/Properties/PublishProfiles/FolderProfile.pubxml.user +++ b/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -5,7 +5,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. <_PublishTargetUrl>E:\code\dysync\bin\Release\net6.0\publish\ - True|2025-12-08T13:20:37.8369271Z||;False|2025-12-08T21:20:21.1646252+08:00||;True|2025-12-08T20:51:50.6845619+08:00||;True|2025-12-08T16:43:45.2425324+08:00||;False|2025-12-08T16:42:23.0308163+08:00||;True|2025-12-08T16:41:52.4103868+08:00||;True|2025-12-08T16:41:49.8972006+08:00||;False|2025-12-08T16:41:39.5343442+08:00||;True|2025-12-08T12:40:19.2430740+08:00||;True|2025-12-08T12:02:30.6005542+08:00||;True|2025-12-08T11:34:29.6673185+08:00||;False|2025-12-08T11:30:56.2857042+08:00||;True|2025-12-08T10:52:43.7427594+08:00||;True|2025-12-08T07:05:03.2845531+08:00||;True|2025-12-07T23:02:10.0037815+08:00||;True|2025-12-07T22:48:25.7859648+08:00||;True|2025-12-07T20:49:13.6683281+08:00||;True|2025-12-07T08:47:30.1236366+08:00||;True|2025-12-06T13:14:32.4410202+08:00||;True|2025-12-06T13:07:29.7182102+08:00||;True|2025-12-06T13:05:46.2855366+08:00||;False|2025-12-06T13:05:40.3550904+08:00||;True|2025-12-06T13:03:47.8773880+08:00||;True|2025-12-06T13:03:28.9521030+08:00||;True|2025-12-05T23:11:51.5026151+08:00||;True|2025-12-05T12:46:26.1415079+08:00||;False|2025-12-05T12:46:19.1274332+08:00||;True|2025-12-05T09:04:36.7111717+08:00||;True|2025-12-05T08:22:51.7343317+08:00||;True|2025-12-05T08:20:32.0383739+08:00||;True|2025-12-04T21:58:29.4112766+08:00||;True|2025-12-04T21:58:10.0382218+08:00||;True|2025-12-04T21:57:55.3894059+08:00||;True|2025-12-04T21:10:38.8943797+08:00||;True|2025-12-04T21:09:31.5024569+08:00||;True|2025-12-04T08:22:47.9617427+08:00||;False|2025-12-04T08:22:41.3759733+08:00||;True|2025-12-04T08:14:02.2478893+08:00||;True|2025-12-04T07:57:00.2208139+08:00||;True|2025-12-03T23:58:13.3693303+08:00||;True|2025-12-03T23:57:40.4257893+08:00||;True|2025-12-03T23:56:38.8717769+08:00||;True|2025-12-03T23:56:24.0663568+08:00||;False|2025-12-03T23:55:36.1902974+08:00||;True|2025-12-03T23:51:30.6688504+08:00||;True|2025-12-03T23:34:17.1648971+08:00||;False|2025-12-03T23:34:07.7649161+08:00||;True|2025-12-03T22:32:56.2435003+08:00||;True|2025-12-03T22:27:45.6059666+08:00||;True|2025-12-03T15:55:28.0186597+08:00||;False|2025-12-03T15:54:17.5032724+08:00||;True|2025-12-03T15:53:10.2273509+08:00||;True|2025-12-02T22:11:37.4645042+08:00||;False|2025-12-02T22:10:47.1320259+08:00||;True|2025-12-02T14:39:58.8932130+08:00||;True|2025-12-02T14:36:37.1529072+08:00||;True|2025-12-02T12:58:22.0951548+08:00||;True|2025-12-02T09:30:33.7066474+08:00||;True|2025-12-02T09:30:14.5481844+08:00||;True|2025-12-02T09:30:00.3123364+08:00||;False|2025-12-02T09:29:54.4615520+08:00||;True|2025-12-02T09:13:01.7995414+08:00||;False|2025-12-02T09:12:55.8360281+08:00||;True|2025-12-02T09:12:31.0156791+08:00||;True|2025-12-02T08:55:11.3773395+08:00||;True|2025-12-02T08:53:21.3927713+08:00||;False|2025-12-02T08:48:55.8638037+08:00||;True|2025-12-02T07:29:25.2192447+08:00||;False|2025-12-02T07:29:10.2504665+08:00||;True|2025-12-02T07:28:29.0769286+08:00||;True|2025-12-01T21:53:07.6474834+08:00||;True|2025-12-01T21:44:28.1674315+08:00||;True|2025-12-01T21:18:47.2119609+08:00||;True|2025-12-01T20:51:19.9948301+08:00||;True|2025-12-01T20:50:36.9904697+08:00||;True|2025-12-01T20:44:10.1695142+08:00||;True|2025-12-01T19:27:58.0479456+08:00||;True|2025-12-01T19:16:02.2288214+08:00||;False|2025-12-01T19:15:56.0372115+08:00||;True|2025-12-01T19:15:16.4854821+08:00||;False|2025-12-01T19:15:06.7001019+08:00||;True|2025-12-01T17:10:38.9739466+08:00||;False|2025-12-01T17:10:18.8928139+08:00||;True|2025-12-01T17:03:59.3171589+08:00||;True|2025-12-01T17:03:12.5681656+08:00||;True|2025-12-01T16:42:51.4415025+08:00||;True|2025-12-01T01:29:59.6975567+08:00||;True|2025-12-01T01:29:45.1898652+08:00||;False|2025-12-01T01:29:33.1787721+08:00||;True|2025-12-01T01:27:33.1297605+08:00||;True|2025-12-01T01:27:27.3976862+08:00||;False|2025-12-01T01:27:20.5193052+08:00||;True|2025-12-01T01:11:11.0210582+08:00||;True|2025-12-01T01:04:04.3307782+08:00||;True|2025-12-01T00:55:49.8018864+08:00||;True|2025-12-01T00:27:25.1323561+08:00||;True|2025-11-30T23:58:20.7284116+08:00||;True|2025-11-30T23:57:58.3027622+08:00||;True|2025-11-30T23:57:43.0829614+08:00||;False|2025-11-30T23:57:33.5606716+08:00||; + True|2025-12-11T14:07:16.6229994Z||;True|2025-12-11T22:05:56.7363206+08:00||;True|2025-12-11T22:01:07.5862406+08:00||;True|2025-12-11T22:00:43.5796594+08:00||;True|2025-12-08T21:20:37.8369271+08:00||;False|2025-12-08T21:20:21.1646252+08:00||;True|2025-12-08T20:51:50.6845619+08:00||;True|2025-12-08T16:43:45.2425324+08:00||;False|2025-12-08T16:42:23.0308163+08:00||;True|2025-12-08T16:41:52.4103868+08:00||;True|2025-12-08T16:41:49.8972006+08:00||;False|2025-12-08T16:41:39.5343442+08:00||;True|2025-12-08T12:40:19.2430740+08:00||;True|2025-12-08T12:02:30.6005542+08:00||;True|2025-12-08T11:34:29.6673185+08:00||;False|2025-12-08T11:30:56.2857042+08:00||;True|2025-12-08T10:52:43.7427594+08:00||;True|2025-12-08T07:05:03.2845531+08:00||;True|2025-12-07T23:02:10.0037815+08:00||;True|2025-12-07T22:48:25.7859648+08:00||;True|2025-12-07T20:49:13.6683281+08:00||;True|2025-12-07T08:47:30.1236366+08:00||;True|2025-12-06T13:14:32.4410202+08:00||;True|2025-12-06T13:07:29.7182102+08:00||;True|2025-12-06T13:05:46.2855366+08:00||;False|2025-12-06T13:05:40.3550904+08:00||;True|2025-12-06T13:03:47.8773880+08:00||;True|2025-12-06T13:03:28.9521030+08:00||;True|2025-12-05T23:11:51.5026151+08:00||;True|2025-12-05T12:46:26.1415079+08:00||;False|2025-12-05T12:46:19.1274332+08:00||;True|2025-12-05T09:04:36.7111717+08:00||;True|2025-12-05T08:22:51.7343317+08:00||;True|2025-12-05T08:20:32.0383739+08:00||;True|2025-12-04T21:58:29.4112766+08:00||;True|2025-12-04T21:58:10.0382218+08:00||;True|2025-12-04T21:57:55.3894059+08:00||;True|2025-12-04T21:10:38.8943797+08:00||;True|2025-12-04T21:09:31.5024569+08:00||;True|2025-12-04T08:22:47.9617427+08:00||;False|2025-12-04T08:22:41.3759733+08:00||;True|2025-12-04T08:14:02.2478893+08:00||;True|2025-12-04T07:57:00.2208139+08:00||;True|2025-12-03T23:58:13.3693303+08:00||;True|2025-12-03T23:57:40.4257893+08:00||;True|2025-12-03T23:56:38.8717769+08:00||;True|2025-12-03T23:56:24.0663568+08:00||;False|2025-12-03T23:55:36.1902974+08:00||;True|2025-12-03T23:51:30.6688504+08:00||;True|2025-12-03T23:34:17.1648971+08:00||;False|2025-12-03T23:34:07.7649161+08:00||;True|2025-12-03T22:32:56.2435003+08:00||;True|2025-12-03T22:27:45.6059666+08:00||;True|2025-12-03T15:55:28.0186597+08:00||;False|2025-12-03T15:54:17.5032724+08:00||;True|2025-12-03T15:53:10.2273509+08:00||;True|2025-12-02T22:11:37.4645042+08:00||;False|2025-12-02T22:10:47.1320259+08:00||;True|2025-12-02T14:39:58.8932130+08:00||;True|2025-12-02T14:36:37.1529072+08:00||;True|2025-12-02T12:58:22.0951548+08:00||;True|2025-12-02T09:30:33.7066474+08:00||;True|2025-12-02T09:30:14.5481844+08:00||;True|2025-12-02T09:30:00.3123364+08:00||;False|2025-12-02T09:29:54.4615520+08:00||;True|2025-12-02T09:13:01.7995414+08:00||;False|2025-12-02T09:12:55.8360281+08:00||;True|2025-12-02T09:12:31.0156791+08:00||;True|2025-12-02T08:55:11.3773395+08:00||;True|2025-12-02T08:53:21.3927713+08:00||;False|2025-12-02T08:48:55.8638037+08:00||;True|2025-12-02T07:29:25.2192447+08:00||;False|2025-12-02T07:29:10.2504665+08:00||;True|2025-12-02T07:28:29.0769286+08:00||;True|2025-12-01T21:53:07.6474834+08:00||;True|2025-12-01T21:44:28.1674315+08:00||;True|2025-12-01T21:18:47.2119609+08:00||;True|2025-12-01T20:51:19.9948301+08:00||;True|2025-12-01T20:50:36.9904697+08:00||;True|2025-12-01T20:44:10.1695142+08:00||;True|2025-12-01T19:27:58.0479456+08:00||;True|2025-12-01T19:16:02.2288214+08:00||;False|2025-12-01T19:15:56.0372115+08:00||;True|2025-12-01T19:15:16.4854821+08:00||;False|2025-12-01T19:15:06.7001019+08:00||;True|2025-12-01T17:10:38.9739466+08:00||;False|2025-12-01T17:10:18.8928139+08:00||;True|2025-12-01T17:03:59.3171589+08:00||;True|2025-12-01T17:03:12.5681656+08:00||;True|2025-12-01T16:42:51.4415025+08:00||;True|2025-12-01T01:29:59.6975567+08:00||;True|2025-12-01T01:29:45.1898652+08:00||;False|2025-12-01T01:29:33.1787721+08:00||;True|2025-12-01T01:27:33.1297605+08:00||;True|2025-12-01T01:27:27.3976862+08:00||;False|2025-12-01T01:27:20.5193052+08:00||;True|2025-12-01T01:11:11.0210582+08:00||;True|2025-12-01T01:04:04.3307782+08:00||;True|2025-12-01T00:55:49.8018864+08:00||;True|2025-12-01T00:27:25.1323561+08:00||; diff --git a/README.md b/README.md index 19045d7..dd34cf6 100644 --- a/README.md +++ b/README.md @@ -97,8 +97,8 @@ Cookie 及 `sec_user_id` 是同步功能的核心,需严格按步骤获取, | 镜像标签 | 架构 | | ----------------- | -------------- | -| `beta_1.8.5` | x86_64 (amd64) | -| `arm_1.8.5` | ARM64 | +| `beta_1.8.6` | x86_64 (amd64) | +| `arm_1.8.6` | ARM64 | ### 最新镜像查看 [镜像列表](http://nas.synology2023.online:10108/api/docker/dysync/1) @@ -116,7 +116,7 @@ docker run -d --restart=always \ -v /opt/dysync/uper:/app/uper \ -p 10103:10101 \ --name dysync2025 \ - ccr.ccs.tencentyun.com/jianzhichu/dysync:beta_1.8.5 + ccr.ccs.tencentyun.com/jianzhichu/dysync:beta_1.8.6 # 注意:-p 后面的容器端口,可以用环境变量类似:ASPNETCORE_URLS = http://+:10108 指定 ``` @@ -130,7 +130,7 @@ version: '3.8' services: dysync: - image: ccr.ccs.tencentyun.com/jianzhichu/dysync:beta_1.8.5 + image: ccr.ccs.tencentyun.com/jianzhichu/dysync:beta_1.8.6 container_name: dysync2025 # 容器名称 restart: unless-stopped # 始终重启容器,除非容器被手动停止或Docker服务停止 ports: diff --git a/app/index.html b/app/index.html index 09a383c..45e638e 100644 --- a/app/index.html +++ b/app/index.html @@ -4,7 +4,9 @@ - + + 抖小云 diff --git a/app/src/App.vue b/app/src/App.vue index 807ba4a..b2d021c 100644 --- a/app/src/App.vue +++ b/app/src/App.vue @@ -34,7 +34,7 @@ const { logout } = useAccountStore(); const showPersonalDrawer = ref(false); const personalRef = ref(null); const emailRef = ref(null); -const open = ref(true); +const open = ref(false); const showSetting = ref(false); const router = useRouter(); @@ -117,6 +117,9 @@ onMounted(() => { color: #722ed1 !important; margin-left: 0em !important; } + .ant-tabs-extra-content { + display: none !important; + } } html { diff --git a/app/src/components/layout/FrontView.vue b/app/src/components/layout/FrontView.vue index e4d3d8f..9c03bda 100644 --- a/app/src/components/layout/FrontView.vue +++ b/app/src/components/layout/FrontView.vue @@ -1,45 +1,107 @@ + + + \ No newline at end of file diff --git a/app/src/pages/login/Login.vue b/app/src/pages/login/Login.vue index ac16ae6..10169f1 100644 --- a/app/src/pages/login/Login.vue +++ b/app/src/pages/login/Login.vue @@ -3,54 +3,78 @@ + + + +/* 适配iOS安全区域 */ +@supports (bottom: env(safe-area-inset-bottom)) { + .login { + padding-bottom: env(safe-area-inset-bottom); + padding-top: env(safe-area-inset-top); + } +} + \ No newline at end of file diff --git a/app/src/pages/login/LoginBox.vue b/app/src/pages/login/LoginBox.vue index 041901c..8bf7d69 100644 --- a/app/src/pages/login/LoginBox.vue +++ b/app/src/pages/login/LoginBox.vue @@ -1,78 +1,70 @@ \ No newline at end of file diff --git a/app/src/pages/mobile/MobileDashboard.vue b/app/src/pages/mobile/MobileDashboard.vue new file mode 100644 index 0000000..2fbdba5 --- /dev/null +++ b/app/src/pages/mobile/MobileDashboard.vue @@ -0,0 +1,999 @@ + + + + + \ No newline at end of file diff --git a/app/src/pages/mylogs/MyLogs.vue b/app/src/pages/mylogs/MyLogs.vue index 052014c..8ef7b53 100644 --- a/app/src/pages/mylogs/MyLogs.vue +++ b/app/src/pages/mylogs/MyLogs.vue @@ -45,6 +45,18 @@ const typeChange = (e) => { loadLogs(); }; const mIfrm = ref(null); + +// 核心:处理日志时间戳,移除 .xxx +08:00 部分 +const formatLogTime = (logContent: string) => { + // 正则匹配:2025-12-11 18:41:39.624 +08:00 格式,捕获前面的日期时间部分 + // 正则解释: + // (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) 捕获 年-月-日 时:分:秒 + // \.\d+ \+08:00 匹配 .毫秒 +时区 部分 + const timeRegex = /(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\.\d+ \+08:00/g; + + // 替换匹配到的内容,只保留捕获的日期时间部分 + return logContent.replace(timeRegex, '$1'); +}; onMounted(() => { // console.log(mIfrm.value); loadLogs(); @@ -54,6 +66,7 @@ const loadLogs = () => { .apiGetLogs(iframeUrl.value) .then((log) => { // console.log(log); + log = formatLogTime(log); const lines = log.split('\n'); // 将文本按换行符分割为行数组 const reversedLines = lines.reverse(); // 对行数组进行倒序操作 const reversedText = reversedLines.join('\n'); // 将行数组重新连接为一个字符串 diff --git a/app/src/router/guards.ts b/app/src/router/guards.ts index b565436..fc063af 100644 --- a/app/src/router/guards.ts +++ b/app/src/router/guards.ts @@ -16,7 +16,7 @@ interface NaviGuard { const loginGuard: NavigationGuard = function (to, from) { // console.log('Authorization', http.checkAuthorization()) const account = useAccountStore(); - if (!http.checkAuthorization() && !/^\/(login|home|init)?$/.test(to.fullPath)) { + if (!http.checkAuthorization() && !/^\/(login|home|init|mobile)?$/.test(to.fullPath)) { account.setLogged(false) return '/login'; } else { diff --git a/app/src/router/routes.ts b/app/src/router/routes.ts index 9e7cb80..fd7f541 100644 --- a/app/src/router/routes.ts +++ b/app/src/router/routes.ts @@ -14,6 +14,18 @@ const routes: RouteRecordRaw[] = [ children: null, component: () => import('@/pages/login'), }, + { + path: '/', + name: 'mobile', + redirect: '/mobile', + meta: { + title: '登录', + renderMenu: false, + icon: 'CreditCardOutlined', + }, + children: null, + component: () => import('@/pages/mobile/MobileDashboard.vue'), + }, // { // path: '/', // name: 'init', @@ -26,6 +38,7 @@ const routes: RouteRecordRaw[] = [ // children: null, // component: () => import('@/pages/init'), // }, + { path: '/front', name: '前端', @@ -45,7 +58,18 @@ const routes: RouteRecordRaw[] = [ }, component: () => import('@/pages/login'), }, - + { + path: '/mobile', + name: 'mobile', + meta: { + icon: 'LoginOutlined', + view: 'blank', + target: '_blank', + cacheable: false, + }, + children: null, + component: () => import('@/pages/mobile/MobileDashboard.vue'), + }, // { // path: '/init', // name: '初始化', diff --git a/app/src/store/coreapi.ts b/app/src/store/coreapi.ts index 52b247a..7efc158 100644 --- a/app/src/store/coreapi.ts +++ b/app/src/store/coreapi.ts @@ -236,7 +236,27 @@ export const useApiStore = defineStore('coreapi', () => { }); } + + //移动端获取日志列表 + async function MobileLogs() { + return http.request>('/api/logs/list', 'get').then(r => { + return r.data; + }).finally(() => { + + }); + } + + //移动端获取日志详情 + async function LogDetail(type: string, date: string) { + return http.request>('/api/logs/content?type=' + type + "&Date=" + date, 'get').then(r => { + return r.data; + }).finally(() => { + + }); + } return { + LogDetail, + MobileLogs, ExportConf, ImportConf, GetDeleteViedos, diff --git a/appsettings.json b/appsettings.json index 97796ea..dae4dc3 100644 --- a/appsettings.json +++ b/appsettings.json @@ -1,7 +1,7 @@ { "dbconn": "", - //"tagName": "arm_1.8.5", - //"tagName": "dev_1.8.5", - "tagName": "beta_1.8.5", + //"tagName": "arm_1.8.6", + //"tagName": "dev_1.8.6", + "tagName": "beta_1.8.6", "dbtype": "Sqlite" } \ No newline at end of file diff --git a/dto/LogFileInfoDto.cs b/dto/LogFileInfoDto.cs new file mode 100644 index 0000000..c738a3b --- /dev/null +++ b/dto/LogFileInfoDto.cs @@ -0,0 +1,40 @@ +using System.ComponentModel.DataAnnotations; + +namespace dy.net.dto +{ + public class LogFileInfoDto + { + + + /// + /// 日志类型(debug/error) + /// + public string Type { get; set; } + + /// + /// 日志日期(格式:20251203) + /// + public string Date { get; set; } + + /// + /// 完整文件名 + /// + public string FileName { get; set; } + } + + + public class LogContentRequest + { + /// + /// 日志类型 + /// + [Required] + public string Type { get; set; } + + /// + /// 日志日期 + /// + [Required] + public string Date { get; set; } + } +} diff --git a/service/LogInfoService.cs b/service/LogInfoService.cs new file mode 100644 index 0000000..b44ce93 --- /dev/null +++ b/service/LogInfoService.cs @@ -0,0 +1,83 @@ +using dy.net.dto; +using System.Globalization; + +namespace dy.net.service +{ + public class LogInfoService + { + + public List GetLogFiles(string logDirectory) + { + var logFiles = new List(); + + // 验证目录是否存在 + if (!Directory.Exists(logDirectory)) + { + Serilog.Log.Error("日志目录不存在:{Directory}", logDirectory); + return logFiles; + } + + // 获取最近10天的日期范围 + var endDate = DateTime.Today; + var startDate = endDate.AddDays(-9); + + // 遍历日期范围,查找对应日志文件 + for (var date = startDate; date <= endDate; date = date.AddDays(1)) + { + var dateStr = date.ToString("yyyyMMdd"); + + // 查找debug日志 + var debugFile = Path.Combine(logDirectory, $"log-debug-{dateStr}.txt"); + if (File.Exists(debugFile)) + { + logFiles.Add(new LogFileInfoDto + { + Type = "debug", + Date = dateStr, + FileName = Path.GetFileName(debugFile) + }); + } + + // 查找error日志 + var errorFile = Path.Combine(logDirectory, $"log-error-{dateStr}.txt"); + if (File.Exists(errorFile)) + { + logFiles.Add(new LogFileInfoDto + { + Type = "error", + Date = dateStr, + FileName = Path.GetFileName(errorFile) + }); + } + } + + return logFiles.OrderByDescending(x => x.Date).ToList(); + } + + + public Stream GetLogFileStream(string logDirectory, string type, string date) + { + // 验证日期格式 + if (!DateTime.TryParseExact(date, "yyyyMMdd", CultureInfo.InvariantCulture, + DateTimeStyles.None, out _)) + { + throw new ArgumentException("日期格式错误,应为yyyyMMdd"); + } + + // 验证类型 + if (type != "debug" && type != "error") + { + throw new ArgumentException("日志类型只能是debug或error"); + } + + var filePath = Path.Combine(logDirectory, $"log-{type}-{date}.txt"); + if (!File.Exists(filePath)) + { + throw new FileNotFoundException("日志文件不存在", filePath); + } + + // 返回文件流(使用FileStream确保流可被前端读取) + return new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + } + } +}