公会-运营统计

This commit is contained in:
khalil
2025-07-16 17:41:39 +08:00
parent 6f5b18652d
commit ccf5293f81
7 changed files with 361 additions and 2 deletions

View File

@@ -0,0 +1,25 @@
package com.accompany.business.dto;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class WeekGuildMemberPartitionStat {
private String date;
private String endDate;
private Integer partitionId;
private Integer guildId;
private Long uid;
private Date guildCreateTime;
private Boolean newGuild;
private BigDecimal guildDiamondFlow;
private BigDecimal guildGoldFlow;
}

View File

@@ -0,0 +1,61 @@
package com.accompany.business.model;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class WeekGuildPartitionStat {
private String date;
private String endDate;
private Integer partitionId;
private Integer newGuildCount;
private Integer newActiveGuildCount;
private BigDecimal newGuildTotalDiamondFlow;
private BigDecimal newGuildTotalGoldFlow;
private Integer guildCount;
private Integer activeGuildCount;
private BigDecimal guildTotalDiamondFlow;
private BigDecimal guildTotalGoldFlow;
private Integer newGuildMemberCount;
private Integer newGuildMemberActiveCount;
private Integer guildMemberCount;
private Integer activeGuildMemberCount;
private String remark;
private Integer adminId;
private Integer lastWeekNewGuildCount;
private BigDecimal lastWeekNewGuildCountWow;
private Integer lastWeekNewActiveGuildCount;
private BigDecimal lastWeekNewActiveGuildCountWow;
private BigDecimal lastWeekNewGuildTotalDiamondFlow;
private BigDecimal lastWeekNewGuildTotalDiamondFlowWow;
private BigDecimal lastWeekNewGuildTotalGoldFlow;
private BigDecimal lastWeekNewGuildTotalGoldFlowWow;
private Integer lastWeekGuildCount;
private BigDecimal lastWeekGuildCountWow;
private Integer lastWeekActiveGuildCount;
private BigDecimal lastWeekActiveGuildCountWow;
private BigDecimal lastWeekGuildTotalDiamondFlow;
private BigDecimal lastWeekGuildTotalDiamondFlowWow;
private BigDecimal lastWeekGuildTotalGoldFlow;
private BigDecimal lastWeekGuildTotalGoldFlowWow;
private Integer lastWeekNewGuildMemberCount;
private BigDecimal lastWeekNewGuildMemberCountWow;
private Integer lastWeekNewGuildMemberActiveCount;
private BigDecimal lastWeekNewGuildMemberActiveCountWow;
private Integer lastWeekGuildMemberCount;
private BigDecimal lastWeekGuildMemberCountWow;
private Integer lastWeekActiveGuildMemberCount;
private BigDecimal lastWeekActiveGuildMemberCountWow;
}

View File

@@ -0,0 +1,10 @@
package com.accompany.business.mybatismapper;
import com.accompany.business.model.WeekGuildPartitionStat;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface WeekGuildPartitionStatMapper extends BaseMapper<WeekGuildPartitionStat> {
}

View File

@@ -0,0 +1,226 @@
package com.accompany.business.service;
import com.accompany.business.dto.WeekGuildMemberPartitionStat;
import com.accompany.business.model.WeekGuildPartitionStat;
import com.accompany.business.model.guild.Guild;
import com.accompany.business.model.guild.GuildMember;
import com.accompany.business.mybatismapper.WeekGuildPartitionStatMapper;
import com.accompany.business.service.guild.GuildMemberService;
import com.accompany.business.service.guild.GuildService;
import com.accompany.common.utils.DateTimeUtil;
import com.accompany.core.enumeration.PartitionEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.*;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;
@Slf4j
@Service
public class WeekGuildPartitionStatService {
@Autowired
private WeekActiveGuildMemberStatService weekActiveGuildMemberStatService;
@Autowired
private WeekGuildPartitionStatMapper mapper;
@Autowired
private GuildService guildService;
@Autowired
private GuildMemberService guildMemberService;
@Resource(name = "bizExecutor")
private ThreadPoolExecutor bizExecutor;
public void stat(List<PartitionEnum> partitionEnumList) {
for (PartitionEnum partitionEnum: partitionEnumList){
bizExecutor.execute(() -> {
ZonedDateTime monday = DateTimeUtil.getDateTimeByZoneId(partitionEnum.getZoneId()).with(DayOfWeek.MONDAY);
String lastWeekMonday = monday.minusWeeks(1L).format(DateTimeUtil.dateFormatter);
String lastWeekSunday = monday.minusDays(1L).format(DateTimeUtil.dateFormatter);
stat(partitionEnum.getId(), partitionEnum.getZoneId(), lastWeekMonday, lastWeekSunday, true);
});
}
}
public void stat(Integer partitionId, String zoneId, String monday, String sunday, boolean needSaveRecord) {
ZonedDateTime zonedStartTime = ZonedDateTime.of(LocalDate.parse(monday, DateTimeUtil.dateFormatter), LocalTime.MIN, ZoneId.of(zoneId));
Date systemStartTime = Date.from(zonedStartTime.withZoneSameLocal(ZoneId.systemDefault()).toInstant());
ZonedDateTime zonedEndTime = ZonedDateTime.of(LocalDate.parse(sunday, DateTimeUtil.dateFormatter), LocalTime.MAX, ZoneId.of(zoneId));
Date systemEndTime = Date.from(zonedEndTime.withZoneSameLocal(ZoneId.systemDefault()).toInstant());
String lastMonday = DateTimeUtil.convertDate(
DateTimeUtil.addDays(DateTimeUtil.convertStrToDate(monday, DateTimeUtil.DEFAULT_DATE_PATTERN), -7), DateTimeUtil.DEFAULT_DATE_PATTERN);
Map<String, Number> diamondCountMap = weekActiveGuildMemberStatService.getZoneDiamondCountMap(partitionId, monday).readAllMap();
Map<String, Number> goldCountMap = weekActiveGuildMemberStatService.getZoneGoldCountMap(partitionId, monday).readAllMap();
Set<String> groupByKeySet = new HashSet<>();
groupByKeySet.addAll(diamondCountMap.keySet());
groupByKeySet.addAll(goldCountMap.keySet());
List<WeekGuildMemberPartitionStat> memberStatDtoList = groupByKeySet.stream().map(key->{
String[] keyArray = key.split("_");
WeekGuildMemberPartitionStat dto = new WeekGuildMemberPartitionStat();
dto.setDate(monday);
dto.setEndDate(sunday);
dto.setPartitionId(partitionId);
dto.setGuildId(Integer.valueOf(keyArray[0]));
dto.setUid(Long.valueOf(keyArray[1]));
dto.setGuildDiamondFlow(diamondCountMap.containsKey(key)? new BigDecimal(diamondCountMap.get(key).toString()): BigDecimal.ZERO);
dto.setGuildGoldFlow(goldCountMap.containsKey(key)? new BigDecimal(goldCountMap.get(key).toString()): BigDecimal.ZERO);
return dto;
}).toList();
List<Guild> validGuildList = guildService.listGuildByPartitionId(partitionId).stream().filter(guild -> Boolean.TRUE.equals(guild.getEnable())).toList();
if (CollectionUtils.isEmpty(validGuildList)){
log.error("[WeekGuildPartitionStat] partitionId {} 分区下没有有效的公会", partitionId);
return;
}
List<GuildMember> guildMemberList = guildMemberService.listByPartitionId(partitionId);
Map<Integer, BigDecimal> guildDiamondFlowMap = memberStatDtoList.stream().collect(Collectors.groupingBy(WeekGuildMemberPartitionStat::getGuildId, Collectors.reducing(BigDecimal.ZERO, WeekGuildMemberPartitionStat::getGuildDiamondFlow, BigDecimal::add)));
Map<Integer, BigDecimal> guildGoldFlowMap = memberStatDtoList.stream().collect(Collectors.groupingBy(WeekGuildMemberPartitionStat::getGuildId, Collectors.reducing(BigDecimal.ZERO, WeekGuildMemberPartitionStat::getGuildGoldFlow, BigDecimal::add)));
WeekGuildPartitionStat lastWeekStat = mapper.selectOne(new LambdaQueryWrapper<WeekGuildPartitionStat>()
.eq(WeekGuildPartitionStat::getDate, lastMonday).eq(WeekGuildPartitionStat::getPartitionId, partitionId));
WeekGuildPartitionStat stat = new WeekGuildPartitionStat();
stat.setDate(monday);
stat.setEndDate(sunday);
stat.setPartitionId(partitionId);
stat.setNewGuildCount((int) validGuildList.stream().filter(g->DateTimeUtil.isBetweenDate(g.getCreateTime(), systemStartTime, systemEndTime)).count());
stat.setNewActiveGuildCount((int) validGuildList.stream().filter(g->DateTimeUtil.isBetweenDate(g.getCreateTime(), systemStartTime, systemEndTime))
.filter(g->guildGoldFlowMap.getOrDefault(g.getId(), BigDecimal.ZERO).compareTo(BigDecimal.ZERO) > 0).count());
stat.setNewGuildTotalDiamondFlow(validGuildList.stream().filter(g->DateTimeUtil.isBetweenDate(g.getCreateTime(), systemStartTime, systemEndTime))
.map(g->guildDiamondFlowMap.getOrDefault(g.getId(), BigDecimal.ZERO)).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
stat.setNewGuildTotalGoldFlow(validGuildList.stream().filter(g->DateTimeUtil.isBetweenDate(g.getCreateTime(), systemStartTime, systemEndTime))
.map(g->guildGoldFlowMap.getOrDefault(g.getId(), BigDecimal.ZERO)).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
stat.setGuildCount(validGuildList.size());
stat.setActiveGuildCount((int) validGuildList.stream().filter(g->guildDiamondFlowMap.getOrDefault(g.getId(), BigDecimal.ZERO).compareTo(BigDecimal.ZERO) > 0).count());
BigDecimal guildTotalDiamondFlow = guildDiamondFlowMap.values().stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
stat.setGuildTotalDiamondFlow(guildTotalDiamondFlow);
BigDecimal guildTotalGoldFlow = guildGoldFlowMap.values().stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
stat.setGuildTotalGoldFlow(guildTotalGoldFlow);
stat.setNewGuildMemberCount((int) guildMemberList.stream().filter(gm->DateTimeUtil.isBetweenDate(gm.getCreateTime(), systemStartTime, systemEndTime)).count());
stat.setNewGuildMemberActiveCount((int) guildMemberList.stream().filter(gm->DateTimeUtil.isBetweenDate(gm.getCreateTime(), systemStartTime, systemEndTime))
.filter(gm->{
String groupByKey = String.join("_", gm.getGuildId().toString(), gm.getUid().toString());
BigDecimal diamondFlow = new BigDecimal(diamondCountMap.getOrDefault(groupByKey, BigDecimal.ZERO).toString());
return diamondFlow.compareTo(BigDecimal.ZERO) > 0;
}).count());
stat.setGuildMemberCount((int) guildMemberList.stream().filter(gm->Boolean.TRUE.equals(gm.getEnable())
||DateTimeUtil.isBetweenDate(gm.getUpdateTime(), systemStartTime, systemEndTime)).count());
stat.setActiveGuildMemberCount((int) guildMemberList.stream().filter(gm->Boolean.TRUE.equals(gm.getEnable())
||DateTimeUtil.isBetweenDate(gm.getUpdateTime(), systemStartTime, systemEndTime))
.filter(gm->{
String groupByKey = String.join("_", gm.getGuildId().toString(), gm.getUid().toString());
BigDecimal diamondFlow = new BigDecimal(diamondCountMap.getOrDefault(groupByKey, BigDecimal.ZERO).toString());
return diamondFlow.compareTo(BigDecimal.ZERO) > 0;
}).count());
if (null == lastWeekStat){
stat.setLastWeekNewGuildCount(0);
stat.setLastWeekNewGuildCountWow(BigDecimal.ONE);
stat.setLastWeekNewActiveGuildCount(0);
stat.setLastWeekNewActiveGuildCountWow(BigDecimal.ONE);
stat.setLastWeekNewGuildTotalDiamondFlow(BigDecimal.ZERO);
stat.setLastWeekNewGuildTotalDiamondFlowWow(BigDecimal.ONE);
stat.setLastWeekNewGuildTotalGoldFlow(BigDecimal.ZERO);
stat.setLastWeekNewGuildTotalGoldFlowWow(BigDecimal.ONE);
stat.setLastWeekGuildCount(0);
stat.setLastWeekGuildCountWow(BigDecimal.ONE);
stat.setLastWeekActiveGuildCount(0);
stat.setLastWeekActiveGuildCountWow(BigDecimal.ONE);
stat.setLastWeekGuildTotalDiamondFlow(BigDecimal.ZERO);
stat.setLastWeekGuildTotalDiamondFlowWow(BigDecimal.ONE);
stat.setLastWeekGuildTotalGoldFlow(BigDecimal.ZERO);
stat.setLastWeekGuildTotalGoldFlowWow(BigDecimal.ONE);
stat.setLastWeekNewGuildMemberCount(0);
stat.setLastWeekNewGuildMemberCountWow(BigDecimal.ONE);
stat.setLastWeekNewGuildMemberActiveCount(0);
stat.setLastWeekNewGuildMemberActiveCountWow(BigDecimal.ONE);
if (!needSaveRecord){
mapper.insert(stat);
}
return;
}
stat.setLastWeekNewGuildCount(lastWeekStat.getNewGuildCount());
BigDecimal lastWeekNewGuildCountWow = lastWeekStat.getNewGuildCount() > 0 ?
BigDecimal.valueOf(stat.getNewGuildCount() - lastWeekStat.getNewGuildCount()).divide(BigDecimal.valueOf(lastWeekStat.getNewGuildCount()), 2, RoundingMode.HALF_UP): BigDecimal.ONE;
stat.setLastWeekNewGuildCountWow(lastWeekNewGuildCountWow);
stat.setLastWeekNewActiveGuildCount(lastWeekStat.getNewActiveGuildCount());
BigDecimal lastWeekNewActiveGuildCountWow = lastWeekStat.getNewActiveGuildCount() > 0 ?
BigDecimal.valueOf(stat.getNewActiveGuildCount() - lastWeekStat.getNewActiveGuildCount()).divide(BigDecimal.valueOf(lastWeekStat.getNewActiveGuildCount()), 2, RoundingMode.HALF_UP): BigDecimal.ONE;
stat.setLastWeekNewActiveGuildCountWow(lastWeekNewActiveGuildCountWow);
stat.setLastWeekNewGuildTotalDiamondFlow(lastWeekStat.getNewGuildTotalDiamondFlow());
BigDecimal lastWeekNewGuildTotalDiamondFlowWow = lastWeekStat.getNewGuildTotalDiamondFlow().compareTo(BigDecimal.ZERO) > 0 ?
(stat.getNewGuildTotalDiamondFlow().subtract(lastWeekStat.getNewGuildTotalDiamondFlow())).divide(lastWeekStat.getNewGuildTotalDiamondFlow(), 2, RoundingMode.HALF_UP): BigDecimal.ONE;
stat.setLastWeekNewGuildTotalDiamondFlowWow(lastWeekNewGuildTotalDiamondFlowWow);
stat.setLastWeekNewGuildTotalGoldFlow(lastWeekStat.getNewGuildTotalGoldFlow());
BigDecimal lastWeekNewGuildTotalGoldFlowWow = lastWeekStat.getNewGuildTotalGoldFlow().compareTo(BigDecimal.ZERO) > 0 ?
(stat.getNewGuildTotalGoldFlow().subtract(lastWeekStat.getNewGuildTotalGoldFlow())).divide(lastWeekStat.getNewGuildTotalGoldFlow(), 2, RoundingMode.HALF_UP): BigDecimal.ONE;
stat.setLastWeekNewGuildTotalGoldFlowWow(lastWeekNewGuildTotalGoldFlowWow);
stat.setLastWeekGuildCount(lastWeekStat.getGuildCount());
BigDecimal lastWeekGuildCountWow = lastWeekStat.getGuildCount() > 0 ?
BigDecimal.valueOf(stat.getGuildCount() - lastWeekStat.getGuildCount()).divide(BigDecimal.valueOf(lastWeekStat.getGuildCount()), 2, RoundingMode.HALF_UP): BigDecimal.ONE;
stat.setLastWeekGuildCountWow(lastWeekGuildCountWow);
stat.setLastWeekActiveGuildCount(lastWeekStat.getActiveGuildCount());
BigDecimal lastWeekActiveGuildCountWow = lastWeekStat.getActiveGuildCount() > 0 ?
BigDecimal.valueOf(stat.getActiveGuildCount() - lastWeekStat.getActiveGuildCount()).divide(BigDecimal.valueOf(lastWeekStat.getActiveGuildCount()), 2, RoundingMode.HALF_UP): BigDecimal.ONE;
stat.setLastWeekActiveGuildCountWow(lastWeekActiveGuildCountWow);
stat.setLastWeekGuildTotalDiamondFlow(lastWeekStat.getGuildTotalDiamondFlow());
BigDecimal lastWeekGuildTotalDiamondFlowWow = lastWeekStat.getGuildTotalDiamondFlow().compareTo(BigDecimal.ZERO) > 0 ?
(stat.getGuildTotalDiamondFlow().subtract(lastWeekStat.getGuildTotalDiamondFlow())).divide(lastWeekStat.getGuildTotalGoldFlow(), 2, RoundingMode.HALF_UP): BigDecimal.ONE;
stat.setLastWeekGuildTotalDiamondFlowWow(lastWeekGuildTotalDiamondFlowWow);
stat.setLastWeekGuildTotalGoldFlow(lastWeekStat.getGuildTotalGoldFlow());
BigDecimal lastWeekGuildTotalGoldFlowWow = lastWeekStat.getGuildTotalGoldFlow().compareTo(BigDecimal.ZERO) > 0 ?
(stat.getGuildTotalGoldFlow().subtract(lastWeekStat.getGuildTotalGoldFlow())).divide(lastWeekStat.getGuildTotalGoldFlow(), 2, RoundingMode.HALF_UP): BigDecimal.ONE;
stat.setLastWeekGuildTotalGoldFlowWow(lastWeekGuildTotalGoldFlowWow);
stat.setLastWeekNewGuildMemberCount(lastWeekStat.getNewGuildMemberCount());
BigDecimal lastWeekNewGuildMemberCountWow = lastWeekStat.getNewGuildMemberCount() > 0 ?
BigDecimal.valueOf(stat.getNewGuildMemberCount()-lastWeekStat.getNewGuildMemberCount()).divide(BigDecimal.valueOf(lastWeekStat.getNewGuildMemberCount()), 2, RoundingMode.HALF_UP): BigDecimal.ONE;
stat.setLastWeekNewGuildMemberCountWow(lastWeekNewGuildMemberCountWow);
stat.setLastWeekNewGuildMemberActiveCount(lastWeekStat.getNewGuildMemberActiveCount());
BigDecimal lastWeekNewGuildMemberActiveCountWow = lastWeekStat.getNewGuildMemberActiveCount() > 0 ?
BigDecimal.valueOf(stat.getNewGuildMemberActiveCount()-lastWeekStat.getNewGuildMemberActiveCount()).divide(BigDecimal.valueOf(lastWeekStat.getNewGuildMemberActiveCount()), 2, RoundingMode.HALF_UP): BigDecimal.ONE;
stat.setLastWeekNewGuildMemberActiveCountWow(lastWeekNewGuildMemberActiveCountWow);
if (!needSaveRecord){
return;
}
mapper.insert(stat);
}
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.accompany.business.mybatismapper.WeekGuildPartitionStatMapper">
</mapper>

View File

@@ -17,13 +17,13 @@ public class GuildOperatorWeekStatTask extends BaseTask {
@Autowired
private WeekGuildOperatorStatService weekGuildOperatorStatService;
@Scheduled(cron = "1 0 0 ? * MON")
@Scheduled(cron = "5 0 0 ? * MON")
public void statWeekEn() {
List<PartitionEnum> partitionEnumList = List.of(PartitionEnum.ENGLISH2);
weekGuildOperatorStatService.stat(partitionEnumList);
}
@Scheduled(cron = "1 0 0 ? * MON", zone = "Asia/Riyadh")
@Scheduled(cron = "5 0 0 ? * MON", zone = "Asia/Riyadh")
public void statWeekAr() {
List<PartitionEnum> partitionEnumList = List.of(PartitionEnum.ARAB, PartitionEnum.TURKEY);
weekGuildOperatorStatService.stat(partitionEnumList);

View File

@@ -0,0 +1,32 @@
package com.accompany.scheduler.task;
import com.accompany.business.service.WeekGuildPartitionStatService;
import com.accompany.core.enumeration.PartitionEnum;
import com.accompany.scheduler.base.BaseTask;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
public class GuildPartitionWeekStatTask extends BaseTask {
@Autowired
private WeekGuildPartitionStatService service;
@Scheduled(cron = "5 0 0 ? * MON")
public void statWeekEn() {
List<PartitionEnum> partitionEnumList = List.of(PartitionEnum.ENGLISH2);
service.stat(partitionEnumList);
}
@Scheduled(cron = "5 0 0 ? * MON", zone = "Asia/Riyadh")
public void statWeekAr() {
List<PartitionEnum> partitionEnumList = List.of(PartitionEnum.ARAB, PartitionEnum.TURKEY);
service.stat(partitionEnumList);
}
}