From 3fdd75a5df8779ae774ccded511a4283a9e9d075 Mon Sep 17 00:00:00 2001 From: ziin Date: Thu, 26 Mar 2026 16:35:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8C=89=E7=85=A7PK=E8=AE=B0=E5=BD=95=E4=B8=BA?= =?UTF-8?q?PK=E5=8F=8C=E6=96=B9=E6=B7=BB=E5=8A=A0=E7=A7=AF=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.cache/.Apifox_Helper/.toolWindow.db | Bin 196608 -> 196608 bytes .idea/ApifoxUploaderProjectSetting.xml | 5 +- .../config/FunctionConfigHolder.java | 6 +- .../config/SaTokenConfigure.java | 3 +- .../controller/PkController.java | 19 ++-- .../pk/model/DTO/PkResultPointsDTO.java | 9 ++ .../pk/service/PKServiceImpl.java | 3 +- .../pk/service/PkResultPointService.java | 7 ++ .../pk/service/PkResultPointServiceImpl.java | 85 ++++++++++++++++++ .../PkResultPointServiceImplTests.java | 75 ++++++++++++++++ 10 files changed, 197 insertions(+), 15 deletions(-) create mode 100644 src/main/java/vvpkassistant/pk/model/DTO/PkResultPointsDTO.java create mode 100644 src/main/java/vvpkassistant/pk/service/PkResultPointService.java create mode 100644 src/main/java/vvpkassistant/pk/service/PkResultPointServiceImpl.java create mode 100644 src/test/java/vvpkassistant/pk/service/PkResultPointServiceImplTests.java diff --git a/.idea/.cache/.Apifox_Helper/.toolWindow.db b/.idea/.cache/.Apifox_Helper/.toolWindow.db index b2028a7504bb96a0e5ffed5da0456533b8ef3036..80e1644eca02a175f73dd051540ff79f97f95bea 100644 GIT binary patch delta 9478 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 delta 12740 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 - - \ No newline at end of file diff --git a/src/main/java/vvpkassistant/config/FunctionConfigHolder.java b/src/main/java/vvpkassistant/config/FunctionConfigHolder.java index a316318..d3f11e8 100644 --- a/src/main/java/vvpkassistant/config/FunctionConfigHolder.java +++ b/src/main/java/vvpkassistant/config/FunctionConfigHolder.java @@ -1,5 +1,6 @@ package vvpkassistant.config; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import vvpkassistant.FunctionConfig.mapper.FunctionConfigMapper; @@ -11,9 +12,10 @@ import java.util.concurrent.CopyOnWriteArrayList; @Component @RequiredArgsConstructor +@Slf4j public class FunctionConfigHolder { // 线程安全的全局配置容器 - public static final List CONFIGS = new CopyOnWriteArrayList<>(); + public static List CONFIGS = new CopyOnWriteArrayList<>(); @Autowired private FunctionConfigMapper configMapper; @@ -26,7 +28,7 @@ public class FunctionConfigHolder { List dbConfigs = configMapper.selectList(null); CONFIGS.clear(); CONFIGS.addAll(dbConfigs); - System.out.println("已加载 "+CONFIGS.size()+" 条功能配置"); + log.info("已加载 {} 条功能配置", CONFIGS.size()); } /** diff --git a/src/main/java/vvpkassistant/config/SaTokenConfigure.java b/src/main/java/vvpkassistant/config/SaTokenConfigure.java index a60a36d..f862d64 100644 --- a/src/main/java/vvpkassistant/config/SaTokenConfigure.java +++ b/src/main/java/vvpkassistant/config/SaTokenConfigure.java @@ -62,7 +62,8 @@ public class SaTokenConfigure implements WebMvcConfigurer { "/systemMessage/list", "/pk/pkListForPython", "/pk/insertPkDetail", - "/pk/updatePkRecordInfo" + "/pk/updatePkRecordInfo", + "/pk/grantPkResultPoints" }; } diff --git a/src/main/java/vvpkassistant/controller/PkController.java b/src/main/java/vvpkassistant/controller/PkController.java index bc9fd69..a6d61c4 100644 --- a/src/main/java/vvpkassistant/controller/PkController.java +++ b/src/main/java/vvpkassistant/controller/PkController.java @@ -1,11 +1,9 @@ package vvpkassistant.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; -import vvpkassistant.CoinRecords.CoinRecordsDao; import vvpkassistant.Data.ResponseData; import vvpkassistant.Data.ResponseInfo; import vvpkassistant.Tools.VVTools; -import vvpkassistant.User.mapper.UserDao; import vvpkassistant.pk.mapper.PkInfoDao; import vvpkassistant.pk.mapper.PkRecordDao; import vvpkassistant.pk.mapper.PkRecordDetailDao; @@ -15,10 +13,12 @@ import vvpkassistant.pk.model.DTO.PkInfoDetailDTO; import vvpkassistant.pk.model.DTO.PkListRequestDTO; import vvpkassistant.pk.model.DTO.PkListUninvitedDTO; import vvpkassistant.pk.model.DTO.PkQueryMyCanUseDTO; +import vvpkassistant.pk.model.DTO.PkResultPointsDTO; import vvpkassistant.pk.model.PkInfoModel; import vvpkassistant.pk.model.PkRecord; import vvpkassistant.pk.model.PkRecordDetail; import vvpkassistant.pk.service.PKService; +import vvpkassistant.pk.service.PkResultPointService; import javax.annotation.Resource; import java.util.List; @@ -32,6 +32,9 @@ public class PkController { @Resource private PKService pkService; + @Resource + private PkResultPointService pkResultPointService; + @Autowired private PkInfoDao pkDao; @@ -41,12 +44,6 @@ public class PkController { @Autowired private PkRecordDetailDao detailDao; - @Autowired - private UserDao userDao; - - @Autowired - private CoinRecordsDao coinRecordsDao; - // 创建pk数据 @PostMapping("addPkData") public ResponseData addPkData(@RequestBody PkInfoModel pkModel) { @@ -155,6 +152,12 @@ public class PkController { return i == 1 ? ResponseData.success("") : ResponseData.error(ResponseInfo.ERROR.getCode(),null); } + // 根据PK结果为用户增加积分 + @PostMapping("grantPkResultPoints") + public ResponseData grantPkResultPoints(@RequestBody PkResultPointsDTO request) { + return ResponseData.success(pkResultPointService.grantPkResultPoints(request)); + } + // 插入pk明细表数据 @PostMapping("insertPkDetail") public ResponseData insert(@RequestBody PkRecordDetail detail) { diff --git a/src/main/java/vvpkassistant/pk/model/DTO/PkResultPointsDTO.java b/src/main/java/vvpkassistant/pk/model/DTO/PkResultPointsDTO.java new file mode 100644 index 0000000..ed061c7 --- /dev/null +++ b/src/main/java/vvpkassistant/pk/model/DTO/PkResultPointsDTO.java @@ -0,0 +1,9 @@ +package vvpkassistant.pk.model.DTO; + +import lombok.Data; + +@Data +public class PkResultPointsDTO { + private Integer winnerUserId; + private Integer loserUserId; +} diff --git a/src/main/java/vvpkassistant/pk/service/PKServiceImpl.java b/src/main/java/vvpkassistant/pk/service/PKServiceImpl.java index 70529ea..3420aa8 100644 --- a/src/main/java/vvpkassistant/pk/service/PKServiceImpl.java +++ b/src/main/java/vvpkassistant/pk/service/PKServiceImpl.java @@ -4,8 +4,6 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; import vvpkassistant.CoinRecords.CoinRecords; import vvpkassistant.CoinRecords.CoinRecordsDao; -import vvpkassistant.Data.ResponseData; -import vvpkassistant.Data.ResponseInfo; import vvpkassistant.Tools.VVTools; import vvpkassistant.User.mapper.UserDao; import vvpkassistant.User.model.UserModel; @@ -242,4 +240,5 @@ public class PKServiceImpl extends ServiceImpl implement return pkInfoModel; } } + } diff --git a/src/main/java/vvpkassistant/pk/service/PkResultPointService.java b/src/main/java/vvpkassistant/pk/service/PkResultPointService.java new file mode 100644 index 0000000..8cc6174 --- /dev/null +++ b/src/main/java/vvpkassistant/pk/service/PkResultPointService.java @@ -0,0 +1,7 @@ +package vvpkassistant.pk.service; + +import vvpkassistant.pk.model.DTO.PkResultPointsDTO; + +public interface PkResultPointService { + String grantPkResultPoints(PkResultPointsDTO request); +} diff --git a/src/main/java/vvpkassistant/pk/service/PkResultPointServiceImpl.java b/src/main/java/vvpkassistant/pk/service/PkResultPointServiceImpl.java new file mode 100644 index 0000000..12528d3 --- /dev/null +++ b/src/main/java/vvpkassistant/pk/service/PkResultPointServiceImpl.java @@ -0,0 +1,85 @@ +package vvpkassistant.pk.service; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import vvpkassistant.CoinRecords.CoinRecords; +import vvpkassistant.CoinRecords.CoinRecordsDao; +import vvpkassistant.Tools.EpochSecondProvider; +import vvpkassistant.User.mapper.UserDao; +import vvpkassistant.common.ErrorCode; +import vvpkassistant.config.FunctionConfigProvider; +import vvpkassistant.exception.BusinessException; +import vvpkassistant.pk.model.DTO.PkResultPointsDTO; + +@Service +public class PkResultPointServiceImpl implements PkResultPointService { + + private static final String PK_WIN_COIN_CONFIG_NAME = "PK胜利增加积分"; + private static final String PK_LOSE_COIN_CONFIG_NAME = "PK失败增加积分"; + private static final int COIN_RECORD_ADD = 1; + + private final UserDao userDao; + private final CoinRecordsDao coinRecordsDao; + private final FunctionConfigProvider functionConfigProvider; + private final EpochSecondProvider epochSecondProvider; + + public PkResultPointServiceImpl( + UserDao userDao, + CoinRecordsDao coinRecordsDao, + FunctionConfigProvider functionConfigProvider, + EpochSecondProvider epochSecondProvider + ) { + this.userDao = userDao; + this.coinRecordsDao = coinRecordsDao; + this.functionConfigProvider = functionConfigProvider; + this.epochSecondProvider = epochSecondProvider; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public String grantPkResultPoints(PkResultPointsDTO request) { + validateRequest(request); + int now = (int) epochSecondProvider.nowEpochSecond(); + int winPoints = parsePositivePoints(PK_WIN_COIN_CONFIG_NAME); + int losePoints = parsePositivePoints(PK_LOSE_COIN_CONFIG_NAME); + + grantPoints(request.getWinnerUserId(), winPoints, PK_WIN_COIN_CONFIG_NAME, now); + grantPoints(request.getLoserUserId(), losePoints, PK_LOSE_COIN_CONFIG_NAME, now); + return String.format("操作成功,胜利方增加%d积分,失败方增加%d积分", winPoints, losePoints); + } + + private static void validateRequest(PkResultPointsDTO request) { + if (request == null || request.getWinnerUserId() == null || request.getLoserUserId() == null) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空"); + } + if (request.getWinnerUserId().equals(request.getLoserUserId())) { + throw new BusinessException(ErrorCode.PARAMS_ERROR, "胜利者和失败者不能是同一用户"); + } + } + + private int parsePositivePoints(String configName) { + String value = functionConfigProvider.getValue(configName); + if (value == null) { + throw new BusinessException(ErrorCode.SYSTEM_ERROR, "未配置" + configName); + } + try { + int points = Integer.parseInt(value); + if (points <= 0) { + throw new BusinessException(ErrorCode.SYSTEM_ERROR, configName + "配置错误"); + } + return points; + } catch (NumberFormatException e) { + throw new BusinessException(ErrorCode.SYSTEM_ERROR, configName + "配置错误"); + } + } + + private void grantPoints(int userId, int points, String configName, int now) { + if (userDao.increasePoints(userId, points) != 1) { + throw new BusinessException(ErrorCode.SYSTEM_ERROR, "用户不存在"); + } + CoinRecords coinRecords = new CoinRecords(configName, userId, points, now, COIN_RECORD_ADD); + if (coinRecordsDao.insert(coinRecords) != 1) { + throw new BusinessException(ErrorCode.SYSTEM_ERROR, "积分记录写入失败"); + } + } +} diff --git a/src/test/java/vvpkassistant/pk/service/PkResultPointServiceImplTests.java b/src/test/java/vvpkassistant/pk/service/PkResultPointServiceImplTests.java new file mode 100644 index 0000000..b81fc3a --- /dev/null +++ b/src/test/java/vvpkassistant/pk/service/PkResultPointServiceImplTests.java @@ -0,0 +1,75 @@ +package vvpkassistant.pk.service; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import vvpkassistant.CoinRecords.CoinRecords; +import vvpkassistant.CoinRecords.CoinRecordsDao; +import vvpkassistant.Tools.EpochSecondProvider; +import vvpkassistant.User.mapper.UserDao; +import vvpkassistant.common.ErrorCode; +import vvpkassistant.config.FunctionConfigProvider; +import vvpkassistant.exception.BusinessException; +import vvpkassistant.pk.model.DTO.PkResultPointsDTO; + +import static org.mockito.Mockito.*; + +class PkResultPointServiceImplTests { + + @Test + void shouldGrantWinAndLosePointsTogether() { + UserDao userDao = mock(UserDao.class); + CoinRecordsDao coinRecordsDao = mock(CoinRecordsDao.class); + FunctionConfigProvider functionConfigProvider = mock(FunctionConfigProvider.class); + EpochSecondProvider epochSecondProvider = () -> 1_234L; + + when(functionConfigProvider.getValue("PK胜利增加积分")).thenReturn("8"); + when(functionConfigProvider.getValue("PK失败增加积分")).thenReturn("3"); + when(userDao.increasePoints(1001, 8)).thenReturn(1); + when(userDao.increasePoints(1002, 3)).thenReturn(1); + when(coinRecordsDao.insert(any())).thenReturn(1); + + PkResultPointServiceImpl service = new PkResultPointServiceImpl( + userDao, coinRecordsDao, functionConfigProvider, epochSecondProvider + ); + PkResultPointsDTO request = new PkResultPointsDTO(); + request.setWinnerUserId(1001); + request.setLoserUserId(1002); + + String result = service.grantPkResultPoints(request); + + Assertions.assertEquals("操作成功,胜利方增加8积分,失败方增加3积分", result); + ArgumentCaptor captor = ArgumentCaptor.forClass(CoinRecords.class); + verify(coinRecordsDao, times(2)).insert(captor.capture()); + Assertions.assertEquals("PK胜利增加积分", captor.getAllValues().get(0).getInfo()); + Assertions.assertEquals(Integer.valueOf(1001), captor.getAllValues().get(0).getUserId()); + Assertions.assertEquals(Integer.valueOf(8), captor.getAllValues().get(0).getNumber()); + Assertions.assertEquals("PK失败增加积分", captor.getAllValues().get(1).getInfo()); + Assertions.assertEquals(Integer.valueOf(1002), captor.getAllValues().get(1).getUserId()); + Assertions.assertEquals(Integer.valueOf(3), captor.getAllValues().get(1).getNumber()); + Assertions.assertEquals(Integer.valueOf(1234), captor.getAllValues().get(0).getTime()); + Assertions.assertEquals(Integer.valueOf(1234), captor.getAllValues().get(1).getTime()); + } + + @Test + void shouldFailWhenWinnerAndLoserAreSameUser() { + UserDao userDao = mock(UserDao.class); + CoinRecordsDao coinRecordsDao = mock(CoinRecordsDao.class); + FunctionConfigProvider functionConfigProvider = mock(FunctionConfigProvider.class); + EpochSecondProvider epochSecondProvider = () -> 1_234L; + + PkResultPointServiceImpl service = new PkResultPointServiceImpl( + userDao, coinRecordsDao, functionConfigProvider, epochSecondProvider + ); + PkResultPointsDTO request = new PkResultPointsDTO(); + request.setWinnerUserId(1001); + request.setLoserUserId(1001); + + BusinessException ex = Assertions.assertThrows(BusinessException.class, + () -> service.grantPkResultPoints(request)); + + Assertions.assertEquals(ErrorCode.PARAMS_ERROR.getCode(), ex.getCode()); + verifyNoInteractions(functionConfigProvider, coinRecordsDao); + verify(userDao, never()).increasePoints(anyInt(), anyInt()); + } +}