analysis.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. package analysis
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/silenceper/wechat/v2/miniprogram/context"
  6. "github.com/silenceper/wechat/v2/util"
  7. )
  8. const (
  9. // 获取用户访问小程序日留存
  10. getAnalysisDailyRetainURL = "https://api.weixin.qq.com/datacube/getweanalysisappiddailyretaininfo?access_token=%s"
  11. // 获取用户访问小程序月留存
  12. getAnalysisMonthlyRetainURL = "https://api.weixin.qq.com/datacube/getweanalysisappidmonthlyretaininfo?access_token=%s"
  13. // 获取用户访问小程序周留存
  14. getAnalysisWeeklyRetainURL = "https://api.weixin.qq.com/datacube/getweanalysisappidweeklyretaininfo?access_token=%s"
  15. // 获取用户访问小程序数据概况
  16. getAnalysisDailySummaryURL = "https://api.weixin.qq.com/datacube/getweanalysisappiddailysummarytrend?access_token=%s"
  17. // 获取用户访问小程序数据日趋势
  18. getAnalysisDailyVisitTrendURL = "https://api.weixin.qq.com/datacube/getweanalysisappiddailyvisittrend?access_token=%s"
  19. // 获取用户访问小程序数据月趋势
  20. getAnalysisMonthlyVisitTrendURL = "https://api.weixin.qq.com/datacube/getweanalysisappidmonthlyvisittrend?access_token=%s"
  21. // 获取用户访问小程序数据周趋势
  22. getAnalysisWeeklyVisitTrendURL = "https://api.weixin.qq.com/datacube/getweanalysisappidweeklyvisittrend?access_token=%s"
  23. // 获取小程序新增或活跃用户的画像分布数据
  24. getAnalysisUserPortraitURL = "https://api.weixin.qq.com/datacube/getweanalysisappiduserportrait?access_token=%s"
  25. // 获取用户小程序访问分布数据
  26. getAnalysisVisitDistributionURL = "https://api.weixin.qq.com/datacube/getweanalysisappidvisitdistribution?access_token=%s"
  27. // 访问页面
  28. getAnalysisVisitPageURL = "https://api.weixin.qq.com/datacube/getweanalysisappidvisitpage?access_token=%s"
  29. // 获取小程序性能数据
  30. getPerformanceDataURL = "https://api.weixin.qq.com/wxa/business/performance/boot?access_token=%s"
  31. )
  32. // Analysis analyis 数据分析
  33. type Analysis struct {
  34. *context.Context
  35. }
  36. // NewAnalysis new
  37. func NewAnalysis(ctx *context.Context) *Analysis {
  38. return &Analysis{ctx}
  39. }
  40. // fetchData 拉取统计数据
  41. func (analysis *Analysis) fetchData(urlStr string, body interface{}) (response []byte, err error) {
  42. var accessToken string
  43. accessToken, err = analysis.GetAccessToken()
  44. if err != nil {
  45. return
  46. }
  47. urlStr = fmt.Sprintf(urlStr, accessToken)
  48. response, err = util.PostJSON(urlStr, body)
  49. return
  50. }
  51. // RetainItem 留存项结构
  52. type RetainItem struct {
  53. Key int `json:"key"` // 标识,0开始表示当天,1表示1甜后,以此类推
  54. Value int `json:"value"` // key对应日期的新增用户数/活跃用户数(key=0时)或留存用户数(k>0时)
  55. }
  56. // ResAnalysisRetain 小程序留存数据返回
  57. type ResAnalysisRetain struct {
  58. util.CommonError
  59. RefDate string `json:"ref_date"` // 日期
  60. VisitUVNew []RetainItem `json:"visit_uv_new"` // 新增用户留存
  61. VisitUV []RetainItem `json:"visit_uv"` // 活跃用户留存
  62. }
  63. // getAnalysisRetain 获取用户访问小程序留存数据(日、月、周)
  64. func (analysis *Analysis) getAnalysisRetain(urlStr string, beginDate, endDate string) (result ResAnalysisRetain, err error) {
  65. body := map[string]string{
  66. "begin_date": beginDate,
  67. "end_date": endDate,
  68. }
  69. response, err := analysis.fetchData(urlStr, body)
  70. if err != nil {
  71. return
  72. }
  73. err = json.Unmarshal(response, &result)
  74. if err != nil {
  75. return
  76. }
  77. if result.ErrCode != 0 {
  78. err = fmt.Errorf("getAnalysisRetain error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
  79. return
  80. }
  81. return
  82. }
  83. // GetAnalysisDailyRetain 获取用户访问小程序日留存
  84. func (analysis *Analysis) GetAnalysisDailyRetain(beginDate, endDate string) (result ResAnalysisRetain, err error) {
  85. return analysis.getAnalysisRetain(getAnalysisDailyRetainURL, beginDate, endDate)
  86. }
  87. // GetAnalysisMonthlyRetain 获取用户访问小程序月留存
  88. func (analysis *Analysis) GetAnalysisMonthlyRetain(beginDate, endDate string) (result ResAnalysisRetain, err error) {
  89. return analysis.getAnalysisRetain(getAnalysisMonthlyRetainURL, beginDate, endDate)
  90. }
  91. // GetAnalysisWeeklyRetain 获取用户访问小程序周留存
  92. func (analysis *Analysis) GetAnalysisWeeklyRetain(beginDate, endDate string) (result ResAnalysisRetain, err error) {
  93. return analysis.getAnalysisRetain(getAnalysisWeeklyRetainURL, beginDate, endDate)
  94. }
  95. // ResAnalysisDailySummary 小程序访问数据概况
  96. type ResAnalysisDailySummary struct {
  97. util.CommonError
  98. List []struct {
  99. RefDate string `json:"ref_date"` // 日期
  100. VisitTotal int `json:"visit_total"` // 累计用户数
  101. SharePV int `json:"share_pv"` // 转发次数
  102. ShareUV int `json:"share_uv"` // 转发人数
  103. } `json:"list"`
  104. }
  105. // GetAnalysisDailySummary 获取用户访问小程序数据概况
  106. func (analysis *Analysis) GetAnalysisDailySummary(beginDate, endDate string) (result ResAnalysisDailySummary, err error) {
  107. body := map[string]string{
  108. "begin_date": beginDate,
  109. "end_date": endDate,
  110. }
  111. response, err := analysis.fetchData(getAnalysisDailySummaryURL, body)
  112. if err != nil {
  113. return
  114. }
  115. err = json.Unmarshal(response, &result)
  116. if err != nil {
  117. return
  118. }
  119. if result.ErrCode != 0 {
  120. err = fmt.Errorf("GetAnalysisDailySummary error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
  121. return
  122. }
  123. return
  124. }
  125. // ResAnalysisVisitTrend 小程序访问数据趋势(日、月、周)
  126. type ResAnalysisVisitTrend struct {
  127. util.CommonError
  128. List []struct {
  129. RefDate string `json:"ref_date"` // 日期
  130. SessionCnt int `json:"session_cnt"` // 打开次数
  131. VisitPV int `json:"visit_pv"` // 访问次数
  132. VisitUV int `json:"visit_uv"` // 访问人数
  133. VisitUVNew int `json:"visit_uv_new"` // 新用户数
  134. StayTimeUV float64 `json:"stay_time_uv"` // 人均停留时长
  135. StayTimeSession float64 `json:"stay_time_session"` // 次均停留时常
  136. VisitDepth float64 `json:"visit_depth"` // 平均访问深度
  137. } `json:"list"`
  138. }
  139. // getAnalysisRetain 获取小程序访问数据趋势(日、月、周)
  140. func (analysis *Analysis) getAnalysisVisitTrend(urlStr string, beginDate, endDate string) (result ResAnalysisVisitTrend, err error) {
  141. body := map[string]string{
  142. "begin_date": beginDate,
  143. "end_date": endDate,
  144. }
  145. response, err := analysis.fetchData(urlStr, body)
  146. if err != nil {
  147. return
  148. }
  149. err = json.Unmarshal(response, &result)
  150. if err != nil {
  151. return
  152. }
  153. if result.ErrCode != 0 {
  154. err = fmt.Errorf("getAnalysisVisitTrend error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
  155. return
  156. }
  157. return
  158. }
  159. // GetAnalysisDailyVisitTrend 获取用户访问小程序数据日趋势
  160. func (analysis *Analysis) GetAnalysisDailyVisitTrend(beginDate, endDate string) (result ResAnalysisVisitTrend, err error) {
  161. return analysis.getAnalysisVisitTrend(getAnalysisDailyVisitTrendURL, beginDate, endDate)
  162. }
  163. // GetAnalysisMonthlyVisitTrend 获取用户访问小程序数据月趋势
  164. func (analysis *Analysis) GetAnalysisMonthlyVisitTrend(beginDate, endDate string) (result ResAnalysisVisitTrend, err error) {
  165. return analysis.getAnalysisVisitTrend(getAnalysisMonthlyVisitTrendURL, beginDate, endDate)
  166. }
  167. // GetAnalysisWeeklyVisitTrend 获取用户访问小程序数据周趋势
  168. func (analysis *Analysis) GetAnalysisWeeklyVisitTrend(beginDate, endDate string) (result ResAnalysisVisitTrend, err error) {
  169. return analysis.getAnalysisVisitTrend(getAnalysisWeeklyVisitTrendURL, beginDate, endDate)
  170. }
  171. // UserPortraitItem 用户画像项目
  172. type UserPortraitItem struct {
  173. ID int `json:"id"` // 属性值id
  174. Name string `json:"name"` // 属性值名称
  175. Value int `json:"value"` // 该场景访问uv
  176. }
  177. // UserPortrait 用户画像
  178. type UserPortrait struct {
  179. Index int `json:"index"` // 分布类型
  180. Province []UserPortraitItem `json:"province"` // 省份,如北京、广东等
  181. City []UserPortraitItem `json:"city"` // 城市,如北京、广州等
  182. Genders []UserPortraitItem `json:"genders"` // 性别,包括男、女、未知
  183. Platforms []UserPortraitItem `json:"platforms"` // 终端类型,包括iPhone, android, 其他
  184. Devices []UserPortraitItem `json:"devices"` // 机型,如苹果iPhone 6, OPPO R9等
  185. Ages []UserPortraitItem `json:"ages"` // 年龄,包括17岁以下、18-24对等区间
  186. }
  187. // ResAnalysisUserPortrait 小程序新增或活跃用户的画像分布数据返回
  188. type ResAnalysisUserPortrait struct {
  189. util.CommonError
  190. RefDate string `json:"ref_date"` // 日期
  191. VisitUVNew UserPortrait `json:"visit_uv_new"` // 新用户画像
  192. VisitUV UserPortrait `json:"visit_uv"` // 活跃用户画像
  193. }
  194. // GetAnalysisUserPortrait 获取小程序新增或活跃用户的画像分布数据
  195. func (analysis *Analysis) GetAnalysisUserPortrait(beginDate, endDate string) (result ResAnalysisUserPortrait, err error) {
  196. body := map[string]string{
  197. "begin_date": beginDate,
  198. "end_date": endDate,
  199. }
  200. response, err := analysis.fetchData(getAnalysisUserPortraitURL, body)
  201. if err != nil {
  202. return
  203. }
  204. err = json.Unmarshal(response, &result)
  205. if err != nil {
  206. return
  207. }
  208. if result.ErrCode != 0 {
  209. err = fmt.Errorf("GetAnalysisUserPortrait error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
  210. return
  211. }
  212. return
  213. }
  214. // VisitDistributionIndexItem 访问分数数据结构
  215. type VisitDistributionIndexItem struct {
  216. Key int `json:"key"` // 场景id
  217. Value int `json:"value"` // 该场景id访问pv
  218. AccessSourceVisitUV int `json:"access_source_visit_uv"` // 该场景id访问uv
  219. }
  220. // VisitDistributionIndex 访问分布单分布类型数据
  221. type VisitDistributionIndex struct {
  222. Index string `json:"index"` // 分布类型
  223. ItemList []VisitDistributionIndexItem `json:"item_list"` // 分布数据列表
  224. }
  225. // ResAnalysisVisitDistribution 小程序访问分布数据返回
  226. type ResAnalysisVisitDistribution struct {
  227. util.CommonError
  228. RefDate string `json:"ref_date"` // 日期
  229. List []VisitDistributionIndex `json:"list"` // 数据列表
  230. }
  231. // GetAnalysisVisitDistribution 获取用户小程序访问分布数据
  232. func (analysis *Analysis) GetAnalysisVisitDistribution(beginDate, endDate string) (result ResAnalysisVisitDistribution, err error) {
  233. body := map[string]string{
  234. "begin_date": beginDate,
  235. "end_date": endDate,
  236. }
  237. response, err := analysis.fetchData(getAnalysisVisitDistributionURL, body)
  238. if err != nil {
  239. return
  240. }
  241. err = json.Unmarshal(response, &result)
  242. if err != nil {
  243. return
  244. }
  245. if result.ErrCode != 0 {
  246. err = fmt.Errorf("GetAnalysisVisitDistribution error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
  247. return
  248. }
  249. return
  250. }
  251. // VisitPageItem 访问单个页面的数据结构
  252. type VisitPageItem struct {
  253. PagePath string `json:"page_path"` // 页面路径
  254. PageVisitPV int `json:"page_visit_pv"` // 访问次数
  255. PageVisitUV int `json:"page_visit_uv"` // 访问人数
  256. PageStaytimePV float64 `json:"page_staytime_pv"` // 次均停留时常
  257. EntrypagePV int `json:"entrypage_pv"` // 进入页次数
  258. ExitpagePV int `json:"exitpage_pv"` // 退出页次数
  259. PageSharePV int `json:"page_share_pv"` // 转发次数
  260. PageShareUV int `json:"page_share_uv"` // 转发人数
  261. }
  262. // ResAnalysisVisitPage 访问小程序页面访问数据返回
  263. type ResAnalysisVisitPage struct {
  264. util.CommonError
  265. RefDate string `json:"ref_date"` // 日期
  266. List []VisitPageItem `json:"list"` // 数据列表
  267. }
  268. // GetAnalysisVisitPage 获取小程序页面访问数据
  269. func (analysis *Analysis) GetAnalysisVisitPage(beginDate, endDate string) (result ResAnalysisVisitPage, err error) {
  270. body := map[string]string{
  271. "begin_date": beginDate,
  272. "end_date": endDate,
  273. }
  274. response, err := analysis.fetchData(getAnalysisVisitPageURL, body)
  275. if err != nil {
  276. return
  277. }
  278. err = json.Unmarshal(response, &result)
  279. if err != nil {
  280. return
  281. }
  282. if result.ErrCode != 0 {
  283. err = fmt.Errorf("GetAnalysisVisitPage error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
  284. return
  285. }
  286. return
  287. }
  288. // GetPerformanceDataRequest 获取小程序性能数据请求
  289. type GetPerformanceDataRequest struct {
  290. Module string `json:"module"`
  291. Time PerformanceDataTime `json:"time"`
  292. Params []PerformanceDataParams `json:"params"`
  293. }
  294. // PerformanceDataTime 获取小程序性能数据开始和结束日期
  295. type PerformanceDataTime struct {
  296. BeginTimestamp int64 `json:"begin_timestamp"`
  297. EndTimestamp int64 `json:"end_timestamp"`
  298. }
  299. // PerformanceDataParams 获取小程序性能数据查询条件
  300. type PerformanceDataParams struct {
  301. Field string `json:"field"`
  302. Value string `json:"value"`
  303. }
  304. // GetPerformanceDataResponse 获取小程序性能数据响应
  305. type GetPerformanceDataResponse struct {
  306. util.CommonError
  307. Body PerformanceDataBody `json:"body"`
  308. }
  309. // PerformanceDataBody 性能数据
  310. type PerformanceDataBody struct {
  311. Tables []PerformanceDataTable `json:"tables"`
  312. Count int64 `json:"count"`
  313. }
  314. // PerformanceDataTable 数据数组
  315. type PerformanceDataTable struct {
  316. ID string `json:"id"`
  317. Lines []PerformanceDataTableLine `json:"lines"`
  318. Zh string `json:"zh"`
  319. }
  320. // PerformanceDataTableLine 按时间排列的性能数据
  321. type PerformanceDataTableLine struct {
  322. Fields []PerformanceDataTableLineField `json:"fields"`
  323. }
  324. // PerformanceDataTableLineField 单天的性能数据
  325. type PerformanceDataTableLineField struct {
  326. RefDate string `json:"refdate"`
  327. Value string `json:"value"`
  328. }
  329. // GetPerformanceData 获取小程序性能数据
  330. // see https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/data-analysis/others/getPerformanceData.html
  331. func (analysis *Analysis) GetPerformanceData(req *GetPerformanceDataRequest) (res GetPerformanceDataResponse, err error) {
  332. var accessToken string
  333. if accessToken, err = analysis.GetAccessToken(); err != nil {
  334. return
  335. }
  336. var response []byte
  337. if response, err = util.PostJSON(fmt.Sprintf(getPerformanceDataURL, accessToken), req); err != nil {
  338. return
  339. }
  340. err = util.DecodeWithError(response, &res, "GetPerformanceData")
  341. return
  342. }