Procházet zdrojové kódy

优化商中需求

lmx před 1 týdnem
rodič
revize
b72dae8db2
17 změnil soubory, kde provedl 235 přidání a 8 odebrání
  1. 2 1
      fs-company/src/main/java/com/fs/company/controller/company/CompanyVoiceRoboticController.java
  2. 2 0
      fs-company/src/main/java/com/fs/company/controller/crm/CrmCustomerController.java
  3. 2 1
      fs-service/src/main/java/com/fs/company/mapper/CompanyAiWorkflowExecMapper.java
  4. 11 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyVoiceRoboticCallLogCallphoneMapper.java
  5. 12 0
      fs-service/src/main/java/com/fs/company/mapper/CrmCustomerCallLogMapper.java
  6. 1 1
      fs-service/src/main/java/com/fs/company/service/ICompanyVoiceRoboticService.java
  7. 7 3
      fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticServiceImpl.java
  8. 9 0
      fs-service/src/main/java/com/fs/crm/mapper/CrmCustomerMapper.java
  9. 8 0
      fs-service/src/main/java/com/fs/crm/param/CrmCustomerListQueryParam.java
  10. 6 0
      fs-service/src/main/java/com/fs/crm/service/ICrmCustomerService.java
  11. 59 0
      fs-service/src/main/java/com/fs/crm/service/impl/CrmCustomerServiceImpl.java
  12. 24 0
      fs-service/src/main/java/com/fs/crm/vo/CrmCustomerListVO.java
  13. 26 0
      fs-service/src/main/java/com/fs/crm/vo/CustomerCallStatVO.java
  14. 4 2
      fs-service/src/main/resources/db/tenant-initTable.sql
  15. 3 0
      fs-service/src/main/resources/mapper/company/CompanyAiWorkflowExecMapper.xml
  16. 31 0
      fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCallLogCallphoneMapper.xml
  17. 28 0
      fs-service/src/main/resources/mapper/company/CrmCustomerCallLogMapper.xml

+ 2 - 1
fs-company/src/main/java/com/fs/company/controller/company/CompanyVoiceRoboticController.java

@@ -347,12 +347,13 @@ public class CompanyVoiceRoboticController extends BaseController
                             @RequestParam(defaultValue = "10") Integer pageSize,
                             @RequestParam(required = false) String customerName,
                             @RequestParam(required = false) String customerPhone,
+                            @RequestParam(required = false) String encryptPhone,
                             @RequestParam Boolean onlyCallNode) {
         if (roboticId == null) {
             return R.error("任务ID不能为空");
         }
         return R.ok(companyVoiceRoboticService.getExecRecords(roboticId, pageNum, pageSize, customerName,
-                customerPhone,onlyCallNode));
+                customerPhone,onlyCallNode,encryptPhone));
     }
 
     @GetMapping("/getCurrentCompanyId")

+ 2 - 0
fs-company/src/main/java/com/fs/company/controller/crm/CrmCustomerController.java

@@ -133,6 +133,8 @@ public class CrmCustomerController extends BaseController
             crmCustomer.setReceiveTimeList(crmCustomer.getReceiveTimeRange().split("--"));
         }
         List<CrmCustomerListVO> list = crmCustomerService.selectCrmCustomerListQueryParam(crmCustomer);
+        // 回填今日/累计 × 手动/AI 外呼次数(接通/总数),仅本接口调用
+        crmCustomerService.fillCallStats(list);
         if (list != null) {
             for (CrmCustomerListVO vo : list) {
                 if(vo.getMobile()!=null){

+ 2 - 1
fs-service/src/main/java/com/fs/company/mapper/CompanyAiWorkflowExecMapper.java

@@ -109,7 +109,8 @@ public interface CompanyAiWorkflowExecMapper extends BaseMapper<CompanyAiWorkflo
             @Param("roboticId") Long roboticId,
             @Param("customerName") String customerName,
             @Param("customerPhone") String customerPhone,
-            @Param(("onlyCallNode")) Boolean onlyCallNode
+            @Param(("onlyCallNode")) Boolean onlyCallNode,
+            @Param("encryptPhone") String encryptPhone
     );
 
     WxContact selectWxContectByWorkflowInstanceId(@Param("workflowInstanceId") String workflowInstanceId);

+ 11 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyVoiceRoboticCallLogCallphoneMapper.java

@@ -5,6 +5,7 @@ import com.fs.company.domain.CompanyVoiceRoboticCallLogCallphone;
 import com.fs.company.domain.CompanyVoiceRoboticCallees;
 import com.fs.company.vo.CompanyVoiceRoboticCallLogCallPhoneVO;
 import com.fs.company.vo.CompanyVoiceRoboticCallLogCount;
+import com.fs.crm.vo.CustomerCallStatVO;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
@@ -96,4 +97,14 @@ public interface CompanyVoiceRoboticCallLogCallphoneMapper extends BaseMapper<Co
     Long selectCompanyIdByBusinessId(@Param("businessId") Long businessId);
 
     List<CompanyVoiceRoboticCallLogCallphone> selectManualAnsweredList(CompanyVoiceRoboticCallLogCallphone companyVoiceRoboticCallLogCallphone);
+
+    /**
+     * 按 customer_id(= callees.user_id)批量统计今日 AI 外呼总数与接通数
+     */
+    List<CustomerCallStatVO> selectAiCallStatToday(@Param("customerIds") List<Long> customerIds);
+
+    /**
+     * 按 customer_id(= callees.user_id)批量统计累计 AI 外呼总数与接通数
+     */
+    List<CustomerCallStatVO> selectAiCallStatTotal(@Param("customerIds") List<Long> customerIds);
 }

+ 12 - 0
fs-service/src/main/java/com/fs/company/mapper/CrmCustomerCallLogMapper.java

@@ -2,6 +2,8 @@ package com.fs.company.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.company.domain.CrmCustomerCallLog;
+import com.fs.crm.vo.CustomerCallStatVO;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -18,4 +20,14 @@ public interface CrmCustomerCallLogMapper extends BaseMapper<CrmCustomerCallLog>
     List<CrmCustomerCallLog> selectCrmCustomerCallLogList(CrmCustomerCallLog crmCustomerCallLog);
 
     Long selectSumBillingMinute(CrmCustomerCallLog crmCustomerCallLog);
+
+    /**
+     * 按 customer_id 批量统计今日手动外呼记录总数与接通数
+     */
+    List<CustomerCallStatVO> selectManualCallStatToday(@Param("customerIds") List<Long> customerIds);
+
+    /**
+     * 按 customer_id 批量统计累计手动外呼记录总数与接通数
+     */
+    List<CustomerCallStatVO> selectManualCallStatTotal(@Param("customerIds") List<Long> customerIds);
 }

+ 1 - 1
fs-service/src/main/java/com/fs/company/service/ICompanyVoiceRoboticService.java

@@ -103,7 +103,7 @@ public interface ICompanyVoiceRoboticService extends IService<CompanyVoiceRoboti
      * @param roboticId 任务ID
      * @return 执行记录列表
      */
-    Map<String, Object> getExecRecords(Long roboticId, Integer pageNum, Integer pageSize,String customerName,String customerPhone, Boolean onlyCallNode);
+    Map<String, Object> getExecRecords(Long roboticId, Integer pageNum, Integer pageSize,String customerName,String customerPhone, Boolean onlyCallNode,String encryptPhone);
 
     void finishAddWxByCallees(Set<Long> roboticIds);
 

+ 7 - 3
fs-service/src/main/java/com/fs/company/service/impl/CompanyVoiceRoboticServiceImpl.java

@@ -39,6 +39,7 @@ import com.fs.crm.service.impl.CrmCustomerServiceImpl;
 import com.fs.enums.ExecutionStatusEnum;
 import com.fs.enums.NodeTypeEnum;
 import com.fs.enums.TaskTypeEnum;
