Commit a5224c7e authored by yanghao's avatar yanghao

chore: 客户跟进纪录的实现和下载接口的实现

parent 2202b83a
package cn.iocoder.yudao.framework.apollo.core.event.export;
import cn.iocoder.yudao.framework.apollo.core.event.export.base.CustomerExportEvent;
import cn.iocoder.yudao.framework.apollo.core.event.export.base.IndirectCustomerExportEvent;
import lombok.Data;
@Data
public class CustomerFollowupExcelExportPushEvent extends CustomerExportEvent {
}
\ No newline at end of file
package cn.iocoder.yudao.module.customer.convert.customerFollowup;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import cn.iocoder.yudao.module.customer.vo.customerFollowup.*;
import cn.iocoder.yudao.module.customer.dal.dataobject.customerFollowup.CustomerFollowupDO;
/**
* 客户跟进 Convert
* @author yanghao
*/
@Mapper
public interface CustomerFollowupConvert {
/*****转换MapStruct*****/
CustomerFollowupConvert INSTANCE = Mappers.getMapper(CustomerFollowupConvert.class);
/***
* 创建VO转实体
* @param bean
* @return
*/
CustomerFollowupDO convert(CustomerFollowupCreateReqVO bean);
/***
* 修改VO转实体
* @param bean
* @return
*/
CustomerFollowupDO convert(CustomerFollowupUpdateReqVO bean);
/***
* 实体转返回VO
* @param bean
* @return
*/
CustomerFollowupBackVO convert(CustomerFollowupDO bean);
/***
* 实体列表转返回VO列表
* @param list
* @return
*/
List<CustomerFollowupBackVO> convertList(List<CustomerFollowupDO> list);
/***
* 实体分页转返回分页
* @param page
* @return
*/
PageResult<CustomerFollowupBackVO> convertPage(PageResult<CustomerFollowupDO> page);
}
package cn.iocoder.yudao.module.customer.dal.dataobject.customerFollowup;
import lombok.*;
import java.util.*;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 客户跟进 DO
*
* @author yanghao
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("ecw_customer_followup")
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CustomerFollowupDO extends BaseDO {
/**
* 主键
*/
@TableId
private Long id;
/**
* 编号
*/
private String number;
/**
* 上一级跟进单号
*/
private String parentNumber;
/**
* 状态 字典customer_followup_status
*/
private Integer status;
/**
* 客户编号
*/
private Long customerId;
/**
* 报价单
*/
private Long offerId;
/**
* 跟进类型 字典customer_followup_type
*/
private Integer followType;
/**
* 跟进时间
*/
private Date followTime;
/**
* 联系人
*/
private String contactName;
/**
* 跟进方式 字典customer_followup_method
*/
private Integer followMethod;
/**
* 客户经理/跟进业务员id
*/
private Long followUserId;
/**
* 目的
*/
private String purpose;
/**
* 跟进结果 字典customer_followup_result_type
*/
private Integer resultType;
/**
* 客户反馈
*/
private String feedback;
/**
* 附件 多个以逗号分隔
*/
private String attatchment;
/**
* 下次跟进时间
*/
private Date nextTime;
/**
* 下次跟进计划
*/
private String nextPlan;
@TableField(exist = false)
private String customerNumber;
@TableField(exist = false)
private String offerNumber;
//creator_name
@TableField(exist = false)
private String creatorName;
// updater_name
@TableField(exist = false)
private String updaterName;
}
package cn.iocoder.yudao.module.customer.dal.mysql.customerFollowup;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQuery;
import cn.iocoder.yudao.framework.mybatis.core.mapper.AbstractMapper;
import cn.iocoder.yudao.module.customer.dal.dataobject.customer.CustomerDO;
import cn.iocoder.yudao.module.customer.dal.dataobject.customerFollowup.CustomerFollowupDO;
import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.module.customer.dto.CustomerPageReqDTO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.customer.vo.customerFollowup.*;
import org.apache.ibatis.annotations.Param;
/**
* 客户跟进 Mapper
* @author yanghao
*/
@Mapper
public interface CustomerFollowupMapper extends AbstractMapper<CustomerFollowupDO> {
List<CustomerFollowupDO> selectPage1(@Param("start") Integer start, @Param("size") Integer size,
@Param("query") CustomerFollowupQueryVO customerFollowupQueryVO);
Long selectCount1(@Param("query") CustomerFollowupQueryVO customerFollowupQueryVO);
@Override
default PageResult<CustomerFollowupDO> selectPage(PageVO page, Object object) {
if (object instanceof CustomerFollowupQueryVO) {
CustomerFollowupQueryVO vo = (CustomerFollowupQueryVO)object;
return selectPage(page, new LambdaQuery<CustomerFollowupDO>()
.eqIfPresent(CustomerFollowupDO::getNumber, vo.getNumber())
.eqIfPresent(CustomerFollowupDO::getParentNumber, vo.getParentNumber())
.eqIfPresent(CustomerFollowupDO::getStatus, vo.getStatus())
.eqIfPresent(CustomerFollowupDO::getCustomerId, vo.getCustomerId())
.eqIfPresent(CustomerFollowupDO::getOfferId, vo.getOfferId())
.eqIfPresent(CustomerFollowupDO::getFollowType, vo.getFollowType())
.betweenIfPresent(CustomerFollowupDO::getFollowTime, vo.getBeginFollowTime(), vo.getEndFollowTime())
.likeIfPresent(CustomerFollowupDO::getContactName, vo.getContactName())
.eqIfPresent(CustomerFollowupDO::getFollowMethod, vo.getFollowMethod())
.eqIfPresent(CustomerFollowupDO::getFollowUserId, vo.getFollowUserId())
.eqIfPresent(CustomerFollowupDO::getPurpose, vo.getPurpose())
.eqIfPresent(CustomerFollowupDO::getResultType, vo.getResultType())
.eqIfPresent(CustomerFollowupDO::getFeedback, vo.getFeedback())
.eqIfPresent(CustomerFollowupDO::getAttatchment, vo.getAttatchment())
.betweenIfPresent(CustomerFollowupDO::getNextTime, vo.getBeginNextTime(), vo.getEndNextTime())
.eqIfPresent(CustomerFollowupDO::getNextPlan, vo.getNextPlan())
.betweenIfPresent(CustomerFollowupDO::getCreateTime, vo.getBeginCreateTime(), vo.getEndCreateTime())
.orderByDesc(CustomerFollowupDO::getId));
}
return null;
}
@Override
default List<CustomerFollowupDO> selectList(Object object) {
if (object instanceof CustomerFollowupQueryVO) {
CustomerFollowupQueryVO vo = (CustomerFollowupQueryVO)object;
return selectList(new LambdaQuery<CustomerFollowupDO>()
.eqIfPresent(CustomerFollowupDO::getNumber, vo.getNumber())
.eqIfPresent(CustomerFollowupDO::getParentNumber, vo.getParentNumber())
.eqIfPresent(CustomerFollowupDO::getStatus, vo.getStatus())
.eqIfPresent(CustomerFollowupDO::getCustomerId, vo.getCustomerId())
.eqIfPresent(CustomerFollowupDO::getOfferId, vo.getOfferId())
.eqIfPresent(CustomerFollowupDO::getFollowType, vo.getFollowType())
.betweenIfPresent(CustomerFollowupDO::getFollowTime, vo.getBeginFollowTime(), vo.getEndFollowTime())
.likeIfPresent(CustomerFollowupDO::getContactName, vo.getContactName())
.eqIfPresent(CustomerFollowupDO::getFollowMethod, vo.getFollowMethod())
.eqIfPresent(CustomerFollowupDO::getFollowUserId, vo.getFollowUserId())
.eqIfPresent(CustomerFollowupDO::getPurpose, vo.getPurpose())
.eqIfPresent(CustomerFollowupDO::getResultType, vo.getResultType())
.eqIfPresent(CustomerFollowupDO::getFeedback, vo.getFeedback())
.eqIfPresent(CustomerFollowupDO::getAttatchment, vo.getAttatchment())
.betweenIfPresent(CustomerFollowupDO::getNextTime, vo.getBeginNextTime(), vo.getEndNextTime())
.eqIfPresent(CustomerFollowupDO::getNextPlan, vo.getNextPlan())
.betweenIfPresent(CustomerFollowupDO::getCreateTime, vo.getBeginCreateTime(), vo.getEndCreateTime())
.orderByDesc(CustomerFollowupDO::getId));
}
return null;
}
}
......@@ -32,5 +32,7 @@ public interface ErrorCodeConstants {
ErrorCode COMPETITOR_NOT_EXISTS = new ErrorCode(1005001011, "客户竞争对手不存在");
ErrorCode COMPETITOR_EXISTS = new ErrorCode(1005001012, "竞争对手名称已存在");
ErrorCode FOLLOWUP_NOT_EXISTS = new ErrorCode(1005001013, "客户跟进不存在");
ErrorCode FOLLOWUP_ALREADY_SUBMITTED = new ErrorCode(1005001014, "客户跟进已提交不可再修改");
}
package cn.iocoder.yudao.module.customer.service.customerFollowup;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.framework.mybatis.core.service.IService;
import cn.iocoder.yudao.module.customer.vo.customerFollowup.*;
import cn.iocoder.yudao.module.customer.dal.dataobject.customerFollowup.CustomerFollowupDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
/**
* 客户跟进 Service 接口
*
* @author yanghao
*/
public interface CustomerFollowupService extends IService<CustomerFollowupDO> {
String generateFollowupNumber();
/**
* 创建客户跟进
* @param createReqVO 创建信息
* @return 编号
*/
Long createFollowup(@Valid CustomerFollowupCreateReqVO createReqVO);
/**
* 更新客户跟进
* @param updateReqVO 更新信息
*/
void updateFollowup(@Valid CustomerFollowupUpdateReqVO updateReqVO);
void updateFollowupStatus(@Valid CustomerFollowupUpdateStatusReqVO updateStatusReqVO);
/**
* 删除客户跟进
* @param id 编号
*/
void deleteFollowup(Long id);
/**
* 获得客户跟进
* @param id 编号
* @return 客户跟进
*/
CustomerFollowupDO getFollowup(Long id);
/**
* 获得客户跟进列表
* @param ids 编号
* @return 客户跟进列表
*/
List<CustomerFollowupDO> getFollowupList(Collection<Long> ids);
/**
* 获得客户跟进分页
* @param page 分页查询
* @param query 查询
* @return 客户跟进分页
*/
PageResult<CustomerFollowupDO> getFollowupPage(CustomerFollowupQueryVO query, PageVO page);
/**
* 获得客户跟进列表, 用于 Excel 导出
* @param query 查询
* @return 客户跟进列表
*/
List<CustomerFollowupDO> getFollowupList(CustomerFollowupQueryVO query);
}
package cn.iocoder.yudao.module.customer.service.customerFollowup;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import javax.annotation.Resource;
import cn.iocoder.yudao.framework.i18n.core.I18nMessage;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.customer.dal.dataobject.customer.CustomerDO;
import cn.iocoder.yudao.module.ecw.enums.CustomerFollowupStatusEnum;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.framework.mybatis.core.service.AbstractService;
import cn.iocoder.yudao.module.customer.vo.customerFollowup.*;
import cn.iocoder.yudao.module.customer.dal.dataobject.customerFollowup.CustomerFollowupDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.customer.convert.customerFollowup.CustomerFollowupConvert;
import cn.iocoder.yudao.module.customer.dal.mysql.customerFollowup.CustomerFollowupMapper;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.customer.enums.ErrorCodeConstants.*;
/**
* 客户跟进 Service 实现类
*
* @author yanghao
*/
@Service
@Validated
public class CustomerFollowupServiceImpl extends AbstractService<CustomerFollowupMapper, CustomerFollowupDO> implements CustomerFollowupService {
@Resource
private CustomerFollowupMapper followupMapper;
/**
* 跟进单编号生成方式:GJ+年份+六位数字,按年份累计
* @return
*/
@Override
public String generateFollowupNumber() {
// 获取当前时间的年份
LocalDate now = LocalDate.now();
int year = now.getYear();
// 获取当前年份的初始化时间
LocalDateTime startOfYear = LocalDateTime.of(year, 1, 1, 0, 0, 0, 0);
Date from = Date.from(startOfYear.atZone(ZoneId.systemDefault()).toInstant());
Long count = followupMapper.selectCount(new LambdaQueryWrapperX<CustomerFollowupDO>()
.ge(CustomerFollowupDO::getCreateTime, from));
return String.format("GJ%d%06d", year, count);
}
@Override
public Long createFollowup(CustomerFollowupCreateReqVO createReqVO) {
String number = generateFollowupNumber();
createReqVO.setNumber(number);
// 插入
CustomerFollowupDO followup = CustomerFollowupConvert.INSTANCE.convert(createReqVO);
followupMapper.insert(followup);
// 返回
return followup.getId();
}
@Override
public void updateFollowup(CustomerFollowupUpdateReqVO updateReqVO) {
// 校验存在
Long id = updateReqVO.getId();
CustomerFollowupDO customerFollowupDO = followupMapper.selectById(id);
if (customerFollowupDO == null) {
throw exception(FOLLOWUP_NOT_EXISTS);
}
if (customerFollowupDO.getStatus().equals(CustomerFollowupStatusEnum.Commited.getValue())) {
throw exception(FOLLOWUP_ALREADY_SUBMITTED);
}
// 更新
CustomerFollowupDO updateObj = CustomerFollowupConvert.INSTANCE.convert(updateReqVO);
followupMapper.updateById(updateObj);
}
@Override
public void updateFollowupStatus(CustomerFollowupUpdateStatusReqVO updateStatusReqVO) {
Long id = updateStatusReqVO.getId();
CustomerFollowupDO customerFollowupDO = followupMapper.selectById(id);
if (customerFollowupDO == null) {
throw exception(FOLLOWUP_NOT_EXISTS);
}
customerFollowupDO.setStatus(updateStatusReqVO.getStatus());
followupMapper.updateById(customerFollowupDO);
}
@Override
public void deleteFollowup(Long id) {
// 校验存在
this.validateFollowupExists(id);
// 删除
followupMapper.deleteById(id);
}
private void validateFollowupExists(Long id) {
if (followupMapper.selectById(id) == null) {
throw exception(FOLLOWUP_NOT_EXISTS);
}
}
@Override
public CustomerFollowupDO getFollowup(Long id) {
return followupMapper.selectById(id);
}
@Override
public List<CustomerFollowupDO> getFollowupList(Collection<Long> ids) {
return followupMapper.selectBatchIds(ids);
}
@Override
public PageResult<CustomerFollowupDO> getFollowupPage(CustomerFollowupQueryVO query, PageVO page) {
page.setPage(query.getPageNo());
page.setRows(query.getPageSize());
IPage<CustomerDO> mpPage = MyBatisUtils.buildPage(page);
log.warn(I18nMessage.getLang().toString());
int start = (page.getPage() - 1) * page.getRows();
int size = page.getRows();
List<CustomerFollowupDO> list = followupMapper.selectPage1(start, size, query);
long total = followupMapper.selectCount1(query);
return new PageResult<>(list, total,
mpPage.getSize(), page.getPage(),
(total + mpPage.getSize() - 1) / mpPage.getSize());
}
@Override
public List<CustomerFollowupDO> getFollowupList(CustomerFollowupQueryVO query) {
return followupMapper.selectPage1(null, null, query);
}
}
package cn.iocoder.yudao.module.customer.vo.customerFollowup;
import cn.iocoder.yudao.framework.excel.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.convert.DictConvert;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import com.alibaba.excel.annotation.ExcelProperty;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 客户跟进 Response VO
* @author yanghao
*/
@Data
@ApiModel("管理后台 - 客户跟进 Response VO")
public class CustomerFollowupBackVO {
@ExcelProperty("主键")
@ApiModelProperty(value = "主键", required = true)
private Long id;
@ExcelProperty("编号")
@ApiModelProperty(value = "编号")
private String number;
@ExcelProperty("上一级跟进单号")
@ApiModelProperty(value = "上一级跟进单号")
private String parentNumber;
@ExcelProperty(value = "状态", converter = DictConvert.class)
@DictFormat("customer_followup_status")
@ApiModelProperty(value = "状态 字典customer_followup_status")
private Integer status;
@ApiModelProperty(value = "客户编号")
private Long customerId;
@ApiModelProperty(value = "报价单")
private Long offerId;
@ExcelProperty(value = "跟进类型", converter = DictConvert.class)
@DictFormat("customer_followup_type")
@ApiModelProperty(value = "跟进类型 字典customer_followup_type")
private Integer followType;
@ExcelProperty("跟进时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "跟进时间")
private Date followTime;
@ExcelProperty("联系人")
@ApiModelProperty(value = "联系人")
private String contactName;
@ExcelProperty(value = "跟进方式", converter = DictConvert.class)
@DictFormat("customer_followup_method")
@ApiModelProperty(value = "跟进类型 字典customer_followup_type")
private Integer followMethod;
@ExcelProperty("客户经理/跟进业务员id")
@ApiModelProperty(value = "客户经理/跟进业务员id")
private Long followUserId;
@ExcelProperty("目的")
@ApiModelProperty(value = "目的")
private String purpose;
@ExcelProperty(value = "跟进结果", converter = DictConvert.class)
@DictFormat("customer_followup_result_type")
@ApiModelProperty(value = "跟进结果 字典customer_followup_result_type")
private Integer resultType;
@ExcelProperty("客户反馈")
@ApiModelProperty(value = "客户反馈")
private String feedback;
@ExcelProperty("附件 多个以逗号分隔")
@ApiModelProperty(value = "附件 多个以逗号分隔")
private String attatchment;
@ExcelProperty("下次跟进时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "下次跟进时间")
private Date nextTime;
@ExcelProperty("下次跟进计划")
@ApiModelProperty(value = "下次跟进计划")
private String nextPlan;
@ExcelProperty("创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
@ExcelProperty("更新时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "更新时间")
private Date updateTime;
@ExcelProperty("客户编号")
@ApiModelProperty(value = "客户编号")
private String customerNumber;
@ExcelProperty("报价单")
@ApiModelProperty(value = "报价单编号")
private String offerNumber;
//creator_name
@ExcelProperty("创建人id")
@ApiModelProperty(value = "创建人名称")
private String creatorName;
// updater_name
@ExcelProperty("更新人id")
@ApiModelProperty(value = "更新人名称")
private String updaterName;
}
package cn.iocoder.yudao.module.customer.vo.customerFollowup;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 客户跟进 Base VO,提供给添加、修改、详细的子 VO 使用
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
*/
@Data
public class CustomerFollowupBaseVO {
@ApiModelProperty(value = "编号")
private String number;
@ApiModelProperty(value = "上一级跟进单号")
private String parentNumber;
@ApiModelProperty(value = "状态 字典customer_followup_status")
private Integer status;
@ApiModelProperty(value = "客户编号")
private Long customerId;
@ApiModelProperty(value = "报价单")
private Long offerId;
@ApiModelProperty(value = "跟进类型 字典customer_followup_type")
private Integer followType;
@ApiModelProperty(value = "跟进时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date followTime;
@ApiModelProperty(value = "联系人")
private String contactName;
@ApiModelProperty(value = "跟进方式 字典customer_followup_method")
private Integer followMethod;
@ApiModelProperty(value = "客户经理/跟进业务员id")
private Long followUserId;
@ApiModelProperty(value = "目的")
private String purpose;
@ApiModelProperty(value = "跟进结果 字典customer_followup_result_type")
private Integer resultType;
@ApiModelProperty(value = "客户反馈")
private String feedback;
@ApiModelProperty(value = "附件 多个以逗号分隔")
private String attatchment;
@ApiModelProperty(value = "下次跟进时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date nextTime;
@ApiModelProperty(value = "下次跟进计划")
private String nextPlan;
}
package cn.iocoder.yudao.module.customer.vo.customerFollowup;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel("管理后台 - 客户跟进创建 Request VO")
public class CustomerFollowupCreateReqVO extends CustomerFollowupBaseVO {
}
package cn.iocoder.yudao.module.customer.vo.customerFollowup;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 客户跟进 Response VO
* @author yanghao
*/
@Data
@ApiModel("管理后台 - 客户跟进 Response VO")
public class CustomerFollowupExcelVO {
@ExcelProperty("主键")
@ApiModelProperty(value = "主键", required = true)
private Long id;
@ExcelProperty("编号")
@ApiModelProperty(value = "编号")
private String number;
@ExcelProperty("上一级跟进单号")
@ApiModelProperty(value = "上一级跟进单号")
private String parentNumber;
@ExcelProperty("状态 字典customer_followup_status")
@ApiModelProperty(value = "状态 字典customer_followup_status")
private Integer status;
@ExcelProperty("客户编号")
@ApiModelProperty(value = "客户编号")
private Long customerId;
@ExcelProperty("报价单")
@ApiModelProperty(value = "报价单")
private Long offerId;
@ExcelProperty("跟进类型 字典customer_followup_type")
@ApiModelProperty(value = "跟进类型 字典customer_followup_type")
private Integer followType;
@ExcelProperty("跟进时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "跟进时间")
private Date followTime;
@ExcelProperty("联系人")
@ApiModelProperty(value = "联系人")
private String contactName;
@ExcelProperty("跟进方式 字典customer_followup_method")
@ApiModelProperty(value = "跟进方式 字典customer_followup_method")
private Integer followMethod;
@ExcelProperty("客户经理/跟进业务员id")
@ApiModelProperty(value = "客户经理/跟进业务员id")
private Long followUserId;
@ExcelProperty("目的")
@ApiModelProperty(value = "目的")
private String purpose;
@ExcelProperty("跟进结果 字典customer_followup_result_type")
@ApiModelProperty(value = "跟进结果 字典customer_followup_result_type")
private Integer resultType;
@ExcelProperty("客户反馈")
@ApiModelProperty(value = "客户反馈")
private String feedback;
@ExcelProperty("附件 多个以逗号分隔")
@ApiModelProperty(value = "附件 多个以逗号分隔")
private String attatchment;
@ExcelProperty("下次跟进时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "下次跟进时间")
private Date nextTime;
@ExcelProperty("下次跟进计划")
@ApiModelProperty(value = "下次跟进计划")
private String nextPlan;
@ExcelProperty("创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;
@ExcelProperty("更新时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "更新时间")
private Date updateTime;
@ApiModelProperty(value = "客户编号")
private String customerNumber;
@ApiModelProperty(value = "报价单编号")
private String offerNumber;
//creator_name
@ApiModelProperty(value = "创建人名称")
private String creatorName;
// updater_name
@ApiModelProperty(value = "更新人名称")
private String updaterName;
}
package cn.iocoder.yudao.module.customer.vo.customerFollowup;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Data
@ApiModel("管理后台 - 客户跟进查询 VO")
public class CustomerFollowupQueryVO extends PageParam {
@ApiModelProperty(value = "编号")
private String number;
@ApiModelProperty(value = "上一级跟进单号")
private String parentNumber;
@ApiModelProperty(value = "状态 字典customer_followup_status")
private Integer status;
@ApiModelProperty(value = "客户编号")
private Long customerId;
@ApiModelProperty(value = "客户编号")
private Long customerDetailId;
@ApiModelProperty(value = "报价单")
private Long offerId;
@ApiModelProperty(value = "跟进类型 字典customer_followup_type")
private Integer followType;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始跟进时间")
private Date beginFollowTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束跟进时间")
private Date endFollowTime;
@ApiModelProperty(value = "联系人")
private String contactName;
@ApiModelProperty(value = "跟进方式 字典customer_followup_method")
private Integer followMethod;
@ApiModelProperty(value = "客户经理/跟进业务员id")
private Long followUserId;
@ApiModelProperty(value = "目的")
private String purpose;
@ApiModelProperty(value = "跟进结果 字典customer_followup_result_type")
private Integer resultType;
@ApiModelProperty(value = "客户反馈")
private String feedback;
@ApiModelProperty(value = "附件 多个以逗号分隔")
private String attatchment;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始下次跟进时间")
private Date beginNextTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束下次跟进时间")
private Date endNextTime;
@ApiModelProperty(value = "下次跟进计划")
private String nextPlan;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "开始创建时间")
private Date beginCreateTime;
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ApiModelProperty(value = "结束创建时间")
private Date endCreateTime;
}
package cn.iocoder.yudao.module.customer.vo.customerFollowup;
import lombok.*;
import java.util.*;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
@ApiModel("管理后台 - 客户跟进更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CustomerFollowupUpdateReqVO extends CustomerFollowupBaseVO {
@ApiModelProperty(value = "主键", required = true)
@NotNull(message = "主键不能为空")
private Long id;
}
package cn.iocoder.yudao.module.customer.vo.customerFollowup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.constraints.NotNull;
@ApiModel("管理后台 - 客户跟进更新状态 Request VO")
@Data
@ToString(callSuper = true)
public class CustomerFollowupUpdateStatusReqVO {
@ApiModelProperty(value = "主键", required = true)
@NotNull(message = "主键不能为空")
private Long id;
@ApiModelProperty(value = "状态 字典customer_followup_status")
private Integer status;
}
<?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.customer.dal.mysql.customerFollowup.CustomerFollowupMapper">
<sql id="queryCondition">
<if test="query.number != null and query.number != '' ">
AND a.number LIKE concat('%', concat( #{query.number}, '%' ))
</if>
<if test="query.parentNumber != null and query.parentNumber != '' ">
AND a.parent_number LIKE concat('%', concat( #{query.parentNumber}, '%' ))
</if>
<if test="query.contactName != null and query.contactName != '' ">
AND a.contact_name LIKE concat('%', concat( #{query.contactName}, '%' ))
</if>
<if test="query.status != null">
AND a.status = #{query.status}
</if>
<if test="query.customerId != null">
AND a.customer_id = #{query.customerId}
</if>
<if test="query.offerId != null">
AND a.offer_id = #{query.offerId}
</if>
<if test="query.followType != null">
AND a.follow_type = #{query.followType}
</if>
<if test="query.followUserId != null">
AND a.follow_user_id = #{query.followUserId}
</if>
<if test="query.resultType != null">
AND a.result_type = #{query.resultType}
</if>
</sql>
<select id="selectPage1" resultType="cn.iocoder.yudao.module.customer.dal.dataobject.customerFollowup.CustomerFollowupDO">
select a.*, b.number as customer_number, c.number as offer_number,
d.nickname as creator_name, e.nickname as updater_name
from ecw_customer_followup a
left join ecw_customer b on a.customer_id = b.id
left join ecw_offer c on a.offer_id = c.offer_id
left join system_user d on a.creator = d.id
left join system_user e on a.updater = e.id
WHERE 1=1 AND a.deleted = 0
<include refid="queryCondition"/>
order by a.id desc
<if test="start != null and size != null">
limit #{start}, #{size}
</if>
</select>
<select id="selectCount1" resultType="java.lang.Long">
select count(1)
from ecw_customer_followup a
WHERE 1=1 AND a.deleted = 0
<include refid="queryCondition"/>
</select>
</mapper>
package cn.iocoder.yudao.module.customer.controller.admin.customerFollowup;
import cn.iocoder.yudao.framework.i18n.core.I18nMessage;
import cn.iocoder.yudao.framework.mybatis.core.vo.PageVO;
import cn.iocoder.yudao.module.customer.dto.CustomerExportReqDTO;
import cn.iocoder.yudao.module.system.api.file.FileMakeApi;
import cn.iocoder.yudao.module.system.api.file.dto.FileMakeReqDTO;
import cn.iocoder.yudao.module.system.enums.download.DownloadTypeEnum;
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.annotations.*;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
import cn.iocoder.yudao.module.customer.vo.customerFollowup.*;
import cn.iocoder.yudao.module.customer.dal.dataobject.customerFollowup.CustomerFollowupDO;
import cn.iocoder.yudao.module.customer.convert.customerFollowup.CustomerFollowupConvert;
import cn.iocoder.yudao.module.customer.service.customerFollowup.CustomerFollowupService;
@Validated
@RestController
@Api(tags = "管理后台 - 客户跟进-新")
@RequestMapping("/customer/followup")
public class CustomerFollowupController {
@Resource
private CustomerFollowupService followupService;
@Resource
private FileMakeApi fileMakeApi;
@PostMapping("/create")
@ApiOperation("创建客户跟进")
// @PreAuthorize("@ss.hasPermission('customer:followup:create')")
public CommonResult<Long> createFollowup(@Valid @RequestBody CustomerFollowupCreateReqVO createReqVO) {
return success(followupService.createFollowup(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新客户跟进")
// @PreAuthorize("@ss.hasPermission('customer:followup:update')")
public CommonResult<Boolean> updateFollowup(@Valid @RequestBody CustomerFollowupUpdateReqVO updateReqVO) {
followupService.updateFollowup(updateReqVO);
return success(true);
}
@PutMapping("/update-status")
@ApiOperation("更新客户跟进状态")
// @PreAuthorize("@ss.hasPermission('customer:followup:update')")
public CommonResult<Boolean> updateFollowupStatus(@Valid @RequestBody CustomerFollowupUpdateStatusReqVO updateStatusReqVO) {
followupService.updateFollowupStatus(updateStatusReqVO);
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除客户跟进")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
// @PreAuthorize("@ss.hasPermission('customer:followup:delete')")
public CommonResult<Boolean> deleteFollowup(@RequestParam("id") Long id) {
followupService.deleteFollowup(id);
return success(true);
}
@GetMapping("/get")
@ApiOperation("获得客户跟进")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
// @PreAuthorize("@ss.hasPermission('customer:followup:query')")
public CommonResult<CustomerFollowupBackVO> getFollowup(@RequestParam("id") Long id) {
CustomerFollowupDO followup = followupService.getFollowup(id);
return success(CustomerFollowupConvert.INSTANCE.convert(followup));
}
@GetMapping("/list")
@ApiOperation("获得客户跟进列表")
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
// @PreAuthorize("@ss.hasPermission('customer:followup:query')")
public CommonResult<List<CustomerFollowupBackVO>> getFollowupList(@RequestParam("ids") Collection<Long> ids) {
List<CustomerFollowupDO> list = followupService.getFollowupList(ids);
return success(CustomerFollowupConvert.INSTANCE.convertList(list));
}
@GetMapping("/page")
@ApiOperation("获得客户跟进分页")
// @PreAuthorize("@ss.hasPermission('customer:followup:query')")
public CommonResult<PageResult<CustomerFollowupBackVO>> getFollowupPage(@Valid CustomerFollowupQueryVO query, PageVO page) {
PageResult<CustomerFollowupDO> pageResult = followupService.getFollowupPage(query, page);
return success(CustomerFollowupConvert.INSTANCE.convertPage(pageResult));
}
@GetMapping("/export-excel")
@ApiOperation("导出客户跟进 Excel")
// @PreAuthorize("@ss.hasPermission('customer:followup:export')")
@OperateLog(type = EXPORT)
public CommonResult<Boolean> exportFollowupExcel(@Valid CustomerFollowupQueryVO query,
HttpServletResponse response) throws IOException {
sendFileMake(query, DownloadTypeEnum.CUSTOMER_FOLLOWUP_EXPORT, "跟进纪录导出Excel");
return success(true);
}
/**
* 支持多选
*
* @param query
* @param downloadTypeEnum
* @param fileName
*/
private void sendFileMake(CustomerFollowupQueryVO query, DownloadTypeEnum downloadTypeEnum, String fileName) {
FileMakeReqDTO reqDTO = new FileMakeReqDTO();
reqDTO.setType(downloadTypeEnum.getType());
reqDTO.setName(fileName);
reqDTO.setFileSuffix("xlsx");
reqDTO.setTemporaryFile(true);
reqDTO.setUserType(2);
reqDTO.setLang(I18nMessage.getLang());
reqDTO.setRequestParams(JSONObject.toJSONString(query));
fileMakeApi.sendFileMake(reqDTO);
}
}
package cn.iocoder.yudao.module.ecw.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 客户状态类型枚举
*/
@AllArgsConstructor
@Getter
public enum CustomerFollowupStatusEnum {
UnCommited(0, "未提交"),
Commited(1, "已提交"),
;
/**
* 类型
*/
private final Integer value;
/**
* 类型名
*/
private final String name;
public static String getNameByValue(Integer value) {
return Arrays.stream(CustomerFollowupStatusEnum.values()).filter(t -> t.getValue().equals(value)).map(CustomerFollowupStatusEnum::getName).findFirst().orElse("");
}
public static CustomerFollowupStatusEnum get(Integer value) {
return Arrays.stream(CustomerFollowupStatusEnum.values()).filter(t -> t.getValue().equals(value)).findFirst().orElse(null);
}
}
package cn.iocoder.yudao.module.sale.listener;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.apollo.core.event.export.CustomerFollowupExcelExportPushEvent;
import cn.iocoder.yudao.framework.excel.util.ExcelUtils;
import cn.iocoder.yudao.module.customer.convert.customerFollowup.CustomerFollowupConvert;
import cn.iocoder.yudao.module.customer.dal.dataobject.customerFollowup.CustomerFollowupDO;
import cn.iocoder.yudao.module.customer.service.customerFollowup.CustomerFollowupService;
import cn.iocoder.yudao.module.customer.vo.customerFollowup.CustomerFollowupBackVO;
import cn.iocoder.yudao.module.customer.vo.customerFollowup.CustomerFollowupQueryVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
import cn.iocoder.yudao.module.infra.service.file.FileService;
import cn.iocoder.yudao.module.system.framework.ue.UeProperties;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileInputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import static cn.iocoder.yudao.framework.excel.constant.ExportConstant.DATA_FORMAT;
/**
* 间接客户excel导出监听
*
* @author zhengYi
*/
@Component("CustomerFollowupExcelExportListener")
@AllArgsConstructor
@Slf4j
public class CustomerFollowupExcelExportListener {
private UeProperties ueProperties;
private FileService fileService;
private final CustomerFollowupService customerFollowupService;
/**
* 客户纪录导出监听
*
* @param event 编号记录
*/
@EventListener(CustomerFollowupExcelExportPushEvent.class)
public void customerIndirectExcelExportPushEvent(CustomerFollowupExcelExportPushEvent event) {
CustomerFollowupQueryVO exportReqVO = JSONObject.parseObject(event.getRequestParams(), CustomerFollowupQueryVO.class);
List<CustomerFollowupDO> list = customerFollowupService.getFollowupList(exportReqVO);
makeExcelUpload(event, list);
}
public void makeExcelUpload(CustomerFollowupExcelExportPushEvent event, List<CustomerFollowupDO> customerFollowupDOList) {
if (StringUtils.isNotBlank(event.getRequestParams())) {
try {
if(CollectionUtil.isEmpty(customerFollowupDOList)) return;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATA_FORMAT);
String nowTime = formatter.format(LocalDateTime.now());
String dir = ueProperties.getTempDir().concat("/customer/excel/");
String fileName = event.getUserId().toString().concat(StrUtil.DASHED).concat(event.getUserType().toString()).concat(StrUtil.DASHED).concat(nowTime).concat("followup.xlsx");
// 导出 Excel
List<CustomerFollowupBackVO> datas = CustomerFollowupConvert.INSTANCE.convertList(customerFollowupDOList);
String path = ExcelUtils.write(dir, fileName, "数据", CustomerFollowupBackVO.class, datas);
// 获取到临时文件
File file = new File(path);
// 创建FileInputStream对象
FileInputStream fileInputStream = new FileInputStream(file);
// 读取文件内容
byte[] fileBytes = new byte[(int) file.length()];
fileInputStream.read(fileBytes);
// 关闭文件流
fileInputStream.close();
// 将文件上传到资源服务器
FileDO fileDO = fileService.createFile(dir, fileName, fileBytes);
event.setPath(fileDO.getPath());
event.setFileName(fileDO.getPath());
event.setUrl(fileDO.getUrl());
event.setFileId(fileDO.getId());
} catch (Exception e) {
// TODO 测试阶段打印堆栈错误信息,便于分析原因
e.printStackTrace();
event.setResult(e.getMessage());
}
} else {
event.setResult("param fail");
}
}
}
......@@ -179,6 +179,14 @@ public enum DownloadTypeEnum implements IntArrayValuable {
*/
REWARD_REDEEM_RECORD(33),
/**
* 客户跟进导出
*/
CUSTOMER_FOLLOWUP_EXPORT(34),
// ....自己补充
;
......
......@@ -336,6 +336,10 @@ public class DownloadLogServiceImpl extends AbstractService<DownloadLogMapper, D
case CUSTOMER_INDIRECT_EXCEL_EXPORT:
customerIndirectExcelExportPushEvent(downloadLog);
break;
//客户跟进纪录导出
case CUSTOMER_FOLLOWUP_EXPORT:
customerFollowupExcelExportPushEvent(downloadLog);
break;
//部门客户列表导出
case CUSTOMER_DEPT_EXCEL_EXPORT:
customerDeptExcelExportPushEvent(downloadLog);
......@@ -593,6 +597,21 @@ public class DownloadLogServiceImpl extends AbstractService<DownloadLogMapper, D
}
private void customerFollowupExcelExportPushEvent(DownloadLogDO downloadLog) {
CustomerFollowupExcelExportPushEvent event = new CustomerFollowupExcelExportPushEvent();
event.setUserId(downloadLog.getUserId());
event.setUserType(downloadLog.getUserType());
event.setLang(downloadLog.getLang());
event.setRequestParams(downloadLog.getRequestParams());
applicationContext.publishEvent(event);
downloadLog.setFileName(event.getFileName());
downloadLog.setPath(event.getPath());
downloadLog.setDownloadUrl(event.getUrl());
downloadLog.setResult(event.getResult());
downloadLog.setFileId(event.getFileId());
}
private void customerDeptExcelExportPushEvent(DownloadLogDO downloadLog) {
CustomerDeptExcelExportPushEvent event = new CustomerDeptExcelExportPushEvent();
event.setUserId(downloadLog.getUserId());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment