feat(console): add reward grant records
This commit is contained in:
parent
8de4ce3837
commit
0104ad5100
119
.deploy/prod-deploy/sql/20260714_reward_grant_record_menu.sql
Normal file
119
.deploy/prod-deploy/sql/20260714_reward_grant_record_menu.sql
Normal file
@ -0,0 +1,119 @@
|
||||
-- Webconsole reward grant record menu and list API permission.
|
||||
-- The menu follows the existing room contribution page and inherits only its roles.
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
INSERT INTO sys_resource (id, resource_name, mapping, method, auth_type, perm, update_time)
|
||||
VALUES (
|
||||
'activity:reward-grant-record:page',
|
||||
'奖励发放记录列表',
|
||||
'/reward-grant-record/page',
|
||||
'GET',
|
||||
3,
|
||||
'activity:reward-grant-record:page',
|
||||
NOW()
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
resource_name = VALUES(resource_name),
|
||||
mapping = VALUES(mapping),
|
||||
method = VALUES(method),
|
||||
auth_type = VALUES(auth_type),
|
||||
perm = VALUES(perm),
|
||||
update_time = NOW();
|
||||
|
||||
-- 关键逻辑:优先使用现有“房间支持活动”的父目录,确保新页面与活动记录同级。
|
||||
INSERT INTO sys_menu (
|
||||
parent_id,
|
||||
menu_name,
|
||||
path,
|
||||
router,
|
||||
menu_type,
|
||||
icon,
|
||||
alias,
|
||||
sort,
|
||||
status,
|
||||
create_user,
|
||||
update_user,
|
||||
create_time,
|
||||
update_time
|
||||
)
|
||||
SELECT
|
||||
source_menu.parent_id,
|
||||
'奖励发放记录',
|
||||
'activity/reward-grant-record/index',
|
||||
'activity/reward-grant-record',
|
||||
2,
|
||||
'form',
|
||||
'activity:reward-grant-record',
|
||||
source_menu.sort - 1,
|
||||
0,
|
||||
'0',
|
||||
'0',
|
||||
NOW(),
|
||||
NOW()
|
||||
FROM sys_menu source_menu
|
||||
LEFT JOIN sys_menu existing ON existing.alias = 'activity:reward-grant-record'
|
||||
WHERE (
|
||||
source_menu.router = 'activity/room/contribution'
|
||||
OR source_menu.router = '/activity/room/contribution'
|
||||
OR source_menu.path = 'activity/room-contribution-list/index'
|
||||
OR source_menu.menu_name = '房间支持活动'
|
||||
)
|
||||
AND source_menu.menu_type = 2
|
||||
AND existing.id IS NULL
|
||||
LIMIT 1;
|
||||
|
||||
-- 关键逻辑:迁移可重复执行,已存在菜单时仍同步页面路径和所属目录。
|
||||
UPDATE sys_menu reward_menu
|
||||
JOIN (
|
||||
SELECT parent_id, sort
|
||||
FROM sys_menu
|
||||
WHERE (
|
||||
router = 'activity/room/contribution'
|
||||
OR router = '/activity/room/contribution'
|
||||
OR path = 'activity/room-contribution-list/index'
|
||||
OR menu_name = '房间支持活动'
|
||||
)
|
||||
AND menu_type = 2
|
||||
LIMIT 1
|
||||
) source_menu ON 1 = 1
|
||||
SET
|
||||
reward_menu.parent_id = source_menu.parent_id,
|
||||
reward_menu.menu_name = '奖励发放记录',
|
||||
reward_menu.path = 'activity/reward-grant-record/index',
|
||||
reward_menu.router = 'activity/reward-grant-record',
|
||||
reward_menu.menu_type = 2,
|
||||
reward_menu.icon = 'form',
|
||||
reward_menu.sort = source_menu.sort - 1,
|
||||
reward_menu.status = 0,
|
||||
reward_menu.update_user = '0',
|
||||
reward_menu.update_time = NOW()
|
||||
WHERE reward_menu.alias = 'activity:reward-grant-record';
|
||||
|
||||
INSERT INTO sys_menu_resource (menu_id, resource_id)
|
||||
SELECT menu.id, resource.id
|
||||
FROM sys_menu menu
|
||||
JOIN sys_resource resource ON resource.id = 'activity:reward-grant-record:page'
|
||||
LEFT JOIN sys_menu_resource existing
|
||||
ON existing.menu_id = menu.id
|
||||
AND existing.resource_id = resource.id
|
||||
WHERE menu.alias = 'activity:reward-grant-record'
|
||||
AND existing.id IS NULL;
|
||||
|
||||
-- 关键逻辑:仅继承已有房间活动记录的角色,避免扩大后台数据可见范围。
|
||||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT DISTINCT source_role.role_id, reward_menu.id
|
||||
FROM sys_role_menu source_role
|
||||
JOIN sys_menu source_menu ON source_menu.id = source_role.menu_id
|
||||
JOIN sys_menu reward_menu ON reward_menu.alias = 'activity:reward-grant-record'
|
||||
LEFT JOIN sys_role_menu existing
|
||||
ON existing.role_id = source_role.role_id
|
||||
AND existing.menu_id = reward_menu.id
|
||||
WHERE (
|
||||
source_menu.router = 'activity/room/contribution'
|
||||
OR source_menu.router = '/activity/room/contribution'
|
||||
OR source_menu.path = 'activity/room-contribution-list/index'
|
||||
OR source_menu.menu_name = '房间支持活动'
|
||||
)
|
||||
AND source_menu.menu_type = 2
|
||||
AND existing.id IS NULL;
|
||||
119
.deploy/test-deploy/sql/20260714_reward_grant_record_menu.sql
Normal file
119
.deploy/test-deploy/sql/20260714_reward_grant_record_menu.sql
Normal file
@ -0,0 +1,119 @@
|
||||
-- Webconsole reward grant record menu and list API permission.
|
||||
-- The menu follows the existing room contribution page and inherits only its roles.
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
INSERT INTO sys_resource (id, resource_name, mapping, method, auth_type, perm, update_time)
|
||||
VALUES (
|
||||
'activity:reward-grant-record:page',
|
||||
'奖励发放记录列表',
|
||||
'/reward-grant-record/page',
|
||||
'GET',
|
||||
3,
|
||||
'activity:reward-grant-record:page',
|
||||
NOW()
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
resource_name = VALUES(resource_name),
|
||||
mapping = VALUES(mapping),
|
||||
method = VALUES(method),
|
||||
auth_type = VALUES(auth_type),
|
||||
perm = VALUES(perm),
|
||||
update_time = NOW();
|
||||
|
||||
-- 关键逻辑:优先使用现有“房间支持活动”的父目录,确保新页面与活动记录同级。
|
||||
INSERT INTO sys_menu (
|
||||
parent_id,
|
||||
menu_name,
|
||||
path,
|
||||
router,
|
||||
menu_type,
|
||||
icon,
|
||||
alias,
|
||||
sort,
|
||||
status,
|
||||
create_user,
|
||||
update_user,
|
||||
create_time,
|
||||
update_time
|
||||
)
|
||||
SELECT
|
||||
source_menu.parent_id,
|
||||
'奖励发放记录',
|
||||
'activity/reward-grant-record/index',
|
||||
'activity/reward-grant-record',
|
||||
2,
|
||||
'form',
|
||||
'activity:reward-grant-record',
|
||||
source_menu.sort - 1,
|
||||
0,
|
||||
'0',
|
||||
'0',
|
||||
NOW(),
|
||||
NOW()
|
||||
FROM sys_menu source_menu
|
||||
LEFT JOIN sys_menu existing ON existing.alias = 'activity:reward-grant-record'
|
||||
WHERE (
|
||||
source_menu.router = 'activity/room/contribution'
|
||||
OR source_menu.router = '/activity/room/contribution'
|
||||
OR source_menu.path = 'activity/room-contribution-list/index'
|
||||
OR source_menu.menu_name = '房间支持活动'
|
||||
)
|
||||
AND source_menu.menu_type = 2
|
||||
AND existing.id IS NULL
|
||||
LIMIT 1;
|
||||
|
||||
-- 关键逻辑:迁移可重复执行,已存在菜单时仍同步页面路径和所属目录。
|
||||
UPDATE sys_menu reward_menu
|
||||
JOIN (
|
||||
SELECT parent_id, sort
|
||||
FROM sys_menu
|
||||
WHERE (
|
||||
router = 'activity/room/contribution'
|
||||
OR router = '/activity/room/contribution'
|
||||
OR path = 'activity/room-contribution-list/index'
|
||||
OR menu_name = '房间支持活动'
|
||||
)
|
||||
AND menu_type = 2
|
||||
LIMIT 1
|
||||
) source_menu ON 1 = 1
|
||||
SET
|
||||
reward_menu.parent_id = source_menu.parent_id,
|
||||
reward_menu.menu_name = '奖励发放记录',
|
||||
reward_menu.path = 'activity/reward-grant-record/index',
|
||||
reward_menu.router = 'activity/reward-grant-record',
|
||||
reward_menu.menu_type = 2,
|
||||
reward_menu.icon = 'form',
|
||||
reward_menu.sort = source_menu.sort - 1,
|
||||
reward_menu.status = 0,
|
||||
reward_menu.update_user = '0',
|
||||
reward_menu.update_time = NOW()
|
||||
WHERE reward_menu.alias = 'activity:reward-grant-record';
|
||||
|
||||
INSERT INTO sys_menu_resource (menu_id, resource_id)
|
||||
SELECT menu.id, resource.id
|
||||
FROM sys_menu menu
|
||||
JOIN sys_resource resource ON resource.id = 'activity:reward-grant-record:page'
|
||||
LEFT JOIN sys_menu_resource existing
|
||||
ON existing.menu_id = menu.id
|
||||
AND existing.resource_id = resource.id
|
||||
WHERE menu.alias = 'activity:reward-grant-record'
|
||||
AND existing.id IS NULL;
|
||||
|
||||
-- 关键逻辑:仅继承已有房间活动记录的角色,避免扩大后台数据可见范围。
|
||||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT DISTINCT source_role.role_id, reward_menu.id
|
||||
FROM sys_role_menu source_role
|
||||
JOIN sys_menu source_menu ON source_menu.id = source_role.menu_id
|
||||
JOIN sys_menu reward_menu ON reward_menu.alias = 'activity:reward-grant-record'
|
||||
LEFT JOIN sys_role_menu existing
|
||||
ON existing.role_id = source_role.role_id
|
||||
AND existing.menu_id = reward_menu.id
|
||||
WHERE (
|
||||
source_menu.router = 'activity/room/contribution'
|
||||
OR source_menu.router = '/activity/room/contribution'
|
||||
OR source_menu.path = 'activity/room-contribution-list/index'
|
||||
OR source_menu.menu_name = '房间支持活动'
|
||||
)
|
||||
AND source_menu.menu_type = 2
|
||||
AND existing.id IS NULL;
|
||||
@ -2,8 +2,11 @@ package com.red.circle.other.inner.endpoint.activity.api;
|
||||
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.inner.model.cmd.activity.RoomContributionRewardRecordPageQryCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.RoomContributionActivityCountDTO;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
@ -30,4 +33,11 @@ public interface RoomContributionActivityCountClientApi {
|
||||
@RequestParam("limitSize") Integer limitSize
|
||||
);
|
||||
|
||||
/**
|
||||
* 查询已成功直发给房主的周流水奖励记录.
|
||||
*/
|
||||
@PostMapping("/pageOwnerRewardSent")
|
||||
ResultResponse<PageResult<RoomContributionActivityCountDTO>> pageOwnerRewardSent(
|
||||
@RequestBody RoomContributionRewardRecordPageQryCmd qryCmd);
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
package com.red.circle.other.inner.model.cmd.activity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 房间周流水奖励发放记录分页查询.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class RoomContributionRewardRecordPageQryCmd implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 房间ID集合,为空时查询全部房间.
|
||||
*/
|
||||
private Set<Long> roomIds;
|
||||
|
||||
/**
|
||||
* 当前页,从1开始.
|
||||
*/
|
||||
private Integer current;
|
||||
|
||||
/**
|
||||
* 每页数量.
|
||||
*/
|
||||
private Integer limitSize;
|
||||
}
|
||||
@ -60,6 +60,21 @@ public class RoomContributionActivityCountDTO extends DTO implements Serializabl
|
||||
*/
|
||||
private BigDecimal balance;
|
||||
|
||||
/**
|
||||
* 房主奖励金币直发事件ID.
|
||||
*/
|
||||
private String ownerRewardCoinsEventId;
|
||||
|
||||
/**
|
||||
* 房主奖励金币直发时间.
|
||||
*/
|
||||
private Timestamp ownerRewardCoinsSentTime;
|
||||
|
||||
/**
|
||||
* 房主奖励比例补差事件ID.
|
||||
*/
|
||||
private String ownerRewardRatioSupplementEventId;
|
||||
|
||||
/**
|
||||
* 创建时间.
|
||||
*/
|
||||
|
||||
@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author pengliang on 2023/5/26
|
||||
@ -101,6 +102,13 @@ public interface WalletGoldClientApi {
|
||||
@GetMapping("/existsEventId")
|
||||
ResultResponse<Boolean> existsEventId(@RequestParam("eventId") String eventId);
|
||||
|
||||
/**
|
||||
* 按事件ID批量查询金币流水.
|
||||
*/
|
||||
@PostMapping("/listByEventIds")
|
||||
ResultResponse<List<WalletGoldAssetRecordDTO>> listByEventIds(
|
||||
@RequestBody Set<String> eventIds);
|
||||
|
||||
|
||||
/**
|
||||
* 获取金币统计.
|
||||
|
||||
@ -15,6 +15,7 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author pengliang on 2024/2/23
|
||||
@ -93,6 +94,13 @@ public class WalletGoldClientCallback implements WalletGoldClient {
|
||||
return ResultResponse.failure(CommonErrorCode.REQUEST_LIMITING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<List<WalletGoldAssetRecordDTO>> listByEventIds(Set<String> eventIds) {
|
||||
log.warn("[listByEventIds] eventIds={}", JacksonUtils.toJson(eventIds));
|
||||
// 奖励记录必须展示真实钱包流水,熔断时明确失败,不能用空列表伪装成发放 0 金币。
|
||||
return ResultResponse.failure(CommonErrorCode.REQUEST_LIMITING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<List<WalletGoldCountDTO>> listWalletGoldCount(String sysOrigin,
|
||||
Integer groupNum) {
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
package com.red.circle.console.adapter.app.activity;
|
||||
|
||||
import com.red.circle.console.app.dto.clienobject.activity.RewardGrantRecordCO;
|
||||
import com.red.circle.console.app.dto.cmd.app.activity.RewardGrantRecordQryCmd;
|
||||
import com.red.circle.console.app.service.app.activity.RewardGrantRecordService;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.framework.web.controller.BaseController;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 奖励发放记录后台接口.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/reward-grant-record")
|
||||
public class RewardGrantRecordRestController extends BaseController {
|
||||
|
||||
private final RewardGrantRecordService rewardGrantRecordService;
|
||||
|
||||
/**
|
||||
* 分页查询.
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public PageResult<RewardGrantRecordCO> page(RewardGrantRecordQryCmd qryCmd) {
|
||||
return rewardGrantRecordService.pageQuery(qryCmd);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,181 @@
|
||||
package com.red.circle.console.app.service.app.activity;
|
||||
|
||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||
import com.red.circle.console.app.dto.clienobject.activity.RewardGrantRecordCO;
|
||||
import com.red.circle.console.app.dto.cmd.app.activity.RewardGrantRecordQryCmd;
|
||||
import com.red.circle.console.app.dto.enums.RewardGrantTypeEnum;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.other.inner.endpoint.activity.RoomContributionActivityCountClient;
|
||||
import com.red.circle.other.inner.endpoint.live.RoomManagerClient;
|
||||
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
||||
import com.red.circle.other.inner.model.cmd.activity.RoomContributionRewardRecordPageQryCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.RoomContributionActivityCountDTO;
|
||||
import com.red.circle.other.inner.model.dto.live.RoomProfileDTO;
|
||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||
import com.red.circle.tool.core.collection.CollectionUtils;
|
||||
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
|
||||
import com.red.circle.wallet.inner.model.dto.WalletGoldAssetRecordDTO;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 奖励发放记录实现.
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RewardGrantRecordServiceImpl implements RewardGrantRecordService {
|
||||
|
||||
private static final String OWNER_REWARD_EVENT_PREFIX = "RCWR:";
|
||||
private static final String OWNER_REWARD_SUPPLEMENT_EVENT_PREFIX = "RCWRS:";
|
||||
|
||||
private final UserProfileClient userProfileClient;
|
||||
private final RoomManagerClient roomManagerClient;
|
||||
private final RoomContributionActivityCountClient roomContributionActivityCountClient;
|
||||
private final WalletGoldClient walletGoldClient;
|
||||
|
||||
@Override
|
||||
public PageResult<RewardGrantRecordCO> pageQuery(RewardGrantRecordQryCmd qryCmd) {
|
||||
RewardGrantTypeEnum rewardType = Objects.requireNonNullElse(qryCmd.getRewardType(),
|
||||
RewardGrantTypeEnum.ROOM_WEEKLY_CONTRIBUTION);
|
||||
if (rewardType != RewardGrantTypeEnum.ROOM_WEEKLY_CONTRIBUTION) {
|
||||
return PageResult.newPageResult(qryCmd.getPageQuery().getLimit());
|
||||
}
|
||||
|
||||
Set<Long> roomIds = resolveRoomIds(qryCmd.getUserAccount());
|
||||
if (StringUtils.isNotBlank(qryCmd.getUserAccount()) && CollectionUtils.isEmpty(roomIds)) {
|
||||
return PageResult.newPageResult(qryCmd.getPageQuery().getLimit());
|
||||
}
|
||||
|
||||
RoomContributionRewardRecordPageQryCmd innerQry =
|
||||
new RoomContributionRewardRecordPageQryCmd()
|
||||
.setRoomIds(roomIds)
|
||||
.setCurrent(qryCmd.getPageQuery().getCursor())
|
||||
.setLimitSize(qryCmd.getPageQuery().getLimit());
|
||||
PageResult<RoomContributionActivityCountDTO> pageResult = ResponseAssert.requiredSuccess(
|
||||
roomContributionActivityCountClient.pageOwnerRewardSent(innerQry));
|
||||
if (CollectionUtils.isEmpty(pageResult.getRecords())) {
|
||||
return pageResult.emptyRecords();
|
||||
}
|
||||
|
||||
Map<Long, RoomProfileDTO> roomProfileMap = loadRooms(pageResult.getRecords());
|
||||
Map<Long, UserProfileDTO> userProfileMap = loadUsers(roomProfileMap);
|
||||
WalletRewardData walletRewardData = loadWalletRewardData(pageResult.getRecords());
|
||||
|
||||
return pageResult.convert(record -> {
|
||||
RoomProfileDTO room = roomProfileMap.get(record.getRoomId());
|
||||
Long userId = Objects.nonNull(room) ? room.getUserId() : null;
|
||||
Set<String> eventIds = rewardEventIds(record);
|
||||
long rewardPenny = eventIds.stream()
|
||||
.mapToLong(eventId -> walletRewardData.amountByEventId().getOrDefault(eventId, 0L))
|
||||
.sum();
|
||||
Timestamp grantTime = eventIds.stream()
|
||||
.map(walletRewardData.timeByEventId()::get)
|
||||
.filter(Objects::nonNull)
|
||||
.max(Timestamp::compareTo)
|
||||
.orElse(record.getOwnerRewardCoinsSentTime());
|
||||
|
||||
return new RewardGrantRecordCO()
|
||||
.setRewardType(rewardType)
|
||||
.setUserProfile(userProfileMap.get(userId))
|
||||
.setRoomProfile(room)
|
||||
.setRoomContribution(record.getContributionValue())
|
||||
// 钱包以分存储,页面统一展示金币单位。
|
||||
.setRewardCoins(BigDecimal.valueOf(rewardPenny, 2))
|
||||
.setDateNumber(record.getDateNumber())
|
||||
.setGrantTime(grantTime);
|
||||
});
|
||||
}
|
||||
|
||||
private Set<Long> resolveRoomIds(String userAccount) {
|
||||
if (StringUtils.isBlank(userAccount)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 平台内查询会先匹配短ID,未命中时继续匹配有效靓号,避免跨平台同号导致漏查。
|
||||
UserProfileDTO user = ResponseAssert.requiredSuccess(userProfileClient.getByAccount(
|
||||
SysOriginPlatformEnum.ATYOU.name(), userAccount.trim()));
|
||||
if (Objects.isNull(user) || Objects.isNull(user.getId())) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Map<Long, RoomProfileDTO> rooms = ResponseAssert.requiredSuccess(
|
||||
roomManagerClient.mapProfileByUserIds(Set.of(user.getId())));
|
||||
return rooms.values().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(RoomProfileDTO::getId)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Map<Long, RoomProfileDTO> loadRooms(
|
||||
Collection<RoomContributionActivityCountDTO> records) {
|
||||
Set<Long> roomIds = records.stream()
|
||||
.map(RoomContributionActivityCountDTO::getRoomId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
return ResponseAssert.requiredSuccess(roomManagerClient.mapProfileByRoomIds(roomIds));
|
||||
}
|
||||
|
||||
private Map<Long, UserProfileDTO> loadUsers(Map<Long, RoomProfileDTO> roomProfileMap) {
|
||||
Set<Long> userIds = roomProfileMap.values().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(RoomProfileDTO::getUserId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
if (CollectionUtils.isEmpty(userIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return ResponseAssert.requiredSuccess(userProfileClient.mapByUserIds(userIds));
|
||||
}
|
||||
|
||||
private WalletRewardData loadWalletRewardData(
|
||||
Collection<RoomContributionActivityCountDTO> records) {
|
||||
Set<String> eventIds = records.stream()
|
||||
.map(this::rewardEventIds)
|
||||
.flatMap(Set::stream)
|
||||
.collect(Collectors.toSet());
|
||||
List<WalletGoldAssetRecordDTO> walletRecords = ResponseAssert.requiredSuccess(
|
||||
walletGoldClient.listByEventIds(eventIds));
|
||||
|
||||
Map<String, Long> amountByEventId = new HashMap<>();
|
||||
Map<String, Timestamp> timeByEventId = new HashMap<>();
|
||||
walletRecords.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(record -> Objects.equals(record.getType(), 0))
|
||||
.forEach(record -> {
|
||||
amountByEventId.merge(record.getEventId(),
|
||||
Objects.requireNonNullElse(record.getPennyAmount(), 0L), Long::sum);
|
||||
if (Objects.nonNull(record.getCreateTime())) {
|
||||
timeByEventId.merge(record.getEventId(), record.getCreateTime(),
|
||||
(left, right) -> left.after(right) ? left : right);
|
||||
}
|
||||
});
|
||||
return new WalletRewardData(amountByEventId, timeByEventId);
|
||||
}
|
||||
|
||||
private Set<String> rewardEventIds(RoomContributionActivityCountDTO record) {
|
||||
Set<String> eventIds = new HashSet<>();
|
||||
eventIds.add(StringUtils.defaultIfBlank(record.getOwnerRewardCoinsEventId(),
|
||||
OWNER_REWARD_EVENT_PREFIX + record.getId()));
|
||||
// 兼容补差字段上线前已发放的数据,派生事件ID后查询实际钱包流水。
|
||||
eventIds.add(StringUtils.defaultIfBlank(record.getOwnerRewardRatioSupplementEventId(),
|
||||
OWNER_REWARD_SUPPLEMENT_EVENT_PREFIX + record.getId()));
|
||||
return eventIds;
|
||||
}
|
||||
|
||||
private record WalletRewardData(Map<String, Long> amountByEventId,
|
||||
Map<String, Timestamp> timeByEventId) {
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.red.circle.console.app.dto.clienobject.activity;
|
||||
|
||||
import com.red.circle.console.app.dto.enums.RewardGrantTypeEnum;
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import com.red.circle.other.inner.model.dto.live.RoomProfileDTO;
|
||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||
import java.io.Serial;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Timestamp;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 奖励发放记录.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RewardGrantRecordCO extends ClientObject {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private RewardGrantTypeEnum rewardType;
|
||||
private UserProfileDTO userProfile;
|
||||
private RoomProfileDTO roomProfile;
|
||||
private BigDecimal roomContribution;
|
||||
private BigDecimal rewardCoins;
|
||||
private Integer dateNumber;
|
||||
private Timestamp grantTime;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.red.circle.console.app.dto.cmd.app.activity;
|
||||
|
||||
import com.red.circle.console.app.dto.enums.RewardGrantTypeEnum;
|
||||
import com.red.circle.framework.core.dto.PageCommand;
|
||||
import java.io.Serial;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 奖励发放记录分页查询.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
public class RewardGrantRecordQryCmd extends PageCommand {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 奖励类型.
|
||||
*/
|
||||
private RewardGrantTypeEnum rewardType = RewardGrantTypeEnum.ROOM_WEEKLY_CONTRIBUTION;
|
||||
|
||||
/**
|
||||
* 用户短ID或靓号.
|
||||
*/
|
||||
private String userAccount;
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.red.circle.console.app.dto.enums;
|
||||
|
||||
/**
|
||||
* 后台奖励发放记录类型.
|
||||
*/
|
||||
public enum RewardGrantTypeEnum {
|
||||
|
||||
/**
|
||||
* 房间周流水奖励.
|
||||
*/
|
||||
ROOM_WEEKLY_CONTRIBUTION
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.console.app.service.app.activity;
|
||||
|
||||
import com.red.circle.console.app.dto.clienobject.activity.RewardGrantRecordCO;
|
||||
import com.red.circle.console.app.dto.cmd.app.activity.RewardGrantRecordQryCmd;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
|
||||
/**
|
||||
* 奖励发放记录.
|
||||
*/
|
||||
public interface RewardGrantRecordService {
|
||||
|
||||
/**
|
||||
* 分页查询奖励发放记录.
|
||||
*/
|
||||
PageResult<RewardGrantRecordCO> pageQuery(RewardGrantRecordQryCmd qryCmd);
|
||||
}
|
||||
@ -6,6 +6,7 @@ import com.red.circle.other.infra.database.mongo.entity.activity.RoomContributio
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
/**
|
||||
@ -85,6 +86,12 @@ public interface RoomContributionActivityCountService {
|
||||
PageResult<RoomContributionActivityCount> pageReceived(long pageNumber, long pageSize,
|
||||
Long roomId);
|
||||
|
||||
/**
|
||||
* 已成功直发给房主的周流水奖励分页记录.
|
||||
*/
|
||||
PageResult<RoomContributionActivityCount> pageOwnerRewardSent(long pageNumber, long pageSize,
|
||||
Set<Long> roomIds);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param roomId
|
||||
|
||||
@ -19,6 +19,7 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -273,6 +274,18 @@ public class RoomContributionActivityCountServiceImpl implements
|
||||
(int) pageNumber, Sort.Order.desc("createTime"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<RoomContributionActivityCount> pageOwnerRewardSent(long pageNumber,
|
||||
long pageSize, Set<Long> roomIds) {
|
||||
Criteria criteria = Criteria.where("ownerRewardCoinsSent").is(Boolean.TRUE);
|
||||
if (CollectionUtils.isNotEmpty(roomIds)) {
|
||||
// 账号筛选先解析成房间ID,避免在奖励集合中做跨集合或模糊查询。
|
||||
criteria.and("roomId").in(roomIds);
|
||||
}
|
||||
return mongoPageHelper.query(new Query(criteria), RoomContributionActivityCount.class,
|
||||
(int) pageSize, (int) pageNumber, Sort.Order.desc("ownerRewardCoinsSentTime"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RoomContributionActivityCount> listRoomContributionByPH(Long roomId,BigDecimal number) {
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.other.app.inner.service.activity.RoomContributionActivityCountClientService;
|
||||
import com.red.circle.other.inner.endpoint.activity.api.RoomContributionActivityCountClientApi;
|
||||
import com.red.circle.other.inner.model.cmd.activity.RoomContributionRewardRecordPageQryCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.RoomContributionActivityCountDTO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
@ -33,4 +34,11 @@ public class RoomContributionActivityCountClientEndpoint implements
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<PageResult<RoomContributionActivityCountDTO>> pageOwnerRewardSent(
|
||||
RoomContributionRewardRecordPageQryCmd qryCmd) {
|
||||
return ResultResponse.success(
|
||||
roomContributionActivityCountClientService.pageOwnerRewardSent(qryCmd));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.red.circle.other.app.inner.service.activity;
|
||||
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.other.inner.model.cmd.activity.RoomContributionRewardRecordPageQryCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.RoomContributionActivityCountDTO;
|
||||
|
||||
/**
|
||||
@ -22,4 +23,10 @@ public interface RoomContributionActivityCountClientService {
|
||||
PageResult<RoomContributionActivityCountDTO> pageReceived(Long roomId, Integer current,
|
||||
Integer limitSize);
|
||||
|
||||
/**
|
||||
* 已成功直发给房主的周流水奖励记录.
|
||||
*/
|
||||
PageResult<RoomContributionActivityCountDTO> pageOwnerRewardSent(
|
||||
RoomContributionRewardRecordPageQryCmd qryCmd);
|
||||
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.other.app.inner.convertor.activity.RoomContributionActivityCountInnerConvertor;
|
||||
import com.red.circle.other.app.inner.service.activity.RoomContributionActivityCountClientService;
|
||||
import com.red.circle.other.infra.database.mongo.service.activity.RoomContributionActivityCountService;
|
||||
import com.red.circle.other.inner.model.cmd.activity.RoomContributionRewardRecordPageQryCmd;
|
||||
import com.red.circle.other.inner.model.dto.activity.RoomContributionActivityCountDTO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -29,4 +30,12 @@ public class RoomContributionActivityCountClientServiceImpl implements
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<RoomContributionActivityCountDTO> pageOwnerRewardSent(
|
||||
RoomContributionRewardRecordPageQryCmd qryCmd) {
|
||||
return roomContributionActivityCountInnerConvertor.toPageRoomContributionActivityCountDTO(
|
||||
roomContributionActivityCountService.pageOwnerRewardSent(qryCmd.getCurrent(),
|
||||
qryCmd.getLimitSize(), qryCmd.getRoomIds()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.red.circle.wallet.infra.database.rds.service;
|
||||
import com.red.circle.framework.mybatis.service.BaseService;
|
||||
import com.red.circle.wallet.infra.database.rds.entity.WalletGoldAssetRecord;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用户金币资产流水 服务.
|
||||
@ -21,6 +22,11 @@ public interface WalletGoldAssetRecordService extends BaseService<WalletGoldAsse
|
||||
*/
|
||||
boolean existsRecentEventId(String eventId);
|
||||
|
||||
/**
|
||||
* 按事件ID批量查询资产流水.
|
||||
*/
|
||||
List<WalletGoldAssetRecord> listByEventIds(Set<String> eventIds);
|
||||
|
||||
/**
|
||||
* 获取本月指定数量资产记录.
|
||||
*/
|
||||
|
||||
@ -10,6 +10,7 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
@ -22,6 +23,8 @@ public class WalletGoldAssetRecordServiceImpl extends
|
||||
BaseServiceImpl<WalletGoldAssetRecordDAO, WalletGoldAssetRecord> implements
|
||||
WalletGoldAssetRecordService {
|
||||
|
||||
private static final int MAX_EVENT_ID_QUERY_SIZE = 200;
|
||||
|
||||
@Override
|
||||
public boolean existsRecent(Long id) {
|
||||
return Optional.ofNullable(
|
||||
@ -44,6 +47,22 @@ public class WalletGoldAssetRecordServiceImpl extends
|
||||
.orElse(Boolean.FALSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WalletGoldAssetRecord> listByEventIds(Set<String> eventIds) {
|
||||
if (eventIds == null || eventIds.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
if (eventIds.size() > MAX_EVENT_ID_QUERY_SIZE) {
|
||||
throw new IllegalArgumentException("eventIds size must not exceed "
|
||||
+ MAX_EVENT_ID_QUERY_SIZE);
|
||||
}
|
||||
// event_id在每个月分片表都有索引;限制批量大小,避免跨月分片广播成大范围查询。
|
||||
return query().in(WalletGoldAssetRecord::getEventId, eventIds)
|
||||
.eq(WalletGoldAssetRecord::getType, 0)
|
||||
.last(PageConstant.formatLimitStrict(eventIds.size()))
|
||||
.list();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WalletGoldAssetRecord> listThisMonth(String sysOrigin, Long userId, Integer type,
|
||||
Long lastId,
|
||||
|
||||
@ -14,6 +14,7 @@ import com.red.circle.wallet.inner.service.wallet.WalletGoldClientService;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -99,6 +100,11 @@ public class WalletGoldClientEndpoint implements WalletGoldClientApi {
|
||||
return ResultResponse.success(walletGoldClientService.existsEventId(eventId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<List<WalletGoldAssetRecordDTO>> listByEventIds(Set<String> eventIds) {
|
||||
return ResultResponse.success(walletGoldClientService.listByEventIds(eventIds));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<List<WalletGoldCountDTO>> listWalletGoldCount(String sysOrigin,
|
||||
Integer groupNum) {
|
||||
|
||||
@ -9,6 +9,7 @@ import com.red.circle.wallet.inner.model.cmd.UserGoldRunningWaterBackQryCmd;
|
||||
import com.red.circle.wallet.inner.model.dto.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author pengliang on 2023/5/26
|
||||
@ -65,6 +66,11 @@ public interface WalletGoldClientService {
|
||||
*/
|
||||
Boolean existsEventId(String eventId);
|
||||
|
||||
/**
|
||||
* 按事件ID批量查询金币流水.
|
||||
*/
|
||||
List<WalletGoldAssetRecordDTO> listByEventIds(Set<String> eventIds);
|
||||
|
||||
/**
|
||||
* 获取最近一个月流水信息(app).
|
||||
*/
|
||||
|
||||
@ -367,6 +367,13 @@ public class WalletGoldClientServiceImpl implements WalletGoldClientService {
|
||||
return walletGoldAssetRecordService.existsRecentEventId(eventId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WalletGoldAssetRecordDTO> listByEventIds(Set<String> eventIds) {
|
||||
return walletGoldAssetRecordService.listByEventIds(eventIds).stream()
|
||||
.map(walletInnerConvertor::toWalletGoldAssetRecordDTO)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AssetRecordRunningWaterDTO> listThisMonth(String sysOrigin, Long userId, Integer type,
|
||||
Long lastId) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user