refactor(pricing): 将券码系统中的faceId替换为userId

- 移除AppVoucherController中的人脸相关依赖和验证逻辑
- 修改VoucherClaimReq和VoucherCodeQueryReq数据传输对象,将faceId字段替换为userId
- 更新VoucherCodeResp和VoucherDetailResp响应对象中的用户标识字段
- 修改数据库实体PriceVoucherCode中领取人标识字段从faceId改为userId
- 更新PriceVoucherCodeMapper中所有SQL查询的人脸ID参数为用户ID参数
- 修改VoucherCodeServiceImpl中券码领取和查询逻辑使用用户ID进行操作
- 更新VoucherServiceImpl中券码验证和使用记录的相关用户标识处理
- 统一数据库表字段和代码中的命名规范,确保用户标识一致性
This commit is contained in:
2026-02-13 20:06:02 +08:00
parent 9a92a4943a
commit 383f9c4a31
12 changed files with 68 additions and 77 deletions

View File

@@ -1,15 +1,12 @@
package com.ycwl.basic.controller.mobile;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.exception.BaseException;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
import com.ycwl.basic.pricing.dto.req.VoucherClaimReq;
import com.ycwl.basic.pricing.dto.req.VoucherPrintReq;
import com.ycwl.basic.pricing.dto.resp.VoucherCodeResp;
import com.ycwl.basic.pricing.dto.resp.VoucherPrintResp;
import com.ycwl.basic.pricing.service.VoucherCodeService;
import com.ycwl.basic.pricing.service.VoucherPrintService;
import com.ycwl.basic.repository.FaceRepository;
import com.ycwl.basic.utils.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -30,8 +27,6 @@ public class AppVoucherController {
private VoucherPrintService voucherPrintService;
@Autowired
private VoucherCodeService voucherCodeService;
@Autowired
private FaceRepository faceRepository;
/**
* 打印小票
@@ -60,11 +55,6 @@ public class AppVoucherController {
@PostMapping("/claim")
public ApiResponse<VoucherCodeResp> claimVoucher(@RequestBody VoucherClaimReq req) {
FaceEntity face = faceRepository.getFace(req.getFaceId());
if (face == null) {
throw new BaseException("请选择人脸");
}
req.setScenicId(face.getScenicId());
VoucherCodeResp result = voucherCodeService.claimVoucher(req);
return ApiResponse.success(result);
}

View File

@@ -1,6 +1,7 @@
package com.ycwl.basic.pricing.controller;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.pricing.dto.req.VoucherBatchCreateReq;
import com.ycwl.basic.pricing.dto.req.VoucherBatchCreateReqV2;
import com.ycwl.basic.pricing.dto.req.VoucherBatchQueryReq;
@@ -96,8 +97,9 @@ public class VoucherManagementController {
}
@GetMapping("/mobile/my-codes")
public ApiResponse<List<VoucherCodeResp>> getMyVoucherCodes(@RequestParam Long faceId) {
List<VoucherCodeResp> codes = voucherCodeService.getMyVoucherCodes(faceId);
public ApiResponse<List<VoucherCodeResp>> getMyVoucherCodes() {
Long userId = Long.valueOf(BaseContextHandler.getUserId());
List<VoucherCodeResp> codes = voucherCodeService.getMyVoucherCodes(userId);
return ApiResponse.success(codes);
}
}

View File

@@ -5,6 +5,5 @@ import lombok.Data;
@Data
public class VoucherClaimReq {
private Long scenicId;
private Long faceId;
private String code;
}

View File

@@ -9,7 +9,7 @@ import lombok.EqualsAndHashCode;
public class VoucherCodeQueryReq extends BaseQueryParameterReq {
private Long batchId;
private Long scenicId;
private Long faceId;
private Long userId;
private Integer status;
private String code;
}

View File

@@ -14,7 +14,7 @@ public class VoucherCodeResp {
private String code;
private Integer status;
private String statusName;
private Long faceId;
private Long userId;
private Date claimedTime;
private Date usedTime;
private String remark;

View File

@@ -102,9 +102,9 @@ public class VoucherDetailResp {
@Data
public static class UserInfo {
/**
* 用户人脸ID
* 用户ID
*/
private Long faceId;
private Long userId;
/**
* 该用户已使用此券码的次数

View File

@@ -39,9 +39,9 @@ public class PriceVoucherCode {
private Integer status;
/**
* 领取人faceId
* 领取人用户ID
*/
private Long faceId;
private Long userId;
/**
* 领取时间

View File

@@ -15,109 +15,109 @@ import java.util.List;
*/
@Mapper
public interface PriceVoucherCodeMapper extends BaseMapper<PriceVoucherCode> {
/**
* 根据券码查询券码信息
* @param code 券码
* @return 券码信息
*/
@Select("SELECT id, batch_id, scenic_id, code, status, face_id, claimed_time, used_time, " +
@Select("SELECT id, batch_id, scenic_id, code, status, user_id, claimed_time, used_time, " +
"current_use_count, last_used_time, remark, create_time, update_time, deleted, deleted_at " +
"FROM price_voucher_code WHERE code = #{code} AND deleted = 0 LIMIT 1")
PriceVoucherCode selectByCode(@Param("code") String code);
/**
* 根据faceId和scenicId统计已领取的券码数量
* @param faceId 用户faceId
* 根据userId和scenicId统计已领取的券码数量
* @param userId 用户ID
* @param scenicId 景区ID
* @return 数量
*/
@Select("SELECT COUNT(1) FROM price_voucher_code WHERE face_id = #{faceId} AND scenic_id = #{scenicId} AND deleted = 0")
Integer countByFaceIdAndScenicId(@Param("faceId") Long faceId, @Param("scenicId") Long scenicId);
@Select("SELECT COUNT(1) FROM price_voucher_code WHERE user_id = #{userId} AND scenic_id = #{scenicId} AND deleted = 0")
Integer countByUserIdAndScenicId(@Param("userId") Long userId, @Param("scenicId") Long scenicId);
/**
* 查询用户在指定景区的可用券码列表
* @param faceId 用户faceId
* @param userId 用户ID
* @param scenicId 景区ID
* @return 券码列表
*/
@Select("SELECT id, batch_id, scenic_id, code, status, face_id, claimed_time, used_time, " +
@Select("SELECT id, batch_id, scenic_id, code, status, user_id, claimed_time, used_time, " +
"current_use_count, last_used_time, remark, create_time, update_time, deleted, deleted_at " +
"FROM price_voucher_code WHERE face_id = #{faceId} AND scenic_id = #{scenicId} AND status = 1 AND deleted = 0 " +
"FROM price_voucher_code WHERE user_id = #{userId} AND scenic_id = #{scenicId} AND status = 1 AND deleted = 0 " +
"ORDER BY claimed_time DESC")
List<PriceVoucherCode> selectAvailableVouchersByFaceIdAndScenicId(@Param("faceId") Long faceId,
List<PriceVoucherCode> selectAvailableVouchersByUserIdAndScenicId(@Param("userId") Long userId,
@Param("scenicId") Long scenicId);
/**
* 根据批次ID获取可领取的券码(未领取状态)
* @param batchId 批次ID
* @param limit 限制数量
* @return 券码列表
*/
@Select("SELECT id, batch_id, scenic_id, code, status, face_id, claimed_time, used_time, " +
@Select("SELECT id, batch_id, scenic_id, code, status, user_id, claimed_time, used_time, " +
"current_use_count, last_used_time, remark, create_time, update_time, deleted, deleted_at " +
"FROM price_voucher_code WHERE batch_id = #{batchId} AND status = 0 AND deleted = 0 LIMIT #{limit}")
List<PriceVoucherCode> selectUnclaimedVouchersByBatchId(@Param("batchId") Long batchId,
@Param("limit") Integer limit);
/**
* 领取券码(更新状态为已领取)
* @param id 券码ID
* @param faceId 用户faceId
* @param userId 用户ID
* @param claimedTime 领取时间
* @return 影响行数
*/
@Update("UPDATE price_voucher_code SET status = 1, face_id = #{faceId}, claimed_time = #{claimedTime}, " +
@Update("UPDATE price_voucher_code SET status = 1, user_id = #{userId}, claimed_time = #{claimedTime}, " +
"update_time = NOW() WHERE id = #{id} AND status = 0 AND deleted = 0")
int claimVoucher(@Param("id") Long id,
@Param("faceId") Long faceId,
@Param("userId") Long userId,
@Param("claimedTime") LocalDateTime claimedTime);
/**
* 根据批次ID查询券码列表(支持分页)
* @param batchId 批次ID
* @return 券码列表
*/
@Select("SELECT id, batch_id, scenic_id, code, status, face_id, claimed_time, used_time, " +
@Select("SELECT id, batch_id, scenic_id, code, status, user_id, claimed_time, used_time, " +
"current_use_count, last_used_time, remark, create_time, update_time, deleted, deleted_at " +
"FROM price_voucher_code WHERE batch_id = #{batchId} AND deleted = 0 ORDER BY create_time DESC")
List<PriceVoucherCode> selectByBatchId(@Param("batchId") Long batchId);
/**
* 查询用户的券码列表
* @param faceId 用户faceId
* @param userId 用户ID
* @param scenicId 景区ID(可选)
* @return 券码列表
*/
@Select("<script>" +
"SELECT id, batch_id, scenic_id, code, status, face_id, claimed_time, used_time, " +
"SELECT id, batch_id, scenic_id, code, status, user_id, claimed_time, used_time, " +
"current_use_count, last_used_time, remark, create_time, update_time, deleted, deleted_at " +
"FROM price_voucher_code WHERE face_id = #{faceId}" +
"FROM price_voucher_code WHERE user_id = #{userId}" +
"<if test='scenicId != null'> AND scenic_id = #{scenicId}</if>" +
" AND deleted = 0 ORDER BY claimed_time DESC" +
"</script>")
List<PriceVoucherCode> selectUserVouchers(@Param("faceId") Long faceId,
List<PriceVoucherCode> selectUserVouchers(@Param("userId") Long userId,
@Param("scenicId") Long scenicId);
/**
* 根据批次ID查询第一个可用的券码
* @param batchId 批次ID
* @return 可用券码
*/
@Select("SELECT id, batch_id, scenic_id, code, status, face_id, claimed_time, used_time, " +
@Select("SELECT id, batch_id, scenic_id, code, status, user_id, claimed_time, used_time, " +
"current_use_count, last_used_time, remark, create_time, update_time, deleted, deleted_at " +
"FROM price_voucher_code WHERE batch_id = #{batchId} AND status = 0 AND deleted = 0 LIMIT 1")
PriceVoucherCode findFirstAvailableByBatchId(@Param("batchId") Long batchId);
/**
* 随机获取一个未被打印过的可用券码
* @param scenicId 景区ID
* @return 可用券码
*/
@Select("SELECT pvc.id, pvc.batch_id, pvc.scenic_id, pvc.code, pvc.status, pvc.face_id, pvc.claimed_time, pvc.used_time, " +
@Select("SELECT pvc.id, pvc.batch_id, pvc.scenic_id, pvc.code, pvc.status, pvc.user_id, pvc.claimed_time, pvc.used_time, " +
"pvc.current_use_count, pvc.last_used_time, pvc.remark, pvc.create_time, pvc.update_time, pvc.deleted, pvc.deleted_at " +
"FROM price_voucher_code pvc WHERE pvc.scenic_id = #{scenicId} AND pvc.status = 0 AND pvc.deleted = 0 " +
"AND NOT EXISTS (SELECT 1 FROM voucher_print_record vpr WHERE vpr.voucher_code_id = pvc.id AND vpr.deleted = 0) " +
"ORDER BY RAND() LIMIT 1")
PriceVoucherCode findRandomUnprintedVoucher(@Param("scenicId") Long scenicId);
}
}

View File

@@ -15,9 +15,9 @@ public interface VoucherCodeService {
PageInfo<VoucherCodeResp> queryCodeList(VoucherCodeQueryReq req);
List<VoucherCodeResp> getMyVoucherCodes(Long faceId);
List<VoucherCodeResp> getMyVoucherCodes(Long userId);
void markCodeAsUsed(Long codeId, String remark);
boolean canClaimVoucher(Long faceId, Long scenicId);
boolean canClaimVoucher(Long userId, Long scenicId);
}

View File

@@ -3,6 +3,7 @@ package com.ycwl.basic.pricing.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ycwl.basic.constant.BaseContextHandler;
import com.ycwl.basic.exception.BizException;
import com.ycwl.basic.pricing.dto.req.VoucherClaimReq;
import com.ycwl.basic.pricing.dto.req.VoucherCodeQueryReq;
@@ -76,32 +77,31 @@ public VoucherCodeResp claimVoucher(VoucherClaimReq req) {
if (req.getScenicId() == null) {
throw new BizException(400, "景区ID不能为空");
}
if (req.getFaceId() == null) {
throw new BizException(400, "用户faceId不能为空");
}
if (!StringUtils.hasText(req.getCode())) {
throw new BizException(400, "券码不能为空");
}
Long userId = Long.valueOf(BaseContextHandler.getUserId());
// 验证券码是否存在且未被领取
LambdaQueryWrapper<PriceVoucherCode> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PriceVoucherCode::getCode, req.getCode())
.eq(PriceVoucherCode::getScenicId, req.getScenicId())
.eq(PriceVoucherCode::getDeleted, 0);
PriceVoucherCode voucherCode = voucherCodeMapper.selectOne(wrapper);
if (voucherCode == null) {
throw new BizException(400, "券码不存在或不属于该景区");
}
if (!Objects.equals(voucherCode.getStatus(), VoucherCodeStatus.UNCLAIMED.getCode())) {
throw new BizException(400, "券码已被领取或已使用");
}
if (!canClaimVoucher(req.getFaceId(), req.getScenicId())) {
if (!canClaimVoucher(userId, req.getScenicId())) {
throw new BizException(400, "该用户在此景区已领取过券码");
}
// 获取券码所属批次
PriceVoucherBatchConfig batch = voucherBatchMapper.selectById(voucherCode.getBatchId());
if (batch == null || batch.getDeleted() == 1) {
@@ -109,18 +109,18 @@ public VoucherCodeResp claimVoucher(VoucherClaimReq req) {
}
// 更新券码状态
voucherCode.setFaceId(req.getFaceId());
voucherCode.setUserId(userId);
voucherCode.setStatus(VoucherCodeStatus.CLAIMED_UNUSED.getCode());
voucherCode.setClaimedTime(new Date());
// 确保currentUseCount被初始化
if (voucherCode.getCurrentUseCount() == null) {
voucherCode.setCurrentUseCount(0);
}
voucherCodeMapper.updateById(voucherCode);
voucherBatchService.updateBatchClaimedCount(batch.getId());
return convertToResp(voucherCode, batch);
}
@@ -132,7 +132,7 @@ public VoucherCodeResp claimVoucher(VoucherClaimReq req) {
wrapper.eq(PriceVoucherCode::getDeleted, 0)
.eq(req.getBatchId() != null, PriceVoucherCode::getBatchId, req.getBatchId())
.eq(req.getScenicId() != null, PriceVoucherCode::getScenicId, req.getScenicId())
.eq(req.getFaceId() != null, PriceVoucherCode::getFaceId, req.getFaceId())
.eq(req.getUserId() != null, PriceVoucherCode::getUserId, req.getUserId())
.eq(req.getStatus() != null, PriceVoucherCode::getStatus, req.getStatus())
.like(StringUtils.hasText(req.getCode()), PriceVoucherCode::getCode, req.getCode())
.orderByDesc(PriceVoucherCode::getId);
@@ -149,9 +149,9 @@ public VoucherCodeResp claimVoucher(VoucherClaimReq req) {
}
@Override
public List<VoucherCodeResp> getMyVoucherCodes(Long faceId) {
public List<VoucherCodeResp> getMyVoucherCodes(Long userId) {
LambdaQueryWrapper<PriceVoucherCode> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PriceVoucherCode::getFaceId, faceId)
wrapper.eq(PriceVoucherCode::getUserId, userId)
.eq(PriceVoucherCode::getDeleted, 0)
.orderByDesc(PriceVoucherCode::getClaimedTime);
@@ -193,8 +193,8 @@ public void markCodeAsUsed(Long codeId, String remark) {
}
@Override
public boolean canClaimVoucher(Long faceId, Long scenicId) {
Integer count = voucherCodeMapper.countByFaceIdAndScenicId(faceId, scenicId);
public boolean canClaimVoucher(Long userId, Long scenicId) {
Integer count = voucherCodeMapper.countByUserIdAndScenicId(userId, scenicId);
return count == 0;
}

View File

@@ -132,7 +132,7 @@ public class VoucherServiceImpl implements IVoucherService {
if (faceId == null) {
voucherInfo.setAvailable(false);
voucherInfo.setUnavailableReason("用户信息缺失,无法验证券码权限");
} else if (!faceId.equals(voucherCodeEntity.getFaceId())) {
} else if (!faceId.equals(voucherCodeEntity.getUserId())) {
voucherInfo.setAvailable(false);
voucherInfo.setUnavailableReason("券码已被其他用户领取");
} else {
@@ -176,7 +176,7 @@ public class VoucherServiceImpl implements IVoucherService {
return new ArrayList<>();
}
List<PriceVoucherCode> voucherCodes = voucherCodeMapper.selectAvailableVouchersByFaceIdAndScenicId(faceId, scenicId);
List<PriceVoucherCode> voucherCodes = voucherCodeMapper.selectAvailableVouchersByUserIdAndScenicId(faceId, scenicId);
List<VoucherInfo> voucherInfos = new ArrayList<>();
for (PriceVoucherCode voucherCode : voucherCodes) {
@@ -234,7 +234,7 @@ public void markVoucherAsUsed(String voucherCode, String remark, String orderId,
PriceVoucherUsageRecord usageRecord = new PriceVoucherUsageRecord();
usageRecord.setVoucherCodeId(voucherCodeEntity.getId());
usageRecord.setVoucherCode(voucherCode);
usageRecord.setFaceId(faceId != null ? faceId : voucherCodeEntity.getFaceId());
usageRecord.setFaceId(faceId != null ? faceId : voucherCodeEntity.getUserId());
usageRecord.setScenicId(voucherCodeEntity.getScenicId());
usageRecord.setBatchId(voucherCodeEntity.getBatchId());
usageRecord.setUsageSequence(newUseCount); // 设置使用序号,表示这是该券码的第几次使用
@@ -279,7 +279,7 @@ public void markVoucherAsUsed(String voucherCode, String remark, String orderId,
return false;
}
Integer count = voucherCodeMapper.countByFaceIdAndScenicId(faceId, scenicId);
Integer count = voucherCodeMapper.countByUserIdAndScenicId(faceId, scenicId);
return count == 0;
}
@@ -435,7 +435,7 @@ public void markVoucherAsUsed(String voucherCode, String remark, String orderId,
// 设置用户信息
if (faceId != null) {
VoucherDetailResp.UserInfo userInfo = new VoucherDetailResp.UserInfo();
userInfo.setFaceId(faceId);
userInfo.setUserId(faceId);
// 计算该用户使用此券码的次数
List<PriceVoucherUsageRecord> userUsageRecords = usageRecordMapper.selectByVoucherCodeAndFaceId(voucherCodeEntity.getId(), faceId);

View File

@@ -53,7 +53,7 @@ public class ReusableVoucherServiceTest {
testVoucherCode.setCode("TEST123");
testVoucherCode.setBatchId(1L);
testVoucherCode.setScenicId(1L);
testVoucherCode.setFaceId(1001L);
testVoucherCode.setUserId(1001L);
testVoucherCode.setStatus(VoucherCodeStatus.CLAIMED_AVAILABLE.getCode());
testVoucherCode.setCurrentUseCount(1);
testVoucherCode.setLastUsedTime(new Date());