沐梦. před 1 dnem
rodič
revize
24b36b12ae

+ 51 - 25
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/controller/CustomerPoolController.java

@@ -34,7 +34,7 @@ import java.util.List;
 /**
  * 客户公海与有效客户统一控制器
  *
- * @author Antigravity
+ * @author tys
  */
 @Validated
 @RequiredArgsConstructor
@@ -64,41 +64,67 @@ public class CustomerPoolController extends BaseController {
      */
     @GetMapping("/list")
     public TableDataInfo<CustomerListVo> list(CustomerListBo bo, PageQuery pageQuery) {
+        return allList(bo, pageQuery);
+    }
+
+    /**
+     * 我负责的客户列表
+     */
+    @GetMapping("/mineList")
+    public TableDataInfo<CustomerListVo> mineList(CustomerListBo bo, PageQuery pageQuery) {
         Long userId = LoginHelper.getLoginUser().getUserId();
         RemoteComStaffVo remoteComStaffVo = remoteComStaffService.selectStaffByUserId(userId);
         Long staffId = (remoteComStaffVo != null) ? remoteComStaffVo.getStaffId() : null;
 
-        boolean isAdmin = LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin();
-        bo.getParams().put("isAdmin", isAdmin ? "true" : "false");
-        bo.getParams().put("createBy", userId);
+        bo.setSalesPersonId(staffId != null ? staffId : -1L);
+        bo.setServiceStaffId(null);
+        bo.setCreateBy(null);
+        bo.setActiveTab("mine");
+        bo.setIsHighSeas("false");
+        return customerPoolService.queryCustomerListPage(bo, pageQuery);
+    }
 
-        if ("mine".equals(bo.getActiveTab())) {
+    /**
+     * 我参与的客户列表
+     */
+    @GetMapping("/involvedList")
+    public TableDataInfo<CustomerListVo> involvedList(CustomerListBo bo, PageQuery pageQuery) {
+        Long userId = LoginHelper.getLoginUser().getUserId();
+        RemoteComStaffVo remoteComStaffVo = remoteComStaffService.selectStaffByUserId(userId);
+        Long staffId = (remoteComStaffVo != null) ? remoteComStaffVo.getStaffId() : null;
+
+        bo.setServiceStaffId(staffId != null ? staffId : -1L);
+        bo.setSalesPersonId(null);
+        bo.setCreateBy(null);
+        bo.setActiveTab("involved");
+        bo.setIsHighSeas("false");
+        return customerPoolService.queryCustomerListPage(bo, pageQuery);
+    }
+
+    @GetMapping("/allList")
+    public TableDataInfo<CustomerListVo> allList(CustomerListBo bo, PageQuery pageQuery) {
+        // 仅系统超级管理员(userId=1)可看全部客户;
+        // 租户管理员(roleKey=admin)属于普通 CRM 用户,仍需按"我负责+我参与"过滤
+        boolean isAdmin = LoginHelper.isSuperAdmin();
+        if (isAdmin) {
+            bo.setIsAdmin("true");
+        } else {
+            bo.setIsAdmin("false");
+            Long userId = LoginHelper.getLoginUser().getUserId();
+            RemoteComStaffVo remoteComStaffVo = remoteComStaffService.selectStaffByUserId(userId);
+            Long staffId = (remoteComStaffVo != null) ? remoteComStaffVo.getStaffId() : null;
+            // salesPersonId 用 staffId 匹配 ci.sales_person_id(我负责的)和 team_member.user_no(我参与的)
             bo.setSalesPersonId(staffId != null ? staffId : -1L);
             bo.setServiceStaffId(null);
-            bo.setCreateBy(null);
-        } else if ("involved".equals(bo.getActiveTab())) {
-            bo.setServiceStaffId(staffId != null ? staffId : -1L);
-            bo.setSalesPersonId(null);
-            bo.setCreateBy(null);
-        } else {
-            // "all" tab
-            if (isAdmin) {
-                // 管理员在"全部客户"时查看所有数据,不加自己ID的限制
-                bo.setSalesPersonId(null);
-                bo.setServiceStaffId(null);
-                bo.setCreateBy(null);
-            } else {
-                // 普通用户在"全部客户"时仍需要限制查看自己创建的/负责的/参与的
-                bo.setCreateBy(userId);
-                bo.setSalesPersonId(staffId != null ? staffId : -1L);
-                bo.setServiceStaffId(staffId != null ? staffId : -1L);
-            }
         }
-        bo.setIsHighSeas("false"); // 强制为有效客户
-
+        bo.setActiveTab("all");
+        bo.setIsHighSeas("false");
+        bo.setCreateBy(null);
+        bo.getParams().remove("createBy");
         return customerPoolService.queryCustomerListPage(bo, pageQuery);
     }
 
+
     /**
      * 获取客户详细信息
      */

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

@@ -52,4 +52,10 @@ public class CustomerListBo extends BaseEntity {
 
     /** 当前选中的 Tab: mine / involved / all */
     private String activeTab;
+
+    /** 是否为管理员 (true: 是, false: 否) */
+    private String isAdmin;
+
+    /** 当前登录用户的系统 userId(用于 team_member.user_no 匹配,区别于 staffId) */
+    private Long currentUserId;
 }

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

@@ -138,4 +138,7 @@ public class SalesleadsBo extends TenantEntity {
 
     @Schema(description = "成交结果")
     private Integer dealResult;
+
+    @Schema(description = "Tab类型: managed(我负责的) / participated(我参与的) / all(全部)")
+    private String tabType;
 }

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

@@ -111,6 +111,9 @@ public class SalesleadsVo implements Serializable {
     @Schema(description = "状态")
     private String status;
 
+    @Schema(description = "项目状态名称")
+    private String statusName;
+
     @Schema(description = "平台标识")
     private String platformCode;
 

+ 4 - 1
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/vo/TeamMemberVo.java

@@ -30,9 +30,12 @@ public class TeamMemberVo implements Serializable {
     @Schema(description = "对象编号")
     private String objectNo;
 
-    @Schema(description = "用户编号")
+    @Schema(description = "用户编号(实际上是staffId)")
     private Long userNo;
 
+    @Schema(description = "系统用户ID(由关联com_staff得出)")
+    private Long userId;
+
     @Schema(description = "真实姓名")
     private String realName;
 

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

@@ -13,7 +13,7 @@ import java.util.List;
 /**
  * 客户公海与有效客户Service接口
  *
- * @author Antigravity
+ * @author tys
  */
 public interface ICustomerPoolService {
 

+ 5 - 1
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CustomerPoolServiceImpl.java

@@ -25,6 +25,7 @@ import org.dromara.customer.mapper.CrmStaffMapper;
 import org.dromara.customer.service.ICustomerPoolService;
 import org.dromara.customer.service.ICustomerInfoService;
 import org.dromara.system.api.*;
+import org.dromara.system.api.domain.vo.RemoteComStaffVo;
 import org.dromara.system.api.domain.vo.RemoteDictDataVo;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import org.springframework.stereotype.Service;
@@ -36,7 +37,7 @@ import java.util.stream.Collectors;
 /**
  * 客户公海与有效客户Service业务层处理
  *
- * @author Antigravity
+ * @author tys
  */
 @Slf4j
 @RequiredArgsConstructor
@@ -69,6 +70,9 @@ public class CustomerPoolServiceImpl implements ICustomerPoolService {
             bo.setIsHighSeas(isHighSeasObj != null ? String.valueOf(isHighSeasObj) : "false");
         }
 
+        log.info("queryCustomerListPage trace - isHighSeas: {}, activeTab: {}, salesPersonId: {}, serviceStaffId: {}, isAdmin: {}", 
+                 bo.getIsHighSeas(), bo.getActiveTab(), bo.getSalesPersonId(), bo.getServiceStaffId(), bo.getIsAdmin());
+
         Page<CustomerListVo> page = customerPoolMapper.selectCustomerListPage(pageQuery.build(), bo);
         List<CustomerListVo> records = page.getRecords();
 

+ 4 - 6
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/SalesleadsServiceImpl.java

@@ -409,7 +409,7 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
     }
 
     /**
-     * 应用用户权限:只允许查看自己是负责人或者产品支持的项目
+     * 应用用户权限:根据 tabType(我负责的、我参与的、全部)做相应的数据权限过滤
      */
     private void applyUserPermission(SalesleadsBo bo) {
         if (bo == null) {
@@ -417,15 +417,13 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
         }
         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);
-            if (staffVo != null && staffVo.getStaffId() != null) {
-                bo.getParams().put("currentUserId", staffVo.getStaffId());
-            } else {
-                bo.getParams().put("currentUserId", -1L);
-            }
+            bo.getParams().put("tabType", bo.getTabType());
         }
     }
 

+ 33 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/TeamMemberServiceImpl.java

@@ -15,13 +15,20 @@ import org.dromara.customer.mapper.TeamMemberMapper;
 import org.dromara.customer.service.IOperationLogService;
 import org.dromara.customer.service.ITeamMemberService;
 import org.dromara.system.api.RemoteDictService;
+import org.dromara.system.api.RemoteComStaffService;
 import org.dromara.system.api.domain.vo.RemoteDictDataVo;
+import org.dromara.system.api.domain.vo.RemoteComStaffVo;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.Collection;
 import java.util.List;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.Objects;
+import java.util.stream.Collectors;
 
 /**
  * 团队成员 Service 业务层处理
@@ -40,6 +47,9 @@ public class TeamMemberServiceImpl implements ITeamMemberService {
     @DubboReference
     private RemoteDictService remoteDictService;
 
+    @DubboReference
+    private RemoteComStaffService remoteComStaffService;
+
     /**
      * 查询
      */
@@ -47,6 +57,12 @@ public class TeamMemberServiceImpl implements ITeamMemberService {
     public TeamMemberVo queryById(Long id) {
         TeamMemberVo vo = baseMapper.selectVoById(id);
         if (vo != null) {
+            if (vo.getUserNo() != null) {
+                List<RemoteComStaffVo> staffList = remoteComStaffService.selectStaffByIds(Collections.singleton(vo.getUserNo()));
+                if (staffList != null && !staffList.isEmpty()) {
+                    vo.setUserId(staffList.get(0).getUserId());
+                }
+            }
             translateMember(vo);
         }
         return vo;
@@ -59,6 +75,23 @@ public class TeamMemberServiceImpl implements ITeamMemberService {
     public List<TeamMemberVo> queryByObjectNo(String objectNo) {
         List<TeamMemberVo> list = baseMapper.selectByObjectNo(objectNo);
         if (list != null && !list.isEmpty()) {
+            Set<Long> staffIds = list.stream()
+                .map(TeamMemberVo::getUserNo)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+            if (!staffIds.isEmpty()) {
+                List<RemoteComStaffVo> staffList = remoteComStaffService.selectStaffByIds(staffIds);
+                if (staffList != null) {
+                    Map<Long, Long> staffIdToUserIdMap = staffList.stream()
+                        .filter(s -> s.getStaffId() != null && s.getUserId() != null)
+                        .collect(Collectors.toMap(RemoteComStaffVo::getStaffId, RemoteComStaffVo::getUserId, (v1, v2) -> v1));
+                    list.forEach(vo -> {
+                        if (vo.getUserNo() != null) {
+                            vo.setUserId(staffIdToUserIdMap.get(vo.getUserNo()));
+                        }
+                    });
+                }
+            }
             list.forEach(this::translateMember);
         }
         return list;

+ 9 - 9
ruoyi-modules/ruoyi-customer/src/main/resources/mapper/customer/CustomerPoolMapper.xml

@@ -54,19 +54,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                               AND tm.is_delete = 0
                         )
                     </if>
-                    <if test="(bo.activeTab == null or bo.activeTab == 'all' or bo.activeTab == '') and bo.params.isAdmin == 'false'">
+                    <!-- 全部客户:我负责的 OR 我参与的(team_member 中有记录) -->
+                    <if test="bo.activeTab == 'all' and bo.salesPersonId != null and bo.isAdmin != 'true'">
                         AND (
-                            ci.create_by = #{bo.params.createBy}
-                            OR ci.sales_person_id = #{bo.salesPersonId}
-                            OR ci.service_staff_id = #{bo.serviceStaffId}
+                            ci.sales_person_id = #{bo.salesPersonId}
                             OR ci.customer_no IN (
-                                SELECT tm.object_no FROM team_member tm 
-                                WHERE tm.user_no = #{bo.serviceStaffId} 
-                                  AND tm.data_type = 12 
+                                SELECT tm.object_no FROM team_member tm
+                                WHERE tm.user_no = #{bo.salesPersonId}
+                                  AND tm.data_type = 12
                                   AND tm.is_delete = 0
                             )
                         )
                     </if>
+
                 </otherwise>
             </choose>
             <if test="bo.platformCode != null and bo.platformCode != ''">
@@ -84,10 +84,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="bo.customerLevelId != null">
                 AND ci.customer_level_id = #{bo.customerLevelId}
             </if>
-            <if test="bo.salesPersonId != null and bo.activeTab != 'mine' and (bo.activeTab != 'all' or bo.params.isAdmin == 'true')">
+            <if test="bo.salesPersonId != null and bo.activeTab != 'mine' and (bo.activeTab != 'all' or bo.isAdmin == 'true')">
                 AND ci.sales_person_id = #{bo.salesPersonId}
             </if>
-            <if test="bo.serviceStaffId != null and bo.activeTab != 'involved' and (bo.activeTab != 'all' or bo.params.isAdmin == 'true')">
+            <if test="bo.serviceStaffId != null and bo.activeTab != 'involved' and (bo.activeTab != 'all' or bo.isAdmin == 'true')">
                 AND ci.service_staff_id = #{bo.serviceStaffId}
             </if>
             <if test="bo.belongingDepartmentId != null">

+ 31 - 2
ruoyi-modules/ruoyi-customer/src/main/resources/mapper/customer/SalesleadsMapper.xml

@@ -6,7 +6,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="selectSalesleadsList" resultType="org.dromara.customer.domain.vo.SalesleadsVo">
         SELECT s.*, cc.company_name AS companyName, ic.industry_category_name AS industry, d.dept_name AS deptName,
-               CASE sra.dealResult WHEN 1 THEN '赢单' WHEN 2 THEN '丢单' ELSE sra.dealResult END AS dealResult
+               CASE sra.dealResult WHEN 1 THEN '赢单' WHEN 2 THEN '丢单' ELSE sra.dealResult END AS dealResult,
+               CASE s.status WHEN '0' THEN '跟进中' WHEN '1' THEN '结案' ELSE s.status END AS statusName
         FROM salesleads s
         LEFT JOIN sys_company cc ON s.company_no COLLATE utf8mb4_unicode_ci = cc.company_code COLLATE utf8mb4_unicode_ci AND cc.del_flag = '0'
         LEFT JOIN industry_category ic ON s.profession = ic.id AND ic.del_flag = '0'
@@ -49,7 +50,35 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 AND sra.dealResult = #{bo.dealResult}
             </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.params.tabType == 'managed'">
+                        AND s.leader = #{bo.params.currentUserId}
+                    </when>
+                    <when test="bo.params.tabType == 'participated'">
+                        AND s.leader != #{bo.params.currentUserId}
+                        AND (
+                            FIND_IN_SET(#{bo.params.currentUserId}, s.product_support)
+                            OR s.id IN (
+                                SELECT CAST(tm.object_no AS UNSIGNED) FROM team_member tm
+                                WHERE tm.user_no = #{bo.params.currentUserId}
+                                  AND tm.data_type = 1
+                                  AND tm.is_delete = 0
+                            )
+                        )
+                    </when>
+                    <otherwise>
+                        AND (
+                            s.leader = #{bo.params.currentUserId}
+                            OR FIND_IN_SET(#{bo.params.currentUserId}, s.product_support)
+                            OR s.id IN (
+                                SELECT CAST(tm.object_no AS UNSIGNED) FROM team_member tm
+                                WHERE tm.user_no = #{bo.params.currentUserId}
+                                  AND tm.data_type = 1
+                                  AND tm.is_delete = 0
+                            )
+                        )
+                    </otherwise>
+                </choose>
             </if>
             ${bo.params.dataScope}
         </where>

+ 4 - 2
ruoyi-modules/ruoyi-customer/src/main/resources/mapper/customer/TeamMemberMapper.xml

@@ -6,13 +6,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <!-- 按对象编号查询成员列表 -->
     <select id="selectByObjectNo" resultType="org.dromara.customer.domain.vo.TeamMemberVo">
-        SELECT tm.* FROM team_member tm
+        SELECT tm.* 
+        FROM team_member tm
         WHERE tm.object_no = #{objectNo} AND tm.is_delete = 0
         ORDER BY tm.iz_manager DESC, tm.create_time ASC
     </select>
 
     <select id="selectPageByObjectNo" resultType="org.dromara.customer.domain.vo.TeamMemberVo">
-        SELECT tm.* FROM team_member tm
+        SELECT tm.* 
+        FROM team_member tm
         WHERE tm.object_no = #{objectNo} AND tm.is_delete = 0
         ORDER BY tm.iz_manager DESC, tm.create_time ASC
     </select>