From 48cd2e1f7b4f7a5d61a2f279460da473c82094a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Fri, 6 Feb 2026 00:15:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(order):=20=E6=B7=BB=E5=8A=A0=E9=80=81?= =?UTF-8?q?=E6=B0=B4=E8=AE=A2=E5=8D=95=E9=85=8D=E9=80=81=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E5=92=8C=E5=AE=8C=E6=95=B4=E4=B8=8B=E5=8D=95=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在GltTicketOrder实体中新增sendTime字段用于记录配送时间 - 移除送水订单查询接口的权限验证要求,开放查询功能 - 实现完整的下单流程:验证登录用户、扣减水票、写入核销记录、创建订单 - 新增createWithWriteOff方法处理事务性下单操作,确保数据一致性 - 添加数据库行锁机制防止并发扣减问题 - 优化水票相关接口描述,明确为可用水票总数 - 移除水票日志添加接口的权限验证和操作日志注解 --- .../controller/GltTicketOrderController.java | 20 ++- .../controller/GltUserTicketController.java | 12 +- .../GltUserTicketLogController.java | 2 - .../gxwebsoft/glt/entity/GltTicketOrder.java | 4 + .../glt/mapper/GltUserTicketMapper.java | 27 +++- .../glt/service/GltTicketOrderService.java | 10 ++ .../impl/GltTicketOrderServiceImpl.java | 115 ++++++++++++++++++ 7 files changed, 169 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java b/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java index bd30f72..d8d7a76 100644 --- a/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java +++ b/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java @@ -5,6 +5,7 @@ import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.common.core.web.BaseController; import com.gxwebsoft.common.core.web.BatchParam; import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.glt.entity.GltTicketOrder; import com.gxwebsoft.glt.param.GltTicketOrderParam; import com.gxwebsoft.glt.service.GltTicketOrderService; @@ -29,7 +30,6 @@ public class GltTicketOrderController extends BaseController { @Resource private GltTicketOrderService gltTicketOrderService; - @PreAuthorize("hasAuthority('glt:gltTicketOrder:list')") @Operation(summary = "分页查询送水订单") @GetMapping("/page") public ApiResult> page(GltTicketOrderParam param) { @@ -37,7 +37,6 @@ public class GltTicketOrderController extends BaseController { return success(gltTicketOrderService.pageRel(param)); } - @PreAuthorize("hasAuthority('glt:gltTicketOrder:list')") @Operation(summary = "查询全部送水订单") @GetMapping() public ApiResult> list(GltTicketOrderParam param) { @@ -45,7 +44,6 @@ public class GltTicketOrderController extends BaseController { return success(gltTicketOrderService.listRel(param)); } - @PreAuthorize("hasAuthority('glt:gltTicketOrder:list')") @Operation(summary = "根据id查询送水订单") @GetMapping("/{id}") public ApiResult get(@PathVariable("id") Integer id) { @@ -53,20 +51,16 @@ public class GltTicketOrderController extends BaseController { return success(gltTicketOrderService.getByIdRel(id)); } - @PreAuthorize("hasAuthority('glt:gltTicketOrder:save')") - @OperationLog @Operation(summary = "添加送水订单") @PostMapping() public ApiResult save(@RequestBody GltTicketOrder gltTicketOrder) { - // 记录当前登录用户id - // User loginUser = getLoginUser(); - // if (loginUser != null) { - // gltTicketOrder.setUserId(loginUser.getUserId()); - // } - if (gltTicketOrderService.save(gltTicketOrder)) { - return success("添加成功"); + // 下单:后端原子完成(扣水票 + 写核销记录 + 生成订单) + User loginUser = getLoginUser(); + if (loginUser == null) { + return fail("请先登录"); } - return fail("添加失败"); + gltTicketOrderService.createWithWriteOff(gltTicketOrder, loginUser.getUserId(), loginUser.getTenantId()); + return success("下单成功"); } @PreAuthorize("hasAuthority('glt:gltTicketOrder:update')") diff --git a/src/main/java/com/gxwebsoft/glt/controller/GltUserTicketController.java b/src/main/java/com/gxwebsoft/glt/controller/GltUserTicketController.java index 15848a1..51bd269 100644 --- a/src/main/java/com/gxwebsoft/glt/controller/GltUserTicketController.java +++ b/src/main/java/com/gxwebsoft/glt/controller/GltUserTicketController.java @@ -38,17 +38,23 @@ public class GltUserTicketController extends BaseController { return success(gltUserTicketService.pageRel(param)); } - @Operation(summary = "我的水票总数") + @Operation(summary = "可用水票总数") @GetMapping("/my-total") public ApiResult myTotal() { Integer userId = getLoginUserId(); if (userId == null) { return fail("未登录"); } - Integer totalQty = gltUserTicketService.sumTotalQtyByUserId(userId); + Integer tenantId = getTenantId(); + if (tenantId == null) { + return fail("租户信息缺失"); + } + Integer availableQty = gltUserTicketService.sumAvailableQtyByUserId(userId, tenantId); Map data = new HashMap<>(); data.put("userId", userId); - data.put("totalQty", totalQty); + // 兼容旧字段:totalQty 表示“可用水票总数” + data.put("totalQty", availableQty); + data.put("availableQty", availableQty); return success(data); } diff --git a/src/main/java/com/gxwebsoft/glt/controller/GltUserTicketLogController.java b/src/main/java/com/gxwebsoft/glt/controller/GltUserTicketLogController.java index 19ab463..8cde690 100644 --- a/src/main/java/com/gxwebsoft/glt/controller/GltUserTicketLogController.java +++ b/src/main/java/com/gxwebsoft/glt/controller/GltUserTicketLogController.java @@ -55,8 +55,6 @@ public class GltUserTicketLogController extends BaseController { return success(gltUserTicketLogService.getByIdRel(id)); } - @PreAuthorize("hasAuthority('glt:gltUserTicketLog:save')") - @OperationLog @Operation(summary = "添加消费日志") @PostMapping() public ApiResult save(@RequestBody GltUserTicketLog gltUserTicketLog) { diff --git a/src/main/java/com/gxwebsoft/glt/entity/GltTicketOrder.java b/src/main/java/com/gxwebsoft/glt/entity/GltTicketOrder.java index 7ad8f18..e91b042 100644 --- a/src/main/java/com/gxwebsoft/glt/entity/GltTicketOrder.java +++ b/src/main/java/com/gxwebsoft/glt/entity/GltTicketOrder.java @@ -54,6 +54,10 @@ public class GltTicketOrder implements Serializable { @Schema(description = "购买数量") private Integer totalNum; + @Schema(description = "配送时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private String sendTime; + @Schema(description = "用户ID") private Integer userId; diff --git a/src/main/java/com/gxwebsoft/glt/mapper/GltUserTicketMapper.java b/src/main/java/com/gxwebsoft/glt/mapper/GltUserTicketMapper.java index 1ec8167..b1eb700 100644 --- a/src/main/java/com/gxwebsoft/glt/mapper/GltUserTicketMapper.java +++ b/src/main/java/com/gxwebsoft/glt/mapper/GltUserTicketMapper.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.gxwebsoft.glt.entity.GltUserTicket; import com.gxwebsoft.glt.param.GltUserTicketParam; +import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Param; import java.util.List; @@ -35,11 +36,31 @@ public interface GltUserTicketMapper extends BaseMapper { List selectListRel(@Param("param") GltUserTicketParam param); /** - * 统计用户水票总数量(sum(total_qty)) + * 统计用户可用水票总数(sum(available_qty)) * * @param userId 用户ID - * @return 总数量 + * @param tenantId 租户ID + * @return 可用总数 */ - Integer sumTotalQtyByUserId(@Param("userId") Integer userId); + Integer sumAvailableQtyByUserId(@Param("userId") Integer userId, + @Param("tenantId") Integer tenantId); + + /** + * 按当前用户锁定水票记录(用于扣减/核销的事务场景) + */ + @Select(""" + SELECT * + FROM glt_user_ticket + WHERE id = #{id} + AND user_id = #{userId} + AND tenant_id = #{tenantId} + AND status = 0 + AND deleted = 0 + LIMIT 1 + FOR UPDATE + """) + GltUserTicket selectByIdForUpdate(@Param("id") Integer id, + @Param("userId") Integer userId, + @Param("tenantId") Integer tenantId); } diff --git a/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java b/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java index 53acf91..39c784b 100644 --- a/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java +++ b/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java @@ -39,4 +39,14 @@ public interface GltTicketOrderService extends IService { */ GltTicketOrder getByIdRel(Integer id); + /** + * 下单(事务):校验水票 -> 扣减水票 -> 写核销记录 -> 创建送水订单。 + * + * @param gltTicketOrder 订单请求体 + * @param userId 当前登录用户ID + * @param tenantId 当前租户ID + * @return 创建后的订单(含id) + */ + GltTicketOrder createWithWriteOff(GltTicketOrder gltTicketOrder, Integer userId, Integer tenantId); + } diff --git a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java index a47e5eb..f4ecf67 100644 --- a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java +++ b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java @@ -1,14 +1,24 @@ package com.gxwebsoft.glt.service.impl; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.exception.BusinessException; import com.gxwebsoft.common.core.web.PageParam; import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.glt.entity.GltTicketOrder; +import com.gxwebsoft.glt.entity.GltUserTicket; +import com.gxwebsoft.glt.entity.GltUserTicketLog; import com.gxwebsoft.glt.mapper.GltTicketOrderMapper; +import com.gxwebsoft.glt.mapper.GltUserTicketMapper; import com.gxwebsoft.glt.param.GltTicketOrderParam; import com.gxwebsoft.glt.service.GltTicketOrderService; +import com.gxwebsoft.glt.service.GltUserTicketLogService; +import com.gxwebsoft.glt.service.GltUserTicketService; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.annotation.Resource; +import java.time.LocalDateTime; import java.util.List; /** @@ -20,6 +30,17 @@ import java.util.List; @Service public class GltTicketOrderServiceImpl extends ServiceImpl implements GltTicketOrderService { + public static final int CHANGE_TYPE_WRITE_OFF = 20; + + @Resource + private GltUserTicketMapper gltUserTicketMapper; + + @Resource + private GltUserTicketService gltUserTicketService; + + @Resource + private GltUserTicketLogService gltUserTicketLogService; + @Override public PageResult pageRel(GltTicketOrderParam param) { PageParam page = new PageParam<>(param); @@ -44,4 +65,98 @@ public class GltTicketOrderServiceImpl extends ServiceImpl