Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,20 @@ private List<ClueOwnerListResponse> buildListData(String orgId, List<ClueOwner>
List<DictConfig> configs = dictConfigMapper.selectListByLambda(configLambdaQueryWrapper);
boolean showReason = CollectionUtils.isNotEmpty(configs) && configs.getFirst().getEnabled();

Map<String, UserDeptDTO> userDeptMap = baseService.getUserDeptMapByUserIds(new ArrayList<>(ownerIds), orgId);
Map<String, UserDeptDTO> userDeptMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
Map<String, UserDeptDTO> originUserDeptMap = baseService.getUserDeptMapByUserIds(new ArrayList<>(ownerIds), orgId);
userDeptMap.putAll(originUserDeptMap);

Map<String, String> userNameMap = baseService.getUserNameMap(userIds);
Map<String, String> userNameMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
userNameMap.putAll(baseService.getUserNameMap(userIds));

List<Dict> dictList = dictMapper.selectByIds(new ArrayList<>(reasonIds));
Map<String, String> dictNameMap = dictList.stream().collect(Collectors.toMap(Dict::getId, Dict::getName));
Map<String, String> dictNameMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
if (!reasonIds.isEmpty()) {
List<Dict> dictList = dictMapper.selectByIds(new ArrayList<>(reasonIds));
for (Dict dict : dictList) {
dictNameMap.put(dict.getId(), dict.getName());
}
}

return owners
.stream()
Expand All @@ -93,12 +101,20 @@ private List<ClueOwnerListResponse> buildListData(String orgId, List<ClueOwner>
} else {
clueOwner.setReasonName(dictNameMap.get(clueOwner.getReasonId()));
}
clueOwner.setOwnerName(userNameMap.get(clueOwner.getOwner()));
clueOwner.setOperatorName(userNameMap.get(clueOwner.getOperator()));
clueOwner.setOwnerName(getUserNameOrDefault(userNameMap, clueOwner.getOwner()));
clueOwner.setOperatorName(getUserNameOrDefault(userNameMap, clueOwner.getOperator()));
return clueOwner;
}).toList();
}

private String getUserNameOrDefault(Map<String, String> userNameMap, String userId) {
if (StringUtils.isBlank(userId)) {
return "未知用户";
}
String name = userNameMap.get(userId);
return StringUtils.isNotBlank(name) ? name : "未知用户";
}

public ClueOwner add(Clue clue, String userId, Boolean addReason) {
ClueOwner clueOwner = new ClueOwner();
clueOwner.setOwner(clue.getOwner());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,20 @@ private List<CustomerOwnerListResponse> buildListData(String orgId, List<Custome
reasonIds.add(owner.getReasonId());
}

Map<String, UserDeptDTO> userDeptMap = baseService.getUserDeptMapByUserIds(new ArrayList<>(ownerIds), orgId);
Map<String, UserDeptDTO> userDeptMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
Map<String, UserDeptDTO> originUserDeptMap = baseService.getUserDeptMapByUserIds(new ArrayList<>(ownerIds), orgId);
userDeptMap.putAll(originUserDeptMap);

Map<String, String> userNameMap = baseService.getUserNameMap(userIds);
Map<String, String> userNameMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
userNameMap.putAll(baseService.getUserNameMap(userIds));

List<Dict> dictList = dictMapper.selectByIds(new ArrayList<>(reasonIds));
Map<String, String> dictNameMap = dictList.stream().collect(Collectors.toMap(Dict::getId, Dict::getName));
Map<String, String> dictNameMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
if (!reasonIds.isEmpty()) {
List<Dict> dictList = dictMapper.selectByIds(new ArrayList<>(reasonIds));
for (Dict dict : dictList) {
dictNameMap.put(dict.getId(), dict.getName());
}
}

LambdaQueryWrapper<DictConfig> configLambdaQueryWrapper = new LambdaQueryWrapper<>();
configLambdaQueryWrapper.eq(DictConfig::getModule, DictModule.CUSTOMER_POOL_RS.name()).eq(DictConfig::getOrganizationId, orgId);
Expand All @@ -94,12 +102,20 @@ private List<CustomerOwnerListResponse> buildListData(String orgId, List<Custome
} else {
customerOwner.setReasonName(dictNameMap.get(customerOwner.getReasonId()));
}
customerOwner.setOwnerName(userNameMap.get(customerOwner.getOwner()));
customerOwner.setOperatorName(userNameMap.get(customerOwner.getOperator()));
customerOwner.setOwnerName(getUserNameOrDefault(userNameMap, customerOwner.getOwner()));
customerOwner.setOperatorName(getUserNameOrDefault(userNameMap, customerOwner.getOperator()));
return customerOwner;
}).toList();
}

private String getUserNameOrDefault(Map<String, String> userNameMap, String userId) {
if (StringUtils.isBlank(userId)) {
return "未知用户";
}
String name = userNameMap.get(userId);
return StringUtils.isNotBlank(name) ? name : "未知用户";
}

public CustomerOwner add(Customer customer, String userId, Boolean addReason) {
CustomerOwner customerOwner = new CustomerOwner();
customerOwner.setOwner(customer.getOwner());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public OpportunityDetailResponse get(@PathVariable String id) {
@RequiresPermissions(value = {PermissionConstants.OPPORTUNITY_MANAGEMENT_UPDATE, PermissionConstants.OPPORTUNITY_MANAGEMENT_RESIGN}, logical = Logical.OR)
@Operation(summary = "更新商机阶段")
public void updateStage(@RequestBody OpportunityStageRequest request) {
opportunityService.updateStage(request, OrganizationContext.getOrganizationId());
opportunityService.updateStage(request, OrganizationContext.getOrganizationId(), SessionUtils.getUserId());
}

@PostMapping("/batch/update")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cn.cordys.crm.opportunity.controller;

import cn.cordys.common.constants.PermissionConstants;
import cn.cordys.context.OrganizationContext;
import cn.cordys.crm.opportunity.dto.response.OpportunityStageHistoryResponse;
import cn.cordys.crm.opportunity.service.OpportunityStageHistoryService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


@Tag(name = "商机阶段变更历史")
@RestController
@RequestMapping("/opportunity/stage/history")
public class OpportunityStageHistoryController {
@Resource
private OpportunityStageHistoryService opportunityStageHistoryService;

@GetMapping("/list/{opportunityId}")
@RequiresPermissions(PermissionConstants.OPPORTUNITY_MANAGEMENT_READ)
@Operation(summary = "商机阶段变更历史列表")
public List<OpportunityStageHistoryResponse> list(@PathVariable String opportunityId) {
return opportunityStageHistoryService.list(opportunityId, OrganizationContext.getOrganizationId());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package cn.cordys.crm.opportunity.domain;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Table;
import lombok.Data;


@Data
@Table(name = "opportunity_stage_history")
public class OpportunityStageHistory {

@Schema(description = "id")
private String id;

@Schema(description = "商机id")
private String opportunityId;

@Schema(description = "原阶段id")
private String fromStage;

@Schema(description = "新阶段id")
private String toStage;

@Schema(description = "变更时间")
private Long changeTime;

@Schema(description = "操作人")
private String operator;

@Schema(description = "失败原因id(当变更为失败阶段时)")
private String failureReasonId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cn.cordys.crm.opportunity.dto.response;

import cn.cordys.crm.opportunity.domain.OpportunityStageHistory;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;


@Data
public class OpportunityStageHistoryResponse extends OpportunityStageHistory {
@Schema(description = "原阶段名称")
private String fromStageName;

@Schema(description = "新阶段名称")
private String toStageName;

@Schema(description = "操作人名称")
private String operatorName;

@Schema(description = "失败原因名称")
private String failureReasonName;
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ public class OpportunityService {
private ExtOpportunityStageConfigMapper extOpportunityStageConfigMapper;
@Resource
private DataScopeService dataScopeService;
@Resource
private OpportunityStageHistoryService opportunityStageHistoryService;

public PagerWithOption<List<OpportunityListResponse>> list(OpportunityPageRequest request, String userId, String orgId,
DeptDataPermissionDTO deptDataPermission, Boolean source) {
Expand Down Expand Up @@ -397,10 +399,10 @@ public void delete(String id, String userId, String orgId) {
Optional.ofNullable(opportunity).ifPresentOrElse(item -> {
opportunityMapper.deleteByPrimaryKey(opportunity.getId());
opportunityFieldService.deleteByResourceId(opportunity.getId());
opportunityStageHistoryService.deleteByOpportunityId(opportunity.getId());
}, () -> {
throw new GenericException("opportunity_not_found");
});
// 添加日志上下文
OperationLogContext.setResourceName(opportunity.getName());

commonNoticeSendService.sendNotice(NotificationConstants.Module.OPPORTUNITY,
Expand All @@ -414,7 +416,6 @@ public void delete(String id, String userId, String orgId) {
*/
public void transfer(OpportunityTransferRequest request, String userId, String orgId) {
List<StageConfigResponse> stageConfigList = extOpportunityStageConfigMapper.getStageConfigList(orgId);
// 过滤出成功阶段
StageConfigResponse successConfig = stageConfigList.stream().filter(config ->
Strings.CI.equals(config.getType(), OpportunityStageType.END.name()) && Strings.CI.equals(config.getRate(), "100")
).findFirst().get();
Expand All @@ -428,16 +429,32 @@ public void transfer(OpportunityTransferRequest request, String userId, String o
}
List<String> ids = opportunityList.stream().map(Opportunity::getId).toList();

long nextPos = getNextPos(orgId, stageConfigList.getFirst().getId());
String firstStageId = stageConfigList.getFirst().getId();
Map<String, String> oldStageMap = opportunityList.stream()
.collect(Collectors.toMap(Opportunity::getId, Opportunity::getStage));

long nextPos = getNextPos(orgId, firstStageId);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ExtOpportunityMapper batchUpdateMapper = sqlSession.getMapper(ExtOpportunityMapper.class);
for (int i = 0; i < ids.size(); i++) {
batchUpdateMapper.transfer(request.getOwner(), userId, ids.get(i), System.currentTimeMillis(), nextPos + i, stageConfigList.getFirst().getId());
batchUpdateMapper.transfer(request.getOwner(), userId, ids.get(i), System.currentTimeMillis(), nextPos + i, firstStageId);
}
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);

// 记录日志
opportunityList.forEach(opportunity -> {
String oldStage = oldStageMap.get(opportunity.getId());
if (!Strings.CI.equals(oldStage, firstStageId)) {
opportunityStageHistoryService.add(
opportunity.getId(),
oldStage,
firstStageId,
userId,
null
);
}
});

List<LogDTO> logs = new ArrayList<>();
opportunityList.forEach(opportunity -> {
Customer originCustomer = new Customer();
Expand Down Expand Up @@ -479,6 +496,7 @@ public void batchDelete(List<String> ids, String userId, String orgId) {
}
opportunityMapper.deleteByIds(toDoIds);
opportunityFieldService.deleteByResourceIds(toDoIds);
opportunityStageHistoryService.deleteByOpportunityIds(toDoIds);
List<LogDTO> logs = new ArrayList<>();
opportunityList.forEach(opportunity -> {
LogDTO logDTO = new LogDTO(opportunity.getOrganizationId(), opportunity.getId(), userId, LogType.DELETE, LogModule.OPPORTUNITY_INDEX, opportunity.getName());
Expand All @@ -487,7 +505,6 @@ public void batchDelete(List<String> ids, String userId, String orgId) {
});
logService.batchAdd(logs);

// 消息通知
opportunityList.forEach(opportunity ->
commonNoticeSendService.sendNotice(NotificationConstants.Module.OPPORTUNITY,
NotificationConstants.Event.BUSINESS_DELETED, opportunity.getName(), userId,
Expand Down Expand Up @@ -633,14 +650,19 @@ public List<OpportunityDetailResponse> batchGetSimpleByIds(List<String> ids) {
*
* @param request
* @param orgId
* @param operatorId
*/
@OperationLog(module = LogModule.OPPORTUNITY_INDEX, type = LogType.UPDATE, resourceId = "{#request.id}")
public void updateStage(OpportunityStageRequest request, String orgId) {
public void updateStage(OpportunityStageRequest request, String orgId, String operatorId) {
final Opportunity oldOpportunity = opportunityMapper.selectByPrimaryKey(request.getId());
if (oldOpportunity == null) {
throw new GenericException(Translator.get("opportunity_not_found"));
}

if (Strings.CI.equals(oldOpportunity.getStage(), request.getStage())) {
return;
}

final List<StageConfigResponse> stageConfigList = extOpportunityStageConfigMapper.getStageConfigList(orgId);

final Optional<StageConfigResponse> successOpt = stageConfigList.stream()
Expand Down Expand Up @@ -676,6 +698,14 @@ public void updateStage(OpportunityStageRequest request, String orgId) {

opportunityMapper.update(newOpportunity);

opportunityStageHistoryService.add(
request.getId(),
oldOpportunity.getStage(),
request.getStage(),
operatorId,
isFailStage ? request.getFailureReason() : null
);

final Map<String, String> originalVal = new HashMap<>(1);
originalVal.put("stage", stageMap.get(oldOpportunity.getStage()));
final Map<String, String> modifiedVal = new HashMap<>(1);
Expand Down Expand Up @@ -840,14 +870,15 @@ public void batchUpdate(ResourceBatchEditRequest request, String userId, String
* @param userId
*/
public void sort(OpportunitySortRequest request, String userId) {
//拖拽节点
Opportunity opportunity = opportunityMapper.selectByPrimaryKey(request.getDragNodeId());
if (opportunity == null) {
throw new GenericException(Translator.get("opportunity_not_found"));
}

boolean stageChanged = !Strings.CI.equals(opportunity.getStage(), request.getStage());

Long pos = DEFAULT_POS;
if (StringUtils.isNotBlank(request.getDropNodeId())) {
//放入节点
Opportunity dropNode = opportunityMapper.selectByPrimaryKey(request.getDropNodeId());
pos = dropNode.getPos();
if (request.getDropPosition() == -1) {
Expand All @@ -866,6 +897,16 @@ public void sort(OpportunitySortRequest request, String userId) {
dragOpportunity.setUpdateUser(userId);
dragOpportunity.setUpdateTime(System.currentTimeMillis());
opportunityMapper.updateById(dragOpportunity);

if (stageChanged) {
opportunityStageHistoryService.add(
request.getDragNodeId(),
opportunity.getStage(),
request.getStage(),
userId,
null
);
}
}

public List<ChartResult> chart(ChartAnalysisRequest request, String userId, String orgId, DeptDataPermissionDTO deptDataPermission) {
Expand Down
Loading