diff --git a/README.md b/README.md index 2ddcb7e2..190c1381 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ - [ ] 完善项目文档 - [x] 可以展示应用列表及其详细信息 - [ ] 实现应用下载&下载列表管理 - - [x] 实现应用安装 + - [x] 实现应用安装&重试安装 - [ ] 实现应用卸载 - [ ] 实现应用更新 - [ ] 支持显示本地是否已经安装 diff --git a/electron/main/backend/download-manager.ts b/electron/main/backend/download-manager.ts index 33008a24..3badfe31 100644 --- a/electron/main/backend/download-manager.ts +++ b/electron/main/backend/download-manager.ts @@ -19,7 +19,8 @@ const tasks = new Map(); let idle = true; // Indicates if the installation manager is idle // Listen for download requests from renderer process -ipcMain.on('queue-install', async (event, download) => { +ipcMain.on('queue-install', async (event, download_json) => { + const download = JSON.parse(download_json); const { id, pkgname } = download || {}; if (!id || !pkgname) { @@ -29,8 +30,8 @@ ipcMain.on('queue-install', async (event, download) => { logger.info(`收到下载任务: ${id}, 软件包名称: ${pkgname}`); - // 避免重复添加同一任务 - if (tasks.has(id)) { + // 避免重复添加同一任务,但允许重试下载 + if (tasks.has(id) && !download.retry) { tasks.get(id)?.webContents.send('install-log', { id, time: Date.now(), diff --git a/src/App.vue b/src/App.vue index bb115d76..b64d1b81 100644 --- a/src/App.vue +++ b/src/App.vue @@ -40,7 +40,7 @@ import DownloadQueue from './components/DownloadQueue.vue'; import DownloadDetail from './components/DownloadDetail.vue'; import { APM_STORE_ARCHITECTURE, APM_STORE_BASE_URL, currentApp } from './global/storeConfig'; import { downloads } from './global/downloadStatus'; -import { handleInstall } from './js/processInstall'; +import { handleInstall, handleRetry } from './modeuls/processInstall'; const logger = pino(); @@ -249,56 +249,58 @@ const escapeHtml = (s) => { }; // 下载管理方法 -const simulateDownload = (download) => { - // 模拟下载进度(实际应该调用真实的下载 API) - const totalSize = Math.random() * 100 + 50; // MB - download.totalSize = totalSize * 1024 * 1024; +// 在这里保留这个方便以后参考 +// const simulateDownload = (download) => { +// // 模拟下载进度(实际应该调用真实的下载 API) +// const totalSize = Math.random() * 100 + 50; // MB +// download.totalSize = totalSize * 1024 * 1024; - const interval = setInterval(() => { - const downloadObj = downloads.value.find(d => d.id === download.id); - if (!downloadObj || downloadObj.status !== 'downloading') { - clearInterval(interval); - return; - } +// const interval = setInterval(() => { +// const downloadObj = downloads.value.find(d => d.id === download.id); +// if (!downloadObj || downloadObj.status !== 'downloading') { +// clearInterval(interval); +// return; +// } - // 更新进度 - downloadObj.progress = Math.min(downloadObj.progress + Math.random() * 10, 100); - downloadObj.downloadedSize = (downloadObj.progress / 100) * downloadObj.totalSize; - downloadObj.speed = (Math.random() * 5 + 1) * 1024 * 1024; // 1-6 MB/s +// // 更新进度 +// downloadObj.progress = Math.min(downloadObj.progress + Math.random() * 10, 100); +// downloadObj.downloadedSize = (downloadObj.progress / 100) * downloadObj.totalSize; +// downloadObj.speed = (Math.random() * 5 + 1) * 1024 * 1024; // 1-6 MB/s - const remainingBytes = downloadObj.totalSize - downloadObj.downloadedSize; - downloadObj.timeRemaining = Math.ceil(remainingBytes / downloadObj.speed); +// const remainingBytes = downloadObj.totalSize - downloadObj.downloadedSize; +// downloadObj.timeRemaining = Math.ceil(remainingBytes / downloadObj.speed); - // 添加日志 - if (downloadObj.progress % 20 === 0 && downloadObj.progress > 0 && downloadObj.progress < 100) { - downloadObj.logs.push({ - time: Date.now(), - message: `下载进度: ${downloadObj.progress.toFixed(0)}%` - }); - } +// // 添加日志 +// if (downloadObj.progress % 20 === 0 && downloadObj.progress > 0 && downloadObj.progress < 100) { +// downloadObj.logs.push({ +// time: Date.now(), +// message: `下载进度: ${downloadObj.progress.toFixed(0)}%` +// }); +// } - // 下载完成 - if (downloadObj.progress >= 100) { - clearInterval(interval); - downloadObj.status = 'installing'; - downloadObj.logs.push({ - time: Date.now(), - message: '下载完成,开始安装...' - }); +// // 下载完成 +// if (downloadObj.progress >= 100) { +// clearInterval(interval); +// downloadObj.status = 'installing'; +// downloadObj.logs.push({ +// time: Date.now(), +// message: '下载完成,开始安装...' +// }); - // 模拟安装 - setTimeout(() => { - downloadObj.status = 'completed'; - downloadObj.endTime = Date.now(); - downloadObj.logs.push({ - time: Date.now(), - message: '安装完成!' - }); - }, 2000); - } - }, 500); -}; +// // 模拟安装 +// setTimeout(() => { +// downloadObj.status = 'completed'; +// downloadObj.endTime = Date.now(); +// downloadObj.logs.push({ +// time: Date.now(), +// message: '安装完成!' +// }); +// }, 2000); +// } +// }, 500); +// }; +// 目前 APM 商店不能暂停下载(因为 APM 本身不支持),但保留这些方法以备将来使用 const pauseDownload = (id) => { const download = downloads.value.find(d => d.id === id); if (download && download.status === 'downloading') { @@ -310,6 +312,7 @@ const pauseDownload = (id) => { } }; +// 同理 const resumeDownload = (id) => { const download = downloads.value.find(d => d.id === id); if (download && download.status === 'paused') { @@ -322,6 +325,7 @@ const resumeDownload = (id) => { } }; +// 同理 const cancelDownload = (id) => { const index = downloads.value.findIndex(d => d.id === id); if (index !== -1) { @@ -342,14 +346,14 @@ const cancelDownload = (id) => { const retryDownload = (id) => { const download = downloads.value.find(d => d.id === id); if (download && download.status === 'failed') { - download.status = 'downloading'; + download.status = 'queued'; download.progress = 0; download.downloadedSize = 0; download.logs.push({ time: Date.now(), message: '重新开始下载...' }); - simulateDownload(download); + handleRetry(download); } }; diff --git a/src/components/DownloadDetail.vue b/src/components/DownloadDetail.vue index 00efbef2..85014c49 100644 --- a/src/components/DownloadDetail.vue +++ b/src/components/DownloadDetail.vue @@ -96,7 +96,7 @@
- + --> - + --> + --> - + -->
@@ -133,15 +134,15 @@ const toggleExpand = () => { }; const pauseDownload = (id) => { - emit('pause', id); + // emit('pause', id); }; const resumeDownload = (id) => { - emit('resume', id); + // emit('resume', id); }; const cancelDownload = (id) => { - emit('cancel', id); + // emit('cancel', id); }; const retryDownload = (id) => { diff --git a/src/global/typedefinition.ts b/src/global/typedefinition.ts index 823404c3..dfac0520 100644 --- a/src/global/typedefinition.ts +++ b/src/global/typedefinition.ts @@ -29,4 +29,5 @@ export interface DownloadItem { message: string; // 日志消息 }>; source: string; // 例如 'APM Store' + retry: boolean; // 当前是否为重试下载 } \ No newline at end of file diff --git a/src/js/processInstall.ts b/src/modeuls/processInstall.ts similarity index 82% rename from src/js/processInstall.ts rename to src/modeuls/processInstall.ts index 454fbae6..adb16b78 100644 --- a/src/js/processInstall.ts +++ b/src/modeuls/processInstall.ts @@ -31,23 +31,28 @@ export const handleInstall = () => { logs: [ { time: Date.now(), message: '开始下载...' } ], - source: 'APM Store' + source: 'APM Store', + retry: false }; downloads.value.push(download); - // 模拟下载进度(实际应该调用真实的下载 API) - // simulateDownload(download); - // Send to main process to start download - window.ipcRenderer.send('queue-install', download); + window.ipcRenderer.send('queue-install', JSON.stringify(download)); - const encodedPkg = encodeURIComponent(currentApp.value.Pkgname); + // const encodedPkg = encodeURIComponent(currentApp.value.Pkgname); // openApmStoreUrl(`apmstore://install?pkg=${encodedPkg}`, { // fallbackText: `/usr/bin/apm-installer --install ${currentApp.value.Pkgname}` // }); }; +export const handleRetry = (download_: DownloadItem) => { + if (!download_?.pkgname) return; + download_.retry = true; + // Send to main process to start download + window.ipcRenderer.send('queue-install', JSON.stringify(download_)); +}; + window.ipcRenderer.on('install-status', (_event, log: InstallLog) => { const downloadObj: any = downloads.value.find(d => d.id === log.id); downloadObj.status = log.message;