chore(addon/aikefu): 增加可以选择消息排序

This commit is contained in:
2025-12-09 10:12:29 +08:00
parent cd37019675
commit 717481dcba
3 changed files with 173 additions and 56 deletions

View File

@@ -271,6 +271,8 @@ class Kefu extends BaseShop
$limit = input("limit/d", 50); $limit = input("limit/d", 50);
$conversation_id = input("conversation_id/s", ""); $conversation_id = input("conversation_id/s", "");
$user_id = input("user_id/s", ""); $user_id = input("user_id/s", "");
$sort_field = input("sort_field/s", "create_time"); // 排序字段
$sort_order = input("sort_order/s", "desc"); // 排序方式asc或desc
$kefu_message_model = new KefuMessageModel(); $kefu_message_model = new KefuMessageModel();
$condition = [ $condition = [
@@ -287,7 +289,9 @@ class Kefu extends BaseShop
$condition[] = ['user_id', '=', $user_id]; $condition[] = ['user_id', '=', $user_id];
} }
$message_list = $kefu_message_model->getMessageList($condition, '*', 'create_time asc', $page, $limit); // 构建排序字符串
$order = $sort_field . ' ' . $sort_order;
$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

View File

@@ -20,48 +20,110 @@
color: #faad14; color: #faad14;
} }
/* 简单消息列表样式 */ /* 消息列表样式优化 - 从message.html复制 */
.simple-message-list { .message-list {
max-height: 500px; max-height: 650px;
overflow-y: auto; overflow-y: auto;
padding: 15px; padding: 25px;
background-color: #fafbfc;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #e8e8e8;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
} }
/* 消息项样式 */
.message-item { .message-item {
margin-bottom: 15px; margin-bottom: 25px;
padding: 10px;
border-radius: 4px;
}
.message-item.user {
background-color: #e6f7ff;
border-left: 3px solid #1890ff;
}
.message-item.assistant {
background-color: #f6ffed;
border-left: 3px solid #52c41a;
}
.message-header {
display: flex; display: flex;
justify-content: space-between; align-items: flex-start;
margin-bottom: 5px;
font-size: 12px;
} }
.message-role {
font-weight: bold; .message-item.user {
color: #333; justify-content: flex-end;
} }
.message-time {
color: #999; .message-item.assistant {
justify-content: flex-start;
} }
/* 头像样式 */
.message-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
margin: 0 12px;
border: 2px solid #fff;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}
/* 消息内容样式 */
.message-content { .message-content {
font-size: 14px; max-width: 70%;
line-height: 1.4; padding: 16px 20px;
color: #666; border-radius: 18px;
word-break: break-word; word-wrap: break-word;
line-height: 1.6;
position: relative;
} }
.empty-message {
text-align: center; .message-item.user .message-content {
background-color: #1E9FFF;
color: white;
border-bottom-right-radius: 4px;
box-shadow: 0 2px 8px rgba(30, 159, 255, 0.3);
}
.message-item.assistant .message-content {
background-color: white;
color: #333;
border-bottom-left-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* 消息时间样式 */
.message-time {
font-size: 12px;
color: #999; color: #999;
padding: 30px; margin-top: 8px;
text-align: center;
}
/* 消息角色样式 */
.message-role {
font-size: 13px;
font-weight: 500;
margin-bottom: 6px;
}
.message-item.user .message-role {
color: rgba(106, 38, 38, 0.9);
text-align: right;
}
.message-item.assistant .message-role {
color: #666;
text-align: left;
}
/* 空状态样式 */
.empty-state {
text-align: center;
padding: 60px 20px;
color: #999;
}
.empty-state i {
font-size: 48px;
margin-bottom: 15px;
display: block;
}
/* 响应式设计 */
@media (max-width: 768px) {
.message-content {
max-width: 85%;
}
} }
</style> </style>
@@ -118,25 +180,35 @@
}}} }}}
</script> </script>
<!-- 简单消息列表模板 --> <!-- 消息列表模板 - 与message.html一致 -->
<script type="text/html" id="messageListTpl"> <script type="text/html" id="messageListTpl">
<div class="simple-message-list"> <div class="message-list">
{{# if(d.length > 0) { {{# if(d.length > 0) {
d.forEach(function(item) { d.forEach(function(item) {
var role = item.role === 'user' ? (item.user_id ? '用户-' + item.user_id : '用户') : '机器人';
var roleClass = item.role === 'user' ? 'user' : 'assistant'; var roleClass = item.role === 'user' ? 'user' : 'assistant';
var roleText = item.role === 'user' ? '用户' : '机器人'; var avatar = item.role === 'user' ? '/addon/aikefu/static/images/user.svg' : '/addon/aikefu/static/images/robot.svg';
}}} }}}
<div class="message-item {{roleClass}}"> <div class="message-item {{roleClass}}">
<div class="message-header"> {{# if(item.role === 'assistant') {
<span class="message-role">{{roleText}}</span> <img src="{{avatar}}" class="message-avatar">
<span class="message-time">{{item.create_time}}</span> }}}
</div> <div>
<div class="message-role">{{role}}</div>
<div class="message-content">{{item.content}}</div> <div class="message-content">{{item.content}}</div>
<div class="message-time">{{item.create_time}}</div>
</div>
{{# if(item.role === 'user') {
<img src="{{avatar}}" class="message-avatar">
}}}
</div> </div>
{{# }); {{# });
} else { } else {
}}} }}}
<div class="empty-message">暂无消息记录</div> <div class="empty-state">
<i class="layui-icon layui-icon-message"></i>
<p>暂无消息记录</p>
</div>
{{# } {{# }
}} }}
</div> </div>
@@ -243,7 +315,7 @@
layer.open({ layer.open({
type: 1, type: 1,
title: '消息记录', title: '消息记录',
content: '<div class="simple-message-list" style="padding: 15px; max-height: 500px; overflow-y: auto;">加载中...</div>', content: '<div class="message-list" style="padding: 25px; max-height: 650px; overflow-y: auto;">加载中...</div>',
area: ['80%', '70%'], area: ['80%', '70%'],
success: function(layero, index) { success: function(layero, index) {
// 获取消息列表 // 获取消息列表
@@ -253,34 +325,48 @@
data: { data: {
conversation_id: data.conversation_id, conversation_id: data.conversation_id,
page: 1, page: 1,
limit: 100 // 加载最多100条消息 limit: 100, // 加载最多100条消息
sort_field: 'create_time',
sort_order: 'desc' // 默认最新消息在前面
}, },
dataType: 'json', dataType: 'json',
success: function(res) { success: function(res) {
var messageList = res.data.messages || []; var messageList = res.data?.messages || [];
var html = ''; var html = '';
if (messageList.length > 0) { if (messageList.length > 0) {
messageList.forEach(function(item) { messageList.forEach(function(item) {
var role = item.role === 'user' ? (item.user_id ? '用户-' + item.user_id : '用户') : '机器人';
var roleClass = item.role === 'user' ? 'user' : 'assistant'; var roleClass = item.role === 'user' ? 'user' : 'assistant';
var roleText = item.role === 'user' ? '用户' : '机器人'; var avatar = item.role === 'user' ? '/addon/aikefu/static/images/user.svg' : '/addon/aikefu/static/images/robot.svg';
html += '<div class="message-item ' + roleClass + '">'; html += '<div class="message-item ' + roleClass + '">';
html += '<div class="message-header">'; if (item.role === 'assistant') {
html += '<span class="message-role">' + roleText + '</span>'; html += '<img src="' + avatar + '" class="message-avatar">';
html += '<span class="message-time">' + item.create_time + '</span>'; }
html += '</div>'; html += '<div>';
html += '<div class="message-role">' + role + '</div>';
html += '<div class="message-content">' + item.content + '</div>'; html += '<div class="message-content">' + item.content + '</div>';
html += '<div class="message-time">' + item.create_time + '</div>';
html += '</div>';
if (item.role === 'user') {
html += '<img src="' + avatar + '" class="message-avatar">';
}
html += '</div>'; html += '</div>';
}); });
} else { } else {
html += '<div class="empty-message">暂无消息记录</div>'; html += '<div class="empty-state">';
html += '<i class="layui-icon layui-icon-message"></i>';
html += '<p>暂无消息记录</p>';
html += '</div>';
} }
layero.find('.simple-message-list').html(html); layero.find('.message-list').html(html);
// 默认滚动到底部(最新消息)
layero.find('.message-list').scrollTop(layero.find('.message-list')[0].scrollHeight);
}, },
error: function() { error: function() {
layero.find('.simple-message-list').html('<div class="empty-message">加载消息失败</div>'); layero.find('.message-list').html('<div class="empty-state">加载消息失败</div>');
} }
}); });
} }

