fix
Helius
2024-01-30 7eb522243fb5dce2b7268fdf0927409d5a3b0d70
fix
41 files modified
40 files added
4668 ■■■■■ changed files
src/main/java/cc/mrbird/febs/common/configure/RabbitConfigure.java 32 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/common/enumerates/DataDictionaryEnum.java 12 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/common/enumerates/ScoreFlowTypeEnum.java 34 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/AdminMallMemberController.java 8 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/ApiMallMemberController.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/ApiMallShoppingCartController.java 4 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/ViewMallMemberController.java 13 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/AddCartDto.java 4 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/ApiXcxSaveInfoDto.java 13 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/entity/MallGoodsCoupon.java 1 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/entity/MallMember.java 9 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/entity/MallMemberCoupon.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/entity/MallOrderInfo.java 5 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/entity/MallShoppingCart.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/mapper/MallShoppingCartMapper.java 2 ●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/quartz/OrderSettlementJob.java 8 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/IApiMallMemberService.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/IApiMallShoppingCartService.java 2 ●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/ICommonService.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/AdminMallGoodsService.java 22 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java 121 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java 20 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallShoppingCartServiceImpl.java 53 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/CommonService.java 14 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/MallGoodsDetailsVo.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/MallMemberVo.java 4 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/MoneyFlowVo.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/OrderDetailVo.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/OrderListVo.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/pay/controller/XcxPayController.java 1 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/rabbit/constants/QueueConstants.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/rabbit/consumer/AgentConsumer.java 24 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/rabbit/enumerates/RabbitQueueEnum.java 6 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/rabbit/producter/AgentProducer.java 14 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/VipSettingUnAliveSettingBo.java 13 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/controller/AdminMallVipBenefitsController.java 59 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/controller/AdminMallVipConfigController.java 73 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/controller/ApiMallVipBenefitsController.java 16 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/controller/ApiMallVipConfigController.java 57 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/controller/ViewVipConfigController.java 172 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/entity/MallVipBenefits.java 55 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/entity/MallVipBenefitsDetails.java 51 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/entity/MallVipBenefitsRecord.java 28 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/entity/MallVipConfig.java 83 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/entity/MallVipConfigBenefits.java 20 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/mapper/MallVipBenefitsDetailsMapper.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/mapper/MallVipBenefitsMapper.java 18 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/mapper/MallVipBenefitsRecordMapper.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/mapper/MallVipConfigBenefitsMapper.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/mapper/MallVipConfigMapper.java 17 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/service/IMallVipBenefitsDetailsService.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/service/IMallVipBenefitsService.java 21 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/service/IMallVipConfigBenefitsService.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/service/IMallVipConfigService.java 25 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/service/IVipCommonService.java 8 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/service/impl/MallVipBenefitsDetailsServiceImpl.java 15 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/service/impl/MallVipBenefitsServiceImpl.java 283 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/service/impl/MallVipConfigBenefitsServiceImpl.java 15 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/service/impl/MallVipConfigServiceImpl.java 168 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/service/impl/VipCommonServiceImpl.java 168 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/vip/vo/VipSettingVo.java 14 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/MallGoodsMapper.xml 7 ●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/MallMemberCouponMapper.xml 3 ●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/MallMemberMapper.xml 4 ●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/MallOrderInfoMapper.xml 7 ●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/MallShoppingCartMapper.xml 2 ●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/MallVipBenefitsMapper.xml 59 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/MallVipConfigMapper.xml 58 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/mallMember/mallMemberList.html 26 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/mallMember/vip-level-setting.html 92 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/score/goodsAdd.html 69 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/vip/coupon-select.html 91 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/vip/goods-select-list.html 233 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/vip/vip-setting.html 245 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/vip/vipBenefits-add.html 489 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/vip/vipBenefits-edit.html 513 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/vip/vipBenefits-list.html 165 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/vip/vipConfig-add.html 256 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/vip/vipConfig-edit.html 291 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/vip/vipConfig-list.html 171 ●●●●● patch | view | raw | blame | history
src/test/java/cc/mrbird/febs/ProfitTest.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/common/configure/RabbitConfigure.java
@@ -138,4 +138,36 @@
        return BindingBuilder.bind(orderCouponQueue()).to(orderCouponExchange()).with(RabbitQueueEnum.ORDER_COUPON.getRoute());
    }
    @Bean
    public DirectExchange getScoreMsgExchange() {
        return new DirectExchange(RabbitQueueEnum.GET_SCORE_MSG.getExchange());
    }
    @Bean
    public Queue getScoreMsgQueue() {
        return new Queue(QueueConstants.GET_SCORE_MSG);
    }
    @Bean
    public Binding getScoreMsgBind() {
        return BindingBuilder.bind(getScoreMsgQueue()).to(getScoreMsgExchange()).with(RabbitQueueEnum.GET_SCORE_MSG.getRoute());
    }
    @Bean
    public DirectExchange vipLevelUp() {
        return new DirectExchange(RabbitQueueEnum.VIP_LEVEL_UP.getExchange());
    }
    @Bean
    public Queue vipLevelUpQueue() {
        return new Queue(QueueConstants.VIP_LEVEL_UP);
    }
    @Bean
    public Binding vipLevelUpBind() {
        return BindingBuilder.bind(vipLevelUpQueue()).to(vipLevelUp()).with(RabbitQueueEnum.VIP_LEVEL_UP.getRoute());
    }
}
src/main/java/cc/mrbird/febs/common/enumerates/DataDictionaryEnum.java
@@ -59,7 +59,17 @@
    WIN_CASH("WIN_PROBABILITY", "WIN_CASH"),
    RANK_BONUS("BONUS_TYPE", "RANK_BONUS"),
    CASHOUT_SETTING("CASHOUT_SET", "CASHOUT_SETTING"),
    INDIRECT_BONUS_SETTING("INDIRECT_BONUS_SETTING", "");
    INDIRECT_BONUS_SETTING("INDIRECT_BONUS_SETTING", ""),
    /**
     * 会员日
     */
    VIP_DATE("VIP_DATE", "VIP_DATE"),
    /**
     * 会员日
     */
    UNALIVE_COUPON("UNALIVE_COUPON", "UNALIVE_COUPON");
    private String type;
src/main/java/cc/mrbird/febs/common/enumerates/ScoreFlowTypeEnum.java
New file
@@ -0,0 +1,34 @@
package cc.mrbird.febs.common.enumerates;
import lombok.Getter;
@Getter
public enum ScoreFlowTypeEnum {
    /**
     *
     */
    PAY(1, "积分支付"),
    BUY(2, "购买商品获得积分");
    private final int value;
    private final String desc;
    ScoreFlowTypeEnum(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }
    public static String getDescByValue(int value) {
        for (ScoreFlowTypeEnum scoreFlowTypeEnum : values()) {
            if (value == scoreFlowTypeEnum.getValue()) {
                return scoreFlowTypeEnum.getDesc();
            }
        }
        return "";
    }
}
src/main/java/cc/mrbird/febs/mall/controller/AdminMallMemberController.java
@@ -20,6 +20,7 @@
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -606,4 +607,11 @@
        return mallMemberService.salemanCoupon(mallmember);
    }
    @PostMapping("vipLevelSetUpdate")
    public FebsResponse vipLevelSetUpdate(MallMember member) {
        member.setVipLevelTime(new Date());
        mallMemberService.updateById(member);
        return new FebsResponse().success().message("操作成功");
    }
}
src/main/java/cc/mrbird/febs/mall/controller/ApiMallMemberController.java
@@ -269,4 +269,10 @@
        return memberService.couponDetails(id);
    }
    @ApiOperation(value = "登录事件", notes = "登录事件")
    @GetMapping(value = "/loginEvent")
    public FebsResponse loginEvent() {
        return new FebsResponse().success().data(memberService.loginEvent());
    }
}
src/main/java/cc/mrbird/febs/mall/controller/ApiMallShoppingCartController.java
@@ -38,8 +38,8 @@
            @ApiResponse(code = 200, message = "success", response = ShoppingCartGoodsVo.class)
    })
    @PostMapping(value = "/findCartGoodsList")
    public FebsResponse findCartGoodsList() {
        return new FebsResponse().success().data(mallShoppingCartService.findCartGoodsList());
    public FebsResponse findCartGoodsList(@RequestParam(required = false, value = "type") Integer type) {
        return new FebsResponse().success().data(mallShoppingCartService.findCartGoodsList(type));
    }
    @ApiOperation(value = "添加商品到购物车", notes = "添加商品到购物车")
src/main/java/cc/mrbird/febs/mall/controller/ViewMallMemberController.java
@@ -18,6 +18,9 @@
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.HashMap;
import java.util.Map;
@Controller("mallMemberView")
@RequestMapping(FebsConstant.VIEW_PREFIX + "modules/mallMember")
@RequiredArgsConstructor
@@ -399,5 +402,15 @@
        return FebsUtil.view("modules/mallMember/couponSelect");
    }
    @GetMapping("vipLevelSetting/{id}")
    public String vipLevelSetting(@PathVariable(value = "id") String id, Model model) {
        MallMember mallMember = mallMemberMapper.selectById(id);
        Map<String, Object> data = new HashMap<>();
        data.put("id", mallMember.getId());
        data.put("level", mallMember.getLevel());
        model.addAttribute("vipLevelSet", data);
        return FebsUtil.view("modules/mallMember/vip-level-setting");
    }
}
src/main/java/cc/mrbird/febs/mall/dto/AddCartDto.java
@@ -21,4 +21,8 @@
    @NotNull(message = "参数不能为空")
    @ApiModelProperty(value = "数量")
    private Integer cnt;
    @NotNull(message = "类型不能为空")
    @ApiModelProperty(value = "1-普通商品 2-积分商品")
    private Integer type;
}
src/main/java/cc/mrbird/febs/mall/dto/ApiXcxSaveInfoDto.java
@@ -1,8 +1,12 @@
package cc.mrbird.febs.mall.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@Data
@ApiModel(value = "ApiXcxSaveInfoDto", description = "小程序接收用户数据")
@@ -22,4 +26,13 @@
    @ApiModelProperty(value = "邀请码")
    private String inviteId;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    @ApiModelProperty(value = "生日")
    private Date birthday;
    @ApiModelProperty(value = "真实姓名")
    private String realName;
}
src/main/java/cc/mrbird/febs/mall/entity/MallGoodsCoupon.java
@@ -26,5 +26,4 @@
    //减免金额
    private BigDecimal realAmount;
}
src/main/java/cc/mrbird/febs/mall/entity/MallMember.java
@@ -8,6 +8,7 @@
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
 * @author wzy
@@ -165,4 +166,12 @@
    //优惠卷名称
    @TableField(exist = false)
    private Long couponId;
    private Date birthday;
    private String realName;
    private Date lastLoginTime;
    private Date vipLevelTime;
}
src/main/java/cc/mrbird/febs/mall/entity/MallMemberCoupon.java
@@ -21,4 +21,10 @@
    private Integer state;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date expireTime;
    /**
     * 来源类型 1-默认 2-积分权益 3-失活会员
     */
    private Integer fromType;
}
src/main/java/cc/mrbird/febs/mall/entity/MallOrderInfo.java
@@ -139,4 +139,9 @@
    @TableField(exist = false)
    private String orderIds;
    @TableField(exist = false)
    private String expressNo;
    private Integer isFree;
}
src/main/java/cc/mrbird/febs/mall/entity/MallShoppingCart.java
@@ -23,6 +23,8 @@
    private Integer cnt;
    private Integer type;
    @TableField(exist = false)
    private MallGoods goods;
src/main/java/cc/mrbird/febs/mall/mapper/MallShoppingCartMapper.java
@@ -12,7 +12,7 @@
 **/
public interface MallShoppingCartMapper extends BaseMapper<MallShoppingCart> {
    List<MallShoppingCart> selectCartGoodsList(@Param("memberId") Long memberId);
    List<MallShoppingCart> selectCartGoodsList(@Param("memberId") Long memberId,@Param("type") Integer type);
    MallShoppingCart selectCartGoodsBySkuId(@Param("skuId") Long skuId, @Param("memberId") Long memberId);
src/main/java/cc/mrbird/febs/mall/quartz/OrderSettlementJob.java
@@ -11,6 +11,7 @@
import cc.mrbird.febs.mall.service.IMallAchieveService;
import cc.mrbird.febs.mall.service.IMallMoneyFlowService;
import cc.mrbird.febs.mall.service.IMemberProfitService;
import cc.mrbird.febs.rabbit.producter.AgentProducer;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
@@ -68,6 +69,9 @@
    @Autowired
    private IMallAchieveService mallAchieveService;
    @Autowired
    private AgentProducer agentProducer;
    /**
     * 普通商品结算
@@ -144,6 +148,10 @@
//                }
//            }
            mallOrderInfoMapper.updateOrderConfirmStatus(DateUtil.date(),DateUtil.offsetDay(new Date(), -value));
            orderInfos.forEach(item -> {
                agentProducer.sendVipLevelUp(item.getId());
            });
        }
    }
    /**
src/main/java/cc/mrbird/febs/mall/service/IApiMallMemberService.java
@@ -14,6 +14,7 @@
import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
public interface IApiMallMemberService extends IService<MallMember> {
    FebsResponse register(RegisterDto registerDto);
@@ -94,4 +95,6 @@
    FebsResponse couponDetails(Long id);
    FebsResponse setInvite(ApiSetInviteDto apiSetInviteDto);
    Map<String, Object> loginEvent();
}
src/main/java/cc/mrbird/febs/mall/service/IApiMallShoppingCartService.java
@@ -13,7 +13,7 @@
 **/
public interface IApiMallShoppingCartService extends IService<MallShoppingCart> {
    List<ShoppingCartGoodsVo> findCartGoodsList();
    List<ShoppingCartGoodsVo> findCartGoodsList(Integer type);
    void addGoodsToCart(List<AddCartDto> addCartDto);
src/main/java/cc/mrbird/febs/mall/service/ICommonService.java
@@ -19,4 +19,6 @@
    void addDataDic(String type, String key, Object value, String description);
    void addDataDic(String type, String key, Object value, String description, boolean isJson);
}
src/main/java/cc/mrbird/febs/mall/service/impl/AdminMallGoodsService.java
@@ -73,16 +73,18 @@
            return new FebsResponse().fail().message("商品编号不能重复");
        }
        Integer carriageType = addMallGoodsDto.getCarriageType();
        if(1 == carriageType){
            if(ObjectUtil.isEmpty(addMallGoodsDto.getCarriageAmount())
                    || BigDecimal.ZERO.compareTo(addMallGoodsDto.getCarriageAmount()) > 0){
                return new FebsResponse().fail().message("固定邮费不能小于零");
            }
        }else{
            Long carriageRuleId = addMallGoodsDto.getCarriageRuleId();
            MallCarriageRule mallCarriageRule = mallCarriageRuleMapper.selectById(carriageRuleId);
            if(ObjectUtil.isEmpty(mallCarriageRule)){
                return new FebsResponse().fail().message("邮费模板不能为空");
        if (addMallGoodsDto.getGoodsType() == 1) {
            if (1 == carriageType) {
                if (ObjectUtil.isEmpty(addMallGoodsDto.getCarriageAmount())
                        || BigDecimal.ZERO.compareTo(addMallGoodsDto.getCarriageAmount()) > 0) {
                    return new FebsResponse().fail().message("固定邮费不能小于零");
                }
            } else {
                Long carriageRuleId = addMallGoodsDto.getCarriageRuleId();
                MallCarriageRule mallCarriageRule = mallCarriageRuleMapper.selectById(carriageRuleId);
                if (ObjectUtil.isEmpty(mallCarriageRule)) {
                    return new FebsResponse().fail().message("邮费模板不能为空");
                }
            }
        }
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java
@@ -1,10 +1,7 @@
package cc.mrbird.febs.mall.service.impl;
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.common.enumerates.AgentLevelEnum;
import cc.mrbird.febs.common.enumerates.DataDictionaryEnum;
import cc.mrbird.febs.common.enumerates.FlowTypeEnum;
import cc.mrbird.febs.common.enumerates.MoneyFlowTypeEnum;
import cc.mrbird.febs.common.enumerates.*;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.common.properties.XcxProperties;
import cc.mrbird.febs.common.utils.*;
@@ -17,8 +14,12 @@
import cc.mrbird.febs.mall.vo.*;
import cc.mrbird.febs.pay.model.BrandWCPayRequestData;
import cc.mrbird.febs.pay.service.IXcxPayService;
import cc.mrbird.febs.vip.VipSettingUnAliveSettingBo;
import cc.mrbird.febs.vip.entity.MallVipConfig;
import cc.mrbird.febs.vip.mapper.MallVipConfigMapper;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
@@ -44,6 +45,7 @@
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
/**
 * @author wzy
@@ -76,6 +78,8 @@
    private final MallGoodsCouponMapper mallGoodsCouponMapper;
    private final MallMemberCouponMapper mallMemberCouponMapper;
    private final MallGoodsMapper mallGoodsMapper;
    private final MallVipConfigMapper mallVipConfigMapper;
    @Value("${spring.profiles.active}")
@@ -129,7 +133,6 @@
        mallMember.setName(registerDto.getName());
        mallMember.setAccountStatus(MallMember.ACCOUNT_STATUS_ENABLE);
        mallMember.setAccountType(MallMember.ACCOUNT_TYPE_NORMAL);
        mallMember.setLevel(AgentLevelEnum.ZERO_LEVEL.name());
        mallMember.setSex("男");
        mallMember.setBindPhone(registerDto.getAccount());
@@ -285,9 +288,13 @@
        mallMemberVo.setChildCnt(CollUtil.isNotEmpty(mallMembers) ? mallMembers.size() : 0);
        MallMemberWallet wallet = mallMemberWalletMapper.selectWalletByMemberId(mallMemberVo.getId());
        MallVipConfig mallVipConfig = mallVipConfigMapper.selectVipConfigByCode(mallMember.getLevel());
        mallMemberVo.setVipInfo(mallVipConfig);
        mallMemberVo.setBalance(wallet.getBalance());
//        mallMemberVo.setScore(wallet.getScore());
//        mallMemberVo.setPrizeScore(wallet.getPrizeScore());
        mallMemberVo.setPrizeScore(wallet.getPrizeScore());
//        mallMemberVo.setTotalCost(mallOrderInfoMapper.selectTotalAmount(id));
        return new FebsResponse().success().data(mallMemberVo);
    }
@@ -304,7 +311,7 @@
            }
        }
        List<MallShoppingCart> carts = mallShoppingCartMapper.selectCartGoodsList(id);
        List<MallShoppingCart> carts = mallShoppingCartMapper.selectCartGoodsList(id, 1);
        Map<String, Object> result = new HashMap<>();
        result.put("order", orderCnt);
        result.put("carts", carts.size());
@@ -377,6 +384,12 @@
        Long id = LoginUserUtil.getLoginUser().getId();
        moneyFlowDto.setMemberId(id);
        IPage<MoneyFlowVo> pages = mallMoneyFlowMapper.selectApiMoneyFlowInPage(page, moneyFlowDto);
        if (moneyFlowDto.getFlowType() == 3) {
            pages.getRecords().forEach(item -> {
                item.setDescription(ScoreFlowTypeEnum.getDescByValue(item.getType()));
            });
        }
        return new FebsResponse().success().data(pages);
    }
@@ -609,7 +622,6 @@
                    mallMember = new MallMember();
                    mallMember.setAccountStatus(MallMember.ACCOUNT_STATUS_ENABLE);
                    mallMember.setAccountType(MallMember.ACCOUNT_TYPE_NORMAL);
                    mallMember.setLevel(AgentLevelEnum.ZERO_LEVEL.name());
                    mallMember.setOpenId(openId);
                    mallMember.setSessionKey(sessionKey);
@@ -703,7 +715,22 @@
        if(StrUtil.isNotEmpty(avatarUrl)){
            mallMember.setAvatar(avatarUrl);
        }
//        mallMember.setSex(1 == apiXcxSaveInfoDto.getGender() ? "女" : "男");
        if (StrUtil.isNotBlank(apiXcxSaveInfoDto.getRealName())) {
            mallMember.setRealName(apiXcxSaveInfoDto.getRealName());
        }
        if (apiXcxSaveInfoDto.getBirthday() != null) {
            mallMember.setBirthday(apiXcxSaveInfoDto.getBirthday());
        }
        List<MallVipConfig> configs = mallVipConfigMapper.selectVipConfigList();
        if (StrUtil.isBlank(mallMember.getLevel()) && CollUtil.isNotEmpty(configs)) {
            MallVipConfig mallVipConfig = configs.get(0);
            mallMember.setLevel(mallVipConfig.getCode());
        }
        mallMember.setSex(1 == apiXcxSaveInfoDto.getGender() ? "女" : "男");
        this.baseMapper.updateById(mallMember);
        return new FebsResponse().success();
    }
@@ -723,7 +750,6 @@
                    mallMember.setPhone(phone);
                    mallMember.setAccountStatus(MallMember.ACCOUNT_STATUS_ENABLE);
                    mallMember.setAccountType(MallMember.ACCOUNT_TYPE_NORMAL);
                    mallMember.setLevel(AgentLevelEnum.ZERO_LEVEL.name());
                    this.baseMapper.insert(mallMember);
                    String inviteId = ShareCodeUtil.toSerialCode(mallMember.getId());
@@ -1052,4 +1078,79 @@
        String wechatLoginUrl =xcxProperties.getWecharLoginUrl();
        return String.format(wechatLoginUrl, xcxProperties.getXcxAppid(), xcxProperties.getXcxSecret(), code);
    }
    @Override
    public Map<String, Object>  loginEvent() {
        MallMember loginUser = LoginUserUtil.getLoginUser();
        MallMember member = this.baseMapper.selectById(loginUser.getId());
        MallMember mallMember = new MallMember();
        mallMember.setId(member.getId());
        mallMember.setLastLoginTime(new Date());
        this.baseMapper.updateById(mallMember);
        DataDictionaryCustom dic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.UNALIVE_COUPON.getType(), DataDictionaryEnum.UNALIVE_COUPON.getCode());
        if (dic == null || StrUtil.isBlank(dic.getValue())) {
            return new HashMap<>();
        }
        Date today = new Date();
        Date lastLoginTime = member.getLastLoginTime();
        if (lastLoginTime == null) {
            lastLoginTime = new Date();
        }
        long days = DateUtil.between(DateUtil.endOfDay(lastLoginTime), DateUtil.endOfDay(today), DateUnit.DAY);
        List<VipSettingUnAliveSettingBo> list = JSONObject.parseArray(dic.getValue(), VipSettingUnAliveSettingBo.class);
        List<Long> couponIds = list.stream().filter(item -> {
            return item.getDay() <= days && item.getCouponId() != null;
        }).map(VipSettingUnAliveSettingBo::getCouponId).collect(Collectors.toList());
        if (CollUtil.isEmpty(couponIds)) {
            return new HashMap<>();
        }
        LambdaQueryWrapper<MallGoodsCoupon> query = new LambdaQueryWrapper<>();
        query.in(MallGoodsCoupon::getId, couponIds)
                .eq(MallGoodsCoupon::getState, 2);
        List<MallGoodsCoupon> coupons = mallGoodsCouponMapper.selectList(query);
        LambdaQueryWrapper<MallMemberCoupon> memberCouponQuery = new LambdaQueryWrapper<>();
        memberCouponQuery.in(MallMemberCoupon::getCouponId, couponIds)
                        .eq(MallMemberCoupon::getMemberId, member.getId())
                        .eq(MallMemberCoupon::getFromType, 3)
                        .ge(MallMemberCoupon::getCreatedTime, DateUtil.beginOfDay(new Date()))
                        .le(MallMemberCoupon::getCreatedTime, DateUtil.endOfDay(new Date()));
        List<MallMemberCoupon> mallMemberCoupons = mallMemberCouponMapper.selectList(memberCouponQuery);
        if (CollUtil.isNotEmpty(mallMemberCoupons)) {
            Map<Long, MallMemberCoupon> map = mallMemberCoupons.stream().collect(Collectors.toMap(MallMemberCoupon::getCouponId, MallMemberCoupon -> MallMemberCoupon));
            coupons = coupons.stream().filter(item -> {
                return map.get(item.getId()) == null;
            }).collect(Collectors.toList());
        }
        if (CollUtil.isEmpty(coupons)) {
            return new HashMap<>();
        }
        coupons.forEach(item -> {
            MallMemberCoupon memberCoupon = new MallMemberCoupon();
            memberCoupon.setCouponId(item.getId());
            memberCoupon.setCouponName(item.getName());
            memberCoupon.setInviteId(member.getInviteId());
            memberCoupon.setCouponUuid(IdUtil.simpleUUID());
            memberCoupon.setState(1);
            memberCoupon.setFromType(3);
            memberCoupon.setExpireTime(DateUtil.offsetDay(DateUtil.date(), item.getExpireDay()));
            memberCoupon.setMemberId(member.getId());
            mallMemberCouponMapper.insert(memberCoupon);
        });
        Map<String, Object> result = new HashMap<>();
        result.put("coupon", coupons);
        return result;
    }
}
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallOrderInfoServiceImpl.java
@@ -23,6 +23,8 @@
import cc.mrbird.febs.pay.service.IXcxPayService;
import cc.mrbird.febs.pay.util.WeixinServiceUtil;
import cc.mrbird.febs.rabbit.producter.AgentProducer;
import cc.mrbird.febs.vip.service.IMallVipConfigBenefitsService;
import cc.mrbird.febs.vip.service.IMallVipConfigService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
@@ -32,6 +34,7 @@
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -86,6 +89,8 @@
    private final MallMemberCouponMapper mallMemberCouponMapper;
    private final MallGoodsCouponMapper mallGoodsCouponMapper;
    private final CouponGoodsMapper couponGoodsMapper;
    private final IMallVipConfigService mallVipConfigService;
    @Override
    @Transactional(rollbackFor = Exception.class)
@@ -145,6 +150,12 @@
                    orderItem.setSkuImage(mallGoods.getThumb());
                    orderItem.setState(1);
                    if (addOrderDto.getType() == 1) {
                        LambdaQueryWrapper<MallShoppingCart> delQuery = new LambdaQueryWrapper<>();
                        delQuery.eq(MallShoppingCart::getGoodsId, item.getSkuId())
                                .eq(MallShoppingCart::getMemberId, member.getId());
                        mallShoppingCartMapper.delete(delQuery);
                    }
                    total = total.add(amount);
                } else {
                    MallGoodsSku sku = mallGoodsSkuMapper.selectSkuInfoById(item.getSkuId());
@@ -314,7 +325,11 @@
        orderInfo.setCancelType(MallOrderInfo.CANCEL_BY_SELF);
        this.baseMapper.updateById(orderInfo);
        if (orderInfo.getOrderType() == 2) {
//            mallMoneyFlowService.addMoneyFlow(member.getId(), orderInfo.getAmount(), MoneyFlowTypeEnum.REFUND.getValue(), orderInfo.getOrderNo(),  FlowTypeEnum.PRIZE_SCORE.getValue());
//            memberWalletService.add(orderInfo.getAmount(), member.getId(), "prizeScore");
            return;
        }
        List<MallOrderItem> mallOrderItemList = mallOrderItemMapper.selectListByOrderId(orderInfo.getId());
        if(CollUtil.isNotEmpty(mallOrderItemList)){
@@ -451,7 +466,7 @@
                orderInfo.setPayTime(new Date());
                orderInfo.setPayResult("1");
                mallMoneyFlowService.addMoneyFlow(member.getId(), orderInfo.getAmount().negate(), MoneyFlowTypeEnum.PAY.getValue(), orderInfo.getOrderNo(),  FlowTypeEnum.PRIZE_SCORE.getValue());
                mallMoneyFlowService.addMoneyFlow(member.getId(), orderInfo.getAmount().negate(), ScoreFlowTypeEnum.PAY.getValue(), orderInfo.getOrderNo(),  FlowTypeEnum.PRIZE_SCORE.getValue(), null, 2);
                break;
            default:
@@ -567,6 +582,7 @@
        orderInfo.setReceivingTime(new Date());
        this.baseMapper.updateById(orderInfo);
        agentProducer.sendGetScoreMsg(orderInfo.getId());
        //生成一条团长提成记录
//        Long orderInfoId = orderInfo.getId();
//        List<MallOrderItem> mallOrderItemList = mallOrderItemMapper.selectListByOrderId(orderInfoId);
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallShoppingCartServiceImpl.java
@@ -1,15 +1,19 @@
package cc.mrbird.febs.mall.service.impl;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.common.exception.GeneratorException;
import cc.mrbird.febs.common.utils.LoginUserUtil;
import cc.mrbird.febs.mall.conversion.MallShoppingCartConversion;
import cc.mrbird.febs.mall.dto.AddCartDto;
import cc.mrbird.febs.mall.entity.MallGoods;
import cc.mrbird.febs.mall.entity.MallGoodsSku;
import cc.mrbird.febs.mall.entity.MallShoppingCart;
import cc.mrbird.febs.mall.mapper.MallGoodsMapper;
import cc.mrbird.febs.mall.mapper.MallGoodsSkuMapper;
import cc.mrbird.febs.mall.mapper.MallShoppingCartMapper;
import cc.mrbird.febs.mall.service.IApiMallShoppingCartService;
import cc.mrbird.febs.mall.vo.ShoppingCartGoodsVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -28,11 +32,15 @@
public class ApiMallShoppingCartServiceImpl extends ServiceImpl<MallShoppingCartMapper, MallShoppingCart> implements IApiMallShoppingCartService {
    private final MallGoodsSkuMapper mallGoodsSkuMapper;
    private final MallGoodsMapper mallGoodsMapper;
    @Override
    public List<ShoppingCartGoodsVo> findCartGoodsList() {
    public List<ShoppingCartGoodsVo> findCartGoodsList(Integer type) {
        if (type == null) {
            type = 1;
        }
        Long memberId = LoginUserUtil.getLoginUser().getId();
        List<MallShoppingCart> carts = this.baseMapper.selectCartGoodsList(memberId);
        List<MallShoppingCart> carts = this.baseMapper.selectCartGoodsList(memberId, type);
        return MallShoppingCartConversion.INSTANCE.entityListToVoList(carts);
    }
@@ -40,22 +48,47 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addGoodsToCart(List<AddCartDto> addCartDtoList) {
        Long memberId = LoginUserUtil.getLoginUser().getId();
        for (AddCartDto addCartDto : addCartDtoList) {
            MallGoodsSku sku = mallGoodsSkuMapper.selectById(addCartDto.getSkuId());
            Long goodsId = null;
            Long skuId = null;
            Long styleId = null;
            MallShoppingCart cartGoods = null;
            if (addCartDto.getType() == 1) {
                MallGoodsSku sku = mallGoodsSkuMapper.selectById(addCartDto.getSkuId());
            if (sku == null) {
                throw new FebsException("sku不存在");
                if (sku == null) {
                    throw new FebsException("sku不存在");
                }
                goodsId = sku.getGoodsId();
                skuId = sku.getId();
                styleId = sku.getStyleId();
                cartGoods = this.baseMapper.selectCartGoodsBySkuId(addCartDto.getSkuId(), memberId);
            } else {
                MallGoods mallGoods = mallGoodsMapper.selectById(addCartDto.getSkuId());
                if (mallGoods == null) {
                    throw new FebsException("积分商品不存在");
                }
                goodsId = mallGoods.getId();
                LambdaQueryWrapper<MallShoppingCart> cartQuery = new LambdaQueryWrapper<>();
                cartQuery.eq(MallShoppingCart::getGoodsId, goodsId)
                        .eq(MallShoppingCart::getMemberId, memberId)
                        .last("limit 1");
                cartGoods = this.baseMapper.selectOne(cartQuery);
            }
            Long memberId = LoginUserUtil.getLoginUser().getId();
            MallShoppingCart cartGoods = this.baseMapper.selectCartGoodsBySkuId(sku.getId(), memberId);
            if (cartGoods == null) {
                cartGoods = new MallShoppingCart();
                cartGoods.setGoodsId(sku.getGoodsId());
                cartGoods.setSkuId(sku.getId());
                cartGoods.setStyleId(sku.getStyleId());
                cartGoods.setGoodsId(goodsId);
                cartGoods.setSkuId(skuId);
                cartGoods.setStyleId(styleId);
                cartGoods.setCnt(addCartDto.getCnt());
                cartGoods.setMemberId(memberId);
                cartGoods.setType(addCartDto.getType());
                this.baseMapper.insert(cartGoods);
            } else {
src/main/java/cc/mrbird/febs/mall/service/impl/CommonService.java
@@ -57,9 +57,19 @@
    @Override
    public void addDataDic(String type, String code, Object value, String description) {
        DataDictionaryCustom dic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(type, code);
        addDataDic(type, code, value, description, true);
    }
        String data = JSONObject.toJSONString(value);
    @Override
    public void addDataDic(String type, String code, Object value, String description, boolean isJson) {
        DataDictionaryCustom dic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(type, code);
        String data = null;
        if (isJson) {
            data = JSONObject.toJSONString(value);
        } else {
            data = (String) value;
        }
        if (dic != null) {
            dic.setValue(data);
            dataDictionaryCustomMapper.updateById(dic);
src/main/java/cc/mrbird/febs/mall/vo/MallGoodsDetailsVo.java
@@ -18,6 +18,9 @@
    @ApiModelProperty(value = "id")
    private Long id;
    @ApiModelProperty(value = "商品主图")
    private String thumb;
    @ApiModelProperty(value = "商品编号")
    private String goodsNo;
src/main/java/cc/mrbird/febs/mall/vo/MallMemberVo.java
@@ -1,5 +1,6 @@
package cc.mrbird.febs.mall.vo;
import cc.mrbird.febs.vip.entity.MallVipConfig;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -95,4 +96,7 @@
    @ApiModelProperty(value = "是否是推销员")
    private Integer isSale;
    @ApiModelProperty(value = "会员信息")
    private MallVipConfig vipInfo;
}
src/main/java/cc/mrbird/febs/mall/vo/MoneyFlowVo.java
@@ -37,4 +37,11 @@
    @ApiModelProperty(value = "时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createdTime;
    @ApiModelProperty(value = "描述")
    private String description;
    @ApiModelProperty(value = "备注")
    private String remark;
}
src/main/java/cc/mrbird/febs/mall/vo/OrderDetailVo.java
@@ -124,5 +124,8 @@
    private Integer deliveryState;
    @ApiModelProperty(value = "是否送货上门  1:是 2:否")
    private Integer isHome;
    @ApiModelProperty(value = "是否赠送 1-是 2-否")
    private Integer isFree;
}
src/main/java/cc/mrbird/febs/mall/vo/OrderListVo.java
@@ -57,4 +57,10 @@
    @ApiModelProperty(value = "是否送货上门  1:是 2:否")
    private Integer isHome;
    @ApiModelProperty(value = "快递单号")
    private String expressNo;
    @ApiModelProperty(value = "是否赠送 1-是 2-否")
    private Integer isFree;
}
src/main/java/cc/mrbird/febs/pay/controller/XcxPayController.java
@@ -327,6 +327,7 @@
                            mallOrderInfoMapper.updateById(order);
                            agentProducer.sendOrderCoupon(order.getId());
//                            agentProducer.sendGetScoreMsg(order.getId());
                            mallMoneyFlowService.addMoneyFlow(
                                    order.getMemberId(),
src/main/java/cc/mrbird/febs/rabbit/constants/QueueConstants.java
@@ -12,4 +12,7 @@
    public static final String ORDER_RETURN_MONEY = "queue_order_return_money_qay";
    public static final String ORDER_COUPON = "queue_order_coupon";
    public static final String GET_SCORE_MSG = "queue_get_score_msg";
    public static final String VIP_LEVEL_UP = "queue_vip_level_up";
}
src/main/java/cc/mrbird/febs/rabbit/consumer/AgentConsumer.java
@@ -5,6 +5,7 @@
import cc.mrbird.febs.mall.service.IMemberProfitService;
import cc.mrbird.febs.rabbit.constants.QueueConstants;
import cc.mrbird.febs.rabbit.enumerates.RabbitQueueEnum;
import cc.mrbird.febs.vip.service.IVipCommonService;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
@@ -82,4 +83,27 @@
            log.error("使用优惠卷异常:", e);
        }
    }
    @Autowired
    private IVipCommonService vipCommonService;
    @RabbitListener(queues = QueueConstants.GET_SCORE_MSG)
    public void getScoreMsg(Long orderId) {
        log.info("收到积分消息:{}", orderId);
        try {
            vipCommonService.getScore(orderId);
        } catch (Exception e) {
            log.error("获取积分消息异常", e);
        }
    }
    @RabbitListener(queues = QueueConstants.VIP_LEVEL_UP)
    public void vipLevelUp(Long orderId) {
        log.info("收到会员升级消息:{}", orderId);
        try {
            vipCommonService.levelUp(orderId);
        } catch (Exception e) {
            log.error("会员升级消息异常", e);
        }
    }
}
src/main/java/cc/mrbird/febs/rabbit/enumerates/RabbitQueueEnum.java
@@ -15,7 +15,11 @@
    ORDER_RETURN_MONEY("exchange_order_return_money_qay", "route_key_order_return_money_qay", "queue_order_return_money_qay"),
    ORDER_COUPON("exchange_order_coupon", "route_key_order_coupon", QueueConstants.ORDER_COUPON);
    ORDER_COUPON("exchange_order_coupon", "route_key_order_coupon", QueueConstants.ORDER_COUPON),
    GET_SCORE_MSG("exchange_get_score_msg", "route_key_get_score_msg", QueueConstants.GET_SCORE_MSG),
    VIP_LEVEL_UP("exchange_vip_level_up", "route_key_vip_level_up", QueueConstants.VIP_LEVEL_UP);
    private String exchange;
src/main/java/cc/mrbird/febs/rabbit/producter/AgentProducer.java
@@ -83,4 +83,18 @@
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend(RabbitQueueEnum.ORDER_COUPON.getExchange(), RabbitQueueEnum.ORDER_COUPON.getRoute(), id, correlationData);
    }
    public void sendGetScoreMsg(Long orderId) {
        log.info("发送获得积分消息:{}", orderId);
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend(RabbitQueueEnum.GET_SCORE_MSG.getExchange(), RabbitQueueEnum.GET_SCORE_MSG.getRoute(), orderId, correlationData);
    }
    public void sendVipLevelUp(Long orderId) {
        log.info("发送会员升级消息:{}", orderId);
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend(RabbitQueueEnum.VIP_LEVEL_UP.getExchange(), RabbitQueueEnum.VIP_LEVEL_UP.getRoute(), orderId, correlationData);
    }
}
src/main/java/cc/mrbird/febs/vip/VipSettingUnAliveSettingBo.java
New file
@@ -0,0 +1,13 @@
package cc.mrbird.febs.vip;
import lombok.Data;
@Data
public class VipSettingUnAliveSettingBo {
    private int day;
    private Long couponId;
    private String couponName;
}
src/main/java/cc/mrbird/febs/vip/controller/AdminMallVipBenefitsController.java
New file
@@ -0,0 +1,59 @@
package cc.mrbird.febs.vip.controller;
import cc.mrbird.febs.common.controller.BaseController;
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.vip.entity.MallVipBenefits;
import cc.mrbird.febs.vip.service.IMallVipBenefitsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
 * 会员权益接口类
 */
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/admin/vip/benefits")
public class AdminMallVipBenefitsController extends BaseController {
    private final IMallVipBenefitsService mallVipBenefitsService;
    @GetMapping("/list")
    public FebsResponse list(QueryRequest request) {
        Map<String, Object> data = getDataTable(mallVipBenefitsService.vipBenefitsListInPage(request));
        return new FebsResponse().success().data(data);
    }
    @GetMapping("/getById/{id}")
    public FebsResponse getById(@PathVariable("id") Long id) {
        return new FebsResponse().success().data(mallVipBenefitsService.findVipBenefitsById(id));
    }
    @PostMapping("/addOrEditBenefits")
    public FebsResponse addOrEditBenefits(@RequestBody MallVipBenefits mallVipBenefits) {
        if (mallVipBenefits.getId() == null) {
            this.mallVipBenefitsService.addVipBenefits(mallVipBenefits);
        } else {
            this.mallVipBenefitsService.editVipBenefits(mallVipBenefits);
        }
        return new FebsResponse().success();
    }
    @GetMapping("/delBenefits/{id}")
    public FebsResponse delBenefits(@PathVariable("id") Long id) {
        this.mallVipBenefitsService.delVipBenefits(id);
        return new FebsResponse().success();
    }
    @GetMapping("/findAllBenefits")
    public FebsResponse findAllBenefits() {
        return new FebsResponse().success().data(mallVipBenefitsService.list());
    }
}
src/main/java/cc/mrbird/febs/vip/controller/AdminMallVipConfigController.java
New file
@@ -0,0 +1,73 @@
package cc.mrbird.febs.vip.controller;
import cc.mrbird.febs.common.controller.BaseController;
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.common.enumerates.DataDictionaryEnum;
import cc.mrbird.febs.mall.service.impl.CommonService;
import cc.mrbird.febs.vip.entity.MallVipConfig;
import cc.mrbird.febs.vip.service.IMallVipConfigService;
import cc.mrbird.febs.vip.vo.VipSettingVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
 * 会员配置接口类
 */
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/admin/vip/config")
public class AdminMallVipConfigController extends BaseController {
    private final IMallVipConfigService mallVipConfigService;
    private final CommonService commonService;
    @GetMapping(value = "/list")
    public FebsResponse list(QueryRequest request) {
        return new FebsResponse().success().data(getDataTable(mallVipConfigService.vipConfigList(request)));
    }
    @PostMapping(value = "/addOrEdit")
    public FebsResponse addOrEdit(@RequestBody MallVipConfig config) {
        if (config.getType() == 1) {
            config.setTimes(null);
            config.setAmount(null);
        } else {
            config.setTargetId(null);
        }
        if (config.getId() == null) {
            mallVipConfigService.addVipConfig(config);
        } else {
            mallVipConfigService.editVipConfig(config);
        }
        return new FebsResponse().success().message("操作成功");
    }
    @GetMapping(value = "/del/{id}")
    public FebsResponse del(@PathVariable("id") Long id) {
        mallVipConfigService.delVipConfig(id);
        return new FebsResponse().success().message("操作成功");
    }
    @PostMapping(value = "/vipSetting")
    public FebsResponse vipSetting(@RequestBody VipSettingVo vipSettingVo) {
        commonService.addDataDic(DataDictionaryEnum.VIP_DATE.getType(), DataDictionaryEnum.VIP_DATE.getCode(), vipSettingVo.getVipDate(), null, false);
        commonService.addDataDic(DataDictionaryEnum.UNALIVE_COUPON.getType(), DataDictionaryEnum.UNALIVE_COUPON.getCode(), vipSettingVo.getItems(), "失活会员优惠券配置", true);
        return new FebsResponse().success();
    }
    @GetMapping(value = "/allList")
    public FebsResponse allList() {
        return new FebsResponse().success().data(mallVipConfigService.list());
    }
}
src/main/java/cc/mrbird/febs/vip/controller/ApiMallVipBenefitsController.java
New file
@@ -0,0 +1,16 @@
package cc.mrbird.febs.vip.controller;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/api/vip/benefits")
public class ApiMallVipBenefitsController {
}
src/main/java/cc/mrbird/febs/vip/controller/ApiMallVipConfigController.java
New file
@@ -0,0 +1,57 @@
package cc.mrbird.febs.vip.controller;
import cc.mrbird.febs.common.controller.BaseController;
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.vip.entity.MallVipBenefits;
import cc.mrbird.febs.vip.entity.MallVipConfig;
import cc.mrbird.febs.vip.service.IMallVipBenefitsService;
import cc.mrbird.febs.vip.service.IMallVipConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/api/vip/config")
@Api(value = "ApiMallVipConfigController", tags = "会员等级接口类")
public class ApiMallVipConfigController extends BaseController {
    private final IMallVipConfigService mallVipConfigService;
    private final IMallVipBenefitsService mallVipBenefitsService;
    @ApiOperation(value = "获取会员等级列表")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = MallVipConfig.class)
    })
    @GetMapping(value = "/findVipList")
    public FebsResponse findVipList() {
        return new FebsResponse().success().data(mallVipConfigService.findConfigList());
    }
    @ApiOperation(value = "获取权益详情")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = MallVipBenefits.class)
    })
    @GetMapping(value = "/findBenefitsDetailList/{id}")
    public FebsResponse findVipDetailList(@PathVariable("id") Long id) {
        MallVipBenefits vipBenefits = mallVipBenefitsService.findVipBenefitsById(id);
        return new FebsResponse().success().data(vipBenefits);
    }
    @ApiOperation(value = "领取权益")
    @PostMapping(value = "/getBenefitsData/{id}")
    public FebsResponse getBenefitsData(@PathVariable("id") Long id) {
        mallVipBenefitsService.getBenefits(id);
        return new FebsResponse().success().message("领取成功");
    }
}
src/main/java/cc/mrbird/febs/vip/controller/ViewVipConfigController.java
New file
@@ -0,0 +1,172 @@
package cc.mrbird.febs.vip.controller;
import cc.mrbird.febs.common.entity.FebsConstant;
import cc.mrbird.febs.common.enumerates.DataDictionaryEnum;
import cc.mrbird.febs.common.utils.FebsUtil;
import cc.mrbird.febs.mall.entity.DataDictionaryCustom;
import cc.mrbird.febs.mall.entity.MallGoods;
import cc.mrbird.febs.mall.entity.MallGoodsCoupon;
import cc.mrbird.febs.mall.mapper.DataDictionaryCustomMapper;
import cc.mrbird.febs.mall.mapper.MallGoodsCouponMapper;
import cc.mrbird.febs.mall.service.IApiMallGoodsService;
import cc.mrbird.febs.vip.VipSettingUnAliveSettingBo;
import cc.mrbird.febs.vip.entity.MallVipBenefits;
import cc.mrbird.febs.vip.entity.MallVipConfig;
import cc.mrbird.febs.vip.entity.MallVipConfigBenefits;
import cc.mrbird.febs.vip.service.IMallVipBenefitsService;
import cc.mrbird.febs.vip.service.IMallVipConfigBenefitsService;
import cc.mrbird.febs.vip.service.IMallVipConfigService;
import cc.mrbird.febs.vip.vo.VipSettingVo;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Controller("mallVipConfig")
@RequestMapping(FebsConstant.VIEW_PREFIX + "modules/vip/config")
@RequiredArgsConstructor
public class ViewVipConfigController {
    private final IMallVipBenefitsService mallVipBenefitsService;
    private final IApiMallGoodsService apiMallGoodsService;
    private final MallGoodsCouponMapper mallGoodsCouponMapper;
    private final IMallVipConfigService mallVipConfigService;
    private final IMallVipConfigBenefitsService mallVipConfigBenefitsService;
    private final DataDictionaryCustomMapper dataDictionaryCustomMapper;
    @GetMapping(value = "/benefitsList")
    public String benefitsList() {
        return FebsUtil.view("modules/vip/vipBenefits-list");
    }
    @GetMapping(value = "/vipBenefitsAdd")
    public String vipBenefitsAdd() {
        return FebsUtil.view("modules/vip/vipBenefits-add");
    }
    @GetMapping(value = "/goodsSelect/{index}")
    public String goodsSelect(@PathVariable("index") String index, Model model) {
        model.addAttribute("tableIndex", index);
        return FebsUtil.view("modules/vip/goods-select-list");
    }
    @GetMapping(value = "/couponSelect/{index}")
    public String couponSelect(@PathVariable("index") String index, Model model) {
        model.addAttribute("tableIndex", index);
        return FebsUtil.view("modules/vip/coupon-select");
    }
    @GetMapping("/editBenefits/{id}")
    public String editBenefits(@PathVariable("id") Long id, Model model) {
        MallVipBenefits vipBenefits = mallVipBenefitsService.findVipBenefitsById(id);
        List<Long> goodsIds = new ArrayList<>();
        List<Long> couponIds = new ArrayList<>();
        vipBenefits.getDetails().forEach(item -> {
            if (item.getIsClick() == 2) {
                return;
            }
            if (item.getLinkType() == 2) {
                goodsIds.add(Long.parseLong(item.getContent()));
            }
            if (item.getLinkType() == 3) {
                couponIds.add(Long.parseLong(item.getContent()));
            }
        });
        List<MallGoods> goodsList = new ArrayList<>();
        if (CollUtil.isNotEmpty(goodsIds)) {
            goodsList = apiMallGoodsService.listByIds(goodsIds);
        }
        List<MallGoodsCoupon> coupons = new ArrayList<>();
        if (CollUtil.isNotEmpty(couponIds)) {
            coupons = mallGoodsCouponMapper.selectBatchIds(couponIds);
        }
        Map<Long, MallGoods> goodsMap = goodsList.stream().collect(Collectors.toMap(MallGoods::getId, MallGoods -> MallGoods));
        Map<Long, MallGoodsCoupon> couponMap = coupons.stream().collect(Collectors.toMap(MallGoodsCoupon::getId, MallGoodsCoupon -> MallGoodsCoupon));
        vipBenefits.getDetails().forEach(item -> {
            if (item.getIsClick() == 2) {
                return;
            }
            if (item.getLinkType() == 2) {
                MallGoods mallGoods = goodsMap.get(Long.parseLong(item.getContent()));
                if (mallGoods != null) {
                    item.setContentName(mallGoods.getGoodsName());
                }
            }
            if (item.getLinkType() == 3) {
                MallGoodsCoupon coupon = couponMap.get(Long.parseLong(item.getContent()));
                if (coupon != null) {
                    item.setContentName(coupon.getName());
                }
            }
        });
        model.addAttribute("benefitsData", vipBenefits);
        return FebsUtil.view("modules/vip/vipBenefits-edit");
    }
    @GetMapping(value = "/levelList")
    public String levelList() {
        return FebsUtil.view("modules/vip/vipConfig-list");
    }
    @GetMapping(value = "/levelAdd")
    public String levelAdd() {
        return FebsUtil.view("modules/vip/vipConfig-add");
    }
    @GetMapping(value = "/levelEdit/{id}")
    public String levelEdit(@PathVariable("id") Long id, Model model) {
        MallVipConfig vipConfig = mallVipConfigService.getById(id);
        if (vipConfig.getType() == 1) {
            MallGoods goods = apiMallGoodsService.getById(vipConfig.getTargetId());
            vipConfig.setTargetId(goods.getId());
            vipConfig.setTargetName(goods.getGoodsName());
        }
        LambdaQueryWrapper<MallVipConfigBenefits> configBenefitsQuery = new LambdaQueryWrapper<>();
        configBenefitsQuery.eq(MallVipConfigBenefits::getConfigId, vipConfig.getId());
        List<MallVipConfigBenefits> list = mallVipConfigBenefitsService.list(configBenefitsQuery);
        List<Long> benefitsIds = list.stream().map(MallVipConfigBenefits::getBenefitsId).collect(Collectors.toList());
        vipConfig.setBenefitsIdList(benefitsIds);
        model.addAttribute("configData", vipConfig);
        return FebsUtil.view("modules/vip/vipConfig-edit");
    }
    @GetMapping(value = "/vipSetting")
    public String vipSetting(Model model) {
        DataDictionaryCustom data = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.VIP_DATE.getType(), DataDictionaryEnum.VIP_DATE.getCode());
        VipSettingVo setting = new VipSettingVo();
        setting.setVipDate(data.getValue());
        DataDictionaryCustom couponData = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.UNALIVE_COUPON.getType(), DataDictionaryEnum.UNALIVE_COUPON.getCode());
        if (couponData != null && StrUtil.isNotBlank(couponData.getValue())) {
            List<VipSettingUnAliveSettingBo> items = JSONObject.parseArray(couponData.getValue(), VipSettingUnAliveSettingBo.class);
            setting.setItems(items);
        }
        model.addAttribute("vipSetting", setting);
        return FebsUtil.view("modules/vip/vip-setting");
    }
}
src/main/java/cc/mrbird/febs/vip/entity/MallVipBenefits.java
New file
@@ -0,0 +1,55 @@
package cc.mrbird.febs.vip.entity;
import cc.mrbird.febs.common.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
@TableName("mall_vip_benefits")
@ApiModel(value = "MallVipBenefits")
public class MallVipBenefits extends BaseEntity {
    /**
     * 权益名称
     */
    @ApiModelProperty(value = "权益名称")
    private String name;
    /**
     * 权益类型;1-积分 2-指定商品 3-暂无
     */
    private Integer type;
    /**
     * 权益图标
     */
    @ApiModelProperty(value = "权益图标")
    private String icon;
    /**
     * 积分倍数
     */
    private BigDecimal scoreMultiple;
    /**
     * 获取途径 1-会员日 2-生日
     */
    private Integer gainType;
    /**
     * 权益备注
     */
    private String remark;
    @TableField(exist = false)
    private Integer isJump;
    @TableField(exist = false)
    private List<MallVipBenefitsDetails> details;
}
src/main/java/cc/mrbird/febs/vip/entity/MallVipBenefitsDetails.java
New file
@@ -0,0 +1,51 @@
package cc.mrbird.febs.vip.entity;
import cc.mrbird.febs.common.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@TableName("mall_vip_benefits_details")
@ApiModel(value = "MallVipBenefitsDetails")
public class MallVipBenefitsDetails extends BaseEntity {
    /**
     * 图片链接
     */
    @ApiModelProperty(value = "图片")
    private String image;
    /**
     * 是否可点击;1-是 2-否
     */
    @ApiModelProperty(value = "是否可点击")
    private Integer isClick;
    /**
     * 链接类型;1-链接 2-领取商品 3-优惠券
     */
    @ApiModelProperty(value = "1-链接 2-领取商品 3-优惠券")
    private Integer linkType;
    /**
     * 内容;根据linkType来的
     */
    @ApiModelProperty(value = "跳转的链接或者商品/优惠券的ID")
    private String content;
    /**
     * 排序
     */
    private String seq;
    /**
     * 权益ID
     */
    private Long benefitsId;
    @TableField(exist = false)
    private String contentName;
}
src/main/java/cc/mrbird/febs/vip/entity/MallVipBenefitsRecord.java
New file
@@ -0,0 +1,28 @@
package cc.mrbird.febs.vip.entity;
import cc.mrbird.febs.common.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
@Data
@TableName(value = "mall_vip_benefits_record")
public class MallVipBenefitsRecord extends BaseEntity {
    private Long memberId ;
    /** 权益名称 */
    private String benefitsName ;
    /** 权益类型; 1-会员日 2-生日 */
    private Integer benefitsType ;
    /** 领取名称 */
    private String receiveName ;
    /** 领取数量 */
    private Integer receiveCnt ;
    /** 领取时间 */
    private Date receiveTime ;
    /** 领取类型;2-商品 3-优惠券 */
    private Integer receiveType ;
    /** 领取ID */
    private Long receiveId ;
}
src/main/java/cc/mrbird/febs/vip/entity/MallVipConfig.java
New file
@@ -0,0 +1,83 @@
package cc.mrbird.febs.vip.entity;
import cc.mrbird.febs.common.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
@ApiModel(value = "MallVipConfig")
@TableName("mall_vip_config")
public class MallVipConfig extends BaseEntity {
    /**
     * 会员名称
     */
    @ApiModelProperty(value = "名称")
    private String name;
    /**
     * 主图
     */
    @ApiModelProperty(value = "主图")
    private String thumb;
    /**
     * 会员编码
     */
    private String code;
    /**
     * 等级
     */
    @ApiModelProperty(value = "会员等级")
    private Integer level;
    /**
     * 有效期
     */
    private Integer validTime;
    /**
     * 有效期类型;day/month/year
     */
    private String validType;
    /**
     * 成为会员条件类型;1-指定商品 2-时间区间内消费金额
     */
    private Integer type;
    /**
     * 消费金额
     */
    private BigDecimal amount;
    /**
     * 指定月数
     */
    private Integer times;
    /**
     * 指定商品ID
     */
    private Long targetId;
    @TableField(exist = false)
    private String targetName;
    @TableField(exist = false)
    private List<MallVipBenefits> benefits;
    @TableField(exist = false)
    private String benefitsIds;
    @TableField(exist = false)
    private List<Long> benefitsIdList;
}
src/main/java/cc/mrbird/febs/vip/entity/MallVipConfigBenefits.java
New file
@@ -0,0 +1,20 @@
package cc.mrbird.febs.vip.entity;
import cc.mrbird.febs.common.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("mall_vip_config_benefits")
public class MallVipConfigBenefits extends BaseEntity {
    /**
     * 会员配置ID
     */
    private Long configId;
    /**
     * 会员权益ID
     */
    private Long benefitsId;
}
src/main/java/cc/mrbird/febs/vip/mapper/MallVipBenefitsDetailsMapper.java
New file
@@ -0,0 +1,7 @@
package cc.mrbird.febs.vip.mapper;
import cc.mrbird.febs.vip.entity.MallVipBenefitsDetails;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface MallVipBenefitsDetailsMapper extends BaseMapper<MallVipBenefitsDetails> {
}
src/main/java/cc/mrbird/febs/vip/mapper/MallVipBenefitsMapper.java
New file
@@ -0,0 +1,18 @@
package cc.mrbird.febs.vip.mapper;
import cc.mrbird.febs.vip.entity.MallVipBenefits;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface MallVipBenefitsMapper extends BaseMapper<MallVipBenefits> {
    IPage<MallVipBenefits> selectVipBenefitsListInPage(Page<MallVipBenefits> page);
    MallVipBenefits selectVipBenefitsById(@Param("id") Long id);
    List<MallVipBenefits> selectVipBenefitsByIds(@Param("list") List<Long> ids);
}
src/main/java/cc/mrbird/febs/vip/mapper/MallVipBenefitsRecordMapper.java
New file
@@ -0,0 +1,7 @@
package cc.mrbird.febs.vip.mapper;
import cc.mrbird.febs.vip.entity.MallVipBenefitsRecord;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface MallVipBenefitsRecordMapper extends BaseMapper<MallVipBenefitsRecord> {
}
src/main/java/cc/mrbird/febs/vip/mapper/MallVipConfigBenefitsMapper.java
New file
@@ -0,0 +1,7 @@
package cc.mrbird.febs.vip.mapper;
import cc.mrbird.febs.vip.entity.MallVipConfigBenefits;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface MallVipConfigBenefitsMapper extends BaseMapper<MallVipConfigBenefits> {
}
src/main/java/cc/mrbird/febs/vip/mapper/MallVipConfigMapper.java
New file
@@ -0,0 +1,17 @@
package cc.mrbird.febs.vip.mapper;
import cc.mrbird.febs.vip.entity.MallVipConfig;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface MallVipConfigMapper extends BaseMapper<MallVipConfig> {
    IPage<MallVipConfig> findVipConfigListInPage(IPage<MallVipConfig> page);
    List<MallVipConfig> selectVipConfigList();
    MallVipConfig selectVipConfigByCode(@Param("code") String code);
}
src/main/java/cc/mrbird/febs/vip/service/IMallVipBenefitsDetailsService.java
New file
@@ -0,0 +1,7 @@
package cc.mrbird.febs.vip.service;
import cc.mrbird.febs.vip.entity.MallVipBenefitsDetails;
import com.baomidou.mybatisplus.extension.service.IService;
public interface IMallVipBenefitsDetailsService extends IService<MallVipBenefitsDetails> {
}
src/main/java/cc/mrbird/febs/vip/service/IMallVipBenefitsService.java
New file
@@ -0,0 +1,21 @@
package cc.mrbird.febs.vip.service;
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.vip.entity.MallVipBenefits;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
public interface IMallVipBenefitsService extends IService<MallVipBenefits> {
    IPage<MallVipBenefits> vipBenefitsListInPage(QueryRequest request);
    MallVipBenefits findVipBenefitsById(Long id);
    void addVipBenefits(MallVipBenefits mallVipBenefits);
    void delVipBenefits(Long id);
    void editVipBenefits(MallVipBenefits mallVipBenefits);
    void getBenefits(Long id);
}
src/main/java/cc/mrbird/febs/vip/service/IMallVipConfigBenefitsService.java
New file
@@ -0,0 +1,7 @@
package cc.mrbird.febs.vip.service;
import cc.mrbird.febs.vip.entity.MallVipConfigBenefits;
import com.baomidou.mybatisplus.extension.service.IService;
public interface IMallVipConfigBenefitsService extends IService<MallVipConfigBenefits> {
}
src/main/java/cc/mrbird/febs/vip/service/IMallVipConfigService.java
New file
@@ -0,0 +1,25 @@
package cc.mrbird.febs.vip.service;
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.vip.entity.MallVipBenefits;
import cc.mrbird.febs.vip.entity.MallVipBenefitsDetails;
import cc.mrbird.febs.vip.entity.MallVipConfig;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
public interface IMallVipConfigService extends IService<MallVipConfig> {
    IPage<MallVipConfig> vipConfigList(QueryRequest request);
    List<MallVipConfig> findConfigList();
    void addVipConfig(MallVipConfig config);
    void editVipConfig(MallVipConfig config);
    void delVipConfig(Long id);
    MallVipBenefits hasVipBenefits(Long memberId);
}
src/main/java/cc/mrbird/febs/vip/service/IVipCommonService.java
New file
@@ -0,0 +1,8 @@
package cc.mrbird.febs.vip.service;
public interface IVipCommonService {
    void getScore(Long orderId);
    void levelUp(Long orderId);
}
src/main/java/cc/mrbird/febs/vip/service/impl/MallVipBenefitsDetailsServiceImpl.java
New file
@@ -0,0 +1,15 @@
package cc.mrbird.febs.vip.service.impl;
import cc.mrbird.febs.vip.entity.MallVipBenefitsDetails;
import cc.mrbird.febs.vip.mapper.MallVipBenefitsDetailsMapper;
import cc.mrbird.febs.vip.service.IMallVipBenefitsDetailsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class MallVipBenefitsDetailsServiceImpl extends ServiceImpl<MallVipBenefitsDetailsMapper, MallVipBenefitsDetails> implements IMallVipBenefitsDetailsService {
}
src/main/java/cc/mrbird/febs/vip/service/impl/MallVipBenefitsServiceImpl.java
New file
@@ -0,0 +1,283 @@
package cc.mrbird.febs.vip.service.impl;
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.common.enumerates.DataDictionaryEnum;
import cc.mrbird.febs.common.enumerates.OrderStatusEnum;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.common.utils.LoginUserUtil;
import cc.mrbird.febs.common.utils.MallUtils;
import cc.mrbird.febs.mall.entity.*;
import cc.mrbird.febs.mall.mapper.*;
import cc.mrbird.febs.mall.vo.AdminMailGoodsDetailVo;
import cc.mrbird.febs.mall.vo.AdminMallNewsInfoVo;
import cc.mrbird.febs.vip.entity.MallVipBenefits;
import cc.mrbird.febs.vip.entity.MallVipBenefitsDetails;
import cc.mrbird.febs.vip.entity.MallVipBenefitsRecord;
import cc.mrbird.febs.vip.entity.MallVipConfig;
import cc.mrbird.febs.vip.mapper.MallVipBenefitsDetailsMapper;
import cc.mrbird.febs.vip.mapper.MallVipBenefitsMapper;
import cc.mrbird.febs.vip.mapper.MallVipBenefitsRecordMapper;
import cc.mrbird.febs.vip.mapper.MallVipConfigMapper;
import cc.mrbird.febs.vip.service.IMallVipBenefitsDetailsService;
import cc.mrbird.febs.vip.service.IMallVipBenefitsService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@Slf4j
@Service
@RequiredArgsConstructor
public class MallVipBenefitsServiceImpl extends ServiceImpl<MallVipBenefitsMapper, MallVipBenefits> implements IMallVipBenefitsService {
    private final IMallVipBenefitsDetailsService mallVipBenefitsDetailsService;
    private final MallMemberCouponMapper mallMemberCouponMapper;
    private final MallGoodsCouponMapper mallGoodsCouponMapper;
    private final MallGoodsMapper mallGoodsMapper;
    private final MallAddressInfoMapper mallAddressInfoMapper;
    private final MallOrderInfoMapper mallOrderInfoMapper;
    private final MallOrderItemMapper mallOrderItemMapper;
    private final MallVipBenefitsRecordMapper mallVipBenefitsRecordMapper;
    private final DataDictionaryCustomMapper dataDictionaryCustomMapper;
    private final MallMemberMapper mallMemberMapper;
    private final MallVipConfigMapper mallVipConfigMapper;
    @Override
    public IPage<MallVipBenefits> vipBenefitsListInPage(QueryRequest request) {
        Page<MallVipBenefits> page = new Page<>(request.getPageNum(), request.getPageSize());
        return this.baseMapper.selectVipBenefitsListInPage(page);
    }
    @Override
    public MallVipBenefits findVipBenefitsById(Long id) {
        return this.baseMapper.selectVipBenefitsById(id);
    }
    @Override
    @Transactional
    public void addVipBenefits(MallVipBenefits mallVipBenefits) {
        if (mallVipBenefits == null) {
            return;
        }
        if (CollUtil.isEmpty(mallVipBenefits.getDetails())) {
            throw new FebsException("权益明细不能为空");
        }
        this.baseMapper.insert(mallVipBenefits);
        mallVipBenefits.getDetails().forEach(item -> {
            item.setBenefitsId(mallVipBenefits.getId());
        });
        this.mallVipBenefitsDetailsService.saveBatch(mallVipBenefits.getDetails());
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delVipBenefits(Long id) {
        this.baseMapper.deleteById(id);
        LambdaQueryWrapper<MallVipBenefitsDetails> delQuery = new LambdaQueryWrapper<>();
        delQuery.eq(MallVipBenefitsDetails::getBenefitsId, id);
        this.mallVipBenefitsDetailsService.remove(delQuery);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editVipBenefits(MallVipBenefits mallVipBenefits) {
        if (mallVipBenefits.getId() == null) {
            throw new FebsException("缺少重要参数");
        }
        this.baseMapper.updateById(mallVipBenefits);
        LambdaQueryWrapper<MallVipBenefitsDetails> delQuery = new LambdaQueryWrapper<>();
        delQuery.eq(MallVipBenefitsDetails::getBenefitsId, mallVipBenefits.getId());
        this.mallVipBenefitsDetailsService.remove(delQuery);
        mallVipBenefits.getDetails().forEach(item -> {
            item.setBenefitsId(mallVipBenefits.getId());
        });
        this.mallVipBenefitsDetailsService.saveBatch(mallVipBenefits.getDetails());
    }
    @Override
    public void getBenefits(Long id) {
        MallMember loginUser = LoginUserUtil.getLoginUser();
        MallMember member = mallMemberMapper.selectById(loginUser.getId());
        MallVipBenefitsDetails benefits = mallVipBenefitsDetailsService.getById(id);
        if (benefits == null) {
            throw new FebsException("权益不存在");
        }
        if (benefits.getIsClick() == 2) {
            throw new FebsException("请联系客服,检查权益设置");
        }
        MallVipBenefits vipBenefits = this.baseMapper.selectById(benefits.getBenefitsId());
        if (vipBenefits == null) {
            throw new FebsException("权益不存在");
        }
        MallVipConfig config = mallVipConfigMapper.selectVipConfigByCode(member.getLevel());
        boolean b = config.getBenefits().stream().anyMatch(item -> {
            return Objects.equals(item.getId(), benefits.getBenefitsId());
        });
        if (!b) {
            throw new FebsException("未达到等级不能领取该权益");
        }
        Integer linkType = benefits.getLinkType();
        if (vipBenefits.getGainType() == 2) {
            String today = DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN);
            boolean isBirthday = member.getBirthday().compareTo(DateUtil.parseDate(today)) == 0;
            if (!isBirthday) {
                throw new FebsException("未达到权益领取条件:未到生日");
            }
        }
        if (vipBenefits.getGainType() == 3) {
            DataDictionaryCustom data = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.VIP_DATE.getType(), DataDictionaryEnum.VIP_DATE.getCode());
            String today = DateUtil.format(new Date(), "MM-dd");
            if (!StrUtil.equals(data.getValue(), today)) {
                throw new FebsException("未达到权益领取条件:未到会员日");
            }
        }
        LambdaQueryWrapper<MallVipBenefitsRecord> recordQuery = new LambdaQueryWrapper<>();
        recordQuery.ge(MallVipBenefitsRecord::getReceiveTime, DateUtil.beginOfDay(new Date()))
                .le(MallVipBenefitsRecord::getReceiveTime, DateUtil.endOfDay(new Date()))
                .eq(MallVipBenefitsRecord::getMemberId, member.getId())
                .eq(MallVipBenefitsRecord::getBenefitsType, vipBenefits.getGainType())
                .eq(MallVipBenefitsRecord::getReceiveId, Long.parseLong(benefits.getContent()));
        List<MallVipBenefitsRecord> mallVipBenefitsRecords = mallVipBenefitsRecordMapper.selectList(recordQuery);
        if (CollUtil.isNotEmpty(mallVipBenefitsRecords)) {
            throw new FebsException("已领取过权益");
        }
        MallVipBenefitsRecord record = new MallVipBenefitsRecord();
        record.setBenefitsType(vipBenefits.getGainType());
        record.setBenefitsName(vipBenefits.getName());
        record.setReceiveTime(new Date());
        record.setReceiveType(linkType);
        record.setReceiveId(Long.parseLong(benefits.getContent()));
        record.setMemberId(member.getId());
        record.setReceiveCnt(1);
        // 商品
        if (linkType == 2) {
            MallGoods goods = mallGoodsMapper.selectGoodsDetailById(Long.parseLong(benefits.getContent()));
            if (goods == null) {
                throw new FebsException("商品不存在");
            }
            LambdaQueryWrapper<MallAddressInfo> query = new LambdaQueryWrapper<>();
            query.eq(MallAddressInfo::getMemberId, member.getId())
                    .eq(MallAddressInfo::getIsDefault, 1)
                    .last("limit 1");
            MallAddressInfo address = mallAddressInfoMapper.selectOne(query);
            if (address == null) {
                throw new FebsException("请设置默认地址");
            }
            String orderNo = MallUtils.getOrderNum();
            MallOrderInfo orderInfo = new MallOrderInfo();
            orderInfo.setOrderNo(orderNo);
            orderInfo.setOrderTime(new Date());
            orderInfo.setMemberId(member.getId());
            orderInfo.setPayTime(new Date());
            orderInfo.setStatus(OrderStatusEnum.WAIT_SHIPPING.getValue());
            orderInfo.setOrderType(goods.getGoodsType());
            orderInfo.setDeliveryType(2);
            orderInfo.setIsFree(1);
            orderInfo.setCarriage(BigDecimal.ZERO);
            orderInfo.setAmount(BigDecimal.ZERO);
            orderInfo.setAddressId(address.getId());
            orderInfo.setName(address.getName());
            orderInfo.setPhone(address.getPhone());
            orderInfo.setIsHome(2);
            orderInfo.setAddress(address.getProvince()+address.getCity()+address.getArea() + address.getAddress());
            orderInfo.setLatitude(address.getLatitude());
            orderInfo.setLongitude(address.getLongitude());
            mallOrderInfoMapper.insert(orderInfo);
            MallOrderItem orderItem = new MallOrderItem();
            if (goods.getGoodsType() == 2) {
                orderItem.setAmount(BigDecimal.ZERO);
                orderItem.setCnt(1);
                orderItem.setOrderId(orderInfo.getId());
                orderItem.setPrice(goods.getScore());
                orderItem.setGoodsId(goods.getId());
                orderItem.setGoodsName(goods.getGoodsName());
                orderItem.setStyleName(goods.getGoodsName());
                orderItem.setSkuName(goods.getGoodsName());
                orderItem.setSkuImage(goods.getThumb());
                orderItem.setState(1);
            } else {
                MallGoodsSku sku = goods.getStyles().get(0).getSkus().get(0);
                orderItem.setAmount(BigDecimal.ZERO);
                orderItem.setCnt(1);
                orderItem.setOrderId(orderInfo.getId());
                orderItem.setPrice(sku.getPresentPrice());
                orderItem.setGoodsId(sku.getGoodsId());
                orderItem.setGoodsName(goods.getGoodsName());
                orderItem.setSkuId(sku.getId());
                orderItem.setState(1);
                orderItem.setStyleName(goods.getStyles().get(0).getName());
                orderItem.setSkuName(sku.getSkuName());
                orderItem.setSkuImage(sku.getSkuImage());
                orderItem.setIsNormal(goods.getIsNormal());
                orderItem.setCostPrice(sku.getCostPrice());
            }
            record.setReceiveName(goods.getGoodsName());
            mallOrderItemMapper.insert(orderItem);
        }
        // 优惠券
        if (linkType == 3) {
            MallGoodsCoupon coupon = mallGoodsCouponMapper.selectById(Long.parseLong(benefits.getContent()));
            if (coupon == null) {
                throw new FebsException("优惠券");
            }
            MallMemberCoupon memberCoupon = new MallMemberCoupon();
            memberCoupon.setCouponId(coupon.getId());
            memberCoupon.setCouponName(coupon.getName());
            memberCoupon.setInviteId(member.getInviteId());
            memberCoupon.setCouponUuid(IdUtil.simpleUUID());
            memberCoupon.setState(1);
            memberCoupon.setFromType(2);
            memberCoupon.setExpireTime(DateUtil.offsetDay(DateUtil.date(), coupon.getExpireDay()));
            memberCoupon.setMemberId(member.getId());
            mallMemberCouponMapper.insert(memberCoupon);
            record.setReceiveName(coupon.getName());
        }
        mallVipBenefitsRecordMapper.insert(record);
    }
}
src/main/java/cc/mrbird/febs/vip/service/impl/MallVipConfigBenefitsServiceImpl.java
New file
@@ -0,0 +1,15 @@
package cc.mrbird.febs.vip.service.impl;
import cc.mrbird.febs.vip.entity.MallVipConfigBenefits;
import cc.mrbird.febs.vip.mapper.MallVipConfigBenefitsMapper;
import cc.mrbird.febs.vip.service.IMallVipConfigBenefitsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class MallVipConfigBenefitsServiceImpl extends ServiceImpl<MallVipConfigBenefitsMapper, MallVipConfigBenefits> implements IMallVipConfigBenefitsService {
}
src/main/java/cc/mrbird/febs/vip/service/impl/MallVipConfigServiceImpl.java
New file
@@ -0,0 +1,168 @@
package cc.mrbird.febs.vip.service.impl;
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.common.enumerates.DataDictionaryEnum;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.mall.entity.DataDictionaryCustom;
import cc.mrbird.febs.mall.entity.MallMember;
import cc.mrbird.febs.mall.mapper.DataDictionaryCustomMapper;
import cc.mrbird.febs.mall.mapper.MallMemberMapper;
import cc.mrbird.febs.vip.entity.MallVipBenefits;
import cc.mrbird.febs.vip.entity.MallVipConfig;
import cc.mrbird.febs.vip.entity.MallVipConfigBenefits;
import cc.mrbird.febs.vip.mapper.MallVipConfigBenefitsMapper;
import cc.mrbird.febs.vip.mapper.MallVipConfigMapper;
import cc.mrbird.febs.vip.service.IMallVipConfigBenefitsService;
import cc.mrbird.febs.vip.service.IMallVipConfigService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
@Slf4j
@Service
@RequiredArgsConstructor
public class MallVipConfigServiceImpl extends ServiceImpl<MallVipConfigMapper, MallVipConfig> implements IMallVipConfigService {
    private final IMallVipConfigBenefitsService mallVipConfigBenefitsService;
    private final MallMemberMapper mallMemberMapper;
    private final DataDictionaryCustomMapper dataDictionaryCustomMapper;
    @Override
    public IPage<MallVipConfig> vipConfigList(QueryRequest request) {
        Page<MallVipConfig> page = new Page<>(request.getPageNum(), request.getPageSize());
        return this.baseMapper.findVipConfigListInPage(page);
    }
    @Override
    public List<MallVipConfig> findConfigList() {
        List<MallVipConfig> configs = this.baseMapper.selectVipConfigList();
        configs.forEach(item -> {
            item.getBenefits().forEach(benefits -> {
                benefits.setIsJump(CollUtil.isEmpty(benefits.getDetails()) ? 2 : 1);
            });
        });
        return configs;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addVipConfig(MallVipConfig config) {
        List<MallVipConfig> configs = this.baseMapper.selectVipConfigList();
        boolean b = configs.stream().anyMatch(item -> {
            return (item.getLevel().equals(config.getLevel()) || config.getCode().equals(item.getCode()));
        });
        if (b) {
            throw new FebsException("会员等级或编码已存在");
        }
        this.baseMapper.insert(config);
        List<MallVipConfigBenefits> configBenefitsList = new ArrayList<>();
        List<String> benefitsIds = StrUtil.split(config.getBenefitsIds(), ',');
        benefitsIds.forEach(item -> {
            MallVipConfigBenefits configBenefits = new MallVipConfigBenefits();
            configBenefits.setConfigId(config.getId());
            configBenefits.setBenefitsId(Long.parseLong(item));
            configBenefitsList.add(configBenefits);
        });
        mallVipConfigBenefitsService.saveBatch(configBenefitsList);
    }
    @Override
    public void editVipConfig(MallVipConfig config) {
        MallVipConfig oldConfig = this.baseMapper.selectById(config.getId());
        List<MallVipConfig> configs = this.baseMapper.selectVipConfigList();
        boolean b = configs.stream().anyMatch(item -> {
            return !item.getId().equals(config.getId()) && (item.getLevel().equals(config.getLevel()) || config.getCode().equals(item.getCode()));
        });
        if (b) {
            throw new FebsException("会员等级或编码已存在");
        }
        if (!config.getCode().equals(oldConfig.getCode())) {
            LambdaQueryWrapper<MallMember> memberQuery = new LambdaQueryWrapper<>();
            memberQuery.eq(MallMember::getLevel, oldConfig.getCode());
            List<MallMember> mallMembers = mallMemberMapper.selectList(memberQuery);
            if (CollUtil.isNotEmpty(mallMembers)) {
                throw new FebsException("会员编码绑定了客户,请调整后修改");
            }
        }
        this.baseMapper.updateById(config);
        LambdaQueryWrapper<MallVipConfigBenefits> delQuery = new LambdaQueryWrapper<>();
        delQuery.eq(MallVipConfigBenefits::getConfigId, config.getId());
        mallVipConfigBenefitsService.remove(delQuery);
        List<MallVipConfigBenefits> configBenefitsList = new ArrayList<>();
        List<String> benefitsIds = StrUtil.split(config.getBenefitsIds(), ',');
        benefitsIds.forEach(item -> {
            MallVipConfigBenefits configBenefits = new MallVipConfigBenefits();
            configBenefits.setConfigId(config.getId());
            configBenefits.setBenefitsId(Long.parseLong(item));
            configBenefitsList.add(configBenefits);
        });
        mallVipConfigBenefitsService.saveBatch(configBenefitsList);
    }
    @Override
    @Transactional
    public void delVipConfig(Long id) {
        this.baseMapper.deleteById(id);
        LambdaQueryWrapper<MallVipConfigBenefits> delQuery = new LambdaQueryWrapper<>();
        delQuery.eq(MallVipConfigBenefits::getConfigId, id);
        this.mallVipConfigBenefitsService.remove(delQuery);
    }
    @Override
    public MallVipBenefits hasVipBenefits(Long memberId) {
        MallMember member = mallMemberMapper.selectById(memberId);
        if (member == null) {
            throw new FebsException("会员不存在");
        }
        MallVipConfig vipConfig = this.baseMapper.selectVipConfigByCode(member.getLevel());
        if (vipConfig == null) {
            throw new FebsException("会员配置不存在");
        }
        String today = DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN);
        boolean isBirthday = member.getBirthday().compareTo(DateUtil.parseDate(today)) == 0;
        List<MallVipBenefits> benefits = vipConfig.getBenefits();
        Optional<MallVipBenefits> max = benefits.stream().filter(item -> {
            if (item.getScoreMultiple() == null) {
                return false;
            }
            // 生日权益
            if (item.getGainType() == 2 && isBirthday) {
                return true;
            }
            DataDictionaryCustom data = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.VIP_DATE.getType(), DataDictionaryEnum.VIP_DATE.getCode());
            String todayTime = DateUtil.format(new Date(), "MM-dd");
            // 会员日
            return item.getGainType() == 1 && StrUtil.equals(data.getValue(), todayTime);
        }).max(Comparator.comparing(MallVipBenefits::getScoreMultiple));
        return max.orElse(null);
    }
}
src/main/java/cc/mrbird/febs/vip/service/impl/VipCommonServiceImpl.java
New file
@@ -0,0 +1,168 @@
package cc.mrbird.febs.vip.service.impl;
import cc.mrbird.febs.common.enumerates.FlowTypeEnum;
import cc.mrbird.febs.common.enumerates.MoneyFlowTypeEnum;
import cc.mrbird.febs.common.enumerates.ScoreFlowTypeEnum;
import cc.mrbird.febs.mall.entity.MallMember;
import cc.mrbird.febs.mall.entity.MallOrderInfo;
import cc.mrbird.febs.mall.entity.MallOrderItem;
import cc.mrbird.febs.mall.mapper.MallMemberMapper;
import cc.mrbird.febs.mall.mapper.MallOrderInfoMapper;
import cc.mrbird.febs.mall.service.IApiMallMemberWalletService;
import cc.mrbird.febs.mall.service.IApiMallOrderInfoService;
import cc.mrbird.febs.mall.service.IMallMoneyFlowService;
import cc.mrbird.febs.rabbit.producter.AgentProducer;
import cc.mrbird.febs.vip.entity.MallVipBenefits;
import cc.mrbird.febs.vip.entity.MallVipConfig;
import cc.mrbird.febs.vip.mapper.MallVipConfigMapper;
import cc.mrbird.febs.vip.service.IMallVipConfigService;
import cc.mrbird.febs.vip.service.IVipCommonService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor
public class VipCommonServiceImpl implements IVipCommonService {
    private final MallOrderInfoMapper mallOrderInfoMapper;
    private final IMallVipConfigService mallVipConfigService;
    private final IMallMoneyFlowService mallMoneyFlowService;
    private final IApiMallMemberWalletService mallMemberWalletService;
    private final MallMemberMapper mallMemberMapper;
    private final MallVipConfigMapper mallVipConfigMapper;
    private final AgentProducer agentProducer;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void getScore(Long orderId) {
        MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectOrderDetailsById(orderId);
        if (mallOrderInfo == null) {
            return;
        }
        Long memberId = mallOrderInfo.getMemberId();
        MallVipBenefits mallVipBenefits = mallVipConfigService.hasVipBenefits(memberId);
        BigDecimal multiple = BigDecimal.ONE;
        String name = "";
        if (mallVipBenefits != null) {
            multiple = mallVipBenefits.getScoreMultiple();
            name = mallVipBenefits.getName();
        }
        List<String> skuNames = mallOrderInfo.getItems().stream().map(MallOrderItem::getSkuName).collect(Collectors.toList());
        double sum = mallOrderInfo.getItems().stream().map(MallOrderItem::getAmount).mapToDouble(BigDecimal::doubleValue).sum();
        int score = multiple.multiply(BigDecimal.valueOf(sum)).intValue();
        mallMoneyFlowService.addMoneyFlow(memberId, new BigDecimal(score), ScoreFlowTypeEnum.BUY.getValue(), mallOrderInfo.getOrderNo(), FlowTypeEnum.PRIZE_SCORE.getValue(), CollUtil.join(skuNames, ","), 2);
        mallMemberWalletService.add(new BigDecimal(score), memberId, "prizeScore");
        agentProducer.sendVipLevelUp(orderId);
    }
    @Override
    public void levelUp(Long orderId) {
        MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectOrderDetailsById(orderId);
        if (mallOrderInfo == null) {
            return;
        }
        MallMember member = mallMemberMapper.selectById(mallOrderInfo.getMemberId());
        if (member == null) {
            log.info("会员不存在");
            return;
        }
        MallVipConfig config = mallVipConfigMapper.selectVipConfigByCode(member.getLevel());
        if (config == null) {
            log.info("会员等级配置不存在");
            return;
        }
//        LambdaQueryWrapper<MallVipConfig> configQuery = new LambdaQueryWrapper<>();
//        configQuery.gt(MallVipConfig::getLevel, config.getLevel())
//                .orderByAsc(MallVipConfig::getLevel)
//                .last("limit 1");
//        MallVipConfig nextLevel = mallVipConfigMapper.selectOne(configQuery);
        List<MallVipConfig> configs = mallVipConfigMapper.selectVipConfigList();
        String nextLevelCode = "";
        for (MallVipConfig nextLevel : configs) {
            if (config.getLevel() >= nextLevel.getLevel()) {
                continue;
            }
            // 指定商品
            if (nextLevel.getType() == 1) {
                boolean hasMatch = mallOrderInfo.getItems().stream().anyMatch(item -> {
                    return item.getGoodsId().equals(nextLevel.getTargetId());
                });
                if (hasMatch) {
                    nextLevelCode = nextLevel.getCode();
                    continue;
                }
            }
            // 时间区间内金额
            if (nextLevel.getType() == 2) {
                Date endTime = DateUtil.endOfDay(new Date());
                Date startTime = getStartTime(nextLevel.getValidType());
                LambdaQueryWrapper<MallOrderInfo> query = new LambdaQueryWrapper<>();
                query.ge(MallOrderInfo::getReceivingTime, startTime)
                        .le(MallOrderInfo::getReceivingTime, endTime)
                        .eq(MallOrderInfo::getStatus, 4)
                        .eq(MallOrderInfo::getMemberId, member.getId());
                List<MallOrderInfo> orderList = mallOrderInfoMapper.selectList(query);
                if (CollUtil.isEmpty(orderList)) {
                    continue;
                }
                double totalAmount = orderList.stream().mapToDouble(item -> {
                    return item.getAmount().doubleValue();
                }).sum();
                if (nextLevel.getAmount().compareTo(BigDecimal.valueOf(totalAmount)) <= 0) {
                    nextLevelCode = nextLevel.getCode();
                }
            }
        }
        if (StrUtil.isNotBlank(nextLevelCode)) {
            MallMember update = new MallMember();
            update.setId(member.getId());
            update.setLevel(nextLevelCode);
            update.setVipLevelTime(new Date());
            mallMemberMapper.updateById(update);
        }
    }
    private Date getStartTime(String type) {
        Date date = new Date();
        switch (type) {
            case "day" :
                return DateUtil.beginOfDay(date);
            case "month":
                return DateUtil.beginOfMonth(date);
            case "year":
                return DateUtil.beginOfYear(date);
            default:
                return date;
        }
    }
}
src/main/java/cc/mrbird/febs/vip/vo/VipSettingVo.java
New file
@@ -0,0 +1,14 @@
package cc.mrbird.febs.vip.vo;
import cc.mrbird.febs.vip.VipSettingUnAliveSettingBo;
import lombok.Data;
import java.util.List;
@Data
public class VipSettingVo {
    private String vipDate;
    private List<VipSettingUnAliveSettingBo> items;
}
src/main/resources/mapper/modules/MallGoodsMapper.xml
@@ -106,7 +106,7 @@
                </if>
                min(b.id) skuId,
                min(b.present_price) price,
                sum(b.stock) stock,
                ifnull(sum(b.stock), a.stock) stock,
                sum(b.sku_volume) saleVolume
            from mall_goods a
                 left join mall_goods_sku b on a.id=b.goods_id
