Commit 4dd96931 authored by zhaobiyan's avatar zhaobiyan

Merge branch 'feature_customer_search' into feature_member_score

parents 6a672e0d ee83b6ba
......@@ -1409,4 +1409,8 @@ public class RedisHelper {
public boolean execute(DefaultRedisScript<Boolean> defaultRedisScript, List<String> keys, Object... args) {
return operations.execute(defaultRedisScript, keys, args);
}
public Long execute4Long(DefaultRedisScript<Long> defaultRedisScript, List<String> keys, Object... args) {
return operations.execute(defaultRedisScript, keys, args);
}
}
\ No newline at end of file
......@@ -88,4 +88,13 @@ public class CustomerExportReqDTO {
private List<Integer> marketType;
private int deptId ;
@ApiModelProperty(value = "会员编号")
private String memberCode;
@ApiModelProperty(value = "会员名称")
private String memberName;
@ApiModelProperty(value = "会员手机")
private String memberMobile;
@ApiModelProperty(value = "会员区号")
private String memberAreaCode;
}
......@@ -92,4 +92,12 @@ public class CustomerPageReqDTO extends PageParam {
@ApiModelProperty(value = "是否潜在客户")
private Boolean isPotential;
@ApiModelProperty(value = "会员编号")
private String memberCode;
@ApiModelProperty(value = "会员名称")
private String memberName;
@ApiModelProperty(value = "会员手机")
private String memberMobile;
@ApiModelProperty(value = "会员区号")
private String memberAreaCode;
}
......@@ -50,4 +50,13 @@ public class IndirectCustomerPageReqDTO {
* 客户来源
*/
private List<Integer> source;
@ApiModelProperty(value = "会员编号")
private String memberCode;
@ApiModelProperty(value = "会员名称")
private String memberName;
@ApiModelProperty(value = "会员手机")
private String memberMobile;
@ApiModelProperty(value = "会员区号")
private String memberAreaCode;
}
......@@ -72,6 +72,7 @@
c.social as default_social,
c.email as default_email,
c.social_number as default_social_number,
c.userid as contact_member_id,
su.nickname as customer_service_name,
su.dept_id as dept_id
from ecw_customer a
......@@ -83,7 +84,7 @@
left join ecw_customer_credit credit
on contact.credit_level = credit.id
left join ecw_country ec on contact.country = ec.id
left join member_user mu on contact.contact_member_id = mu.id
WHERE 1=1 AND contact.deleted = 0
......@@ -113,6 +114,7 @@
c.social as default_social,
c.email as default_email,
c.social_number as default_social_number,
c.userid as contact_member_id,
su.nickname as customer_service_name,
su.dept_id as dept_id
from ecw_customer a
......@@ -124,7 +126,7 @@
left join ecw_customer_credit credit
on contact.credit_level = credit.id
left join ecw_country ec on contact.country = ec.id
left join member_user mu on contact.contact_member_id = mu.id
WHERE 1=1 AND contact.deleted = 0
......@@ -154,6 +156,7 @@
c.social as default_social,
c.email as default_email,
c.social_number as default_social_number,
c.userid as contact_member_id,
su.nickname as customer_service_name,
su.dept_id as dept_id
from ecw_customer a
......@@ -165,7 +168,7 @@
left join ecw_customer_credit credit
on contact.credit_level = credit.id
left join ecw_country ec on contact.country = ec.id
left join member_user mu on contact.contact_member_id = mu.id
WHERE 1=1 AND contact.deleted = 0
......@@ -190,6 +193,7 @@
c.social as default_social,
c.email as default_email,
c.social_number as default_social_number,
c.userid as contact_member_id,
su.nickname as customer_service_name,
su.dept_id as dept_id
from ecw_customer a
......@@ -201,7 +205,7 @@
left join ecw_customer_credit credit
on contact.credit_level = credit.id
left join ecw_country ec on contact.country = ec.id
left join member_user mu on contact.contact_member_id = mu.id
WHERE 1=1 AND contact.deleted = 0
......@@ -394,6 +398,19 @@
</foreach>
</if>
</if>
<!-- 会员信息 -->
<if test="query.memberCode != null and query.memberCode != '' ">
AND mu.code like concat('%',#{query.memberCode},'%')
</if>
<if test="query.memberName != null and query.memberName != '' ">
AND mu.nickname like concat('%',#{query.memberName},'%')
</if>
<if test="query.memberMobile != null and query.memberMobile != '' ">
AND mu.mobile like concat('%',#{query.memberMobile},'%')
</if>
<if test="query.memberAreaCode != null and query.memberAreaCode != '' ">
AND mu.area_code like concat('%',#{query.memberAreaCode},'%')
</if>
</sql>
<select id="getMyCustomerExcelVoList"
resultType="cn.iocoder.yudao.module.customer.dal.dataobject.customer.CustomerDO">
......@@ -447,6 +464,7 @@
c.social as default_social,
c.email as default_email,
c.social_number as default_social_number,
c.userid as contact_member_id,
su.nickname as customer_service_name,
su.dept_id as dept_id
from ecw_customer a
......@@ -458,7 +476,7 @@
left join ecw_customer_credit credit
on contact.credit_level = credit.id
left join ecw_country ec on contact.country = ec.id
left join member_user mu on contact.contact_member_id = mu.id
WHERE 1=1 AND contact.deleted = 0
<include refid="myCustomerQuery"/>
......@@ -660,6 +678,19 @@
</foreach>
</if>
</if>
<!-- 会员信息 -->
<if test="query.memberCode != null and query.memberCode != '' ">
AND mu.code like concat('%',#{query.memberCode},'%')
</if>
<if test="query.memberName != null and query.memberName != '' ">
AND mu.nickname like concat('%',#{query.memberName},'%')
</if>
<if test="query.memberMobile != null and query.memberMobile != '' ">
AND mu.mobile like concat('%',#{query.memberMobile},'%')
</if>
<if test="query.memberAreaCode != null and query.memberAreaCode != '' ">
AND mu.area_code like concat('%',#{query.memberAreaCode},'%')
</if>
</sql>
<select id="searchCustomer" resultType="cn.iocoder.yudao.module.customer.dal.dataobject.customer.CustomerDO">
select contact.*,
......@@ -1385,6 +1416,7 @@
c.social as default_social,
c.email as default_email,
c.social_number as default_social_number,
c.userid as contact_member_id,
su.nickname as customer_service_name,
su.dept_id as dept_id
from ecw_customer a
......@@ -1396,7 +1428,7 @@
left join ecw_customer_credit credit
on contact.credit_level = credit.id
left join ecw_country ec on contact.country = ec.id
left join member_user mu on contact.contact_member_id = mu.id
WHERE 1=1 AND contact.deleted = 0
......@@ -1419,6 +1451,7 @@
c.social as default_social,
c.email as default_email,
c.social_number as default_social_number,
c.userid as contact_member_id,
su.nickname as customer_service_name,
su.dept_id as dept_id
from ecw_customer a
......@@ -1430,7 +1463,7 @@
left join ecw_customer_credit credit
on contact.credit_level = credit.id
left join ecw_country ec on contact.country = ec.id
left join member_user mu on contact.contact_member_id = mu.id
WHERE 1=1 AND contact.deleted = 0
......@@ -1494,6 +1527,7 @@
c.social as default_social,
c.email as default_email,
c.social_number as default_social_number,
c.userid as contact_member_id,
su.nickname as customer_service_name,
su.dept_id as dept_id
from ecw_customer a
......@@ -1506,7 +1540,7 @@
on contact.credit_level = credit.id
left join ecw_country ec on contact.country = ec.id
left join member_user mu on contact.contact_member_id = mu.id
WHERE 1=1 AND contact.deleted = 0 AND contact.enter_open_sea_time is NOT NULL
<include refid="myCustomerQuery"/>
......@@ -1529,6 +1563,7 @@
c.social as default_social,
c.email as default_email,
c.social_number as default_social_number,
c.userid as contact_member_id,
su.nickname as customer_service_name,
su.dept_id as dept_id
from ecw_customer a
......@@ -1541,7 +1576,7 @@
on contact.credit_level = credit.id
left join ecw_country ec on contact.country = ec.id
left join member_user mu on contact.contact_member_id = mu.id
WHERE 1=1 AND contact.deleted = 0 AND contact.enter_open_sea_time is NOT NULL
<include refid="myCustomerQuery"/>
</select>
......@@ -1601,6 +1636,7 @@
c.social as default_social,
c.email as default_email,
c.social_number as default_social_number,
c.userid as contact_member_id,
su.nickname as customer_service_name,
su.dept_id as dept_id
from ecw_customer a
......@@ -1612,7 +1648,7 @@
left join ecw_customer_credit credit
on contact.credit_level = credit.id
left join ecw_country ec on contact.country = ec.id
left join member_user mu on contact.contact_member_id = mu.id
WHERE 1=1 AND contact.deleted = 0
<if test="deptId != null and deptId>0">
......@@ -1638,6 +1674,7 @@
c.social as default_social,
c.email as default_email,
c.social_number as default_social_number,
c.userid as contact_member_id,
su.nickname as customer_service_name,
su.dept_id as dept_id
from ecw_customer a
......@@ -1649,7 +1686,7 @@
left join ecw_customer_credit credit
on contact.credit_level = credit.id
left join ecw_country ec on contact.country = ec.id
left join member_user mu on contact.contact_member_id = mu.id
WHERE 1=1 AND contact.deleted = 0
<if test="deptId != null and deptId>0">
......
......@@ -49,12 +49,18 @@
concat( c.area_code, c.phone_new, '' ) AS default_contact_phone,
c.email AS default_email,
agent.NAME AS agent_customer_name,
su.nickname AS customer_service_name
su.nickname AS customer_service_name,
mu.code as member_code,
mu.nickname as member_nickname,
mu.mobile as member_mobile,
mu.area_code as member_area_code
FROM
ecw_indirect_customer a
LEFT JOIN ecw_indirect_customer_contacts c ON a.id = c.customer_id
LEFT JOIN ecw_customer agent ON a.agent_customer_id = agent.id
LEFT JOIN system_user su ON a.customer_service = su.id
left join ecw_customer_contacts ecc on agent.id = ecc.customer_id
left join member_user mu on ecc.userid = mu.id
WHERE
c.is_default = 1 AND a.deleted = 0
AND c.deleted = 0
......@@ -150,7 +156,19 @@
</foreach>
</if>
</if>
<!-- 会员信息 -->
<if test="query.memberCode != null and query.memberCode != '' ">
AND contact.member_code like concat('%',#{query.memberCode},'%')
</if>
<if test="query.memberName != null and query.memberName != '' ">
AND contact.member_nickname like concat('%',#{query.memberName},'%')
</if>
<if test="query.memberMobile != null and query.memberMobile != '' ">
AND contact.member_mobile like concat('%',#{query.memberMobile},'%')
</if>
<if test="query.memberAreaCode != null and query.memberAreaCode != '' ">
AND contact.member_area_code like concat('%',#{query.memberAreaCode},'%')
</if>
</sql>
<select id="getOpenSeaCustomerPageReqCount" resultType="java.lang.Long"
parameterType="cn.iocoder.yudao.module.customer.dto.indirectCustomer.IndirectCustomerPageReqDTO">
......@@ -164,12 +182,18 @@
concat( c.area_code, c.phone_new, '' ) AS default_contact_phone,
c.email AS default_email,
agent.NAME AS agent_customer_name,
su.nickname AS customer_service_name
su.nickname AS customer_service_name,
mu.code as member_code,
mu.nickname as member_nickname,
mu.mobile as member_mobile,
mu.area_code as member_area_code
FROM
ecw_indirect_customer a
LEFT JOIN ecw_indirect_customer_contacts c ON a.id = c.customer_id
LEFT JOIN ecw_customer agent ON a.agent_customer_id = agent.id
LEFT JOIN system_user su ON a.customer_service = su.id
left join ecw_customer_contacts ecc on agent.id = ecc.customer_id
left join member_user mu on ecc.userid = mu.id
WHERE
c.is_default = 1 AND a.deleted = 0
AND c.deleted = 0
......@@ -190,12 +214,18 @@
concat( c.area_code, c.phone_new, '' ) AS default_contact_phone,
c.email AS default_email,
agent.NAME AS agent_customer_name,
su.nickname AS customer_service_name
su.nickname AS customer_service_name,
mu.code as member_code,
mu.nickname as member_nickname,
mu.mobile as member_mobile,
mu.area_code as member_area_code
FROM
ecw_indirect_customer a
LEFT JOIN ecw_indirect_customer_contacts c ON a.id = c.customer_id
LEFT JOIN ecw_customer agent ON a.agent_customer_id = agent.id
LEFT JOIN system_user su ON a.customer_service = su.id
left join ecw_customer_contacts ecc on agent.id = ecc.customer_id
left join member_user mu on ecc.userid = mu.id
WHERE
c.is_default = 1 AND a.deleted = 0
AND c.deleted = 0
......
package cn.iocoder.yudao.module.member.controller.admin.job;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 会员编号刷新任务
* @author zhaobiyan
*/
@Component
@Slf4j
public class MemberCodeFlushTask implements JobHandler {
@Resource
private MemberUserService userService;
@Override
public String execute(String param) throws Exception {
userService.historyCodeFlush();
return "";
}
}
......@@ -36,6 +36,7 @@ import cn.iocoder.yudao.module.member.vo.userCardAuth.UserCardAuthCreateReqVO;
import cn.iocoder.yudao.module.member.vo.userEnterpriseAuth.UserEnterpriseAuthBackVO;
import cn.iocoder.yudao.module.member.vo.userEnterpriseAuth.UserEnterpriseAuthCreateReqVO;
import cn.iocoder.yudao.module.member.vo.userOperationLog.UserOperationLogBackVO;
import com.alibaba.excel.util.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
......@@ -459,5 +460,10 @@ public class MemberUserController {
return success(null);
}
@PutMapping("/memberCode/flush")
@ApiOperation("刷新历史会员编码")
public CommonResult<String> memberCodeFlush() {
userService.historyCodeFlush();
return success(null);
}
}
......@@ -234,6 +234,6 @@ public class MemberUserDO extends TenantBaseDO {
*/
private Boolean isDeal;
private String code;
}
......@@ -171,8 +171,12 @@ public interface MemberUserMapper extends BaseMapperX<MemberUserDO> {
"</script>"
})
MemberUserDO info(@Param("id") Long id);
@Update("update ecw_customer_contacts set userid = null where userid = #{userId}")
void unbindingCustomer(@Param("userId") Long userId);
String getCurrentMaxMemberCode();
void updateMemberCodeById(@Param("code")String memberCode, @Param("id")Long id);
void clearMemberCode();
}
......@@ -218,4 +218,7 @@ public interface MemberUserService {
void memberCancellation(Long userId);
List<MemberUserDO> getByCursor(Long startUserId, long limit);
void historyCodeFlush();
}
......@@ -12,6 +12,7 @@ import cn.iocoder.yudao.framework.i18n.core.I18nMessage;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.framework.redis.helper.RedisHelper;
import cn.iocoder.yudao.module.ecw.api.customer.CustomerApi;
import cn.iocoder.yudao.module.ecw.api.internalMessage.ClientInternalMessageApi;
import cn.iocoder.yudao.module.ecw.api.internalMessage.dto.InternalMessageCreateDto;
......@@ -32,19 +33,23 @@ import cn.iocoder.yudao.module.member.dal.mysql.userEnterpriseAuth.UserEnterpris
import cn.iocoder.yudao.module.member.enums.UserOperationLogTypeEnum;
import cn.iocoder.yudao.module.member.enums.UserQueryAuthTypeEnum;
import cn.iocoder.yudao.module.member.service.userOperationLog.UserOperationLogService;
import cn.iocoder.yudao.module.member.util.MemberUserCodeUtils;
import cn.iocoder.yudao.module.member.vo.member.MemberUpdateReqVO;
import cn.iocoder.yudao.module.member.vo.userOperationLog.UserOperationLogCreateReqVO;
import cn.iocoder.yudao.module.product.service.coupon.CouponService;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import com.alibaba.excel.util.CollectionUtils;
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.core.toolkit.Wrappers;
import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
......@@ -53,6 +58,7 @@ import javax.annotation.Resource;
import javax.validation.Valid;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
......@@ -102,6 +108,9 @@ public class MemberUserServiceImpl implements MemberUserService {
@Resource
private ParamValidatorApi paramValidatorApi;
@Resource
private RedisHelper redisHelper;
@Override
public MemberUserDO getUserByMobile(String mobile) {
......@@ -207,6 +216,7 @@ public class MemberUserServiceImpl implements MemberUserService {
}
user.setEnglishName(englishName);
user.setNickname(englishName);
user.setCode(getNextMemberCode());
memberUserMapper.insert(user);
//站内信
InternalMessageCreateDto dto = InternalMessageCreateDto.builder().toIdList(Arrays.asList(user.getId()))
......@@ -524,4 +534,62 @@ public class MemberUserServiceImpl implements MemberUserService {
memberUserMapper.unbindingCustomer(userId);
}
@Override
public List<MemberUserDO> getByCursor(Long startUserId, long limit) {
if (startUserId == null) {
return Collections.emptyList();
}
LambdaQueryWrapper<MemberUserDO> wrapper = Wrappers.lambdaQuery();
wrapper.gt(MemberUserDO::getId, startUserId);
wrapper.orderByAsc(MemberUserDO::getId);
wrapper.last("limit " + limit);
return memberUserMapper.getList(wrapper);
}
@Override
public void historyCodeFlush() {
Long startUserId = 0L;
long limit = 500;
memberUserMapper.clearMemberCode();
redisHelper.delete("memberCode:max:number");
while(true) {
List<MemberUserDO> result = this.getByCursor(startUserId, limit);
if (CollectionUtils.isEmpty(result)) {
break;
}
result.forEach(memberUserDO -> {
String memberCode = getNextMemberCode();
memberUserMapper.updateMemberCodeById(memberCode, memberUserDO.getId());
});
startUserId = result.stream().mapToLong(MemberUserDO::getId).max().orElse(Long.MAX_VALUE);
}
}
private String getNextMemberCode() {
String key = "memberCode:max:number";
String incrIfExistScript = "if redis.call(\"exists\", KEYS[1]) == 1 then\n" +
" return redis.call(\"incr\", KEYS[1])\n" +
"else\n" +
" return nil\n" +
"end";
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setScriptText(incrIfExistScript);
redisScript.setResultType(Long.class);
Long nextMemberCodeNumber = redisHelper.execute4Long(redisScript, Collections.singletonList(key));
if (nextMemberCodeNumber != null) {
return MemberUserCodeUtils.generateMemberCode(nextMemberCodeNumber);
}
synchronized(this) {
nextMemberCodeNumber = redisHelper.execute4Long(redisScript, Collections.singletonList(key));
if (nextMemberCodeNumber != null) {
return MemberUserCodeUtils.generateMemberCode(nextMemberCodeNumber);
}
String currentMaxMemberCode = memberUserMapper.getCurrentMaxMemberCode();
Long memberCodeMaxNumber = MemberUserCodeUtils.getMemberCodeNumber(currentMaxMemberCode);
redisHelper.set(key, String.valueOf(memberCodeMaxNumber), 5, TimeUnit.MINUTES);
return MemberUserCodeUtils.generateMemberCode(redisHelper.incrBy(key, 1));
}
}
}
package cn.iocoder.yudao.module.member.util;
import org.apache.commons.lang.StringUtils;
import org.json.JSONObject;
/**
* @author zhaobiyan
*/
public class MemberUserCodeUtils {
private static final String MEMBER_CODE_PREFIX = "EC";
private static final int DEFAULT_LENGTH = 6;
public static String generateMemberCode(Long codeNumber) {
StringBuilder codeNumberStr = new StringBuilder(String.valueOf(codeNumber));
if (codeNumberStr.length() >= DEFAULT_LENGTH) {
return MEMBER_CODE_PREFIX + codeNumberStr;
}
int supplyCount = DEFAULT_LENGTH - codeNumberStr.length();
for (int i = 0; i < supplyCount; i++) {
codeNumberStr.insert(0, "0");
}
return MEMBER_CODE_PREFIX + codeNumberStr;
}
public static Long getMemberCodeNumber(String currentMaxMemberCode) {
if (StringUtils.isBlank(currentMaxMemberCode)) {
return 0L;
}
String[] split = currentMaxMemberCode.split(MEMBER_CODE_PREFIX);
return Long.parseLong(split[1]);
}
}
......@@ -83,4 +83,15 @@
) as t
${ew.customSqlSegment}
</select>
<select id="getCurrentMaxMemberCode" resultType="String">
select code from member_user order by code desc limit 1
</select>
<update id="updateMemberCodeById" >
update member_user set code = #{code} where id = #{id}
</update>
<update id="clearMemberCode">
update member_user set code = ''
</update>
</mapper>
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