Compare commits

...

2 Commits

2 changed files with 568 additions and 331 deletions

View File

@@ -1,85 +1,10 @@
import request from '@/utils/request';
import request from '@/utils/request'
/**
* 获取会话列表
* @param {Object} params - 请求参数
* @param {number} params.user - 用户ID
* @returns {Promise}
*/
export function getConversationList(params) {
// 获取学生AI对话消息列表管理员查看
export function getMessagesToAdmin(params) {
return request({
url: '/aitutor/aichat/conversations',
url: '/aitutor/aichat/getMessagesToAdmin',
method: 'get',
params
});
}
/**
* 发送消息
* @param {Object} data - 请求体
* @param {string} data.query - 查询内容
* @param {string} [data.conversation_id] - 会话ID
* @param {number} data.user - 用户ID
* @param {number} data.user_id - 用户ID
* @param {string} data.user_name - 用户名
* @param {string} data.user_role - 用户角色
* @param {string} data.user_token - 用户token
* @returns {Promise}
*/
export function sendMessage(data) {
return request({
url: '/aitutor/aichat/stream',
method: 'post',
data,
headers: {
'Accept': 'text/event-stream'
}
});
}
/**
* 提交反馈
* @param {Object} data - 请求体
* @param {string} data.message_id - 消息ID
* @param {number} data.user_id - 用户ID
* @param {string} data.rating - 评分('like'或'dislike')
* @param {string} [data.content] - 反馈内容
* @returns {Promise}
*/
export function submitFeedback(data) {
return request({
url: '/aitutor/aichat/feedback',
method: 'post',
data
});
}
/**
* 获取反馈列表
* @param {Object} params - 请求参数
* @param {string} params.conversation_id - 会话ID
* @param {number} params.user_id - 用户ID
* @returns {Promise}
*/
export function getFeedbacks(params) {
return request({
url: '/aitutor/aichat/app/feedbacks',
method: 'get',
params
});
}
/**
* 获取历史消息
* @param {Object} params - 请求参数
* @param {string} params.conversation_id - 会话ID
* @param {number} params.user - 用户ID
* @returns {Promise}
*/
export function getHistoryMessages(params) {
return request({
url: '/aitutor/aichat/history',
method: 'get',
params
});
params: params
})
}

View File

@@ -1,273 +1,585 @@
<template>
<div class="app-container">
<div class="search-form">
<el-form :inline="true" :model="queryParams" ref="queryForm" label-width="68px">
<el-form-item label="用户ID" prop="user">
<el-input v-model="queryParams.user" placeholder="请输入用户ID" clearable size="small" />
</el-form-item>
<el-form-item label="会话ID" prop="conversation_id">
<el-input v-model="queryParams.conversation_id" placeholder="请输入会话ID" clearable size="small" />
</el-form-item>
<el-form-item label="消息内容" prop="content">
<el-input v-model="queryParams.content" placeholder="请输入消息内容" clearable size="small" />
</el-form-item>
<el-form-item label="时间段">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
size="small"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
<el-button type="success" icon="el-icon-menu" size="small" @click="getConversationsByUser">查询会话</el-button>
<el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="app-container">
<div class="search-form-container">
<el-form :model="queryParams" ref="queryForm" size="small" v-show="showSearch" label-width="80px" class="search-form">
<el-row :gutter="20">
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="学号" prop="stuNo">
<el-input v-model="queryParams.stuNo" placeholder="请输入学号" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="姓名" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入姓名" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="所属班级" prop="classId">
<el-cascader placeholder="请选择班级" v-model="classVlue1" :show-all-levels="false"
:options="ClassNameList" @change="handleChange1" clearable filterable style="width: 100%">
<template slot-scope="{ node, data }">
<span>{{ data.label }}</span>
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
</template>
</el-cascader>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="学院" prop="deptId">
<el-select v-model="queryParams.deptId" filterable clearable placeholder="请选择学院" style="width: 100%">
<el-option v-for="item in dept_list" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="辅导员" prop="cphName">
<el-input v-model="queryParams.cphName" placeholder="请输入辅导员" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="年级" prop="gradeId">
<el-select v-model="queryParams.gradeId" filterable clearable placeholder="请选择年级" style="width: 100%">
<el-option v-for="item in grade_list" :key="item.gradeId" :label="item.gradeName" :value="item.gradeId">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
<el-form-item class="search-buttons">
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<el-table v-loading="loading" :data="historyList" border fit highlight-current-row style="width: 100%">
<el-table-column label="序号" type="index" width="50" align="center" />
<el-table-column prop="user" label="用户ID" width="100" align="center" />
<el-table-column prop="conversation_id" label="会话ID" width="180" align="center" />
<el-table-column prop="message_id" label="消息ID" width="180" align="center" />
<el-table-column prop="type" label="消息类型" width="80" align="center">
<template slot-scope="scope">
<el-tag :type="scope.row.type === 'user' ? 'primary' : 'success'" size="small">
{{ scope.row.type === 'user' ? '用户' : 'AI' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="content" label="消息内容" min-width="300">
<template slot-scope="scope">
<div v-html="scope.row.content"></div>
</template>
</el-table-column>
<el-table-column prop="feedback" label="反馈状态" width="100" align="center">
<template slot-scope="scope">
<div v-if="scope.row.feedback === 'like'"><i class="el-icon-thumb text-primary"></i> 点赞</div>
<div v-else-if="scope.row.feedback === 'dislike'"><i class="el-icon-minus text-danger"></i> 点踩</div>
<div v-else>无反馈</div>
</template>
</el-table-column>
<el-table-column prop="created_at" label="创建时间" width="180" align="center" />
<el-table-column label="操作" width="150" align="center" fixed="right">
<template slot-scope="scope">
<el-button type="primary" icon="el-icon-view" size="mini" @click="viewMessage(scope.row)">查看详情</el-button>
</template>
</el-table-column>
</el-table>
<el-row :gutter="10" class="mb8">
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="studentList" style="width: 100%">
<el-table-column label="学号" align="center" prop="stuNo" min-width="120" />
<el-table-column label="姓名" align="center" prop="name" min-width="100" />
<el-table-column label="性别" align="center" prop="gender" min-width="80" />
<el-table-column label="学院名称" align="center" prop="deptId" min-width="120">
<template slot-scope="scope">
<span>{{ scope.row.dept.deptName }}</span>
</template>
</el-table-column>
<el-table-column label="专业名称" align="center" prop="majorId" min-width="200">
<template slot-scope="scope">
<span>{{ scope.row.srsMajors.majorName }}</span>
</template>
</el-table-column>
<el-table-column label="班级名称" align="center" prop="classId" min-width="200">
<template slot-scope="scope">
<span>{{ scope.row.srsClass.className }}</span>
</template>
</el-table-column>
<el-table-column label="辅导员" align="center" prop="cphName" min-width="100" />
<el-table-column label="学生状态" align="center" prop="status" min-width="100">
<template slot-scope="scope">
<dict-tag :options="dict.type.srs_stu_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" min-width="120">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-chat-dot-round" @click="viewConversations(scope.row)">查看会话列表</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<el-pagination
v-show="total > 0"
:current-page="queryParams.pageNum"
:page-size="queryParams.pageSize"
:total="total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize" @pagination="getList" />
<!-- AI对话记录弹出对话框 -->
<el-dialog
title="AI对话记录"
:visible.sync="dialogVisible"
width="80%"
:before-close="closeChatHistory"
class="chat-dialog"
>
<div class="dialog-header" v-if="currentStudent">
<span class="student-info">学生{{ currentStudent.name }}{{ currentStudent.stuNo }}</span>
</div>
<div v-loading="chatLoading" class="chat-content">
<div v-if="chatMessages.length === 0 && !chatLoading" class="no-chat">
<el-empty description="暂无对话记录"></el-empty>
</div>
<div v-for="message in chatMessages" :key="message.id" class="message-item">
<div class="message-header">
<span class="message-time">{{ parseTime(message.created_at * 1000, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
<div class="feedback-status" v-if="message.feedback">
<el-tag v-if="message.feedback && message.feedback.rating === 'like'" type="success" size="mini">
<i class="el-icon-thumb-up"></i> 点赞
</el-tag>
<el-tag v-else-if="message.feedback && message.feedback.rating === 'dislike'" type="danger" size="mini">
<i class="el-icon-thumb-down"></i> 点踩
</el-tag>
</div>
</div>
<div class="message-content">
<div class="user-message">
<div class="message-label">学生提问</div>
<div class="message-text user-text">{{ message.query }}</div>
</div>
<div class="ai-message">
<div class="message-label">AI回答</div>
<div class="message-text ai-text" :class="{
'feedback-like': message.feedback && message.feedback.rating === 'like',
'feedback-dislike': message.feedback && message.feedback.rating === 'dislike'
}">{{ message.answer }}</div>
</div>
</div>
</div>
</div>
</el-dialog>
</div>
</div>
</template>
<script>
import { getHistoryMessages, getFeedbacks, getConversationList } from "@/api/aitutor/chat";
import { getTokenKeySessionStorage } from "@/utils/auth";
import { listStudent, getClassName } from "@/api/stuCQS/basedata/student";
import { getMessagesToAdmin } from "@/api/aitutor/chat";
import { listGrade } from "@/api/stuCQS/basedata/grade";
import { getDeptName } from "@/api/system/dept";
export default {
name: "ChatHistory",
data() {
return {
loading: false,
historyList: [],
conversationList: [], // 存储会话列表
total: 0,
queryParams: {
pageNum: 1,
pageSize: 10,
user: undefined,
conversation_id: undefined,
content: undefined
},
dateRange: [],
userToken: getTokenKeySessionStorage()
};
},
created() {
this.getList();
},
methods: {
/** 根据用户ID查询会话列表 */
getConversationsByUser() {
if (!this.queryParams.user) {
this.$message.error('请输入用户ID');
return;
}
this.loading = true;
const params = {
user: this.queryParams.user
};
getConversationList(params).then(response => {
if (response.code === 200) {
let conversationData = response.data;
// 如果返回的是字符串形式的JSON尝试解析
if (typeof conversationData === 'string') {
name: "ChatHistory",
dicts: ['srs_stu_status'],
data() {
return {
// 遮罩层
loading: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 学生信息表格数据
studentList: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
name: null,
stuNo: null,
deptId: null,
classId: null,
cphName: null,
gradeId: null
},
// 班级名称列表
ClassNameList: [],
// 班级搜索选择
classVlue1: [],
// 学院列表
dept_list: [],
// 年级列表
grade_list: [],
// AI对话记录相关
dialogVisible: false,
chatMessages: [],
chatLoading: false,
currentStudent: null
};
},
created() {
this.getList();
this.getClassNameList();
this.listDept();
this.listGrade();
},
methods: {
/** 查询学生信息列表 */
getList() {
this.loading = true;
listStudent(this.queryParams).then(response => {
console.log('学生列表API响应:', response);
// 根据实际API响应结构调整数据获取方式
if (response.data) {
this.studentList = response.data.rows || response.data || [];
this.total = response.data.total || response.total || 0;
} else {
this.studentList = response.rows || [];
this.total = response.total || 0;
}
this.loading = false;
}).catch(error => {
console.error('获取学生列表失败:', error);
this.$message.error('获取学生列表失败');
this.loading = false;
});
},
/** 获取班级名称列表 */
getClassNameList() {
getClassName().then(res => {
this.ClassNameList = res.data;
});
},
/** 获取学院列表 */
async listDept() {
try {
conversationData = JSON.parse(conversationData);
} catch (e) {
console.error('解析会话列表数据失败:', e);
let res = await getDeptName();
this.dept_list = [...res.data];
} catch (error) {
console.error('获取学院列表失败:', error);
}
}
// 格式化数据
if (Array.isArray(conversationData)) {
this.conversationList = conversationData;
if (conversationData.length > 0) {
this.$message.success(`成功获取到${conversationData.length}条会话记录`);
// 如果只有一条会话可以自动填充到会话ID输入框
if (conversationData.length === 1) {
this.queryParams.conversation_id = conversationData[0].conversation_id;
}
} else {
this.$message.info('未找到该用户的会话记录');
}
} else if (conversationData && Array.isArray(conversationData.list)) {
this.conversationList = conversationData.list;
this.$message.success(`成功获取到${conversationData.list.length}条会话记录`);
} else {
this.conversationList = [];
this.$message.info('未找到该用户的会话记录');
}
} else {
this.$message.error("获取会话列表失败:" + (response.msg || response.message));
}
this.loading = false;
}).catch(error => {
console.error('获取会话列表失败:', error);
this.$message.error("网络错误:" + error.message);
this.loading = false;
});
},
/** 查询历史消息列表 */
getList() {
this.loading = true;
// 处理日期范围
if (this.dateRange && this.dateRange.length > 0) {
this.queryParams.start_time = this.dateRange[0];
this.queryParams.end_time = this.dateRange[1];
} else {
this.queryParams.start_time = undefined;
this.queryParams.end_time = undefined;
}
// 检查user参数是否存在
if (!this.queryParams.user) {
this.$message.error('请输入用户ID');
this.loading = false;
return;
}
// 添加user参数以匹配API要求
const params = {
...this.queryParams,
user: this.queryParams.user
};
getHistoryMessages(params).then(response => {
// 假设接口返回格式为 { code: 200, data: { list: [], total: 0 } }
// 根据实际接口调整
if (response.code === 200) {
let historyData = response.data;
// 如果返回的是字符串形式的JSON尝试解析
if (typeof historyData === 'string') {
},
/** 获取年级列表 */
async listGrade() {
try {
historyData = JSON.parse(historyData);
} catch (e) {
console.error('解析历史消息数据失败:', e);
let res = await listGrade();
if (res.code == 200) {
this.grade_list = [...res.rows];
}
} catch (error) {
console.error('获取年级列表失败:', error);
}
}
// 格式化数据
if (Array.isArray(historyData)) {
this.historyList = historyData;
this.total = historyData.length;
} else if (historyData && Array.isArray(historyData.list)) {
this.historyList = historyData.list;
this.total = historyData.total;
} else {
this.historyList = [];
this.total = 0;
}
} else {
this.$message.error("获取历史消息失败:" + (response.msg || response.message));
},
/** 搜索班级选择 */
handleChange1(value) {
this.queryParams.classId = value[2];
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.classVlue1 = [];
this.handleQuery();
},
/** 查看AI对话记录 */
viewConversations(row) {
this.currentStudent = row;
this.dialogVisible = true;
this.chatLoading = true;
this.chatMessages = [];
getMessagesToAdmin({
user: row.stuNo
}).then(response => {
console.log('对话记录API响应:', response);
if (response.code === 200 && response.data && response.data.data) {
this.chatMessages = response.data.data;
} else {
this.$modal.msgWarning(response.msg || '该学生暂无对话记录');
}
this.chatLoading = false;
}).catch(error => {
console.error('获取对话记录失败:', error);
this.$modal.msgError('获取对话记录失败');
this.chatLoading = false;
});
},
/** 关闭对话记录 */
closeChatHistory() {
this.dialogVisible = false;
this.currentStudent = null;
this.chatMessages = [];
}
this.loading = false;
}).catch(error => {
console.error('获取历史消息失败:', error);
this.$message.error("网络错误:" + error.message);
this.loading = false;
});
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];
this.$refs.queryForm.resetFields();
this.handleQuery();
},
/** 查看消息详情 */
viewMessage(row) {
// 这里可以实现查看消息详情的逻辑
this.$modal.msgDetail('消息详情', {
user: row.user,
conversation_id: row.conversation_id,
message_id: row.message_id,
type: row.type,
content: row.content,
feedback: row.feedback,
created_at: row.created_at
});
// 如果需要更复杂的详情展示,可以打开一个新的弹窗组件
// this.$refs.detailDialog.open(row);
},
/** 分页大小改变 */
handleSizeChange(val) {
this.queryParams.pageSize = val;
this.getList();
},
/** 当前页码改变 */
handleCurrentChange(val) {
this.queryParams.pageNum = val;
this.getList();
}
}
};
</script>
<style scoped>
.search-form {
margin-bottom: 20px;
.app-container {
padding: 20px;
}
.pagination-container {
margin-top: 20px;
text-align: right;
.mb8 {
margin-bottom: 8px;
}
.el-table .cell {
word-break: break-word;
}
/* 搜索表单容器样式 */
.search-form-container {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 0.5rem;
padding: 1.25rem;
margin-bottom: 1.25rem;
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.05);
box-sizing: border-box;
}
.search-form {
margin: 0;
width: 100%;
box-sizing: border-box;
}
.search-form .el-row {
display: flex;
flex-wrap: wrap;
margin: 0 -0.625rem;
}
.search-form .el-col {
padding: 0 0.625rem;
box-sizing: border-box;
min-width: 0;
flex-shrink: 0;
}
.search-form .el-form-item {
margin-bottom: 1rem;
width: 100%;
box-sizing: border-box;
}
.search-form .el-form-item__label {
font-weight: 500;
color: #606266;
white-space: nowrap;
min-width: 5rem;
box-sizing: border-box;
}
.search-form .el-form-item__content {
flex: 1;
min-width: 0;
box-sizing: border-box;
}
.search-form .el-input,
.search-form .el-select,
.search-form .el-cascader {
width: 100%;
min-width: 8rem;
box-sizing: border-box;
}
.search-form .el-input__inner,
.search-form .el-select .el-input__inner {
box-sizing: border-box;
transition: all 0.3s ease;
}
/* 搜索按钮样式 */
.search-buttons {
text-align: center;
margin-top: 0.625rem;
width: 100%;
box-sizing: border-box;
}
.search-buttons .el-button {
margin: 0 0.5rem;
padding: 0.5rem 1.25rem;
border-radius: 0.25rem;
font-weight: 500;
box-sizing: border-box;
min-width: 4rem;
}
.search-buttons .el-button--primary {
background: linear-gradient(135deg, #409eff 0%, #1890ff 100%);
border: none;
box-shadow: 0 0.125rem 0.25rem rgba(64, 158, 255, 0.3);
}
.search-buttons .el-button--primary:hover {
background: linear-gradient(135deg, #66b1ff 0%, #40a9ff 100%);
box-shadow: 0 0.25rem 0.5rem rgba(64, 158, 255, 0.4);
}
/* 缩放适配 - 针对110%等非标准缩放 */
@media screen and (min-resolution: 1.1dppx) and (max-resolution: 1.3dppx) {
.search-form-container {
padding: 1rem;
}
.search-form .el-form-item {
margin-bottom: 0.875rem;
}
.search-form .el-form-item__label {
min-width: 4.5rem;
font-size: 0.875rem;
}
.search-form .el-input,
.search-form .el-select,
.search-form .el-cascader {
min-width: 7rem;
}
}
/* 响应式调整 */
@media (max-width: 768px) {
.search-form-container {
padding: 0.9375rem;
}
.search-form .el-form-item {
margin-bottom: 0.75rem;
}
.search-form .el-form-item__label {
min-width: auto;
margin-bottom: 0.25rem;
}
.search-buttons {
text-align: left;
}
.search-buttons .el-button {
margin: 0.25rem 0.5rem 0.25rem 0;
}
}
/* 超小屏幕适配 */
@media (max-width: 480px) {
.search-form .el-col {
flex: 0 0 100%;
max-width: 100%;
}
.search-form .el-form-item__label {
width: 100%;
text-align: left;
}
}
/* 对话框样式 */
.chat-dialog .el-dialog__body {
padding: 0;
}
.dialog-header {
background: #f8f9fa;
padding: 16px 20px;
border-bottom: 1px solid #e9ecef;
margin-bottom: 0;
}
.student-info {
color: #606266;
font-size: 14px;
font-weight: 500;
}
.chat-content {
max-height: 500px;
overflow-y: auto;
padding: 20px;
}
.no-chat {
text-align: center;
padding: 40px 0;
}
.message-item {
margin-bottom: 24px;
border: 1px solid #e4e7ed;
border-radius: 8px;
overflow: hidden;
}
.message-header {
background: #f5f7fa;
padding: 12px 16px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #e4e7ed;
}
.message-time {
color: #909399;
font-size: 12px;
}
.feedback-status {
display: flex;
align-items: center;
}
.message-content {
padding: 16px;
}
.user-message,
.ai-message {
margin-bottom: 16px;
}
.user-message:last-child,
.ai-message:last-child {
margin-bottom: 0;
}
.message-label {
font-weight: 600;
color: #303133;
margin-bottom: 8px;
font-size: 14px;
}
.message-text {
padding: 12px 16px;
border-radius: 6px;
line-height: 1.6;
font-size: 14px;
word-wrap: break-word;
}
.user-text {
background: #f0f9ff;
border: 1px solid #e1f5fe;
color: #0277bd;
}
.ai-text {
background: #f8f9fa;
border: 1px solid #e9ecef;
color: #495057;
}
.ai-text.feedback-like {
background: #f0f9ff;
border-color: #4caf50;
box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.1);
}
.ai-text.feedback-dislike {
background: #fff5f5;
border-color: #f56565;
box-shadow: 0 0 0 2px rgba(245, 101, 101, 0.1);
}
/* 滚动条样式 */
.chat-content::-webkit-scrollbar {
width: 6px;
}
.chat-content::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.chat-content::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
}
.chat-content::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
</style>