Compare commits
11 Commits
c985d14181
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| d24365234c | |||
| a7a093c48b | |||
| 37ebde7b9d | |||
| 79d541e4df | |||
| 3fdd75a5df | |||
| 8b8bfc4b6f | |||
| 57796a6ed1 | |||
| be1a488430 | |||
| f8715bd5df | |||
| 5bf27ed459 | |||
| 994d71a10c |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -28,3 +28,4 @@ replay_pid*
|
||||
/target/
|
||||
/AGENTS.md
|
||||
/.xcodemap/
|
||||
/src/test/
|
||||
|
||||
BIN
.idea/.cache/.Apifox_Helper/.toolWindow.db
generated
BIN
.idea/.cache/.Apifox_Helper/.toolWindow.db
generated
Binary file not shown.
5
.idea/ApifoxUploaderProjectSetting.xml
generated
5
.idea/ApifoxUploaderProjectSetting.xml
generated
File diff suppressed because one or more lines are too long
81
.idea/MyBatisCodeHelperDatasource.xml
generated
81
.idea/MyBatisCodeHelperDatasource.xml
generated
@@ -4,8 +4,87 @@
|
||||
<option name="projectProfile">
|
||||
<ProjectProfile>
|
||||
<option name="controllerTemplateString" value=" #* @vtlvariable name="tableName" type="java.lang.String" *# #* @vtlvariable name="entityPackageName" type="java.lang.String" *# #* @vtlvariable name="entityClassName" type="java.lang.String" *# #* @vtlvariable name="servicePackageName" type="java.lang.String" *# #* @vtlvariable name="serviceInterfacePackage" type="java.lang.String" *# #* @vtlvariable name="serviceClassName" type="java.lang.String" *# #* @vtlvariable name="serviceInterfaceClassName" type="java.lang.String" *# #* @vtlvariable name="mapperPackageName" type="java.lang.String" *# #* @vtlvariable name="mapperClassName" type="java.lang.String" *# #* @vtlvariable name="controllerPackage" type="java.lang.String" *# #* @vtlvariable name="tableRemark" type="java.lang.String" *# #* @vtlvariable name="myDate" type="java.util.Date" *# #* @vtlvariable name="simpleDateFormat" type="java.text.SimpleDateFormat" *# package $!{controllerPackage}; import $!{entityPackageName}.$!{entityClassName}; ###set($realServiceName = $!{serviceClassName}+'Impl') import $!{servicePackageName}.$!{serviceClassName}; import org.springframework.web.bind.annotation.*; #set($serviceFirstLower = $!{serviceClassName.substring(0,1).toLowerCase()}+$!{serviceClassName.substring(1,$!{serviceClassName.length()})}) import org.springframework.beans.factory.annotation.Autowired; /** * $!{tableRemark}($!{tableName})表控制层 * * @author xxxxx */ @RestController @RequestMapping("/$!{tableName}") public class $!{entityClassName}Controller { /** * 服务对象 */ @Autowired private $!{serviceClassName} $!{serviceFirstLower}; /** * 通过主键查询单条数据 * * @param id 主键 * @return 单条数据 */ @GetMapping("selectOne") public $!{entityClassName} selectOne(Integer id) { return $!{serviceFirstLower}.selectByPrimaryKey(id); } }" />
|
||||
<option name="generatedClassPathList">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/src/main/java/vvpkassistant/User/model" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="javaMapperPackage" value="vvpkassistant.iterm_recoder" />
|
||||
<option name="javaMapperPath" value="$PROJECT_DIR$/src/main/java" />
|
||||
<option name="javaModelPackage" value="vvpkassistant.iterm_recoder" />
|
||||
<option name="javaModelPath" value="$PROJECT_DIR$/src/main/java" />
|
||||
<option name="lastDatabaseCrudChooseModuleName" value="vvPkAssistant" />
|
||||
<option name="moduleNameToPackageAndPathMap">
|
||||
<map>
|
||||
<entry key="vvPkAssistant">
|
||||
<value>
|
||||
<UserPackageAndPathInfoByModule>
|
||||
<option name="javaMapperPackage" value="vvpkassistant.iterm_recoder" />
|
||||
<option name="javaMapperPath" value="$PROJECT_DIR$/src/main/java" />
|
||||
<option name="javaModelPacakge" value="vvpkassistant.iterm_recoder" />
|
||||
<option name="javaModelPath" value="$PROJECT_DIR$/src/main/java" />
|
||||
<option name="javaServiceInterfacePath" value="$PROJECT_DIR$/src/main/java" />
|
||||
<option name="javaServicePath" value="$PROJECT_DIR$/src/main/java" />
|
||||
<option name="xmlPackage" value="mapper" />
|
||||
<option name="xmlPath" value="$PROJECT_DIR$/src/main/resources" />
|
||||
</UserPackageAndPathInfoByModule>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<option name="mybatisPlusIdType" value="AUTO" />
|
||||
<option name="tableGenerateConfigs">
|
||||
<map>
|
||||
<entry key="ruoyi-vue-pro:pk_item">
|
||||
<value>
|
||||
<TableGenerateConfig>
|
||||
<option name="generatedKey" value="" />
|
||||
<option name="javaModelName" value="PkItem" />
|
||||
<option name="moduleName" value="vvPkAssistant" />
|
||||
<option name="mybatisplusIdType" value="INPUT" />
|
||||
<option name="sequenceColumn" value="" />
|
||||
<option name="sequenceId" value="" />
|
||||
<option name="useActualColumnName" value="false" />
|
||||
</TableGenerateConfig>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="ruoyi-vue-pro:pk_item_recoder">
|
||||
<value>
|
||||
<TableGenerateConfig>
|
||||
<option name="generatedKey" value="" />
|
||||
<option name="javaModelName" value="PkItemRecoder" />
|
||||
<option name="moduleName" value="vvPkAssistant" />
|
||||
<option name="mybatisplusIdType" value="AUTO" />
|
||||
<option name="sequenceColumn" value="" />
|
||||
<option name="sequenceId" value="" />
|
||||
<option name="useActualColumnName" value="false" />
|
||||
</TableGenerateConfig>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="ruoyi-vue-pro:system_tenant">
|
||||
<value>
|
||||
<TableGenerateConfig>
|
||||
<option name="generatedKey" value="id" />
|
||||
<option name="javaModelName" value="SystemTenant" />
|
||||
<option name="moduleName" value="vvPkAssistant" />
|
||||
<option name="mybatisplusIdType" value="AUTO" />
|
||||
<option name="sequenceColumn" value="" />
|
||||
<option name="sequenceId" value="" />
|
||||
<option name="useActualColumnName" value="false" />
|
||||
</TableGenerateConfig>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="ruoyi-vue-pro:system_users">
|
||||
<value>
|
||||
<TableGenerateConfig>
|
||||
<option name="generatedKey" value="id" />
|
||||
<option name="javaModelName" value="SystemUsers" />
|
||||
<option name="sequenceColumn" value="" />
|
||||
<option name="sequenceId" value="" />
|
||||
<option name="useActualColumnName" value="false" />
|
||||
</TableGenerateConfig>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="vv_assistant:user">
|
||||
<value>
|
||||
<TableGenerateConfig>
|
||||
@@ -19,6 +98,8 @@
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<option name="xmlMapperPackage" value="mapper" />
|
||||
<option name="xmlMapperPath" value="$PROJECT_DIR$/src/main/resources" />
|
||||
</ProjectProfile>
|
||||
</option>
|
||||
</component>
|
||||
|
||||
13
pom.xml
13
pom.xml
@@ -98,19 +98,6 @@
|
||||
<version>2.8.9</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 日志 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>2.20.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.20.0</version>
|
||||
</dependency>
|
||||
|
||||
<!--腾讯云存储-->
|
||||
<dependency>
|
||||
<groupId>com.qcloud</groupId>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package vvpkassistant.Tools;
|
||||
|
||||
public interface EpochSecondProvider {
|
||||
long nowEpochSecond();
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package vvpkassistant.Tools;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class LogUtil {
|
||||
// 获取 Logger 实例
|
||||
private static final Logger logger = LogManager.getLogger(LogUtil.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(LogUtil.class);
|
||||
|
||||
// 封装不同级别的日志方法
|
||||
public static void trace(String message) {
|
||||
logger.trace(message);
|
||||
}
|
||||
@@ -28,10 +27,9 @@ public class LogUtil {
|
||||
}
|
||||
|
||||
public static void fatal(String message) {
|
||||
logger.fatal(message);
|
||||
logger.error(message);
|
||||
}
|
||||
|
||||
// 记录异常信息
|
||||
public static void error(String message, Throwable throwable) {
|
||||
logger.error(message, throwable);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package vvpkassistant.Tools;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SystemEpochSecondProvider implements EpochSecondProvider {
|
||||
@Override
|
||||
public long nowEpochSecond() {
|
||||
return VVTools.currentTimeStamp();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ import java.util.Map;
|
||||
************************/
|
||||
public class VVTools {
|
||||
|
||||
private static final long SECONDS_PER_HOUR = 3600L;
|
||||
|
||||
// 获取当前时间戳
|
||||
public static long currentTimeStamp() {
|
||||
long timeStamp = Calendar.getInstance().getTimeInMillis() / 1000;
|
||||
@@ -117,12 +119,12 @@ public class VVTools {
|
||||
public static long calculateHoursRound(long expireTime, long currentTime) {
|
||||
if (expireTime <= currentTime) return 0;
|
||||
long diffSeconds = expireTime - currentTime;
|
||||
return diffSeconds / 3600;
|
||||
return (diffSeconds + SECONDS_PER_HOUR - 1) / SECONDS_PER_HOUR;
|
||||
}
|
||||
|
||||
// 返还积分用(不足1小时忽略)
|
||||
public static long calculateHoursFloor(long expireTime, long currentTime) {
|
||||
if (expireTime <= currentTime) return 0;
|
||||
return (expireTime - currentTime) / 3600;
|
||||
return (expireTime - currentTime) / SECONDS_PER_HOUR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,21 @@ import vvpkassistant.User.model.UserModel;
|
||||
@Mapper
|
||||
public interface UserDao extends BaseMapper<UserModel> {
|
||||
|
||||
// 原子扣减积分:当 points >= cost 时扣减,返回受影响行数(1=成功,0=积分不足/用户不存在)
|
||||
default int decreasePointsIfEnough(Integer userId, int cost) {
|
||||
return update(null, Wrappers.<UserModel>lambdaUpdate()
|
||||
.eq(UserModel::getId, userId)
|
||||
.ge(UserModel::getPoints, cost)
|
||||
.setSql("points = points - " + cost));
|
||||
}
|
||||
|
||||
// 原子增加积分:返回受影响行数(1=成功,0=用户不存在)
|
||||
default int increasePoints(Integer userId, int amount) {
|
||||
return update(null, Wrappers.<UserModel>lambdaUpdate()
|
||||
.eq(UserModel::getId, userId)
|
||||
.setSql("points = points + " + amount));
|
||||
}
|
||||
|
||||
// 根据用户的手机号查询用户
|
||||
default UserModel queryWithPhoneNumber(String phoneNumber) {
|
||||
return selectOne(Wrappers.<UserModel>lambdaQuery()
|
||||
|
||||
@@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@TableName("system_users")
|
||||
public class UserModel {
|
||||
@@ -15,4 +17,99 @@ public class UserModel {
|
||||
private Integer status; // 用户状态 0 正常 其他业务逻辑待定
|
||||
private String userChatId; // 聊天使用的id,使用微信的openid作为标识
|
||||
private Integer points; // 用户积分
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 岗位编号数组
|
||||
*/
|
||||
private String postIds;
|
||||
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
private String email;
|
||||
/**
|
||||
* 用户性别
|
||||
*/
|
||||
private Byte sex;
|
||||
|
||||
/**
|
||||
* 头像地址
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 最后登录IP
|
||||
*/
|
||||
private String loginIp;
|
||||
|
||||
/**
|
||||
* 最后登录时间
|
||||
*/
|
||||
private Date loginDate;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String creator;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updater;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 能否登录主播爬虫客户端
|
||||
*/
|
||||
private Byte crawl;
|
||||
|
||||
/**
|
||||
* 能否登录大哥爬虫客户端
|
||||
*/
|
||||
private Byte bigBrother;
|
||||
|
||||
/**
|
||||
* 能否登录网页 AI
|
||||
*/
|
||||
private Byte webAi;
|
||||
|
||||
}
|
||||
|
||||
@@ -14,34 +14,5 @@ import vvpkassistant.mail.model.MailModel;
|
||||
* @date: 2025/8/4 16:19
|
||||
*/
|
||||
public interface UserService extends IService<UserModel> {
|
||||
// UserModelVO loginWithMail(UserModelDTO model);
|
||||
//
|
||||
// UserModelVO updateUserInfo(UserModelDTO userModelDTO);
|
||||
//
|
||||
// UserModelVO addUserWithMail(UserModelDTO model);
|
||||
//
|
||||
// Boolean activateAccount(String token);
|
||||
//
|
||||
// Boolean verificationMail(String token);
|
||||
//
|
||||
// Object generatedQrcode();
|
||||
//
|
||||
// Object checkQrcode(String uuid);
|
||||
//
|
||||
// LoginInfoDTO scanQrcode(ScanInfoDTO scanInfoDTO);
|
||||
//
|
||||
// void confirm(ScanInfoDTO scanInfoDTO);
|
||||
//
|
||||
// void logOut(Integer id);
|
||||
//
|
||||
// boolean setPassWord(UserModelDTO userModelDTO);
|
||||
//
|
||||
// Object sendForgetPassWordMail(MailModel mailModel);
|
||||
//
|
||||
// Object resetPassWord(UserModelDTO userModelDTO);
|
||||
//
|
||||
// Boolean updateUserMail(MailModel mailModel);
|
||||
//
|
||||
// Boolean checkUserName(UserModelDTO userModelDTO);
|
||||
|
||||
}
|
||||
|
||||
@@ -56,324 +56,4 @@ public class UserServiceImpl extends ServiceImpl<UserDao, UserModel> implements
|
||||
.expireAfterWrite(2, TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// @Override
|
||||
// public UserModelVO loginWithMail(UserModelDTO model) {
|
||||
// if (model.getUserNameOrEmail().isEmpty()){
|
||||
// throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户名或邮箱不能为空");
|
||||
// }
|
||||
//
|
||||
// LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
// lambdaQueryWrapper.eq(UserModel::getEmail,model.getUserNameOrEmail())
|
||||
// .or()
|
||||
// .eq(UserModel::getUserName,model.getUserNameOrEmail())
|
||||
// .in(UserModel::getStatus, 0,2);
|
||||
//
|
||||
// UserModel userModel = userDao.selectOne(lambdaQueryWrapper);
|
||||
// if (userModel == null) {
|
||||
// throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
// }
|
||||
//
|
||||
// String password = userModel.getPassword();
|
||||
// UserModelVO userModelVO = BeanUtil.copyProperties(userModel, UserModelVO.class);
|
||||
// if (BcryptUtils.matchPassword(password, model.getPassword())) {
|
||||
// StpUtil.login(userModel.getId());
|
||||
// userModelVO.setToken(StpUtil.getTokenValue());
|
||||
// userModelVO.setChatInfo(wxChatParam);
|
||||
// return userModelVO;
|
||||
// }else {
|
||||
// throw new BusinessException(ErrorCode.PASSWORD_ERROR);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public UserModelVO updateUserInfo(UserModelDTO userModelDTO) {
|
||||
//
|
||||
// UserModel userInfo = userDao.selectById(userModelDTO.getId());
|
||||
// if (userInfo == null) {
|
||||
// throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
// }
|
||||
//// 用户没有密码的情况下设置密码
|
||||
// if (userInfo.getPassword() == null && userModelDTO.getNewPassword() != null) {
|
||||
// if (!userModelDTO.getNewPassword().isEmpty()){
|
||||
// if (userModelDTO.getNewPassword().length()<6){
|
||||
// throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位");
|
||||
// }
|
||||
// userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getNewPassword()));
|
||||
// }
|
||||
// }
|
||||
// if (userModelDTO.getEmail() != null) {
|
||||
// mailService.sendVerificationMail(userModelDTO.getEmail(), userModelDTO.getId());
|
||||
// }
|
||||
//
|
||||
//// 用户有密码的情况下重新设置密码
|
||||
// if (userInfo.getPassword() != null && userModelDTO.getOldPassword() != null) {
|
||||
// if (BcryptUtils.matchPassword(userInfo.getPassword(),userModelDTO.getOldPassword())) {
|
||||
// userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getNewPassword()));
|
||||
// }else {
|
||||
// throw new BusinessException(ErrorCode.PASSWORD_ERROR,"旧密码不正确");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// UserModel userModel = BeanUtil.copyProperties(userModelDTO, UserModel.class);
|
||||
// int i = userDao.updateById(userModel);
|
||||
// // 返回结果
|
||||
// UserModel afterUserInfo = userDao.selectById(userModel.getId());
|
||||
// UserModelVO userModelVO = BeanUtil.copyProperties(afterUserInfo, UserModelVO.class);
|
||||
// userModelVO.setNewAccount(false);
|
||||
// if (i == 1){
|
||||
// return userModelVO;
|
||||
// }else {
|
||||
// throw new BusinessException(ErrorCode.SYSTEM_ERROR);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public UserModelVO addUserWithMail(UserModelDTO userModelDTO) {
|
||||
// LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
//
|
||||
//
|
||||
// LambdaQueryWrapper<UserModel> usernameWrapper = new LambdaQueryWrapper<>();
|
||||
//
|
||||
// lambdaQueryWrapper.eq(UserModel::getEmail,userModelDTO.getEmail());
|
||||
// UserModel userModel = userDao.selectOne(lambdaQueryWrapper);
|
||||
//
|
||||
//
|
||||
// UserModel usernameModel = userDao.selectOne(usernameWrapper
|
||||
// .eq(UserModel::getUserName, userModelDTO.getUserName()));
|
||||
//
|
||||
// if (userModel != null) {
|
||||
// throw new BusinessException(ErrorCode.MAIL_ALREADY_EXIST);
|
||||
// }
|
||||
// if (usernameModel != null) {
|
||||
// throw new BusinessException(ErrorCode.USERNAME_ALREADY_EXIST);
|
||||
// }
|
||||
// if (userModelDTO.getPassword().length() < 6 ){
|
||||
// throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位");
|
||||
// }
|
||||
// if (userModelDTO.getUserName().isEmpty()){
|
||||
// throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户名不能为空");
|
||||
// }
|
||||
//
|
||||
// userModelDTO.setPassword(BcryptUtils.encryptPassword(userModelDTO.getPassword()));
|
||||
// userModelDTO.setCreateTime(VVTools.currentTimeStamp());
|
||||
// //设置状态为待验证
|
||||
// userModelDTO.setStatus(2);
|
||||
// //设置积分为0
|
||||
// userModelDTO.setPoints(0);
|
||||
// UserModel userModelEntity = BeanUtil.copyProperties(userModelDTO, UserModel.class);
|
||||
// userModelEntity.setMailVerification(1);
|
||||
// if ( userDao.insert(userModelEntity) != 1){
|
||||
// throw new BusinessException(ErrorCode.ADD_FAILED,"用户注册失败");
|
||||
// }
|
||||
// mailService.sendMail(userModelDTO.getEmail(),userModelEntity.getId());
|
||||
// // 判断用户是否为邀请用户
|
||||
// if (userModelDTO.getInviterId() != null) {
|
||||
// UserModel oldUser = userDao.selectById(userModelDTO.getInviterId());
|
||||
// oldUser.setPoints(oldUser.getPoints() + 10);
|
||||
// userDao.updateById(oldUser);
|
||||
// }
|
||||
// UserModelVO userModelVO = BeanUtil.copyProperties(userModelEntity, UserModelVO.class);
|
||||
// StpUtil.login(userModelVO.getId());
|
||||
// userModelVO.setToken(StpUtil.getTokenValue());
|
||||
// userModelVO.setHavaPassword(true);
|
||||
// userModelVO.setNewAccount(true);
|
||||
// userModelVO.setChatInfo(wxChatParam);
|
||||
// log.info("用户{}注册,邮箱{},手机号{}",userModelVO.getId(),userModelVO.getEmail(),userModelVO.getPhoneNumber());
|
||||
// return userModelVO;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Boolean activateAccount(String token) {
|
||||
// Integer userId = SaTempUtil.parseToken(token, Integer.class);
|
||||
// UserModel userModel = userDao.selectById(userId);
|
||||
// if (userModel == null) {
|
||||
// throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
// }
|
||||
// if (userModel.getStatus() == 0){
|
||||
// throw new BusinessException(ErrorCode.USER_HAS_ACTIVATED);
|
||||
// }
|
||||
// userModel.setStatus(0);
|
||||
// userModel.setMailVerification(0);
|
||||
// if (userDao.updateById(userModel) == 1){
|
||||
// return true;
|
||||
// }else {
|
||||
// throw new BusinessException(ErrorCode.UPDATE_FAILED,"激活失败");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Boolean verificationMail(String token) {
|
||||
// Integer userId = SaTempUtil.parseToken(token, Integer.class);
|
||||
// UserModel userModel = userDao.selectById(userId);
|
||||
// userModel.setMailVerification(0);
|
||||
// if (userDao.updateById(userModel) == 1){
|
||||
// return true;
|
||||
// }
|
||||
// throw new BusinessException(ErrorCode.SYSTEM_ERROR,"邮箱验证失败");
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public QrcodeVO generatedQrcode() {
|
||||
// String uuid = UUID.randomUUID().toString();
|
||||
// QrcodeEntity qrcodeEntity = new QrcodeEntity();
|
||||
// qrcodeEntity.setUuid(uuid);
|
||||
// qrcodeEntity.setType("qrcdoe");
|
||||
// String base64QR = null;
|
||||
// try {
|
||||
// base64QR = QRCodeUtil.generateQRCode(JSONUtil.toJsonStr(qrcodeEntity), 200, 200);
|
||||
// } catch (WriterException | IOException e) {
|
||||
// log.error(e.getMessage());
|
||||
// throw new BusinessException(ErrorCode.SYSTEM_ERROR,"二维码生成失败");
|
||||
// }
|
||||
//
|
||||
// LoginInfoDTO loginInfoDTO = new LoginInfoDTO();
|
||||
// loginInfoDTO.setStatus(LoginStatusEnum.UNSCANNED.name());
|
||||
// loginInfoDTO.setUuid(uuid);
|
||||
//
|
||||
// // 二维码uuid绑定,存入缓存
|
||||
// qrcodeCache.put(uuid,loginInfoDTO);
|
||||
// // 返回生成的二维码信息
|
||||
// QrcodeVO vo = QrcodeVO.builder().uuid(uuid).qrcode("data:image/png;base64," + base64QR).build();
|
||||
// log.info("-------生成二维码成功:{}-------", uuid);
|
||||
// return vo;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Object checkQrcode(String uuid) {
|
||||
// LoginInfoDTO loginInfoDTO = qrcodeCache.getIfPresent(uuid);
|
||||
// if (loginInfoDTO == null) {
|
||||
// throw new BusinessException(ErrorCode.QRCODE_EXPIRED);
|
||||
// }
|
||||
// if (Objects.equals(loginInfoDTO.getStatus(), LoginStatusEnum.SCANNED.name())) {
|
||||
// return loginInfoDTO;
|
||||
// }
|
||||
// if (LoginStatusEnum.CONFIRMED.name().equals(loginInfoDTO.getStatus())) {
|
||||
// UserModel userModel = userDao.selectById(loginInfoDTO.getId());
|
||||
// StpUtil.login(userModel.getId());
|
||||
// UserModelVO userModelVO = BeanUtil.copyProperties(userModel, UserModelVO.class);
|
||||
// userModelVO.setToken(StpUtil.getTokenValue());
|
||||
// userModelVO.setChatInfo(wxChatParam);
|
||||
// return userModelVO;
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public LoginInfoDTO scanQrcode(ScanInfoDTO scanInfoDTO) {
|
||||
// LoginInfoDTO loginInfoDTO = qrcodeCache.getIfPresent(scanInfoDTO.getUuid());
|
||||
// if (loginInfoDTO != null) {
|
||||
// loginInfoDTO.setStatus(LoginStatusEnum.SCANNED.name());
|
||||
// qrcodeCache.put(scanInfoDTO.getUuid(),loginInfoDTO);
|
||||
// }
|
||||
// log.info("-------扫码成功uuid:{}-------", scanInfoDTO.getUuid());
|
||||
// return loginInfoDTO;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void confirm(ScanInfoDTO scanInfoDTO) {
|
||||
// LoginInfoDTO loginInfoDTO = qrcodeCache.getIfPresent(scanInfoDTO.getUuid());
|
||||
// if (loginInfoDTO != null) {
|
||||
// loginInfoDTO.setStatus(LoginStatusEnum.CONFIRMED.name());
|
||||
// loginInfoDTO.setId(scanInfoDTO.getId());
|
||||
// qrcodeCache.put(scanInfoDTO.getUuid(),loginInfoDTO);
|
||||
// }
|
||||
// log.info("-------确认登录成功uuid:{}-------", scanInfoDTO.getUuid());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void logOut(Integer id) {
|
||||
// StpUtil.logout(id);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean setPassWord(UserModelDTO userModelDTO) {
|
||||
// UserModel userModel = userDao.selectById(userModelDTO.getId());
|
||||
// if (userModel == null) {
|
||||
// throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
// }
|
||||
// if (userModel.getPassword()!= null){
|
||||
// throw new BusinessException(ErrorCode.SYSTEM_ERROR,"已设置过密码");
|
||||
// }
|
||||
// if (userModelDTO.getPassword().length()< 6 ){
|
||||
// throw new BusinessException(ErrorCode.PARAMS_ERROR,"密码长度不能小于 6 位");
|
||||
// }
|
||||
// if (!Objects.equals(userModelDTO.getPassword(), userModelDTO.getConfirmPassword())) {
|
||||
// log.error("密码{},确认密码{}",userModelDTO.getPassword(),userModelDTO.getConfirmPassword());
|
||||
// throw new BusinessException(ErrorCode.PARAMS_ERROR,"两次密码输入不一致");
|
||||
// }else{
|
||||
// UserModel saveEntity = BeanUtil.copyProperties(userModelDTO, UserModel.class);
|
||||
// saveEntity.setPassword(BcryptUtils.encryptPassword(userModelDTO.getPassword()));
|
||||
// return userDao.updateById(saveEntity) == 1 ;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Object sendForgetPassWordMail(MailModel mailModel) {
|
||||
// LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
// UserModel userModel = userDao.selectOne(lambdaQueryWrapper
|
||||
// .eq(UserModel::getEmail, mailModel.getMailAddress())
|
||||
// .eq(UserModel::getStatus, 0)
|
||||
// .eq(UserModel::getMailVerification, 0));
|
||||
// if (userModel == null) {
|
||||
// throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
// }
|
||||
//
|
||||
// mailService.sendForgetPassWordMail(mailModel.getMailAddress(),userModel.getId());
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Object resetPassWord(UserModelDTO userModelDTO) {
|
||||
// Integer i = SaTempUtil.parseToken(userModelDTO.getToken(), Integer.class);
|
||||
// UserModel userModel = userDao.selectById(i);
|
||||
// if (userModel == null) {
|
||||
// throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
// }
|
||||
// if (userModelDTO.getPassword().equals(userModelDTO.getConfirmPassword())) {
|
||||
// userModel.setPassword(BcryptUtils.encryptPassword(userModelDTO.getPassword()));
|
||||
// return userDao.updateById(userModel) == 1;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Boolean updateUserMail(MailModel mailModel) {
|
||||
// String mail = CacheHolder.VERIFICATION_MAIL.getIfPresent(mailModel.getCode());
|
||||
// if (mail != null && mail.isEmpty()) {
|
||||
// throw new BusinessException(ErrorCode.SYSTEM_ERROR,"验证码过期或验证码错误");
|
||||
// }
|
||||
// LambdaQueryWrapper<UserModel> duplicateMailUserWrapper = new LambdaQueryWrapper<>();
|
||||
//
|
||||
// LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
//
|
||||
// UserModel duplicateMailUser = userDao.selectOne(duplicateMailUserWrapper
|
||||
// .eq(UserModel::getEmail, mailModel.getMailAddress()));
|
||||
// if (duplicateMailUser != null) {
|
||||
// throw new BusinessException(ErrorCode.SYSTEM_ERROR,"邮箱地址已被使用");
|
||||
// }
|
||||
//
|
||||
// UserModel userModel = userDao.selectOne(lambdaQueryWrapper
|
||||
// .eq(UserModel::getEmail, mail)
|
||||
// .eq(UserModel::getMailVerification, 0 ));
|
||||
//
|
||||
// if (userModel == null) {
|
||||
// throw new BusinessException(ErrorCode.USER_MAIL_NOT_VERIFICATION);
|
||||
// }
|
||||
// userModel.setEmail(mailModel.getMailAddress());
|
||||
// mailService.sendVerificationMail(mailModel.getMailAddress(),userModel.getId());
|
||||
// userModel.setMailVerification(1);
|
||||
// return userDao.updateById(userModel) == 1;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Boolean checkUserName(UserModelDTO userModelDTO) {
|
||||
// LambdaQueryWrapper<UserModel> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
// UserModel userModel = userDao.selectOne(lambdaQueryWrapper
|
||||
// .eq(UserModel::getUserName, userModelDTO.getUserName()));
|
||||
// return userModel == null;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -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<FunctionConfigModel> CONFIGS = new CopyOnWriteArrayList<>();
|
||||
public static List<FunctionConfigModel> CONFIGS = new CopyOnWriteArrayList<>();
|
||||
|
||||
@Autowired
|
||||
private FunctionConfigMapper configMapper;
|
||||
@@ -26,7 +28,7 @@ public class FunctionConfigHolder {
|
||||
List<FunctionConfigModel> dbConfigs = configMapper.selectList(null);
|
||||
CONFIGS.clear();
|
||||
CONFIGS.addAll(dbConfigs);
|
||||
System.out.println("已加载 "+CONFIGS.size()+" 条功能配置");
|
||||
log.info("已加载 {} 条功能配置", CONFIGS.size());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package vvpkassistant.config;
|
||||
|
||||
public interface FunctionConfigProvider {
|
||||
String getValue(String functionName);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package vvpkassistant.config;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class HolderBackedFunctionConfigProvider implements FunctionConfigProvider {
|
||||
@Override
|
||||
public String getValue(String functionName) {
|
||||
return FunctionConfigHolder.getValue(functionName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,11 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
"/user/inputUserInfo",
|
||||
"/user/resetPassword",
|
||||
"/pk/pkList",
|
||||
"/systemMessage/list"
|
||||
"/systemMessage/list",
|
||||
"/pk/pkListForPython",
|
||||
"/pk/insertPkDetail",
|
||||
"/pk/updatePkRecordInfo",
|
||||
"/pk/grantPkResultPoints"
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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<PkInfoModel> 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<Object> grantPkResultPoints(@RequestBody PkResultPointsDTO request) {
|
||||
return ResponseData.success(pkResultPointService.grantPkResultPoints(request));
|
||||
}
|
||||
|
||||
// 插入pk明细表数据
|
||||
@PostMapping("insertPkDetail")
|
||||
public ResponseData<Object> insert(@RequestBody PkRecordDetail detail) {
|
||||
|
||||
45
src/main/java/vvpkassistant/controller/PkItemController.java
Normal file
45
src/main/java/vvpkassistant/controller/PkItemController.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package vvpkassistant.controller;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
import vvpkassistant.exception.BusinessException;
|
||||
import vvpkassistant.item.model.PkItem;
|
||||
import vvpkassistant.item.model.DTO.PkItemPurchaseDTO;
|
||||
import vvpkassistant.item.service.PkItemPurchaseService;
|
||||
import vvpkassistant.item.service.PkItemService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("pkItem")
|
||||
public class PkItemController {
|
||||
|
||||
@Resource
|
||||
private PkItemService pkItemService;
|
||||
|
||||
@Resource
|
||||
private PkItemPurchaseService pkItemPurchaseService;
|
||||
|
||||
@GetMapping("list")
|
||||
public ResponseData<List<PkItem>> list() {
|
||||
return ResponseData.success(pkItemService.selectItemList());
|
||||
}
|
||||
|
||||
@PostMapping("buy")
|
||||
public ResponseData<Object> buy(@RequestBody PkItemPurchaseDTO request) {
|
||||
if (request == null || request.getItemId() == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "itemId不能为空");
|
||||
}
|
||||
long userId = StpUtil.getLoginIdAsLong();
|
||||
return ResponseData.success(pkItemPurchaseService.purchase(userId, request.getItemId()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import org.springframework.web.bind.annotation.*;
|
||||
import vvpkassistant.CoinRecords.CoinRecords;
|
||||
import vvpkassistant.CoinRecords.CoinRecordsDao;
|
||||
import vvpkassistant.Data.ResponseData;
|
||||
import vvpkassistant.Data.ResponseInfo;
|
||||
import vvpkassistant.Data.WxChatParam;
|
||||
import vvpkassistant.User.mapper.UserDao;
|
||||
import vvpkassistant.User.mapper.SignInRecordDao;
|
||||
@@ -35,6 +34,7 @@ import vvpkassistant.pk.mapper.PkRecordDao;
|
||||
import vvpkassistant.pk.model.PkInfoModel;
|
||||
import vvpkassistant.pk.model.PkRecordDetail;
|
||||
import vvpkassistant.pk.mapper.PkRecordDetailDao;
|
||||
import vvpkassistant.pk.service.PkPinService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
@@ -76,6 +76,9 @@ public class UserController {
|
||||
@Resource
|
||||
private MailService mailService;
|
||||
|
||||
@Resource
|
||||
private PkPinService pkPinService;
|
||||
|
||||
// 配置用户信息
|
||||
@PostMapping("inputUserInfo")
|
||||
public ResponseData<Object> inputUserInfo(@RequestBody UserInputUserInfoDTO param) {
|
||||
@@ -269,13 +272,13 @@ public class UserController {
|
||||
// 签到
|
||||
@PostMapping("signIn")
|
||||
public ResponseData<Object> signIn() {
|
||||
int userId = Integer.parseInt(StpUtil.getLoginId().toString());
|
||||
int i = signInRecordDao.checkSignStatus(userId);
|
||||
long userId = StpUtil.getLoginIdAsLong();
|
||||
int i = signInRecordDao.checkSignStatus((int) userId);
|
||||
if (i != 0) {
|
||||
throw new BusinessException(ErrorCode.SIGN_IN_FAIL);
|
||||
}
|
||||
|
||||
int result = signInRecordDao.signIn(userId);
|
||||
int result = signInRecordDao.signIn((int) userId);
|
||||
UserModel userModel = userDao.selectById(userId);
|
||||
int count = Integer.parseInt(FunctionConfigHolder.getValue("签到增加积分"));
|
||||
|
||||
@@ -287,7 +290,7 @@ public class UserController {
|
||||
|
||||
if (result == 1) {
|
||||
// 增加记录
|
||||
CoinRecords coinRecords = new CoinRecords("签到增加积分",userId,count, (int) VVTools.currentTimeStamp(),1);
|
||||
CoinRecords coinRecords = new CoinRecords("签到增加积分", (int) userId,count, (int) VVTools.currentTimeStamp(),1);
|
||||
coinRecordsDao.insert(coinRecords);
|
||||
return ResponseData.success(null);
|
||||
}else {
|
||||
@@ -305,81 +308,23 @@ public class UserController {
|
||||
// 置顶文章
|
||||
@PostMapping("pinToTop")
|
||||
public ResponseData<Object> pinToTop(@RequestBody UserPinToTopDTO request) {
|
||||
// 文章id
|
||||
Integer articleId = request.getArticleId();
|
||||
PkInfoModel pkInfoModel = pkInfoDao.selectById(articleId);
|
||||
Integer userId = pkInfoModel.getSenderId();
|
||||
// 到期时间戳
|
||||
Integer pinExpireTime = request.getPinExpireTime();
|
||||
|
||||
long currentTimeStamp = VVTools.currentTimeStamp();
|
||||
long hour = VVTools.calculateHoursRound(pinExpireTime, currentTimeStamp);
|
||||
String coin = FunctionConfigHolder.getValue("置顶扣除积分");
|
||||
int totalCoin = (int) (Integer.parseInt(coin) * hour);
|
||||
|
||||
UserModel userModel = userDao.selectById(userId);
|
||||
if (userModel != null) {
|
||||
// 扣除积分 更新数据
|
||||
Integer points = userModel.getPoints();
|
||||
if (points - totalCoin > 0) {
|
||||
userModel.setPoints(userModel.getPoints() - totalCoin);
|
||||
userDao.updateById(userModel);
|
||||
// 设置置顶到期时间
|
||||
pkInfoModel.setPinExpireTime(pinExpireTime);
|
||||
// 设置创建置顶的时间
|
||||
pkInfoModel.setPinCreateTime((int) VVTools.currentTimeStamp());
|
||||
// 更新pk文章数据
|
||||
int i = pkInfoDao.updateById(pkInfoModel);
|
||||
if (i == 1) {
|
||||
String info = String.format("置顶成功,扣除%d积分",totalCoin);
|
||||
// 增加积分变动记录
|
||||
CoinRecords coinRecords = new CoinRecords("置顶扣除积分",userId,totalCoin, (int) VVTools.currentTimeStamp(),0);
|
||||
coinRecordsDao.insert(coinRecords);
|
||||
// 返回给前端数据
|
||||
return ResponseData.success(info);
|
||||
}else {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
}else {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR,String.format("积分不足,需要%d积分",totalCoin));
|
||||
}
|
||||
}else {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR,"用户不存在");
|
||||
if (request == null || request.getArticleId() == null || request.getPinExpireTime() == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
|
||||
}
|
||||
int operatorUserId = Integer.parseInt(StpUtil.getLoginId().toString());
|
||||
String info = pkPinService.pinToTop(operatorUserId, request.getArticleId(), request.getPinExpireTime());
|
||||
return ResponseData.success(info);
|
||||
}
|
||||
|
||||
// 取消置顶
|
||||
@PostMapping("cancelPin")
|
||||
public ResponseData<Object> cancelPin(@RequestBody UserCancelPinDTO request) {
|
||||
Integer articleId = request.getArticleId();
|
||||
PkInfoModel pkInfoModel = pkInfoDao.selectById(articleId);
|
||||
Integer pinExpireTime = pkInfoModel.getPinExpireTime();
|
||||
long hour = VVTools.calculateHoursFloor(pinExpireTime, VVTools.currentTimeStamp());
|
||||
|
||||
String coin = FunctionConfigHolder.getValue("置顶扣除积分");
|
||||
// 计算总积分。用于返还给用户
|
||||
int totalCoin = (int) (Integer.parseInt(coin) * hour);
|
||||
|
||||
// 获取用户对象
|
||||
UserModel userModel = userDao.selectById(pkInfoModel.getSenderId());
|
||||
Integer points = userModel.getPoints();
|
||||
// 返还用户积分
|
||||
userModel.setPoints(points + totalCoin);
|
||||
// 更新数据库
|
||||
userDao.updateById(userModel);
|
||||
|
||||
// 重置置顶时间
|
||||
pkInfoModel.setPinExpireTime(0);
|
||||
pkInfoModel.setPinCreateTime(0);
|
||||
int i = pkInfoDao.updateById(pkInfoModel);
|
||||
if (i == 1) {
|
||||
// 添加积分更变相关记录
|
||||
CoinRecords coinRecords = new CoinRecords("取消置顶返还积分",pkInfoModel.getSenderId(),totalCoin, (int) VVTools.currentTimeStamp(),1);
|
||||
coinRecordsDao.insert(coinRecords);
|
||||
return ResponseData.success(String.format("操作成功,返还%d积分",totalCoin));
|
||||
}else {
|
||||
return ResponseData.error(ResponseInfo.ERROR.getCode(),null);
|
||||
if (request == null || request.getArticleId() == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
|
||||
}
|
||||
int operatorUserId = Integer.parseInt(StpUtil.getLoginId().toString());
|
||||
String info = pkPinService.cancelPin(operatorUserId, request.getArticleId());
|
||||
return ResponseData.success(info);
|
||||
|
||||
}
|
||||
|
||||
|
||||
27
src/main/java/vvpkassistant/item/PkItemMapper.java
Normal file
27
src/main/java/vvpkassistant/item/PkItemMapper.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package vvpkassistant.item;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import vvpkassistant.item.model.PkItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/27 10:13
|
||||
*/
|
||||
@Mapper
|
||||
public interface PkItemMapper {
|
||||
int deleteByPrimaryKey(Long id);
|
||||
|
||||
int insert(PkItem record);
|
||||
|
||||
int insertSelective(PkItem record);
|
||||
|
||||
PkItem selectByPrimaryKey(Long id);
|
||||
|
||||
List<PkItem> selectItemList();
|
||||
|
||||
int updateByPrimaryKeySelective(PkItem record);
|
||||
|
||||
int updateByPrimaryKey(PkItem record);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package vvpkassistant.item.model.DTO;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PkItemPurchaseDTO {
|
||||
|
||||
private Long itemId;
|
||||
}
|
||||
78
src/main/java/vvpkassistant/item/model/PkItem.java
Normal file
78
src/main/java/vvpkassistant/item/model/PkItem.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package vvpkassistant.item.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/27 10:13
|
||||
*/
|
||||
@Data
|
||||
public class PkItem {
|
||||
/**
|
||||
* 主键Id
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 套餐名称
|
||||
*/
|
||||
private String itemName;
|
||||
|
||||
/**
|
||||
* 套餐价格
|
||||
*/
|
||||
private Integer itemPrice;
|
||||
|
||||
/**
|
||||
* 套餐描述
|
||||
*/
|
||||
private String itemDesc;
|
||||
|
||||
/**
|
||||
* 功能
|
||||
*/
|
||||
private String itemFunction;
|
||||
|
||||
/**
|
||||
* 时长
|
||||
*/
|
||||
private Integer itemDuration;
|
||||
|
||||
/**
|
||||
* 是否上架
|
||||
*/
|
||||
private Integer itemStatus;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String creator;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updater;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
private Boolean deleted;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package vvpkassistant.item.service;
|
||||
|
||||
public interface PkItemPurchaseService {
|
||||
|
||||
String purchase(Long userId, Long itemId);
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
package vvpkassistant.item.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.User.model.UserModel;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
import vvpkassistant.exception.BusinessException;
|
||||
import vvpkassistant.item.PkItemMapper;
|
||||
import vvpkassistant.item.model.PkItem;
|
||||
import vvpkassistant.iterm_recoder.mapper.PkItemRecoderMapper;
|
||||
import vvpkassistant.iterm_recoder.model.PkItemRecoder;
|
||||
import vvpkassistant.tenant.mapper.SystemTenantMapper;
|
||||
import vvpkassistant.tenant.model.SystemTenant;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class PkItemPurchaseServiceImpl implements PkItemPurchaseService {
|
||||
|
||||
private static final byte ENABLED = 1;
|
||||
private static final int COIN_RECORD_DEDUCT = 0;
|
||||
private static final long SECONDS_PER_HOUR = 3600L;
|
||||
private static final ZoneId SHANGHAI_ZONE_ID = ZoneId.of("Asia/Shanghai");
|
||||
|
||||
private final PkItemMapper pkItemMapper;
|
||||
private final UserDao userDao;
|
||||
private final SystemTenantMapper systemTenantMapper;
|
||||
private final CoinRecordsDao coinRecordsDao;
|
||||
private final PkItemRecoderMapper pkItemRecoderMapper;
|
||||
private final EpochSecondProvider epochSecondProvider;
|
||||
|
||||
public PkItemPurchaseServiceImpl(
|
||||
PkItemMapper pkItemMapper,
|
||||
UserDao userDao,
|
||||
SystemTenantMapper systemTenantMapper,
|
||||
CoinRecordsDao coinRecordsDao,
|
||||
PkItemRecoderMapper pkItemRecoderMapper,
|
||||
EpochSecondProvider epochSecondProvider
|
||||
) {
|
||||
this.pkItemMapper = pkItemMapper;
|
||||
this.userDao = userDao;
|
||||
this.systemTenantMapper = systemTenantMapper;
|
||||
this.coinRecordsDao = coinRecordsDao;
|
||||
this.pkItemRecoderMapper = pkItemRecoderMapper;
|
||||
this.epochSecondProvider = epochSecondProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String purchase(Long userId, Long itemId) {
|
||||
validateRequest(userId, itemId);
|
||||
PkItem item = loadAvailableItem(itemId);
|
||||
UserModel user = loadUser(userId);
|
||||
ItemFunction function = resolveFunction(item.getItemFunction());
|
||||
long now = epochSecondProvider.nowEpochSecond();
|
||||
|
||||
ensureTenantBound(user);
|
||||
ensureNotPurchasedToday(userId, itemId, now);
|
||||
deductPoints(userId, item.getItemPrice());
|
||||
enableUserFunction(user.getId(), function);
|
||||
extendTenantExpireTime(user.getTenantId(), function, item.getItemDuration(), now);
|
||||
insertConsumeRecord(userId, item, now);
|
||||
insertPurchaseRecord(userId, itemId, now);
|
||||
return "购买成功:" + item.getItemName();
|
||||
}
|
||||
|
||||
private static void validateRequest(Long userId, Long itemId) {
|
||||
if (userId == null || itemId == null) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
private PkItem loadAvailableItem(Long itemId) {
|
||||
PkItem item = pkItemMapper.selectByPrimaryKey(itemId);
|
||||
if (item == null || Boolean.TRUE.equals(item.getDeleted()) || item.getItemStatus() == null || item.getItemStatus() != 0) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "商品不存在或已下架");
|
||||
}
|
||||
if (item.getItemPrice() == null || item.getItemPrice() < 0) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "商品价格配置错误");
|
||||
}
|
||||
if (item.getItemDuration() == null || item.getItemDuration() <= 0) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "商品时长配置错误");
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
private UserModel loadUser(Long userId) {
|
||||
UserModel user = userDao.selectById(userId);
|
||||
if (user == null) {
|
||||
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
private static void ensureTenantBound(UserModel user) {
|
||||
if (user.getTenantId() == null) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "用户未绑定租户");
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureNotPurchasedToday(Long userId, Long itemId, long now) {
|
||||
Map<String, Long> dayRange = todayRangeInShanghai(now);
|
||||
Date startTime = toDate(dayRange.get("start"));
|
||||
Date endTime = toDate(dayRange.get("end"));
|
||||
long count = pkItemRecoderMapper.countTodayPurchase(userId, String.valueOf(itemId), startTime, endTime);
|
||||
if (count > 0) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "该商品今日已购买");
|
||||
}
|
||||
}
|
||||
|
||||
private void deductPoints(Long userId, Integer itemPrice) {
|
||||
int intUserId = toIntId(userId);
|
||||
if (userDao.decreasePointsIfEnough(intUserId, itemPrice) == 1) {
|
||||
return;
|
||||
}
|
||||
if (userDao.selectById(userId) == null) {
|
||||
throw new BusinessException(ErrorCode.USER_DOES_NOT_EXIST);
|
||||
}
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, String.format("积分不足,需要%d积分", itemPrice));
|
||||
}
|
||||
|
||||
private void enableUserFunction(Integer userId, ItemFunction function) {
|
||||
UserModel updateModel = new UserModel();
|
||||
updateModel.setId(userId);
|
||||
switch (function) {
|
||||
case CRAWL:
|
||||
updateModel.setCrawl(ENABLED);
|
||||
break;
|
||||
case WEB_AI:
|
||||
updateModel.setWebAi(ENABLED);
|
||||
break;
|
||||
case BIG_BROTHER:
|
||||
updateModel.setBigBrother(ENABLED);
|
||||
break;
|
||||
default:
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "暂不支持的商品功能");
|
||||
}
|
||||
if (userDao.updateById(updateModel) != 1) {
|
||||
throw new BusinessException(ErrorCode.UPDATE_FAILED, "更新用户功能失败");
|
||||
}
|
||||
}
|
||||
|
||||
private void extendTenantExpireTime(Long tenantId, ItemFunction function, Integer durationHours, long now) {
|
||||
SystemTenant tenant = systemTenantMapper.selectById(tenantId);
|
||||
if (tenant == null || Boolean.TRUE.equals(tenant.getDeleted())) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "租户不存在");
|
||||
}
|
||||
Date expireTime = calculateExpireTime(getExpireTime(tenant, function), durationHours, now);
|
||||
SystemTenant updateModel = new SystemTenant();
|
||||
updateModel.setId(tenantId);
|
||||
applyExpireTime(updateModel, function, expireTime);
|
||||
if (systemTenantMapper.updateById(updateModel) != 1) {
|
||||
throw new BusinessException(ErrorCode.UPDATE_FAILED, "更新租户功能时长失败");
|
||||
}
|
||||
}
|
||||
|
||||
private void insertConsumeRecord(Long userId, PkItem item, long now) {
|
||||
CoinRecords coinRecords = new CoinRecords(
|
||||
"购买商品:" + item.getItemName(),
|
||||
toIntId(userId),
|
||||
item.getItemPrice(),
|
||||
toIntEpoch(now),
|
||||
COIN_RECORD_DEDUCT
|
||||
);
|
||||
if (coinRecordsDao.insert(coinRecords) != 1) {
|
||||
throw new BusinessException(ErrorCode.ADD_FAILED, "写入消费记录失败");
|
||||
}
|
||||
}
|
||||
|
||||
private void insertPurchaseRecord(Long userId, Long itemId, long now) {
|
||||
Date nowDate = toDate(now);
|
||||
PkItemRecoder recoder = new PkItemRecoder();
|
||||
recoder.setUserId(userId);
|
||||
recoder.setItemId(String.valueOf(itemId));
|
||||
recoder.setCreator(String.valueOf(userId));
|
||||
recoder.setCreateTime(nowDate);
|
||||
recoder.setUpdater(String.valueOf(userId));
|
||||
recoder.setUpdateTime(nowDate);
|
||||
recoder.setDeleted(Boolean.FALSE);
|
||||
if (pkItemRecoderMapper.insert(recoder) != 1) {
|
||||
throw new BusinessException(ErrorCode.ADD_FAILED, "写入购买记录失败");
|
||||
}
|
||||
}
|
||||
|
||||
private static Date calculateExpireTime(Date currentExpireTime, Integer durationHours, long now) {
|
||||
long durationSeconds = Math.multiplyExact(durationHours.longValue(), SECONDS_PER_HOUR);
|
||||
long baseEpochSecond = resolveBaseEpochSecond(currentExpireTime, now);
|
||||
return toDate(Math.addExact(baseEpochSecond, durationSeconds));
|
||||
}
|
||||
|
||||
private static long resolveBaseEpochSecond(Date currentExpireTime, long now) {
|
||||
if (currentExpireTime == null) {
|
||||
return now;
|
||||
}
|
||||
return Math.max(currentExpireTime.toInstant().getEpochSecond(), now);
|
||||
}
|
||||
|
||||
private static Date getExpireTime(SystemTenant tenant, ItemFunction function) {
|
||||
switch (function) {
|
||||
case CRAWL:
|
||||
return tenant.getCrawlExpireTime();
|
||||
case WEB_AI:
|
||||
return tenant.getAiExpireTime();
|
||||
case BIG_BROTHER:
|
||||
return tenant.getBrotherExpireTime();
|
||||
default:
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "暂不支持的商品功能");
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyExpireTime(SystemTenant tenant, ItemFunction function, Date expireTime) {
|
||||
switch (function) {
|
||||
case CRAWL:
|
||||
tenant.setCrawlExpireTime(expireTime);
|
||||
return;
|
||||
case WEB_AI:
|
||||
tenant.setAiExpireTime(expireTime);
|
||||
return;
|
||||
case BIG_BROTHER:
|
||||
tenant.setBrotherExpireTime(expireTime);
|
||||
return;
|
||||
default:
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "暂不支持的商品功能");
|
||||
}
|
||||
}
|
||||
|
||||
private static ItemFunction resolveFunction(String itemFunction) {
|
||||
if ("crawl".equalsIgnoreCase(itemFunction)) {
|
||||
return ItemFunction.CRAWL;
|
||||
}
|
||||
if ("webAi".equalsIgnoreCase(itemFunction) || "web_ai".equalsIgnoreCase(itemFunction) || "ai".equalsIgnoreCase(itemFunction)) {
|
||||
return ItemFunction.WEB_AI;
|
||||
}
|
||||
if ("bigBrother".equalsIgnoreCase(itemFunction) || "big_brother".equalsIgnoreCase(itemFunction) || "brother".equalsIgnoreCase(itemFunction)) {
|
||||
return ItemFunction.BIG_BROTHER;
|
||||
}
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "未知的商品功能类型:" + itemFunction);
|
||||
}
|
||||
|
||||
private static Date toDate(long epochSecond) {
|
||||
return Date.from(Instant.ofEpochSecond(epochSecond));
|
||||
}
|
||||
|
||||
private static Map<String, Long> todayRangeInShanghai(long epochSecond) {
|
||||
LocalDate targetDate = Instant.ofEpochSecond(epochSecond)
|
||||
.atZone(SHANGHAI_ZONE_ID)
|
||||
.toLocalDate();
|
||||
long start = targetDate.atStartOfDay(SHANGHAI_ZONE_ID).toEpochSecond();
|
||||
long end = targetDate.plusDays(1).atStartOfDay(SHANGHAI_ZONE_ID).toEpochSecond() - 1;
|
||||
Map<String, Long> dayRange = new HashMap<>();
|
||||
dayRange.put("start", start);
|
||||
dayRange.put("end", end);
|
||||
return dayRange;
|
||||
}
|
||||
|
||||
private static int toIntId(Long id) {
|
||||
if (id > Integer.MAX_VALUE) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "用户编号超出范围");
|
||||
}
|
||||
return id.intValue();
|
||||
}
|
||||
|
||||
private static int toIntEpoch(long epochSecond) {
|
||||
if (epochSecond > Integer.MAX_VALUE) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "时间超出范围");
|
||||
}
|
||||
return (int) epochSecond;
|
||||
}
|
||||
|
||||
private enum ItemFunction {
|
||||
CRAWL,
|
||||
WEB_AI,
|
||||
BIG_BROTHER
|
||||
}
|
||||
}
|
||||
13
src/main/java/vvpkassistant/item/service/PkItemService.java
Normal file
13
src/main/java/vvpkassistant/item/service/PkItemService.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package vvpkassistant.item.service;
|
||||
|
||||
import vvpkassistant.item.model.PkItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/27 10:13
|
||||
*/
|
||||
public interface PkItemService {
|
||||
List<PkItem> selectItemList();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package vvpkassistant.item.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import vvpkassistant.item.PkItemMapper;
|
||||
import vvpkassistant.item.model.PkItem;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/27 10:13
|
||||
*/
|
||||
@Service
|
||||
public class PkItemServiceImpl implements PkItemService {
|
||||
|
||||
@Resource
|
||||
private PkItemMapper pkItemMapper;
|
||||
|
||||
@Override
|
||||
public List<PkItem> selectItemList() {
|
||||
return pkItemMapper.selectItemList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package vvpkassistant.iterm_recoder.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import vvpkassistant.iterm_recoder.model.PkItemRecoder;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Mapper
|
||||
public interface PkItemRecoderMapper extends BaseMapper<PkItemRecoder> {
|
||||
|
||||
@Select("select count(1) from pk_item_recoder where user_Id = #{userId} and item_id = #{itemId} and deleted = 0 and create_time between #{startTime} and #{endTime}")
|
||||
long countTodayPurchase(
|
||||
@Param("userId") Long userId,
|
||||
@Param("itemId") String itemId,
|
||||
@Param("startTime") Date startTime,
|
||||
@Param("endTime") Date endTime
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package vvpkassistant.iterm_recoder.model;
|
||||
|
||||
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 lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@TableName("pk_item_recoder")
|
||||
public class PkItemRecoder {
|
||||
|
||||
@TableId(value = "Id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
@TableField("user_id")
|
||||
private Long userId;
|
||||
|
||||
@TableField("item_id")
|
||||
private String itemId;
|
||||
|
||||
private String creator;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
private String updater;
|
||||
|
||||
private Date updateTime;
|
||||
|
||||
private Boolean deleted;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package vvpkassistant.pk.model.DTO;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PkResultPointsDTO {
|
||||
private Integer winnerUserId;
|
||||
private Integer loserUserId;
|
||||
private Boolean draw;
|
||||
}
|
||||
@@ -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<PkInfoDao, PkInfoModel> implement
|
||||
return pkInfoModel;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
8
src/main/java/vvpkassistant/pk/service/PkPinService.java
Normal file
8
src/main/java/vvpkassistant/pk/service/PkPinService.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package vvpkassistant.pk.service;
|
||||
|
||||
public interface PkPinService {
|
||||
String pinToTop(int operatorUserId, int articleId, int pinExpireTime);
|
||||
|
||||
String cancelPin(int operatorUserId, int articleId);
|
||||
}
|
||||
|
||||
167
src/main/java/vvpkassistant/pk/service/PkPinServiceImpl.java
Normal file
167
src/main/java/vvpkassistant/pk/service/PkPinServiceImpl.java
Normal file
@@ -0,0 +1,167 @@
|
||||
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.Tools.VVTools;
|
||||
import vvpkassistant.User.mapper.UserDao;
|
||||
import vvpkassistant.User.model.UserModel;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
import vvpkassistant.config.FunctionConfigProvider;
|
||||
import vvpkassistant.exception.BusinessException;
|
||||
import vvpkassistant.pk.mapper.PkInfoDao;
|
||||
import vvpkassistant.pk.model.PkInfoModel;
|
||||
|
||||
@Service
|
||||
public class PkPinServiceImpl implements PkPinService {
|
||||
|
||||
private static final String PIN_COIN_CONFIG_NAME = "置顶扣除积分";
|
||||
private static final int COIN_RECORD_ADD = 1;
|
||||
private static final int COIN_RECORD_DEDUCT = 0;
|
||||
|
||||
private final PkInfoDao pkInfoDao;
|
||||
private final UserDao userDao;
|
||||
private final CoinRecordsDao coinRecordsDao;
|
||||
private final FunctionConfigProvider functionConfigProvider;
|
||||
private final EpochSecondProvider epochSecondProvider;
|
||||
|
||||
public PkPinServiceImpl(
|
||||
PkInfoDao pkInfoDao,
|
||||
UserDao userDao,
|
||||
CoinRecordsDao coinRecordsDao,
|
||||
FunctionConfigProvider functionConfigProvider,
|
||||
EpochSecondProvider epochSecondProvider
|
||||
) {
|
||||
this.pkInfoDao = pkInfoDao;
|
||||
this.userDao = userDao;
|
||||
this.coinRecordsDao = coinRecordsDao;
|
||||
this.functionConfigProvider = functionConfigProvider;
|
||||
this.epochSecondProvider = epochSecondProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String pinToTop(int operatorUserId, int articleId, int pinExpireTime) {
|
||||
long now = epochSecondProvider.nowEpochSecond();
|
||||
ensureExpireTimeValid(pinExpireTime, now);
|
||||
|
||||
PkInfoModel pkInfoModel = pkInfoDao.selectById(articleId);
|
||||
if (pkInfoModel == null) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "该信息不存在");
|
||||
}
|
||||
ensureOwner(operatorUserId, pkInfoModel.getSenderId());
|
||||
|
||||
int costPerHour = getPinCoinPerHour();
|
||||
long hours = VVTools.calculateHoursRound(pinExpireTime, now);
|
||||
int totalCoin = toIntCoin(multiplyCoin(costPerHour, hours, "置顶时长过长"), "置顶时长过长");
|
||||
|
||||
ensureDeductPoints(operatorUserId, totalCoin);
|
||||
updatePinTime(pkInfoModel, pinExpireTime, (int) now);
|
||||
insertCoinRecord("置顶扣除积分", operatorUserId, totalCoin, (int) now, COIN_RECORD_DEDUCT);
|
||||
|
||||
return String.format("置顶成功,扣除%d积分", totalCoin);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String cancelPin(int operatorUserId, int articleId) {
|
||||
long now = epochSecondProvider.nowEpochSecond();
|
||||
|
||||
PkInfoModel pkInfoModel = pkInfoDao.selectById(articleId);
|
||||
if (pkInfoModel == null) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "该信息不存在");
|
||||
}
|
||||
ensureOwner(operatorUserId, pkInfoModel.getSenderId());
|
||||
|
||||
int costPerHour = getPinCoinPerHour();
|
||||
int pinExpireTime = pkInfoModel.getPinExpireTime() == null ? 0 : pkInfoModel.getPinExpireTime();
|
||||
long hours = VVTools.calculateHoursFloor(pinExpireTime, now);
|
||||
int refundCoin = toIntCoin(multiplyCoin(costPerHour, hours, "返还积分计算溢出"), "返还积分计算溢出");
|
||||
|
||||
if (refundCoin > 0) {
|
||||
int updated = userDao.increasePoints(operatorUserId, refundCoin);
|
||||
if (updated != 1) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "用户不存在");
|
||||
}
|
||||
}
|
||||
|
||||
pkInfoModel.setPinExpireTime(0);
|
||||
pkInfoModel.setPinCreateTime(0);
|
||||
if (pkInfoDao.updateById(pkInfoModel) != 1) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
|
||||
insertCoinRecord("取消置顶返还积分", operatorUserId, refundCoin, (int) now, COIN_RECORD_ADD);
|
||||
return String.format("操作成功,返还%d积分", refundCoin);
|
||||
}
|
||||
|
||||
private static void ensureExpireTimeValid(int pinExpireTime, long now) {
|
||||
if (pinExpireTime <= now) {
|
||||
throw new BusinessException(ErrorCode.PARAMS_ERROR, "置顶到期时间必须大于当前时间");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ensureOwner(int operatorUserId, Integer senderId) {
|
||||
if (senderId == null || senderId != operatorUserId) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "无权限操作");
|
||||
}
|
||||
}
|
||||
|
||||
private int getPinCoinPerHour() {
|
||||
String value = functionConfigProvider.getValue(PIN_COIN_CONFIG_NAME);
|
||||
if (value == null) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "未配置置顶扣除积分");
|
||||
}
|
||||
int coin;
|
||||
try {
|
||||
coin = Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "置顶扣除积分配置错误");
|
||||
}
|
||||
if (coin <= 0) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "置顶扣除积分配置错误");
|
||||
}
|
||||
return coin;
|
||||
}
|
||||
|
||||
private static long multiplyCoin(int costPerHour, long hours, String overflowMessage) {
|
||||
try {
|
||||
return Math.multiplyExact((long) costPerHour, hours);
|
||||
} catch (ArithmeticException e) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, overflowMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private static int toIntCoin(long coin, String overflowMessage) {
|
||||
if (coin > Integer.MAX_VALUE) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, overflowMessage);
|
||||
}
|
||||
return (int) coin;
|
||||
}
|
||||
|
||||
private void ensureDeductPoints(int operatorUserId, int totalCoin) {
|
||||
int updated = userDao.decreasePointsIfEnough(operatorUserId, totalCoin);
|
||||
if (updated == 1) {
|
||||
return;
|
||||
}
|
||||
UserModel userModel = userDao.selectById(operatorUserId);
|
||||
if (userModel == null) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, "用户不存在");
|
||||
}
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR, String.format("积分不足,需要%d积分", totalCoin));
|
||||
}
|
||||
|
||||
private void updatePinTime(PkInfoModel pkInfoModel, int pinExpireTime, int now) {
|
||||
pkInfoModel.setPinExpireTime(pinExpireTime);
|
||||
pkInfoModel.setPinCreateTime(now);
|
||||
if (pkInfoDao.updateById(pkInfoModel) != 1) {
|
||||
throw new BusinessException(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
private void insertCoinRecord(String desc, int userId, int coin, int now, int type) {
|
||||
coinRecordsDao.insert(new CoinRecords(desc, userId, coin, now, type));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package vvpkassistant.pk.service;
|
||||
|
||||
import vvpkassistant.pk.model.DTO.PkResultPointsDTO;
|
||||
|
||||
public interface PkResultPointService {
|
||||
String grantPkResultPoints(PkResultPointsDTO request);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
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 String PK_DRAW_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();
|
||||
if (isDraw(request)) {
|
||||
return grantDrawPoints(request, now);
|
||||
}
|
||||
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 String grantDrawPoints(PkResultPointsDTO request, int now) {
|
||||
int drawPoints = parsePositivePoints(PK_DRAW_COIN_CONFIG_NAME);
|
||||
grantPoints(request.getWinnerUserId(), drawPoints, PK_DRAW_COIN_CONFIG_NAME, now);
|
||||
grantPoints(request.getLoserUserId(), drawPoints, PK_DRAW_COIN_CONFIG_NAME, now);
|
||||
return String.format("操作成功,平局双方各增加%d积分", drawPoints);
|
||||
}
|
||||
|
||||
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 static boolean isDraw(PkResultPointsDTO request) {
|
||||
return Boolean.TRUE.equals(request.getDraw());
|
||||
}
|
||||
|
||||
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, "积分记录写入失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package vvpkassistant.tenant.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import vvpkassistant.tenant.model.SystemTenant;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/27 13:17
|
||||
*/
|
||||
|
||||
@Mapper
|
||||
public interface SystemTenantMapper extends BaseMapper<SystemTenant> {
|
||||
}
|
||||
137
src/main/java/vvpkassistant/tenant/model/SystemTenant.java
Normal file
137
src/main/java/vvpkassistant/tenant/model/SystemTenant.java
Normal file
@@ -0,0 +1,137 @@
|
||||
package vvpkassistant.tenant.model;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/3/27 13:17
|
||||
*/
|
||||
|
||||
/**
|
||||
* 租户表
|
||||
*/
|
||||
@Data
|
||||
@TableName("system_tenant")
|
||||
public class SystemTenant {
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 租户名
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 联系人的用户编号
|
||||
*/
|
||||
private Long contactUserId;
|
||||
|
||||
/**
|
||||
* 联系人
|
||||
*/
|
||||
private String contactName;
|
||||
|
||||
/**
|
||||
* 联系手机
|
||||
*/
|
||||
private String contactMobile;
|
||||
|
||||
/**
|
||||
* 租户状态(0正常 1停用)
|
||||
*/
|
||||
private Byte status;
|
||||
|
||||
/**
|
||||
* 绑定域名
|
||||
*/
|
||||
private String website;
|
||||
|
||||
/**
|
||||
* 租户套餐编号
|
||||
*/
|
||||
private Long packageId;
|
||||
|
||||
/**
|
||||
* 过期时间
|
||||
*/
|
||||
private Date expireTime;
|
||||
|
||||
/**
|
||||
* 账号数量
|
||||
*/
|
||||
private Integer accountCount;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String creator;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updater;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
private Boolean deleted;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 爬虫到期时间
|
||||
*/
|
||||
private Date crawlExpireTime;
|
||||
|
||||
/**
|
||||
* AI 到期时间
|
||||
*/
|
||||
private Date aiExpireTime;
|
||||
|
||||
/**
|
||||
* 大哥过期时间
|
||||
*/
|
||||
private Date brotherExpireTime;
|
||||
|
||||
/**
|
||||
* 上级租户 Id
|
||||
*/
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 租户类型:代理,用户
|
||||
*/
|
||||
private String tenantType;
|
||||
|
||||
/**
|
||||
* 代理级别
|
||||
*/
|
||||
private Integer tenantLevel;
|
||||
|
||||
/**
|
||||
* 初始用户
|
||||
*/
|
||||
private String initialUser;
|
||||
|
||||
}
|
||||
@@ -3,14 +3,13 @@
|
||||
spring:
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://47.79.98.113:3326/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
|
||||
username: root
|
||||
password: niu995228
|
||||
url: jdbc:mysql://49.235.115.212:3336/vv_assistant
|
||||
|
||||
password: wfn53400
|
||||
|
||||
redis:
|
||||
database: 1
|
||||
host: localhost
|
||||
host: 47.79.98.113
|
||||
port: 16379
|
||||
timeout: 5000
|
||||
password: ezyPM2UQkPO8O6i8s9
|
||||
@@ -58,4 +58,4 @@ dromara:
|
||||
domain: https://vv-1317974657.cos.ap-shanghai.myqcloud.com # 访问域名,注意“/”结尾,例如:https://abc.cos.ap-nanjing.myqcloud.com/
|
||||
base-path: /headerIcon/ # 基础路径
|
||||
|
||||
IM-secretKey: 04452c3231ae4fe5
|
||||
IM-secretKey: 7a2b9359f06646f9
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="DEBUG">
|
||||
<Appenders>
|
||||
<!-- 控制台输出 -->
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
|
||||
</Console>
|
||||
<!-- 文件输出 -->
|
||||
<File name="FileAppender" fileName="logs/app.log">
|
||||
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
|
||||
</File>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="DEBUG">
|
||||
<AppenderRef ref="Console"/>
|
||||
<AppenderRef ref="FileAppender"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
60
src/main/resources/logback-spring.xml
Normal file
60
src/main/resources/logback-spring.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="true" scanPeriod="60 seconds">
|
||||
<contextName>vvPkAssistant</contextName>
|
||||
|
||||
<property name="PATTERN_DEFAULT"
|
||||
value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | %highlight(${LOG_LEVEL_PATTERN:-%5p} ${PID:- }) | %boldYellow(%thread) %boldGreen(%-40.40logger{39}) | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%ex}"/>
|
||||
<property name="FILE_PATTERN"
|
||||
value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} | ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } | %thread %-40.40logger{39} | %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%ex}"/>
|
||||
<property name="LOG_FILE_PATH" value="${LOG_FILE:-${user.dir}/logs/vvpkassistant}"/>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<pattern>${PATTERN_DEFAULT}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_FILE_PATH}.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN:-${LOG_FILE_PATH}.%d{yyyy-MM-dd}.%i.gz}</fileNamePattern>
|
||||
<maxHistory>${LOGBACK_ROLLINGPOLICY_MAX_HISTORY:-30}</maxHistory>
|
||||
<maxFileSize>${LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE:-10MB}</maxFileSize>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${FILE_PATTERN}</pattern>
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<springProfile name="local,dev">
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
|
||||
<logger name="vvpkassistant" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</logger>
|
||||
|
||||
<logger name="com.baomidou.mybatisplus" level="INFO"/>
|
||||
</springProfile>
|
||||
|
||||
<springProfile name="prod">
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</root>
|
||||
|
||||
<logger name="vvpkassistant" level="INFO" additivity="false">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
</logger>
|
||||
|
||||
<logger name="org.springframework" level="WARN"/>
|
||||
<logger name="com.baomidou.mybatisplus" level="WARN"/>
|
||||
<logger name="org.redisson" level="WARN"/>
|
||||
</springProfile>
|
||||
</configuration>
|
||||
206
src/main/resources/mapper/PkItemMapper.xml
Normal file
206
src/main/resources/mapper/PkItemMapper.xml
Normal file
@@ -0,0 +1,206 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="vvpkassistant.item.PkItemMapper">
|
||||
<resultMap id="BaseResultMap" type="vvpkassistant.item.model.PkItem">
|
||||
<!--@mbg.generated-->
|
||||
<!--@Table pk_item-->
|
||||
<id column="id" jdbcType="BIGINT" property="id" />
|
||||
<result column="item_name" jdbcType="VARCHAR" property="itemName" />
|
||||
<result column="item_price" jdbcType="INTEGER" property="itemPrice" />
|
||||
<result column="item_desc" jdbcType="VARCHAR" property="itemDesc" />
|
||||
<result column="item_function" jdbcType="VARCHAR" property="itemFunction" />
|
||||
<result column="item_duration" jdbcType="INTEGER" property="itemDuration" />
|
||||
<result column="item_status" jdbcType="INTEGER" property="itemStatus" />
|
||||
<result column="remark" jdbcType="VARCHAR" property="remark" />
|
||||
<result column="creator" jdbcType="VARCHAR" property="creator" />
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||
<result column="updater" jdbcType="VARCHAR" property="updater" />
|
||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
|
||||
<result column="deleted" jdbcType="BIT" property="deleted" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
id, item_name, item_price, item_desc, item_function, item_duration, item_status,
|
||||
remark, creator, create_time, updater, update_time, deleted
|
||||
</sql>
|
||||
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
|
||||
<!--@mbg.generated-->
|
||||
select
|
||||
<include refid="Base_Column_List" />
|
||||
from pk_item
|
||||
where id = #{id,jdbcType=BIGINT}
|
||||
</select>
|
||||
<select id="selectItemList" resultMap="BaseResultMap">
|
||||
select
|
||||
<include refid="Base_Column_List" />
|
||||
from pk_item
|
||||
where deleted = 0
|
||||
and
|
||||
item_status = 0
|
||||
order by id desc
|
||||
</select>
|
||||
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
|
||||
<!--@mbg.generated-->
|
||||
delete from pk_item
|
||||
where id = #{id,jdbcType=BIGINT}
|
||||
</delete>
|
||||
<insert id="insert" parameterType="vvpkassistant.item.model.PkItem">
|
||||
<!--@mbg.generated-->
|
||||
insert into pk_item (id, item_name, item_price,
|
||||
item_desc, item_function, item_duration,
|
||||
item_status, remark, creator,
|
||||
create_time, updater, update_time,
|
||||
deleted)
|
||||
values (#{id,jdbcType=BIGINT}, #{itemName,jdbcType=VARCHAR}, #{itemPrice,jdbcType=INTEGER},
|
||||
#{itemDesc,jdbcType=VARCHAR}, #{itemFunction,jdbcType=VARCHAR}, #{itemDuration,jdbcType=INTEGER},
|
||||
#{itemStatus,jdbcType=INTEGER}, #{remark,jdbcType=VARCHAR}, #{creator,jdbcType=VARCHAR},
|
||||
#{createTime,jdbcType=TIMESTAMP}, #{updater,jdbcType=VARCHAR}, #{updateTime,jdbcType=TIMESTAMP},
|
||||
#{deleted,jdbcType=BIT})
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="vvpkassistant.item.model.PkItem">
|
||||
<!--@mbg.generated-->
|
||||
insert into pk_item
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="id != null">
|
||||
id,
|
||||
</if>
|
||||
<if test="itemName != null">
|
||||
item_name,
|
||||
</if>
|
||||
<if test="itemPrice != null">
|
||||
item_price,
|
||||
</if>
|
||||
<if test="itemDesc != null">
|
||||
item_desc,
|
||||
</if>
|
||||
<if test="itemFunction != null">
|
||||
item_function,
|
||||
</if>
|
||||
<if test="itemDuration != null">
|
||||
item_duration,
|
||||
</if>
|
||||
<if test="itemStatus != null">
|
||||
item_status,
|
||||
</if>
|
||||
<if test="remark != null">
|
||||
remark,
|
||||
</if>
|
||||
<if test="creator != null">
|
||||
creator,
|
||||
</if>
|
||||
<if test="createTime != null">
|
||||
create_time,
|
||||
</if>
|
||||
<if test="updater != null">
|
||||
updater,
|
||||
</if>
|
||||
<if test="updateTime != null">
|
||||
update_time,
|
||||
</if>
|
||||
<if test="deleted != null">
|
||||
deleted,
|
||||
</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="id != null">
|
||||
#{id,jdbcType=BIGINT},
|
||||
</if>
|
||||
<if test="itemName != null">
|
||||
#{itemName,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="itemPrice != null">
|
||||
#{itemPrice,jdbcType=INTEGER},
|
||||
</if>
|
||||
<if test="itemDesc != null">
|
||||
#{itemDesc,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="itemFunction != null">
|
||||
#{itemFunction,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="itemDuration != null">
|
||||
#{itemDuration,jdbcType=INTEGER},
|
||||
</if>
|
||||
<if test="itemStatus != null">
|
||||
#{itemStatus,jdbcType=INTEGER},
|
||||
</if>
|
||||
<if test="remark != null">
|
||||
#{remark,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="creator != null">
|
||||
#{creator,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="createTime != null">
|
||||
#{createTime,jdbcType=TIMESTAMP},
|
||||
</if>
|
||||
<if test="updater != null">
|
||||
#{updater,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="updateTime != null">
|
||||
#{updateTime,jdbcType=TIMESTAMP},
|
||||
</if>
|
||||
<if test="deleted != null">
|
||||
#{deleted,jdbcType=BIT},
|
||||
</if>
|
||||
</trim>
|
||||
</insert>
|
||||
<update id="updateByPrimaryKeySelective" parameterType="vvpkassistant.item.model.PkItem">
|
||||
<!--@mbg.generated-->
|
||||
update pk_item
|
||||
<set>
|
||||
<if test="itemName != null">
|
||||
item_name = #{itemName,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="itemPrice != null">
|
||||
item_price = #{itemPrice,jdbcType=INTEGER},
|
||||
</if>
|
||||
<if test="itemDesc != null">
|
||||
item_desc = #{itemDesc,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="itemFunction != null">
|
||||
item_function = #{itemFunction,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="itemDuration != null">
|
||||
item_duration = #{itemDuration,jdbcType=INTEGER},
|
||||
</if>
|
||||
<if test="itemStatus != null">
|
||||
item_status = #{itemStatus,jdbcType=INTEGER},
|
||||
</if>
|
||||
<if test="remark != null">
|
||||
remark = #{remark,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="creator != null">
|
||||
creator = #{creator,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="createTime != null">
|
||||
create_time = #{createTime,jdbcType=TIMESTAMP},
|
||||
</if>
|
||||
<if test="updater != null">
|
||||
updater = #{updater,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="updateTime != null">
|
||||
update_time = #{updateTime,jdbcType=TIMESTAMP},
|
||||
</if>
|
||||
<if test="deleted != null">
|
||||
deleted = #{deleted,jdbcType=BIT},
|
||||
</if>
|
||||
</set>
|
||||
where id = #{id,jdbcType=BIGINT}
|
||||
</update>
|
||||
<update id="updateByPrimaryKey" parameterType="vvpkassistant.item.model.PkItem">
|
||||
<!--@mbg.generated-->
|
||||
update pk_item
|
||||
set item_name = #{itemName,jdbcType=VARCHAR},
|
||||
item_price = #{itemPrice,jdbcType=INTEGER},
|
||||
item_desc = #{itemDesc,jdbcType=VARCHAR},
|
||||
item_function = #{itemFunction,jdbcType=VARCHAR},
|
||||
item_duration = #{itemDuration,jdbcType=INTEGER},
|
||||
item_status = #{itemStatus,jdbcType=INTEGER},
|
||||
remark = #{remark,jdbcType=VARCHAR},
|
||||
creator = #{creator,jdbcType=VARCHAR},
|
||||
create_time = #{createTime,jdbcType=TIMESTAMP},
|
||||
updater = #{updater,jdbcType=VARCHAR},
|
||||
update_time = #{updateTime,jdbcType=TIMESTAMP},
|
||||
deleted = #{deleted,jdbcType=BIT}
|
||||
where id = #{id,jdbcType=BIGINT}
|
||||
</update>
|
||||
</mapper>
|
||||
20
src/main/resources/mapper/PkItemRecoderMapper.xml
Normal file
20
src/main/resources/mapper/PkItemRecoderMapper.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="vvpkassistant.iterm_recoder.mapper.PkItemRecoderMapper">
|
||||
<resultMap id="BaseResultMap" type="vvpkassistant.iterm_recoder.model.PkItemRecoder">
|
||||
<!--@mbg.generated-->
|
||||
<!--@Table pk_item_recoder-->
|
||||
<id column="Id" jdbcType="BIGINT" property="id" />
|
||||
<result column="user_id" jdbcType="BIGINT" property="userId" />
|
||||
<result column="item_id" jdbcType="VARCHAR" property="itemId" />
|
||||
<result column="creator" jdbcType="VARCHAR" property="creator" />
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||
<result column="updater" jdbcType="VARCHAR" property="updater" />
|
||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
|
||||
<result column="deleted" jdbcType="BIT" property="deleted" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
Id, user_Id, item_id, creator, create_time, updater, update_time, deleted
|
||||
</sql>
|
||||
</mapper>
|
||||
38
src/main/resources/mapper/SystemTenantMapper.xml
Normal file
38
src/main/resources/mapper/SystemTenantMapper.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="vvpkassistant.tenant.mapper.SystemTenantMapper">
|
||||
<resultMap id="BaseResultMap" type="vvpkassistant.tenant.model.SystemTenant">
|
||||
<!--@mbg.generated-->
|
||||
<!--@Table system_tenant-->
|
||||
<id column="id" jdbcType="BIGINT" property="id" />
|
||||
<result column="name" jdbcType="VARCHAR" property="name" />
|
||||
<result column="contact_user_id" jdbcType="BIGINT" property="contactUserId" />
|
||||
<result column="contact_name" jdbcType="VARCHAR" property="contactName" />
|
||||
<result column="contact_mobile" jdbcType="VARCHAR" property="contactMobile" />
|
||||
<result column="status" jdbcType="TINYINT" property="status" />
|
||||
<result column="website" jdbcType="VARCHAR" property="website" />
|
||||
<result column="package_id" jdbcType="BIGINT" property="packageId" />
|
||||
<result column="expire_time" jdbcType="TIMESTAMP" property="expireTime" />
|
||||
<result column="account_count" jdbcType="INTEGER" property="accountCount" />
|
||||
<result column="creator" jdbcType="VARCHAR" property="creator" />
|
||||
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||
<result column="updater" jdbcType="VARCHAR" property="updater" />
|
||||
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
|
||||
<result column="deleted" jdbcType="BIT" property="deleted" />
|
||||
<result column="remark" jdbcType="VARCHAR" property="remark" />
|
||||
<result column="crawl_expire_time" jdbcType="TIMESTAMP" property="crawlExpireTime" />
|
||||
<result column="ai_expire_time" jdbcType="TIMESTAMP" property="aiExpireTime" />
|
||||
<result column="brother_expire_time" jdbcType="TIMESTAMP" property="brotherExpireTime" />
|
||||
<result column="parent_Id" jdbcType="BIGINT" property="parentId" />
|
||||
<result column="tenant_type" jdbcType="VARCHAR" property="tenantType" />
|
||||
<result column="tenant_level" jdbcType="INTEGER" property="tenantLevel" />
|
||||
<result column="initial_user" jdbcType="VARCHAR" property="initialUser" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
id, `name`, contact_user_id, contact_name, contact_mobile, `status`, website, package_id,
|
||||
expire_time, account_count, creator, create_time, updater, update_time, deleted,
|
||||
remark, crawl_expire_time, ai_expire_time, brother_expire_time, parent_Id, tenant_type,
|
||||
tenant_level, initial_user
|
||||
</sql>
|
||||
</mapper>
|
||||
@@ -0,0 +1,109 @@
|
||||
package vvpkassistant.pk.service;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import vvpkassistant.CoinRecords.CoinRecordsDao;
|
||||
import vvpkassistant.Tools.EpochSecondProvider;
|
||||
import vvpkassistant.User.mapper.UserDao;
|
||||
import vvpkassistant.User.model.UserModel;
|
||||
import vvpkassistant.common.ErrorCode;
|
||||
import vvpkassistant.config.FunctionConfigProvider;
|
||||
import vvpkassistant.exception.BusinessException;
|
||||
import vvpkassistant.pk.mapper.PkInfoDao;
|
||||
import vvpkassistant.pk.model.PkInfoModel;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class PkPinServiceImplTests {
|
||||
|
||||
@Test
|
||||
void shouldFailWhenExpireTimeNotInFuture() {
|
||||
PkPinServiceImpl service = newServiceWithNow(100L);
|
||||
BusinessException ex = Assertions.assertThrows(BusinessException.class,
|
||||
() -> service.pinToTop(1, 10, 100));
|
||||
Assertions.assertEquals(ErrorCode.PARAMS_ERROR.getCode(), ex.getCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFailWhenPointsNotEnoughEvenIfLessThanOneHour() {
|
||||
long now = 1_000L;
|
||||
|
||||
PkInfoDao pkInfoDao = mock(PkInfoDao.class);
|
||||
UserDao userDao = mock(UserDao.class);
|
||||
CoinRecordsDao coinRecordsDao = mock(CoinRecordsDao.class);
|
||||
FunctionConfigProvider functionConfigProvider = mock(FunctionConfigProvider.class);
|
||||
EpochSecondProvider epochSecondProvider = () -> now;
|
||||
|
||||
when(functionConfigProvider.getValue("置顶扣除积分")).thenReturn("10");
|
||||
|
||||
PkInfoModel pkInfoModel = new PkInfoModel();
|
||||
pkInfoModel.setId(10);
|
||||
pkInfoModel.setSenderId(1);
|
||||
when(pkInfoDao.selectById(10)).thenReturn(pkInfoModel);
|
||||
|
||||
when(userDao.decreasePointsIfEnough(1, 10)).thenReturn(0);
|
||||
UserModel userModel = new UserModel();
|
||||
userModel.setId(1);
|
||||
userModel.setPoints(9);
|
||||
when(userDao.selectById(1)).thenReturn(userModel);
|
||||
|
||||
PkPinServiceImpl service = new PkPinServiceImpl(
|
||||
pkInfoDao, userDao, coinRecordsDao, functionConfigProvider, epochSecondProvider
|
||||
);
|
||||
|
||||
int pinExpireTime = (int) (now + 1);
|
||||
BusinessException ex = Assertions.assertThrows(BusinessException.class,
|
||||
() -> service.pinToTop(1, 10, pinExpireTime));
|
||||
Assertions.assertTrue(ex.getMessage().contains("积分不足"));
|
||||
|
||||
verify(pkInfoDao, never()).updateById(any());
|
||||
verify(coinRecordsDao, never()).insert(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSucceedAndChargeOneHourWhenJustOneSecond() {
|
||||
long now = 2_000L;
|
||||
|
||||
PkInfoDao pkInfoDao = mock(PkInfoDao.class);
|
||||
UserDao userDao = mock(UserDao.class);
|
||||
CoinRecordsDao coinRecordsDao = mock(CoinRecordsDao.class);
|
||||
FunctionConfigProvider functionConfigProvider = mock(FunctionConfigProvider.class);
|
||||
EpochSecondProvider epochSecondProvider = () -> now;
|
||||
|
||||
when(functionConfigProvider.getValue("置顶扣除积分")).thenReturn("10");
|
||||
|
||||
PkInfoModel pkInfoModel = new PkInfoModel();
|
||||
pkInfoModel.setId(10);
|
||||
pkInfoModel.setSenderId(1);
|
||||
when(pkInfoDao.selectById(10)).thenReturn(pkInfoModel);
|
||||
|
||||
when(userDao.decreasePointsIfEnough(1, 10)).thenReturn(1);
|
||||
when(pkInfoDao.updateById(any())).thenReturn(1);
|
||||
when(coinRecordsDao.insert(any())).thenReturn(1);
|
||||
|
||||
PkPinServiceImpl service = new PkPinServiceImpl(
|
||||
pkInfoDao, userDao, coinRecordsDao, functionConfigProvider, epochSecondProvider
|
||||
);
|
||||
|
||||
int pinExpireTime = (int) (now + 1);
|
||||
String msg = service.pinToTop(1, 10, pinExpireTime);
|
||||
Assertions.assertTrue(msg.contains("扣除10积分"));
|
||||
|
||||
ArgumentCaptor<PkInfoModel> captor = ArgumentCaptor.forClass(PkInfoModel.class);
|
||||
verify(pkInfoDao).updateById(captor.capture());
|
||||
Assertions.assertEquals(Integer.valueOf(pinExpireTime), captor.getValue().getPinExpireTime());
|
||||
Assertions.assertEquals(Integer.valueOf((int) now), captor.getValue().getPinCreateTime());
|
||||
}
|
||||
|
||||
private static PkPinServiceImpl newServiceWithNow(long now) {
|
||||
PkInfoDao pkInfoDao = mock(PkInfoDao.class);
|
||||
UserDao userDao = mock(UserDao.class);
|
||||
CoinRecordsDao coinRecordsDao = mock(CoinRecordsDao.class);
|
||||
FunctionConfigProvider functionConfigProvider = mock(FunctionConfigProvider.class);
|
||||
EpochSecondProvider epochSecondProvider = () -> now;
|
||||
return new PkPinServiceImpl(pkInfoDao, userDao, coinRecordsDao, functionConfigProvider, epochSecondProvider);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
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<CoinRecords> 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 shouldGrantDrawPointsToBothUsers() {
|
||||
UserDao userDao = mock(UserDao.class);
|
||||
CoinRecordsDao coinRecordsDao = mock(CoinRecordsDao.class);
|
||||
FunctionConfigProvider functionConfigProvider = mock(FunctionConfigProvider.class);
|
||||
EpochSecondProvider epochSecondProvider = () -> 1_234L;
|
||||
|
||||
when(functionConfigProvider.getValue("PK平局增加积分")).thenReturn("5");
|
||||
when(userDao.increasePoints(1001, 5)).thenReturn(1);
|
||||
when(userDao.increasePoints(1002, 5)).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);
|
||||
request.setDraw(true);
|
||||
|
||||
String result = service.grantPkResultPoints(request);
|
||||
|
||||
Assertions.assertEquals("操作成功,平局双方各增加5积分", result);
|
||||
ArgumentCaptor<CoinRecords> 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(5), 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(5), 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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user