chore(addon/aikefu): 支持后台管理消息列表针对流式消息的处理

This commit is contained in:
2025-12-10 16:47:43 +08:00
parent 34db5cd074
commit 4a53db1f4c
3 changed files with 103 additions and 19 deletions

View File

@@ -803,27 +803,76 @@ class Kefu extends BaseApi
$kefu_message_model = new KefuMessageModel();
$kefu_conversation_model = new KefuConversationModel();
// 发送请求
$response = $this->curlRequest($url, 'POST', $requestData, $headers);
// 开启事务,确保数据一致性
Db::startTrans();
try {
// 发送请求
$response = $this->curlRequest($url, 'POST', $requestData, $headers);
// 解析响应
$result = json_decode($response, true);
// 解析响应
$result = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
return $this->response($this->error('解析响应失败'));
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \Exception('解析响应失败');
}
// 验证响应数据
if (empty($result) || !isset($result['conversation_id'])) {
throw new \Exception('API返回数据格式错误或缺少必要字段');
}
$final_conversation_id = $result['conversation_id'] ?? $conversation_id;
$final_message_id = $result['message_id'] ?? $result['id'] ?? '';
// 检查用户消息是否已存在,避免重复存储
$existing_user_message = $kefu_message_model->getMessageInfo([
['site_id', '=', $this->site_id],
['user_id', '=', $user_id],
['conversation_id', '=', $final_conversation_id],
['role', '=', 'user'],
['content', '=', $message ?? '']
]);
if (empty($existing_user_message['data'])) {
// 保存用户消息
$this->saveUserMessage($kefu_message_model, $this->site_id, $user_id, $final_conversation_id, $final_message_id, $message ?? '');
$this->log('非流式用户消息已保存会话ID' . $final_conversation_id, 'info');
}
// 检查助手消息是否已存在
$existing_assistant_message = $kefu_message_model->getMessageInfo([
['site_id', '=', $this->site_id],
['user_id', '=', $user_id],
['conversation_id', '=', $final_conversation_id],
['role', '=', 'assistant'],
['message_id', '=', $final_message_id]
]);
if (empty($existing_assistant_message['data'])) {
// 保存机器人回复
$this->saveAssistantMessage($kefu_message_model, $this->site_id, $user_id, $final_conversation_id, $final_message_id, $result['answer'] ?? '');
$this->log('非流式助手消息已保存会话ID' . $final_conversation_id, 'info');
}
// 更新会话状态或创建新会话
$this->updateOrCreateConversation($kefu_conversation_model, $this->site_id, $user_id, $final_conversation_id);
// 提交事务
Db::commit();
$this->log('非流式对话数据已完整保存会话ID' . $final_conversation_id, 'info');
// 返回成功响应保持与Dify API一致的响应结构
return $this->response($this->success($result));
} catch (\Exception $e) {
// 回滚事务
Db::rollback();
$error_msg = '非流式对话存储失败:' . $e->getMessage() . ',错误行:' . $e->getLine() . ',错误文件:' . $e->getFile();
$this->log($error_msg, 'error');
return $this->response($this->error($error_msg));
}
// 保存用户消息
$this->saveUserMessage($kefu_message_model, $this->site_id, $user_id, $result['conversation_id'] ?? $conversation_id, $result['message_id'] ?? '', $message ?? '');
// 保存机器人回复
$this->saveAssistantMessage($kefu_message_model, $this->site_id, $user_id, $result['conversation_id'] ?? $conversation_id, $result['id'] ?? '', $result['answer'] ?? '');
// 更新会话状态或创建新会话
$this->updateOrCreateConversation($kefu_conversation_model, $this->site_id, $user_id, $result['conversation_id'] ?? $conversation_id);
// 返回成功响应保持与Dify API一致的响应结构
return $this->response($this->success($result));
}
/**

View File

@@ -273,6 +273,7 @@ class Kefu extends BaseShop
$user_id = input("user_id/s", "");
$sort_field = input("sort_field/s", "create_time"); // 排序字段
$sort_order = input("sort_order/s", "desc"); // 排序方式asc或desc
$status = input("status/s", "completed"); // 默认只显示已完成的消息
$kefu_message_model = new KefuMessageModel();
$condition = [
@@ -289,9 +290,15 @@ class Kefu extends BaseShop
$condition[] = ['user_id', '=', $user_id];
}
// 添加状态过滤(默认只显示已完成的消息,避免显示临时数据)
if (!empty($status)) {
$condition[] = ['status', '=', $status];
}
// 构建排序字符串
$order = $sort_field . ' ' . $sort_order;
$message_list = $kefu_message_model->getMessageList($condition, '*', $order, $page, $limit);
// 适配layui table的返回格式同时保持与Dify API风格一致
$result = [
'code' => 0, // layui table要求成功状态码为0
@@ -301,7 +308,8 @@ class Kefu extends BaseShop
'messages' => $message_list['data'], // 消息列表
'page_info' => [
'limit' => $limit,
'offset' => ($page - 1) * $limit
'offset' => ($page - 1) * $limit,
'total' => $message_list['total'] // 添加总记录数到page_info
]
] // 数据列表
];

View File

@@ -220,6 +220,17 @@
<label for="user_id">用户ID</label>
<input type="text" name="user_id" id="msg_user_id" placeholder="请输入用户ID进行过滤" value="{$user_id ?? ''}" class="layui-input" style="width: 200px; display: inline-block;">
</div>
<div class="search-item">
<label for="status">消息状态</label>
<div class="layui-input-inline" style="width: 150px;">
<select name="status" id="msg_status" class="layui-select">
<option value="completed">已完成</option>
<option value="streaming">流式中</option>
<option value="failed">失败</option>
<option value="">全部状态</option>
</select>
</div>
</div>
<div class="search-item">
<label for="sort_order">排序方式</label>
<div class="layui-input-inline" style="width: 200px;">
@@ -267,6 +278,7 @@
var total = 0;
var conversation_id = $('#msg_conversation_id').val();
var user_id = $('#msg_user_id').val();
var status = 'completed'; // 默认只显示已完成的消息
var sortField = 'create_time'; // 排序字段:创建时间
var sortOrder = 'desc'; // 默认倒序(最新消息在前面)
@@ -325,6 +337,11 @@
requestData.user_id = user_id;
}
// 添加状态过滤
if (status) {
requestData.status = status;
}
$.ajax({
url: ns.url("aikefu://shop/kefu/getMessageList"),
type: 'POST',
@@ -461,6 +478,7 @@
$('#msg_searchBtn').click(function() {
conversation_id = $('#msg_conversation_id').val().trim();
user_id = $('#msg_user_id').val().trim();
status = $('#msg_status').val(); // 获取当前选择的状态
sortOrder = $('#msg_sortOrder').val(); // 获取当前选择的排序方式
page = 1;
loadConversationInfo();
@@ -471,9 +489,11 @@
$('#msg_resetBtn').click(function() {
$('#msg_conversation_id').val('');
$('#msg_user_id').val('');
$('#msg_status').val('completed'); // 重置为默认状态
$('#msg_sortOrder').val('desc'); // 重置为默认排序
conversation_id = '';
user_id = '';
status = 'completed'; // 重置为默认状态
sortOrder = 'desc'; // 重置为默认排序
page = 1;
loadConversationInfo();
@@ -487,6 +507,13 @@
loadMessageList(true); // 切换排序时强制滚动到顶部
});
// 状态变更事件
$('#msg_status').change(function() {
status = $(this).val();
page = 1; // 切换状态时重置到第一页
loadMessageList(true); // 切换状态时强制滚动到顶部
});
// 初始化加载(默认显示所有消息)
loadConversationInfo();
loadMessageList();