Administrator
2026-07-01 e1d1b5e5a2248381bc4faa2ac0e629676d17ff3c
feat(mall): 支持优惠券多选绑定功能

- 将 AdminCouponSelectVo 中的 couponId 字段改为 couponIds 列表
- 修改 AdminMallMemberServiceImpl 实现优惠券批量绑定逻辑
- 更新 ApiMallMemberServiceImpl 中的优惠券领取和扫描逻辑支持多张优惠券
- 在前端页面将单选下拉框改为多选组件,使用 xmSelect 实现
- 更新 MallMember 实体类添加 couponIds 列表字段
- 修改 SalemanCouponMapper 返回优惠券列表而非单个对象
- 添加优惠券重复绑定检查避免重复操作
6 files modified
138 ■■■■■ changed files
src/main/java/cc/mrbird/febs/mall/entity/MallMember.java 5 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/mapper/SalemanCouponMapper.java 4 ●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/AdminMallMemberServiceImpl.java 22 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java 53 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/AdminCouponSelectVo.java 4 ●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/mallMember/couponSelect.html 50 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/entity/MallMember.java
@@ -9,6 +9,7 @@
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
 * @author wzy
@@ -162,10 +163,12 @@
    //优惠卷名称
    @TableField(exist = false)
    private String couponName;
    //优惠卷名称
    @TableField(exist = false)
    private Long couponId;
    //优惠卷ID列表(支持多选)
    @TableField(exist = false)
    private List<Long> couponIds;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
