diff --git a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/material/props/ProductProps.java b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/material/props/ProductProps.java index 3553d572..bd9143fd 100644 --- a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/material/props/ProductProps.java +++ b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/material/props/ProductProps.java @@ -80,6 +80,9 @@ public class ProductProps implements Serializable { */ private String countSysOrigin; + /** CP用户id,购买CP戒指时透传. */ + private Long cpUserId; + /** * 资源类型. */ diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/material/PropsPurchasingCmdExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/material/PropsPurchasingCmdExe.java index 0db71a8b..18346bdd 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/material/PropsPurchasingCmdExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/material/PropsPurchasingCmdExe.java @@ -103,6 +103,7 @@ public class PropsPurchasingCmdExe { .setPropsPrices(receipt.getProcessAmount()) .setAppendWealth(cmd.isPayGold()) .setFree(cmd.isFree()) + .setCpUserId(PropsCommodityType.CP_RING == commodity.getPropsType() ? cmd.getCpUserId() : null) .setCountSysOrigin(cmd.requireReqSysOrigin()) ); @@ -123,6 +124,7 @@ public class PropsPurchasingCmdExe { .setPropsOriginDesc("CP ring sync to partner") .setPropsResources(commodity.getPropsResources()) .setPropsPrices(BigDecimal.ZERO) + .setCpUserId(cmd.requiredReqUserId()) .setFree(Boolean.TRUE) ); log.info("购买CP戒指并同步给CP方, userId={}, cpUserId={}, propsId={}", diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/material/query/PropsUserBackpackQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/material/query/PropsUserBackpackQryExe.java index 259c3435..276e1d71 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/material/query/PropsUserBackpackQryExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/material/query/PropsUserBackpackQryExe.java @@ -38,7 +38,7 @@ public class PropsUserBackpackQryExe { cmd.setType(PropsCommodityType.LAYOUT); } return Optional.ofNullable( - propsStoreGateway.listUserPropsBackpack(cmd.getUserId(), cmd.getType())) + propsStoreGateway.listUserPropsBackpack(cmd.getUserId(), cmd.getType(), cmd.getCpUserId())) .orElseGet(CollectionUtils::newArrayList); } diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/material/PropsStoreBackpackTypeQryCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/material/PropsStoreBackpackTypeQryCmd.java index 9c41142b..5633624b 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/material/PropsStoreBackpackTypeQryCmd.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/material/PropsStoreBackpackTypeQryCmd.java @@ -31,4 +31,7 @@ public class PropsStoreBackpackTypeQryCmd extends AppExtCommand { @NotNull(message = "type required.") private PropsCommodityType type; + /** CP用户id,CP_RING类型时必传. */ + private Long cpUserId; + } diff --git a/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/gateway/props/PropsStoreGateway.java b/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/gateway/props/PropsStoreGateway.java index 54bba338..5fa64722 100644 --- a/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/gateway/props/PropsStoreGateway.java +++ b/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/gateway/props/PropsStoreGateway.java @@ -61,9 +61,10 @@ public interface PropsStoreGateway { * * @param userId 用户id * @param propsType 道具类型 + * @param cpUserId CP用户id,CP_RING类型时传入,其他类型可为null * @return 背包道具 */ - List listUserPropsBackpack(Long userId, PropsCommodityType propsType); + List listUserPropsBackpack(Long userId, PropsCommodityType propsType, Long cpUserId); /** * 获取用户使用的贵族和靓号ID. diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/props/CpRingBackpackDAO.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/props/CpRingBackpackDAO.java new file mode 100644 index 00000000..682556fd --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/props/CpRingBackpackDAO.java @@ -0,0 +1,13 @@ +package com.red.circle.other.infra.database.rds.dao.props; + +import com.red.circle.framework.mybatis.dao.BaseDAO; +import com.red.circle.other.infra.database.rds.entity.props.CpRingBackpack; + +/** + * CP戒指背包 DAO. + * + * @author tf + */ +public interface CpRingBackpackDAO extends BaseDAO { + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/props/CpRingBackpack.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/props/CpRingBackpack.java new file mode 100644 index 00000000..76834b7c --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/props/CpRingBackpack.java @@ -0,0 +1,47 @@ +package com.red.circle.other.infra.database.rds.entity.props; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.red.circle.framework.mybatis.entity.TimestampBaseEntity; +import java.io.Serial; +import java.sql.Timestamp; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 用户CP戒指背包. + * + * @author tf + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("user_cp_ring_backpack") +public class CpRingBackpack extends TimestampBaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** 用户id. */ + @TableField("user_id") + private Long userId; + + /** CP用户id. */ + @TableField("cp_user_id") + private Long cpUserId; + + /** 道具id. */ + @TableField("props_id") + private Long propsId; + + /** 过期时间. */ + @TableField("expire_time") + private Timestamp expireTime; + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/props/CpRingBackpackService.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/props/CpRingBackpackService.java new file mode 100644 index 00000000..fe1d99aa --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/props/CpRingBackpackService.java @@ -0,0 +1,33 @@ +package com.red.circle.other.infra.database.rds.service.props; + +import com.red.circle.framework.mybatis.service.BaseService; +import com.red.circle.other.infra.database.rds.entity.props.CpRingBackpack; +import java.util.List; + +/** + * CP戒指背包服务. + * + * @author tf + */ +public interface CpRingBackpackService extends BaseService { + + /** + * 保存或续期CP戒指. + * + * @param userId 用户id + * @param cpUserId CP用户id + * @param propsId 道具id + * @param days 天数 + */ + void saveOrRenew(Long userId, Long cpUserId, Long propsId, Integer days); + + /** + * 查询未过期的CP戒指列表. + * + * @param userId 用户id + * @param cpUserId CP用户id,为null时查询所有CP的戒指 + * @return 戒指列表 + */ + List listNotExpired(Long userId, Long cpUserId); + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/props/impl/CpRingBackpackServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/props/impl/CpRingBackpackServiceImpl.java new file mode 100644 index 00000000..9f0b48e9 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/props/impl/CpRingBackpackServiceImpl.java @@ -0,0 +1,64 @@ +package com.red.circle.other.infra.database.rds.service.props.impl; + +import com.red.circle.framework.mybatis.constant.PageConstant; +import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl; +import com.red.circle.other.infra.database.rds.dao.props.CpRingBackpackDAO; +import com.red.circle.other.infra.database.rds.entity.props.CpRingBackpack; +import com.red.circle.other.infra.database.rds.service.props.CpRingBackpackService; +import com.red.circle.tool.core.date.TimestampUtils; + +import java.sql.Timestamp; +import java.util.List; +import java.util.Objects; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +/** + * CP戒指背包服务实现. + * + * @author tf + */ +@Service +@RequiredArgsConstructor +public class CpRingBackpackServiceImpl extends BaseServiceImpl + implements CpRingBackpackService { + + @Override + public void saveOrRenew(Long userId, Long cpUserId, Long propsId, Integer days) { + CpRingBackpack existing = query() + .eq(CpRingBackpack::getUserId, userId) + .eq(CpRingBackpack::getCpUserId, cpUserId) + .eq(CpRingBackpack::getPropsId, propsId) + .last(PageConstant.LIMIT_ONE) + .getOne(); + + if (Objects.isNull(existing)) { + save(new CpRingBackpack() + .setUserId(userId) + .setCpUserId(cpUserId) + .setPropsId(propsId) + .setExpireTime(TimestampUtils.nowPlusDays(days))); + return; + } + + // 已过期从当前时间续期,未过期在原有过期时间上追加 + long remaining = TimestampUtils.expiredIntervalMillisecond(existing.getExpireTime(), TimestampUtils.now()); + Timestamp base = remaining < 0 ? TimestampUtils.now() : existing.getExpireTime(); + Timestamp appended = TimestampUtils.nowPlusDays(days); + existing.setExpireTime(TimestampUtils.dateTimePlusNanos(base, + TimestampUtils.between(TimestampUtils.now(), appended).toNanos())); + updateSelectiveById(existing); + } + + @Override + public List listNotExpired(Long userId, Long cpUserId) { + var query = query() + .eq(CpRingBackpack::getUserId, userId) + .gt(CpRingBackpack::getExpireTime, TimestampUtils.now()); + if (Objects.nonNull(cpUserId)) { + query.eq(CpRingBackpack::getCpUserId, cpUserId); + } + return query.list(); + } + +} diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/props/PropsStoreGatewayImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/props/PropsStoreGatewayImpl.java index 54b17cd0..5968ff28 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/props/PropsStoreGatewayImpl.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/props/PropsStoreGatewayImpl.java @@ -12,6 +12,7 @@ import com.red.circle.other.infra.convertor.material.PropsNobleVipInfraConvertor import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService; import com.red.circle.other.infra.database.mongo.service.props.StatisticsPropsSaleQuotaService; import com.red.circle.other.infra.database.rds.entity.props.*; +import com.red.circle.other.infra.database.rds.service.props.CpRingBackpackService; import com.red.circle.other.infra.database.rds.service.props.PropsBackpackService; import com.red.circle.other.infra.database.rds.service.props.PropsCommodityStoreService; import com.red.circle.other.infra.database.rds.service.props.PropsNobleVipAbilityService; @@ -70,6 +71,7 @@ public class PropsStoreGatewayImpl implements PropsStoreGateway { private final RoomThemeUserBackpackService roomThemeUserBackpackService; private final StatisticsPropsSaleQuotaService statisticsPropsSaleQuotaService; private final PropsNobleVipInfraConvertor propsNobleVipInfraConvertor; + private final CpRingBackpackService cpRingBackpackService; private final TaskMqMessage taskMqMessage; @Override @@ -220,7 +222,7 @@ public class PropsStoreGatewayImpl implements PropsStoreGateway { } @Override - public List listUserPropsBackpack(Long userId, PropsCommodityType propsType) { + public List listUserPropsBackpack(Long userId, PropsCommodityType propsType, Long cpUserId) { List propBackpacks = propsBackpackService .listNotExpiredByUserIdAndType(userId, propsType); @@ -233,6 +235,10 @@ public class PropsStoreGatewayImpl implements PropsStoreGateway { return listUserPropsBackpack(propBackpacks, getPropsId(propBackpacks)); } + if (Objects.equals(propsType, PropsCommodityType.CP_RING)) { + return listCpRingBackpack(userId, cpUserId, propBackpacks); + } + if (Objects.equals(propsType, PropsCommodityType.RIDE)) { return listUserPropsBackpack(propBackpacks, getPropsId(propBackpacks)); } @@ -390,6 +396,27 @@ public class PropsStoreGatewayImpl implements PropsStoreGateway { .collect(Collectors.toList()); } + private List listCpRingBackpack(Long userId, Long cpUserId, + List propBackpacks) { + List cpRings = cpRingBackpackService.listNotExpired(userId, cpUserId); + if (CollectionUtils.isEmpty(cpRings)) { + return Lists.newArrayList(); + } + Set propsIds = cpRings.stream().map(CpRingBackpack::getPropsId).collect(Collectors.toSet()); + Map sourceRecordMap = propsSourceRecordService.mapByIds(propsIds); + return cpRings.stream().map(ring -> { + PropsSourceRecord source = sourceRecordMap.get(ring.getPropsId()); + if (Objects.isNull(source)) { + return null; + } + return new UserBackpackProps() + .setUserId(ring.getUserId()) + .setType(PropsCommodityType.CP_RING.name()) + .setExpireTime(ring.getExpireTime()) + .setPropsResources(toPropsResources(source)); + }).filter(Objects::nonNull).collect(Collectors.toList()); + } + private boolean saveOrUpdateThemeBackpack(PropsItem backpack) { RoomThemeUserBackpack themeBackpack = roomThemeUserBackpackService.query() .eq(RoomThemeUserBackpack::getUserId, backpack.getUserId()) @@ -539,6 +566,14 @@ public class PropsStoreGatewayImpl implements PropsStoreGateway { .setPropsId(productProps.propsResourcesId()) .setValidDays(productProps.getDays()) ); + if (Objects.equals(productProps.propsResourcesType(), PropsCommodityType.CP_RING) + && Objects.nonNull(productProps.getCpUserId())) { + cpRingBackpackService.saveOrRenew( + productProps.finallyAcceptedUserId(), + productProps.getCpUserId(), + productProps.propsResourcesId(), + productProps.getDays()); + } } }