From cd43f34cbd4717e78a548ee45fa20859d1277daa Mon Sep 17 00:00:00 2001 From: shenmo Date: Sun, 22 Mar 2026 19:18:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=85=B3=E4=BA=8E?= =?UTF-8?q?=E5=AF=B9=E8=AF=9D=E6=A1=86=E5=B9=B6=E4=BC=98=E5=8C=96=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E5=88=87=E6=8D=A2=E6=8C=89=E9=92=AE=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 AboutModal 组件显示应用版本和相关信息 - 重构 ThemeToggle 组件为更简洁的图标按钮 - 在侧边栏添加关于按钮并实现打开对话框功能 - 通过预加载脚本获取 package.json 版本号 - 支持命令行参数 --version/-v 显示版本号 --- electron/main/index.ts | 37 ++++++----- electron/preload/index.ts | 9 +++ src/App.vue | 16 +++++ src/components/AboutModal.vue | 116 +++++++++++++++++++++++++++++++++ src/components/AppSidebar.vue | 36 +++++++--- src/components/ThemeToggle.vue | 40 ++++-------- 6 files changed, 201 insertions(+), 53 deletions(-) create mode 100644 src/components/AboutModal.vue diff --git a/electron/main/index.ts b/electron/main/index.ts index 1c83c533..ab771229 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -19,6 +19,28 @@ import { isLoaded } from "../global.js"; import { tasks } from "./backend/install-manager.js"; import { sendTelemetryOnce } from "./backend/telemetry.js"; +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +process.env.APP_ROOT = path.join(__dirname, "../.."); + +/** 与项目 package.json 一致的版本号:打包用 app.getVersion(),未打包时读 package.json */ +function getAppVersion(): string { + if (app.isPackaged) return app.getVersion(); + const pkgPath = path.join(process.env.APP_ROOT ?? __dirname, "package.json"); + try { + const raw = fs.readFileSync(pkgPath, "utf8"); + const pkg = JSON.parse(raw) as { version?: string }; + return typeof pkg.version === "string" ? pkg.version : "dev"; + } catch { + return "dev"; + } +} + +// 处理 --version 参数(在单实例检查之前) +if (process.argv.includes("--version") || process.argv.includes("-v")) { + console.log(getAppVersion()); + process.exit(0); +} + // Assure single instance application if (!app.requestSingleInstanceLock()) { app.exit(0); @@ -28,7 +50,6 @@ import "./backend/install-manager.js"; import "./handle-url-scheme.js"; const logger = pino({ name: "index.ts" }); -const __dirname = path.dirname(fileURLToPath(import.meta.url)); // The built directory structure // @@ -40,8 +61,6 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)); // ├─┬ dist // │ └── index.html > Electron-Renderer // -process.env.APP_ROOT = path.join(__dirname, "../.."); - export const MAIN_DIST = path.join(process.env.APP_ROOT, "dist-electron"); export const RENDERER_DIST = path.join(process.env.APP_ROOT, "dist"); export const VITE_DEV_SERVER_URL = process.env.VITE_DEV_SERVER_URL; @@ -64,18 +83,6 @@ if (!app.requestSingleInstanceLock()) { let win: BrowserWindow | null = null; const preload = path.join(__dirname, "../preload/index.mjs"); const indexHtml = path.join(RENDERER_DIST, "index.html"); -/** 与项目 package.json 一致的版本号:打包用 app.getVersion(),未打包时读 package.json */ -function getAppVersion(): string { - if (app.isPackaged) return app.getVersion(); - const pkgPath = path.join(process.env.APP_ROOT ?? __dirname, "package.json"); - try { - const raw = fs.readFileSync(pkgPath, "utf8"); - const pkg = JSON.parse(raw) as { version?: string }; - return typeof pkg.version === "string" ? pkg.version : "dev"; - } catch { - return "dev"; - } -} const getUserAgent = (): string => { return `Spark-Store/${getAppVersion()}`; diff --git a/electron/preload/index.ts b/electron/preload/index.ts index aab78e57..ef9543a0 100644 --- a/electron/preload/index.ts +++ b/electron/preload/index.ts @@ -36,6 +36,15 @@ contextBridge.exposeInMainWorld("apm_store", { return arch; } })(), + version: (() => { + // 从 package.json 读取版本号 + try { + const pkg = require("../../package.json"); + return pkg.version || "unknown"; + } catch { + return "unknown"; + } + })(), }); // --------- Preload scripts loading --------- diff --git a/src/App.vue b/src/App.vue index 0555d3bd..f7cf0438 100644 --- a/src/App.vue +++ b/src/App.vue @@ -23,6 +23,7 @@ @toggle-theme="toggleTheme" @select-category="selectCategory" @close="isSidebarOpen = false" + @open-about="openAboutModal" /> @@ -132,6 +133,11 @@ @close="closeUninstallModal" @success="onUninstallSuccess" /> + + @@ -150,6 +156,7 @@ import DownloadDetail from "./components/DownloadDetail.vue"; import InstalledAppsModal from "./components/InstalledAppsModal.vue"; import UpdateAppsModal from "./components/UpdateAppsModal.vue"; import UninstallConfirmModal from "./components/UninstallConfirmModal.vue"; +import AboutModal from "./components/AboutModal.vue"; import { APM_STORE_BASE_URL, currentApp, @@ -240,6 +247,7 @@ const updateLoading = ref(false); const updateError = ref(""); const showUninstallModal = ref(false); const uninstallTargetApp: Ref = ref(null); +const showAboutModal = ref(false); /** 启动参数 --no-apm => 仅 Spark;--no-spark => 仅 APM;由主进程 IPC 提供 */ const storeFilter = ref<"spark" | "apm" | "both">("both"); @@ -834,6 +842,14 @@ const uninstallInstalledApp = (app: App) => { requestUninstall(app); }; +const openAboutModal = () => { + showAboutModal.value = true; +}; + +const closeAboutModal = () => { + showAboutModal.value = false; +}; + // TODO: 目前 APM 商店不能暂停下载 const pauseDownload = (id: DownloadItem) => { const download = downloads.value.find((d) => d.id === id.id); diff --git a/src/components/AboutModal.vue b/src/components/AboutModal.vue new file mode 100644 index 00000000..677ebb0c --- /dev/null +++ b/src/components/AboutModal.vue @@ -0,0 +1,116 @@ + + + diff --git a/src/components/AppSidebar.vue b/src/components/AppSidebar.vue index 6f66c95e..dd922758 100644 --- a/src/components/AppSidebar.vue +++ b/src/components/AppSidebar.vue @@ -17,17 +17,19 @@ > - +
+ + +
-
@@ -84,6 +86,17 @@ >
+ +
+ +
@@ -103,6 +116,7 @@ const emit = defineEmits<{ (e: "toggle-theme"): void; (e: "select-category", category: string): void; (e: "close"): void; + (e: "open-about"): void; }>(); const toggleTheme = () => { @@ -112,4 +126,8 @@ const toggleTheme = () => { const selectCategory = (category: string) => { emit("select-category", category); }; + +const openAbout = () => { + emit("open-about"); +}; diff --git a/src/components/ThemeToggle.vue b/src/components/ThemeToggle.vue index 573ad361..d89196d1 100644 --- a/src/components/ThemeToggle.vue +++ b/src/components/ThemeToggle.vue @@ -1,24 +1,12 @@ @@ -37,21 +25,15 @@ const toggle = () => { emit("toggle"); }; -const label = computed(() => { - if (props.themeMode === "auto") return "跟随系统"; - if (props.themeMode === "dark") return "深色主题"; - return "浅色主题"; +const title = computed(() => { + if (props.themeMode === "auto") return "自动模式"; + if (props.themeMode === "dark") return "深色模式"; + return "浅色模式"; }); const iconClass = computed(() => { - if (props.themeMode === "auto") return "fa-adjust text-slate-500"; - if (props.themeMode === "dark") return "fa-moon text-amber-200"; - return "fa-sun text-amber-400"; -}); - -const togglePosition = computed(() => { - if (props.themeMode === "auto") return "translate-x-4"; - if (props.themeMode === "dark") return "translate-x-7"; - return "translate-x-1"; + if (props.themeMode === "auto") return "fa-adjust"; + if (props.themeMode === "dark") return "fa-moon"; + return "fa-sun"; });