沐梦. 13 часов назад
Родитель
Сommit
452f3c099d

+ 6 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/bo/SalesAnnualFinalizationBo.java

@@ -24,6 +24,12 @@ import java.util.List;
 @Schema(description = "年度入围项目业务对象")
 public class SalesAnnualFinalizationBo extends BaseEntity {
 
+    @Schema(description = "时间查询类型")
+    private String timeType;
+
+    @Schema(description = "查询类型:1-我负责的,2-我参与的")
+    private Integer queryType;
+
     /**
      * 主键ID
      */

+ 10 - 1
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/bo/SalesleadsBo.java

@@ -23,6 +23,9 @@ import java.util.List;
 @AutoMapper(target = Salesleads.class, reverseConvertGenerate = false)
 public class SalesleadsBo extends TenantEntity {
 
+    @Schema(description = "时间查询类型")
+    private String timeType;
+
     @Schema(description = "主键ID")
     private Long id;
 
@@ -133,9 +136,15 @@ public class SalesleadsBo extends TenantEntity {
     @Schema(description = "批量操作ID列表")
     private List<Long> ids;
 
-    @Schema(description = "保留已有项目负责人(认领时使用)")
+    @Schema(description = "保留已有业务负责人(认领时使用)")
     private Boolean keepOldManager;
 
+    @Schema(description = "保留已有业务负责人为团队成员(转移线索时使用)")
+    private Boolean keepAsTeamMember;
+
+    @Schema(description = "保留已有业务负责人为团队成员(转移商机时使用)")
+    private Integer keepOldOwner;
+
     @Schema(description = "成交结果")
     private Integer dealResult;
 

+ 3 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/bo/TeamMemberBo.java

@@ -63,4 +63,7 @@ public class TeamMemberBo {
 
     /** 平台标识 */
     private String platformCode;
+
+    /** 是否系统同步:系统同步时不需要校验角色编辑权限 */
+    private Boolean isSystemSync;
 }

+ 1 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/vo/SalesleadsVo.java

@@ -1,5 +1,6 @@
 package org.dromara.customer.domain.vo;
 
+import cn.idev.excel.annotation.ExcelProperty;
 import io.github.linpeilie.annotations.AutoMapper;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;

+ 1 - 1
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/ISalesleadsService.java

@@ -47,7 +47,7 @@ public interface ISalesleadsService {
     Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
 
     /**
-     * 认领销售线索(设置项目负责人)
+     * 认领销售线索(设置业务负责人)
      */
     Boolean claimLeads(SalesleadsBo bo);
 

+ 8 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CrmVisitPlanServiceImpl.java

@@ -21,6 +21,7 @@ import org.dromara.customer.service.ICrmVisitPlanService;
 import org.dromara.customer.service.ICrmVisitRoutineService;
 import org.dromara.customer.service.ITeamMemberService;
 import org.dromara.customer.service.IOperationLogService;
+import org.dromara.common.satoken.utils.LoginHelper;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -65,6 +66,13 @@ public class CrmVisitPlanServiceImpl implements ICrmVisitPlanService {
 
     private LambdaQueryWrapper<VisitPlan> buildQueryWrapper(CrmVisitPlanBo bo) {
         LambdaQueryWrapper<VisitPlan> lqw = Wrappers.lambdaQuery();
+        
+        // 数据权限过滤:当前登录用户只能看见自己新增的数据
+        Long userId = LoginHelper.getUserId();
+        if (userId != null && !LoginHelper.isSuperAdmin(userId)) {
+            lqw.eq(VisitPlan::getCreateBy, userId);
+        }
+
         lqw.like(StringUtils.isNotBlank(bo.getPlanNo()), VisitPlan::getPlanNo, bo.getPlanNo());
         lqw.eq(bo.getVisitorId() != null, VisitPlan::getVisitorId, bo.getVisitorId());
         lqw.like(StringUtils.isNotBlank(bo.getVisitorName()), VisitPlan::getVisitorName, bo.getVisitorName());

+ 41 - 2
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CustomerCareServiceImpl.java

@@ -22,6 +22,9 @@ import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import cn.hutool.core.date.DateUtil;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.system.api.RemoteComStaffService;
+import org.dromara.system.api.domain.vo.RemoteComStaffVo;
 
 /**
  * 客户关怀Service业务层处理
@@ -36,6 +39,9 @@ public class CustomerCareServiceImpl implements ICustomerCareService {
     private final CustomerCareMapper baseMapper;
     private final IOperationLogService operationLogService;
 
+    @DubboReference
+    private RemoteComStaffService remoteComStaffService;
+
     /**
      * 查询客户关怀
      */
@@ -72,13 +78,46 @@ public class CustomerCareServiceImpl implements ICustomerCareService {
         lqw.eq(StringUtils.isNotBlank(bo.getConcernType()), CustomerCare::getConcernType, bo.getConcernType());
         lqw.eq(bo.getAuditStatus() != null, CustomerCare::getAuditStatus, bo.getAuditStatus());
         lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), CustomerCare::getPlatformCode, bo.getPlatformCode());
-        if ("mine".equals(bo.getScope())) {
-            lqw.eq(CustomerCare::getCreateBy, LoginHelper.getUserId());
+        applyUserPermission(bo);
+        if (bo.getParams() != null && Boolean.TRUE.equals(bo.getParams().get("restrictToUser"))) {
+            String staffName = (String) bo.getParams().get("staffName");
+            if (StringUtils.isBlank(staffName)) {
+                staffName = "-1"; // 如果当前用户没有绑定员工,则强制查不到数据
+            }
+            lqw.eq(CustomerCare::getSalesman, staffName);
         }
         lqw.orderByDesc(CustomerCare::getId);
         return lqw;
     }
 
+    /**
+     * 应用用户权限:根据 scope(mine、all)做相应的数据权限过滤
+     */
+    private void applyUserPermission(CustomerCareBo bo) {
+        if (bo == null) {
+            return;
+        }
+        boolean isSuperAdmin = LoginHelper.isSuperAdmin();
+        String scope = bo.getScope();
+
+        // 如果是超级管理员,并且选择的是“全部”,则不加任何限制
+        if (isSuperAdmin && (scope == null || "all".equals(scope) || scope.isEmpty())) {
+            return;
+        }
+
+        RemoteComStaffVo staffVo = remoteComStaffService.selectStaffByUserId(LoginHelper.getUserId());
+        Long staffId = (staffVo != null && staffVo.getStaffId() != null) ? staffVo.getStaffId() : -1L;
+        String staffName = (staffVo != null && staffVo.getStaffName() != null) ? staffVo.getStaffName() : "";
+
+        if (bo.getParams() == null) {
+            bo.setParams(new java.util.HashMap<>());
+        }
+        bo.getParams().put("currentUserId", staffId);
+        bo.getParams().put("staffName", staffName);
+        bo.getParams().put("restrictToUser", true);
+        bo.getParams().put("scope", scope);
+    }
+
     /**
      * 新增客户关怀
      */

+ 17 - 12
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/SalesAnnualFinalizationServiceImpl.java

@@ -375,18 +375,23 @@ public class SalesAnnualFinalizationServiceImpl implements ISalesAnnualFinalizat
         if (bo == null) {
             return;
         }
-        if (!LoginHelper.isSuperAdmin()) {
-            RemoteComStaffVo staffVo = remoteComStaffService.selectStaffByUserId(LoginHelper.getUserId());
-            if (bo.getParams() == null) {
-                bo.setParams(new java.util.HashMap<>());
-            }
-            bo.getParams().put("restrictToUser", true);
-            if (staffVo != null && staffVo.getStaffId() != null) {
-                bo.getParams().put("currentUserId", staffVo.getStaffId());
-            } else {
-                bo.getParams().put("currentUserId", -1L);
-            }
+        boolean isSuperAdmin = LoginHelper.isSuperAdmin();
+        Integer queryType = bo.getQueryType();
+
+        // 如果是超级管理员且未指定查询类型(不是“我负责的”也不是“我参与的”),则不限制
+        if (isSuperAdmin && queryType == null) {
+            return;
         }
-    }
 
+        RemoteComStaffVo staffVo = remoteComStaffService.selectStaffByUserId(LoginHelper.getUserId());
+        if (bo.getParams() == null) {
+            bo.setParams(new java.util.HashMap<>());
+        }
+        bo.getParams().put("restrictToUser", true);
+        if (staffVo != null && staffVo.getStaffId() != null) {
+            bo.getParams().put("currentUserId", staffVo.getStaffId());
+        } else {
+            bo.getParams().put("currentUserId", -1L);
+        }
+    }
 }

+ 40 - 12
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/SalesleadsServiceImpl.java

@@ -96,6 +96,9 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
         if (add.getProjectType() == null || add.getProjectType().isEmpty()) {
             add.setProjectType(CustomerConstants.PROJECT_TYPE_LEADS);
         }
+        if (add.getStatus() == null || add.getStatus().isEmpty()) {
+            add.setStatus("0");
+        }
         boolean success = baseMapper.insert(add) > 0;
         if (success) {
             // 确保主键已回填
@@ -175,7 +178,7 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
     }
 
     /**
-     * 认领销售线索 - 设置项目负责人(支持批量)
+     * 认领销售线索 - 设置业务负责人(支持批量)
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -202,7 +205,7 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
             if (success) {
                 // 处理原负责人逻辑
                 if (oldData != null && oldData.getLeader() != null && !oldData.getLeader().equals(bo.getLeader())) {
-                    if (Boolean.TRUE.equals(bo.getKeepOldManager())) {
+                    if (isKeepOldManager(bo)) {
                         // 保留:将原负责人降级为普通团队成员
                         demoteLeaderToMember(id, oldData.getLeader(), oldData.getLeaderName());
                     } else {
@@ -249,6 +252,25 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
         teamMemberService.insertOrUpdateMember(memberBo);
     }
 
+    /**
+     * 判断是否需要保留原负责人为团队成员
+     */
+    private boolean isKeepOldManager(SalesleadsBo bo) {
+        if (bo == null) {
+            return false;
+        }
+        if (Boolean.TRUE.equals(bo.getKeepOldManager())) {
+            return true;
+        }
+        if (Boolean.TRUE.equals(bo.getKeepAsTeamMember())) {
+            return true;
+        }
+        if (bo.getKeepOldOwner() != null && bo.getKeepOldOwner() == 1) {
+            return true;
+        }
+        return false;
+    }
+
     /**
      * 转移销售线索 - 更换负责人(支持批量)
      */
@@ -272,7 +294,7 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
             if (success) {
                 // 处理原负责人逻辑
                 if (oldData != null && oldData.getLeader() != null && !oldData.getLeader().equals(bo.getLeader())) {
-                    if (Boolean.TRUE.equals(bo.getKeepOldManager())) {
+                    if (isKeepOldManager(bo)) {
                         // 保留:将原负责人降级为普通团队成员
                         demoteLeaderToMember(id, oldData.getLeader(), oldData.getLeaderName());
                     } else {
@@ -415,16 +437,22 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
         if (bo == null) {
             return;
         }
-        if (!LoginHelper.isSuperAdmin()) {
-            RemoteComStaffVo staffVo = remoteComStaffService.selectStaffByUserId(LoginHelper.getUserId());
-            Long staffId = (staffVo != null && staffVo.getStaffId() != null) ? staffVo.getStaffId() : -1L;
-            if (bo.getParams() == null) {
-                bo.setParams(new java.util.HashMap<>());
-            }
-            bo.getParams().put("currentUserId", staffId);
-            bo.getParams().put("restrictToUser", true);
-            bo.getParams().put("tabType", bo.getTabType());
+        boolean isSuperAdmin = LoginHelper.isSuperAdmin();
+        String tabType = bo.getTabType();
+
+        // 如果是超级管理员,并且没有指定特定选项卡过滤,则不加任何限制
+        if (isSuperAdmin && (tabType == null || "all".equals(tabType) || tabType.isEmpty())) {
+            return;
+        }
+
+        RemoteComStaffVo staffVo = remoteComStaffService.selectStaffByUserId(LoginHelper.getUserId());
+        Long staffId = (staffVo != null && staffVo.getStaffId() != null) ? staffVo.getStaffId() : -1L;
+        if (bo.getParams() == null) {
+            bo.setParams(new java.util.HashMap<>());
         }
+        bo.getParams().put("currentUserId", staffId);
+        bo.getParams().put("restrictToUser", true);
+        bo.getParams().put("tabType", tabType);
     }
 
 }

+ 7 - 6
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/TeamMemberServiceImpl.java

@@ -191,16 +191,16 @@ public class TeamMemberServiceImpl implements ITeamMemberService {
                 }
             }
         }
-        if (bo.getId() != null) {
+        if (bo.getId() != null && !Boolean.TRUE.equals(bo.getIsSystemSync())) {
             TeamMemberVo member = baseMapper.selectVoById(bo.getId());
             if (member != null) {
                 if (Integer.valueOf(12).equals(member.getDataType())) {
                     if ("1".equals(member.getRoleCode()) || "B0001".equals(member.getRoleCode()) || "3".equals(member.getRoleCode())) {
-                        throw new ServiceException("业务负责人和客服支持是不可编辑的");
+                        throw new ServiceException("业务负责人、产品支持和客服支持是不可编辑的");
                     }
                 } else if (Integer.valueOf(1).equals(member.getDataType()) || Integer.valueOf(2).equals(member.getDataType())) {
                     if ("1".equals(member.getRoleCode()) || "3".equals(member.getRoleCode())) {
-                        throw new ServiceException("项目负责人、产品支持和客服支持是不可编辑的");
+                        throw new ServiceException("业务负责人、产品支持和客服支持是不可编辑的");
                     }
                 }
             }
@@ -228,11 +228,11 @@ public class TeamMemberServiceImpl implements ITeamMemberService {
             for (TeamMemberVo member : members) {
                 if (Integer.valueOf(12).equals(member.getDataType())) {
                     if ("1".equals(member.getRoleCode()) || "B0001".equals(member.getRoleCode()) || "3".equals(member.getRoleCode())) {
-                        throw new ServiceException("业务负责人和客服支持是不可删除的");
+                        throw new ServiceException("业务负责人、产品支持和客服支持是不可删除的");
                     }
                 } else if (Integer.valueOf(1).equals(member.getDataType()) || Integer.valueOf(2).equals(member.getDataType())) {
                     if ("1".equals(member.getRoleCode()) || "3".equals(member.getRoleCode())) {
-                        throw new ServiceException("项目负责人、产品支持和客服支持是不可删除的");
+                        throw new ServiceException("业务负责人、产品支持和客服支持是不可删除的");
                     }
                 }
             }
@@ -277,6 +277,7 @@ public class TeamMemberServiceImpl implements ITeamMemberService {
         if (existing != null) {
             // 已存在,更新
             bo.setId(existing.getId());
+            bo.setIsSystemSync(true);
             return updateMember(bo);
         } else {
             // 不存在,新增
@@ -291,7 +292,7 @@ public class TeamMemberServiceImpl implements ITeamMemberService {
         if (existing != null) {
             if (Integer.valueOf(12).equals(existing.getDataType())) {
                 if ("1".equals(existing.getRoleCode()) || "B0001".equals(existing.getRoleCode()) || "3".equals(existing.getRoleCode())) {
-                    throw new ServiceException("业务负责人和客服支持是不可删除的");
+                    throw new ServiceException("业务负责人、产品支持和客服支持是不可删除的");
                 }
             }
             boolean flag = baseMapper.deleteById(existing.getId()) > 0;

+ 38 - 1
ruoyi-modules/ruoyi-customer/src/main/resources/mapper/customer/SalesAnnualFinalizationMapper.xml

@@ -52,7 +52,44 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 )
             </if>
             <if test="bo.params.restrictToUser == true">
-                AND (s.leader = #{bo.params.currentUserId} OR FIND_IN_SET(#{bo.params.currentUserId}, s.product_support) > 0)
+                <choose>
+                    <when test="bo.queryType == 1">
+                        AND s.leader = #{bo.params.currentUserId}
+                    </when>
+                    <when test="bo.queryType == 2">
+                        AND s.leader != #{bo.params.currentUserId}
+                        AND FIND_IN_SET(#{bo.params.currentUserId}, s.product_support) > 0
+                    </when>
+                    <otherwise>
+                        AND (s.leader = #{bo.params.currentUserId} OR FIND_IN_SET(#{bo.params.currentUserId}, s.product_support) > 0)
+                    </otherwise>
+                </choose>
+            </if>
+            <if test="bo.params.beginTime != null and bo.params.beginTime != ''">
+                <choose>
+                    <when test="bo.timeType == '2' or bo.timeType == 2">
+                        AND date_format(s.sign_up_deadline,'%Y-%m-%d') &gt;= #{bo.params.beginTime}
+                    </when>
+                    <when test="bo.timeType == '3' or bo.timeType == 3">
+                        AND date_format(s.tender_deadline,'%Y-%m-%d') &gt;= #{bo.params.beginTime}
+                    </when>
+                    <otherwise>
+                        AND date_format(s.create_time,'%Y-%m-%d') &gt;= #{bo.params.beginTime}
+                    </otherwise>
+                </choose>
+            </if>
+            <if test="bo.params.endTime != null and bo.params.endTime != ''">
+                <choose>
+                    <when test="bo.timeType == '2' or bo.timeType == 2">
+                        AND date_format(s.sign_up_deadline,'%Y-%m-%d') &lt;= #{bo.params.endTime}
+                    </when>
+                    <when test="bo.timeType == '3' or bo.timeType == 3">
+                        AND date_format(s.tender_deadline,'%Y-%m-%d') &lt;= #{bo.params.endTime}
+                    </when>
+                    <otherwise>
+                        AND date_format(s.create_time,'%Y-%m-%d') &lt;= #{bo.params.endTime}
+                    </otherwise>
+                </choose>
             </if>
             ${bo.params.dataScope}
         </where>

+ 26 - 0
ruoyi-modules/ruoyi-customer/src/main/resources/mapper/customer/SalesleadsMapper.xml

@@ -80,6 +80,32 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                     </otherwise>
                 </choose>
             </if>
+            <if test="bo.params.beginTime != null and bo.params.beginTime != ''">
+                <choose>
+                    <when test="bo.timeType == '2'">
+                        AND date_format(s.approval_date,'%Y-%m-%d') &gt;= #{bo.params.beginTime}
+                    </when>
+                    <when test="bo.timeType == '3'">
+                        AND date_format(s.expected_completion_time,'%Y-%m-%d') &gt;= #{bo.params.beginTime}
+                    </when>
+                    <otherwise>
+                        AND date_format(s.create_time,'%Y-%m-%d') &gt;= #{bo.params.beginTime}
+                    </otherwise>
+                </choose>
+            </if>
+            <if test="bo.params.endTime != null and bo.params.endTime != ''">
+                <choose>
+                    <when test="bo.timeType == '2'">
+                        AND date_format(s.approval_date,'%Y-%m-%d') &lt;= #{bo.params.endTime}
+                    </when>
+                    <when test="bo.timeType == '3'">
+                        AND date_format(s.expected_completion_time,'%Y-%m-%d') &lt;= #{bo.params.endTime}
+                    </when>
+                    <otherwise>
+                        AND date_format(s.create_time,'%Y-%m-%d') &lt;= #{bo.params.endTime}
+                    </otherwise>
+                </choose>
+            </if>
             ${bo.params.dataScope}
         </where>
         ORDER BY create_time DESC