Sfoglia il codice sorgente

修复权限问题

沐梦. 3 giorni fa
parent
commit
85396c19a4

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

@@ -114,6 +114,9 @@ public class SalesleadsBo extends TenantEntity {
     @Schema(description = "产品支持")
     private String productSupport;
 
+    @Schema(description = "产品支持姓名")
+    private String productSupportName;
+
 
     @Schema(description = "项目进度")
     private String projectSchedule;

+ 113 - 63
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CustomerInfoServiceImpl.java

@@ -329,22 +329,12 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
                 vo.setCreateByName(name);
             }
             if (vo.getUpdateBy() != null) {
-                String name = userMap.get(Long.parseLong(vo.getUpdateBy()));
-                if (name == null && "-1".equals(vo.getUpdateBy())) name = "系统";
-                vo.setUpdateByName(name);
+                vo.setUpdateByName(userMap.get(Long.parseLong(vo.getUpdateBy())));
             }
         }
-
         return vo;
     }
 
-    /**
-     * 分页查询客户信息列表
-     *
-     * @param bo        查询条件
-     * @param pageQuery 分页参数
-     * @return 客户信息分页列表
-     */
     @Override
     public TableDataInfo<CustomerInfoVo> queryPageList(CustomerInfoBo bo, PageQuery pageQuery) {
         LambdaQueryWrapper<CustomerInfo> lqw = buildQueryWrapper(bo);
@@ -369,7 +359,11 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
                     IndustryCategoryVo::getIndustryCategoryName,
                     (e, r) -> e
                 ));
-            records.forEach(vo -> vo.setIndustryCategory(industryMap.get(vo.getIndustryCategoryId())));
+            records.forEach(vo -> {
+                String name = industryMap.get(vo.getIndustryCategoryId());
+                vo.setIndustryCategory(name);
+                vo.setIndustryName(name);
+            });
         }
 
         // === 2. 提取客户ID,查询销售信息 ===
@@ -383,22 +377,12 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
             .filter(Objects::nonNull)
             .collect(Collectors.toCollection(() -> new HashSet<>(records.size())));
 