+import com.fs.his.utils.PhoneUtil;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.impl.QwExternalContactServiceImpl;
@@ -1764,11 +1765,14 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
                                               Integer pageSize,
                                               String customerName,
                                               String customerPhone,
-                                              Boolean onlyCallNode) {
+                                              Boolean onlyCallNode,
+                                              String encryptPhone) {
         //分页查询主数据
         PageHelper.startPage(pageNum, pageSize);
-
-        List<WorkflowExecRecordVo> records = companyAiWorkflowExecMapper.selectExecRecordsByRoboticId(roboticId, customerName, customerPhone, onlyCallNode);
+        if(StringUtils.isNotBlank(encryptPhone)){
+            encryptPhone = PhoneUtil.encryptPhone(encryptPhone);
+        }
+        List<WorkflowExecRecordVo> records = companyAiWorkflowExecMapper.selectExecRecordsByRoboticId(roboticId, customerName, customerPhone, onlyCallNode,encryptPhone);
 
         PageInfo<WorkflowExecRecordVo> pageInfo = new PageInfo<>(records);
 

+ 9 - 0
fs-service/src/main/java/com/fs/crm/mapper/CrmCustomerMapper.java

@@ -244,6 +244,9 @@ public interface CrmCustomerMapper extends BaseMapper<CrmCustomer> {
             "<if test = 'maps.tags != null and  maps.tags !=\"\"    '> " +
             "and find_in_set(#{maps.tags}, c.tags)   " +
             "</if>" +
+            "<if test = 'maps.customTag != null and maps.customTag != \"\"   '> " +
+            "and c.tags like CONCAT('%',#{maps.customTag},'%') " +
+            "</if>" +
             "<if test = 'maps.status != null      '> " +
             "and c.status =#{maps.status} " +
             "</if>" +
@@ -283,6 +286,12 @@ public interface CrmCustomerMapper extends BaseMapper<CrmCustomer> {
             "<if test = 'maps.deptId != null  and maps.deptId != 0 '> " +
             "AND (c.dept_id = #{maps.deptId} OR c.dept_id IN ( SELECT t.dept_id FROM company_dept t WHERE find_in_set(#{maps.deptId}, ancestors) )) " +
             "</if>" +
+            "<if test = 'maps.roboticId != null and maps.taskCustomerFilter != null and maps.taskCustomerFilter == \"notInTask\"   '> " +
+            "and c.customer_id NOT IN (SELECT ce.user_id FROM company_voice_robotic_callees ce WHERE ce.robotic_id = #{maps.roboticId}) " +
+            "</if>" +
+            "<if test = 'maps.roboticId != null and maps.taskCustomerFilter != null and maps.taskCustomerFilter == \"inTask\"   '> " +
+            "and c.customer_id IN (SELECT ce.user_id FROM company_voice_robotic_callees ce WHERE ce.robotic_id = #{maps.roboticId}) " +
+            "</if>" +
             "${maps.params.dataScope}"+
             " order by c.customer_id desc "+
             "</script>"})

+ 8 - 0
fs-service/src/main/java/com/fs/crm/param/CrmCustomerListQueryParam.java

@@ -107,5 +107,13 @@ public class CrmCustomerListQueryParam extends BaseQueryParam
 
     private String intentionDegree;
 
+    /** AI外呼任务ID,用于“已在任务”筛选 */
+    private Long roboticId;
+
+    /** 任务客户筛选类型:notInTask=未在任务(可追加),inTask=已在任务(不可追加),null=全部 */
+    private String taskCustomerFilter;
+
+    /** 自定义标签模糊搜索(LIKE '%customTag%') */
+    private String customTag;
 
 }

+ 6 - 0
fs-service/src/main/java/com/fs/crm/service/ICrmCustomerService.java

@@ -92,6 +92,12 @@ public interface ICrmCustomerService
 
     List<CrmCustomerListVO> selectCrmCustomerListQueryParam(CrmCustomerListQueryParam crmCustomer);
 
+    /**
+     * 为客户选择/追加客户列表回填今日/累计 × 手动/AI 的外呼次数(接通/总数)
+     * 采用二阶段批量聚合,请求数与页大小无关
+     */
+    void fillCallStats(List<CrmCustomerListVO> list);
+
     List<CrmMyCustomerListQueryVO> selectCrmMyCustomerListQuery(CrmMyCustomerListQueryParam param);
 
     List<CrmCustomerListQueryVO> selectCrmCustomerListQuery(CrmCustomerListQueryParam param);

+ 59 - 0
fs-service/src/main/java/com/fs/crm/service/impl/CrmCustomerServiceImpl.java

@@ -19,6 +19,8 @@ import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyDeptMapper;
 import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.company.mapper.CompanyVoiceRoboticCallLogCallphoneMapper;
+import com.fs.company.mapper.CrmCustomerCallLogMapper;
 import com.fs.crm.domain.*;
 import com.fs.crm.dto.CrmCustomerAssignCompanyDTO;
 import com.fs.crm.dto.CrmCustomerAssignUserDTO;
@@ -93,6 +95,12 @@ public class CrmCustomerServiceImpl extends ServiceImpl<CrmCustomerMapper, CrmCu
     @Autowired
     private IWxSopExecuteService wxSopExecuteService;
 
+    @Autowired
+    private CrmCustomerCallLogMapper crmCustomerCallLogMapper;
+
+    @Autowired
+    private CompanyVoiceRoboticCallLogCallphoneMapper companyVoiceRoboticCallLogCallphoneMapper;
+
     /**
      * 查询客户
      *
@@ -303,6 +311,57 @@ public class CrmCustomerServiceImpl extends ServiceImpl<CrmCustomerMapper, CrmCu
         return crmCustomerMapper.selectCrmCustomerListQueryParam(crmCustomer);
     }
 
+    @Override
+    public void fillCallStats(List<CrmCustomerListVO> list) {
+        if (list == null || list.isEmpty()) {
+            return;
+        }
+        List<Long> customerIds = list.stream()
+                .map(CrmCustomerListVO::getCustomerId)
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(Collectors.toList());
+        if (customerIds.isEmpty()) {
+            return;
+        }
+        Map<Long, CustomerCallStatVO> manualToday = toStatMap(crmCustomerCallLogMapper.selectManualCallStatToday(customerIds));
+        Map<Long, CustomerCallStatVO> manualTotal = toStatMap(crmCustomerCallLogMapper.selectManualCallStatTotal(customerIds));
+        Map<Long, CustomerCallStatVO> aiToday = toStatMap(companyVoiceRoboticCallLogCallphoneMapper.selectAiCallStatToday(customerIds));
+        Map<Long, CustomerCallStatVO> aiTotal = toStatMap(companyVoiceRoboticCallLogCallphoneMapper.selectAiCallStatTotal(customerIds));
+
+        for (CrmCustomerListVO vo : list) {
+            Long id = vo.getCustomerId();
+            CustomerCallStatVO mt = id == null ? null : manualToday.get(id);
+            vo.setTodayManualTotalCount(mt == null || mt.getTotalCount() == null ? 0 : mt.getTotalCount());
+            vo.setTodayManualConnectCount(mt == null || mt.getConnectCount() == null ? 0 : mt.getConnectCount());
+
+            CustomerCallStatVO ml = id == null ? null : manualTotal.get(id);
+            vo.setTotalManualTotalCount(ml == null || ml.getTotalCount() == null ? 0 : ml.getTotalCount());
+            vo.setTotalManualConnectCount(ml == null || ml.getConnectCount() == null ? 0 : ml.getConnectCount());
+
+            CustomerCallStatVO at = id == null ? null : aiToday.get(id);
+            vo.setTodayAiTotalCount(at == null || at.getTotalCount() == null ? 0 : at.getTotalCount());
+            vo.setTodayAiConnectCount(at == null || at.getConnectCount() == null ? 0 : at.getConnectCount());
+
+            CustomerCallStatVO al = id == null ? null : aiTotal.get(id);
+            vo.setTotalAiTotalCount(al == null || al.getTotalCount() == null ? 0 : al.getTotalCount());
+            vo.setTotalAiConnectCount(al == null || al.getConnectCount() == null ? 0 : al.getConnectCount());
+        }
+    }
+
+    private Map<Long, CustomerCallStatVO> toStatMap(List<CustomerCallStatVO> stats) {
+        if (stats == null || stats.isEmpty()) {
+            return Collections.emptyMap();
+        }
+        Map<Long, CustomerCallStatVO> map = new HashMap<>(stats.size() * 2);
+        for (CustomerCallStatVO s : stats) {
+            if (s.getCustomerId() != null) {
+                map.put(s.getCustomerId(), s);
+            }
+        }
+        return map;
+    }
+
     @Override
     public List<CrmMyCustomerListQueryVO> selectCrmMyCustomerListQuery(CrmMyCustomerListQueryParam param) {
         return crmCustomerMapper.selectCrmMyCustomerListQuery(param);

+ 24 - 0
fs-service/src/main/java/com/fs/crm/vo/CrmCustomerListVO.java

@@ -129,4 +129,28 @@ public class CrmCustomerListVO implements Serializable
     @Excel(name = "进线客户提交日期" )
     private String registerSubmitTime;
 
+    /** 今日手动外呼总数 */
+    private Integer todayManualTotalCount;
+
+    /** 今日手动外呼接通数(call_time>0) */
+    private Integer todayManualConnectCount;
+
+    /** 今日AI外呼总数 */
+    private Integer todayAiTotalCount;
+
+    /** 今日AI外呼接通数(call_time>0) */
+    private Integer todayAiConnectCount;
+
+    /** 累计手动外呼总数 */
+    private Integer totalManualTotalCount;
+
+    /** 累计手动外呼接通数(call_time>0) */
+    private Integer totalManualConnectCount;
+
+    /** 累计AI外呼总数 */
+    private Integer totalAiTotalCount;
+
+    /** 累计AI外呼接通数(call_time>0) */
+    private Integer totalAiConnectCount;
+
 }

+ 26 - 0
fs-service/src/main/java/com/fs/crm/vo/CustomerCallStatVO.java

@@ -0,0 +1,26 @@
+package com.fs.crm.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 客户外呼统计聚合结果(按 customer_id 分组)
+ *
+ * 用于客户选择/追加客户列表中按批量聚合方式回填
+ * 今日/累计 × 手动/AI 的外呼次数(接通/总数)。
+ */
+@Data
+public class CustomerCallStatVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 客户ID */
+    private Long customerId;
+
+    /** 总数 */
+    private Integer totalCount;
+
+    /** 接通数(call_time > 0) */
+    private Integer connectCount;
+}

+ 4 - 2
fs-service/src/main/resources/db/tenant-initTable.sql

@@ -2804,7 +2804,8 @@ CREATE TABLE `company_voice_robotic_callees`
     INDEX            `idx_phone_is_generate`(`phone`, `is_generate`) USING BTREE,
     INDEX            `idx_user_name`(`user_name`) USING BTREE,
     INDEX            `idx_phone`(`phone`) USING BTREE,
-    INDEX            `idx_robotic_id`(`robotic_id`) USING BTREE
+    INDEX            `idx_robotic_id`(`robotic_id`) USING BTREE,
+    INDEX            `idx_user_id`(`user_id`) USING BTREE
 ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '任务外呼电话' ROW_FORMAT = DYNAMIC;
 
 -- ----------------------------
@@ -3084,7 +3085,8 @@ CREATE TABLE `crm_customer`
     INDEX                   `customer_user_id`(`customer_user_id`) USING BTREE,
     INDEX                   `company_id`(`company_id`) USING BTREE,
     INDEX                   `is_line`(`is_line`) USING BTREE,
