From 44df4562409daf8e87b38926aa54e397ce329ece Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=B2=A1=E5=A4=8D=E4=B9=A0?= <2353956224@qq.com>
Date: Fri, 13 Mar 2026 17:48:00 +0800
Subject: [PATCH] =?UTF-8?q?mac=E4=B8=8D=E5=BC=BA=E5=88=B6=E6=9B=B4?=
=?UTF-8?q?=E6=96=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/App.vue | 3 +-
src/components/UpdateNotification.vue | 39 +++-
src/hooks/useUpdate.js | 206 +++++++++++-------
src/pages/UpdateChecker.vue | 32 ++-
....timestamp-1773392797167-9352ce3e637ed.mjs | 25 +++
5 files changed, 218 insertions(+), 87 deletions(-)
create mode 100644 vite.config.js.timestamp-1773392797167-9352ce3e637ed.mjs
diff --git a/src/App.vue b/src/App.vue
index 12491b4..d2ac8ac 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -14,7 +14,8 @@
-
+
+
diff --git a/src/components/UpdateNotification.vue b/src/components/UpdateNotification.vue
index 8ce93ac..f74428f 100644
--- a/src/components/UpdateNotification.vue
+++ b/src/components/UpdateNotification.vue
@@ -38,10 +38,31 @@
{{ updateInfo.releaseNotes }}
-
+
+
+
+
+ Mac 版本请前往官网下载最新安装包
+
+
+
+
+
+
+
+
+
+
+
@@ -107,6 +128,7 @@ const {
progress,
error,
currentVersion,
+ isMac,
checkForUpdates,
downloadUpdate,
installUpdate,
@@ -120,4 +142,13 @@ function formatBytes(bytes) {
const i = Math.floor(Math.log(bytes) / Math.log(k))
return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`
}
+
+// 打开下载页面
+const openDownloadPage = () => {
+ if (isElectronEnv) {
+ window.electronAPI.openExternal?.('https://yolozs.com/')
+ } else {
+ window.open('https://yolozs.com/', '_blank')
+ }
+}
diff --git a/src/hooks/useUpdate.js b/src/hooks/useUpdate.js
index 89d3867..d9732d5 100644
--- a/src/hooks/useUpdate.js
+++ b/src/hooks/useUpdate.js
@@ -1,94 +1,141 @@
-import { ref, onMounted, onUnmounted } from 'vue'
+import { ref, onMounted, onUnmounted, computed } from 'vue'
import { isElectron } from '../utils/electronBridge'
-// NOTE: Since we are using JS, we don't have interfaces, but structure remains same.
+// ============== 单例状态 ==============
+// 在函数外部定义,确保所有组件共享同一个状态
+
+const status = ref('idle')
+const updateInfo = ref(null)
+const progress = ref(null)
+const error = ref(null)
+const currentVersion = ref('')
+const platform = ref('unknown')
+let listenersSetup = false // 标记是否已设置监听器
+let unsubList = [] // 取消订阅列表
+
+const isMac = computed(() => platform.value === 'mac')
+const isWindows = computed(() => platform.value === 'windows')
+
+// 平台判断
+const getPlatformInfo = () => {
+ const navPlatform = navigator.platform || ''
+ const ua = navigator.userAgent || ''
+ const appVersion = navigator.appVersion || ''
+
+ console.log('[useUpdate] 平台检测信息:', {
+ navPlatform,
+ userAgent: ua,
+ appVersion
+ })
+
+ const p = navPlatform.toLowerCase()
+ if (p.includes('mac')) return 'mac'
+ if (p.includes('win')) return 'windows'
+ if (p.includes('linux')) return 'linux'
+
+ const u = ua.toLowerCase()
+ if (u.includes('macintosh') || u.includes('mac os') || u.includes('macintel')) return 'mac'
+ if (u.includes('windows') || u.includes('win32') || u.includes('win64')) return 'windows'
+ if (u.includes('linux')) return 'linux'
+
+ const av = appVersion.toLowerCase()
+ if (av.includes('mac')) return 'mac'
+ if (av.includes('win')) return 'windows'
+ if (av.includes('linux')) return 'linux'
+
+ return 'unknown'
+}
+
+// 获取当前版本
+const fetchVersion = () => {
+ if (!isElectron()) {
+ currentVersion.value = 'web'
+ return
+ }
+ window.electronAPI.getAppVersion().then(v => {
+ currentVersion.value = v
+ }).catch(console.error)
+}
+
+// 设置监听器(只执行一次)
+const setupListeners = () => {
+ if (!isElectron() || listenersSetup) return
+
+ listenersSetup = true
+ const api = window.electronAPI
+
+ // 正在检查
+ if (api.onUpdateChecking) {
+ unsubList.push(api.onUpdateChecking(() => {
+ status.value = 'checking'
+ }))
+ }
+
+ // 发现新版本
+ unsubList.push(api.onUpdateAvailable((info) => {
+ updateInfo.value = info
+ status.value = 'available'
+ error.value = null
+ }))
+
+ // 无可用更新
+ if (api.onUpdateNotAvailable) {
+ unsubList.push(api.onUpdateNotAvailable(() => {
+ status.value = 'idle'
+ }))
+ }
+
+ unsubList.push(api.onUpdateProgress((prog) => {
+ progress.value = prog
+ status.value = 'downloading'
+ }))
+
+ unsubList.push(api.onUpdateDownloaded(() => {
+ status.value = 'downloaded'
+ progress.value = null
+ }))
+
+ unsubList.push(api.onUpdateError((err) => {
+ error.value = err.message
+ status.value = 'error'
+ }))
+
+ // macOS 手动安装提示
+ if (api.onUpdateManualInstall) {
+ unsubList.push(api.onUpdateManualInstall((info) => {
+ console.log('macOS 需要手动安装更新:', info.path)
+ alert(`更新已下载完成!\n\n请手动安装更新文件:\n${info.path}\n\n应用将退出。`)
+ }))
+ }
+}
+
+// 清理监听器
+const cleanupListeners = () => {
+ unsubList.forEach(unsub => unsub && unsub())
+ unsubList = []
+ listenersSetup = false
+}
/**
* 应用更新 Hook (Vue Composable)
- * 管理更新状态、进度和操作
+ * 单例模式:所有组件共享同一个状态和监听器
* 注意:此 Composable 仅在 Electron 环境中有效
*/
export function useUpdate() {
- const status = ref('idle')
- const updateInfo = ref(null)
- const progress = ref(null)
- const error = ref(null)
- const currentVersion = ref('')
-
- // 获取当前版本
- const fetchVersion = () => {
- if (!isElectron()) {
- currentVersion.value = 'web'
- return
- }
- window.electronAPI.getAppVersion().then(v => {
- currentVersion.value = v
- }).catch(console.error)
- }
-
- let unsubList = []
-
- // 监听更新事件
- const setupListeners = () => {
- if (!isElectron()) return
-
- const api = window.electronAPI
-
- // 正在检查
- if (api.onUpdateChecking) {
- unsubList.push(api.onUpdateChecking(() => {
- status.value = 'checking'
- }))
- }
-
- // 发现新版本
- unsubList.push(api.onUpdateAvailable((info) => {
- updateInfo.value = info
- status.value = 'available'
- error.value = null
- }))
-
- // 无可用更新
- if (api.onUpdateNotAvailable) {
- unsubList.push(api.onUpdateNotAvailable(() => {
- status.value = 'idle'
- }))
- }
-
- unsubList.push(api.onUpdateProgress((prog) => {
- progress.value = prog
- status.value = 'downloading'
- }))
-
- unsubList.push(api.onUpdateDownloaded(() => {
- status.value = 'downloaded'
- progress.value = null
- }))
-
- unsubList.push(api.onUpdateError((err) => {
- error.value = err.message
- status.value = 'error'
- }))
-
- // macOS 手动安装提示
- if (api.onUpdateManualInstall) {
- unsubList.push(api.onUpdateManualInstall((info) => {
- console.log('macOS 需要手动安装更新:', info.path)
- // 显示提示让用户知道需要手动安装
- alert(`更新已下载完成!\n\n请手动安装更新文件:\n${info.path}\n\n应用将退出。`)
- }))
- }
- }
-
+ // 每个组件挂载时的初始化逻辑
onMounted(() => {
+ // 检测平台(确保只设置一次)
+ if (isElectron() && platform.value === 'unknown') {
+ platform.value = getPlatformInfo()
+ console.log('[useUpdate] 平台检测结果:', platform.value)
+ }
fetchVersion()
setupListeners()
})
- onUnmounted(() => {
- unsubList.forEach(unsub => unsub && unsub())
- unsubList = []
- })
+ // 注意:不在这里清理监听器,因为是单例模式
+ // 只在最后一个组件卸载时才清理(这里简化处理,不清理)
+ // 如果需要严格清理,可以使用引用计数
const checkForUpdates = () => {
if (!isElectron()) return
@@ -132,6 +179,9 @@ export function useUpdate() {
progress,
error,
currentVersion,
+ platform,
+ isMac,
+ isWindows,
checkForUpdates,
downloadUpdate,
installUpdate,
diff --git a/src/pages/UpdateChecker.vue b/src/pages/UpdateChecker.vue
index 940a2af..e439121 100644
--- a/src/pages/UpdateChecker.vue
+++ b/src/pages/UpdateChecker.vue
@@ -76,10 +76,24 @@
{{ updateInfo.releaseNotes }}
-
+
+
+
+ Mac 版本请前往官网下载最新安装包
+
+
+
+
+
+
+
+
必须更新后才能使用程序
@@ -185,6 +199,7 @@ const {
progress,
error,
currentVersion,
+ isMac,
checkForUpdates,
downloadUpdate,
installUpdate
@@ -304,6 +319,15 @@ function formatBytes(bytes) {
return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`
}
+// 打开下载页面(Mac 用户)
+function openDownloadPage() {
+ if (isElectronEnv) {
+ window.electronAPI.openExternal?.('https://yolozs.com/')
+ } else {
+ window.open('https://yolozs.com/', '_blank')
+ }
+}
+
onUnmounted(() => {
if (timeoutTimer) clearTimeout(timeoutTimer)
if (countdownTimer) clearInterval(countdownTimer)
diff --git a/vite.config.js.timestamp-1773392797167-9352ce3e637ed.mjs b/vite.config.js.timestamp-1773392797167-9352ce3e637ed.mjs
new file mode 100644
index 0000000..0e9836f
--- /dev/null
+++ b/vite.config.js.timestamp-1773392797167-9352ce3e637ed.mjs
@@ -0,0 +1,25 @@
+// vite.config.js
+import { defineConfig } from "file:///D:/git/gitea/web-fusion/node_modules/vite/dist/node/index.js";
+import vue from "file:///D:/git/gitea/web-fusion/node_modules/@vitejs/plugin-vue/dist/index.mjs";
+import { resolve } from "path";
+var __vite_injected_original_dirname = "D:\\git\\gitea\\web-fusion";
+var vite_config_default = defineConfig({
+ plugins: [vue()],
+ resolve: {
+ alias: {
+ "@": resolve(__vite_injected_original_dirname, "src")
+ }
+ },
+ server: {
+ port: 5173,
+ host: true
+ },
+ build: {
+ outDir: "dist",
+ sourcemap: false
+ }
+});
+export {
+ vite_config_default as default
+};
+//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcuanMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJEOlxcXFxnaXRcXFxcZ2l0ZWFcXFxcd2ViLWZ1c2lvblwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiRDpcXFxcZ2l0XFxcXGdpdGVhXFxcXHdlYi1mdXNpb25cXFxcdml0ZS5jb25maWcuanNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL0Q6L2dpdC9naXRlYS93ZWItZnVzaW9uL3ZpdGUuY29uZmlnLmpzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHZ1ZSBmcm9tICdAdml0ZWpzL3BsdWdpbi12dWUnXHJcbmltcG9ydCB7IHJlc29sdmUgfSBmcm9tICdwYXRoJ1xyXG5cclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcclxuICAgIHBsdWdpbnM6IFt2dWUoKV0sXHJcbiAgICByZXNvbHZlOiB7XHJcbiAgICAgICAgYWxpYXM6IHtcclxuICAgICAgICAgICAgJ0AnOiByZXNvbHZlKF9fZGlybmFtZSwgJ3NyYycpXHJcbiAgICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNlcnZlcjoge1xyXG4gICAgICAgIHBvcnQ6IDUxNzMsXHJcbiAgICAgICAgaG9zdDogdHJ1ZVxyXG4gICAgfSxcclxuICAgIGJ1aWxkOiB7XHJcbiAgICAgICAgb3V0RGlyOiAnZGlzdCcsXHJcbiAgICAgICAgc291cmNlbWFwOiBmYWxzZVxyXG4gICAgfVxyXG59KVxyXG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQStQLFNBQVMsb0JBQW9CO0FBQzVSLE9BQU8sU0FBUztBQUNoQixTQUFTLGVBQWU7QUFGeEIsSUFBTSxtQ0FBbUM7QUFLekMsSUFBTyxzQkFBUSxhQUFhO0FBQUEsRUFDeEIsU0FBUyxDQUFDLElBQUksQ0FBQztBQUFBLEVBQ2YsU0FBUztBQUFBLElBQ0wsT0FBTztBQUFBLE1BQ0gsS0FBSyxRQUFRLGtDQUFXLEtBQUs7QUFBQSxJQUNqQztBQUFBLEVBQ0o7QUFBQSxFQUNBLFFBQVE7QUFBQSxJQUNKLE1BQU07QUFBQSxJQUNOLE1BQU07QUFBQSxFQUNWO0FBQUEsRUFDQSxPQUFPO0FBQUEsSUFDSCxRQUFRO0FBQUEsSUFDUixXQUFXO0FBQUEsRUFDZjtBQUNKLENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg==