1
This commit is contained in:
parent
28ae34e2fa
commit
b69c58bddf
@ -1,7 +1,10 @@
|
||||
package com.red.circle.console.adapter.app.user;
|
||||
|
||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||
import com.red.circle.console.app.service.app.user.DatavService;
|
||||
import com.red.circle.console.app.dto.clientobject.datav.CountryDashboardCO;
|
||||
import com.red.circle.console.app.dto.cmd.datav.CountryDashboardQryCmd;
|
||||
import com.red.circle.console.app.service.app.datav.CountryDashboardService;
|
||||
import com.red.circle.console.app.service.app.user.DatavService;
|
||||
import com.red.circle.framework.web.controller.BaseController;
|
||||
import com.red.circle.other.inner.model.cmd.user.OnlineCountQryCmd;
|
||||
import com.red.circle.other.inner.model.dto.user.ActiveUserCountryCodeDTO;
|
||||
@ -24,7 +27,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequestMapping(value = "/datav", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public class DatavRestController extends BaseController {
|
||||
|
||||
private final DatavService userExpandService;
|
||||
private final DatavService userExpandService;
|
||||
private final CountryDashboardService countryDashboardService;
|
||||
|
||||
@GetMapping("/active/user-country-code")
|
||||
public List<ActiveUserCountryCodeDTO> latestActiveUserCountryCode() {
|
||||
@ -37,8 +41,13 @@ public class DatavRestController extends BaseController {
|
||||
}
|
||||
|
||||
@GetMapping("/online/room/count")
|
||||
public String onlineRoomCount(@RequestParam("sysOrigin") String sysOrigin) {
|
||||
return Objects.toString(userExpandService.count(sysOrigin));
|
||||
}
|
||||
|
||||
}
|
||||
public String onlineRoomCount(@RequestParam("sysOrigin") String sysOrigin) {
|
||||
return Objects.toString(userExpandService.count(sysOrigin));
|
||||
}
|
||||
|
||||
@GetMapping("/country-dashboard")
|
||||
public CountryDashboardCO countryDashboard(CountryDashboardQryCmd cmd) {
|
||||
return countryDashboardService.query(cmd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,454 @@
|
||||
package com.red.circle.console.app.service.app.datav;
|
||||
|
||||
import com.red.circle.console.app.dto.clientobject.datav.CountryDashboardCO;
|
||||
import com.red.circle.console.app.dto.clientobject.datav.CountryDashboardMetricCO;
|
||||
import com.red.circle.console.app.dto.cmd.datav.CountryDashboardQryCmd;
|
||||
import com.red.circle.console.infra.database.rds.dao.datav.CountryDashboardDAO;
|
||||
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardMetricDTO;
|
||||
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardUserCountryDTO;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.YearMonth;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.WeekFields;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiConsumer;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.Decimal128;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 国家数据大屏.
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CountryDashboardServiceImpl implements CountryDashboardService {
|
||||
|
||||
private static final String COLLECTION_GIFT_GIVE_RUNNING_WATER = "gift_give_running_water";
|
||||
private static final String PERIOD_ALL = "ALL";
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
private static final DateTimeFormatter MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");
|
||||
private static final int USER_COUNTRY_BATCH_SIZE = 1000;
|
||||
|
||||
private final CountryDashboardDAO countryDashboardDAO;
|
||||
private final MongoTemplate mongoTemplate;
|
||||
|
||||
@Override
|
||||
public CountryDashboardCO query(CountryDashboardQryCmd cmd) {
|
||||
QueryCondition condition = QueryCondition.of(cmd);
|
||||
Map<String, CountryDashboardMetricCO> rows = new LinkedHashMap<>();
|
||||
|
||||
mergeSql(rows, countryDashboardDAO.listNewUsers(
|
||||
condition.periodType, condition.startTime, condition.endTime,
|
||||
condition.countryKeyword, condition.sysOrigin));
|
||||
mergeSql(rows, countryDashboardDAO.listNewUserRecharge(
|
||||
condition.periodType, condition.startTime, condition.endTime,
|
||||
condition.countryKeyword, condition.sysOrigin));
|
||||
mergeSql(rows, countryDashboardDAO.listOfficialRecharge(
|
||||
condition.periodType, condition.startTime, condition.endTime,
|
||||
condition.countryKeyword, condition.sysOrigin));
|
||||
mergeSql(rows, countryDashboardDAO.listDealerRecharge(
|
||||
condition.periodType, condition.startTime, condition.endTime,
|
||||
condition.countryKeyword, condition.sysOrigin));
|
||||
mergeSql(rows, countryDashboardDAO.listSalaryExchange(
|
||||
condition.periodType, condition.startTime, condition.endTime,
|
||||
condition.countryKeyword, condition.sysOrigin));
|
||||
mergeSql(rows, countryDashboardDAO.listLuckyGift(
|
||||
condition.periodType, condition.startTime, condition.endTime,
|
||||
condition.countryKeyword, condition.sysOrigin));
|
||||
mergeSql(rows, countryDashboardDAO.listWalletGame(
|
||||
condition.periodType, condition.startTime, condition.endTime,
|
||||
condition.countryKeyword, condition.sysOrigin));
|
||||
mergeSql(rows, countryDashboardDAO.listLuckyBoxGame(
|
||||
condition.periodType, condition.startTime, condition.endTime,
|
||||
condition.countryKeyword, condition.sysOrigin));
|
||||
|
||||
mergeMongo(rows, condition, listGiftConsume(condition),
|
||||
(row, amount) -> row.setGiftConsume(add(row.getGiftConsume(), amount)));
|
||||
mergeMongo(rows, condition, listLuckyGiftAnchorShare(condition),
|
||||
(row, amount) -> row.setLuckyGiftAnchorShare(add(row.getLuckyGiftAnchorShare(), amount)));
|
||||
|
||||
List<CountryDashboardMetricCO> records = rows.values().stream()
|
||||
.peek(this::calculateFormulaFields)
|
||||
.sorted(Comparator.comparing(CountryDashboardMetricCO::getPeriodKey,
|
||||
Comparator.nullsLast(Comparator.reverseOrder()))
|
||||
.thenComparing(CountryDashboardMetricCO::getCountryCode,
|
||||
Comparator.nullsLast(String::compareTo)))
|
||||
.toList();
|
||||
|
||||
CountryDashboardMetricCO total = buildTotal(records, condition.periodType);
|
||||
|
||||
return new CountryDashboardCO()
|
||||
.setPeriodType(condition.periodType)
|
||||
.setStartDate(condition.startDate)
|
||||
.setEndDate(condition.endDate)
|
||||
.setComputedAt(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
|
||||
.setTotal(total)
|
||||
.setRecords(records);
|
||||
}
|
||||
|
||||
private void mergeSql(Map<String, CountryDashboardMetricCO> rows,
|
||||
List<CountryDashboardMetricDTO> metrics) {
|
||||
if (metrics == null || metrics.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (CountryDashboardMetricDTO metric : metrics) {
|
||||
CountryDashboardMetricCO row = getRow(rows, metric.getCountryCode(), metric.getCountryName(),
|
||||
metric.getPeriodKey(), metric.getPeriodName());
|
||||
row.setCountryNewUser(row.getCountryNewUser() + safeLong(metric.getCountryNewUser()));
|
||||
row.setNewUserRecharge(add(row.getNewUserRecharge(), metric.getNewUserRecharge()));
|
||||
row.setOfficialRecharge(add(row.getOfficialRecharge(), metric.getOfficialRecharge()));
|
||||
row.setDealerRecharge(add(row.getDealerRecharge(), metric.getDealerRecharge()));
|
||||
row.setSalaryExchange(add(row.getSalaryExchange(), metric.getSalaryExchange()));
|
||||
row.setLuckyGiftTotalFlow(add(row.getLuckyGiftTotalFlow(), metric.getLuckyGiftTotalFlow()));
|
||||
row.setLuckyGiftPayout(add(row.getLuckyGiftPayout(), metric.getLuckyGiftPayout()));
|
||||
row.setGameTotalFlow(add(row.getGameTotalFlow(), metric.getGameTotalFlow()));
|
||||
row.setGamePayout(add(row.getGamePayout(), metric.getGamePayout()));
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeMongo(Map<String, CountryDashboardMetricCO> rows, QueryCondition condition,
|
||||
List<MongoMetric> metrics, BiConsumer<CountryDashboardMetricCO, BigDecimal> merger) {
|
||||
if (metrics == null || metrics.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Long, CountryDashboardUserCountryDTO> countryMap = mapUserCountries(
|
||||
metrics.stream().map(MongoMetric::userId).filter(Objects::nonNull).distinct().toList());
|
||||
|
||||
for (MongoMetric metric : metrics) {
|
||||
CountryDashboardUserCountryDTO country = countryMap.get(metric.userId());
|
||||
if (country == null || !matchesCountry(country, condition.countryKeyword)) {
|
||||
continue;
|
||||
}
|
||||
PeriodBucket bucket = condition.toPeriodBucket(metric.day());
|
||||
CountryDashboardMetricCO row = getRow(rows, country.getCountryCode(), country.getCountryName(),
|
||||
bucket.key(), bucket.name());
|
||||
merger.accept(row, metric.amount());
|
||||
}
|
||||
}
|
||||
|
||||
private List<MongoMetric> listGiftConsume(QueryCondition condition) {
|
||||
List<Criteria> criteria = baseGiftCriteria(condition);
|
||||
criteria.add(Criteria.where("luckyGift").ne(Boolean.TRUE));
|
||||
criteria.add(Criteria.where("originId").regex("^\\d+$"));
|
||||
criteria.add(new Criteria().orOperator(
|
||||
Criteria.where("dynamicContentId").exists(false),
|
||||
Criteria.where("dynamicContentId").is(null),
|
||||
Criteria.where("dynamicContentId").is("")
|
||||
));
|
||||
return aggregateGiftAmount(criteria, "$giftValue.actualAmount", false);
|
||||
}
|
||||
|
||||
private List<MongoMetric> listLuckyGiftAnchorShare(QueryCondition condition) {
|
||||
List<Criteria> criteria = baseGiftCriteria(condition);
|
||||
criteria.add(Criteria.where("luckyGift").is(Boolean.TRUE));
|
||||
return aggregateGiftAmount(criteria, "$acceptUsers.targetAmount", true);
|
||||
}
|
||||
|
||||
private List<Criteria> baseGiftCriteria(QueryCondition condition) {
|
||||
List<Criteria> criteria = new ArrayList<>();
|
||||
criteria.add(Criteria.where("refunded").ne(Boolean.TRUE));
|
||||
criteria.add(Criteria.where("userId").ne(null));
|
||||
if (condition.startTime != null) {
|
||||
criteria.add(Criteria.where("createTime").gte(Timestamp.valueOf(condition.startTime)));
|
||||
}
|
||||
if (condition.endTime != null) {
|
||||
criteria.add(Criteria.where("createTime").lt(Timestamp.valueOf(condition.endTime)));
|
||||
}
|
||||
if (hasText(condition.sysOrigin)) {
|
||||
criteria.add(Criteria.where("sysOrigin").is(condition.sysOrigin));
|
||||
}
|
||||
return criteria;
|
||||
}
|
||||
|
||||
private List<MongoMetric> aggregateGiftAmount(List<Criteria> criteria, String amountPath,
|
||||
boolean unwindAcceptUsers) {
|
||||
List<AggregationOperation> operations = new ArrayList<>();
|
||||
operations.add(Aggregation.match(new Criteria().andOperator(criteria.toArray(new Criteria[0]))));
|
||||
if (unwindAcceptUsers) {
|
||||
operations.add(Aggregation.unwind("acceptUsers"));
|
||||
}
|
||||
operations.add(projectGiftDayAmount(amountPath));
|
||||
operations.add(Aggregation.group("userId", "day").sum("amount").as("amount"));
|
||||
|
||||
return mongoTemplate.aggregate(Aggregation.newAggregation(operations),
|
||||
COLLECTION_GIFT_GIVE_RUNNING_WATER, Document.class)
|
||||
.getMappedResults()
|
||||
.stream()
|
||||
.map(this::toMongoMetric)
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private AggregationOperation projectGiftDayAmount(String amountPath) {
|
||||
return context -> new Document("$project",
|
||||
new Document("userId", "$userId")
|
||||
.append("amount", amountPath)
|
||||
.append("day", new Document("$dateToString",
|
||||
new Document("format", "%Y-%m-%d").append("date", "$createTime"))));
|
||||
}
|
||||
|
||||
private MongoMetric toMongoMetric(Document document) {
|
||||
Object id = document.get("_id");
|
||||
if (!(id instanceof Document idDoc)) {
|
||||
return null;
|
||||
}
|
||||
Long userId = toLong(idDoc.get("userId"));
|
||||
String day = Objects.toString(idDoc.get("day"), null);
|
||||
BigDecimal amount = toBigDecimal(document.get("amount"));
|
||||
if (userId == null || !hasText(day) || amount == null) {
|
||||
return null;
|
||||
}
|
||||
return new MongoMetric(userId, day, amount);
|
||||
}
|
||||
|
||||
private Map<Long, CountryDashboardUserCountryDTO> mapUserCountries(Collection<Long> userIds) {
|
||||
Map<Long, CountryDashboardUserCountryDTO> result = new HashMap<>();
|
||||
if (userIds == null || userIds.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
List<Long> ids = new ArrayList<>(userIds);
|
||||
for (int start = 0; start < ids.size(); start += USER_COUNTRY_BATCH_SIZE) {
|
||||
int end = Math.min(start + USER_COUNTRY_BATCH_SIZE, ids.size());
|
||||
List<CountryDashboardUserCountryDTO> batch = countryDashboardDAO.listUserCountryByIds(
|
||||
ids.subList(start, end));
|
||||
if (batch == null) {
|
||||
continue;
|
||||
}
|
||||
for (CountryDashboardUserCountryDTO item : batch) {
|
||||
result.put(item.getUserId(), item);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean matchesCountry(CountryDashboardUserCountryDTO country, String keyword) {
|
||||
if (!hasText(keyword)) {
|
||||
return true;
|
||||
}
|
||||
String countryCode = Objects.toString(country.getCountryCode(), "");
|
||||
String countryName = Objects.toString(country.getCountryName(), "");
|
||||
return countryCode.equals(keyword) || countryName.contains(keyword);
|
||||
}
|
||||
|
||||
private CountryDashboardMetricCO getRow(Map<String, CountryDashboardMetricCO> rows,
|
||||
String countryCode, String countryName, String periodKey, String periodName) {
|
||||
String fixedCountryCode = hasText(countryCode) ? countryCode : "UNKNOWN";
|
||||
String fixedCountryName = hasText(countryName) ? countryName : fixedCountryCode;
|
||||
String fixedPeriodKey = hasText(periodKey) ? periodKey : PERIOD_ALL;
|
||||
String fixedPeriodName = hasText(periodName) ? periodName : "全部";
|
||||
return rows.computeIfAbsent(fixedCountryCode + "|" + fixedPeriodKey,
|
||||
key -> new CountryDashboardMetricCO()
|
||||
.setCountryCode(fixedCountryCode)
|
||||
.setCountryName(fixedCountryName)
|
||||
.setPeriodKey(fixedPeriodKey)
|
||||
.setPeriodName(fixedPeriodName));
|
||||
}
|
||||
|
||||
private void calculateFormulaFields(CountryDashboardMetricCO row) {
|
||||
row.setTotalRecharge(add(row.getOfficialRecharge(), row.getDealerRecharge()));
|
||||
row.setLuckyGiftProfit(safe(row.getLuckyGiftTotalFlow())
|
||||
.subtract(safe(row.getLuckyGiftPayout()))
|
||||
.subtract(safe(row.getLuckyGiftAnchorShare())));
|
||||
row.setGameProfit(safe(row.getGameTotalFlow()).subtract(safe(row.getGamePayout())));
|
||||
}
|
||||
|
||||
private CountryDashboardMetricCO buildTotal(List<CountryDashboardMetricCO> records,
|
||||
String periodType) {
|
||||
CountryDashboardMetricCO total = new CountryDashboardMetricCO()
|
||||
.setCountryCode("ALL")
|
||||
.setCountryName("全部国家")
|
||||
.setPeriodKey(PERIOD_ALL.equals(periodType) ? PERIOD_ALL : "TOTAL")
|
||||
.setPeriodName("合计");
|
||||
for (CountryDashboardMetricCO row : records) {
|
||||
total.setCountryNewUser(total.getCountryNewUser() + safeLong(row.getCountryNewUser()));
|
||||
total.setNewUserRecharge(add(total.getNewUserRecharge(), row.getNewUserRecharge()));
|
||||
total.setOfficialRecharge(add(total.getOfficialRecharge(), row.getOfficialRecharge()));
|
||||
total.setDealerRecharge(add(total.getDealerRecharge(), row.getDealerRecharge()));
|
||||
total.setSalaryExchange(add(total.getSalaryExchange(), row.getSalaryExchange()));
|
||||
total.setGiftConsume(add(total.getGiftConsume(), row.getGiftConsume()));
|
||||
total.setLuckyGiftTotalFlow(add(total.getLuckyGiftTotalFlow(), row.getLuckyGiftTotalFlow()));
|
||||
total.setLuckyGiftPayout(add(total.getLuckyGiftPayout(), row.getLuckyGiftPayout()));
|
||||
total.setLuckyGiftAnchorShare(add(total.getLuckyGiftAnchorShare(), row.getLuckyGiftAnchorShare()));
|
||||
total.setGameTotalFlow(add(total.getGameTotalFlow(), row.getGameTotalFlow()));
|
||||
total.setGamePayout(add(total.getGamePayout(), row.getGamePayout()));
|
||||
}
|
||||
calculateFormulaFields(total);
|
||||
return total;
|
||||
}
|
||||
|
||||
private static BigDecimal add(BigDecimal left, BigDecimal right) {
|
||||
return safe(left).add(safe(right));
|
||||
}
|
||||
|
||||
private static BigDecimal safe(BigDecimal value) {
|
||||
return value == null ? BigDecimal.ZERO : value;
|
||||
}
|
||||
|
||||
private static long safeLong(Long value) {
|
||||
return value == null ? 0L : value;
|
||||
}
|
||||
|
||||
private static BigDecimal toBigDecimal(Object value) {
|
||||
if (value == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
if (value instanceof BigDecimal bigDecimal) {
|
||||
return bigDecimal;
|
||||
}
|
||||
if (value instanceof Decimal128 decimal128) {
|
||||
return decimal128.bigDecimalValue();
|
||||
}
|
||||
if (value instanceof Number number) {
|
||||
return new BigDecimal(number.toString());
|
||||
}
|
||||
return new BigDecimal(Objects.toString(value, "0"));
|
||||
}
|
||||
|
||||
private static Long toLong(Object value) {
|
||||
if (value instanceof Number number) {
|
||||
return number.longValue();
|
||||
}
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return Long.valueOf(Objects.toString(value));
|
||||
}
|
||||
|
||||
private static boolean hasText(String value) {
|
||||
return value != null && !value.trim().isEmpty();
|
||||
}
|
||||
|
||||
private record MongoMetric(Long userId, String day, BigDecimal amount) {
|
||||
}
|
||||
|
||||
private record PeriodBucket(String key, String name) {
|
||||
}
|
||||
|
||||
private static final class QueryCondition {
|
||||
|
||||
private final String periodType;
|
||||
private final String startDate;
|
||||
private final String endDate;
|
||||
private final LocalDateTime startTime;
|
||||
private final LocalDateTime endTime;
|
||||
private final String countryKeyword;
|
||||
private final String sysOrigin;
|
||||
|
||||
private QueryCondition(String periodType, String startDate, String endDate,
|
||||
LocalDateTime startTime, LocalDateTime endTime, String countryKeyword,
|
||||
String sysOrigin) {
|
||||
this.periodType = periodType;
|
||||
this.startDate = startDate;
|
||||
this.endDate = endDate;
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
this.countryKeyword = countryKeyword;
|
||||
this.sysOrigin = sysOrigin;
|
||||
}
|
||||
|
||||
private static QueryCondition of(CountryDashboardQryCmd cmd) {
|
||||
String periodType = normalizePeriodType(cmd == null ? null : cmd.getPeriodType());
|
||||
LocalDate start = parseDate(cmd == null ? null : cmd.getStartDate());
|
||||
LocalDate end = parseDate(cmd == null ? null : cmd.getEndDate());
|
||||
|
||||
if (!PERIOD_ALL.equals(periodType) && start == null && end == null) {
|
||||
LocalDate today = LocalDate.now();
|
||||
switch (periodType) {
|
||||
case "WEEK" -> {
|
||||
start = today.with(DayOfWeek.MONDAY);
|
||||
end = today.with(DayOfWeek.SUNDAY);
|
||||
}
|
||||
case "MONTH" -> {
|
||||
start = today.withDayOfMonth(1);
|
||||
end = today.withDayOfMonth(today.lengthOfMonth());
|
||||
}
|
||||
default -> {
|
||||
start = today;
|
||||
end = today;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (start != null && end == null) {
|
||||
end = start;
|
||||
}
|
||||
if (start == null && end != null) {
|
||||
start = end;
|
||||
}
|
||||
if (start != null && end != null && end.isBefore(start)) {
|
||||
throw new IllegalArgumentException("endDate must not be before startDate.");
|
||||
}
|
||||
|
||||
return new QueryCondition(
|
||||
periodType,
|
||||
start == null ? null : DATE_FORMATTER.format(start),
|
||||
end == null ? null : DATE_FORMATTER.format(end),
|
||||
start == null ? null : start.atStartOfDay(),
|
||||
end == null ? null : end.plusDays(1).atStartOfDay(),
|
||||
trimToNull(cmd == null ? null : cmd.getCountryKeyword()),
|
||||
trimToNull(cmd == null ? null : cmd.getSysOrigin())
|
||||
);
|
||||
}
|
||||
|
||||
private PeriodBucket toPeriodBucket(String day) {
|
||||
if (PERIOD_ALL.equals(periodType)) {
|
||||
return new PeriodBucket(PERIOD_ALL, "全部");
|
||||
}
|
||||
LocalDate date = LocalDate.parse(day, DATE_FORMATTER);
|
||||
if ("MONTH".equals(periodType)) {
|
||||
return new PeriodBucket(date.format(MONTH_FORMATTER), date.format(MONTH_FORMATTER));
|
||||
}
|
||||
if ("WEEK".equals(periodType)) {
|
||||
WeekFields weekFields = WeekFields.ISO;
|
||||
int weekYear = date.get(weekFields.weekBasedYear());
|
||||
int week = date.get(weekFields.weekOfWeekBasedYear());
|
||||
String key = String.format(Locale.ROOT, "%d-W%02d", weekYear, week);
|
||||
return new PeriodBucket(key, key);
|
||||
}
|
||||
return new PeriodBucket(day, day);
|
||||
}
|
||||
|
||||
private static String normalizePeriodType(String periodType) {
|
||||
String value = trimToNull(periodType);
|
||||
if (value == null) {
|
||||
return "DAY";
|
||||
}
|
||||
value = value.toUpperCase(Locale.ROOT);
|
||||
return switch (value) {
|
||||
case "DAY", "WEEK", "MONTH", "ALL" -> value;
|
||||
default -> "DAY";
|
||||
};
|
||||
}
|
||||
|
||||
private static LocalDate parseDate(String value) {
|
||||
String fixed = trimToNull(value);
|
||||
return fixed == null ? null : LocalDate.parse(fixed, DATE_FORMATTER);
|
||||
}
|
||||
|
||||
private static String trimToNull(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
return trimmed.isEmpty() ? null : trimmed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.red.circle.console.app.dto.clientobject.datav;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 国家数据大屏结果.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CountryDashboardCO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String periodType;
|
||||
|
||||
private String startDate;
|
||||
|
||||
private String endDate;
|
||||
|
||||
private String computedAt;
|
||||
|
||||
private CountryDashboardMetricCO total;
|
||||
|
||||
private List<CountryDashboardMetricCO> records;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
package com.red.circle.console.app.dto.clientobject.datav;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 国家数据大屏单行指标.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CountryDashboardMetricCO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String countryCode;
|
||||
|
||||
private String countryName;
|
||||
|
||||
private String periodKey;
|
||||
|
||||
private String periodName;
|
||||
|
||||
private Long countryNewUser = 0L;
|
||||
|
||||
private BigDecimal newUserRecharge = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal dealerRecharge = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal salaryExchange = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal totalRecharge = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal giftConsume = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal luckyGiftTotalFlow = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal luckyGiftPayout = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal luckyGiftAnchorShare = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal luckyGiftProfit = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal gameTotalFlow = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal gamePayout = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal gameProfit = BigDecimal.ZERO;
|
||||
|
||||
/**
|
||||
* 官方直充总额,服务端用于计算总充值.
|
||||
*/
|
||||
private BigDecimal officialRecharge = BigDecimal.ZERO;
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.red.circle.console.app.dto.cmd.datav;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 国家数据大屏查询.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CountryDashboardQryCmd implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* DAY / WEEK / MONTH / ALL.
|
||||
*/
|
||||
private String periodType;
|
||||
|
||||
/**
|
||||
* yyyy-MM-dd.
|
||||
*/
|
||||
private String startDate;
|
||||
|
||||
/**
|
||||
* yyyy-MM-dd.
|
||||
*/
|
||||
private String endDate;
|
||||
|
||||
/**
|
||||
* 国家编码或国家名称关键字.
|
||||
*/
|
||||
private String countryKeyword;
|
||||
|
||||
/**
|
||||
* 系统来源.
|
||||
*/
|
||||
private String sysOrigin;
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.red.circle.console.app.service.app.datav;
|
||||
|
||||
import com.red.circle.console.app.dto.clientobject.datav.CountryDashboardCO;
|
||||
import com.red.circle.console.app.dto.cmd.datav.CountryDashboardQryCmd;
|
||||
|
||||
/**
|
||||
* 国家数据大屏.
|
||||
*/
|
||||
public interface CountryDashboardService {
|
||||
|
||||
CountryDashboardCO query(CountryDashboardQryCmd cmd);
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package com.red.circle.console.infra.database.rds.dao.datav;
|
||||
|
||||
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardMetricDTO;
|
||||
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardUserCountryDTO;
|
||||
import com.red.circle.console.infra.database.rds.entity.app.IUserBaseInfo;
|
||||
import com.red.circle.framework.mybatis.dao.BaseDAO;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 国家数据大屏聚合.
|
||||
*/
|
||||
public interface CountryDashboardDAO extends BaseDAO<IUserBaseInfo> {
|
||||
|
||||
List<CountryDashboardMetricDTO> listNewUsers(
|
||||
@Param("periodType") String periodType,
|
||||
@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime,
|
||||
@Param("countryKeyword") String countryKeyword,
|
||||
@Param("sysOrigin") String sysOrigin);
|
||||
|
||||
List<CountryDashboardMetricDTO> listNewUserRecharge(
|
||||
@Param("periodType") String periodType,
|
||||
@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime,
|
||||
@Param("countryKeyword") String countryKeyword,
|
||||
@Param("sysOrigin") String sysOrigin);
|
||||
|
||||
List<CountryDashboardMetricDTO> listOfficialRecharge(
|
||||
@Param("periodType") String periodType,
|
||||
@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime,
|
||||
@Param("countryKeyword") String countryKeyword,
|
||||
@Param("sysOrigin") String sysOrigin);
|
||||
|
||||
List<CountryDashboardMetricDTO> listDealerRecharge(
|
||||
@Param("periodType") String periodType,
|
||||
@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime,
|
||||
@Param("countryKeyword") String countryKeyword,
|
||||
@Param("sysOrigin") String sysOrigin);
|
||||
|
||||
List<CountryDashboardMetricDTO> listSalaryExchange(
|
||||
@Param("periodType") String periodType,
|
||||
@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime,
|
||||
@Param("countryKeyword") String countryKeyword,
|
||||
@Param("sysOrigin") String sysOrigin);
|
||||
|
||||
List<CountryDashboardMetricDTO> listLuckyGift(
|
||||
@Param("periodType") String periodType,
|
||||
@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime,
|
||||
@Param("countryKeyword") String countryKeyword,
|
||||
@Param("sysOrigin") String sysOrigin);
|
||||
|
||||
List<CountryDashboardMetricDTO> listWalletGame(
|
||||
@Param("periodType") String periodType,
|
||||
@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime,
|
||||
@Param("countryKeyword") String countryKeyword,
|
||||
@Param("sysOrigin") String sysOrigin);
|
||||
|
||||
List<CountryDashboardMetricDTO> listLuckyBoxGame(
|
||||
@Param("periodType") String periodType,
|
||||
@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime,
|
||||
@Param("countryKeyword") String countryKeyword,
|
||||
@Param("sysOrigin") String sysOrigin);
|
||||
|
||||
List<CountryDashboardUserCountryDTO> listUserCountryByIds(@Param("userIds") Collection<Long> userIds);
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.red.circle.console.infra.database.rds.dto.datav;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 国家数据大屏 SQL 聚合结果.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CountryDashboardMetricDTO {
|
||||
|
||||
private String countryCode;
|
||||
|
||||
private String countryName;
|
||||
|
||||
private String periodKey;
|
||||
|
||||
private String periodName;
|
||||
|
||||
private Long countryNewUser;
|
||||
|
||||
private BigDecimal newUserRecharge;
|
||||
|
||||
private BigDecimal officialRecharge;
|
||||
|
||||
private BigDecimal dealerRecharge;
|
||||
|
||||
private BigDecimal salaryExchange;
|
||||
|
||||
private BigDecimal luckyGiftTotalFlow;
|
||||
|
||||
private BigDecimal luckyGiftPayout;
|
||||
|
||||
private BigDecimal gameTotalFlow;
|
||||
|
||||
private BigDecimal gamePayout;
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.red.circle.console.infra.database.rds.dto.datav;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 用户国家归属.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CountryDashboardUserCountryDTO {
|
||||
|
||||
private Long userId;
|
||||
|
||||
private String countryCode;
|
||||
|
||||
private String countryName;
|
||||
}
|
||||
@ -0,0 +1,266 @@
|
||||
<?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.red.circle.console.infra.database.rds.dao.datav.CountryDashboardDAO">
|
||||
|
||||
<sql id="CountryColumns">
|
||||
NULLIF(u.country_code, '') AS countryCode,
|
||||
NULLIF(u.country_name, '') AS countryName
|
||||
</sql>
|
||||
|
||||
<sql id="PeriodColumnsT">
|
||||
<choose>
|
||||
<when test="periodType == 'DAY'">DATE_FORMAT(t.create_time, '%Y-%m-%d')</when>
|
||||
<when test="periodType == 'WEEK'">DATE_FORMAT(t.create_time, '%x-W%v')</when>
|
||||
<when test="periodType == 'MONTH'">DATE_FORMAT(t.create_time, '%Y-%m')</when>
|
||||
<otherwise>'ALL'</otherwise>
|
||||
</choose>
|
||||
AS periodKey,
|
||||
<choose>
|
||||
<when test="periodType == 'DAY'">DATE_FORMAT(t.create_time, '%Y-%m-%d')</when>
|
||||
<when test="periodType == 'WEEK'">DATE_FORMAT(t.create_time, '%x-W%v')</when>
|
||||
<when test="periodType == 'MONTH'">DATE_FORMAT(t.create_time, '%Y-%m')</when>
|
||||
<otherwise>'全部'</otherwise>
|
||||
</choose>
|
||||
AS periodName
|
||||
</sql>
|
||||
|
||||
<sql id="PeriodColumnsU">
|
||||
<choose>
|
||||
<when test="periodType == 'DAY'">DATE_FORMAT(u.create_time, '%Y-%m-%d')</when>
|
||||
<when test="periodType == 'WEEK'">DATE_FORMAT(u.create_time, '%x-W%v')</when>
|
||||
<when test="periodType == 'MONTH'">DATE_FORMAT(u.create_time, '%Y-%m')</when>
|
||||
<otherwise>'ALL'</otherwise>
|
||||
</choose>
|
||||
AS periodKey,
|
||||
<choose>
|
||||
<when test="periodType == 'DAY'">DATE_FORMAT(u.create_time, '%Y-%m-%d')</when>
|
||||
<when test="periodType == 'WEEK'">DATE_FORMAT(u.create_time, '%x-W%v')</when>
|
||||
<when test="periodType == 'MONTH'">DATE_FORMAT(u.create_time, '%Y-%m')</when>
|
||||
<otherwise>'全部'</otherwise>
|
||||
</choose>
|
||||
AS periodName
|
||||
</sql>
|
||||
|
||||
<sql id="UserWhere">
|
||||
AND (u.is_del = 0 OR u.is_del IS NULL)
|
||||
<if test="countryKeyword != null and countryKeyword != ''">
|
||||
AND (
|
||||
u.country_code = #{countryKeyword}
|
||||
OR u.country_name LIKE CONCAT('%', #{countryKeyword}, '%')
|
||||
)
|
||||
</if>
|
||||
<if test="sysOrigin != null and sysOrigin != ''">
|
||||
AND u.origin_sys = #{sysOrigin}
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<sql id="SourceTimeWhere">
|
||||
<if test="startTime != null">
|
||||
AND t.create_time >= #{startTime}
|
||||
</if>
|
||||
<if test="endTime != null">
|
||||
AND t.create_time < #{endTime}
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<sql id="UserTimeWhere">
|
||||
<if test="startTime != null">
|
||||
AND u.create_time >= #{startTime}
|
||||
</if>
|
||||
<if test="endTime != null">
|
||||
AND u.create_time < #{endTime}
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<sql id="SourceSysOriginWhere">
|
||||
<if test="sysOrigin != null and sysOrigin != ''">
|
||||
AND t.sys_origin = #{sysOrigin}
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<select id="listNewUsers"
|
||||
resultType="com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardMetricDTO">
|
||||
SELECT
|
||||
<include refid="CountryColumns"/>,
|
||||
<include refid="PeriodColumnsU"/>,
|
||||
COUNT(1) AS countryNewUser
|
||||
FROM user_base_info u
|
||||
WHERE 1 = 1
|
||||
<include refid="UserWhere"/>
|
||||
<include refid="UserTimeWhere"/>
|
||||
GROUP BY countryCode, countryName, periodKey, periodName
|
||||
</select>
|
||||
|
||||
<select id="listNewUserRecharge"
|
||||
resultType="com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardMetricDTO">
|
||||
SELECT
|
||||
<include refid="CountryColumns"/>,
|
||||
<include refid="PeriodColumnsT"/>,
|
||||
IFNULL(SUM(t.unit_price), 0) AS newUserRecharge
|
||||
FROM order_purchase_history t
|
||||
INNER JOIN user_base_info u ON u.id = t.user_id
|
||||
WHERE t.evn = 'PROD'
|
||||
AND t.is_trial_period = 0
|
||||
AND t.status = 'COMPLETE'
|
||||
<include refid="UserWhere"/>
|
||||
<include refid="SourceTimeWhere"/>
|
||||
<include refid="UserTimeWhere"/>
|
||||
<include refid="SourceSysOriginWhere"/>
|
||||
<choose>
|
||||
<when test="periodType == 'DAY'">AND DATE(u.create_time) = DATE(t.create_time)</when>
|
||||
<when test="periodType == 'WEEK'">AND DATE_FORMAT(u.create_time, '%x-W%v') = DATE_FORMAT(t.create_time, '%x-W%v')</when>
|
||||
<when test="periodType == 'MONTH'">AND DATE_FORMAT(u.create_time, '%Y-%m') = DATE_FORMAT(t.create_time, '%Y-%m')</when>
|
||||
</choose>
|
||||
GROUP BY countryCode, countryName, periodKey, periodName
|
||||
</select>
|
||||
|
||||
<select id="listOfficialRecharge"
|
||||
resultType="com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardMetricDTO">
|
||||
SELECT
|
||||
<include refid="CountryColumns"/>,
|
||||
<include refid="PeriodColumnsT"/>,
|
||||
IFNULL(SUM(t.unit_price), 0) AS officialRecharge
|
||||
FROM order_purchase_history t
|
||||
INNER JOIN user_base_info u ON u.id = t.user_id
|
||||
WHERE t.evn = 'PROD'
|
||||
AND t.is_trial_period = 0
|
||||
AND t.status = 'COMPLETE'
|
||||
<include refid="UserWhere"/>
|
||||
<include refid="SourceTimeWhere"/>
|
||||
<include refid="SourceSysOriginWhere"/>
|
||||
GROUP BY countryCode, countryName, periodKey, periodName
|
||||
</select>
|
||||
|
||||
<select id="listDealerRecharge"
|
||||
resultType="com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardMetricDTO">
|
||||
SELECT
|
||||
<include refid="CountryColumns"/>,
|
||||
<include refid="PeriodColumnsT"/>,
|
||||
IFNULL(SUM(t.recharge_amount), 0) AS dealerRecharge
|
||||
FROM user_gold_coin_recharge t
|
||||
INNER JOIN user_base_info u ON u.id = t.user_id
|
||||
WHERE t.gold_coin_source IN (2, 3)
|
||||
<include refid="UserWhere"/>
|
||||
<include refid="SourceTimeWhere"/>
|
||||
<include refid="SourceSysOriginWhere"/>
|
||||
GROUP BY countryCode, countryName, periodKey, periodName
|
||||
</select>
|
||||
|
||||
<select id="listSalaryExchange"
|
||||
resultType="com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardMetricDTO">
|
||||
SELECT
|
||||
<include refid="CountryColumns"/>,
|
||||
<include refid="PeriodColumnsT"/>,
|
||||
IFNULL(SUM(t.amount), 0) AS salaryExchange
|
||||
FROM (
|
||||
SELECT user_id, sys_origin, amount, create_time
|
||||
FROM user_salary_account_running_water
|
||||
WHERE type = 1 AND salary_event = 'SALARY_EXCHANGE'
|
||||
UNION ALL
|
||||
SELECT user_id, sys_origin, amount, create_time
|
||||
FROM user_salary_diamond_running_water
|
||||
WHERE type = 1 AND salary_event = 'SALARY_EXCHANGE_GOLD_COINS'
|
||||
) t
|
||||
INNER JOIN user_base_info u ON u.id = t.user_id
|
||||
WHERE 1 = 1
|
||||
<include refid="UserWhere"/>
|
||||
<include refid="SourceTimeWhere"/>
|
||||
<include refid="SourceSysOriginWhere"/>
|
||||
GROUP BY countryCode, countryName, periodKey, periodName
|
||||
</select>
|
||||
|
||||
<select id="listLuckyGift"
|
||||
resultType="com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardMetricDTO">
|
||||
SELECT
|
||||
<include refid="CountryColumns"/>,
|
||||
<include refid="PeriodColumnsT"/>,
|
||||
IFNULL(SUM(t.pay_amount), 0) AS luckyGiftTotalFlow,
|
||||
IFNULL(SUM(t.award_amount), 0) AS luckyGiftPayout
|
||||
FROM game_lucky_gift_count t
|
||||
INNER JOIN user_base_info u ON u.id = t.user_id
|
||||
WHERE 1 = 1
|
||||
<include refid="UserWhere"/>
|
||||
<include refid="SourceTimeWhere"/>
|
||||
<include refid="SourceSysOriginWhere"/>
|
||||
GROUP BY countryCode, countryName, periodKey, periodName
|
||||
</select>
|
||||
|
||||
<select id="listWalletGame"
|
||||
resultType="com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardMetricDTO">
|
||||
SELECT
|
||||
<include refid="CountryColumns"/>,
|
||||
<include refid="PeriodColumnsT"/>,
|
||||
IFNULL(SUM(CASE WHEN t.type = 1 THEN t.penny_amount ELSE 0 END) / 100.00, 0) AS gameTotalFlow,
|
||||
IFNULL(SUM(CASE WHEN t.type = 0 THEN t.penny_amount ELSE 0 END) / 100.00, 0) AS gamePayout
|
||||
FROM wallet_gold_asset_record t
|
||||
INNER JOIN user_base_info u ON u.id = t.user_id
|
||||
WHERE (
|
||||
t.event_type IN (
|
||||
'GAME_SLOT_MACHINE',
|
||||
'GAME_BARBECUE',
|
||||
'TURNTABLE_GAME',
|
||||
'LUDO_GAME',
|
||||
'GAME_BURST_CRYSTAL',
|
||||
'EGG',
|
||||
'FRUIT_GAME',
|
||||
'DOUBLE_LAYER_FRUIT',
|
||||
'DOUBLE_LAYER_BARBECUE',
|
||||
'GAME_FRUIT_BET',
|
||||
'GAME_FRUIT_AWARD',
|
||||
'GAME_BACK',
|
||||
'GAME_WINNING',
|
||||
'LUDO_VICTORY',
|
||||
'LUDO_REFUND',
|
||||
'GAME_LUDO_REFUND',
|
||||
'USD_GAME_WIN',
|
||||
'USD_GAME_REFUND',
|
||||
'USD_GAME_REFUND_DRAW',
|
||||
'TEEN_PATTI',
|
||||
'BET_TEEN_PATTI',
|
||||
'LOTTERY_NUMBER_BET',
|
||||
'LOTTERY_REWARD'
|
||||
)
|
||||
OR t.event_type LIKE 'BAISHUN_GAME%'
|
||||
OR t.event_type LIKE 'YOMI_GAME%'
|
||||
OR t.event_type LIKE 'HKYS_GAME%'
|
||||
OR t.event_type LIKE 'HOT_GAME%'
|
||||
)
|
||||
AND t.event_type NOT IN ('LUCKY_GIFT', 'LUCKY_GIFT_GOLD_REWARD', 'LUCKY_BOX_GAME', 'NEW_LUCKY_BOX_GAME', 'GAME_RAKE')
|
||||
AND t.event_type NOT LIKE 'GIVE_GIFT%'
|
||||
AND t.event_type NOT LIKE 'ACCEPT_GIFT%'
|
||||
<include refid="UserWhere"/>
|
||||
<include refid="SourceTimeWhere"/>
|
||||
<include refid="SourceSysOriginWhere"/>
|
||||
GROUP BY countryCode, countryName, periodKey, periodName
|
||||
</select>
|
||||
|
||||
<select id="listLuckyBoxGame"
|
||||
resultType="com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardMetricDTO">
|
||||
SELECT
|
||||
<include refid="CountryColumns"/>,
|
||||
<include refid="PeriodColumnsT"/>,
|
||||
IFNULL(SUM(t.pay_amount), 0) AS gameTotalFlow,
|
||||
IFNULL(SUM(t.gift_amount), 0) AS gamePayout
|
||||
FROM game_lucky_box_count t
|
||||
INNER JOIN user_base_info u ON u.id = t.user_id
|
||||
WHERE 1 = 1
|
||||
<include refid="UserWhere"/>
|
||||
<include refid="SourceTimeWhere"/>
|
||||
<include refid="SourceSysOriginWhere"/>
|
||||
GROUP BY countryCode, countryName, periodKey, periodName
|
||||
</select>
|
||||
|
||||
<select id="listUserCountryByIds"
|
||||
resultType="com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardUserCountryDTO">
|
||||
SELECT
|
||||
id AS userId,
|
||||
NULLIF(country_code, '') AS countryCode,
|
||||
NULLIF(country_name, '') AS countryName
|
||||
FROM user_base_info
|
||||
WHERE id IN
|
||||
<foreach collection="userIds" item="userId" open="(" separator="," close=")">
|
||||
#{userId}
|
||||
</foreach>
|
||||
</select>
|
||||
</mapper>
|
||||
@ -72,4 +72,5 @@ red-circle:
|
||||
- /console/datav/active/user-country-code
|
||||
- /console/datav/online/user/count
|
||||
- /console/datav/online/room/count
|
||||
- /console/datav/country-dashboard
|
||||
- /console/user/base/info/im/sig
|
||||
|
||||
@ -12,6 +12,7 @@ public class BaishunRuntimeConfig {
|
||||
|
||||
String sysOrigin;
|
||||
String platformBaseUrl;
|
||||
String luckyGiftUrl;
|
||||
String appId;
|
||||
String appName;
|
||||
String appChannel;
|
||||
|
||||
@ -52,7 +52,9 @@ public class BaishunRuntimeConfigResolver {
|
||||
|
||||
ApiAccount resolved = new ApiAccount();
|
||||
resolved.setStandardId(base.getStandardId());
|
||||
resolved.setUrl(defaultIfBlank(resolveLuckyGiftApiUrl(config.getPlatformBaseUrl()), base.getUrl()));
|
||||
resolved.setUrl(defaultIfBlank(
|
||||
resolveLuckyGiftApiUrl(config.getLuckyGiftUrl(), config.getPlatformBaseUrl()),
|
||||
base.getUrl()));
|
||||
resolved.setAppId(defaultIfBlank(config.getAppId(), base.getAppId()));
|
||||
resolved.setAppChannel(defaultIfBlank(config.getAppChannel(), base.getAppChannel()));
|
||||
resolved.setAppKey(defaultIfBlank(config.getAppKey(), base.getAppKey()));
|
||||
@ -72,6 +74,7 @@ public class BaishunRuntimeConfigResolver {
|
||||
return base.toBuilder()
|
||||
.sysOrigin(normalizeSysOrigin(defaultIfBlank(row.getSysOrigin(), base.getSysOrigin())))
|
||||
.platformBaseUrl(defaultIfBlank(row.getPlatformBaseUrl(), base.getPlatformBaseUrl()))
|
||||
.luckyGiftUrl(defaultIfBlank(row.getLuckyGiftUrl(), base.getLuckyGiftUrl()))
|
||||
.appId(row.getAppId() != null && row.getAppId() > 0 ? String.valueOf(row.getAppId()) : base.getAppId())
|
||||
.appName(defaultIfBlank(row.getAppName(), base.getAppName()))
|
||||
.appChannel(defaultIfBlank(row.getAppChannel(), base.getAppChannel()))
|
||||
@ -84,7 +87,11 @@ public class BaishunRuntimeConfigResolver {
|
||||
.build();
|
||||
}
|
||||
|
||||
private String resolveLuckyGiftApiUrl(String platformBaseUrl) {
|
||||
private String resolveLuckyGiftApiUrl(String luckyGiftUrl, String platformBaseUrl) {
|
||||
String configuredUrl = trim(luckyGiftUrl);
|
||||
if (StringUtils.isNotBlank(configuredUrl)) {
|
||||
return trimTrailingSlash(configuredUrl);
|
||||
}
|
||||
String baseUrl = trim(platformBaseUrl);
|
||||
if (StringUtils.isBlank(baseUrl)) {
|
||||
return null;
|
||||
|
||||
@ -35,6 +35,7 @@ class BaishunRuntimeConfigResolverTest {
|
||||
when(providerConfigService.getBySysOrigin("LIKEI")).thenReturn(new BaishunProviderConfig()
|
||||
.setSysOrigin("LIKEI")
|
||||
.setPlatformBaseUrl("https://provider.example.com/")
|
||||
.setLuckyGiftUrl("https://lucky.example.com/lucky_gift/start_game")
|
||||
.setAppId(4581045902L)
|
||||
.setAppChannel("yumiparty")
|
||||
.setAppKey("provider-key"));
|
||||
@ -42,7 +43,7 @@ class BaishunRuntimeConfigResolverTest {
|
||||
ApiAccount resolved = resolver.resolveLuckyGiftApiAccount("LIKEI", 99L);
|
||||
|
||||
assertEquals(99L, resolved.getStandardId());
|
||||
assertEquals("https://provider.example.com/lucky_gift/start_game", resolved.getUrl());
|
||||
assertEquals("https://lucky.example.com/lucky_gift/start_game", resolved.getUrl());
|
||||
assertEquals("4581045902", resolved.getAppId());
|
||||
assertEquals("yumiparty", resolved.getAppChannel());
|
||||
assertEquals("provider-key", resolved.getAppKey());
|
||||
|
||||
@ -37,6 +37,9 @@ public class BaishunProviderConfig extends TimestampBaseEntity {
|
||||
@TableField("platform_base_url")
|
||||
private String platformBaseUrl;
|
||||
|
||||
@TableField("lucky_gift_url")
|
||||
private String luckyGiftUrl;
|
||||
|
||||
@TableField("app_id")
|
||||
private Long appId;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user