| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- /**
- * 平台埋点 SDK(uni-app / Vue 通用)
- *
- * 使用方式:
- * 1. 复制到前端项目 utils/analytics.js
- * 2. 初始化:Analytics.init({ baseUrl: 'https://api.xxx.com', getToken: () => uni.getStorageSync('token') })
- * 3. 上报:Analytics.report('MERCHANT_VIEW', { merchantId: 1001 })
- *
- * 注意:请勿再调用旧接口 POST /track/event
- */
- let config = {
- baseUrl: '',
- getToken: () => '',
- channel: '',
- city: '',
- };
- function uuid() {
- return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
- const r = (Math.random() * 16) | 0;
- const v = c === 'x' ? r : (r & 0x3) | 0x8;
- return v.toString(16);
- });
- }
- function getDeviceType() {
- // #ifdef APP-PLUS
- const platform = uni.getSystemInfoSync().platform;
- if (platform === 'ios') return 'IOS';
- if (platform === 'android') return 'ANDROID';
- // #endif
- // #ifdef MP-WEIXIN
- return 'MINI_PROGRAM';
- // #endif
- return 'H5';
- }
- function request(url, data) {
- return new Promise((resolve, reject) => {
- uni.request({
- url: `${config.baseUrl}${url}`,
- method: 'POST',
- data,
- header: {
- 'Content-Type': 'application/json',
- Authorization: config.getToken() || '',
- },
- success: (res) => {
- if (res.data && res.data.success) {
- resolve(res.data);
- } else {
- reject(res.data || res);
- }
- },
- fail: reject,
- });
- });
- }
- const Analytics = {
- init(options = {}) {
- config = { ...config, ...options };
- },
- /**
- * 统一埋点上报
- * @param {string} scene 场景码,如 MERCHANT_VIEW
- * @param {object} payload 业务参数
- */
- report(scene, payload = {}) {
- const body = {
- scene,
- eventId: uuid(),
- userId: payload.userId,
- merchantId: payload.merchantId,
- targetId: payload.targetId || payload.contentId,
- contentType: payload.contentType,
- amount: payload.amount,
- durationMs: payload.durationMs,
- deviceType: payload.deviceType || getDeviceType(),
- channel: payload.channel || config.channel,
- city: payload.city || config.city,
- };
- return request('/analytics/front/report', body);
- },
- /** 批量上报 */
- batch(events) {
- const list = (events || []).map((item) => ({
- scene: item.scene,
- eventId: uuid(),
- userId: item.userId,
- merchantId: item.merchantId,
- targetId: item.targetId || item.contentId,
- contentType: item.contentType,
- amount: item.amount,
- durationMs: item.durationMs,
- deviceType: item.deviceType || getDeviceType(),
- channel: item.channel || config.channel,
- city: item.city || config.city,
- }));
- return request('/analytics/front/batch', { events: list });
- },
- /** 在线心跳,durationMs 为距上次心跳的毫秒数 */
- heartbeat(durationMs, extra = {}) {
- return request('/analytics/front/heartbeat', {
- durationMs,
- deviceType: extra.deviceType || getDeviceType(),
- channel: extra.channel || config.channel,
- city: extra.city || config.city,
- });
- },
- /** App 启动 */
- onLaunch(extra = {}) {
- return this.report('APP_LAUNCH', extra);
- },
- /** 商家浏览埋点 */
- merchantView(data) {
- return request('/analytics/front/merchant/view', {
- eventId: data.eventId || uuid(),
- merchantId: data.merchantId,
- shopType: data.shopType,
- visitUv: data.visitUv,
- visitPv: data.visitPv,
- userId: data.userId,
- });
- },
- /** 访问商户(委托 merchantView) */
- onMerchantView(merchantId, extra = {}) {
- return this.merchantView({
- merchantId,
- shopType: extra.shopType,
- visitUv: extra.visitUv != null ? extra.visitUv : 0,
- visitPv: extra.visitPv != null ? extra.visitPv : 1,
- userId: extra.userId,
- eventId: extra.eventId,
- });
- },
- /** 内容互动(点赞/评论/收藏),increment 默认 +1 */
- onContentInteract(contentId, contentType, extra = {}) {
- return this.contentInteract({
- contentId,
- contentType,
- increment: extra.increment != null ? extra.increment : 1,
- userId: extra.userId,
- eventId: extra.eventId,
- });
- },
- /** 内容互动埋点 */
- contentInteract(data) {
- return request('/analytics/front/content/interact', {
- eventId: data.eventId || uuid(),
- contentId: data.contentId,
- contentType: data.contentType,
- increment: data.increment,
- userId: data.userId,
- });
- },
- /** AI 请求上报 */
- aiRequest(data) {
- return request('/analytics/front/ai-request', {
- requestId: data.requestId || uuid(),
- apiName: data.apiName,
- apiUrl: data.apiUrl,
- responseDurationMs: data.responseDurationMs,
- isTimeout: data.isTimeout,
- });
- },
- /** 用户注册埋点 */
- userRegister(data) {
- return request('/analytics/front/user/register', {
- eventId: data.eventId || uuid(),
- userId: data.userId,
- userPhone: data.userPhone,
- registerTime: data.registerTime,
- channel: data.channel,
- city: data.city,
- });
- },
- /** 用户登录埋点 */
- userLogin(data) {
- return request('/analytics/front/user/login', {
- eventId: data.eventId || uuid(),
- userId: data.userId,
- firstLaunchTime: data.firstLaunchTime,
- lastActiveTime: data.lastActiveTime,
- city: data.city,
- deviceName: data.deviceName,
- });
- },
- /** 用户登出埋点 */
- userLogout(data) {
- return request('/analytics/front/user/logout', {
- eventId: data.eventId || uuid(),
- userId: data.userId,
- firstLaunchTime: data.firstLaunchTime,
- lastActiveTime: data.lastActiveTime,
- city: data.city,
- deviceName: data.deviceName,
- onlineDurationMin: data.onlineDurationMin,
- });
- },
- /** AI 对话结束埋点 */
- aiChatEnd(data) {
- return request('/analytics/front/ai-chat/end', {
- eventId: data.eventId || uuid(),
- chatId: data.chatId,
- userId: data.userId,
- startTime: data.startTime,
- messageCount: data.messageCount,
- aiResponseDurationMs: data.aiResponseDurationMs,
- });
- },
- /** 内容发布埋点 */
- contentPublish(data) {
- return request('/analytics/front/content/publish', {
- eventId: data.eventId || uuid(),
- contentId: data.contentId,
- contentType: data.contentType,
- authorType: data.authorType,
- authorId: data.authorId,
- publishTime: data.publishTime,
- });
- },
- /** 启动心跳定时器,默认60秒 */
- startHeartbeat(intervalMs = 60000) {
- if (this._heartbeatTimer) {
- clearInterval(this._heartbeatTimer);
- }
- let last = Date.now();
- this._heartbeatTimer = setInterval(() => {
- const now = Date.now();
- this.heartbeat(now - last).catch(() => {});
- last = now;
- }, intervalMs);
- },
- stopHeartbeat() {
- if (this._heartbeatTimer) {
- clearInterval(this._heartbeatTimer);
- this._heartbeatTimer = null;
- }
- },
- };
- export default Analytics;
|