AnalyticsManager.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. /**
  2. * 埋点管理器 - 负责游戏内事件追踪和数据上报
  3. */
  4. // 事件属性类型定义
  5. export interface EventProperties {
  6. [key: string]: string | number | boolean;
  7. }
  8. // 小程序生命周期事件属性
  9. export interface MPLifecycleProperties {
  10. scene?: number; // 场景值
  11. query?: string; // 启动参数
  12. shareTicket?: string; // 分享票据
  13. referrerInfo?: any; // 来源信息
  14. }
  15. // 场景加载事件属性
  16. export interface SceneLoadProperties {
  17. scene_name: string; // 场景名称
  18. load_time?: number; // 加载时长(ms)
  19. success: boolean; // 是否成功
  20. error_msg?: string; // 错误信息
  21. }
  22. // 游戏进度事件属性
  23. export interface GameProgressProperties {
  24. level?: number; // 关卡等级
  25. score?: number; // 分数
  26. time_spent?: number; // 耗时(秒)
  27. result?: string; // 结果
  28. }
  29. // 方块合成事件属性
  30. export interface BlockMergeProperties extends EventProperties {
  31. merge_level: number; // 合成等级 (2, 3, 4)
  32. weapon_type?: string; // 武器类型
  33. shape_type?: string; // 形状类型
  34. session_id?: string; // 会话ID
  35. }
  36. // 游戏失败事件属性
  37. export interface GameFailureProperties extends EventProperties {
  38. $event_duration: number; // 停留时长(秒)
  39. $section_id: number; // 关卡id
  40. $section_name: string; // 关卡名称
  41. $section_type: string; // 关卡类型 (0=主线关卡,1=活动关卡,2=挑战关卡,3=支线关卡)
  42. }
  43. // 商店打开事件属性
  44. export interface OpenShopProperties extends EventProperties {
  45. shop_type?: string; // 商店类型
  46. entry_point?: string; // 进入商店的入口点
  47. user_level?: number; // 用户等级
  48. user_money?: number; // 用户金币数量
  49. user_diamonds?: number; // 用户钻石数量
  50. }
  51. // 小程序分享事件属性
  52. export interface MPShareProperties extends EventProperties {
  53. share_type?: string; // 分享类型 (game_result, achievement, invite)
  54. share_content?: string; // 分享内容描述
  55. share_target?: string; // 分享目标 (friend, group, timeline)
  56. level?: number; // 当前关卡
  57. score?: number; // 当前分数
  58. user_level?: number; // 用户等级
  59. }
  60. // 查看商城内容事件属性
  61. export interface ViewMallContentProperties extends EventProperties {
  62. content_type?: string; // 内容类型 (weapon, skill, decoration)
  63. content_id?: string; // 内容ID
  64. content_name?: string; // 内容名称
  65. price?: number; // 价格
  66. currency_type?: string; // 货币类型 (coin, diamond)
  67. user_money?: number; // 用户当前金币
  68. user_diamonds?: number; // 用户当前钻石
  69. view_duration?: number; // 查看时长(秒)
  70. }
  71. // 用户首次注册事件属性
  72. export interface UserFirstRegisterProperties extends EventProperties {
  73. register_time?: number; // 注册时间戳
  74. channel?: string; // 注册渠道(如 wechat_game, web)
  75. scene?: number; // 启动场景值
  76. query?: string; // 启动参数
  77. }
  78. // 小程序注册事件属性
  79. export interface MPRegisterProperties extends EventProperties {
  80. register_time?: number; // 注册时间戳
  81. scene?: number; // 启动场景值
  82. query?: string; // 启动参数
  83. }
  84. // 小程序登录事件属性
  85. export interface MPLoginProperties extends EventProperties {
  86. login_time?: number; // 登录时间戳
  87. scene?: number; // 启动场景值
  88. query?: string; // 启动参数
  89. }
  90. // 小程序登出事件属性
  91. export interface MPLogoutProperties extends EventProperties {
  92. logout_time?: number; // 登出时间戳
  93. scene?: number; // 场景值
  94. }
  95. // 创建角色事件属性
  96. export interface CreateRoleProperties extends EventProperties {
  97. role_id: string; // 角色ID
  98. role_name?: string; // 角色名称
  99. role_class?: string; // 角色职业/类型
  100. create_time?: number; // 创建时间戳
  101. user_level?: number; // 用户等级
  102. }
  103. // 广告展示事件属性
  104. export interface AdShowProperties extends EventProperties {
  105. ad_type?: string; // 广告类型 (rewarded_video, banner, interstitial)
  106. ad_placement?: string; // 广告位置 (shop_reward, level_reward, extra_coins)
  107. ad_source?: string; // 广告来源
  108. reward_type?: string; // 奖励类型 (coins, diamonds, items)
  109. reward_amount?: number; // 奖励数量
  110. user_level?: number; // 用户等级
  111. show_result?: string; // 展示结果 (success, failed, closed)
  112. }
  113. // 小程序添加收藏事件属性
  114. export interface MPAddFavoritesProperties extends EventProperties {
  115. favorite_type?: string; // 收藏类型 (game, achievement, score)
  116. trigger_point?: string; // 触发点 (game_end, achievement_unlock, manual)
  117. user_level?: number; // 用户等级
  118. game_progress?: number; // 游戏进度百分比
  119. }
  120. // 方块选择点击事件属性
  121. export interface BlockSelectionClickProperties extends EventProperties {
  122. button_type: string; // 按钮类型 (add_ball, add_coin, refresh_block)
  123. button_cost?: number; // 按钮费用
  124. user_money?: number; // 用户当前金币数量
  125. user_level?: number; // 用户等级
  126. usage_count?: number; // 该按钮的使用次数
  127. success: boolean; // 操作是否成功
  128. failure_reason?: string; // 失败原因(如金币不足)
  129. }
  130. // 开始关卡事件属性
  131. export interface StartSectionProperties extends EventProperties {
  132. $section_id: number; // 关卡ID
  133. $section_name: string; // 关卡名称
  134. $section_type: string; // 关卡类型 (0=主线关卡,1=活动关卡,2=挑战关卡,3=支线关卡)
  135. total_waves?: number; // 总波次数
  136. total_enemies?: number; // 总敌人数量
  137. energy_max?: number; // 初始最大能量值
  138. user_level?: number; // 用户等级
  139. user_money?: number; // 用户当前金币数量
  140. background_image?: string; // 背景图片
  141. }
  142. /**
  143. * 埋点管理器单例类
  144. */
  145. export class AnalyticsManager {
  146. private static instance: AnalyticsManager;
  147. private isEnabled: boolean = true;
  148. private sessionId: string;
  149. private userId: string;
  150. private deviceInfo: any = {};
  151. private constructor() {
  152. this.sessionId = this.generateSessionId();
  153. this.userId = this.getUserId();
  154. this.initDeviceInfo();
  155. }
  156. /**
  157. * 获取单例实例
  158. */
  159. public static getInstance(): AnalyticsManager {
  160. if (!AnalyticsManager.instance) {
  161. AnalyticsManager.instance = new AnalyticsManager();
  162. }
  163. return AnalyticsManager.instance;
  164. }
  165. /**
  166. * 初始化埋点管理器
  167. */
  168. public init(): void {
  169. console.log('[AnalyticsManager] 埋点管理器初始化完成');
  170. console.log('[AnalyticsManager] SessionId:', this.sessionId);
  171. console.log('[AnalyticsManager] UserId:', this.userId);
  172. }
  173. /**
  174. * 设置埋点开关
  175. */
  176. public setEnabled(enabled: boolean): void {
  177. this.isEnabled = enabled;
  178. console.log('[AnalyticsManager] 埋点功能', enabled ? '已启用' : '已禁用');
  179. }
  180. /**
  181. * 发送事件
  182. */
  183. public track(eventName: string, properties: EventProperties = {}): void {
  184. if (!this.isEnabled) {
  185. return;
  186. }
  187. const eventData = {
  188. event_name: eventName,
  189. timestamp: Date.now(),
  190. session_id: this.sessionId,
  191. user_id: this.userId,
  192. device_info: this.deviceInfo,
  193. properties: properties
  194. };
  195. // 输出到控制台(实际项目中应该发送到服务器)
  196. console.log('[AnalyticsManager] 事件追踪:', JSON.stringify(eventData, null, 2));
  197. // 这里可以集成第三方埋点SDK,如:
  198. // - 微信小游戏数据助手
  199. // - TalkingData
  200. // - 友盟统计
  201. // - 自定义服务器接口
  202. this.sendToServer(eventData);
  203. }
  204. // ==================== 小程序生命周期事件 ====================
  205. /**
  206. * 小程序启动事件
  207. */
  208. public trackMPLaunch(properties: MPLifecycleProperties = {}): void {
  209. this.track('$MPLaunch', {
  210. scene: properties.scene || 0,
  211. query: properties.query || '',
  212. shareTicket: properties.shareTicket || '',
  213. referrerInfo: JSON.stringify(properties.referrerInfo || {}),
  214. ...properties
  215. });
  216. }
  217. /**
  218. * 小程序显示事件
  219. */
  220. public trackMPShow(properties: MPLifecycleProperties = {}): void {
  221. this.track('$MPShow', {
  222. scene: properties.scene || 0,
  223. query: properties.query || '',
  224. ...properties
  225. });
  226. }
  227. /**
  228. * 小程序隐藏事件
  229. */
  230. public trackMPHide(): void {
  231. this.track('$MPHide', {
  232. hide_time: Date.now()
  233. });
  234. }
  235. // ==================== 场景加载事件 ====================
  236. /**
  237. * 场景加载开始事件
  238. */
  239. public trackSceneLoadStart(sceneName: string): void {
  240. this.track('$SceneLoadStart', {
  241. scene_name: sceneName,
  242. start_time: Date.now()
  243. });
  244. }
  245. /**
  246. * 场景加载完成事件
  247. */
  248. public trackSceneLoaded(properties: SceneLoadProperties): void {
  249. this.track('$SceneLoaded', {
  250. scene_name: properties.scene_name,
  251. load_time: properties.load_time || 0,
  252. success: properties.success,
  253. error_msg: properties.error_msg || '',
  254. ...properties
  255. });
  256. }
  257. /**
  258. * 场景卸载事件
  259. */
  260. public trackSceneUnloaded(sceneName: string): void {
  261. this.track('$SceneUnloaded', {
  262. scene_name: sceneName,
  263. unload_time: Date.now()
  264. });
  265. }
  266. // ==================== 游戏进度事件 ====================
  267. /**
  268. * 完成关卡事件
  269. */
  270. public trackCompleteSection(properties: GameProgressProperties): void {
  271. this.track('$CompleteSection', {
  272. level: properties.level || 1,
  273. score: properties.score || 0,
  274. time_spent: properties.time_spent || 0,
  275. result: properties.result || 'success',
  276. ...properties
  277. });
  278. }
  279. /**
  280. * 等级提升事件
  281. */
  282. public trackUpdateLevel(oldLevel: number, newLevel: number): void {
  283. this.track('$UpdateLevel', {
  284. old_level: oldLevel,
  285. new_level: newLevel,
  286. level_diff: newLevel - oldLevel
  287. });
  288. }
  289. // ==================== 新手引导事件 ====================
  290. /**
  291. * 新手引导开始事件
  292. */
  293. public trackTutorialStart(): void {
  294. this.track('$TutorialStart', {
  295. start_time: Date.now()
  296. });
  297. }
  298. /**
  299. * 新手引导完成事件
  300. */
  301. public trackTutorialFinish(timeSpent: number): void {
  302. this.track('$TutorialFinish', {
  303. time_spent: timeSpent,
  304. finish_time: Date.now()
  305. });
  306. }
  307. // ==================== 方块合成事件 ====================
  308. /**
  309. * 追踪方块合成等级达成事件
  310. * @param mergeLevel 合成等级 (2, 3, 4)
  311. * @param weaponType 武器类型
  312. * @param shapeType 形状类型
  313. */
  314. public trackBlockMergeLevel(mergeLevel: number, weaponType?: string, shapeType?: string): void {
  315. if (mergeLevel < 2 || mergeLevel > 4) {
  316. console.warn(`[Analytics] Invalid merge level: ${mergeLevel}. Only levels 2-4 are tracked.`);
  317. return;
  318. }
  319. const properties: BlockMergeProperties = {
  320. merge_level: mergeLevel,
  321. session_id: this.sessionId
  322. };
  323. if (weaponType) {
  324. properties.weapon_type = weaponType;
  325. }
  326. if (shapeType) {
  327. properties.shape_type = shapeType;
  328. }
  329. // 上报合成等级达成事件
  330. this.track('$block_merge', properties);
  331. console.log(`[Analytics] Block merge level ${mergeLevel} achieved:`, properties);
  332. }
  333. /**
  334. * 追踪方块合成等级2达成
  335. */
  336. public trackMergeLevel2(weaponType?: string, shapeType?: string): void {
  337. this.trackBlockMergeLevel(2, weaponType, shapeType);
  338. }
  339. /**
  340. * 追踪方块合成等级3达成
  341. */
  342. public trackMergeLevel3(weaponType?: string, shapeType?: string): void {
  343. this.trackBlockMergeLevel(3, weaponType, shapeType);
  344. }
  345. /**
  346. * 追踪方块合成等级4达成
  347. */
  348. public trackMergeLevel4(weaponType?: string, shapeType?: string): void {
  349. this.trackBlockMergeLevel(4, weaponType, shapeType);
  350. }
  351. /**
  352. * 追踪游戏失败事件(墙体摧毁)
  353. */
  354. public trackGameFailure(properties: GameFailureProperties): void {
  355. if (!this.isEnabled) {
  356. console.log('[AnalyticsManager] 埋点已禁用,跳过 $GameFailure 事件');
  357. return;
  358. }
  359. console.log('[AnalyticsManager] 追踪游戏失败事件:', properties);
  360. this.track('$GameFailure', properties);
  361. }
  362. /**
  363. * 追踪商店打开事件
  364. */
  365. public trackOpenShop(properties: OpenShopProperties = {}): void {
  366. if (!this.isEnabled) {
  367. console.log('[AnalyticsManager] 埋点已禁用,跳过 $OpenShop 事件');
  368. return;
  369. }
  370. console.log('[AnalyticsManager] 追踪商店打开事件:', properties);
  371. this.track('$OpenShop', properties);
  372. }
  373. /**
  374. * 追踪方块选择点击事件
  375. */
  376. public trackBlockSelectionClick(properties: BlockSelectionClickProperties): void {
  377. if (!this.isEnabled) {
  378. console.log('[AnalyticsManager] 埋点已禁用,跳过 $block_selection_click 事件');
  379. return;
  380. }
  381. console.log('[AnalyticsManager] 追踪方块选择点击事件:', properties);
  382. this.track('$block_selection_click', properties);
  383. }
  384. /**
  385. * 追踪开始关卡事件
  386. */
  387. public trackStartSection(properties: StartSectionProperties): void {
  388. if (!this.isEnabled) {
  389. console.log('[AnalyticsManager] 埋点已禁用,跳过 $StartSection 事件');
  390. return;
  391. }
  392. console.log('[AnalyticsManager] 追踪开始关卡事件:', properties);
  393. this.track('$StartSection', properties);
  394. }
  395. // ==================== 小程序分享事件 ====================
  396. /**
  397. * 追踪小程序分享事件
  398. */
  399. public trackMPShare(properties: MPShareProperties = {}): void {
  400. if (!this.isEnabled) {
  401. console.log('[AnalyticsManager] 埋点已禁用,跳过 $MPShare 事件');
  402. return;
  403. }
  404. console.log('[AnalyticsManager] 追踪小程序分享事件:', properties);
  405. this.track('$MPShare', properties);
  406. }
  407. // ==================== 商城内容查看事件 ====================
  408. /**
  409. * 追踪查看商城内容事件
  410. */
  411. public trackViewMallContent(properties: ViewMallContentProperties = {}): void {
  412. if (!this.isEnabled) {
  413. console.log('[AnalyticsManager] 埋点已禁用,跳过 $ViewMallContent 事件');
  414. return;
  415. }
  416. console.log('[AnalyticsManager] 追踪查看商城内容事件:', properties);
  417. this.track('$ViewMallContent', properties);
  418. }
  419. // ==================== 广告展示事件 ====================
  420. /**
  421. * 追踪广告展示事件
  422. */
  423. public trackAdShow(properties: AdShowProperties = {}): void {
  424. if (!this.isEnabled) {
  425. console.log('[AnalyticsManager] 埋点已禁用,跳过 $AdShow 事件');
  426. return;
  427. }
  428. console.log('[AnalyticsManager] 追踪广告展示事件:', properties);
  429. this.track('$AdShow', properties);
  430. }
  431. // ==================== 小程序添加收藏事件 ====================
  432. /**
  433. * 追踪小程序添加收藏事件
  434. */
  435. public trackMPAddFavorites(properties: MPAddFavoritesProperties = {}): void {
  436. if (!this.isEnabled) {
  437. console.log('[AnalyticsManager] 埋点已禁用,跳过 $MPAddFavorites 事件');
  438. return;
  439. }
  440. console.log('[AnalyticsManager] 追踪小程序添加收藏事件:', properties);
  441. this.track('$MPAddFavorites', properties);
  442. }
  443. // ==================== 用户注册与账号事件 ====================
  444. /**
  445. * 追踪用户首次注册事件
  446. */
  447. public trackUserFirstRegister(properties: UserFirstRegisterProperties = {}): void {
  448. if (!this.isEnabled) {
  449. console.log('[AnalyticsManager] 埋点已禁用,跳过 $UserFirstRegister 事件');
  450. return;
  451. }
  452. const payload = {
  453. register_time: properties.register_time || Date.now(),
  454. channel: properties.channel || (typeof wx !== 'undefined' ? 'wechat_game' : 'web'),
  455. scene: properties.scene || 0,
  456. query: properties.query || '',
  457. ...properties
  458. };
  459. console.log('[AnalyticsManager] 追踪用户首次注册事件:', payload);
  460. this.track('$UserFirstRegister', payload);
  461. }
  462. /**
  463. * 追踪小程序注册事件
  464. */
  465. public trackMPRegister(properties: MPRegisterProperties = {}): void {
  466. if (!this.isEnabled) {
  467. console.log('[AnalyticsManager] 埋点已禁用,跳过 $MPRegister 事件');
  468. return;
  469. }
  470. const payload = {
  471. register_time: properties.register_time || Date.now(),
  472. scene: properties.scene || 0,
  473. query: properties.query || '',
  474. ...properties
  475. };
  476. console.log('[AnalyticsManager] 追踪小程序注册事件:', payload);
  477. this.track('$MPRegister', payload);
  478. }
  479. /**
  480. * 追踪小程序登录事件
  481. */
  482. public trackMPLogin(properties: MPLoginProperties = {}): void {
  483. if (!this.isEnabled) {
  484. console.log('[AnalyticsManager] 埋点已禁用,跳过 $MPLogin 事件');
  485. return;
  486. }
  487. const payload = {
  488. login_time: properties.login_time || Date.now(),
  489. scene: properties.scene || 0,
  490. query: properties.query || '',
  491. ...properties
  492. };
  493. console.log('[AnalyticsManager] 追踪小程序登录事件:', payload);
  494. this.track('$MPLogin', payload);
  495. }
  496. /**
  497. * 追踪小程序登出事件
  498. */
  499. public trackMPLogout(properties: MPLogoutProperties = {}): void {
  500. if (!this.isEnabled) {
  501. console.log('[AnalyticsManager] 埋点已禁用,跳过 $MPLogout 事件');
  502. return;
  503. }
  504. const payload = {
  505. logout_time: properties.logout_time || Date.now(),
  506. scene: properties.scene || 0,
  507. ...properties
  508. };
  509. console.log('[AnalyticsManager] 追踪小程序登出事件:', payload);
  510. this.track('$MPLogout', payload);
  511. }
  512. /**
  513. * 追踪创建角色事件
  514. */
  515. public trackCreateRole(properties: CreateRoleProperties): void {
  516. if (!this.isEnabled) {
  517. console.log('[AnalyticsManager] 埋点已禁用,跳过 $CreateRole 事件');
  518. return;
  519. }
  520. const payload = {
  521. role_id: properties.role_id,
  522. role_name: properties.role_name || '',
  523. role_class: properties.role_class || '',
  524. create_time: properties.create_time || Date.now(),
  525. user_level: properties.user_level || 1,
  526. ...properties
  527. };
  528. console.log('[AnalyticsManager] 追踪创建角色事件:', payload);
  529. this.track('$CreateRole', payload);
  530. }
  531. // ==================== 私有方法 ====================
  532. /**
  533. * 生成会话ID
  534. */
  535. private generateSessionId(): string {
  536. return 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
  537. }
  538. /**
  539. * 获取用户ID
  540. */
  541. private getUserId(): string {
  542. const storage: any = (globalThis as any).localStorage;
  543. const wxAny: any = (globalThis as any).wx;
  544. let userId: string | null = null;
  545. try {
  546. if (storage && typeof storage.getItem === 'function') {
  547. userId = storage.getItem('analytics_user_id');
  548. } else if (wxAny && typeof wxAny.getStorageSync === 'function') {
  549. userId = wxAny.getStorageSync('analytics_user_id') || null;
  550. }
  551. } catch {
  552. // ignore storage errors
  553. }
  554. if (!userId) {
  555. userId = 'user_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
  556. try {
  557. if (storage && typeof storage.setItem === 'function') {
  558. storage.setItem('analytics_user_id', userId);
  559. } else if (wxAny && typeof wxAny.setStorageSync === 'function') {
  560. wxAny.setStorageSync('analytics_user_id', userId);
  561. }
  562. } catch {
  563. // ignore storage errors
  564. }
  565. }
  566. return userId;
  567. }
  568. /**
  569. * 初始化设备信息
  570. */
  571. private initDeviceInfo(): void {
  572. const safeNavigator: any = (globalThis as any).navigator || {};
  573. const safeScreen: any = (globalThis as any).screen || {};
  574. const wxAny: any = (globalThis as any).wx;
  575. // 优先使用微信小游戏的系统信息,无需时区字段
  576. if (wxAny && typeof wxAny.getSystemInfoSync === 'function') {
  577. const sys = wxAny.getSystemInfoSync();
  578. this.deviceInfo = {
  579. platform: 'wechat_game',
  580. user_agent: safeNavigator.userAgent || 'wechat_game',
  581. screen_width: sys.screenWidth ?? safeScreen.width ?? 0,
  582. screen_height: sys.screenHeight ?? safeScreen.height ?? 0,
  583. language: sys.language || safeNavigator.language || 'zh_CN',
  584. brand: sys.brand,
  585. model: sys.model,
  586. system: sys.system,
  587. version: sys.version,
  588. pixelRatio: sys.pixelRatio
  589. };
  590. } else {
  591. // Web 环境的基础设备信息,移除时区字段以避免 Intl 依赖
  592. this.deviceInfo = {
  593. platform: 'web',
  594. user_agent: safeNavigator.userAgent || 'unknown',
  595. screen_width: safeScreen.width || 0,
  596. screen_height: safeScreen.height || 0,
  597. language: safeNavigator.language || 'en'
  598. };
  599. }
  600. }
  601. /**
  602. * 发送数据到服务器
  603. */
  604. private sendToServer(eventData: any): void {
  605. // 实际项目中应该发送到服务器
  606. // 这里只是模拟发送过程
  607. // 示例:使用fetch发送到服务器
  608. /*
  609. fetch('/api/analytics/track', {
  610. method: 'POST',
  611. headers: {
  612. 'Content-Type': 'application/json',
  613. },
  614. body: JSON.stringify(eventData)
  615. }).catch(error => {
  616. console.error('[AnalyticsManager] 发送埋点数据失败:', error);
  617. });
  618. */
  619. // 或者集成第三方SDK
  620. // 例如:wx.reportAnalytics(eventName, eventData);
  621. }
  622. }
  623. // 导出单例实例,方便全局使用
  624. export const Analytics = AnalyticsManager.getInstance();