Files
gdt-tool/src/renderer/components/UpdateDialog.vue
T
zhanggy 0eb2dcf8c2 feat: implement auto-update functionality with GitHub integration
- Added AutoUpdater class to manage update checks and downloads.
- Integrated auto-updater in the main process after the main window is created.
- Enhanced preload script to expose update-related IPC channels.
- Created UpdateDialog component to handle user interactions for updates.
- Implemented state management for update status using Pinia store.
- Added localization support for update messages in multiple languages.
- Documented auto-update configuration steps for private GitHub repositories.
- Created .env.example for GitHub token configuration.
2025-10-28 22:53:26 +08:00

196 lines
5.3 KiB
Vue

<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-spacer>
<v-btn
color="primary"
variant="text"
@click="skipUpdate"
>
{{ t('update.skipUpdate') }}
</v-btn>
<v-btn
color="primary"
variant="flat"
@click="downloadUpdate"
:loading="isDownloading"
>
{{ 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-spacer>
<v-btn
color="primary"
variant="text"
@click="cancelDownload"
:disabled="isDownloadComplete"
>
{{ 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-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-spacer>
<v-btn
color="primary"
variant="flat"
@click="closeDialog"
>
{{ t('common.ok') }}
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script setup lang="ts">
import { computed, onMounted, onUnmounted } from 'vue'
import { useAppStore, UpdateStatus } from '@/renderer/store/app'
import { useI18n } from 'vue-i18n'
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 ? (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>