Commit a341fef5 authored by zhangfeng's avatar zhangfeng

Merge branch 'refs/heads/feature_member_score' into dev

parents 39db271e 00ba2d32
...@@ -3,6 +3,8 @@ package cn.iocoder.yudao.framework.common.util.date; ...@@ -3,6 +3,8 @@ package cn.iocoder.yudao.framework.common.util.date;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
...@@ -149,4 +151,18 @@ public class DateUtils { ...@@ -149,4 +151,18 @@ public class DateUtils {
public static String formatDateTime(Date date) { public static String formatDateTime(Date date) {
return null == date ? "" : DateUtil.format(date, FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND); return null == date ? "" : DateUtil.format(date, FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND);
} }
public static Date getNextDayStart(Date date) {
LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
localDateTime = localDateTime.plusDays(1).withHour(0).withMinute(0).withSecond(0);
java.time.LocalDate localDate = localDateTime.toLocalDate();
return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
}
public static Date addDays(Date date ,int days) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, days);
return calendar.getTime();
}
} }
package cn.iocoder.yudao.module.member.api.score;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateReqDTO;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateRespDTO;
public interface MemberUserScoreApi {
MemberUserScoreOperateRespDTO operateScore(MemberUserScoreOperateReqDTO req);
}
package cn.iocoder.yudao.module.member.api.score.dto;
import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class MemberUserScoreDetailUpdateReqDto {
private Long memberId;
private Integer scoreCount;
private ScoreOperateTypeEnum operateType;
private ScoreSourceTypeEnum sourceType;
private Long scoreLogId;
private Integer expireDays;
}
package cn.iocoder.yudao.module.member.api.score.dto;
import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;
import java.util.Map;
@Data
@Builder
@ToString
public class MemberUserScoreOperateReqDTO {
/**
* 会员id
*/
private Long memberId;
/**
* 积分数量
*/
private Integer scoreCount;
/**
* 积分来源
*/
private ScoreSourceTypeEnum sourceType;
/**
* 人工操作时必传,其他来源不需要传
*/
private ScoreOperateTypeEnum operateType;
/**
* 积分规则id
*/
private Long ruleId;
/**
* 积分过期时间
*/
private Integer expireDays;
/**
* 扩展参数
*/
private Map<String, Object> extParam;
}
package cn.iocoder.yudao.module.member.api.score.dto;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class MemberUserScoreOperateRespDTO {
private boolean success;
private int code;
private MemberUserScoreOperateReqDTO reqDTO;
public static MemberUserScoreOperateRespDTO success(MemberUserScoreOperateReqDTO req){
return MemberUserScoreOperateRespDTO.builder().success(true).code(200).reqDTO(req).build();
}
}
package cn.iocoder.yudao.module.member.api.score.dto;
import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class MemberUserScoreUpdateReqDTO {
private Long memberId;
private Integer scoreCount;
private ScoreOperateTypeEnum operateType;
private ScoreSourceTypeEnum sourceType;
}
...@@ -40,4 +40,9 @@ public interface ErrorCodeConstants { ...@@ -40,4 +40,9 @@ public interface ErrorCodeConstants {
ErrorCode EMAIL_CODE_ERROR = new ErrorCode(1004007004, "验证码错误"); ErrorCode EMAIL_CODE_ERROR = new ErrorCode(1004007004, "验证码错误");
ErrorCode MEMBER_ID_IS_NULL = new ErrorCode(1004008001, "member.id.is.null");
ErrorCode SCORE_COUNT_ERROR = new ErrorCode(1004008002, "score.count.error");
ErrorCode MEMBER_SCORE_NOT_ENOUGH = new ErrorCode(1004008002, "member.score.not.enough");
} }
package cn.iocoder.yudao.module.member.enums;
public enum MemberScoreStatueEnum {
AVAILABLE(1, "可用"),
PART_AVAILABLE(2, "部分可用"),
NOT_AVAILABLE(3, "不可用")
;
private final int value;
private final String name;
MemberScoreStatueEnum(int value, String name) {
this.value = value;
this.name = name;
}
public int getValue() {
return value;
}
public String getName() {
return name;
}
}
package cn.iocoder.yudao.module.member.enums;
public enum MemberUserScoreTypeEnum {
HOLD_SCORE(1, "持有积分"),
EXPIRED_SCORE(2, "过期积分"),
INVALID_SCORE(3, "已失效积分")
;
private final int value;
private final String name;
MemberUserScoreTypeEnum(int value, String name) {
this.value = value;
this.name = name;
}
public int getValue() {
return value;
}
public String getName() {
return name;
}
}
package cn.iocoder.yudao.module.member.enums;
import java.util.stream.Stream;
public enum ScoreOperateTypeEnum {
ADD(1, "增加"),
REDUCE(2, "减少");
private final int value;
private final String name;
ScoreOperateTypeEnum(int value, String name) {
this.value = value;
this.name = name;
}
public int getValue() {
return value;
}
public String getName() {
return name;
}
public static ScoreOperateTypeEnum parseByValue(int value) {
return Stream.of(values()).filter(e -> e.getValue() == value).findAny().orElse(null);
}
}
package cn.iocoder.yudao.module.member.enums;
import com.google.common.collect.Sets;
import java.util.Set;
public enum ScoreSourceTypeEnum {
MANUAL_OPERATE(1, "人工操作", null),
EXCHANGE_REWARD(2, "兑换礼品", ScoreOperateTypeEnum.REDUCE),
SYSTEM_EXPIRED(3, "系统失效", ScoreOperateTypeEnum.REDUCE),
;
private final int value;
private final String name;
private final ScoreOperateTypeEnum operateType;
ScoreSourceTypeEnum(int value, String name, ScoreOperateTypeEnum operateType) {
this.value = value;
this.name = name;
this.operateType = operateType;
}
public int getValue() {
return value;
}
public String getName() {
return name;
}
public ScoreOperateTypeEnum getOperateType() {
return operateType;
}
public static Set<ScoreSourceTypeEnum> getInvalidScoreStatusSourceType() {
return Sets.newHashSet(MANUAL_OPERATE, SYSTEM_EXPIRED);
}
}
package cn.iocoder.yudao.module.member.api.score;
import cn.iocoder.yudao.framework.redis.helper.RedisDistributedLock;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreDetailUpdateReqDto;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateReqDTO;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateRespDTO;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreUpdateReqDTO;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import cn.iocoder.yudao.module.member.service.memberUserScore.MemberUserScoreService;
import cn.iocoder.yudao.module.member.service.memberUserScoreDetail.MemberUserScoreDetailService;
import cn.iocoder.yudao.module.member.service.memberUserScoreLog.MemberUserScoreLogService;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogCreateReq;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Slf4j
@Service
public class MemberUserScoreApiImpl implements MemberUserScoreApi{
@Resource
private MemberUserScoreLogService logService;
@Resource
private MemberUserScoreDetailService scoreDetailService;
@Resource
private MemberUserScoreService memberUserScoreService;
@Resource
private RedisDistributedLock redisDistributedLock;
@Override
@Transactional(rollbackFor = Exception.class)
public MemberUserScoreOperateRespDTO operateScore(MemberUserScoreOperateReqDTO req) {
//todo 校验
String lockKey = "member:operate:socre:" + req.getMemberId();
boolean lock = redisDistributedLock.lock(lockKey, 5000, 3, 100);
if (!lock) {
return MemberUserScoreOperateRespDTO.builder().success(false).code(500).reqDTO(req).build();
}
try {
Long logId = saveScoreLog(req);
saveScoreDetail(req, logId);
updateUserScore(req);
} finally {
redisDistributedLock.releaseLock(lockKey);
}
return MemberUserScoreOperateRespDTO.success(req);
}
private void updateUserScore(MemberUserScoreOperateReqDTO req) {
memberUserScoreService.updateUserScore(MemberUserScoreUpdateReqDTO.builder()
.memberId(req.getMemberId())
.scoreCount(req.getScoreCount())
.operateType(req.getSourceType() == ScoreSourceTypeEnum.MANUAL_OPERATE ?
req.getOperateType() : req.getSourceType().getOperateType())
.sourceType(req.getSourceType())
.build());
}
private void saveScoreDetail(MemberUserScoreOperateReqDTO req, Long scoreLogId) {
scoreDetailService.updateScoreDetail(MemberUserScoreDetailUpdateReqDto.builder()
.memberId(req.getMemberId())
.scoreCount(req.getScoreCount())
.operateType(req.getSourceType() == ScoreSourceTypeEnum.MANUAL_OPERATE ?
req.getOperateType() : req.getSourceType().getOperateType())
.sourceType(req.getSourceType())
.scoreLogId(scoreLogId)
.expireDays(req.getExpireDays())
.build());
}
private Long saveScoreLog(MemberUserScoreOperateReqDTO req) {
return logService.createScoreLog(MemberUserScoreLogCreateReq.builder()
.memberId(req.getMemberId())
.scoreCount(req.getScoreCount())
.operateType(req.getSourceType() == ScoreSourceTypeEnum.MANUAL_OPERATE ?
req.getOperateType().getValue() : req.getSourceType().getOperateType().getValue())
.sourceType(req.getSourceType().getValue())
.extParam(req.getExtParam())
.build());
}
}
...@@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.member.controller.admin.memberUserScore; ...@@ -2,9 +2,9 @@ package cn.iocoder.yudao.module.member.controller.admin.memberUserScore;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.module.member.service.memberUserScore.MemberUserScoreService; import cn.iocoder.yudao.module.member.service.memberUserScore.MemberUserScoreService;
import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreBackVO; import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreBackVO;
import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreOperateQueryVO;
import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreQueryVO; import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreQueryVO;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
...@@ -36,4 +36,12 @@ public class MemberUserScoreController { ...@@ -36,4 +36,12 @@ public class MemberUserScoreController {
PageResult<MemberUserScoreBackVO> pageResult = userScoreService.getUserScorePage(query); PageResult<MemberUserScoreBackVO> pageResult = userScoreService.getUserScorePage(query);
return success(pageResult); return success(pageResult);
} }
@PostMapping("/operate")
@ApiOperation("操作积分")
@PreAuthorize("@ss.hasPermission('member:user-score:operate')")
public CommonResult<Boolean> operate(@Valid @RequestBody MemberUserScoreOperateQueryVO query) {
userScoreService.operate(query);
return success(null);
}
} }
package cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreDetail;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.util.Date;
/**
* 会员积分 DO
*
* @author 系统管理员
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("member_user_score_detail")
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class MemberUserScoreDetailDO extends BaseDO {
@TableId
private Long id;
private Long memberId;
private Integer scoreCount;
private Integer status;
private Integer remainCount;
private Date expireTime;
private String extParam = "{}";
@Getter
public enum MemberUserScoreDetailExtKey {
LOG_IDS("logIds");
private final String key;
MemberUserScoreDetailExtKey(String key) {
this.key = key;
}
}
}
...@@ -19,4 +19,6 @@ public interface MemberUserScoreMapper extends AbstractMapper<MemberUserScoreDO> ...@@ -19,4 +19,6 @@ public interface MemberUserScoreMapper extends AbstractMapper<MemberUserScoreDO>
List<MemberUserScoreBackVO> getUserScoreList(@Param("start") int start,@Param("size") int size,@Param("query") MemberUserScoreQueryVO query); List<MemberUserScoreBackVO> getUserScoreList(@Param("start") int start,@Param("size") int size,@Param("query") MemberUserScoreQueryVO query);
int countUserScore(@Param("query") MemberUserScoreQueryVO query); int countUserScore(@Param("query") MemberUserScoreQueryVO query);
MemberUserScoreDO getByMemberId(@Param("memberId") Long memberId);
} }
package cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreDetail;
import cn.iocoder.yudao.framework.mybatis.core.mapper.AbstractMapper;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreDetail.MemberUserScoreDetailDO;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreLog.MemberUserScoreLogDO;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* 会员积分详情 Mapper
* @author 系统管理员
*/
@Mapper
public interface MemberUserScoreDetailMapper extends AbstractMapper<MemberUserScoreDetailDO> {
Long getScoreTotalByStatus(@Param("memberId") Long memberId, @Param("statusList") Collection<Integer> statusList);
}
package cn.iocoder.yudao.module.member.service.memberUserScore; package cn.iocoder.yudao.module.member.service.memberUserScore;
import java.util.*; import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.framework.mybatis.core.service.IService; import cn.iocoder.yudao.framework.mybatis.core.service.IService;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreUpdateReqDTO;
import cn.iocoder.yudao.module.member.vo.memberUserScore.*; import cn.iocoder.yudao.module.member.vo.memberUserScore.*;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScore.MemberUserScoreDO; import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScore.MemberUserScoreDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
...@@ -48,4 +48,8 @@ public interface MemberUserScoreService extends IService<MemberUserScoreDO> { ...@@ -48,4 +48,8 @@ public interface MemberUserScoreService extends IService<MemberUserScoreDO> {
* @return 会员积分列表 * @return 会员积分列表
*/ */
List<MemberUserScoreDO> getUserScoreList(MemberUserScoreQueryVO query); List<MemberUserScoreDO> getUserScoreList(MemberUserScoreQueryVO query);
void operate(MemberUserScoreOperateQueryVO query);
void updateUserScore(MemberUserScoreUpdateReqDTO query);
} }
...@@ -2,16 +2,31 @@ package cn.iocoder.yudao.module.member.service.memberUserScore; ...@@ -2,16 +2,31 @@ package cn.iocoder.yudao.module.member.service.memberUserScore;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService; import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.member.api.score.MemberUserScoreApi;
import cn.iocoder.yudao.module.member.api.score.MemberUserScoreApiImpl;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateReqDTO;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreOperateRespDTO;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreUpdateReqDTO;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScore.MemberUserScoreDO; import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScore.MemberUserScoreDO;
import cn.iocoder.yudao.module.member.dal.mysql.memberUserScore.MemberUserScoreMapper; import cn.iocoder.yudao.module.member.dal.mysql.memberUserScore.MemberUserScoreMapper;
import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum;
import cn.iocoder.yudao.module.member.enums.ScoreSourceTypeEnum;
import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreBackVO; import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreBackVO;
import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreOperateQueryVO;
import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreQueryVO; import cn.iocoder.yudao.module.member.vo.memberUserScore.MemberUserScoreQueryVO;
import com.alibaba.excel.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collection; import java.util.*;
import java.util.List; import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;
/** /**
* 会员积分 Service 实现类 * 会员积分 Service 实现类
...@@ -25,6 +40,9 @@ public class MemberUserScoreServiceImpl extends AbstractService<MemberUserScoreM ...@@ -25,6 +40,9 @@ public class MemberUserScoreServiceImpl extends AbstractService<MemberUserScoreM
@Resource @Resource
private MemberUserScoreMapper userScoreMapper; private MemberUserScoreMapper userScoreMapper;
@Resource
private MemberUserScoreApiImpl scoreApi;
@Override @Override
public void deleteUserScore(Long id) { public void deleteUserScore(Long id) {
// 删除 // 删除
...@@ -54,4 +72,75 @@ public class MemberUserScoreServiceImpl extends AbstractService<MemberUserScoreM ...@@ -54,4 +72,75 @@ public class MemberUserScoreServiceImpl extends AbstractService<MemberUserScoreM
public List<MemberUserScoreDO> getUserScoreList(MemberUserScoreQueryVO query) { public List<MemberUserScoreDO> getUserScoreList(MemberUserScoreQueryVO query) {
return userScoreMapper.selectList(query); return userScoreMapper.selectList(query);
} }
@Transactional(rollbackFor = Exception.class)
@Override
public void operate(MemberUserScoreOperateQueryVO query) {
if (CollectionUtils.isEmpty(query.getMemberIds())) {
throw exception(MEMBER_ID_IS_NULL);
}
if (query.getScoreCount() <= 0) {
throw exception(SCORE_COUNT_ERROR);
}
// 校验用户当前积分是否满足扣减要求
if (query.getOperateType() == 2) {
LambdaQueryWrapper<MemberUserScoreDO> wrapper = Wrappers.lambdaQuery();
wrapper.in(MemberUserScoreDO::getMemberId, query.getMemberIds());
List<MemberUserScoreDO> userScoreDOList = this.list(wrapper);
List<MemberUserScoreDO> notEnoughScoreList = userScoreDOList.stream()
.filter(item -> item.getHoldScore() < query.getScoreCount()).collect(Collectors.toList());
if (!notEnoughScoreList.isEmpty()) {
throw exception(MEMBER_SCORE_NOT_ENOUGH);
}
}
query.getMemberIds().forEach(memberId -> {
Map<String,Object> extParam = new HashMap<>();
extParam.put("comment", query.getComment());
MemberUserScoreOperateRespDTO memberUserScoreOperateRespDTO = scoreApi.operateScore(MemberUserScoreOperateReqDTO.builder()
.memberId(memberId)
.scoreCount(query.getScoreCount())
.operateType(ScoreOperateTypeEnum.parseByValue(query.getOperateType()))
.sourceType(ScoreSourceTypeEnum.MANUAL_OPERATE)
.extParam(extParam)
.build());
});
}
@Override
public void updateUserScore(MemberUserScoreUpdateReqDTO query) {
// 增加积分,只需要增加持有积分即可
// 减少积分,持有积分减少, 已兑换或者已失效积分增加
if (query.getMemberId() == null) {
throw exception(MEMBER_ID_IS_NULL);
}
MemberUserScoreDO memberUserScoreDO = userScoreMapper.getByMemberId(query.getMemberId());
if (memberUserScoreDO == null) {
memberUserScoreDO = initMemberUserScore(query.getMemberId());
}
if (query.getOperateType() == ScoreOperateTypeEnum.ADD) {
memberUserScoreDO.setHoldScore(memberUserScoreDO.getHoldScore() + query.getScoreCount());
this.saveOrUpdate(memberUserScoreDO);
}
if (query.getOperateType() == ScoreOperateTypeEnum.REDUCE) {
if (memberUserScoreDO.getHoldScore() < query.getScoreCount()) {
throw exception(MEMBER_SCORE_NOT_ENOUGH);
}
memberUserScoreDO.setHoldScore(memberUserScoreDO.getHoldScore() - query.getScoreCount());
if (ScoreSourceTypeEnum.getInvalidScoreStatusSourceType().contains(query.getSourceType())) {
memberUserScoreDO.setExpiredScore(memberUserScoreDO.getExpiredScore() + query.getScoreCount());
} else {
memberUserScoreDO.setUsedScore(memberUserScoreDO.getUsedScore() + query.getScoreCount());
}
this.saveOrUpdate(memberUserScoreDO);
}
}
private MemberUserScoreDO initMemberUserScore(Long memberId) {
MemberUserScoreDO memberUserScoreDO = new MemberUserScoreDO();
memberUserScoreDO.setMemberId(memberId);
memberUserScoreDO.setHoldScore(0);
memberUserScoreDO.setExpiredScore(0);
memberUserScoreDO.setUsedScore(0);
memberUserScoreDO.setCreateTime(new Date());
return memberUserScoreDO;
}
} }
package cn.iocoder.yudao.module.member.service.memberUserScoreDetail;
import cn.iocoder.yudao.framework.mybatis.core.service.IService;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreDetailUpdateReqDto;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreDetail.MemberUserScoreDetailDO;
/**
* 会员积分日志 Service 接口
*
* @author 系统管理员
*/
public interface MemberUserScoreDetailService extends IService<MemberUserScoreDetailDO> {
void updateScoreDetail(MemberUserScoreDetailUpdateReqDto reqDto);
}
package cn.iocoder.yudao.module.member.service.memberUserScoreDetail;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.member.api.score.dto.MemberUserScoreDetailUpdateReqDto;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreDetail.MemberUserScoreDetailDO;
import cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreDetail.MemberUserScoreDetailMapper;
import cn.iocoder.yudao.module.member.enums.MemberScoreStatueEnum;
import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addDays;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.getNextDayStart;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.MEMBER_ID_IS_NULL;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.MEMBER_SCORE_NOT_ENOUGH;
/**
* 会员积分详情 Service 实现类
*
* @author 系统管理员
*/
@Service
@Validated
public class MemberUserScoreDetailServiceImpl extends AbstractService<MemberUserScoreDetailMapper, MemberUserScoreDetailDO> implements MemberUserScoreDetailService {
@Resource
private MemberUserScoreDetailMapper detailMapper;
@Override
public void updateScoreDetail(MemberUserScoreDetailUpdateReqDto reqDto) {
// 增加积分,只需要新增一条记录
// 减少积分,使已有记录失效
if (reqDto.getMemberId() == null) {
throw exception(MEMBER_ID_IS_NULL);
}
if (reqDto.getOperateType() == ScoreOperateTypeEnum.ADD) {
update4Add(reqDto);
}
if (reqDto.getOperateType() == ScoreOperateTypeEnum.REDUCE) {
update4Reduce(reqDto);
}
}
private void update4Reduce(MemberUserScoreDetailUpdateReqDto reqDto) {
Long scoreCount = detailMapper.getScoreTotalByStatus(reqDto.getMemberId(), Lists.newArrayList(MemberScoreStatueEnum.AVAILABLE.getValue(), MemberScoreStatueEnum.PART_AVAILABLE.getValue()));
if (scoreCount == null || scoreCount < reqDto.getScoreCount()) {
throw exception(MEMBER_SCORE_NOT_ENOUGH);
}
LambdaQueryWrapper<MemberUserScoreDetailDO> wrappers = Wrappers.lambdaQuery();
wrappers.eq(MemberUserScoreDetailDO::getMemberId, reqDto.getMemberId());
wrappers.in(MemberUserScoreDetailDO::getStatus, Lists.newArrayList(MemberScoreStatueEnum.AVAILABLE.getValue(), MemberScoreStatueEnum.PART_AVAILABLE.getValue()));
wrappers.orderByAsc(MemberUserScoreDetailDO::getExpireTime);
List<MemberUserScoreDetailDO> detailList = this.list(wrappers);
int needCount = reqDto.getScoreCount();
List<MemberUserScoreDetailDO> updateDetailList = new ArrayList<>();
for (MemberUserScoreDetailDO memberUserScoreDetailDO : detailList) {
if (needCount == 0) {
break;
}
if (memberUserScoreDetailDO.getRemainCount() <= needCount) {
needCount -= memberUserScoreDetailDO.getRemainCount();
memberUserScoreDetailDO.setRemainCount(0);
memberUserScoreDetailDO.setStatus(MemberScoreStatueEnum.NOT_AVAILABLE.getValue());
memberUserScoreDetailDO.setExtParam(addScoreLogId(memberUserScoreDetailDO.getExtParam(), reqDto.getScoreLogId()));
updateDetailList.add(memberUserScoreDetailDO);
} else {
memberUserScoreDetailDO.setRemainCount(memberUserScoreDetailDO.getRemainCount() - needCount);
needCount = 0;
memberUserScoreDetailDO.setStatus(MemberScoreStatueEnum.PART_AVAILABLE.getValue());
memberUserScoreDetailDO.setExtParam(addScoreLogId(memberUserScoreDetailDO.getExtParam(), reqDto.getScoreLogId()));
updateDetailList.add(memberUserScoreDetailDO);
}
}
this.updateBatch(updateDetailList);
}
private void update4Add(MemberUserScoreDetailUpdateReqDto reqDto) {
MemberUserScoreDetailDO memberUserScoreDetailDO = new MemberUserScoreDetailDO();
memberUserScoreDetailDO.setMemberId(reqDto.getMemberId());
memberUserScoreDetailDO.setScoreCount(reqDto.getScoreCount());
memberUserScoreDetailDO.setStatus(MemberScoreStatueEnum.AVAILABLE.getValue());
memberUserScoreDetailDO.setRemainCount(reqDto.getScoreCount());
memberUserScoreDetailDO.setCreateTime(new Date());
if (reqDto.getExpireDays() != null) {
memberUserScoreDetailDO.setExpireTime(addDays(getNextDayStart(memberUserScoreDetailDO.getCreateTime()), reqDto.getExpireDays()));
}
Map<String, Object> extParma = new HashMap<>();
extParma.put(MemberUserScoreDetailDO.MemberUserScoreDetailExtKey.LOG_IDS.getKey(), Lists.newArrayList(reqDto.getScoreLogId()));
memberUserScoreDetailDO.setExtParam(JSONUtil.toJsonStr(extParma));
this.saveOrUpdate(memberUserScoreDetailDO);
}
private String addScoreLogId(String extParam, Long scoreLogId) {
JSONObject extParamJson = JSONUtil.parseObj(extParam);
if (extParam == null ){
extParamJson = new JSONObject();
}
List<Long> logIds = extParamJson.get(MemberUserScoreDetailDO.MemberUserScoreDetailExtKey.LOG_IDS.getKey(), List.class);
if (logIds == null) {
logIds = new ArrayList<>();
}
logIds.add(scoreLogId);
extParamJson.set(MemberUserScoreDetailDO.MemberUserScoreDetailExtKey.LOG_IDS.getKey(), logIds);
return extParamJson.toStringPretty();
}
}
...@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; ...@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.service.IService; import cn.iocoder.yudao.framework.mybatis.core.service.IService;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreLog.MemberUserScoreLogDO; import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreLog.MemberUserScoreLogDO;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogCreateReq;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO;
/** /**
...@@ -14,4 +15,6 @@ import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQu ...@@ -14,4 +15,6 @@ import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQu
public interface MemberUserScoreLogService extends IService<MemberUserScoreLogDO> { public interface MemberUserScoreLogService extends IService<MemberUserScoreLogDO> {
PageResult<MemberUserScoreLogBackVO> getPage(MemberUserScoreLogQueryVO query); PageResult<MemberUserScoreLogBackVO> getPage(MemberUserScoreLogQueryVO query);
Long createScoreLog(MemberUserScoreLogCreateReq createReq);
} }
package cn.iocoder.yudao.module.member.service.memberUserScoreLog; package cn.iocoder.yudao.module.member.service.memberUserScoreLog;
import cn.hutool.core.lang.generator.SnowflakeGenerator;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService; import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreLog.MemberUserScoreLogDO; import cn.iocoder.yudao.module.member.dal.dataobject.memberUserScoreLog.MemberUserScoreLogDO;
import cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreLog.MemberUserScoreLogMapper; import cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreLog.MemberUserScoreLogMapper;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBackVO;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogCreateReq;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO; import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO;
import cn.iocoder.yudao.module.system.service.dict.DictTypeService; import cn.iocoder.yudao.module.system.service.dict.DictTypeService;
import com.alibaba.excel.util.CollectionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collections;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.MEMBER_ID_IS_NULL;
/** /**
* 会员积分日志 Service 实现类 * 会员积分日志 Service 实现类
...@@ -28,6 +39,9 @@ public class MemberUserScoreLogServiceImpl extends AbstractService<MemberUserSco ...@@ -28,6 +39,9 @@ public class MemberUserScoreLogServiceImpl extends AbstractService<MemberUserSco
@Resource @Resource
private DictTypeService dictTypeService; private DictTypeService dictTypeService;
@Resource
private SnowflakeGenerator snowflakeGenerator;
@Override @Override
public PageResult<MemberUserScoreLogBackVO> getPage(MemberUserScoreLogQueryVO query) { public PageResult<MemberUserScoreLogBackVO> getPage(MemberUserScoreLogQueryVO query) {
...@@ -37,4 +51,23 @@ public class MemberUserScoreLogServiceImpl extends AbstractService<MemberUserSco ...@@ -37,4 +51,23 @@ public class MemberUserScoreLogServiceImpl extends AbstractService<MemberUserSco
int total = userScoreLogMapper.getPageCount(query); int total = userScoreLogMapper.getPageCount(query);
return new PageResult<>(list, total, query.getPageSize(), query.getPageNo(), (total + query.getPageSize() - 1) / query.getPageSize()); return new PageResult<>(list, total, query.getPageSize(), query.getPageNo(), (total + query.getPageSize() - 1) / query.getPageSize());
} }
@Override
public Long createScoreLog(MemberUserScoreLogCreateReq createReq) {
if (createReq.getMemberId() == null) {
throw exception(MEMBER_ID_IS_NULL);
}
MemberUserScoreLogDO userScoreLogDO = new MemberUserScoreLogDO();
userScoreLogDO.setId(snowflakeGenerator.next());
userScoreLogDO.setMemberId(createReq.getMemberId());
userScoreLogDO.setScoreCount(createReq.getScoreCount());
userScoreLogDO.setOperateType(createReq.getOperateType());
userScoreLogDO.setSourceType(createReq.getSourceType());
userScoreLogDO.setRuleId(createReq.getRuleId());
if (createReq.getExtParam() != null) {
userScoreLogDO.setExtParam(JSONUtil.toJsonStr(createReq.getExtParam()));
}
this.saveOrUpdate(userScoreLogDO);
return userScoreLogDO.getId();
}
} }
package cn.iocoder.yudao.module.member.vo.memberUserScore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* @author zhaobiyan
*/
@Data
@ApiModel("管理后台 - 操作积分 VO")
public class MemberUserScoreOperateQueryVO {
@ApiModelProperty(value = "会员id列表")
private List<Long> memberIds;
@ApiModelProperty(value = "操作类型 1:新增 2:删除")
private Integer operateType;
@ApiModelProperty(value = "积分数量")
private Integer scoreCount;
@ApiModelProperty(value = "备注")
private String comment;
}
package cn.iocoder.yudao.module.member.vo.memberUserScoreLog;
import lombok.Builder;
import lombok.Data;
import java.util.Map;
/**
* @author zhaobiyan
*/
@Data
@Builder
public class MemberUserScoreLogCreateReq {
private Long memberId;
private Integer scoreCount;
private Integer operateType;
private Integer sourceType;
private Long ruleId;
private Map<String, Object> extParam;
}
<?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="cn.iocoder.yudao.module.member.dal.mysql.memberUserScoreDetail.MemberUserScoreDetailMapper">
<select id="getScoreTotalByStatus" resultType="java.lang.Long">
select sum(remain_count)
from member_user_score_detail
where member_id = #{memberId}
<if test="statusList != null and statusList.size >0">
and status in
<foreach collection="statusList" item="status" open="(" close=")" separator=",">
#{status}
</foreach>
</if>
</select>
</mapper>
...@@ -30,6 +30,10 @@ ...@@ -30,6 +30,10 @@
where 1 = 1 where 1 = 1
<include refid="scoreCondition"/> <include refid="scoreCondition"/>
</select> </select>
<select id="getByMemberId"
resultType="cn.iocoder.yudao.module.member.dal.dataobject.memberUserScore.MemberUserScoreDO">
select * from member_user_score where member_id = #{memberId} and deleted = 0
</select>
<sql id="scoreCondition"> <sql id="scoreCondition">
<if test="query.key != null and query.key != ''"> <if test="query.key != null and query.key != ''">
......
...@@ -6,14 +6,14 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; ...@@ -6,14 +6,14 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
// TODO 待办:请将下面的错误码复制到 yudao-module-reward-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!! // TODO 待办:请将下面的错误码复制到 yudao-module-reward-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
// ========== 礼品 TODO 补充编号 ========== // ========== 礼品 TODO 补充编号 ==========
public interface ErrorCodeConstants { public interface ErrorCodeConstants {
ErrorCode REWARD_NOT_EXISTS = new ErrorCode(1010011001, "礼品不存在"); ErrorCode REWARD_NOT_EXISTS = new ErrorCode(1010011001, "reward.do.not.exist");
ErrorCode REWARD_ENDTIME_ERROR = new ErrorCode(1001011002, "礼品结束时间不能早于当前时间"); ErrorCode REWARD_ENDTIME_ERROR = new ErrorCode(1001011002, "reward.end.time.less.than.now");
ErrorCode REWARD_STATUS_NOT_ALLOW_DELETE = new ErrorCode(1001011003, "只有未启用可删除"); ErrorCode REWARD_STATUS_NOT_ALLOW_DELETE = new ErrorCode(1001011003, "reward.status.not.allow.delete");
ErrorCode REWARD_STATUS_NOT_ALLOW_ClOSE = new ErrorCode(1001011004, "未启用礼品不可关闭"); ErrorCode REWARD_STATUS_NOT_ALLOW_ClOSE = new ErrorCode(1001011004, "reward.status.not.allow.close");
ErrorCode REWARD_STATUS_CHANGE_ERROR = new ErrorCode(1001011005, "礼品状态操作不符合规则"); ErrorCode REWARD_STATUS_CHANGE_ERROR = new ErrorCode(1001011005, "reward.status.change.error");
ErrorCode REWARD_STATUS_NOT_ALLOW_DELAY = new ErrorCode(1001011006, "只允许延期启用状态礼品"); ErrorCode REWARD_STATUS_NOT_ALLOW_DELAY = new ErrorCode(1001011006, "reward.status.not.allow.delay");
ErrorCode REWARD_STATUS_NOT_ALLOW_CREATE = new ErrorCode(1001011007, "创建的礼品状态只能是启用或未启用"); ErrorCode REWARD_STATUS_NOT_ALLOW_CREATE = new ErrorCode(1001011007, "reward.status.not.allow.create");
ErrorCode REWARD_START_OR_END_TIME_NOT_ALLOW_CREATE = new ErrorCode(1001011008, "活动时间不合法"); ErrorCode REWARD_START_OR_END_TIME_NOT_ALLOW_CREATE = new ErrorCode(1001011008, "reward.time.not.allow");
ErrorCode REWARD_PICK_METHOD_NOT_ALLOW_CREATE = new ErrorCode(1001011009, "领取方式不合法"); ErrorCode REWARD_PICK_METHOD_NOT_ALLOW_CREATE = new ErrorCode(1001011009, "领取方式不合法");
ErrorCode REWARD_STATUS_NOT_ALLOW_UPDATE = new ErrorCode(1001011010, "礼物状态不允许编辑"); ErrorCode REWARD_STATUS_NOT_ALLOW_UPDATE = new ErrorCode(1001011010, "礼物状态不允许编辑");
ErrorCode REWARD_STATUS_NOT_ALLOW_ENABLE = new ErrorCode(1001011011, "礼物不能启用"); ErrorCode REWARD_STATUS_NOT_ALLOW_ENABLE = new ErrorCode(1001011011, "礼物不能启用");
......
...@@ -42,7 +42,7 @@ public class RewardController { ...@@ -42,7 +42,7 @@ public class RewardController {
return success(rewardService.create(createReqVO)); return success(rewardService.create(createReqVO));
} }
@PutMapping("/update") @PostMapping("/update")
@ApiOperation("更新礼品") @ApiOperation("更新礼品")
//@PreAuthorize("@ss.hasPermission('reward::update')") //@PreAuthorize("@ss.hasPermission('reward::update')")
public CommonResult<Boolean> update(@Valid @RequestBody RewardUpdateReqVO updateReqVO) { public CommonResult<Boolean> update(@Valid @RequestBody RewardUpdateReqVO updateReqVO) {
......
...@@ -114,6 +114,7 @@ yudao: ...@@ -114,6 +114,7 @@ yudao:
- cn.iocoder.yudao.module.wealth.enums.ErrorCodeConstants - cn.iocoder.yudao.module.wealth.enums.ErrorCodeConstants
- cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants - cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants
- cn.iocoder.yudao.module.system.enums.ErrorCodeConstants - cn.iocoder.yudao.module.system.enums.ErrorCodeConstants
- cn.iocoder.yudao.module.reward.enums.ErrorCodeConstants
tenant: # 多租户相关配置项 tenant: # 多租户相关配置项
enable: false enable: false
ignore-urls: ignore-urls:
......
...@@ -262,3 +262,5 @@ order.already.in.merge.pkg= ...@@ -262,3 +262,5 @@ order.already.in.merge.pkg=
customer.is.new.or.old.no.change= customer.is.new.or.old.no.change=
order.is.pre.installed= order.is.pre.installed=
order.is.not.pre.installed= order.is.not.pre.installed=
member.id.is.null=
score.count.error=
\ No newline at end of file
...@@ -998,4 +998,15 @@ order.already.in.merge.pkg=The order has been placed under the packaging box ...@@ -998,4 +998,15 @@ order.already.in.merge.pkg=The order has been placed under the packaging box
customer.is.new.or.old.no.change=customer current business type is {}, it's no change customer.is.new.or.old.no.change=customer current business type is {}, it's no change
order.is.pre.installed=Order pre installed order.is.pre.installed=Order pre installed
customer.delay.approval.times.more.then.one=delay approval times more then one customer.delay.approval.times.more.then.one=delay approval times more then one
member.id.is.null=no member ids
score.count.error= score count must > 0
member.score.not.enough = member score not enough
reward.do.not.exist=The reward does not exist
reward.end.time.less.than.now=The reward end time is less than the current time
reward.status.not.allow.delete=Only not enable can delete
reward.status.not.allow.close=Not enable reward can not close
reward.status.change.error=The reward status change error
reward.status.not.allow.delay=Only enable status can delay
reward.status.not.allow.create=Only enabled or disabled reward status can be created
reward.time.not.allow=The reward time is not allow
\ No newline at end of file
...@@ -1002,3 +1002,15 @@ order.already.in.merge.pkg=\u8BA2\u5355\u5DF2\u5728\u5408\u5305\u7BB1\u4E0B ...@@ -1002,3 +1002,15 @@ order.already.in.merge.pkg=\u8BA2\u5355\u5DF2\u5728\u5408\u5305\u7BB1\u4E0B
customer.is.new.or.old.no.change=\u5BA2\u6237\u5F53\u524D\u4E1A\u7EE9\u7C7B\u578B\u662F{}\u5BA2\u6237\uFF0C\u4E0D\u9700\u8981\u66F4\u65B0 customer.is.new.or.old.no.change=\u5BA2\u6237\u5F53\u524D\u4E1A\u7EE9\u7C7B\u578B\u662F{}\u5BA2\u6237\uFF0C\u4E0D\u9700\u8981\u66F4\u65B0
order.is.pre.installed=\u8BA2\u5355\u5DF2\u9884\u88C5 order.is.pre.installed=\u8BA2\u5355\u5DF2\u9884\u88C5
order.is.not.pre.installed =\u8BA2\u5355\u672A\u88C5\u7BB1\uFF0C\u4E0D\u80FD\u5408\u5305 order.is.not.pre.installed =\u8BA2\u5355\u672A\u88C5\u7BB1\uFF0C\u4E0D\u80FD\u5408\u5305
member.id.is.null=\u7F3A\u5C11\u4F1A\u5458id
score.count.error=\u79EF\u5206\u5FC5\u987B > 0
member.score.not.enough = \u4F1A\u5458\u79EF\u5206\u4E0D\u8DB3
reward.do.not.exist=\u793C\u54C1\u4E0D\u5B58\u5728
reward.end.time.less.than.now=\u793C\u54C1\u7ED3\u675F\u65F6\u95F4\u4E0D\u80FD\u65E9\u4E8E\u5F53\u524D\u65F6\u95F4
reward.status.not.allow.delete=\u53EA\u6709\u672A\u542F\u7528\u53EF\u5220\u9664
reward.status.not.allow.close=\u672A\u542F\u7528\u793C\u54C1\u4E0D\u53EF\u5173\u95ED
reward.status.change.error=\u793C\u54C1\u72B6\u6001\u64CD\u4F5C\u4E0D\u7B26\u5408\u89C4\u5219
reward.status.not.allow.delay=\u53EA\u5141\u8BB8\u5EF6\u671F\u542F\u7528\u72B6\u6001\u793C\u54C1
reward.status.not.allow.create=\u521B\u5EFA\u7684\u793C\u54C1\u72B6\u6001\u53EA\u80FD\u662F\u542F\u7528\u6216\u672A\u542F\u7528
reward.time.not.allow=\u6D3B\u52A8\u65F6\u95F4\u4E0D\u5408\u6CD5
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment