diff --git a/backend/src/main/java/com/unis/crm/controller/OpportunityController.java b/backend/src/main/java/com/unis/crm/controller/OpportunityController.java index 4446b9a7..887c2374 100644 --- a/backend/src/main/java/com/unis/crm/controller/OpportunityController.java +++ b/backend/src/main/java/com/unis/crm/controller/OpportunityController.java @@ -5,6 +5,7 @@ import com.unis.crm.common.CurrentUserUtils; import com.unis.crm.dto.opportunity.CreateOpportunityFollowUpRequest; import com.unis.crm.dto.opportunity.CreateOpportunityRequest; import com.unis.crm.dto.opportunity.OmsPreSalesOptionDTO; +import com.unis.crm.dto.opportunity.OpportunityItemDTO; import com.unis.crm.dto.opportunity.OpportunityMetaDTO; import com.unis.crm.dto.opportunity.OpportunityOverviewDTO; import com.unis.crm.dto.opportunity.PushOpportunityToOmsRequest; @@ -45,6 +46,13 @@ public class OpportunityController { return ApiResponse.success(opportunityService.getOverview(CurrentUserUtils.requireCurrentUserId(userId), keyword, stage)); } + @GetMapping("/{opportunityId}") + public ApiResponse getDetail( + @RequestHeader("X-User-Id") Long userId, + @PathVariable("opportunityId") Long opportunityId) { + return ApiResponse.success(opportunityService.getDetail(CurrentUserUtils.requireCurrentUserId(userId), opportunityId)); + } + @GetMapping("/oms/pre-sales") public ApiResponse> getOmsPreSalesOptions(@RequestHeader("X-User-Id") Long userId) { return ApiResponse.success(opportunityService.getOmsPreSalesOptions(CurrentUserUtils.requireCurrentUserId(userId))); diff --git a/backend/src/main/java/com/unis/crm/dto/opportunity/OpportunityItemDTO.java b/backend/src/main/java/com/unis/crm/dto/opportunity/OpportunityItemDTO.java index 7e195218..f7e7bc41 100644 --- a/backend/src/main/java/com/unis/crm/dto/opportunity/OpportunityItemDTO.java +++ b/backend/src/main/java/com/unis/crm/dto/opportunity/OpportunityItemDTO.java @@ -28,8 +28,12 @@ public class OpportunityItemDTO { private String source; private Long salesExpansionId; private String salesExpansionName; + private String salesExpansionIntent; + private Boolean salesExpansionActive; private Long channelExpansionId; private String channelExpansionName; + private String channelExpansionIntent; + private String channelExpansionEstablishedDate; private Long preSalesId; private String preSalesName; private String competitorName; @@ -214,6 +218,22 @@ public class OpportunityItemDTO { this.salesExpansionName = salesExpansionName; } + public String getSalesExpansionIntent() { + return salesExpansionIntent; + } + + public void setSalesExpansionIntent(String salesExpansionIntent) { + this.salesExpansionIntent = salesExpansionIntent; + } + + public Boolean getSalesExpansionActive() { + return salesExpansionActive; + } + + public void setSalesExpansionActive(Boolean salesExpansionActive) { + this.salesExpansionActive = salesExpansionActive; + } + public Long getChannelExpansionId() { return channelExpansionId; } @@ -230,6 +250,22 @@ public class OpportunityItemDTO { this.channelExpansionName = channelExpansionName; } + public String getChannelExpansionIntent() { + return channelExpansionIntent; + } + + public void setChannelExpansionIntent(String channelExpansionIntent) { + this.channelExpansionIntent = channelExpansionIntent; + } + + public String getChannelExpansionEstablishedDate() { + return channelExpansionEstablishedDate; + } + + public void setChannelExpansionEstablishedDate(String channelExpansionEstablishedDate) { + this.channelExpansionEstablishedDate = channelExpansionEstablishedDate; + } + public Long getPreSalesId() { return preSalesId; } diff --git a/backend/src/main/java/com/unis/crm/mapper/OpportunityMapper.java b/backend/src/main/java/com/unis/crm/mapper/OpportunityMapper.java index 149b3ad2..7645efd4 100644 --- a/backend/src/main/java/com/unis/crm/mapper/OpportunityMapper.java +++ b/backend/src/main/java/com/unis/crm/mapper/OpportunityMapper.java @@ -36,6 +36,11 @@ public interface OpportunityMapper { @Param("keyword") String keyword, @Param("stage") String stage); + @DataScope(tableAlias = "o", ownerColumn = "owner_user_id") + OpportunityItemDTO selectOpportunityDetail( + @Param("userId") Long userId, + @Param("opportunityId") Long opportunityId); + @DataScope(tableAlias = "o", ownerColumn = "owner_user_id") List selectOpportunityFollowUps( @Param("userId") Long userId, diff --git a/backend/src/main/java/com/unis/crm/service/OpportunityService.java b/backend/src/main/java/com/unis/crm/service/OpportunityService.java index 10ed11dc..6942e3f5 100644 --- a/backend/src/main/java/com/unis/crm/service/OpportunityService.java +++ b/backend/src/main/java/com/unis/crm/service/OpportunityService.java @@ -3,6 +3,7 @@ package com.unis.crm.service; import com.unis.crm.dto.opportunity.CreateOpportunityFollowUpRequest; import com.unis.crm.dto.opportunity.CreateOpportunityRequest; import com.unis.crm.dto.opportunity.OmsPreSalesOptionDTO; +import com.unis.crm.dto.opportunity.OpportunityItemDTO; import com.unis.crm.dto.opportunity.OpportunityMetaDTO; import com.unis.crm.dto.opportunity.OpportunityOverviewDTO; import com.unis.crm.dto.opportunity.PushOpportunityToOmsRequest; @@ -15,6 +16,8 @@ public interface OpportunityService { OpportunityOverviewDTO getOverview(Long userId, String keyword, String stage); + OpportunityItemDTO getDetail(Long userId, Long opportunityId); + List getOmsPreSalesOptions(Long userId); Long createOpportunity(Long userId, CreateOpportunityRequest request); diff --git a/backend/src/main/java/com/unis/crm/service/impl/OpportunityServiceImpl.java b/backend/src/main/java/com/unis/crm/service/impl/OpportunityServiceImpl.java index 6fb0492e..605f3afc 100644 --- a/backend/src/main/java/com/unis/crm/service/impl/OpportunityServiceImpl.java +++ b/backend/src/main/java/com/unis/crm/service/impl/OpportunityServiceImpl.java @@ -91,6 +91,21 @@ public class OpportunityServiceImpl implements OpportunityService { return new OpportunityOverviewDTO(items); } + @Override + public OpportunityItemDTO getDetail(Long userId, Long opportunityId) { + if (opportunityId == null || opportunityId <= 0) { + throw new BusinessException("商机不存在"); + } + + OpportunityItemDTO item = opportunityMapper.selectOpportunityDetail(userId, opportunityId); + if (item == null) { + throw new BusinessException("未找到商机详情"); + } + + attachFollowUps(userId, List.of(item)); + return item; + } + @Override public List getOmsPreSalesOptions(Long userId) { if (userId == null || userId <= 0) { diff --git a/backend/src/main/resources/mapper/opportunity/OpportunityMapper.xml b/backend/src/main/resources/mapper/opportunity/OpportunityMapper.xml index 4f9d9eb8..c483fb5d 100644 --- a/backend/src/main/resources/mapper/opportunity/OpportunityMapper.xml +++ b/backend/src/main/resources/mapper/opportunity/OpportunityMapper.xml @@ -90,8 +90,25 @@ coalesce(o.source, '主动开发') as source, o.sales_expansion_id as salesExpansionId, coalesce(se.candidate_name, '') as salesExpansionName, + case se.intent_level + when 'high' then '高' + when 'medium' then '中' + when 'low' then '低' + else '' + end as salesExpansionIntent, + case + when o.sales_expansion_id is null then null + else (se.employment_status = 'active') + end as salesExpansionActive, o.channel_expansion_id as channelExpansionId, coalesce(ce.channel_name, '') as channelExpansionName, + case ce.intent_level + when 'high' then '高' + when 'medium' then '中' + when 'low' then '低' + else '' + end as channelExpansionIntent, + coalesce(to_char(ce.contact_established_date, 'YYYY-MM-DD'), '') as channelExpansionEstablishedDate, o.pre_sales_id as preSalesId, coalesce(o.pre_sales_name, '') as preSalesName, coalesce(o.competitor_name, '') as competitorName, @@ -177,6 +194,141 @@ order by coalesce(o.updated_at, o.created_at) desc, o.id desc + +