Files
gdt-tool/src/renderer/components/UpdateDialog.vue
T
2025-11-05 14:46:49 +08:00

200 lines
5.3 KiB
Vue

<script setup lang="ts">
import { computed, onMounted, onUnmounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { useAppStore } from '@/renderer/store/app';
const { t } = useI18n();
const appStore = useAppStore();
// 从store获取状态
const updateStatus = computed(() => appStore.updateStatus);
const downloadProgress = computed(() => appStore.downloadProgress);
// 对话框显示状态
const dialogVisible = computed({
get: () => {
return appStore.updateDialogVisible
|| updateStatus.value.status === 'available'
|| updateStatus.value.status === 'downloading'
|| updateStatus.value.status === 'downloaded'
|| (updateStatus.value.status === 'error' && !!updateStatus.value.error);
},
set: (value: boolean) => {
if (value) {
appStore.showUpdateDialog();
} else {
appStore.hideUpdateDialog();
}
},
});
const latestVersion = computed(() => {
// 这里应该从API获取最新版本号,暂时使用固定值
return `v${(updateStatus.value.currentVersion || '1.0.0').replace(/^v?/, '').split('.').map((n, i) =>
i === 2 ? (Number.parseInt(n) + 1).toString() : n,
).join('.')}`;
});
const isDownloading = computed(() => updateStatus.value.status === 'downloading');
const isDownloadComplete = computed(() => downloadProgress.value >= 100);
// 方法
const downloadUpdate = async () => {
await appStore.startUpdateDownload();
};
const skipUpdate = () => {
appStore.setUpdateStatus('not-available', updateStatus.value.currentVersion);
dialogVisible.value = false;
};
const cancelDownload = () => {
// 取消下载逻辑
appStore.setUpdateStatus('not-available', updateStatus.value.currentVersion);
dialogVisible.value = false;
};
const laterInstall = () => {
dialogVisible.value = false;
};
const installUpdate = () => {
// 安装更新,这需要触发quitAndInstall
window.mainApi.invoke('msgInstallUpdate');
dialogVisible.value = false;
};
const closeDialog = () => {
appStore.setUpdateStatus('idle');
dialogVisible.value = false;
};
// 监听更新下载进度
onMounted(() => {
// 监听主进程发来的更新相关事件
window.mainApi.on('update-download-progress', (_, progress) => {
appStore.setDownloadProgress(progress.percent);
});
});
onUnmounted(() => {
// 移除事件监听器
window.mainApi.off('update-download-progress', () => {});
});
</script>
<template>
<v-dialog
v-model="dialogVisible"
max-width="500"
persistent
:scrim="false"
>
<v-card v-if="updateStatus.status === 'available'">
<v-card-title class="headline">
{{ t('update.newVersionAvailable') }}
</v-card-title>
<v-card-text>
<div>{{ t('update.currentVersion') }}: {{ updateStatus.currentVersion }}</div>
<div>{{ t('update.latestVersion') }}: {{ latestVersion }}</div>
<div class="mt-3">
{{ t('update.updateDescription') }}
</div>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn
color="primary"
variant="text"
@click="skipUpdate"
>
{{ t('update.skipUpdate') }}
</v-btn>
<v-btn
color="primary"
variant="flat"
:loading="isDownloading"
@click="downloadUpdate"
>
{{ t('update.downloadUpdate') }}
</v-btn>
</v-card-actions>
</v-card>
<v-card v-else-if="updateStatus.status === 'downloading'">
<v-card-title class="headline">
{{ t('update.downloadingUpdate') }}
</v-card-title>
<v-card-text>
<v-progress-linear
:model-value="downloadProgress"
color="primary"
height="25"
rounded
>
<strong>{{ Math.round(downloadProgress) }}%</strong>
</v-progress-linear>
<div class="mt-3">
{{ t('update.downloadProgressText') }}
</div>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn
color="primary"
variant="text"
:disabled="isDownloadComplete"
@click="cancelDownload"
>
{{ t('common.cancel') }}
</v-btn>
</v-card-actions>
</v-card>
<v-card v-else-if="updateStatus.status === 'downloaded'">
<v-card-title class="headline">
{{ t('update.updateDownloaded') }}
</v-card-title>
<v-card-text>
{{ t('update.updateReadyToInstall') }}
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn
color="primary"
variant="text"
@click="laterInstall"
>
{{ t('update.laterInstall') }}
</v-btn>
<v-btn
color="primary"
variant="flat"
@click="installUpdate"
>
{{ t('update.installNow') }}
</v-btn>
</v-card-actions>
</v-card>
<v-card v-else-if="updateStatus.status === 'error'">
<v-card-title class="headline">
{{ t('update.updateError') }}
</v-card-title>
<v-card-text>
{{ updateStatus.error }}
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn
color="primary"
variant="flat"
@click="closeDialog"
>
{{ t('common.ok') }}
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>