Răsfoiți Sursa

feet:AI分配跟踪人员对接和通知发送

panzhilin 3 zile în urmă
părinte
comite
5b17e2042e

+ 295 - 0
alien-store/src/main/java/shop/alien/store/service/impl/LifeFeedbackServiceImpl.java

@@ -21,6 +21,9 @@ import shop.alien.mapper.LifeFeedbackMapper;
 import shop.alien.mapper.LifeLogMapper;
 import shop.alien.mapper.LifeNoticeMapper;
 import shop.alien.mapper.StoreUserMapper;
+import shop.alien.mapper.LifeSysMapper;
+import shop.alien.entity.store.LifeSys;
+import shop.alien.store.util.ai.AiFeedbackAssignUtils;
 import shop.alien.entity.store.LifeNotice;
 import shop.alien.entity.store.StoreUser;
 import shop.alien.entity.store.vo.WebSocketVo;
@@ -29,6 +32,7 @@ import shop.alien.store.service.LifeFeedbackService;
 import shop.alien.store.service.LifeFeedbackReplyService;
 import shop.alien.store.service.LifeImgService;
 import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 
 import java.util.Date;
 import java.util.List;
@@ -50,6 +54,8 @@ public class LifeFeedbackServiceImpl extends ServiceImpl<LifeFeedbackMapper, Lif
     private final LifeNoticeMapper lifeNoticeMapper;
     private final StoreUserMapper storeUserMapper;
     private final WebSocketProcess webSocketProcess;
+    private final AiFeedbackAssignUtils aiFeedbackAssignUtils;
+    private final LifeSysMapper lifeSysMapper;
 
     @Override
     public R<String> submitFeedback(LifeFeedbackDto dto) {
@@ -155,6 +161,27 @@ public class LifeFeedbackServiceImpl extends ServiceImpl<LifeFeedbackMapper, Lif
             // 4. 记录日志(只记录详细内容)
             saveLog(feedback.getId(), feedback.getContent(), "0");
 
+            // 5. 调用AI分配跟踪人员
+            // 根据AI接口文档:用户端和商户端反馈都需要分配跟踪人员
+            // AI返回的 staff_id 对应 life_sys 表的 id
+            Integer assignedStaffId = assignStaffByAI(feedback);
+            if (assignedStaffId != null) {
+                // 更新反馈记录的跟踪人员(虽然AI接口会自动更新,但本地也需要同步更新)
+                feedback.setStaffId(assignedStaffId);
+                this.updateById(feedback);
+                
+                // 记录分配跟踪人员日志
+                saveLog(feedback.getId(), "已分配跟踪人员,ID: " + assignedStaffId + " (life_sys)", "1");
+                
+                // 发送分配跟踪人员通知给中台(平台端跟踪人员)
+                sendStaffAssignmentNotice(feedback, assignedStaffId);
+            }
+
+            // 6. 发送提交反馈工单通知到中台(需要已分配跟踪人员)
+            if (feedback.getStaffId() != null) {
+                sendFeedbackSubmittedNoticeToPlatform(feedback);
+            }
+            
             return R.success("提交成功");
         } catch (Exception e) {
             log.error("提交反馈失败", e);
@@ -340,6 +367,9 @@ public class LifeFeedbackServiceImpl extends ServiceImpl<LifeFeedbackMapper, Lif
             // 4. 记录日志(只记录内容)
             saveLog(dto.getFeedbackId(), dto.getContent(), "2");
 
+            // 5. 发送用户回复通知给平台端(跟踪人员)
+            sendUserReplyNoticeToPlatform(originalFeedback, dto.getContent());
+
             return R.success("回复成功");
         } catch (Exception e) {
             log.error("用户回复失败", e);
@@ -701,5 +731,270 @@ public class LifeFeedbackServiceImpl extends ServiceImpl<LifeFeedbackMapper, Lif
             log.error("发送平台回复通知异常,feedbackId={}, error={}", feedback.getId(), e.getMessage(), e);
         }
     }
+
+    /**
+     * 调用AI分配跟踪人员
+     * @param feedback 反馈记录
+     * @return 分配的跟踪人员ID(对应life_sys表的id),失败返回null
+     */
+    private Integer assignStaffByAI(LifeFeedback feedback) {
+        try {
+            // 调用AI工具类分配跟踪人员(只需要feedback_id)
+            return aiFeedbackAssignUtils.assignStaffByAI(feedback);
+        } catch (Exception e) {
+            log.error("调用AI分配跟踪人员失败,feedbackId={}, error={}", feedback.getId(), e.getMessage(), e);
+            return null;
+        }
+    }
+
+    /**
+     * 发送分配跟踪人员通知给中台(平台端)
+     * 
+     * 根据AI接口文档:
+     * - staff_id 对应 life_sys 表的 id
+     * - 用户端和商户端反馈都需要发送通知
+     * 
+     * @param feedback 反馈记录
+     * @param staffId 跟踪人员ID(对应life_sys表的id)
+     */
+    private void sendStaffAssignmentNotice(LifeFeedback feedback, Integer staffId) {
+        try {
+            // 如果没有分配跟踪人员,则无法发送通知
+            if (staffId == null) {
+                log.warn("未分配跟踪人员,无法发送通知,feedbackId={}", feedback.getId());
+                return;
+            }
+            
+            // 查询跟踪人员信息(从life_sys表查询)
+            LifeSys staff = lifeSysMapper.selectById(staffId);
+            if (staff == null) {
+                log.warn("未找到跟踪人员信息(life_sys),无法发送通知,staffId={}, feedbackId={}", 
+                        staffId, feedback.getId());
+                return;
+            }
+            
+            // 平台端接收者ID格式:staff_{staffId}(与用户回复通知保持一致)
+            String receiverId = "staff_" + staffId;
+            
+            // 获取用户信息(用于显示在通知中)
+            String userName = "用户";
+            if (feedback.getUserId() != null) {
+                StoreUser storeUser = storeUserMapper.selectById(feedback.getUserId());
+                if (storeUser != null && storeUser.getPhone() != null) {
+                    userName = storeUser.getPhone();
+                }
+            }
+            
+            // 获取反馈来源名称
+            String sourceName = feedback.getFeedbackSource() != null && feedback.getFeedbackSource() == 1 ? "商户" : "用户";
+            
+            // 构建通知消息
+            JSONObject messageJson = new JSONObject();
+            messageJson.put("feedbackId", feedback.getId());
+            messageJson.put("staffId", staffId);
+            messageJson.put("staffName", staff.getUserName()); // life_sys表使用userName字段
+            messageJson.put("userId", feedback.getUserId());
+            messageJson.put("userName", userName);
+            messageJson.put("feedbackSource", feedback.getFeedbackSource());
+            messageJson.put("feedbackContent", feedback.getContent());
+            messageJson.put("message", "您已被分配处理" + sourceName + "反馈工单,反馈内容:" + feedback.getContent());
+
+            // 创建通知记录
+            LifeNotice lifeNotice = new LifeNotice();
+            lifeNotice.setReceiverId(receiverId);
+            lifeNotice.setContext(messageJson.toJSONString());
+            lifeNotice.setTitle("反馈工单分配通知");
+            lifeNotice.setSenderId("system");
+            lifeNotice.setIsRead(0);
+            lifeNotice.setNoticeType(1); // 1-系统通知
+            lifeNotice.setBusinessId(feedback.getId());
+            
+            // 保存通知
+            lifeNoticeMapper.insert(lifeNotice);
+            
+            // 通过WebSocket发送实时通知
+            WebSocketVo webSocketVo = new WebSocketVo();
+            webSocketVo.setSenderId("system");
+            webSocketVo.setReceiverId(receiverId);
+            webSocketVo.setCategory("notice");
+            webSocketVo.setNoticeType("1");
+            webSocketVo.setIsRead(0);
+            webSocketVo.setText(JSONObject.toJSONString(lifeNotice));
+            
+            try {
+                webSocketProcess.sendMessage(receiverId, JSONObject.toJSONString(webSocketVo));
+                log.info("分配跟踪人员通知发送成功(中台),feedbackId={}, receiverId={}, staffId={}, staffName={}", 
+                        feedback.getId(), receiverId, staffId, staff.getUserName());
+            } catch (Exception e) {
+                log.error("发送WebSocket通知失败,feedbackId={}, receiverId={}, error={}", 
+                        feedback.getId(), receiverId, e.getMessage());
+            }
+            
+        } catch (Exception e) {
+            log.error("发送分配跟踪人员通知异常(中台),feedbackId={}, error={}", feedback.getId(), e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 发送提交反馈工单通知到中台
+     * 
+     * 根据AI接口文档:
+     * - staff_id 对应 life_sys 表的 id
+     * - 用户端和商户端反馈都会发送通知
+     * 
+     * @param feedback 反馈记录
+     */
+    private void sendFeedbackSubmittedNoticeToPlatform(LifeFeedback feedback) {
+        try {
+            // 如果没有分配跟踪人员,则无法发送通知到中台
+            if (feedback.getStaffId() == null) {
+                log.warn("反馈未分配跟踪人员,无法发送提交通知到中台,feedbackId={}", feedback.getId());
+                return;
+            }
+            
+            // 查询跟踪人员信息(从life_sys表查询)
+            LifeSys staff = lifeSysMapper.selectById(feedback.getStaffId());
+            if (staff == null) {
+                log.warn("未找到跟踪人员信息(life_sys),无法发送通知,staffId={}, feedbackId={}", 
+                        feedback.getStaffId(), feedback.getId());
+                return;
+            }
+            
+            // 获取用户信息(用于显示在通知中)
+            String userName = "用户";
+            if (feedback.getUserId() != null) {
+                StoreUser storeUser = storeUserMapper.selectById(feedback.getUserId());
+                if (storeUser != null && storeUser.getPhone() != null) {
+                    userName = storeUser.getPhone();
+                }
+            }
+            
+            // 获取反馈来源名称
+            String sourceName = feedback.getFeedbackSource() != null && feedback.getFeedbackSource() == 1 ? "商户" : "用户";
+            
+            // 中台接收者ID格式:staff_{staffId}
+            String receiverId = "staff_" + feedback.getStaffId();
+            
+            // 构建通知消息
+            JSONObject messageJson = new JSONObject();
+            messageJson.put("feedbackId", feedback.getId());
+            messageJson.put("staffId", feedback.getStaffId());
+            messageJson.put("staffName", staff.getUserName()); // life_sys表使用userName字段
+            messageJson.put("userId", feedback.getUserId());
+            messageJson.put("userName", userName);
+            messageJson.put("feedbackSource", feedback.getFeedbackSource());
+            messageJson.put("feedbackContent", feedback.getContent());
+            messageJson.put("message", sourceName + "提交了新的反馈工单,反馈内容:" + feedback.getContent());
+
+            // 创建通知记录
+            LifeNotice lifeNotice = new LifeNotice();
+            lifeNotice.setReceiverId(receiverId);
+            lifeNotice.setContext(messageJson.toJSONString());
+            lifeNotice.setTitle("反馈工单提交通知");
+            lifeNotice.setSenderId("system");
+            lifeNotice.setIsRead(0);
+            lifeNotice.setNoticeType(1); // 1-系统通知
+            lifeNotice.setBusinessId(feedback.getId());
+            
+            // 保存通知
+            lifeNoticeMapper.insert(lifeNotice);
+            
+            // 通过WebSocket发送实时通知
+            WebSocketVo webSocketVo = new WebSocketVo();
+            webSocketVo.setSenderId("system");
+            webSocketVo.setReceiverId(receiverId);
+            webSocketVo.setCategory("notice");
+            webSocketVo.setNoticeType("1");
+            webSocketVo.setIsRead(0);
+            webSocketVo.setText(JSONObject.toJSONString(lifeNotice));
+            
+            try {
+                webSocketProcess.sendMessage(receiverId, JSONObject.toJSONString(webSocketVo));
+                log.info("{}提交反馈工单通知发送成功(中台),feedbackId={}, receiverId={}, staffId={}", 
+                        sourceName, feedback.getId(), receiverId, feedback.getStaffId());
+            } catch (Exception e) {
+                log.error("发送WebSocket通知失败,feedbackId={}, receiverId={}, error={}", 
+                        feedback.getId(), receiverId, e.getMessage());
+            }
+            
+        } catch (Exception e) {
+            log.error("发送提交反馈工单通知异常(中台),feedbackId={}, error={}", feedback.getId(), e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 发送用户回复通知给平台端(跟踪人员)
+     * 
+     * 根据AI接口文档:
+     * - staff_id 对应 life_sys 表的 id
+     * 
+     * @param feedback 反馈记录
+     * @param replyContent 用户回复内容
+     */
+    private void sendUserReplyNoticeToPlatform(LifeFeedback feedback, String replyContent) {
+        try {
+            // 如果反馈没有分配跟踪人员,则无法发送通知
+            if (feedback.getStaffId() == null) {
+                log.warn("反馈未分配跟踪人员,无法发送用户回复通知,feedbackId={}", feedback.getId());
+                return;
+            }
+            
+            // 查询跟踪人员信息(从life_sys表查询)
+            LifeSys staff = lifeSysMapper.selectById(feedback.getStaffId());
+            if (staff == null) {
+                log.warn("未找到跟踪人员信息(life_sys),无法发送通知,staffId={}, feedbackId={}", 
+                        feedback.getStaffId(), feedback.getId());
+                return;
+            }
+            
+            // 获取反馈来源名称
+            String sourceName = feedback.getFeedbackSource() != null && feedback.getFeedbackSource() == 1 ? "商户" : "用户";
+            
+            // 构建接收者ID(平台端跟踪人员,使用staff_前缀)
+            String receiverId = "staff_" + feedback.getStaffId();
+            
+            // 构建通知消息
+            JSONObject messageJson = new JSONObject();
+            messageJson.put("feedbackId", feedback.getId());
+            messageJson.put("staffId", feedback.getStaffId());
+            messageJson.put("staffName", staff.getUserName()); // life_sys表使用userName字段
+            messageJson.put("feedbackSource", feedback.getFeedbackSource());
+            messageJson.put("message", sourceName + "已回复您的意见反馈:" + replyContent);
+
+            // 创建通知记录
+            LifeNotice lifeNotice = new LifeNotice();
+            lifeNotice.setReceiverId(receiverId);
+            lifeNotice.setContext(messageJson.toJSONString());
+            lifeNotice.setTitle(sourceName + "回复通知");
+            lifeNotice.setSenderId("system");
+            lifeNotice.setIsRead(0);
+            lifeNotice.setNoticeType(1); // 1-系统通知
+            lifeNotice.setBusinessId(feedback.getId());
+            
+            // 保存通知
+            lifeNoticeMapper.insert(lifeNotice);
+            
+            // 通过WebSocket发送实时通知
+            WebSocketVo webSocketVo = new WebSocketVo();
+            webSocketVo.setSenderId("system");
+            webSocketVo.setReceiverId(receiverId);
+            webSocketVo.setCategory("notice");
+            webSocketVo.setNoticeType("1");
+            webSocketVo.setIsRead(0);
+            webSocketVo.setText(JSONObject.toJSONString(lifeNotice));
+            
+            try {
+                webSocketProcess.sendMessage(receiverId, JSONObject.toJSONString(webSocketVo));
+                log.info("{}回复通知发送成功,feedbackId={}, receiverId={}, staffId={}", 
+                        sourceName, feedback.getId(), receiverId, feedback.getStaffId());
+            } catch (Exception e) {
+                log.error("发送WebSocket通知失败,feedbackId={}, receiverId={}, error={}", 
+                        feedback.getId(), receiverId, e.getMessage());
+            }
+            
+        } catch (Exception e) {
+            log.error("发送用户回复通知异常,feedbackId={}, error={}", feedback.getId(), e.getMessage(), e);
+        }
+    }
 }
 

+ 49 - 23
alien-store/src/main/java/shop/alien/store/util/ai/AiFeedbackAssignUtils.java

@@ -1,7 +1,6 @@
 package shop.alien.store.util.ai;
 
 import com.alibaba.fastjson2.JSONObject;
-import com.fasterxml.jackson.databind.JsonNode;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;
@@ -18,7 +17,6 @@ import shop.alien.store.feign.AlienAIFeign;
 
 import java.io.IOException;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 @Slf4j
@@ -191,13 +189,31 @@ public class AiFeedbackAssignUtils {
 
     /**
      * 调用AI接口分配跟踪人员
+     * 
+     * 根据AI接口文档:
+     * - 接口路径: /api/v1/feedback_assign_staff/assign
+     * - 请求方法: POST
+     * - Content-Type: application/json
+     * - 需要JWT Token认证
+     * 
+     * 请求参数:
+     * - feedback_id: Integer (必填) - 反馈工单ID
+     * 
+     * 响应格式:
+     * {
+     *     "code": 200,
+     *     "message": "成功分配跟踪人员",
+     *     "data": {
+     *         "staff_id": 101,  // 对应 life_sys 表的 id
+     *         "success": true,
+     *         "message": "成功分配跟踪人员"
+     *     }
+     * }
      *
      * @param feedback 反馈记录
-     * @param imageUrls 图片URL列表
-     * @param videoUrls 视频URL列表
-     * @return 分配的跟踪人员ID,失败返回null
+     * @return 分配的跟踪人员ID(对应life_sys表的id),失败返回null
      */
-    public Integer assignStaffByAI(LifeFeedback feedback, List<String> imageUrls, List<String> videoUrls) {
+    public Integer assignStaffByAI(LifeFeedback feedback) {
         try {
             // 1. 获取访问令牌
             String accessToken = getAccessToken();
@@ -206,21 +222,9 @@ public class AiFeedbackAssignUtils {
                 return null;
             }
 
-            // 2. 构建请求参数
+            // 2. 构建请求参数(只需要feedback_id)
             Map<String, Object> requestBody = new HashMap<>();
             requestBody.put("feedback_id", feedback.getId());
-            requestBody.put("feedback_content", feedback.getContent());
-            requestBody.put("feedback_type", feedback.getFeedbackType());
-            requestBody.put("feedback_source", feedback.getFeedbackSource());
-            requestBody.put("feedback_way", feedback.getFeedbackWay());
-            requestBody.put("contact_way", feedback.getContactWay());
-            requestBody.put("user_id", feedback.getUserId());
-            if (imageUrls != null && !imageUrls.isEmpty()) {
-                requestBody.put("image_urls", imageUrls);
-            }
-            if (videoUrls != null && !videoUrls.isEmpty()) {
-                requestBody.put("video_urls", videoUrls);
-            }
 
             // 3. 设置请求头
             HttpHeaders headers = new HttpHeaders();
@@ -230,7 +234,8 @@ public class AiFeedbackAssignUtils {
             HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
 
             // 4. 调用AI接口
-            log.info("调用AI分配跟踪人员接口,feedbackId={}, url={}", feedback.getId(), assignStaffUrl);
+            log.info("调用AI分配跟踪人员接口,feedbackId={}, url={}, requestBody={}", 
+                    feedback.getId(), assignStaffUrl, requestBody);
             ResponseEntity<String> response = restTemplate.postForEntity(assignStaffUrl, requestEntity, String.class);
 
             // 5. 处理响应
@@ -245,17 +250,34 @@ public class AiFeedbackAssignUtils {
                     if (code != null && code == 200) {
                         JSONObject data = responseJson.getJSONObject("data");
                         if (data != null) {
+                            Boolean success = data.getBoolean("success");
                             Integer staffId = data.getInteger("staff_id");
-                            if (staffId != null) {
-                                log.info("AI分配跟踪人员成功,feedbackId={}, staffId={}, staffName={}", 
-                                        feedback.getId(), staffId, data.getString("staff_name"));
+                            
+                            if (Boolean.TRUE.equals(success) && staffId != null) {
+                                log.info("AI分配跟踪人员成功,feedbackId={}, staffId={} (对应life_sys表)", 
+                                        feedback.getId(), staffId);
                                 return staffId;
+                            } else {
+                                String dataMessage = data.getString("message");
+                                log.warn("AI分配跟踪人员失败,feedbackId={}, success={}, message={}", 
+                                        feedback.getId(), success, dataMessage);
                             }
                         }
                     } else {
                         String message = responseJson.getString("message");
                         log.error("AI分配跟踪人员失败,feedbackId={}, code={}, message={}", 
                                 feedback.getId(), code, message);
+                        
+                        // 处理认证错误
+                        if (code != null) {
+                            if (code == 40101) {
+                                log.error("AI接口认证失败:缺少认证信息");
+                            } else if (code == 40102) {
+                                log.error("AI接口认证失败:Token已过期");
+                            } else if (code == 40104) {
+                                log.error("AI接口认证失败:Token不存在或已被注销");
+                            }
+                        }
                     }
                 }
             } else {
@@ -267,6 +289,10 @@ public class AiFeedbackAssignUtils {
         } catch (org.springframework.web.client.HttpServerErrorException.ServiceUnavailable e) {
             log.error("AI分配跟踪人员接口返回503 Service Unavailable错误: {}", e.getResponseBodyAsString());
             return null;
+        } catch (org.springframework.web.client.HttpClientErrorException e) {
+            log.error("AI分配跟踪人员接口返回客户端错误,feedbackId={}, status={}, body={}", 
+                    feedback.getId(), e.getStatusCode(), e.getResponseBodyAsString());
+            return null;
         } catch (Exception e) {
             log.error("调用AI分配跟踪人员接口异常,feedbackId={}", feedback.getId(), e);
             return null;