feat(crm): 添加跟进记录功能并优化字典数据相关接口- 新增跟进记录相关功能,包括创建、编辑、删除和查询跟进记录
- 添加跟进用户记录相关功能和接口 - 优化字典数据相关接口,支持批量获取字典数据 - 修复加班定时任务相关代码,提高异常处理能力
This commit is contained in:
parent
c2af2a8374
commit
e7376d5b6e
@ -44,15 +44,22 @@ public class WorkOvertimeJob {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
List<BpmOAOvertimeDO> bpmOAOvertimeDOS = overtimeMapper.selectList(new LambdaQueryWrapper<BpmOAOvertimeDO>()
|
||||
.eq(BpmOAOvertimeDO::getSettlementFlag, 0)
|
||||
.eq(BpmOAOvertimeDO::getResult, BpmProcessInstanceResultEnum.APPROVE)
|
||||
.ge(BpmOAOvertimeDO::getEndTime, now));
|
||||
.eq(BpmOAOvertimeDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult())
|
||||
.le(BpmOAOvertimeDO::getEndTime, now));
|
||||
if (CollectionUtil.isNotEmpty(bpmOAOvertimeDOS)) {
|
||||
List<Long> ids = bpmOAOvertimeDOS.stream().map(BpmOAOvertimeDO::getId).collect(Collectors.toList());
|
||||
List<BpmOAOvertimeItemDO> items = overtimeItemService.getByOvertimeIds(ids);
|
||||
Map<Long, List<BpmOAOvertimeItemDO>> map = items.stream().collect(Collectors.groupingBy(BpmOAOvertimeItemDO::getOaOvertimeId));
|
||||
for (BpmOAOvertimeDO bpmOAOvertimeDO : bpmOAOvertimeDOS) {
|
||||
List<BpmOAOvertimeItemDO> bpmOAOvertimeItemDOS = map.get(bpmOAOvertimeDO.getId());
|
||||
if (CollectionUtil.isEmpty(bpmOAOvertimeItemDOS)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
overtimeService.handlingOvertime(bpmOAOvertimeDO, bpmOAOvertimeItemDOS, now);
|
||||
} catch (Exception e) {
|
||||
log.error("处理加班失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
log.info("结束 加班定时任务");
|
||||
|
@ -1,11 +1,13 @@
|
||||
package cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo;
|
||||
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 跟进记录 Response VO")
|
||||
@Data
|
||||
@ -58,4 +60,8 @@ public class CrmRecordRespVO {
|
||||
|
||||
private String ownUserName;
|
||||
|
||||
|
||||
@Schema(description = "跟进用户列表")
|
||||
@ExcelProperty("跟进用户列表")
|
||||
private List<AdminUserRespDTO> adminUserRespDTOS;
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
package cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import javax.validation.constraints.*;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 跟进记录新增/修改 Request VO")
|
||||
@Data
|
||||
@ -40,4 +43,7 @@ public class CrmRecordSaveReqVO {
|
||||
@Schema(description = "跟进状态")
|
||||
private Integer followStatus;
|
||||
|
||||
@Schema(description = "跟进用户ids")
|
||||
private List<Long> userIds = new ArrayList<>();
|
||||
|
||||
}
|
||||
|
@ -2,11 +2,13 @@ package cn.iocoder.yudao.module.crm.dal.dataobject.crmrecord;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 跟进记录 DO
|
||||
|
@ -0,0 +1,38 @@
|
||||
package cn.iocoder.yudao.module.crm.dal.dataobject.crmrecorduser;
|
||||
|
||||
import lombok.*;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 跟进用户记录 DO
|
||||
*
|
||||
* @author 艾楷
|
||||
*/
|
||||
@TableName("crm_record_user")
|
||||
@KeySequence("crm_record_user_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public class CrmRecordUserDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 跟进记录id
|
||||
*/
|
||||
private Long recordId;
|
||||
/**
|
||||
* 跟进用户id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
}
|
@ -31,5 +31,8 @@ public interface CrmRecordMapper extends BaseMapperX<CrmRecordDO> {
|
||||
.orderByDesc(CrmRecordDO::getId));
|
||||
}
|
||||
|
||||
|
||||
|
||||
List<RecordStatisticsRespVO> selectStatistics(@Param("userIds") List<Long> userIds, @Param("createTime") LocalDateTime[] createTime);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package cn.iocoder.yudao.module.crm.dal.mysql.crmrecorduser;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecorduser.CrmRecordUserDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 跟进用户记录 Mapper
|
||||
*
|
||||
* @author 艾楷
|
||||
*/
|
||||
@Mapper
|
||||
public interface CrmRecordUserMapper extends BaseMapperX<CrmRecordUserDO> {
|
||||
|
||||
|
||||
}
|
@ -12,14 +12,8 @@ import cn.iocoder.yudao.module.crm.controller.admin.crmanalysis.vo.UserVolumeVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CustomerStatisticRespVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.RecordStatisticsRespVO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmachievement.CrmAchievementMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmclues.CrmCluesMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontract.CrmContractMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmcontractreceivables.CrmContractReceivablesMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmcustomer.CrmCustomerMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecord.CrmRecordMapper;
|
||||
import cn.iocoder.yudao.module.crm.service.crmrecord.CrmRecordService;
|
||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
|
||||
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
@ -148,7 +142,7 @@ public class CustomerServiceImpl implements CustomerService {
|
||||
v.setCustomerCount(0L);
|
||||
v.setSuccessCount(0L);
|
||||
v.setSuccessPer(per);
|
||||
}else {
|
||||
} else {
|
||||
v.setCustomerCount(Long.valueOf(customerMap.get(v.getId()).getCount()));
|
||||
v.setSuccessCount(Long.valueOf(customerMap.get(v.getId()).getDealsCount()));
|
||||
|
||||
@ -175,14 +169,11 @@ public class CustomerServiceImpl implements CustomerService {
|
||||
PageResult<AdminUserApiVO> pageResult = adminUserApi.getUserPageByRole(dto).getCheckedData();
|
||||
PageResult<UserRecordVO> pageResult1 = BeanUtils.toBean(pageResult, UserRecordVO.class);
|
||||
if (CollectionUtil.isNotEmpty(pageResult1.getList())) {
|
||||
|
||||
// 获取所有用户跟进统计列表
|
||||
List<Long> userIds = convertList(pageResult1.getList(), UserRecordVO::getId);
|
||||
List<RecordStatisticsRespVO> respVOS = recordService.getRecordStatistics(userIds, pageReqVO.getCreateTime());
|
||||
Map<String, RecordStatisticsRespVO> recordMap = convertMap(respVOS, RecordStatisticsRespVO::getCreator);
|
||||
|
||||
pageResult1.getList().forEach(v -> {
|
||||
|
||||
RecordStatisticsRespVO respVO = recordMap.get(v.getId().toString());
|
||||
if (respVO == null) {
|
||||
// 设置跟进总数量
|
||||
@ -193,7 +184,7 @@ public class CustomerServiceImpl implements CustomerService {
|
||||
v.setBusinessCount(0L);
|
||||
// 设置跟进线索数量
|
||||
v.setCluesCount(0L);
|
||||
}else {
|
||||
} else {
|
||||
// 设置跟进总数量
|
||||
v.setTotalCount(Long.valueOf(respVO.getCount()));
|
||||
// 设置跟进客户数量
|
||||
@ -205,7 +196,6 @@ public class CustomerServiceImpl implements CustomerService {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return pageResult1;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
package cn.iocoder.yudao.module.crm.service.crmrecord;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.CrmRecordPageReqVO;
|
||||
@ -11,16 +14,21 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmclues.CrmCluesDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecord.CrmRecordDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmrecorduser.CrmRecordUserDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmbusiness.CrmBusinessMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmclues.CrmCluesMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmcustomer.CrmCustomerMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecord.CrmRecordMapper;
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecorduser.CrmRecordUserMapper;
|
||||
import cn.iocoder.yudao.module.hrm.enums.RelationEnum;
|
||||
import cn.iocoder.yudao.module.hrm.enums.TypesEnum;
|
||||
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
|
||||
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
|
||||
import cn.iocoder.yudao.module.system.api.dict.dto.DictParameterRespDTO;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -28,9 +36,13 @@ import org.springframework.validation.annotation.Validated;
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.RECORD_NOT_EXISTS;
|
||||
|
||||
/**
|
||||
@ -45,6 +57,8 @@ public class CrmRecordServiceImpl implements CrmRecordService {
|
||||
@Resource
|
||||
private CrmRecordMapper recordMapper;
|
||||
@Resource
|
||||
private CrmRecordUserMapper crmRecordUserMapper;
|
||||
@Resource
|
||||
private CrmCustomerMapper customerMapper;
|
||||
@Resource
|
||||
private AdminUserApi adminUserApi;
|
||||
@ -61,7 +75,14 @@ public class CrmRecordServiceImpl implements CrmRecordService {
|
||||
// 插入
|
||||
CrmRecordDO record = BeanUtils.toBean(createReqVO, CrmRecordDO.class);
|
||||
recordMapper.insert(record);
|
||||
|
||||
// -- 插入跟进用户
|
||||
List<CrmRecordUserDO> recordUsers = new ArrayList<>();
|
||||
for (Long userId : createReqVO.getUserIds()) {
|
||||
recordUsers.add(new CrmRecordUserDO().setRecordId(record.getId()).setUserId(userId));
|
||||
}
|
||||
if (!recordUsers.isEmpty()) {
|
||||
crmRecordUserMapper.insertBatch(recordUsers);
|
||||
}
|
||||
//更新客户
|
||||
if (TypesEnum.CUSTOMER.getValue().equals(createReqVO.getTypes())) {
|
||||
customerMapper.updateById(CrmCustomerDO.builder()
|
||||
@ -89,8 +110,6 @@ public class CrmRecordServiceImpl implements CrmRecordService {
|
||||
.followTime(LocalDateTime.now())
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
// 返回
|
||||
return record.getId();
|
||||
}
|
||||
@ -102,15 +121,43 @@ public class CrmRecordServiceImpl implements CrmRecordService {
|
||||
// 更新
|
||||
CrmRecordDO updateObj = BeanUtils.toBean(updateReqVO, CrmRecordDO.class);
|
||||
recordMapper.updateById(updateObj);
|
||||
// -- 编辑更近用户的话
|
||||
List<CrmRecordUserDO> oldCrmRecordUsers = crmRecordUserMapper.selectList(new LambdaQueryWrapper<CrmRecordUserDO>()
|
||||
.eq(CrmRecordUserDO::getRecordId, updateReqVO.getId()));
|
||||
List<Long> oldUserIds = oldCrmRecordUsers.stream().map(CrmRecordUserDO::getUserId).collect(Collectors.toList());
|
||||
List<Long> userIds = updateReqVO.getUserIds();
|
||||
List<List<Long>> list = CollectionUtils.diffList(oldUserIds, userIds,
|
||||
ObjectUtil::equal
|
||||
);
|
||||
if (CollUtil.isNotEmpty(list.get(0))) {
|
||||
List<CrmRecordUserDO> crmRecordUserDOS = new ArrayList<>();
|
||||
for (Long userId : list.get(0)) {
|
||||
CrmRecordUserDO crmRecordUserDO = new CrmRecordUserDO();
|
||||
crmRecordUserDO.setRecordId(updateReqVO.getId());
|
||||
crmRecordUserDO.setUserId(userId);
|
||||
crmRecordUserDOS.add(crmRecordUserDO);
|
||||
}
|
||||
crmRecordUserMapper.insertBatch(crmRecordUserDOS);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(list.get(2))) {
|
||||
crmRecordUserMapper.delete(new LambdaQueryWrapper<CrmRecordUserDO>()
|
||||
.in(CrmRecordUserDO::getUserId, list.get(2)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRecord(Long id) {
|
||||
// 校验存在
|
||||
validateRecordExists(id);
|
||||
// 删除
|
||||
// 删除该记录下的跟进用户
|
||||
Long adminId = SecurityFrameworkUtils.getLoginUserId();
|
||||
List<CrmRecordUserDO> crmRecordUserDOS = crmRecordUserMapper.selectList(new LambdaQueryWrapper<CrmRecordUserDO>().eq(CrmRecordUserDO::getRecordId, id));
|
||||
crmRecordUserMapper.delete(new LambdaQueryWrapper<CrmRecordUserDO>().eq(CrmRecordUserDO::getRecordId, id).eq(CrmRecordUserDO::getUserId, adminId));
|
||||
// 删除如果是最后一个的话删除一下
|
||||
if (crmRecordUserDOS.size() == 1 && adminId.equals(crmRecordUserDOS.get(0).getUserId())){
|
||||
recordMapper.deleteById(id);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateRecordExists(Long id) {
|
||||
if (recordMapper.selectById(id) == null) {
|
||||
@ -132,26 +179,88 @@ public class CrmRecordServiceImpl implements CrmRecordService {
|
||||
} else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
|
||||
ids = adminUserApi.getUserListBySubordinateIds(adminId).getCheckedData();
|
||||
}
|
||||
PageResult<CrmRecordDO> pageResult = recordMapper.selectPage(pageReqVO, ids);
|
||||
LocalDateTime beginTime = pageReqVO.getNextTime() != null && pageReqVO.getNextTime().length > 0 ? pageReqVO.getNextTime()[0] : null;
|
||||
LocalDateTime endTime = pageReqVO.getNextTime() != null && pageReqVO.getNextTime().length > 0 ? pageReqVO.getNextTime()[1] : null;
|
||||
MPJLambdaWrapper<CrmRecordDO> wrapper = new MPJLambdaWrapper<CrmRecordDO>()
|
||||
.selectAll(CrmRecordDO.class)
|
||||
.leftJoin(CrmRecordUserDO.class, CrmRecordUserDO::getRecordId, CrmRecordDO::getId)
|
||||
.eqIfExists(CrmRecordDO::getTypes, pageReqVO.getTypes())
|
||||
.eqIfExists(CrmRecordDO::getTypesId, pageReqVO.getTypesId())
|
||||
.eqIfExists(CrmRecordDO::getContent, pageReqVO.getContent())
|
||||
.eqIfExists(CrmRecordDO::getRecordType, pageReqVO.getRecordType())
|
||||
.ge(beginTime != null, CrmRecordDO::getNextTime, beginTime)
|
||||
.le(endTime != null, CrmRecordDO::getNextTime, endTime)
|
||||
.in(CollUtil.isNotEmpty(ids), CrmRecordUserDO::getUserId, ids)
|
||||
.groupBy(CrmRecordDO::getId)
|
||||
.orderByDesc(CrmRecordDO::getId);
|
||||
PageResult<CrmRecordDO> pageResult = recordMapper.selectJoinPage(pageReqVO, CrmRecordDO.class, wrapper);
|
||||
PageResult<CrmRecordRespVO> pageResult1 = BeanUtils.toBean(pageResult, CrmRecordRespVO.class);
|
||||
List<CrmRecordRespVO> list = pageResult1.getList();
|
||||
Map<Long, List<CrmRecordUserDO>> crmRecordUserMap = new HashMap<>();
|
||||
List<CrmRecordUserDO> crmRecordUserList = new ArrayList<>();
|
||||
if (CollUtil.isNotEmpty(list)) {
|
||||
crmRecordUserList = crmRecordUserMapper.selectList(new LambdaQueryWrapper<CrmRecordUserDO>().in(CrmRecordUserDO::getRecordId, list.stream().map(CrmRecordRespVO::getId).collect(Collectors.toList())));
|
||||
crmRecordUserMap = crmRecordUserList.stream().collect(Collectors.groupingBy(CrmRecordUserDO::getRecordId));
|
||||
}
|
||||
|
||||
|
||||
for (CrmRecordRespVO crmRecordRespVO : pageResult1.getList()) {
|
||||
DictDataRespDTO dto = dictDataApi.getDictData("follow_status", crmRecordRespVO.getRecordType().toString()).getCheckedData();
|
||||
List<String> recordTypes = list.stream().map(CrmRecordRespVO::getRecordType).map(String::valueOf).collect(Collectors.toList());
|
||||
List<DictDataRespDTO> respDTOS = CollUtil.isNotEmpty(recordTypes) ? dictDataApi.getByValues(new DictParameterRespDTO().setDictType("follow_status").setValues(recordTypes)).getCheckedData() : new ArrayList<>();
|
||||
Map<String, DictDataRespDTO> dictDataMap = CollectionUtils.convertMap(respDTOS, DictDataRespDTO::getValue);
|
||||
Map<String, List<Long>> typeIdMap = list.stream().collect(Collectors.groupingBy(CrmRecordRespVO::getTypes, Collectors.mapping(CrmRecordRespVO::getTypesId, Collectors.toList())));
|
||||
// 批量查询客户、业务和线索数据
|
||||
Map<Long, CrmCustomerDO> customerMap = new HashMap<>();
|
||||
if (CollUtil.isNotEmpty(typeIdMap.get(TypesEnum.CUSTOMER.getValue()))) {
|
||||
customerMap = customerMapper.selectBatchIds(typeIdMap.get(TypesEnum.CUSTOMER.getValue())).stream()
|
||||
.collect(Collectors.toMap(CrmCustomerDO::getId, item -> item));
|
||||
}
|
||||
Map<Long, CrmBusinessDO> businessMap = new HashMap<>();
|
||||
if (CollUtil.isNotEmpty(typeIdMap.get(TypesEnum.BUSINESS.getValue()))) {
|
||||
businessMap = crmBusinessMapper.selectBatchIds(typeIdMap.get(TypesEnum.BUSINESS.getValue())).stream()
|
||||
.collect(Collectors.toMap(CrmBusinessDO::getId, item -> item));
|
||||
}
|
||||
Map<Long, CrmCluesDO> cluesMap = new HashMap<>();
|
||||
if (CollUtil.isNotEmpty(typeIdMap.get(TypesEnum.CLUES.getValue()))) {
|
||||
cluesMap = cluesMapper.selectBatchIds(typeIdMap.get(TypesEnum.CLUES.getValue())).stream()
|
||||
.collect(Collectors.toMap(CrmCluesDO::getId, item -> item));
|
||||
}
|
||||
List<Long> userIds = crmRecordUserList.stream().map(CrmRecordUserDO::getUserId).distinct().collect(Collectors.toList());
|
||||
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserList(userIds).getCheckedData().stream().collect(Collectors.toMap(AdminUserRespDTO::getId, item -> item));
|
||||
for (CrmRecordRespVO crmRecordRespVO : list) {
|
||||
// 设置记录类型名称
|
||||
DictDataRespDTO dto = dictDataMap.get(crmRecordRespVO.getRecordType().toString());
|
||||
if (dto != null) {
|
||||
crmRecordRespVO.setRecordTypeName(dto.getLabel());
|
||||
if (TypesEnum.CUSTOMER.getValue().equals(crmRecordRespVO.getTypes())) {
|
||||
CrmCustomerDO customerDO = customerMapper.selectById(crmRecordRespVO.getTypesId());
|
||||
}
|
||||
// 根据类型设置名称
|
||||
String types = crmRecordRespVO.getTypes();
|
||||
if (TypesEnum.CUSTOMER.getValue().equals(types)) {
|
||||
CrmCustomerDO customerDO = customerMap.get(crmRecordRespVO.getTypesId());
|
||||
if (customerDO != null) {
|
||||
crmRecordRespVO.setTypesName(customerDO.getName());
|
||||
} else if (TypesEnum.BUSINESS.getValue().equals(crmRecordRespVO.getTypes())) {
|
||||
CrmBusinessDO crmBusinessDO = crmBusinessMapper.selectById(crmRecordRespVO.getTypesId());
|
||||
}
|
||||
} else if (TypesEnum.BUSINESS.getValue().equals(types)) {
|
||||
CrmBusinessDO crmBusinessDO = businessMap.get(crmRecordRespVO.getTypesId());
|
||||
if (crmBusinessDO != null) {
|
||||
crmRecordRespVO.setTypesName(crmBusinessDO.getName());
|
||||
} else if (TypesEnum.CLUES.getValue().equals(crmRecordRespVO.getTypes())) {
|
||||
CrmCluesDO crmCluesDO = cluesMapper.selectById(crmRecordRespVO.getTypesId());
|
||||
}
|
||||
} else if (TypesEnum.CLUES.getValue().equals(types)) {
|
||||
CrmCluesDO crmCluesDO = cluesMap.get(crmRecordRespVO.getTypesId());
|
||||
if (crmCluesDO != null) {
|
||||
crmRecordRespVO.setTypesName(crmCluesDO.getName());
|
||||
}
|
||||
AdminUserRespDTO adminUserRespDTO = adminUserApi.getUser(crmRecordRespVO.getCreator()).getCheckedData();
|
||||
crmRecordRespVO.setOwnUserName(adminUserRespDTO.getNickname());
|
||||
|
||||
}
|
||||
// 获取创建者信息
|
||||
List<CrmRecordUserDO> crmRecordUserDOS = crmRecordUserMap.get(crmRecordRespVO.getId());
|
||||
List<AdminUserRespDTO> adminUserRespDTOS = new ArrayList<>();
|
||||
if (CollUtil.isEmpty(crmRecordUserDOS)) {
|
||||
crmRecordRespVO.setAdminUserRespDTOS(adminUserRespDTOS);
|
||||
continue;
|
||||
}
|
||||
for (CrmRecordUserDO crmRecordUserDO : crmRecordUserDOS) {
|
||||
AdminUserRespDTO adminUserRespDTO = userMap.get(crmRecordUserDO.getUserId());
|
||||
adminUserRespDTOS.add(adminUserRespDTO);
|
||||
}
|
||||
crmRecordRespVO.setAdminUserRespDTOS(adminUserRespDTOS);
|
||||
}
|
||||
return pageResult1;
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
package cn.iocoder.yudao.module.crm.service.crmrecorduser;
|
||||
|
||||
/**
|
||||
* 跟进用户记录 Service 接口
|
||||
*
|
||||
* @author 艾楷
|
||||
*/
|
||||
public interface CrmRecordUserService {
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.crm.service.crmrecorduser;
|
||||
|
||||
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecorduser.CrmRecordUserMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 跟进用户记录 Service 实现类
|
||||
*
|
||||
* @author 艾楷
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class CrmRecordUserServiceImpl implements CrmRecordUserService {
|
||||
|
||||
@Resource
|
||||
private CrmRecordUserMapper crmRecordUserMapper;
|
||||
|
||||
|
||||
}
|
@ -11,27 +11,30 @@
|
||||
|
||||
<select id="selectStatistics" resultType="cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.RecordStatisticsRespVO">
|
||||
SELECT
|
||||
creator AS creator,
|
||||
COUNT(1) AS count,
|
||||
SUM(CASE WHEN types = 'business' THEN 1 ELSE 0 END) AS businessCount,
|
||||
SUM(CASE WHEN types = 'customer' THEN 1 ELSE 0 END) AS customerCount,
|
||||
SUM(CASE WHEN types = 'clues' THEN 1 ELSE 0 END) AS cluesCount
|
||||
b.user_id AS creator,
|
||||
COUNT( a.id ) AS count,
|
||||
SUM( CASE WHEN a.types = 'business' THEN 1 ELSE 0 END ) AS businessCount,
|
||||
SUM( CASE WHEN a.types = 'customer' THEN 1 ELSE 0 END ) AS customerCount,
|
||||
SUM( CASE WHEN a.types = 'clues' THEN 1 ELSE 0 END ) AS cluesCount
|
||||
FROM
|
||||
crm_record
|
||||
WHERE
|
||||
deleted = 0
|
||||
AND creator IN
|
||||
crm_record as a
|
||||
LEFT JOIN crm_record_user as b on a.id = b.record_id
|
||||
<where>
|
||||
a.deleted = 0
|
||||
and b.deleted = 0
|
||||
AND b.user_id IN
|
||||
<foreach item="userId" collection="userIds" separator="," open="(" close=")" index="">
|
||||
#{userId}
|
||||
</foreach>
|
||||
<if test="createTime != null and createTime.length > 0">
|
||||
<if test="createTime[0] != null">
|
||||
AND create_time >= #{createTime[0]}
|
||||
AND b.create_time >= #{createTime[0]}
|
||||
</if>
|
||||
<if test="createTime[1] != null">
|
||||
AND create_time <= #{createTime[1]}
|
||||
AND b.create_time <= #{createTime[1]}
|
||||
</if>
|
||||
</if>
|
||||
GROUP BY creator
|
||||
GROUP BY b.user_id
|
||||
</where>
|
||||
</select>
|
||||
</mapper>
|
||||
|
@ -0,0 +1,12 @@
|
||||
<?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="cn.iocoder.yudao.module.crm.dal.mysql.recorduser.RecordUserMapper">
|
||||
|
||||
<!--
|
||||
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
|
||||
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
|
||||
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
|
||||
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
|
||||
-->
|
||||
|
||||
</mapper>
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.api.dict;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
|
||||
import cn.iocoder.yudao.module.system.api.dict.dto.DictParameterRespDTO;
|
||||
import cn.iocoder.yudao.module.system.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
@ -9,6 +10,8 @@ import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.Collection;
|
||||
@ -38,6 +41,12 @@ public interface DictDataApi {
|
||||
CommonResult<DictDataRespDTO> getDictData(@RequestParam("dictType") String dictType,
|
||||
@RequestParam("value") String value);
|
||||
|
||||
|
||||
@PostMapping(PREFIX + "/getByValues")
|
||||
@Operation(summary = "获得指定的字典数据-(值多选筛选)")
|
||||
CommonResult<List<DictDataRespDTO>> getByValues(@RequestBody DictParameterRespDTO dto);
|
||||
|
||||
|
||||
@GetMapping(PREFIX + "/parse")
|
||||
@Operation(summary = "解析获得指定的字典数据")
|
||||
@Parameters({
|
||||
|
@ -0,0 +1,19 @@
|
||||
package cn.iocoder.yudao.module.system.api.dict.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "RPC 服务 - 字典数据 Response DTO")
|
||||
@Data
|
||||
public class DictParameterRespDTO {
|
||||
|
||||
@Schema(description = "字典值", requiredMode = Schema.RequiredMode.REQUIRED, example = "iocoder")
|
||||
private List<String> values;
|
||||
|
||||
|
||||
@Schema(description = "字典类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "sys_common_sex")
|
||||
private String dictType;
|
||||
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
package cn.iocoder.yudao.module.system.api.dict;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
|
||||
import cn.iocoder.yudao.module.system.api.dict.dto.DictParameterRespDTO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
|
||||
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -34,6 +36,12 @@ public class DictDataApiImpl implements DictDataApi {
|
||||
return success(BeanUtils.toBean(dictData, DictDataRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<List<DictDataRespDTO>> getByValues(DictParameterRespDTO dto) {
|
||||
List<DictDataDO> list = dictDataService.getDictDataList(dto.getDictType(), dto.getValues());
|
||||
return success(BeanUtil.copyToList(list, DictDataRespDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<DictDataRespDTO> parseDictData(String dictType, String label) {
|
||||
DictDataDO dictData = dictDataService.parseDictData(dictType, label);
|
||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.dict;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.system.api.dict.dto.DictParameterRespDTO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.system.service.dict;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.system.api.dict.dto.DictParameterRespDTO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
|
||||
|
@ -854,7 +854,7 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
List<DeptDO> deptList = deptService.getAllList();
|
||||
Map<Long, List<DeptDO>> map = deptList.stream().collect(Collectors.groupingBy(DeptDO::getParentId));
|
||||
this.getSubordinateDeptIds(map, nextIds, ids);
|
||||
|
||||
nextIds.add(dept.getId());
|
||||
nextIds = nextIds.stream().distinct().collect(Collectors.toList());
|
||||
// 2. 获取部门对应的用户信息
|
||||
List<AdminUserDO> users = this.getUserListByDeptIds(nextIds, null);
|
||||
|
@ -41,16 +41,16 @@ spring:
|
||||
datasource:
|
||||
master:
|
||||
name: ruoyi-vue-pro
|
||||
url: jdbc:mysql://47.97.8.94:3306/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
|
||||
url: jdbc:mysql://rm-bp1yloyj508qld78jno.mysql.rds.aliyuncs.com:3306/${spring.datasource.dynamic.datasource.slave.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
username: root
|
||||
password: yhtkj@2024!
|
||||
password: Znalyrds2024
|
||||
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
|
||||
name: ruoyi-vue-pro
|
||||
url: jdbc:mysql://47.97.8.94:3306/${spring.datasource.dynamic.datasource.master.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
|
||||
url: jdbc:mysql://rm-bp1yloyj508qld78jno.mysql.rds.aliyuncs.com:3306/${spring.datasource.dynamic.datasource.slave.name}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
username: root
|
||||
password: yhtkj@2024!
|
||||
password: Znalyrds2024
|
||||
|
||||
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
|
||||
redis:
|
||||
|
Loading…
Reference in New Issue
Block a user