Commit 09e200c364a05a572120f29273c30dc76edf7c63

Authored by YunaiV
1 parent b9246d15

mp:完成公众号统计的用户增减数据

Showing 15 changed files with 591 additions and 12 deletions
yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/ErrorCodeConstants.java
@@ -14,6 +14,9 @@ public interface ErrorCodeConstants { @@ -14,6 +14,9 @@ public interface ErrorCodeConstants {
14 ErrorCode ACCOUNT_GENERATE_QR_CODE_FAIL = new ErrorCode(1006000001, "生成公众号二维码失败,原因:{}"); 14 ErrorCode ACCOUNT_GENERATE_QR_CODE_FAIL = new ErrorCode(1006000001, "生成公众号二维码失败,原因:{}");
15 ErrorCode ACCOUNT_CLEAR_QUOTA_FAIL = new ErrorCode(1006000001, "清空公众号的 API 配额失败,原因:{}"); 15 ErrorCode ACCOUNT_CLEAR_QUOTA_FAIL = new ErrorCode(1006000001, "清空公众号的 API 配额失败,原因:{}");
16 16
  17 + // ========== 公众号账号 1006001000============
  18 + ErrorCode STATISTICS_GET_USER_SUMMARY_FAIL = new ErrorCode(1006001000, "获取用户增减数据失败,原因:{}");
  19 +
17 // TODO 要处理下 20 // TODO 要处理下
18 ErrorCode COMMON_NOT_EXISTS = new ErrorCode(1006001002, "用户不存在"); 21 ErrorCode COMMON_NOT_EXISTS = new ErrorCode(1006001002, "用户不存在");
19 22
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/MpAccountController.java
@@ -33,14 +33,14 @@ public class MpAccountController { @@ -33,14 +33,14 @@ public class MpAccountController {
33 @PostMapping("/create") 33 @PostMapping("/create")
34 @ApiOperation("创建公众号账号") 34 @ApiOperation("创建公众号账号")
35 @PreAuthorize("@ss.hasPermission('mp:account:create')") 35 @PreAuthorize("@ss.hasPermission('mp:account:create')")
36 - public CommonResult<Long> createWxAccount(@Valid @RequestBody MpAccountCreateReqVO createReqVO) { 36 + public CommonResult<Long> createAccount(@Valid @RequestBody MpAccountCreateReqVO createReqVO) {
37 return success(mpAccountService.createAccount(createReqVO)); 37 return success(mpAccountService.createAccount(createReqVO));
38 } 38 }
39 39
40 @PutMapping("/update") 40 @PutMapping("/update")
41 @ApiOperation("更新公众号账号") 41 @ApiOperation("更新公众号账号")
42 @PreAuthorize("@ss.hasPermission('mp:account:update')") 42 @PreAuthorize("@ss.hasPermission('mp:account:update')")
43 - public CommonResult<Boolean> updateWxAccount(@Valid @RequestBody MpAccountUpdateReqVO updateReqVO) { 43 + public CommonResult<Boolean> updateAccount(@Valid @RequestBody MpAccountUpdateReqVO updateReqVO) {
44 mpAccountService.updateAccount(updateReqVO); 44 mpAccountService.updateAccount(updateReqVO);
45 return success(true); 45 return success(true);
46 } 46 }
@@ -49,7 +49,7 @@ public class MpAccountController { @@ -49,7 +49,7 @@ public class MpAccountController {
49 @ApiOperation("删除公众号账号") 49 @ApiOperation("删除公众号账号")
50 @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) 50 @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
51 @PreAuthorize("@ss.hasPermission('mp:account:delete')") 51 @PreAuthorize("@ss.hasPermission('mp:account:delete')")
52 - public CommonResult<Boolean> deleteWxAccount(@RequestParam("id") Long id) { 52 + public CommonResult<Boolean> deleteAccount(@RequestParam("id") Long id) {
53 mpAccountService.deleteAccount(id); 53 mpAccountService.deleteAccount(id);
54 return success(true); 54 return success(true);
55 } 55 }
@@ -58,7 +58,7 @@ public class MpAccountController { @@ -58,7 +58,7 @@ public class MpAccountController {
58 @ApiOperation("获得公众号账号") 58 @ApiOperation("获得公众号账号")
59 @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) 59 @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
60 @PreAuthorize("@ss.hasPermission('mp:account:query')") 60 @PreAuthorize("@ss.hasPermission('mp:account:query')")
61 - public CommonResult<MpAccountRespVO> getWxAccount(@RequestParam("id") Long id) { 61 + public CommonResult<MpAccountRespVO> getAccount(@RequestParam("id") Long id) {
62 MpAccountDO wxAccount = mpAccountService.getAccount(id); 62 MpAccountDO wxAccount = mpAccountService.getAccount(id);
63 return success(MpAccountConvert.INSTANCE.convert(wxAccount)); 63 return success(MpAccountConvert.INSTANCE.convert(wxAccount));
64 } 64 }
@@ -66,7 +66,7 @@ public class MpAccountController { @@ -66,7 +66,7 @@ public class MpAccountController {
66 @GetMapping("/page") 66 @GetMapping("/page")
67 @ApiOperation("获得公众号账号分页") 67 @ApiOperation("获得公众号账号分页")
68 @PreAuthorize("@ss.hasPermission('mp:account:query')") 68 @PreAuthorize("@ss.hasPermission('mp:account:query')")
69 - public CommonResult<PageResult<MpAccountRespVO>> getWxAccountPage(@Valid MpAccountPageReqVO pageVO) { 69 + public CommonResult<PageResult<MpAccountRespVO>> getAccountPage(@Valid MpAccountPageReqVO pageVO) {
70 PageResult<MpAccountDO> pageResult = mpAccountService.getAccountPage(pageVO); 70 PageResult<MpAccountDO> pageResult = mpAccountService.getAccountPage(pageVO);
71 return success(MpAccountConvert.INSTANCE.convertPage(pageResult)); 71 return success(MpAccountConvert.INSTANCE.convertPage(pageResult));
72 } 72 }
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/account/vo/MpAccountUpdateReqVO.java
@@ -13,7 +13,7 @@ import javax.validation.constraints.*; @@ -13,7 +13,7 @@ import javax.validation.constraints.*;
13 @ToString(callSuper = true) 13 @ToString(callSuper = true)
14 public class MpAccountUpdateReqVO extends MpAccountBaseVO { 14 public class MpAccountUpdateReqVO extends MpAccountBaseVO {
15 15
16 - @ApiModelProperty(value = "编号", required = true) 16 + @ApiModelProperty(value = "编号", required = true, example = "1024")
17 @NotNull(message = "编号不能为空") 17 @NotNull(message = "编号不能为空")
18 private Long id; 18 private Long id;
19 19
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/MpStatisticsController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mp.controller.admin.statistics;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.mp.convert.statistics.MpStatisticsConvert;
  5 +import cn.iocoder.yudao.module.mp.service.statistics.MpStatisticsService;
  6 +import cn.iocoder.yudao.module.mp.controller.admin.statistics.vo.MpStatisticsGetReqVO;
  7 +import io.swagger.annotations.Api;
  8 +import io.swagger.annotations.ApiOperation;
  9 +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary;
  10 +import org.springframework.security.access.prepost.PreAuthorize;
  11 +import org.springframework.validation.annotation.Validated;
  12 +import org.springframework.web.bind.annotation.GetMapping;
  13 +import org.springframework.web.bind.annotation.RequestMapping;
  14 +import org.springframework.web.bind.annotation.RestController;
  15 +
  16 +import javax.annotation.Resource;
  17 +import java.util.List;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  20 +
  21 +@Api(tags = "管理后台 - 公众号统计")
  22 +@RestController
  23 +@RequestMapping("/mp/statistics")
  24 +@Validated
  25 +public class MpStatisticsController {
  26 +
  27 + @Resource
  28 + private MpStatisticsService mpStatisticsService;
  29 +
  30 + @GetMapping("/user-summary")
  31 + @ApiOperation("获得用户增减数据")
  32 + @PreAuthorize("@ss.hasPermission('mp:statistics:query')")
  33 + public CommonResult<List<WxDataCubeUserSummary>> getAccount(MpStatisticsGetReqVO getReqVO) {
  34 + List<WxDataCubeUserSummary> list = mpStatisticsService.getUserSummary(getReqVO.getId(), getReqVO.getDate());
  35 + return success(MpStatisticsConvert.INSTANCE.convertList01(list));
  36 + }
  37 +
  38 +}
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsGetReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mp.controller.admin.statistics.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +
  8 +import javax.validation.constraints.NotNull;
  9 +import java.time.LocalDateTime;
  10 +
  11 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  12 +
  13 +@ApiModel("管理后台 - 获得统计数据 Request VO")
  14 +@Data
  15 +public class MpStatisticsGetReqVO {
  16 +
  17 + @ApiModelProperty(value = "公众号账号的编号", required = true, example = "1024")
  18 + @NotNull(message = "公众号账号的编号不能为空")
  19 + private Long id;
  20 +
  21 + @ApiModelProperty(value = "查询时间范围")
  22 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  23 + @NotNull(message = "查询时间范围不能为空")
  24 + private LocalDateTime[] date;
  25 +
  26 +}
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/statistics/vo/MpStatisticsUserSummaryRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mp.controller.admin.statistics.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +import java.util.Date;
  8 +
  9 +@ApiModel("管理后台 - 某一天的用户增减数据 Response VO")
  10 +@Data
  11 +public class MpStatisticsUserSummaryRespVO {
  12 +
  13 + @ApiModelProperty(value = "日期", required = true)
  14 + private Date refDate;
  15 +
  16 + @ApiModelProperty(value = "用户来源", required = true, example = "0")
  17 + private Integer userSource;
  18 +
  19 + @ApiModelProperty(value = "新关注的用户数量", required = true, example = "10")
  20 + private Integer newUser;
  21 +
  22 + @ApiModelProperty(value = "取消关注的用户数量", required = true, example = "20")
  23 + private Integer cancelUser;
  24 +
  25 +}
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/statistics/MpStatisticsConvert.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mp.convert.statistics;
  2 +
  3 +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary;
  4 +import org.mapstruct.Mapper;
  5 +import org.mapstruct.factory.Mappers;
  6 +
  7 +import java.util.List;
  8 +
  9 +@Mapper
  10 +public interface MpStatisticsConvert {
  11 +
  12 + MpStatisticsConvert INSTANCE = Mappers.getMapper(MpStatisticsConvert.class);
  13 +
  14 + List<WxDataCubeUserSummary> convertList01(List<WxDataCubeUserSummary> list);
  15 +
  16 +}
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java
@@ -38,7 +38,11 @@ public class DefaultMpServiceFactory implements MpServiceFactory { @@ -38,7 +38,11 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
38 /** 38 /**
39 * 微信 appId 与 WxMpService 的映射 39 * 微信 appId 与 WxMpService 的映射
40 */ 40 */
41 - private volatile Map<String, WxMpService> mpServices; 41 + private volatile Map<String, WxMpService> appId2MpServices;
  42 + /**
  43 + * 公众号账号 id 与 WxMpService 的映射
  44 + */
  45 + private volatile Map<Long, WxMpService> id2MpServices;
42 /** 46 /**
43 * 微信 appId 与 WxMpMessageRouter 的映射 47 * 微信 appId 与 WxMpMessageRouter 的映射
44 */ 48 */
@@ -62,26 +66,34 @@ public class DefaultMpServiceFactory implements MpServiceFactory { @@ -62,26 +66,34 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
62 66
63 @Override 67 @Override
64 public void init(List<MpAccountDO> list) { 68 public void init(List<MpAccountDO> list) {
65 - Map<String, WxMpService> mpServices = Maps.newHashMap(); 69 + Map<String, WxMpService> appId2MpServices = Maps.newHashMap();
  70 + Map<Long, WxMpService> id2MpServices = Maps.newHashMap();
66 Map<String, WxMpMessageRouter> mpMessageRouters = Maps.newHashMap(); 71 Map<String, WxMpMessageRouter> mpMessageRouters = Maps.newHashMap();
67 // 处理 list 72 // 处理 list
68 list.forEach(account -> { 73 list.forEach(account -> {
69 // 构建 WxMpService 对象 74 // 构建 WxMpService 对象
70 WxMpService mpService = buildMpService(account); 75 WxMpService mpService = buildMpService(account);
71 - mpServices.put(account.getAppId(), mpService); 76 + appId2MpServices.put(account.getAppId(), mpService);
  77 + id2MpServices.put(account.getId(), mpService);
72 // 构建 WxMpMessageRouter 对象 78 // 构建 WxMpMessageRouter 对象
73 WxMpMessageRouter mpMessageRouter = buildMpMessageRouter(mpService); 79 WxMpMessageRouter mpMessageRouter = buildMpMessageRouter(mpService);
74 mpMessageRouters.put(account.getAppId(), mpMessageRouter); 80 mpMessageRouters.put(account.getAppId(), mpMessageRouter);
75 }); 81 });
76 82
77 // 设置到缓存 83 // 设置到缓存
78 - this.mpServices = mpServices; 84 + this.appId2MpServices = appId2MpServices;
  85 + this.id2MpServices = id2MpServices;
79 this.mpMessageRouters = mpMessageRouters; 86 this.mpMessageRouters = mpMessageRouters;
80 } 87 }
81 88
82 @Override 89 @Override
  90 + public WxMpService getMpService(Long id) {
  91 + return id2MpServices.get(id);
  92 + }
  93 +
  94 + @Override
83 public WxMpService getMpService(String appId) { 95 public WxMpService getMpService(String appId) {
84 - return mpServices.get(appId); 96 + return appId2MpServices.get(appId);
85 } 97 }
86 98
87 @Override 99 @Override
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/MpServiceFactory.java
@@ -22,6 +22,20 @@ public interface MpServiceFactory { @@ -22,6 +22,20 @@ public interface MpServiceFactory {
22 void init(List<MpAccountDO> list); 22 void init(List<MpAccountDO> list);
23 23
24 /** 24 /**
  25 + * 获得 id 对应的 WxMpService 实例
  26 + *
  27 + * @param id 微信公众号的编号
  28 + * @return WxMpService 实例
  29 + */
  30 + WxMpService getMpService(Long id);
  31 +
  32 + default WxMpService getRequiredMpService(Long id) {
  33 + WxMpService wxMpService = getMpService(id);
  34 + Assert.notNull(wxMpService, "找到对应 id({}) 的 WxMpService,请核实!", id);
  35 + return wxMpService;
  36 + }
  37 +
  38 + /**
25 * 获得 appId 对应的 WxMpService 实例 39 * 获得 appId 对应的 WxMpService 实例
26 * 40 *
27 * @param appId 微信公众号 appId 41 * @param appId 微信公众号 appId
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/statistics/MpStatisticsService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mp.service.statistics;
  2 +
  3 +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary;
  4 +
  5 +import java.time.LocalDateTime;
  6 +import java.util.List;
  7 +
  8 +/**
  9 + * 公众号统计 Service 接口
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +public interface MpStatisticsService {
  14 +
  15 + /**
  16 + * 获取用户增减数据
  17 + *
  18 + * @param id 公众号账号编号
  19 + * @param date 时间区间
  20 + * @return 用户增减数据
  21 + */
  22 + List<WxDataCubeUserSummary> getUserSummary(Long id, LocalDateTime[] date);
  23 +
  24 +}
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/statistics/MpStatisticsServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mp.service.statistics;
  2 +
  3 +import cn.hutool.core.date.DateUtil;
  4 +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
  5 +import me.chanjar.weixin.common.error.WxErrorException;
  6 +import me.chanjar.weixin.mp.api.WxMpService;
  7 +import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary;
  8 +import org.springframework.context.annotation.Lazy;
  9 +import org.springframework.stereotype.Service;
  10 +
  11 +import javax.annotation.Resource;
  12 +import java.time.LocalDateTime;
  13 +import java.util.List;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  16 +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.STATISTICS_GET_USER_SUMMARY_FAIL;
  17 +
  18 +/**
  19 + * 公众号统计 Service 实现类
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +@Service
  24 +public class MpStatisticsServiceImpl implements MpStatisticsService {
  25 +
  26 + @Resource
  27 + @Lazy // 延迟加载,解决循环依赖的问题
  28 + private MpServiceFactory mpServiceFactory;
  29 +
  30 + @Override
  31 + public List<WxDataCubeUserSummary> getUserSummary(Long id, LocalDateTime[] date) {
  32 + WxMpService mpService = mpServiceFactory.getRequiredMpService(id);
  33 + try {
  34 + return mpService.getDataCubeService().getUserSummary(
  35 + DateUtil.date(date[0]), DateUtil.date(date[1]));
  36 + } catch (WxErrorException e) {
  37 + throw exception(STATISTICS_GET_USER_SUMMARY_FAIL, e.getError().getErrorMsg());
  38 + }
  39 + }
  40 +
  41 +
  42 +}
yudao-ui-admin/src/api/mp/statistics.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// TODO 获得公众号账号分页
  4 +export function getInterfaceSummary(query) {
  5 + return request({
  6 + url: '/mp/account/page',
  7 + method: 'get',
  8 + params: query
  9 + })
  10 +}
  11 +
  12 +// TODO 获得公众号账号分页
  13 +export function getUserSummary(query) {
  14 + return request({
  15 + url: '/mp/statistics/user-summary',
  16 + method: 'get',
  17 + params: query
  18 + })
  19 +}
  20 +
  21 +// TODO 获得公众号账号分页
  22 +export function getUserCumulate(query) {
  23 + return request({
  24 + url: '/mp/account/page',
  25 + method: 'get',
  26 + params: query
  27 + })
  28 +}
yudao-ui-admin/src/utils/dateUtils.js
@@ -32,3 +32,35 @@ export function beginOfDay(date) { @@ -32,3 +32,35 @@ export function beginOfDay(date) {
32 export function endOfDay(date) { 32 export function endOfDay(date) {
33 return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999); 33 return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999);
34 } 34 }
  35 +
  36 +export function betweenDay(date1, date2) {
  37 + // 适配 string 字符串的日期
  38 + if (typeof date1 === 'string') {
  39 + date1 = new Date(date1);
  40 + }
  41 + if (typeof date2 === 'string') {
  42 + date2 = new Date(date2);
  43 + }
  44 + return Math.floor((date2.getTime() - date1.getTime()) / (24 * 3600 * 1000));
  45 +}
  46 +
  47 +export function formatDate(date, fmt) {
  48 + const o = {
  49 + "M+": date.getMonth() + 1, //月份
  50 + "d+": date.getDate(), //日
  51 + "H+": date.getHours(), //小时
  52 + "m+": date.getMinutes(), //分
  53 + "s+": date.getSeconds(), //秒
  54 + "q+": Math.floor((date.getMonth() + 3) / 3), //季度
  55 + "S": date.getMilliseconds() //毫秒
  56 + };
  57 + if (/(y+)/.test(fmt)) { // 年份
  58 + fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
  59 + }
  60 + for (const k in o) {
  61 + if (new RegExp("(" + k + ")").test(fmt)) {
  62 + fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  63 + }
  64 + }
  65 + return fmt;
  66 +}
yudao-ui-admin/src/views/mp/account/index.vue
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
33 <!-- <el-table-column label="消息加解密密钥" align="center" prop="aesKey"/>--> 33 <!-- <el-table-column label="消息加解密密钥" align="center" prop="aesKey"/>-->
34 <el-table-column label="服务器地址(URL)" align="center" prop="appId" width="360"> 34 <el-table-column label="服务器地址(URL)" align="center" prop="appId" width="360">
35 <template v-slot="scope"> 35 <template v-slot="scope">
36 - {{ 'http://服务端地址/mp/open/' + scope.row.appId }} 36 + {{ 'http://服务端地址/mp/open/' + scope.row.appId }}
37 </template> 37 </template>
38 </el-table-column> 38 </el-table-column>
39 <el-table-column label="二维码" align="center" prop="qrCodeUrl"> 39 <el-table-column label="二维码" align="center" prop="qrCodeUrl">
yudao-ui-admin/src/views/mp/statistics/index.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 + <el-card class="box-card">
  4 + <div slot="header" class="clearfix">
  5 + <span class="demonstration">时间范围</span>
  6 + <el-date-picker v-model="date" style="width: 260px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
  7 + range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"
  8 + :picker-options="datePickerOptions" :default-time="['00:00:00', '23:59:59']"
  9 + @change="changeDate" >
  10 + </el-date-picker>
  11 + </div>
  12 + <el-row>
  13 + <el-col :span="12">
  14 + <div id="userCumulateChart" :style="{width: '80%', height: '500px'}"></div>
  15 + </el-col>
  16 + <el-col :span="12">
  17 + <div id="interfaceSummaryChart" :style="{width: '80%', height: '500px'}"></div>
  18 + </el-col>
  19 + <el-col :span="12">
  20 + <div id="interfaceSummaryChart2" :style="{width: '80%', height: '500px'}"></div>
  21 + </el-col>
  22 + </el-row>
  23 +
  24 + <el-row>
  25 + <el-col :span="12" class="card-box">
  26 + <el-card>
  27 + <div slot="header">
  28 + <span>用户增减数据</span>
  29 + </div>
  30 + <div class="el-table el-table--enable-row-hover el-table--medium">
  31 + <div ref="userSummary" style="height: 420px" />
  32 + </div>
  33 + </el-card>
  34 + </el-col>
  35 +
  36 + <el-col :span="12" class="card-box">
  37 + <el-card>
  38 + <div slot="header">
  39 + <span>内存信息</span>
  40 + </div>
  41 + <div class="el-table el-table--enable-row-hover el-table--medium">
  42 + <div ref="usedmemory" style="height: 420px" />
  43 + </div>
  44 + </el-card>
  45 + </el-col>
  46 + </el-row>
  47 + </el-card>
  48 + </div>
  49 +</template>
  50 +
  51 +<script>
  52 +// 引入基本模板
  53 +import * as echarts from 'echarts'
  54 +
  55 +// 引入柱状图组件
  56 +require('echarts/lib/chart/bar')
  57 +// 引入柱拆线组件
  58 +require('echarts/lib/chart/line')
  59 +// 引入提示框和title组件
  60 +require('echarts/lib/component/tooltip')
  61 +require('echarts/lib/component/title')
  62 +require('echarts/lib/component/legend')
  63 +
  64 +import { getInterfaceSummary, getUserSummary, getUserCumulate } from '@/api/mp/statistics'
  65 +import { datePickerOptions } from "@/utils/constants";
  66 +import {beginOfDay, betweenDay, endOfDay, formatDate} from "@/utils/dateUtils";
  67 +
  68 +export default {
  69 + name: 'mpStatistics',
  70 + data() {
  71 + return {
  72 + date : [beginOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24 * 7)), // -7 天
  73 + endOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24))], // -1 天
  74 +
  75 + xAxisDate: [], // X 轴的日期范围
  76 + seriesData1: [],
  77 + seriesData2: [],
  78 + seriesData3: [],
  79 + seriesData4: [],
  80 + seriesData5: [],
  81 + seriesData6: [],
  82 + seriesData7: [],
  83 +
  84 + userSummaryOption: { // 用户增减数据
  85 + color: ['#67C23A', '#e5323e'],
  86 + legend: {
  87 + data: ['新增用户','取消关注的用户']
  88 + },
  89 + tooltip: {},
  90 + xAxis: {
  91 + data: this.xAxisDate
  92 + },
  93 + yAxis: {
  94 + minInterval: 1
  95 + },
  96 + series: [{
  97 + name: '新增用户',
  98 + type: 'bar',
  99 + label: {
  100 + normal: {
  101 + show: true
  102 + }
  103 + },
  104 + barGap: 0,
  105 + data: []
  106 + }, {
  107 + name: '取消关注的用户',
  108 + type: 'bar',
  109 + label: {
  110 + normal: {
  111 + show: true
  112 + }
  113 + },
  114 + data: []
  115 + }]
  116 + },
  117 +
  118 + // 静态变量
  119 + datePickerOptions: datePickerOptions,
  120 + }
  121 + },
  122 + created() {
  123 +
  124 + },
  125 + mounted: function() {
  126 + this.getSummary()
  127 + },
  128 + computed: {
  129 +
  130 + },
  131 + methods: {
  132 + changeDate() {
  133 +
  134 +
  135 +
  136 + this.seriesData1 = []
  137 + this.seriesData2 = []
  138 + this.seriesData5 = []
  139 + this.seriesData6 = []
  140 +
  141 + this.getSummary()
  142 + },
  143 + getSummary() {
  144 + // 必须选择 7 天内,因为公众号有时间跨度限制为 7
  145 + if (betweenDay(this.date[0], this.date[1]) >= 7) {
  146 + this.$message.error('时间间隔 7 天以内,请重新选择')
  147 + return false
  148 + }
  149 + this.xAxisDate = []
  150 + const days = betweenDay(this.date[0], this.date[1]) // 相差天数
  151 + for(let i = 0; i <= days; i++){
  152 + this.xAxisDate.push(formatDate(new Date(this.date[0].getTime() + 3600 * 1000 * 24 * i), 'yyyy-MM-dd'));
  153 + this.seriesData2.push(0)
  154 + this.seriesData5.push(0)
  155 + this.seriesData6.push(0)
  156 + }
  157 +
  158 + // 用户增减数据
  159 + this.userSummaryOption.xAxis.data = [];
  160 + this.userSummaryOption.series[0].data = [];
  161 + this.userSummaryOption.series[1].data = [];
  162 + getUserSummary({
  163 + id: 1,
  164 + date: [formatDate(this.date[0], 'yyyy-MM-dd HH:mm:ss'), formatDate(this.date[1], 'yyyy-MM-dd HH:mm:ss'),]
  165 + }).then(response => {
  166 + this.userSummaryOption.xAxis.data = this.xAxisDate;
  167 + // 处理数据
  168 + this.xAxisDate.forEach((date, index) => {
  169 + response.data.forEach((item) => {
  170 + // 匹配日期
  171 + const refDate = formatDate(new Date(item.refDate), 'yyyy-MM-dd');
  172 + if (refDate.indexOf(date) === -1) {
  173 + return;
  174 + }
  175 + // 设置数据到对应的位置
  176 + this.userSummaryOption.series[0].data[index] = item.newUser;
  177 + this.userSummaryOption.series[1].data[index] = item.cancelUser;
  178 + })
  179 + })
  180 + // 绘制图表
  181 + let userSummaryChart = echarts.init(this.$refs.userSummary);
  182 + userSummaryChart.setOption(this.userSummaryOption)
  183 + })
  184 + // .catch(() => {})
  185 +
  186 + // getUserCumulate({
  187 + // startDate: this.startDate,
  188 + // endDate: this.endDate
  189 + // }).then(response => {
  190 + // response.data.forEach((item, index, arr) => {
  191 + // this.$set(this.seriesData7, index, item.cumulateUser)
  192 + // })
  193 + // // 基于准备好的dom,初始化echarts实例
  194 + // let userCumulateChart = echarts.init(document.getElementById('userCumulateChart'))
  195 + // // 绘制图表
  196 + // userCumulateChart.setOption({
  197 + // title: { text: '累计用户数据' },
  198 + // legend: {
  199 + // data: ['累计用户量']
  200 + // },
  201 + // xAxis: {
  202 + // type: 'category',
  203 + // data: this.xAxisData
  204 + // },
  205 + // yAxis: {
  206 + // type: 'value'
  207 + // },
  208 + // series: [{
  209 + // name:'累计用户量',
  210 + // data: this.seriesData7,
  211 + // type: 'line',
  212 + // smooth: true,
  213 + // label: {
  214 + // normal: {
  215 + // show: true
  216 + // }
  217 + // }
  218 + // }]
  219 + // })
  220 + // }).catch(() => {
  221 + // })
  222 + //
  223 + // //获取接口数据
  224 + // getInterfaceSummary({
  225 + // startDate: this.startDate,
  226 + // endDate: this.endDate
  227 + // }).then(response => {
  228 + // response.data.forEach((item, index, arr) => {
  229 + // this.$set(this.seriesData1, index, item.callbackCount)
  230 + // this.$set(this.seriesData2, index, item.maxTimeCost)
  231 + // this.$set(this.seriesData3, index, item.totalTimeCost)
  232 + // this.$set(this.seriesData4, index, item.failCount)
  233 + // })
  234 + // // 基于准备好的dom,初始化echarts实例
  235 + // let interfaceSummaryChart = echarts.init(document.getElementById('interfaceSummaryChart'))
  236 + // // 绘制图表
  237 + // interfaceSummaryChart.setOption({
  238 + // title: { text: '接口分析数据' },
  239 + // color: ['#67C23A', '#e5323e'],
  240 + // legend: {
  241 + // data: ['被动回复用户消息的次数','失败次数']
  242 + // },
  243 + // tooltip: {},
  244 + // xAxis: {
  245 + // data: this.xAxisData
  246 + // },
  247 + // yAxis: {},
  248 + // series: [{
  249 + // name: '被动回复用户消息的次数',
  250 + // type: 'bar',
  251 + // label: {
  252 + // normal: {
  253 + // show: true
  254 + // }
  255 + // },
  256 + // barGap: 0,
  257 + // data: this.seriesData1
  258 + // },
  259 + // {
  260 + // name: '失败次数',
  261 + // type: 'bar',
  262 + // label: {
  263 + // normal: {
  264 + // show: true
  265 + // }
  266 + // },
  267 + // data: this.seriesData4
  268 + // }]
  269 + // })
  270 + //
  271 + // // 基于准备好的dom,初始化echarts实例
  272 + // let interfaceSummaryChart2 = echarts.init(document.getElementById('interfaceSummaryChart2'))
  273 + // // 绘制图表
  274 + // interfaceSummaryChart2.setOption({
  275 + // title: { text: '接口分析数据' },
  276 + // color: ['#E6A23C', '#409EFF'],
  277 + // legend: {
  278 + // data: ['最大耗时','总耗时']
  279 + // },
  280 + // tooltip: {},
  281 + // xAxis: {
  282 + // data: this.xAxisData
  283 + // },
  284 + // yAxis: {},
  285 + // series: [
  286 + // {
  287 + // name: '最大耗时',
  288 + // type: 'bar',
  289 + // label: {
  290 + // normal: {
  291 + // show: true
  292 + // }
  293 + // },
  294 + // data: this.seriesData2
  295 + // },
  296 + // {
  297 + // name: '总耗时',
  298 + // type: 'bar',
  299 + // label: {
  300 + // normal: {
  301 + // show: true
  302 + // }
  303 + // },
  304 + // data: this.seriesData3
  305 + // }]
  306 + // })
  307 + // }).catch(() => {
  308 + // })
  309 + }
  310 + }
  311 +}
  312 +</script>
  313 +
  314 +<style lang="scss" scoped>
  315 +.demonstration{
  316 + font-size: 15px;
  317 + margin-right: 10px;
  318 +}
  319 +</style>