Procházet zdrojové kódy

Merge remote-tracking branch 'origin/dev' into dev

jinshihui před 1 týdnem
rodič
revize
0b94b34c06
24 změnil soubory, kde provedl 1064 přidání a 13 odebrání
  1. 37 2
      nightFragrance-massage/src/main/java/com/ylx/giftCard/controller/GiftCardController.java
  2. 28 2
      nightFragrance-massage/src/main/java/com/ylx/giftCard/domain/GiftCard.java
  3. 25 0
      nightFragrance-massage/src/main/java/com/ylx/giftCard/domain/dto/GiftCardPurchaseDTO.java
  4. 43 0
      nightFragrance-massage/src/main/java/com/ylx/giftCard/domain/vo/GiftCardDetailVO.java
  5. 53 0
      nightFragrance-massage/src/main/java/com/ylx/giftCard/domain/vo/GiftCardVO.java
  6. 5 0
      nightFragrance-massage/src/main/java/com/ylx/giftCard/service/IGiftCardOrderService.java
  7. 12 0
      nightFragrance-massage/src/main/java/com/ylx/giftCard/service/IGiftCardService.java
  8. 154 1
      nightFragrance-massage/src/main/java/com/ylx/giftCard/service/impl/GiftCardOrderServiceImpl.java
  9. 146 0
      nightFragrance-massage/src/main/java/com/ylx/giftCard/service/impl/GiftCardServiceImpl.java
  10. 2 2
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/TWxUser.java
  11. 17 4
      nightFragrance-massage/src/main/java/com/ylx/massage/service/TWxUserService.java
  12. 52 2
      nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TWxUserServiceImpl.java
  13. 48 0
      nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/controller/ShoppingFundsDetailController.java
  14. 63 0
      nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/domain/ShoppingFundsDetail.java
  15. 46 0
      nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/domain/dto/ShoppingFundsDetailQueryDto.java
  16. 46 0
      nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/domain/vo/ShoppingFundsDetailAddDto.java
  17. 53 0
      nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/domain/vo/ShoppingFundsDetailQueryVo.java
  18. 19 0
      nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/mapper/ShoppingFundsDetailMapper.java
  19. 25 0
      nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/service/ShoppingFundsDetailService.java
  20. 52 0
      nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/service/impl/ShoppingFundsDetailServiceImpl.java
  21. 43 0
      nightFragrance-massage/src/main/java/com/ylx/shoppingfunds/controller/MyShoppingFundsController.java
  22. 38 0
      nightFragrance-massage/src/main/java/com/ylx/shoppingfunds/domain/dto/MyShoppingFundsUpdateDto.java
  23. 27 0
      nightFragrance-massage/src/main/java/com/ylx/shoppingfunds/domain/vo/MyShoppingFundsQueryVo.java
  24. 30 0
      nightFragrance-massage/src/main/resources/mapper/giftCard/ShoppingFundsDetailMapper.xml

+ 37 - 2
nightFragrance-massage/src/main/java/com/ylx/giftCard/controller/GiftCardController.java

@@ -1,13 +1,48 @@
 package com.ylx.giftCard.controller;
 
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ylx.common.core.domain.R;
+import com.ylx.giftCard.domain.GiftCard;
+import com.ylx.giftCard.domain.dto.GiftCardPurchaseDTO;
+import com.ylx.giftCard.domain.vo.GiftCardDetailVO;
+import com.ylx.giftCard.domain.vo.GiftCardVO;
+import com.ylx.giftCard.service.IGiftCardService;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
 
 @RestController
 @RequestMapping("/gift/card")
 @Api(tags = {"购物卡"})
 @Slf4j
 public class GiftCardController {
+
+    @Resource
+    private IGiftCardService giftCardService;
+
+    @GetMapping("/page")
+    @ApiOperation("购物卡分页列表接口")
+    public R<Page<GiftCardVO>> getGiftCardPage(Page<GiftCard> page) {
+        Page<GiftCardVO> pageData = giftCardService.getGiftCardPage(page);
+        return R.ok(pageData);
+    }
+
+    @PostMapping("/purchase")
+    @ApiOperation("购物卡购买接口")
+    public R<String> purchaseGiftCard(@Validated @RequestBody GiftCardPurchaseDTO dto) {
+        boolean success = giftCardService.purchaseGiftCard(dto);
+        return success ? R.ok("购买成功") : R.fail("购买失败,库存不足或商品不存在");
+    }
+
+    @GetMapping("/{id}/detail")
+    @ApiOperation("获取购物卡详情")
+    public R<GiftCardDetailVO> getGiftCardDetail(@PathVariable Long id) {
+        GiftCardDetailVO detail = giftCardService.getGiftCardDetail(id);
+        return ObjectUtil.isNotNull(detail) ? R.ok(detail) : R.fail("购物卡不存在或已被删除");
+    }
 }

+ 28 - 2
nightFragrance-massage/src/main/java/com/ylx/giftCard/domain/GiftCard.java

@@ -1,12 +1,13 @@
 package com.ylx.giftCard.domain;
 
-import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.ylx.common.core.domain.BaseEntity;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
 import java.math.BigDecimal;
-import java.time.LocalDateTime;
+import java.time.LocalDate;
 
 /**
  * 购物卡信息表
@@ -37,6 +38,26 @@ public class GiftCard extends BaseEntity {
      */
     private BigDecimal amount;
 
+    /**
+     * 库存数量,0表示无库存
+     */
+    private Integer stock;
+
+    /**
+     * 累计销量
+     */
+    private Integer sales;
+
+    /**
+     * 有效期开始日期
+     */
+    private LocalDate validStartDate;
+
+    /**
+     * 有效期结束日期
+     */
+    private LocalDate validEndDate;
+
     /**
      * 商户提成比例,如 1.00 表示 1%
      */
@@ -57,4 +78,9 @@ public class GiftCard extends BaseEntity {
      */
     private String description;
 
+    /**
+     * 是否删除:0=否,1=是。
+     */
+    private Integer isDelete;
+
 }

+ 25 - 0
nightFragrance-massage/src/main/java/com/ylx/giftCard/domain/dto/GiftCardPurchaseDTO.java

@@ -0,0 +1,25 @@
+package com.ylx.giftCard.domain.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import javax.validation.constraints.*;
+
+@ApiModel("购物卡购买DTO")
+@Data
+public class GiftCardPurchaseDTO {
+
+    @NotNull(message = "购物卡ID不能为空")
+    @Positive(message = "购物卡ID必须为正整数")
+    @ApiModelProperty("购物卡ID")
+    private Long id;
+
+    @NotNull(message = "购买数量不能为空")
+    @Min(value = 1, message = "购买数量必须大于0")
+    @ApiModelProperty("购买数量")
+    private Integer quantity;
+
+    @ApiModelProperty("商户id")
+    private String merchantId;
+
+}

+ 43 - 0
nightFragrance-massage/src/main/java/com/ylx/giftCard/domain/vo/GiftCardDetailVO.java

@@ -0,0 +1,43 @@
+package com.ylx.giftCard.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+@ApiModel("购物卡详情DTO")
+@Data
+public class GiftCardDetailVO {
+
+    @ApiModelProperty("购物卡ID")
+    private Long id;
+
+    @ApiModelProperty("购物卡名称")
+    private String name;
+
+    @ApiModelProperty("价格(单位:元,保留两位小数)")
+    private BigDecimal price; // 建议用 BigDecimal 避免浮点误差
+
+    @ApiModelProperty("适用范围描述")
+    private String scopeDesc = "全平台可用";
+
+    @ApiModelProperty("有效期开始日期")
+    private LocalDate validStartDate;
+
+    @ApiModelProperty("有效期结束日期")
+    private LocalDate validEndDate;
+
+    @ApiModelProperty("服务商户描述")
+    private String merchantDesc = "全平台商户可用";
+
+    @ApiModelProperty("库存数量")
+    private Integer stock;
+
+    @ApiModelProperty("销量")
+    private Integer sales;
+
+    @ApiModelProperty("封面图URL")
+    private String coverUrl;
+}

+ 53 - 0
nightFragrance-massage/src/main/java/com/ylx/giftCard/domain/vo/GiftCardVO.java

@@ -0,0 +1,53 @@
+package com.ylx.giftCard.domain.vo;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.ylx.giftCard.domain.GiftCard;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 礼品卡视图对象(Value Object)类
+ * 用于封装礼品卡相关的数据,提供前端展示使用
+ */
+@Data
+public class GiftCardVO {
+
+    @ApiModelProperty("礼品卡ID")
+    private Long id;
+
+    @ApiModelProperty("礼品卡名称")
+    private String name;
+
+    @ApiModelProperty("礼品卡金额")
+    private BigDecimal amount;
+
+    @ApiModelProperty("礼品卡图片URL")
+    private String imageUrl;
+
+    @ApiModelProperty("销售数量")
+    private Integer sales;
+
+    @ApiModelProperty("库存数量")
+    private Integer stock;
+
+    @ApiModelProperty("售罄状态")
+    private Boolean isSoldOut;
+
+    /**
+     * 构造函数,用于将实体对象转换为视图对象
+     *
+     * @param entity 礼品卡实体对象
+     */
+    public GiftCardVO(GiftCard entity) {
+        this.id = entity.getId();
+        this.name = entity.getName();
+        this.amount = entity.getAmount();
+        this.imageUrl = entity.getImageUrl();
+        this.sales = entity.getSales();
+        this.stock = entity.getStock();
+        // 判断库存是否为null或小于等于0,若是则标记为售罄
+        this.isSoldOut = ObjectUtil.isNull(entity.getStock()) || entity.getStock() <= 0;
+    }
+}

+ 5 - 0
nightFragrance-massage/src/main/java/com/ylx/giftCard/service/IGiftCardOrderService.java

@@ -1,7 +1,12 @@
 package com.ylx.giftCard.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.ylx.giftCard.domain.GiftCard;
 import com.ylx.giftCard.domain.GiftCardOrder;
 
+import java.util.List;
+
 public interface IGiftCardOrderService extends IService<GiftCardOrder> {
+
+    List<GiftCardOrder> buildOrders(GiftCard card, Integer quantity, String merchantId);
 }

+ 12 - 0
nightFragrance-massage/src/main/java/com/ylx/giftCard/service/IGiftCardService.java

@@ -1,4 +1,16 @@
 package com.ylx.giftCard.service;
 
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ylx.giftCard.domain.GiftCard;
+import com.ylx.giftCard.domain.dto.GiftCardPurchaseDTO;
+import com.ylx.giftCard.domain.vo.GiftCardDetailVO;
+import com.ylx.giftCard.domain.vo.GiftCardVO;
+
 public interface IGiftCardService {
+
+    Page<GiftCardVO> getGiftCardPage(Page<GiftCard> page);
+
+    boolean purchaseGiftCard(GiftCardPurchaseDTO dto);
+
+    GiftCardDetailVO getGiftCardDetail(Long id);
 }

+ 154 - 1
nightFragrance-massage/src/main/java/com/ylx/giftCard/service/impl/GiftCardOrderServiceImpl.java

@@ -1,12 +1,165 @@
 package com.ylx.giftCard.service.impl;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ylx.common.core.domain.model.WxLoginUser;
+import com.ylx.common.exception.ServiceException;
+import com.ylx.common.utils.DateUtils;
+import com.ylx.common.utils.SecurityUtils;
+import com.ylx.giftCard.domain.GiftCard;
 import com.ylx.giftCard.domain.GiftCardOrder;
 import com.ylx.giftCard.mapper.GiftCardOrderMapper;
 import com.ylx.giftCard.service.IGiftCardOrderService;
+import com.ylx.massage.domain.TJs;
+import com.ylx.massage.service.TJsService;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
 @Service
 public class GiftCardOrderServiceImpl extends ServiceImpl<GiftCardOrderMapper, GiftCardOrder> implements IGiftCardOrderService {
 
-}
+    @Resource
+    private TJsService jsService;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public List<GiftCardOrder> buildOrders(GiftCard card, Integer quantity, String merchantId) {
+        // 1. 参数校验
+        if (ObjectUtil.isNull(card)) {
+            throw new IllegalArgumentException("购物卡信息不能为空");
+        }
+        if (quantity == null || quantity <= 0) {
+            throw new IllegalArgumentException("购买数量必须大于0");
+        }
+
+        // 2. 获取用户信息
+        WxLoginUser wxLoginUser = SecurityUtils.getWxLoginUser();
+        if (ObjectUtil.isNull(wxLoginUser)) {
+            log.warn("用户未登录,无法创建订单");
+            throw new ServiceException("用户未登录");
+        }
+
+        // 3. 查询商户信息(只查询一次,避免重复查询)
+        TJs merchant = null;
+        if (StrUtil.isNotEmpty(merchantId)) {
+            merchant = this.jsService.getById(merchantId);
+            if (ObjectUtil.isNull(merchant)) {
+                log.warn("商户信息不存在,ID: {}", merchantId);
+            }
+        }
+
+        // 4. 批量创建订单
+        List<GiftCardOrder> orders = new ArrayList<>(quantity);
+        for (int i = 0; i < quantity; i++) {
+            GiftCardOrder order = createSingleOrder(card, wxLoginUser, merchant, i + 1, quantity);
+            orders.add(order);
+        }
+
+        // 5. 批量插入订单
+        boolean insertResult = this.saveBatch(orders);
+        if (!insertResult) {
+            log.warn("批量创建购物卡订单失败,购物卡ID: {},下单人ID: {},总数量: {}", card.getId(), wxLoginUser.getId(), quantity);
+            throw new ServiceException("批量创建订单失败");
+        }
+
+        log.info("批量创建购物卡订单成功,购物卡ID: {},下单人ID: {},总数量: {}", card.getId(), wxLoginUser.getId(), quantity);
+        return orders;
+    }
+
+    /**
+     * 创建单个订单
+     */
+    private GiftCardOrder createSingleOrder(GiftCard card, WxLoginUser wxLoginUser, TJs merchant, int currentSeq, int totalQuantity) {
+        GiftCardOrder order = new GiftCardOrder();
+
+        // 生成唯一订单号
+        String orderNo = generateUniqueOrderNo(currentSeq);
+        order.setOrderNo(orderNo);
+
+        // 设置购物卡信息
+        setGiftCardInfo(order, card);
+
+        // 设置用户信息
+        setUserInfo(order, wxLoginUser);
+
+        // 设置商户信息
+        setMerchantInfo(order, merchant);
+
+        // 计算金额(每张卡的金额)
+        calculateAmountPerCard(order, card);
+
+        // 设置订单状态和时间
+        order.setStatus(1); // 已支付
+        order.setCreateTime(DateUtils.getNowDate());
+        order.setUpdateTime(order.getCreateTime());
+
+        return order;
+    }
+
+    /**
+     * 生成唯一订单号(带序列号)
+     */
+    private String generateUniqueOrderNo(int sequence) {
+        long timestamp = System.currentTimeMillis();
+        String randomNum = RandomUtil.randomNumbers(6);
+        // 可以加入序列号信息,便于区分同批订单中的不同卡
+        return "GC" + timestamp + randomNum + String.format("%02d", sequence); // 序列号补零
+    }
+
+    /**
+     * 设置购物卡信息
+     */
+    private void setGiftCardInfo(GiftCardOrder order, GiftCard card) {
+        order.setGiftCardId(card.getId());
+        order.setGiftCardName(card.getName());
+        order.setGiftCardAmount(card.getAmount());
+        order.setCommissionRate(card.getCommissionRate());
+    }
+
+    /**
+     * 设置用户信息
+     */
+    private void setUserInfo(GiftCardOrder order, WxLoginUser wxLoginUser) {
+        order.setUserId(wxLoginUser.getId());
+        order.setUserName(wxLoginUser.getUsername());
+        order.setUserPhone(wxLoginUser.getCPhone());
+    }
+
+    /**
+     * 设置商户信息
+     */
+    private void setMerchantInfo(GiftCardOrder order, TJs merchant) {
+        if (ObjectUtil.isNotNull(merchant)) {
+            order.setMerchantId(merchant.getId());
+            order.setMerchantName(merchant.getcName());
+            order.setMerchantNickName(merchant.getcNickName());
+            // order.setMerchantAccount(merchant.getAccount());
+        }
+    }
+
+    /**
+     * 计算单张卡的金额(每张卡的金额相同)
+     */
+    private void calculateAmountPerCard(GiftCardOrder order, GiftCard card) {
+        // 单张卡的支付金额 = 购物卡面额
+        BigDecimal payAmount = card.getAmount().setScale(2, RoundingMode.HALF_UP);
+        order.setPayAmount(payAmount);
+
+        // 单张卡的佣金金额 = 面额 * 佣金率 / 100
+        BigDecimal commissionAmount = payAmount
+                .multiply(card.getCommissionRate())
+                .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
+        order.setCommissionAmount(commissionAmount);
+    }
+}

+ 146 - 0
nightFragrance-massage/src/main/java/com/ylx/giftCard/service/impl/GiftCardServiceImpl.java

@@ -1,11 +1,157 @@
 package com.ylx.giftCard.service.impl;
 
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ylx.giftCard.domain.GiftCard;
+import com.ylx.giftCard.domain.GiftCardOrder;
+import com.ylx.giftCard.domain.dto.GiftCardPurchaseDTO;
+import com.ylx.giftCard.domain.vo.GiftCardDetailVO;
+import com.ylx.giftCard.domain.vo.GiftCardVO;
 import com.ylx.giftCard.mapper.GiftCardMapper;
+import com.ylx.giftCard.service.IGiftCardOrderService;
 import com.ylx.giftCard.service.IGiftCardService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+
+@Slf4j
 @Service
 public class GiftCardServiceImpl extends ServiceImpl<GiftCardMapper, GiftCard> implements IGiftCardService {
+
+    @Resource
+    private IGiftCardOrderService giftCardOrderService;
+
+    private static final int NOT_DELETE = 0;
+    private static final int PUBLISHED = 1;
+
+    @Override
+    public Page<GiftCardVO> getGiftCardPage(Page<GiftCard> page) {
+
+        LambdaQueryWrapper<GiftCard> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(GiftCard::getIsDelete, NOT_DELETE);
+        wrapper.eq(GiftCard::getIsPublished, PUBLISHED);
+        wrapper.orderByDesc(GiftCard::getCreateTime);
+
+        Page<GiftCard> giftCardPage = this.baseMapper.selectPage(page, wrapper);
+        Page<GiftCardVO> pageData = new Page<>(
+                giftCardPage.getCurrent(),
+                giftCardPage.getSize(),
+                giftCardPage.getTotal()
+        );
+
+        if (CollectionUtil.isNotEmpty(giftCardPage.getRecords())) {
+            List<GiftCardVO> voList = giftCardPage.getRecords().stream()
+                    .map(GiftCardVO::new)
+                    .collect(Collectors.toList());
+            pageData.setRecords(voList);
+        }
+
+        return pageData;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean purchaseGiftCard(GiftCardPurchaseDTO dto) {
+        Long id = dto.getId();
+        Integer quantity = dto.getQuantity();
+        String merchantId = dto.getMerchantId();
+
+        GiftCard card = this.getById(id);
+        if (ObjectUtil.isNull(card)) {
+            log.warn("购买失败,购物卡不存在,ID: {}", id);
+            return false;
+        }
+
+        // 2. 校验购物卡状态
+        if (card.getIsDelete() != NOT_DELETE) {
+            log.warn("购买失败,购物卡已删除,ID: {}", id);
+            return false;
+        }
+        if (card.getIsPublished() != PUBLISHED) {
+            log.warn("购买失败,购物卡未上架,ID: {}", id);
+            return false;
+        }
+
+        // 3. 校验库存是否充足
+        if (card.getStock() < quantity) {
+            log.warn("购买失败,库存不足,ID: {},库存: {},需求数量: {}", id, card.getStock(), quantity);
+            return false;
+        }
+
+        // 4. 扣减库存(使用乐观锁防止超卖)
+        String updateExpr = String.format("stock = stock - %d, sales = sales + %d", quantity, quantity);
+
+        LambdaUpdateWrapper<GiftCard> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.eq(GiftCard::getId, id)
+                .eq(GiftCard::getIsDelete, NOT_DELETE)
+                .eq(GiftCard::getIsPublished, PUBLISHED)
+                .ge(GiftCard::getStock, quantity) // 关键:确保库存充足
+                .setSql(updateExpr);
+
+        int rowsAffected = this.baseMapper.update(null, updateWrapper);
+
+        if (rowsAffected <= 0) {
+            log.warn("购买失败,库存不足或商品不存在,购物卡ID: {}", id);
+            return false;
+        }
+
+        log.info("购买成功,购物卡ID: {}, 数量: {}", id, quantity);
+
+        // 5. 异步创建订单(传入完整的购物卡对象,避免异步方法中再次查询)
+        createOrderAsync(card, quantity, merchantId);
+
+        // 6. 异步添加购物金明细 TODO
+
+        return true;
+    }
+
+    @Override
+    public GiftCardDetailVO getGiftCardDetail(Long id) {
+
+        LambdaQueryWrapper<GiftCard> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(GiftCard::getId, id)
+                .eq(GiftCard::getIsDelete, NOT_DELETE)
+                .eq(GiftCard::getIsPublished, PUBLISHED);
+
+        GiftCard card = this.getOne(wrapper);
+        if (ObjectUtil.isNull(card)) {
+            return null;
+        }
+
+        GiftCardDetailVO vo = new GiftCardDetailVO();
+        BeanUtil.copyProperties(card, vo);
+        return vo;
+    }
+
+    /**
+     * 异步创建订单
+     */
+    @Async
+    public void createOrderAsync(GiftCard card, Integer quantity, String merchantId) {
+        try {
+            // 注意:异步方法中不要依赖主线程的事务,订单创建失败不应影响库存扣减
+            List<GiftCardOrder> orders = this.giftCardOrderService.buildOrders(card, quantity, merchantId);
+
+            if (orders != null && !orders.isEmpty()) {
+                log.info("购物卡订单创建成功,订单数量: {},购物卡ID: {}", orders.size(), card.getId());
+            } else {
+                log.warn("购物卡订单创建返回为空,购物卡ID: {}", card.getId());
+            }
+        } catch (Exception e) {
+            log.error("异步创建订单失败,订单数据: cardId={}, quantity={}, merchantId={}",
+                    card.getId(), quantity, merchantId, e);
+        }
+    }
+
 }

+ 2 - 2
nightFragrance-massage/src/main/java/com/ylx/massage/domain/TWxUser.java

@@ -106,10 +106,10 @@ public class TWxUser implements Serializable {
     private JSONArray cAddressList;
 
     /**
-     * 当前余额
+     * 当前购物金剩余(原余额
      */
     @TableField("d_balance")
-    @ApiModelProperty("当前余")
+    @ApiModelProperty("当前购物金剩余")
     private BigDecimal dBalance;
 
     /**

+ 17 - 4
nightFragrance-massage/src/main/java/com/ylx/massage/service/TWxUserService.java

@@ -2,14 +2,12 @@ package com.ylx.massage.service;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.ylx.massage.domain.TOrder;
 import com.ylx.massage.domain.TWxUser;
 import com.ylx.massage.domain.vo.TWxUserVo;
+import com.ylx.shoppingfunds.domain.dto.MyShoppingFundsUpdateDto;
+import com.ylx.shoppingfunds.domain.vo.MyShoppingFundsQueryVo;
 
 import java.math.BigDecimal;
-import java.time.YearMonth;
-import java.util.List;
-import java.util.Map;
 
 
 /**
@@ -47,4 +45,19 @@ public interface TWxUserService extends IService<TWxUser> {
      * @return TWxUser 登录用户
      */
     TWxUser phoneLogin(String phone);
+
+    /**
+     * 根据userId获取我的购物金余额信息
+     * @param userId
+     * @return
+     */
+    MyShoppingFundsQueryVo queryMyShoppingFunds(String userId);
+
+    /**
+     * 更新我的购物金余额
+     * @param userId
+     * @param amount
+     * @param expenseType
+     */
+    void updateMyShoppingFunds(String userId, BigDecimal amount, Integer expenseType);
 }

+ 52 - 2
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TWxUserServiceImpl.java

@@ -1,6 +1,7 @@
 package com.ylx.massage.service.impl;
 
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -9,9 +10,14 @@ import com.ylx.massage.domain.TWxUser;
 import com.ylx.massage.domain.vo.TWxUserVo;
 import com.ylx.massage.mapper.TWxUserMapper;
 import com.ylx.massage.service.TWxUserService;
+import com.ylx.shopingfundsdetail.service.ShoppingFundsDetailService;
+import com.ylx.shoppingfunds.domain.dto.MyShoppingFundsUpdateDto;
+import com.ylx.shoppingfunds.domain.vo.MyShoppingFundsQueryVo;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
-import java.util.Collection;
+import javax.annotation.Resource;
+import java.math.BigDecimal;
 import java.util.List;
 import java.util.Optional;
 
@@ -21,7 +27,8 @@ import java.util.Optional;
  */
 @Service
 public class TWxUserServiceImpl extends ServiceImpl<TWxUserMapper, TWxUser> implements TWxUserService {
-
+    @Resource(name = "shoppingFundsDetailService")
+    private ShoppingFundsDetailService shoppingFundsDetailService;
     @Override
     public TWxUser getByOpenId(String openId) {
         LambdaQueryWrapper<TWxUser> wrapper = new LambdaQueryWrapper<>();
@@ -80,4 +87,47 @@ public class TWxUserServiceImpl extends ServiceImpl<TWxUserMapper, TWxUser> impl
         }
         return user;
     }
+
+    /**
+     * 查询我的购物金余额
+     * @param userId
+     * @return
+     */
+    @Override
+    public MyShoppingFundsQueryVo queryMyShoppingFunds(String userId) {
+        TWxUser user = this.getById(userId);
+        if (ObjectUtil.isNull(user)) {
+            throw new IllegalArgumentException("参数有误,用户不存在");
+        }
+        MyShoppingFundsQueryVo myShoppingFundsVo = new MyShoppingFundsQueryVo();
+        myShoppingFundsVo.setWxUserId(user.getId());
+        myShoppingFundsVo.setDBalance(user.getdBalance());
+        return myShoppingFundsVo;
+    }
+
+    /**
+     * 更新我的购物金余额
+     * @param userId
+     * @param amount
+     * @param expenseType
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateMyShoppingFunds(String userId, BigDecimal amount, Integer expenseType) {
+        TWxUser user = this.getById(userId);
+        if (ObjectUtil.isNull(user)){
+            throw new IllegalArgumentException("参数有误,用户不存在");
+        }
+        //表示购卡
+        if(expenseType.equals(0)){
+            user.setdBalance(user.getdBalance().add(amount));
+        }else if(expenseType.equals(1)){
+            //表示消费购物金
+            if(user.getdBalance().compareTo(amount)<0) {
+                throw new IllegalArgumentException("参数有误,余额不足");
+            }
+            user.setdBalance(user.getdBalance().subtract(amount));
+        }
+        this.updateById(user);
+    }
 }

+ 48 - 0
nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/controller/ShoppingFundsDetailController.java

@@ -0,0 +1,48 @@
+package com.ylx.shopingfundsdetail.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ylx.common.core.domain.R;
+import com.ylx.shopingfundsdetail.domain.dto.ShoppingFundsDetailQueryDto;
+import com.ylx.shopingfundsdetail.domain.vo.ShoppingFundsDetailAddDto;
+import com.ylx.shopingfundsdetail.domain.vo.ShoppingFundsDetailQueryVo;
+import com.ylx.shopingfundsdetail.service.ShoppingFundsDetailService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 类描述:我的购物金明细C端
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/1 10:58
+ */
+@RestController
+@RequestMapping("/shopping/funds/detail")
+@Api(tags = {"购物金明细"})
+@Slf4j
+public class ShoppingFundsDetailController {
+    @Resource(name = "shoppingFundsDetailService")
+    private ShoppingFundsDetailService shoppingFundsDetailService;
+
+    @ApiOperation("查询购物金明细")
+    @PostMapping(value="queryShoppingFundsDetail")
+    public R<Page<ShoppingFundsDetailQueryVo>> queryShoppingFundsDetail(@RequestBody ShoppingFundsDetailQueryDto shoppingFundsDetailQueryDto) {
+        Page<ShoppingFundsDetailQueryVo> v =  shoppingFundsDetailService.queryShoppingFundsDetail(shoppingFundsDetailQueryDto);
+        return R.ok(v);
+    }
+
+    @ApiOperation("新增购物金明细")
+    @PostMapping(value="addShoppingFundsDetail")
+    public R<?> addShoppingFundsDetail(@RequestBody ShoppingFundsDetailAddDto dto) {
+        shoppingFundsDetailService.addShoppingFundsDetail(dto);
+        return R.ok();
+    }
+
+}

+ 63 - 0
nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/domain/ShoppingFundsDetail.java

@@ -0,0 +1,63 @@
+package com.ylx.shopingfundsdetail.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ylx.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+/**
+ * 类描述:购物金明细表
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/1 10:28
+ */
+@Data
+@TableName(value = "t_shopping_funds_detail",autoResultMap = true)
+@ApiModel(value = "ShoppingFundsDetail", description = "购物金明细记录表")
+public class ShoppingFundsDetail extends BaseEntity {
+    private static final long serialVersionUID = -5890473596508557032L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    @ApiModelProperty("主键")
+    private Long id;
+    /**
+     * 购物卡id
+     */
+    @TableField("gift_card_id")
+    @ApiModelProperty("购物卡id")
+    private Long giftCardId;
+
+    @TableField("user_id")
+    @ApiModelProperty("用户id")
+    private String userId;
+    /**
+     * 购物金消费类型
+     */
+    @TableField("expense_type")
+    @ApiModelProperty("消费类型:0-收入,1-支出")
+    private Integer expenseType;
+    /**
+     * 金额
+     */
+    @TableField("amount")
+    @ApiModelProperty("金额")
+    private BigDecimal amount;
+    /**
+     * 对应余额
+     */
+    @TableField("balance")
+    @ApiModelProperty("对应余额")
+    private BigDecimal balance;
+
+}

+ 46 - 0
nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/domain/dto/ShoppingFundsDetailQueryDto.java

@@ -0,0 +1,46 @@
+package com.ylx.shopingfundsdetail.domain.dto;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 类描述:我的购物金明细dto
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/1 11:04
+ */
+@Data
+@ApiModel("我的购物金明细dto")
+public class ShoppingFundsDetailQueryDto {
+
+    @NotNull(message = "页码不能为空")
+    @ApiModelProperty("页码")
+    private Integer pageNo;
+    @NotNull(message = "页数不能为空")
+    @ApiModelProperty("页数")
+    private Integer pageSize;
+    @NotBlank(message = "用户id不能为空")
+    @ApiModelProperty("用户id")
+    private String userId;
+
+    /**
+     * 开始时间
+     */
+    @ApiModelProperty("查询开始时间")
+    private String startTime;
+
+    /**
+     * 结束时间
+     */
+    @ApiModelProperty("查询结束时间")
+    private String endTime;
+
+}

+ 46 - 0
nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/domain/vo/ShoppingFundsDetailAddDto.java

@@ -0,0 +1,46 @@
+package com.ylx.shopingfundsdetail.domain.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+/**
+ * 类描述:新增购物金明细dto
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/1 11:04
+ */
+@Data
+@ApiModel("新增我的购物金明细")
+public class ShoppingFundsDetailAddDto {
+
+    @NotBlank(message = "用户id不能为空")
+    @ApiModelProperty("用户id")
+    private String userId;
+    /**
+     * 购物卡id
+     */
+    @NotBlank(message = "购物卡id不能为空")
+    @ApiModelProperty("购物卡id")
+    private Long giftCardId;
+    /**
+     * 购物金消费类型
+     */
+    @NotNull(message = "消费类型不能为空")
+    @ApiModelProperty("消费类型:0-收入,1-支出")
+    private Integer expenseType;
+
+    /**
+     * 金额
+     */
+    @NotBlank(message = "金额不能为空")
+    @ApiModelProperty("金额")
+    private BigDecimal amount;
+
+}

+ 53 - 0
nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/domain/vo/ShoppingFundsDetailQueryVo.java

@@ -0,0 +1,53 @@
+package com.ylx.shopingfundsdetail.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 类描述:我的购物金明细vo
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/1 11:04
+ */
+@Data
+@ApiModel("我的购物金明细vo")
+public class ShoppingFundsDetailQueryVo {
+    /**
+     * 主键ID
+     */
+    @ApiModelProperty("主键")
+    private Long id;
+
+    @ApiModelProperty("用户id")
+    private String userId;
+    /**
+     * 购物金消费类型
+     */
+    @ApiModelProperty("消费类型:0-收入,1-支出")
+    private Integer expenseType;
+    /**
+     * 前端展示消费类型
+     */
+    @ApiModelProperty("消费类型:0-收入,1-支出")
+    private String expenseTypeName;
+    /**
+     * 金额
+     */
+    @ApiModelProperty("金额")
+    private BigDecimal amount;
+    /**
+     * 对应余额
+     */
+    @ApiModelProperty("对应余额")
+    private BigDecimal balance;
+    /**
+     * 创建时间
+     */
+    @ApiModelProperty("创建时间")
+    private String createTime;
+
+}

+ 19 - 0
nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/mapper/ShoppingFundsDetailMapper.java

@@ -0,0 +1,19 @@
+package com.ylx.shopingfundsdetail.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ylx.shopingfundsdetail.domain.ShoppingFundsDetail;
+import com.ylx.shopingfundsdetail.domain.dto.ShoppingFundsDetailQueryDto;
+import com.ylx.shopingfundsdetail.domain.vo.ShoppingFundsDetailQueryVo;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 类描述:购物金明细数据库操作
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/1 10:51
+ */
+public interface ShoppingFundsDetailMapper extends BaseMapper<ShoppingFundsDetail> {
+    Page<ShoppingFundsDetailQueryVo> queryShoppingFundsDetail(@Param("dto")  ShoppingFundsDetailQueryDto shoppingFundsDetailQueryDto, @Param("page") Page<ShoppingFundsDetailQueryVo> page);
+}

+ 25 - 0
nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/service/ShoppingFundsDetailService.java

@@ -0,0 +1,25 @@
+package com.ylx.shopingfundsdetail.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ylx.shopingfundsdetail.domain.ShoppingFundsDetail;
+import com.ylx.shopingfundsdetail.domain.dto.ShoppingFundsDetailQueryDto;
+import com.ylx.shopingfundsdetail.domain.vo.ShoppingFundsDetailAddDto;
+import com.ylx.shopingfundsdetail.domain.vo.ShoppingFundsDetailQueryVo;
+
+import java.util.List;
+
+/**
+ * 类描述:
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/1 10:55
+ */
+public interface ShoppingFundsDetailService extends IService<ShoppingFundsDetail> {
+
+    Page<ShoppingFundsDetailQueryVo> queryShoppingFundsDetail(ShoppingFundsDetailQueryDto shoppingFundsDetailQueryDto);
+
+    void addShoppingFundsDetail(ShoppingFundsDetailAddDto dto);
+
+}

+ 52 - 0
nightFragrance-massage/src/main/java/com/ylx/shopingfundsdetail/service/impl/ShoppingFundsDetailServiceImpl.java

@@ -0,0 +1,52 @@
+package com.ylx.shopingfundsdetail.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ylx.massage.domain.TWxUser;
+import com.ylx.massage.service.TWxUserService;
+import com.ylx.shopingfundsdetail.domain.ShoppingFundsDetail;
+import com.ylx.shopingfundsdetail.domain.dto.ShoppingFundsDetailQueryDto;
+import com.ylx.shopingfundsdetail.domain.vo.ShoppingFundsDetailAddDto;
+import com.ylx.shopingfundsdetail.domain.vo.ShoppingFundsDetailQueryVo;
+import com.ylx.shopingfundsdetail.mapper.ShoppingFundsDetailMapper;
+import com.ylx.shopingfundsdetail.service.ShoppingFundsDetailService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * 类描述:
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/1 10:56
+ */
+@Service("shoppingFundsDetailService")
+public class ShoppingFundsDetailServiceImpl extends ServiceImpl<ShoppingFundsDetailMapper, ShoppingFundsDetail> implements ShoppingFundsDetailService {
+
+    @Resource
+    private TWxUserService wxUserService;
+    @Override
+    public Page<ShoppingFundsDetailQueryVo> queryShoppingFundsDetail(ShoppingFundsDetailQueryDto shoppingFundsDetailQueryDto) {
+        Page<ShoppingFundsDetailQueryVo> page = new Page<ShoppingFundsDetailQueryVo>(shoppingFundsDetailQueryDto.getPageNo(), shoppingFundsDetailQueryDto.getPageSize());
+        return baseMapper.queryShoppingFundsDetail(shoppingFundsDetailQueryDto,page);
+    }
+
+    /**
+     * 新增购物金明细
+     * @param dto
+     */
+    @Override
+    public void addShoppingFundsDetail(ShoppingFundsDetailAddDto dto) {
+        ShoppingFundsDetail shoppingFundsDetail = new ShoppingFundsDetail();
+        BeanUtils.copyProperties(dto, shoppingFundsDetail);
+        TWxUser user = wxUserService.getById(dto.getUserId());
+        if (ObjectUtil.isNull(user)){
+            throw new IllegalArgumentException("参数有误,用户不存在");
+        }
+        shoppingFundsDetail.setBalance(user.getdBalance());
+        baseMapper.insert(shoppingFundsDetail);
+    }
+}

+ 43 - 0
nightFragrance-massage/src/main/java/com/ylx/shoppingfunds/controller/MyShoppingFundsController.java

@@ -0,0 +1,43 @@
+package com.ylx.shoppingfunds.controller;
+
+import com.ylx.common.core.domain.R;
+import com.ylx.massage.service.TWxUserService;
+import com.ylx.shoppingfunds.domain.dto.MyShoppingFundsUpdateDto;
+import com.ylx.shoppingfunds.domain.vo.MyShoppingFundsQueryVo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+/**
+ * 类描述:我的购物金
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/1 8:53
+ */
+@RestController
+@RequestMapping("/shoppingFunds")
+@Api(tags = {"我的购物金"})
+@Slf4j
+public class MyShoppingFundsController {
+    @Resource
+    private TWxUserService wxUserService;
+
+
+    @ApiOperation("查询我的购物金剩余")
+    @GetMapping(value="queryMyShoppingFunds")
+    public R<MyShoppingFundsQueryVo> queryMyShoppingFunds(@RequestParam("userId")String userId) {
+        return R.ok(wxUserService.queryMyShoppingFunds(userId));
+    }
+
+    @ApiOperation("更新购物金")
+    @PostMapping(value="updateMyShoppingFunds")
+    public R<?> updateMyShoppingFunds(@RequestBody MyShoppingFundsUpdateDto myShoppingFundsUpdateDto) {
+       wxUserService.updateMyShoppingFunds(myShoppingFundsUpdateDto.getWxUserId(), myShoppingFundsUpdateDto.getAmount(), myShoppingFundsUpdateDto.getExpenseType());
+        return R.ok();
+    }
+
+}

+ 38 - 0
nightFragrance-massage/src/main/java/com/ylx/shoppingfunds/domain/dto/MyShoppingFundsUpdateDto.java

@@ -0,0 +1,38 @@
+package com.ylx.shoppingfunds.domain.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 类描述:更新我的购物金余额
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/1 9:21
+ */
+@Data
+@ApiModel("更新我的购物金余额dto")
+public class MyShoppingFundsUpdateDto implements Serializable {
+    private static final long serialVersionUID = -1987716391112070123L;
+
+    @NotBlank(message = "userId不能为空")
+    @ApiModelProperty("微信用户userId")
+    private String  wxUserId;
+
+    @NotBlank(message = "金额不能为空")
+    @ApiModelProperty("若是购卡即这次购卡花费;若消费购物金则表示这次消费金额")
+    private BigDecimal amount;
+
+    @NotNull(message = "消费类型不能为空")
+    @ApiModelProperty("消费类型:0-购卡,1-消费")
+    private Integer expenseType;
+
+
+
+}

+ 27 - 0
nightFragrance-massage/src/main/java/com/ylx/shoppingfunds/domain/vo/MyShoppingFundsQueryVo.java

@@ -0,0 +1,27 @@
+package com.ylx.shoppingfunds.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 类描述:查询我的购物金余额vo
+ *
+ * @author Administrator
+ * @version 1.0
+ * @date 2026/6/1 9:00
+ */
+@Data
+@ApiModel("我的购物金余额vo")
+public class MyShoppingFundsQueryVo implements Serializable {
+    private static final long serialVersionUID = -1987716391112070123L;
+
+    @ApiModelProperty("微信用户userId")
+    private String  wxUserId;
+
+    @ApiModelProperty("当前购物金剩余")
+    private BigDecimal dBalance;
+}

+ 30 - 0
nightFragrance-massage/src/main/resources/mapper/giftCard/ShoppingFundsDetailMapper.xml

@@ -0,0 +1,30 @@
+<?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="com.ylx.shopingfundsdetail.mapper.ShoppingFundsDetailMapper">
+    <!-- C端购物金明细 -->
+    <select id="queryShoppingFundsDetail" resultType="com.ylx.shopingfundsdetail.domain.vo.ShoppingFundsDetailQueryVo">
+        select
+            d.id AS id,
+            d.user_id AS userId,
+            d.expense_type AS expenseType,
+            CASE
+             WHEN d.expense_type = 0 THEN '收入'
+             WHEN d.expense_type = 1 THEN '支出'
+            ELSE '未知'
+            END            AS expenseTypeName,
+            d.amount AS amount,
+            d.balance AS balance,
+            d.create_time AS createTime
+        from t_shopping_funds_detail d
+        where 1=1
+        <if test="dto.userId != null">
+            and d.user_id = #{dto.userId}
+        </if>
+        <if test="dto.startTime != null and dto.endTime != null and dto.startTime != '' and dto.endTime != ''">
+            and DATE_FORMAT(d.create_time, '%Y-%m-%d') >= #{dto.startTime}
+            and DATE_FORMAT(d.create_time, '%Y-%m-%d') &lt;= #{dto.endTime}
+        </if>
+    </select>
+</mapper>