Merge branch 'dev' into frx

# Conflicts:
#	yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/job/workovertime/WorkOvertimeJob.java
This commit is contained in:
furongxin 2025-01-24 17:52:01 +08:00
commit 4ee2f84947
27 changed files with 414 additions and 65 deletions

View File

@ -45,14 +45,21 @@ public class WorkOvertimeJob {
List<BpmOAOvertimeDO> bpmOAOvertimeDOS = overtimeMapper.selectList(new LambdaQueryWrapper<BpmOAOvertimeDO>() List<BpmOAOvertimeDO> bpmOAOvertimeDOS = overtimeMapper.selectList(new LambdaQueryWrapper<BpmOAOvertimeDO>()
.eq(BpmOAOvertimeDO::getSettlementFlag, 0) .eq(BpmOAOvertimeDO::getSettlementFlag, 0)
.eq(BpmOAOvertimeDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult()) .eq(BpmOAOvertimeDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult())
.ge(BpmOAOvertimeDO::getEndTime, now)); .le(BpmOAOvertimeDO::getEndTime, now));
if (CollectionUtil.isNotEmpty(bpmOAOvertimeDOS)) { if (CollectionUtil.isNotEmpty(bpmOAOvertimeDOS)) {
List<Long> ids = bpmOAOvertimeDOS.stream().map(BpmOAOvertimeDO::getId).collect(Collectors.toList()); List<Long> ids = bpmOAOvertimeDOS.stream().map(BpmOAOvertimeDO::getId).collect(Collectors.toList());
List<BpmOAOvertimeItemDO> items = overtimeItemService.getByOvertimeIds(ids); List<BpmOAOvertimeItemDO> items = overtimeItemService.getByOvertimeIds(ids);
Map<Long, List<BpmOAOvertimeItemDO>> map = items.stream().collect(Collectors.groupingBy(BpmOAOvertimeItemDO::getOaOvertimeId)); Map<Long, List<BpmOAOvertimeItemDO>> map = items.stream().collect(Collectors.groupingBy(BpmOAOvertimeItemDO::getOaOvertimeId));
for (BpmOAOvertimeDO bpmOAOvertimeDO : bpmOAOvertimeDOS) { for (BpmOAOvertimeDO bpmOAOvertimeDO : bpmOAOvertimeDOS) {
List<BpmOAOvertimeItemDO> bpmOAOvertimeItemDOS = map.get(bpmOAOvertimeDO.getId()); List<BpmOAOvertimeItemDO> bpmOAOvertimeItemDOS = map.get(bpmOAOvertimeDO.getId());
overtimeService.handlingOvertime(bpmOAOvertimeDO, bpmOAOvertimeItemDOS, now); if (CollectionUtil.isEmpty(bpmOAOvertimeItemDOS)) {
continue;
}
try {
overtimeService.handlingOvertime(bpmOAOvertimeDO, bpmOAOvertimeItemDOS, now);
} catch (Exception e) {
log.error("处理加班失败", e);
}
} }
} }
log.info("结束 加班定时任务"); log.info("结束 加班定时任务");

View File

@ -1,11 +1,13 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo; 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.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 跟进记录 Response VO") @Schema(description = "管理后台 - 跟进记录 Response VO")
@Data @Data
@ -58,4 +60,8 @@ public class CrmRecordRespVO {
private String ownUserName; private String ownUserName;
@Schema(description = "跟进用户列表")
@ExcelProperty("跟进用户列表")
private List<AdminUserRespDTO> adminUserRespDTOS;
} }

View File

@ -1,10 +1,13 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo; package cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import javax.validation.constraints.*;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Schema(description = "管理后台 - 跟进记录新增/修改 Request VO") @Schema(description = "管理后台 - 跟进记录新增/修改 Request VO")
@Data @Data
@ -40,4 +43,7 @@ public class CrmRecordSaveReqVO {
@Schema(description = "跟进状态") @Schema(description = "跟进状态")
private Integer followStatus; private Integer followStatus;
@Schema(description = "跟进用户ids")
private List<Long> userIds = new ArrayList<>();
} }

View File

@ -2,11 +2,13 @@ package cn.iocoder.yudao.module.crm.dal.dataobject.crmrecord;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*; import lombok.*;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
/** /**
* 跟进记录 DO * 跟进记录 DO

View File

@ -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") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 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;
}

View File

@ -31,5 +31,8 @@ public interface CrmRecordMapper extends BaseMapperX<CrmRecordDO> {
.orderByDesc(CrmRecordDO::getId)); .orderByDesc(CrmRecordDO::getId));
} }
List<RecordStatisticsRespVO> selectStatistics(@Param("userIds") List<Long> userIds, @Param("createTime") LocalDateTime[] createTime); List<RecordStatisticsRespVO> selectStatistics(@Param("userIds") List<Long> userIds, @Param("createTime") LocalDateTime[] createTime);
} }

View File

@ -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> {
}

View File

@ -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.crmcustomer.vo.CustomerStatisticRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.RecordStatisticsRespVO; 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.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.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.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.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@ -148,7 +142,7 @@ public class CustomerServiceImpl implements CustomerService {
v.setCustomerCount(0L); v.setCustomerCount(0L);
v.setSuccessCount(0L); v.setSuccessCount(0L);
v.setSuccessPer(per); v.setSuccessPer(per);
}else { } else {
v.setCustomerCount(Long.valueOf(customerMap.get(v.getId()).getCount())); v.setCustomerCount(Long.valueOf(customerMap.get(v.getId()).getCount()));
v.setSuccessCount(Long.valueOf(customerMap.get(v.getId()).getDealsCount())); 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<AdminUserApiVO> pageResult = adminUserApi.getUserPageByRole(dto).getCheckedData();
PageResult<UserRecordVO> pageResult1 = BeanUtils.toBean(pageResult, UserRecordVO.class); PageResult<UserRecordVO> pageResult1 = BeanUtils.toBean(pageResult, UserRecordVO.class);
if (CollectionUtil.isNotEmpty(pageResult1.getList())) { if (CollectionUtil.isNotEmpty(pageResult1.getList())) {
// 获取所有用户跟进统计列表 // 获取所有用户跟进统计列表
List<Long> userIds = convertList(pageResult1.getList(), UserRecordVO::getId); List<Long> userIds = convertList(pageResult1.getList(), UserRecordVO::getId);
List<RecordStatisticsRespVO> respVOS = recordService.getRecordStatistics(userIds, pageReqVO.getCreateTime()); List<RecordStatisticsRespVO> respVOS = recordService.getRecordStatistics(userIds, pageReqVO.getCreateTime());
Map<String, RecordStatisticsRespVO> recordMap = convertMap(respVOS, RecordStatisticsRespVO::getCreator); Map<String, RecordStatisticsRespVO> recordMap = convertMap(respVOS, RecordStatisticsRespVO::getCreator);
pageResult1.getList().forEach(v -> { pageResult1.getList().forEach(v -> {
RecordStatisticsRespVO respVO = recordMap.get(v.getId().toString()); RecordStatisticsRespVO respVO = recordMap.get(v.getId().toString());
if (respVO == null) { if (respVO == null) {
// 设置跟进总数量 // 设置跟进总数量
@ -193,7 +184,7 @@ public class CustomerServiceImpl implements CustomerService {
v.setBusinessCount(0L); v.setBusinessCount(0L);
// 设置跟进线索数量 // 设置跟进线索数量
v.setCluesCount(0L); v.setCluesCount(0L);
}else { } else {
// 设置跟进总数量 // 设置跟进总数量
v.setTotalCount(Long.valueOf(respVO.getCount())); v.setTotalCount(Long.valueOf(respVO.getCount()));
// 设置跟进客户数量 // 设置跟进客户数量
@ -205,7 +196,6 @@ public class CustomerServiceImpl implements CustomerService {
} }
}); });
} }
return pageResult1; return pageResult1;
} }

View File

@ -1,6 +1,9 @@
package cn.iocoder.yudao.module.crm.service.crmrecord; 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.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.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.CrmRecordPageReqVO; 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.crmclues.CrmCluesDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO; 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.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.crmbusiness.CrmBusinessMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmclues.CrmCluesMapper; 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.crmcustomer.CrmCustomerMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecord.CrmRecordMapper; 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.RelationEnum;
import cn.iocoder.yudao.module.hrm.enums.TypesEnum; 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.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO; 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.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; 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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -28,9 +36,13 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; 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.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; import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.RECORD_NOT_EXISTS;
/** /**
@ -45,6 +57,8 @@ public class CrmRecordServiceImpl implements CrmRecordService {
@Resource @Resource
private CrmRecordMapper recordMapper; private CrmRecordMapper recordMapper;
@Resource @Resource
private CrmRecordUserMapper crmRecordUserMapper;
@Resource
private CrmCustomerMapper customerMapper; private CrmCustomerMapper customerMapper;
@Resource @Resource
private AdminUserApi adminUserApi; private AdminUserApi adminUserApi;
@ -61,7 +75,14 @@ public class CrmRecordServiceImpl implements CrmRecordService {
// 插入 // 插入
CrmRecordDO record = BeanUtils.toBean(createReqVO, CrmRecordDO.class); CrmRecordDO record = BeanUtils.toBean(createReqVO, CrmRecordDO.class);
recordMapper.insert(record); 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())) { if (TypesEnum.CUSTOMER.getValue().equals(createReqVO.getTypes())) {
customerMapper.updateById(CrmCustomerDO.builder() customerMapper.updateById(CrmCustomerDO.builder()
@ -89,8 +110,6 @@ public class CrmRecordServiceImpl implements CrmRecordService {
.followTime(LocalDateTime.now()) .followTime(LocalDateTime.now())
.build()); .build());
} }
// 返回 // 返回
return record.getId(); return record.getId();
} }
@ -102,14 +121,42 @@ public class CrmRecordServiceImpl implements CrmRecordService {
// 更新 // 更新
CrmRecordDO updateObj = BeanUtils.toBean(updateReqVO, CrmRecordDO.class); CrmRecordDO updateObj = BeanUtils.toBean(updateReqVO, CrmRecordDO.class);
recordMapper.updateById(updateObj); 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 @Override
public void deleteRecord(Long id) { public void deleteRecord(Long id) {
// 校验存在 // 校验存在
validateRecordExists(id); validateRecordExists(id);
// 删除 // 删除该记录下的跟进用户
recordMapper.deleteById(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) { private void validateRecordExists(Long id) {
@ -132,26 +179,88 @@ public class CrmRecordServiceImpl implements CrmRecordService {
} else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) { } else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
ids = adminUserApi.getUserListBySubordinateIds(adminId).getCheckedData(); 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); 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));
}
List<String> recordTypes = list.stream().map(CrmRecordRespVO::getRecordType).map(String::valueOf).collect(Collectors.toList());
for (CrmRecordRespVO crmRecordRespVO : pageResult1.getList()) { List<DictDataRespDTO> respDTOS = CollUtil.isNotEmpty(recordTypes) ? dictDataApi.getByValues(new DictParameterRespDTO().setDictType("follow_status").setValues(recordTypes)).getCheckedData() : new ArrayList<>();
DictDataRespDTO dto = dictDataApi.getDictData("follow_status", crmRecordRespVO.getRecordType().toString()).getCheckedData(); Map<String, DictDataRespDTO> dictDataMap = CollectionUtils.convertMap(respDTOS, DictDataRespDTO::getValue);
crmRecordRespVO.setRecordTypeName(dto.getLabel()); Map<String, List<Long>> typeIdMap = list.stream().collect(Collectors.groupingBy(CrmRecordRespVO::getTypes, Collectors.mapping(CrmRecordRespVO::getTypesId, Collectors.toList())));
if (TypesEnum.CUSTOMER.getValue().equals(crmRecordRespVO.getTypes())) { // 批量查询客户业务和线索数据
CrmCustomerDO customerDO = customerMapper.selectById(crmRecordRespVO.getTypesId()); Map<Long, CrmCustomerDO> customerMap = new HashMap<>();
crmRecordRespVO.setTypesName(customerDO.getName()); if (CollUtil.isNotEmpty(typeIdMap.get(TypesEnum.CUSTOMER.getValue()))) {
} else if (TypesEnum.BUSINESS.getValue().equals(crmRecordRespVO.getTypes())) { customerMap = customerMapper.selectBatchIds(typeIdMap.get(TypesEnum.CUSTOMER.getValue())).stream()
CrmBusinessDO crmBusinessDO = crmBusinessMapper.selectById(crmRecordRespVO.getTypesId()); .collect(Collectors.toMap(CrmCustomerDO::getId, item -> item));
crmRecordRespVO.setTypesName(crmBusinessDO.getName()); }
} else if (TypesEnum.CLUES.getValue().equals(crmRecordRespVO.getTypes())) { Map<Long, CrmBusinessDO> businessMap = new HashMap<>();
CrmCluesDO crmCluesDO = cluesMapper.selectById(crmRecordRespVO.getTypesId()); if (CollUtil.isNotEmpty(typeIdMap.get(TypesEnum.BUSINESS.getValue()))) {
crmRecordRespVO.setTypesName(crmCluesDO.getName()); 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());
} }
AdminUserRespDTO adminUserRespDTO = adminUserApi.getUser(crmRecordRespVO.getCreator()).getCheckedData(); // 根据类型设置名称
crmRecordRespVO.setOwnUserName(adminUserRespDTO.getNickname()); 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(types)) {
CrmBusinessDO crmBusinessDO = businessMap.get(crmRecordRespVO.getTypesId());
if (crmBusinessDO != null) {
crmRecordRespVO.setTypesName(crmBusinessDO.getName());
}
} else if (TypesEnum.CLUES.getValue().equals(types)) {
CrmCluesDO crmCluesDO = cluesMap.get(crmRecordRespVO.getTypesId());
if (crmCluesDO != null) {
crmRecordRespVO.setTypesName(crmCluesDO.getName());
}
}
// 获取创建者信息
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; return pageResult1;
} }

View File

@ -0,0 +1,10 @@
package cn.iocoder.yudao.module.crm.service.crmrecorduser;
/**
* 跟进用户记录 Service 接口
*
* @author 艾楷
*/
public interface CrmRecordUserService {
}