View File

@@ -220,6 +220,13 @@
<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="sort_order">排序方式</label>
<select name="sort_order" id="msg_sortOrder" class="layui-select" style="width: 200px; display: inline-block;">
<option value="desc">最新消息在前面</option>
<option value="asc">最新消息在后面</option>
</select>
</div>
<div class="search-item"> <div class="search-item">
<button type="button" class="layui-btn layui-btn-primary" id="msg_searchBtn">搜索</button> <button type="button" class="layui-btn layui-btn-primary" id="msg_searchBtn">搜索</button>
<button type="button" class="layui-btn" id="msg_resetBtn">重置</button> <button type="button" class="layui-btn" id="msg_resetBtn">重置</button>
@@ -247,12 +254,14 @@
var laypage = layui.laypage; var laypage = layui.laypage;
var layer = layui.layer; var layer = layui.layer;
// 分页参数 // 分页和排序参数
var page = 1; var page = 1;
var limit = 50; var limit = 50;
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 sortField = 'create_time'; // 排序字段:创建时间
var sortOrder = 'desc'; // 默认倒序(最新消息在前面)
// 加载会话信息当指定会话ID时显示 // 加载会话信息当指定会话ID时显示
function loadConversationInfo() { function loadConversationInfo() {
@@ -294,7 +303,9 @@
// 构建请求数据 // 构建请求数据
var requestData = { var requestData = {
page: page, page: page,
limit: limit limit: limit,
sort_field: sortField, // 排序字段:创建时间
sort_order: sortOrder // 排序方式:倒序/正序
}; };
// 如果有会话ID则添加到请求数据中 // 如果有会话ID则添加到请求数据中
@@ -376,8 +387,14 @@
} }
$('#msg_messageList').html(html); $('#msg_messageList').html(html);
// 滚动到底部 // 根据排序方式调整滚动位置
if (sortOrder === 'asc') {
// 正序时滚动到顶部
$('#msg_messageList').scrollTop(0);
} else {
// 倒序时滚动到底部
$('#msg_messageList').scrollTop($('#msg_messageList')[0].scrollHeight); $('#msg_messageList').scrollTop($('#msg_messageList')[0].scrollHeight);
}
// 渲染分页 // 渲染分页
renderPagination(); renderPagination();
} else { } else {
@@ -434,6 +451,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();
sortOrder = $('#msg_sortOrder').val(); // 获取当前选择的排序方式
page = 1; page = 1;
loadConversationInfo(); loadConversationInfo();
loadMessageList(); loadMessageList();
@@ -443,13 +461,22 @@
$('#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_sortOrder').val('desc'); // 重置为默认排序
conversation_id = ''; conversation_id = '';
user_id = ''; user_id = '';
sortOrder = 'desc'; // 重置为默认排序
page = 1; page = 1;
loadConversationInfo(); loadConversationInfo();
loadMessageList(); loadMessageList();
}); });
// 排序方式变更事件
$('#msg_sortOrder').change(function() {
sortOrder = $(this).val();
page = 1; // 切换排序时重置到第一页
loadMessageList();
});
// 初始化加载(默认显示所有消息) // 初始化加载(默认显示所有消息)
loadConversationInfo(); loadConversationInfo();
loadMessageList(); loadMessageList();