Explorar o código

Merge branch 'hurx'

hurx hai 1 mes
pai
achega
836ac10134

+ 1 - 1
ruoyi-api/ruoyi-api-system/src/main/java/org/dromara/system/api/RemoteAddressAreaService.java

@@ -16,5 +16,5 @@ public interface RemoteAddressAreaService {
 
     Long getIdsByName(String province);
 
-    List<org.dromara.system.api.domain.dto.AddressAreaDTO> getChinaArea();
+    List<AddressAreaDTO> getChinaArea();
 }

+ 10 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/controller/constant/CustomerConstants.java

@@ -36,6 +36,16 @@ public interface CustomerConstants {
      */
     Integer ACTION_TYPE_DELETE = 3;
 
+    /**
+     * 操作类型:认领
+     */
+    Integer ACTION_TYPE_CLAIM = 4;
+
+    /**
+     * 操作类型:转移
+     */
+    Integer ACTION_TYPE_TRANSFER = 5;
+
     /**
      * 团队角色:业务负责人
      */

+ 5 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/CustomerContact.java

@@ -129,5 +129,10 @@ public class CustomerContact extends TenantEntity {
      */
     private String remark;
 
+    /**
+     * 平台标识
+     */
+    private String platformCode;
+
 
 }

+ 10 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/bo/CustomerContactBo.java

@@ -124,5 +124,15 @@ public class CustomerContactBo extends BaseEntity {
 
     private String customerName;
 
+    /**
+     * 平台标识
+     */
+    private String platformCode;
+
+    /**
+     * 客户编号
+     */
+    private String customerNo;
+
 
 }

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

@@ -35,6 +35,9 @@ public class CustomerListBo extends BaseEntity {
     /** 客户等级ID */
     private Long customerLevelId;
 
+    /** 所属部门ID */
+    private Long belongingDepartmentId;
+
     /** 是否为公海客户 (true: 是, false: 否) */
     private String isHighSeas;
 }

+ 6 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/domain/vo/CustomerContactVo.java

@@ -150,5 +150,11 @@ public class CustomerContactVo implements Serializable {
 
     private String customerName;
 
+    /**
+     * 平台标识
+     */
+    @ExcelProperty(value = "平台标识")
+    private String platformCode;
+
     private Date createTime;
 }

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

@@ -42,6 +42,9 @@ public class SalesleadsVo implements Serializable {
     @Schema(description = "部门编号")
     private String deptNo;
 
+    @Schema(description = "部门名称")
+    private String deptName;
+
     @Schema(description = "客户编号")
     private String customerNo;
 

+ 9 - 0
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CustomerContactServiceImpl.java

@@ -144,6 +144,7 @@ public class CustomerContactServiceImpl extends ServiceImpl<CustomerContactMappe
         lqw.eq(StringUtils.isNotBlank(bo.getStatus()), CustomerContact::getStatus, bo.getStatus());
         lqw.like(StringUtils.isNotBlank(bo.getDeptName()), CustomerContact::getDeptName, bo.getDeptName());
         lqw.like(StringUtils.isNotBlank(bo.getRoleName()), CustomerContact::getRoleName, bo.getRoleName());
+        lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), CustomerContact::getPlatformCode, bo.getPlatformCode());
 
         if (ObjectUtil.isNotEmpty(bo.getCustomerName())) {
             CustomerInfoVo customerInfoVo = customerInfoMapper.selectVoOne(new LambdaQueryWrapper<CustomerInfo>().eq(CustomerInfo::getCustomerName, bo.getCustomerName()));
@@ -153,6 +154,14 @@ public class CustomerContactServiceImpl extends ServiceImpl<CustomerContactMappe
                 lqw.eq(CustomerContact::getCustomerId, 0);
             }
         }
