chore(addon/aikefu): 支持后台管理消息列表针对流式消息的处理
This commit is contained in:
@@ -803,27 +803,76 @@ class Kefu extends BaseApi
|
|||||||
$kefu_message_model = new KefuMessageModel();
|
$kefu_message_model = new KefuMessageModel();
|
||||||
$kefu_conversation_model = new KefuConversationModel();
|
$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) {
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||||
return $this->response($this->error('解析响应失败'));
|
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ class Kefu extends BaseShop
|
|||||||
$user_id = input("user_id/s", "");
|
$user_id = input("user_id/s", "");
|
||||||
$sort_field = input("sort_field/s", "create_time"); // 排序字段
|
$sort_field = input("sort_field/s", "create_time"); // 排序字段
|
||||||
$sort_order = input("sort_order/s", "desc"); // 排序方式:asc或desc
|
$sort_order = input("sort_order/s", "desc"); // 排序方式:asc或desc
|
||||||
|
$status = input("status/s", "completed"); // 默认只显示已完成的消息
|
||||||
|
|
||||||
$kefu_message_model = new KefuMessageModel();
|
$kefu_message_model = new KefuMessageModel();
|
||||||
$condition = [
|
$condition = [
|
||||||
@@ -289,9 +290,15 @@ class Kefu extends BaseShop
|
|||||||
$condition[] = ['user_id', '=', $user_id];
|
$condition[] = ['user_id', '=', $user_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加状态过滤(默认只显示已完成的消息,避免显示临时数据)
|
||||||
|
if (!empty($status)) {
|
||||||
|
$condition[] = ['status', '=', $status];
|
||||||
|
}
|
||||||
|
|
||||||
// 构建排序字符串
|
// 构建排序字符串
|
||||||
$order = $sort_field . ' ' . $sort_order;
|
$order = $sort_field . ' ' . $sort_order;
|
||||||
$message_list = $kefu_message_model->getMessageList($condition, '*', $order, $page, $limit);
|
$message_list = $kefu_message_model->getMessageList($condition, '*', $order, $page, $limit);
|
||||||
|
|
||||||
// 适配layui table的返回格式,同时保持与Dify API风格一致
|
// 适配layui table的返回格式,同时保持与Dify API风格一致
|
||||||
$result = [
|
$result = [
|
||||||
'code' => 0, // layui table要求成功状态码为0
|
'code' => 0, // layui table要求成功状态码为0
|
||||||
@@ -301,7 +308,8 @@ class Kefu extends BaseShop
|
|||||||
'messages' => $message_list['data'], // 消息列表
|
'messages' => $message_list['data'], // 消息列表
|
||||||
'page_info' => [
|
'page_info' => [
|
||||||
'limit' => $limit,
|
'limit' => $limit,
|
||||||
'offset' => ($page - 1) * $limit
|
'offset' => ($page - 1) * $limit,
|
||||||
|
'total' => $message_list['total'] // 添加总记录数到page_info
|
||||||
]
|
]
|
||||||
] // 数据列表
|
] // 数据列表
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -220,6 +220,17 @@
|
|||||||
<label for="user_id">用户ID</label>
|
<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;">
|
<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>
|
||||||
|
<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">
|
<div class="search-item">
|
||||||
<label for="sort_order">排序方式</label>
|
<label for="sort_order">排序方式</label>
|
||||||
<div class="layui-input-inline" style="width: 200px;">
|
<div class="layui-input-inline" style="width: 200px;">
|
||||||
@@ -267,6 +278,7 @@
|
|||||||
var total = 0;
|
var total = 0;
|
||||||
var conversation_id = $('#msg_conversation_id').val();
|
var conversation_id = $('#msg_conversation_id').val();
|
||||||
var user_id = $('#msg_user_id').val();
|
var user_id = $('#msg_user_id').val();
|
||||||
|
var status = 'completed'; // 默认只显示已完成的消息
|
||||||
var sortField = 'create_time'; // 排序字段:创建时间
|
var sortField = 'create_time'; // 排序字段:创建时间
|
||||||
var sortOrder = 'desc'; // 默认倒序(最新消息在前面)
|
var sortOrder = 'desc'; // 默认倒序(最新消息在前面)
|
||||||
|
|
||||||
@@ -325,6 +337,11 @@
|
|||||||
requestData.user_id = user_id;
|
requestData.user_id = user_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加状态过滤
|
||||||
|
if (status) {
|
||||||
|
requestData.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: ns.url("aikefu://shop/kefu/getMessageList"),
|
url: ns.url("aikefu://shop/kefu/getMessageList"),
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
@@ -461,6 +478,7 @@
|
|||||||
$('#msg_searchBtn').click(function() {
|
$('#msg_searchBtn').click(function() {
|
||||||
conversation_id = $('#msg_conversation_id').val().trim();
|
conversation_id = $('#msg_conversation_id').val().trim();
|
||||||
user_id = $('#msg_user_id').val().trim();
|
user_id = $('#msg_user_id').val().trim();
|
||||||
|
status = $('#msg_status').val(); // 获取当前选择的状态
|
||||||
sortOrder = $('#msg_sortOrder').val(); // 获取当前选择的排序方式
|
sortOrder = $('#msg_sortOrder').val(); // 获取当前选择的排序方式
|
||||||
page = 1;
|
page = 1;
|
||||||
loadConversationInfo();
|
loadConversationInfo();
|
||||||
@@ -471,9 +489,11 @@
|
|||||||
$('#msg_resetBtn').click(function() {
|
$('#msg_resetBtn').click(function() {
|
||||||
$('#msg_conversation_id').val('');
|
$('#msg_conversation_id').val('');
|
||||||
$('#msg_user_id').val('');
|
$('#msg_user_id').val('');
|
||||||
|
$('#msg_status').val('completed'); // 重置为默认状态
|
||||||
$('#msg_sortOrder').val('desc'); // 重置为默认排序
|
$('#msg_sortOrder').val('desc'); // 重置为默认排序
|
||||||
conversation_id = '';
|
conversation_id = '';
|
||||||
user_id = '';
|
user_id = '';
|
||||||
|
status = 'completed'; // 重置为默认状态
|
||||||
sortOrder = 'desc'; // 重置为默认排序
|
sortOrder = 'desc'; // 重置为默认排序
|
||||||
page = 1;
|
page = 1;
|
||||||
loadConversationInfo();
|
loadConversationInfo();
|
||||||
@@ -487,6 +507,13 @@
|
|||||||
loadMessageList(true); // 切换排序时强制滚动到顶部
|
loadMessageList(true); // 切换排序时强制滚动到顶部
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 状态变更事件
|
||||||
|
$('#msg_status').change(function() {
|
||||||
|
status = $(this).val();
|
||||||
|
page = 1; // 切换状态时重置到第一页
|
||||||
|
loadMessageList(true); // 切换状态时强制滚动到顶部
|
||||||
|
});
|
||||||
|
|
||||||
// 初始化加载(默认显示所有消息)
|
// 初始化加载(默认显示所有消息)
|
||||||
loadConversationInfo();
|
loadConversationInfo();
|
||||||
loadMessageList();
|
loadMessageList();
|
||||||
|
|||||||
Reference in New Issue
Block a user