@@ -123,9 +123,12 @@
                    <if test="record.isNormal != null and record.isNormal != ''">
                        and a.is_normal = #{record.isNormal}
                    </if>
                    <if test="record.goodsType != null and record.goodsType != '' and record.goodsType != 3">
                    <if test="record.goodsType != null and record.goodsType != '' and record.goodsType == 1">
                        and a.goods_type = #{record.goodsType} and a.present_price != 0
                    </if>
                    <if test="record.goodsType != null and record.goodsType != '' and record.goodsType == 2">
                        and a.goods_type = #{record.goodsType}
                    </if>
                    <if test="record.goodsType == 3">
                        and a.present_price = 0
                    </if>
src/main/resources/mapper/modules/MallMemberCouponMapper.xml
@@ -6,7 +6,8 @@
        select
        a.*,
        b.cost_amount costAmount,
        b.real_amount realAmount
        b.real_amount realAmount,
        b.type type
        from mall_member_coupon a
        INNER join mall_goods_coupon b on b.id = a.coupon_id and b.state = 2
        <where>
src/main/resources/mapper/modules/MallMemberMapper.xml
@@ -4,11 +4,11 @@
    <select id="selectMallMemberListInPage" resultType="cc.mrbird.febs.mall.entity.MallMember">
        SELECT m.*,a.name referrerName,IFNULL(c.balance,0) balance,IFNULL(c.score,0) score,IFNULL(c.prize_score,0) prizeScore,IFNULL(c.commission,0) commission
        ,d.description levelName
        ,vipConfig.name levelName
        FROM mall_member m
        left join mall_member a on m.referrer_id = a.invite_id
        LEFT JOIN mall_member_wallet c on c.member_id = m.id
        LEFT JOIN data_dictionary_custom d on d.code = m.level and type='AGENT_LEVEL'
        left join mall_vip_config vipConfig on m.level = vipConfig.code
        <where>
            <if test="record != null" >
                <if test="record.name!=null and record.name!=''">
src/main/resources/mapper/modules/MallOrderInfoMapper.xml
@@ -127,6 +127,7 @@
        <result column="take_unique_code" property="takeUniqueCode" />
        <result column="delivery_state" property="deliveryState" />
        <result column="is_home" property="isHome" />
        <result column="is_free" property="isFree" />
        <result column="del_flag" property="delFlag" />
        <result column="leader_name" property="leaderName" />
        <result column="leader_phone" property="leaderPhone" />
@@ -215,7 +216,7 @@
            a.status,
            count(1) cnt
        from mall_order_info a
        where a.del_flag=2 and a.member_id=#{memberId}
        where a.del_flag=2 and a.member_id=#{memberId} and order_type = 1
        group by a.status
    </select>
@@ -374,6 +375,7 @@
        <result column="take_unique_code" property="takeUniqueCode" />
        <result column="delivery_state" property="deliveryState" />
        <result column="is_home" property="isHome" />
        <result column="is_free" property="isFree" />
        <result column="del_flag" property="delFlag" />
        <result column="leader_name" property="leaderName" />
        <result column="leader_phone" property="leaderPhone" />
@@ -386,12 +388,15 @@
        <result column="city" property="city" />
        <result column="township" property="township" />
        <result column="detail_address" property="detailAddress" />
        <result column="express_no" property="expressNo" />
    </resultMap>
    <select id="selectNewApiOrderListInPage" resultMap="NewOrderInfoMap">
        select
        a.*
        ,express.express_no
        from mall_order_info a
            left join mall_express_info express on a.id=express.order_id
        <where>
            a.del_flag=2
            <if test="record.memberId != null">
src/main/resources/mapper/modules/MallShoppingCartMapper.xml
@@ -13,7 +13,7 @@
    </resultMap>
    
    <select id="selectCartGoodsList" resultMap="ShoppingCartMap">
        select * from mall_shopping_cart where member_id=#{memberId}
        select * from mall_shopping_cart where member_id=#{memberId} and type = #{type}
    </select>
    <select id="selectCartGoodsBySkuId" resultType="cc.mrbird.febs.mall.entity.MallShoppingCart">
src/main/resources/mapper/modules/MallVipBenefitsMapper.xml
New file
@@ -0,0 +1,59 @@
<?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="cc.mrbird.febs.vip.mapper.MallVipBenefitsMapper">
    <resultMap id="VipBenefitsMap" type="cc.mrbird.febs.vip.entity.MallVipBenefits">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="type" column="type" />
        <result property="gainType" column="gain_type" />
        <result property="icon" column="icon" />
        <result property="scoreMultiple" column="score_multiple" />
        <result property="remark" column="remark" />
        <collection property="details" ofType="cc.mrbird.febs.vip.entity.MallVipBenefitsDetails">
            <id property="id" column="c_id" />
            <result property="image" column="image" />
            <result property="isClick" column="is_click" />
            <result property="linkType" column="link_type" />
            <result property="content" column="content" />
            <result property="benefitsId" column="benefits_id" />
            <result property="seq" column="seq" />
        </collection>
    </resultMap>
    <select id="selectVipBenefitsListInPage" resultType="cc.mrbird.febs.vip.entity.MallVipBenefits">
        select * from mall_vip_benefits
    </select>
    <select id="selectVipBenefitsById" resultMap="VipBenefitsMap">
        select
            benefits.*,
            benefitsDetail.id c_id
            ,benefitsDetail.image
            ,benefitsDetail.is_click
            ,benefitsDetail.link_type
            ,benefitsDetail.content
            ,benefitsDetail.seq
        from mall_vip_benefits benefits
            left join mall_vip_benefits_details benefitsDetail on benefits.id=benefitsDetail.benefits_id
        where benefits.id=#{id}
    </select>
    <select id="selectVipBenefitsByIds" resultMap="VipBenefitsMap">
        select
            benefits.*,
            benefitsDetail.id c_id
             ,benefitsDetail.image
             ,benefitsDetail.is_click
             ,benefitsDetail.link_type
             ,benefitsDetail.content
             ,benefitsDetail.seq
        from mall_vip_benefits benefits
                 left join mall_vip_benefits_details benefitsDetail on benefits.id=benefitsDetail.benefits_id
        where benefits.id in
        <foreach collection="list" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </select>
</mapper>
src/main/resources/mapper/modules/MallVipConfigMapper.xml
New file
@@ -0,0 +1,58 @@
<?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="cc.mrbird.febs.vip.mapper.MallVipConfigMapper">
    <resultMap id="vipConfigMap" type="cc.mrbird.febs.vip.entity.MallVipConfig">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="thumb" column="thumb" />
        <result property="level" column="level" />
        <result property="validTime" column="valid_time" />
        <result property="validType" column="valid_type" />
        <result property="type" column="type" />
        <result property="code" column="code" />
        <result property="amount" column="amount" />
        <result property="times" column="times" />
        <result property="targetId" column="target_id" />
        <collection property="benefits" ofType="cc.mrbird.febs.vip.entity.MallVipBenefits">
            <id property="id" column="c_id" />
            <result property="name" column="c_name" />
            <result property="icon" column="c_icon" />
            <collection property="details" ofType="cc.mrbird.febs.vip.entity.MallVipBenefitsDetails">
                <id property="id" column="d_id" />
            </collection>
        </collection>
    </resultMap>
    <select id="findVipConfigListInPage" resultType="cc.mrbird.febs.vip.entity.MallVipConfig">
        select * from mall_vip_config
    </select>
    <select id="selectVipConfigList" resultMap="vipConfigMap">
        select
            config.*
            ,benefits.id c_id
            ,benefits.name c_name
            ,benefits.icon c_icon
            ,details.id d_id
        from mall_vip_config config
            inner join mall_vip_config_benefits configBenefits on config.id=configBenefits.config_id
            inner join mall_vip_benefits benefits on configBenefits.benefits_id=benefits.id
            left join mall_vip_benefits_details details on benefits.id = details.benefits_id
        order by level
    </select>
    <select id="selectVipConfigByCode" resultMap="vipConfigMap">
        select
            config.*
             ,benefits.id c_id
             ,benefits.name c_name
             ,benefits.icon c_icon
        from mall_vip_config config
                 inner join mall_vip_config_benefits configBenefits on config.id=configBenefits.config_id
                 inner join mall_vip_benefits benefits on configBenefits.benefits_id=benefits.id
        where config.code=#{code}
    </select>
</mapper>
src/main/resources/templates/febs/views/modules/mallMember/mallMemberList.html
@@ -111,6 +111,7 @@
<script type="text/html" id="toolbar">
    <div class="layui-btn-container">
        <button class="layui-btn layui-btn-normal layui-btn-sm" type="button" lay-event="updateReferer">修改推荐人</button>
        <button class="layui-btn layui-btn-normal layui-btn-sm" type="button" lay-event="updateVipLevel">修改会员等级</button>
<!--        <button class="layui-btn layui-btn-normal layui-btn-sm" type="button" lay-event="registMember">添加会员</button>-->
<!--        <button class="layui-btn layui-btn-normal layui-btn-sm" type="button" lay-event="balance">拨付余额</button>-->
<!--        <button class="layui-btn layui-btn-normal layui-btn-sm" type="button" lay-event="score">拨付赠送积分</button>-->
@@ -294,10 +295,10 @@
                    {field: 'inviteId', title: '邀请码', minWidth: 100,align:'left'},
                    {field: 'balance', title: '余额', minWidth: 100,align:'left'},
                    // {field: 'score', title: '赠送积分', minWidth: 100,align:'left'},
                    // {field: 'prizeScore', title: '竞猜积分', minWidth: 100,align:'left'},
                    {field: 'prizeScore', title: '积分', minWidth: 100,align:'left'},
                    // {field: 'commission', title: '佣金', minWidth: 100,align:'left'},
                    {field: 'referrerName', title: '推荐人', minWidth: 100,align:'left'},
                    {field: 'levelName', title: '会员类型', minWidth: 100,align:'left'},
                    {field: 'levelName', title: '会员等级', minWidth: 100,align:'left'},
                    // {field: 'referrerName', title: '推荐人', minWidth: 100,align:'left'},
                    {field: 'isSalesman', title: '推销员设置', templet: '#isSalesmanSwitch', minWidth: 100,align:'center'},
                    // {field: 'director', title: '总监', templet:'#switchDirector', minWidth: 100},
@@ -376,6 +377,27 @@
                });
            }
            if (layEvent === 'updateVipLevel') {
                var checkData = table.checkStatus('userTable').data;
                if (checkData.length > 1) {
                    febs.alert.warn('每次只能修改一个用户');
                    return;
                }
                // var idList = [];
                // for (var i = 0; i < checkData.length; i++) {
                //     idList.push(checkData[i].id);
                // }
                febs.modal.open('设置会员等级', 'modules/mallMember/vipLevelSetting/' + checkData[0].id, {
                    btn: ['确认', '取消'],
                    yes: function (index, layero) {
                        $('#vip-level-set').find('#submit').trigger('click');
                    },
                    btn2: function () {
                        layer.closeAll();
                    }
                });
            }
            if (layEvent === 'resetPwd') {
                febs.modal.confirm('重置登录密码', '是否重置选中账号登录密码?', function () {
                    var ids = [];
src/main/resources/templates/febs/views/modules/mallMember/vip-level-setting.html
New file
@@ -0,0 +1,92 @@
<style>
    #vip-level-set {
        padding: 20px 25px 25px 0;
    }
    #vip-level-set .layui-treeSelect .ztree li a, .ztree li span {
        margin: 0 0 2px 3px !important;
    }
    #vip-level-set #data-permission-tree-block {
        border: 1px solid #eee;
        border-radius: 2px;
        padding: 3px 0;
    }
    #vip-level-set .layui-treeSelect .ztree li span.button.switch {
        top: 1px;
        left: 3px;
    }
</style>
<div class="layui-fluid" id="vip-level-set">
    <form class="layui-form" action="" lay-filter="vip-level-set-form">
        <div class="layui-form-item febs-hide">
            <label class="layui-form-label febs-form-item-require">id:</label>
            <div class="layui-input-block">
                <input type="text" name="id">
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-inline">
                <label class="layui-form-label">会员等级:</label>
                <div class="layui-input-inline">
                    <select lay-verify="required" name="level" class="vip-level-set-level" id="levelSet">
                        <option value="">请选择</option>
                    </select>
                </div>
            </div>
        </div>
        <div class="layui-form-item febs-hide">
            <button class="layui-btn" lay-submit="" lay-filter="vip-level-set-form-submit" id="submit"></button>
        </div>
    </form>
</div>
<script data-th-inline="javascript">
    layui.use(['febs', 'form', 'formSelects', 'validate', 'treeSelect', 'eleTree'], function () {
        var $ = layui.jquery,
            febs = layui.febs,
            layer = layui.layer,
            formSelects = layui.formSelects,
            treeSelect = layui.treeSelect,
            form = layui.form,
            eleTree = layui.eleTree,
            vipLevelSet = [[${vipLevelSet}]],
            $view = $('#vip-level-set'),
            validate = layui.validate,
            _deptTree;
        form.render();
        initUserValue();
        function initUserValue() {
            form.val("vip-level-set-form", {
                "id": vipLevelSet.id,
                "level": vipLevelSet.level
            });
        }
        //(下拉框)
        $.get(ctx + 'admin/vip/config/allList', function (res) {
            var data = res.data;
            for (var k in data)
            {
                $(".vip-level-set-level").append("<option value='" + data[k].code + "'>" + data[k].name + "</option>");
            }
            layui.use('form', function () {
                var form = layui.form;
                $("#levelSet").val(vipLevelSet.level)
                form.render();
            });
        });
        form.on('submit(vip-level-set-form-submit)', function (data) {
            febs.post(ctx + 'admin/mallMember/vipLevelSetUpdate', data.field, function () {
                layer.closeAll();
                febs.alert.success('操作成功');
                $('#febs-member-list').find('#reset').click();
            });
            return false;
        });
    });
</script>
src/main/resources/templates/febs/views/modules/score/goodsAdd.html
@@ -207,31 +207,58 @@
            }
        });
        var E = window.wangEditor;
        const editorConfig = { MENU_CONF: {} };
        editorConfig.MENU_CONF['uploadImage'] = {
            server: '/admin/goods/uploadFileBase64',
            fieldName : "file",
            customInsert(res, insertFn) {
                insertFn(res.data.src, res.data.title, '')
            },
        }
        // var E = window.wangEditor;
        // const editorConfig = { MENU_CONF: {} };
        // editorConfig.MENU_CONF['uploadImage'] = {
        //     server: '/admin/goods/uploadFileBase64',
        //     fieldName : "file",
        //     customInsert(res, insertFn) {
        //         insertFn(res.data.src, res.data.title, '')
        //     },
        // }
        //
        // const editor = E.createEditor({
        //     selector: '#editor-container',
        //     config : editorConfig,
        //     mode: 'default'
        // });
        //
        // const toolbar = E.createToolbar({
        //     editor,
        //     selector: '#toolbar-container',
        //     mode: 'default'
        // });
        const editor = E.createEditor({
            selector: '#editor-container',
            config : editorConfig,
            mode: 'default'
        });
        const toolbar = E.createToolbar({
            editor,
            selector: '#toolbar-container',
            mode: 'default'
        });
        const E = window.wangEditor;
        const editor = new E('#toolbar-container', '#editor-container'); // 传入两个元素
        editor.config.showLinkImg = false;
        editor.config.uploadFileName = 'file';
        editor.config.customUploadImg = function (files, insertImgFn) {
            // files 是 input 中选中的文件列表
            // insertImgFn 是获取图片 url 后,插入到编辑器的方法
            // 上传图片,返回结果,将图片插入到编辑器中
            for (let i = 0; i < files.length; i++){
                var form = new FormData();
                form.append("file", files[0]);
                $.ajax({
                    url:'/admin/goods/uploadFileBase64',
                    type: "post",
                    processData: false,
                    contentType: false,
                    data: form,
                    dataType: 'json',
                    success(res) {
                        // 上传代码返回结果之后,将图片插入到编辑器中
                        insertImgFn(res.data.src, res.data.title, '')
                    }
                })
            }
        };
        editor.create();
        form.on('submit(score-goods-add-form-submit)', function (data) {
            data.field.goodsType = 2;
            data.field.goodsDetails = editor.getHtml();
            data.field.goodsDetails = editor.txt.html();
            $.ajax({
                'url':ctx + 'admin/goods/addMallGoods',
                'type':'post',
src/main/resources/templates/febs/views/modules/vip/coupon-select.html
New file
@@ -0,0 +1,91 @@
<style>
    #vip-coupon-select {
        padding: 20px 25px 25px 0;
    }
    #vip-coupon-select .layui-treeSelect .ztree li a, .ztree li span {
        margin: 0 0 2px 3px !important;
    }
    #vip-coupon-select #data-permission-tree-block {
        border: 1px solid #eee;
        border-radius: 2px;
        padding: 3px 0;
    }
    #vip-coupon-select .layui-treeSelect .ztree li span.button.switch {
        top: 1px;
        left: 3px;
    }
    #vip-coupon-select img{
        max-width:100px
    }
</style>
<div class="layui-fluid" id="vip-coupon-select">
    <form class="layui-form" action="" lay-filter="vip-coupon-select-form">
        <div class="layui-form-item">
            <label class="layui-form-label">优惠卷:</label>
            <div class="layui-input-inline">
                <select name="couponId" class="vip-coupon-select-category" id="couponCategarySelect" lay-filter="coupon-select">
                    <option value="">请选择</option>
                </select>
            </div>
        </div>
        <div class="layui-form-item febs-hide">
            <button class="layui-btn" lay-submit="" lay-filter="vip-coupon-select-form-submit" id="submit"></button>
        </div>
    </form>
</div>
<script data-th-inline="javascript">
    layui.use(['febs', 'form', 'formSelects', 'validate', 'treeSelect', 'eleTree', 'laydate','upload'], function () {
        var $ = layui.$,
            febs = layui.febs,
            layer = layui.layer,
            formSelects = layui.formSelects,
            treeSelect = layui.treeSelect,
            form = layui.form,
            laydate = layui.laydate,
            eleTree = layui.eleTree,
            tableIndex = [[${tableIndex}]],
            $view = $('#vip-coupon-select'),
            upload = layui.upload,
            selectData,
            couponList,
            validate = layui.validate;
        form.render();
        laydate.render({
            elem: '#febs-form-group-date'
        });
        formSelects.render();
        //(下拉框)
        $.get(ctx + 'admin/goods/coupon/tree', function (data) {
            couponList = data;
            for (var k in data)
            {
                $(".vip-coupon-select-category").append("<option value='" + data[k].couponId + "'>" + data[k].couponName + "</option>");
            }
            layui.use('form', function () {
                var form = layui.form;
                $("#couponCategarySelect").val('')
                form.render();
            });
        });
        form.on('select(coupon-select)', function(data) {
            for(var i = 0; i<couponList.length; i++) {
                if (data.value == couponList[i].couponId) {
                    selectData = couponList[i];
                }
            }
        });
        form.on('submit(vip-coupon-select-form-submit)', function (data) {
            parent.setCouponSelect(tableIndex, selectData)
        });
    });
</script>
src/main/resources/templates/febs/views/modules/vip/goods-select-list.html
New file
@@ -0,0 +1,233 @@
<div class="layui-fluid layui-anim febs-anim" id="febs-select-goods" lay-title="商品列表">
    <div class="layui-row febs-container">
        <div class="layui-col-md12">
            <div class="layui-tab layui-tab-brief" lay-filter="goods-select-tab">
                <ul class="layui-tab-title">
                    <li class="layui-this">付费商品</li>
                    <li>积分商品</li>
                </ul>
                <div class="layui-tab-content">
                    <div class="layui-tab-item layui-show">
                        <div class="layui-card">
                            <div class="layui-card-body febs-table-full">
                                <form class="layui-form layui-table-form" lay-filter="goods-select-table-form" id="form">
                                    <div class="layui-row">
                                        <div class="layui-col-md10">
                                            <div class="layui-form-item">
                                                <div class="layui-inline">
                                                    <label class="layui-form-label layui-form-label-sm">商品名称</label>
                                                    <div class="layui-input-inline">
                                                        <input type="text" placeholder="商品名称" name="goodsName" autocomplete="off" class="layui-input">
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                        <div class="layui-col-md2 layui-col-sm12 layui-col-xs12 table-action-area">
                                            <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain table-action" id="query">
                                                <i class="layui-icon">&#xe848;</i>
                                            </div>
                                        </div>
                                    </div>
                                </form>
                                <table lay-filter="goodsListTable" id="goodsListTable" lay-data="{id: 'goodsListTable'}"></table>
                            </div>
                        </div>
                    </div>
                    <div class="layui-tab-item">
                        <div class="layui-card">
                            <div class="layui-card-body febs-table-full" id="scoreForm">
                                <form class="layui-form layui-table-form" lay-filter="goods-select-table-form">
                                    <div class="layui-row">
                                        <div class="layui-col-md10">
                                            <div class="layui-form-item">
                                                <div class="layui-inline">
                                                    <label class="layui-form-label layui-form-label-sm">商品名称</label>
                                                    <div class="layui-input-inline">
                                                        <input type="text" placeholder="商品名称" name="goodsName" autocomplete="off" class="layui-input">
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                        <div class="layui-col-md2 layui-col-sm12 layui-col-xs12 table-action-area">
                                            <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain table-action" id="scoreQuery">
                                                <i class="layui-icon">&#xe848;</i>
                                            </div>
                                        </div>
                                    </div>
                                </form>
                                <table lay-filter="scoreGoodsListTable" id="scoreGoodsListTable" lay-data="{id: 'scoreGoodsListTable'}"></table>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="layui-form-item febs-hide">
            <button class="layui-btn" id="goods-select-form-submit"></button>
            <button class="layui-btn" id="goods-select-close"></button>
        </div>
    </div>
</div>
<style type="text/css">
    .layui-table-cell{
        text-align:center;
        height: auto;
        white-space: nowrap; /*文本不会换行,在同一行显示*/
        overflow: hidden; /*超出隐藏*/
        text-overflow: ellipsis; /*省略号显示*/
    }
    .layui-table img{
        max-width:100px
    }
    ::-webkit-scrollbar {
        height: 20px !important;
        background-color: #f4f4f4;
    }
</style>
<script type="text/html" id="isSkuFormat">
    {{# if(d.isSku === 1) { }}
        <span>是</span>
    {{# } else { }}
        <span>否</span>
    {{# } }}
</script>
<script type="text/html" id="goodsTypeFormat">
    {{# if(d.isNormal == 1) { }}
        <span>普通商品</span>
    {{# } else { }}
        <span>套餐</span>
    {{# } }}
</script>
<style>
    .layui-form-onswitch {
        background-color: #5FB878 !important;
    }
</style>
<!-- 表格操作栏 end -->
<script data-th-inline="javascript" type="text/javascript">
    // 引入组件并初始化
    layui.use([ 'jquery', 'form', 'table', 'febs'], function () {
        var $ = layui.jquery,
            febs = layui.febs,
            form = layui.form,
            table = layui.table,
            element = layui.element,
            $view = $('#febs-select-goods'),
            $query = $view.find('#query'),
            $searchForm = $view.find('#form'),
            $scoreSearchForm = $view.find('#scoreForm'),
            $scoreQuery = $view.find('#scoreQuery'),
            sortObject = {field: 'isSale', type: 'asc'},
            tableIns,
            tableIndex = [[${tableIndex}]],
            tableSelect = 'goodsListTable',
            scoreTableIns;
        form.render();
        let currPageGoods = 1;//首先默认值为1,防止出错
        //获取当前页
        currPageGoods = $view.find(".layui-laypage-em").next().html();
        // 表格初始化
        initTable();
        initScoreTable();
        // 查询按钮
        $query.on('click', function () {
            var params = $.extend(getQueryParams($searchForm), {field: sortObject.field, order: sortObject.type});
            tableIns.reload({where: params, page: {curr: 1}});
        });
        // 查询按钮
        $scoreQuery.on('click', function () {
            var params = $.extend(getQueryParams($scoreSearchForm), {field: sortObject.field, order: sortObject.type});
            scoreTableIns.reload({where: params, page: {curr: 1}});
        });
        function initTable() {
            var tableFeilds = [
                {type: 'radio', title: ''},
                {field: 'goodsName', title: '商品名称', minWidth: 140,align:'left'},
                {field: 'thumb', title: '缩略图',
                    templet: function (d) {
                        return '<a lay-event="seeImgThumb"><img id="seeImgThumb'+d.id+'" src="'+d.thumb+'" alt=""></a>';
                    }, minWidth: 150,align:'center'},
                {field: 'categaryName', title: '分类', minWidth: 140,align:'left'},
                {templet:"#goodsTypeFormat",  title: '商品类型', minWidth: 140,align:'left'},
                {field: 'presentPrice', title: '现价', minWidth: 100,align:'left'},
                {field: 'originalPrice', title: '原价', minWidth: 100,align:'left'},
                {field: 'stock', title: '商品库存', minWidth: 100,align:'left'},
                {field: 'skuVolume', title: '商品销量', minWidth: 100,align:'left'},
            ];
            tableIns = febs.table.init({
                elem: $("#goodsListTable"),
                id: 'goodsListTable',
                url: ctx + 'admin/goods/goodsList?goodsType=1&isSale=1',
                cols: [tableFeilds]
            });
        }
        // table.on('row(goodsListTable)', function(obj){
        //     var data = obj.data; // 获取当前行数据
        //
        //     console.log(obj)
        //     // obj.setRowChecked({
        //     //     type: 'radio'
        //     // });
        // });
        function initScoreTable() {
            var scoreFields = [
                {type: 'radio', title: ''},
                {field: 'goodsName', title: '商品名称', minWidth: 140,align:'left'},
                {field: 'thumb', title: '缩略图',
                    templet: function (d) {
                        return '<a lay-event="seeImgThumb"><img id="seeImgThumb'+d.id+'" src="'+d.thumb+'" alt=""></a>';
                    }, minWidth: 150,align:'center'},
                {field: 'categaryName', title: '分类', minWidth: 140,align:'left'},
                {field: 'presentPrice', title: '现价', minWidth: 100,align:'left'},
                {field: 'originalPrice', title: '原价', minWidth: 100,align:'left'},
                {field: 'stock', title: '商品库存', minWidth: 100,align:'left'},
                {field: 'skuVolume', title: '商品销量', minWidth: 100,align:'left'},
            ]
            scoreTableIns = febs.table.init({
                elem: $("#scoreGoodsListTable"),
                id: 'scoreGoodsListTable',
                url: ctx + 'admin/goods/goodsList?goodsType=2&isSale=1',
                cols: [scoreFields]
            });
        }
        // 获取查询参数
        function getQueryParams(elem) {
            return {
                goodsName: elem.find('input[name="goodsName"]').val().trim(),
            };
        }
        $("#goods-select-form-submit").on('click', function() {
            var checkData = table.checkStatus(tableSelect).data;
            if (checkData.length > 0) {
                if (tableIndex != -1) {
                    parent.setGoodsSelect(tableIndex, checkData[0]);
                } else {
                    parent.setConfigGoodsSelect(tableIndex, checkData[0]);
                }
            }
        })
        element.on('tab(goods-select-tab)', function(data) {
            if (data.index == 0) {
                tableSelect = 'goodsListTable';
            }
            if (data.index == 1) {
                tableSelect = 'scoreGoodsListTable';
            }
        });
    })
</script>
src/main/resources/templates/febs/views/modules/vip/vip-setting.html
New file
@@ -0,0 +1,245 @@
<div class="layui-fluid layui-anim febs-anim" id="vip-setting" lay-title="会员设置">
    <div class="layui-row layui-col-space8 febs-container">
        <form class="layui-form" action="" lay-filter="vip-setting-form">
            <div class="layui-card">
                <div class="layui-card-body">
                    <blockquote class="layui-elem-quote blue-border">会员日设置</blockquote>
                    <div class="layui-form-item">
                        <div class="layui-col-lg6">
                            <label class="layui-form-label ">会员日:</label>
                            <div class="layui-input-block">
                                <input type="text" name="vipDate" id="vipDate" autocomplete="off" class="layui-input" >
                            </div>
                        </div>
                    </div>
                    <blockquote class="layui-elem-quote blue-border">失活客户优惠券</blockquote>
                    <div class="layui-form-item">
                        <div class="layui-col-lg6">
                            <table id="unAliveCouponItem" lay-filter="unAliveCouponItem"></table>
                        </div>
                    </div>
                </div>
                <div class="layui-card-footer">
                    <button class="layui-btn layui-btn-normal" lay-submit="" lay-filter="vip-setting-form-submit" id="submit">保存</button>
                </div>
            </div>
        </form>
    </div>
</div>
<style>
    .layui-form-label {
        width: 120px;
    }
    .layui-form-item .layui-input-block {
        margin-left: 150px;
    }
    .layui-table-form .layui-form-item {
        margin-bottom: 20px !important;
    }
    .layui-table-cell {
        height:auto;
    }
</style>
<script type="text/html" id="toolbar">
    <div class="layui-btn-container">
        <button class="layui-btn layui-btn-sm" type="button" lay-event="addCoupon">新增</button>
        <button class="layui-btn layui-btn-danger layui-btn-sm" type="button" lay-event="delCoupon">删除</button>
    </div>
</script>
<script type="text/html" id="detailsEvent">
    <input type="text" name="couponName" autocomplete="off" data-index="{{d.index}}" value="{{d.couponName}}" class="layui-input couponSelect" readonly>
    <input type="text" name="couponId" autocomplete="off" value="{{d.couponId}}" class="layui-input couponId febs-hide" readonly>
</script>
<script data-th-inline="javascript" type="text/javascript">
    layui.use(['dropdown', 'jquery', 'validate', 'febs', 'form', 'eleTree', 'laydate', 'table'], function () {
        var $ = layui.jquery,
            febs = layui.febs,
            form = layui.form,
            table = layui.table,
            laydate = layui.laydate,
            unAliveCouponItemsData = [],
            vipSetting = [[${vipSetting}]],
            validate = layui.validate,
            $view = $('#vip-setting');
        form.verify(validate);
        form.render();
        laydate.render({
            elem: '#vipDate'
            ,format: 'MM-dd'
        });
        table.render({
            elem: '#unAliveCouponItem'
            ,toolbar:"#toolbar"
            ,cols: [[ //表头
                {type: 'checkbox'}
                , {field: 'day', title: '失活天数', edit:'text', width:250}
                ,{templet: '#detailsEvent', title: '优惠券', width:350}
            ]]
            ,data: []
        });
        table.on('toolbar(unAliveCouponItem)', function(obj){
            var data = obj.data;
            if(obj.event === 'delCoupon'){
                var hasData = table.cache['unAliveCouponItem'];
                var checkData = table.checkStatus('unAliveCouponItem').data;
                if (checkData.length <= 0) {
                    febs.alert.warn('请选择删除数据');
                    return;
                }
                for (let i = 0; i < checkData.length; i++) {
                    var delData = checkData[i];
                    for (let j = 0; j < hasData.length; j++) {
                        if (hasData[j].index == delData.index) {
                            hasData.splice(j, 1);
                            break;
                        }
                    }
                }
                for (let i = 0; i < hasData.length; i++) {
                    hasData[i].index = i + 1;
                }
                unAliveCouponItemsData=hasData;
                reloadTable(hasData);
            }
            if(obj.event === 'addCoupon'){
                var addData = {};
                addTableDate(addData);
            }
        });
        form.on('submit(vip-setting-form-submit)', function (data) {
            data.field.items = unAliveCouponItemsData;
            $.ajax({
                'url':ctx + 'admin/vip/config/vipSetting',
                'type':'post',
                'dataType':'json',
                'headers' : {'Content-Type' : 'application/json;charset=utf-8'}, //接口json格式
                'traditional': true,//ajax传递数组必须添加属性
                'data':JSON.stringify(data.field),
                'success':function (data) {
                    if(data.code==200){
                        febs.alert.success("设置成功");
                    }else{
                        febs.alert.warn(data.message);
                    }
                },
                'error':function () {
                    febs.alert.warn('服务器繁忙');
                }
            })
            window.location.reload();
            return false;
        });
        table.on('edit(unAliveCouponItem)', function(obj){
            var value = obj.value //得到修改后的值
                ,data = obj.data //得到所在行所有键值
                ,field = obj.field; //得到字段
            for (let i = 0; i < unAliveCouponItemsData.length; i++) {
                if (unAliveCouponItemsData[i].index == data.index) {
                    unAliveCouponItemsData[i] = data;
                }
            }
        });
        function addTableDate(data) {
            var hasData = table.cache['unAliveCouponItem'];
            data.index = hasData.length + 1;
            data.couponName = ''
            data.couponId = ''
            data.day = ''
            unAliveCouponItemsData.push(data);
            reloadTable(unAliveCouponItemsData);
            return data.index;
        }
        function reloadTable(data) {
            table.reload('unAliveCouponItem', {
                data : data
            });
            listenerCouponSelect();
        }
        function listenerCouponSelect() {
            $(".couponSelect").each(function(index, elem) {
                var dataIndex = $(this).attr('data-index');
                $(this).off('click')
                $(this).on('click', function() {
                    febs.modal.open('选择优惠券', 'modules/vip/config/couponSelect/' + dataIndex, {
                        btn: ['提交', '取消'],
                        yes: function (index, layero) {
                            $('#vip-coupon-select').find('#submit').trigger('click');
                            layer.close(index);
                        },
                        btn2: function () {
                        }
                    });
                })
            });
        }
        window.setCouponSelect = function(tableIndex, data) {
            var hasData = table.cache['unAliveCouponItem'];
            for(var i = 0; i<hasData.length; i++) {
                if (tableIndex == hasData[i].index) {
                    hasData[i].couponId = data.couponId;
                    hasData[i].couponName = data.couponName
                }
            }
            unAliveCouponItemsData = hasData;
            $(".couponSelect").each(function(index, elem) {
                var dataIndex = $(this).attr('data-index');
                if (dataIndex == tableIndex) {
                    $(this).val(data.couponName);
                    $(this).next().val(data.couponId);
                }
            });
        }
        initVipSettingValue();
        function initVipSettingValue() {
            form.val("vip-setting-form", {
                "vipDate": vipSetting.vipDate,
            });
            var details = vipSetting.items;
            if (details) {
                for(var i = 0; i < details.length; i++) {
                    details[i].index = i + 1;
                }
                unAliveCouponItemsData = details;
                reloadTable(details);
            }
        }
    });
</script>
src/main/resources/templates/febs/views/modules/vip/vipBenefits-add.html
New file
@@ -0,0 +1,489 @@
<div class="layui-fluid layui-anim febs-anim" id="febs-vipBenefits-add" lay-title="新增会员权益">
    <div class="layui-row febs-container">
        <div class="layui-col-md12">
            <div class="layui-fluid" id="act-add">
                <form class="layui-form" action="" lay-filter="vipBenefits-add-form">
                    <div class="layui-tab-item layui-show">
                        <blockquote class="layui-elem-quote blue-border">基本信息设置</blockquote>
                        <div class="layui-row layui-col-space10 layui-form-item">
                            <div class="layui-col-lg6">
                                <label class="layui-form-label febs-form-item-require">权益名称:</label>
                                <div class="layui-input-block">
                                    <input type="text" name="name" lay-verify="required"
                                           placeholder="" autocomplete="off" class="layui-input">
                                </div>
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <div class="layui-col-lg6">
                                <label class="layui-form-label febs-form-item-require">权益生效类型</label>
                                <div class="layui-input-block">
                                    <select name="gainType" class="gain-type" lay-filter="gain-type-select">
                                        <option value="1">会员日</option>
                                        <option value="2">会员生日</option>
                                    </select>
                                </div>
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <div class="layui-col-lg6">
                                <label class="layui-form-label febs-form-item-require">权益类型</label>
                                <div class="layui-input-block">
                                    <select name="type" class="benefits-type" lay-filter="benefits-type-select">
                                        <option value="1">积分</option>
                                        <option value="2">其他</option>
                                    </select>
                                </div>
                            </div>
                            <div class="layui-col-lg6" id="scoreMultiple">
                                <label class="layui-form-label febs-form-item-require">积分倍数:</label>
                                <div class="layui-input-block">
                                    <input type="text" name="scoreMultiple" placeholder="" autocomplete="off" class="layui-input">
                                </div>
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <label class="layui-form-label febs-form-item-require">权益ICON</label>
                            <div class="layui-input-block">
                                <div class="layui-upload">
                                    <button type="button" class="layui-btn layui-btn-normal layui-btn" id="test2">上传</button>
                                    <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
                                        <div class="layui-upload-list">
                                            <img class="layui-upload-img" id="demo2" style="width: 100px" >
                                        </div>
                                    </blockquote>
                                </div>
                            </div>
                        </div>
                        <div class="layui-form-item febs-hide">
                            <label class="layui-form-label">缩略图链接:</label>
                            <div class="layui-input-block">
                                <input type="text" id="benefitsIcon" lay-verify="required" name="icon" autocomplete="off" class="layui-input" readonly>
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <label class="layui-form-label">备注:</label>
                            <div class="layui-input-block">
                                <label>
                                    <textarea name="remark" rows="5" autocomplete="off" class="layui-textarea" ></textarea>
                                </label>
                            </div>
                        </div>
                        <blockquote class="layui-elem-quote blue-border">权益详情页面设置</blockquote>
                        <div class="layui-row layui-col-space10 layui-form-item">
                            <div class="layui-col-lg3">
                                <label class="layui-form-label">是否可点击</label>
                                <div class="layui-input-block">
                                    <input type="radio" name="isClick" value="1" title="是" lay-filter="isClick"/>
                                    <input type="radio" name="isClick" value="2" title="否" lay-filter="isClick" checked />
                                </div>
                            </div>
                            <div class="layui-col-lg3 febs-hide" id="linkTypeDiv">
                                <label class="layui-form-label febs-form-item-require">点击类型</label>
                                <div class="layui-input-block">
                                    <select name="linkType" class="linkType" lay-filter="link-type-select">
                                        <option value="">请选择</option>
                                        <option value="1">链接</option>
                                        <option value="2">领取商品</option>
                                        <option value="3">优惠券</option>
                                    </select>
                                </div>
                            </div>
                            <div class="layui-col-lg6">
                                <button type="button" class="layui-btn layui-btn-normal layui-btn" id="addBenefits" >添加</button>
                            </div>
                            <div class="layui-form-item">
                                <table id="benefitsDetailsItem" lay-filter="benefitsDetailsItem"></table>
                            </div>
                        </div>
                    </div>
                    <div class="layui-form-item febs-hide">
                        <button class="layui-btn" lay-submit="" lay-filter="vipBenefits-add-form-submit" id="submit">保存</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>
<style>
    .blue-border {
        border-left-color: #2db7f5;
        font-size: 18px;
    }
    .layui-table-cell {
        height:auto;
    }
</style>
<script type="text/html" id="toolbar">
    <div class="layui-btn-container">
        <button class="layui-btn layui-btn-danger layui-btn-sm" type="button" lay-event="delAct">删除</button>
    </div>
</script>
<script type="text/html" id="awardtableImgUpload">
    <div class="layui-upload">
        <button type="button" class="layui-btn layui-btn-normal layui-btn-xs sku-img" id="awardImg{{d.index}}">上传</button></br>
        <img class="layui-upload-img" id="awardImageUrls{{d.index}}" style="width: 100px; display:none;" src="{{d.image}}" >
        <input type="text" id="awardImage{{d.index}}" name="awardImage{{d.index}}" autocomplete="off" value="{{d.image}}" class="layui-input febs-hide">
    </div>
</script>
<!--<script type="text/html" id="seqInput">-->
<!--    <input type="text" name="seq" autocomplete="off" class="layui-input">-->
<!--</script>-->
<!-- 表格操作栏 end -->
<script data-th-inline="javascript">
    layui.use(['febs', 'form', 'formSelects', 'validate', 'treeSelect', 'eleTree','dropdown', 'laydate', 'layedit', 'upload', 'element', 'table', 'xmSelect'], function () {
        var $ = layui.jquery,
            febs = layui.febs,
            layer = layui.layer,
            table = layui.table,
            formSelects = layui.formSelects,
            treeSelect = layui.treeSelect,
            form = layui.form,
            laydate = layui.laydate,
            eleTree = layui.eleTree,
            $view = $('#febs-vip-benefits'),
            layedit = layui.layedit,
            upload = layui.upload,
            validate = layui.validate,
            element = layui.element;
        form.render();
        formSelects.render();
        //图片上传
        upload.render({
            elem: '#test2'
            ,url: ctx + 'admin/goods/uploadFileBase64' //改成您自己的上传接口
            ,done: function(res){
                $('#demo2').attr('src', res.data.src);
                $("#benefitsIcon").val(res.data.src);
            }
        });
        var tableBenefitsItemsData=[];
        var tableIns = table.render({
            elem: '#benefitsDetailsItem'
            ,limit:999
            ,toolbar:"#toolbar"
            ,defaultToolbar:[]
            ,cols: [[ //表头
                {type: 'checkbox'}
                ,{field: 'index', title: '序号', width:70}
                ,{field: 'isClick', title: '是否可点击',
                    templet: function (d) {
                        if (d.isClick == '1') {
                            return '<span>是</span>'
                        } else if (d.isClick == '2') {
                            return '<span>否</span>'
                        }else{
                            return ''
                        }
                    }, minWidth: 80,align:'center'}
                ,{field: 'seq', title: '排序', edit:'text'}
                ,{templet: '#awardtableImgUpload', title: '详情图片', width:150}
                ,{templet: '#detailsEvent', title: '操作对应属性'}
                ,{field: 'linkType', title: '类型',
                    templet: function (d) {
                        if (d.linkType == '1') {
                            return '<span>链接</span>'
                        } else if (d.linkType == '2') {
                            return '<span>指定商品</span>'
                        }else if (d.linkType == '3') {
                            return '<span>优惠券</span>'
                        }else{
                            return ''
                        }
                    }, minWidth: 80,align:'center'}
            ]]
            ,data: []
        });
        table.on('toolbar(benefitsDetailsItem)', function(obj){
            var data = obj.data;
            var hasData = table.cache['benefitsDetailsItem'];
            var checkData = table.checkStatus('benefitsDetailsItem').data;
            if (checkData.length <= 0) {
                febs.alert.warn('请选择删除数据');
                return;
            }
            if(obj.event === 'delAct'){
                for (let i = 0; i < checkData.length; i++) {
                    var delData = checkData[i];
                    for (let j = 0; j < hasData.length; j++) {
                        if (hasData[j].index == delData.index) {
                            hasData.splice(j, 1);
                            break;
                        }
                    }
                }
                for (let i = 0; i < hasData.length; i++) {
                    hasData[i].index = i + 1;
                }
                tableBenefitsItemsData=hasData;
                reloadTable(hasData);
            }
        });
        function addTableDate(data) {
            var hasData = table.cache['benefitsDetailsItem'];
            data.index = hasData.length + 1;
            data.contentName = ''
            data.content = ''
            tableBenefitsItemsData.push(data);
            reloadTable(tableBenefitsItemsData);
            return data.index;
        }
        function reloadTable(data) {
            table.reload('benefitsDetailsItem', {
                data : data
            });
            for (let i = 0; i < data.length; i++) {
                if (data[i].image) {
                    $('#awardImageUrls'+ (i+1)).css('display','block');
                }
                // 重新绑定图片上传
                bindUpload(i+1);
                listenerLinkContent();
                listenerGoodsSelect();
                listenerCouponSelect();
            }
        }
        table.on('edit(benefitsDetailsItem)', function(obj){
            var value = obj.value //得到修改后的值
                ,data = obj.data //得到所在行所有键值
                ,field = obj.field; //得到字段
            for (let i = 0; i < tableBenefitsItemsData.length; i++) {
                if (tableBenefitsItemsData[i].index == data.index) {
                    tableBenefitsItemsData[i] = data;
                }
            }
        });
        function listenerLinkContent() {
            var hasData = table.cache['benefitsDetailsItem'];
            $(".linkContent").each(function(index, elem) {
                var dataIndex = $(this).attr('data-index');
                var $this = $(this);
                $(this).off('blur')
                $(this).on('blur', function() {
                    var data = $this.val();
                    hasData[dataIndex - 1].content = data;
                    tableBenefitsItemsData = hasData;
                })
            });
        }
        function listenerGoodsSelect() {
            var hasData = table.cache['benefitsDetailsItem'];
            $(".goodsSelect").each(function(index, elem) {
                var dataIndex = $(this).attr('data-index');
                $(this).off('click')
                $(this).on('click', function() {
                    febs.modal.open('选择商品', 'modules/vip/config/goodsSelect/' + dataIndex, {
                        btn: ['提交', '取消'],
                        yes: function (index, layero) {
                            $('#febs-select-goods').find('#goods-select-form-submit').trigger('click');
                            layer.close(index);
                        },
                        btn2: function () {
                        }
                    });
                })
            });
        }
        function listenerCouponSelect() {
            $(".couponSelect").each(function(index, elem) {
                var dataIndex = $(this).attr('data-index');
                $(this).off('click')
                $(this).on('click', function() {
                    febs.modal.open('选择优惠券', 'modules/vip/config/couponSelect/' + dataIndex, {
                        btn: ['提交', '取消'],
                        yes: function (index, layero) {
                            $('#vip-coupon-select').find('#submit').trigger('click');
                            layer.close(index);
                        },
                        btn2: function () {
                        }
                    });
                })
            });
        }
        $('#addBenefits').on('click', function (){
            var isClickVal = $("input[name='isClick']:checked").val();
            var linkTypeVal = $("select[name='linkType']").val();
            if(isClickVal == 1 && (linkTypeVal == null || linkTypeVal == "")) {
                febs.alert.warn('链接类型不能为空');
                return false;
            }
            var data = {};
            if (isClickVal == 1) {
                data.linkType = linkTypeVal;
            }
            data.isClick = isClickVal;
            addTableDate(data);
            if (linkTypeVal == 1) {
                listenerLinkContent();
            }
            if (linkTypeVal == 2) {
                listenerGoodsSelect();
            }
            if (linkTypeVal == 3) {
                listenerCouponSelect();
            }
        });
        function bindUpload(index) {
            // 普通图片上传
            upload.render({
                elem: '#awardImg' + index
                ,url: ctx + 'admin/goods/uploadFileBase64' //改成您自己的上传接口
                ,done: function(res){
                    febs.alert.success("上传成功");
                    $('#awardImageUrls' + index).attr('src', res.data.src);
                    $('#awardImageUrls'+ index).css('display','block');
                    $('#awardImage'+ index).val(res.data.src);
                    for (let i = 0; i < tableBenefitsItemsData.length; i++) {
                        if(tableBenefitsItemsData[i].index == index) {
                            tableBenefitsItemsData[i].image = res.data.src;
                        }
                    }
                    reloadTable(tableBenefitsItemsData);
                }
            });
        }
        form.on('radio(isClick)', function(data) {
            if (data.value == 2) {
                $('#linkTypeDiv').hide();
            } else {
                $('#linkTypeDiv').show();
            }
        });
        form.on('select(benefits-type-select)', function(data) {
            if (data.value == 1) {
                $('#scoreMultiple').show();
            } else {
                $('#scoreMultiple').hide();
            }
        });
        form.on('submit(vipBenefits-add-form-submit)', function (data) {
            data.field.details = tableBenefitsItemsData;
            $.ajax({
                'url':ctx + 'admin/vip/benefits/addOrEditBenefits',
                'type':'post',
                'dataType':'json',
                'headers' : {'Content-Type' : 'application/json;charset=utf-8'}, //接口json格式
                'traditional': true,//ajax传递数组必须添加属性
                'data':JSON.stringify(data.field),
                'success':function (data) {
                    if(data.code==200){
                        layer.closeAll();
                        febs.alert.success(data.message);
                        $('#febs-vip-benefits').find('#reset').click();
                    }else{
                        febs.alert.warn(data.message);
                    }
                },
                'error':function () {
                    febs.alert.warn('服务器繁忙');
                }
            })
            return false;
        });
        window.setGoodsSelect = function(tableIndex, data) {
            var hasData = table.cache['benefitsDetailsItem'];
            for(var i = 0; i<hasData.length; i++) {
                if (tableIndex == hasData[i].index) {
                    hasData[i].content = data.id;
                    hasData[i].contentName = data.goodsName
                }
            }
            tableBenefitsItemsData = hasData;
            $(".goodsSelect").each(function(index, elem) {
                var dataIndex = $(this).attr('data-index');
                if (dataIndex == tableIndex) {
                    $(this).val(data.goodsName);
                    $(this).next().val(data.id);
                }
            });
        }
        window.setCouponSelect = function(tableIndex, data) {
            var hasData = table.cache['benefitsDetailsItem'];
            for(var i = 0; i<hasData.length; i++) {
                if (tableIndex == hasData[i].index) {
                    hasData[i].content = data.couponId;
                    hasData[i].contentName = data.couponName
                }
            }
            tableBenefitsItemsData = hasData;
            console.log(tableBenefitsItemsData)
            $(".couponSelect").each(function(index, elem) {
                var dataIndex = $(this).attr('data-index');
                if (dataIndex == tableIndex) {
                    $(this).val(data.couponName);
                    $(this).next().val(data.couponId);
                }
            });
        }
    });
</script>
<script type="text/html" id="detailsEvent">
    {{# if(d.isClick == 1 && d.linkType == 1){ }}
    <input type="text" name="content" autocomplete="off" data-index="{{d.index}}" value="{{d.content}}" class="layui-input linkContent">
    {{# } }}
    {{# if( d.isClick == 1 && d.linkType == 2){ }}
    <input type="text" autocomplete="off" name="contentName" data-index="{{d.index}}" value="{{d.contentName}}" class="layui-input goodsSelect" readonly>
    <input type="text" name="content" autocomplete="off" value="{{d.content}}" class="layui-input goodsSelectId febs-hide" readonly>
    {{# }  }}
    {{# if(d.isClick == 1 && d.linkType == 3){ }}
    <input type="text" name="contentName" autocomplete="off" data-index="{{d.index}}" value="{{d.contentName}}" class="layui-input couponSelect" readonly>
    <input type="text" name="content" autocomplete="off" value="{{d.content}}" class="layui-input couponSelectId febs-hide" readonly>
    {{# } }}
</script>
src/main/resources/templates/febs/views/modules/vip/vipBenefits-edit.html
New file
@@ -0,0 +1,513 @@
<div class="layui-fluid layui-anim febs-anim" id="febs-vipBenefits-edit" lay-title="编辑会员权益">
    <div class="layui-row febs-container">
        <div class="layui-col-md12">
            <div class="layui-fluid" id="act-add">
                <form class="layui-form" action="" lay-filter="vipBenefits-edit-form">
                    <div class="layui-form-item febs-hide">
                        <label class="layui-form-label febs-form-item-require">id:</label>
                        <div class="layui-input-block">
                            <input type="text" name="id">
                        </div>
                    </div>
                    <div class="layui-tab-item layui-show">
                        <blockquote class="layui-elem-quote blue-border">基本信息设置</blockquote>
                        <div class="layui-row layui-col-space10 layui-form-item">
                            <div class="layui-col-lg6">
                                <label class="layui-form-label febs-form-item-require">权益名称:</label>
                                <div class="layui-input-block">
                                    <input type="text" name="name" lay-verify="required"
                                           placeholder="" autocomplete="off" class="layui-input">
                                </div>
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <div class="layui-col-lg6">
                                <label class="layui-form-label febs-form-item-require">权益生效类型</label>
                                <div class="layui-input-block">
                                    <select name="gainType" class="gain-type" lay-filter="gain-type-select">
                                        <option value="1">会员日</option>
                                        <option value="2">会员生日</option>
                                    </select>
                                </div>
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <div class="layui-col-lg6">
                                <label class="layui-form-label febs-form-item-require">权益类型</label>
                                <div class="layui-input-block">
                                    <select name="type" class="benefits-type" lay-filter="benefits-type-select">
                                        <option value="1">积分</option>
                                        <option value="2">其他</option>
                                    </select>
                                </div>
                            </div>
                            <div class="layui-col-lg6" id="scoreMultiple">
                                <label class="layui-form-label febs-form-item-require">积分倍数:</label>
                                <div class="layui-input-block">
                                    <input type="text" name="scoreMultiple" placeholder="" autocomplete="off" class="layui-input">
                                </div>
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <label class="layui-form-label febs-form-item-require">权益ICON</label>
                            <div class="layui-input-block">
                                <div class="layui-upload">
                                    <button type="button" class="layui-btn layui-btn-normal layui-btn" id="test2">上传</button>
                                    <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
                                        <div class="layui-upload-list">
                                            <img class="layui-upload-img" id="demo2" style="width: 100px" >
                                        </div>
                                    </blockquote>
                                </div>
                            </div>
                        </div>
                        <div class="layui-form-item febs-hide">
                            <label class="layui-form-label">缩略图链接:</label>
                            <div class="layui-input-block">
                                <input type="text" id="benefitsIcon" lay-verify="required" name="icon" autocomplete="off" class="layui-input" readonly>
                            </div>
                        </div>
                        <div class="layui-form-item">
                            <label class="layui-form-label">备注:</label>
                            <div class="layui-input-block">
                                <label>
                                    <textarea name="remark" rows="5" autocomplete="off" class="layui-textarea" ></textarea>
                                </label>
                            </div>
                        </div>
                        <blockquote class="layui-elem-quote blue-border">权益详情页面设置</blockquote>
                        <div class="layui-row layui-col-space10 layui-form-item">
                            <div class="layui-col-lg3">
                                <label class="layui-form-label">是否可点击</label>
                                <div class="layui-input-block">
                                    <input type="radio" name="isClick" value="1" title="是" lay-filter="isClick"/>
                                    <input type="radio" name="isClick" value="2" title="否" lay-filter="isClick" checked />
                                </div>
                            </div>
                            <div class="layui-col-lg3 febs-hide" id="linkTypeDiv">
                                <label class="layui-form-label febs-form-item-require">点击类型</label>
                                <div class="layui-input-block">
                                    <select name="linkType" class="linkType" lay-filter="link-type-select">
                                        <option value="">请选择</option>
                                        <option value="1">链接</option>
                                        <option value="2">领取商品</option>
                                        <option value="3">优惠券</option>
                                    </select>
                                </div>
                            </div>
                            <div class="layui-col-lg6">
                                <button type="button" class="layui-btn layui-btn-normal layui-btn" id="addBenefits" >添加</button>
                            </div>
                            <div class="layui-form-item">
                                <table id="benefitsDetailsItem" lay-filter="benefitsDetailsItem"></table>
                            </div>
                        </div>
                    </div>
                    <div class="layui-form-item febs-hide">
                        <button class="layui-btn" lay-submit="" lay-filter="vipBenefits-edit-form-submit" id="submit">保存</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>
<style>
    .blue-border {
        border-left-color: #2db7f5;
        font-size: 18px;
    }
    .layui-table-cell {
        height:auto;
    }
</style>
<script type="text/html" id="toolbar">
    <div class="layui-btn-container">
        <button class="layui-btn layui-btn-danger layui-btn-sm" type="button" lay-event="delAct">删除</button>
    </div>
</script>
<script type="text/html" id="awardtableImgUpload">
    <div class="layui-upload">
        <button type="button" class="layui-btn layui-btn-normal layui-btn-xs sku-img" id="awardImg{{d.index}}">上传</button></br>
        <img class="layui-upload-img" id="awardImageUrls{{d.index}}" style="width: 100px; display:none;" src="{{d.image}}" >
        <input type="text" id="awardImage{{d.index}}" name="awardImage{{d.index}}" autocomplete="off" value="{{d.image}}" class="layui-input febs-hide">
    </div>
</script>
<!-- 表格操作栏 end -->
<script data-th-inline="javascript">
    layui.use(['febs', 'form', 'formSelects', 'validate', 'treeSelect', 'eleTree','dropdown', 'laydate', 'layedit', 'upload', 'element', 'table', 'xmSelect'], function () {
        var $ = layui.jquery,
            febs = layui.febs,
            layer = layui.layer,
            table = layui.table,
            formSelects = layui.formSelects,
            treeSelect = layui.treeSelect,
            form = layui.form,
            laydate = layui.laydate,
            eleTree = layui.eleTree,
            $view = $('#febs-vip-benefits'),
            layedit = layui.layedit,
            upload = layui.upload,
            validate = layui.validate,
            benefitsData = [[${benefitsData}]],
            element = layui.element;
        var tableBenefitsItemsData=[];
        form.render();
        formSelects.render();
        //图片上传
        upload.render({
            elem: '#test2'
            ,url: ctx + 'admin/goods/uploadFileBase64' //改成您自己的上传接口
            ,done: function(res){
                $('#demo2').attr('src', res.data.src);
                $("#benefitsIcon").val(res.data.src);
            }
        });
        var tableIns = table.render({
            elem: '#benefitsDetailsItem'
            ,limit:999
            ,toolbar:"#toolbar"
            ,defaultToolbar:[]
            ,cols: [[ //表头
                {type: 'checkbox'}
                ,{field: 'index', title: '序号', width:70}
                ,{field: 'isClick', title: '是否可点击',
                    templet: function (d) {
                        if (d.isClick == '1') {
                            return '<span>是</span>'
                        } else if (d.isClick == '2') {
                            return '<span>否</span>'
                        }else{
                            return ''
                        }
                    }, minWidth: 80,align:'center'}
                ,{field: 'seq', title: '排序', edit:'text'}
                ,{templet: '#awardtableImgUpload', title: '详情图片', width:150}
                ,{templet: '#detailsEvent', title: '操作对应属性'}
                ,{field: 'linkType', title: '类型',
                    templet: function (d) {
                        if (d.linkType == '1') {
                            return '<span>链接</span>'
                        } else if (d.linkType == '2') {
                            return '<span>指定商品</span>'
                        }else if (d.linkType == '3') {
                            return '<span>优惠券</span>'
                        }else{
                            return ''
                        }
                    }, minWidth: 80,align:'center'}
            ]]
            ,data: []
        });
        table.on('toolbar(benefitsDetailsItem)', function(obj){
            var data = obj.data;
            var hasData = table.cache['benefitsDetailsItem'];
            var checkData = table.checkStatus('benefitsDetailsItem').data;
            if (checkData.length <= 0) {
                febs.alert.warn('请选择删除数据');
                return;
            }
            if(obj.event === 'delAct'){
                for (let i = 0; i < checkData.length; i++) {
                    var delData = checkData[i];
                    for (let j = 0; j < hasData.length; j++) {
                        if (hasData[j].index == delData.index) {
                            hasData.splice(j, 1);
                            break;
                        }
                    }
                }
                for (let i = 0; i < hasData.length; i++) {
                    hasData[i].index = i + 1;
                }
                tableBenefitsItemsData=hasData;
                reloadTable(hasData);
            }
        });
        function addTableDate(data) {
            var hasData = table.cache['benefitsDetailsItem'];
            data.index = hasData.length + 1;
            data.contentName = ''
            data.content = ''
            tableBenefitsItemsData.push(data);
            reloadTable(tableBenefitsItemsData);
            return data.index;
        }
        function reloadTable(data) {
            table.reload('benefitsDetailsItem', {
                data : data
            });
            for (let i = 0; i < data.length; i++) {
                if (data[i].image) {
                    $('#awardImageUrls'+ (i+1)).css('display','block');
                }
                // 重新绑定图片上传
                bindUpload(i+1);
                listenerLinkContent();
                listenerGoodsSelect();
                listenerCouponSelect();
            }
        }
        table.on('edit(benefitsDetailsItem)', function(obj){
            var value = obj.value //得到修改后的值
                ,data = obj.data //得到所在行所有键值
                ,field = obj.field; //得到字段
            for (let i = 0; i < tableBenefitsItemsData.length; i++) {
                if (tableBenefitsItemsData[i].index == data.index) {
                    tableBenefitsItemsData[i] = data;
                }
            }
        });
        function listenerLinkContent() {
            var hasData = table.cache['benefitsDetailsItem'];
            $(".linkContent").each(function(index, elem) {
                var dataIndex = $(this).attr('data-index');
                var $this = $(this);
                $(this).off('blur')
                $(this).on('blur', function() {
                    var data = $this.val();
                    hasData[dataIndex - 1].content = data;
                    tableBenefitsItemsData = hasData;
                })
            });
        }
        function listenerGoodsSelect() {
            var hasData = table.cache['benefitsDetailsItem'];
            $(".goodsSelect").each(function(index, elem) {
                var dataIndex = $(this).attr('data-index');
                $(this).off('click')
                $(this).on('click', function() {
                    febs.modal.open('选择商品', 'modules/vip/config/goodsSelect/' + dataIndex, {
                        btn: ['提交', '取消'],
                        yes: function (index, layero) {
                            $('#febs-select-goods').find('#goods-select-form-submit').trigger('click');
                            layer.close(index);
                        },
                        btn2: function () {
                        }
                    });
                })
            });
        }
        function listenerCouponSelect() {
            $(".couponSelect").each(function(index, elem) {
                var dataIndex = $(this).attr('data-index');
                $(this).off('click')
                $(this).on('click', function() {
                    febs.modal.open('选择优惠券', 'modules/vip/config/couponSelect/' + dataIndex, {
                        btn: ['提交', '取消'],
                        yes: function (index, layero) {
                            $('#vip-coupon-select').find('#submit').trigger('click');
                            layer.close(index);
                        },
                        btn2: function () {
                        }
                    });
                })
            });
        }
        $('#addBenefits').on('click', function (){
            var isClickVal = $("input[name='isClick']:checked").val();
            var linkTypeVal = $("select[name='linkType']").val();
            if(isClickVal == 1 && (linkTypeVal == null || linkTypeVal == "")) {
                febs.alert.warn('链接类型不能为空');
                return false;
            }
            var data = {};
            if (isClickVal == 1) {
                data.linkType = linkTypeVal;
            }
            data.isClick = isClickVal;
            addTableDate(data);
            if (linkTypeVal == 1) {
                listenerLinkContent();
            }
            if (linkTypeVal == 2) {
                listenerGoodsSelect();
            }
            if (linkTypeVal == 3) {
                listenerCouponSelect();
            }
        });
        function bindUpload(index) {
            // 普通图片上传
            upload.render({
                elem: '#awardImg' + index
                ,url: ctx + 'admin/goods/uploadFileBase64' //改成您自己的上传接口
                ,done: function(res){
                    febs.alert.success("上传成功");
                    $('#awardImageUrls' + index).attr('src', res.data.src);
                    $('#awardImageUrls'+ index).css('display','block');
                    $('#awardImage'+ index).val(res.data.src);
                    for (let i = 0; i < tableBenefitsItemsData.length; i++) {
                        if(tableBenefitsItemsData[i].index == index) {
                            tableBenefitsItemsData[i].image = res.data.src;
                        }
                    }
                    reloadTable(tableBenefitsItemsData);
                }
            });
        }
        form.on('radio(isClick)', function(data) {
            if (data.value == 2) {
                $('#linkTypeDiv').hide();
            } else {
                $('#linkTypeDiv').show();
            }
        });
        form.on('select(benefits-type-select)', function(data) {
            if (data.value == 1) {
                $('#scoreMultiple').show();
            } else {
                $('#scoreMultiple').hide();
            }
        });
        form.on('submit(vipBenefits-edit-form-submit)', function (data) {
            data.field.details = tableBenefitsItemsData;
            $.ajax({
                'url':ctx + 'admin/vip/benefits/addOrEditBenefits',
                'type':'post',
                'dataType':'json',
                'headers' : {'Content-Type' : 'application/json;charset=utf-8'}, //接口json格式
                'traditional': true,//ajax传递数组必须添加属性
                'data':JSON.stringify(data.field),
                'success':function (data) {
                    if(data.code==200){
                        layer.closeAll();
                        febs.alert.success(data.message);
                        $('#febs-vip-benefits').find('#reset').click();
                    }else{
                        febs.alert.warn(data.message);
                    }
                },
                'error':function () {
                    febs.alert.warn('服务器繁忙');
                }
            })
            return false;
        });
        window.setGoodsSelect = function(tableIndex, data) {
            var hasData = table.cache['benefitsDetailsItem'];
            for(var i = 0; i<hasData.length; i++) {
                if (tableIndex == hasData[i].index) {
                    hasData[i].content = data.id;
                    hasData[i].contentName = data.goodsName
                }
            }
            tableBenefitsItemsData = hasData;
            $(".goodsSelect").each(function(index, elem) {
                var dataIndex = $(this).attr('data-index');
                if (dataIndex == tableIndex) {
                    $(this).val(data.goodsName);
                    $(this).next().val(data.id);
                }
            });
        }
        window.setCouponSelect = function(tableIndex, data) {
            var hasData = table.cache['benefitsDetailsItem'];
            for(var i = 0; i<hasData.length; i++) {
                if (tableIndex == hasData[i].index) {
                    hasData[i].content = data.couponId;
                    hasData[i].contentName = data.couponName
                }
            }
            tableBenefitsItemsData = hasData;
            $(".couponSelect").each(function(index, elem) {
                var dataIndex = $(this).attr('data-index');
                if (dataIndex == tableIndex) {
                    $(this).val(data.couponName);
                    $(this).next().val(data.couponId);
                }
            });
        }
        initValue();
        function initValue() {
            form.val("vipBenefits-edit-form", {
                "id": benefitsData.id,
                "name": benefitsData.name,
                "gainType": benefitsData.gainType,
                "type": benefitsData.type,
                "scoreMultiple": benefitsData.scoreMultiple,
                "remark": benefitsData.remark,
                "icon":benefitsData.icon,
            });
            $('#demo2').attr('src', benefitsData.icon);
            var details = benefitsData.details;
            for(var i = 0; i < details.length; i++) {
                details[i].index = i + 1;
            }
            reloadTable(details);
            tableBenefitsItemsData = details;
        }
    });
</script>
<script type="text/html" id="detailsEvent">
    {{# if(d.isClick == 1 && d.linkType == 1){ }}
    <input type="text" name="content" autocomplete="off" data-index="{{d.index}}" value="{{d.content}}" class="layui-input linkContent">
    {{# } }}
    {{# if( d.isClick == 1 && d.linkType == 2){ }}
    <input type="text" autocomplete="off" name="contentName" data-index="{{d.index}}" value="{{d.contentName}}" class="layui-input goodsSelect" readonly>
    <input type="text" name="content" autocomplete="off" value="{{d.content}}" class="layui-input goodsSelectId febs-hide" readonly>
    {{# }  }}
    {{# if(d.isClick == 1 && d.linkType == 3){ }}
    <input type="text" name="contentName" autocomplete="off" data-index="{{d.index}}" value="{{d.contentName}}" class="layui-input couponSelect" readonly>
    <input type="text" name="content" autocomplete="off" value="{{d.content}}" class="layui-input couponSelectId febs-hide" readonly>
    {{# } }}
</script>
src/main/resources/templates/febs/views/modules/vip/vipBenefits-list.html
New file
@@ -0,0 +1,165 @@
<div class="layui-fluid layui-anim febs-anim" id="febs-vip-benefits" lay-title="会员权益">
    <div class="layui-row febs-container">
        <div class="layui-col-md12">
            <div class="layui-card">
                <div class="layui-card-body febs-table-full">
                    <form class="layui-form layui-table-form" lay-filter="vip-benefits-table-form">
                        <div class="layui-row">
                            <div class="layui-col-md2 layui-col-sm12 layui-col-xs12 table-action-area">
                                <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain table-action" id="add">
                                    新增
                                </div>
                                <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain table-action" id="query">
                                    <i class="layui-icon">&#xe848;</i>
                                </div>
                                <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain table-action" id="reset">
                                    <i class="layui-icon">&#xe79b;</i>
                                </div>
                            </div>
                        </div>
                    </form>
                    <table lay-filter="vipBenefitsTable" lay-data="{id: 'vipBenefitsTable'}"></table>
                </div>
            </div>
        </div>
    </div>
</div>
<style>
    .layui-table-cell {
        height: auto;
    }
    .layui-form-onswitch {
        background-color: #5FB878 !important;
    }
</style>
<!-- 表格操作栏 start -->
<script type="text/html" id="user-option">
    <span shiro:lacksPermission="vipBenefits:view,vipBenefits:update,vipBenefits:delete">
        <span class="layui-badge-dot febs-bg-orange"></span> 无权限
    </span>
    <a lay-event="edit" shiro:hasPermission="vipBenefits:update"><i
            class="layui-icon febs-edit-area febs-blue">&#xe7a5;</i></a>
</script>
<!-- 表格操作栏 end -->
<script data-th-inline="none" type="text/javascript">
    // 引入组件并初始化
    layui.use([ 'jquery', 'form', 'table', 'febs'], function () {
        var $ = layui.jquery,
            febs = layui.febs,
            form = layui.form,
            table = layui.table,
            $view = $('#febs-vip-benefits'),
            $query = $view.find('#query'),
            $add = $view.find('#add'),
            $reset = $view.find('#reset'),
            $searchForm = $view.find('form'),
            sortObject = {field: 'phone', type: null},
            tableIns;
        form.render();
        // 表格初始化
        initTable();
        // 初始化表格操作栏各个按钮功能
        table.on('tool(vipBenefitsTable)', function (obj) {
            var data = obj.data,
                layEvent = obj.event;
            if (layEvent === 'benefitsUpdate') {
                febs.modal.open('编辑', 'modules/vip/config/editBenefits/' + data.id, {
                    btn: ['提交', '取消'],
                    yes: function (index, layero) {
                        $('#febs-vipBenefits-edit').find('#submit').trigger('click');
                    },
                    btn2: function () {
                        layer.closeAll();
                    }
                });
            }
            if (layEvent === 'delBenefits') {
                febs.modal.confirm('删除', '确认删除?', function () {
                    delBenefits(data.id);
                });
            }
        });
        function delBenefits(id) {
            febs.get(ctx + 'admin/vip/benefits/delBenefits/' + id, null, function () {
                febs.alert.success('操作成功');
                $query.click();
            });
        }
        // 查询按钮
        $query.on('click', function () {
            var params = $.extend(getQueryParams(), {field: sortObject.field, order: sortObject.type});
            tableIns.reload({where: params, page: {curr: 1}});
        });
        // 刷新按钮
        $reset.on('click', function () {
            $searchForm[0].reset();
            sortObject.type = 'null';
            tableIns.reload({where: getQueryParams(), page: {curr: 1}, initSort: sortObject});
        });
        $add.on('click', function () {
            febs.modal.open('新增', 'modules/vip/config/vipBenefitsAdd/', {
                btn: ['提交', '取消'],
                yes: function (index, layero) {
                    $('#febs-vipBenefits-add').find('#submit').trigger('click');
                },
                btn2: function () {
                    layer.closeAll();
                }
            });
        });
        function initTable() {
            tableIns = febs.table.init({
                elem: $view.find('table'),
                id: 'vipBenefitsTable',
                url: ctx + 'admin/vip/benefits/list',
                cols: [[
                    {field: 'name', title: '权益名称', minWidth: 120, align: 'center'},
                    {
                        field: 'icon', title: 'ICON',
                        templet: function (d) {
                            return '<a lay-event="seeImgThumb"><img id="seeImgThumb'+d.id+'" src="'+d.icon+'" alt=""></a>';
                        }, minWidth: 150, align: 'center'
                    },
                    {field: 'remark', title: '备注', minWidth: 120, align: 'center'},
                    {field: 'createdTime', title: '创建时间', minWidth: 120, align: 'center'},
                    {
                        title: '操作',
                        templet: function (d) {
                            return '<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="benefitsUpdate" shiro:hasPermission="user:update">编辑</button>'
                                + '<button class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delBenefits" shiro:hasPermission="user:update">删除</button>'
                        }, minWidth: 300, align: 'center'
                    }
                ]]
            });
        }
        // 获取查询参数
        function getQueryParams() {
            return {
            };
        }
        form.on('switch(isTopSwitch)', function (data) {
            console.log(data.value);
            if (data.elem.checked) {
                febs.post(ctx + 'admin/news/topNews/' + data.value, null, function () {
                    febs.alert.success('设置成功');
                    $query.click();
                });
            } else {
                febs.post(ctx + 'admin/news/unTopNews/' + data.value, null, function () {
                    febs.alert.success('设置成功');
                    $query.click();
                });
            }
        })
    })
</script>
src/main/resources/templates/febs/views/modules/vip/vipConfig-add.html
New file
@@ -0,0 +1,256 @@
<style>
    #vipConfig-add {
        padding: 20px 25px 25px 0;
    }
    #vipConfig-add .layui-treeSelect .ztree li a, .ztree li span {
        margin: 0 0 2px 3px !important;
    }
    #vipConfig-add #data-permission-tree-block {
        border: 1px solid #eee;
        border-radius: 2px;
        padding: 3px 0;
    }
    #vipConfig-add .layui-treeSelect .ztree li span.button.switch {
        top: 1px;
        left: 3px;
    }
    #vipConfig-add img{
        max-width:100px
    }
</style>
<div class="layui-fluid" id="febs-vipConfig-add">
    <form class="layui-form" action="" lay-filter="vipConfig-add-form">
        <div class="layui-form-item">
            <div class="layui-col-lg6">
                <label class="layui-form-label febs-form-item-require">会员名称:</label>
                <div class="layui-input-block">
                    <input type="text" name="name" lay-verify="required" autocomplete="off" class="layui-input" >
                </div>
            </div>
            <div class="layui-col-lg6">
                <label class="layui-form-label febs-form-item-require">会员等级:</label>
                <div class="layui-input-block">
                    <input type="number" name="level" lay-verify="required" autocomplete="off" class="layui-input" >
                </div>
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-col-lg6">
                <label class="layui-form-label febs-form-item-require">会员编码:</label>
                <div class="layui-input-block">
                    <input type="text" name="code" lay-verify="required" autocomplete="off" class="layui-input" >
                </div>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">主图:</label>
            <div class="layui-input-block">
                <button type="button" class="layui-btn" id="imageUpload" style="background-color: #009688; margin-bottom: 2px">图片上传</button>
                <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
                    <div class=" layui-upload-list view-images" id="thumbImage">
                    </div>
                </blockquote>
                <div class="febs-hide">
                    <input type="text" id="thumb"  name="thumb" autocomplete="off" class="layui-input" readonly>
                </div>
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-col-lg4">
                <label class="layui-form-label febs-form-item-require">有效期:</label>
                <div class="layui-input-block">
                    <input type="number" name="validTime" lay-verify="required" autocomplete="off" class="layui-input" >
                </div>
            </div>
            <div class="layui-col-lg2">
                <select name="validType" class="valid-type" lay-filter="valid-type-select">
                    <option value="day">日</option>
                    <option value="month">月</option>
                    <option value="year">年</option>
                </select>
            </div>
        </div>
        <div id="layui-form-item">
            <div class="layui-col-lg6">
                <label class="layui-form-label febs-form-item-require">成为会员条件:</label>
                <div class="layui-input-block">
                    <select name="type" class="valid-type" lay-filter="type-select">
                        <option value="1">指定商品</option>
                        <option value="2">时间区间内消费金额</option>
                    </select>
                </div>
            </div>
            <div class="layui-col-lg6" id="targetGoods">
                <label class="layui-form-label febs-form-item-require">指定商品:</label>
                <div class="layui-input-block">
                    <input type="text" id="selectGoods" name="targetName" placeholder="点击选择商品" autocomplete="off" class="layui-input" >
                    <input type="text" id="selectGoodsId" name="targetId" placeholder="点击选择商品" autocomplete="off" class="layui-input febs-hide" >
                </div>
            </div>
            <div class="layui-col-lg6 febs-hide" id="targetShopping">
                <div class="layui-input-inline layui-col-lg2">
                    <input type="text" name="times" autocomplete="off" class="layui-input" >
                </div>
                <div class="layui-form-mid">月内,消费</div>
                <div class="layui-input-inline layui-col-lg2">
                    <input type="text" name="amount" autocomplete="off" class="layui-input" >
                </div>
                <div class="layui-form-mid">金额</div>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">选择会员权益:</label>
            <div class="layui-input-block">
<!--                <select name="benefitsIds" class="vip-benefits-list" id="vip-benefits-list">-->
<!--                </select>-->
                <div id="vip-benefits-list"></div>
            </div>
        </div>
        <div class="layui-form-item febs-hide">
            <button class="layui-btn" lay-submit="" lay-filter="vipConfig-add-form-submit" id="submit"></button>
        </div>
    </form>
</div>
<script data-th-inline="javascript">
    layui.use(['febs', 'form', 'formSelects', 'validate', 'treeSelect', 'eleTree','layedit', 'laydate', 'upload', 'xmSelect'], function () {
        var $ = layui.$,
            febs = layui.febs,
            layer = layui.layer,
            upload = layui.upload,
            formSelects = layui.formSelects,
            form = layui.form,
            laydate = layui.laydate,
            layedit = layui.layedit,
            $view = $('#vipConfig-add'),
            validate = layui.validate;
        var benefitsList = xmSelect.render({
            el: '#vip-benefits-list',
            prop: {
                name: 'name',
                value: 'id',
            },
            data: []
        })
        //(下拉框)
        $.get(ctx + 'admin/vip/benefits/findAllBenefits', function (data) {
            benefitsList.update({
                data : data.data,
                autoRow: true,
            });
        });
        form.render();
        formSelects.render();
        form.on('submit(vipConfig-add-form-submit)', function (data) {
            data.field.benefitsIds = benefitsList.getValue('valueStr');
            $.ajax({
                'url':ctx + 'admin/vip/config/addOrEdit',
                'type':'post',
                'dataType':'json',
                'headers' : {'Content-Type' : 'application/json;charset=utf-8'}, //接口json格式
                'traditional': true,//ajax传递数组必须添加属性
                'data':JSON.stringify(data.field),
                'success':function (data) {
                    if(data.code==200){
                        layer.closeAll();
                        febs.alert.success(data.message);
                        $('#febs-vip-level').find('#reset').click();
                    }else{
                        febs.alert.warn(data.message);
                    }
                },
                'error':function () {
                    febs.alert.warn('服务器繁忙');
                }
            })
            return false;
            return false;
        });
        form.on('select(type-select)', function(data) {
            if (data.value == 1) {
                $("#targetGoods").show();
                $("#targetShopping").hide();
            } else {
                $("#targetGoods").hide();
                $("#targetShopping").show();
            }
        })
        upload.render({
            elem: '#imageUpload'
            ,url: ctx + 'admin/goods/uploadFileBase64' //改成您自己的上传接口
            ,multiple: false
            ,before: function(obj){
                //预读本地文件示例,不支持ie8
                obj.preview(function(index, file, result){
                    $('#thumbImage').html('<img src="'+ result +'" alt="'+ file.name +'" class="layui-upload-img" style="width: 100px">')
                });
            }
            ,done: function(res){
                $("#thumb").val(res.data.src);
            }
        });
        bindUpload();
        function bindUpload() {
            upload.render({
                elem: '.upload'
                ,url: ctx + 'admin/goods/uploadFileBase64' //改成您自己的上传接口
                ,accept: 'file'
                ,before: function(obj){
                    layer.msg('上传中', {icon: 16, time: 0});
                }
                ,done: function(res){
                    var item = this.item;
                    //如果上传失败
                    if(res.code !== 0){
                        return layer.msg('上传失败');
                    }
                    // $(item).parent().prev().find('input').val(res.data[0]);
                    $("#videoUrl").val(res.data.src);
                    layer.msg('上传完毕', {icon: 1});
                }
                ,error: function(err){
                    return layer.msg('上传失败');
                }
            });
        }
        $("#selectGoods").on('click', function() {
            febs.modal.open('选择商品', 'modules/vip/config/goodsSelect/' + -1, {
                btn: ['提交', '取消'],
                yes: function (index, layero) {
                    $('#febs-select-goods').find('#goods-select-form-submit').trigger('click');
                    layer.close(index);
                },
                btn2: function () {
                }
            });
        })
        window.setConfigGoodsSelect = function(tableIndex, data) {
            $("#selectGoods").val(data.goodsName);
            $("#selectGoodsId").val(data.id);
        }
    });
</script>
src/main/resources/templates/febs/views/modules/vip/vipConfig-edit.html
New file
@@ -0,0 +1,291 @@
<style>
    #vipConfig-edit {
        padding: 20px 25px 25px 0;
    }
    #vipConfig-edit .layui-treeSelect .ztree li a, .ztree li span {
        margin: 0 0 2px 3px !important;
    }
    #vipConfig-edit #data-permission-tree-block {
        border: 1px solid #eee;
        border-radius: 2px;
        padding: 3px 0;
    }
    #vipConfig-edit .layui-treeSelect .ztree li span.button.switch {
        top: 1px;
        left: 3px;
    }
    #vipConfig-edit img{
        max-width:100px
    }
</style>
<div class="layui-fluid" id="febs-vipConfig-edit">
    <form class="layui-form" action="" lay-filter="vipConfig-edit-form">
        <div class="layui-form-item">
            <input type="text" name="id" lay-verify="required" autocomplete="off" class="layui-input febs-hide" >
            <div class="layui-col-lg6">
                <label class="layui-form-label febs-form-item-require">会员名称:</label>
                <div class="layui-input-block">
                    <input type="text" name="name" lay-verify="required" autocomplete="off" class="layui-input" >
                </div>
            </div>
            <div class="layui-col-lg6">
                <label class="layui-form-label febs-form-item-require">会员等级:</label>
                <div class="layui-input-block">
                    <input type="number" name="level" lay-verify="required" autocomplete="off" class="layui-input" >
                </div>
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-col-lg6">
                <label class="layui-form-label febs-form-item-require">会员编码:</label>
                <div class="layui-input-block">
                    <input type="text" name="code" lay-verify="required" autocomplete="off" class="layui-input" >
                </div>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">主图:</label>
            <div class="layui-input-block">
                <button type="button" class="layui-btn" id="imageUpload" style="background-color: #009688; margin-bottom: 2px">图片上传</button>
                <blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
                    <div class=" layui-upload-list view-images" id="thumbImage">
                    </div>
                </blockquote>
                <div class="febs-hide">
                    <input type="text" id="thumb"  name="thumb" autocomplete="off" class="layui-input" readonly>
                </div>
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-col-lg4">
                <label class="layui-form-label febs-form-item-require">有效期:</label>
                <div class="layui-input-block">
                    <input type="number" name="validTime" lay-verify="required" autocomplete="off" class="layui-input" >
                </div>
            </div>
            <div class="layui-col-lg2">
                <select name="validType" class="valid-type" lay-filter="valid-type-select">
                    <option value="day">日</option>
                    <option value="month">月</option>
                    <option value="year">年</option>
                </select>
            </div>
        </div>
        <div id="layui-form-item">
            <div class="layui-col-lg6">
                <label class="layui-form-label febs-form-item-require">成为会员条件:</label>
                <div class="layui-input-block">
                    <select name="type" class="valid-type" lay-filter="type-select">
                        <option value="1">指定商品</option>
                        <option value="2">时间区间内消费金额</option>
                    </select>
                </div>
            </div>
            <div class="layui-col-lg6" id="targetGoods">
                <label class="layui-form-label febs-form-item-require">指定商品:</label>
                <div class="layui-input-block">
                    <input type="text" id="selectGoods" name="targetName" placeholder="点击选择商品" autocomplete="off" class="layui-input" >
                    <input type="text" id="selectGoodsId" name="targetId" placeholder="点击选择商品" autocomplete="off" class="layui-input febs-hide" >
                </div>
            </div>
            <div class="layui-col-lg6 febs-hide" id="targetShopping">
                <div class="layui-input-inline layui-col-lg2">
                    <input type="text" name="times" autocomplete="off" class="layui-input" >
                </div>
                <div class="layui-form-mid">月内,消费</div>
                <div class="layui-input-inline layui-col-lg2">
                    <input type="text" name="amount" autocomplete="off" class="layui-input" >
                </div>
                <div class="layui-form-mid">金额</div>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label febs-form-item-require">选择会员权益:</label>
            <div class="layui-input-block">
<!--                <select name="benefitsIds" class="vip-benefits-list" id="vip-benefits-list">-->
<!--                </select>-->
                <div id="vip-benefits-list"></div>
            </div>
        </div>
        <div class="layui-form-item febs-hide">
            <button class="layui-btn" lay-submit="" lay-filter="vipConfig-edit-form-submit" id="submit"></button>
        </div>
    </form>
</div>
<script data-th-inline="javascript">
    layui.use(['febs', 'form', 'formSelects', 'validate', 'treeSelect', 'eleTree','layedit', 'laydate', 'upload', 'xmSelect'], function () {
        var $ = layui.$,
            febs = layui.febs,
            layer = layui.layer,
            upload = layui.upload,
            formSelects = layui.formSelects,
            form = layui.form,
            laydate = layui.laydate,
            layedit = layui.layedit,
            vipConfigData = [[${configData}]]
            $view = $('#vipConfig-edit'),
            validate = layui.validate;
        var benefitsList = xmSelect.render({
            el: '#vip-benefits-list',
            prop: {
                name: 'name',
                value: 'id',
            },
            data: []
        })
        //(下拉框)
        $.get(ctx + 'admin/vip/benefits/findAllBenefits', function (data) {
            benefitsList.update({
                data : data.data,
                autoRow: true,
            });
            initValue();
        });
        form.render();
        formSelects.render();
        form.on('submit(vipConfig-edit-form-submit)', function (data) {
            data.field.benefitsIds = benefitsList.getValue('valueStr');
            $.ajax({
                'url':ctx + 'admin/vip/config/addOrEdit',
                'type':'post',
                'dataType':'json',
                'headers' : {'Content-Type' : 'application/json;charset=utf-8'}, //接口json格式
                'traditional': true,//ajax传递数组必须添加属性
                'data':JSON.stringify(data.field),
                'success':function (data) {
                    if(data.code==200){
                        layer.closeAll();
                        febs.alert.success(data.message);
                        $('#febs-vip-level').find('#reset').click();
                    }else{
                        febs.alert.warn(data.message);
                    }
                },
                'error':function () {
                    febs.alert.warn('服务器繁忙');
                }
            })
            return false;
        });
        form.on('select(type-select)', function(data) {
            if (data.value == 1) {
                $("#targetGoods").show();
                $("#targetShopping").hide();
            } else {
                $("#targetGoods").hide();
                $("#targetShopping").show();
            }
        })
        upload.render({
            elem: '#imageUpload'
            ,url: ctx + 'admin/goods/uploadFileBase64' //改成您自己的上传接口
            ,multiple: false
            ,before: function(obj){
                //预读本地文件示例,不支持ie8
                obj.preview(function(index, file, result){
                    $('#thumbImage').html('<img src="'+ result +'" alt="'+ file.name +'" class="layui-upload-img" style="width: 100px">')
                });
            }
            ,done: function(res){
                $("#thumb").val(res.data.src);
            }
        });
        bindUpload();
        function bindUpload() {
            upload.render({
                elem: '.upload'
                ,url: ctx + 'admin/goods/uploadFileBase64' //改成您自己的上传接口
                ,accept: 'file'
                ,before: function(obj){
                    layer.msg('上传中', {icon: 16, time: 0});
                }
                ,done: function(res){
                    var item = this.item;
                    //如果上传失败
                    if(res.code !== 0){
                        return layer.msg('上传失败');
                    }
                    // $(item).parent().prev().find('input').val(res.data[0]);
                    $("#videoUrl").val(res.data.src);
                    layer.msg('上传完毕', {icon: 1});
                }
                ,error: function(err){
                    return layer.msg('上传失败');
                }
            });
        }
        $("#selectGoods").on('click', function() {
            febs.modal.open('选择商品', 'modules/vip/config/goodsSelect/' + -1, {
                btn: ['提交', '取消'],
                yes: function (index, layero) {
                    $('#febs-select-goods').find('#goods-select-form-submit').trigger('click');
                    layer.close(index);
                },
                btn2: function () {
                }
            });
        })
        window.setConfigGoodsSelect = function(tableIndex, data) {
            $("#selectGoods").val(data.goodsName);
            $("#selectGoodsId").val(data.id);
        }
        function initValue() {
            form.val("vipConfig-edit-form", {
                "id": vipConfigData.id,
                "name": vipConfigData.name,
                "level": vipConfigData.level,
                "type" : vipConfigData.type,
                "validTime": vipConfigData.validTime,
                "validType": vipConfigData.validType,
                "targetName":vipConfigData.targetName,
                "targetId":vipConfigData.targetId,
                "times" : vipConfigData.times,
                "amount" : vipConfigData.amount,
                "code" : vipConfigData.code,
            });
            $('#thumbImage').html('<img src="'+ vipConfigData.thumb +'" class="layui-upload-img" style="width: 100px">')
            $("#thumb").val(vipConfigData.thumb);
            if (vipConfigData.type == 1) {
                $("#targetGoods").show();
                $("#targetShopping").hide();
            } else {
                $("#targetGoods").hide();
                $("#targetShopping").show();
            }
            var arr = []
            arr.push(vipConfigData.benefitsIdList)
            console.log(vipConfigData.benefitsIdList)
            benefitsList.setValue(vipConfigData.benefitsIdList);
        }
    });
</script>
src/main/resources/templates/febs/views/modules/vip/vipConfig-list.html
New file
@@ -0,0 +1,171 @@
<div class="layui-fluid layui-anim febs-anim" id="febs-vip-level" lay-title="会员权益">
    <div class="layui-row febs-container">
        <div class="layui-col-md12">
            <div class="layui-card">
                <div class="layui-card-body febs-table-full">
                    <form class="layui-form layui-table-form" lay-filter="vip-benefits-level-table-form">
                        <div class="layui-row">
                            <div class="layui-col-md2 layui-col-sm12 layui-col-xs12 table-action-area">
                                <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain table-action" id="add">
                                    新增
                                </div>
                                <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain table-action" id="query">
                                    <i class="layui-icon">&#xe848;</i>
                                </div>
                                <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain table-action" id="reset">
                                    <i class="layui-icon">&#xe79b;</i>
                                </div>
                            </div>
                        </div>
                    </form>
                    <table lay-filter="vipBenefitsLevelTable" lay-data="{id: 'vipBenefitsLevelTable'}"></table>
                </div>
            </div>
        </div>
    </div>
</div>
<style>
    .layui-table-cell {
        height: auto;
    }
    .layui-form-onswitch {
        background-color: #5FB878 !important;
    }
</style>
<!-- 表格操作栏 start -->
<script type="text/html" id="user-option">
    <span shiro:lacksPermission="vipConfig:view,vipConfig:update,vipConfig:delete">
        <span class="layui-badge-dot febs-bg-orange"></span> 无权限
    </span>
    <a lay-event="edit" shiro:hasPermission="vipConfig:update"><i
            class="layui-icon febs-edit-area febs-blue">&#xe7a5;</i></a>
</script>
<script type="text/html" id="validTypeFormat">
    {{# if(d.validType == "day") { }}
    <span>日</span>
    {{# } else if(d.validType == "month") { }}
    <span>月</span>
    {{# } else { }}
    <span>年</span>
    {{# } }}
</script>
<script type="text/html" id="typeFormat">
    {{# if(d.validType == "day") { }}
    <span>指定商品</span>
    {{# } else { }}
    <span>周期内消费指定金额</span>
    {{# } }}
</script>
<!-- 表格操作栏 end -->
<script data-th-inline="none" type="text/javascript">
    // 引入组件并初始化
    layui.use([ 'jquery', 'form', 'table', 'febs'], function () {
        var $ = layui.jquery,
            febs = layui.febs,
            form = layui.form,
            table = layui.table,
            $view = $('#febs-vip-level'),
            $query = $view.find('#query'),
            $add = $view.find('#add'),
            $reset = $view.find('#reset'),
            $searchForm = $view.find('form'),
            sortObject = {field: 'phone', type: null},
            tableIns;
        form.render();
        // 表格初始化
        initTable();
        // 初始化表格操作栏各个按钮功能
        table.on('tool(vipBenefitsLevelTable)', function (obj) {
            var data = obj.data,
                layEvent = obj.event;
            if (layEvent === 'benefitsUpdate') {
                febs.modal.open('编辑', 'modules/vip/config/levelEdit/' + data.id, {
                    btn: ['提交', '取消'],
                    yes: function (index, layero) {
                        $('#febs-vipConfig-edit').find('#submit').trigger('click');
                    },
                    btn2: function () {
                        layer.closeAll();
                    }
                });
            }
            if (layEvent === 'delVipConfig') {
                febs.modal.confirm('删除', '确认删除?', function () {
                    delVipConfig(data.id);
                });
            }
        });
        function delVipConfig(id) {
            febs.get(ctx + 'admin/vip/config/del/' + id, null, function () {
                febs.alert.success('操作成功');
                $query.click();
            });
        }
        // 查询按钮
        $query.on('click', function () {
            var params = $.extend(getQueryParams(), {field: sortObject.field, order: sortObject.type});
            tableIns.reload({where: params, page: {curr: 1}});
        });
        // 刷新按钮
        $reset.on('click', function () {
            $searchForm[0].reset();
            sortObject.type = 'null';
            tableIns.reload({where: getQueryParams(), page: {curr: 1}, initSort: sortObject});
        });
        $add.on('click', function () {
            febs.modal.open('新增', 'modules/vip/config/levelAdd/', {
                btn: ['提交', '取消'],
                yes: function (index, layero) {
                    $('#febs-vipConfig-add').find('#submit').trigger('click');
                },
                btn2: function () {
                    layer.closeAll();
                }
            });
        });
        function initTable() {
            tableIns = febs.table.init({
                elem: $view.find('table'),
                id: 'vipBenefitsLevelTable',
                url: ctx + 'admin/vip/config/list',
                cols: [[
                    {field: 'name', title: '会员名称', minWidth: 120, align: 'center'},
                    {
                        field: 'thumb', title: '主图',
                        templet: function (d) {
                            return '<a lay-event="seeImgThumb"><img id="seeImgThumb'+d.id+'" src="'+d.thumb+'" alt=""></a>';
                        }, minWidth: 150, align: 'center'
                    },
                    {field: 'level', title: '等级', minWidth: 120, align: 'center'},
                    {field: 'validTime', title: '有效时长', minWidth: 120, align: 'center'},
                    {templet:"#validTypeFormat",title: '有效类型', minWidth: 120, align: 'center'},
                    {templet:"#typeFormat", title: '成为会员条件', minWidth: 120, align: 'center'},
                    {
                        title: '操作',
                        templet: function (d) {
                            return '<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="benefitsUpdate" shiro:hasPermission="user:update">编辑</button>'
                                + '<button class="layui-btn layui-btn-danger layui-btn-xs" lay-event="delVipConfig" shiro:hasPermission="user:update">删除</button>'
                        }, minWidth: 300, align: 'center'
                    }
                ]]
            });
        }
        // 获取查询参数
        function getQueryParams() {
            return {
            };
        }
    })
</script>
src/test/java/cc/mrbird/febs/ProfitTest.java
@@ -967,4 +967,10 @@
        BigDecimal amount = new BigDecimal("0.15").setScale(2,BigDecimal.ROUND_DOWN);
        System.out.println(amount);
    }
    @Test
    public void aaaTest() {
//        agentConsumer.vipLevelUp(133L);
        agentConsumer.getScoreMsg(152L);
    }
}