mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 10:37:41 +08:00 
			
		
		
		
	mp:完成公众号统计的用户增减数据
This commit is contained in:
		| @ -14,6 +14,9 @@ public interface ErrorCodeConstants { | |||||||
|     ErrorCode ACCOUNT_GENERATE_QR_CODE_FAIL = new ErrorCode(1006000001, "生成公众号二维码失败,原因:{}"); |     ErrorCode ACCOUNT_GENERATE_QR_CODE_FAIL = new ErrorCode(1006000001, "生成公众号二维码失败,原因:{}"); | ||||||
|     ErrorCode ACCOUNT_CLEAR_QUOTA_FAIL = new ErrorCode(1006000001, "清空公众号的 API 配额失败,原因:{}"); |     ErrorCode ACCOUNT_CLEAR_QUOTA_FAIL = new ErrorCode(1006000001, "清空公众号的 API 配额失败,原因:{}"); | ||||||
|  |  | ||||||
|  |     // ========== 公众号账号 1006001000============ | ||||||
|  |     ErrorCode STATISTICS_GET_USER_SUMMARY_FAIL = new ErrorCode(1006001000, "获取用户增减数据失败,原因:{}"); | ||||||
|  |  | ||||||
|     // TODO 要处理下 |     // TODO 要处理下 | ||||||
|     ErrorCode COMMON_NOT_EXISTS = new ErrorCode(1006001002, "用户不存在"); |     ErrorCode COMMON_NOT_EXISTS = new ErrorCode(1006001002, "用户不存在"); | ||||||
|  |  | ||||||
|  | |||||||
| @ -33,14 +33,14 @@ public class MpAccountController { | |||||||
|     @PostMapping("/create") |     @PostMapping("/create") | ||||||
|     @ApiOperation("创建公众号账号") |     @ApiOperation("创建公众号账号") | ||||||
|     @PreAuthorize("@ss.hasPermission('mp:account:create')") |     @PreAuthorize("@ss.hasPermission('mp:account:create')") | ||||||
|     public CommonResult<Long> createWxAccount(@Valid @RequestBody MpAccountCreateReqVO createReqVO) { |     public CommonResult<Long> createAccount(@Valid @RequestBody MpAccountCreateReqVO createReqVO) { | ||||||
|         return success(mpAccountService.createAccount(createReqVO)); |         return success(mpAccountService.createAccount(createReqVO)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @PutMapping("/update") |     @PutMapping("/update") | ||||||
|     @ApiOperation("更新公众号账号") |     @ApiOperation("更新公众号账号") | ||||||
|     @PreAuthorize("@ss.hasPermission('mp:account:update')") |     @PreAuthorize("@ss.hasPermission('mp:account:update')") | ||||||
|     public CommonResult<Boolean> updateWxAccount(@Valid @RequestBody MpAccountUpdateReqVO updateReqVO) { |     public CommonResult<Boolean> updateAccount(@Valid @RequestBody MpAccountUpdateReqVO updateReqVO) { | ||||||
|         mpAccountService.updateAccount(updateReqVO); |         mpAccountService.updateAccount(updateReqVO); | ||||||
|         return success(true); |         return success(true); | ||||||
|     } |     } | ||||||
| @ -49,7 +49,7 @@ public class MpAccountController { | |||||||
|     @ApiOperation("删除公众号账号") |     @ApiOperation("删除公众号账号") | ||||||
|     @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) |     @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) | ||||||
|     @PreAuthorize("@ss.hasPermission('mp:account:delete')") |     @PreAuthorize("@ss.hasPermission('mp:account:delete')") | ||||||
|     public CommonResult<Boolean> deleteWxAccount(@RequestParam("id") Long id) { |     public CommonResult<Boolean> deleteAccount(@RequestParam("id") Long id) { | ||||||
|         mpAccountService.deleteAccount(id); |         mpAccountService.deleteAccount(id); | ||||||
|         return success(true); |         return success(true); | ||||||
|     } |     } | ||||||
| @ -58,7 +58,7 @@ public class MpAccountController { | |||||||
|     @ApiOperation("获得公众号账号") |     @ApiOperation("获得公众号账号") | ||||||
|     @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) |     @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) | ||||||
|     @PreAuthorize("@ss.hasPermission('mp:account:query')") |     @PreAuthorize("@ss.hasPermission('mp:account:query')") | ||||||
|     public CommonResult<MpAccountRespVO> getWxAccount(@RequestParam("id") Long id) { |     public CommonResult<MpAccountRespVO> getAccount(@RequestParam("id") Long id) { | ||||||
|         MpAccountDO wxAccount = mpAccountService.getAccount(id); |         MpAccountDO wxAccount = mpAccountService.getAccount(id); | ||||||
|         return success(MpAccountConvert.INSTANCE.convert(wxAccount)); |         return success(MpAccountConvert.INSTANCE.convert(wxAccount)); | ||||||
|     } |     } | ||||||
| @ -66,7 +66,7 @@ public class MpAccountController { | |||||||
|     @GetMapping("/page") |     @GetMapping("/page") | ||||||
|     @ApiOperation("获得公众号账号分页") |     @ApiOperation("获得公众号账号分页") | ||||||
|     @PreAuthorize("@ss.hasPermission('mp:account:query')") |     @PreAuthorize("@ss.hasPermission('mp:account:query')") | ||||||
|     public CommonResult<PageResult<MpAccountRespVO>> getWxAccountPage(@Valid MpAccountPageReqVO pageVO) { |     public CommonResult<PageResult<MpAccountRespVO>> getAccountPage(@Valid MpAccountPageReqVO pageVO) { | ||||||
|         PageResult<MpAccountDO> pageResult = mpAccountService.getAccountPage(pageVO); |         PageResult<MpAccountDO> pageResult = mpAccountService.getAccountPage(pageVO); | ||||||
|         return success(MpAccountConvert.INSTANCE.convertPage(pageResult)); |         return success(MpAccountConvert.INSTANCE.convertPage(pageResult)); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -13,7 +13,7 @@ import javax.validation.constraints.*; | |||||||
| @ToString(callSuper = true) | @ToString(callSuper = true) | ||||||
| public class MpAccountUpdateReqVO extends MpAccountBaseVO { | public class MpAccountUpdateReqVO extends MpAccountBaseVO { | ||||||
|  |  | ||||||
|     @ApiModelProperty(value = "编号", required = true) |     @ApiModelProperty(value = "编号", required = true, example = "1024") | ||||||
|     @NotNull(message = "编号不能为空") |     @NotNull(message = "编号不能为空") | ||||||
|     private Long id; |     private Long id; | ||||||
|  |  | ||||||
|  | |||||||
| @ -0,0 +1,38 @@ | |||||||
|  | package cn.iocoder.yudao.module.mp.controller.admin.statistics; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||||||
|  | import cn.iocoder.yudao.module.mp.convert.statistics.MpStatisticsConvert; | ||||||
|  | import cn.iocoder.yudao.module.mp.service.statistics.MpStatisticsService; | ||||||
|  | import cn.iocoder.yudao.module.mp.controller.admin.statistics.vo.MpStatisticsGetReqVO; | ||||||
|  | import io.swagger.annotations.Api; | ||||||
|  | import io.swagger.annotations.ApiOperation; | ||||||
|  | import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; | ||||||
|  | import org.springframework.security.access.prepost.PreAuthorize; | ||||||
|  | import org.springframework.validation.annotation.Validated; | ||||||
|  | import org.springframework.web.bind.annotation.GetMapping; | ||||||
|  | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
|  | import org.springframework.web.bind.annotation.RestController; | ||||||
|  |  | ||||||
|  | import javax.annotation.Resource; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||||||
|  |  | ||||||
|  | @Api(tags = "管理后台 - 公众号统计") | ||||||
|  | @RestController | ||||||
|  | @RequestMapping("/mp/statistics") | ||||||
|  | @Validated | ||||||
|  | public class MpStatisticsController { | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private MpStatisticsService mpStatisticsService; | ||||||
|  |  | ||||||
|  |     @GetMapping("/user-summary") | ||||||
|  |     @ApiOperation("获得用户增减数据") | ||||||
|  |     @PreAuthorize("@ss.hasPermission('mp:statistics:query')") | ||||||
|  |     public CommonResult<List<WxDataCubeUserSummary>> getAccount(MpStatisticsGetReqVO getReqVO) { | ||||||
|  |         List<WxDataCubeUserSummary> list = mpStatisticsService.getUserSummary(getReqVO.getId(), getReqVO.getDate()); | ||||||
|  |         return success(MpStatisticsConvert.INSTANCE.convertList01(list)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,26 @@ | |||||||
|  | package cn.iocoder.yudao.module.mp.controller.admin.statistics.vo; | ||||||
|  |  | ||||||
|  | import io.swagger.annotations.ApiModel; | ||||||
|  | import io.swagger.annotations.ApiModelProperty; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.springframework.format.annotation.DateTimeFormat; | ||||||
|  |  | ||||||
|  | import javax.validation.constraints.NotNull; | ||||||
|  | import java.time.LocalDateTime; | ||||||
|  |  | ||||||
|  | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||||||
|  |  | ||||||
|  | @ApiModel("管理后台 - 获得统计数据 Request VO") | ||||||
|  | @Data | ||||||
|  | public class MpStatisticsGetReqVO { | ||||||
|  |  | ||||||
|  |     @ApiModelProperty(value = "公众号账号的编号", required = true, example = "1024") | ||||||
|  |     @NotNull(message = "公众号账号的编号不能为空") | ||||||
|  |     private Long id; | ||||||
|  |  | ||||||
|  |     @ApiModelProperty(value = "查询时间范围") | ||||||
|  |     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||||||
|  |     @NotNull(message = "查询时间范围不能为空") | ||||||
|  |     private LocalDateTime[] date; | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,25 @@ | |||||||
|  | package cn.iocoder.yudao.module.mp.controller.admin.statistics.vo; | ||||||
|  |  | ||||||
|  | import io.swagger.annotations.ApiModel; | ||||||
|  | import io.swagger.annotations.ApiModelProperty; | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.util.Date; | ||||||
|  |  | ||||||
|  | @ApiModel("管理后台 - 某一天的用户增减数据 Response VO") | ||||||
|  | @Data | ||||||
|  | public class MpStatisticsUserSummaryRespVO { | ||||||
|  |  | ||||||
|  |     @ApiModelProperty(value = "日期", required = true) | ||||||
|  |     private Date refDate; | ||||||
|  |  | ||||||
|  |     @ApiModelProperty(value = "用户来源", required = true, example = "0") | ||||||
|  |     private Integer userSource; | ||||||
|  |  | ||||||
|  |     @ApiModelProperty(value = "新关注的用户数量", required = true, example = "10") | ||||||
|  |     private Integer newUser; | ||||||
|  |  | ||||||
|  |     @ApiModelProperty(value = "取消关注的用户数量", required = true, example = "20") | ||||||
|  |     private Integer cancelUser; | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,16 @@ | |||||||
|  | package cn.iocoder.yudao.module.mp.convert.statistics; | ||||||
|  |  | ||||||
|  | import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; | ||||||
|  | import org.mapstruct.Mapper; | ||||||
|  | import org.mapstruct.factory.Mappers; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | @Mapper | ||||||
|  | public interface MpStatisticsConvert { | ||||||
|  |  | ||||||
|  |     MpStatisticsConvert INSTANCE = Mappers.getMapper(MpStatisticsConvert.class); | ||||||
|  |  | ||||||
|  |     List<WxDataCubeUserSummary> convertList01(List<WxDataCubeUserSummary> list); | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -38,7 +38,11 @@ public class DefaultMpServiceFactory implements MpServiceFactory { | |||||||
|     /** |     /** | ||||||
|      * 微信 appId 与 WxMpService 的映射 |      * 微信 appId 与 WxMpService 的映射 | ||||||
|      */ |      */ | ||||||
|     private volatile Map<String, WxMpService> mpServices; |     private volatile Map<String, WxMpService> appId2MpServices; | ||||||
|  |     /** | ||||||
|  |      * 公众号账号 id 与 WxMpService 的映射 | ||||||
|  |      */ | ||||||
|  |     private volatile Map<Long, WxMpService> id2MpServices; | ||||||
|     /** |     /** | ||||||
|      * 微信 appId 与 WxMpMessageRouter 的映射 |      * 微信 appId 与 WxMpMessageRouter 的映射 | ||||||
|      */ |      */ | ||||||
| @ -62,26 +66,34 @@ public class DefaultMpServiceFactory implements MpServiceFactory { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public void init(List<MpAccountDO> list) { |     public void init(List<MpAccountDO> list) { | ||||||
|         Map<String, WxMpService> mpServices = Maps.newHashMap(); |         Map<String, WxMpService> appId2MpServices = Maps.newHashMap(); | ||||||
|  |         Map<Long, WxMpService> id2MpServices = Maps.newHashMap(); | ||||||
|         Map<String, WxMpMessageRouter> mpMessageRouters = Maps.newHashMap(); |         Map<String, WxMpMessageRouter> mpMessageRouters = Maps.newHashMap(); | ||||||
|         // 处理 list |         // 处理 list | ||||||
|         list.forEach(account -> { |         list.forEach(account -> { | ||||||
|             // 构建 WxMpService 对象 |             // 构建 WxMpService 对象 | ||||||
|             WxMpService mpService = buildMpService(account); |             WxMpService mpService = buildMpService(account); | ||||||
|             mpServices.put(account.getAppId(), mpService); |             appId2MpServices.put(account.getAppId(), mpService); | ||||||
|  |             id2MpServices.put(account.getId(), mpService); | ||||||
|             // 构建 WxMpMessageRouter 对象 |             // 构建 WxMpMessageRouter 对象 | ||||||
|             WxMpMessageRouter mpMessageRouter = buildMpMessageRouter(mpService); |             WxMpMessageRouter mpMessageRouter = buildMpMessageRouter(mpService); | ||||||
|             mpMessageRouters.put(account.getAppId(), mpMessageRouter); |             mpMessageRouters.put(account.getAppId(), mpMessageRouter); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         // 设置到缓存 |         // 设置到缓存 | ||||||
|         this.mpServices = mpServices; |         this.appId2MpServices = appId2MpServices; | ||||||
|  |         this.id2MpServices = id2MpServices; | ||||||
|         this.mpMessageRouters = mpMessageRouters; |         this.mpMessageRouters = mpMessageRouters; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public WxMpService getMpService(Long id) { | ||||||
|  |         return id2MpServices.get(id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public WxMpService getMpService(String appId) { |     public WxMpService getMpService(String appId) { | ||||||
|         return mpServices.get(appId); |         return appId2MpServices.get(appId); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|  | |||||||
| @ -21,6 +21,20 @@ public interface MpServiceFactory { | |||||||
|      */ |      */ | ||||||
|     void init(List<MpAccountDO> list); |     void init(List<MpAccountDO> list); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得 id 对应的 WxMpService 实例 | ||||||
|  |      * | ||||||
|  |      * @param id 微信公众号的编号 | ||||||
|  |      * @return WxMpService 实例 | ||||||
|  |      */ | ||||||
|  |     WxMpService getMpService(Long id); | ||||||
|  |  | ||||||
|  |     default WxMpService getRequiredMpService(Long id) { | ||||||
|  |         WxMpService wxMpService = getMpService(id); | ||||||
|  |         Assert.notNull(wxMpService, "找到对应 id({}) 的 WxMpService,请核实!", id); | ||||||
|  |         return wxMpService; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 获得 appId 对应的 WxMpService 实例 |      * 获得 appId 对应的 WxMpService 实例 | ||||||
|      * |      * | ||||||
|  | |||||||
| @ -0,0 +1,24 @@ | |||||||
|  | package cn.iocoder.yudao.module.mp.service.statistics; | ||||||
|  |  | ||||||
|  | import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; | ||||||
|  |  | ||||||
|  | import java.time.LocalDateTime; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 公众号统计 Service 接口 | ||||||
|  |  * | ||||||
|  |  * @author 芋道源码 | ||||||
|  |  */ | ||||||
|  | public interface MpStatisticsService { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取用户增减数据 | ||||||
|  |      * | ||||||
|  |      * @param id 公众号账号编号 | ||||||
|  |      * @param date 时间区间 | ||||||
|  |      * @return 用户增减数据 | ||||||
|  |      */ | ||||||
|  |     List<WxDataCubeUserSummary> getUserSummary(Long id, LocalDateTime[] date); | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,42 @@ | |||||||
|  | package cn.iocoder.yudao.module.mp.service.statistics; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.date.DateUtil; | ||||||
|  | import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; | ||||||
|  | import me.chanjar.weixin.common.error.WxErrorException; | ||||||
|  | import me.chanjar.weixin.mp.api.WxMpService; | ||||||
|  | import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; | ||||||
|  | import org.springframework.context.annotation.Lazy; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  |  | ||||||
|  | import javax.annotation.Resource; | ||||||
|  | import java.time.LocalDateTime; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
|  | import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.STATISTICS_GET_USER_SUMMARY_FAIL; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 公众号统计 Service 实现类 | ||||||
|  |  * | ||||||
|  |  * @author 芋道源码 | ||||||
|  |  */ | ||||||
|  | @Service | ||||||
|  | public class MpStatisticsServiceImpl implements MpStatisticsService { | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     @Lazy // 延迟加载,解决循环依赖的问题 | ||||||
|  |     private MpServiceFactory mpServiceFactory; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public List<WxDataCubeUserSummary> getUserSummary(Long id, LocalDateTime[] date) { | ||||||
|  |         WxMpService mpService = mpServiceFactory.getRequiredMpService(id); | ||||||
|  |         try { | ||||||
|  |             return mpService.getDataCubeService().getUserSummary( | ||||||
|  |                     DateUtil.date(date[0]), DateUtil.date(date[1])); | ||||||
|  |         } catch (WxErrorException e) { | ||||||
|  |             throw exception(STATISTICS_GET_USER_SUMMARY_FAIL, e.getError().getErrorMsg()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								yudao-ui-admin/src/api/mp/statistics.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								yudao-ui-admin/src/api/mp/statistics.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | import request from '@/utils/request' | ||||||
|  |  | ||||||
|  | // TODO 获得公众号账号分页 | ||||||
|  | export function getInterfaceSummary(query) { | ||||||
|  |   return request({ | ||||||
|  |     url: '/mp/account/page', | ||||||
|  |     method: 'get', | ||||||
|  |     params: query | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // TODO 获得公众号账号分页 | ||||||
|  | export function getUserSummary(query) { | ||||||
|  |   return request({ | ||||||
|  |     url: '/mp/statistics/user-summary', | ||||||
|  |     method: 'get', | ||||||
|  |     params: query | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // TODO 获得公众号账号分页 | ||||||
|  | export function getUserCumulate(query) { | ||||||
|  |   return request({ | ||||||
|  |     url: '/mp/account/page', | ||||||
|  |     method: 'get', | ||||||
|  |     params: query | ||||||
|  |   }) | ||||||
|  | } | ||||||
| @ -32,3 +32,35 @@ export function beginOfDay(date) { | |||||||
| export function endOfDay(date) { | export function endOfDay(date) { | ||||||
|   return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999); |   return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export function betweenDay(date1, date2) { | ||||||
|  |   // 适配 string 字符串的日期 | ||||||
|  |   if (typeof date1 === 'string') { | ||||||
|  |     date1 = new Date(date1); | ||||||
|  |   } | ||||||
|  |   if (typeof date2 === 'string') { | ||||||
|  |     date2 = new Date(date2); | ||||||
|  |   } | ||||||
|  |   return Math.floor((date2.getTime() - date1.getTime()) / (24 * 3600 * 1000)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function formatDate(date, fmt) { | ||||||
|  |   const o = { | ||||||
|  |     "M+": date.getMonth() + 1, //月份 | ||||||
|  |     "d+": date.getDate(), //日 | ||||||
|  |     "H+": date.getHours(), //小时 | ||||||
|  |     "m+": date.getMinutes(), //分 | ||||||
|  |     "s+": date.getSeconds(), //秒 | ||||||
|  |     "q+": Math.floor((date.getMonth() + 3) / 3), //季度 | ||||||
|  |     "S": date.getMilliseconds() //毫秒 | ||||||
|  |   }; | ||||||
|  |   if (/(y+)/.test(fmt)) { // 年份 | ||||||
|  |     fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length)); | ||||||
|  |   } | ||||||
|  |   for (const k in o) { | ||||||
|  |     if (new RegExp("(" + k + ")").test(fmt)) { | ||||||
|  |       fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return fmt; | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										319
									
								
								yudao-ui-admin/src/views/mp/statistics/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										319
									
								
								yudao-ui-admin/src/views/mp/statistics/index.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,319 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="app-container"> | ||||||
|  |     <el-card class="box-card"> | ||||||
|  |       <div slot="header" class="clearfix"> | ||||||
|  |         <span class="demonstration">时间范围</span> | ||||||
|  |         <el-date-picker v-model="date" style="width: 260px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange" | ||||||
|  |                         range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" | ||||||
|  |                         :picker-options="datePickerOptions" :default-time="['00:00:00', '23:59:59']" | ||||||
|  |                         @change="changeDate"  > | ||||||
|  |         </el-date-picker> | ||||||
|  |       </div> | ||||||
|  |       <el-row> | ||||||
|  |         <el-col :span="12"> | ||||||
|  |           <div id="userCumulateChart" :style="{width: '80%', height: '500px'}"></div> | ||||||
|  |         </el-col> | ||||||
|  |         <el-col :span="12"> | ||||||
|  |           <div id="interfaceSummaryChart" :style="{width: '80%', height: '500px'}"></div> | ||||||
|  |         </el-col> | ||||||
|  |         <el-col :span="12"> | ||||||
|  |           <div id="interfaceSummaryChart2" :style="{width: '80%', height: '500px'}"></div> | ||||||
|  |         </el-col> | ||||||
|  |       </el-row> | ||||||
|  |  | ||||||
|  |       <el-row> | ||||||
|  |         <el-col :span="12" class="card-box"> | ||||||
|  |           <el-card> | ||||||
|  |             <div slot="header"> | ||||||
|  |               <span>用户增减数据</span> | ||||||
|  |             </div> | ||||||
|  |             <div class="el-table el-table--enable-row-hover el-table--medium"> | ||||||
|  |               <div ref="userSummary" style="height: 420px" /> | ||||||
|  |             </div> | ||||||
|  |           </el-card> | ||||||
|  |         </el-col> | ||||||
|  |  | ||||||
|  |         <el-col :span="12" class="card-box"> | ||||||
|  |           <el-card> | ||||||
|  |             <div slot="header"> | ||||||
|  |               <span>内存信息</span> | ||||||
|  |             </div> | ||||||
|  |             <div class="el-table el-table--enable-row-hover el-table--medium"> | ||||||
|  |               <div ref="usedmemory" style="height: 420px" /> | ||||||
|  |             </div> | ||||||
|  |           </el-card> | ||||||
|  |         </el-col> | ||||||
|  |       </el-row> | ||||||
|  |     </el-card> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | // 引入基本模板 | ||||||
|  | import * as echarts from 'echarts' | ||||||
|  |  | ||||||
|  | // 引入柱状图组件 | ||||||
|  | require('echarts/lib/chart/bar') | ||||||
|  | // 引入柱拆线组件 | ||||||
|  | require('echarts/lib/chart/line') | ||||||
|  | // 引入提示框和title组件 | ||||||
|  | require('echarts/lib/component/tooltip') | ||||||
|  | require('echarts/lib/component/title') | ||||||
|  | require('echarts/lib/component/legend') | ||||||
|  |  | ||||||
|  | import { getInterfaceSummary, getUserSummary, getUserCumulate } from '@/api/mp/statistics' | ||||||
|  | import { datePickerOptions } from "@/utils/constants"; | ||||||
|  | import {beginOfDay, betweenDay, endOfDay, formatDate} from "@/utils/dateUtils"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'mpStatistics', | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       date : [beginOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24 * 7)), // -7 天 | ||||||
|  |         endOfDay(new Date(new Date().getTime() - 3600 * 1000 * 24))], // -1 天 | ||||||
|  |  | ||||||
|  |       xAxisDate: [], // X 轴的日期范围 | ||||||
|  |       seriesData1: [], | ||||||
|  |       seriesData2: [], | ||||||
|  |       seriesData3: [], | ||||||
|  |       seriesData4: [], | ||||||
|  |       seriesData5: [], | ||||||
|  |       seriesData6: [], | ||||||
|  |       seriesData7: [], | ||||||
|  |  | ||||||
|  |       userSummaryOption: { // 用户增减数据 | ||||||
|  |         color: ['#67C23A', '#e5323e'], | ||||||
|  |         legend: { | ||||||
|  |           data: ['新增用户','取消关注的用户'] | ||||||
|  |         }, | ||||||
|  |         tooltip: {}, | ||||||
|  |         xAxis: { | ||||||
|  |           data: this.xAxisDate | ||||||
|  |         }, | ||||||
|  |         yAxis: { | ||||||
|  |           minInterval: 1 | ||||||
|  |         }, | ||||||
|  |         series: [{ | ||||||
|  |           name: '新增用户', | ||||||
|  |           type: 'bar', | ||||||
|  |           label: { | ||||||
|  |             normal: { | ||||||
|  |               show: true | ||||||
|  |             } | ||||||
|  |           }, | ||||||
|  |           barGap: 0, | ||||||
|  |           data: [] | ||||||
|  |         }, { | ||||||
|  |           name: '取消关注的用户', | ||||||
|  |           type: 'bar', | ||||||
|  |           label: { | ||||||
|  |             normal: { | ||||||
|  |               show: true | ||||||
|  |             } | ||||||
|  |           }, | ||||||
|  |           data: [] | ||||||
|  |         }] | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       // 静态变量 | ||||||
|  |       datePickerOptions: datePickerOptions, | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |  | ||||||
|  |   }, | ||||||
|  |   mounted: function() { | ||||||
|  |     this.getSummary() | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |  | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     changeDate() { | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |       this.seriesData1 = [] | ||||||
|  |       this.seriesData2 = [] | ||||||
|  |       this.seriesData5 = [] | ||||||
|  |       this.seriesData6 = [] | ||||||
|  |  | ||||||
|  |       this.getSummary() | ||||||
|  |     }, | ||||||
|  |     getSummary() { | ||||||
|  |       // 必须选择 7 天内,因为公众号有时间跨度限制为 7 | ||||||
|  |       if (betweenDay(this.date[0], this.date[1]) >= 7) { | ||||||
|  |         this.$message.error('时间间隔 7 天以内,请重新选择') | ||||||
|  |         return false | ||||||
|  |       } | ||||||
|  |       this.xAxisDate = [] | ||||||
|  |       const days = betweenDay(this.date[0], this.date[1]) // 相差天数 | ||||||
|  |       for(let i = 0; i <= days; i++){ | ||||||
|  |         this.xAxisDate.push(formatDate(new Date(this.date[0].getTime() + 3600 * 1000 * 24 * i), 'yyyy-MM-dd')); | ||||||
|  |         this.seriesData2.push(0) | ||||||
|  |         this.seriesData5.push(0) | ||||||
|  |         this.seriesData6.push(0) | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // 用户增减数据 | ||||||
|  |       this.userSummaryOption.xAxis.data = []; | ||||||
|  |       this.userSummaryOption.series[0].data = []; | ||||||
|  |       this.userSummaryOption.series[1].data = []; | ||||||
|  |       getUserSummary({ | ||||||
|  |         id: 1, | ||||||
|  |         date: [formatDate(this.date[0], 'yyyy-MM-dd HH:mm:ss'), formatDate(this.date[1], 'yyyy-MM-dd HH:mm:ss'),] | ||||||
|  |       }).then(response => { | ||||||
|  |         this.userSummaryOption.xAxis.data = this.xAxisDate; | ||||||
|  |         // 处理数据 | ||||||
|  |         this.xAxisDate.forEach((date, index) => { | ||||||
|  |           response.data.forEach((item) => { | ||||||
|  |             // 匹配日期 | ||||||
|  |             const refDate = formatDate(new Date(item.refDate), 'yyyy-MM-dd'); | ||||||
|  |             if (refDate.indexOf(date) === -1) { | ||||||
|  |               return; | ||||||
|  |             } | ||||||
|  |             // 设置数据到对应的位置 | ||||||
|  |             this.userSummaryOption.series[0].data[index] = item.newUser; | ||||||
|  |             this.userSummaryOption.series[1].data[index] = item.cancelUser; | ||||||
|  |           }) | ||||||
|  |         }) | ||||||
|  |         // 绘制图表 | ||||||
|  |         let userSummaryChart = echarts.init(this.$refs.userSummary); | ||||||
|  |         userSummaryChart.setOption(this.userSummaryOption) | ||||||
|  |       }) | ||||||
|  |           // .catch(() => {}) | ||||||
|  |  | ||||||
|  |       // getUserCumulate({ | ||||||
|  |       //   startDate: this.startDate, | ||||||
|  |       //   endDate: this.endDate | ||||||
|  |       // }).then(response => { | ||||||
|  |       //   response.data.forEach((item, index, arr) => { | ||||||
|  |       //     this.$set(this.seriesData7, index, item.cumulateUser) | ||||||
|  |       //   }) | ||||||
|  |       //   // 基于准备好的dom,初始化echarts实例 | ||||||
|  |       //   let userCumulateChart = echarts.init(document.getElementById('userCumulateChart')) | ||||||
|  |       //   // 绘制图表 | ||||||
|  |       //   userCumulateChart.setOption({ | ||||||
|  |       //     title: { text: '累计用户数据' }, | ||||||
|  |       //     legend: { | ||||||
|  |       //       data: ['累计用户量'] | ||||||
|  |       //     }, | ||||||
|  |       //     xAxis: { | ||||||
|  |       //       type: 'category', | ||||||
|  |       //       data: this.xAxisData | ||||||
|  |       //     }, | ||||||
|  |       //     yAxis: { | ||||||
|  |       //       type: 'value' | ||||||
|  |       //     }, | ||||||
|  |       //     series: [{ | ||||||
|  |       //       name:'累计用户量', | ||||||
|  |       //       data: this.seriesData7, | ||||||
|  |       //       type: 'line', | ||||||
|  |       //       smooth: true, | ||||||
|  |       //       label: { | ||||||
|  |       //         normal: { | ||||||
|  |       //           show: true | ||||||
|  |       //         } | ||||||
|  |       //       } | ||||||
|  |       //     }] | ||||||
|  |       //   }) | ||||||
|  |       // }).catch(() => { | ||||||
|  |       // }) | ||||||
|  |       // | ||||||
|  |       // //获取接口数据 | ||||||
|  |       // getInterfaceSummary({ | ||||||
|  |       //   startDate: this.startDate, | ||||||
|  |       //   endDate: this.endDate | ||||||
|  |       // }).then(response => { | ||||||
|  |       //   response.data.forEach((item, index, arr) => { | ||||||
|  |       //     this.$set(this.seriesData1, index, item.callbackCount) | ||||||
|  |       //     this.$set(this.seriesData2, index, item.maxTimeCost) | ||||||
|  |       //     this.$set(this.seriesData3, index, item.totalTimeCost) | ||||||
|  |       //     this.$set(this.seriesData4, index, item.failCount) | ||||||
|  |       //   }) | ||||||
|  |       //   // 基于准备好的dom,初始化echarts实例 | ||||||
|  |       //   let interfaceSummaryChart = echarts.init(document.getElementById('interfaceSummaryChart')) | ||||||
|  |       //   // 绘制图表 | ||||||
|  |       //   interfaceSummaryChart.setOption({ | ||||||
|  |       //     title: { text: '接口分析数据' }, | ||||||
|  |       //     color: ['#67C23A', '#e5323e'], | ||||||
|  |       //     legend: { | ||||||
|  |       //       data: ['被动回复用户消息的次数','失败次数'] | ||||||
|  |       //     }, | ||||||
|  |       //     tooltip: {}, | ||||||
|  |       //     xAxis: { | ||||||
|  |       //       data: this.xAxisData | ||||||
|  |       //     }, | ||||||
|  |       //     yAxis: {}, | ||||||
|  |       //     series: [{ | ||||||
|  |       //       name: '被动回复用户消息的次数', | ||||||
|  |       //       type: 'bar', | ||||||
|  |       //       label: { | ||||||
|  |       //         normal: { | ||||||
|  |       //           show: true | ||||||
|  |       //         } | ||||||
|  |       //       }, | ||||||
|  |       //       barGap: 0, | ||||||
|  |       //       data: this.seriesData1 | ||||||
|  |       //     }, | ||||||
|  |       //       { | ||||||
|  |       //         name: '失败次数', | ||||||
|  |       //         type: 'bar', | ||||||
|  |       //         label: { | ||||||
|  |       //           normal: { | ||||||
|  |       //             show: true | ||||||
|  |       //           } | ||||||
|  |       //         }, | ||||||
|  |       //         data: this.seriesData4 | ||||||
|  |       //       }] | ||||||
|  |       //   }) | ||||||
|  |       // | ||||||
|  |       //   // 基于准备好的dom,初始化echarts实例 | ||||||
|  |       //   let interfaceSummaryChart2 = echarts.init(document.getElementById('interfaceSummaryChart2')) | ||||||
|  |       //   // 绘制图表 | ||||||
|  |       //   interfaceSummaryChart2.setOption({ | ||||||
|  |       //     title: { text: '接口分析数据' }, | ||||||
|  |       //     color: ['#E6A23C', '#409EFF'], | ||||||
|  |       //     legend: { | ||||||
|  |       //       data: ['最大耗时','总耗时'] | ||||||
|  |       //     }, | ||||||
|  |       //     tooltip: {}, | ||||||
|  |       //     xAxis: { | ||||||
|  |       //       data: this.xAxisData | ||||||
|  |       //     }, | ||||||
|  |       //     yAxis: {}, | ||||||
|  |       //     series: [ | ||||||
|  |       //       { | ||||||
|  |       //         name: '最大耗时', | ||||||
|  |       //         type: 'bar', | ||||||
|  |       //         label: { | ||||||
|  |       //           normal: { | ||||||
|  |       //             show: true | ||||||
|  |       //           } | ||||||
|  |       //         }, | ||||||
|  |       //         data: this.seriesData2 | ||||||
|  |       //       }, | ||||||
|  |       //       { | ||||||
|  |       //         name: '总耗时', | ||||||
|  |       //         type: 'bar', | ||||||
|  |       //         label: { | ||||||
|  |       //           normal: { | ||||||
|  |       //             show: true | ||||||
|  |       //           } | ||||||
|  |       //         }, | ||||||
|  |       //         data: this.seriesData3 | ||||||
|  |       //       }] | ||||||
|  |       //   }) | ||||||
|  |       // }).catch(() => { | ||||||
|  |       // }) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .demonstration{ | ||||||
|  |   font-size: 15px; | ||||||
|  |   margin-right: 10px; | ||||||
|  | } | ||||||
|  | </style> | ||||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV