master:档口会员功能完善;

pull/1121/head
liujiang 2025-11-16 15:17:20 +08:00
parent 82d72b8ac2
commit d804726b95
13 changed files with 220 additions and 58 deletions

View File

@ -6,8 +6,10 @@ import com.ruoyi.common.core.controller.XktBaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.web.controller.xkt.vo.storeMember.StoreMemberAuditVO;
import com.ruoyi.web.controller.xkt.vo.storeMember.StoreMemberCreateVO;
import com.ruoyi.web.controller.xkt.vo.storeMember.StoreMemberPageVO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberAuditDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberCreateDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberPageDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberPageResDTO;
@ -41,6 +43,14 @@ public class StoreMemberController extends XktBaseController {
return R.ok(storeMemberService.create(BeanUtil.toBean(createVO, StoreMemberCreateDTO.class)));
}
@PreAuthorize("@ss.hasAnyRoles('admin,general_admin')")
@ApiOperation(value = "审核档口会员", httpMethod = "PUT", response = R.class)
@Log(title = "审核档口会员", businessType = BusinessType.UPDATE)
@PutMapping("/audit")
public R<Integer> audit(@Validated @RequestBody StoreMemberAuditVO auditVO) {
return R.ok(storeMemberService.audit(BeanUtil.toBean(auditVO, StoreMemberAuditDTO.class)));
}
@PreAuthorize("@ss.hasAnyRoles('admin')")
@Log(title = "新增档口会员no money", businessType = BusinessType.INSERT)
@PostMapping("/no-money/{storeId}")

View File

@ -0,0 +1,27 @@
package com.ruoyi.web.controller.xkt.vo.storeMember;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@Data
@ApiModel
@Accessors(chain = true)
public class StoreMemberAuditVO {
@NotNull(message = "档口会员ID不能为空!")
@ApiModelProperty(value = "档口会员ID", required = true)
private Long storeMemberId;
@NotNull(message = "会员状态不能为空!")
@ApiModelProperty(value = "会员状态", required = true)
private Integer memberStatus;
}

View File

@ -6,6 +6,8 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* @author liujiang
* @version v1.0
@ -18,5 +20,7 @@ public class StoreMemberPageVO extends BasePageVO {
@ApiModelProperty(value = "档口名称")
private String storeName;
@ApiModelProperty(value = "会员状态")
private List<Integer> memberStatusList;
}

View File

@ -746,9 +746,10 @@ public class XktTask {
*/
public void autoCloseExpireStoreMember() {
final Date yesterday = java.sql.Date.valueOf(LocalDate.now().minusDays(1));
// 截止昨天,会员过期的档口
// 截止昨天,会员过期的档口 必须是正式使用的会员
List<StoreMember> expireList = this.storeMemberMapper.selectList(new LambdaQueryWrapper<StoreMember>()
.eq(StoreMember::getDelFlag, Constants.UNDELETED).eq(StoreMember::getEndTime, yesterday));
.eq(StoreMember::getDelFlag, Constants.UNDELETED).eq(StoreMember::getMemberStatus, StoreMemberStatus.AUDIT_PASS.getValue())
.eq(StoreMember::getEndTime, yesterday));
if (CollectionUtils.isEmpty(expireList)) {
return;
}
@ -763,7 +764,7 @@ public class XktTask {
*/
public void saveStoreMemberToRedis() {
List<StoreMember> memberList = this.storeMemberMapper.selectList(new LambdaQueryWrapper<StoreMember>()
.eq(StoreMember::getDelFlag, Constants.UNDELETED));
.eq(StoreMember::getMemberStatus, StoreMemberStatus.AUDIT_PASS.getValue()).eq(StoreMember::getDelFlag, Constants.UNDELETED));
if (CollectionUtils.isEmpty(memberList)) {
return;
}
@ -793,11 +794,10 @@ public class XktTask {
/**
* 03:00redis
*/
public void updateStoreWeightToES() throws IOException {
public void updateStoreWeightToES() {
// 找到昨天开通会员的所有档口
List<StoreMember> memberList = this.storeMemberMapper.selectList(new LambdaQueryWrapper<StoreMember>()
.eq(StoreMember::getDelFlag, Constants.UNDELETED)
.eq(StoreMember::getLevel, StoreMemberLevel.STRENGTH_CONSTRUCT.getValue())
.eq(StoreMember::getDelFlag, Constants.UNDELETED).eq(StoreMember::getMemberStatus, StoreMemberStatus.AUDIT_PASS.getValue())
.eq(StoreMember::getVoucherDate, java.sql.Date.valueOf(LocalDate.now().minusDays(1))));
if (CollectionUtils.isEmpty(memberList)) {
return;

View File

@ -3390,20 +3390,22 @@ CREATE TABLE `store_homepage`
DROP TABLE IF EXISTS `store_member`;
CREATE TABLE `store_member`
(
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '档口会员主键',
`store_id` bigint UNSIGNED NOT NULL COMMENT '档口ID',
`level` int UNSIGNED NOT NULL COMMENT '会员等级',
`start_time` date NOT NULL COMMENT '开始时间',
`end_time` date NOT NULL COMMENT '结束时间',
`voucher_date` date NOT NULL COMMENT '单据日期',
`version` bigint UNSIGNED NOT NULL COMMENT '版本号',
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '删除标志0代表存在 2代表删除',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '档口会员主键',
`store_id` bigint(20) UNSIGNED NOT NULL COMMENT '档口ID',
`level` int(10) UNSIGNED NULL DEFAULT NULL COMMENT '会员等级',
`start_time` date NULL DEFAULT NULL COMMENT '开始时间',
`end_time` date NULL DEFAULT NULL COMMENT '结束时间',
`member_status` tinyint(3) UNSIGNED NULL DEFAULT NULL COMMENT '会员状态',
`voucher_date` date NOT NULL COMMENT '单据日期',
`pay_price` decimal(10, 2) UNSIGNED NULL DEFAULT NULL COMMENT '支付金额',
`version` bigint(20) UNSIGNED NOT NULL COMMENT '版本号',
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '删除标志0代表存在 2代表删除',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

View File

@ -5,6 +5,7 @@ import com.ruoyi.common.core.domain.XktBaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.Date;
/**
@ -32,6 +33,14 @@ public class StoreMember extends XktBaseEntity {
*
*/
private Integer level;
/**
* 1 2 3 使 4
*/
private Integer memberStatus;
/**
*
*/
private BigDecimal payPrice;
/**
* yyyy-MM-dd
*/

View File

@ -94,7 +94,7 @@ public class StoreProductDemandTemplate extends XktBaseEntity {
*/
private Integer selectDemandCode;
/**
*
*
*/
private Integer selectMakeTime;
/**
@ -126,7 +126,7 @@ public class StoreProductDemandTemplate extends XktBaseEntity {
*/
private Integer selectEmergency;
/**
*
*
*/
private Integer selectQuantity;
/**

View File

@ -0,0 +1,23 @@
package com.ruoyi.xkt.dto.storeMember;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@Data
@ApiModel
@Accessors(chain = true)
public class StoreMemberAuditDTO {
@ApiModelProperty(value = "档口会员ID")
private Long storeMemberId;
@ApiModelProperty(value = "会员状态")
private Integer memberStatus;
}

View File

@ -6,6 +6,8 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* @author liujiang
* @version v1.0
@ -18,5 +20,7 @@ public class StoreMemberPageDTO extends BasePageDTO {
@ApiModelProperty(value = "档口名称")
private String storeName;
@ApiModelProperty(value = "会员状态")
private List<Integer> memberStatusList;
}

View File

@ -0,0 +1,41 @@
package com.ruoyi.xkt.enums;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.exception.ServiceException;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
*
*
* @author liujiang
* @date 2025-11-16 23:42
*/
@Getter
@AllArgsConstructor
public enum StoreMemberStatus {
// 未购买待审核
WAIT_AUDIT(1, "未购买待审核"),
// 已购买待审核(续费状态)
BOUGHT_WAIT_AUDIT(2, "已购买待审核"),
// 审核通过(正式使用)
AUDIT_PASS(3, "审核通过"),
// 审核拒绝
AUDIT_REJECT(4, "审核拒绝"),
;
private final Integer value;
private final String label;
public static StoreMemberStatus of(Integer value) {
for (StoreMemberStatus e : StoreMemberStatus.values()) {
if (e.getValue().equals(value)) {
return e;
}
}
throw new ServiceException("会员状态不存在!", HttpStatus.ERROR);
}
}

View File

@ -1,6 +1,7 @@
package com.ruoyi.xkt.service;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.xkt.dto.storeMember.StoreMemberAuditDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberCreateDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberPageDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberPageResDTO;
@ -37,4 +38,11 @@ public interface IStoreMemberService {
*/
Integer createNoMoney(Long storeId);
/**
*
*
* @param auditDTO
* @return Integer
*/
Integer audit(StoreMemberAuditDTO auditDTO);
}

View File

@ -12,6 +12,7 @@ import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.xkt.domain.Store;
import com.ruoyi.xkt.domain.StoreMember;
import com.ruoyi.xkt.dto.storeMember.StoreMemberAuditDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberCreateDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberPageDTO;
import com.ruoyi.xkt.dto.storeMember.StoreMemberPageResDTO;
@ -29,10 +30,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.*;
/**
* 广Service
@ -74,44 +72,22 @@ public class StoreMemberServiceImpl implements IStoreMemberService {
Optional.ofNullable(createDTO.getPayPrice()).orElseThrow(() -> new RuntimeException("购买金额不能为空!"));
// 看是否已存在会员
StoreMember storeMember = this.storeMemberMapper.selectOne(new LambdaQueryWrapper<StoreMember>()
.eq(StoreMember::getStoreId, createDTO.getStoreId()).eq(StoreMember::getDelFlag, Constants.UNDELETED));
int count;
// 已存在会员,则在之前的基础上续期
.eq(StoreMember::getStoreId, createDTO.getStoreId()).eq(StoreMember::getMemberStatus, StoreMemberStatus.AUDIT_PASS.getValue())
.eq(StoreMember::getDelFlag, Constants.UNDELETED));
if (ObjectUtils.isNotEmpty(storeMember)) {
// 续期结束时间在原来基础上再加一年
Date memberEndTime = storeMember.getEndTime();
// 直接增加一年
Date memberEndTimePlus = Date.from(memberEndTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
.plusYears(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
storeMember.setEndTime(memberEndTimePlus);
storeMember.setUpdateBy(SecurityUtils.getUsername());
count = this.storeMemberMapper.updateById(storeMember);
// 将状态置为 2 已购买待审核
storeMember.setMemberStatus(StoreMemberStatus.BOUGHT_WAIT_AUDIT.getValue());
} else {
storeMember = new StoreMember();
storeMember.setStoreId(createDTO.getStoreId());
// 最低等级会员:实力质造
storeMember.setLevel(StoreMemberLevel.STRENGTH_CONSTRUCT.getValue());
storeMember.setStartTime(java.sql.Date.valueOf(LocalDate.now()));
// 过期时间设置为1年后
storeMember.setEndTime(java.sql.Date.valueOf(LocalDate.now().plusYears(1)));
storeMember.setVoucherDate(java.sql.Date.valueOf(LocalDate.now()));
// 将状态置为 1 未购买待审核
storeMember.setMemberStatus(StoreMemberStatus.WAIT_AUDIT.getValue());
storeMember.setCreateBy(SecurityUtils.getUsername());
count = this.storeMemberMapper.insert(storeMember);
// 将档口权重增加1
Store store = Optional.ofNullable(this.storeMapper.selectOne(new LambdaQueryWrapper<Store>()
.eq(Store::getId, createDTO.getStoreId()).eq(Store::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("档口不存在!", HttpStatus.ERROR));
store.setStoreWeight(ObjectUtils.defaultIfNull(store.getStoreWeight(), 0) + 1);
this.storeMapper.updateById(store);
// 将档口会员信息添加到 redis 中
redisCache.setCacheObject(CacheConstants.STORE_MEMBER + createDTO.getStoreId(), storeMember);
}
// 新增订购成功的消息通知
this.noticeService.createSingleNotice(SecurityUtils.getUserId(), "购买会员成功!", NoticeType.NOTICE.getValue(), NoticeOwnerType.SYSTEM.getValue(),
createDTO.getStoreId(), UserNoticeType.SYSTEM_MSG.getValue(), "恭喜您!购买:实力质造 会员成功!");
// 扣除会员费
assetService.payVipFee(createDTO.getStoreId(), createDTO.getPayPrice());
return count;
storeMember.setVoucherDate(java.sql.Date.valueOf(LocalDate.now()));
storeMember.setPayPrice(createDTO.getPayPrice());
this.storeMemberMapper.insertOrUpdate(storeMember);
return 1;
}
/**
@ -129,7 +105,8 @@ public class StoreMemberServiceImpl implements IStoreMemberService {
}
// 看是否已存在会员
StoreMember storeMember = this.storeMemberMapper.selectOne(new LambdaQueryWrapper<StoreMember>()
.eq(StoreMember::getStoreId, storeId).eq(StoreMember::getDelFlag, Constants.UNDELETED));
.eq(StoreMember::getStoreId, storeId).eq(StoreMember::getMemberStatus, StoreMemberStatus.AUDIT_PASS.getValue())
.eq(StoreMember::getDelFlag, Constants.UNDELETED));
int count;
// 已存在会员,则在之前的基础上续期
if (ObjectUtils.isNotEmpty(storeMember)) {
@ -164,6 +141,57 @@ public class StoreMemberServiceImpl implements IStoreMemberService {
return count;
}
/**
*
*
* @param auditDTO
* @return Integer
*/
@Override
@Transactional
public Integer audit(StoreMemberAuditDTO auditDTO) {
// 用户是否为超级管理员
if (!SecurityUtils.isSuperAdmin()) {
throw new ServiceException("当前用户非超级管理员,无权限操作!", HttpStatus.ERROR);
}
StoreMember storeMember = Optional.ofNullable(this.storeMemberMapper.selectOne(new LambdaQueryWrapper<StoreMember>()
.eq(StoreMember::getId, auditDTO.getStoreMemberId()).eq(StoreMember::getDelFlag, Constants.UNDELETED)
.in(StoreMember::getMemberStatus, Arrays.asList(StoreMemberStatus.WAIT_AUDIT.getValue(), StoreMemberStatus.BOUGHT_WAIT_AUDIT.getValue()))))
.orElseThrow(() -> new ServiceException("会员不存在!", HttpStatus.ERROR));
if (Objects.equals(auditDTO.getMemberStatus(), StoreMemberStatus.AUDIT_PASS.getValue())) {
// 若结束时间在当前时间之前,则直接设置为当前时间
Date startTime = ObjectUtils.isEmpty(storeMember.getEndTime()) ? new Date()
: (storeMember.getEndTime().after(new Date()) ? storeMember.getEndTime() : new Date());
// 直接增加一年
Date endTime = Date.from(startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
.plusYears(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
storeMember.setStartTime(startTime);
storeMember.setEndTime(endTime);
storeMember.setUpdateBy(SecurityUtils.getUsername());
storeMember.setMemberStatus(StoreMemberStatus.AUDIT_PASS.getValue());
// 最低等级会员:实力质造
storeMember.setLevel(StoreMemberLevel.STRENGTH_CONSTRUCT.getValue());
storeMember.setVoucherDate(java.sql.Date.valueOf(LocalDate.now()));
// 将档口权重增加1
Store store = Optional.ofNullable(this.storeMapper.selectOne(new LambdaQueryWrapper<Store>()
.eq(Store::getId, storeMember.getStoreId()).eq(Store::getDelFlag, Constants.UNDELETED)))
.orElseThrow(() -> new ServiceException("档口不存在!", HttpStatus.ERROR));
store.setStoreWeight(ObjectUtils.defaultIfNull(store.getStoreWeight(), 0) + 1);
this.storeMapper.updateById(store);
// 将档口会员信息添加到 redis 中
redisCache.setCacheObject(CacheConstants.STORE_MEMBER + storeMember.getStoreId(), storeMember);
// 新增订购成功的消息通知
this.noticeService.createSingleNotice(SecurityUtils.getUserId(), "购买会员成功!", NoticeType.NOTICE.getValue(), NoticeOwnerType.SYSTEM.getValue(),
storeMember.getStoreId(), UserNoticeType.SYSTEM_MSG.getValue(), "恭喜您!购买:实力质造 会员成功!");
// 扣除会员费
assetService.payVipFee(storeMember.getStoreId(), storeMember.getPayPrice());
} else {
// 如果审核驳回,则直接将该笔审核置为无效
storeMember.setDelFlag(Constants.DELETED);
}
return this.storeMemberMapper.updateById(storeMember);
}
/**
*
*

View File

@ -20,6 +20,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
WHERE
sm.del_flag = 0
<if test="storeName != null and storeName != ''"> and s.store_name like concat('%', #{storeName}, '%')</if>
<if test="memberStatusList != null and memberStatusList.size() > 0">
and sm.member_status in
<foreach collection="memberStatusList" item="item" index="index" open="(" separator="," close=")">
#{item}
</foreach>
</if>
ORDER BY
sm.create_time DESC
</select>