/** * 埋点服务 * 提供分享和下载打印事件的上报功能 */ import { getAppUUID } from './uuid'; // 格式化时间为 yyyy-MM-dd HH:mm function formatTime(date: Date = new Date()): string { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}`; } /** * 获取今天的日期字符串(yyyy-MM-dd) */ function getTodayString(): string { const date = new Date(); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } /** * 获取事件计数(当天该事件上报的次数) * 使用本地存储持久化,每天重置计数 */ function getEventCount(eventName: string): number { try { const storageKey = `tracker_count_${eventName}`; const dateKey = `tracker_date_${eventName}`; const today = getTodayString(); // 获取上次记录的日期 const lastDate = wx.getStorageSync(dateKey); let currentCount = 0; // 如果是今天,获取上次的计数;否则重置为0 if (lastDate === today) { currentCount = wx.getStorageSync(storageKey) || 0; } // 递增计数 const newCount = currentCount + 1; // 保存计数和日期 wx.setStorageSync(storageKey, newCount); wx.setStorageSync(dateKey, today); return newCount; } catch (error) { console.error('获取事件计数失败:', error); return 1; // 如果存储失败,返回 1 } } /** * 埋点追踪器(单例模式) */ class Tracker { private static instance: Tracker | null = null; private openLog: boolean; private constructor() { this.openLog = true; } /** * 获取 Tracker 单例实例 */ public static getInstance(): Tracker { if (!Tracker.instance) { Tracker.instance = new Tracker(); } return Tracker.instance; } printLog(tip: string, message?: string | object): void { if (this.openLog) { if (message) { if (typeof message === 'object') { console.log(tip, ':', JSON.stringify(message, null, 2)); } else { console.log(tip, ':', message as string); } } else { console.log(tip); } } } /** * 生成公共埋点属性 * @param eventName 事件名称 * @param pageName 页面名称 * @param extraParams 额外的参数对象 * @returns 包含公共属性和额外参数的埋点参数对象 */ private getCommonEventParams( eventName: string, pageName: string, extraParams?: Record, ): Record { return { count: getEventCount(eventName), date_time: formatTime(), uuid: getAppUUID(), page_name: pageName, ...extraParams, }; } /** * 统一业务埋点入口。pageName 使用页面 route,内容使用稳定的 worksheet_id。 */ report( eventName: string, pageName: string, extraParams?: Record, ): void { try { this.sendEvent( eventName, this.getCommonEventParams(eventName, pageName, extraParams), ); } catch (error) { console.error(`上报 ${eventName} 事件失败:`, error); } } reportPageView(pageName: string): void { this.report('page_view', pageName); } reportWorksheetClick( pageName: string, extraParams: Record, ): void { this.report('worksheet_click', pageName, extraParams); } reportPreviewView( pageName: string, extraParams: Record, ): void { this.report('preview_view', pageName, extraParams); } reportGenerateStart( pageName: string, extraParams: Record, ): void { this.report('generate_start', pageName, extraParams); } reportGenerateResult( pageName: string, success: boolean, extraParams: Record, ): void { this.report( success ? 'generate_success' : 'generate_fail', pageName, extraParams, ); } reportExportClick( pageName: string, extraParams: Record, ): void { this.report('export_click', pageName, extraParams); } reportExportResult( pageName: string, success: boolean, extraParams: Record, ): void { this.report( success ? 'export_success' : 'export_fail', pageName, extraParams, ); } reportFavorite( pageName: string, worksheetId: string, favorited: boolean, ): void { this.report(favorited ? 'favorite_add' : 'favorite_remove', pageName, { worksheet_id: worksheetId, }); } /** * 上报分享点击事件 * @param pageName 页面名称 */ reportShare(pageName: string, extraParams?: Record): void { this.report('share_click', pageName, extraParams); } /** * 上报下载打印事件 * @param pageName 页面名称 * @param mode 模式(可选) */ reportDownload(pageName: string, mode?: string): void { // 兼容旧调用;新代码请使用 reportExportClick / reportExportResult。 this.reportExportClick(pageName, { ...(mode && { mode }) }); } /** * 发送事件(仅在线上环境上报) * @param eventName 事件名称 * @param params 事件参数 */ sendEvent(eventName: string, params: Record): void { try { // 获取当前环境,只在 release 环境下上报 const accountInfo = wx.getAccountInfoSync(); const env = accountInfo.miniProgram.envVersion || 'release'; if (env === 'release') { this.printLog(`[${env}] 事件上报`, { eventName, params }); wx.reportEvent(eventName, params); } else { // 非线上环境,只打印日志,不上报 this.printLog(`[${env}] 事件上报已跳过`, { eventName, params }); } } catch (error) { console.error('获取环境信息失败:', error); // 如果获取环境信息失败,为了安全起见不上报 } } } // 导出 Tracker 单例实例 const tracker = Tracker.getInstance(); export default tracker;