From e143eebee73dce0b89d7b852a0aefb27bfba6951 Mon Sep 17 00:00:00 2001 From: gmh01 Date: Thu, 23 Jul 2026 21:26:55 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E5=86=99=E6=89=93?= =?UTF-8?q?=E5=8C=85=E6=B5=81=E7=A8=8B=EF=BC=8C=E7=A7=BB=E9=99=A4=20Pinia?= =?UTF-8?q?=20=E6=94=B9=E7=94=A8=E6=9C=AC=E5=9C=B0=E7=8A=B6=E6=80=81=20+?= =?UTF-8?q?=20=E5=85=A8=E5=B1=8F=E5=8F=A0=E5=8A=A0=E5=B1=82=E5=8A=A8?= =?UTF-8?q?=E7=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/PackProgress.vue | 205 ----------------------------- src/stores/packaging.js | 57 -------- src/views/PackPage.vue | 221 ++++++++++++++++++++++++++++---- 3 files changed, 198 insertions(+), 285 deletions(-) delete mode 100644 src/components/PackProgress.vue delete mode 100644 src/stores/packaging.js diff --git a/src/components/PackProgress.vue b/src/components/PackProgress.vue deleted file mode 100644 index a6bd741..0000000 --- a/src/components/PackProgress.vue +++ /dev/null @@ -1,205 +0,0 @@ - - - - - diff --git a/src/stores/packaging.js b/src/stores/packaging.js deleted file mode 100644 index 2314325..0000000 --- a/src/stores/packaging.js +++ /dev/null @@ -1,57 +0,0 @@ -import { defineStore } from 'pinia' -import { nextTick } from 'vue' - -export const usePackagingStore = defineStore('packaging', { - state: () => ({ - isPacking: false, - progress: { - stage: '', - message: '', - percent: 0 - }, - result: null, - _cleanup: null - }), - - actions: { - async startPacking(projectPath, outputPath) { - this._cleanup?.() - - this.isPacking = true - this.progress = { stage: 'starting', message: '准备开始...', percent: 0 } - this.result = null - - this._cleanup = window.api.pack.onProgress((progress) => { - this.progress = progress - }) - - await nextTick() - - try { - const result = await window.api.pack.start(projectPath, outputPath) - this.isPacking = false - this.result = result - } catch (err) { - this.isPacking = false - this.result = { success: false, error: err.message } - } - this._cleanup?.() - this._cleanup = null - }, - - cancelPacking() { - window.api.pack.cancel() - this.isPacking = false - this._cleanup?.() - this._cleanup = null - }, - - reset() { - this.isPacking = false - this.progress = { stage: '', message: '', percent: 0 } - this.result = null - this._cleanup?.() - this._cleanup = null - } - } -}) diff --git a/src/views/PackPage.vue b/src/views/PackPage.vue index c9fd313..5d35e78 100644 --- a/src/views/PackPage.vue +++ b/src/views/PackPage.vue @@ -38,41 +38,54 @@ -
+

打包过程可能需要几分钟,请耐心等待

- - -
+

打包完成!

安装包已生成

-

{{ packStore.result.outputPath }}

+

{{ result.outputPath }}

-
+

打包失败

-

{{ packStore.result.error }}

+

{{ result.error }}

