记得上下班打卡 | git大法好,push需谨慎

Commit c5e013ba authored by 姜秀龙's avatar 姜秀龙

Merge branch 'jxl-vip' into test

parents a65625e5 e9c4b455
...@@ -7,6 +7,7 @@ import lombok.Data; ...@@ -7,6 +7,7 @@ import lombok.Data;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal;
@ApiModel(value = "AdamMemberBuildParam", description = "编辑会员入参") @ApiModel(value = "AdamMemberBuildParam", description = "编辑会员入参")
@Data @Data
...@@ -39,6 +40,8 @@ public class AdamMemberBuildParam implements Serializable { ...@@ -39,6 +40,8 @@ public class AdamMemberBuildParam implements Serializable {
@ApiModelProperty(required = true, value = "是否开售:1-开售|2-停售") @ApiModelProperty(required = true, value = "是否开售:1-开售|2-停售")
@NotNull(message = "是否开售不能为空") @NotNull(message = "是否开售不能为空")
private Integer onsale; private Integer onsale;
@ApiModelProperty(required = false, value = "双倍积分[1-关闭,2-开启]")
private BigDecimal integralRate;
@ApiModelProperty(required = false, value = "限购数量,0不限购[200]", example = "0") @ApiModelProperty(required = false, value = "限购数量,0不限购[200]", example = "0")
private Integer limitation; private Integer limitation;
@ApiModelProperty(required = false, value = "限购开始时间[yyyy-MM-dd]") @ApiModelProperty(required = false, value = "限购开始时间[yyyy-MM-dd]")
......
...@@ -31,6 +31,10 @@ public class AdamMemberPriceBuildParam implements Serializable { ...@@ -31,6 +31,10 @@ public class AdamMemberPriceBuildParam implements Serializable {
@ApiModelProperty(required = true, value = "有效天数") @ApiModelProperty(required = true, value = "有效天数")
@Min(value = 1, message = "有效天数不得小于1") @Min(value = 1, message = "有效天数不得小于1")
private Integer days; private Integer days;
@ApiModelProperty(required = false, value = "价格包名称")
private String name;
@ApiModelProperty(required = false, value = "价格状态[0-不可用|1-上线中|2-已下线],删除传2")
private Integer state;
@ApiModelProperty(required = false, value = "双倍积分[1-关闭,2-开启]") @ApiModelProperty(required = false, value = "双倍积分[1-关闭,2-开启]")
private BigDecimal integralRate; private BigDecimal integralRate;
......
...@@ -36,4 +36,6 @@ public class AdamMemberRightsBuildParam implements Serializable { ...@@ -36,4 +36,6 @@ public class AdamMemberRightsBuildParam implements Serializable {
private String detail; private String detail;
@ApiModelProperty(required = false, value = "展示顺序") @ApiModelProperty(required = false, value = "展示顺序")
private Integer seqNo; private Integer seqNo;
@ApiModelProperty(required = false, value = "绑定价格包ID,空表示全档回退共用")
private String memberPriceId;
} }
package com.liquidnet.service.adam.dto.vo; package com.liquidnet.service.adam.dto.vo;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.service.adam.entity.AdamAddresses;
import com.liquidnet.service.adam.entity.AdamMemberPrice; import com.liquidnet.service.adam.entity.AdamMemberPrice;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
...@@ -10,18 +8,17 @@ import lombok.Data; ...@@ -10,18 +8,17 @@ import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.util.List;
@ApiModel(value = "AdamMemberPriceVo", description = "会员价格") @ApiModel(value = "AdamMemberPriceVo", description = "会员价格")
@Data @Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class AdamMemberPriceVo implements Serializable { public class AdamMemberPriceVo implements Serializable {
private static final long serialVersionUID = -8106910166417645208L; private static final long serialVersionUID = -8106910166417645208L;
@ApiModelProperty(position = 1, value = "会员价格ID") @ApiModelProperty(position = 1, value = "会员价格ID")
private String memberPriceId; private String memberPriceId;
@ApiModelProperty(position = 2, value = "会员类型ID") @ApiModelProperty(position = 2, value = "会员类型ID")
private String memberId; private String memberId;
// @ApiModelProperty(position = 3, value = "价格状态[0-不可用,1-上线中,2-已下线]")
// private Integer state;
@ApiModelProperty(position = 4, value = "价格包名称") @ApiModelProperty(position = 4, value = "价格包名称")
private String name; private String name;
@ApiModelProperty(position = 5, value = "原价") @ApiModelProperty(position = 5, value = "原价")
...@@ -32,12 +29,8 @@ public class AdamMemberPriceVo implements Serializable { ...@@ -32,12 +29,8 @@ public class AdamMemberPriceVo implements Serializable {
private BigDecimal priceSpecial; private BigDecimal priceSpecial;
@ApiModelProperty(position = 8, value = "有效天数") @ApiModelProperty(position = 8, value = "有效天数")
private Integer days; private Integer days;
// @ApiModelProperty(position = 8, value = "会员包须知") @ApiModelProperty(position = 9, value = "本价格包权益")
// private String detail; private List<AdamMemberRightsVo> rightsVoList;
// @JsonFormat(shape=JsonFormat.Shape.STRING, pattern= DateUtil.DATE_FULL_STR)
// private LocalDateTime createdAt;
// @JsonFormat(shape=JsonFormat.Shape.STRING, pattern= DateUtil.DATE_FULL_STR)
// private LocalDateTime updatedAt;
private static final AdamMemberPriceVo obj = new AdamMemberPriceVo(); private static final AdamMemberPriceVo obj = new AdamMemberPriceVo();
...@@ -53,15 +46,11 @@ public class AdamMemberPriceVo implements Serializable { ...@@ -53,15 +46,11 @@ public class AdamMemberPriceVo implements Serializable {
if (null == source) return this; if (null == source) return this;
this.setMemberPriceId(source.getMemberPriceId()); this.setMemberPriceId(source.getMemberPriceId());
this.setMemberId(source.getMemberId()); this.setMemberId(source.getMemberId());
// this.setState(source.getState());
this.setName(source.getName()); this.setName(source.getName());
this.setPrice(source.getPrice()); this.setPrice(source.getPrice());
this.setPriceFixed(source.getPriceFixed()); this.setPriceFixed(source.getPriceFixed());
this.setPriceSpecial(source.getPriceSpecial()); this.setPriceSpecial(source.getPriceSpecial());
this.setDays(source.getDays()); this.setDays(source.getDays());
// this.setDetail(source.getDetail());
// this.setCreatedAt(source.getCreatedAt());
// this.setUpdatedAt(source.getUpdatedAt());
return this; return this;
} }
} }
...@@ -25,6 +25,8 @@ public class AdamMemberRightsVo implements java.io.Serializable, Cloneable { ...@@ -25,6 +25,8 @@ public class AdamMemberRightsVo implements java.io.Serializable, Cloneable {
private String cover; private String cover;
@ApiModelProperty(position = 7, value = "详情内容") @ApiModelProperty(position = 7, value = "详情内容")
private String detail; private String detail;
@ApiModelProperty(position = 8, value = "绑定价格包ID,空表示全档回退共用")
private String memberPriceId;
public AdamMemberRightsVo setSeqNo(Integer seqNo) { public AdamMemberRightsVo setSeqNo(Integer seqNo) {
this.seqNo = seqNo; this.seqNo = seqNo;
...@@ -60,6 +62,7 @@ public class AdamMemberRightsVo implements java.io.Serializable, Cloneable { ...@@ -60,6 +62,7 @@ public class AdamMemberRightsVo implements java.io.Serializable, Cloneable {
this.setLabel(source.getLabel()); this.setLabel(source.getLabel());
this.setCover(source.getCover()); this.setCover(source.getCover());
this.setDetail(source.getDetail()); this.setDetail(source.getDetail());
this.setMemberPriceId(source.getMemberPriceId());
return this; return this;
} }
} }
...@@ -62,10 +62,8 @@ public class AdamMemberVo implements java.io.Serializable, Cloneable { ...@@ -62,10 +62,8 @@ public class AdamMemberVo implements java.io.Serializable, Cloneable {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateUtil.DATE_FULL_STR) @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateUtil.DATE_FULL_STR)
private LocalDateTime limiteAt; private LocalDateTime limiteAt;
@ApiModelProperty(position = 20, value = "会员卡价格信息") @ApiModelProperty(position = 20, value = "会员卡价格信息(含各档 rightsVoList)")
private List<AdamMemberPriceVo> priceVoList; private List<AdamMemberPriceVo> priceVoList;
@ApiModelProperty(position = 21, value = "会员专属权益")
private List<AdamMemberRightsVo> rightsVoList;
@ApiModelProperty(position = 22, value = "用户会员信息") @ApiModelProperty(position = 22, value = "用户会员信息")
private AdamUserMemberVo userMemberVo; private AdamUserMemberVo userMemberVo;
@ApiModelProperty(position = 23, value = "购买会员限购[0-名额已满|1-允许购买|2-限购未开始]") @ApiModelProperty(position = 23, value = "购买会员限购[0-名额已满|1-允许购买|2-限购未开始]")
......
package com.liquidnet.service.adam.dto.vo.admin;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 会员订单详情-优先券使用情况
*/
@Data
public class AdamMemberPriorityCouponAdminVo implements Serializable {
private static final long serialVersionUID = 1L;
private String ucouponId;
private String name;
private String mobile;
/** 专享标识文案 */
private String exclusiveLabel;
private Integer exclusive;
/** 用户券状态文案 */
private String stateLabel;
private Integer state;
private String title;
/** 券类型文案 */
private String couTypeLabel;
private Integer couType;
private LocalDateTime bindAt;
private LocalDateTime duedAt;
private LocalDateTime usedAt;
}
...@@ -7,6 +7,8 @@ import com.liquidnet.service.adam.dto.vo.AdamUserMemberVo; ...@@ -7,6 +7,8 @@ import com.liquidnet.service.adam.dto.vo.AdamUserMemberVo;
import com.liquidnet.service.adam.entity.AdamUser; import com.liquidnet.service.adam.entity.AdamUser;
import lombok.Data; import lombok.Data;
import java.util.List;
/** /**
* @author AnJiabin <anjiabin@zhengzai.tv> * @author AnJiabin <anjiabin@zhengzai.tv>
* @version V1.0 * @version V1.0
...@@ -23,4 +25,6 @@ public class MemberOrderDetailAdminVo { ...@@ -23,4 +25,6 @@ public class MemberOrderDetailAdminVo {
private AdamUserInfoVo adamUserInfoVo; private AdamUserInfoVo adamUserInfoVo;
private AdamUserMemberVo adamUserMemberVo; private AdamUserMemberVo adamUserMemberVo;
private AdamMemberOrderExtVo adamMemberOrderExtVo; private AdamMemberOrderExtVo adamMemberOrderExtVo;
/** 该用户优先券(cou_type=101)使用情况 */
private List<AdamMemberPriorityCouponAdminVo> priorityCouponList;
} }
...@@ -35,6 +35,8 @@ import org.springframework.validation.annotation.Validated; ...@@ -35,6 +35,8 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -102,6 +104,10 @@ public class AdamMemberAdminController extends BaseController { ...@@ -102,6 +104,10 @@ public class AdamMemberAdminController extends BaseController {
) )
); );
mmap.put("member", member); mmap.put("member", member);
mmap.put("memberPriceList", java.util.Collections.emptyList());
mmap.put("memberRightsList", java.util.Collections.emptyList());
mmap.put("couponMemberDtoListMap", java.util.Collections.emptyMap());
mmap.put("memberPrice", null);
if (null != member) { if (null != member) {
List<AdamMemberRights> memberRightsList = adamMemberRightsAdminService.list(Wrappers.lambdaQuery(AdamMemberRights.class) List<AdamMemberRights> memberRightsList = adamMemberRightsAdminService.list(Wrappers.lambdaQuery(AdamMemberRights.class)
...@@ -109,6 +115,8 @@ public class AdamMemberAdminController extends BaseController { ...@@ -109,6 +115,8 @@ public class AdamMemberAdminController extends BaseController {
.eq(AdamMemberRights::getMemberId, member.getMemberId()) .eq(AdamMemberRights::getMemberId, member.getMemberId())
.select( .select(
AdamMemberRights::getMrightsId, AdamMemberRights::getMrightsId,
AdamMemberRights::getMemberId,
AdamMemberRights::getMemberPriceId,
AdamMemberRights::getCover, AdamMemberRights::getCover,
AdamMemberRights::getTitle, AdamMemberRights::getTitle,
AdamMemberRights::getSubTitle, AdamMemberRights::getSubTitle,
...@@ -116,6 +124,7 @@ public class AdamMemberAdminController extends BaseController { ...@@ -116,6 +124,7 @@ public class AdamMemberAdminController extends BaseController {
) )
); );
mmap.put("memberRightsList", memberRightsList); mmap.put("memberRightsList", memberRightsList);
mmap.put("couponMemberDtoListMap", java.util.Collections.emptyMap());
if (!CollectionUtils.isEmpty(memberRightsList)) { if (!CollectionUtils.isEmpty(memberRightsList)) {
List<String> mrightsIdList = memberRightsList.stream().map(AdamMemberRights::getMrightsId).collect(Collectors.toList()); List<String> mrightsIdList = memberRightsList.stream().map(AdamMemberRights::getMrightsId).collect(Collectors.toList());
...@@ -127,17 +136,28 @@ public class AdamMemberAdminController extends BaseController { ...@@ -127,17 +136,28 @@ public class AdamMemberAdminController extends BaseController {
mmap.put("couponMemberDtoListMap", couponMemberDtoListMap); mmap.put("couponMemberDtoListMap", couponMemberDtoListMap);
} }
AdamMemberPrice memberPrice = adamMemberPriceAdminService.getOne(Wrappers.lambdaQuery(AdamMemberPrice.class) List<AdamMemberPrice> memberPriceList = adamMemberPriceAdminService.list(Wrappers.lambdaQuery(AdamMemberPrice.class)
.eq(AdamMemberPrice::getState, 1) .in(AdamMemberPrice::getState, Arrays.asList(1, 2))
.eq(AdamMemberPrice::getMemberId, member.getMemberId()) .eq(AdamMemberPrice::getMemberId, member.getMemberId())
.orderByAsc(AdamMemberPrice::getState)
.orderByAsc(AdamMemberPrice::getDays)
.select( .select(
AdamMemberPrice::getMemberPriceId, AdamMemberPrice::getMemberPriceId,
AdamMemberPrice::getMemberId,
AdamMemberPrice::getName,
AdamMemberPrice::getPrice, AdamMemberPrice::getPrice,
AdamMemberPrice::getPriceFixed, AdamMemberPrice::getPriceFixed,
AdamMemberPrice::getPriceSpecial, AdamMemberPrice::getPriceSpecial,
AdamMemberPrice::getDays AdamMemberPrice::getDays,
AdamMemberPrice::getState
) )
); );
mmap.put("memberPriceList", memberPriceList);
AdamMemberPrice memberPrice = CollectionUtils.isEmpty(memberPriceList) ? null
: memberPriceList.stream()
.filter(p -> p.getState() != null && p.getState() == 1)
.max(Comparator.comparing(AdamMemberPrice::getDays, Comparator.nullsFirst(Integer::compareTo)))
.orElse(null);
mmap.put("memberPrice", memberPrice); mmap.put("memberPrice", memberPrice);
} }
mmap.put("platformUrl", platformUrl); mmap.put("platformUrl", platformUrl);
...@@ -167,7 +187,7 @@ public class AdamMemberAdminController extends BaseController { ...@@ -167,7 +187,7 @@ public class AdamMemberAdminController extends BaseController {
@PostMapping("edit_price") @PostMapping("edit_price")
@ResponseBody @ResponseBody
public AjaxResult editPrice(@Validated AdamMemberPriceBuildParam parameter) { public AjaxResult editPrice(@Validated AdamMemberPriceBuildParam parameter) {
return this.toAjax(adamMemberPriceAdminService.edit(parameter)); return AjaxResult.success(adamMemberPriceAdminService.edit(parameter));
} }
@ApiOperation(value = "会员套餐:权益编辑") @ApiOperation(value = "会员套餐:权益编辑")
...@@ -179,13 +199,27 @@ public class AdamMemberAdminController extends BaseController { ...@@ -179,13 +199,27 @@ public class AdamMemberAdminController extends BaseController {
if (parameter.getState() != 2) { if (parameter.getState() != 2) {
// 这里编辑包含新增、更新、删除分别对应state:1,1,2 // 这里编辑包含新增、更新、删除分别对应state:1,1,2
parameter.setState(1); parameter.setState(1);
if (StringUtils.isBlank(parameter.getMemberPriceId())) {
return AjaxResult.warn("请指定权益所属价格包");
}
} else if (StringUtils.isBlank(parameter.getMrightsId())) { } else if (StringUtils.isBlank(parameter.getMrightsId())) {
return AjaxResult.warn("请指定要删除的权益ID"); return AjaxResult.warn("请指定要删除的权益ID");
} }
if (null == parameter.getSeqNo()) { if (null == parameter.getSeqNo()) {
parameter.setSeqNo(0); parameter.setSeqNo(0);
} }
return this.toAjax(adamMemberRightsAdminService.edit(parameter)); AdamMemberRights rights = adamMemberRightsAdminService.edit(parameter);
if (rights == null || StringUtils.isBlank(rights.getMrightsId())) {
return AjaxResult.error("权益保存失败");
}
// 显式回传 id,避免实体序列化字段名差异导致前端读不到
Map<String, Object> data = new HashMap<>(8);
data.put("mrightsId", rights.getMrightsId());
data.put("memberId", rights.getMemberId());
data.put("memberPriceId", rights.getMemberPriceId());
data.put("state", rights.getState());
data.put("title", rights.getTitle());
return AjaxResult.success(data);
} }
// @ApiOperation(value = "会员套餐:券编辑") // @ApiOperation(value = "会员套餐:券编辑")
......
...@@ -25,10 +25,12 @@ import org.apache.shiro.authz.annotation.RequiresPermissions; ...@@ -25,10 +25,12 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
@Api(tags = "会员码管理") @Api(tags = "会员码管理")
...@@ -46,34 +48,69 @@ public class AdamMemberCodeAdminController extends BaseController { ...@@ -46,34 +48,69 @@ public class AdamMemberCodeAdminController extends BaseController {
@GetMapping("mgt") @GetMapping("mgt")
public String viewCodeMgt(@RequestParam String memberId, ModelMap mmap) { public String viewCodeMgt(@RequestParam String memberId, ModelMap mmap) {
mmap.put("memberId", memberId); mmap.put("memberId", memberId);
AdamMemberPrice memberPrice = adamMemberPriceAdminService.getOne(Wrappers.lambdaQuery(AdamMemberPrice.class) List<AdamMemberPrice> memberPriceList = adamMemberPriceAdminService.list(Wrappers.lambdaQuery(AdamMemberPrice.class)
.eq(AdamMemberPrice::getState, 1) .eq(AdamMemberPrice::getState, 1)
.eq(AdamMemberPrice::getMemberId, memberId) .eq(AdamMemberPrice::getMemberId, memberId)
.select( .select(
AdamMemberPrice::getMid,
AdamMemberPrice::getMemberPriceId, AdamMemberPrice::getMemberPriceId,
AdamMemberPrice::getName,
AdamMemberPrice::getPrice, AdamMemberPrice::getPrice,
AdamMemberPrice::getPriceFixed, AdamMemberPrice::getPriceFixed,
AdamMemberPrice::getPriceSpecial, AdamMemberPrice::getPriceSpecial,
AdamMemberPrice::getDays AdamMemberPrice::getDays
) )
.orderByAsc(AdamMemberPrice::getDays)
); );
// 默认选中天数最长的价格包(通常为年卡),创建时可改选其它档
AdamMemberPrice memberPrice = CollectionUtils.isEmpty(memberPriceList) ? null
: memberPriceList.stream()
.max(Comparator.comparing(AdamMemberPrice::getDays, Comparator.nullsFirst(Integer::compareTo)))
.orElse(null);
mmap.put("memberPrice", memberPrice); mmap.put("memberPrice", memberPrice);
mmap.put("memberPriceList", memberPriceList);
return prefix + "/code_mgt"; return prefix + "/code_mgt";
} }
@ApiOperation(value = "会员码:上线价格包列表")
@RequiresPermissions("adam:member:code:creation")
@GetMapping("mgt/prices")
@ResponseBody
public AjaxResult listOnlinePrices(@RequestParam String memberId) {
List<AdamMemberPrice> memberPriceList = adamMemberPriceAdminService.list(Wrappers.lambdaQuery(AdamMemberPrice.class)
.eq(AdamMemberPrice::getState, 1)
.eq(AdamMemberPrice::getMemberId, memberId)
.select(
AdamMemberPrice::getMid,
AdamMemberPrice::getMemberPriceId,
AdamMemberPrice::getName,
AdamMemberPrice::getPrice,
AdamMemberPrice::getPriceFixed,
AdamMemberPrice::getPriceSpecial,
AdamMemberPrice::getDays
)
.orderByAsc(AdamMemberPrice::getDays)
);
return AjaxResult.success(memberPriceList);
}
@RequiresPermissions("adam:member:code:mgt:list") @RequiresPermissions("adam:member:code:mgt:list")
@Log(title = "会员管理:会员码:管理", businessType = BusinessType.LIST) @Log(title = "会员管理:会员码:管理", businessType = BusinessType.LIST)
@PostMapping("mgt/list") @PostMapping("mgt/list")
@ResponseBody @ResponseBody
public TableDataInfo listCodeMgt(@RequestParam String memberId) { public TableDataInfo listCodeMgt(@RequestParam String memberId) {
// TODO: 2021/9/23 码生成记录
LambdaQueryWrapper<AdamMemberCodeBatch> queryWrapper = Wrappers.lambdaQuery(AdamMemberCodeBatch.class); LambdaQueryWrapper<AdamMemberCodeBatch> queryWrapper = Wrappers.lambdaQuery(AdamMemberCodeBatch.class);
queryWrapper.eq(AdamMemberCodeBatch::getState, 1); queryWrapper.eq(AdamMemberCodeBatch::getState, 1);
// 本页按会员进入:只看该会员批次(member_id 精确匹配)
if (StringUtils.isNotBlank(memberId)) {
queryWrapper.eq(AdamMemberCodeBatch::getMemberId, memberId);
}
queryWrapper.select( queryWrapper.select(
AdamMemberCodeBatch::getBatchNo, AdamMemberCodeBatch::getBatchNo,
AdamMemberCodeBatch::getMemberName, AdamMemberCodeBatch::getMemberName,
AdamMemberCodeBatch::getMemberCombo, AdamMemberCodeBatch::getMemberCombo,
AdamMemberCodeBatch::getMemberPriceId,
AdamMemberCodeBatch::getGenNum, AdamMemberCodeBatch::getGenNum,
AdamMemberCodeBatch::getUseNum, AdamMemberCodeBatch::getUseNum,
AdamMemberCodeBatch::getDetail, AdamMemberCodeBatch::getDetail,
......
...@@ -2,13 +2,12 @@ ...@@ -2,13 +2,12 @@
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> <html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head> <head>
<th:block th:include="include :: header('会员码管理')" /> <th:block th:include="include :: header('会员码管理')" />
<th:block th:include="include :: select2-css" />
</head> </head>
<body class="gray-bg"> <body class="gray-bg">
<div class="container-div"> <div class="container-div">
<div class="row"> <div class="row">
<div class="btn-group-sm" id="toolbar" role="group"> <div class="btn-group-sm" id="toolbar" role="group">
<a class="btn btn-success" href="#member-gencode-form" data-toggle="modal" shiro:hasPermission="adam:member:code:creation"> <a id="btnCreateMemberCode" class="btn btn-success" href="javascript:void(0)" onclick="openCreateModal()" shiro:hasPermission="adam:member:code:creation">
<i class="fa fa-plus"></i> 创建 <i class="fa fa-plus"></i> 创建
</a> </a>
</div> </div>
...@@ -24,14 +23,21 @@ ...@@ -24,14 +23,21 @@
<form role="form" id="form-member-code-generate"> <form role="form" id="form-member-code-generate">
<input name="memberId" type="hidden" th:value="${memberId}" readonly> <input name="memberId" type="hidden" th:value="${memberId}" readonly>
<input name="memberPriceId" type="hidden" th:value="${memberPrice.memberPriceId}" readonly>
<div class="form-group"> <div class="form-group">
<label class="pull-left">生产数量:</label> <label>兑换套餐:</label>
<input type="number" name="genNum" class="form-control" style="width: 30%;height: 20px;" placeholder="生产数量"> <!-- 不用 select2:动态 option 会被 select2 吃掉只剩一条 -->
<select name="memberPriceId" id="memberPriceId" class="form-control noselect2" required>
<option value="">加载中...</option>
</select>
<p class="help-block m-b-none text-muted" style="margin-top:6px;">兑换后按所选价格包天数开会员,并发放该档权益</p>
</div> </div>
<div class="form-group"> <div class="form-group">
<!-- <label>备注:</label>--> <label>生产数量:</label>
<textarea rows="3" name="detail" placeholder="备注描述" class="form-control"></textarea> <input type="text" name="genNum" class="form-control" placeholder="请输入生产数量(1-100)" maxlength="3">
</div>
<div class="form-group">
<label>备注描述:</label>
<textarea rows="3" name="detail" placeholder="请输入备注描述" class="form-control"></textarea>
</div> </div>
<div class="text-center" style="margin-bottom: -15px;margin-top: 10px;"> <div class="text-center" style="margin-bottom: -15px;margin-top: 10px;">
<button class="btn btn-sm btn-primary m-t-n-xs" type="button" onclick="memberCodeGenerate()"> <button class="btn btn-sm btn-primary m-t-n-xs" type="button" onclick="memberCodeGenerate()">
...@@ -45,33 +51,48 @@ ...@@ -45,33 +51,48 @@
</div> </div>
</div> </div>
<th:block th:include="include :: footer" /> <th:block th:include="include :: footer" />
<th:block th:include="include :: select2-js" />
<script th:inline="javascript"> <script th:inline="javascript">
var viewMemberCodeListFlg = [[${@permission.hasPermi('adam:member:code:list')}]]; var viewMemberCodeListFlg = [[${@permission.hasPermi('adam:member:code:list')}]];
var memberId = [[${memberId}]]; var memberId = [[${memberId}]];
var prefix = ctx + "adam/mcode"; var prefix = ctx + "adam/mcode";
var onlinePriceList = [];
$(function() { $(function() {
var options = { var options = {
url: prefix + "/mgt/list?memberId=" + memberId, url: prefix + "/mgt/list",
createUrl: prefix + "/mgt/creation/{id}", createUrl: prefix + "/mgt/creation/{id}",
exportUrl: prefix + "/export_code", exportUrl: prefix + "/export_code",
detailUrl: ctx + "adam/order/orderList/detail/{id}", detailUrl: ctx + "adam/order/orderList/detail/{id}",
sortName: "createdAt", sortName: "createdAt",
sortOrder: "desc", sortOrder: "desc",
modalName: "会员码创建记录", modalName: "会员码创建记录",
queryParams: function (params) {
return {
pageSize: params.limit,
pageNum: params.offset / params.limit + 1,
searchValue: params.search,
orderByColumn: params.sort,
isAsc: params.order,
memberId: memberId
};
},
columns: [{ columns: [{
checkbox: true checkbox: true
}, },
{ {
field: 'memberName', field: 'memberName',
title: '会员名称', title: '会员名称',
width: 220 width: 180
}, },
{ {
field: 'memberCombo', field: 'memberCombo',
title: '会员套餐名称', title: '兑换套餐',
width: 180 width: 200
},
{
field: 'memberPriceId',
title: '价格包ID',
width: 140
}, },
{ {
field: 'genNum', field: 'genNum',
...@@ -86,7 +107,7 @@ ...@@ -86,7 +107,7 @@
{ {
field: 'detail', field: 'detail',
title: '备注', title: '备注',
width: 280 width: 220
}, },
{ {
field: 'operator', field: 'operator',
...@@ -112,9 +133,10 @@ ...@@ -112,9 +133,10 @@
}] }]
}; };
$.table.init(options); $.table.init(options);
// 打开列表页就拉套餐
reloadOnlinePrices();
}); });
/* 会员码列表 */
function memberCodeList(batchNo) { function memberCodeList(batchNo) {
$.modal.openTab("会员码列表", prefix + '/mgt/code?batchNo=' + batchNo); $.modal.openTab("会员码列表", prefix + '/mgt/code?batchNo=' + batchNo);
} }
...@@ -122,6 +144,9 @@ ...@@ -122,6 +144,9 @@
$("#form-member-code-generate").validate({ $("#form-member-code-generate").validate({
onkeyup: false, onkeyup: false,
rules:{ rules:{
memberPriceId: {
required: true
},
genNum: { genNum: {
required: true, required: true,
number: true, number: true,
...@@ -135,6 +160,9 @@ ...@@ -135,6 +160,9 @@
} }
}, },
messages: { messages: {
memberPriceId: {
required: "请选择兑换套餐"
},
genNum: { genNum: {
required: "请输入生产数量", required: "请输入生产数量",
number: "生产数量必须为数字", number: "生产数量必须为数字",
...@@ -146,28 +174,85 @@ ...@@ -146,28 +174,85 @@
minlength: "备注描述不得少于2个字符", minlength: "备注描述不得少于2个字符",
maxlength: "备注描述不得大于100个字符" maxlength: "备注描述不得大于100个字符"
} }
}, },
focusCleanup: true focusCleanup: true
}); });
function fillPriceOptions(list) {
onlinePriceList = list || [];
var $sel = $('#memberPriceId');
$sel.empty();
if (!onlinePriceList.length) {
$sel.append($('<option></option>').val('').text('暂无上线价格包'));
$('#btnCreateMemberCode').addClass('disabled');
return;
}
// 默认不选中:合上时不会误以为只有年卡一条;点开可见全部上线档
$sel.append($('<option></option>').val('').text('请选择兑换套餐(共' + onlinePriceList.length + '档)'));
$.each(onlinePriceList, function (i, mp) {
var text = (mp.name || '未命名') + ' · ' + (mp.days != null ? mp.days : '-') + '天 · ¥' + (mp.price != null ? mp.price : '-');
$sel.append($('<option></option>').attr('value', mp.memberPriceId).text(text));
});
$('#btnCreateMemberCode').removeClass('disabled');
console.log('[member-code] online prices:', onlinePriceList.length, onlinePriceList);
}
function reloadOnlinePrices(done) {
$.ajax({
url: prefix + '/mgt/prices',
type: 'get',
data: { memberId: memberId },
dataType: 'json',
success: function (res) {
var list = (res && res.code == web_status.SUCCESS && res.data) ? res.data : [];
fillPriceOptions(list);
if (typeof done === 'function') {
done(list);
}
},
error: function () {
fillPriceOptions([]);
$.modal.msgWarning("加载兑换套餐失败,请刷新页面重试");
if (typeof done === 'function') {
done([]);
}
}
});
}
function openCreateModal() {
if ($('#btnCreateMemberCode').hasClass('disabled')) {
$.modal.alertWarning("暂无上线价格包,请先在会员套餐中配置并上线");
return;
}
reloadOnlinePrices(function (list) {
if (!list.length) {
$.modal.alertWarning("暂无上线价格包,请先在会员套餐中配置并上线");
return;
}
$('#member-gencode-form').modal('show');
});
}
function memberCodeGenerate() { function memberCodeGenerate() {
if (!$('#memberPriceId').val()) {
$.modal.alertWarning("请选择兑换套餐");
return;
}
if ($.validate.form("form-member-code-generate")) { if ($.validate.form("form-member-code-generate")) {
$('#member-gencode-form').hide(); $('#member-gencode-form').modal('hide');
$.operate.saveModal(prefix + "/mgt/creation", $('#form-member-code-generate').serialize(), memberCodeGenerateCallback); $.operate.saveModal(prefix + "/mgt/creation", $('#form-member-code-generate').serialize(), memberCodeGenerateCallback);
} }
} }
function memberCodeGenerateCallback(result) { function memberCodeGenerateCallback(result) {
if (typeof callback == "function") {
callback(result);
}
if (result.code == web_status.SUCCESS) { if (result.code == web_status.SUCCESS) {
$.modal.alertSuccess(result.msg); $.modal.alertSuccess(result.msg);
setTimeout("refreshTab()", 1500); setTimeout("refreshTab()", 1500);
} else if (result.code == web_status.WARNING) { } else if (result.code == web_status.WARNING) {
$('#member-gencode-form').show(); $('#member-gencode-form').modal('show');
$.modal.alertWarning(result.msg); $.modal.alertWarning(result.msg);
} else { } else {
$('#member-gencode-form').show(); $('#member-gencode-form').modal('show');
$.modal.alertError(result.msg); $.modal.alertError(result.msg);
} }
} }
......
...@@ -178,6 +178,56 @@ ...@@ -178,6 +178,56 @@
</div> </div>
<div class="row" style="margin-top: 10px;">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="ibox-title ibox-title-gray dashboard-header">
<h5>优先券使用情况</h5>
</div>
<div class="ibox-content">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>券ID</th>
<th>姓名</th>
<th>手机号</th>
<th>专享标识</th>
<th>用户券状态</th>
<th>券标题</th>
<th>券类型</th>
<th>发放时间</th>
<th>到期时间</th>
<th>使用时间</th>
</tr>
</thead>
<tbody>
<tr th:each="coupon : ${orderDetailsVo.priorityCouponList}">
<td th:text="${coupon.ucouponId}"></td>
<td th:text="${coupon.name}"></td>
<td th:text="${coupon.mobile}"></td>
<td th:text="${coupon.exclusiveLabel}"></td>
<td>
<span class="badge badge-success" th:if="${coupon.state == 1}" th:text="${coupon.stateLabel}"></span>
<span class="badge badge-danger" th:if="${coupon.state == 5}" th:text="${coupon.stateLabel}"></span>
<span class="badge badge-warning" th:if="${coupon.state == 3}" th:text="${coupon.stateLabel}"></span>
<span class="badge badge-inverse" th:if="${coupon.state != 1 and coupon.state != 5 and coupon.state != 3}" th:text="${coupon.stateLabel}"></span>
</td>
<td th:text="${coupon.title}"></td>
<td th:text="${coupon.couTypeLabel}"></td>
<td th:text="${coupon.bindAt != null ? #temporals.format(coupon.bindAt, 'yyyy-MM-dd HH:mm:ss') : '-'}"></td>
<td th:text="${coupon.duedAt != null ? #temporals.format(coupon.duedAt, 'yyyy-MM-dd HH:mm:ss') : '-'}"></td>
<td th:text="${coupon.usedAt != null ? #temporals.format(coupon.usedAt, 'yyyy-MM-dd HH:mm:ss') : '-'}"></td>
</tr>
<tr th:if="${orderDetailsVo.priorityCouponList == null or #lists.isEmpty(orderDetailsVo.priorityCouponList)}">
<td colspan="10" class="text-center">暂无优先券记录</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</section> </section>
<th:block th:include="include :: footer" /> <th:block th:include="include :: footer" />
......
...@@ -6,5 +6,5 @@ import com.liquidnet.service.adam.entity.AdamMemberPrice; ...@@ -6,5 +6,5 @@ import com.liquidnet.service.adam.entity.AdamMemberPrice;
public interface IAdamMemberPriceAdminService extends IService<AdamMemberPrice> { public interface IAdamMemberPriceAdminService extends IService<AdamMemberPrice> {
boolean edit(AdamMemberPriceBuildParam param); AdamMemberPrice edit(AdamMemberPriceBuildParam param);
} }
...@@ -6,5 +6,5 @@ import com.liquidnet.service.adam.entity.AdamMemberRights; ...@@ -6,5 +6,5 @@ import com.liquidnet.service.adam.entity.AdamMemberRights;
public interface IAdamMemberRightsAdminService extends IService<AdamMemberRights> { public interface IAdamMemberRightsAdminService extends IService<AdamMemberRights> {
boolean edit(AdamMemberRightsBuildParam param); AdamMemberRights edit(AdamMemberRightsBuildParam param);
} }
...@@ -18,9 +18,12 @@ import com.liquidnet.service.adam.dto.vo.AdamMemberOrderExtVo; ...@@ -18,9 +18,12 @@ import com.liquidnet.service.adam.dto.vo.AdamMemberOrderExtVo;
import com.liquidnet.service.adam.dto.vo.AdamMemberOrderVo; import com.liquidnet.service.adam.dto.vo.AdamMemberOrderVo;
import com.liquidnet.service.adam.dto.vo.AdamUserInfoVo; import com.liquidnet.service.adam.dto.vo.AdamUserInfoVo;
import com.liquidnet.service.adam.dto.vo.AdamUserMemberVo; import com.liquidnet.service.adam.dto.vo.AdamUserMemberVo;
import com.liquidnet.service.adam.dto.vo.admin.AdamMemberPriorityCouponAdminVo;
import com.liquidnet.service.adam.dto.vo.admin.MemberOrderDetailAdminVo; import com.liquidnet.service.adam.dto.vo.admin.MemberOrderDetailAdminVo;
import com.liquidnet.service.adam.entity.*; import com.liquidnet.service.adam.entity.*;
import com.liquidnet.service.adam.mapper.*; import com.liquidnet.service.adam.mapper.*;
import com.liquidnet.service.candy.dto.admin.CandyPriorityCouponUsageDto;
import com.liquidnet.service.candy.mapper.CandyUserCouponMapper;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
...@@ -63,6 +66,8 @@ public class AdamMemberOrderAdminServiceImpl extends ServiceImpl<AdamMemberOrder ...@@ -63,6 +66,8 @@ public class AdamMemberOrderAdminServiceImpl extends ServiceImpl<AdamMemberOrder
private AdamMemberOrderExtMapper adamMemberOrderExtMapper; private AdamMemberOrderExtMapper adamMemberOrderExtMapper;
@Autowired @Autowired
private AdamMemberRefundMapper adamMemberRefundMapper; private AdamMemberRefundMapper adamMemberRefundMapper;
@Autowired
private CandyUserCouponMapper candyUserCouponMapper;
@Autowired @Autowired
private RedisDataSourceUtil redisDataSourceUtil; private RedisDataSourceUtil redisDataSourceUtil;
...@@ -124,9 +129,92 @@ public class AdamMemberOrderAdminServiceImpl extends ServiceImpl<AdamMemberOrder ...@@ -124,9 +129,92 @@ public class AdamMemberOrderAdminServiceImpl extends ServiceImpl<AdamMemberOrder
detailAdminVo.setAdamUserInfoVo(adamUserInfoVo); detailAdminVo.setAdamUserInfoVo(adamUserInfoVo);
detailAdminVo.setAdamUser(adamUser); detailAdminVo.setAdamUser(adamUser);
detailAdminVo.setAdamMemberOrderExtVo(AdamMemberOrderExtVo.getNew().copy(adamMemberOrderExt)); detailAdminVo.setAdamMemberOrderExtVo(AdamMemberOrderExtVo.getNew().copy(adamMemberOrderExt));
detailAdminVo.setPriorityCouponList(buildPriorityCouponList(adamMemberOrderVo.getUid()));
return detailAdminVo; return detailAdminVo;
} }
private List<AdamMemberPriorityCouponAdminVo> buildPriorityCouponList(String uid) {
List<AdamMemberPriorityCouponAdminVo> result = new ArrayList<>();
if (uid == null || uid.isEmpty()) {
return result;
}
List<CandyPriorityCouponUsageDto> usageList = candyUserCouponMapper.selectPriorityCouponUsageByUid(uid);
if (CollectionUtils.isEmpty(usageList)) {
return result;
}
for (CandyPriorityCouponUsageDto usage : usageList) {
AdamMemberPriorityCouponAdminVo vo = new AdamMemberPriorityCouponAdminVo();
vo.setUcouponId(usage.getUcouponId());
vo.setName(usage.getName());
vo.setMobile(usage.getMobile());
vo.setExclusive(usage.getExclusive());
vo.setExclusiveLabel(resolveExclusiveLabel(usage.getExclusive()));
vo.setState(usage.getState());
vo.setStateLabel(resolveCouponStateLabel(usage.getState()));
vo.setTitle(usage.getTitle());
vo.setCouType(usage.getCouType());
vo.setCouTypeLabel(resolveCouTypeLabel(usage.getCouType()));
vo.setBindAt(usage.getBindAt());
vo.setDuedAt(usage.getDuedAt());
vo.setUsedAt(usage.getUsedAt());
result.add(vo);
}
return result;
}
private String resolveExclusiveLabel(Integer exclusive) {
if (null == exclusive) {
return "-";
}
if (exclusive == 1) {
return "会员礼包";
}
if (exclusive == 0) {
return "常规";
}
return String.valueOf(exclusive);
}
private String resolveCouponStateLabel(Integer state) {
if (null == state) {
return "-";
}
switch (state) {
case 1:
return "可用";
case 2:
return "无效";
case 3:
return "已过期";
case 5:
return "已使用";
case 9:
return "移除不展示(过期或已使用)";
default:
return String.valueOf(state);
}
}
private String resolveCouTypeLabel(Integer couType) {
if (null == couType) {
return "-";
}
switch (couType) {
case 1:
return "代金卷";
case 2:
return "满减卷";
case 3:
return "兑换卷";
case 4:
return "折扣卷";
case 101:
return "优先卷";
default:
return String.valueOf(couType);
}
}
@Override @Override
@Transactional @Transactional
public AjaxResult refundProcessing(AdamMemberOrderRefundParam param, AdamMemberOrder memberOrder) { public AjaxResult refundProcessing(AdamMemberOrderRefundParam param, AdamMemberOrder memberOrder) {
......
...@@ -19,8 +19,9 @@ import org.springframework.util.CollectionUtils; ...@@ -19,8 +19,9 @@ import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.stream.IntStream; import java.util.stream.Collectors;
@Service @Service
public class AdamMemberRightsAdminServiceImpl extends ServiceImpl<AdamMemberRightsMapper, AdamMemberRights> implements IAdamMemberRightsAdminService { public class AdamMemberRightsAdminServiceImpl extends ServiceImpl<AdamMemberRightsMapper, AdamMemberRights> implements IAdamMemberRightsAdminService {
...@@ -30,7 +31,7 @@ public class AdamMemberRightsAdminServiceImpl extends ServiceImpl<AdamMemberRigh ...@@ -30,7 +31,7 @@ public class AdamMemberRightsAdminServiceImpl extends ServiceImpl<AdamMemberRigh
private RedisDataSourceUtil redisDataSourceUtil; private RedisDataSourceUtil redisDataSourceUtil;
@Override @Override
public boolean edit(AdamMemberRightsBuildParam param) { public AdamMemberRights edit(AdamMemberRightsBuildParam param) {
String loginName = ShiroUtils.getLoginName(); String loginName = ShiroUtils.getLoginName();
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
String mrightsId = param.getMrightsId(); String mrightsId = param.getMrightsId();
...@@ -40,6 +41,7 @@ public class AdamMemberRightsAdminServiceImpl extends ServiceImpl<AdamMemberRigh ...@@ -40,6 +41,7 @@ public class AdamMemberRightsAdminServiceImpl extends ServiceImpl<AdamMemberRigh
if (isAddFlag) { if (isAddFlag) {
saveOrUpdateInfo.setMrightsId(IDGenerator.nextMilliId2()); saveOrUpdateInfo.setMrightsId(IDGenerator.nextMilliId2());
saveOrUpdateInfo.setMemberId(param.getMemberId()); saveOrUpdateInfo.setMemberId(param.getMemberId());
saveOrUpdateInfo.setMemberPriceId(StringUtils.trimToNull(param.getMemberPriceId()));
saveOrUpdateInfo.setState(1); saveOrUpdateInfo.setState(1);
saveOrUpdateInfo.setSeqNo(param.getSeqNo()); saveOrUpdateInfo.setSeqNo(param.getSeqNo());
...@@ -57,57 +59,44 @@ public class AdamMemberRightsAdminServiceImpl extends ServiceImpl<AdamMemberRigh ...@@ -57,57 +59,44 @@ public class AdamMemberRightsAdminServiceImpl extends ServiceImpl<AdamMemberRigh
.eq(AdamMemberRights::getMemberId, param.getMemberId()) .eq(AdamMemberRights::getMemberId, param.getMemberId())
.eq(AdamMemberRights::getMrightsId, param.getMrightsId()); .eq(AdamMemberRights::getMrightsId, param.getMrightsId());
saveOrUpdateInfo.setMrightsId(param.getMrightsId());
saveOrUpdateInfo.setMemberId(param.getMemberId());
saveOrUpdateInfo.setState(param.getState()); saveOrUpdateInfo.setState(param.getState());
saveOrUpdateInfo.setOperator(loginName); saveOrUpdateInfo.setOperator(loginName);
saveOrUpdateInfo.setUpdatedAt(now); saveOrUpdateInfo.setUpdatedAt(now);
if (param.getState() != 2) { if (param.getState() != 2) {
saveOrUpdateInfo.setMemberPriceId(StringUtils.trimToNull(param.getMemberPriceId()));
saveOrUpdateInfo.setSeqNo(param.getSeqNo()); saveOrUpdateInfo.setSeqNo(param.getSeqNo());
saveOrUpdateInfo.setTitle(param.getTitle()); saveOrUpdateInfo.setTitle(param.getTitle());
saveOrUpdateInfo.setSubTitle(param.getSubTitle()); saveOrUpdateInfo.setSubTitle(param.getSubTitle());
saveOrUpdateInfo.setLabel(param.getLabel()); saveOrUpdateInfo.setLabel(param.getLabel());
saveOrUpdateInfo.setCover(param.getCover()); saveOrUpdateInfo.setCover(param.getCover());
saveOrUpdateInfo.setDetail(param.getDetail()); saveOrUpdateInfo.setDetail(param.getDetail());
// 允许清空绑定:用 set 显式更新可空字段
updateWrapper.set(AdamMemberRights::getMemberPriceId, StringUtils.trimToNull(param.getMemberPriceId()));
} }
saveOrUpadateRst = adamMemberRightsMapper.update(saveOrUpdateInfo, updateWrapper) > 0; saveOrUpadateRst = adamMemberRightsMapper.update(saveOrUpdateInfo, updateWrapper) > 0;
} }
if (!saveOrUpadateRst) {
if (saveOrUpadateRst) { return null;
// 同步REDIS:用户端:购买会员详情页:权益列表
List<AdamMemberRightsVo> vos = (List<AdamMemberRightsVo>) redisDataSourceUtil.getRedisAdamUtil().get(AdamRedisConst.INFO_MEMBER_RIGHTS.concat(param.getMemberId()));
if (CollectionUtils.isEmpty(vos)) {
vos = new ArrayList<>();
}
if (isAddFlag) {
vos.add(AdamMemberRightsVo.getNew().copy(saveOrUpdateInfo));
} else {
if (param.getState() == 2) {// 移除
vos.removeIf(r -> r.getMrightsId().equals(param.getMrightsId()));
} else {
List<AdamMemberRightsVo> finalVos = vos;
int idx = IntStream.range(0, finalVos.size())
.filter(i -> finalVos.get(i).getMrightsId().equals(mrightsId))
.findFirst().orElse(-1);
if (-1 == idx) {
vos.add(AdamMemberRightsVo.getNew().copy(saveOrUpdateInfo));
} else {
AdamMemberRightsVo existVo = vos.get(idx);
existVo.setSeqNo(saveOrUpdateInfo.getSeqNo());
existVo.setTitle(saveOrUpdateInfo.getTitle());
existVo.setSubTitle(saveOrUpdateInfo.getSubTitle());
existVo.setLabel(saveOrUpdateInfo.getLabel());
existVo.setCover(saveOrUpdateInfo.getCover());
existVo.setDetail(saveOrUpdateInfo.getDetail());
vos.set(idx, existVo);
}
}
} }
redisDataSourceUtil.getRedisAdamUtil().set(AdamRedisConst.INFO_MEMBER_RIGHTS.concat(param.getMemberId()), vos); // 与价格包一致:从 DB 全量重载 Redis,避免增量补丁丢权益 / 缺 memberPriceId
refreshMemberRightsRedis(param.getMemberId());
return saveOrUpdateInfo;
} }
return saveOrUpadateRst; private void refreshMemberRightsRedis(String memberId) {
List<AdamMemberRights> onlineList = adamMemberRightsMapper.selectList(Wrappers.lambdaQuery(AdamMemberRights.class)
.eq(AdamMemberRights::getMemberId, memberId)
.eq(AdamMemberRights::getState, 1)
.orderByAsc(AdamMemberRights::getSeqNo));
List<AdamMemberRightsVo> vos = CollectionUtils.isEmpty(onlineList) ? new ArrayList<>()
: onlineList.stream()
.sorted(Comparator.comparing(AdamMemberRights::getSeqNo, Comparator.nullsLast(Integer::compareTo)))
.map(r -> AdamMemberRightsVo.getNew().copy(r))
.collect(Collectors.toList());
redisDataSourceUtil.getRedisAdamUtil().set(AdamRedisConst.INFO_MEMBER_RIGHTS.concat(memberId), vos);
} }
} }
...@@ -6,14 +6,14 @@ spring: ...@@ -6,14 +6,14 @@ spring:
druid: druid:
# 主库数据源 # 主库数据源
master: master:
url: jdbc:mysql://${liquidnet.mysql.master.urlHostAndPort}/${liquidnet.mysql.master.database-name}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 url: jdbc:mysql://${liquidnet.mysql.master.urlHostAndPort}/${liquidnet.mysql.master.database-name}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&connectTimeout=5000&socketTimeout=10000
username: ${liquidnet.mysql.master.username} username: ${liquidnet.mysql.master.username}
password: ${liquidnet.mysql.master.password} password: ${liquidnet.mysql.master.password}
# 从库数据源 # 从库数据源
slave: slave:
# 从数据源开关/默认关闭 # 从数据源开关/默认关闭
enabled: false enabled: false
url: jdbc:mysql://${liquidnet.mysql.slave.urlHostAndPort}/${liquidnet.mysql.slave.database-name}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 url: jdbc:mysql://${liquidnet.mysql.slave.urlHostAndPort}/${liquidnet.mysql.slave.database-name}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&connectTimeout=5000&socketTimeout=10000
username: ${liquidnet.mysql.slave.username} username: ${liquidnet.mysql.slave.username}
password: ${liquidnet.mysql.slave.password} password: ${liquidnet.mysql.slave.password}
# 初始连接数 # 初始连接数
......
...@@ -6,14 +6,14 @@ spring: ...@@ -6,14 +6,14 @@ spring:
druid: druid:
# 主库数据源 # 主库数据源
master: master:
url: jdbc:mysql://${liquidnet.mysql.master.urlHostAndPort}/${liquidnet.mysql.master.database-name}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 url: jdbc:mysql://${liquidnet.mysql.master.urlHostAndPort}/${liquidnet.mysql.master.database-name}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&connectTimeout=5000&socketTimeout=10000
username: ${liquidnet.mysql.master.username} username: ${liquidnet.mysql.master.username}
password: ${liquidnet.mysql.master.password} password: ${liquidnet.mysql.master.password}
# 从库数据源 # 从库数据源
slave: slave:
# 从数据源开关/默认关闭 # 从数据源开关/默认关闭
enabled: false enabled: false
url: jdbc:mysql://${liquidnet.mysql.slave.urlHostAndPort}/${liquidnet.mysql.slave.database-name}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 url: jdbc:mysql://${liquidnet.mysql.slave.urlHostAndPort}/${liquidnet.mysql.slave.database-name}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&connectTimeout=5000&socketTimeout=10000
username: ${liquidnet.mysql.slave.username} username: ${liquidnet.mysql.slave.username}
password: ${liquidnet.mysql.slave.password} password: ${liquidnet.mysql.slave.password}
# 初始连接数 # 初始连接数
......
...@@ -32,6 +32,11 @@ public class AdamMemberRights implements Serializable { ...@@ -32,6 +32,11 @@ public class AdamMemberRights implements Serializable {
*/ */
private String memberId; private String memberId;
/**
* 绑定的价格包ID;空表示兼容老逻辑(该卡下任意价格包可回退使用)
*/
private String memberPriceId;
/** /**
* 发放状态[0-INIT|1-NORMAL|2-INVALID] * 发放状态[0-INIT|1-NORMAL|2-INVALID]
*/ */
......
package com.liquidnet.service.candy.dto.admin;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 优先券使用情况查询结果
*/
@Data
public class CandyPriorityCouponUsageDto implements Serializable {
private static final long serialVersionUID = 1L;
private String ucouponId;
private String name;
private String mobile;
private Integer exclusive;
private Integer state;
private String title;
private Integer couType;
private LocalDateTime bindAt;
private LocalDateTime duedAt;
private LocalDateTime usedAt;
}
...@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; ...@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.liquidnet.service.candy.dto.CandyUserCouponBasicDto; import com.liquidnet.service.candy.dto.CandyUserCouponBasicDto;
import com.liquidnet.service.candy.dto.CouponDao; import com.liquidnet.service.candy.dto.CouponDao;
import com.liquidnet.service.candy.dto.admin.CandyPriorityCouponUsageDto;
import com.liquidnet.service.candy.entity.CandyUserCoupon; import com.liquidnet.service.candy.entity.CandyUserCoupon;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
...@@ -44,4 +45,9 @@ public interface CandyUserCouponMapper extends BaseMapper<CandyUserCoupon> { ...@@ -44,4 +45,9 @@ public interface CandyUserCouponMapper extends BaseMapper<CandyUserCoupon> {
* 查询羊毛卷信息 * 查询羊毛卷信息
*/ */
List<CouponDao> WoolRoll(); List<CouponDao> WoolRoll();
/**
* 按用户查优先券使用情况(cou_type=101)
*/
List<CandyPriorityCouponUsageDto> selectPriorityCouponUsageByUid(@Param("uid") String uid);
} }
...@@ -109,4 +109,24 @@ ...@@ -109,4 +109,24 @@
and d.status = 6 and d.status = 6
order by a.used_at; order by a.used_at;
</select> </select>
<select id="selectPriorityCouponUsageByUid" resultType="com.liquidnet.service.candy.dto.admin.CandyPriorityCouponUsageDto">
SELECT
cuc.ucoupon_id AS ucouponId,
auml.`name` AS `name`,
auml.mobile AS mobile,
cuc.`exclusive` AS exclusive,
cuc.state AS state,
ac.title AS title,
ac.cou_type AS couType,
cuc.bind_at AS bindAt,
cuc.dued_at AS duedAt,
cuc.used_at AS usedAt
FROM candy_user_coupon AS cuc
LEFT JOIN adam_user_mobile_locate AS auml ON auml.uid = cuc.uid
JOIN candy_coupon AS ac ON ac.coupon_id = cuc.coupon_id
WHERE cuc.uid = #{uid,jdbcType=VARCHAR}
AND ac.cou_type = 101
ORDER BY cuc.bind_at DESC, cuc.ucoupon_id DESC
</select>
</mapper> </mapper>
-- 多档会员:权益绑价格包 + 老数据洗到年档
-- 月卡/体验等价格包请在 admin「会员套餐」页新增,不要用本脚本灌业务数据。
-- ========== 1) DDL(若已执行过可跳过)==========
ALTER TABLE adam_member_rights
ADD COLUMN member_price_id VARCHAR(64) NULL COMMENT '绑定价格包ID(必绑具体档;空仅历史兼容,执行下方洗数后应无空)' AFTER member_id;
CREATE INDEX idx_amember_rights_price_id ON adam_member_rights (member_price_id);
-- ========== 2) 洗数:NULL 权益绑到该会员「天数最大」的价格包(视为年档)==========
-- 若同一 member 有多条 days 并列最大,取 member_price_id 字典序最小的一条
UPDATE adam_member_rights r
INNER JOIN (
SELECT p.member_id, MIN(p.member_price_id) AS year_price_id
FROM adam_member_price p
INNER JOIN (
SELECT member_id, MAX(days) AS max_days
FROM adam_member_price
WHERE state IN (1, 2)
GROUP BY member_id
) m ON m.member_id = p.member_id AND m.max_days = p.days
WHERE p.state IN (1, 2)
GROUP BY p.member_id
) y ON y.member_id = r.member_id
SET r.member_price_id = y.year_price_id
WHERE r.member_price_id IS NULL
AND r.state = 1;
-- 检查是否还有空绑定(期望 0 行)
-- SELECT mid, mrights_id, member_id, title FROM adam_member_rights WHERE state = 1 AND member_price_id IS NULL;
-- ========== 3) Redis(会员价/权益读 Redis,Mongo 已注释不用)==========
-- 洗数后必须刷缓存,否则线上仍是旧 rights(缺 memberPriceId)。
-- 任选其一:
-- A) admin 打开会员套餐,随便保存一条该卡权益(会 refreshMemberRightsRedis)
-- B) 手工删 key(memberId 按实际替换,登登登一般是 1):
-- DEL adam:info:member:rights:1
-- DEL adam:info:member:price:1
-- (若有 V 版)DEL adam:info:member:rights:v:1
-- 下次请求会按代码从 DB/逻辑重建;价格包建议在 admin 保存一次价格以确保 price 列表正确。
-- ========== 4) 后续运营 ==========
-- admin 新增月卡/体验价格包后,在「编辑」弹窗内配置本档权益与券张数。
...@@ -353,6 +353,9 @@ alter table adam_member add limite_at datetime(3) null comment '限购结束时 ...@@ -353,6 +353,9 @@ alter table adam_member add limite_at datetime(3) null comment '限购结束时
alter table adam_member_price modify price_fixed decimal(8, 2) null comment '购买价格'; alter table adam_member_price modify price_fixed decimal(8, 2) null comment '购买价格';
alter table adam_member_price add price_special decimal(8, 2) null comment '特价:首次、首年优惠价' after price_fixed; alter table adam_member_price add price_special decimal(8, 2) null comment '特价:首次、首年优惠价' after price_fixed;
# 多档会员:权益可绑价格包(详见 db_adam_member_price_multi_package.sql
# alter table adam_member_rights add member_price_id varchar(64) null comment '绑定价格包ID,空表示全档回退共用' after member_id;
# 会员码表调整 # 会员码表调整
alter table adam_member_code modify state tinyint null comment '状态[0-可用|1-已用|2-无效]'; alter table adam_member_code modify state tinyint null comment '状态[0-可用|1-已用|2-无效]';
create index idx_amember_code_id on adam_member_code (code); create index idx_amember_code_id on adam_member_code (code);
......
...@@ -24,6 +24,9 @@ import org.springframework.web.bind.annotation.RequestParam; ...@@ -24,6 +24,9 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ApiSupport(order = 10030) @ApiSupport(order = 10030)
@Api(tags = "会员信息") @Api(tags = "会员信息")
...@@ -52,30 +55,61 @@ public class AdamMemberController { ...@@ -52,30 +55,61 @@ public class AdamMemberController {
// memberVo.setBuySwitch(adamRdmService.getSwitch(AdamRedisConst.SWITCH_BUY_MEMBER)); // memberVo.setBuySwitch(adamRdmService.getSwitch(AdamRedisConst.SWITCH_BUY_MEMBER));
memberVo.calculateLimitMarker(adamRdmService.getMaxMemberLimitation()); memberVo.calculateLimitMarker(adamRdmService.getMaxMemberLimitation());
memberVo.setPriceVoList(adamRdmService.getMemberPriceVoByMemberId(memberVo.getMemberId()));
String currentUid = CurrentUtil.getCurrentUid(); String currentUid = CurrentUtil.getCurrentUid();
int rightsVFlag = 0;
if (!StringUtils.isEmpty(currentUid)) { if (!StringUtils.isEmpty(currentUid)) {
AdamUserMemberVo userMemberVo = adamRdmService.getUserMemberVoByUid(currentUid); AdamUserMemberVo userMemberVo = adamRdmService.getUserMemberVoByUid(currentUid);
memberVo.setUserMemberVo(userMemberVo); memberVo.setUserMemberVo(userMemberVo);
if (null != userMemberVo && userMemberVo.isActive() && userMemberVo.isOldMember()) {
if (null == userMemberVo || !userMemberVo.isActive()) { rightsVFlag = 1;
memberVo.setRightsVoList(adamRdmService.getMemberRightsVoByMemberId(memberVo.getMemberId(), 0));
} else if (userMemberVo.isActive()) {
memberVo.setRightsVoList(
userMemberVo.isOldMember() ? adamRdmService.getMemberRightsVoByMemberId(memberVo.getMemberId(), 1)
: adamRdmService.getMemberRightsVoByMemberId(memberVo.getMemberId(), 0)
);
} }
} else { } else {
memberVo.setUserMemberVo(null); memberVo.setUserMemberVo(null);
memberVo.setRightsVoList(adamRdmService.getMemberRightsVoByMemberId(memberVo.getMemberId(), 0));
} }
// 权益只挂在价格包下:priceVoList[].rightsVoList
memberVo.setPriceVoList(attachRightsToPriceList(
adamRdmService.getMemberPriceVoByMemberId(memberVo.getMemberId()),
adamRdmService.getMemberRightsVoByMemberId(memberVo.getMemberId(), rightsVFlag),
rightsVFlag
));
} }
return ResponseDto.success(memberVo); return ResponseDto.success(memberVo);
} }
/**
* 将权益挂到对应价格包。
* vFlag=0:按 memberPriceId 精确匹配;
* vFlag=1:老会员展示用权益无价格包绑定,挂到每个价格包下。
*/
private List<AdamMemberPriceVo> attachRightsToPriceList(List<AdamMemberPriceVo> priceVoList,
List<AdamMemberRightsVo> rightsVoList,
int rightsVFlag) {
if (priceVoList == null || priceVoList.isEmpty()) {
return priceVoList;
}
List<AdamMemberRightsVo> allRights = rightsVoList == null ? Collections.emptyList() : rightsVoList;
for (AdamMemberPriceVo priceVo : priceVoList) {
if (rightsVFlag == 1) {
priceVo.setRightsVoList(allRights);
continue;
}
String priceId = priceVo.getMemberPriceId();
if (StringUtils.isEmpty(priceId)) {
priceVo.setRightsVoList(Collections.emptyList());
continue;
}
List<AdamMemberRightsVo> matched = new ArrayList<>();
for (AdamMemberRightsVo rightsVo : allRights) {
if (priceId.equals(rightsVo.getMemberPriceId())) {
matched.add(rightsVo);
}
}
priceVo.setRightsVoList(matched);
}
return priceVoList;
}
@ApiOperationSupport(order = 2) @ApiOperationSupport(order = 2)
@ApiOperation(value = "会员协议") @ApiOperation(value = "会员协议")
@GetMapping("agreement") @GetMapping("agreement")
......
...@@ -376,7 +376,8 @@ public class AdamMemberOrderServiceImpl implements IAdamMemberOrderService { ...@@ -376,7 +376,8 @@ public class AdamMemberOrderServiceImpl implements IAdamMemberOrderService {
if (now.isAfter(AdamUserMemberVo.spotTime)) { if (now.isAfter(AdamUserMemberVo.spotTime)) {
// 权益券发放 // 权益券发放
toMqSqls.add(SqlMapping.get("candy_mgt_coupon.add_for_member")); toMqSqls.add(SqlMapping.get("candy_mgt_coupon.add_for_member"));
LinkedList<Object[]> initMemberRightsCouponObjs = this.issueMemberRightsCouponProcessing(now, userInfoVo.getMobile(), handleMemberOrderVo.getMemberId()); LinkedList<Object[]> initMemberRightsCouponObjs = this.issueMemberRightsCouponProcessing(
now, userInfoVo.getMobile(), handleMemberOrderVo.getMemberId(), handleMemberOrderVo.getMemberPriceId());
queueUtils.sendMsgByRedis(MQConst.AdamQueue.SQL_UMEMBER.getKey(), queueUtils.sendMsgByRedis(MQConst.AdamQueue.SQL_UMEMBER.getKey(),
SqlMapping.gets(toMqSqls, operationObjs, initMemberOrderObjs, initMemberOrderExtObjs, updateUserInfoObjs, updateUserMobileLocateObjs, initMemberRightsCouponObjs) SqlMapping.gets(toMqSqls, operationObjs, initMemberOrderObjs, initMemberOrderExtObjs, updateUserInfoObjs, updateUserMobileLocateObjs, initMemberRightsCouponObjs)
...@@ -576,7 +577,8 @@ public class AdamMemberOrderServiceImpl implements IAdamMemberOrderService { ...@@ -576,7 +577,8 @@ public class AdamMemberOrderServiceImpl implements IAdamMemberOrderService {
// 权益券发放 // 权益券发放
toMqSqls.add(SqlMapping.get("candy_mgt_coupon.add_for_member")); toMqSqls.add(SqlMapping.get("candy_mgt_coupon.add_for_member"));
LinkedList<Object[]> initMemberRightsCouponObjs = this.issueMemberRightsCouponProcessing(now, userInfoVo.getMobile(), initMemberOrderVo.getMemberId()); LinkedList<Object[]> initMemberRightsCouponObjs = this.issueMemberRightsCouponProcessing(
now, userInfoVo.getMobile(), initMemberOrderVo.getMemberId(), initMemberOrderVo.getMemberPriceId());
s = System.currentTimeMillis(); s = System.currentTimeMillis();
queueUtils.sendMsgByRedis(MQConst.AdamQueue.SQL_UMEMBER.getKey(), queueUtils.sendMsgByRedis(MQConst.AdamQueue.SQL_UMEMBER.getKey(),
...@@ -652,27 +654,25 @@ public class AdamMemberOrderServiceImpl implements IAdamMemberOrderService { ...@@ -652,27 +654,25 @@ public class AdamMemberOrderServiceImpl implements IAdamMemberOrderService {
} }
/** /**
* 发放会员专属特权券 * 发放会员专属特权券(仅发放绑定当前价格包的权益)
*
* @param now 时间
* @param mobile 用户手机号
* @param memberId 会员ID
* @return LinkedList<Object[]>
*/ */
private LinkedList<Object[]> issueMemberRightsCouponProcessing(LocalDateTime now, String mobile, String memberId) { private LinkedList<Object[]> issueMemberRightsCouponProcessing(LocalDateTime now, String mobile, String memberId, String memberPriceId) {
LinkedList<Object[]> initMemberRightsCouponObjs = CollectionUtil.linkedListObjectArr(); LinkedList<Object[]> initMemberRightsCouponObjs = CollectionUtil.linkedListObjectArr();
List<AdamMemberRightsVo> memberRightsVoList = adamRdmService.getMemberRightsVoByMemberId(memberId, 0); List<AdamMemberRightsVo> memberRightsVoList = adamRdmService.getMemberRightsVoByMemberId(memberId, 0);
memberRightsVoList = filterRightsByMemberPriceId(memberRightsVoList, memberPriceId);
if (!CollectionUtils.isEmpty(memberRightsVoList)) { if (!CollectionUtils.isEmpty(memberRightsVoList)) {
memberRightsVoList.forEach(r -> { memberRightsVoList.forEach(r -> {
List<AdamMemberRightsCouponVo> memberRightsCouponVoList = adamRdmService.getMemberRightsCouponVoByRightsId(r.getMrightsId()); List<AdamMemberRightsCouponVo> memberRightsCouponVoList = adamRdmService.getMemberRightsCouponVoByRightsId(r.getMrightsId());
if (!CollectionUtils.isEmpty(memberRightsCouponVoList)) { if (!CollectionUtils.isEmpty(memberRightsCouponVoList)) {
// 该权益下关联券统计
Map<String, Long> rightsCouponCtMap = memberRightsCouponVoList.stream() Map<String, Long> rightsCouponCtMap = memberRightsCouponVoList.stream()
.collect(Collectors.groupingBy(AdamMemberRightsCouponVo::getCouponId, Collectors.counting())); .collect(Collectors.groupingBy(AdamMemberRightsCouponVo::getCouponId, Collectors.counting()));
rightsCouponCtMap.forEach((couponId, num) -> { rightsCouponCtMap.forEach((couponId, num) -> {
if (num <= 0) {
return;
}
initMemberRightsCouponObjs.add( initMemberRightsCouponObjs.add(
new Object[]{r.getMrightsId(), couponId, num, mobile, now, mobile, now} new Object[]{r.getMrightsId(), couponId, num, mobile, now, mobile, now}
); );
...@@ -683,4 +683,16 @@ public class AdamMemberOrderServiceImpl implements IAdamMemberOrderService { ...@@ -683,4 +683,16 @@ public class AdamMemberOrderServiceImpl implements IAdamMemberOrderService {
return initMemberRightsCouponObjs; return initMemberRightsCouponObjs;
} }
/**
* 只使用绑定当前价格包的权益(需先执行洗数把历史 NULL 绑到年档)
*/
private List<AdamMemberRightsVo> filterRightsByMemberPriceId(List<AdamMemberRightsVo> rightsVoList, String memberPriceId) {
if (CollectionUtils.isEmpty(rightsVoList) || StringUtils.isEmpty(memberPriceId)) {
return Collections.emptyList();
}
return rightsVoList.stream()
.filter(r -> memberPriceId.equals(r.getMemberPriceId()))
.collect(Collectors.toList());
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment