From 1e082944723477b3c34ae315f574823ff1ef4e8c Mon Sep 17 00:00:00 2001 From: digua Date: Wed, 17 Dec 2025 20:43:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=86=E6=9E=90=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release.yml | 4 ++ electron.vite.config.ts | 104 ++++++++++++++++--------------- electron/main/analytics.ts | 112 ++++++++++++++++++++++++++++++++++ electron/main/index.ts | 6 ++ package.json | 1 + pnpm-lock.yaml | 12 ++++ 6 files changed, 191 insertions(+), 48 deletions(-) create mode 100644 electron/main/analytics.ts diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9c1f8ee..cefba5e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -62,6 +62,8 @@ jobs: APPLE_API_KEY: ~/private_keys/AuthKey_${{ secrets.APPLE_API_KEY_ID }}.p8 APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} + # 分析服务 + MAIN_VITE_APTABASE_APP_KEY: ${{ secrets.APTABASE_APP_KEY }} run: pnpm build:mac - name: Upload macOS artifacts @@ -112,6 +114,8 @@ jobs: - name: Build Electron app for Windows env: GH_TOKEN: ${{ secrets.GH_TOKEN }} + # 分析服务 + MAIN_VITE_APTABASE_APP_KEY: ${{ secrets.APTABASE_APP_KEY }} run: pnpm build:win - name: Upload Windows artifacts diff --git a/electron.vite.config.ts b/electron.vite.config.ts index 40d7603..3a828ce 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -1,60 +1,68 @@ import { resolve } from 'path' -import { defineConfig, externalizeDepsPlugin } from 'electron-vite' +import { defineConfig, externalizeDepsPlugin, loadEnv } from 'electron-vite' import vue from '@vitejs/plugin-vue' import ui from '@nuxt/ui/vite' -export default defineConfig({ - main: { - plugins: [externalizeDepsPlugin()], - build: { - rollupOptions: { - input: { - index: resolve(__dirname, 'electron/main/index.ts'), - 'worker/dbWorker': resolve(__dirname, 'electron/main/worker/dbWorker.ts'), - }, +export default defineConfig(({ mode }) => { + // 加载环境变量(带 MAIN_VITE_ 前缀) + const env = loadEnv(mode) + + return { + main: { + plugins: [externalizeDepsPlugin()], + define: { + 'process.env.APTABASE_APP_KEY': JSON.stringify(env.MAIN_VITE_APTABASE_APP_KEY || ''), }, - }, - }, - preload: { - plugins: [externalizeDepsPlugin()], - build: { - rollupOptions: { - input: { - index: resolve(__dirname, 'electron/preload/index.ts'), - }, - }, - }, - }, - renderer: { - resolve: { - alias: { - '@': resolve('src/'), - '~': resolve('src/'), - }, - }, - plugins: [ - vue(), - ui({ - ui: { - colors: { - primary: 'pink', // 使用自定义 pink 作为主色 - neutral: 'slate', + build: { + rollupOptions: { + input: { + index: resolve(__dirname, 'electron/main/index.ts'), + 'worker/dbWorker': resolve(__dirname, 'electron/main/worker/dbWorker.ts'), }, }, - }), - ], - root: 'src/', - build: { - sourcemap: false, - rollupOptions: { - input: { - index: resolve(__dirname, 'src/index.html'), + }, + }, + preload: { + plugins: [externalizeDepsPlugin()], + build: { + rollupOptions: { + input: { + index: resolve(__dirname, 'electron/preload/index.ts'), + }, }, }, }, - server: { - host: '0.0.0.0', - port: 3400, + renderer: { + resolve: { + alias: { + '@': resolve('src/'), + '~': resolve('src/'), + }, + }, + plugins: [ + vue(), + ui({ + ui: { + colors: { + primary: 'pink', // 使用自定义 pink 作为主色 + neutral: 'slate', + }, + }, + }), + ], + root: 'src/', + build: { + sourcemap: false, + rollupOptions: { + input: { + index: resolve(__dirname, 'src/index.html'), + }, + }, + }, + server: { + host: '0.0.0.0', + port: 3400, + }, }, - }, + } }) diff --git a/electron/main/analytics.ts b/electron/main/analytics.ts new file mode 100644 index 0000000..6f58d92 --- /dev/null +++ b/electron/main/analytics.ts @@ -0,0 +1,112 @@ +/** + * 应用分析模块 + * 使用 Aptabase 进行匿名使用统计 + */ + +import { app } from 'electron' +import { initialize, trackEvent } from '@aptabase/electron/main' +import * as fs from 'fs' +import * as path from 'path' + +// 分析数据存储路径 +function getAnalyticsPath(): string { + return path.join(app.getPath('userData'), 'analytics.json') +} + +// 分析数据结构 +interface AnalyticsData { + lastReportDate: string | null +} + +// 读取分析数据 +function loadAnalyticsData(): AnalyticsData { + try { + const filePath = getAnalyticsPath() + if (fs.existsSync(filePath)) { + const data = fs.readFileSync(filePath, 'utf-8') + return JSON.parse(data) + } + } catch (error) { + console.error('[Analytics] 读取分析数据失败:', error) + } + return { lastReportDate: null } +} + +// 保存分析数据 +function saveAnalyticsData(data: AnalyticsData): void { + try { + const filePath = getAnalyticsPath() + fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8') + } catch (error) { + console.error('[Analytics] 保存分析数据失败:', error) + } +} + +// 获取今天的日期字符串 (YYYY-MM-DD) +function getTodayString(): string { + const now = new Date() + return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}` +} + +/** + * 初始化分析模块 + * 必须在 app.whenReady() 之前调用 + */ +export function initAnalytics(): void { + const appKey = process.env.APTABASE_APP_KEY + + if (!appKey) { + return + } + + try { + initialize(appKey) + console.log('[Analytics] Aptabase 初始化成功') + } catch (error) { + console.error('[Analytics] Aptabase 初始化失败:', error) + } +} + +/** + * 上报每日活跃事件 + */ +export function trackDailyActive(): void { + const appKey = process.env.APTABASE_APP_KEY + if (!appKey) { + return + } + + try { + const data = loadAnalyticsData() + const today = getTodayString() + + // 检查今天是否已经上报过 + if (data.lastReportDate === today) { + return + } + + // 上报每日活跃事件 + trackEvent('app_daily_active') + + data.lastReportDate = today + saveAnalyticsData(data) + } catch (error) { + console.error('[Analytics] 上报每日活跃失败:', error) + } +} + +/** + * 事件上报 + */ +export function trackAppEvent(eventName: string, properties?: Record): void { + const appKey = process.env.APTABASE_APP_KEY + if (!appKey) { + return + } + + try { + trackEvent(eventName, properties) + } catch (error) { + console.error(`[Analytics] 上报事件 ${eventName} 失败:`, error) + } +} diff --git a/electron/main/index.ts b/electron/main/index.ts index 267a86d..7539482 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -4,6 +4,7 @@ import { optimizer, is, platform } from '@electron-toolkit/utils' import * as fs from 'fs/promises' import { checkUpdate } from './update' import mainIpcMain from './ipcMain' +import { initAnalytics, trackDailyActive } from './analytics' class MainProcess { mainWindow: BrowserWindow | null @@ -44,6 +45,8 @@ class MainProcess { // 初始化程序 async init() { + initAnalytics() + // 注册应用协议 app.setAsDefaultProtocolClient('chatlab') @@ -101,6 +104,9 @@ class MainProcess { // 设置Windows应用程序用户模型id if (process.platform === 'win32') app.setAppUserModelId(app.getName()) + // 记录日活(用于统计操作系统版本、客户端版本,便于更好的适配客户端) + trackDailyActive() + // 创建主窗口 console.log('[Main] Creating window...') await this.createWindow() diff --git a/package.json b/package.json index 9becd3e..7c09cc3 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "postinstall": "electron-rebuild" }, "dependencies": { + "@aptabase/electron": "^0.3.1", "@electron-toolkit/preload": "^3.0.1", "@electron-toolkit/utils": "^4.0.0", "@types/markdown-it": "^14.1.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0bb4ad3..6d63deb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@aptabase/electron': + specifier: ^0.3.1 + version: 0.3.1(electron@35.7.5) '@electron-toolkit/preload': specifier: ^3.0.1 version: 3.0.2(electron@35.7.5) @@ -139,6 +142,11 @@ packages: '@antfu/utils@9.3.0': resolution: {integrity: sha512-9hFT4RauhcUzqOE4f1+frMKLZrgNog5b06I7VmZQV1BkvwvqrbC8EBZf3L1eEL2AKb6rNKjER0sEvJiSP1FXEA==} + '@aptabase/electron@0.3.1': + resolution: {integrity: sha512-FECaGsjuoQu70F+M6V1evdgLP7yaq/sne9fC60AZZ6B9RsCDlxFBnJzdq3+xevHlUx6AB5o9ygUhQ+ONT9EqiA==} + peerDependencies: + electron: '>= 3.x' + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -3722,6 +3730,10 @@ snapshots: '@antfu/utils@9.3.0': {} + '@aptabase/electron@0.3.1(electron@35.7.5)': + dependencies: + electron: 35.7.5 + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.28.5