+ +
+
+
+
+
+
{{ stageLabel }}
+
+
+
+
{{ progressMsg }}
+ +
+
@@ -80,18 +93,22 @@ import { ref, computed, onBeforeUnmount } from 'vue' import { useRouter } from 'vue-router' import { useProjectStore } from '../stores/project' -import { usePackagingStore } from '../stores/packaging' -import PackProgress from '../components/PackProgress.vue' const router = useRouter() const store = useProjectStore() -const packStore = usePackagingStore() -const outputPath = ref(null) if (!store.hasProject) { router.replace('/') } +const outputPath = ref(null) +const isPacking = ref(false) +const result = ref(null) +const progressStage = ref('') +const progressMsg = ref('') +const progressPct = ref(0) +const showOverlay = ref(false) + const fileCount = computed(() => countFiles(store.files)) const platformLabel = computed(() => { @@ -102,6 +119,74 @@ const platformLabel = computed(() => { return p }) +const stageLabel = computed(() => { + const labels = { + 'starting': '准备开始…', + 'prepare': '准备中…', + 'copy-files': '复制文件…', + 'configure': '配置应用…', + 'install': '安装依赖…', + 'download': '下载中…', + 'build': '打包中…', + 'sign': '签名中…', + 'complete': '打包完成', + 'error': '出错了' + } + return labels[progressStage.value] || progressStage.value || '准备开始…' +}) + +const isIndeterminate = computed(() => { + return ['starting', 'install', 'download'].includes(progressStage.value) +}) + +const barStyle = computed(() => { + if (isIndeterminate.value) return {} + return { width: Math.round(progressPct.value) + '%' } +}) + +async function startPack() { + isPacking.value = true + result.value = null + progressStage.value = 'starting' + progressMsg.value = '正在准备打包环境…' + progressPct.value = 0 + showOverlay.value = true + + const cleanup = window.api.pack.onProgress((p) => { + progressStage.value = p.stage + progressMsg.value = p.message + if (p.percent != null) progressPct.value = p.percent + }) + + try { + const res = await window.api.pack.start(store.projectPath, outputPath.value) + isPacking.value = false + result.value = res + if (res.error) { + progressStage.value = 'error' + progressMsg.value = res.error + } else { + progressStage.value = 'complete' + progressMsg.value = '打包完成!' + progressPct.value = 100 + } + } catch (err) { + isPacking.value = false + result.value = { success: false, error: err.message } + progressStage.value = 'error' + progressMsg.value = err.message + } + cleanup?.() +} + +function cancelPack() { + window.api.pack.cancel() + isPacking.value = false + showOverlay.value = false + progressStage.value = '' + progressMsg.value = '' +} + async function selectOutputPath() { const ext = process.platform === 'win32' ? 'exe' : process.platform === 'darwin' ? 'dmg' : 'AppImage' const path = await window.api.dialog.saveFile({ @@ -111,12 +196,10 @@ async function selectOutputPath() { if (path) outputPath.value = path } -function startPack() { - packStore.startPacking(store.projectPath, outputPath.value) -} - function goBack() { - packStore.reset() + showOverlay.value = false + isPacking.value = false + result.value = null router.push('/editor') } @@ -130,8 +213,8 @@ function countFiles(files) { } onBeforeUnmount(() => { - if (!packStore.result) { - packStore.reset() + if (isPacking.value) { + window.api.pack.cancel() } }) @@ -252,4 +335,96 @@ onBeforeUnmount(() => { word-break: break-all; max-width: 100%; } + +.pack-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(15, 23, 42, 0.85); + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; +} + +.overlay-content { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); + box-shadow: var(--shadow-md); + padding: 32px 40px; + min-width: 380px; + display: flex; + flex-direction: column; + align-items: center; + gap: 16px; +} + +.overlay-spinner { + width: 48px; + height: 48px; + display: flex; + align-items: center; + justify-content: center; +} + +.spinner-ring { + width: 36px; + height: 36px; + border: 3px solid var(--border); + border-top-color: var(--primary); + border-radius: 50%; + animation: spin 0.7s linear infinite; +} + +@keyframes spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} + +.overlay-stage { + font-size: 16px; + font-weight: 600; + color: var(--text); +} + +.overlay-bar { + width: 100%; + height: 6px; + background: var(--border); + border-radius: 3px; + overflow: hidden; +} + +.overlay-bar-fill { + height: 100%; + background: linear-gradient(90deg, var(--primary), #818cf8); + border-radius: 3px; + transition: width 0.25s ease; +} + +.overlay-bar-fill.pulse { + width: 28%; + animation: slide 1.2s ease-in-out infinite; +} + +@keyframes slide { + 0% { transform: translateX(-100%); } + 50% { transform: translateX(200%); } + 100% { transform: translateX(400%); } +} + +.overlay-msg { + font-size: 13px; + color: var(--text-secondary); + text-align: center; + word-break: break-all; + max-width: 360px; +} + +.overlay-cancel { + margin-top: 4px; +}