+        if (ObjectUtil.isNotEmpty(bo.getCustomerNo())) {
+            CustomerInfoVo customerInfoVo = customerInfoMapper.selectVoOne(new LambdaQueryWrapper<CustomerInfo>().eq(CustomerInfo::getCustomerNo, bo.getCustomerNo()));
+            if (ObjectUtil.isNotEmpty(customerInfoVo)) {
+                lqw.eq(CustomerContact::getCustomerId, customerInfoVo.getId());
+            } else {
+                lqw.eq(CustomerContact::getCustomerId, 0);
+            }
+        }
         if (bo.getDeptId() != null) {
             // 1. 获取当前部门及所有子部门的 ID 列表
             List<Long> deptIds = remoteDeptService.selectDeptChildrenIds(bo.getDeptId());

+ 36 - 21
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/CustomerInfoServiceImpl.java

@@ -529,6 +529,15 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
         // if (StringUtils.isBlank(bo.getPlatformCode())) {
         //     bo.setPlatformCode(PlatformContext.getPlatform());
         // }
+        // 强制处理 isHighSeas 参数逻辑
+        Object isHighSeas = StringUtils.isNotBlank(bo.getIsHighSeas()) ? bo.getIsHighSeas() : bo.getParams().get("isHighSeas");
+        if (isHighSeas == null) {
+            // 如果没传,默认当做有效客户处理
+            bo.setIsHighSeas("false");
+        } else {
+            bo.setIsHighSeas(String.valueOf(isHighSeas));
+        }
+
         Page<CustomerListVo> page = baseMapper.selectCustomerListPage(pageQuery.build(), bo);
 
         // 补充业务员名称和信用等级名称
@@ -619,9 +628,6 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
         lqw.orderByDesc(CustomerInfo::getId);
         lqw.eq(StringUtils.isNotBlank(bo.getCustomerNo()), CustomerInfo::getCustomerNo, bo.getCustomerNo());
         lqw.eq(bo.getBelongCompanyId() != null, CustomerInfo::getBelongCompanyId, bo.getBelongCompanyId());
-        lqw.eq(bo.getSalesPersonId() != null, CustomerInfo::getSalesPersonId, bo.getSalesPersonId());
-        lqw.eq(bo.getServiceStaffId() != null, CustomerInfo::getServiceStaffId, bo.getServiceStaffId());
-        lqw.eq(bo.getBelongingDepartmentId() != null, CustomerInfo::getBelongingDepartmentId, bo.getBelongingDepartmentId());
         lqw.like(StringUtils.isNotBlank(bo.getCompanyName()), CustomerInfo::getCompanyName, bo.getCompanyName());
         lqw.like(StringUtils.isNotBlank(bo.getCustomerName()), CustomerInfo::getCustomerName, bo.getCustomerName());
         lqw.like(StringUtils.isNotBlank(bo.getBusinessCustomerName()), CustomerInfo::getBusinessCustomerName, bo.getBusinessCustomerName());
@@ -645,6 +651,21 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
         lqw.eq(StringUtils.isNotBlank(bo.getProvincialCityCounty()), CustomerInfo::getProvincialCityCounty, bo.getProvincialCityCounty());
         lqw.eq(StringUtils.isNotBlank(bo.getStatus()), CustomerInfo::getStatus, bo.getStatus());
         lqw.eq(StringUtils.isNotBlank(bo.getPlatformCode()), CustomerInfo::getPlatformCode, bo.getPlatformCode());
+        lqw.eq(bo.getSalesPersonId() != null, CustomerInfo::getSalesPersonId, bo.getSalesPersonId());
+        lqw.eq(bo.getServiceStaffId() != null, CustomerInfo::getServiceStaffId, bo.getServiceStaffId());
+        lqw.eq(bo.getBelongingDepartmentId() != null, CustomerInfo::getBelongingDepartmentId, bo.getBelongingDepartmentId());
+        Object isHighSeasObj = StringUtils.isNotBlank(bo.getIsHighSeas()) ? bo.getIsHighSeas() : bo.getParams().get("isHighSeas");
+        String isHighSeasStr = (isHighSeasObj != null) ? StringUtils.lowerCase(String.valueOf(isHighSeasObj)) : "false";
+
+        if ("true".equals(isHighSeasStr)) {
+            // 公海客户:负责人和客服均为空(或为0)
+            lqw.and(w -> w.and(a -> a.isNull(CustomerInfo::getSalesPersonId).or().eq(CustomerInfo::getSalesPersonId, 0))
+                         .and(b -> b.isNull(CustomerInfo::getServiceStaffId).or().eq(CustomerInfo::getServiceStaffId, 0)));
+        } else {
+            // 有效客户:负责人不为空(且不为0) OR 客服不为空(且不为0)
+            lqw.and(w -> w.and(a -> a.isNotNull(CustomerInfo::getSalesPersonId).ne(CustomerInfo::getSalesPersonId, 0))
+                         .or(b -> b.isNotNull(CustomerInfo::getServiceStaffId).ne(CustomerInfo::getServiceStaffId, 0)));
+        }
         return lqw;
     }
 
@@ -1282,7 +1303,7 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
                     customerInfo.setBelongingDepartmentId(deptId);
                     updateList.add(customerInfo);
                 } else {
-                    log.warn("客户 ID: {} 的销售信息不存在,跳过更新", customerId);
+                    log.warn("客户 ID: {} 不存在,跳过更新", customerId);
                 }
             }
 
@@ -1293,8 +1314,8 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
                         updateList.size(), salesPersonId, deptId);
                     return updateList.size();
                 } else {
-                    log.error("批量更新销售信息失败");
-                    throw new ServiceException("批量更新销售信息失败");
+                    log.error("批量更新客户信息失败");
+                    throw new ServiceException("批量更新客户信息失败");
                 }
             }
 
@@ -1334,7 +1355,7 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
                     customerInfo.setServiceStaffId(serviceStaffId);
                     updateList.add(customerInfo);
                 } else {
-                    log.warn("客户 ID: {} 的销售信息不存在,跳过更新", customerId);
+                    log.warn("客户 ID: {} 不存在,跳过更新", customerId);
                 }
             }
 
@@ -1345,8 +1366,8 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
                         updateList.size(), serviceStaffId);
                     return updateList.size();
                 } else {
-                    log.error("批量更新销售信息失败");
-                    throw new ServiceException("批量更新销售信息失败");
+                    log.error("批量更新客户信息失败");
+                    throw new ServiceException("批量更新客户信息失败");
                 }
             }
 
@@ -1437,18 +1458,12 @@ public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, Cus
         }
 
         // 更新销售负责人和客服
-        salesInfo.setSalesPersonId(claimBo.getSalesPersonId());
-        salesInfo.setServiceStaffId(claimBo.getServiceStaffId());
-        boolean flag = customerSalesInfoMapper.updateById(salesInfo) > 0;
-
-        if (flag) {
-            // 认领成功后,将客户主表状态改为有效 (通常 0 代表有效/正常)
-            CustomerInfo customer = new CustomerInfo();
-            customer.setId(customerId);
-            customer.setStatus("0"); // 设置为有效客户
-            baseMapper.updateById(customer);
-        }
-        return flag;
+        CustomerInfo customer = new CustomerInfo();
+        customer.setId(customerId);
+        customer.setSalesPersonId(claimBo.getSalesPersonId());
+        customer.setServiceStaffId(claimBo.getServiceStaffId());
+        customer.setStatus("0"); // 认领成功后,将客户主表状态改为有效
+        return baseMapper.updateById(customer) > 0;
     }
 
     @Override

+ 20 - 7
ruoyi-modules/ruoyi-customer/src/main/java/org/dromara/customer/service/impl/SalesleadsServiceImpl.java

@@ -82,9 +82,13 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
             add.setProjectType(CustomerConstants.PROJECT_TYPE_LEADS);
         }
         boolean success = baseMapper.insert(add) > 0;
-        if (success && add.getLeader() != null) {
-            // 新增成功后,将负责人同步到团队成员表
-            syncLeaderToTeamMember(add.getId(), add.getLeader(), add.getLeaderName());
+        if (success) {
+            if (add.getLeader() != null) {
+                // 新增成功后,将负责人同步到团队成员表
+                syncLeaderToTeamMember(add.getId(), add.getLeader(), add.getLeaderName());
+            }
+            // 记录日志
+            operationLogService.recordLog(CustomerConstants.DATA_TYPE_LEADS, String.valueOf(add.getId()), CustomerConstants.ACTION_TYPE_INSERT, null, "创建了销售线索", add.getProjectName());
         }
         return success;
     }
