mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-07-12 15:16:43 +02:00
Add files via upload
This commit is contained in:
+134
-14
@@ -3747,14 +3747,10 @@ async function loadGroups() {
|
|||||||
// 加载对话列表(修改为支持分组和置顶)
|
// 加载对话列表(修改为支持分组和置顶)
|
||||||
async function loadConversationsWithGroups(searchQuery = '') {
|
async function loadConversationsWithGroups(searchQuery = '') {
|
||||||
try {
|
try {
|
||||||
// 先加载分组列表(如果还没有加载)
|
// 总是重新加载分组列表和分组映射,确保缓存是最新的
|
||||||
if (groupsCache.length === 0) {
|
// 这样可以正确处理分组被删除后的情况
|
||||||
await loadGroups();
|
await loadGroups();
|
||||||
}
|
await loadConversationGroupMapping();
|
||||||
// 先加载分组映射(如果还没有加载)
|
|
||||||
if (Object.keys(conversationGroupMappingCache).length === 0) {
|
|
||||||
await loadConversationGroupMapping();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果有搜索关键词,使用更大的limit以获取所有匹配结果
|
// 如果有搜索关键词,使用更大的limit以获取所有匹配结果
|
||||||
const limit = (searchQuery && searchQuery.trim()) ? 1000 : 100;
|
const limit = (searchQuery && searchQuery.trim()) ? 1000 : 100;
|
||||||
@@ -3927,6 +3923,17 @@ async function showConversationContextMenu(event) {
|
|||||||
const menu = document.getElementById('conversation-context-menu');
|
const menu = document.getElementById('conversation-context-menu');
|
||||||
if (!menu) return;
|
if (!menu) return;
|
||||||
|
|
||||||
|
// 先隐藏子菜单,确保每次打开菜单时子菜单都是关闭状态
|
||||||
|
const submenu = document.getElementById('move-to-group-submenu');
|
||||||
|
if (submenu) {
|
||||||
|
submenu.style.display = 'none';
|
||||||
|
submenuVisible = false;
|
||||||
|
}
|
||||||
|
// 清除所有定时器
|
||||||
|
clearSubmenuHideTimeout();
|
||||||
|
clearSubmenuShowTimeout();
|
||||||
|
submenuLoading = false;
|
||||||
|
|
||||||
const convId = contextMenuConversationId;
|
const convId = contextMenuConversationId;
|
||||||
// 先获取对话的置顶状态并更新菜单文本(在显示菜单之前)
|
// 先获取对话的置顶状态并更新菜单文本(在显示菜单之前)
|
||||||
if (convId) {
|
if (convId) {
|
||||||
@@ -3985,8 +3992,7 @@ async function showConversationContextMenu(event) {
|
|||||||
const viewportWidth = window.innerWidth;
|
const viewportWidth = window.innerWidth;
|
||||||
const viewportHeight = window.innerHeight;
|
const viewportHeight = window.innerHeight;
|
||||||
|
|
||||||
// 获取子菜单的宽度(如果存在)
|
// 获取子菜单的宽度(如果存在,重用之前获取的submenu变量)
|
||||||
const submenu = document.getElementById('move-to-group-submenu');
|
|
||||||
const submenuWidth = submenu ? 180 : 0; // 子菜单宽度 + 间距
|
const submenuWidth = submenu ? 180 : 0; // 子菜单宽度 + 间距
|
||||||
|
|
||||||
let left = event.clientX;
|
let left = event.clientX;
|
||||||
@@ -4035,8 +4041,14 @@ async function showConversationContextMenu(event) {
|
|||||||
|
|
||||||
// 点击外部关闭菜单
|
// 点击外部关闭菜单
|
||||||
const closeMenu = (e) => {
|
const closeMenu = (e) => {
|
||||||
if (!menu.contains(e.target)) {
|
// 检查点击是否在主菜单或子菜单内
|
||||||
menu.style.display = 'none';
|
const moveToGroupSubmenuEl = document.getElementById('move-to-group-submenu');
|
||||||
|
const clickedInMenu = menu.contains(e.target);
|
||||||
|
const clickedInSubmenu = moveToGroupSubmenuEl && moveToGroupSubmenuEl.contains(e.target);
|
||||||
|
|
||||||
|
if (!clickedInMenu && !clickedInSubmenu) {
|
||||||
|
// 使用 closeContextMenu 确保同时关闭主菜单和子菜单
|
||||||
|
closeContextMenu();
|
||||||
document.removeEventListener('click', closeMenu);
|
document.removeEventListener('click', closeMenu);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -4245,6 +4257,21 @@ async function showMoveToGroupSubmenu() {
|
|||||||
const submenu = document.getElementById('move-to-group-submenu');
|
const submenu = document.getElementById('move-to-group-submenu');
|
||||||
if (!submenu) return;
|
if (!submenu) return;
|
||||||
|
|
||||||
|
// 如果子菜单已经显示,不需要重复渲染
|
||||||
|
if (submenuVisible && submenu.style.display === 'block') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果正在加载中,避免重复调用
|
||||||
|
if (submenuLoading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除隐藏定时器
|
||||||
|
clearSubmenuHideTimeout();
|
||||||
|
|
||||||
|
// 标记为加载中
|
||||||
|
submenuLoading = true;
|
||||||
submenu.innerHTML = '';
|
submenu.innerHTML = '';
|
||||||
|
|
||||||
// 确保分组列表已加载 - 强制重新加载以确保数据是最新的
|
// 确保分组列表已加载 - 强制重新加载以确保数据是最新的
|
||||||
@@ -4362,6 +4389,8 @@ async function showMoveToGroupSubmenu() {
|
|||||||
submenu.appendChild(addItem);
|
submenu.appendChild(addItem);
|
||||||
|
|
||||||
submenu.style.display = 'block';
|
submenu.style.display = 'block';
|
||||||
|
submenuVisible = true;
|
||||||
|
submenuLoading = false;
|
||||||
|
|
||||||
// 计算子菜单位置,防止溢出
|
// 计算子菜单位置,防止溢出
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -4386,6 +4415,86 @@ async function showMoveToGroupSubmenu() {
|
|||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 隐藏移动到分组子菜单的定时器
|
||||||
|
let submenuHideTimeout = null;
|
||||||
|
// 显示子菜单的防抖定时器
|
||||||
|
let submenuShowTimeout = null;
|
||||||
|
// 子菜单是否正在加载中
|
||||||
|
let submenuLoading = false;
|
||||||
|
// 子菜单是否已显示
|
||||||
|
let submenuVisible = false;
|
||||||
|
|
||||||
|
// 隐藏移动到分组子菜单
|
||||||
|
function hideMoveToGroupSubmenu() {
|
||||||
|
const submenu = document.getElementById('move-to-group-submenu');
|
||||||
|
if (submenu) {
|
||||||
|
submenu.style.display = 'none';
|
||||||
|
submenuVisible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除隐藏子菜单的定时器
|
||||||
|
function clearSubmenuHideTimeout() {
|
||||||
|
if (submenuHideTimeout) {
|
||||||
|
clearTimeout(submenuHideTimeout);
|
||||||
|
submenuHideTimeout = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除显示子菜单的定时器
|
||||||
|
function clearSubmenuShowTimeout() {
|
||||||
|
if (submenuShowTimeout) {
|
||||||
|
clearTimeout(submenuShowTimeout);
|
||||||
|
submenuShowTimeout = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理鼠标进入"移动到分组"菜单项(带防抖)
|
||||||
|
function handleMoveToGroupSubmenuEnter() {
|
||||||
|
// 清除隐藏定时器
|
||||||
|
clearSubmenuHideTimeout();
|
||||||
|
|
||||||
|
// 如果子菜单已经显示,不需要重复调用
|
||||||
|
const submenu = document.getElementById('move-to-group-submenu');
|
||||||
|
if (submenu && submenuVisible && submenu.style.display === 'block') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除之前的显示定时器
|
||||||
|
clearSubmenuShowTimeout();
|
||||||
|
|
||||||
|
// 使用防抖延迟显示,避免频繁触发
|
||||||
|
submenuShowTimeout = setTimeout(() => {
|
||||||
|
showMoveToGroupSubmenu();
|
||||||
|
submenuShowTimeout = null;
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理鼠标离开"移动到分组"菜单项
|
||||||
|
function handleMoveToGroupSubmenuLeave(event) {
|
||||||
|
const submenu = document.getElementById('move-to-group-submenu');
|
||||||
|
if (!submenu) return;
|
||||||
|
|
||||||
|
// 清除显示定时器
|
||||||
|
clearSubmenuShowTimeout();
|
||||||
|
|
||||||
|
// 检查鼠标是否移动到子菜单
|
||||||
|
const relatedTarget = event.relatedTarget;
|
||||||
|
if (relatedTarget && submenu.contains(relatedTarget)) {
|
||||||
|
// 鼠标移动到子菜单,不清除
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除之前的隐藏定时器
|
||||||
|
clearSubmenuHideTimeout();
|
||||||
|
|
||||||
|
// 延迟隐藏,给用户时间移动到子菜单
|
||||||
|
submenuHideTimeout = setTimeout(() => {
|
||||||
|
hideMoveToGroupSubmenu();
|
||||||
|
submenuHideTimeout = null;
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
// 移动对话到分组
|
// 移动对话到分组
|
||||||
async function moveConversationToGroup(convId, groupId) {
|
async function moveConversationToGroup(convId, groupId) {
|
||||||
try {
|
try {
|
||||||
@@ -4508,7 +4617,12 @@ function closeContextMenu() {
|
|||||||
const submenu = document.getElementById('move-to-group-submenu');
|
const submenu = document.getElementById('move-to-group-submenu');
|
||||||
if (submenu) {
|
if (submenu) {
|
||||||
submenu.style.display = 'none';
|
submenu.style.display = 'none';
|
||||||
|
submenuVisible = false;
|
||||||
}
|
}
|
||||||
|
// 清除所有定时器
|
||||||
|
clearSubmenuHideTimeout();
|
||||||
|
clearSubmenuShowTimeout();
|
||||||
|
submenuLoading = false;
|
||||||
contextMenuConversationId = null;
|
contextMenuConversationId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5077,8 +5191,11 @@ async function deleteGroup() {
|
|||||||
await showMoveToGroupSubmenu();
|
await showMoveToGroupSubmenu();
|
||||||
} else {
|
} else {
|
||||||
exitGroupDetail();
|
exitGroupDetail();
|
||||||
loadGroups();
|
await loadGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 刷新对话列表,确保之前被分组的对话能立即显示
|
||||||
|
await loadConversationsWithGroups();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('删除分组失败:', error);
|
console.error('删除分组失败:', error);
|
||||||
alert('删除失败: ' + (error.message || '未知错误'));
|
alert('删除失败: ' + (error.message || '未知错误'));
|
||||||
@@ -5221,8 +5338,11 @@ async function deleteGroupFromContext() {
|
|||||||
if (currentGroupId === groupId) {
|
if (currentGroupId === groupId) {
|
||||||
exitGroupDetail();
|
exitGroupDetail();
|
||||||
}
|
}
|
||||||
loadGroups();
|
await loadGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 刷新对话列表,确保之前被分组的对话能立即显示
|
||||||
|
await loadConversationsWithGroups();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('删除分组失败:', error);
|
console.error('删除分组失败:', error);
|
||||||
alert('删除失败: ' + (error.message || '未知错误'));
|
alert('删除失败: ' + (error.message || '未知错误'));
|
||||||
|
|||||||
@@ -450,8 +450,13 @@ function handleStreamEvent(event, progressElement, progressId,
|
|||||||
loadActiveTasks();
|
loadActiveTasks();
|
||||||
// 延迟刷新对话列表,确保用户消息已保存,updated_at已更新
|
// 延迟刷新对话列表,确保用户消息已保存,updated_at已更新
|
||||||
// 这样新对话才能正确显示在最近对话列表的顶部
|
// 这样新对话才能正确显示在最近对话列表的顶部
|
||||||
|
// 使用loadConversationsWithGroups确保分组映射缓存正确加载,无论是否有分组都能立即显示
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loadConversations();
|
if (typeof loadConversationsWithGroups === 'function') {
|
||||||
|
loadConversationsWithGroups();
|
||||||
|
} else if (typeof loadConversations === 'function') {
|
||||||
|
loadConversations();
|
||||||
|
}
|
||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -910,7 +910,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<span>批量管理</span>
|
<span>批量管理</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="context-menu-item context-menu-item-has-submenu" onmouseenter="showMoveToGroupSubmenu()">
|
<div class="context-menu-item context-menu-item-has-submenu" onmouseenter="handleMoveToGroupSubmenuEnter()" onmouseleave="handleMoveToGroupSubmenuLeave(event)">
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
</svg>
|
</svg>
|
||||||
@@ -918,7 +918,7 @@
|
|||||||
<svg class="submenu-arrow" width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg class="submenu-arrow" width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M9 18l6-6-6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M9 18l6-6-6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
</svg>
|
</svg>
|
||||||
<div id="move-to-group-submenu" class="context-submenu" style="display: none;"></div>
|
<div id="move-to-group-submenu" class="context-submenu" style="display: none;" onmouseenter="clearSubmenuHideTimeout()" onmouseleave="hideMoveToGroupSubmenu()"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="context-menu-divider"></div>
|
<div class="context-menu-divider"></div>
|
||||||
<div class="context-menu-item context-menu-item-danger" onclick="deleteConversationFromContext()">
|
<div class="context-menu-item context-menu-item-danger" onclick="deleteConversationFromContext()">
|
||||||
|
|||||||
Reference in New Issue
Block a user