-        if (infoIds.isEmpty()) {
-            return TableDataInfo.build(result);
-        }
-
-        if (companyIds.isEmpty()) {
-            return TableDataInfo.build(result);
-        }
-
-        List<CustomerSalesInfoVo> salesInfoVos = customerSalesInfoMapper.selectVoList(
-            new LambdaQueryWrapper<CustomerSalesInfo>()
-                .in(CustomerSalesInfo::getCustomerId, infoIds)
-        );
-
-        if (CollUtil.isEmpty(salesInfoVos)) {
-            // 即使没有销售信息,也要返回客户列表(只是销售字段为空)
-            return TableDataInfo.build(result);
+        List<CustomerSalesInfoVo> salesInfoVos = Collections.emptyList();
+        if (!infoIds.isEmpty()) {
+            salesInfoVos = customerSalesInfoMapper.selectVoList(
+                new LambdaQueryWrapper<CustomerSalesInfo>()
+                    .in(CustomerSalesInfo::getCustomerId, infoIds)
+            );
         }
 
         // === 3. 构建 customerId -> CustomerSalesInfoVo 映射
@@ -406,7 +390,7 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
             .collect(Collectors.toMap(
                 CustomerSalesInfoVo::getCustomerId,
                 Function.identity(),
-                (existing, replacement) -> existing // 若有重复,保留第一个
+                (existing, replacement) -> existing
             ));
 
         // === 4. 收集人员和部门ID ===
@@ -431,36 +415,82 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
             ? Collections.emptyMap()
             : remoteErpDeptService.selectDeptNameByIds(deptIds);
 
-        // === 6. 回填人员和部门名称到 salesInfoVo ===
         for (CustomerSalesInfoVo vo : salesInfoVos) {
             vo.setSalesPerson(staffMap.get(vo.getSalesPersonId()));
             vo.setServiceStaff(staffMap.get(vo.getServiceStaffId()));
             vo.setBelongingDepartment(deptMap.get(vo.getBelongingDepartmentId()));
         }
-        //系统人员与部门
+
+        // 系统人员与部门,以及客户等级
         Set<Long> comStaffIds = new HashSet<>();
         Set<Long> comDeptIds = new HashSet<>();
+        Set<Long> customerLevelIds = new HashSet<>();
 
         for (CustomerInfoVo vo : records) {
             if (vo.getSalesPersonId() != null) comStaffIds.add(vo.getSalesPersonId());
             if (vo.getServiceStaffId() != null) comStaffIds.add(vo.getServiceStaffId());
             if (vo.getBelongingDepartmentId() != null) comDeptIds.add(vo.getBelongingDepartmentId());
+            if (vo.getCustomerLevelId() != null) customerLevelIds.add(vo.getCustomerLevelId());
         }
 
         // === 远程调用获取名称 ===
-        Map<Long, String> comStaffMap = staffIds.isEmpty()
-            ? Collections.emptyMap()
-            : remoteComStaffService.selectStaffNameByIds(comStaffIds);
+        List<RemoteComStaffVo> comStaffList = comStaffIds.isEmpty()
+            ? Collections.emptyList()
+            : remoteComStaffService.selectStaffByIds(comStaffIds);
+        Map<Long, RemoteComStaffVo> comStaffMap = comStaffList.stream()
+            .collect(Collectors.toMap(RemoteComStaffVo::getStaffId, Function.identity(), (v1, v2) -> v1));
 
-        Map<Long, String> comDeptMap = deptIds.isEmpty()
+        Map<Long, String> comDeptMap = comDeptIds.isEmpty()
             ? Collections.emptyMap()
             : remoteDeptService.selectDeptNameByIds(comDeptIds);
 
-        // === 回填系统人员和部门名称到 customerInfoVo ===
+        Map<Long, String> customerLevelMap = customerLevelIds.isEmpty()
+            ? Collections.emptyMap()
+            : remoteComCustomerLevelService.selectCustomerLevelNameByIds(customerLevelIds);
+
+        // 字典翻译
+        List<RemoteDictDataVo> enterpriseTypeDicts = remoteDictService.selectDictDataByType("enterprise_type");
+        Map<String, String> enterpriseTypeMap = enterpriseTypeDicts == null ? Collections.emptyMap() : enterpriseTypeDicts.stream()
+            .collect(Collectors.toMap(RemoteDictDataVo::getDictValue, RemoteDictDataVo::getDictLabel, (k1, k2) -> k1));
+        List<RemoteDictDataVo> q0001Dicts = remoteDictService.selectDictDataByType("Q0001");
+        Map<String, String> q0001Map = q0001Dicts == null ? Collections.emptyMap() : q0001Dicts.stream()
+            .collect(Collectors.toMap(RemoteDictDataVo::getDictValue, RemoteDictDataVo::getDictLabel, (k1, k2) -> k1));
+
+        List<RemoteDictDataVo> cooperationDicts = remoteDictService.selectDictDataByType("cooperation_status");
+        Map<String, String> cooperationMap = cooperationDicts == null ? Collections.emptyMap() : cooperationDicts.stream()
+            .collect(Collectors.toMap(RemoteDictDataVo::getDictValue, RemoteDictDataVo::getDictLabel, (k1, k2) -> k1));
+
+        // === 回填系统人员、部门名称、企业类型、等级、合作状态到 customerInfoVo ===
         records.forEach(v -> {
-            v.setSalesPersonName(comStaffMap.get(v.getSalesPersonId()));
-            v.setServiceStaffName(comStaffMap.get(v.getServiceStaffId()));
-            v.setBelongingDepartmentName(comDeptMap.get(v.getBelongingDepartmentId()));
+            RemoteComStaffVo salesPerson = comStaffMap.get(v.getSalesPersonId());
+            RemoteComStaffVo serviceStaff = comStaffMap.get(v.getServiceStaffId());
+
+            if (salesPerson != null) {
+                v.setSalesPersonName(salesPerson.getStaffName());
+                v.setDeptName(salesPerson.getDeptName());
+            }
+            if (serviceStaff != null) {
+                v.setServiceStaffName(serviceStaff.getStaffName());
+            }
+
+            String dName = comDeptMap.get(v.getBelongingDepartmentId());
+            v.setBelongingDepartmentName(dName);
+            if (v.getDeptName() == null) {
+                v.setDeptName(dName);
+            }
+
+            v.setCustomerLevelName(customerLevelMap.get(v.getCustomerLevelId()));
+
+            String typeValue = v.getCustomerTypeId() != null ? String.valueOf(v.getCustomerTypeId()) : null;
+            if (typeValue != null) {
+                String typeName = enterpriseTypeMap.get(typeValue);
+                if (typeName == null) {
+                    typeName = q0001Map.get(typeValue);
+                }
+                v.setEnterpriseTypeName(typeName);
+            }
+
+            v.setCooperationName(cooperationMap.get(v.getStatus()));
         });
 
         // === 7. 将销售信息回填到客户VO ===
@@ -1730,37 +1760,57 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
         customer.setStatus("0"); // 认领成功后,将客户主表状态改为有效
         boolean updated = baseMapper.updateById(customer) > 0;
 
-        if (updated && claimBo.getSalesPersonId() != null) {
+        if (updated) {
             // 2. 将业务员加入团队成员
-            // 检查是否已在团队中
-            Long count = teamMemberMapper.selectCount(new LambdaQueryWrapper<TeamMember>()
-                .eq(TeamMember::getDataType, 12)
-                .eq(TeamMember::getObjectNo, customer.getCustomerNo())
-                .eq(TeamMember::getUserNo, claimBo.getSalesPersonId()));
-
-            if (count == 0) {
-                TeamMember member = new TeamMember();
-                member.setDataType(12); // 客户类型
-                member.setObjectNo(customer.getCustomerNo());
-                member.setUserNo(claimBo.getSalesPersonId());
-                member.setRoleCode("B0001"); // 业务负责人
-                member.setIzManager(1);
-                member.setUpdateAccredit(1);
-                member.setPlatformCode(PlatformContext.getPlatform());
-
-                // 获取真实姓名:直接从业务人员表获取
-                CrmStaff staff = crmStaffMapper.selectById(claimBo.getSalesPersonId());
-                if (staff != null) {
-                    member.setRealName(staff.getStaffName());
-                }
-
-                teamMemberMapper.insert(member);
+            if (claimBo.getSalesPersonId() != null) {
+                saveOrUpdateTeamMember(customer.getCustomerNo(), claimBo.getSalesPersonId(), "B0001", 1, 1);
+            }
+            // 3. 将客服支持加入团队成员
+            if (claimBo.getServiceStaffId() != null) {
+                saveOrUpdateTeamMember(customer.getCustomerNo(), claimBo.getServiceStaffId(), "3", 0, 0);
             }
         }
 
         return updated;
     }
 
+    private void saveOrUpdateTeamMember(String objectNo, Long userNo, String roleCode, Integer izManager, Integer updateAccredit) {
+        TeamMemberVo existing = teamMemberMapper.selectByObjectNoAndUserNoWithDeleted(objectNo, userNo);
+        String realName = "";
+        CrmStaff staff = crmStaffMapper.selectById(userNo);
+        if (staff != null) {
+            realName = staff.getStaffName();
+        }
+
+        if (existing != null) {
+            teamMemberMapper.restoreMemberById(
+                existing.getId(),
+                userNo,
+                realName,
+                roleCode,
+                updateAccredit,
+                izManager,
+                LoginHelper.getUserId(),
+                LoginHelper.getDeptId(),
+                PlatformContext.getPlatform()
+            );
+        } else {
+            TeamMember member = new TeamMember();
+            member.setDataType(12); 
+            member.setObjectNo(objectNo);
+            member.setUserNo(userNo);
+            member.setRealName(realName);
+            member.setRoleCode(roleCode);
+            member.setIzManager(izManager);
+            member.setUpdateAccredit(updateAccredit);
+            member.setPlatformCode(PlatformContext.getPlatform());
+            member.setCreateUserId(LoginHelper.getUserId());
+            member.setCreateOrgId(LoginHelper.getDeptId());
+            member.setIsDelete(0);
+            teamMemberMapper.insert(member);
+        }
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int releaseToPool(List<Long> customerIds, String reason) {

+ 114 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/SalesAnnualFinalizationServiceImpl.java

@@ -25,9 +25,12 @@ import org.dromara.customer.service.ITeamMemberService;
 import org.dromara.customer.service.ISalesAnnualFinalizationService;
 import org.dromara.customer.controller.constant.CustomerConstants;
 import org.dromara.system.api.RemoteUserService;
+import org.dromara.system.api.RemoteComStaffService;
 import org.dromara.system.api.domain.vo.RemoteUserVo;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.api.domain.vo.RemoteComStaffVo;
 
 
 import java.time.Duration;
@@ -55,11 +58,15 @@ public class SalesAnnualFinalizationServiceImpl implements ISalesAnnualFinalizat
     @DubboReference
     private RemoteUserService remoteUserService;
 
+    @DubboReference
+    private RemoteComStaffService remoteComStaffService;
+
     /**
      * 查询年度入围项目列表
      */
     @Override
     public TableDataInfo<SalesAnnualFinalizationVo> queryPageList(SalesAnnualFinalizationBo bo, PageQuery pageQuery) {
+        applyUserPermission(bo);
         IPage<SalesAnnualFinalizationVo> result = baseMapper.selectSalesAnnualFinalizationList(pageQuery.build(), bo);
         return TableDataInfo.build(result);
     }
@@ -69,6 +76,7 @@ public class SalesAnnualFinalizationServiceImpl implements ISalesAnnualFinalizat
      */
     @Override
     public List<SalesAnnualFinalizationVo> queryList(SalesAnnualFinalizationBo bo) {
+        applyUserPermission(bo);
         return baseMapper.selectSalesAnnualFinalizationList(bo);
     }
 
@@ -143,6 +151,11 @@ public class SalesAnnualFinalizationServiceImpl implements ISalesAnnualFinalizat
                 memberBo.setIzManager(1);
                 teamMemberService.insertOrUpdateMember(memberBo);
             }
+
+            // 同步产品支持到团队成员表
+            if (add.getProductSupport() != null && !add.getProductSupport().isEmpty()) {
+                syncProductSupportToTeamMember(add.getId(), logDataType, add.getProductSupport());
+            }
         }
         return flag;
     }
@@ -181,6 +194,20 @@ public class SalesAnnualFinalizationServiceImpl implements ISalesAnnualFinalizat
                 memberBo.setIzManager(1);
                 teamMemberService.insertOrUpdateMember(memberBo);
             }
+
+            // 同步产品支持到团队成员表
+            if (update.getProductSupport() != null && !update.getProductSupport().isEmpty()) {
+                if (oldData == null || !ObjectUtil.equals(oldData.getProductSupport(), update.getProductSupport())) {
+                    if (oldData != null && oldData.getProductSupport() != null && !oldData.getProductSupport().isEmpty()) {
+                        removeProductSupportFromTeamMember(update.getId(), logDataType, oldData.getProductSupport());
+                    }
+                    syncProductSupportToTeamMember(update.getId(), logDataType, update.getProductSupport());
+                }
+            } else {
+                if (oldData != null && oldData.getProductSupport() != null && !oldData.getProductSupport().isEmpty()) {
+                    removeProductSupportFromTeamMember(update.getId(), logDataType, oldData.getProductSupport());
+                }
+            }
         }
         return flag;
     }
@@ -275,4 +302,91 @@ public class SalesAnnualFinalizationServiceImpl implements ISalesAnnualFinalizat
         }
         return result;
     }
+
+    /**
+     * 安全转换 Long
+     */
+    private Long tryParseLong(String val) {
+        if (val == null) {
+            return null;
+        }
+        try {
+            return Long.valueOf(val.trim());
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 从团队成员中安全移除产品支持
+     */
+    private void removeProductSupportFromTeamMember(Long objectNo, Integer dataType, String productSupport) {
+        if (productSupport == null || productSupport.isEmpty()) {
+            return;
+        }
+        String[] supportIdStrArray = productSupport.split(",");
+        for (String idStr : supportIdStrArray) {
+            Long id = tryParseLong(idStr);
+            if (id != null) {
+                teamMemberService.removeMember(dataType, String.valueOf(objectNo), id);
+            }
+        }
+    }
+
+    /**
+     * 同步产品支持到团队成员表(适配逗号分隔的多值)
+     */
+    private void syncProductSupportToTeamMember(Long objectNo, Integer dataType, String productSupport) {
+        if (productSupport == null || productSupport.isEmpty()) {
+            return;
+        }
+        String[] supportIdStrArray = productSupport.split(",");
+        java.util.Set<Long> supportIds = new java.util.HashSet<>();
+        for (String idStr : supportIdStrArray) {
+            Long id = tryParseLong(idStr);
+            if (id != null) {
+                supportIds.add(id);
+            }
+        }
+        if (supportIds.isEmpty()) {
+            return;
+        }
+
+        Map<Long, String> nameMap = remoteComStaffService.selectStaffNameByIds(supportIds);
+
+        for (Long id : supportIds) {
+            String realName = nameMap != null ? nameMap.get(id) : null;
+            TeamMemberBo memberBo = new TeamMemberBo();
+            memberBo.setDataType(dataType);
+            memberBo.setObjectNo(String.valueOf(objectNo));
+            memberBo.setUserNo(id);
+            memberBo.setRealName(realName);
+            memberBo.setRoleCode("3"); // 字典角色 3 代表产品支持
+            memberBo.setIzManager(0);
+            memberBo.setUpdateAccredit(0);
+            teamMemberService.insertOrUpdateMember(memberBo);
+        }
+    }
+
+    /**
+     * 应用用户权限:只允许查看自己是负责人或者产品支持的项目
+     */
+    private void applyUserPermission(SalesAnnualFinalizationBo bo) {
+        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);
+            }
+        }
+    }
+
 }

+ 158 - 1
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/SalesleadsServiceImpl.java

@@ -13,6 +13,10 @@ import org.dromara.customer.domain.Salesleads;
 import org.dromara.customer.domain.bo.SalesleadsBo;
 import org.dromara.customer.domain.bo.TeamMemberBo;
 import org.dromara.customer.domain.vo.SalesleadsVo;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.system.api.RemoteComStaffService;
+import org.dromara.system.api.domain.vo.RemoteComStaffVo;
+import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.customer.mapper.SalesleadsMapper;
 import org.dromara.customer.service.IOperationLogService;
 import org.dromara.customer.service.ISalesleadsService;
@@ -23,6 +27,8 @@ import org.springframework.transaction.annotation.Transactional;
 import java.time.Duration;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * 销售线索/项目商机 Service 业务层处理
@@ -40,6 +46,9 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
     private final ITeamMemberService teamMemberService;
     private final IOperationLogService operationLogService;
 
+    @DubboReference
+    private RemoteComStaffService remoteComStaffService;
+
     /**
      * 查询
      */
@@ -47,6 +56,7 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
     public SalesleadsVo queryById(Long id) {
         SalesleadsBo bo = new SalesleadsBo();
         bo.setId(id);
+        applyUserPermission(bo);
         List<SalesleadsVo> list = baseMapper.selectSalesleadsList(bo);
         return list.isEmpty() ? null : list.get(0);
     }
@@ -56,6 +66,7 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
      */
     @Override
     public TableDataInfo<SalesleadsVo> queryPageList(SalesleadsBo bo, PageQuery pageQuery) {
+        applyUserPermission(bo);
         IPage<SalesleadsVo> result = baseMapper.selectSalesleadsList(pageQuery.build(), bo);
         return TableDataInfo.build(result);
     }
@@ -65,6 +76,7 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
      */
     @Override
     public List<SalesleadsVo> queryList(SalesleadsBo bo) {
+        applyUserPermission(bo);
         return baseMapper.selectSalesleadsList(bo);
     }
 
@@ -91,6 +103,10 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
                 // 新增成功后,将负责人同步到团队成员表
                 syncLeaderToTeamMember(add.getId(), add.getLeader(), add.getLeaderName());
             }
+            if (add.getId() != null && bo.getProductSupport() != null && !bo.getProductSupport().isEmpty()) {
+                // 新增成功后,将产品支持同步到团队成员表
+                syncProductSupportToTeamMember(add.getId(), bo.getProductSupport(), bo.getProductSupportName());
+            }
             // 记录日志
             operationLogService.recordLog(CustomerConstants.DATA_TYPE_LEADS, String.valueOf(add.getId()), CustomerConstants.ACTION_TYPE_INSERT, null, "创建了销售线索", add.getProjectName());
         }
@@ -131,6 +147,22 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
                 syncLeaderToTeamMember(bo.getId(), bo.getLeader(), bo.getLeaderName());
             }
         }
+        if (success) {
+            if (bo.getProductSupport() != null && !bo.getProductSupport().isEmpty()) {
+                if (oldData == null || !ObjectUtils.equals(oldData.getProductSupport(), bo.getProductSupport())) {
+                    // 如果旧产品支持存在,则从团队成员中移除
+                    if (oldData != null && oldData.getProductSupport() != null && !oldData.getProductSupport().isEmpty()) {
+                        removeProductSupportFromTeamMember(bo.getId(), oldData.getProductSupport());
+                    }
+                    syncProductSupportToTeamMember(bo.getId(), bo.getProductSupport(), bo.getProductSupportName());
+                }
+            } else {
+                // 如果新产品支持为空,但旧产品支持存在,则从团队中移除
+                if (oldData != null && oldData.getProductSupport() != null && !oldData.getProductSupport().isEmpty()) {
+                    removeProductSupportFromTeamMember(bo.getId(), oldData.getProductSupport());
+                }
+            }
+        }
         return success;
     }
 
@@ -161,6 +193,7 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
             update.setId(id);
             update.setLeader(bo.getLeader());
             update.setLeaderName(bo.getLeaderName());
+            update.setProductSupport(bo.getProductSupport());
             update.setIzClue(0); // 认领后转为项目商机
             update.setProjectType(CustomerConstants.PROJECT_TYPE_OPPORTUNITY);
             update.setStatus("0"); // 转为商机后,状态设为跟进中
@@ -179,6 +212,21 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
                 }
 
                 syncLeaderToTeamMember(id, bo.getLeader(), bo.getLeaderName());
+                
+                // 处理产品支持同步逻辑
+                if (bo.getProductSupport() != null && !bo.getProductSupport().isEmpty()) {
+                    if (oldData == null || !ObjectUtils.equals(oldData.getProductSupport(), bo.getProductSupport())) {
+                        if (oldData != null && oldData.getProductSupport() != null && !oldData.getProductSupport().isEmpty()) {
+                            removeProductSupportFromTeamMember(id, oldData.getProductSupport());
+                        }
+                        syncProductSupportToTeamMember(id, bo.getProductSupport(), bo.getProductSupportName());
+                    }
+                } else {
+                    if (oldData != null && oldData.getProductSupport() != null && !oldData.getProductSupport().isEmpty()) {
+                        removeProductSupportFromTeamMember(id, oldData.getProductSupport());
+                    }
+                }
+                
                 // 记录日志
                 operationLogService.recordLog(CustomerConstants.DATA_TYPE_LEADS, String.valueOf(id), CustomerConstants.ACTION_TYPE_CLAIM, null, "认领了销售线索", bo.getLeaderName());
             }
@@ -247,17 +295,105 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
      */
     private void syncLeaderToTeamMember(Long objectNo, Long leaderId, String leaderName) {
         if (leaderId == null) return;
+        String realName = leaderName;
+        if (realName == null || realName.isEmpty()) {
+            Map<Long, String> nameMap = remoteComStaffService.selectStaffNameByIds(Set.of(leaderId));
+            if (nameMap != null && nameMap.containsKey(leaderId)) {
+                realName = nameMap.get(leaderId);
+            }
+        }
         TeamMemberBo memberBo = new TeamMemberBo();
         memberBo.setDataType(CustomerConstants.DATA_TYPE_LEADS);
         memberBo.setObjectNo(String.valueOf(objectNo));
         memberBo.setUserNo(leaderId);
-        memberBo.setRealName(leaderName);
+        memberBo.setRealName(realName);
         memberBo.setRoleCode(CustomerConstants.TEAM_ROLE_LEADER); // 业务负责人的字典值
         memberBo.setIzManager(1);
         memberBo.setUpdateAccredit(1);
         teamMemberService.insertOrUpdateMember(memberBo);
     }
 
