0325-海宁pad走访修改
This commit is contained in:
@@ -4,6 +4,8 @@ import com.ruoyi.group.domain.dto.CustGroupMemberQueryDTO;
|
|||||||
import com.ruoyi.group.domain.entity.CustGroup;
|
import com.ruoyi.group.domain.entity.CustGroup;
|
||||||
import com.ruoyi.group.domain.entity.CustGroupMember;
|
import com.ruoyi.group.domain.entity.CustGroupMember;
|
||||||
import com.ruoyi.group.domain.vo.CustGroupMemberVO;
|
import com.ruoyi.group.domain.vo.CustGroupMemberVO;
|
||||||
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
import com.ruoyi.group.mapper.CustGroupMapper;
|
import com.ruoyi.group.mapper.CustGroupMapper;
|
||||||
import com.ruoyi.group.mapper.CustGroupMemberMapper;
|
import com.ruoyi.group.mapper.CustGroupMemberMapper;
|
||||||
import com.ruoyi.group.service.ICustGroupService;
|
import com.ruoyi.group.service.ICustGroupService;
|
||||||
@@ -43,7 +45,10 @@ public class CustGroupMemberServiceImpl implements ICustGroupMemberService {
|
|||||||
// 检查客群是否存在
|
// 检查客群是否存在
|
||||||
CustGroup custGroup = custGroupMapper.selectById(groupId);
|
CustGroup custGroup = custGroupMapper.selectById(groupId);
|
||||||
if (custGroup == null) {
|
if (custGroup == null) {
|
||||||
return "客群不存在";
|
throw new ServiceException("客群不存在");
|
||||||
|
}
|
||||||
|
if (!SecurityUtils.getUsername().equals(custGroup.getUserName())) {
|
||||||
|
throw new ServiceException("无权限操作该客群");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除客户关联
|
// 删除客户关联
|
||||||
@@ -52,6 +57,7 @@ public class CustGroupMemberServiceImpl implements ICustGroupMemberService {
|
|||||||
if (member != null && member.getGroupId().equals(groupId)) {
|
if (member != null && member.getGroupId().equals(groupId)) {
|
||||||
// 设置手动移除标识
|
// 设置手动移除标识
|
||||||
member.setManualRemove(1);
|
member.setManualRemove(1);
|
||||||
|
custGroupMemberMapper.updateById(member);
|
||||||
// 逻辑删除
|
// 逻辑删除
|
||||||
custGroupMemberMapper.deleteById(memberId);
|
custGroupMemberMapper.deleteById(memberId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import com.ruoyi.common.utils.StringUtils;
|
|||||||
import com.ruoyi.system.mapper.SysDeptMapper;
|
import com.ruoyi.system.mapper.SysDeptMapper;
|
||||||
import com.ruoyi.ibs.cmpm.domain.vo.GridCmpmVO;
|
import com.ruoyi.ibs.cmpm.domain.vo.GridCmpmVO;
|
||||||
import com.ruoyi.ibs.cmpm.service.GridCmpmService;
|
import com.ruoyi.ibs.cmpm.service.GridCmpmService;
|
||||||
import com.ruoyi.ibs.draw.mapper.DrawGridCustUserUnbindMapper;
|
import com.ruoyi.ibs.draw.mapper.DrawGridShapeRelateMapper;
|
||||||
import com.ruoyi.ibs.grid.service.RegionGridListService;
|
import com.ruoyi.ibs.grid.service.RegionGridListService;
|
||||||
import com.ruoyi.group.domain.dto.CustGroupMemberTemplate;
|
import com.ruoyi.group.domain.dto.CustGroupMemberTemplate;
|
||||||
import com.ruoyi.group.domain.dto.CustGroupQueryDTO;
|
import com.ruoyi.group.domain.dto.CustGroupQueryDTO;
|
||||||
@@ -59,7 +59,7 @@ public class CustGroupServiceImpl implements ICustGroupService {
|
|||||||
private RegionGridListService regionGridListService;
|
private RegionGridListService regionGridListService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private DrawGridCustUserUnbindMapper drawGridCustUserUnbindMapper;
|
private DrawGridShapeRelateMapper drawGridShapeRelateMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private TransactionTemplate transactionTemplate;
|
private TransactionTemplate transactionTemplate;
|
||||||
@@ -418,6 +418,8 @@ public class CustGroupServiceImpl implements ICustGroupService {
|
|||||||
|
|
||||||
log.info("找到 {} 个动态客群需要更新", dynamicGroups.size());
|
log.info("找到 {} 个动态客群需要更新", dynamicGroups.size());
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
|
int successCount = 0;
|
||||||
|
int failureCount = 0;
|
||||||
|
|
||||||
for (CustGroup custGroup : dynamicGroups) {
|
for (CustGroup custGroup : dynamicGroups) {
|
||||||
// 检查有效期,过期的客群跳过更新
|
// 检查有效期,过期的客群跳过更新
|
||||||
@@ -429,22 +431,18 @@ public class CustGroupServiceImpl implements ICustGroupService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
updateDynamicCustGroup(custGroup);
|
updateDynamicCustGroup(custGroup);
|
||||||
|
successCount++;
|
||||||
log.info("动态客群更新成功,客群ID:{},客群名称:{}", custGroup.getId(), custGroup.getGroupName());
|
log.info("动态客群更新成功,客群ID:{},客群名称:{}", custGroup.getId(), custGroup.getGroupName());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
failureCount++;
|
||||||
log.error("动态客群更新失败,客群ID:{},客群名称:{}", custGroup.getId(), custGroup.getGroupName(), e);
|
log.error("动态客群更新失败,客群ID:{},客群名称:{}", custGroup.getId(), custGroup.getGroupName(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("动态客群更新完成,总计:{},成功:{},失败:{}",
|
log.info("动态客群更新完成,总计:{},成功:{},失败:{}",
|
||||||
dynamicGroups.size(),
|
dynamicGroups.size(),
|
||||||
dynamicGroups.stream().filter(g -> {
|
successCount,
|
||||||
// 假设更新成功的状态设置
|
failureCount);
|
||||||
LambdaQueryWrapper<CustGroup> w = new LambdaQueryWrapper<>();
|
|
||||||
w.eq(CustGroup::getId, g.getId());
|
|
||||||
// 这里简单统计,实际可以通过更精确的方式
|
|
||||||
return true;
|
|
||||||
}).count(),
|
|
||||||
0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -655,7 +653,6 @@ public class CustGroupServiceImpl implements ICustGroupService {
|
|||||||
int batchSize = 1000;
|
int batchSize = 1000;
|
||||||
int successCount = 0;
|
int successCount = 0;
|
||||||
int skippedCount = 0;
|
int skippedCount = 0;
|
||||||
int restoredCount = 0;
|
|
||||||
for (int i = 0; i < memberList.size(); i += batchSize) {
|
for (int i = 0; i < memberList.size(); i += batchSize) {
|
||||||
int endIndex = Math.min(i + batchSize, memberList.size());
|
int endIndex = Math.min(i + batchSize, memberList.size());
|
||||||
List<CustGroupMember> batchList = memberList.subList(i, endIndex);
|
List<CustGroupMember> batchList = memberList.subList(i, endIndex);
|
||||||
@@ -665,30 +662,23 @@ public class CustGroupServiceImpl implements ICustGroupService {
|
|||||||
custGroupMemberMapper.insert(member);
|
custGroupMemberMapper.insert(member);
|
||||||
successCount++;
|
successCount++;
|
||||||
} catch (DuplicateKeyException e) {
|
} catch (DuplicateKeyException e) {
|
||||||
// 客户已存在,检查是否是被手动移除的
|
// 客户已存在(包含被手动移除后保留的记录),直接跳过,避免再次加入客群
|
||||||
LambdaQueryWrapper<CustGroupMember> queryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<CustGroupMember> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
queryWrapper.eq(CustGroupMember::getGroupId, member.getGroupId())
|
queryWrapper.eq(CustGroupMember::getGroupId, member.getGroupId())
|
||||||
.eq(CustGroupMember::getCustId, member.getCustId())
|
.eq(CustGroupMember::getCustId, member.getCustId())
|
||||||
.eq(CustGroupMember::getCustType, member.getCustType());
|
.eq(CustGroupMember::getCustType, member.getCustType());
|
||||||
CustGroupMember existMember = custGroupMemberMapper.selectOne(queryWrapper);
|
CustGroupMember existMember = custGroupMemberMapper.selectOne(queryWrapper);
|
||||||
|
skippedCount++;
|
||||||
if (existMember != null && existMember.getManualRemove() != null && existMember.getManualRemove() == 1) {
|
if (existMember != null && existMember.getManualRemove() != null && existMember.getManualRemove() == 1) {
|
||||||
// 是被手动移除的客户,清除标记并恢复
|
log.debug("客户已被手动移除,跳过重新导入:groupId={}, custId={}", member.getGroupId(), member.getCustId());
|
||||||
existMember.setManualRemove(0);
|
|
||||||
existMember.setDelFlag(0);
|
|
||||||
existMember.setCustName(member.getCustName());
|
|
||||||
custGroupMemberMapper.updateById(existMember);
|
|
||||||
restoredCount++;
|
|
||||||
log.debug("恢复手动移除的客户:groupId={}, custId={}", member.getGroupId(), member.getCustId());
|
|
||||||
} else {
|
} else {
|
||||||
// 正常存在的客户,跳过
|
|
||||||
skippedCount++;
|
|
||||||
log.debug("客户已存在,跳过:groupId={}, custId={}", member.getGroupId(), member.getCustId());
|
log.debug("客户已存在,跳过:groupId={}, custId={}", member.getGroupId(), member.getCustId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.info("客群客户导入完成(模板),客群ID:{},成功:{},跳过重复:{},恢复:{}",
|
log.info("客群客户导入完成(模板),客群ID:{},成功:{},跳过重复:{}",
|
||||||
custGroup.getId(), successCount, skippedCount, restoredCount);
|
custGroup.getId(), successCount, skippedCount);
|
||||||
// 更新创建状态为成功
|
// 更新创建状态为成功
|
||||||
custGroup.setCreateStatus("1");
|
custGroup.setCreateStatus("1");
|
||||||
custGroup.setUpdateBy(custGroup.getCreateBy());
|
custGroup.setUpdateBy(custGroup.getCreateBy());
|
||||||
@@ -747,7 +737,6 @@ public class CustGroupServiceImpl implements ICustGroupService {
|
|||||||
// 分批批量插入(每批1000条)
|
// 分批批量插入(每批1000条)
|
||||||
int batchSize = 1000;
|
int batchSize = 1000;
|
||||||
int totalInserted = 0;
|
int totalInserted = 0;
|
||||||
int totalRestored = 0;
|
|
||||||
int totalSkipped = 0;
|
int totalSkipped = 0;
|
||||||
|
|
||||||
for (int i = 0; i < memberList.size(); i += batchSize) {
|
for (int i = 0; i < memberList.size(); i += batchSize) {
|
||||||
@@ -759,28 +748,13 @@ public class CustGroupServiceImpl implements ICustGroupService {
|
|||||||
// SQL层面的批量插入
|
// SQL层面的批量插入
|
||||||
custGroupMemberMapper.batchInsertMembers(batchList);
|
custGroupMemberMapper.batchInsertMembers(batchList);
|
||||||
|
|
||||||
// 查询本批中被手动移除的客户,需要恢复
|
int manualRemovedCount = countManualRemovedMembers(custGroup.getId(), batchList);
|
||||||
List<CustGroupMember> toRestore = findManualRemovedToRestore(custGroup.getId(), batchList);
|
totalInserted += batchList.size() - manualRemovedCount;
|
||||||
if (!toRestore.isEmpty()) {
|
totalSkipped += manualRemovedCount;
|
||||||
// 恢复被手动移除的客户
|
|
||||||
for (CustGroupMember m : toRestore) {
|
|
||||||
batchList.stream()
|
|
||||||
.filter(b -> b.getCustId().equals(m.getCustId()) && b.getCustType().equals(m.getCustType()))
|
|
||||||
.findFirst()
|
|
||||||
.ifPresent(origin -> m.setCustName(origin.getCustName()));
|
|
||||||
m.setManualRemove(0);
|
|
||||||
custGroupMemberMapper.updateById(m);
|
|
||||||
}
|
|
||||||
log.info("本批恢复被手动移除的客户:{} 条", toRestore.size());
|
|
||||||
totalRestored += toRestore.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
totalInserted += batchList.size() - toRestore.size();
|
|
||||||
totalSkipped += toRestore.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("客群客户导入完成(网格),客群ID:{},插入:{},恢复:{},跳过:{}",
|
log.info("客群客户导入完成(网格),客群ID:{},插入:{},跳过:{}",
|
||||||
custGroup.getId(), totalInserted, totalRestored, totalSkipped);
|
custGroup.getId(), totalInserted, totalSkipped);
|
||||||
|
|
||||||
// 更新创建状态为成功
|
// 更新创建状态为成功
|
||||||
custGroup.setCreateStatus("1");
|
custGroup.setCreateStatus("1");
|
||||||
@@ -814,29 +788,21 @@ public class CustGroupServiceImpl implements ICustGroupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查找需要恢复的被手动移除的客户
|
* 统计本批中被手动移除、因此需要持续排除的客户数量
|
||||||
*
|
|
||||||
* @param groupId 客群ID
|
|
||||||
* @param batchList 本批导入的客户列表
|
|
||||||
* @return 需要恢复的客户列表
|
|
||||||
*/
|
*/
|
||||||
private List<CustGroupMember> findManualRemovedToRestore(Long groupId, List<CustGroupMember> batchList) {
|
private int countManualRemovedMembers(Long groupId, List<CustGroupMember> batchList) {
|
||||||
// 构建本批客户的 (custId, custType) 集合
|
|
||||||
Set<String> batchKeys = batchList.stream()
|
Set<String> batchKeys = batchList.stream()
|
||||||
.map(m -> m.getCustId() + "|" + m.getCustType())
|
.map(m -> m.getCustId() + "|" + m.getCustType())
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
// 查询该客群所有被手动移除的客户
|
|
||||||
LambdaQueryWrapper<CustGroupMember> queryWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<CustGroupMember> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
queryWrapper.eq(CustGroupMember::getGroupId, groupId)
|
queryWrapper.eq(CustGroupMember::getGroupId, groupId)
|
||||||
.eq(CustGroupMember::getManualRemove, 1)
|
.eq(CustGroupMember::getManualRemove, 1);
|
||||||
.eq(CustGroupMember::getDelFlag, 0);
|
|
||||||
List<CustGroupMember> manualRemovedList = custGroupMemberMapper.selectList(queryWrapper);
|
List<CustGroupMember> manualRemovedList = custGroupMemberMapper.selectList(queryWrapper);
|
||||||
|
|
||||||
// 筛选出本批中需要恢复的
|
return (int) manualRemovedList.stream()
|
||||||
return manualRemovedList.stream()
|
|
||||||
.filter(m -> batchKeys.contains(m.getCustId() + "|" + m.getCustType()))
|
.filter(m -> batchKeys.contains(m.getCustId() + "|" + m.getCustType()))
|
||||||
.collect(Collectors.toList());
|
.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -907,7 +873,7 @@ public class CustGroupServiceImpl implements ICustGroupService {
|
|||||||
}
|
}
|
||||||
// 使用 selectCustByDrawGridId 方法(直接在SQL中拼接headId,绕过拦截器)
|
// 使用 selectCustByDrawGridId 方法(直接在SQL中拼接headId,绕过拦截器)
|
||||||
for (Long gridId : gridImportDTO.getDrawGridIds()) {
|
for (Long gridId : gridImportDTO.getDrawGridIds()) {
|
||||||
List<RegionCustUser> custUsers = drawGridCustUserUnbindMapper.selectCustByDrawGridId(gridId, headId);
|
List<RegionCustUser> custUsers = drawGridShapeRelateMapper.selectCustByDrawGridId(gridId, headId);
|
||||||
if (custUsers != null && !custUsers.isEmpty()) {
|
if (custUsers != null && !custUsers.isEmpty()) {
|
||||||
for (RegionCustUser custUser : custUsers) {
|
for (RegionCustUser custUser : custUsers) {
|
||||||
CustGroupMember member = new CustGroupMember();
|
CustGroupMember member = new CustGroupMember();
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|||||||
import com.ruoyi.ibs.draw.domain.dto.grid.DrawGridCustListDTO;
|
import com.ruoyi.ibs.draw.domain.dto.grid.DrawGridCustListDTO;
|
||||||
import com.ruoyi.ibs.draw.domain.entity.DrawGridCustUserUnbind;
|
import com.ruoyi.ibs.draw.domain.entity.DrawGridCustUserUnbind;
|
||||||
import com.ruoyi.ibs.draw.domain.vo.DrawGridCustVO;
|
import com.ruoyi.ibs.draw.domain.vo.DrawGridCustVO;
|
||||||
import com.ruoyi.ibs.grid.domain.entity.RegionCustUser;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -19,14 +17,4 @@ public interface DrawGridCustUserUnbindMapper extends BaseMapper<DrawGridCustUse
|
|||||||
List<DrawGridCustVO> getCustList(DrawGridCustListDTO drawGridCustListDTO);
|
List<DrawGridCustVO> getCustList(DrawGridCustListDTO drawGridCustListDTO);
|
||||||
|
|
||||||
List<DrawGridCustVO> getCustListByManager(DrawGridCustListDTO drawGridCustListDTO);
|
List<DrawGridCustVO> getCustListByManager(DrawGridCustListDTO drawGridCustListDTO);
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据绘制网格ID查询所有客户(用于客群导入,拼接headId绕过拦截器)
|
|
||||||
* @param gridId 绘制网格ID
|
|
||||||
* @param headId 总行机构号前三位(用于拼接动态表名)
|
|
||||||
* @return 客户列表
|
|
||||||
*/
|
|
||||||
List<RegionCustUser> selectCustByDrawGridId(@Param("gridId") Long gridId, @Param("headId") String headId);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ package com.ruoyi.ibs.draw.mapper;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.ruoyi.ibs.draw.domain.entity.DrawGridShapeRelate;
|
import com.ruoyi.ibs.draw.domain.entity.DrawGridShapeRelate;
|
||||||
|
import com.ruoyi.ibs.grid.domain.entity.RegionCustUser;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author 吴凯程
|
* @Author 吴凯程
|
||||||
@@ -23,10 +23,7 @@ public interface DrawGridShapeRelateMapper extends BaseMapper<DrawGridShapeRelat
|
|||||||
List<DrawGridShapeRelate> selectByGridId(@Param("gridId") Long gridId);
|
List<DrawGridShapeRelate> selectByGridId(@Param("gridId") Long gridId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据网格ID查询所有客户(用于客群导入,直接拼接headId绕过拦截器)
|
* 根据绘制网格ID查询所有客户(用于客群导入,直接拼接headId绕过拦截器)
|
||||||
* @param gridId 网格ID
|
|
||||||
* @param headId 部门代码(用于拼接动态表名)
|
|
||||||
* @return 客户列表,包含 custId, custName, custType
|
|
||||||
*/
|
*/
|
||||||
List<Map<String, Object>> selectCustListByGridId(@Param("gridId") Long gridId, @Param("headId") String headId);
|
List<RegionCustUser> selectCustByDrawGridId(@Param("gridId") Long gridId, @Param("headId") String headId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,16 +56,4 @@
|
|||||||
<if test="custType != null and custType != ''">AND b.cust_type = #{custType}</if>
|
<if test="custType != null and custType != ''">AND b.cust_type = #{custType}</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 根据绘制网格ID查询所有客户(用于客群导入,直接拼接headId绕过拦截器) -->
|
|
||||||
<select id="selectCustByDrawGridId" resultType="com.ruoyi.ibs.grid.domain.entity.RegionCustUser">
|
|
||||||
SELECT DISTINCT
|
|
||||||
sc.cust_id,
|
|
||||||
sc.cust_name,
|
|
||||||
sc.cust_type
|
|
||||||
FROM grid_draw_shape_relate sr
|
|
||||||
INNER JOIN draw_shape_cust_${headId} sc ON sc.shape_id = sr.shape_id
|
|
||||||
WHERE sr.grid_id = #{gridId}
|
|
||||||
AND sr.delete_flag = '0'
|
|
||||||
</select>
|
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper
|
||||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.ruoyi.ibs.draw.mapper.DrawGridShapeRelateMapper">
|
||||||
|
|
||||||
|
<select id="selectByGridId" resultType="com.ruoyi.ibs.draw.domain.entity.DrawGridShapeRelate">
|
||||||
|
SELECT *
|
||||||
|
FROM grid_draw_shape_relate
|
||||||
|
WHERE grid_id = #{gridId}
|
||||||
|
AND delete_flag = '0'
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectCustByDrawGridId" resultType="com.ruoyi.ibs.grid.domain.entity.RegionCustUser">
|
||||||
|
SELECT DISTINCT
|
||||||
|
sc.cust_id,
|
||||||
|
sc.cust_name,
|
||||||
|
sc.cust_type
|
||||||
|
FROM grid_draw_shape_relate sr
|
||||||
|
INNER JOIN draw_shape_cust_${headId} sc ON sc.shape_id = sr.shape_id
|
||||||
|
WHERE sr.grid_id = #{gridId}
|
||||||
|
AND sr.delete_flag = '0'
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -68,7 +68,7 @@ mybatis-plus:
|
|||||||
# 搜索指定包别名
|
# 搜索指定包别名
|
||||||
typeAliasesPackage: com.ruoyi.**.domain
|
typeAliasesPackage: com.ruoyi.**.domain
|
||||||
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||||
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
mapperLocations: classpath*:mapper/*Mapper.xml,classpath*:mapper/**/*Mapper.xml
|
||||||
# 加载全局的配置文件
|
# 加载全局的配置文件
|
||||||
configLocation: classpath:mybatis/mybatis-config.xml
|
configLocation: classpath:mybatis/mybatis-config.xml
|
||||||
type-handlers-package: com.ruoyi.ibs.handler
|
type-handlers-package: com.ruoyi.ibs.handler
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ export function deleteCustGroup(idList) {
|
|||||||
// 手动移除客群客户
|
// 手动移除客群客户
|
||||||
export function removeMembers(groupId, memberIds) {
|
export function removeMembers(groupId, memberIds) {
|
||||||
return request({
|
return request({
|
||||||
url: '/group/cust/removeMembers',
|
url: '/group/member/remove',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
params: { groupId: groupId },
|
params: { groupId: groupId },
|
||||||
data: memberIds
|
data: memberIds
|
||||||
|
|||||||
@@ -48,6 +48,11 @@
|
|||||||
<el-table-column label="身份证号" prop="custIdc" show-overflow-tooltip />
|
<el-table-column label="身份证号" prop="custIdc" show-overflow-tooltip />
|
||||||
<el-table-column label="统信码" prop="socialCreditCode" show-overflow-tooltip />
|
<el-table-column label="统信码" prop="socialCreditCode" show-overflow-tooltip />
|
||||||
<el-table-column label="添加时间" prop="createTime" width="180" />
|
<el-table-column label="添加时间" prop="createTime" width="180" />
|
||||||
|
<el-table-column v-if="isMineView" label="操作" align="center" width="100" fixed="right">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button type="text" size="mini" @click="handleRemove(scope.row)">移除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
@@ -63,7 +68,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listCustGroupMembers } from '@/api/group/custGroup'
|
import { listCustGroupMembers, removeMembers } from '@/api/group/custGroup'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CustGroupDetail',
|
name: 'CustGroupDetail',
|
||||||
@@ -71,6 +76,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
groupId: null,
|
groupId: null,
|
||||||
|
viewType: 'mine',
|
||||||
memberList: [],
|
memberList: [],
|
||||||
total: 0,
|
total: 0,
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@@ -83,6 +89,7 @@ export default {
|
|||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.groupId = this.$route.query.groupId
|
this.groupId = this.$route.query.groupId
|
||||||
|
this.viewType = this.$route.query.viewType || 'mine'
|
||||||
if (this.groupId) {
|
if (this.groupId) {
|
||||||
this.getList()
|
this.getList()
|
||||||
} else {
|
} else {
|
||||||
@@ -94,11 +101,17 @@ export default {
|
|||||||
'$route.query.groupId'(newGroupId) {
|
'$route.query.groupId'(newGroupId) {
|
||||||
if (newGroupId && newGroupId !== this.groupId) {
|
if (newGroupId && newGroupId !== this.groupId) {
|
||||||
this.groupId = newGroupId
|
this.groupId = newGroupId
|
||||||
|
this.viewType = this.$route.query.viewType || 'mine'
|
||||||
this.queryParams.pageNum = 1
|
this.queryParams.pageNum = 1
|
||||||
this.getList()
|
this.getList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
isMineView() {
|
||||||
|
return this.viewType === 'mine'
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/** 查询客户列表 */
|
/** 查询客户列表 */
|
||||||
getList(param) {
|
getList(param) {
|
||||||
@@ -128,9 +141,27 @@ export default {
|
|||||||
this.handleQuery()
|
this.handleQuery()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleRemove(row) {
|
||||||
|
this.$modal.confirm(`确认移除客户“${row.custName || row.custId}”吗?移除后后续动态更新不会再加入客群。`).then(() => {
|
||||||
|
return removeMembers(this.groupId, [row.id])
|
||||||
|
}).then(() => {
|
||||||
|
this.$modal.msgSuccess('移除成功')
|
||||||
|
if (this.memberList.length === 1 && this.queryParams.pageNum > 1) {
|
||||||
|
this.queryParams.pageNum -= 1
|
||||||
|
}
|
||||||
|
this.getList()
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
|
||||||
/** 返回 */
|
/** 返回 */
|
||||||
goBack() {
|
goBack() {
|
||||||
this.$router.push({ path: '/group/custGroup' })
|
this.$router.push({
|
||||||
|
path: '/group/custGroup',
|
||||||
|
query: {
|
||||||
|
tab: this.viewType,
|
||||||
|
refresh: Date.now()
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
/** 序号计算方法 */
|
/** 序号计算方法 */
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="customer-wrap">
|
<div class="customer-wrap">
|
||||||
<el-radio-group v-model="activeTab" class="group-tab-radio" @input="handleTabChange">
|
<div class="nav_box">
|
||||||
<el-radio-button label="mine">我创建的</el-radio-button>
|
<el-radio-group v-model="activeTab" class="header-radio" @input="handleTabChange">
|
||||||
<el-radio-button label="sharedToMe">下发给我的</el-radio-button>
|
<el-radio-button label="mine">我创建的</el-radio-button>
|
||||||
</el-radio-group>
|
<el-radio-button label="sharedToMe">下发给我的</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-show="showSearch" class="search-area">
|
<div v-show="showSearch" class="search-area">
|
||||||
<el-form
|
<el-form
|
||||||
@@ -214,8 +216,16 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
this.activeTab = this.$route.query.tab || 'mine'
|
||||||
this.getList()
|
this.getList()
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
'$route.query.refresh'() {
|
||||||
|
this.activeTab = this.$route.query.tab || 'mine'
|
||||||
|
this.queryParams.pageNum = 1
|
||||||
|
this.getList()
|
||||||
|
}
|
||||||
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.clearRefreshTimer()
|
this.clearRefreshTimer()
|
||||||
},
|
},
|
||||||
@@ -304,7 +314,7 @@ export default {
|
|||||||
handleView(row) {
|
handleView(row) {
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
path: '/group/custGroup/detail',
|
path: '/group/custGroup/detail',
|
||||||
query: { groupId: row.id }
|
query: { groupId: row.id, viewType: this.activeTab }
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -347,61 +357,66 @@ export default {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow: 0 3px 8px 0 #00000017;
|
box-shadow: 0 3px 8px 0 #00000017;
|
||||||
border-radius: 16px 16px 0 0;
|
border-radius: 16px 16px 0 0;
|
||||||
padding: 24px 30px;
|
padding: 0 30px 24px;
|
||||||
|
|
||||||
.group-tab-radio {
|
.nav_box {
|
||||||
display: flex;
|
overflow: hidden;
|
||||||
align-items: center;
|
margin: 0 -30px 8px;
|
||||||
justify-content: space-between;
|
border-radius: 16px 16px 0 0;
|
||||||
border-bottom: 1px solid #ebebeb;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
|
|
||||||
.el-radio-button {
|
.header-radio {
|
||||||
flex: 1;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid #ebebeb;
|
||||||
|
|
||||||
::v-deep .el-radio-button__inner {
|
.el-radio-button {
|
||||||
width: 100%;
|
flex: 1;
|
||||||
border: none;
|
|
||||||
font-weight: 400;
|
|
||||||
letter-spacing: 0.44px;
|
|
||||||
line-height: 25px;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #666666;
|
|
||||||
padding: 11px 0 12px 0;
|
|
||||||
border-radius: 0;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
::v-deep .el-radio-button__orig-radio:checked + .el-radio-button__inner {
|
::v-deep .el-radio-button__inner {
|
||||||
background-color: #4886f8;
|
width: 100%;
|
||||||
font-weight: 400;
|
border: none;
|
||||||
color: #ffffff;
|
font-weight: 400;
|
||||||
border-bottom-left-radius: 0;
|
letter-spacing: 0.44px;
|
||||||
border-bottom-right-radius: 0;
|
line-height: 25px;
|
||||||
}
|
font-size: 16px;
|
||||||
|
color: #666666;
|
||||||
&:nth-child(2) {
|
padding: 11px 0 12px 0;
|
||||||
&::before,
|
border-radius: 0;
|
||||||
&::after {
|
box-shadow: none;
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
height: 21px;
|
|
||||||
width: 1px;
|
|
||||||
background: #ebebeb;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&::after {
|
::v-deep .el-radio-button__orig-radio:checked + .el-radio-button__inner {
|
||||||
right: 1px;
|
background-color: #4886f8;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #ffffff;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
&.is-active {
|
&:nth-child(2) {
|
||||||
&::before,
|
&::before,
|
||||||
&::after {
|
&::after {
|
||||||
content: none;
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
height: 21px;
|
||||||
|
width: 1px;
|
||||||
|
background: #ebebeb;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
right: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -371,21 +371,30 @@
|
|||||||
width="150px"
|
width="150px"
|
||||||
v-if="columns[16].visible"
|
v-if="columns[16].visible"
|
||||||
></el-table-column>
|
></el-table-column>
|
||||||
<el-table-column align="left" prop="interAddr" label="实地拜访地址" show-overflow-tooltip width="180px" v-if="columns[17].visible"></el-table-column>
|
<el-table-column align="left" prop="interAddr" label="实地拜访地址" show-overflow-tooltip width="180px" v-if="isPersonalFeedbackTab && columns[17].visible"></el-table-column>
|
||||||
<el-table-column align="left" prop="colStafName" label="协同走访客户经理" show-overflow-tooltip width="160px" v-if="columns[18].visible"></el-table-column>
|
<el-table-column align="left" prop="colStafName" label="协同走访客户经理" show-overflow-tooltip width="160px" v-if="isPersonalFeedbackTab && columns[18].visible"></el-table-column>
|
||||||
<el-table-column align="left" prop="laterNote" label="事后备注" show-overflow-tooltip width="180px" v-if="columns[19].visible"></el-table-column>
|
<el-table-column align="left" prop="laterNote" label="事后备注" show-overflow-tooltip width="180px" v-if="isPersonalFeedbackTab && columns[19].visible"></el-table-column>
|
||||||
<el-table-column align="left" prop="intentionProductValue" label="走访反馈" show-overflow-tooltip width="160px" v-if="columns[20].visible"></el-table-column>
|
<el-table-column align="left" prop="intentionProductValue" label="走访反馈" show-overflow-tooltip width="160px" v-if="isPersonalFeedbackTab && columns[20].visible"></el-table-column>
|
||||||
<el-table-column align="left" prop="feedbackStatus" label="反馈状态" show-overflow-tooltip width="120px" v-if="columns[21].visible"></el-table-column>
|
<el-table-column align="left" prop="feedbackStatus" label="反馈状态" show-overflow-tooltip width="120px" v-if="isPersonalFeedbackTab && columns[21].visible"></el-table-column>
|
||||||
<el-table-column align="left" prop="sourceOfInterview" label="走访来源" show-overflow-tooltip width="140px" v-if="columns[22].visible"></el-table-column>
|
<el-table-column align="left" prop="sourceOfInterview" label="走访来源" show-overflow-tooltip width="140px" v-if="isPersonalFeedbackTab && columns[22].visible"></el-table-column>
|
||||||
<el-table-column align="left" prop="filename" label="批量导入文件名" show-overflow-tooltip width="180px" v-if="columns[23].visible"></el-table-column>
|
<el-table-column align="left" prop="filename" label="批量导入文件名" show-overflow-tooltip width="180px" v-if="isPersonalFeedbackTab && columns[23].visible"></el-table-column>
|
||||||
<el-table-column align="left" prop="outCallStatus" label="外呼状态" show-overflow-tooltip width="120px" v-if="columns[24].visible"></el-table-column>
|
<el-table-column align="left" prop="outCallStatus" label="外呼状态" show-overflow-tooltip width="120px" v-if="isPersonalFeedbackTab && columns[24].visible"></el-table-column>
|
||||||
<el-table-column align="left" prop="outCallIntention" label="客户意愿" show-overflow-tooltip width="140px" v-if="columns[25].visible"></el-table-column>
|
<el-table-column align="left" prop="outCallIntention" label="客户意愿" show-overflow-tooltip width="140px" v-if="isPersonalFeedbackTab && columns[25].visible"></el-table-column>
|
||||||
<el-table-column align="left" prop="source" label="走访渠道" show-overflow-tooltip width="120px" v-if="columns[26].visible"></el-table-column>
|
<el-table-column align="left" prop="source" label="走访渠道" show-overflow-tooltip width="120px" v-if="isPersonalFeedbackTab && columns[26].visible">
|
||||||
<el-table-column align="left" prop="analysisValue" label="nlp模型提取" show-overflow-tooltip width="140px" v-if="columns[27].visible"></el-table-column>
|
|
||||||
<el-table-column align="left" prop="facility" label="预授信额度" show-overflow-tooltip width="140px" v-if="columns[28].visible"></el-table-column>
|
|
||||||
<el-table-column align="center" label="操作" fixed="right" width="100">
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button type="text" size="mini" @click="handleEditFeedback(scope.row)">编辑</el-button>
|
<span>{{ formatSourceLabel(scope.row.source) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="left" prop="analysisValue" label="nlp模型提取" show-overflow-tooltip width="140px" v-if="isPersonalFeedbackTab && columns[27].visible"></el-table-column>
|
||||||
|
<el-table-column align="left" prop="facility" label="预授信额度" show-overflow-tooltip width="140px" v-if="isPersonalFeedbackTab && columns[28].visible"></el-table-column>
|
||||||
|
<el-table-column v-if="isPersonalFeedbackTab" align="center" label="操作" fixed="right" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
size="mini"
|
||||||
|
:disabled="isFeedbackCompleted(scope.row)"
|
||||||
|
@click="handleEditFeedback(scope.row)"
|
||||||
|
>反馈</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -410,7 +419,7 @@
|
|||||||
<el-form ref="feedbackFormRef" :model="feedbackForm" label-width="100px" class="feedback-form">
|
<el-form ref="feedbackFormRef" :model="feedbackForm" label-width="100px" class="feedback-form">
|
||||||
<el-form-item label="走访渠道" required>
|
<el-form-item label="走访渠道" required>
|
||||||
<el-radio-group v-model="feedbackForm.source">
|
<el-radio-group v-model="feedbackForm.source">
|
||||||
<el-radio v-for="item in sourceOptions" :key="item" :label="item">{{ item }}</el-radio>
|
<el-radio v-for="item in sourceOptions" :key="item.value" :label="item.value">{{ item.label }}</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="客户意愿" required>
|
<el-form-item label="客户意愿" required>
|
||||||
@@ -429,7 +438,7 @@
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="预览结果">
|
<el-form-item label="走访反馈">
|
||||||
<div class="feedback-preview">{{ feedbackPreview || "-" }}</div>
|
<div class="feedback-preview">{{ feedbackPreview || "-" }}</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@@ -445,7 +454,11 @@
|
|||||||
import { mapGetters } from "vuex";
|
import { mapGetters } from "vuex";
|
||||||
import { getPADVisitRecord, updatePADVisitFeedback } from "@/api/task/PADvisitRecord.js";
|
import { getPADVisitRecord, updatePADVisitFeedback } from "@/api/task/PADvisitRecord.js";
|
||||||
|
|
||||||
const SOURCE_OPTIONS = ["企业微信", "PAD"];
|
const SOURCE_OPTIONS = [
|
||||||
|
{ label: "PAD", value: "1" },
|
||||||
|
{ label: "企业微信", value: "2" },
|
||||||
|
{ label: "电话", value: "4" }
|
||||||
|
];
|
||||||
const FEEDBACK_TYPE_OPTIONS = ["拒绝", "考虑", "意愿", "其他", "愿意", "现场办理"];
|
const FEEDBACK_TYPE_OPTIONS = ["拒绝", "考虑", "意愿", "其他", "愿意", "现场办理"];
|
||||||
const FEEDBACK_PRODUCT_OPTIONS = [
|
const FEEDBACK_PRODUCT_OPTIONS = [
|
||||||
"丰收互联",
|
"丰收互联",
|
||||||
@@ -567,7 +580,11 @@ export default {
|
|||||||
},
|
},
|
||||||
// 海宁
|
// 海宁
|
||||||
is875() {
|
is875() {
|
||||||
return this.userName.slice(0, 3) === '875'
|
const deptId = this.deptId === null || this.deptId === undefined ? '' : String(this.deptId)
|
||||||
|
return deptId.slice(0, 3) === '965'
|
||||||
|
},
|
||||||
|
isPersonalFeedbackTab() {
|
||||||
|
return this.is875 && this.selectedTab === '0'
|
||||||
},
|
},
|
||||||
feedbackPreview() {
|
feedbackPreview() {
|
||||||
return this.buildFeedbackValue(this.feedbackForm.feedbackSelections)
|
return this.buildFeedbackValue(this.feedbackForm.feedbackSelections)
|
||||||
@@ -632,10 +649,23 @@ export default {
|
|||||||
.map(item => `${item.feedbackType}:${item.products.join(",")}`)
|
.map(item => `${item.feedbackType}:${item.products.join(",")}`)
|
||||||
.join(";");
|
.join(";");
|
||||||
},
|
},
|
||||||
|
isFeedbackCompleted(row) {
|
||||||
|
const source = row && row.source !== null && row.source !== undefined ? String(row.source).trim() : "";
|
||||||
|
const intentionProductValue = row && row.intentionProductValue ? String(row.intentionProductValue).trim() : "";
|
||||||
|
return !!source && !!intentionProductValue;
|
||||||
|
},
|
||||||
|
formatSourceLabel(source) {
|
||||||
|
const sourceValue = source === null || source === undefined ? "" : String(source);
|
||||||
|
const matched = this.sourceOptions.find(item => item.value === sourceValue);
|
||||||
|
return matched ? matched.label : (sourceValue || "-");
|
||||||
|
},
|
||||||
handleEditFeedback(row) {
|
handleEditFeedback(row) {
|
||||||
|
if (this.isFeedbackCompleted(row)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.feedbackForm = {
|
this.feedbackForm = {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
source: row.source || "",
|
source: row.source === null || row.source === undefined ? "" : String(row.source),
|
||||||
feedbackSelections: this.parseFeedbackValue(row.intentionProductValue)
|
feedbackSelections: this.parseFeedbackValue(row.intentionProductValue)
|
||||||
};
|
};
|
||||||
this.feedbackDialogVisible = true;
|
this.feedbackDialogVisible = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user