Ver Fonte

销售端客户管理AI客户分析与客户AI聊天存档功能提交

peicj há 2 semanas atrás
pai
commit
6f494ae0d0
19 ficheiros alterados com 1199 adições e 28 exclusões
  1. 0 7
      fs-company/src/main/java/com/fs/company/controller/crm/CrmCustomerController.java
  2. 107 0
      fs-company/src/main/java/com/fs/company/controller/crm/chat/CrmCustomerChatMessageController.java
  3. 156 0
      fs-company/src/main/java/com/fs/company/controller/crm/chat/CrmCustomerChatSessionController.java
  4. 2 1
      fs-service/src/main/java/com/fs/crm/domain/CrmCustomerAnalyze.java
  5. 58 0
      fs-service/src/main/java/com/fs/crm/domain/CrmCustomerChatMessage.java
  6. 49 0
      fs-service/src/main/java/com/fs/crm/domain/CrmCustomerChatSession.java
  7. 86 0
      fs-service/src/main/java/com/fs/crm/mapper/CrmCustomerChatMessageMapper.java
  8. 60 0
      fs-service/src/main/java/com/fs/crm/mapper/CrmCustomerChatSessionMapper.java
  9. 2 11
      fs-service/src/main/java/com/fs/crm/mapper/CrmCustomerMapper.java
  10. 0 4
      fs-service/src/main/java/com/fs/crm/param/CrmCustomerListQueryParam.java
  11. 0 4
      fs-service/src/main/java/com/fs/crm/param/CrmLineCustomerListQueryParam.java
  12. 75 0
      fs-service/src/main/java/com/fs/crm/service/ICrmCustomerChatMessageService.java
  13. 53 0
      fs-service/src/main/java/com/fs/crm/service/ICrmCustomerChatSessionService.java
  14. 158 0
      fs-service/src/main/java/com/fs/crm/service/impl/CrmCustomerChatMessageServiceImpl.java
  15. 163 0
      fs-service/src/main/java/com/fs/crm/service/impl/CrmCustomerChatSessionServiceImpl.java
  16. 1 1
      fs-service/src/main/resources/application-common.yml
  17. 6 0
      fs-service/src/main/resources/mapper/crm/CrmCustomerAnalyzeMapper.xml
  18. 115 0
      fs-service/src/main/resources/mapper/crm/CrmCustomerChatMessageMapper.xml
  19. 108 0
      fs-service/src/main/resources/mapper/crm/CrmCustomerChatSessionMapper.xml

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

@@ -189,13 +189,6 @@ public class CrmCustomerController extends BaseController
         param.setCompanyId(loginUser.getCompany().getCompanyId());
 //        if(loginUser.getCompany().getCompanyId()==116){   // 河北湘银信息咨询服务有限公司(JZ-1)客户假删除不显示
 //            param.setCompanyId(0L);
-//        }
-        //默认值处理
-//        if(param.getIntentionDegreeGt() != null && param.getIntentionDegreeGt() == 0){
-//            param.setIntentionDegreeGt(null);
-//        }
-//        if(param.getIntentionDegreelt() != null && param.getIntentionDegreelt() == 0){
-//            param.setIntentionDegreelt(null);
 //        }
         if (param.getIsReceive() != null && param.getIsReceive() == 0){
             CrmLineCustomerListQueryParam param1 = new CrmLineCustomerListQueryParam();

+ 107 - 0
fs-company/src/main/java/com/fs/company/controller/crm/chat/CrmCustomerChatMessageController.java

@@ -0,0 +1,107 @@
+package com.fs.company.controller.crm.chat;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.crm.domain.CrmCustomerChatMessage;
+import com.fs.crm.service.ICrmCustomerChatMessageService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 聊天消息记录 Controller
+ * 
+ * @author ylrz
+ * @date 2026-03-30
+ */
+@RestController
+@RequestMapping("/crm/customer/chat/chatMsg")
+public class CrmCustomerChatMessageController extends BaseController {
+
+    @Autowired
+    private ICrmCustomerChatMessageService chatMessageService;
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    /**
+     * 查询聊天消息记录列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(CrmCustomerChatMessage chatMessage) {
+        // 支持游标分页参数
+        Long cursor = chatMessage.getCursor();
+        Integer limit = chatMessage.getLimit();
+        String direction = chatMessage.getDirection();
+
+        List<CrmCustomerChatMessage> list = chatMessageService.selectChatMessagesBySession(
+            chatMessage.getSessionId(), cursor, limit, direction);
+        return getDataTable(list);
+    }
+
+    /**
+     * 批量保存消息
+     */
+    @PostMapping("/batch")
+    public AjaxResult batchSave(@RequestBody Map<String, Object> params) {
+        try {
+            @SuppressWarnings("unchecked")
+            List<Map<String, Object>> messagesData = (List<Map<String, Object>>) params.get("messages");
+            
+            if (messagesData == null || messagesData.isEmpty()) {
+                return AjaxResult.error("消息列表不能为空");
+            }
+            
+            // 转换为 ChatMessage 对象
+            List<CrmCustomerChatMessage> messages = convertToChatMessages(messagesData);
+            
+            int result = chatMessageService.batchSaveChatMessages(messages);
+            return result > 0 ? AjaxResult.success("保存成功") : AjaxResult.error("保存失败");
+        } catch (Exception e) {
+            logger.error("批量保存消息失败", e);
+            return AjaxResult.error("批量保存失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 新增聊天消息记录
+     */
+    @PostMapping
+    public AjaxResult add(@RequestBody CrmCustomerChatMessage chatMessage) {
+        return toAjax(chatMessageService.insertChatMessage(chatMessage));
+    }
+
+    /**
+     * 修改聊天消息记录
+     */
+    @PutMapping
+    public AjaxResult edit(@RequestBody CrmCustomerChatMessage chatMessage) {
+        return toAjax(chatMessageService.updateChatMessage(chatMessage));
+    }
+
+    /**
+     * 删除聊天消息记录
+     */
+    @DeleteMapping("/{msgIds}")
+    public AjaxResult remove(@PathVariable Long[] msgIds) {
+        return toAjax(chatMessageService.deleteChatMessageByIds(msgIds));
+    }
+
+    /**
+     * 将 Map 转换为 ChatMessage 对象
+     */
+    private List<CrmCustomerChatMessage> convertToChatMessages(List<Map<String, Object>> messagesData) {
+        try {
+            // 使用 Jackson ObjectMapper 进行类型转换
+            String json = objectMapper.writeValueAsString(messagesData);
+            return objectMapper.readValue(json, objectMapper.getTypeFactory()
+                    .constructCollectionType(List.class, CrmCustomerChatMessage.class));
+        } catch (Exception e) {
+            logger.error("转换消息数据失败", e);
+            throw new RuntimeException("消息数据转换失败:" + e.getMessage());
+        }
+    }
+}

+ 156 - 0
fs-company/src/main/java/com/fs/company/controller/crm/chat/CrmCustomerChatSessionController.java

@@ -0,0 +1,156 @@
+package com.fs.company.controller.crm.chat;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.utils.ServletUtils;
+import com.fs.crm.domain.CrmCustomerChatMessage;
+import com.fs.crm.domain.CrmCustomerChatSession;
+import com.fs.crm.service.ICrmCustomerChatMessageService;
+import com.fs.crm.service.ICrmCustomerChatSessionService;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 聊天会话 Controller
+ * 
+ * @author ylrz
+ * @date 2026-03-30
+ */
+@RestController
+@RequestMapping("/crm/customer/chat/chatSession")
+public class CrmCustomerChatSessionController extends BaseController {
+
+    @Autowired
+    private ICrmCustomerChatSessionService chatSessionService;
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    private ICrmCustomerChatMessageService chatMessageService;
+
+    /**
+     * 查询聊天会话列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo list(CrmCustomerChatSession chatSession) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        chatSession.setUserId(loginUser.getUser().getUserId());
+        List<CrmCustomerChatSession> list = chatSessionService.selectChatSessionList(chatSession);
+        //根据会话查询对应的消息数据
+        list.forEach(session -> {
+            List<CrmCustomerChatMessage> messageList =chatMessageService.selectChatMessageBySessionIdLimit(session.getSessionId());
+            session.setMessageList(messageList);
+        });
+
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取会话详情
+     */
+    @GetMapping("/{sessionId}")
+    public AjaxResult getInfo(@PathVariable Long sessionId) {
+        return AjaxResult.success(chatSessionService.selectChatSessionById(sessionId));
+    }
+
+    /**
+     * 新增聊天会话
+     */
+    @PostMapping
+    public AjaxResult add(@RequestBody CrmCustomerChatSession chatSession) {
+        // 设置默认值
+        if (chatSession.getTitle() == null || chatSession.getTitle().isEmpty()) {
+            chatSession.setTitle("新会话");
+        }
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        chatSession.setUserId(loginUser.getUser().getUserId());
+        int result = chatSessionService.insertChatSession(chatSession);
+        if (result > 0) {
+            return AjaxResult.success(chatSession);
+        }
+        return error("新增失败");
+    }
+
+    /**
+     * 更新会话标题
+     */
+    @PutMapping("/title")
+    public AjaxResult updateTitle(@RequestBody Map<String, Object> params) {
+        try {
+            Long sessionId = Long.valueOf(params.get("sessionId").toString());
+            String title = (String) params.get("title");
+            
+            if (title == null) {
+                return error("参数错误");
+            }
+            
+            int result = chatSessionService.updateChatSessionTitle(sessionId, title);
+            return result > 0 ? success("更新成功") : error("更新失败");
+        } catch (Exception e) {
+            logger.error("更新会话标题失败", e);
+            return error("更新失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 更新置顶状态
+     */
+    @PutMapping("/pin")
+    public AjaxResult updatePin(@RequestBody Map<String, Object> params) {
+        try {
+            Long sessionId = Long.valueOf(params.get("sessionId").toString());
+            Integer isPinned = (Integer) params.get("isPinned");
+            
+            if (isPinned == null) {
+                return error("置顶参数错误");
+            }
+            int result = chatSessionService.updateChatSessionPin(sessionId, isPinned);
+            return result > 0 ? success("置顶成功") : error("置顶失败");
+        } catch (Exception e) {
+            return error("置顶失败:" + e.getMessage());
+        }
+    }
+    /**
+     * 更新客户绑定
+     */
+    @PutMapping("/customer")
+    public AjaxResult updateCustomer(@RequestBody Map<String, Object> params) {
+        try {
+            Long sessionId = Long.valueOf(params.get("sessionId").toString());
+            Long customerId = Long.parseLong(params.get("customerId").toString());
+            int result = chatSessionService.updateChatSessionCustomer(sessionId, customerId);
+            return result > 0 ? success("更新客户绑定成功") : error("更新客户绑定失败");
+        } catch (Exception e) {
+            return error("更新客户绑定失败:" + e.getMessage());
+        }
+    }
+    /**
+     * 修改聊天会话
+     */
+    @PutMapping
+    public AjaxResult edit(@RequestBody CrmCustomerChatSession chatSession) {
+        return toAjax(chatSessionService.updateChatSession(chatSession));
+    }
+
+    /**
+     * 删除聊天会话
+     */
+    @DeleteMapping("/{sessionId}")
+    public AjaxResult remove(@PathVariable Long sessionId) {
+        return toAjax(chatSessionService.deleteChatSessionById(sessionId));
+    }
+
+    /**
+     * 批量删除聊天会话
+     */
+    @DeleteMapping
+    public AjaxResult removeBatch(@RequestBody Long[] sessionIds) {
+        return toAjax(chatSessionService.deleteChatSessionByIds(sessionIds));
+    }
+}

+ 2 - 1
fs-service/src/main/java/com/fs/crm/domain/CrmCustomerAnalyze.java

@@ -65,5 +65,6 @@ public class CrmCustomerAnalyze extends BaseEntity{
     /** 预留字符串型字段 */
     @Excel(name = "预留字符串型字段")
     private String reserveStr;
-
+    /** 客户集合 */
+    private Long[] customerIds;
 }

+ 58 - 0
fs-service/src/main/java/com/fs/crm/domain/CrmCustomerChatMessage.java

@@ -0,0 +1,58 @@
+package com.fs.crm.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import java.util.Date;
+
+/**
+ * 聊天消息记录对象 crm_customer_chat_message
+ * 
+ * @author ylrz
+ * @date 2026-03-30
+ */
+@Data
+public class CrmCustomerChatMessage extends BaseEntity {
+
+    /** 消息 ID */
+    private Long msgId;
+
+    /** 会话 ID */
+    private Long sessionId;
+
+    /** 发送者类型 (1-用户 2-AI) */
+    private Integer senderType;
+
+    /** 内容类型 (1-文本 2-图片 3-文件 4-语音) */
+    private Integer contentType;
+
+    /** 消息内容 */
+    private String content;
+
+    /** 元数据 (JSON 格式存储图片 URL/文件信息等) */
+    private String metadata;
+
+    /** 消耗的 token 数量 */
+    private Integer tokenCount;
+
+    /** AI 模型名称 */
+    private String modelName;
+
+    /** 耗时 (毫秒) */
+    private Integer costTime;
+
+    /** 状态 (1-成功 0-失败) */
+    private Integer status;
+
+    /** 创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /** 更新时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+    // 支持游标分页参数
+    private Long cursor;
+    private Integer limit;
+    private String direction;
+}

+ 49 - 0
fs-service/src/main/java/com/fs/crm/domain/CrmCustomerChatSession.java

@@ -0,0 +1,49 @@
+package com.fs.crm.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 聊天会话对象 crm_customer_chat_session
+ * 
+ * @author ylrz
+ * @date 2026-03-30
+ */
+@Data
+public class CrmCustomerChatSession extends BaseEntity {
+
+    /** 会话 ID */
+    private Long sessionId;
+
+    /** 用户 ID */
+    private Long userId;
+
+    /** 关联客户 ID */
+    private Long customerId;
+
+    /** 会话标题 */
+    private String title;
+
+    /** AI 角色 ID */
+    private Long roleId;
+
+    /** 是否置顶 (0-否 1-是) */
+    private Integer isPinned;
+
+    /** 状态 (1-正常 0-删除) */
+    private Integer status;
+
+    /** 创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /** 更新时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+    /** 消息列表*/
+    private List<CrmCustomerChatMessage> messageList;
+}

+ 86 - 0
fs-service/src/main/java/com/fs/crm/mapper/CrmCustomerChatMessageMapper.java

@@ -0,0 +1,86 @@
+package com.fs.crm.mapper;
+import com.fs.crm.domain.CrmCustomerChatMessage;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * 聊天消息记录 Mapper 接口
+ * 
+ * @author ylrz
+ * @date 2026-03-30
+ */
+public interface CrmCustomerChatMessageMapper {
+
+    /**
+     * 查询聊天消息记录
+     * 
+     * @param msgId 消息 ID
+     * @return 聊天消息记录
+     */
+    CrmCustomerChatMessage selectChatMessageById(Long msgId);
+
+    /**
+     * 根据会话 ID 查询消息列表(带游标分页)
+     * 
+     * @param sessionId 会话 ID
+     * @param cursor 时间游标(加载该时间之前的消息)
+     * @param limit 每次加载的数量
+     * @param direction 方向(before-向前加载,after-向后加载)
+     * @return 消息列表
+     */
+    List<CrmCustomerChatMessage> selectChatMessagesBySession(
+        @Param("sessionId") Long sessionId,
+        @Param("cursor") Long cursor,
+        @Param("limit") Integer limit,
+        @Param("direction") String direction
+    );
+
+    /**
+     * 批量插入消息记录
+     * 
+     * @param messages 消息列表
+     * @return 影响行数
+     */
+    int batchInsertChatMessage(@Param("messages") List<CrmCustomerChatMessage> messages);
+
+    /**
+     * 新增聊天消息记录
+     * 
+     @param chatMessage 聊天消息记录
+     * @return 影响行数
+     */
+    int insertChatMessage(CrmCustomerChatMessage chatMessage);
+
+    /**
+     * 修改聊天消息记录
+     * 
+     * @param chatMessage 聊天消息记录
+     * @return 影响行数
+     */
+    int updateChatMessage(CrmCustomerChatMessage chatMessage);
+
+    /**
+     * 删除聊天消息记录
+     * 
+     * @param msgId 消息 ID
+     * @return 影响行数
+     */
+    int deleteChatMessageById(Long msgId);
+
+    /**
+     * 批量删除聊天消息记录
+     * 
+     * @param msgIds 需要删除的消息 ID 数组
+     * @return 影响行数
+     */
+    int deleteChatMessageByIds(Long[] msgIds);
+
+    /**
+     * 根据会话 ID 查询消息分页列表
+     * @param sessionId sessionId
+     */
+    @Select("SELECT * FROM crm_customer_chat_message WHERE session_id = #{sessionId} ORDER BY create_time DESC LIMIT 50")
+    List<CrmCustomerChatMessage> selectChatMessageBySessionIdLimit(@Param("sessionId") Long sessionId);
+}

+ 60 - 0
fs-service/src/main/java/com/fs/crm/mapper/CrmCustomerChatSessionMapper.java

@@ -0,0 +1,60 @@
+package com.fs.crm.mapper;
+
+import com.fs.crm.domain.CrmCustomerChatSession;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Update;
+
+import java.util.List;
+
+/**
+ * 聊天会话 Mapper 接口
+ */
+public interface CrmCustomerChatSessionMapper {
+
+    /**
+     * 查询聊天会话
+     */
+    CrmCustomerChatSession selectChatSessionById(Long sessionId);
+
+    /**
+     * 查询聊天会话列表
+     */
+    List<CrmCustomerChatSession> selectChatSessionList(CrmCustomerChatSession chatSession);
+
+    /**
+     * 新增聊天会话
+     */
+    int insertChatSession(CrmCustomerChatSession chatSession);
+
+    /**
+     * 修改聊天会话
+     */
+    int updateChatSession(CrmCustomerChatSession chatSession);
+
+    /**
+     * 删除聊天会话
+     */
+    int deleteChatSessionById(Long sessionId);
+
+    /**
+     * 批量删除聊天会话
+     */
+    int deleteChatSessionByIds(Long[] sessionIds);
+
+    /**
+     * 更新会话标题
+     */
+    int updateChatSessionTitle(@Param("sessionId") Long sessionId, @Param("title") String title);
+
+    /**
+     * 更新置顶状态
+     */
+    int updateChatSessionPin(@Param("sessionId") Long sessionId, @Param("isPinned") Integer isPinned);
+
+    int updateChatSessionCustomer(@Param("sessionId") Long sessionId, @Param("customerId") Long customerId);
+    /**
+     * 更新用户所有会话的置顶状态为0
+     */
+    @Update("update crm_customer_chat_session set is_pinned = 0 where user_id = #{userId}")
+    int updateIsPinnedByUserId(@Param("userId") Long userId);
+}

+ 2 - 11
fs-service/src/main/java/com/fs/crm/mapper/CrmCustomerMapper.java

@@ -357,11 +357,8 @@ public interface CrmCustomerMapper extends BaseMapper<CrmCustomer> {
             "<if test = 'maps.attritionLevel != null'> " +
             "and ca.attrition_level = #{maps.attritionLevel} " +
             "</if>" +
-            "<if test = 'maps.intentionDegreeGt != null'> " +
-            "and ca.intention_degree &gt;= #{maps.intentionDegreeGt} " +
-            "</if>" +
-            "<if test = 'maps.intentionDegreelt != null'> " +
-            "and ca.intention_degree &lt;= #{maps.intentionDegreelt} " +
+            "<if test = 'maps.intentionDegree != null and maps.intentionDegree != \"\" ' > " +
+            "and ca.intention_degree = #{maps.intentionDegree} " +
             "</if>" +
             "<if test = 'maps.companyId != null     '> " +
             "and c.company_id =#{maps.companyId} " +
@@ -503,12 +500,6 @@ public interface CrmCustomerMapper extends BaseMapper<CrmCustomer> {
             "<if test = 'maps.attritionLevel != null'> " +
             "and ca.attrition_level = #{maps.attritionLevel} " +
             "</if>" +
-            "<if test = 'maps.intentionDegreeGt != null'> " +
-            "and ca.intention_degree &gt;= #{maps.intentionDegreeGt} " +
-            "</if>" +
-            "<if test = 'maps.intentionDegreelt != null'> " +
-            "and ca.intention_degree &lt;= #{maps.intentionDegreelt} " +
-            "</if>" +
             "<if test = 'maps.intentionDegree != null and maps.intentionDegree != \"\" ' > " +
             "and ca.intention_degree = #{maps.intentionDegree} " +
             "</if>" +

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

@@ -105,10 +105,6 @@ public class CrmCustomerListQueryParam extends BaseQueryParam
 
     /** 流失风险等级 0:无风险;1:低风险;2:中风险;3:高风险 */
     private Long attritionLevel;
-    /** 意向度>= */
-    private Long intentionDegreeGt;
-    /** 意向度<= */
-    private Long intentionDegreelt;
     /** 意向度 */
     private String intentionDegree;
 

+ 0 - 4
fs-service/src/main/java/com/fs/crm/param/CrmLineCustomerListQueryParam.java

@@ -87,10 +87,6 @@ public class CrmLineCustomerListQueryParam extends BaseQueryParam
 
     /** 流失风险等级 0:无风险;1:低风险;2:中风险;3:高风险 */
     private Long attritionLevel;
-    /** 意向度>= */
-    private Long intentionDegreeGt;
-    /** 意向度<= */
-    private Long intentionDegreelt;
 
     /** 意向度 */
     private String intentionDegree;

+ 75 - 0
fs-service/src/main/java/com/fs/crm/service/ICrmCustomerChatMessageService.java

@@ -0,0 +1,75 @@
+package com.fs.crm.service;
+
+import com.fs.crm.domain.CrmCustomerChatMessage;
+
+import java.util.List;
+
+/**
+ * 聊天消息记录 Service 接口
+ * 
+ * @author ylrz
+ * @date 2026-03-30
+ */
+public interface ICrmCustomerChatMessageService {
+
+    /**
+     * 查询聊天消息记录
+     * 
+     * @param msgId 消息 ID
+     * @return 聊天消息记录
+     */
+    CrmCustomerChatMessage selectChatMessageById(Long msgId);
+
+    /**
+     * 根据会话 ID 查询消息列表(带游标分页)
+     * 
+     * @param sessionId 会话 ID
+     * @param cursor 时间游标
+     * @param limit 每次加载数量
+     * @param direction 方向
+     * @return 消息列表
+     */
+    List<CrmCustomerChatMessage> selectChatMessagesBySession(Long sessionId, Long cursor, Integer limit, String direction);
+
+    /**
+     * 批量保存消息
+     * 
+     * @param messages 消息列表
+     * @return 影响行数
+     */
+    int batchSaveChatMessages(List<CrmCustomerChatMessage> messages);
+
+    /**
+     * 新增聊天消息记录
+     * 
+     * @param chatMessage 聊天消息记录
+     * @return 影响行数
+     */
+    int insertChatMessage(CrmCustomerChatMessage chatMessage);
+
+    /**
+     * 修改聊天消息记录
+     * 
+     * @param chatMessage 聊天消息记录
+     * @return 影响行数
+     */
+    int updateChatMessage(CrmCustomerChatMessage chatMessage);
+
+    /**
+     * 删除聊天消息记录
+     * 
+     * @param msgIds 需要删除的消息 ID 数组
+     * @return 影响行数
+     */
+    int deleteChatMessageByIds(Long[] msgIds);
+
+    /**
+     * 批量删除聊天消息记录
+     * 
+     * @param msgIds 消息 ID 数组
+     * @return 影响行数
+     */
+    int batchDeleteChatMessage(Long[] msgIds);
+
+    List<CrmCustomerChatMessage> selectChatMessageBySessionIdLimit(Long sessionId);
+}

+ 53 - 0
fs-service/src/main/java/com/fs/crm/service/ICrmCustomerChatSessionService.java

@@ -0,0 +1,53 @@
+package com.fs.crm.service;
+
+import com.fs.crm.domain.CrmCustomerChatSession;
+
+import java.util.List;
+
+/**
+ * 聊天会话 Service 接口
+ */
+public interface ICrmCustomerChatSessionService {
+
+    /**
+     * 查询聊天会话
+     */
+    CrmCustomerChatSession selectChatSessionById(Long sessionId);
+
+    /**
+     * 查询聊天会话列表
+     */
+    List<CrmCustomerChatSession> selectChatSessionList(CrmCustomerChatSession chatSession);
+
+    /**
+     * 新增聊天会话
+     */
+    int insertChatSession(CrmCustomerChatSession chatSession);
+
+    /**
+     * 修改聊天会话
+     */
+    int updateChatSession(CrmCustomerChatSession chatSession);
+
+    /**
+     * 更新会话标题
+     */
+    int updateChatSessionTitle(Long sessionId, String title);
+
+    /**
+     * 更新置顶状态
+     */
+    int updateChatSessionPin(Long sessionId, Integer isPinned);
+
+    /**
+     * 批量删除聊天会话
+     */
+    int deleteChatSessionByIds(Long[] sessionIds);
+
+    /**
+     * 删除聊天会话信息
+     */
+    int deleteChatSessionById(Long sessionId);
+
+    int updateChatSessionCustomer(Long sessionId, Long customerId);
+}

+ 158 - 0
fs-service/src/main/java/com/fs/crm/service/impl/CrmCustomerChatMessageServiceImpl.java

@@ -0,0 +1,158 @@
+package com.fs.crm.service.impl;
+
+import com.fs.common.utils.DateUtils;
+import com.fs.crm.domain.CrmCustomerChatMessage;
+import com.fs.crm.mapper.CrmCustomerChatMessageMapper;
+import com.fs.crm.service.ICrmCustomerChatMessageService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 聊天消息记录 Service 业务层处理
+ * 
+ * @author ylrz
+ * @date 2026-03-30
+ */
+@Slf4j
+@Service
+public class CrmCustomerChatMessageServiceImpl implements ICrmCustomerChatMessageService {
+
+    @Autowired
+    private CrmCustomerChatMessageMapper chatMessageMapper;
+
+    /**
+     * 查询聊天消息记录
+     * 
+     * @param msgId 消息 ID
+     * @return 聊天消息记录
+     */
+    @Override
+    public CrmCustomerChatMessage selectChatMessageById(Long msgId) {
+        return chatMessageMapper.selectChatMessageById(msgId);
+    }
+
+    /**
+     * 根据会话 ID 查询消息列表(带游标分页)
+     * 
+     * @param sessionId 会话 ID
+     * @param cursor 时间游标
+     * @param limit 每次加载数量
+     * @param direction 方向
+     * @return 消息列表
+     */
+    @Override
+    public List<CrmCustomerChatMessage> selectChatMessagesBySession(Long sessionId, Long cursor, Integer limit, String direction) {
+        // 默认每次加载 50 条
+        if (limit == null) {
+            limit = 50;
+        }
+        return chatMessageMapper.selectChatMessagesBySession(sessionId, cursor, limit, direction);
+    }
+
+    /**
+     * 批量保存消息
+     * 
+     * @param messages 消息列表
+     * @return 影响行数
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int batchSaveChatMessages(List<CrmCustomerChatMessage> messages) {
+        if (messages == null || messages.isEmpty()) {
+            return 0;
+        }
+        
+        try {
+            // 设置默认值
+            for (CrmCustomerChatMessage message : messages) {
+                if (message.getStatus() == null) {
+                    message.setStatus(1);
+                }
+                if (message.getContentType() == null) {
+                    message.setContentType(1); // 默认文本
+                }
+                if (message.getCreateTime() == null) {
+                    message.setCreateTime(DateUtils.getNowDate());
+                }
+            }
+            
+            // 批量插入
+            int result = chatMessageMapper.batchInsertChatMessage(messages);
+            log.info("批量保存消息成功,保存数量:{}", messages.size());
+            return result;
+        } catch (Exception e) {
+            log.error("批量保存消息失败", e);
+            throw new RuntimeException("批量保存消息失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 新增聊天消息记录
+     * 
+     * @param chatMessage 聊天消息记录
+     * @return 影响行数
+     */
+    @Override
+    public int insertChatMessage(CrmCustomerChatMessage chatMessage) {
+        if (chatMessage.getCreateTime() == null) {
+            chatMessage.setCreateTime(DateUtils.getNowDate());
+        }
+        if (chatMessage.getStatus() == null) {
+            chatMessage.setStatus(1);
+        }
+        int result = chatMessageMapper.insertChatMessage(chatMessage);
+        log.info("新增消息成功,msgId: {}", chatMessage.getMsgId());
+        return result;
+    }
+
+    /**
+     * 修改聊天消息记录
+     * 
+     * @param chatMessage 聊天消息记录
+     * @return 影响行数
+     */
+    @Override
+    public int updateChatMessage(CrmCustomerChatMessage chatMessage) {
+        chatMessage.setUpdateTime(DateUtils.getNowDate());
+        int result = chatMessageMapper.updateChatMessage(chatMessage);
+        log.info("更新消息成功,msgId: {}", chatMessage.getMsgId());
+        return result;
+    }
+
+    /**
+     * 批量删除聊天消息记录
+     * 
+     * @param msgIds 需要删除的消息 ID 数组
+     * @return 影响行数
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int deleteChatMessageByIds(Long[] msgIds) {
+        if (msgIds == null || msgIds.length == 0) {
+            return 0;
+        }
+        int result = chatMessageMapper.deleteChatMessageByIds(msgIds);
+        log.info("批量删除消息成功,删除数量:{}", msgIds.length);
+        return result;
+    }
+
+    /**
+     * 删除聊天消息记录信息
+     * 
+     * @param msgIds 消息 ID
+     * @return 影响行数
+     */
+    @Override
+    public int batchDeleteChatMessage(Long[] msgIds) {
+        return this.deleteChatMessageByIds(msgIds);
+    }
+
+    @Override
+    public List<CrmCustomerChatMessage> selectChatMessageBySessionIdLimit(Long sessionId) {
+        return chatMessageMapper.selectChatMessageBySessionIdLimit(sessionId);
+    }
+}

+ 163 - 0
fs-service/src/main/java/com/fs/crm/service/impl/CrmCustomerChatSessionServiceImpl.java

@@ -0,0 +1,163 @@
+package com.fs.crm.service.impl;
+
+import com.fs.common.utils.DateUtils;
+import com.fs.crm.domain.CrmCustomerChatSession;
+import com.fs.crm.mapper.CrmCustomerChatSessionMapper;
+import com.fs.crm.service.ICrmCustomerChatSessionService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+/**
+ * 聊天会话 Service 业务层处理
+ * 
+ * @author ylrz
+ * @date 2026-03-30
+ */
+@Slf4j
+@Service
+public class CrmCustomerChatSessionServiceImpl implements ICrmCustomerChatSessionService {
+
+    @Autowired
+    private CrmCustomerChatSessionMapper chatSessionMapper;
+
+    /**
+     * 查询聊天会话
+     * 
+     * @param sessionId 会话 ID
+     * @return 聊天会话
+     */
+    @Override
+    public CrmCustomerChatSession selectChatSessionById(Long sessionId) {
+        return chatSessionMapper.selectChatSessionById(sessionId);
+    }
+
+    /**
+     * 查询聊天会话列表
+     * 
+     * @param chatSession 聊天会话
+     * @return 聊天会话
+     */
+    @Override
+    public List<CrmCustomerChatSession> selectChatSessionList(CrmCustomerChatSession chatSession) {
+        // 默认按置顶降序,时间降序排列
+        return chatSessionMapper.selectChatSessionList(chatSession);
+    }
+
+    /**
+     * 新增聊天会话
+     * 
+     * @param chatSession 聊天会话
+     * @return 影响行数
+     */
+    @Override
+    public int insertChatSession(CrmCustomerChatSession chatSession) {
+        if (chatSession.getCreateTime() == null) {
+            chatSession.setCreateTime(DateUtils.getNowDate());
+        }
+        if (chatSession.getStatus() == null) {
+            chatSession.setStatus(1);
+        }
+        if (chatSession.getIsPinned() == null) {
+            chatSession.setIsPinned(0);
+        }
+        int result = chatSessionMapper.insertChatSession(chatSession);
+        log.info("新增会话成功,sessionId: {}", chatSession.getSessionId());
+        return result;
+    }
+
+    /**
+     * 修改聊天会话
+     * 
+     * @param chatSession 聊天会话
+     * @return 影响行数
+     */
+    @Override
+    public int updateChatSession(CrmCustomerChatSession chatSession) {
+        chatSession.setUpdateTime(DateUtils.getNowDate());
+        int result = chatSessionMapper.updateChatSession(chatSession);
+        log.info("更新会话成功,sessionId: {}", chatSession.getSessionId());
+        return result;
+    }
+
+    /**
+     * 更新会话标题
+     * 
+     * @param sessionId 会话 ID
+     * @param title 新标题
+     * @return 影响行数
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int updateChatSessionTitle(Long sessionId, String title) {
+        try {
+            int result = chatSessionMapper.updateChatSessionTitle(sessionId, title);
+            log.info("更新会话标题成功,sessionId: {}, title: {}", sessionId, title);
+            return result;
+        } catch (Exception e) {
+            log.error("更新会话标题失败", e);
+            throw new RuntimeException("更新会话标题失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 更新置顶状态
+     * 
+     * @param sessionId 会话 ID
+     * @param isPinned 是否置顶
+     * @return 影响行数
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int updateChatSessionPin(Long sessionId, Integer isPinned) {
+        try {
+            CrmCustomerChatSession crmCustomerChatSession = chatSessionMapper.selectChatSessionById(sessionId);
+            if(crmCustomerChatSession != null){
+                chatSessionMapper.updateIsPinnedByUserId(crmCustomerChatSession.getUserId());
+                //再处理置顶数据为1
+                return chatSessionMapper.updateChatSessionPin(sessionId, isPinned);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("更新置顶状态失败:" + e.getMessage());
+        }
+        return 0;
+    }
+
+    /**
+     * 批量删除聊天会话
+     * 
+     * @param sessionIds 需要删除的会话 ID 数组
+     * @return 影响行数
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int deleteChatSessionByIds(Long[] sessionIds) {
+        if (sessionIds == null || sessionIds.length == 0) {
+            return 0;
+        }
+        int result = chatSessionMapper.deleteChatSessionByIds(sessionIds);
+        log.info("批量删除会话成功,删除数量:{}", sessionIds.length);
+        return result;
+    }
+
+    /**
+     * 删除聊天会话信息
+     * 
+     * @param sessionId 会话 ID
+     * @return 影响行数
+     */
+    @Override
+    public int deleteChatSessionById(Long sessionId) {
+        int result = chatSessionMapper.deleteChatSessionById(sessionId);
+        log.info("删除会话成功,sessionId: {}", sessionId);
+        return result;
+    }
+
+    @Override
+    public int updateChatSessionCustomer(Long sessionId, Long customerId) {
+        return chatSessionMapper.updateChatSessionCustomer(sessionId, customerId);
+    }
+}

+ 1 - 1
fs-service/src/main/resources/application-common.yml

@@ -36,7 +36,7 @@ server:
 # 日志配置
 logging:
   level:
-    com.fs: info
+    com.fs: DEBUG
     org.springframework: warn
 
 express:

+ 6 - 0
fs-service/src/main/resources/mapper/crm/CrmCustomerAnalyzeMapper.xml

@@ -178,6 +178,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="aiChatRecord != null  and aiChatRecord != ''"> and a.ai_chat_record = #{aiChatRecord}</if>
             <if test="reserveInt != null "> and a.reserve_int = #{reserveInt}</if>
             <if test="reserveStr != null  and reserveStr != ''"> and a.reserve_str = #{reserveStr}</if>
+            <if test="customerIds != null and customerIds.length > 0">
+                and a.customer_id in
+                <foreach item="customerId" collection="customerIds" open="(" separator="," close=")">
+                    #{customerId}
+                </foreach>
+            </if>
         </where>
         order by a.create_time desc
     </select>

+ 115 - 0
fs-service/src/main/resources/mapper/crm/CrmCustomerChatMessageMapper.xml

@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.crm.mapper.CrmCustomerChatMessageMapper">
+
+    <resultMap type="CrmCustomerChatMessage" id="ChatMessageResult">
+        <result property="msgId"    column="msg_id"    />
+        <result property="sessionId"    column="session_id"    />
+        <result property="senderType"    column="sender_type"    />
+        <result property="contentType"    column="content_type"    />
+        <result property="content"    column="content"    />
+        <result property="metadata"    column="metadata"    />
+        <result property="tokenCount"    column="token_count"    />
+        <result property="modelName"    column="model_name"    />
+        <result property="costTime"    column="cost_time"    />
+        <result property="status"    column="status"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <!-- 查询消息列表(带游标分页) -->
+    <select id="selectChatMessagesBySession" parameterType="java.util.HashMap" resultMap="ChatMessageResult">
+        SELECT msg_id, session_id, sender_type, content_type, content, metadata,
+               token_count, model_name, cost_time, status, create_time
+        FROM crm_customer_chat_message
+        WHERE session_id = #{sessionId}
+          AND status = 1
+        <if test="cursor != null">
+            <choose>
+                <when test="direction == 'before'">
+                    AND create_time &lt; FROM_UNIXTIME(#{cursor} / 1000)
+                </when>
+                <when test="direction == 'after'">
+                    AND create_time &gt; FROM_UNIXTIME(#{cursor} / 1000)
+                </when>
+            </choose>
+        </if>
+        ORDER BY create_time DESC
+        LIMIT #{limit}
+    </select>
+    <select id="selectChatMessageById" parameterType="Long" resultType="com.fs.crm.domain.CrmCustomerChatMessage">
+        SELECT * FROM crm_customer_chat_message WHERE msg_id = #{msgId}
+    </select>
+
+    <!-- 批量插入消息 -->
+    <insert id="batchInsertChatMessage" parameterType="java.util.List">
+        INSERT INTO crm_customer_chat_message
+        (session_id, sender_type, content_type, content, metadata, token_count, model_name, cost_time, status, create_time)
+        VALUES
+        <foreach item="message" collection="messages" separator=",">
+            (#{message.sessionId}, #{message.senderType}, #{message.contentType}, #{message.content},
+             #{message.metadata}, #{message.tokenCount}, #{message.modelName}, #{message.costTime},
+             #{message.status}, NOW())
+        </foreach>
+    </insert>
+
+    <!-- 新增消息 -->
+    <insert id="insertChatMessage" parameterType="com.fs.crm.domain.CrmCustomerChatMessage">
+        INSERT INTO crm_customer_chat_message
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="sessionId != null">session_id,</if>
+            <if test="senderType != null">sender_type,</if>
+            <if test="contentType != null">content_type,</if>
+            <if test="content != null and content != ''">content,</if>
+            <if test="metadata != null">metadata,</if>
+            <if test="tokenCount != null">token_count,</if>
+            <if test="modelName != null">model_name,</if>
+            <if test="costTime != null">cost_time,</if>
+            <if test="status != null">status,</if>
+            create_time,
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="sessionId != null">#{sessionId},</if>
+            <if test="senderType != null">#{senderType},</if>
+            <if test="contentType != null">#{contentType},</if>
+            <if test="content != null and content != ''">#{content},</if>
+            <if test="metadata != null">#{metadata},</if>
+            <if test="tokenCount != null">#{tokenCount},</if>
+            <if test="modelName != null">#{modelName},</if>
+            <if test="costTime != null">#{costTime},</if>
+            <if test="status != null">#{status},</if>
+            NOW(),
+        </trim>
+    </insert>
+
+    <!-- 更新消息 -->
+    <update id="updateChatMessage" parameterType="com.fs.crm.domain.CrmCustomerChatMessage">
+        UPDATE crm_customer_chat_message
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="content != null">content = #{content},</if>
+            <if test="metadata != null">metadata = #{metadata},</if>
+            <if test="tokenCount != null">token_count = #{tokenCount},</if>
+            <if test="modelName != null">model_name = #{modelName},</if>
+            <if test="costTime != null">cost_time = #{costTime},</if>
+            <if test="status != null">status = #{status},</if>
+            update_time = NOW(),
+        </trim>
+        WHERE msg_id = #{msgId}
+    </update>
+
+    <!-- 删除消息 -->
+    <delete id="deleteChatMessageById" parameterType="Long">
+        DELETE FROM crm_customer_chat_message WHERE msg_id = #{msgId}
+    </delete>
+
+    <!-- 批量删除消息 -->
+    <delete id="deleteChatMessageByIds" parameterType="Long">
+        DELETE FROM crm_customer_chat_message WHERE msg_id IN
+        <foreach item="msgId" collection="array" open="(" separator="," close=")">
+            #{msgId}
+        </foreach>
+    </delete>
+
+</mapper>

+ 108 - 0
fs-service/src/main/resources/mapper/crm/CrmCustomerChatSessionMapper.xml

@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.crm.mapper.CrmCustomerChatSessionMapper">
+
+    <resultMap type="CrmCustomerChatSession" id="ChatSessionResult">
+        <result property="sessionId"    column="session_id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="customerId"    column="customer_id"    />
+        <result property="title"    column="title"    />
+        <result property="roleId"    column="role_id"    />
+        <result property="isPinned"    column="is_pinned"    />
+        <result property="status"    column="status"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <!-- 查询会话列表 -->
+    <select id="selectChatSessionList" parameterType="com.fs.crm.domain.CrmCustomerChatSession" resultMap="ChatSessionResult">
+        SELECT session_id, user_id, customer_id, title, role_id, is_pinned, status, create_time, update_time
+        FROM crm_customer_chat_session
+        WHERE status = 1
+        <if test="userId != null">
+            AND user_id = #{userId}
+        </if>
+        <if test="customerId != null">
+            AND customer_id = #{customerId}
+        </if>
+        ORDER BY is_pinned DESC, create_time DESC
+    </select>
+
+    <!-- 查询会话详情 -->
+    <select id="selectChatSessionById" parameterType="Long" resultMap="ChatSessionResult">
+        SELECT session_id, user_id, customer_id, title, role_id, is_pinned, status, create_time, update_time
+        FROM crm_customer_chat_session
+        WHERE session_id = #{sessionId} AND status = 1
+    </select>
+
+    <!-- 新增会话 -->
+    <insert id="insertChatSession" parameterType="com.fs.crm.domain.CrmCustomerChatSession" useGeneratedKeys="true" keyProperty="sessionId">
+        INSERT INTO crm_customer_chat_session
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="userId != null">user_id,</if>
+            <if test="customerId != null">customer_id,</if>
+            <if test="title != null and title != ''">title,</if>
+            <if test="roleId != null">role_id,</if>
+            <if test="isPinned != null">is_pinned,</if>
+            <if test="status != null">status,</if>
+            create_time,
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="userId != null">#{userId},</if>
+            <if test="customerId != null">#{customerId},</if>
+            <if test="title != null and title != ''">#{title},</if>
+            <if test="roleId != null">#{roleId},</if>
+            <if test="isPinned != null">#{isPinned},</if>
+            <if test="status != null">#{status},</if>
+            NOW(),
+        </trim>
+    </insert>
+
+    <!-- 更新会话 -->
+    <update id="updateChatSession" parameterType="com.fs.crm.domain.CrmCustomerChatSession">
+        UPDATE crm_customer_chat_session
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="title != null">title = #{title},</if>
+            <if test="roleId != null">role_id = #{roleId},</if>
+            <if test="isPinned != null">is_pinned = #{isPinned},</if>
+            <if test="status != null">status = #{status},</if>
+            update_time = NOW(),
+        </trim>
+        WHERE session_id = #{sessionId}
+    </update>
+
+    <!-- 更新会话标题 -->
+    <update id="updateChatSessionTitle">
+        UPDATE crm_customer_chat_session
+        SET title = #{title}, update_time = NOW()
+        WHERE session_id = #{sessionId}
+    </update>
+
+    <!-- 更新置顶状态 -->
+    <update id="updateChatSessionPin">
+        UPDATE crm_customer_chat_session
+        SET is_pinned = #{isPinned}, update_time = NOW()
+        WHERE session_id = #{sessionId}
+    </update>
+
+    <!-- 删除会话(逻辑删除) -->
+    <update id="deleteChatSessionById" parameterType="Long">
+        UPDATE crm_customer_chat_session SET status = 0, update_time = NOW() WHERE session_id = #{sessionId}
+    </update>
+
+    <!-- 批量删除会话 -->
+    <update id="deleteChatSessionByIds" parameterType="Long">
+        UPDATE crm_customer_chat_session SET status = 0, update_time = NOW() WHERE session_id IN
+        <foreach item="sessionId" collection="array" open="(" separator="," close=")">
+            #{sessionId}
+        </foreach>
+    </update>
+    <update id="updateChatSessionCustomer">
+        UPDATE crm_customer_chat_session
+        SET customer_id = #{customerId}, update_time = NOW()
+        WHERE session_id = #{sessionId}
+    </update>
+
+</mapper>