mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-12-02 04:01:52 +08:00
CRM-客户: 完善客户导入
This commit is contained in:
parent
d8b2da8eed
commit
4605e93105
@ -26,8 +26,8 @@ public interface ErrorCodeConstants {
|
|||||||
|
|
||||||
// ========== 联系人管理 1-020-003-000 ==========
|
// ========== 联系人管理 1-020-003-000 ==========
|
||||||
ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在");
|
ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在");
|
||||||
ErrorCode CONTACT_BUSINESS_LINK_NOT_EXISTS = new ErrorCode( 1_020_003_001, "联系人商机关联不存在");
|
ErrorCode CONTACT_BUSINESS_LINK_NOT_EXISTS = new ErrorCode(1_020_003_001, "联系人商机关联不存在");
|
||||||
ErrorCode CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS = new ErrorCode( 1_020_003_002, "联系人已关联合同,不能删除");
|
ErrorCode CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS = new ErrorCode(1_020_003_002, "联系人已关联合同,不能删除");
|
||||||
|
|
||||||
// ========== 回款 1-020-004-000 ==========
|
// ========== 回款 1-020-004-000 ==========
|
||||||
ErrorCode RECEIVABLE_NOT_EXISTS = new ErrorCode(1_020_004_000, "回款不存在");
|
ErrorCode RECEIVABLE_NOT_EXISTS = new ErrorCode(1_020_004_000, "回款不存在");
|
||||||
@ -48,6 +48,9 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode CUSTOMER_LOCK_EXCEED_LIMIT = new ErrorCode(1_020_006_009, "锁定客户失败,超出锁定规则上限");
|
ErrorCode CUSTOMER_LOCK_EXCEED_LIMIT = new ErrorCode(1_020_006_009, "锁定客户失败,超出锁定规则上限");
|
||||||
ErrorCode CUSTOMER_OWNER_EXCEED_LIMIT = new ErrorCode(1_020_006_010, "操作失败,超出客户数拥有上限");
|
ErrorCode CUSTOMER_OWNER_EXCEED_LIMIT = new ErrorCode(1_020_006_010, "操作失败,超出客户数拥有上限");
|
||||||
ErrorCode CUSTOMER_DELETE_FAIL_HAVE_REFERENCE = new ErrorCode(1_020_006_011, "删除客户失败,有关联{}");
|
ErrorCode CUSTOMER_DELETE_FAIL_HAVE_REFERENCE = new ErrorCode(1_020_006_011, "删除客户失败,有关联{}");
|
||||||
|
ErrorCode CUSTOMER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_020_006_012, "导入客户数据不能为空!");
|
||||||
|
ErrorCode CUSTOMER_CREATE_NAME_NOT_NULL = new ErrorCode(1_020_006_013, "客户名称不能为空!");
|
||||||
|
ErrorCode CUSTOMER_NAME_EXISTS = new ErrorCode(1_020_006_014, "已存在名为【{}】的客户!");
|
||||||
|
|
||||||
// ========== 权限管理 1_020_007_000 ==========
|
// ========== 权限管理 1_020_007_000 ==========
|
||||||
ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在");
|
ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在");
|
||||||
|
@ -21,6 +21,7 @@ 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 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;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameters;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
@ -29,9 +30,11 @@ import org.mapstruct.ap.internal.util.Collections;
|
|||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -169,6 +172,36 @@ public class CrmCustomerController {
|
|||||||
BeanUtils.toBean(list, CrmCustomerRespVO.class));
|
BeanUtils.toBean(list, CrmCustomerRespVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-import-template")
|
||||||
|
@Operation(summary = "获得导入客户模板")
|
||||||
|
public void importTemplate(HttpServletResponse response) throws IOException {
|
||||||
|
// 手动创建导出 demo
|
||||||
|
List<CrmCustomerImportExcelVO> list = Arrays.asList(
|
||||||
|
CrmCustomerImportExcelVO.builder().name("芋道").industryId(1).level(1).source(1).mobile("15601691300").telephone("")
|
||||||
|
.website("https://doc.iocoder.cn/").qq("").wechat("").email("yunai@iocoder.cn").description("").remark("")
|
||||||
|
.areaId(null).detailAddress("").build(),
|
||||||
|
CrmCustomerImportExcelVO.builder().name("源码").industryId(1).level(1).source(1).mobile("15601691300").telephone("")
|
||||||
|
.website("https://doc.iocoder.cn/").qq("").wechat("").email("yunai@iocoder.cn").description("").remark("")
|
||||||
|
.areaId(null).detailAddress("").build()
|
||||||
|
);
|
||||||
|
// 输出
|
||||||
|
ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/import")
|
||||||
|
@Operation(summary = "导入客户")
|
||||||
|
@Parameters({
|
||||||
|
@Parameter(name = "file", description = "Excel 文件", required = true),
|
||||||
|
@Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true")
|
||||||
|
})
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:customer:import')")
|
||||||
|
public CommonResult<CrmCustomerImportRespVO> importExcel(@RequestParam("file") MultipartFile file,
|
||||||
|
@RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception {
|
||||||
|
List<CrmCustomerImportExcelVO> list = ExcelUtils.read(file, CrmCustomerImportExcelVO.class);
|
||||||
|
return success(customerService.importCustomerList(list, updateSupport));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@PutMapping("/transfer")
|
@PutMapping("/transfer")
|
||||||
@Operation(summary = "转移客户")
|
@Operation(summary = "转移客户")
|
||||||
@PreAuthorize("@ss.hasPermission('crm:customer:update')")
|
@PreAuthorize("@ss.hasPermission('crm:customer:update')")
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
package cn.iocoder.yudao.module.crm.controller.admin.customer.vo;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||||
|
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户 Excel 导入 VO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题
|
||||||
|
public class CrmCustomerImportExcelVO {
|
||||||
|
|
||||||
|
@ExcelProperty("客户名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "所属行业", converter = DictConvert.class)
|
||||||
|
@DictFormat(CRM_CUSTOMER_INDUSTRY)
|
||||||
|
private Integer industryId;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "客户等级", converter = DictConvert.class)
|
||||||
|
@DictFormat(CRM_CUSTOMER_LEVEL)
|
||||||
|
private Integer level;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "客户来源", converter = DictConvert.class)
|
||||||
|
@DictFormat(CRM_CUSTOMER_SOURCE)
|
||||||
|
private Integer source;
|
||||||
|
|
||||||
|
@ExcelProperty("手机")
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
@ExcelProperty("电话")
|
||||||
|
private String telephone;
|
||||||
|
|
||||||
|
@ExcelProperty("网址")
|
||||||
|
private String website;
|
||||||
|
|
||||||
|
@Size(max = 20, message = "QQ长度不能超过 20 个字符")
|
||||||
|
@ExcelProperty("QQ")
|
||||||
|
private String qq;
|
||||||
|
|
||||||
|
@Size(max = 255, message = "微信长度不能超过 255 个字符")
|
||||||
|
@ExcelProperty("微信")
|
||||||
|
private String wechat;
|
||||||
|
|
||||||
|
@Size(max = 255, message = "邮箱长度不能超过 255 个字符")
|
||||||
|
@ExcelProperty("邮箱")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Size(max = 4096, message = "客户描述长度不能超过 4096 个字符")
|
||||||
|
@ExcelProperty("客户描述")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@ExcelProperty("备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@ExcelProperty("地区编号")
|
||||||
|
private Integer areaId;
|
||||||
|
|
||||||
|
@ExcelProperty("详细地址")
|
||||||
|
private String detailAddress;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package cn.iocoder.yudao.module.crm.controller.admin.customer.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 客户导入 Response VO")
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class CrmCustomerImportRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "创建成功的客户名数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private List<String> createCustomerNames;
|
||||||
|
|
||||||
|
@Schema(description = "更新成功的客户名数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private List<String> updateCustomerNames;
|
||||||
|
|
||||||
|
@Schema(description = "导入失败的客户集合,key 为客户名,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private Map<String, String> failureCustomerNames;
|
||||||
|
|
||||||
|
}
|
@ -107,4 +107,8 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
|
|||||||
.gt(CrmCustomerDO::getOwnerUserId, 0));
|
.gt(CrmCustomerDO::getOwnerUserId, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default CrmCustomerDO selectByCustomerName(String name) {
|
||||||
|
return selectOne(CrmCustomerDO::getName, name);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.crm.service.customer;
|
package cn.iocoder.yudao.module.crm.service.customer;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerLockReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
||||||
import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO;
|
import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO;
|
||||||
import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
|
import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
|
||||||
@ -108,6 +105,15 @@ public interface CrmCustomerService {
|
|||||||
*/
|
*/
|
||||||
Long createCustomer(CrmCustomerCreateReqBO customerCreateReq, Long userId);
|
Long createCustomer(CrmCustomerCreateReqBO customerCreateReq, Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量导入客户
|
||||||
|
*
|
||||||
|
* @param importCustomers 导入客户列表
|
||||||
|
* @param isUpdateSupport 是否支持更新
|
||||||
|
* @return 导入结果
|
||||||
|
*/
|
||||||
|
CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, Boolean isUpdateSupport);
|
||||||
|
|
||||||
// ==================== 公海相关操作 ====================
|
// ==================== 公海相关操作 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,15 +3,14 @@ package cn.iocoder.yudao.module.crm.service.customer;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||||
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.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerLockReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert;
|
import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO;
|
||||||
@ -41,10 +40,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
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.filterList;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
|
||||||
@ -236,7 +232,50 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
return customer.getId();
|
return customer.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 公海相关操作 ====================
|
@Override
|
||||||
|
public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, Boolean isUpdateSupport) {
|
||||||
|
if (CollUtil.isEmpty(importCustomers)) {
|
||||||
|
throw exception(CUSTOMER_IMPORT_LIST_IS_EMPTY);
|
||||||
|
}
|
||||||
|
CrmCustomerImportRespVO respVO = CrmCustomerImportRespVO.builder().createCustomerNames(new ArrayList<>())
|
||||||
|
.updateCustomerNames(new ArrayList<>()).failureCustomerNames(new LinkedHashMap<>()).build();
|
||||||
|
importCustomers.forEach(importCustomer -> {
|
||||||
|
// 校验,判断是否有不符合的原因
|
||||||
|
try {
|
||||||
|
validateCustomerForCreate(importCustomer);
|
||||||
|
} catch (ServiceException ex) {
|
||||||
|
respVO.getFailureCustomerNames().put(importCustomer.getName(), ex.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 判断如果不存在,在进行插入
|
||||||
|
CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName());
|
||||||
|
if (existCustomer == null) {
|
||||||
|
customerMapper.insert(BeanUtils.toBean(importCustomer, CrmCustomerDO.class));
|
||||||
|
respVO.getCreateCustomerNames().add(importCustomer.getName());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 如果存在,判断是否允许更新
|
||||||
|
if (!isUpdateSupport) {
|
||||||
|
respVO.getFailureCustomerNames().put(importCustomer.getName(),
|
||||||
|
StrUtil.format(CUSTOMER_NAME_EXISTS.getMsg(), importCustomer.getName()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CrmCustomerDO updateCustomer = BeanUtils.toBean(importCustomer, CrmCustomerDO.class);
|
||||||
|
updateCustomer.setId(existCustomer.getId());
|
||||||
|
customerMapper.updateById(updateCustomer);
|
||||||
|
respVO.getUpdateCustomerNames().add(importCustomer.getName());
|
||||||
|
});
|
||||||
|
return respVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateCustomerForCreate(CrmCustomerImportExcelVO importCustomer) {
|
||||||
|
// 校验客户名称不能为空
|
||||||
|
if (StrUtil.isEmptyIfStr(importCustomer.getName())) {
|
||||||
|
throw exception(CUSTOMER_CREATE_NAME_NOT_NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 公海相关操作 ====================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
Loading…
Reference in New Issue
Block a user