src/main/java/cc/mrbird/febs/mall/mapper/SalemanCouponMapper.java
@@ -4,8 +4,10 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface SalemanCouponMapper extends BaseMapper<SalemanCoupon> {
    SalemanCoupon selectByMemberId(@Param("memberId")Long memberId);
    List<SalemanCoupon> selectByMemberId(@Param("memberId")Long memberId);
}
src/main/java/cc/mrbird/febs/mall/service/impl/AdminMallMemberServiceImpl.java
@@ -391,21 +391,25 @@
        if(ObjectUtil.isEmpty(member)){
            throw new FebsException("请刷新页面");
        }
        Long couponId = mallmember.getCouponId();
        List<Long> couponIds = mallmember.getCouponIds();
        if(CollUtil.isEmpty(couponIds)){
            return new FebsResponse().fail().message("请选择优惠券");
        }
        QueryWrapper<SalemanCoupon> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.eq("member_id",member.getId());
        List<SalemanCoupon> salemanCouponList = salemanCouponMapper.selectList(objectQueryWrapper);
        if(CollUtil.isNotEmpty(salemanCouponList)){
            SalemanCoupon salemanCoupon = salemanCouponList.get(0);
            salemanCoupon.setCouponId(couponId);
            salemanCouponMapper.updateById(salemanCoupon);
            return new FebsResponse().success().message("操作成功");
        for(Long couponId : couponIds){
            // 检查是否已绑定,已绑定则跳过
            QueryWrapper<SalemanCoupon> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("member_id", member.getId());
            queryWrapper.eq("coupon_id", couponId);
            SalemanCoupon exist = salemanCouponMapper.selectOne(queryWrapper);
            if(ObjectUtil.isNotEmpty(exist)){
                continue;
        }
        SalemanCoupon salemanCoupon = new SalemanCoupon();
        salemanCoupon.setMemberId(member.getId());
        salemanCoupon.setCouponId(couponId);
        salemanCouponMapper.insert(salemanCoupon);
        }
        return new FebsResponse().success().message("操作成功");
    }
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java
@@ -24,6 +24,7 @@
import cc.mrbird.febs.vip.mapper.MallVipConfigMapper;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import java.util.List;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
@@ -923,45 +924,40 @@
    @Override
    public FebsResponse getCoupon(GetCouponDto getCouponDto) {
        Long memberId = LoginUserUtil.getLoginUser().getId();
        Long goodsId = getCouponDto.getGoodsId();
        String couponUUID = IdUtil.simpleUUID();
//        String couponUUID = getCouponDto.getCouponUUID();
//        QueryWrapper<MallMemberCoupon> objectQueryWrapper = new QueryWrapper<>();
//        objectQueryWrapper.eq("coupon_uuid",couponUUID);
//        List<MallMemberCoupon> mallMemberCouponDone = mallMemberCouponMapper.selectList(objectQueryWrapper);
//        if(CollUtil.isNotEmpty(mallMemberCouponDone)){
//            return new FebsResponse().success();
//        }
        //验证商品存不存在,且上没上架
        MallGoods mallGoods = mallGoodsMapper.selectById(goodsId);
        if(ObjectUtil.isEmpty(mallGoods) || MallGoods.ISSALE_STATUS_ENABLE != mallGoods.getIsSale()){
            return new FebsResponse().success();
        }
        //通过邀请人信息,获取能领取的优惠卷信息
        MallMember mallMember = this.baseMapper.selectInfoByInviteId(getCouponDto.getInviteId());
        if(ObjectUtil.isNotEmpty(mallMember)){
            SalemanCoupon salemanCoupon = salemanCouponMapper.selectByMemberId(mallMember.getId());
            if(ObjectUtil.isNotEmpty(salemanCoupon)){
            List<SalemanCoupon> salemanCouponList = salemanCouponMapper.selectByMemberId(mallMember.getId());
            if(CollUtil.isNotEmpty(salemanCouponList)){
                for(SalemanCoupon salemanCoupon : salemanCouponList){
                Long couponId = salemanCoupon.getCouponId();
                Long goodsId = getCouponDto.getGoodsId();
                MallGoods mallGoods = mallGoodsMapper.selectById(goodsId);
                //验证商品存不存在,且上没上架
                if(ObjectUtil.isNotEmpty(mallGoods)
                    && MallGoods.ISSALE_STATUS_ENABLE == mallGoods.getIsSale()){
//                List<MallMemberCoupon> mallMemberCoupons = mallMemberCouponMapper.selectListByMemberIdAndGoodsIdAndCouponId(memberId, goodsId, couponId,mallMember.getInviteId());
//                List<MallMemberCoupon> mallMemberCoupons = mallMemberCouponMapper.selectListByMemberIdAndGoodsIdAndCouponIdWithOutInviteId(memberId, goodsId, couponId);
                    List<MallMemberCoupon> mallMemberCoupons = mallMemberCouponMapper.selectListByMemberIdAndGoodsIdAndCouponIdWithOutInviteId(memberId, goodsId);
                    if(CollUtil.isEmpty(mallMemberCoupons)){
                        //商品优惠卷如果绑定了,那么当前登陆者获取一张卷
                    //验证是否已经领取过该优惠券
                    List<MallMemberCoupon> mallMemberCoupons = mallMemberCouponMapper.selectListByMemberIdCouponIdWithOutInviteId(memberId, couponId);
                    if(CollUtil.isNotEmpty(mallMemberCoupons)){
                        continue;
                    }
                    //商品优惠卷如果绑定了该商品,那么当前登陆者获取一张卷
                        List<CouponGoods> couponGoodsList = couponGoodsMapper.selectByGoodIdAndCouponId(goodsId,couponId);
                        MallGoodsCoupon mallGoodsCoupon = mallGoodsCouponMapper.selectById(couponId);
                        if(CollUtil.isNotEmpty(couponGoodsList)){
                    if(CollUtil.isNotEmpty(couponGoodsList) && ObjectUtil.isNotEmpty(mallGoodsCoupon)){
                            MallMemberCoupon mallMemberCoupon = new MallMemberCoupon();
                            mallMemberCoupon.setCouponId(couponId);
                            mallMemberCoupon.setCouponName(mallGoodsCoupon.getName());
                            mallMemberCoupon.setMemberId(memberId);
                            mallMemberCoupon.setGoodsId(goodsId);
                            mallMemberCoupon.setCouponUuid(couponUUID);
                        mallMemberCoupon.setCouponUuid(IdUtil.simpleUUID());
                            mallMemberCoupon.setInviteId(mallMember.getInviteId());
                            mallMemberCoupon.setState(1);
                            mallMemberCoupon.setExpireTime(DateUtil.offsetDay(DateUtil.date(),mallGoodsCoupon.getExpireDay()));
                            mallMemberCouponMapper.insert(mallMemberCoupon);
                        }
                    }
                }
            }
@@ -972,22 +968,23 @@
    @Override
    public FebsResponse scanCoupon(GetCouponDto getCouponDto) {
        Long memberId = LoginUserUtil.getLoginUser().getId();
        String couponUUID = IdUtil.simpleUUID();
        //通过邀请人信息,获取能领取的优惠卷信息
        MallMember mallMember = this.baseMapper.selectInfoByInviteId(getCouponDto.getInviteId());
        if(ObjectUtil.isNotEmpty(mallMember)){
            SalemanCoupon salemanCoupon = salemanCouponMapper.selectByMemberId(mallMember.getId());
            if(ObjectUtil.isNotEmpty(salemanCoupon)){
            List<SalemanCoupon> salemanCouponList = salemanCouponMapper.selectByMemberId(mallMember.getId());
            if(CollUtil.isNotEmpty(salemanCouponList)){
                for(SalemanCoupon salemanCoupon : salemanCouponList){
                Long couponId = salemanCoupon.getCouponId();
                List<MallMemberCoupon> mallMemberCoupons = mallMemberCouponMapper.selectListByMemberIdCouponIdWithOutInviteId(memberId, couponId);
                if(CollUtil.isEmpty(mallMemberCoupons)){
                    //商品优惠卷如果绑定了,那么当前登陆者获取一张卷
                    MallGoodsCoupon mallGoodsCoupon = mallGoodsCouponMapper.selectById(couponId);
                        if(ObjectUtil.isNotEmpty(mallGoodsCoupon)){
                    MallMemberCoupon mallMemberCoupon = new MallMemberCoupon();
                    mallMemberCoupon.setCouponId(couponId);
                    mallMemberCoupon.setCouponName(mallGoodsCoupon.getName());
                    mallMemberCoupon.setMemberId(memberId);
                    mallMemberCoupon.setCouponUuid(couponUUID);
                            mallMemberCoupon.setCouponUuid(IdUtil.simpleUUID());
                    mallMemberCoupon.setInviteId(mallMember.getInviteId());
                    mallMemberCoupon.setState(1);
                    mallMemberCoupon.setExpireTime(DateUtil.offsetDay(DateUtil.date(),mallGoodsCoupon.getExpireDay()));
@@ -995,6 +992,8 @@
                }
            }
        }
            }
        }
        return new FebsResponse().success();
    }
src/main/java/cc/mrbird/febs/mall/vo/AdminCouponSelectVo.java
@@ -3,12 +3,14 @@
import io.swagger.annotations.ApiModel;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(value = "AdminCouponSelectVo", description = "信息返回类")
public class AdminCouponSelectVo {
    private Long id;
    private Long couponId;
    private List<Long> couponIds;
    private String couponName;
}
src/main/resources/templates/febs/views/modules/mallMember/couponSelect.html
@@ -31,10 +31,8 @@
        <div class="layui-form-item">
            <label class="layui-form-label">优惠卷:</label>
            <div class="layui-input-inline">
                <select name="couponId" class="coupon-select-category" id="couponCategarySelect">
                    <option value="">请选择</option>
                </select>
            <div class="layui-input-block">
                <div id="coupon-select-multi"></div>
            </div>
        </div>
@@ -45,7 +43,7 @@
</div>
<script data-th-inline="javascript">
    layui.use(['febs', 'form', 'formSelects', 'validate', 'treeSelect', 'eleTree', 'laydate','upload'], function () {
    layui.use(['febs', 'form', 'formSelects', 'validate', 'treeSelect', 'eleTree', 'laydate','upload', 'xmSelect'], function () {
        var $ = layui.$,
            febs = layui.febs,
            layer = layui.layer,
@@ -57,6 +55,7 @@
            adminCouponSelectVo = [[${adminCouponSelectVo}]],
            $view = $('#coupon-select'),
            upload = layui.upload,
            xmSelect = layui.xmSelect,
            validate = layui.validate;
        form.render();
@@ -66,27 +65,48 @@
        formSelects.render();
        //(下拉框)
        $.get(ctx + 'admin/goods/coupon/tree', function (data) {
            for (var k in data)
            {
                $(".coupon-select-category").append("<option value='" + data[k].couponId + "'>" + data[k].couponName + "</option>");
        // 多选优惠券
        var couponMultiSelect = xmSelect.render({
            el: '#coupon-select-multi',
            language: 'zn',
            tips: '请选择优惠券',
            filterable: true,
            data: []
        });
        febs.get(ctx + 'admin/goods/coupon/tree', null, function(data) {
            var options = [];
            for (var k in data) {
                options.push({
                    name: data[k].couponName,
                    value: data[k].couponId
                });
            }
            layui.use('form', function () {
                var form = layui.form;
                $("#couponCategarySelect").val('')
                form.render();
            couponMultiSelect.update({
                data: options,
                autoRow: true
            });
        });
        initUserValue();
        function initUserValue() {
            form.val("coupon-select-form", {
                "id": adminCouponSelectVo.id,
                "id": adminCouponSelectVo.id
            });
        }
        form.on('submit(coupon-select-form-submit)', function (data) {
            var selected = couponMultiSelect.getValue();
            if (!selected || selected.length === 0) {
                febs.alert.warn('请选择优惠券');
                return false;
            }
            var couponIds = [];
            for (var i = 0; i < selected.length; i++) {
                couponIds.push(selected[i].value);
            }
            data.field.couponIds = couponIds;
            febs.post(ctx + 'admin/mallMember/salemanCoupon', data.field, function () {
                layer.closeAll();
                febs.alert.success('操作成功');