diff --git a/electron/electron-down.js b/electron/electron-down.js index 223f7035b..1ef300a6f 100644 --- a/electron/electron-down.js +++ b/electron/electron-down.js @@ -20,87 +20,88 @@ function initialize(options = {}) { ...options, onStarted: (item) => { - downloadManager.addDownloadItem(item); - syncDownloadItems(); - }, - onProgress: (item) => { - downloadManager.updateDownloadItem(item.path); + downloadManager.add(item); syncDownloadItems(); }, onCancel: (item) => { - downloadManager.updateDownloadItem(item.getSavePath()) + downloadManager.refresh(item.getSavePath()) + syncDownloadItems(); + }, + onInterrupted: (item) => { + downloadManager.refresh(item.getSavePath()); + syncDownloadItems(); + }, + onProgress: (item) => { + downloadManager.refresh(item.path); syncDownloadItems(); }, onCompleted: (item) => { - downloadManager.updateDownloadItem(item.path); + downloadManager.refresh(item.path); syncDownloadItems(); } }); - // IPC - 获取下载任务 - ipcMain.handle('getDownloadTasks', () => { - return { - items: downloadManager.getDownloadItems() - }; - }); + // IPC + ipcMain.handle('downloadManager', async (event, {action, path}) => { + switch (action) { + case "get": { + return { + items: downloadManager.get() + }; + } - // IPC - 暂停下载任务 - ipcMain.handle('pauseDownloadTask', async (event, {path}) => { - downloadManager.pauseDownloadItem(path); - syncDownloadItems(); - return true; - }); + case "pause": { + downloadManager.pause(path); + syncDownloadItems(); + return true; + } - // IPC - 恢复下载任务 - ipcMain.handle('resumeDownloadTask', async (event, {path}) => { - downloadManager.resumeDownloadItem(path); - syncDownloadItems(); - return true; - }); + case "resume": { + downloadManager.resume(path); + syncDownloadItems(); + return true; + } - // IPC - 取消下载任务 - ipcMain.handle('cancelDownloadTask', async (event, {path}) => { - downloadManager.cancelDownloadItem(path); - syncDownloadItems(); - return true; - }); + case "cancel": { + downloadManager.cancel(path); + syncDownloadItems(); + return true; + } - // IPC - 从下载历史中移除下载项 - ipcMain.handle('removeFromDownloadHistory', async (event, {path}) => { - downloadManager.removeFromDownloadHistory(path); - syncDownloadItems(); - return true; - }); + case "remove": { + downloadManager.remove(path); + syncDownloadItems(); + return true; + } - // IPC - 清理下载历史 - ipcMain.handle('clearDownloadHistory', async () => { - downloadManager.clearHistory(); - syncDownloadItems(); - return true; - }); + case "removeAll": { + downloadManager.removeAll(); + syncDownloadItems(); + return true; + } - // IPC - 打开下载文件 - ipcMain.handle('openDownloadedFile', async (event, {path}) => { - if (fs.existsSync(path)) { - return shell.openPath(path); + case "openFile": { + if (!fs.existsSync(path)) { + throw new Error('file not found'); + } + return shell.openPath(path); + } + + case "showFolder": { + if (!fs.existsSync(path)) { + throw new Error('file not found'); + } + shell.showItemInFolder(path); + return true; + } } - throw new Error('file not found'); - }); - - // IPC - 显示下载文件 - ipcMain.handle('showDownloadedFileInFolder', async (event, {path}) => { - if (fs.existsSync(path)) { - shell.showItemInFolder(path); - return true; - } - throw new Error('file not found'); }); } function syncDownloadItems() { // 同步下载项到渲染进程 if (downloadWindow) { - downloadWindow.webContents.send('download-items', downloadManager.getDownloadItems()); + downloadWindow.webContents.send('download-items', downloadManager.get()); } } @@ -123,7 +124,7 @@ async function open(language = 'zh', theme = 'light') { // 如果窗口已存在,直接显示 if (downloadWindow) { // 更新窗口数据 - await updateDownloadWindow(language, theme) + await updateWindow(language, theme) // 显示窗口并聚焦 downloadWindow.show(); downloadWindow.focus(); @@ -215,7 +216,7 @@ async function open(language = 'zh', theme = 'light') { // 将语言包发送到渲染进程 downloadWindow.webContents.once('dom-ready', () => { - updateDownloadWindow(language, theme) + updateWindow(language, theme) }); // 显示窗口 @@ -236,7 +237,7 @@ function destroy() { } } -async function updateDownloadWindow(language, theme) { +async function updateWindow(language, theme) { if (downloadWindow) { try { const finalLanguage = getLanguagePack(language); @@ -256,5 +257,5 @@ module.exports = { open, close, destroy, - updateDownloadWindow + updateWindow } diff --git a/electron/electron.js b/electron/electron.js index e3fd2784f..6d07f4d7c 100644 --- a/electron/electron.js +++ b/electron/electron.js @@ -2802,11 +2802,11 @@ ipcMain.on("rendererReq", async (event, args) => { case 'openDownloadWindow': ret = await electronDown.open(args.language || 'zh', args.theme || 'light'); break; - case 'createDownloadTask': - ret = await electronDown.download(mainWindow, args.url, args.options || {}); - break; case 'updateDownloadWindow': - ret = await electronDown.updateDownloadWindow(args.language, args.theme); + ret = await electronDown.updateWindow(args.language, args.theme); + break; + case 'createDownload': + ret = await electronDown.download(mainWindow, args.url, args.options || {}); break; case 'watchFile': ret = await watchFile(args.path); diff --git a/electron/package.json b/electron/package.json index 4b78c77a8..127fa5248 100755 --- a/electron/package.json +++ b/electron/package.json @@ -26,7 +26,7 @@ "url": "https://github.com/kuaifan/dootask.git" }, "devDependencies": { - "@dootask/electron-dl": "^4.0.0-rc.1", + "@dootask/electron-dl": "^4.0.0-rc.2", "@electron-forge/cli": "^7.8.3", "@electron-forge/maker-deb": "^7.8.3", "@electron-forge/maker-rpm": "^7.8.3", diff --git a/electron/render/download/index.html b/electron/render/download/index.html index 190a18037..cd7d8bfd1 100644 --- a/electron/render/download/index.html +++ b/electron/render/download/index.html @@ -1 +1,502 @@ -123 + + + + + Download + + + + + +
+
+ +
+ + +
+
+ +
+
+
+
+ + + +
+
{{ query ? lang.noSearchResult : lang.noItems }}
+
+
+
+
+
+
+
+
+
{{ item.filename }}
+
+
+ + + {{ formatBytes(item.received) }} ({{ item.percent }}%) + + + {{ formatBytes(item.total) }} + + + {{ formatTime(item.endTime) }} + {{ formatTime(item.startTime) }} + + + {{ getStateText(item) }} + +
+
+
+ + {{ formatBytes(item.speed) }}/s + + + + + + + + +
+
+
+
+
+ + +
+
+ + + + + + + {{ toast.message }} +
+
+
+ + + + diff --git a/electron/render/download/style.css b/electron/render/download/style.css index 9e204b1a1..19e50749b 100644 --- a/electron/render/download/style.css +++ b/electron/render/download/style.css @@ -1,527 +1,543 @@ /* 下载管理器样式 - Chrome 风格 */ * { - margin: 0; - padding: 0; - box-sizing: border-box; + margin: 0; + padding: 0; + box-sizing: border-box; } :root { - --color-bg: #fff; - --color-text: #202124; + --color-bg: #fff; + --color-text: #202124; - --color-toolbar-bg: #fff; - --color-toolbar-border: #dadce0; + --color-toolbar-bg: #fff; + --color-toolbar-border: #dadce0; - --color-input-bg: #efefef; - --color-input-text: #202124; - --color-input-placeholder: #5f6368; - --color-input-focus-border: #1a73e8; - --color-input-focus-ring: rgba(26, 115, 232, .2); + --color-input-bg: #efefef; + --color-input-text: #202124; + --color-input-placeholder: #5f6368; + --color-input-focus-border: #1a73e8; + --color-input-focus-ring: rgba(26, 115, 232, .2); - --color-action-btn-bg: #fff; - --color-action-btn-border: #dadce0; - --color-action-btn-text: #1a73e8; - --color-action-btn-hover-bg: #f8f9fa; - --color-action-btn-hover-border: #c8c9ca; - --color-action-btn-danger-text: #d93025; - --color-action-btn-danger-hover-bg: #fce8e6; + --color-action-btn-bg: #fff; + --color-action-btn-border: #dadce0; + --color-action-btn-text: #1a73e8; + --color-action-btn-hover-bg: #f8f9fa; + --color-action-btn-hover-border: #c8c9ca; + --color-action-btn-danger-text: #d93025; + --color-action-btn-danger-hover-bg: #fce8e6; - --color-icon-btn: #5f6368; - --color-icon-btn-hover-bg: #f8f9fa; - --color-icon-btn-hover-color: #202124; - --color-icon-btn-danger: #d93025; - --color-icon-btn-danger-hover-bg: #fce8e6; - --color-icon-btn-danger-hover-color: #d93025; + --color-icon-btn: #5f6368; + --color-icon-btn-hover-bg: #f8f9fa; + --color-icon-btn-hover-color: #202124; + --color-icon-btn-danger: #d93025; + --color-icon-btn-danger-hover-bg: #fce8e6; + --color-icon-btn-danger-hover-color: #d93025; - --color-content-bg: #fff; - --color-task-item-bg: #fff; - --color-task-item-border: #e8eaed; - --color-task-item-hover-bg: #f8f9fa; - --color-task-name: #202124; - --color-task-name-clickable: #1a73e8; + --color-content-bg: #fff; + --color-task-item-bg: #fff; + --color-task-item-border: #e8eaed; + --color-task-item-hover-bg: #f8f9fa; + --color-task-name: #202124; + --color-task-name-clickable: #1a73e8; - --color-progress-bar: #e8eaed; - --color-progress-fill: #1a73e8; - --color-progress-text: #5f6368; - --color-task-meta: #5f6368; - --color-speed: #1a73e8; + --color-progress-bar: #e8eaed; + --color-progress-fill: #1a73e8; + --color-progress-text: #5f6368; + --color-task-meta: #5f6368; + --color-speed: #1a73e8; - --color-empty-state: #5f6368; - --color-empty-text: #5f6368; - --color-status-completed-bg: #e8f5e8; - --color-status-completed-text: #137333; - --color-status-failed-bg: #fce8e6; - --color-status-failed-text: #d93025; - --color-status-cancelled-bg: #e8eaed; - --color-status-cancelled-text: #5f6368; + --color-empty-state: #5f6368; + --color-empty-text: #5f6368; + --color-state-completed-bg: #e8f5e8; + --color-state-completed-text: #137333; + --color-state-failed-bg: #fce8e6; + --color-state-failed-text: #d93025; + --color-state-cancelled-bg: #e8eaed; + --color-state-cancelled-text: #5f6368; + --color-state-paused-bg: #fff3e0; + --color-state-paused-text: #f57c00; - --scrollbar-thumb: rgba(0, 0, 0, 0.2); - --scrollbar-thumb-hover: rgba(0, 0, 0, 0.3); + --scrollbar-thumb: rgba(0, 0, 0, 0.2); + --scrollbar-thumb-hover: rgba(0, 0, 0, 0.3); } .dark { - --color-bg: #202124; - --color-text: #e8eaed; + --color-bg: #202124; + --color-text: #e8eaed; - --color-toolbar-bg: #2d2e30; - --color-toolbar-border: #3c4043; + --color-toolbar-bg: #2d2e30; + --color-toolbar-border: #3c4043; - --color-input-bg: #282828; - --color-input-text: #e8eaed; - --color-input-placeholder: #9aa0a6; - --color-input-focus-border: #8ab4f8; - --color-input-focus-ring: rgba(138, 180, 248, .12); + --color-input-bg: #282828; + --color-input-text: #e8eaed; + --color-input-placeholder: #9aa0a6; + --color-input-focus-border: #8ab4f8; + --color-input-focus-ring: rgba(138, 180, 248, .12); - --color-action-btn-bg: #2d2e30; - --color-action-btn-border: #5f6368; - --color-action-btn-text: #8ab4f8; - --color-action-btn-hover-bg: #35363a; - --color-action-btn-hover-border: #70757a; - --color-action-btn-danger-text: #f28b82; - --color-action-btn-danger-hover-bg: #35363a; + --color-action-btn-bg: #2d2e30; + --color-action-btn-border: #5f6368; + --color-action-btn-text: #8ab4f8; + --color-action-btn-hover-bg: #35363a; + --color-action-btn-hover-border: #70757a; + --color-action-btn-danger-text: #f28b82; + --color-action-btn-danger-hover-bg: #35363a; - --color-icon-btn: #9aa0a6; - --color-icon-btn-hover-bg: #35363a; - --color-icon-btn-hover-color: #e8eaed; - --color-icon-btn-danger: #f28b82; - --color-icon-btn-danger-hover-bg: #3d1a1a; - --color-icon-btn-danger-hover-color: #f28b82; + --color-icon-btn: #9aa0a6; + --color-icon-btn-hover-bg: #35363a; + --color-icon-btn-hover-color: #e8eaed; + --color-icon-btn-danger: #f28b82; + --color-icon-btn-danger-hover-bg: #3d1a1a; + --color-icon-btn-danger-hover-color: #f28b82; - --color-content-bg: #2d2e30; - --color-task-item-bg: #2d2e30; - --color-task-item-border: #3c4043; - --color-task-item-hover-bg: #35363a; - --color-task-name: #e8eaed; - --color-task-name-clickable: #8ab4f8; + --color-content-bg: #2d2e30; + --color-task-item-bg: #2d2e30; + --color-task-item-border: #3c4043; + --color-task-item-hover-bg: #35363a; + --color-task-name: #e8eaed; + --color-task-name-clickable: #8ab4f8; - --color-progress-bar: #3c4043; - --color-progress-fill: #8ab4f8; - --color-progress-text: #9aa0a6; - --color-task-meta: #9aa0a6; - --color-speed: #8ab4f8; + --color-progress-bar: #3c4043; + --color-progress-fill: #8ab4f8; + --color-progress-text: #9aa0a6; + --color-task-meta: #9aa0a6; + --color-speed: #8ab4f8; - --color-empty-state: #9aa0a6; - --color-empty-text: #9aa0a6; - --color-status-completed-bg: #1e3a1e; - --color-status-completed-text: #81c995; - --color-status-failed-bg: #3d1a1a; - --color-status-failed-text: #f28b82; - --color-status-cancelled-bg: #3c4043; - --color-status-cancelled-text: #9aa0a6; + --color-empty-state: #9aa0a6; + --color-empty-text: #9aa0a6; + --color-state-completed-bg: #1e3a1e; + --color-state-completed-text: #81c995; + --color-state-failed-bg: #3d1a1a; + --color-state-failed-text: #f28b82; + --color-state-cancelled-bg: #3c4043; + --color-state-cancelled-text: #9aa0a6; + --color-state-paused-bg: #522f2f; + --color-state-paused-text: #f57c00; - --scrollbar-thumb: rgba(255, 255, 255, 0.2); - --scrollbar-thumb-hover: rgba(255, 255, 255, 0.3); + --scrollbar-thumb: rgba(255, 255, 255, 0.2); + --scrollbar-thumb-hover: rgba(255, 255, 255, 0.3); - body { - color-scheme: dark; - } + body { + color-scheme: dark; + } } body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - background: var(--color-bg); - color: var(--color-text); - font-size: 13px; - overflow: hidden; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + background: var(--color-bg); + color: var(--color-text); + font-size: 13px; + overflow: hidden; } .download-manager { - display: flex; - flex-direction: column; - height: 100vh; + display: flex; + flex-direction: column; + height: 100vh; } /* 工具栏 */ .toolbar { - display: flex; - justify-content: space-between; - align-items: center; - gap: 32px; - padding: 0 24px; - background: var(--color-toolbar-bg); - border-bottom: 1px solid var(--color-toolbar-border); - flex-shrink: 0; + display: flex; + justify-content: space-between; + align-items: center; + gap: 32px; + padding: 0 24px; + background: var(--color-toolbar-bg); + border-bottom: 1px solid var(--color-toolbar-border); + flex-shrink: 0; } .search { - flex: 1; - padding: 8px 0; + flex: 1; + padding: 8px 0; } .search-input { - width: 100%; - max-width: 380px; - height: 32px; - padding: 0 12px 0 32px; - border: 0; - border-radius: 6px; - margin: 1px 0; - font-size: 13px; - outline: none; - color: var(--color-input-text); - background: var(--color-input-bg) url('data:image/svg+xml;utf8,') no-repeat 8px center; - background-size: 18px 18px; - transition: all 0.3s; + width: 100%; + max-width: 380px; + height: 32px; + padding: 0 12px 0 32px; + border: 0; + border-radius: 6px; + margin: 1px 0; + font-size: 13px; + outline: none; + color: var(--color-input-text); + background: var(--color-input-bg) url('data:image/svg+xml;utf8,') no-repeat 8px center; + background-size: 18px 18px; + transition: all 0.3s; } .search-input::placeholder { - color: var(--color-input-placeholder); + color: var(--color-input-placeholder); } .search-input:focus { - border-color: var(--color-input-focus-border); - box-shadow: 0 0 0 2px var(--color-input-focus-ring); + border-color: var(--color-input-focus-border); + box-shadow: 0 0 0 2px var(--color-input-focus-ring); } .actions { - display: flex; - gap: 10px; + display: flex; + gap: 10px; } .action-btn { - padding: 6px 12px; - border: 1px solid var(--color-action-btn-border); - background: var(--color-action-btn-bg); - cursor: pointer; - border-radius: 4px; - font-size: 12px; - color: var(--color-action-btn-text); - transition: all 0.15s; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + padding: 6px 12px; + border: 1px solid var(--color-action-btn-border); + background: var(--color-action-btn-bg); + cursor: pointer; + border-radius: 4px; + font-size: 12px; + color: var(--color-action-btn-text); + transition: all 0.15s; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .action-btn:hover:not(:disabled) { - background: var(--color-action-btn-hover-bg); - border-color: var(--color-action-btn-hover-border); + background: var(--color-action-btn-hover-bg); + border-color: var(--color-action-btn-hover-border); } .action-btn:disabled { - opacity: 0.38; - cursor: not-allowed; + opacity: 0.38; + cursor: not-allowed; } .action-btn.small { - padding: 4px 8px; - font-size: 11px; + padding: 4px 8px; + font-size: 11px; } .action-btn.danger { - color: var(--color-action-btn-danger-text); + color: var(--color-action-btn-danger-text); } .action-btn.danger:hover:not(:disabled) { - background: var(--color-action-btn-danger-hover-bg); + background: var(--color-action-btn-danger-hover-bg); } /* 图标按钮样式 */ .icon-btn { - padding: 6px; - border: none; - background: transparent; - cursor: pointer; - border-radius: 4px; - color: var(--color-icon-btn); - transition: all 0.15s; - display: inline-flex; - align-items: center; - justify-content: center; + padding: 6px; + border: none; + background: transparent; + cursor: pointer; + border-radius: 4px; + color: var(--color-icon-btn); + transition: all 0.15s; + display: inline-flex; + align-items: center; + justify-content: center; } .icon-btn svg { - width: 20px; - height: 20px; + width: 20px; + height: 20px; } .icon-btn:hover { - background: var(--color-icon-btn-hover-bg); - color: var(--color-icon-btn-hover-color); + background: var(--color-icon-btn-hover-bg); + color: var(--color-icon-btn-hover-color); } .icon-btn.danger { - color: var(--color-icon-btn-danger); + color: var(--color-icon-btn-danger); } .icon-btn.danger:hover { - background: var(--color-icon-btn-danger-hover-bg); - color: var(--color-icon-btn-danger-hover-color); + background: var(--color-icon-btn-danger-hover-bg); + color: var(--color-icon-btn-danger-hover-color); } /* 内容区 */ .content { - flex: 1; - overflow: hidden; - background: var(--color-content-bg); + flex: 1; + overflow: hidden; + background: var(--color-content-bg); } .tab-content { - height: 100%; - overflow-y: auto; + height: 100%; + overflow-y: auto; } /* 空状态 */ .empty-state { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; - padding: 48px 24px; - color: var(--color-empty-state); - text-align: center; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + padding: 48px 24px; + color: var(--color-empty-state); + text-align: center; } .empty-icon { - margin-bottom: 20px; - opacity: 0.6; + margin-bottom: 20px; + opacity: 0.6; } .empty-text { - font-size: 14px; - color: var(--color-empty-text); + font-size: 14px; + color: var(--color-empty-text); } /* 任务列表 */ .task-list { - padding: 0; + padding: 0; } .task-item { - display: flex; - align-items: center; - padding: 16px 24px; - background: var(--color-task-item-bg); - border-bottom: 1px solid var(--color-task-item-border); - transition: background-color 0.15s; - position: relative; - overflow: hidden; + display: flex; + align-items: center; + padding: 16px 24px; + background: var(--color-task-item-bg); + border-bottom: 1px solid var(--color-task-item-border); + transition: background-color 0.15s; + position: relative; + overflow: hidden; } .task-item > * { - position: relative; - z-index: 1; + position: relative; + z-index: 1; } .task-item:hover { - background: var(--color-task-item-hover-bg); + background: var(--color-task-item-hover-bg); } .task-item:last-child { - border-bottom: none; + border-bottom: none; } /* 整块背景进度条(下载中样式) */ -.task-item.downloading-item::before { - content: ''; - position: absolute; - top: 0; - left: 0; - bottom: 0; - width: var(--progress, 0%); - background: var(--color-progress-fill); - opacity: 0.12; - pointer-events: none; - transition: width 0.3s ease; - z-index: 0; +.task-item.progressing-item::before { + content: ''; + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: var(--progress, 0%); + background: var(--color-progress-fill); + opacity: 0.12; + pointer-events: none; + transition: width 0.3s ease; + z-index: 0; } .task-icon { - margin-right: 16px; - flex-shrink: 0; + margin-right: 16px; + flex-shrink: 0; } .file-icon { - width: 40px; - height: 40px; - border-radius: 4px; - display: flex; - align-items: center; - justify-content: center; + width: 40px; + height: 40px; + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; } .file-icon svg { - width: 28px; - height: 28px; + width: 28px; + height: 28px; } .task-info { - flex: 1; - display: flex; - flex-direction: column; - justify-content: center; - gap: 6px; - min-width: 0; + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + gap: 6px; + min-width: 0; } .task-name { - min-width: 0; - width: auto; - font-weight: 400; - font-size: 13px; - color: var(--color-task-name); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + min-width: 0; + width: auto; + font-weight: 400; + font-size: 13px; + color: var(--color-task-name); } .task-name-clickable { - display: inline-block; - cursor: pointer; - color: var(--color-task-name-clickable); - text-decoration: none; + display: inline-block; + cursor: pointer; + color: var(--color-task-name-clickable); + text-decoration: none; + max-width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .task-name-clickable:hover { - text-decoration: underline; + text-decoration: underline; } .task-progress { - margin-bottom: 4px; + margin-bottom: 4px; } .progress-bar { - width: 100%; - height: 4px; - background: var(--color-progress-bar); - border-radius: 2px; - margin-bottom: 6px; - overflow: hidden; + width: 100%; + height: 4px; + background: var(--color-progress-bar); + border-radius: 2px; + margin-bottom: 6px; + overflow: hidden; } .progress-fill { - height: 100%; - background: var(--color-progress-fill); - border-radius: 2px; - transition: width 0.3s ease; + height: 100%; + background: var(--color-progress-fill); + border-radius: 2px; + transition: width 0.3s ease; } .progress-text { - font-size: 11px; - color: var(--color-progress-text); - display: flex; - justify-content: space-between; - align-items: center; + font-size: 11px; + color: var(--color-progress-text); + display: flex; + justify-content: space-between; + align-items: center; } .speed { - display: flex; - align-items: center; - color: var(--color-speed); - font-weight: 400; + display: flex; + align-items: center; + color: var(--color-speed); + font-weight: 400; } .task-meta { - display: flex; - align-items: center; - gap: 12px; - height: 20px; - font-size: 12px; - color: var(--color-task-meta); + display: flex; + align-items: center; + gap: 12px; + height: 20px; + font-size: 12px; + color: var(--color-task-meta); } -.status { - padding: 2px 8px; - border-radius: 4px; - font-size: 11px; - font-weight: 400; +.task-meta > span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } -.status.completed { - background: var(--color-status-completed-bg); - color: var(--color-status-completed-text); +.state { + padding: 2px 8px; + border-radius: 4px; + font-size: 11px; + font-weight: 400; } -.status.failed { - background: var(--color-status-failed-bg); - color: var(--color-status-failed-text); +.state.completed { + background: var(--color-state-completed-bg); + color: var(--color-state-completed-text); } -.status.cancelled { - background: var(--color-status-cancelled-bg); - color: var(--color-status-cancelled-text); +.state.cancelled { + background: var(--color-state-cancelled-bg); + color: var(--color-state-cancelled-text); +} + +.state.interrupted { + background: var(--color-state-failed-bg); + color: var(--color-state-failed-text); +} + +.state.paused { + background: var(--color-state-paused-bg); + color: var(--color-state-paused-text); } .task-actions { - display: flex; - gap: 12px; - margin-left: 16px; - flex-shrink: 0; + display: flex; + gap: 12px; + margin-left: 16px; + flex-shrink: 0; } /* 平台特定样式 */ body.darwin { - font-family: -apple-system, BlinkMacSystemFont, sans-serif; + font-family: -apple-system, BlinkMacSystemFont, sans-serif; } body.win32 { - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } /* 滚动条样式 */ .tab-content::-webkit-scrollbar { - width: 8px; + width: 8px; } .tab-content::-webkit-scrollbar-track { - background: transparent; + background: transparent; } .tab-content::-webkit-scrollbar-thumb { - background: var(--scrollbar-thumb); - border-radius: 4px; + background: var(--scrollbar-thumb); + border-radius: 4px; } .tab-content::-webkit-scrollbar-thumb:hover { - background: var(--scrollbar-thumb-hover); + background: var(--scrollbar-thumb-hover); } /* 深色模式通过 .dark 类启用变量,不再依赖系统配色偏好 */ /* Toast 提示框样式 */ .toast { - position: fixed; - bottom: 20px; - left: 50%; - transform: translateX(-50%); - z-index: 1000; - animation: toast-slide-up 0.3s ease-out; + position: fixed; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + z-index: 1000; + animation: toast-slide-up 0.3s ease-out; } .toast-content { - display: flex; - align-items: center; - gap: 8px; - padding: 12px 16px; - background: #323232; - color: #fff; - border-radius: 6px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - font-size: 13px; - min-width: 200px; - white-space: nowrap; + display: flex; + align-items: center; + gap: 8px; + padding: 12px 16px; + background: #323232; + color: #fff; + border-radius: 6px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + font-size: 13px; + min-width: 200px; + white-space: nowrap; } .toast.success .toast-content { - background: #4caf50; + background: #4caf50; } .toast.error .toast-content { - background: #f44336; + background: #f44336; } .toast-message { - flex: 1; + flex: 1; } @keyframes toast-slide-up { - from { - opacity: 0; - transform: translate(-50%, 20px); - } - to { - opacity: 1; - transform: translate(-50%, 0); - } + from { + opacity: 0; + transform: translate(-50%, 20px); + } + to { + opacity: 1; + transform: translate(-50%, 0); + } } diff --git a/electron/utils/download.js b/electron/utils/download.js index 33e9ccc10..8c024ff6d 100644 --- a/electron/utils/download.js +++ b/electron/utils/download.js @@ -30,7 +30,7 @@ class DownloadManager { * 转换下载项格式 * @param {Electron.DownloadItem} downloadItem */ - convertItem(downloadItem) { + convert(downloadItem) { return { filename: downloadItem.getFilename(), path: downloadItem.getSavePath(), @@ -52,27 +52,26 @@ class DownloadManager { * 添加下载项 * @param {Electron.DownloadItem} downloadItem */ - addDownloadItem(downloadItem) { + add(downloadItem) { // 根据保存路径,如果下载项已存在,则取消下载(避免重复下载) - this.cancelDownloadItem(downloadItem.getSavePath()); + this.cancel(downloadItem.getSavePath()); // 添加下载项 this.downloadHistory.unshift({ - ...this.convertItem(downloadItem), + ...this.convert(downloadItem), _source: downloadItem, }); if (this.downloadHistory.length > 1000) { this.downloadHistory = this.downloadHistory.slice(0, 1000); } store.set('downloadHistory', this.downloadHistory); - loger.info(`Download item added: ${downloadItem.getSavePath()}`); } /** * 获取下载列表 * @returns {*} */ - getDownloadItems() { + get() { return this.downloadHistory.map(item => { return { ...item, @@ -87,7 +86,7 @@ class DownloadManager { * 更新下载项 * @param {string} path */ - updateDownloadItem(path) { + refresh(path) { const item = this.downloadHistory.find(d => d.path === path) if (!item) { return; @@ -97,16 +96,15 @@ class DownloadManager { loger.warn(`Download item not found for path: ${path}`); return; } - Object.assign(item, this.convertItem(downloadItem)) + Object.assign(item, this.convert(downloadItem)) store.set('downloadHistory', this.downloadHistory); - loger.info(`Download item updated: ${path} - ${item.state} (${item.percent}%)`); } /** * 暂停下载项 * @param {string} path */ - pauseDownloadItem(path) { + pause(path) { const item = this.downloadHistory.find(d => d.path === path) if (!item) { return; @@ -117,14 +115,14 @@ class DownloadManager { return; } downloadItem.pause(); - this.updateDownloadItem(path); + this.refresh(path); } /** * 恢复下载项 * @param {string} path */ - resumeDownloadItem(path) { + resume(path) { const item = this.downloadHistory.find(d => d.path === path) if (!item) { return; @@ -135,14 +133,14 @@ class DownloadManager { return; } downloadItem.resume(); - this.updateDownloadItem(path); + this.refresh(path); } /** * 取消下载项 * @param {string} path */ - cancelDownloadItem(path) { + cancel(path) { const item = this.downloadHistory.find(d => d.path === path) if (!item) { return; @@ -153,39 +151,39 @@ class DownloadManager { return; } downloadItem.cancel(); - this.updateDownloadItem(path); + this.refresh(path); } /** * 取消所有下载项 */ - cancelAllDownloadItems() { + cancelAll() { this.downloadHistory.forEach(item => { - this.cancelDownloadItem(item.path); + this.cancel(item.path); }); } /** - * 从下载历史中移除下载项 + * 删除下载项 * @param {string} path */ - removeFromDownloadHistory(path) { + remove(path) { const index = this.downloadHistory.findIndex(item => item.path === path); if (index > -1) { - this.cancelDownloadItem(path); + this.cancel(path); this.downloadHistory.splice(index, 1); store.set('downloadHistory', this.downloadHistory); } } /** - * 清空下载历史 + * 清空下载项 */ - clearHistory() { - this.cancelAllDownloadItems(); + removeAll() { + this.cancelAll(); this.downloadHistory = []; store.set('downloadHistory', []); } } -module.exports = { DownloadManager }; +module.exports = {DownloadManager}; diff --git a/resources/assets/js/pages/manage/setting/keyboard.vue b/resources/assets/js/pages/manage/setting/keyboard.vue index cc3a304a6..ba39928d4 100644 --- a/resources/assets/js/pages/manage/setting/keyboard.vue +++ b/resources/assets/js/pages/manage/setting/keyboard.vue @@ -7,7 +7,7 @@ {{mateName}}
+
Shift
+
- +
{{mateName}}
+
{{altName}}
+
L
diff --git a/resources/assets/js/store/actions.js b/resources/assets/js/store/actions.js index 930043e49..66bf9d426 100644 --- a/resources/assets/js/store/actions.js +++ b/resources/assets/js/store/actions.js @@ -466,7 +466,7 @@ export default { } if ($A.Electron) { $A.Electron.request({ - action: 'createDownloadTask', + action: 'createDownload', url }); $A.Electron.request({