refactor: lead pool service

This commit is contained in:
song-cc-rock
2025-02-19 10:56:48 +08:00
committed by Craftsman
parent 8b26fc63ca
commit 249c5eaa9c
8 changed files with 127 additions and 61 deletions

View File

@@ -13,12 +13,11 @@ import io.cordys.crm.customer.domain.CustomerPoolRelation;
import io.cordys.crm.customer.dto.CustomerPoolDTO;
import io.cordys.crm.customer.dto.request.CustomerPoolSaveRequest;
import io.cordys.crm.customer.mapper.ExtCustomerPoolMapper;
import io.cordys.crm.system.constants.ScopeKey;
import io.cordys.crm.system.domain.Department;
import io.cordys.crm.system.domain.Role;
import io.cordys.crm.system.domain.User;
import io.cordys.crm.system.dto.ScopeNameDTO;
import io.cordys.crm.system.mapper.ExtUserMapper;
import io.cordys.crm.system.service.UserExtendService;
import io.cordys.mybatis.BaseMapper;
import io.cordys.mybatis.lambda.LambdaQueryWrapper;
import jakarta.annotation.Resource;
@@ -29,8 +28,6 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
@@ -54,6 +51,8 @@ public class CustomerPoolService {
private BaseMapper<CustomerPoolRelation> customerPoolRelationMapper;
@Resource
private ExtCustomerPoolMapper extCustomerPoolMapper;
@Resource
private UserExtendService userExtendService;
/**
* 分页获取公海池
@@ -76,8 +75,8 @@ public class CustomerPoolService {
List<Role> roles = roleMapper.selectByIds(unionIds.toArray(new String[0]));
List<Department> departments = departmentMapper.selectByIds(unionIds.toArray(new String[0]));
pools.forEach(pool -> {
pool.setMembers(getScope(users, roles, departments, JSON.parseArray(pool.getScopeId(), String.class)));
pool.setOwners(getScope(users, roles, departments, JSON.parseArray(pool.getOwnerId(), String.class)));
pool.setMembers(userExtendService.getScope(users, roles, departments, JSON.parseArray(pool.getScopeId(), String.class)));
pool.setOwners(userExtendService.getScope(users, roles, departments, JSON.parseArray(pool.getOwnerId(), String.class)));
});
return pools;
}
@@ -189,34 +188,4 @@ public class CustomerPoolService {
throw new GenericException(Translator.get("customer_pool_access_fail"));
}
}
/**
* 获取成员范围集合
* @param users 用户
* @param roles 角色
* @param departments 部门
* @param scopeIds 范围ID集合
* @return 范围集合
*/
private List<ScopeNameDTO> getScope(List<User> users, List<Role> roles, List<Department> departments, List<String> scopeIds) {
Map<String, String> userMap = users.stream().collect(Collectors.toMap(User::getId, User::getName));
Map<String, String> roleMap = roles.stream().collect(Collectors.toMap(Role::getId, Role::getName));
Map<String, String> departmentMap = departments.stream().collect(Collectors.toMap(Department::getId, Department::getName));
List<ScopeNameDTO> scopes = new ArrayList<>();
scopeIds.forEach(scopeId -> {
ScopeNameDTO scope = ScopeNameDTO.builder().id(scopeId).build();
if (userMap.containsKey(scopeId)) {
scope.setName(userMap.get(scopeId));
scope.setScope(ScopeKey.USER.name());
} else if (roleMap.containsKey(scopeId)) {
scope.setName(roleMap.get(scopeId));
scope.setScope(ScopeKey.ROLE.name());
} else if (departmentMap.containsKey(scopeId)) {
scope.setName(departmentMap.get(scopeId));
scope.setScope(ScopeKey.DEPARTMENT.name());
}
scopes.add(scope);
});
return scopes;
}
}

View File

@@ -1,15 +1,17 @@
package io.cordys.crm.lead.dto;
import io.cordys.crm.lead.domain.LeadPool;
import io.cordys.crm.system.dto.ScopeNameDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class LeadPoolDTO extends LeadPool {
@Schema(description = "管理员")
private String ownerName;
@Schema(description = "成员")
private String scopeName;
@Schema(description = "成员集合")
private List<ScopeNameDTO> members;
@Schema(description = "管理员集合")
private List<ScopeNameDTO> owners;
}

View File

@@ -1,10 +1,13 @@
package io.cordys.crm.lead.dto.request;
import io.cordys.crm.system.dto.RuleConditionDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
import lombok.NonNull;
import java.util.List;
@Data
@Builder
public class LeadPoolRecycleRuleSaveRequest {
@@ -20,5 +23,5 @@ public class LeadPoolRecycleRuleSaveRequest {
private String operator;
@Schema(description = "回收条件")
private String condition;
private List<RuleConditionDTO> conditions;
}

View File

@@ -4,11 +4,14 @@ import io.cordys.common.groups.Created;
import io.cordys.common.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import java.util.List;
@Data
@NoArgsConstructor
public class LeadPoolSaveRequest {
@@ -23,13 +26,13 @@ public class LeadPoolSaveRequest {
@Schema(description = "线索池名称")
private String name;
@NotBlank
@Schema(description = "成员ID")
private String scopeId;
@NotNull
@Schema(description = "范围ID集合")
private List<String> scopeIds;
@NotBlank
@Schema(description = "管理员ID")
private String ownerId;
@NotNull
@Schema(description = "管理员ID集合")
private List<String> ownerIds;
@NonNull
@Schema(description = "启用/禁用")

View File

@@ -4,6 +4,7 @@ import io.cordys.common.exception.GenericException;
import io.cordys.common.pager.condition.BasePageRequest;
import io.cordys.common.uid.IDGenerator;
import io.cordys.common.util.BeanUtils;
import io.cordys.common.util.JSON;
import io.cordys.common.util.Translator;
import io.cordys.context.OrganizationContext;
import io.cordys.crm.lead.domain.LeadPool;
@@ -14,7 +15,10 @@ import io.cordys.crm.lead.dto.LeadPoolDTO;
import io.cordys.crm.lead.dto.request.LeadPoolSaveRequest;
import io.cordys.crm.lead.mapper.ExtLeadPoolMapper;
import io.cordys.crm.system.domain.Department;
import io.cordys.crm.system.domain.Role;
import io.cordys.crm.system.domain.User;
import io.cordys.crm.system.mapper.ExtUserMapper;
import io.cordys.crm.system.service.UserExtendService;
import io.cordys.mybatis.BaseMapper;
import io.cordys.mybatis.lambda.LambdaQueryWrapper;
import jakarta.annotation.Resource;
@@ -25,16 +29,22 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class LeadPoolService {
@Resource
private ExtUserMapper extUserMapper;
@Resource
private BaseMapper<LeadPool> leadPoolMapper;
@Resource
private BaseMapper<User> userMapper;
@Resource
private BaseMapper<Role> roleMapper;
@Resource
private BaseMapper<Department> departmentMapper;
@Resource
private BaseMapper<LeadPoolPickRule> leadPoolPickRuleMapper;
@Resource
private BaseMapper<LeadPoolRecycleRule> leadPoolRecycleRuleMapper;
@@ -42,6 +52,8 @@ public class LeadPoolService {
private BaseMapper<LeadPoolRelation> leadPoolRelationMapper;
@Resource
private ExtLeadPoolMapper extLeadPoolMapper;
@Resource
private UserExtendService userExtendService;
/**
* 分页获取线索池
@@ -49,7 +61,25 @@ public class LeadPoolService {
* @return 线索池列表
*/
public List<LeadPoolDTO> page(BasePageRequest request) {
return extLeadPoolMapper.list(request, OrganizationContext.getOrganizationId());
List<LeadPoolDTO> pools = extLeadPoolMapper.list(request, OrganizationContext.getOrganizationId());
if (CollectionUtils.isEmpty(pools)) {
return new ArrayList<>();
}
List<String> scopeIds = new ArrayList<>();
List<String> ownerIds = new ArrayList<>();
pools.forEach(pool -> {
scopeIds.addAll(JSON.parseArray(pool.getScopeId(), String.class));
ownerIds.addAll(JSON.parseArray(pool.getOwnerId(), String.class));
});
List<String> unionIds = ListUtils.union(scopeIds, ownerIds).stream().distinct().toList();
List<User> users = userMapper.selectByIds(unionIds.toArray(new String[0]));
List<Role> roles = roleMapper.selectByIds(unionIds.toArray(new String[0]));
List<Department> departments = departmentMapper.selectByIds(unionIds.toArray(new String[0]));
pools.forEach(pool -> {
pool.setMembers(userExtendService.getScope(users, roles, departments, JSON.parseArray(pool.getScopeId(), String.class)));
pool.setOwners(userExtendService.getScope(users, roles, departments, JSON.parseArray(pool.getOwnerId(), String.class)));
});
return pools;
}
/**
@@ -60,6 +90,8 @@ public class LeadPoolService {
LeadPool pool = new LeadPool();
BeanUtils.copyBean(pool, request);
pool.setOrganizationId(currentOrgId);
pool.setOwnerId(JSON.toJSONString(request.getOwnerIds()));
pool.setScopeId(JSON.toJSONString(request.getScopeIds()));
pool.setUpdateTime(System.currentTimeMillis());
pool.setUpdateUser(currentUserId);
LeadPoolPickRule pickRule = new LeadPoolPickRule();
@@ -68,6 +100,7 @@ public class LeadPoolService {
pickRule.setUpdateUser(currentUserId);
LeadPoolRecycleRule recycleRule = new LeadPoolRecycleRule();
BeanUtils.copyBean(recycleRule, request.getRecycleRule());
recycleRule.setCondition(JSON.toJSONString(request.getRecycleRule().getConditions()));
recycleRule.setUpdateTime(System.currentTimeMillis());
recycleRule.setUpdateUser(currentUserId);
if (pool.getId() == null) {
@@ -150,9 +183,9 @@ public class LeadPoolService {
* @param accessUserId 访问用户ID
*/
private void checkPoolOwner(LeadPool pool, String accessUserId) {
// split multiple owner by comma
List<String> ownerIds = List.of(pool.getOwnerId().split(","));
if (!ownerIds.contains(accessUserId)) {
List<String> ownerIds = JSON.parseArray(pool.getOwnerId(), String.class);
List<String> ownerUserIds = extUserMapper.getUserIdsByScope(ownerIds, pool.getOrganizationId());
if (!ownerUserIds.contains(accessUserId)) {
throw new GenericException(Translator.get("lead_pool_access_fail"));
}
}

View File

@@ -0,0 +1,47 @@
package io.cordys.crm.system.service;
import io.cordys.crm.system.constants.ScopeKey;
import io.cordys.crm.system.domain.Department;
import io.cordys.crm.system.domain.Role;
import io.cordys.crm.system.domain.User;
import io.cordys.crm.system.dto.ScopeNameDTO;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class UserExtendService {
/**
* 获取成员范围集合
* @param users 用户
* @param roles 角色
* @param departments 部门
* @param scopeIds 范围ID集合
* @return 范围集合
*/
public List<ScopeNameDTO> getScope(List<User> users, List<Role> roles, List<Department> departments, List<String> scopeIds) {
Map<String, String> userMap = users.stream().collect(Collectors.toMap(User::getId, User::getName));
Map<String, String> roleMap = roles.stream().collect(Collectors.toMap(Role::getId, Role::getName));
Map<String, String> departmentMap = departments.stream().collect(Collectors.toMap(Department::getId, Department::getName));
List<ScopeNameDTO> scopes = new ArrayList<>();
scopeIds.forEach(scopeId -> {
ScopeNameDTO scope = ScopeNameDTO.builder().id(scopeId).build();
if (userMap.containsKey(scopeId)) {
scope.setName(userMap.get(scopeId));
scope.setScope(ScopeKey.USER.name());
} else if (roleMap.containsKey(scopeId)) {
scope.setName(roleMap.get(scopeId));
scope.setScope(ScopeKey.ROLE.name());
} else if (departmentMap.containsKey(scopeId)) {
scope.setName(departmentMap.get(scopeId));
scope.setScope(ScopeKey.DEPARTMENT.name());
}
scopes.add(scope);
});
return scopes;
}
}

View File

@@ -5,9 +5,9 @@ CREATE TABLE lead_pool
(
`id` VARCHAR(32) NOT NULL COMMENT 'id',
`name` VARCHAR(255) NOT NULL COMMENT '线索池名称',
`scope_id` VARCHAR(1000) NOT NULL COMMENT '成员id',
`scope_id` TEXT NOT NULL COMMENT '成员id',
`organization_id` VARCHAR(32) NOT NULL COMMENT '组织架构id',
`owner_id` VARCHAR(1000) NOT NULL COMMENT '管理员id',
`owner_id` TEXT NOT NULL COMMENT '管理员id',
`enable` BIT(1) NOT NULL DEFAULT 1 COMMENT '启用/禁用',
`auto` BIT(1) NOT NULL DEFAULT 0 COMMENT '自动回收',
`create_time` BIGINT NOT NULL COMMENT '创建时间',

View File

@@ -3,6 +3,7 @@ package io.cordys.crm.lead.controller;
import io.cordys.common.pager.Pager;
import io.cordys.common.pager.condition.BasePageRequest;
import io.cordys.common.util.BeanUtils;
import io.cordys.common.util.JSON;
import io.cordys.common.util.Translator;
import io.cordys.crm.base.BaseTest;
import io.cordys.crm.lead.domain.LeadPool;
@@ -13,6 +14,7 @@ import io.cordys.crm.lead.dto.LeadPoolDTO;
import io.cordys.crm.lead.dto.request.LeadPoolPickRuleSaveRequest;
import io.cordys.crm.lead.dto.request.LeadPoolRecycleRuleSaveRequest;
import io.cordys.crm.lead.dto.request.LeadPoolSaveRequest;
import io.cordys.crm.system.dto.RuleConditionDTO;
import io.cordys.mybatis.BaseMapper;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.MethodOrderer;
@@ -54,10 +56,16 @@ public class LeadPoolControllerTests extends BaseTest {
LeadPool leadPool = createLeadPool();
LeadPoolSaveRequest request = new LeadPoolSaveRequest();
BeanUtils.copyBean(request, leadPool);
request.setOwnerIds(List.of("cc"));
request.setScopeIds(List.of("cc"));
LeadPoolPickRuleSaveRequest pickRule = LeadPoolPickRuleSaveRequest.builder()
.pickNumber(1).limitOnNumber(true).pickIntervalDays(1).limitPreOwner(true).build();
request.setPickRule(pickRule);
LeadPoolRecycleRuleSaveRequest recycleRule = LeadPoolRecycleRuleSaveRequest.builder().expireNotice(true).noticeDays(10).build();
RuleConditionDTO condition = new RuleConditionDTO();
condition.setColumn("name");
condition.setOperator("=");
condition.setValues(List.of("cc"));
LeadPoolRecycleRuleSaveRequest recycleRule = LeadPoolRecycleRuleSaveRequest.builder().expireNotice(true).noticeDays(10).conditions(List.of(condition)).build();
request.setRecycleRule(recycleRule);
this.requestPostWithOk("/lead-pool/add", request);
}
@@ -80,6 +88,8 @@ public class LeadPoolControllerTests extends BaseTest {
leadPool.setId(testLeadPool.getId());
LeadPoolSaveRequest request = new LeadPoolSaveRequest();
BeanUtils.copyBean(request, leadPool);
request.setOwnerIds(List.of("cc"));
request.setScopeIds(List.of("cc"));
LeadPoolPickRuleSaveRequest pickRule = LeadPoolPickRuleSaveRequest.builder()
.pickNumber(1).limitOnNumber(true).pickIntervalDays(1).limitPreOwner(true).build();
request.setPickRule(pickRule);
@@ -88,9 +98,9 @@ public class LeadPoolControllerTests extends BaseTest {
MvcResult mvcResult = this.requestPost("/lead-pool/update", request).andExpect(status().is5xxServerError()).andReturn();
assert mvcResult.getResponse().getContentAsString().contains(Translator.get("lead_pool_access_fail"));
// update owner id by sql
leadPool.setOwnerId("admin");
leadPool.setOwnerId(JSON.toJSONString(List.of("admin")));
leadPoolMapper.updateById(leadPool);
request.setOwnerId("admin");
request.setOwnerIds(List.of("admin"));
this.requestPostWithOk("/lead-pool/update", request);
}
@@ -128,9 +138,8 @@ public class LeadPoolControllerTests extends BaseTest {
private LeadPool createLeadPool() {
LeadPool leadPool = new LeadPool();
leadPool.setName("default-lead-pool");
leadPool.setScopeId("default-dp");
leadPool.setScopeId(JSON.toJSONString(List.of("default-dp")));
leadPool.setOrganizationId(DEFAULT_ORGANIZATION_ID);
leadPool.setOwnerId("default-owner");
leadPool.setEnable(true);
leadPool.setAuto(true);
return leadPool;