diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/performance/CrmPerformanceConfigController.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/performance/CrmPerformanceConfigController.java new file mode 100644 index 0000000..aba14a7 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/performance/CrmPerformanceConfigController.java @@ -0,0 +1,149 @@ +package cn.iocoder.yudao.module.crm.controller.admin.performance; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.performance.vo.config.CrmPerformanceConfigPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.performance.vo.config.CrmPerformanceConfigRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.performance.vo.config.CrmPerformanceConfigSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.performance.CrmPerformanceConfigDO; +import cn.iocoder.yudao.module.crm.enums.performance.CrmPerformanceConfigObjectTypeEnum; +import cn.iocoder.yudao.module.crm.service.performance.CrmPerformanceConfigService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + +@Tag(name = "管理后台 - CRM 业绩目标设置") +@RestController +@RequestMapping("/crm/performance-config") +@Validated +public class CrmPerformanceConfigController { + + @Resource + private CrmPerformanceConfigService performanceConfigService; + + @Resource + private DeptApi deptApi; + @Resource + private AdminUserApi adminUserApi; + + @PostMapping("/create") + @Operation(summary = "创建业绩目标") + @PreAuthorize("@ss.hasPermission('crm:performance-config:create')") + public CommonResult createPerformanceConfig(@Valid @RequestBody CrmPerformanceConfigSaveReqVO createReqVO) { + return success(performanceConfigService.createPerformanceConfig(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新业绩目标") + @PreAuthorize("@ss.hasPermission('crm:performance-config:update')") + public CommonResult updatePerformanceConfig(@Valid @RequestBody CrmPerformanceConfigSaveReqVO updateReqVO) { + performanceConfigService.updatePerformanceConfig(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除业绩目标") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('crm:performance-config:delete')") + public CommonResult deletePerformanceConfig(@RequestParam("id") Long id) { + performanceConfigService.deletePerformanceConfig(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得业绩目标") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('crm:performance-config:query')") + public CommonResult getPerformanceConfig(@RequestParam("id") Long id) { + // 1. 获取业绩目标 + CrmPerformanceConfigDO performanceConfig = performanceConfigService.getPerformanceConfig(id); + // 2. 拼接数据 + return success(buildPerformanceConfigDetail(performanceConfig)); + } + + private CrmPerformanceConfigRespVO buildPerformanceConfigDetail(CrmPerformanceConfigDO performanceConfig) { + if (performanceConfig == null) { + return null; + } + // 1. 转换成 VO + CrmPerformanceConfigRespVO respVO = BeanUtils.toBean(performanceConfig, CrmPerformanceConfigRespVO.class); + // 2. 拼接目标对象名称 + return buildPerformanceConfigObjectName(respVO); + } + + @GetMapping("/page") + @Operation(summary = "获得业绩目标分页") + @PreAuthorize("@ss.hasPermission('crm:performance-config:query')") + public CommonResult> getPerformanceConfigPage(@Valid CrmPerformanceConfigPageReqVO pageReqVO) { + // 1. 查询业绩目标分页 + PageResult pageResult = performanceConfigService.getPerformanceConfigPage(pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty(pageResult.getTotal())); + } + // 2. 拼接数据 + return success(BeanUtils.toBean(pageResult, CrmPerformanceConfigRespVO.class) + .setList(buildPerformanceConfigDetailList(pageResult.getList()))); + } + + private List buildPerformanceConfigDetailList(List list) { + if (CollUtil.isEmpty(list)) { + return emptyList(); + } + // 1. 转换成 VO + List voList = BeanUtils.toBean(list, CrmPerformanceConfigRespVO.class); + // 2. 拼接目标对象名称 + return buildPerformanceConfigObjectNameList(voList); + } + + // ========== VO 拼装 ========== + + private CrmPerformanceConfigRespVO buildPerformanceConfigObjectName(CrmPerformanceConfigRespVO config) { + if (config == null) { + return null; + } + return buildPerformanceConfigObjectNameList(singletonList(config)).get(0); + } + + private List buildPerformanceConfigObjectNameList(List list) { + if (CollUtil.isEmpty(list)) { + return emptyList(); + } + // 1.1 获取部门列表 + Map deptMap = deptApi.getDeptMap(convertSet(list, CrmPerformanceConfigRespVO::getObjectId, + item -> Objects.equals(item.getObjectType(), CrmPerformanceConfigObjectTypeEnum.DEPT.getObjectType()))); + // 1.2 获取员工列表 + Map userMap = adminUserApi.getUserMap(convertSet(list, CrmPerformanceConfigRespVO::getObjectId, + item -> Objects.equals(item.getObjectType(), CrmPerformanceConfigObjectTypeEnum.USER.getObjectType()))); + // 2. 设置目标对象名称 + list.forEach(item -> { + if (Objects.equals(item.getObjectType(), CrmPerformanceConfigObjectTypeEnum.DEPT.getObjectType())) { + findAndThen(deptMap, item.getObjectId(), dept -> item.setObjectName(dept.getName())); + } else if (Objects.equals(item.getObjectType(), CrmPerformanceConfigObjectTypeEnum.USER.getObjectType())) { + findAndThen(userMap, item.getObjectId(), user -> item.setObjectName(user.getNickname())); + } + }); + return list; + } + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/performance/vo/config/CrmPerformanceConfigPageReqVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/performance/vo/config/CrmPerformanceConfigPageReqVO.java new file mode 100644 index 0000000..49f9ea5 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/performance/vo/config/CrmPerformanceConfigPageReqVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.crm.controller.admin.performance.vo.config; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.performance.CrmPerformanceConfigBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.performance.CrmPerformanceConfigObjectTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - CRM 业绩目标设置分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CrmPerformanceConfigPageReqVO extends PageParam { + + @Schema(description = "目标对象编号", example = "1") + private Long objectId; + + @Schema(description = "目标对象类型", example = "2") + @InEnum(value = CrmPerformanceConfigObjectTypeEnum.class, message = "目标对象类型,必须是 {value}") + private Integer objectType; + + @Schema(description = "年份", example = "2026") + private Integer year; + + @Schema(description = "目标类型", example = "5") + @InEnum(value = CrmPerformanceConfigBizTypeEnum.class, message = "目标类型,必须是 {value}") + private Integer bizType; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/performance/vo/config/CrmPerformanceConfigRespVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/performance/vo/config/CrmPerformanceConfigRespVO.java new file mode 100644 index 0000000..9007ea5 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/performance/vo/config/CrmPerformanceConfigRespVO.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.crm.controller.admin.performance.vo.config; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - CRM 业绩目标设置 Response VO") +@Data +public class CrmPerformanceConfigRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "目标对象编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long objectId; + + @Schema(description = "目标对象名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "销售部") + private String objectName; + + @Schema(description = "目标对象类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer objectType; + + @Schema(description = "年份", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026") + private Integer year; + + @Schema(description = "一月目标金额", requiredMode = Schema.RequiredMode.REQUIRED) + private BigDecimal januaryTargetPrice; + + @Schema(description = "二月目标金额", requiredMode = Schema.RequiredMode.REQUIRED) + private BigDecimal februaryTargetPrice; + + @Schema(description = "三月目标金额", requiredMode = Schema.RequiredMode.REQUIRED) + private BigDecimal marchTargetPrice; + + @Schema(description = "四月目标金额", requiredMode = Schema.RequiredMode.REQUIRED) + private BigDecimal aprilTargetPrice; + + @Schema(description = "五月目标金额", requiredMode = Schema.RequiredMode.REQUIRED) + private BigDecimal mayTargetPrice; + + @Schema(description = "六月目标金额", requiredMode = Schema.RequiredMode.REQUIRED) + private BigDecimal juneTargetPrice; + + @Schema(description = "七月目标金额", requiredMode = Schema.RequiredMode.REQUIRED) + private BigDecimal julyTargetPrice; + + @Schema(description = "八月目标金额", requiredMode = Schema.RequiredMode.REQUIRED) + private BigDecimal augustTargetPrice; + + @Schema(description = "九月目标金额", requiredMode = Schema.RequiredMode.REQUIRED) + private BigDecimal septemberTargetPrice; + + @Schema(description = "十月目标金额", requiredMode = Schema.RequiredMode.REQUIRED) + private BigDecimal octoberTargetPrice; + + @Schema(description = "十一月目标金额", requiredMode = Schema.RequiredMode.REQUIRED) + private BigDecimal novemberTargetPrice; + + @Schema(description = "十二月目标金额", requiredMode = Schema.RequiredMode.REQUIRED) + private BigDecimal decemberTargetPrice; + + @Schema(description = "目标类型", + requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + private Integer bizType; + + @Schema(description = "年度目标金额", requiredMode = Schema.RequiredMode.REQUIRED) + private BigDecimal yearTargetPrice; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/performance/vo/config/CrmPerformanceConfigSaveReqVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/performance/vo/config/CrmPerformanceConfigSaveReqVO.java new file mode 100644 index 0000000..06e5081 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/performance/vo/config/CrmPerformanceConfigSaveReqVO.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.crm.controller.admin.performance.vo.config; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.performance.CrmPerformanceConfigBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.performance.CrmPerformanceConfigObjectTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - CRM 业绩目标设置新增/修改 Request VO") +@Data +public class CrmPerformanceConfigSaveReqVO { + + @Schema(description = "编号", example = "1") + private Long id; + + @Schema(description = "目标对象编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "目标对象编号不能为空") + private Long objectId; + + @Schema(description = "目标对象类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "目标对象类型不能为空") + @InEnum(value = CrmPerformanceConfigObjectTypeEnum.class, message = "目标对象类型,必须是 {value}") + private Integer objectType; + + @Schema(description = "年份", requiredMode = Schema.RequiredMode.REQUIRED, example = "2026") + @NotNull(message = "年份不能为空") + private Integer year; + + @Schema(description = "一月目标金额") + private BigDecimal januaryTargetPrice; + + @Schema(description = "二月目标金额") + private BigDecimal februaryTargetPrice; + + @Schema(description = "三月目标金额") + private BigDecimal marchTargetPrice; + + @Schema(description = "四月目标金额") + private BigDecimal aprilTargetPrice; + + @Schema(description = "五月目标金额") + private BigDecimal mayTargetPrice; + + @Schema(description = "六月目标金额") + private BigDecimal juneTargetPrice; + + @Schema(description = "七月目标金额") + private BigDecimal julyTargetPrice; + + @Schema(description = "八月目标金额") + private BigDecimal augustTargetPrice; + + @Schema(description = "九月目标金额") + private BigDecimal septemberTargetPrice; + + @Schema(description = "十月目标金额") + private BigDecimal octoberTargetPrice; + + @Schema(description = "十一月目标金额") + private BigDecimal novemberTargetPrice; + + @Schema(description = "十二月目标金额") + private BigDecimal decemberTargetPrice; + + @Schema(description = "目标类型", + requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "目标类型不能为空") + @InEnum(value = CrmPerformanceConfigBizTypeEnum.class, message = "目标类型,必须是 {value}") + private Integer bizType; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsFunnelController.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsFunnelController.java index 85e0c3d..ac9da2b 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsFunnelController.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsFunnelController.java @@ -45,6 +45,13 @@ public class CrmStatisticsFunnelController { return success(funnelService.getBusinessSummaryByEndStatus(reqVO)); } + @GetMapping("/get-business-summary-by-status") + @Operation(summary = "获取商机阶段统计", description = "用于【销售漏斗】页面的【销售漏斗分析】") + @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')") + public CommonResult> getBusinessSummaryByStatus(@Valid CrmStatisticsFunnelReqVO reqVO) { + return success(funnelService.getBusinessSummaryByStatus(reqVO)); + } + @GetMapping("/get-business-summary-by-date") @Operation(summary = "获取新增商机分析(按日期)", description = "用于【销售漏斗】页面") @PreAuthorize("@ss.hasPermission('crm:statistics-funnel:query')") diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceController.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceController.java index 185b428..554467f 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceController.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceController.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.crm.controller.admin.statistics; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceReqVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceSummaryRespVO; import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsPerformanceService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -49,4 +50,11 @@ public class CrmStatisticsPerformanceController { return success(performanceService.getReceivablePricePerformance(performanceReqVO)); } + @GetMapping("/get-contract-summary") + @Operation(summary = "合同汇总表") + @PreAuthorize("@ss.hasPermission('crm:statistics-performance:query')") + public CommonResult> getContractSummary(@Valid CrmStatisticsPerformanceReqVO performanceReqVO) { + return success(performanceService.getContractSummary(performanceReqVO)); + } + } diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceTargetController.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceTargetController.java new file mode 100644 index 0000000..47a6375 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsPerformanceTargetController.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceTargetReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceTargetRespVO; +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsPerformanceTargetService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - CRM 业绩目标统计") +@RestController +@RequestMapping("/crm/statistics-performance-target") +@Validated +public class CrmStatisticsPerformanceTargetController { + + @Resource + private CrmStatisticsPerformanceTargetService performanceTargetService; + + @GetMapping("/get-performance-target-summary") + @Operation(summary = "获取业绩目标完成情况") + @PreAuthorize("@ss.hasPermission('crm:statistics-performance-target:query')") + public CommonResult> getPerformanceTargetSummary(@Valid CrmStatisticsPerformanceTargetReqVO reqVO) { + return success(performanceTargetService.getPerformanceTargetSummary(reqVO)); + } + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsProductController.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsProductController.java new file mode 100644 index 0000000..18ec853 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/CrmStatisticsProductController.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product.CrmStatisticsProductCategoryRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product.CrmStatisticsProductReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product.CrmStatisticsProductSalesRespVO; +import cn.iocoder.yudao.module.crm.service.statistics.CrmStatisticsProductService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - CRM 产品统计") +@RestController +@RequestMapping("/crm/statistics-product") +@Validated +public class CrmStatisticsProductController { + + @Resource + private CrmStatisticsProductService productService; + + @GetMapping("/get-product-sales-list") + @Operation(summary = "获取产品销售情况统计") + @PreAuthorize("@ss.hasPermission('crm:statistics-product:query')") + public CommonResult> getProductSalesList(@Valid CrmStatisticsProductReqVO reqVO) { + return success(productService.getProductSalesList(reqVO)); + } + + @GetMapping("/get-product-category-summary") + @Operation(summary = "获取产品分类销售分析") + @PreAuthorize("@ss.hasPermission('crm:statistics-product:query')") + public CommonResult> getProductCategorySummary(@Valid CrmStatisticsProductReqVO reqVO) { + return success(productService.getProductCategorySummary(reqVO)); + } + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessSummaryByStatusRespVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessSummaryByStatusRespVO.java new file mode 100644 index 0000000..92513ab --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsBusinessSummaryByStatusRespVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - CRM 商机阶段统计 Response VO") +@NoArgsConstructor +@AllArgsConstructor +@Data +public class CrmStatisticsBusinessSummaryByStatusRespVO { + + @Schema(description = "商机阶段编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long statusId; + + @Schema(description = "商机阶段名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "初步接洽") + private String statusName; + + @Schema(description = "赢单率,百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "50") + private Integer statusPercent; + + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer sort; + + @Schema(description = "商机数", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long businessCount; + + @Schema(description = "商机总金额,单位:元", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private BigDecimal totalPrice; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsFunnelReqVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsFunnelReqVO.java index dac3406..82c7f2f 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsFunnelReqVO.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/funnel/CrmStatisticsFunnelReqVO.java @@ -28,6 +28,9 @@ public class CrmStatisticsFunnelReqVO extends PageParam { @Schema(description = "负责人用户 id", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1") private Long userId; + @Schema(description = "商机状态组编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1") + private Long statusTypeId; + /** * userIds 目前不用前端传递,目前是方便后端通过 deptId 读取编号后,设置回来 * 后续,可能会支持选择部分用户进行查询 diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceSummaryRespVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceSummaryRespVO.java new file mode 100644 index 0000000..ef9e486 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceSummaryRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - CRM 员工业绩合同汇总 Response VO") +@Data +public class CrmStatisticsPerformanceSummaryRespVO { + + @Schema(description = "时间轴", requiredMode = Schema.RequiredMode.REQUIRED, example = "202401") + private String time; + + @Schema(description = "合同数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Integer contractCount; + + @Schema(description = "合同金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000.00") + private BigDecimal contractPrice; + + @Schema(description = "回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "8000.00") + private BigDecimal receivablePrice; + + @Schema(description = "未回款金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000.00") + private BigDecimal unreceivedPrice; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceTargetActualRespVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceTargetActualRespVO.java new file mode 100644 index 0000000..1747008 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceTargetActualRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - CRM 业绩目标完成实际值 Response VO") +@Data +@Accessors(chain = true) +public class CrmStatisticsPerformanceTargetActualRespVO { + + @Schema(description = "月份", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer month; + + @Schema(description = "完成金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "8000.00") + private BigDecimal currentPrice; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceTargetReqVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceTargetReqVO.java new file mode 100644 index 0000000..dc7b650 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceTargetReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.performance.CrmPerformanceConfigBizTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - CRM 业绩目标完成情况 Request VO") +@Data +public class CrmStatisticsPerformanceTargetReqVO { + + @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "部门 id 不能为空") + private Long deptId; + + @Schema(description = "负责人用户 id", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1") + private Long userId; + + @Schema(description = "负责人用户 id 集合", hidden = true, example = "2") + private List userIds; + + @Schema(description = "年份", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024") + @NotNull(message = "年份不能为空") + private Integer year; + + @Schema(description = "目标类型", + requiredMode = Schema.RequiredMode.REQUIRED, example = "5") + @NotNull(message = "目标类型不能为空") + @InEnum(value = CrmPerformanceConfigBizTypeEnum.class, message = "目标类型,必须是 {value}") + private Integer bizType; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceTargetRespVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceTargetRespVO.java new file mode 100644 index 0000000..85b5ece --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/performance/CrmStatisticsPerformanceTargetRespVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - CRM 业绩目标完成情况 Response VO") +@Data +@Accessors(chain = true) +public class CrmStatisticsPerformanceTargetRespVO { + + @Schema(description = "月份", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer month; + + @Schema(description = "目标金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "10000.00") + private BigDecimal targetPrice; + + @Schema(description = "完成金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "8000.00") + private BigDecimal currentPrice; + + @Schema(description = "完成率", requiredMode = Schema.RequiredMode.REQUIRED, example = "80.00") + private BigDecimal completionRate; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/product/CrmStatisticsProductCategoryRespVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/product/CrmStatisticsProductCategoryRespVO.java new file mode 100644 index 0000000..bcccf95 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/product/CrmStatisticsProductCategoryRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - CRM 产品分类销售分析 Response VO") +@Data +public class CrmStatisticsProductCategoryRespVO { + + @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Long categoryId; + + @Schema(description = "产品分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "软件") + private String categoryName; + + @Schema(description = "合同数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "3") + private Integer contractCount; + + @Schema(description = "销售数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private BigDecimal productCount; + + @Schema(description = "销售金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "20000.00") + private BigDecimal productTotalPrice; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/product/CrmStatisticsProductReqVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/product/CrmStatisticsProductReqVO.java new file mode 100644 index 0000000..dbf7465 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/product/CrmStatisticsProductReqVO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - CRM 产品分析 Request VO") +@Data +public class CrmStatisticsProductReqVO { + + @Schema(description = "部门 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "部门 id 不能为空") + private Long deptId; + + @Schema(description = "负责人用户 id", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1") + private Long userId; + + @Schema(description = "负责人用户 id 集合", hidden = true, example = "2") + private List userIds; + + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @NotEmpty(message = "请选择时间范围") + @Size(min = 2, max = 2, message = "请选择时间范围") + private LocalDateTime[] times; + + @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "10") + private Long categoryId; + + @Schema(description = "产品分类编号集合", hidden = true, example = "10") + private List categoryIds; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "20") + private Long productId; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/product/CrmStatisticsProductSalesRespVO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/product/CrmStatisticsProductSalesRespVO.java new file mode 100644 index 0000000..c4fdfe9 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/statistics/vo/product/CrmStatisticsProductSalesRespVO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - CRM 产品销售情况 Response VO") +@Data +public class CrmStatisticsProductSalesRespVO { + + @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + private Long categoryId; + + @Schema(description = "产品分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "软件") + private String categoryName; + + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + private Long productId; + + @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CRM 专业版") + private String productName; + + @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30") + private Long contractId; + + @Schema(description = "合同编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "HT20240101001") + private String contractNo; + + @Schema(description = "合同名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "CRM 采购合同") + private String contractName; + + @Schema(description = "负责人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long ownerUserId; + + @Schema(description = "负责人姓名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿") + private String ownerUserName; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "40") + private Long customerId; + + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试客户") + private String customerName; + + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") + private BigDecimal productPrice; + + @Schema(description = "销售数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private BigDecimal productCount; + + @Schema(description = "销售金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "200.00") + private BigDecimal productTotalPrice; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/performance/CrmPerformanceConfigDO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/performance/CrmPerformanceConfigDO.java new file mode 100644 index 0000000..265f622 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/performance/CrmPerformanceConfigDO.java @@ -0,0 +1,107 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.performance; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.enums.performance.CrmPerformanceConfigBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.performance.CrmPerformanceConfigObjectTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * CRM 业绩目标 DO + * + * @author 芋道源码 + */ +@TableName("crm_performance_config") +@KeySequence("crm_performance_config_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmPerformanceConfigDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 目标类型 + * + * 枚举 {@link CrmPerformanceConfigBizTypeEnum} + */ + private Integer bizType; + /** + * 目标对象编号 + */ + private Long objectId; + /** + * 目标对象类型 + * + * 枚举 {@link CrmPerformanceConfigObjectTypeEnum} + */ + private Integer objectType; + + /** + * 年份 + */ + private Integer year; + /** + * 年度目标金额 + */ + private BigDecimal yearTargetPrice; + /** + * 一月目标金额 + */ + private BigDecimal januaryTargetPrice; + /** + * 二月目标金额 + */ + private BigDecimal februaryTargetPrice; + /** + * 三月目标金额 + */ + private BigDecimal marchTargetPrice; + /** + * 四月目标金额 + */ + private BigDecimal aprilTargetPrice; + /** + * 五月目标金额 + */ + private BigDecimal mayTargetPrice; + /** + * 六月目标金额 + */ + private BigDecimal juneTargetPrice; + /** + * 七月目标金额 + */ + private BigDecimal julyTargetPrice; + /** + * 八月目标金额 + */ + private BigDecimal augustTargetPrice; + /** + * 九月目标金额 + */ + private BigDecimal septemberTargetPrice; + /** + * 十月目标金额 + */ + private BigDecimal octoberTargetPrice; + /** + * 十一月目标金额 + */ + private BigDecimal novemberTargetPrice; + /** + * 十二月目标金额 + */ + private BigDecimal decemberTargetPrice; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/permission/CrmOwnerRecordDO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/permission/CrmOwnerRecordDO.java new file mode 100644 index 0000000..4961e91 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/permission/CrmOwnerRecordDO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.crm.dal.dataobject.permission; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * CRM 负责人变更记录 DO + * + * @author 芋道源码 + */ +@TableName("crm_owner_record") +@KeySequence("crm_owner_record_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CrmOwnerRecordDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * CRM 业务类型 + * + * 枚举 {@link CrmBizTypeEnum} + */ + private Integer bizType; + /** + * CRM 业务编号 + */ + private Long bizId; + /** + * 变更前负责人 + */ + private Long preOwnerUserId; + /** + * 变更后负责人 + */ + private Long postOwnerUserId; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java index cc6d598..8d73026 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java @@ -72,6 +72,7 @@ public interface CrmBusinessMapper extends BaseMapperX { default PageResult selectPage(CrmStatisticsFunnelReqVO pageVO) { return selectPage(pageVO, new LambdaQueryWrapperX() .in(CrmBusinessDO::getOwnerUserId, pageVO.getUserIds()) + .eqIfPresent(CrmBusinessDO::getStatusTypeId, pageVO.getStatusTypeId()) .betweenIfPresent(CrmBusinessDO::getCreateTime, pageVO.getTimes())); } diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/performance/CrmPerformanceConfigMapper.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/performance/CrmPerformanceConfigMapper.java new file mode 100644 index 0000000..b9332a3 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/performance/CrmPerformanceConfigMapper.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.performance; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.crm.controller.admin.performance.vo.config.CrmPerformanceConfigPageReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.performance.CrmPerformanceConfigDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * CRM 业绩目标配置 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface CrmPerformanceConfigMapper extends BaseMapperX { + + default PageResult selectPage(CrmPerformanceConfigPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(CrmPerformanceConfigDO::getObjectId, reqVO.getObjectId()) + .eqIfPresent(CrmPerformanceConfigDO::getObjectType, reqVO.getObjectType()) + .eqIfPresent(CrmPerformanceConfigDO::getYear, reqVO.getYear()) + .eqIfPresent(CrmPerformanceConfigDO::getBizType, reqVO.getBizType()) + .orderByDesc(CrmPerformanceConfigDO::getYear) + .orderByAsc(CrmPerformanceConfigDO::getObjectType) + .orderByAsc(CrmPerformanceConfigDO::getObjectId) + .orderByAsc(CrmPerformanceConfigDO::getBizType)); + } + + default CrmPerformanceConfigDO selectByObjectIdAndObjectTypeAndYearAndBizType(Long objectId, Integer objectType, + Integer year, Integer bizType) { + return selectOne(new LambdaQueryWrapperX() + .eq(CrmPerformanceConfigDO::getObjectId, objectId) + .eq(CrmPerformanceConfigDO::getObjectType, objectType) + .eq(CrmPerformanceConfigDO::getYear, year) + .eq(CrmPerformanceConfigDO::getBizType, bizType)); + } + + default List selectListByObjectIdsAndObjectTypeAndYearAndBizType(Collection objectIds, + Integer objectType, + Integer year, + Integer bizType) { + return selectList(new LambdaQueryWrapperX() + .in(CrmPerformanceConfigDO::getObjectId, objectIds) + .eq(CrmPerformanceConfigDO::getObjectType, objectType) + .eq(CrmPerformanceConfigDO::getYear, year) + .eq(CrmPerformanceConfigDO::getBizType, bizType)); + } + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmOwnerRecordMapper.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmOwnerRecordMapper.java new file mode 100644 index 0000000..542f396 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/permission/CrmOwnerRecordMapper.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.permission; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsPoolSummaryByDateRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsPoolSummaryByUserRespVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmOwnerRecordDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * CRM 负责人变更记录 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface CrmOwnerRecordMapper extends BaseMapperX { + + /** + * 进入公海客户数(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectPoolCustomerPutCountByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 公海领取客户数(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectPoolCustomerTakeCountByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 进入公海客户数(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectPoolCustomerPutCountByUser(CrmStatisticsCustomerReqVO reqVO); + + /** + * 公海领取客户数(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List selectPoolCustomerTakeCountByUser(CrmStatisticsCustomerReqVO reqVO); + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java index 171d432..002f90c 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsCustomerMapper.java @@ -1,16 +1,10 @@ package cn.iocoder.yudao.module.crm.dal.mysql.statistics; -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.hutool.core.util.RandomUtil; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; import org.apache.ibatis.annotations.Mapper; -import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.List; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; - /** * CRM 客户分析 Mapper * @@ -118,65 +112,6 @@ public interface CrmStatisticsCustomerMapper { /** - * 进入公海客户数(按日期) - * - * @param reqVO 请求参数 - * @return 统计数据 - */ - // TODO: @芋艿 模拟数据, 需要增加 crm_owner_record 表 - default List selectPoolCustomerPutCountByDate(CrmStatisticsCustomerReqVO reqVO) { - LocalDateTime currrentDate = LocalDateTimeUtil.beginOfDay(reqVO.getTimes()[0]); - LocalDateTime endDate = LocalDateTimeUtil.endOfDay(reqVO.getTimes()[1]); - List voList = new ArrayList<>(); - while (currrentDate.isBefore(endDate)) { - voList.add(new CrmStatisticsPoolSummaryByDateRespVO() - .setTime(LocalDateTimeUtil.format(currrentDate, "yyyy-MM-dd")) - .setCustomerPutCount(RandomUtil.randomInt(0, 10)) - .setCustomerTakeCount(RandomUtil.randomInt(0, 10))); - currrentDate = currrentDate.plusDays(1); - } - - return voList; - } - - /** - * 公海领取客户数(按日期) - * - * @param reqVO 请求参数 - * @return 统计数据 - */ - // TODO: @芋艿 模拟数据, 需要增加 crm_owner_record 表 - default List selectPoolCustomerTakeCountByDate(CrmStatisticsCustomerReqVO reqVO) { - return selectPoolCustomerPutCountByDate(reqVO); - } - - /** - * 进入公海客户数(按用户) - * - * @param reqVO 请求参数 - * @return 统计数据 - */ - // TODO: @芋艿 模拟数据, 需要增加 crm_owner_record 表 - default List selectPoolCustomerPutCountByUser(CrmStatisticsCustomerReqVO reqVO) { - return convertList(reqVO.getUserIds(), userId -> - (CrmStatisticsPoolSummaryByUserRespVO) new CrmStatisticsPoolSummaryByUserRespVO() - .setCustomerPutCount(RandomUtil.randomInt(0, 10)) - .setCustomerTakeCount(RandomUtil.randomInt(0, 10)) - .setOwnerUserId(userId)); - } - - /** - * 公海领取客户数(按用户) - * - * @param reqVO 请求参数 - * @return 统计数据 - */ - // TODO: @芋艿 模拟数据, 需要增加 crm_owner_record 表 - default List selectPoolCustomerTakeCountByUser(CrmStatisticsCustomerReqVO reqVO) { - return selectPoolCustomerPutCountByUser(reqVO); - } - - /** * 客户成交周期(按日期) * * @param reqVO 请求参数 diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsFunnelMapper.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsFunnelMapper.java index d69fa62..5745858 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsFunnelMapper.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsFunnelMapper.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.crm.dal.mysql.statistics; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessInversionRateSummaryByDateRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByDateRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByEndStatusRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsBusinessSummaryByStatusRespVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.funnel.CrmStatisticsFunnelReqVO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -23,6 +24,8 @@ public interface CrmStatisticsFunnelMapper { List selectBusinessSummaryListGroupByEndStatus(CrmStatisticsFunnelReqVO reqVO); + List selectBusinessSummaryListGroupByStatus(CrmStatisticsFunnelReqVO reqVO); + List selectBusinessSummaryGroupByDate(CrmStatisticsFunnelReqVO reqVO); List selectBusinessInversionRateSummaryByDate(CrmStatisticsFunnelReqVO reqVO); diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceMapper.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceMapper.java index 6467a09..f713bf5 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceMapper.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceMapper.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.dal.mysql.statistics; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceReqVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceSummaryRespVO; import org.apache.ibatis.annotations.Mapper; import java.util.List; @@ -38,4 +39,12 @@ public interface CrmStatisticsPerformanceMapper { */ List selectReceivablePricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + /** + * 合同汇总表 + * + * @param performanceReqVO 参数 + * @return 合同汇总表 + */ + List selectContractSummary(CrmStatisticsPerformanceReqVO performanceReqVO); + } diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceTargetMapper.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceTargetMapper.java new file mode 100644 index 0000000..0a9fedb --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsPerformanceTargetMapper.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceTargetActualRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceTargetReqVO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * CRM 业绩目标完成情况 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface CrmStatisticsPerformanceTargetMapper { + + /** + * 按月统计合同金额 + * + * @param reqVO 请求参数 + * @return 按月统计合同金额 + */ + List selectContractActualByMonth(CrmStatisticsPerformanceTargetReqVO reqVO); + + /** + * 按月统计回款金额 + * + * @param reqVO 请求参数 + * @return 按月统计回款金额 + */ + List selectReceivableActualByMonth(CrmStatisticsPerformanceTargetReqVO reqVO); + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsProductMapper.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsProductMapper.java new file mode 100644 index 0000000..03f79b4 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/statistics/CrmStatisticsProductMapper.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.crm.dal.mysql.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product.CrmStatisticsProductCategoryRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product.CrmStatisticsProductReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product.CrmStatisticsProductSalesRespVO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * CRM 产品分析 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface CrmStatisticsProductMapper { + + /** + * 获取产品销售情况统计 + * + * @param reqVO 请求参数 + * @return 产品销售情况 + */ + List selectProductSalesList(CrmStatisticsProductReqVO reqVO); + + /** + * 获取产品分类销售分析 + * + * @param reqVO 请求参数 + * @return 产品分类销售分析 + */ + List selectProductCategorySummary(CrmStatisticsProductReqVO reqVO); + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java index 5c1eb8d..790a9bf 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java @@ -104,6 +104,9 @@ public interface ErrorCodeConstants { ErrorCode FOLLOW_UP_RECORD_NOT_EXISTS = new ErrorCode(1_020_013_000, "跟进记录不存在"); ErrorCode FOLLOW_UP_RECORD_DELETE_DENIED = new ErrorCode(1_020_013_001, "删除跟进记录失败,原因:没有权限"); - // ========== 数据统计 1_020_014_000 ========== + // ========== 业绩目标配置 1_020_011_000 ========== + ErrorCode PERFORMANCE_CONFIG_NOT_EXISTS = new ErrorCode(1_020_011_000, "业绩目标配置不存在"); + ErrorCode PERFORMANCE_CONFIG_EXISTS = new ErrorCode(1_020_011_001, "该对象当前年份的业绩目标配置已存在"); + ErrorCode PERFORMANCE_CONFIG_TYPE_INVALID = new ErrorCode(1_020_011_002, "目标对象类型不正确"); } diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/performance/CrmPerformanceConfigBizTypeEnum.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/performance/CrmPerformanceConfigBizTypeEnum.java new file mode 100644 index 0000000..026244d --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/performance/CrmPerformanceConfigBizTypeEnum.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.crm.enums.performance; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * CRM 业绩目标业务类型枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum CrmPerformanceConfigBizTypeEnum implements ArrayValuable { + + CRM_CONTRACT(CrmBizTypeEnum.CRM_CONTRACT.getType(), "销售目标"), + CRM_RECEIVABLE(CrmBizTypeEnum.CRM_RECEIVABLE.getType(), "回款目标"); + + public static final Integer[] ARRAYS = Arrays.stream(values()) + .map(CrmPerformanceConfigBizTypeEnum::getBizType).toArray(Integer[]::new); + + /** + * 业务类型 + */ + private final Integer bizType; + /** + * 名称 + */ + private final String name; + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/performance/CrmPerformanceConfigObjectTypeEnum.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/performance/CrmPerformanceConfigObjectTypeEnum.java new file mode 100644 index 0000000..51fb496 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/performance/CrmPerformanceConfigObjectTypeEnum.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.crm.enums.performance; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * CRM 业绩目标对象类型枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum CrmPerformanceConfigObjectTypeEnum implements ArrayValuable { + + DEPT(2, "部门"), + USER(3, "员工"); + + public static final Integer[] ARRAYS = Arrays.stream(values()) + .map(CrmPerformanceConfigObjectTypeEnum::getObjectType).toArray(Integer[]::new); + + /** + * 对象类型 + */ + private final Integer objectType; + /** + * 名称 + */ + private final String name; + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java index 11ac107..2b0101c 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java @@ -28,7 +28,9 @@ import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO; +import cn.iocoder.yudao.module.crm.service.permission.CrmOwnerRecordService; import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmOwnerRecordCreateReqBO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO; import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; @@ -66,6 +68,8 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { @Resource private CrmCustomerMapper customerMapper; + @Resource + private CrmOwnerRecordService ownerRecordService; @Resource private CrmPermissionService permissionService; @@ -407,6 +411,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { // 2. 领取公海数据 List updateCustomers = new ArrayList<>(); List createPermissions = new ArrayList<>(); + List ownerRecords = new ArrayList<>(); customers.forEach(customer -> { // 2.1. 设置负责人 updateCustomers.add(new CrmCustomerDO().setId(customer.getId()) @@ -414,11 +419,16 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { // 2.2. 创建负责人数据权限 createPermissions.add(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) .setBizId(customer.getId()).setUserId(ownerUserId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); + // 2.3. 记录负责人从公海变更为指定人员 + ownerRecords.add(new CrmOwnerRecordCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) + .setBizId(customer.getId()).setPreOwnerUserId(customer.getOwnerUserId()).setPostOwnerUserId(ownerUserId)); }); // 2.2 更新客户负责人 customerMapper.updateBatch(updateCustomers); // 2.3 创建负责人数据权限 permissionService.createPermissionBatch(createPermissions); + // 2.4 记录负责人变更历史 + ownerRecordService.createOwnerRecordList(ownerRecords); // TODO @芋艿:要不要处理关联的联系人??? // 3. 记录操作日志 @@ -459,6 +469,8 @@ public class CrmCustomerServiceImpl implements CrmCustomerService { if (updateOwnerUserIncr == 0) { throw exception(CUSTOMER_UPDATE_OWNER_USER_FAIL); } + ownerRecordService.createOwnerRecord(new CrmOwnerRecordCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()) + .setBizId(customer.getId()).setPreOwnerUserId(customer.getOwnerUserId()).setPostOwnerUserId(null)); // 2. 联系人的负责人,也要设置为 null。因为:因为领取后,负责人也要关联过来,这块和 receiveCustomer 是对应的 contactService.updateOwnerUserIdByCustomerId(customer.getId(), null); diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/performance/CrmPerformanceConfigService.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/performance/CrmPerformanceConfigService.java new file mode 100644 index 0000000..0da304f --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/performance/CrmPerformanceConfigService.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.crm.service.performance; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.crm.controller.admin.performance.vo.config.CrmPerformanceConfigPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.performance.vo.config.CrmPerformanceConfigSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.performance.CrmPerformanceConfigDO; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; + +/** + * CRM 业绩目标设置 Service 接口 + * + * @author 芋道源码 + */ +public interface CrmPerformanceConfigService { + + /** + * 创建业绩目标 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createPerformanceConfig(@Valid CrmPerformanceConfigSaveReqVO createReqVO); + + /** + * 更新业绩目标 + * + * @param updateReqVO 更新信息 + */ + void updatePerformanceConfig(@Valid CrmPerformanceConfigSaveReqVO updateReqVO); + + /** + * 删除业绩目标 + * + * @param id 编号 + */ + void deletePerformanceConfig(Long id); + + /** + * 获得业绩目标 + * + * @param id 编号 + * @return 业绩目标 + */ + CrmPerformanceConfigDO getPerformanceConfig(Long id); + + /** + * 获得业绩目标分页 + * + * @param pageReqVO 分页查询 + * @return 业绩目标分页 + */ + PageResult getPerformanceConfigPage(CrmPerformanceConfigPageReqVO pageReqVO); + + /** + * 根据对象、年份、目标类型获得业绩目标配置 + * + * @param objectId 对象编号 + * @param objectType 对象类型 + * @param year 年份 + * @param bizType 业务类型 + * @return 业绩目标配置 + */ + CrmPerformanceConfigDO getPerformanceConfig(Long objectId, Integer objectType, Integer year, Integer bizType); + + /** + * 根据对象数组、年份、目标类型获得业绩目标配置列表 + * + * @param objectIds 对象编号数组 + * @param objectType 对象类型 + * @param year 年份 + * @param bizType 业务类型 + * @return 业绩目标配置列表 + */ + List getPerformanceConfigList(Collection objectIds, Integer objectType, Integer year, + Integer bizType); + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/performance/CrmPerformanceConfigServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/performance/CrmPerformanceConfigServiceImpl.java new file mode 100644 index 0000000..1e5c545 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/performance/CrmPerformanceConfigServiceImpl.java @@ -0,0 +1,170 @@ +package cn.iocoder.yudao.module.crm.service.performance; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.performance.vo.config.CrmPerformanceConfigPageReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.performance.vo.config.CrmPerformanceConfigSaveReqVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.performance.CrmPerformanceConfigDO; +import cn.iocoder.yudao.module.crm.dal.mysql.performance.CrmPerformanceConfigMapper; +import cn.iocoder.yudao.module.crm.enums.performance.CrmPerformanceConfigObjectTypeEnum; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import static cn.hutool.core.collection.CollUtil.isEmpty; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*; +import static java.util.Collections.singleton; + +/** + * CRM 业绩目标设置 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class CrmPerformanceConfigServiceImpl implements CrmPerformanceConfigService { + + @Resource + private CrmPerformanceConfigMapper performanceConfigMapper; + + @Resource + private DeptApi deptApi; + @Resource + private AdminUserApi adminUserApi; + + @Override + public Long createPerformanceConfig(CrmPerformanceConfigSaveReqVO createReqVO) { + // 1.1 校验目标对象 + validatePerformanceConfigObject(createReqVO.getObjectType(), createReqVO.getObjectId()); + // 1.2 校验唯一 + validatePerformanceConfigNotExists(null, createReqVO); + + // 2. 插入 + CrmPerformanceConfigDO performanceConfig = BeanUtils.toBean(createReqVO, CrmPerformanceConfigDO.class); + fillTargetPrice(performanceConfig); + performanceConfigMapper.insert(performanceConfig); + return performanceConfig.getId(); + } + + @Override + public void updatePerformanceConfig(CrmPerformanceConfigSaveReqVO updateReqVO) { + // 1.1 校验存在 + validatePerformanceConfigExists(updateReqVO.getId()); + // 1.2 校验目标对象 + validatePerformanceConfigObject(updateReqVO.getObjectType(), updateReqVO.getObjectId()); + // 1.3 校验唯一 + validatePerformanceConfigNotExists(updateReqVO.getId(), updateReqVO); + + // 2. 更新 + CrmPerformanceConfigDO updateObj = BeanUtils.toBean(updateReqVO, CrmPerformanceConfigDO.class); + fillTargetPrice(updateObj); + performanceConfigMapper.updateById(updateObj); + } + + @Override + public void deletePerformanceConfig(Long id) { + // 1. 校验存在 + validatePerformanceConfigExists(id); + // 2. 删除 + performanceConfigMapper.deleteById(id); + } + + @Override + public CrmPerformanceConfigDO getPerformanceConfig(Long id) { + return validatePerformanceConfigExists(id); + } + + @Override + public PageResult getPerformanceConfigPage(CrmPerformanceConfigPageReqVO pageReqVO) { + return performanceConfigMapper.selectPage(pageReqVO); + } + + private CrmPerformanceConfigDO validatePerformanceConfigExists(Long id) { + CrmPerformanceConfigDO performanceConfig = performanceConfigMapper.selectById(id); + if (performanceConfig == null) { + throw exception(PERFORMANCE_CONFIG_NOT_EXISTS); + } + return performanceConfig; + } + + private void validatePerformanceConfigNotExists(Long id, CrmPerformanceConfigSaveReqVO reqVO) { + CrmPerformanceConfigDO performanceConfig = performanceConfigMapper.selectByObjectIdAndObjectTypeAndYearAndBizType( + reqVO.getObjectId(), reqVO.getObjectType(), reqVO.getYear(), reqVO.getBizType()); + if (performanceConfig == null || Objects.equals(performanceConfig.getId(), id)) { + return; + } + throw exception(PERFORMANCE_CONFIG_EXISTS); + } + + private void validatePerformanceConfigObject(Integer objectType, Long objectId) { + // 情况一:部门 + if (Objects.equals(objectType, CrmPerformanceConfigObjectTypeEnum.DEPT.getObjectType())) { + deptApi.validateDeptList(singleton(objectId)); + return; + } + // 情况二:员工 + if (Objects.equals(objectType, CrmPerformanceConfigObjectTypeEnum.USER.getObjectType())) { + adminUserApi.validateUserList(singleton(objectId)); + return; + } + throw exception(PERFORMANCE_CONFIG_TYPE_INVALID); + } + + @Override + public CrmPerformanceConfigDO getPerformanceConfig(Long objectId, Integer objectType, Integer year, Integer bizType) { + return performanceConfigMapper.selectByObjectIdAndObjectTypeAndYearAndBizType(objectId, objectType, year, bizType); + } + + @Override + public List getPerformanceConfigList(Collection objectIds, Integer objectType, + Integer year, Integer bizType) { + if (isEmpty(objectIds)) { + return Collections.emptyList(); + } + return performanceConfigMapper.selectListByObjectIdsAndObjectTypeAndYearAndBizType(objectIds, objectType, + year, bizType); + } + + private void fillTargetPrice(CrmPerformanceConfigDO performanceConfig) { + // 1. 空值设置为 0 + performanceConfig.setJanuaryTargetPrice(defaultIfNull(performanceConfig.getJanuaryTargetPrice())); + performanceConfig.setFebruaryTargetPrice(defaultIfNull(performanceConfig.getFebruaryTargetPrice())); + performanceConfig.setMarchTargetPrice(defaultIfNull(performanceConfig.getMarchTargetPrice())); + performanceConfig.setAprilTargetPrice(defaultIfNull(performanceConfig.getAprilTargetPrice())); + performanceConfig.setMayTargetPrice(defaultIfNull(performanceConfig.getMayTargetPrice())); + performanceConfig.setJuneTargetPrice(defaultIfNull(performanceConfig.getJuneTargetPrice())); + performanceConfig.setJulyTargetPrice(defaultIfNull(performanceConfig.getJulyTargetPrice())); + performanceConfig.setAugustTargetPrice(defaultIfNull(performanceConfig.getAugustTargetPrice())); + performanceConfig.setSeptemberTargetPrice(defaultIfNull(performanceConfig.getSeptemberTargetPrice())); + performanceConfig.setOctoberTargetPrice(defaultIfNull(performanceConfig.getOctoberTargetPrice())); + performanceConfig.setNovemberTargetPrice(defaultIfNull(performanceConfig.getNovemberTargetPrice())); + performanceConfig.setDecemberTargetPrice(defaultIfNull(performanceConfig.getDecemberTargetPrice())); + // 2. 计算年度目标 + performanceConfig.setYearTargetPrice(performanceConfig.getJanuaryTargetPrice() + .add(performanceConfig.getFebruaryTargetPrice()) + .add(performanceConfig.getMarchTargetPrice()) + .add(performanceConfig.getAprilTargetPrice()) + .add(performanceConfig.getMayTargetPrice()) + .add(performanceConfig.getJuneTargetPrice()) + .add(performanceConfig.getJulyTargetPrice()) + .add(performanceConfig.getAugustTargetPrice()) + .add(performanceConfig.getSeptemberTargetPrice()) + .add(performanceConfig.getOctoberTargetPrice()) + .add(performanceConfig.getNovemberTargetPrice()) + .add(performanceConfig.getDecemberTargetPrice())); + } + + private BigDecimal defaultIfNull(BigDecimal value) { + return value == null ? BigDecimal.ZERO : value; + } + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmOwnerRecordService.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmOwnerRecordService.java new file mode 100644 index 0000000..c73e225 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmOwnerRecordService.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.crm.service.permission; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsPoolSummaryByDateRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsPoolSummaryByUserRespVO; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmOwnerRecordCreateReqBO; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * CRM 负责人变更记录 Service 接口 + * + * @author 芋道源码 + */ +public interface CrmOwnerRecordService { + + /** + * 创建负责人变更记录 + * + * @param createReqBO 创建信息 + * @return 编号 + */ + Long createOwnerRecord(@Valid CrmOwnerRecordCreateReqBO createReqBO); + + /** + * 批量创建负责人变更记录 + * + * @param createReqBOs 创建信息 + */ + void createOwnerRecordList(@Valid List createReqBOs); + + /** + * 进入公海客户数(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getPoolCustomerPutCountByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 公海领取客户数(按日期) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getPoolCustomerTakeCountByDate(CrmStatisticsCustomerReqVO reqVO); + + /** + * 进入公海客户数(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getPoolCustomerPutCountByUser(CrmStatisticsCustomerReqVO reqVO); + + /** + * 公海领取客户数(按用户) + * + * @param reqVO 请求参数 + * @return 统计数据 + */ + List getPoolCustomerTakeCountByUser(CrmStatisticsCustomerReqVO reqVO); + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmOwnerRecordServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmOwnerRecordServiceImpl.java new file mode 100644 index 0000000..6220e36 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/CrmOwnerRecordServiceImpl.java @@ -0,0 +1,65 @@ +package cn.iocoder.yudao.module.crm.service.permission; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsCustomerReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsPoolSummaryByDateRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.CrmStatisticsPoolSummaryByUserRespVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmOwnerRecordDO; +import cn.iocoder.yudao.module.crm.dal.mysql.permission.CrmOwnerRecordMapper; +import cn.iocoder.yudao.module.crm.service.permission.bo.CrmOwnerRecordCreateReqBO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * CRM 负责人变更记录 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class CrmOwnerRecordServiceImpl implements CrmOwnerRecordService { + + @Resource + private CrmOwnerRecordMapper ownerRecordMapper; + + @Override + public Long createOwnerRecord(CrmOwnerRecordCreateReqBO createReqBO) { + CrmOwnerRecordDO ownerRecord = BeanUtils.toBean(createReqBO, CrmOwnerRecordDO.class); + ownerRecordMapper.insert(ownerRecord); + return ownerRecord.getId(); + } + + @Override + public void createOwnerRecordList(List createReqBOs) { + if (CollUtil.isEmpty(createReqBOs)) { + return; + } + List list = BeanUtils.toBean(createReqBOs, CrmOwnerRecordDO.class); + ownerRecordMapper.insertBatch(list); + } + + @Override + public List getPoolCustomerPutCountByDate(CrmStatisticsCustomerReqVO reqVO) { + return ownerRecordMapper.selectPoolCustomerPutCountByDate(reqVO); + } + + @Override + public List getPoolCustomerTakeCountByDate(CrmStatisticsCustomerReqVO reqVO) { + return ownerRecordMapper.selectPoolCustomerTakeCountByDate(reqVO); + } + + @Override + public List getPoolCustomerPutCountByUser(CrmStatisticsCustomerReqVO reqVO) { + return ownerRecordMapper.selectPoolCustomerPutCountByUser(reqVO); + } + + @Override + public List getPoolCustomerTakeCountByUser(CrmStatisticsCustomerReqVO reqVO) { + return ownerRecordMapper.selectPoolCustomerTakeCountByUser(reqVO); + } + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmOwnerRecordCreateReqBO.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmOwnerRecordCreateReqBO.java new file mode 100644 index 0000000..80e0311 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/permission/bo/CrmOwnerRecordCreateReqBO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.crm.service.permission.bo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * CRM 负责人变更记录 Create Req BO + * + * @author 芋道源码 + */ +@Data +public class CrmOwnerRecordCreateReqBO { + + /** + * CRM 业务类型 + */ + @NotNull(message = "CRM 业务类型不能为空") + @InEnum(CrmBizTypeEnum.class) + private Integer bizType; + + /** + * CRM 业务编号 + */ + @NotNull(message = "CRM 业务编号不能为空") + private Long bizId; + + /** + * 变更前负责人 + */ + private Long preOwnerUserId; + + /** + * 变更后负责人 + */ + private Long postOwnerUserId; + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java index 1df4d5a..17c4601 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsCustomerServiceImpl.java @@ -10,6 +10,7 @@ import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.customer.*; import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsCustomerMapper; +import cn.iocoder.yudao.module.crm.service.permission.CrmOwnerRecordService; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; @@ -42,6 +43,9 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe private CrmStatisticsCustomerMapper customerMapper; @Resource + private CrmOwnerRecordService ownerRecordService; + + @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @@ -201,8 +205,8 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe } // 2. 按天统计,获取分项统计数据 - List customerPutCountList = customerMapper.selectPoolCustomerPutCountByDate(reqVO); - List customerTakeCountList = customerMapper.selectPoolCustomerTakeCountByDate(reqVO); + List customerPutCountList = ownerRecordService.getPoolCustomerPutCountByDate(reqVO); + List customerTakeCountList = ownerRecordService.getPoolCustomerTakeCountByDate(reqVO); // 3. 按照日期间隔,合并数据 List timeRanges = LocalDateTimeUtils.getDateRangeList(reqVO.getTimes()[0], reqVO.getTimes()[1], reqVO.getInterval()); @@ -228,8 +232,8 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe } // 2. 按用户统计,获取分项统计数据 - List customerPutCountList = customerMapper.selectPoolCustomerPutCountByUser(reqVO); - List customerTakeCountList = customerMapper.selectPoolCustomerTakeCountByUser(reqVO); + List customerPutCountList = ownerRecordService.getPoolCustomerPutCountByUser(reqVO); + List customerTakeCountList = ownerRecordService.getPoolCustomerTakeCountByUser(reqVO); // 3.1 按照用户,合并统计数据 List summaryList = convertList(reqVO.getUserIds(), userId -> { @@ -331,7 +335,6 @@ public class CrmStatisticsCustomerServiceImpl implements CrmStatisticsCustomerSe reqVO.setUserIds(userIds); // 2. 获取客户产品统计数据 - // TODO @dhb52:未读取产品名 return customerMapper.selectCustomerDealCycleGroupByProductId(reqVO); } diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelService.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelService.java index 10458da..fd4c451 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelService.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelService.java @@ -30,6 +30,14 @@ public interface CrmStatisticsFunnelService { List getBusinessSummaryByEndStatus(CrmStatisticsFunnelReqVO reqVO); /** + * 获得商机阶段统计 + * + * @param reqVO 请求 + * @return 商机阶段统计 + */ + List getBusinessSummaryByStatus(CrmStatisticsFunnelReqVO reqVO); + + /** * 获取新增商机分析(按日期) * * @param reqVO 请求 diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelServiceImpl.java index f4a04ed..02f463f 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelServiceImpl.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsFunnelServiceImpl.java @@ -71,6 +71,18 @@ public class CrmStatisticsFunnelServiceImpl implements CrmStatisticsFunnelServic } @Override + public List getBusinessSummaryByStatus(CrmStatisticsFunnelReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2. 获得统计数据 + return funnelMapper.selectBusinessSummaryListGroupByStatus(reqVO); + } + + @Override public List getBusinessSummaryByDate(CrmStatisticsFunnelReqVO reqVO) { // 1. 获得用户编号数组 reqVO.setUserIds(getUserIds(reqVO)); diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceService.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceService.java index 15423af..b20d27a 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceService.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceService.java @@ -4,11 +4,12 @@ package cn.iocoder.yudao.module.crm.service.statistics; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceReqVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceSummaryRespVO; import java.util.List; /** - * CRM 员工绩效统计 Service 接口 + * CRM 员工业绩统计 Service 接口 * * @author scholar */ @@ -38,5 +39,12 @@ public interface CrmStatisticsPerformanceService { */ List getReceivablePricePerformance(CrmStatisticsPerformanceReqVO performanceReqVO); + /** + * 员工合同汇总表 + * + * @param performanceReqVO 排行参数 + * @return 员工合同汇总表 + */ + List getContractSummary(CrmStatisticsPerformanceReqVO performanceReqVO); } diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceServiceImpl.java index 719813e..bc8e1c1 100644 --- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceServiceImpl.java +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceServiceImpl.java @@ -5,6 +5,7 @@ import cn.hutool.core.collection.ListUtil; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceReqVO; import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceSummaryRespVO; import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsPerformanceMapper; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; @@ -56,6 +57,29 @@ public class CrmStatisticsPerformanceServiceImpl implements CrmStatisticsPerform return getPerformance(performanceReqVO, performanceMapper::selectReceivablePricePerformance); } + @Override + public List getContractSummary(CrmStatisticsPerformanceReqVO performanceReqVO) { + List userIds = getUserIds(performanceReqVO); + if (CollUtil.isEmpty(userIds)) { + return Collections.emptyList(); + } + performanceReqVO.setUserIds(userIds); + + int year = performanceReqVO.getTimes()[0].getYear(); + List summaryList = performanceMapper.selectContractSummary(performanceReqVO); + Map summaryMap = convertMap(summaryList, + CrmStatisticsPerformanceSummaryRespVO::getTime); + List result = new ArrayList<>(); + for (int month = 1; month <= 12; month++) { + String currentMonth = String.format("%d%02d", year, month); + CrmStatisticsPerformanceSummaryRespVO summary = summaryMap.get(currentMonth); + result.add(summary != null ? summary : new CrmStatisticsPerformanceSummaryRespVO().setTime(currentMonth) + .setContractCount(0).setContractPrice(BigDecimal.ZERO) + .setReceivablePrice(BigDecimal.ZERO).setUnreceivedPrice(BigDecimal.ZERO)); + } + return result; + } + /** * 获得员工业绩数据 * @@ -117,4 +141,4 @@ public class CrmStatisticsPerformanceServiceImpl implements CrmStatisticsPerform return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); } -} \ No newline at end of file +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceTargetService.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceTargetService.java new file mode 100644 index 0000000..ba534d1 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceTargetService.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceTargetReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceTargetRespVO; + +import java.util.List; + +/** + * CRM 业绩目标统计 Service 接口 + * + * @author 芋道源码 + */ +public interface CrmStatisticsPerformanceTargetService { + + /** + * 获取业绩目标完成情况 + * + * @param reqVO 请求参数 + * @return 业绩目标完成情况 + */ + List getPerformanceTargetSummary(CrmStatisticsPerformanceTargetReqVO reqVO); + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceTargetServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceTargetServiceImpl.java new file mode 100644 index 0000000..d56a6bf --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsPerformanceTargetServiceImpl.java @@ -0,0 +1,190 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceTargetActualRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceTargetReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.performance.CrmStatisticsPerformanceTargetRespVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.performance.CrmPerformanceConfigDO; +import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsPerformanceTargetMapper; +import cn.iocoder.yudao.module.crm.enums.performance.CrmPerformanceConfigBizTypeEnum; +import cn.iocoder.yudao.module.crm.enums.performance.CrmPerformanceConfigObjectTypeEnum; +import cn.iocoder.yudao.module.crm.service.performance.CrmPerformanceConfigService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * CRM 业绩目标统计 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class CrmStatisticsPerformanceTargetServiceImpl implements CrmStatisticsPerformanceTargetService { + + @Resource + private CrmStatisticsPerformanceTargetMapper performanceTargetMapper; + @Resource + private CrmPerformanceConfigService performanceConfigService; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + + @Override + public List getPerformanceTargetSummary(CrmStatisticsPerformanceTargetReqVO reqVO) { + // 1. 获得用户编号数组 + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + + // 2.1 获得目标配置 + List performanceConfigs = getPerformanceConfigs(reqVO); + // 2.2 获得实际完成金额 + List actualList = ObjUtil.equal(reqVO.getBizType(), + CrmPerformanceConfigBizTypeEnum.CRM_RECEIVABLE.getBizType()) + ? performanceTargetMapper.selectReceivableActualByMonth(reqVO) + : performanceTargetMapper.selectContractActualByMonth(reqVO); + Map actualMap = convertMap(actualList, + CrmStatisticsPerformanceTargetActualRespVO::getMonth, + CrmStatisticsPerformanceTargetActualRespVO::getCurrentPrice); + + // 3. 组装数据返回 + List result = new ArrayList<>(); + for (int month = 1; month <= 12; month++) { + BigDecimal targetPrice = getMonthTargetPrice(performanceConfigs, month); + BigDecimal currentPrice = actualMap.getOrDefault(month, BigDecimal.ZERO); + result.add(new CrmStatisticsPerformanceTargetRespVO().setMonth(month).setTargetPrice(targetPrice) + .setCurrentPrice(currentPrice) + .setCompletionRate(calculateCompletionRate(currentPrice, targetPrice))); + } + return result; + } + + private List getPerformanceConfigs(CrmStatisticsPerformanceTargetReqVO reqVO) { + // 情况一:选中某个用户 + if (ObjUtil.isNotNull(reqVO.getUserId())) { + CrmPerformanceConfigDO performanceConfig = performanceConfigService.getPerformanceConfig(reqVO.getUserId(), + CrmPerformanceConfigObjectTypeEnum.USER.getObjectType(), reqVO.getYear(), reqVO.getBizType()); + return performanceConfig == null ? Collections.emptyList() : ListUtil.of(performanceConfig); + } + // 情况二:选中某个部门 + return performanceConfigService.getPerformanceConfigList(getDeptIds(reqVO.getDeptId()), + CrmPerformanceConfigObjectTypeEnum.DEPT.getObjectType(), reqVO.getYear(), reqVO.getBizType()); + } + + private BigDecimal getMonthTargetPrice(List performanceConfigs, int month) { + return performanceConfigs.stream() + .map(performanceConfig -> getMonthTargetPrice(performanceConfig, month)) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + @SuppressWarnings("EnhancedSwitchMigration") + private BigDecimal getMonthTargetPrice(CrmPerformanceConfigDO performanceConfig, int month) { + // 1. 无目标配置,返回 0 + if (performanceConfig == null) { + return BigDecimal.ZERO; + } + // 2. 获得月份目标 + BigDecimal targetPrice; + switch (month) { + case 1: + targetPrice = performanceConfig.getJanuaryTargetPrice(); + break; + case 2: + targetPrice = performanceConfig.getFebruaryTargetPrice(); + break; + case 3: + targetPrice = performanceConfig.getMarchTargetPrice(); + break; + case 4: + targetPrice = performanceConfig.getAprilTargetPrice(); + break; + case 5: + targetPrice = performanceConfig.getMayTargetPrice(); + break; + case 6: + targetPrice = performanceConfig.getJuneTargetPrice(); + break; + case 7: + targetPrice = performanceConfig.getJulyTargetPrice(); + break; + case 8: + targetPrice = performanceConfig.getAugustTargetPrice(); + break; + case 9: + targetPrice = performanceConfig.getSeptemberTargetPrice(); + break; + case 10: + targetPrice = performanceConfig.getOctoberTargetPrice(); + break; + case 11: + targetPrice = performanceConfig.getNovemberTargetPrice(); + break; + case 12: + targetPrice = performanceConfig.getDecemberTargetPrice(); + break; + default: + targetPrice = BigDecimal.ZERO; + } + return targetPrice != null ? targetPrice : BigDecimal.ZERO; + } + + private BigDecimal calculateCompletionRate(BigDecimal currentPrice, BigDecimal targetPrice) { + if (targetPrice == null || targetPrice.compareTo(BigDecimal.ZERO) == 0) { + return BigDecimal.ZERO; + } + return currentPrice.multiply(BigDecimal.valueOf(100)).divide(targetPrice, 2, RoundingMode.HALF_UP); + } + + /** + * 获取用户编号数组 + * + * 如果用户编号为空,则获得部门下的用户编号数组,包括子部门的所有用户编号 + * + * @param reqVO 请求参数 + * @return 用户编号数组 + */ + private List getUserIds(CrmStatisticsPerformanceTargetReqVO reqVO) { + // 情况一:选中某个用户 + if (ObjUtil.isNotNull(reqVO.getUserId())) { + return ListUtil.of(reqVO.getUserId()); + } + // 情况二:选中某个部门 + // 2.1 获得部门列表 + List deptIds = getDeptIds(reqVO.getDeptId()); + // 2.2 获得用户编号 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); + } + + /** + * 获得部门编号数组,包括子部门 + * + * @param deptId 部门编号 + * @return 部门编号数组 + */ + private List getDeptIds(Long deptId) { + List deptIds = convertList(deptApi.getChildDeptList(deptId), DeptRespDTO::getId); + deptIds.add(deptId); + return deptIds; + } + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsProductService.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsProductService.java new file mode 100644 index 0000000..055aa5f --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsProductService.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product.CrmStatisticsProductCategoryRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product.CrmStatisticsProductReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product.CrmStatisticsProductSalesRespVO; + +import java.util.List; + +/** + * CRM 产品分析 Service 接口 + * + * @author 芋道源码 + */ +public interface CrmStatisticsProductService { + + /** + * 获取产品销售情况统计 + * + * @param reqVO 请求参数 + * @return 产品销售情况 + */ + List getProductSalesList(CrmStatisticsProductReqVO reqVO); + + /** + * 获取产品分类销售分析 + * + * @param reqVO 请求参数 + * @return 产品分类销售分析 + */ + List getProductCategorySummary(CrmStatisticsProductReqVO reqVO); + +} diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsProductServiceImpl.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsProductServiceImpl.java new file mode 100644 index 0000000..830cb00 --- /dev/null +++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/statistics/CrmStatisticsProductServiceImpl.java @@ -0,0 +1,104 @@ +package cn.iocoder.yudao.module.crm.service.statistics; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.module.crm.controller.admin.product.vo.category.CrmProductCategoryListReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product.CrmStatisticsProductCategoryRespVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product.CrmStatisticsProductReqVO; +import cn.iocoder.yudao.module.crm.controller.admin.statistics.vo.product.CrmStatisticsProductSalesRespVO; +import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; +import cn.iocoder.yudao.module.crm.dal.mysql.statistics.CrmStatisticsProductMapper; +import cn.iocoder.yudao.module.crm.service.product.CrmProductCategoryService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +/** + * CRM 产品分析 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class CrmStatisticsProductServiceImpl implements CrmStatisticsProductService { + + @Resource + private CrmStatisticsProductMapper productMapper; + + @Resource + private AdminUserApi adminUserApi; + @Resource + private DeptApi deptApi; + @Resource + private CrmProductCategoryService productCategoryService; + + @Override + public List getProductSalesList(CrmStatisticsProductReqVO reqVO) { + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + setCategoryIds(reqVO); + return productMapper.selectProductSalesList(reqVO); + } + + @Override + public List getProductCategorySummary(CrmStatisticsProductReqVO reqVO) { + reqVO.setUserIds(getUserIds(reqVO)); + if (CollUtil.isEmpty(reqVO.getUserIds())) { + return Collections.emptyList(); + } + setCategoryIds(reqVO); + return productMapper.selectProductCategorySummary(reqVO); + } + + /** + * 设置产品分类编号数组,选择父分类时,包含子分类 + * + * @param reqVO 请求参数 + */ + private void setCategoryIds(CrmStatisticsProductReqVO reqVO) { + if (ObjUtil.isNull(reqVO.getCategoryId())) { + return; + } + List categoryIds = ListUtil.of(reqVO.getCategoryId()); + List categoryList = productCategoryService.getProductCategoryList( + new CrmProductCategoryListReqVO()); + categoryIds.addAll(convertList(categoryList, CrmProductCategoryDO::getId, + category -> Objects.equals(category.getParentId(), reqVO.getCategoryId()))); + reqVO.setCategoryIds(categoryIds); + } + + /** + * 获取用户编号数组 + * + * 如果用户编号为空,则获得部门下的用户编号数组,包括子部门的所有用户编号 + * + * @param reqVO 请求参数 + * @return 用户编号数组 + */ + private List getUserIds(CrmStatisticsProductReqVO reqVO) { + // 情况一:选中某个用户 + if (ObjUtil.isNotNull(reqVO.getUserId())) { + return ListUtil.of(reqVO.getUserId()); + } + // 情况二:选中某个部门 + // 2.1 获得部门列表 + List deptIds = convertList(deptApi.getChildDeptList(reqVO.getDeptId()), DeptRespDTO::getId); + deptIds.add(reqVO.getDeptId()); + // 2.2 获得用户编号 + return convertList(adminUserApi.getUserListByDeptIds(deptIds), AdminUserRespDTO::getId); + } + +} diff --git a/yudao-module-crm/src/main/resources/mapper/permission/CrmOwnerRecordMapper.xml b/yudao-module-crm/src/main/resources/mapper/permission/CrmOwnerRecordMapper.xml new file mode 100644 index 0000000..efafb61 --- /dev/null +++ b/yudao-module-crm/src/main/resources/mapper/permission/CrmOwnerRecordMapper.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + diff --git a/yudao-module-crm/src/main/resources/mapper/statistics/CrmStatisticsFunnelMapper.xml b/yudao-module-crm/src/main/resources/mapper/statistics/CrmStatisticsFunnelMapper.xml index a074062..e3ef36d 100644 --- a/yudao-module-crm/src/main/resources/mapper/statistics/CrmStatisticsFunnelMapper.xml +++ b/yudao-module-crm/src/main/resources/mapper/statistics/CrmStatisticsFunnelMapper.xml @@ -25,6 +25,9 @@ AND end_status = #{status} + + AND status_type_id = #{reqVO.statusTypeId} + AND owner_user_id IN #{userId} @@ -38,9 +41,12 @@ SELECT end_status AS endStatus, COUNT(*) AS businessCount, - SUM(total_price) AS totalPrice + IFNULL(SUM(total_price), 0) AS totalPrice FROM crm_business WHERE deleted = 0 AND end_status IS NOT NULL + + AND status_type_id = #{statusTypeId} + AND owner_user_id IN #{userId} @@ -50,14 +56,44 @@ GROUP BY end_status + + + + diff --git a/yudao-module-crm/src/main/resources/mapper/statistics/CrmStatisticsPerformanceTargetMapper.xml b/yudao-module-crm/src/main/resources/mapper/statistics/CrmStatisticsPerformanceTargetMapper.xml new file mode 100644 index 0000000..36b2552 --- /dev/null +++ b/yudao-module-crm/src/main/resources/mapper/statistics/CrmStatisticsPerformanceTargetMapper.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + diff --git a/yudao-module-crm/src/main/resources/mapper/statistics/CrmStatisticsProductMapper.xml b/yudao-module-crm/src/main/resources/mapper/statistics/CrmStatisticsProductMapper.xml new file mode 100644 index 0000000..b69e0c1 --- /dev/null +++ b/yudao-module-crm/src/main/resources/mapper/statistics/CrmStatisticsProductMapper.xml @@ -0,0 +1,68 @@ + + + + + + contract.deleted = 0 + AND contract_product.deleted = 0 + AND product.deleted = 0 + AND contract.audit_status = ${@cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum@APPROVE.status} + AND contract.owner_user_id IN + + #{userId} + + AND contract.order_date BETWEEN #{times[0],javaType=java.time.LocalDateTime} AND #{times[1],javaType=java.time.LocalDateTime} + + AND product.category_id IN + + #{categoryId} + + + + AND product.id = #{productId} + + + + + + + + diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/checkrecord/MesDvCheckRecordLineController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/checkrecord/MesDvCheckRecordLineController.java index 080971c..7fb9b4c 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/checkrecord/MesDvCheckRecordLineController.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/checkrecord/MesDvCheckRecordLineController.java @@ -83,6 +83,16 @@ public class MesDvCheckRecordLineController { return success(new PageResult<>(buildCheckRecordLineRespVOList(pageResult.getList()), pageResult.getTotal())); } + @GetMapping("/list-by-record-id") + @Operation(summary = "获得指定点检记录的明细列表") + @Parameter(name = "recordId", description = "点检记录编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:dv-check-record:query')") + public CommonResult> getCheckRecordLineListByRecordId( + @RequestParam("recordId") Long recordId) { + List list = checkRecordLineService.getCheckRecordLineListByRecordId(recordId); + return success(buildCheckRecordLineRespVOList(list)); + } + // ==================== 拼接 VO ==================== private List buildCheckRecordLineRespVOList(List list) { diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/maintenrecord/MesDvMaintenRecordLineController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/maintenrecord/MesDvMaintenRecordLineController.java index 39e40c9..72742fd 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/maintenrecord/MesDvMaintenRecordLineController.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/maintenrecord/MesDvMaintenRecordLineController.java @@ -89,6 +89,16 @@ public class MesDvMaintenRecordLineController { return success(new PageResult<>(buildMaintenRecordLineRespVOList(pageResult.getList()), pageResult.getTotal())); } + @GetMapping("/list-by-record-id") + @Operation(summary = "获得指定保养记录的明细列表") + @Parameter(name = "recordId", description = "保养记录编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:dv-mainten-record:query')") + public CommonResult> getMaintenRecordLineListByRecordId( + @RequestParam("recordId") Long recordId) { + List list = maintenRecordLineService.getMaintenRecordLineListByRecordId(recordId); + return success(buildMaintenRecordLineRespVOList(list)); + } + @GetMapping("/export-excel") @Operation(summary = "导出设备保养记录明细 Excel") @PreAuthorize("@ss.hasPermission('mes:dv-mainten-record:export')") diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/repair/MesDvRepairLineController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/repair/MesDvRepairLineController.java index 18ec6cd..dbe3155 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/repair/MesDvRepairLineController.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/repair/MesDvRepairLineController.java @@ -89,6 +89,16 @@ public class MesDvRepairLineController { return success(new PageResult<>(buildRepairLineRespVOList(pageResult.getList()), pageResult.getTotal())); } + @GetMapping("/list-by-repair-id") + @Operation(summary = "获得指定维修工单的明细列表") + @Parameter(name = "repairId", description = "维修工单编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:dv-repair:query')") + public CommonResult> getRepairLineListByRepairId( + @RequestParam("repairId") Long repairId) { + List list = repairLineService.getRepairLineListByRepairId(repairId); + return success(buildRepairLineRespVOList(list)); + } + @GetMapping("/export-excel") @Operation(summary = "导出维修工单行 Excel") @PreAuthorize("@ss.hasPermission('mes:dv-repair:export')") diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java index c2d586c..8cfa634 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java @@ -96,6 +96,16 @@ public class MesProWorkOrderBomController { return success(new PageResult<>(buildWorkOrderBomRespVOList(pageResult.getList()), pageResult.getTotal())); } + @GetMapping("/list-by-work-order-id") + @Operation(summary = "获得工单 BOM 列表") + @Parameter(name = "workOrderId", description = "工单编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:pro-work-order:query')") + public CommonResult> getWorkOrderBomListByWorkOrderId( + @RequestParam("workOrderId") Long workOrderId) { + List list = workOrderBomService.getWorkOrderBomListByWorkOrderId(workOrderId); + return success(buildWorkOrderBomRespVOList(list)); + } + @GetMapping("/item-list-by-work-order-id") @Operation(summary = "获得工单物料需求列表") @Parameter(name = "workOrderId", description = "工单编号", required = true) diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/stocktaking/task/vo/result/MesWmStockTakingTaskResultRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/stocktaking/task/vo/result/MesWmStockTakingTaskResultRespVO.java index 8f074d8..cc5638c 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/stocktaking/task/vo/result/MesWmStockTakingTaskResultRespVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/stocktaking/task/vo/result/MesWmStockTakingTaskResultRespVO.java @@ -77,6 +77,10 @@ public class MesWmStockTakingTaskResultRespVO { @ExcelProperty("账面数量") private BigDecimal quantity; + @Schema(description = "实盘数量", example = "98.000000") + @ExcelProperty("实盘数量") + private BigDecimal takingQuantity; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") private LocalDateTime createTime; diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/repair/MesDvRepairLineService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/repair/MesDvRepairLineService.java index 5fdb0e8..3d2b981 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/repair/MesDvRepairLineService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/repair/MesDvRepairLineService.java @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.dv.repair.MesDvRepairLineDO; import jakarta.validation.Valid; +import java.util.List; + /** * MES 维修工单行 Service 接口 * @@ -53,6 +55,14 @@ public interface MesDvRepairLineService { PageResult getRepairLinePage(MesDvRepairLinePageReqVO pageReqVO); /** + * 获得指定维修工单的明细列表 + * + * @param repairId 维修工单编号 + * @return 明细列表 + */ + List getRepairLineListByRepairId(Long repairId); + + /** * 根据维修工单编号删除所有行 * * @param repairId 维修工单编号 diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/repair/MesDvRepairLineServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/repair/MesDvRepairLineServiceImpl.java index abd31fd..61dce77 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/repair/MesDvRepairLineServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/repair/MesDvRepairLineServiceImpl.java @@ -12,6 +12,8 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.List; + import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; @@ -100,6 +102,11 @@ public class MesDvRepairLineServiceImpl implements MesDvRepairLineService { } @Override + public List getRepairLineListByRepairId(Long repairId) { + return repairLineMapper.selectListByRepairId(repairId); + } + + @Override public void deleteByRepairId(Long repairId) { repairLineMapper.deleteByRepairId(repairId); } diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 083530c..de6f6d6 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -273,7 +273,7 @@ yudao: permit-all_urls: - /admin-api/mp/open/** # 微信公众号开放平台,微信回调接口,不需要登录 api-encrypt: - enable: true # 是否开启 API 加密 + enable: false # 是否开启 API 加密。默认关闭,避免低版本 JDK 8(8u120 以下)启动时 bcprov 的 JCE 认证报错 algorithm: AES # 加密算法,支持 AES、RSA 等 request-key: 52549111389893486934626385991395 # 【AES 案例】请求加密的秘钥,,必须 16、24、32 位 response-key: 96103715984234343991809655248883 # 【AES 案例】响应加密的秘钥,AES 案例,必须 16、24、32 位