diff --git a/frontend/electron/main.ts b/frontend/electron/main.ts index c634dd3..4af05d3 100644 --- a/frontend/electron/main.ts +++ b/frontend/electron/main.ts @@ -490,6 +490,26 @@ ipcMain.handle('open-url', async (_event, url: string) => { } }) +// 打开文件 +ipcMain.handle('open-file', async (_event, filePath: string) => { + try { + await shell.openPath(filePath) + } catch (error) { + console.error('打开文件失败:', error) + throw error + } +}) + +// 显示文件所在目录并选中文件 +ipcMain.handle('show-item-in-folder', async (_event, filePath: string) => { + try { + shell.showItemInFolder(filePath) + } catch (error) { + console.error('显示文件所在目录失败:', error) + throw error + } +}) + // 环境检查 ipcMain.handle('check-environment', async () => { const appRoot = getAppRoot() diff --git a/frontend/electron/preload.ts b/frontend/electron/preload.ts index 2f19132..4e64079 100644 --- a/frontend/electron/preload.ts +++ b/frontend/electron/preload.ts @@ -50,6 +50,10 @@ contextBridge.exposeInMainWorld('electronAPI', { saveLogsToFile: (logs: string) => ipcRenderer.invoke('save-logs-to-file', logs), loadLogsFromFile: () => ipcRenderer.invoke('load-logs-from-file'), + // 文件系统操作 + openFile: (filePath: string) => ipcRenderer.invoke('open-file', filePath), + showItemInFolder: (filePath: string) => ipcRenderer.invoke('show-item-in-folder', filePath), + // 监听下载进度 onDownloadProgress: (callback: (progress: any) => void) => { ipcRenderer.on('download-progress', (_, progress) => callback(progress)) diff --git a/frontend/src/types/electron.d.ts b/frontend/src/types/electron.d.ts index 33b22c3..832e76a 100644 --- a/frontend/src/types/electron.d.ts +++ b/frontend/src/types/electron.d.ts @@ -40,6 +40,10 @@ export interface ElectronAPI { saveLogsToFile: (logs: string) => Promise loadLogsFromFile: () => Promise + // 文件系统操作 + openFile: (filePath: string) => Promise + showItemInFolder: (filePath: string) => Promise + // 监听下载进度 onDownloadProgress: (callback: (progress: any) => void) => void removeDownloadProgressListener: () => void diff --git a/frontend/src/views/History.vue b/frontend/src/views/History.vue index 7882573..17965de 100644 --- a/frontend/src/views/History.vue +++ b/frontend/src/views/History.vue @@ -90,32 +90,6 @@
- - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -187,7 +161,21 @@
{{ record.date }} + + + {{ record.status }} + + @@ -287,6 +275,30 @@ @@ -316,13 +328,14 @@ import { HistoryOutlined, UserOutlined, GiftOutlined, - ExclamationCircleOutlined, FileSearchOutlined, FileTextOutlined, RightOutlined, + FolderOpenOutlined, + FileOutlined, } from '@ant-design/icons-vue' import { Service } from '@/api/services/Service' -import type { HistorySearchIn, HistoryData, HistoryDataGetIn } from '@/api/models' +import type { HistorySearchIn, HistoryData } from '@/api' import dayjs from 'dayjs' // 响应式数据 @@ -565,6 +578,70 @@ const loadUserLog = async (jsonFile: string) => { } } +// 打开日志文件 +const handleOpenLogFile = async () => { + if (!currentJsonFile.value) { + message.warning('请先选择一条记录') + return + } + + try { + // 将 .json 扩展名替换为 .log + const logFilePath = currentJsonFile.value.replace(/\.json$/, '.log') + + console.log('尝试打开日志文件:', logFilePath) + console.log('electronAPI 可用性:', !!window.electronAPI) + console.log('openFile 方法可用性:', !!(window.electronAPI && (window.electronAPI as any).openFile)) + + // 调用系统API打开文件 + if (window.electronAPI && (window.electronAPI as any).openFile) { + await (window.electronAPI as any).openFile(logFilePath) + message.success('日志文件已打开') + } else { + const errorMsg = !window.electronAPI + ? '当前环境不支持打开文件功能(electronAPI 不可用)' + : '当前环境不支持打开文件功能(openFile 方法不可用)' + console.error(errorMsg) + message.error(errorMsg) + } + } catch (error) { + console.error('打开日志文件失败:', error) + message.error(`打开日志文件失败: ${error}`) + } +} + +// 打开日志文件所在目录 +const handleOpenLogDirectory = async () => { + if (!currentJsonFile.value) { + message.warning('请先选择一条记录') + return + } + + try { + // 将 .json 扩展名替换为 .log + const logFilePath = currentJsonFile.value.replace(/\.json$/, '.log') + + console.log('尝试打开日志文件目录:', logFilePath) + console.log('electronAPI 可用性:', !!window.electronAPI) + console.log('showItemInFolder 方法可用性:', !!(window.electronAPI && (window.electronAPI as any).showItemInFolder)) + + // 调用系统API打开目录并选中文件 + if (window.electronAPI && (window.electronAPI as any).showItemInFolder) { + await (window.electronAPI as any).showItemInFolder(logFilePath) + message.success('日志文件目录已打开') + } else { + const errorMsg = !window.electronAPI + ? '当前环境不支持打开目录功能(electronAPI 不可用)' + : '当前环境不支持打开目录功能(showItemInFolder 方法不可用)' + console.error(errorMsg) + message.error(errorMsg) + } + } catch (error) { + console.error('打开日志文件目录失败:', error) + message.error(`打开日志文件目录失败: ${error}`) + } +} + // 获取日期状态颜色 const getDateStatusColor = (users: Record) => { const hasError = Object.values(users).some( @@ -612,7 +689,7 @@ const getDateStatusColor = (users: Record) => { /* 左侧日期栏 */ .date-sidebar { - width: 320px; + width: 200px; flex-shrink: 0; display: flex; flex-direction: column; @@ -947,6 +1024,16 @@ const getDateStatusColor = (users: Record) => { } } +/* 带tooltip的错误tag样式 */ +.error-tag-with-tooltip { + cursor: help; + position: relative; +} + +.error-tag-with-tooltip:hover { + opacity: 0.8; +} + /* 统计数据标题样式 */ .stat-subtitle { font-size: 12px;