feat: 管理端与用户端批量更新(订单/邀请双码/tabBar/审核与分销等)
- 管理端:用户详情、企业看板双小程序码、超管设置与用户列表等 - 后端:订单接口、邀请码企业版+个人版、分析与测试相关调整 - 微信小程序/抖音:自定义 tabBar 居中与拍摄钮上移、相机页与结果页、订单页、支付与统计 - 新增 faceResultDetail 工具与 mp 分析迁移脚本 Made-with: Cursor
This commit is contained in:
@@ -1,18 +1,52 @@
|
||||
/**
|
||||
* 小程序埋点:批量上报 /api/analytics/events(可选登录,便于超管后台关联用户)
|
||||
* 小程序埋点:批量上报 /api/analytics/events
|
||||
* - session_id 区分每次启动
|
||||
* - 自动采集平台、网络、设备、场景值
|
||||
* - 定时 flush + 页面隐藏 flush
|
||||
*/
|
||||
const { request } = require('./request.js')
|
||||
|
||||
const MAX_BATCH = 30
|
||||
const FLUSH_INTERVAL = 10000
|
||||
const queue = []
|
||||
let lastPageReport = { path: '', t: 0 }
|
||||
|
||||
function getAppSafe() {
|
||||
const sessionId = 'wx_' + Date.now().toString(36) + Math.random().toString(36).slice(2, 6)
|
||||
|
||||
let _deviceInfo = null
|
||||
function getDeviceInfo() {
|
||||
if (_deviceInfo) return _deviceInfo
|
||||
try {
|
||||
return getApp()
|
||||
const sys = wx.getSystemInfoSync()
|
||||
_deviceInfo = {
|
||||
brand: sys.brand,
|
||||
model: sys.model,
|
||||
system: sys.system,
|
||||
platform: sys.platform,
|
||||
version: sys.version,
|
||||
SDKVersion: sys.SDKVersion,
|
||||
screenWidth: sys.screenWidth,
|
||||
screenHeight: sys.screenHeight,
|
||||
pixelRatio: sys.pixelRatio
|
||||
}
|
||||
} catch (e) {
|
||||
return null
|
||||
_deviceInfo = {}
|
||||
}
|
||||
return _deviceInfo
|
||||
}
|
||||
|
||||
let _networkType = 'unknown'
|
||||
function refreshNetwork() {
|
||||
try {
|
||||
wx.getNetworkType({
|
||||
success(res) { _networkType = res.networkType || 'unknown' }
|
||||
})
|
||||
} catch (e) {}
|
||||
}
|
||||
refreshNetwork()
|
||||
|
||||
function getAppSafe() {
|
||||
try { return getApp() } catch (e) { return null }
|
||||
}
|
||||
|
||||
function getCurrentRoute() {
|
||||
@@ -21,19 +55,27 @@ function getCurrentRoute() {
|
||||
return p && p.route ? p.route : ''
|
||||
}
|
||||
|
||||
function getScene() {
|
||||
const app = getAppSafe()
|
||||
return (app && app.globalData && app.globalData.scene) || ''
|
||||
}
|
||||
|
||||
function track(eventName, props) {
|
||||
if (!eventName || typeof eventName !== 'string') return
|
||||
const app = getAppSafe()
|
||||
const openId =
|
||||
app && app.globalData
|
||||
? (app.globalData.openId || (app.globalData.userInfo && (app.globalData.userInfo.openid || app.globalData.userInfo.openId)) || '')
|
||||
: ''
|
||||
const openId = app && app.globalData
|
||||
? (app.globalData.openId || (app.globalData.userInfo && (app.globalData.userInfo.openid || app.globalData.userInfo.openId)) || '')
|
||||
: ''
|
||||
queue.push({
|
||||
event_name: eventName,
|
||||
page_path: getCurrentRoute(),
|
||||
props: props && typeof props === 'object' ? props : {},
|
||||
client_ts: Date.now(),
|
||||
openid: openId || undefined
|
||||
openid: openId || undefined,
|
||||
session_id: sessionId,
|
||||
platform: 'wechat',
|
||||
network: _networkType,
|
||||
scene: getScene()
|
||||
})
|
||||
if (queue.length >= MAX_BATCH) {
|
||||
flush()
|
||||
@@ -41,15 +83,13 @@ function track(eventName, props) {
|
||||
}
|
||||
|
||||
/** 页面曝光(防抖:同路径 2 秒内只记一次) */
|
||||
function reportPageView() {
|
||||
function reportPageView(extraProps) {
|
||||
const path = getCurrentRoute()
|
||||
if (!path) return
|
||||
const now = Date.now()
|
||||
if (path === lastPageReport.path && now - lastPageReport.t < 2000) {
|
||||
return
|
||||
}
|
||||
if (path === lastPageReport.path && now - lastPageReport.t < 2000) return
|
||||
lastPageReport = { path, t: now }
|
||||
track('page_view', { path })
|
||||
track('page_view', { path, ...(extraProps || {}) })
|
||||
}
|
||||
|
||||
function flush() {
|
||||
@@ -59,16 +99,57 @@ function flush() {
|
||||
url: '/api/analytics/events',
|
||||
method: 'POST',
|
||||
needAuth: true,
|
||||
data: { events },
|
||||
data: { events, device: getDeviceInfo() },
|
||||
allow401: false,
|
||||
success() {},
|
||||
fail() {}
|
||||
})
|
||||
}
|
||||
|
||||
/** 上报应用启动(首次 onLaunch 调用一次) */
|
||||
function reportAppLaunch(launchOptions) {
|
||||
const opts = launchOptions || {}
|
||||
track('app_launch', {
|
||||
scene: opts.scene,
|
||||
query: opts.query || {},
|
||||
referrerInfo: opts.referrerInfo || {},
|
||||
device: getDeviceInfo()
|
||||
})
|
||||
}
|
||||
|
||||
/** 上报分享行为 */
|
||||
function reportShare(channel, extra) {
|
||||
track('share', { channel: channel || 'friend', ...(extra || {}) })
|
||||
flush()
|
||||
}
|
||||
|
||||
/** 上报支付结果 */
|
||||
function reportPayResult(success, extra) {
|
||||
track(success ? 'pay_success' : 'pay_fail', extra || {})
|
||||
flush()
|
||||
}
|
||||
|
||||
let _flushTimer = null
|
||||
function startAutoFlush() {
|
||||
if (_flushTimer) return
|
||||
_flushTimer = setInterval(flush, FLUSH_INTERVAL)
|
||||
}
|
||||
function stopAutoFlush() {
|
||||
if (_flushTimer) {
|
||||
clearInterval(_flushTimer)
|
||||
_flushTimer = null
|
||||
}
|
||||
}
|
||||
startAutoFlush()
|
||||
|
||||
module.exports = {
|
||||
track,
|
||||
flush,
|
||||
reportPageView,
|
||||
getCurrentRoute
|
||||
reportAppLaunch,
|
||||
reportShare,
|
||||
reportPayResult,
|
||||
getCurrentRoute,
|
||||
startAutoFlush,
|
||||
stopAutoFlush
|
||||
}
|
||||
|
||||
@@ -130,15 +130,15 @@ function wxPay(options) {
|
||||
// 支付成功后轮询后端订单状态 3~5 次,确保通过微信订单查询接口确认成功
|
||||
pollOrderStatus(orderId, 5, 1000, (ok, order) => {
|
||||
if (ok) {
|
||||
try { require('./analytics').reportPayResult(true, { productType: productType || '', orderId, amount }) } catch (e) {}
|
||||
wx.showToast({
|
||||
title: '支付成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
// 将本地订单信息一并透传给业务方
|
||||
success && success({ payRes, order })
|
||||
} else {
|
||||
// 落库状态暂未确认,但微信侧已成功,一般稍后会自动对齐
|
||||
try { require('./analytics').reportPayResult(true, { productType: productType || '', orderId, amount, note: 'poll_pending' }) } catch (e) {}
|
||||
wx.showToast({
|
||||
title: '支付结果处理中,请稍后在历史中查看',
|
||||
icon: 'none',
|
||||
@@ -150,8 +150,9 @@ function wxPay(options) {
|
||||
},
|
||||
fail: (payErr) => {
|
||||
console.error('支付失败', payErr)
|
||||
|
||||
if (payErr.errMsg.indexOf('cancel') !== -1) {
|
||||
const isCancel = payErr.errMsg && payErr.errMsg.indexOf('cancel') !== -1
|
||||
try { require('./analytics').reportPayResult(false, { productType: productType || '', orderId, reason: isCancel ? 'cancel' : 'fail' }) } catch (e) {}
|
||||
if (isCancel) {
|
||||
wx.showToast({
|
||||
title: '支付已取消',
|
||||
icon: 'none'
|
||||
|
||||
Reference in New Issue
Block a user