feat(themes): 新增推荐主题与用户主题批量删除功能
- 新增 getRecommendedThemes:按真实下载量降序返回8个未购买主题 - 新增 batchDeleteUserThemes:支持用户批量逻辑删除已购主题 - 补充接口注释与 Swagger 文档,开放 /themes/recommended 免鉴权路径
This commit is contained in:
@@ -91,7 +91,8 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
"/themes/purchase",
|
||||
"/themes/purchased",
|
||||
"/themes/purchase/list",
|
||||
"/themes/detail"
|
||||
"/themes/detail",
|
||||
"/themes/recommended"
|
||||
};
|
||||
}
|
||||
@Bean
|
||||
|
||||
@@ -83,4 +83,12 @@ public class ThemesController {
|
||||
return ResultUtils.success(result);
|
||||
}
|
||||
|
||||
@GetMapping("/recommended")
|
||||
@Operation(summary = "推荐主题列表", description = "按真实下载数量降序返回推荐主题")
|
||||
public BaseResponse<List<KeyboardThemesRespVO>> getRecommendedThemes() {
|
||||
Long userId = StpUtil.getLoginIdAsLong();
|
||||
List<KeyboardThemesRespVO> result = themesService.getRecommendedThemes(userId);
|
||||
return ResultUtils.success(result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Boolean> batchDeleteUserThemes(@RequestBody BatchDeleteUserThemesReq req) {
|
||||
Long userId = StpUtil.getLoginIdAsLong();
|
||||
userThemesService.batchDeleteUserThemes(userId, req.getThemeIds());
|
||||
return ResultUtils.success(true);
|
||||
}
|
||||
}
|
||||
@@ -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<Long> themeIds;
|
||||
}
|
||||
@@ -29,4 +29,11 @@ public interface KeyboardThemesService extends IService<KeyboardThemes>{
|
||||
*/
|
||||
KeyboardThemesRespVO getThemeDetail(Long themeId, Long userId);
|
||||
|
||||
/**
|
||||
* 推荐主题列表(按真实下载数量降序)
|
||||
* @param userId 用户ID
|
||||
* @return 推荐主题列表
|
||||
*/
|
||||
List<KeyboardThemesRespVO> getRecommendedThemes(Long userId);
|
||||
|
||||
}
|
||||
|
||||
@@ -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<KeyboardUserThemes>{
|
||||
|
||||
/**
|
||||
* 批量删除用户主题(逻辑删除)
|
||||
* @param userId 用户ID
|
||||
* @param themeIds 主题ID列表
|
||||
*/
|
||||
void batchDeleteUserThemes(Long userId, List<Long> themeIds);
|
||||
|
||||
}
|
||||
|
||||
@@ -27,16 +27,34 @@ public class KeyboardThemesServiceImpl extends ServiceImpl<KeyboardThemesMapper,
|
||||
@Lazy // 延迟加载,打破循环依赖
|
||||
private KeyboardThemePurchaseService purchaseService;
|
||||
|
||||
|
||||
/**
|
||||
* 根据风格查询主题列表
|
||||
* <p>查询规则:</p>
|
||||
* <ul>
|
||||
* <li>当themeStyle为9999时,查询所有主题并按排序字段升序排列</li>
|
||||
* <li>其他情况下,查询指定风格的主题</li>
|
||||
* <li>查询结果均过滤已删除和未启用的主题</li>
|
||||
* <li>返回的主题列表包含用户的购买状态</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param themeStyle 主题风格ID,9999表示查询所有风格
|
||||
* @param userId 用户ID,用于判断主题购买状态
|
||||
* @return 主题列表,包含主题详情和购买状态
|
||||
*/
|
||||
@Override
|
||||
public List<KeyboardThemesRespVO> selectThemesByStyle(Long themeStyle, Long userId) {
|
||||
// 根据风格参数查询主题列表
|
||||
List<KeyboardThemes> 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<KeyboardThemesMapper,
|
||||
.list();
|
||||
}
|
||||
|
||||
// 查询用户已购买的主题ID集合
|
||||
Set<Long> purchasedThemeIds = purchaseService.lambdaQuery()
|
||||
.eq(KeyboardThemePurchase::getUserId, userId)
|
||||
.eq(KeyboardThemePurchase::getPayStatus, (short) 1)
|
||||
@@ -52,6 +71,7 @@ public class KeyboardThemesServiceImpl extends ServiceImpl<KeyboardThemesMapper,
|
||||
.map(KeyboardThemePurchase::getThemeId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 转换为VO并设置购买状态
|
||||
return themesList.stream().map(theme -> {
|
||||
KeyboardThemesRespVO vo = BeanUtil.copyProperties(theme, KeyboardThemesRespVO.class);
|
||||
vo.setIsPurchased(purchasedThemeIds.contains(theme.getId()));
|
||||
@@ -59,26 +79,73 @@ public class KeyboardThemesServiceImpl extends ServiceImpl<KeyboardThemesMapper,
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主题详情
|
||||
* <p>查询指定ID的主题详情,并返回用户对该主题的购买状态</p>
|
||||
*
|
||||
* @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
|
||||
/*
|
||||
获取推荐主题列表
|
||||
<p>推荐规则:根据真实下载量降序排序,排除用户已购买的主题,最多返回8个主题</p>
|
||||
|
||||
@param userId 用户ID
|
||||
* @return 推荐主题列表,包含主题详情和购买状态(推荐列表中的主题购买状态均为未购买)
|
||||
*/
|
||||
public List<KeyboardThemesRespVO> getRecommendedThemes(Long userId) {
|
||||
// 查询用户已购买的主题ID集合
|
||||
Set<Long> 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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<KeyboardUserThemesMapper, KeyboardUserThemes> implements KeyboardUserThemesService{
|
||||
|
||||
|
||||
/**
|
||||
* 批量删除用户主题(逻辑删除)
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param themeIds 主题ID列表
|
||||
*/
|
||||
@Override
|
||||
public void batchDeleteUserThemes(Long userId, List<Long> themeIds) {
|
||||
this.lambdaUpdate()
|
||||
.eq(KeyboardUserThemes::getUserId, userId)
|
||||
.in(KeyboardUserThemes::getThemeId, themeIds)
|
||||
.set(KeyboardUserThemes::getViewDeleted, true)
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<KeyboardUserWalle
|
||||
|
||||
private String formatBalance(BigDecimal balance) {
|
||||
if (balance.compareTo(new BigDecimal("10000")) >= 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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user