Tcode平台改造升级-AI助手菜单显示功能修改
This commit is contained in:
324
src/layouts/AILayout/ViewHistoryAside/ViewHistoryAsideNew.vue
Normal file
324
src/layouts/AILayout/ViewHistoryAside/ViewHistoryAsideNew.vue
Normal file
@@ -0,0 +1,324 @@
|
||||
<template>
|
||||
<Card class="ViewHistoryAside">
|
||||
<!-- 1. 新对话按钮 -->
|
||||
<div class="new-conv-wrap">
|
||||
<d-button
|
||||
variant="solid"
|
||||
class="new-conv-btn"
|
||||
@click="handleNewConversation"
|
||||
>
|
||||
<template #icon>
|
||||
<d-icon name="icon-plus" />
|
||||
</template>
|
||||
新对话
|
||||
<span class="shortcut">Ctrl+N</span>
|
||||
</d-button>
|
||||
</div>
|
||||
|
||||
<!-- 2. 功能入口区域 -->
|
||||
<div class="function-list">
|
||||
<div class="function-item" @click="handleFunction('write')">
|
||||
<d-icon name="icon-pencil" />
|
||||
<span>帮我写</span>
|
||||
</div>
|
||||
<div class="function-item" @click="handleFunction('create')">
|
||||
<d-icon name="icon-magic" />
|
||||
<span>AI 创作</span>
|
||||
</div>
|
||||
<div class="function-item" @click="handleFunction('app')">
|
||||
<d-icon name="icon-app" />
|
||||
<span>应用生成</span>
|
||||
</div>
|
||||
<div class="function-item" @click="handleFunction('cloud')">
|
||||
<d-icon name="icon-cloud" />
|
||||
<span>云盘</span>
|
||||
</div>
|
||||
<div class="function-item more-item" @click="toggleMoreFunc">
|
||||
<span>更多</span>
|
||||
<d-icon name="icon-arrow-right" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3. 历史对话标题 -->
|
||||
<div class="history-title">历史对话</div>
|
||||
|
||||
<!-- 4. 历史对话列表 -->
|
||||
<div class="history-conv-list">
|
||||
<!-- 列表项(循环渲染) -->
|
||||
<div
|
||||
v-if="dhlsList.length>0"
|
||||
v-for="(item, index) in dhlsList"
|
||||
:key="item.id"
|
||||
class="conv-item"
|
||||
@click="selectConversation(item)"
|
||||
@mouseenter="hoverIndex = index"
|
||||
@mouseleave="hoverIndex = null"
|
||||
>
|
||||
<!-- 对话标题 + 星标(收藏标识) -->
|
||||
<div class="conv-title">
|
||||
<span>{{ item.question }}</span>
|
||||
<d-icon
|
||||
v-if="item.isStarred"
|
||||
name="icon-star"
|
||||
class="star-icon"
|
||||
@click.stop="toggleStar(item)"
|
||||
/>
|
||||
</div>
|
||||
<!-- 未读小红点 -->
|
||||
<d-badge
|
||||
v-if="item.unreadCount > 0"
|
||||
:content="item.unreadCount"
|
||||
class="unread-badge"
|
||||
/>
|
||||
<!-- 更多操作按钮(hover显示) -->
|
||||
<d-icon
|
||||
v-show="hoverIndex === index"
|
||||
name="icon-more-operate"
|
||||
class="more-icon"
|
||||
@click.stop="handleMore(item)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 无数据占位 -->
|
||||
<NoData v-else :small="false"></NoData>
|
||||
</div>
|
||||
</Card>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { Message } from 'vue-devui/message';
|
||||
import { useTimeFormat } from '@/utils/hooks/useTimeFormat';
|
||||
import axios from 'axios';
|
||||
|
||||
// ========== 状态与数据 ==========
|
||||
const hoverIndex = ref(null); // 鼠标悬浮的列表项索引
|
||||
const { formatTime } = useTimeFormat();
|
||||
const VITE_AI_API_HOST = import.meta.env.VITE_AI_API_HOST;
|
||||
|
||||
// 历史对话列表(新增 isStarred:星标收藏;unreadCount:未读小红点)
|
||||
const dhlsList = ref([
|
||||
{
|
||||
question: "解决菜单功能异常",
|
||||
id: 1,
|
||||
isStarred: true,
|
||||
unreadCount: 0
|
||||
},
|
||||
{
|
||||
question: "项目界面与前端实现",
|
||||
id: 2,
|
||||
isStarred: true,
|
||||
unreadCount: 0
|
||||
},
|
||||
{
|
||||
question: "添加拓扑折叠置顶",
|
||||
id: 3,
|
||||
isStarred: false,
|
||||
unreadCount: 0
|
||||
},
|
||||
{
|
||||
question: "Vue3 代码片段展示组件",
|
||||
id: 4,
|
||||
isStarred: false,
|
||||
unreadCount: 0
|
||||
},
|
||||
{
|
||||
question: "Spring Boot 项目文件结构解释",
|
||||
id: 5,
|
||||
isStarred: false,
|
||||
unreadCount: 0
|
||||
},
|
||||
{
|
||||
question: "调用接口获取文件信息",
|
||||
id: 6,
|
||||
isStarred: false,
|
||||
unreadCount: 1
|
||||
},
|
||||
{
|
||||
question: "Nuxt 项目创建及报错处理",
|
||||
id: 7,
|
||||
isStarred: false,
|
||||
unreadCount: 0
|
||||
},
|
||||
{
|
||||
question: "手机版对话",
|
||||
id: 8,
|
||||
isStarred: false,
|
||||
unreadCount: 0
|
||||
}
|
||||
]);
|
||||
|
||||
// ========== 方法 ==========
|
||||
// 新对话按钮点击
|
||||
const handleNewConversation = () => {
|
||||
console.log("创建新对话");
|
||||
// 可添加:清空当前对话、初始化新会话等逻辑
|
||||
};
|
||||
|
||||
// 功能入口点击
|
||||
const handleFunction = (type) => {
|
||||
console.log("点击功能:", type);
|
||||
// 可添加:跳转到对应功能页的逻辑
|
||||
};
|
||||
|
||||
// 展开/收起“更多”功能
|
||||
const toggleMoreFunc = () => {
|
||||
console.log("切换更多功能展开状态");
|
||||
// 可添加:下拉菜单展开逻辑
|
||||
};
|
||||
|
||||
// 选择对话
|
||||
const selectConversation = (item) => {
|
||||
console.log("选中对话:", item);
|
||||
// 可添加:加载对应对话内容的逻辑
|
||||
};
|
||||
|
||||
// 切换星标收藏
|
||||
const toggleStar = (item) => {
|
||||
item.isStarred = !item.isStarred;
|
||||
Message.success(item.isStarred ? "已收藏" : "已取消收藏");
|
||||
};
|
||||
|
||||
// 更多操作
|
||||
const handleMore = (item) => {
|
||||
console.log("更多操作:", item);
|
||||
// 可添加:编辑/删除/分享等逻辑
|
||||
};
|
||||
|
||||
// 接口获取历史对话(替换模拟数据)
|
||||
const getQuestionHistory = async () => {
|
||||
try {
|
||||
const { data } = await axios.get(`${VITE_AI_API_HOST}/api/conversationList?userId=?`);
|
||||
if (data.questions) {
|
||||
// 给接口返回的数据补充 isStarred/unreadCount 字段
|
||||
dhlsList.value = data.questions.map(item => ({
|
||||
...item,
|
||||
isStarred: item.isCollected || false, // 假设接口返回 isCollected 表示收藏
|
||||
unreadCount: item.unreadNum || 0 // 假设接口返回 unreadNum 表示未读
|
||||
}));
|
||||
}
|
||||
} catch (err) {
|
||||
Message.warning('获取历史对话失败!');
|
||||
}
|
||||
};
|
||||
|
||||
// 组件挂载时加载数据
|
||||
onMounted(() => {
|
||||
getQuestionHistory();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ViewHistoryAside {
|
||||
width: 18vw;
|
||||
position: fixed;
|
||||
top: 64px;
|
||||
left: 20px;
|
||||
height: 85vh;
|
||||
padding: 12px 16px;
|
||||
|
||||
// 新对话按钮样式
|
||||
.new-conv-wrap {
|
||||
margin-bottom: 16px;
|
||||
.new-conv-btn {
|
||||
width: 100%;
|
||||
background-color: #e6f7ff;
|
||||
color: #1890ff;
|
||||
justify-content: flex-start;
|
||||
.shortcut {
|
||||
margin-left: auto;
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 功能入口列表样式
|
||||
.function-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
.function-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.more-item {
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 历史对话标题样式
|
||||
.history-title {
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
margin-bottom: 12px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
// 历史对话列表样式
|
||||
.history-conv-list {
|
||||
height: calc(100% - 180px); // 自适应剩余高度
|
||||
overflow-y: auto;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #ddd transparent;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: #ddd;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
// 列表项样式
|
||||
.conv-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 4px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-bottom: 4px;
|
||||
transition: background-color 0.2s;
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
// 对话标题+星标
|
||||
.conv-title {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
.star-icon {
|
||||
color: #faad14;
|
||||
}
|
||||
}
|
||||
|
||||
// 未读小红点
|
||||
.unread-badge {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
// 更多操作按钮
|
||||
.more-icon {
|
||||
opacity: 0.6;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,596 @@
|
||||
<template>
|
||||
<div class="chat-sidebar">
|
||||
<div class="top-section">
|
||||
<div class="new-chat-btn" @click="handleNewChat">
|
||||
<div class="btn-content">
|
||||
<d-icon name="icon-edit" size="16px"></d-icon>
|
||||
<span class="btn-text">新对话</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-container">
|
||||
|
||||
<div class="menu-section">
|
||||
<div
|
||||
v-for="menu in menuList"
|
||||
:key="menu.id"
|
||||
class="menu-item"
|
||||
@click="handleMenuClick(menu)"
|
||||
>
|
||||
<d-icon :name="menu.icon" size="16px" class="menu-icon"></d-icon>
|
||||
<span class="menu-text">{{ menu.title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="search-section">
|
||||
<d-search icon-position="left" style="width: 100%" placeholder="搜索历史对话" v-model="searchText" @change="loadData" @search="loadData"></d-search>
|
||||
</div>
|
||||
|
||||
<div class="history-section">
|
||||
<div class="section-title">历史对话</div>
|
||||
|
||||
<div v-if="dhlsList.length > 0">
|
||||
<div
|
||||
v-for="(item, index) in dhlsList"
|
||||
:key="item.conversationId"
|
||||
:class="['history-item', { 'active': props.CONV_ID === item.conversationId }]"
|
||||
@click="handleSelect(item)"
|
||||
@mouseenter="hoverIndex = index"
|
||||
@mouseleave="hoverIndex = null"
|
||||
>
|
||||
<template v-if="item.isEditing">
|
||||
<d-input
|
||||
v-model="item.tempTitle"
|
||||
autofocus
|
||||
class="edit-input"
|
||||
@keypress.enter="confirmEdit(item)"
|
||||
@blur="cancelEdit(item)"
|
||||
/>
|
||||
<div class="edit-actions">
|
||||
<d-icon name="icon-right" class="action-icon success" @click.stop="confirmEdit(item)"/>
|
||||
<d-icon name="icon-error" class="action-icon danger" @click.stop="cancelEdit(item)"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<d-icon name="icon-message" size="16px" class="item-icon"></d-icon>
|
||||
|
||||
<div class="item-content" @dblclick="startEdit(item)">
|
||||
<span class="item-title text-ellipsis">{{ item.title || '新对话' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="item-actions">
|
||||
<d-icon v-if="item.is_collected" name="icon-star-o" size="14px" class="pin-icon" style="color: #f7ba2a;"></d-icon>
|
||||
|
||||
<d-icon v-if="item.isPinned" name="icon-pin-fill" size="14px" class="pin-icon"></d-icon>
|
||||
|
||||
<div class="hover-actions" v-show="hoverIndex === index">
|
||||
<d-dropdown trigger="click" :close-on-click="true" align="start">
|
||||
<d-icon name="icon-more-operate" size="16px" class="more-btn"></d-icon>
|
||||
<template #menu>
|
||||
<ul class="dropdown-menu">
|
||||
<li @click.stop="handlePin(item)">
|
||||
{{ item.isPinned ? '取消置顶' : '置顶' }}
|
||||
</li>
|
||||
<li @click.stop="toggleCollect(item)">
|
||||
{{ item.is_collected ? '取消收藏' : '收藏' }}
|
||||
</li>
|
||||
<li @click.stop="startEdit(item)">重命名</li>
|
||||
<li @click.stop="handleDelete([item.conversationId])" class="danger">删除</li>
|
||||
</ul>
|
||||
</template>
|
||||
</d-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="empty-state">
|
||||
暂无历史对话
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bottom-section">
|
||||
<div class="bottom-controls">
|
||||
<div class="limit-select">
|
||||
<span>保存条数</span>
|
||||
<d-select
|
||||
v-model="historyLimit"
|
||||
size="sm"
|
||||
class="mini-select"
|
||||
@value-change="handleHistoryLimitChange"
|
||||
>
|
||||
<d-option value="10">10</d-option>
|
||||
<d-option value="20">20</d-option>
|
||||
<d-option value="30">30</d-option>
|
||||
<d-option value="0">不限</d-option>
|
||||
</d-select>
|
||||
</div>
|
||||
<div class="batch-btn" @click="openBatchManageModal">
|
||||
<d-icon name="icon-property-setting"></d-icon>
|
||||
<span>批量管理</span>
|
||||
</div>
|
||||
</div>
|
||||
<BatchManageModal :username="props.username" @loadData="loadData" ref="BatchManageModalRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref, defineEmits, defineExpose, defineProps } from 'vue';
|
||||
import BatchManageModal from './BatchManageModal.vue';
|
||||
import { Message } from 'vue-devui/message';
|
||||
import { useTimeFormat } from '@/utils/hooks/useTimeFormat';
|
||||
import {
|
||||
fetchChangeConversationTitle,
|
||||
fetchConversationList,
|
||||
fetchDeleteConversation,
|
||||
fetchToggleConversationCollect
|
||||
} from '@/api/jyh';
|
||||
|
||||
// --- Props & Emits ---
|
||||
const props = defineProps(['username', 'CONV_ID']);
|
||||
const emit = defineEmits(['select-conv','onNewConvo']);
|
||||
|
||||
// --- State ---
|
||||
const searchText = ref('');
|
||||
const historyLimit = ref('30');
|
||||
const hoverIndex = ref(null);
|
||||
const BatchManageModalRef = ref(null);
|
||||
const dhlsList = ref([]); // 历史对话列表
|
||||
const page = ref({
|
||||
pageNum: 1,
|
||||
size: 30 // 默认 30,与 historyLimit 对应
|
||||
});
|
||||
|
||||
// 静态菜单数据
|
||||
const menuList = [
|
||||
{ id: 'write', title: 'SBOM分析', icon: 'icon-accelerations' },
|
||||
{ id: 'create', title: '许可证合规检测', icon: 'icon-add-example' },
|
||||
{ id: 'app', title: '供应链安全检测', icon: 'icon-branch-merge-o' },
|
||||
{ id: 'cloud', title: '代码安全审计', icon: 'icon-add-token' },
|
||||
{ id: 'more', title: '漏洞智能修复', icon: 'icon-assembly-new' },
|
||||
];
|
||||
|
||||
const { formatTime } = useTimeFormat();
|
||||
|
||||
// --- Methods ---
|
||||
|
||||
// 1. 加载数据
|
||||
const loadData = async () => {
|
||||
await getQuestionHistory();
|
||||
};
|
||||
|
||||
const getQuestionHistory = async () => {
|
||||
if (props.username) {
|
||||
const { data } = await fetchConversationList({
|
||||
"userId": props.username,
|
||||
"list_type": "history", // 或者根据需求调整,例如同时获取收藏
|
||||
"is_manage": false,
|
||||
"page": page.value.pageNum,
|
||||
"size": page.value.size,
|
||||
"search": searchText.value
|
||||
});
|
||||
if (data.code === 200) {
|
||||
// 处理数据,补充前端状态字段
|
||||
dhlsList.value = data.data.map(item => ({
|
||||
...item,
|
||||
isEditing: false,
|
||||
tempTitle: '',
|
||||
isPinned: item.isPinned || false // 如果后端有置顶字段则使用,否则默认 false
|
||||
}));
|
||||
} else {
|
||||
// Message.error(data.msg || '接口异常!');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 2. 新建对话
|
||||
const handleNewChat = () => {
|
||||
emit('select-conv', null);
|
||||
};
|
||||
|
||||
// 3. 选中对话
|
||||
const handleSelect = (item) => {
|
||||
if (item.isEditing) return; // 编辑中不触发选中
|
||||
emit('select-conv', item.conversationId);
|
||||
};
|
||||
|
||||
// 4. 菜单点击
|
||||
const handleMenuClick = (menu) => {
|
||||
console.log('点击菜单:', menu.title);
|
||||
// 路由跳转或功能触发逻辑
|
||||
};
|
||||
|
||||
// 5. 编辑/重命名逻辑
|
||||
const startEdit = (item) => {
|
||||
item.isEditing = true;
|
||||
item.tempTitle = item.title;
|
||||
};
|
||||
|
||||
const confirmEdit = async (item) => {
|
||||
if (!item.tempTitle.trim()) {
|
||||
Message.error('标题不能为空');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await fetchChangeConversationTitle({
|
||||
conversationId: item.conversationId,
|
||||
newTitle: item.tempTitle,
|
||||
userId: props.username,
|
||||
});
|
||||
|
||||
if (res.data.code === 200 || res.data.code === 20001 || res.data.code === 20000) {
|
||||
item.title = item.tempTitle;
|
||||
item.isEditing = false;
|
||||
Message.success('标题修改成功');
|
||||
} else {
|
||||
Message.error(res.data.msg || '修改失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('编辑失败:', error);
|
||||
item.tempTitle = item.title;
|
||||
item.isEditing = false;
|
||||
}
|
||||
};
|
||||
|
||||
const cancelEdit = (item) => {
|
||||
item.isEditing = false;
|
||||
item.tempTitle = item.title;
|
||||
};
|
||||
|
||||
// 6. 收藏逻辑
|
||||
const toggleCollect = async (item) => {
|
||||
if (!props.username) {
|
||||
return Message.error('请先登录');
|
||||
}
|
||||
try {
|
||||
const res = await fetchToggleConversationCollect({
|
||||
userId: props.username,
|
||||
conversationIdList: [item.conversationId]
|
||||
});
|
||||
|
||||
if (res.data.code === 200 || res.data.code === 20000) {
|
||||
await loadData(); // 重新加载以更新状态
|
||||
Message.success(res.data.msg || '操作成功');
|
||||
} else {
|
||||
Message.error(res.data.msg);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('收藏操作失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 7. 删除逻辑
|
||||
const handleDelete = async (conversationIds) => {
|
||||
if (!props.username) {
|
||||
return Message.error('请先登录');
|
||||
}
|
||||
try {
|
||||
const res = await fetchDeleteConversation({
|
||||
userId: props.username,
|
||||
conversationIdList: conversationIds
|
||||
}
|
||||
);
|
||||
|
||||
if (res.data.code === 200 || res.data.code === 20000) {
|
||||
Message.success(res.data.message || '删除成功');
|
||||
loadData();
|
||||
} else {
|
||||
Message.error(res.data.msg || '删除对话失败!');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除对话失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 8. 置顶逻辑 (前端模拟)
|
||||
const handlePin = (item) => {
|
||||
item.isPinned = !item.isPinned;
|
||||
// 本地排序:置顶的排前面
|
||||
dhlsList.value.sort((a, b) => (b.isPinned ? 1 : 0) - (a.isPinned ? 1 : 0));
|
||||
// 如果有后端置顶接口,请在这里调用
|
||||
};
|
||||
|
||||
// 9. 批量管理 & 分页条数
|
||||
const openBatchManageModal = () => {
|
||||
if (BatchManageModalRef.value) {
|
||||
BatchManageModalRef.value.openModal();
|
||||
}
|
||||
};
|
||||
|
||||
const handleHistoryLimitChange = (val) => {
|
||||
page.value.size = Number(val) || 10000; // 0 为不限
|
||||
page.value.pageNum = 1;
|
||||
loadData();
|
||||
};
|
||||
|
||||
// --- Lifecycle ---
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
getQuestionHistory,
|
||||
loadData
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 容器样式:固定宽度,高度适配 */
|
||||
.chat-sidebar {
|
||||
width: 260px;
|
||||
height: 85vh; /* 或 100% */
|
||||
background-color: #f7f8fa; /* 浅灰背景 */
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 12px;
|
||||
box-sizing: border-box;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
color: #333;
|
||||
position: fixed; /* 保持原来的固定定位 */
|
||||
top: 64px;
|
||||
left: 20px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
/* 1. 顶部:新对话按钮 */
|
||||
.top-section {
|
||||
flex-shrink: 0;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.new-chat-btn {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #eef4ff; /* 浅蓝背景 */
|
||||
color: #2563eb; /* 蓝色文字 */
|
||||
border-radius: 8px;
|
||||
padding: 10px 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: #dbeafe;
|
||||
}
|
||||
|
||||
.btn-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 2. 中间滚动区域 */
|
||||
.scroll-container {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
/* 隐藏滚动条但保持功能 */
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: #ddd;
|
||||
border-radius: 2px;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
/* 功能菜单 */
|
||||
.menu-section {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
color: #4b5563;
|
||||
font-size: 14px;
|
||||
transition: background-color 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: #e5e7eb;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
margin-right: 10px;
|
||||
color: #6b7280;
|
||||
}
|
||||
.menu-text {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 分割线 */
|
||||
.divider {
|
||||
height: 1px;
|
||||
background-color: #e5e7eb;
|
||||
margin: 8px 4px;
|
||||
}
|
||||
|
||||
/* 搜索框 */
|
||||
.search-section {
|
||||
padding: 0 4px 8px 4px;
|
||||
}
|
||||
|
||||
/* 历史对话列表 */
|
||||
.history-section {
|
||||
.section-title {
|
||||
font-size: 12px;
|
||||
color: #9ca3af;
|
||||
padding: 8px 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.history-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 8px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
transition: background-color 0.2s;
|
||||
height: 40px; /* 固定高度 */
|
||||
|
||||
&:hover {
|
||||
background-color: #e5e7eb;
|
||||
|
||||
.item-actions .pin-icon {
|
||||
display: none; /* 悬停时隐藏置顶/收藏图标,显示更多操作 */
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #e5e7eb; /* 选中态背景 */
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.item-icon {
|
||||
margin-right: 10px;
|
||||
color: #9ca3af;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 14px;
|
||||
color: #374151;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.text-ellipsis {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.item-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 20px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.pin-icon {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.hover-actions {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-color: #e5e7eb;
|
||||
padding-left: 4px;
|
||||
|
||||
.more-btn {
|
||||
color: #6b7280;
|
||||
&:hover { color: #374151; }
|
||||
}
|
||||
}
|
||||
|
||||
/* 编辑框样式 */
|
||||
.edit-input {
|
||||
height: 30px;
|
||||
font-size: 13px;
|
||||
width: 100%;
|
||||
}
|
||||
.edit-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-left: 4px;
|
||||
.action-icon {
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
&.success { color: #50d4ab; }
|
||||
&.danger { color: #f66f6a; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
color: #9ca3af;
|
||||
font-size: 13px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
/* 3. 底部区域:批量管理等 */
|
||||
.bottom-section {
|
||||
flex-shrink: 0;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.bottom-controls {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
padding: 0 4px;
|
||||
|
||||
.limit-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
:deep(.devui-select) {
|
||||
width: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
.batch-btn {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
&:hover { color: #2563eb; }
|
||||
}
|
||||
}
|
||||
|
||||
/* 下拉菜单样式 */
|
||||
.dropdown-menu {
|
||||
list-style: none;
|
||||
padding: 4px 0;
|
||||
margin: 0;
|
||||
min-width: 100px;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
||||
|
||||
li {
|
||||
padding: 8px 12px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
color: #374151;
|
||||
|
||||
&:hover {
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
|
||||
&.danger {
|
||||
color: #ef4444;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -139,6 +139,7 @@
|
||||
</div>
|
||||
|
||||
<ViewHistoryAside ref="viewHistoryRef" :CONV_ID="CONV_ID" :username="username" v-show="isHistoryVisible" @select-conv="handleSelectConv"/>
|
||||
<!-- <ViewHistoryAsideNew ref="viewHistoryRef" :CONV_ID="CONV_ID" :username="username" v-show="isHistoryVisible" @onNewConvo="onNewConvo" @select-conv="handleSelectConv"/>-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -153,6 +154,7 @@ import OssDetail from './components/OssDetail.vue';
|
||||
import Other from './components/Other.vue';
|
||||
import AIList from './components/AIList.vue';
|
||||
import ViewHistoryAside from './components/ViewHistoryAside/ViewHistoryAside.vue';
|
||||
import ViewHistoryAsideNew from './components/ViewHistoryAside/ViewHistoryAsideNew.vue';
|
||||
import axios from 'axios';
|
||||
import { useDiscussGetUserInfo } from '@/api/discussion/hook';
|
||||
import { Message } from 'vue-devui/message';
|
||||
@@ -196,7 +198,7 @@ const messages = ref([]);
|
||||
const followupQuestions = ref([]);
|
||||
|
||||
// 控制 ViewHistoryAside 组件的显示状态
|
||||
const isHistoryVisible = ref(false);
|
||||
const isHistoryVisible = ref(true);
|
||||
|
||||
|
||||
// 切换 ViewHistoryAside 组件的显示与隐藏
|
||||
|
||||
Reference in New Issue
Block a user