chore(addon/aikefu): update html

This commit is contained in:
2025-12-06 11:51:16 +08:00
parent c0da89735c
commit cdcd9eeffa
3 changed files with 525 additions and 552 deletions

View File

@@ -1,98 +1,104 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智能客服配置</title>
<link rel="stylesheet" href="/__STATIC__/admin/css/global.css">
<link rel="stylesheet" href="/__STATIC__/admin/css/form.css">
</head>
<body>
<div class="main">
<div class="container">
<div class="page-title">
<h2>智能客服配置</h2>
<style>
.word-aux {
margin-left: 110px;
color: #999;
font-size: 12px;
margin-top: 5px;
}
.required {
color: red;
}
</style>
<div class="layui-form form-wrap">
<div class="layui-form-item">
<label class="layui-form-label"><span class="required">*</span>Dify API密钥</label>
<div class="layui-input-block">
<input type="text" name="api_key" placeholder="请输入Dify API密钥" value="{$config_info.data.value.api_key ?? ''}" class="layui-input">
</div>
<div class="card">
<form id="kefuConfigForm">
<div class="form-group">
<label for="api_key">Dify API密钥</label>
<input type="text" name="api_key" id="api_key" value="{$config_info.api_key ?? ''}" placeholder="请输入Dify API密钥">
<div class="form-tips">
<div class="word-aux">
从Dify平台获取的API密钥用于调用Dify聊天机器人API。
<a href="https://dify.ai/" target="_blank">前往Dify平台</a>
</div>
</div>
<div class="form-group">
<label for="base_url">API基础地址</label>
<input type="text" name="base_url" id="base_url" value="{$config_info.base_url ?? 'https://api.dify.ai/v1'}" placeholder="请输入Dify API基础地址">
<div class="form-tips">
Dify API的基础地址默认为https://api.dify.ai/v1
<div class="layui-form-item">
<label class="layui-form-label">API基础地址</label>
<div class="layui-input-block">
<input type="text" name="base_url" placeholder="请输入Dify API基础地址" value="{$config_info.data.value.base_url ?? 'https://api.dify.ai/v1'}" class="layui-input">
</div>
<div class="word-aux">Dify API的基础地址默认为https://api.dify.ai/v1</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">聊天接口端点:</label>
<div class="layui-input-block">
<input type="text" name="chat_endpoint" placeholder="请输入聊天接口端点" value="{$config_info.data.value.chat_endpoint ?? '/chat-messages'}" class="layui-input">
</div>
<div class="word-aux">聊天接口的端点,默认为/chat-messages</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><span class="required">*</span>状态:</label>
<div class="layui-input-block">
<input type="checkbox" name="status" value="1" lay-skin="switch" {if condition="isset($config_info.data.value.status) && $config_info.data.value.status == 1"} checked {/if}>
</div>
<div class="word-aux">启用或禁用智能客服功能</div>
</div>
<div class="form-row">
<button class="layui-btn" lay-submit lay-filter="save">保存</button>
<button class="layui-btn layui-btn-primary" onclick="back()">返回</button>
</div>
</div>
<div class="form-group">
<label for="chat_endpoint">聊天接口端点</label>
<input type="text" name="chat_endpoint" id="chat_endpoint" value="{$config_info.chat_endpoint ?? '/chat-messages'}" placeholder="请输入聊天接口端点">
<div class="form-tips">
聊天接口的端点,默认为/chat-messages
</div>
</div>
<div class="form-group">
<label for="status">状态</label>
<div class="radio-group">
<label class="radio-item">
<input type="radio" name="status" value="1" {if isset($config_info.status) && $config_info.status == 1}checked{/if}>
<span>启用</span>
</label>
<label class="radio-item">
<input type="radio" name="status" value="0" {if !isset($config_info.status) || $config_info.status == 0}checked{/if}>
<span>禁用</span>
</label>
</div>
<div class="form-tips">
启用或禁用智能客服功能
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">保存配置</button>
<button type="reset" class="btn btn-default">重置</button>
</div>
</form>
</div>
</div>
</div>
<script src="/__STATIC__/admin/js/jquery.min.js"></script>
<script src="/__STATIC__/admin/js/layer/layer.js"></script>
<script>
$(function() {
$('#kefuConfigForm').on('submit', function(e) {
e.preventDefault();
layui.use('form', function() {
var form = layui.form;
var repeat_flag = false; //防重复标识
form.render();
var formData = $(this).serialize();
/**
* 监听提交
*/
form.on('submit(save)', function(data) {
if (repeat_flag) return false;
repeat_flag = true;
$.ajax({
url: '/shop/aikefu/kefu/saveConfig',
url: ns.url("aikefu://shop/kefu/saveConfig"),
type: 'POST',
data: formData,
data: data.field,
dataType: 'json',
success: function(res) {
repeat_flag = false;
if (res.code === 0) {
layer.msg('保存成功', {icon: 1});
layer.confirm('保存成功', {
title: '操作提示',
btn: ['返回列表', '继续编辑'],
yes: function(index, layero) {
location.reload();
layer.close(index);
},
btn2: function(index, layero) {
layer.close(index);
}
});
} else {
layer.msg(res.message, {icon: 2});
}
},
error: function() {
repeat_flag = false;
layer.msg('请求失败,请稍后重试', {icon: 2});
}
});
return false;
});
});
function back() {
window.history.back();
}
</script>
</body>
</html>

View File

@@ -1,192 +1,180 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>会话管理</title>
<link rel="stylesheet" href="/__STATIC__/admin/css/global.css">
<link rel="stylesheet" href="/__STATIC__/admin/css/table.css">
</head>
<body>
<div class="main">
<div class="container">
<div class="page-title">
<h2>会话管理</h2>
</div>
<div class="card">
<style>
.search-box {
padding: 10px 0;
border-bottom: 1px solid #eee;
margin-bottom: 15px;
}
.search-item {
display: inline-block;
margin-right: 15px;
vertical-align: middle;
}
.search-item label {
display: inline-block;
width: 80px;
text-align: right;
margin-right: 10px;
vertical-align: middle;
}
.search-item input,
.search-item select {
width: 150px;
display: inline-block;
vertical-align: middle;
}
.layui-btn-container {
margin-bottom: 15px;
text-align: right;
}
.layui-btn-sm {
margin-left: 5px;
}
.status-active {
color: #52c41a;
}
.status-inactive {
color: #faad14;
}
</style>
<div class="layui-card-body">
<!-- 搜索区域 -->
<div class="search-box">
<form class="layui-form" id="searchForm">
<div class="search-item">
<label for="user_id">用户ID</label>
<input type="text" name="user_id" id="user_id" placeholder="请输入用户ID">
<input type="text" name="user_id" id="user_id" placeholder="请输入用户ID" class="layui-input">
</div>
<div class="search-item">
<label for="status">状态</label>
<select name="status" id="status">
<select name="status" id="status" class="layui-select">
<option value="">全部</option>
<option value="1">活跃</option>
<option value="0">已结束</option>
</select>
</div>
<div class="search-item">
<button type="button" class="btn btn-primary" id="searchBtn">搜索</button>
<button type="button" class="btn btn-default" id="resetBtn">重置</button>
</div>
</div>
<div class="table-container">
<table class="table table-hover">
<thead>
<tr>
<th>ID</th>
<th>会话ID</th>
<th>用户ID</th>
<th>会话名称</th>
<th>状态</th>
<th>创建时间</th>
<th>更新时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="conversationList">
<!-- 会话列表将通过JavaScript动态加载 -->
</tbody>
</table>
</div>
<div class="pagination" id="pagination">
<!-- 分页将通过JavaScript动态加载 -->
</div>
</div>
<button type="button" class="layui-btn layui-btn-primary" id="searchBtn">搜索</button>
<button type="button" class="layui-btn layui-btn-primary" id="resetBtn">重置</button>
</div>
</form>
</div>
<script src="/__STATIC__/admin/js/jquery.min.js"></script>
<script src="/__STATIC__/admin/js/layer/layer.js"></script>
<!-- 表格区域 -->
<table class="layui-table" id="conversationTable" lay-filter="conversationTable"></table>
</div>
<script type="text/html" id="toolbarDemo">
<div class="layui-btn-container">
<!-- 可以在这里添加按钮 -->
</div>
</script>
<script type="text/html" id="statusTpl">
{{# if(d.status === 1) {
return '<span class="status-active">活跃</span>';
} else {
return '<span class="status-inactive">已结束</span>';
}}}
</script>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-xs" lay-event="view">查看消息</a>
<a class="layui-btn layui-btn-xs layui-btn-warning" lay-event="end">结束会话</a>
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="delete">删除</a>
</script>
<script>
$(function() {
// 分页参数
var page = 1;
var limit = 10;
var total = 0;
layui.use(['table', 'form', 'layer'], function() {
var table = layui.table;
var form = layui.form;
var layer = layui.layer;
// 加载会话列表
function loadConversationList() {
var user_id = $('#user_id').val();
var status = $('#status').val();
$.ajax({
url: '/shop/aikefu/kefu/getConversationList',
type: 'POST',
data: {
page: page,
limit: limit,
user_id: user_id,
status: status
},
dataType: 'json',
success: function(res) {
if (res.code === 0) {
var list = res.data.list;
total = res.data.total;
var html = '';
if (list.length > 0) {
list.forEach(function(item) {
html += '<tr>';
html += '<td>' + item.id + '</td>';
html += '<td>' + item.conversation_id + '</td>';
html += '<td>' + item.user_id + '</td>';
html += '<td>' + item.name + '</td>';
html += '<td>' + (item.status === 1 ? '<span class="status-active">活跃</span>' : '<span class="status-inactive">已结束</span>') + '</td>';
html += '<td>' + item.create_time + '</td>';
html += '<td>' + item.update_time + '</td>';
html += '<td>';
html += '<a href="javascript:;" class="btn btn-small btn-primary" onclick="viewMessages(' + item.id + ', \'' + item.conversation_id + '\')">查看消息</a>';
html += '<a href="javascript:;" class="btn btn-small btn-warning" onclick="endConversation(' + item.id + ')">结束会话</a>';
html += '<a href="javascript:;" class="btn btn-small btn-danger" onclick="deleteConversation(' + item.id + ')">删除</a>';
html += '</td>';
html += '</tr>';
});
} else {
html += '<tr><td colspan="8" class="text-center">暂无会话数据</td></tr>';
}
$('#conversationList').html(html);
// 渲染分页
renderPagination();
} else {
layer.msg('加载失败:' + res.message, {icon: 2});
}
},
error: function() {
layer.msg('请求失败,请稍后重试', {icon: 2});
// 渲染表格
var tableIns = table.render({
elem: '#conversationTable',
url: ns.url("aikefu://shop/kefu/getConversationList"),
method: 'POST',
toolbar: '#toolbarDemo',
defaultToolbar: ['filter', 'exports', 'print'],
title: '会话管理',
cols: [[
{field: 'id', title: 'ID', width: 80, align: 'center', fixed: 'left'},
{field: 'conversation_id', title: '会话ID', width: 200, align: 'center'},
{field: 'user_id', title: '用户ID', width: 150, align: 'center'},
{field: 'name', title: '会话名称', width: 180, align: 'center'},
{field: 'status', title: '状态', width: 100, align: 'center', templet: '#statusTpl'},
{field: 'create_time', title: '创建时间', width: 180, align: 'center'},
{field: 'update_time', title: '更新时间', width: 180, align: 'center'},
{fixed: 'right', title: '操作', width: 200, align: 'center', toolbar: '#barDemo'}
]],
page: true,
limit: 10,
limits: [10, 20, 30, 50, 100],
height: 'full-200',
text: {
none: '暂无会话数据'
}
});
// 搜索按钮点击事件
$('#searchBtn').click(function() {
// 执行搜索
tableIns.reload({
page: {
curr: 1
},
where: {
user_id: $('#user_id').val(),
status: $('#status').val()
}
});
});
// 渲染分页
function renderPagination() {
var pages = Math.ceil(total / limit);
var html = '';
// 重置按钮点击事件
$('#resetBtn').click(function() {
$('#user_id').val('');
$('#status').val('');
form.render('select');
if (pages > 1) {
html += '<ul class="pagination-list">';
// 上一页
if (page > 1) {
html += '<li><a href="javascript:;" onclick="changePage(' + (page - 1) + ')">上一页</a></li>';
} else {
html += '<li class="disabled"><a href="javascript:;">上一页</a></li>';
// 执行重置后的搜索
tableIns.reload({
page: {
curr: 1
},
where: {
user_id: '',
status: ''
}
});
});
// 页码
for (var i = 1; i <= pages; i++) {
if (i === page) {
html += '<li class="active"><a href="javascript:;">' + i + '</a></li>';
} else {
html += '<li><a href="javascript:;" onclick="changePage(' + i + ')">' + i + '</a></li>';
}
}
// 下一页
if (page < pages) {
html += '<li><a href="javascript:;" onclick="changePage(' + (page + 1) + ')">下一页</a></li>';
} else {
html += '<li class="disabled"><a href="javascript:;">下一页</a></li>';
}
html += '</ul>';
}
$('#pagination').html(html);
}
// 切换页码
window.changePage = function(p) {
page = p;
loadConversationList();
}
// 监听行工具事件
table.on('tool(conversationTable)', function(obj) {
var data = obj.data;
var layEvent = obj.event;
if (layEvent === 'view') {
// 查看消息
window.viewMessages = function(id, conversation_id) {
layer.open({
type: 2,
title: '消息记录',
content: '/shop/aikefu/kefu/message?conversation_id=' + conversation_id,
content: ns.url("aikefu://shop/kefu/message", {conversation_id: data.conversation_id}),
area: ['90%', '90%']
});
}
} else if (layEvent === 'end') {
// 结束会话
window.endConversation = function(id) {
layer.confirm('确定要结束该会话吗?', function(index) {
$.ajax({
url: '/shop/aikefu/kefu/endConversation',
url: ns.url("aikefu://shop/kefu/endConversation"),
type: 'POST',
data: {id: id},
data: {id: data.id},
dataType: 'json',
success: function(res) {
if (res.code === 0) {
layer.msg('会话已结束', {icon: 1});
loadConversationList();
// 重新加载表格数据
tableIns.reload();
} else {
layer.msg('操作失败:' + res.message, {icon: 2});
}
@@ -197,20 +185,19 @@
});
layer.close(index);
});
}
} else if (layEvent === 'delete') {
// 删除会话
window.deleteConversation = function(id) {
layer.confirm('确定要删除该会话吗?删除后将无法恢复', function(index) {
$.ajax({
url: '/shop/aikefu/kefu/deleteConversation',
url: ns.url("aikefu://shop/kefu/deleteConversation"),
type: 'POST',
data: {id: id},
data: {id: data.id},
dataType: 'json',
success: function(res) {
if (res.code === 0) {
layer.msg('会话已删除', {icon: 1});
loadConversationList();
// 重新加载表格数据
tableIns.reload();
} else {
layer.msg('操作失败:' + res.message, {icon: 2});
}
@@ -222,24 +209,6 @@
layer.close(index);
});
}
// 搜索
$('#searchBtn').click(function() {
page = 1;
loadConversationList();
});
// 重置
$('#resetBtn').click(function() {
$('#user_id').val('');
$('#status').val('');
page = 1;
loadConversationList();
});
// 初始化加载
loadConversationList();
});
</script>
</body>
</html>

View File

@@ -1,11 +1,3 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>消息管理</title>
<link rel="stylesheet" href="/__STATIC__/admin/css/global.css">
<link rel="stylesheet" href="/__STATIC__/admin/css/table.css">
<style>
.message-list {
max-height: 600px;
@@ -14,6 +6,7 @@
background-color: #f5f7fa;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #e6e6e6;
}
.message-item {
margin-bottom: 20px;
@@ -37,9 +30,10 @@
padding: 12px 16px;
border-radius: 18px;
word-wrap: break-word;
line-height: 1.5;
}
.message-item.user .message-content {
background-color: #409eff;
background-color: #1E9FFF;
color: white;
border-bottom-right-radius: 4px;
}
@@ -66,55 +60,79 @@
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border: 1px solid #e6e6e6;
}
.conversation-info h3 {
margin: 0 0 10px 0;
font-size: 16px;
color: #333;
font-weight: bold;
}
.conversation-info p {
margin: 5px 0;
font-size: 14px;
color: #606266;
}
.status-active {
color: #52c41a;
}
.status-inactive {
color: #faad14;
}
.search-box {
margin-bottom: 20px;
padding: 15px;
background-color: white;
border-radius: 8px;
border: 1px solid #e6e6e6;
}
.search-item {
margin-right: 15px;
}
.search-item label {
display: inline-block;
width: 80px;
text-align: right;
margin-right: 10px;
}
.layui-btn-sm {
margin-left: 5px;
}
</style>
</head>
<body>
<div class="main">
<div class="container">
<div class="page-title">
<h2>消息管理</h2>
<div class="layui-card-body">
<!-- 搜索区域 -->
<div class="search-box">
<form class="layui-form" id="searchForm">
<div class="search-item">
<label for="conversation_id">会话ID</label>
<input type="text" name="conversation_id" id="conversation_id" placeholder="请输入会话ID" value="{$conversation_id ?? ''}" class="layui-input" style="width: 200px; display: inline-block;">
</div>
<div class="card">
<div class="search-item">
<button type="button" class="layui-btn layui-btn-primary" id="searchBtn">搜索</button>
</div>
</form>
</div>
<!-- 会话信息 -->
<div id="conversationInfo" class="conversation-info">
<!-- 会话信息将通过JavaScript动态加载 -->
</div>
<div class="search-box">
<div class="search-item">
<label for="conversation_id">会话ID</label>
<input type="text" name="conversation_id" id="conversation_id" placeholder="请输入会话ID" value="{$conversation_id ?? ''}">
</div>
<div class="search-item">
<button type="button" class="btn btn-primary" id="searchBtn">搜索</button>
</div>
</div>
<!-- 消息列表 -->
<div class="message-list" id="messageList">
<!-- 消息列表将通过JavaScript动态加载 -->
</div>
<div class="pagination" id="pagination">
<!-- 分页将通过JavaScript动态加载 -->
</div>
</div>
</div>
<!-- 分页 -->
<div class="layui-fixbar" id="pagination"></div>
</div>
<script src="/__STATIC__/admin/js/jquery.min.js"></script>
<script src="/__STATIC__/admin/js/layer/layer.js"></script>
<script>
$(function() {
layui.use(['laypage', 'layer'], function() {
var laypage = layui.laypage;
var layer = layui.layer;
// 分页参数
var page = 1;
var limit = 50;
@@ -123,10 +141,13 @@
// 加载会话信息
function loadConversationInfo() {
if (!conversation_id) return;
if (!conversation_id) {
$('#conversationInfo').html('<h3>会话详情</h3><p>请输入会话ID进行搜索</p>');
return;
}
$.ajax({
url: '/shop/aikefu/kefu/getConversationInfo',
url: ns.url("aikefu://shop/kefu/getConversationInfo"),
type: 'POST',
data: {
conversation_id: conversation_id
@@ -156,12 +177,12 @@
// 加载消息列表
function loadMessageList() {
if (!conversation_id) {
$('#messageList').html('<div style="text-align: center; padding: 50px;">请输入会话ID进行搜索</div>');
$('#messageList').html('<div style="text-align: center; padding: 50px; color: #999;">请输入会话ID进行搜索</div>');
return;
}
$.ajax({
url: '/shop/aikefu/kefu/getMessageList',
url: ns.url("aikefu://shop/kefu/getMessageList"),
type: 'POST',
data: {
page: page,
@@ -196,7 +217,7 @@
html += '</div>';
});
} else {
html += '<div style="text-align: center; padding: 50px;">暂无消息记录</div>';
html += '<div style="text-align: center; padding: 50px; color: #999;">暂无消息记录</div>';
}
$('#messageList').html(html);
@@ -216,48 +237,27 @@
// 渲染分页
function renderPagination() {
var pages = Math.ceil(total / limit);
var html = '';
if (pages > 1) {
html += '<ul class="pagination-list">';
// 上一页
if (page > 1) {
html += '<li><a href="javascript:;" onclick="changePage(' + (page - 1) + ')">上一页</a></li>';
} else {
html += '<li class="disabled"><a href="javascript:;">上一页</a></li>';
if (total <= limit) {
$('#pagination').html('');
return;
}
// 页码
for (var i = 1; i <= pages; i++) {
if (i === page) {
html += '<li class="active"><a href="javascript:;">' + i + '</a></li>';
} else {
html += '<li><a href="javascript:;" onclick="changePage(' + i + ')">' + i + '</a></li>';
}
}
// 下一页
if (page < pages) {
html += '<li><a href="javascript:;" onclick="changePage(' + (page + 1) + ')">下一页</a></li>';
} else {
html += '<li class="disabled"><a href="javascript:;">下一页</a></li>';
}
html += '</ul>';
}
$('#pagination').html(html);
}
// 切换页码
window.changePage = function(p) {
page = p;
laypage.render({
elem: 'pagination',
count: total,
limit: limit,
curr: page,
layout: ['prev', 'page', 'next', 'count', 'skip'],
jump: function(obj, first) {
if (!first) {
page = obj.curr;
loadMessageList();
}
}
});
}
// 搜索
// 搜索按钮点击事件
$('#searchBtn').click(function() {
conversation_id = $('#conversation_id').val();
page = 1;
@@ -272,5 +272,3 @@
}
});
</script>
</body>
</html>