会员:后台调整会员等级

plp
owen 3 years ago
parent f884054d2c
commit 8ffbc15cec

@ -9,7 +9,7 @@ create table member_level
name varchar(30) default '' not null comment '', name varchar(30) default '' not null comment '',
experience int default 0 not null comment '', experience int default 0 not null comment '',
level int default 0 not null comment '', level int default 0 not null comment '',
discount int(4) default 100 not null comment '', discount tinyint default 100 not null comment '',
icon varchar(255) default '' not null comment '', icon varchar(255) default '' not null comment '',
background_url varchar(255) default '' not null comment '', background_url varchar(255) default '' not null comment '',
status tinyint default 0 not null comment '', status tinyint default 0 not null comment '',
@ -28,9 +28,9 @@ create table member_level_log
user_id bigint default 0 not null comment '', user_id bigint default 0 not null comment '',
level_id bigint default 0 not null comment '', level_id bigint default 0 not null comment '',
level int default 0 not null comment '', level int default 0 not null comment '',
discount int(4) default 100 not null comment '', discount tinyint default 100 not null comment '',
experience int(4) default 0 not null comment '', experience int default 0 not null comment '',
user_experience int(4) default 0 not null comment '', user_experience int default 0 not null comment '',
remark varchar(255) default '' not null comment '', remark varchar(255) default '' not null comment '',
description varchar(255) default '' not null comment '', description varchar(255) default '' not null comment '',
creator varchar(64) default '' null comment '', creator varchar(64) default '' null comment '',
@ -68,54 +68,27 @@ create index idx_user_biz_type on member_experience_log (user_id, biz_type) comm
-- --
insert system_dict_type(name, type) values ('', 'member_experience_biz_type'); insert system_dict_type(name, type) values ('', 'member_experience_biz_type');
insert system_dict_data(dict_type, label, value, sort) values ('member_experience_biz_type', '', '0', 0); insert system_dict_data(dict_type, label, value, sort) values ('member_experience_biz_type', '', '0', 0);
insert system_dict_data(dict_type, label, value, sort) values ('member_experience_biz_type', '', '1', 1); insert system_dict_data(dict_type, label, value, sort) values ('member_experience_biz_type', '', '1', 1);
insert system_dict_data(dict_type, label, value, sort) values ('member_experience_biz_type', '', '2', 2); insert system_dict_data(dict_type, label, value, sort) values ('member_experience_biz_type', '', '2', 2);
insert system_dict_data(dict_type, label, value, sort) values ('member_experience_biz_type', '退', '3', 3);
insert system_dict_data(dict_type, label, value, sort) values ('member_experience_biz_type', '', '4', 4);
insert system_dict_data(dict_type, label, value, sort) values ('member_experience_biz_type', '', '5', 5);
-- SQL -- SQL
INSERT INTO system_menu( INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)
name, permission, type, sort, parent_id, VALUES ('', '', 2, 3, 2262, 'level', '', 'member/level/index', 0, 'MemberLevel');
path, icon, component, status, component_name
)
VALUES (
'', '', 2, 3, 2262,
'level', '', 'member/level/index', 0, 'MemberLevel'
);
-- ID -- ID
-- MySQL OraclePostgreSQLSQLServer @parentId -- MySQL OraclePostgreSQLSQLServer @parentId
SELECT @parentId := LAST_INSERT_ID(); SELECT @parentId := LAST_INSERT_ID();
-- SQL -- SQL
INSERT INTO system_menu( INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
name, permission, type, sort, parent_id, VALUES ('', 'member:level:query', 3, 1, @parentId, '', '', '', 0);
path, icon, component, status INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
) VALUES ('', 'member:level:create', 3, 2, @parentId, '', '', '', 0);
VALUES ( INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
'', 'member:level:query', 3, 1, @parentId, VALUES ('', 'member:level:update', 3, 3, @parentId, '', '', '', 0);
'', '', '', 0 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
); VALUES ('', 'member:level:delete', 3, 4, @parentId, '', '', '', 0);
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status
)
VALUES (
'', 'member:level:create', 3, 2, @parentId,
'', '', '', 0
);
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status
)
VALUES (
'', 'member:level:update', 3, 3, @parentId,
'', '', '', 0
);
INSERT INTO system_menu(
name, permission, type, sort, parent_id,
path, icon, component, status
)
VALUES (
'', 'member:level:delete', 3, 4, @parentId,
'', '', '', 0
);

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.member.api.level;
import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
/**
* API
*
* @author owen
*/
public interface MemberLevelApi {
/**
*
*
* @param userId ID
* @param experience
* @param bizType
* @param bizId
*/
void plusExperience(Long userId, Integer experience, MemberExperienceBizTypeEnum bizType, String bizId);
}

@ -51,4 +51,5 @@ public interface ErrorCodeConstants {
ErrorCode LEVEL_LOG_NOT_EXISTS = new ErrorCode(1004007100, "会员等级记录不存在"); ErrorCode LEVEL_LOG_NOT_EXISTS = new ErrorCode(1004007100, "会员等级记录不存在");
ErrorCode EXPERIENCE_LOG_NOT_EXISTS = new ErrorCode(1004007200, "会员经验记录不存在"); ErrorCode EXPERIENCE_LOG_NOT_EXISTS = new ErrorCode(1004007200, "会员经验记录不存在");
ErrorCode LEVEL_REASON_NOT_EXISTS = new ErrorCode(1004007300, "会员等级调整原因不能为空");
} }

@ -12,13 +12,17 @@ import lombok.Getter;
@AllArgsConstructor @AllArgsConstructor
public enum MemberExperienceBizTypeEnum { public enum MemberExperienceBizTypeEnum {
/** /**
* * 退
*/ */
SYSTEM(0, "系统"), ADMIN(0, "管理员调整","管理员调整获得{}经验"),
ORDER(1, "订单"), INVITE_REGISTER(1, "邀新奖励","邀请好友获得{}经验"),
SIGN_IN(2, "签到"), ORDER(2, "下单奖励", "下单获得{}经验"),
REFUND(3, "退单扣除","退单获得{}经验"),
SIGN_IN(4, "签到奖励","签到获得{}经验"),
LOTTERY(5, "抽奖奖励","抽奖获得{}经验"),
; ;
private final int value; private final int value;
private final String name; private final String title;
private final String desc;
} }

@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.member.api.level;
import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
import cn.iocoder.yudao.module.member.service.level.MemberLevelService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* API
*
* @author owen
*/
@Service
@Validated
public class MemberLevelApiImpl implements MemberLevelApi {
@Resource
private MemberLevelService memberLevelService;
public void plusExperience(Long userId, Integer experience, MemberExperienceBizTypeEnum bizType, String bizId) {
memberLevelService.plusExperience(userId, experience, bizType, bizId);
}
}

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.member.controller.admin.level; package cn.iocoder.yudao.module.member.controller.admin.level;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
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.module.member.controller.admin.level.vo.*; import cn.iocoder.yudao.module.member.controller.admin.level.vo.*;
@ -77,9 +76,9 @@ public class MemberLevelController {
@GetMapping("/list-all-simple") @GetMapping("/list-all-simple")
@Operation(summary = "获取会员等级精简信息列表", description = "只包含被开启的会员等级,主要用于前端的下拉选项") @Operation(summary = "获取会员等级精简信息列表", description = "只包含被开启的会员等级,主要用于前端的下拉选项")
public CommonResult<List<MemberLevelSimpleRespVO>> getSimpleUserList() { public CommonResult<List<MemberLevelSimpleRespVO>> getSimpleLevelList() {
// 获用户列表,只要开启状态的 // 获用户列表,只要开启状态的
List<MemberLevelDO> list = levelService.getLevelListByStatus(CommonStatusEnum.ENABLE.getStatus()); List<MemberLevelDO> list = levelService.getEnableLevelList();
// 排序后,返回给前端 // 排序后,返回给前端
return success(MemberLevelConvert.INSTANCE.convertSimpleList(list)); return success(MemberLevelConvert.INSTANCE.convertSimpleList(list));
} }

@ -7,8 +7,10 @@ import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReq
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserRespVO; import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserRespVO;
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO; import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert; import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO; import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.service.level.MemberLevelService;
import cn.iocoder.yudao.module.member.service.tag.MemberTagService; import cn.iocoder.yudao.module.member.service.tag.MemberTagService;
import cn.iocoder.yudao.module.member.service.user.MemberUserService; import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
@ -38,6 +40,8 @@ public class MemberUserController {
private MemberUserService memberUserService; private MemberUserService memberUserService;
@Resource @Resource
private MemberTagService memberTagService; private MemberTagService memberTagService;
@Resource
private MemberLevelService memberLevelService;
@PutMapping("/update") @PutMapping("/update")
@Operation(summary = "更新会员用户") @Operation(summary = "更新会员用户")
@ -72,7 +76,11 @@ public class MemberUserController {
.flatMap(Collection::stream) .flatMap(Collection::stream)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
List<MemberTagDO> tags = memberTagService.getTagList(tagIds); List<MemberTagDO> tags = memberTagService.getTagList(tagIds);
return success(MemberUserConvert.INSTANCE.convertPage(pageResult, tags));
// 处理会员级别返显
List<MemberLevelDO> levels = memberLevelService.getEnableLevelList();
return success(MemberUserConvert.INSTANCE.convertPage(pageResult, tags, levels));
} }
} }

@ -53,4 +53,7 @@ public class MemberUserBaseVO {
@Schema(description = "会员标签", example = "[1, 2]") @Schema(description = "会员标签", example = "[1, 2]")
private List<Long> tagIds; private List<Long> tagIds;
@Schema(description = "会员等级编号", example = "1")
private Long levelId;
} }

@ -32,7 +32,10 @@ public class MemberUserPageReqVO extends PageParam {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime; private LocalDateTime[] createTime;
@Schema(description = "会员标签", example = "[1, 2]") @Schema(description = "会员标签编号列表", example = "[1, 2]")
private List<Long> tagIds; private List<Long> tagIds;
@Schema(description = "会员等级标号", example = "1")
private Long levelId;
} }

@ -35,4 +35,7 @@ public class MemberUserRespVO extends MemberUserBaseVO {
@Schema(description = "会员标签", example = "[红色, 快乐]") @Schema(description = "会员标签", example = "[红色, 快乐]")
private List<String> tagNames; private List<String> tagNames;
@Schema(description = "会员等级", example = "黄金会员")
private String levelName;
} }

@ -17,4 +17,7 @@ public class MemberUserUpdateReqVO extends MemberUserBaseVO {
@NotNull(message = "编号不能为空") @NotNull(message = "编号不能为空")
private Long id; private Long id;
@Schema(description = "会员级别修改原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "推广需要")
private String levelReason;
} }

@ -1,10 +1,13 @@
package cn.iocoder.yudao.module.member.convert.user; package cn.iocoder.yudao.module.member.convert.user;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserRespVO; import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserRespVO;
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO; import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserInfoRespVO; import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserInfoRespVO;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO; import cn.iocoder.yudao.module.member.dal.dataobject.tag.MemberTagDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
@ -34,11 +37,18 @@ public interface MemberUserConvert {
MemberUserRespVO convert03(MemberUserDO bean); MemberUserRespVO convert03(MemberUserDO bean);
default PageResult<MemberUserRespVO> convertPage(PageResult<MemberUserDO> pageResult, default PageResult<MemberUserRespVO> convertPage(PageResult<MemberUserDO> pageResult,
List<MemberTagDO> tags) { List<MemberTagDO> tags,
List<MemberLevelDO> levels) {
PageResult<MemberUserRespVO> result = convertPage(pageResult); PageResult<MemberUserRespVO> result = convertPage(pageResult);
// 处理关联数据
Map<Long, String> tagMap = convertMap(tags, MemberTagDO::getId, MemberTagDO::getName); Map<Long, String> tagMap = convertMap(tags, MemberTagDO::getId, MemberTagDO::getName);
Map<Long, String> levelMap = convertMap(levels, MemberLevelDO::getId, MemberLevelDO::getName);
// 填充关联数据
for (MemberUserRespVO vo : result.getList()) { for (MemberUserRespVO vo : result.getList()) {
vo.setTagNames(convertList(vo.getTagIds(), tagMap::get)); vo.setTagNames(convertList(vo.getTagIds(), tagMap::get));
vo.setLevelName(MapUtil.getStr(levelMap, vo.getLevelId(), StrUtil.EMPTY));
} }
return result; return result;
} }

@ -26,6 +26,8 @@ public interface MemberLevelMapper extends BaseMapperX<MemberLevelDO> {
default List<MemberLevelDO> selectListByStatus(Integer status) { default List<MemberLevelDO> selectListByStatus(Integer status) {
return selectList(MemberLevelDO::getStatus, status); return selectList(new LambdaQueryWrapperX<MemberLevelDO>()
.eq(MemberLevelDO::getStatus, status)
.orderByAsc(MemberLevelDO::getLevel));
} }
} }

@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO; import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List; import java.util.List;
@ -47,4 +48,16 @@ public interface MemberUserMapper extends BaseMapperX<MemberUserDO> {
.orderByDesc(MemberUserDO::getId)); .orderByDesc(MemberUserDO::getId));
} }
/**
*
*
* @param userId
* @return
*/
default int cancelUserLevel(Long userId) {
return update(null, new LambdaUpdateWrapper<MemberUserDO>()
.eq(MemberUserDO::getId, userId)
.set(MemberUserDO::getExperience, 0)
.set(MemberUserDO::getLevelId, null));
}
} }

@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceLogExportReqVO; import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceLogExportReqVO;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceLogPageReqVO; import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceLogPageReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberExperienceLogDO; import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberExperienceLogDO;
import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -54,4 +55,23 @@ public interface MemberExperienceLogService {
*/ */
List<MemberExperienceLogDO> getExperienceLogList(MemberExperienceLogExportReqVO exportReqVO); List<MemberExperienceLogDO> getExperienceLogList(MemberExperienceLogExportReqVO exportReqVO);
/**
*
*
* @param userId
* @param experience
* @param totalExperience
*/
void createAdjustLog(Long userId, int experience, int totalExperience);
/**
* ,
*
* @param userId
* @param experience
* @param totalExperience
* @param bizType
* @param bizId ID
*/
void createBizLog(Long userId, int experience, int totalExperience, MemberExperienceBizTypeEnum bizType, String bizId);
} }

@ -1,10 +1,12 @@
package cn.iocoder.yudao.module.member.service.level; package cn.iocoder.yudao.module.member.service.level;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceLogExportReqVO; import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceLogExportReqVO;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceLogPageReqVO; import cn.iocoder.yudao.module.member.controller.admin.level.vo.experience.MemberExperienceLogPageReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberExperienceLogDO; import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberExperienceLogDO;
import cn.iocoder.yudao.module.member.dal.mysql.level.MemberExperienceLogMapper; import cn.iocoder.yudao.module.member.dal.mysql.level.MemberExperienceLogMapper;
import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -61,4 +63,24 @@ public class MemberExperienceLogServiceImpl implements MemberExperienceLogServic
return experienceLogMapper.selectList(exportReqVO); return experienceLogMapper.selectList(exportReqVO);
} }
@Override
public void createAdjustLog(Long userId, int experience, int totalExperience) {
// 管理员调整时, 没有业务编号, 记录对应的枚举值
String bizId = MemberExperienceBizTypeEnum.ADMIN.getValue() + "";
this.createBizLog(userId, experience, totalExperience, MemberExperienceBizTypeEnum.ADMIN, bizId);
}
@Override
public void createBizLog(Long userId, int experience, int totalExperience, MemberExperienceBizTypeEnum bizType, String bizId) {
MemberExperienceLogDO experienceLogDO = new MemberExperienceLogDO();
experienceLogDO.setUserId(userId);
experienceLogDO.setExperience(experience);
experienceLogDO.setTotalExperience(totalExperience);
experienceLogDO.setBizId(bizId);
experienceLogDO.setBizType(bizType.getValue());
experienceLogDO.setTitle(bizType.getTitle());
experienceLogDO.setDescription(StrUtil.format(bizType.getDesc(), experience));
experienceLogMapper.insert(experienceLogDO);
}
} }

@ -3,7 +3,9 @@ package cn.iocoder.yudao.module.member.service.level;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.log.MemberLevelLogExportReqVO; import cn.iocoder.yudao.module.member.controller.admin.level.vo.log.MemberLevelLogExportReqVO;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.log.MemberLevelLogPageReqVO; import cn.iocoder.yudao.module.member.controller.admin.level.vo.log.MemberLevelLogPageReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelLogDO; import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelLogDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -54,4 +56,29 @@ public interface MemberLevelLogService {
*/ */
List<MemberLevelLogDO> getLevelLogList(MemberLevelLogExportReqVO exportReqVO); List<MemberLevelLogDO> getLevelLogList(MemberLevelLogExportReqVO exportReqVO);
/**
*
*
* @param userId
* @param reason
*/
void createCancelLog(Long userId, String reason);
/**
*
*
* @param user
* @param level
* @param experience
* @param reason
*/
void createAdjustLog(MemberUserDO user, MemberLevelDO level, int experience, String reason);
/**
*
*
* @param user
* @param level
*/
void createAutoUpgradeLog(MemberUserDO user, MemberLevelDO level);
} }

@ -3,7 +3,9 @@ package cn.iocoder.yudao.module.member.service.level;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.log.MemberLevelLogExportReqVO; import cn.iocoder.yudao.module.member.controller.admin.level.vo.log.MemberLevelLogExportReqVO;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.log.MemberLevelLogPageReqVO; import cn.iocoder.yudao.module.member.controller.admin.level.vo.log.MemberLevelLogPageReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelLogDO; import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelLogDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.level.MemberLevelLogMapper; import cn.iocoder.yudao.module.member.dal.mysql.level.MemberLevelLogMapper;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -61,4 +63,53 @@ public class MemberLevelLogServiceImpl implements MemberLevelLogService {
return levelLogMapper.selectList(exportReqVO); return levelLogMapper.selectList(exportReqVO);
} }
@Override
public void createCancelLog(Long userId, String reason) {
MemberLevelLogDO levelLogDO = new MemberLevelLogDO();
levelLogDO.setUserId(userId);
levelLogDO.setRemark(reason);
levelLogDO.setDescription("管理员取消");
levelLogMapper.insert(levelLogDO);
// 给会员发送等级变动消息
notifyMember(userId, levelLogDO);
}
@Override
public void createAdjustLog(MemberUserDO user, MemberLevelDO level, int experience, String reason) {
MemberLevelLogDO levelLogDO = new MemberLevelLogDO();
levelLogDO.setUserId(user.getId());
levelLogDO.setLevelId(level.getId());
levelLogDO.setLevel(level.getLevel());
levelLogDO.setDiscount(level.getDiscount());
levelLogDO.setUserExperience(level.getExperience());
levelLogDO.setExperience(experience);
levelLogDO.setRemark(reason);
levelLogDO.setDescription("管理员调整为:" + level.getName());
levelLogMapper.insert(levelLogDO);
// 给会员发送等级变动消息
notifyMember(user.getId(), levelLogDO);
}
@Override
public void createAutoUpgradeLog(MemberUserDO user, MemberLevelDO level) {
MemberLevelLogDO levelLogDO = new MemberLevelLogDO();
levelLogDO.setUserId(user.getId());
levelLogDO.setLevelId(level.getId());
levelLogDO.setLevel(level.getLevel());
levelLogDO.setDiscount(level.getDiscount());
levelLogDO.setExperience(level.getExperience());
levelLogDO.setUserExperience(user.getExperience());
levelLogDO.setDescription("成为:" + level.getName());
levelLogMapper.insert(levelLogDO);
// 给会员发送等级变动消息
notifyMember(user.getId(), levelLogDO);
}
private void notifyMember(Long userId, MemberLevelLogDO level) {
//todo: 给会员发消息
}
} }

@ -1,11 +1,15 @@
package cn.iocoder.yudao.module.member.service.level; package cn.iocoder.yudao.module.member.service.level;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.MemberLevelCreateReqVO; import cn.iocoder.yudao.module.member.controller.admin.level.vo.MemberLevelCreateReqVO;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.MemberLevelPageReqVO; import cn.iocoder.yudao.module.member.controller.admin.level.vo.MemberLevelPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.MemberLevelUpdateReqVO; import cn.iocoder.yudao.module.member.controller.admin.level.vo.MemberLevelUpdateReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
import javax.annotation.Nullable;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -71,4 +75,33 @@ public interface MemberLevelService {
* @return * @return
*/ */
List<MemberLevelDO> getLevelListByStatus(Integer status); List<MemberLevelDO> getLevelListByStatus(Integer status);
/**
*
*
* @return
*/
default List<MemberLevelDO> getEnableLevelList() {
return getLevelListByStatus(CommonStatusEnum.ENABLE.getStatus());
}
/**
*
*
* @param user
* @param levelId
* @param levelReason
*/
void updateUserLevel(MemberUserDO user, @Nullable Long levelId, String levelReason);
/**
*
*
* @param userId ID
* @param experience
* @param bizType
* @param bizId
*/
void plusExperience(Long userId, Integer experience, MemberExperienceBizTypeEnum bizType, String bizId);
} }

@ -1,6 +1,9 @@
package cn.iocoder.yudao.module.member.service.level; package cn.iocoder.yudao.module.member.service.level;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.member.controller.admin.level.vo.MemberLevelCreateReqVO; import cn.iocoder.yudao.module.member.controller.admin.level.vo.MemberLevelCreateReqVO;
@ -8,14 +11,19 @@ import cn.iocoder.yudao.module.member.controller.admin.level.vo.MemberLevelPageR
import cn.iocoder.yudao.module.member.controller.admin.level.vo.MemberLevelUpdateReqVO; import cn.iocoder.yudao.module.member.controller.admin.level.vo.MemberLevelUpdateReqVO;
import cn.iocoder.yudao.module.member.convert.level.MemberLevelConvert; import cn.iocoder.yudao.module.member.convert.level.MemberLevelConvert;
import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO; import cn.iocoder.yudao.module.member.dal.dataobject.level.MemberLevelDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.level.MemberLevelMapper; import cn.iocoder.yudao.module.member.dal.mysql.level.MemberLevelMapper;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.member.enums.MemberExperienceBizTypeEnum;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
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.Collection;
import java.util.Comparator;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -33,6 +41,12 @@ public class MemberLevelServiceImpl implements MemberLevelService {
@Resource @Resource
private MemberLevelMapper levelMapper; private MemberLevelMapper levelMapper;
@Resource
private MemberLevelLogService memberLevelLogService;
@Resource
private MemberExperienceLogService memberExperienceLogService;
@Resource
private MemberUserMapper memberUserMapper;
@Override @Override
public Long createLevel(MemberLevelCreateReqVO createReqVO) { public Long createLevel(MemberLevelCreateReqVO createReqVO) {
@ -153,4 +167,113 @@ public class MemberLevelServiceImpl implements MemberLevelService {
public List<MemberLevelDO> getLevelListByStatus(Integer status) { public List<MemberLevelDO> getLevelListByStatus(Integer status) {
return levelMapper.selectListByStatus(status); return levelMapper.selectListByStatus(status);
} }
@Transactional(rollbackFor = Exception.class)
@Override
public void updateUserLevel(MemberUserDO user, Long levelId, String reason) {
// 未调整的情况1
if (user.getLevelId() == null && levelId == null) {
return;
}
// 未调整的情况2
if (ObjUtil.equal(user.getLevelId(), levelId)) {
return;
}
// 需要后台用户填写为什么调整会员的等级
if (StrUtil.isBlank(reason)) {
throw exception(LEVEL_REASON_NOT_EXISTS);
}
int experience;
int totalExperience = 0;
// 记录等级变动
if (levelId == null) {
experience = -user.getExperience();
// 取消了会员的等级
memberLevelLogService.createCancelLog(user.getId(), reason);
memberUserMapper.cancelUserLevel(user.getId());
} else {
MemberLevelDO level = validateLevelExists(levelId);
// 变动经验值 = 等级的升级经验 - 会员当前的经验;正数为增加经验,负数为扣减经验
experience = level.getExperience() - user.getExperience();
// 会员当前的经验 = 等级的升级经验
totalExperience = level.getExperience();
memberLevelLogService.createAdjustLog(user, level, experience, reason);
// 更新会员表上的等级编号、经验值
updateUserLevelIdAndExperience(user.getId(), levelId, totalExperience);
}
// 记录会员经验变动
memberExperienceLogService.createAdjustLog(user.getId(), experience, totalExperience);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void plusExperience(Long userId, Integer experience, MemberExperienceBizTypeEnum bizType, String bizId) {
if (experience == 0) {
return;
}
MemberUserDO user = memberUserMapper.selectById(userId);
if (user.getExperience() == null) {
user.setExperience(0);
}
// 防止扣出负数
int userExperience = NumberUtil.max(user.getExperience() + experience, 0);
// 创建经验记录
memberExperienceLogService.createBizLog(userId, experience, userExperience, bizType, bizId);
// 计算会员等级
Long levelId = calcLevel(user, userExperience);
// 更新会员表上的等级编号、经验值
updateUserLevelIdAndExperience(user.getId(), levelId, userExperience);
}
private void updateUserLevelIdAndExperience(Long userId, Long levelId, Integer experience) {
memberUserMapper.updateById(new MemberUserDO()
.setId(userId)
.setLevelId(levelId).setExperience(experience)
);
}
/**
*
*
* @param user
* @param userExperience
* @return null
*/
private Long calcLevel(MemberUserDO user, int userExperience) {
List<MemberLevelDO> list = getEnableLevelList();
if (CollUtil.isEmpty(list)) {
log.warn("计算会员等级失败:会员等级配置不存在");
return null;
}
MemberLevelDO matchLevel = list.stream()
.filter(level -> userExperience >= level.getExperience())
.max(Comparator.nullsFirst(Comparator.comparing(MemberLevelDO::getLevel)))
.orElse(null);
if (matchLevel == null) {
log.warn("计算会员等级失败:未找到会员{}经验{}对应的等级配置", user.getId(), userExperience);
return null;
}
// 等级没有变化
if (ObjectUtil.equal(matchLevel.getId(), user.getLevelId())) {
return null;
}
// 保存等级变更记录
memberLevelLogService.createAutoUpgradeLog(user, matchLevel);
return matchLevel.getId();
}
} }

@ -8,13 +8,14 @@ import cn.iocoder.yudao.module.infra.api.file.FileApi;
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO; import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO; import cn.iocoder.yudao.module.member.controller.admin.user.vo.MemberUserUpdateReqVO;
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserResetPasswordReqVO; import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserResetPasswordReqVO;
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserUpdateMobileReqVO;
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserUpdatePasswordReqVO; import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserUpdatePasswordReqVO;
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserUpdateReqVO; import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserUpdateReqVO;
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppMemberUserUpdateMobileReqVO;
import cn.iocoder.yudao.module.member.convert.auth.AuthConvert; import cn.iocoder.yudao.module.member.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert; import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.member.service.level.MemberLevelService;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi; import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
@ -55,6 +56,9 @@ public class MemberUserServiceImpl implements MemberUserService {
@Resource @Resource
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
@Resource
private MemberLevelService memberLevelService;
@Override @Override
public MemberUserDO getUserByMobile(String mobile) { public MemberUserDO getUserByMobile(String mobile) {
return memberUserMapper.selectByMobile(mobile); return memberUserMapper.selectByMobile(mobile);
@ -180,16 +184,20 @@ public class MemberUserServiceImpl implements MemberUserService {
return passwordEncoder.encode(password); return passwordEncoder.encode(password);
} }
@Transactional(rollbackFor = Exception.class)
@Override @Override
public void updateUser(MemberUserUpdateReqVO updateReqVO) { public void updateUser(MemberUserUpdateReqVO updateReqVO) {
// 校验存在 // 校验存在
validateUserExists(updateReqVO.getId()); MemberUserDO user = validateUserExists(updateReqVO.getId());
// 校验手机唯一 // 校验手机唯一
validateMobileUnique(updateReqVO.getId(), updateReqVO.getMobile()); validateMobileUnique(updateReqVO.getId(), updateReqVO.getMobile());
// 更新 // 更新
MemberUserDO updateObj = MemberUserConvert.INSTANCE.convert(updateReqVO); MemberUserDO updateObj = MemberUserConvert.INSTANCE.convert(updateReqVO);
memberUserMapper.updateById(updateObj); memberUserMapper.updateById(updateObj);
// 会员级别修改
memberLevelService.updateUserLevel(user, updateReqVO.getLevelId(), updateReqVO.getLevelReason());
} }
@VisibleForTesting @VisibleForTesting

Loading…
Cancel
Save