+    /**
+     * 安全转换 Long
+     */
+    private Long tryParseLong(String val) {
+        if (val == null) {
+            return null;
+        }
+        try {
+            return Long.valueOf(val.trim());
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 从团队成员中安全移除产品支持
+     */
+    private void removeProductSupportFromTeamMember(Long objectNo, String productSupport) {
+        if (productSupport == null || productSupport.isEmpty()) {
+            return;
+        }
+        String[] supportIdStrArray = productSupport.split(",");
+        for (String idStr : supportIdStrArray) {
+            Long id = tryParseLong(idStr);
+            if (id != null) {
+                teamMemberService.removeMember(CustomerConstants.DATA_TYPE_LEADS, String.valueOf(objectNo), id);
+            }
+        }
+    }
+
+    /**
+     * 同步产品支持到团队成员表(适配逗号分隔的多值)
+     */
+    private void syncProductSupportToTeamMember(Long objectNo, String productSupport, String supportName) {
+        if (productSupport == null || productSupport.isEmpty()) {
+            return;
+        }
+        String[] supportIdStrArray = productSupport.split(",");
+        Set<Long> supportIds = new java.util.HashSet<>();
+        for (String idStr : supportIdStrArray) {
+            Long id = tryParseLong(idStr);
+            if (id != null) {
+                supportIds.add(id);
+            }
+        }
+        if (supportIds.isEmpty()) {
+            return;
+        }
+
+        Map<Long, String> nameMap = remoteComStaffService.selectStaffNameByIds(supportIds);
+        String[] supportNameArray = null;
+        if (supportName != null && !supportName.isEmpty()) {
+            supportNameArray = supportName.split(",");
+        }
+
+        int index = 0;
+        for (String idStr : supportIdStrArray) {
+            Long id = tryParseLong(idStr);
+            if (id != null) {
+                String realName = nameMap != null ? nameMap.get(id) : null;
+                if (realName == null || realName.isEmpty()) {
+                    if (supportNameArray != null && index < supportNameArray.length) {
+                        realName = supportNameArray[index].trim();
+                    } else {
+                        realName = supportName;
+                    }
+                }
+                TeamMemberBo memberBo = new TeamMemberBo();
+                memberBo.setDataType(CustomerConstants.DATA_TYPE_LEADS);
+                memberBo.setObjectNo(String.valueOf(objectNo));
+                memberBo.setUserNo(id);
+                memberBo.setRealName(realName);
+                memberBo.setRoleCode("3"); 
+                memberBo.setIzManager(0);
+                memberBo.setUpdateAccredit(0);
+                teamMemberService.insertOrUpdateMember(memberBo);
+            }
+            index++;
+        }
+    }
+
     /**
      * 获取项目进度名称
      */
@@ -272,4 +408,25 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
         };
     }
 
+    /**
+     * 应用用户权限:只允许查看自己是负责人或者产品支持的项目
+     */
+    private void applyUserPermission(SalesleadsBo bo) {
+        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);
+            }
+        }
+    }
+
 }

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

@@ -2,6 +2,7 @@ package org.dromara.customer.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.customer.controller.constant.CustomerConstants;
@@ -158,6 +159,20 @@ public class TeamMemberServiceImpl implements ITeamMemberService {
                 }
             }
         }
+        if (bo.getId() != null) {
+            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("业务负责人和客服支持是不可编辑的");
+                    }
+                } 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("项目负责人、产品支持和客服支持是不可编辑的");
+                    }
+                }
+            }
+        }
         TeamMember update = MapstructUtils.convert(bo, TeamMember.class);
         boolean flag = baseMapper.updateById(update) > 0;
         if (flag) {
@@ -178,6 +193,17 @@ public class TeamMemberServiceImpl implements ITeamMemberService {
             if (members == null || members.isEmpty()) {
                 return false;
             }
+            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("业务负责人和客服支持是不可删除的");
+                    }
+                } 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("项目负责人、产品支持和客服支持是不可删除的");
+                    }
+                }
+            }
             boolean flag = baseMapper.deleteByIds(ids) > 0;
             if (flag) {
                 for (TeamMemberVo member : members) {
@@ -231,6 +257,11 @@ public class TeamMemberServiceImpl implements ITeamMemberService {
     public Boolean removeMember(Integer dataType, String objectNo, Long userNo) {
         TeamMemberVo existing = baseMapper.selectByObjectNoAndUserNo(objectNo, userNo);
         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("业务负责人和客服支持是不可删除的");
+                }
+            }
             boolean flag = baseMapper.deleteById(existing.getId()) > 0;
             if (flag) {
                 operationLogService.recordLog(dataType, objectNo, CustomerConstants.ACTION_TYPE_DELETE, null, CustomerConstants.MODULE_TEAM_MEMBER, existing.getRealName());

+ 3 - 0
ruoyi-modules/ruoyi-customer/src/main/resources/mapper/customer/SalesAnnualFinalizationMapper.xml

@@ -51,6 +51,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                     AND (sra.IsDelete = 0 OR sra.IsDelete IS NULL)
                 )
             </if>
+            <if test="bo.params.restrictToUser == true">
+                AND (s.leader = #{bo.params.currentUserId} OR FIND_IN_SET(#{bo.params.currentUserId}, s.product_support) > 0)
+            </if>
             ${bo.params.dataScope}
         </where>
         ORDER BY s.create_time DESC

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

@@ -48,6 +48,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="bo.dealResult != null">
                 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)
+            </if>
             ${bo.params.dataScope}
         </where>
         ORDER BY create_time DESC