修复展示

This commit is contained in:
zhx 2026-07-21 14:36:46 +08:00
parent 712d76307f
commit 7d0f99d2e5

View File

@ -19,6 +19,7 @@ import com.red.circle.other.infra.common.activity.send.SendRewardSingle;
import com.red.circle.other.infra.database.rds.dao.activity.aslan.AslanGiftChallengeMapper;
import com.red.circle.other.infra.database.rds.entity.activity.PropsActivityRewardConfig;
import com.red.circle.other.infra.database.rds.entity.activity.PropsActivityRewardGroup;
import com.red.circle.other.infra.database.rds.entity.badge.BadgePictureConfig;
import com.red.circle.other.infra.database.rds.model.activity.aslan.AslanGiftChallengeRows.ActivityRow;
import com.red.circle.other.infra.database.rds.model.activity.aslan.AslanGiftChallengeRows.DeliveryItemRow;
import com.red.circle.other.infra.database.rds.model.activity.aslan.AslanGiftChallengeRows.GiftLedgerRow;
@ -30,6 +31,7 @@ import com.red.circle.other.infra.database.rds.model.activity.aslan.AslanGiftCha
import com.red.circle.other.infra.database.rds.model.activity.aslan.AslanGiftChallengeRows.UserScoreRow;
import com.red.circle.other.infra.database.rds.service.activity.PropsActivityRewardConfigService;
import com.red.circle.other.infra.database.rds.service.activity.PropsActivityRewardGroupService;
import com.red.circle.other.infra.database.rds.service.badge.BadgePictureConfigService;
import com.red.circle.other.inner.endpoint.material.props.PropsActivityRewardConfigClient;
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import com.red.circle.other.inner.enums.material.GiftCurrencyType;
@ -120,6 +122,7 @@ public class AslanGiftChallengeServiceImpl implements AslanGiftChallengeService
private final PropsActivityRewardConfigService rewardConfigService;
private final PropsActivityRewardGroupService rewardGroupService;
private final PropsActivityRewardConfigClient rewardConfigClient;
private final BadgePictureConfigService badgePictureConfigService;
private final UserProfileClient userProfileClient;
private final UserProfileGateway userProfileGateway;
@ -1014,7 +1017,8 @@ public class AslanGiftChallengeServiceImpl implements AslanGiftChallengeService
// 展示字段获取失败不影响核心发放快照type/content/quantity 等实际发放字段始终直接
// 来自同一事务读取的本地奖励配置确保同一期所有用户收到完全一致的资源版本
Map<Long, List<PropsActivityRewardConfigInfoDTO>> displayDetails = loadRewardDetails(groupIds);
Map<Long, List<PropsActivityRewardConfigInfoDTO>> displayDetails = loadRewardDetails(
activity.getSysOrigin(), groupIds);
Map<Long, PropsActivityRewardConfigInfoDTO> displayByConfigId = displayDetails.values().stream()
.filter(Objects::nonNull).flatMap(List::stream).filter(Objects::nonNull)
.filter(item -> item.getId() != null)
@ -1638,21 +1642,33 @@ public class AslanGiftChallengeServiceImpl implements AslanGiftChallengeService
if (!snapshots.isEmpty()) {
// 活动一旦启用就只展示冻结模板某组快照缺失时返回空而不是回退实时资源组避免
// 页面展示与实际 delivery item 在配置异常时悄悄采用两个版本
return snapshots.stream().filter(item -> groupIds.contains(item.getResourceGroupId()))
Map<Long, List<RewardItem>> items = snapshots.stream()
.filter(item -> groupIds.contains(item.getResourceGroupId()))
.collect(Collectors.groupingBy(RewardSnapshotRow::getResourceGroupId,
Collectors.mapping(this::toRewardItem, Collectors.toList())));
// 老活动启用时 BADGE cover/sourceUrl 尚未被写入快照这里仅按冻结 content
// 补展示图片不修改 type/content/quantity确保现网可见性与历史发奖事实解耦
enrichBadgePictures(activity.getSysOrigin(), items.values().stream()
.filter(Objects::nonNull).flatMap(List::stream).toList());
return items;
}
return loadRewardDetails(groupIds).entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey, entry -> toRewardItems(entry.getValue())));
return loadRewardDetails(activity.getSysOrigin(), groupIds).entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey, entry -> toRewardItems(entry.getValue())));
}
private Map<Long, List<PropsActivityRewardConfigInfoDTO>> loadRewardDetails(Set<Long> groupIds) {
private Map<Long, List<PropsActivityRewardConfigInfoDTO>> loadRewardDetails(String sysOrigin,
Set<Long> groupIds) {
if (groupIds == null || groupIds.isEmpty()) {
return Collections.emptyMap();
}
try {
return Optional.ofNullable(rewardConfigClient.mapByGroupIds(groupIds).getBody())
Map<Long, List<PropsActivityRewardConfigInfoDTO>> details = Optional.ofNullable(
rewardConfigClient.mapByGroupIds(groupIds).getBody())
.orElse(Collections.emptyMap());
enrichBadgePictureDetails(sysOrigin, details.values().stream()
.filter(Objects::nonNull).flatMap(List::stream).toList());
return details;
} catch (Exception exception) {
// 奖励展示服务短暂失败不应让活动详情积分和任务状态整体不可用
log.warn("Load Aslan Gift Challenge reward details failed, groupIds={}", groupIds,
@ -1661,6 +1677,85 @@ public class AslanGiftChallengeServiceImpl implements AslanGiftChallengeService
}
}
private void enrichBadgePictureDetails(String sysOrigin,
List<PropsActivityRewardConfigInfoDTO> items) {
// detail 是高频读接口只为缺封面的徽章收集 ID并通过一次 IN 查询批量补图
// 已完整冻结的活动不会额外访问徽章图片表
Map<Long, BadgePictureConfig> pictures = loadBadgePictures(sysOrigin, items.stream()
.filter(Objects::nonNull)
.filter(item -> isBadgeReward(item.getType())
&& StringUtils.isBlank(item.getCover()))
.map(PropsActivityRewardConfigInfoDTO::getContent).toList());
items.stream().filter(Objects::nonNull)
.filter(item -> isBadgeReward(item.getType())
&& StringUtils.isBlank(item.getCover()))
.forEach(item -> {
BadgePictureConfig picture = pictures.get(parseRewardResourceId(item.getContent()));
if (picture == null) {
return;
}
if (StringUtils.isBlank(item.getCover())) {
item.setCover(picture.getSelectUrl());
}
if (StringUtils.isBlank(item.getSourceUrl())) {
item.setSourceUrl(picture.getAnimationUrl());
}
});
}
private void enrichBadgePictures(String sysOrigin, List<RewardItem> items) {
Map<Long, BadgePictureConfig> pictures = loadBadgePictures(sysOrigin, items.stream()
.filter(Objects::nonNull)
.filter(item -> isBadgeReward(item.getType())
&& StringUtils.isBlank(item.getCover()))
.map(RewardItem::getContent).toList());
items.stream().filter(Objects::nonNull)
.filter(item -> isBadgeReward(item.getType())
&& StringUtils.isBlank(item.getCover()))
.forEach(item -> {
BadgePictureConfig picture = pictures.get(parseRewardResourceId(item.getContent()));
if (picture == null) {
return;
}
if (StringUtils.isBlank(item.getCover())) {
item.setCover(picture.getSelectUrl());
}
if (StringUtils.isBlank(item.getSourceUrl())) {
item.setSourceUrl(picture.getAnimationUrl());
}
});
}
private Map<Long, BadgePictureConfig> loadBadgePictures(String sysOrigin,
List<String> contents) {
Set<Long> badgeIds = contents.stream().map(this::parseRewardResourceId)
.filter(Objects::nonNull).collect(Collectors.toSet());
if (StringUtils.isBlank(sysOrigin) || badgeIds.isEmpty()) {
return Collections.emptyMap();
}
try {
return Optional.ofNullable(badgePictureConfigService.mapBadge(sysOrigin, badgeIds))
.orElse(Collections.emptyMap());
} catch (Exception exception) {
// 图片配置只影响 H5 展示查询失败时保留奖励组的发奖字段不能让整个活动详情降级为空
log.warn("Load Aslan Gift Challenge badge pictures failed, origin={}, badgeIds={}",
sysOrigin, badgeIds, exception);
return Collections.emptyMap();
}
}
private Long parseRewardResourceId(String content) {
try {
return StringUtils.isBlank(content) ? null : Long.valueOf(content.trim());
} catch (NumberFormatException ignored) {
return null;
}
}
private boolean isBadgeReward(String type) {
return "BADGE".equals(type) || "PROP_COUPON".equals(type);
}
private List<RewardItem> toRewardItems(List<PropsActivityRewardConfigInfoDTO> items) {
return Optional.ofNullable(items).orElse(Collections.emptyList()).stream()
.sorted(Comparator.comparingInt(item -> Optional.ofNullable(item.getSort()).orElse(0)))