@@ -99,6 +103,9 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
         Salesleads update = MapstructUtils.convert(bo, Salesleads.class);
         boolean success = baseMapper.updateById(update) > 0;
         if (success && oldData != null) {
+            // 记录日志
+            operationLogService.recordLog(CustomerConstants.DATA_TYPE_LEADS, String.valueOf(bo.getId()), CustomerConstants.ACTION_TYPE_UPDATE, null, "修改了销售线索", bo.getProjectName());
+            
             if (!ObjectUtils.equals(oldData.getProjectSchedule(), bo.getProjectSchedule())) {
                 operationLogService.recordLog(CustomerConstants.DATA_TYPE_LEADS, String.valueOf(bo.getId()), CustomerConstants.ACTION_TYPE_UPDATE, null, CustomerConstants.MODULE_PROJECT_PROGRESS, bo.getProjectSchedule());
             }
@@ -138,9 +145,12 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
             update.setId(id);
             update.setLeader(bo.getLeader());
             update.setLeaderName(bo.getLeaderName());
-            result = result && baseMapper.updateById(update) > 0;
-            if (result) {
+            boolean success = baseMapper.updateById(update) > 0;
+            result = result && success;
+            if (success) {
                 syncLeaderToTeamMember(id, bo.getLeader(), bo.getLeaderName());
+                // 记录日志
+                operationLogService.recordLog(CustomerConstants.DATA_TYPE_LEADS, String.valueOf(id), CustomerConstants.ACTION_TYPE_CLAIM, null, "认领了销售线索", bo.getLeaderName());
             }
         }
         return result;
@@ -163,9 +173,12 @@ public class SalesleadsServiceImpl implements ISalesleadsService {
             update.setId(id);
             update.setLeader(bo.getLeader());
             update.setLeaderName(bo.getLeaderName());
-            result = result && baseMapper.updateById(update) > 0;
-            if (result) {
+            boolean success = baseMapper.updateById(update) > 0;
+            result = result && success;
+            if (success) {
                 syncLeaderToTeamMember(id, bo.getLeader(), bo.getLeaderName());
+                // 记录日志
+                operationLogService.recordLog(CustomerConstants.DATA_TYPE_LEADS, String.valueOf(id), CustomerConstants.ACTION_TYPE_TRANSFER, null, "转移了销售线索", bo.getLeaderName());
             }
         }
         return result;

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

@@ -1,16 +1,20 @@
 package org.dromara.customer.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import lombok.RequiredArgsConstructor;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.customer.controller.constant.CustomerConstants;
+import org.dromara.customer.domain.Salesleads;
 import org.dromara.customer.domain.TeamMember;
 import org.dromara.customer.domain.bo.TeamMemberBo;
 import org.dromara.customer.domain.vo.TeamMemberVo;
+import org.dromara.customer.mapper.SalesleadsMapper;
 import org.dromara.customer.mapper.TeamMemberMapper;
 import org.dromara.customer.service.IOperationLogService;
 import org.dromara.customer.service.ITeamMemberService;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.Collection;
 import java.util.List;
@@ -26,6 +30,7 @@ import java.util.List;
 public class TeamMemberServiceImpl implements ITeamMemberService {
 
     private final TeamMemberMapper baseMapper;
+    private final SalesleadsMapper salesleadsMapper;
     private final IOperationLogService operationLogService;
 
     /**
@@ -122,14 +127,35 @@ public class TeamMemberServiceImpl implements ITeamMemberService {
      * 删除
      */
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public Boolean deleteByIds(Collection<Long> ids) {
         if (ids != null && !ids.isEmpty()) {
-            Long firstId = ids.iterator().next();
-            TeamMemberVo member = baseMapper.selectVoById(firstId);
+            List<TeamMemberVo> members = baseMapper.selectVoByIds(ids);
+            if (members == null || members.isEmpty()) {
+                return false;
+            }
             boolean flag = baseMapper.deleteByIds(ids) > 0;
-            if (flag && member != null) {
-                Integer dataType = member.getDataType() != null ? member.getDataType() : CustomerConstants.DATA_TYPE_LEADS;
-                operationLogService.recordLog(dataType, member.getObjectNo(), CustomerConstants.ACTION_TYPE_DELETE, null, CustomerConstants.MODULE_TEAM_MEMBER, member.getRealName());
+            if (flag) {
+                for (TeamMemberVo member : members) {
+                    // 同步清理销售线索中的负责人信息
+                    if (CustomerConstants.DATA_TYPE_LEADS.equals(member.getDataType()) && member.getObjectNo() != null) {
+                        try {
+                            Long leadsId = Long.valueOf(member.getObjectNo());
+                            Salesleads leads = salesleadsMapper.selectById(leadsId);
+                            if (leads != null && member.getUserNo() != null && member.getUserNo().equals(leads.getLeader())) {
+                                // 如果删除的是负责人,则清空负责人字段
+                                salesleadsMapper.update(null, new LambdaUpdateWrapper<Salesleads>()
+                                    .set(Salesleads::getLeader, null)
+                                    .set(Salesleads::getLeaderName, null)
+                                    .eq(Salesleads::getId, leadsId));
+                            }
+                        } catch (Exception e) {
+                            // 忽略转换错误或同步异常,不影响主流程
+                        }
+                    }
+                    Integer dataType = member.getDataType() != null ? member.getDataType() : CustomerConstants.DATA_TYPE_LEADS;
+                    operationLogService.recordLog(dataType, member.getObjectNo(), CustomerConstants.ACTION_TYPE_DELETE, null, CustomerConstants.MODULE_TEAM_MEMBER, member.getRealName());
+                }
             }
             return flag;
         }

+ 17 - 13
ruoyi-modules/ruoyi-customer/src/main/resources/mapper/customer/CustomerInfoMapper.xml

@@ -61,18 +61,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             csi.credit_amount AS creditAmount,
             csi.credit_management_id AS creditLevelId,
             csi.accounts_receivable AS accountsReceivable,
-            csi.sales_person_id AS salesPersonId,
+            ci.sales_person_id AS salesPersonId,
             ci.belong_company_id AS belongCompanyId,
             ci.customer_type_id AS enterpriseTypeId,
             ci.customer_level_id AS customerLevelId,
-            csi.service_staff_id AS serviceStaffId,
-            csi.belonging_department_id AS belongingDepartmentId,
+            ci.service_staff_id AS serviceStaffId,
+            ci.belonging_department_id AS belongingDepartmentId,
             ci.status
         FROM customer_info ci
         LEFT JOIN customer_sales_info csi ON ci.id = csi.customer_id AND csi.del_flag = '0'
         LEFT JOIN industry_category ic ON ci.industry_category_id = ic.id AND ic.del_flag = '0'
         <where>
             ci.del_flag = '0'
+            <choose>
+                <when test="bo.isHighSeas == 'true'">
+                    AND (ci.sales_person_id IS NULL OR ci.sales_person_id = 0)
+                    AND (ci.service_staff_id IS NULL OR ci.service_staff_id = 0)
+                </when>
+                <otherwise>
+                    AND ( (ci.sales_person_id IS NOT NULL AND ci.sales_person_id != 0) 
+                       OR (ci.service_staff_id IS NOT NULL AND ci.service_staff_id != 0) )
+                </otherwise>
+            </choose>
             <if test="bo.platformCode != null and bo.platformCode != ''">
                 AND ci.platform_code = #{bo.platformCode}
             </if>
@@ -89,19 +99,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 AND ci.customer_level_id = #{bo.customerLevelId}
             </if>
             <if test="bo.salesPersonId != null">
-                AND csi.sales_person_id = #{bo.salesPersonId}
+                AND ci.sales_person_id = #{bo.salesPersonId}
             </if>
             <if test="bo.serviceStaffId != null">
-                AND csi.service_staff_id = #{bo.serviceStaffId}
+                AND ci.service_staff_id = #{bo.serviceStaffId}
             </if>
-            <if test="bo.yearSalesMin != null">
-                AND csi.credit_amount &gt;= #{bo.yearSalesMin}
-            </if>
-            <if test="bo.yearSalesMax != null">
-                AND csi.credit_amount &lt;= #{bo.yearSalesMax}
-            </if>
-            <if test="bo.isHighSeas != null and bo.isHighSeas == 'true'">
-                AND (csi.sales_person_id IS NULL AND csi.service_staff_id IS NULL)
+            <if test="bo.belongingDepartmentId != null">
+                AND ci.belonging_department_id = #{bo.belongingDepartmentId}
             </if>
         </where>
         ORDER BY ci.id DESC

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

@@ -5,10 +5,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 <mapper namespace="org.dromara.customer.mapper.SalesleadsMapper">
 
     <select id="selectSalesleadsList" resultType="org.dromara.customer.domain.vo.SalesleadsVo">
-        SELECT s.*, cc.company_name AS companyName, ic.industry_category_name AS industry
+        SELECT s.*, cc.company_name AS companyName, ic.industry_category_name AS industry, d.dept_name AS deptName
         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'
+        LEFT JOIN com_staff cs ON s.leader = cs.staff_id
+        LEFT JOIN sys_dept d ON cs.dept_id = d.dept_id
         <where>
             s.del_flag = '0'
             <if test="bo.izClue != null">
@@ -36,7 +38,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 AND s.leader = #{bo.leader}
             </if>
             <if test="bo.deptNo != null and bo.deptNo != ''">
-                AND s.dept_no = #{bo.deptNo}
+                AND cs.dept_id = #{bo.deptNo}
             </if>
             ${bo.params.dataScope}
         </where>