diff --git a/src/main/java/com/yolo/keyborad/config/SaTokenConfigure.java b/src/main/java/com/yolo/keyborad/config/SaTokenConfigure.java index efe584b..2e03108 100644 --- a/src/main/java/com/yolo/keyborad/config/SaTokenConfigure.java +++ b/src/main/java/com/yolo/keyborad/config/SaTokenConfigure.java @@ -91,7 +91,8 @@ public class SaTokenConfigure implements WebMvcConfigurer { "/themes/purchase", "/themes/purchased", "/themes/purchase/list", - "/themes/detail" + "/themes/detail", + "/themes/recommended" }; } @Bean diff --git a/src/main/java/com/yolo/keyborad/controller/ThemesController.java b/src/main/java/com/yolo/keyborad/controller/ThemesController.java index 2c2f258..0e6030a 100644 --- a/src/main/java/com/yolo/keyborad/controller/ThemesController.java +++ b/src/main/java/com/yolo/keyborad/controller/ThemesController.java @@ -83,4 +83,12 @@ public class ThemesController { return ResultUtils.success(result); } + @GetMapping("/recommended") + @Operation(summary = "推荐主题列表", description = "按真实下载数量降序返回推荐主题") + public BaseResponse> getRecommendedThemes() { + Long userId = StpUtil.getLoginIdAsLong(); + List result = themesService.getRecommendedThemes(userId); + return ResultUtils.success(result); + } + } diff --git a/src/main/java/com/yolo/keyborad/controller/UserThemesController.java b/src/main/java/com/yolo/keyborad/controller/UserThemesController.java new file mode 100644 index 0000000..283d60e --- /dev/null +++ b/src/main/java/com/yolo/keyborad/controller/UserThemesController.java @@ -0,0 +1,34 @@ +package com.yolo.keyborad.controller; + +import cn.dev33.satoken.stp.StpUtil; +import com.yolo.keyborad.common.BaseResponse; +import com.yolo.keyborad.common.ResultUtils; +import com.yolo.keyborad.model.dto.usertheme.BatchDeleteUserThemesReq; +import com.yolo.keyborad.service.KeyboardUserThemesService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +/* + * @author: ziin + * @date: 2025/12/11 + */ +@RestController +@Slf4j +@RequestMapping("/user-themes") +@Tag(name = "用户主题") +public class UserThemesController { + + @Resource + private KeyboardUserThemesService userThemesService; + + @PostMapping("/batch-delete") + @Operation(summary = "批量删除用户主题", description = "批量逻辑删除用户主题") + public BaseResponse batchDeleteUserThemes(@RequestBody BatchDeleteUserThemesReq req) { + Long userId = StpUtil.getLoginIdAsLong(); + userThemesService.batchDeleteUserThemes(userId, req.getThemeIds()); + return ResultUtils.success(true); + } +} diff --git a/src/main/java/com/yolo/keyborad/model/dto/usertheme/BatchDeleteUserThemesReq.java b/src/main/java/com/yolo/keyborad/model/dto/usertheme/BatchDeleteUserThemesReq.java new file mode 100644 index 0000000..2d038c7 --- /dev/null +++ b/src/main/java/com/yolo/keyborad/model/dto/usertheme/BatchDeleteUserThemesReq.java @@ -0,0 +1,20 @@ +package com.yolo.keyborad.model.dto.usertheme; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/* + * @author: ziin + * @date: 2025/12/11 + */ +@Schema(description = "批量删除用户主题请求") +@Data +public class BatchDeleteUserThemesReq { + /** + * 主题ID列表 + */ + @Schema(description = "主题ID列表") + private List themeIds; +} diff --git a/src/main/java/com/yolo/keyborad/service/KeyboardThemesService.java b/src/main/java/com/yolo/keyborad/service/KeyboardThemesService.java index 8572a57..8e23099 100644 --- a/src/main/java/com/yolo/keyborad/service/KeyboardThemesService.java +++ b/src/main/java/com/yolo/keyborad/service/KeyboardThemesService.java @@ -29,4 +29,11 @@ public interface KeyboardThemesService extends IService{ */ KeyboardThemesRespVO getThemeDetail(Long themeId, Long userId); + /** + * 推荐主题列表(按真实下载数量降序) + * @param userId 用户ID + * @return 推荐主题列表 + */ + List getRecommendedThemes(Long userId); + } diff --git a/src/main/java/com/yolo/keyborad/service/KeyboardUserThemesService.java b/src/main/java/com/yolo/keyborad/service/KeyboardUserThemesService.java index a73dd3e..2b0bb81 100644 --- a/src/main/java/com/yolo/keyborad/service/KeyboardUserThemesService.java +++ b/src/main/java/com/yolo/keyborad/service/KeyboardUserThemesService.java @@ -2,12 +2,20 @@ package com.yolo.keyborad.service; import com.yolo.keyborad.model.entity.KeyboardUserThemes; import com.baomidou.mybatisplus.extension.service.IService; - /* + +import java.util.List; +/* * @author: ziin * @date: 2025/12/11 13:31 */ public interface KeyboardUserThemesService extends IService{ + /** + * 批量删除用户主题(逻辑删除) + * @param userId 用户ID + * @param themeIds 主题ID列表 + */ + void batchDeleteUserThemes(Long userId, List themeIds); } diff --git a/src/main/java/com/yolo/keyborad/service/impl/KeyboardThemesServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/KeyboardThemesServiceImpl.java index 8786969..22e985d 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/KeyboardThemesServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/KeyboardThemesServiceImpl.java @@ -27,16 +27,34 @@ public class KeyboardThemesServiceImpl extends ServiceImpl查询规则:

+ *
    + *
  • 当themeStyle为9999时,查询所有主题并按排序字段升序排列
  • + *
  • 其他情况下,查询指定风格的主题
  • + *
  • 查询结果均过滤已删除和未启用的主题
  • + *
  • 返回的主题列表包含用户的购买状态
  • + *
+ * + * @param themeStyle 主题风格ID,9999表示查询所有风格 + * @param userId 用户ID,用于判断主题购买状态 + * @return 主题列表,包含主题详情和购买状态 + */ @Override public List selectThemesByStyle(Long themeStyle, Long userId) { + // 根据风格参数查询主题列表 List themesList; if (themeStyle == 9999) { + // 查询所有主题,按排序字段升序 themesList = this.lambdaQuery() .eq(KeyboardThemes::getDeleted, false) .eq(KeyboardThemes::getThemeStatus, true) .orderByAsc(KeyboardThemes::getSort) .list(); } else { + // 查询指定风格的主题 themesList = this.lambdaQuery() .eq(KeyboardThemes::getDeleted, false) .eq(KeyboardThemes::getThemeStatus, true) @@ -44,6 +62,7 @@ public class KeyboardThemesServiceImpl extends ServiceImpl purchasedThemeIds = purchaseService.lambdaQuery() .eq(KeyboardThemePurchase::getUserId, userId) .eq(KeyboardThemePurchase::getPayStatus, (short) 1) @@ -52,6 +71,7 @@ public class KeyboardThemesServiceImpl extends ServiceImpl { KeyboardThemesRespVO vo = BeanUtil.copyProperties(theme, KeyboardThemesRespVO.class); vo.setIsPurchased(purchasedThemeIds.contains(theme.getId())); @@ -59,26 +79,73 @@ public class KeyboardThemesServiceImpl extends ServiceImpl查询指定ID的主题详情,并返回用户对该主题的购买状态

+ * + * @param themeId 主题ID + * @param userId 用户ID,用于判断购买状态 + * @return 主题详情VO,包含主题信息和购买状态;如果主题不存在或已删除则返回null + */ @Override public KeyboardThemesRespVO getThemeDetail(Long themeId, Long userId) { + // 查询主题详情 KeyboardThemes theme = this.lambdaQuery() .eq(KeyboardThemes::getId, themeId) .eq(KeyboardThemes::getDeleted, false) .eq(KeyboardThemes::getThemeStatus, true) .one(); + // 主题不存在或已删除,返回null if (theme == null) { return null; } + // 查询用户是否购买该主题 boolean isPurchased = purchaseService.lambdaQuery() .eq(KeyboardThemePurchase::getUserId, userId) .eq(KeyboardThemePurchase::getThemeId, themeId) .eq(KeyboardThemePurchase::getPayStatus, (short) 1) .exists(); + // 转换为VO并设置购买状态 KeyboardThemesRespVO vo = BeanUtil.copyProperties(theme, KeyboardThemesRespVO.class); vo.setIsPurchased(isPurchased); return vo; } + + @Override + /* + 获取推荐主题列表 +

推荐规则:根据真实下载量降序排序,排除用户已购买的主题,最多返回8个主题

+ + @param userId 用户ID + * @return 推荐主题列表,包含主题详情和购买状态(推荐列表中的主题购买状态均为未购买) + */ + public List getRecommendedThemes(Long userId) { + // 查询用户已购买的主题ID集合 + Set purchasedThemeIds = purchaseService.lambdaQuery() + .eq(KeyboardThemePurchase::getUserId, userId) + .eq(KeyboardThemePurchase::getPayStatus, (short) 1) + .list() + .stream() + .map(KeyboardThemePurchase::getThemeId) + .collect(Collectors.toSet()); + + // 查询推荐主题列表:未删除、已启用、未购买、按真实下载量降序、限制8条 + return this.lambdaQuery() + .eq(KeyboardThemes::getDeleted, false) + .eq(KeyboardThemes::getThemeStatus, true) + .notIn(!purchasedThemeIds.isEmpty(), KeyboardThemes::getId, purchasedThemeIds) + .orderByDesc(KeyboardThemes::getRealDownloadCount) + .last("LIMIT 8") + .list() + .stream() + .map(theme -> { + KeyboardThemesRespVO vo = BeanUtil.copyProperties(theme, KeyboardThemesRespVO.class); + // 推荐列表中的主题均为未购买状态 + vo.setIsPurchased(false); + return vo; + }).collect(Collectors.toList()); + } } diff --git a/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserThemesServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserThemesServiceImpl.java index 9f70902..7e6a880 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserThemesServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserThemesServiceImpl.java @@ -1,7 +1,6 @@ package com.yolo.keyborad.service.impl; import org.springframework.stereotype.Service; -import org.springframework.beans.factory.annotation.Autowired; import java.util.List; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yolo.keyborad.model.entity.KeyboardUserThemes; @@ -15,4 +14,19 @@ import com.yolo.keyborad.service.KeyboardUserThemesService; @Service public class KeyboardUserThemesServiceImpl extends ServiceImpl implements KeyboardUserThemesService{ + + /** + * 批量删除用户主题(逻辑删除) + * + * @param userId 用户ID + * @param themeIds 主题ID列表 + */ + @Override + public void batchDeleteUserThemes(Long userId, List themeIds) { + this.lambdaUpdate() + .eq(KeyboardUserThemes::getUserId, userId) + .in(KeyboardUserThemes::getThemeId, themeIds) + .set(KeyboardUserThemes::getViewDeleted, true) + .update(); + } } diff --git a/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserWalletServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserWalletServiceImpl.java index e863d5e..de7695b 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserWalletServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/KeyboardUserWalletServiceImpl.java @@ -9,6 +9,7 @@ import com.yolo.keyborad.model.entity.KeyboardUserWallet; import com.yolo.keyborad.service.KeyboardUserWalletService; import java.math.BigDecimal; +import java.math.RoundingMode; /* * @author: ziin @@ -33,9 +34,9 @@ public class KeyboardUserWalletServiceImpl extends ServiceImpl= 0) { - BigDecimal kValue = balance.divide(new BigDecimal("1000"), 2, BigDecimal.ROUND_HALF_UP); + BigDecimal kValue = balance.divide(new BigDecimal("1000"), 2, RoundingMode.HALF_UP); return kValue.stripTrailingZeros().toPlainString() + "K"; } - return balance.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString(); + return balance.setScale(2, RoundingMode.HALF_UP).toPlainString(); } }