-    INDEX                   `mobile`(`mobile`) USING BTREE
+    INDEX                   `mobile`(`mobile`) USING BTREE,
+    INDEX                   `company_receive_user_idx`(`company_id`, `receive_user_id`) USING BTREE
 ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '客户表' ROW_FORMAT = DYNAMIC;
 
 -- ----------------------------

+ 3 - 0
fs-service/src/main/resources/mapper/company/CompanyAiWorkflowExecMapper.xml

@@ -205,6 +205,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <if test="customerPhone != null and customerPhone != ''">
             AND c.phone LIKE CONCAT('%', #{customerPhone}, '%')
         </if>
+        <if test="encryptPhone != null and encryptPhone != ''">
+            AND c.phone = #{encryptPhone}
+        </if>
         <if test="onlyCallNode != null and onlyCallNode == true">
             AND e.status = 11
         </if>

+ 31 - 0
fs-service/src/main/resources/mapper/company/CompanyVoiceRoboticCallLogCallphoneMapper.xml

@@ -312,4 +312,35 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         order by t1.handle_flag asc, t1.create_time desc
     </select>
 
+    <!-- 按 customer_id(= callees.user_id)批量统计今日 AI 外呼(总数 / 接通数) -->
+    <select id="selectAiCallStatToday" resultType="com.fs.crm.vo.CustomerCallStatVO">
+        SELECT
+            ce.user_id   AS customerId,
+            COUNT(1)     AS totalCount,
+            SUM(CASE WHEN aic.call_time &gt; 0 THEN 1 ELSE 0 END) AS connectCount
+        FROM company_voice_robotic_call_log_callphone aic
+        INNER JOIN company_voice_robotic_callees ce ON ce.id = aic.caller_id
+        WHERE ce.user_id IN
+        <foreach collection="customerIds" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+        AND DATE(aic.create_time) = CURDATE()
+        GROUP BY ce.user_id
+    </select>
+
+    <!-- 按 customer_id(= callees.user_id)批量统计累计 AI 外呼(总数 / 接通数) -->
+    <select id="selectAiCallStatTotal" resultType="com.fs.crm.vo.CustomerCallStatVO">
+        SELECT
+            ce.user_id   AS customerId,
+            COUNT(1)     AS totalCount,
+            SUM(CASE WHEN aic.call_time &gt; 0 THEN 1 ELSE 0 END) AS connectCount
+        FROM company_voice_robotic_call_log_callphone aic
+        INNER JOIN company_voice_robotic_callees ce ON ce.id = aic.caller_id
+        WHERE ce.user_id IN
+        <foreach collection="customerIds" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+        GROUP BY ce.user_id
+    </select>
+
 </mapper>

+ 28 - 0
fs-service/src/main/resources/mapper/company/CrmCustomerCallLogMapper.xml

@@ -121,5 +121,33 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </where>
     </select>
 
+    <!-- 按 customer_id 批量统计今日手动外呼(总数 / 接通数) -->
+    <select id="selectManualCallStatToday" resultType="com.fs.crm.vo.CustomerCallStatVO">
+        SELECT
+            customer_id      AS customerId,
+            COUNT(1)         AS totalCount,
+            SUM(CASE WHEN call_time &gt; 0 THEN 1 ELSE 0 END) AS connectCount
+        FROM crm_customer_call_log
+        WHERE customer_id IN
+        <foreach collection="customerIds" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+        AND DATE(create_time) = CURDATE()
+        GROUP BY customer_id
+    </select>
+
+    <!-- 按 customer_id 批量统计累计手动外呼(总数 / 接通数) -->
+    <select id="selectManualCallStatTotal" resultType="com.fs.crm.vo.CustomerCallStatVO">
+        SELECT
+            customer_id      AS customerId,
+            COUNT(1)         AS totalCount,
+            SUM(CASE WHEN call_time &gt; 0 THEN 1 ELSE 0 END) AS connectCount
+        FROM crm_customer_call_log
+        WHERE customer_id IN
+        <foreach collection="customerIds" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+        GROUP BY customer_id
+    </select>
 
 </mapper>