View File

@ -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;
}

View File

@ -11,27 +11,30 @@
<select id="selectStatistics" resultType="cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.RecordStatisticsRespVO"> <select id="selectStatistics" resultType="cn.iocoder.yudao.module.crm.controller.admin.crmrecord.vo.RecordStatisticsRespVO">
SELECT SELECT
creator AS creator, b.user_id AS creator,
COUNT(1) AS count, COUNT( a.id ) AS count,
SUM(CASE WHEN types = 'business' THEN 1 ELSE 0 END) AS businessCount, SUM( CASE WHEN a.types = 'business' THEN 1 ELSE 0 END ) AS businessCount,
SUM(CASE WHEN types = 'customer' THEN 1 ELSE 0 END) AS customerCount, SUM( CASE WHEN a.types = 'customer' THEN 1 ELSE 0 END ) AS customerCount,
SUM(CASE WHEN types = 'clues' THEN 1 ELSE 0 END) AS cluesCount SUM( CASE WHEN a.types = 'clues' THEN 1 ELSE 0 END ) AS cluesCount
FROM FROM
crm_record crm_record as a
WHERE LEFT JOIN crm_record_user as b on a.id = b.record_id
deleted = 0 <where>
AND creator IN a.deleted = 0
and b.deleted = 0
AND b.user_id IN
<foreach item="userId" collection="userIds" separator="," open="(" close=")" index=""> <foreach item="userId" collection="userIds" separator="," open="(" close=")" index="">
#{userId} #{userId}
</foreach> </foreach>
<if test="createTime != null and createTime.length > 0"> <if test="createTime != null and createTime.length > 0">
<if test="createTime[0] != null"> <if test="createTime[0] != null">
AND create_time &gt;= #{createTime[0]} AND b.create_time &gt;= #{createTime[0]}
</if> </if>
<if test="createTime[1] != null"> <if test="createTime[1] != null">
AND create_time &lt;= #{createTime[1]} AND b.create_time &lt;= #{createTime[1]}
</if> </if>
</if> </if>
GROUP BY creator GROUP BY b.user_id
</where>
</select> </select>
</mapper> </mapper>

View File

@ -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>

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.api.dict;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; 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.DictDataRespDTO;
import cn.iocoder.yudao.module.system.api.dict.dto.DictParameterRespDTO;
import cn.iocoder.yudao.module.system.enums.ApiConstants; import cn.iocoder.yudao.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; 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 io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping; 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 org.springframework.web.bind.annotation.RequestParam;
import java.util.Collection; import java.util.Collection;
@ -23,8 +26,8 @@ public interface DictDataApi {
@GetMapping(PREFIX + "/valid") @GetMapping(PREFIX + "/valid")
@Operation(summary = "校验字典数据们是否有效") @Operation(summary = "校验字典数据们是否有效")
@Parameters({ @Parameters({
@Parameter(name = "dictType", description = "字典类型", example = "SEX", required = true), @Parameter(name = "dictType", description = "字典类型", example = "SEX", required = true),
@Parameter(name = "descriptions", description = "字典数据值的数组", example = "1,2", required = true) @Parameter(name = "descriptions", description = "字典数据值的数组", example = "1,2", required = true)
}) })
CommonResult<Boolean> validateDictDataList(@RequestParam("dictType") String dictType, CommonResult<Boolean> validateDictDataList(@RequestParam("dictType") String dictType,
@RequestParam("values") Collection<String> values); @RequestParam("values") Collection<String> values);
@ -38,6 +41,12 @@ public interface DictDataApi {
CommonResult<DictDataRespDTO> getDictData(@RequestParam("dictType") String dictType, CommonResult<DictDataRespDTO> getDictData(@RequestParam("dictType") String dictType,
@RequestParam("value") String value); @RequestParam("value") String value);
@PostMapping(PREFIX + "/getByValues")
@Operation(summary = "获得指定的字典数据-(值多选筛选)")
CommonResult<List<DictDataRespDTO>> getByValues(@RequestBody DictParameterRespDTO dto);
@GetMapping(PREFIX + "/parse") @GetMapping(PREFIX + "/parse")
@Operation(summary = "解析获得指定的字典数据") @Operation(summary = "解析获得指定的字典数据")
@Parameters({ @Parameters({

View File

@ -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;
}

View File

@ -1,9 +1,11 @@
package cn.iocoder.yudao.module.system.api.dict; 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.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 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.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.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.service.dict.DictDataService; import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -34,6 +36,12 @@ public class DictDataApiImpl implements DictDataApi {
return success(BeanUtils.toBean(dictData, DictDataRespDTO.class)); 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 @Override
public CommonResult<DictDataRespDTO> parseDictData(String dictType, String label) { public CommonResult<DictDataRespDTO> parseDictData(String dictType, String label) {
DictDataDO dictData = dictDataService.parseDictData(dictType, label); DictDataDO dictData = dictDataService.parseDictData(dictType, label);

View File

@ -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.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 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.controller.admin.dict.vo.data.DictDataPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

View File

@ -80,7 +80,8 @@ public class HolidayGrantJob {
editList.add(holidayBalanceSettingDO); editList.add(holidayBalanceSettingDO);
Long holidaySettingId = holidayBalanceSettingDO.getHolidaySettingId(); Long holidaySettingId = holidayBalanceSettingDO.getHolidaySettingId();
// 发放假期 // 发放假期
holidayUserRecordService.grant(holidaySettingMap.get(holidaySettingId), holidaySettingRangeMap.get(holidaySettingId), holidayBalanceSettingDO, holidayWorkingAgeDOMap.get(holidaySettingId)); holidayUserRecordService.grant(holidaySettingMap.get(holidaySettingId), holidaySettingRangeMap.get(holidaySettingId),
holidayBalanceSettingDO, holidayWorkingAgeDOMap.get(holidaySettingId), false);
} }
} }
// -- // 按照员工入职日 每年员工入职日 // -- // 按照员工入职日 每年员工入职日
@ -91,7 +92,8 @@ public class HolidayGrantJob {
for (HolidayBalanceSettingDO holidayBalanceSettingDO : employmentGrantList) { for (HolidayBalanceSettingDO holidayBalanceSettingDO : employmentGrantList) {
Long holidaySettingId = holidayBalanceSettingDO.getHolidaySettingId(); Long holidaySettingId = holidayBalanceSettingDO.getHolidaySettingId();
// 发放假期 // 发放假期
holidayUserRecordService.grant(holidaySettingMap.get(holidaySettingId), holidaySettingRangeMap.get(holidaySettingId), holidayBalanceSettingDO, holidayWorkingAgeDOMap.get(holidaySettingId)); holidayUserRecordService.grant(holidaySettingMap.get(holidaySettingId), holidaySettingRangeMap.get(holidaySettingId),
holidayBalanceSettingDO, holidayWorkingAgeDOMap.get(holidaySettingId), false);
} }
} }
if (CollectionUtil.isNotEmpty(editList)) { if (CollectionUtil.isNotEmpty(editList)) {

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.system.service.attendance.groupuser; package cn.iocoder.yudao.module.system.service.attendance.groupuser;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.date.LocalDateTimeUtil;
import cn.iocoder.yudao.framework.common.Constants; import cn.iocoder.yudao.framework.common.Constants;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
@ -10,11 +12,17 @@ import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGr
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserSaveReqVO; import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO; import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO; import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysetting.HolidaySettingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysettingrange.HolidaySettingRangeDO;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupuser.AttendanceGroupUserMapper; import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupuser.AttendanceGroupUserMapper;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper; import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper;
import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO; import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO;
import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService; import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService;
import cn.iocoder.yudao.module.system.service.holiday.holidaysetting.HolidaySettingService;
import cn.iocoder.yudao.module.system.service.holiday.holidaysettingrange.HolidaySettingRangeService;
import cn.iocoder.yudao.module.system.service.holiday.holidayuserrecord.HolidayUserRecordService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -25,6 +33,7 @@ import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -47,6 +56,13 @@ public class AttendanceGroupUserServiceImpl implements AttendanceGroupUserServic
private AttendancePunchRecordMapper attendancePunchRecordMapper; private AttendancePunchRecordMapper attendancePunchRecordMapper;
@Resource @Resource
private AttendancePunchRecordService attendancePunchRecordService; private AttendancePunchRecordService attendancePunchRecordService;
@Resource
private HolidayUserRecordService holidayUserRecordService;
@Resource
private HolidaySettingRangeService holidaySettingRangeService;
@Resource
@Lazy
private HolidaySettingService holidaySettingService;
@Override @Override
public AttendanceGroupUserCreateOrDelVO createOrDel(Long attendanceGroupId, List<Long> userIds) { public AttendanceGroupUserCreateOrDelVO createOrDel(Long attendanceGroupId, List<Long> userIds) {
@ -66,10 +82,28 @@ public class AttendanceGroupUserServiceImpl implements AttendanceGroupUserServic
.in(AttendanceGroupUserDO::getUserId, delIds)); .in(AttendanceGroupUserDO::getUserId, delIds));
} }
if (CollectionUtil.isNotEmpty(saveIds)) { if (CollectionUtil.isNotEmpty(saveIds)) {
List<HolidaySettingRangeDO> items = new ArrayList<>();
for (Long userId : saveIds) { for (Long userId : saveIds) {
list.add(new AttendanceGroupUserDO().setUserId(userId).setAttendanceGroupId(attendanceGroupId)); list.add(new AttendanceGroupUserDO().setUserId(userId).setAttendanceGroupId(attendanceGroupId));
HolidaySettingRangeDO item = new HolidaySettingRangeDO();
item.setType(3);
item.setObjectId(userId);
items.add(item);
} }
groupUserMapper.insertBatch(list); groupUserMapper.insertBatch(list);
// -- 新添加到考勤组的 需要同步更新员工假期余额
// -- 获取当前用户所在的考勤组 - 再根据考勤组 查询对应的加班规则
List<Long> holidaySettingIds = holidaySettingRangeService.getHolidaySettingIdsByGroupId(attendanceGroupId);
if (CollUtil.isNotEmpty(holidaySettingIds)) {
List<HolidaySettingDO> holidaySettings = holidaySettingService.getHolidaySettingByIds(holidaySettingIds);
Map<Long, HolidaySettingDO> holidaySettingMap = holidaySettings.stream().collect(Collectors.toMap(HolidaySettingDO::getId, holidaySettingDO -> holidaySettingDO));
for (HolidaySettingDO holidaySetting : holidaySettings) {
holidayUserRecordService.grant(holidaySetting,
items, holidaySettingMap.get(holidaySetting.getId()).getHolidayBalanceSettingDO(), ListUtil.empty(), true);
}
}
} }
vo.setAttendanceGroupId(attendanceGroupId); vo.setAttendanceGroupId(attendanceGroupId);
vo.setDelUserIds(delIds); vo.setDelUserIds(delIds);
@ -151,4 +185,4 @@ public class AttendanceGroupUserServiceImpl implements AttendanceGroupUserServic
.stream().map(AttendanceGroupUserDO::getUserId).collect(Collectors.toList()); .stream().map(AttendanceGroupUserDO::getUserId).collect(Collectors.toList());
} }
} }

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.service.dict; package cn.iocoder.yudao.module.system.service.dict;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.DictDataPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO; import cn.iocoder.yudao.module.system.controller.admin.dict.vo.data.DictDataSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO; import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;

View File

@ -102,4 +102,12 @@ public interface HolidaySettingService {
* @return * @return
*/ */
List<HolidaySettingDO> getLimitBalanceHolidayList(); List<HolidaySettingDO> getLimitBalanceHolidayList();
/**
* 根据ids获取
*
* @param holidaySettingIds
* @return
*/
List<HolidaySettingDO> getHolidaySettingByIds(List<Long> holidaySettingIds);
} }

View File

@ -289,6 +289,16 @@ public class HolidaySettingServiceImpl implements HolidaySettingService {
return holidaySettingMapper.getLimitBalanceHolidayList(); return holidaySettingMapper.getLimitBalanceHolidayList();
} }
@Override
public List<HolidaySettingDO> getHolidaySettingByIds(List<Long> holidaySettingIds) {
List<HolidaySettingDO> holidaySettingDOS = holidaySettingMapper.selectBatchIds(holidaySettingIds);
Map<Long, HolidayBalanceSettingDO> map = holidayBalanceSettingService.selectBySettingIds(holidaySettingIds);
for (HolidaySettingDO holidaySettingDO : holidaySettingDOS) {
holidaySettingDO.setHolidayBalanceSettingDO(map.get(holidaySettingDO.getId()));
}
return holidaySettingDOS;
}
/** /**
* 编辑假期设置 * 编辑假期设置

View File

@ -84,4 +84,20 @@ public interface HolidaySettingRangeService {
* @return * @return
*/ */
List<HolidaySettingRangeDO> getListByHolidaySettingIds(List<Long> holidaySettingIds); List<HolidaySettingRangeDO> getListByHolidaySettingIds(List<Long> holidaySettingIds);
/**
* 根据考勤组id获取当前考勤组所在的假期
*
* @param groupId
* @return
*/
List<HolidaySettingRangeDO> getByGroupId(Long groupId);
/**
* 根据考勤组id 获取和考勤组关联的假期ids
*
* @param groupId
* @return
*/
List<Long> getHolidaySettingIdsByGroupId(Long groupId);
} }

View File

@ -101,11 +101,23 @@ public class HolidaySettingRangeServiceImpl implements HolidaySettingRangeServic
@Override @Override
public List<HolidaySettingRangeDO> getListByHolidaySettingIds(List<Long> holidaySettingIds) { public List<HolidaySettingRangeDO> getListByHolidaySettingIds(List<Long> holidaySettingIds) {
if (CollUtil.isEmpty(holidaySettingIds)){ if (CollUtil.isEmpty(holidaySettingIds)) {
return Collections.emptyList(); return Collections.emptyList();
} }
return holidaySettingRangeMapper.selectList(new LambdaQueryWrapper<HolidaySettingRangeDO>() return holidaySettingRangeMapper.selectList(new LambdaQueryWrapper<HolidaySettingRangeDO>()
.in(HolidaySettingRangeDO::getHolidaySettingId, holidaySettingIds)); .in(HolidaySettingRangeDO::getHolidaySettingId, holidaySettingIds));
} }
@Override
public List<HolidaySettingRangeDO> getByGroupId(Long groupId) {
return holidaySettingRangeMapper.selectList(new LambdaQueryWrapper<HolidaySettingRangeDO>()
.eq(HolidaySettingRangeDO::getType, 1)
.eq(HolidaySettingRangeDO::getObjectId, groupId));
}
@Override
public List<Long> getHolidaySettingIdsByGroupId(Long groupId) {
return this.getByGroupId(groupId).stream().map(HolidaySettingRangeDO::getHolidaySettingId).collect(Collectors.toList());
}
} }

View File

@ -78,7 +78,7 @@ public interface HolidayUserRecordService {
* @param holidayBalanceSettingDO * @param holidayBalanceSettingDO
* @param holidayWorkingAgeDOS * @param holidayWorkingAgeDOS
*/ */
void grant(HolidaySettingDO holidaySetting, List<HolidaySettingRangeDO> holidaySettingRangeDOS, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayWorkingAgeDO> holidayWorkingAgeDOS); void grant(HolidaySettingDO holidaySetting, List<HolidaySettingRangeDO> holidaySettingRangeDOS, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayWorkingAgeDO> holidayWorkingAgeDOS, Boolean recordZero);
/** /**
* 清空假期余额 * 清空假期余额

View File

@ -94,7 +94,8 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
List<HolidayUserRecordDO> newHolidayUserRecordDOList = new ArrayList<>(); List<HolidayUserRecordDO> newHolidayUserRecordDOList = new ArrayList<>();
List<HolidayUserDO> newHolidayUserDOList = new ArrayList<>(); List<HolidayUserDO> newHolidayUserDOList = new ArrayList<>();
String remark = myself.getNickname() + "" + targetUser.getNickname() + (createReqVO.getDirection() == 0 ? "增加" : "减去"); String remark = myself.getNickname() + "" + targetUser.getNickname() + (createReqVO.getDirection() == 0 ? "增加" : "减去");
this.calculateUserHolidays(userQuotaMap, userId, holidayUserDOMap, holidaySetting, holidayBalanceSettingDO, newHolidayUserRecordDOList, newHolidayUserDOList, now, remark, createReqVO.getDirection(), createReqVO.getReason()); this.calculateUserHolidays(userQuotaMap, userId, holidayUserDOMap, holidaySetting, holidayBalanceSettingDO, newHolidayUserRecordDOList,
newHolidayUserDOList, now, remark, createReqVO.getDirection(), createReqVO.getReason(), false);
if (CollUtil.isNotEmpty(newHolidayUserRecordDOList)) { if (CollUtil.isNotEmpty(newHolidayUserRecordDOList)) {
holidayUserRecordMapper.insertBatch(newHolidayUserRecordDOList); holidayUserRecordMapper.insertBatch(newHolidayUserRecordDOList);
@ -184,7 +185,8 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
List<HolidayUserRecordDO> newHolidayUserRecordDOList = new ArrayList<>(); List<HolidayUserRecordDO> newHolidayUserRecordDOList = new ArrayList<>();
List<HolidayUserDO> newHolidayUserDOList = new ArrayList<>(); List<HolidayUserDO> newHolidayUserDOList = new ArrayList<>();
String remark = targetUser.getNickname() + "使用了 "; String remark = targetUser.getNickname() + "使用了 ";
this.calculateUserHolidays(userQuotaMap, dto.getUserId(), holidayUserDOMap, holidaySetting, holidayBalanceSettingDO, newHolidayUserRecordDOList, newHolidayUserDOList, now, remark, dto.getDirection(), dto.getReason()); this.calculateUserHolidays(userQuotaMap, dto.getUserId(), holidayUserDOMap, holidaySetting, holidayBalanceSettingDO,
newHolidayUserRecordDOList, newHolidayUserDOList, now, remark, dto.getDirection(), dto.getReason(), false);
List<HolidayUserRecordDO> editList = new ArrayList<>(); List<HolidayUserRecordDO> editList = new ArrayList<>();
if (dto.getDirection() == 1) { if (dto.getDirection() == 1) {
@ -292,7 +294,8 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
@Override @Override
public void grant(HolidaySettingDO holidaySetting, List<HolidaySettingRangeDO> holidaySettingRangeDOS, HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayWorkingAgeDO> holidayWorkingAgeDOS) { public void grant(HolidaySettingDO holidaySetting, List<HolidaySettingRangeDO> holidaySettingRangeDOS,
HolidayBalanceSettingDO holidayBalanceSettingDO, List<HolidayWorkingAgeDO> holidayWorkingAgeDOS, Boolean recordZero) {
// -- 先查询出所有用户 // -- 先查询出所有用户
List<AdminUserDO> users = this.getUsersByRange(holidaySetting, holidaySettingRangeDOS); List<AdminUserDO> users = this.getUsersByRange(holidaySetting, holidaySettingRangeDOS);
// -- 计算获取每个人的假期额度 // -- 计算获取每个人的假期额度
@ -334,7 +337,8 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
} }
for (Long userId : userIds) { for (Long userId : userIds) {
String remark = "系统按照规则自动 增加"; String remark = "系统按照规则自动 增加";
this.calculateUserHolidays(userQuotaMap, userId, holidayUserDOMap, holidaySetting, holidayBalanceSettingDO, newHolidayUserRecordDOList, newHolidayUserDOList, now, remark, 0, null); this.calculateUserHolidays(userQuotaMap, userId, holidayUserDOMap, holidaySetting, holidayBalanceSettingDO,
newHolidayUserRecordDOList, newHolidayUserDOList, now, remark, 0, null, recordZero);
} }
// TODO: 2024/10/23 这里可能还会慢 // TODO: 2024/10/23 这里可能还会慢
if (CollUtil.isNotEmpty(newHolidayUserRecordDOList)) { if (CollUtil.isNotEmpty(newHolidayUserRecordDOList)) {
@ -427,10 +431,10 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
private void calculateUserHolidays(Map<Long, BigDecimal> userQuotaMap, Long userId, Map<Long, HolidayUserDO> holidayUserDOMap, private void calculateUserHolidays(Map<Long, BigDecimal> userQuotaMap, Long userId, Map<Long, HolidayUserDO> holidayUserDOMap,
HolidaySettingDO holidaySetting, HolidayBalanceSettingDO holidayBalanceSettingDO, HolidaySettingDO holidaySetting, HolidayBalanceSettingDO holidayBalanceSettingDO,
List<HolidayUserRecordDO> newHolidayUserRecordDOList, List<HolidayUserDO> newHolidayUserDOList, List<HolidayUserRecordDO> newHolidayUserRecordDOList, List<HolidayUserDO> newHolidayUserDOList,
LocalDateTime now, String remark, Integer direction, String reason) { LocalDateTime now, String remark, Integer direction, String reason, Boolean recordZero) {
BigDecimal quota = userQuotaMap.get(userId); BigDecimal quota = userQuotaMap.get(userId);
// -- 如果是0的话就不记录了 // -- 如果是0的话就不记录了 -- 如果不记录0 并且是0 直接return
if (quota == null || BigDecimal.ZERO.compareTo(quota) == 0) { if (quota == null || (BigDecimal.ZERO.compareTo(quota) == 0 && !recordZero)) {
return; return;
} }
HolidayUserDO holidayUserDO = holidayUserDOMap.get(userId); HolidayUserDO holidayUserDO = holidayUserDOMap.get(userId);
@ -783,7 +787,8 @@ public class HolidayUserRecordServiceImpl implements HolidayUserRecordService {
List<HolidayUserRecordDO> newHolidayUserRecordDOList = new ArrayList<>(); List<HolidayUserRecordDO> newHolidayUserRecordDOList = new ArrayList<>();
List<HolidayUserDO> newHolidayUserDOList = new ArrayList<>(); List<HolidayUserDO> newHolidayUserDOList = new ArrayList<>();
String remark = "加班" + (dto.getDirection() == 0 ? "增加" : "减去"); String remark = "加班" + (dto.getDirection() == 0 ? "增加" : "减去");
this.calculateUserHolidays(userQuotaMap, userId, holidayUserDOMap, holidaySetting, holidayBalanceSettingDO, newHolidayUserRecordDOList, newHolidayUserDOList, now, remark, dto.getDirection(), dto.getReason()); this.calculateUserHolidays(userQuotaMap, userId, holidayUserDOMap, holidaySetting, holidayBalanceSettingDO,
newHolidayUserRecordDOList, newHolidayUserDOList, now, remark, dto.getDirection(), dto.getReason(), false);
if (CollUtil.isNotEmpty(newHolidayUserRecordDOList)) { if (CollUtil.isNotEmpty(newHolidayUserRecordDOList)) {
holidayUserRecordMapper.insertBatch(newHolidayUserRecordDOList); holidayUserRecordMapper.insertBatch(newHolidayUserRecordDOList);
} }

View File

@ -854,7 +854,7 @@ public class AdminUserServiceImpl implements AdminUserService {
List<DeptDO> deptList = deptService.getAllList(); List<DeptDO> deptList = deptService.getAllList();
Map<Long, List<DeptDO>> map = deptList.stream().collect(Collectors.groupingBy(DeptDO::getParentId)); Map<Long, List<DeptDO>> map = deptList.stream().collect(Collectors.groupingBy(DeptDO::getParentId));
this.getSubordinateDeptIds(map, nextIds, ids); this.getSubordinateDeptIds(map, nextIds, ids);
nextIds.add(dept.getId());
nextIds = nextIds.stream().distinct().collect(Collectors.toList()); nextIds = nextIds.stream().distinct().collect(Collectors.toList());
// 2. 获取部门对应的用户信息 // 2. 获取部门对应的用户信息
List<AdminUserDO> users = this.getUserListByDeptIds(nextIds, null); List<AdminUserDO> users = this.getUserListByDeptIds(nextIds, null);