mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-07-06 12:37:56 +02:00
Add files via upload
This commit is contained in:
@@ -911,42 +911,17 @@ const monitorState = {
|
||||
};
|
||||
|
||||
function openMonitorPanel() {
|
||||
const modal = document.getElementById('monitor-modal');
|
||||
if (!modal) {
|
||||
return;
|
||||
// 切换到MCP监控页面
|
||||
if (typeof switchPage === 'function') {
|
||||
switchPage('mcp-monitor');
|
||||
}
|
||||
modal.style.display = 'block';
|
||||
|
||||
// 重置显示状态
|
||||
const statsContainer = document.getElementById('monitor-stats');
|
||||
const execContainer = document.getElementById('monitor-executions');
|
||||
if (statsContainer) {
|
||||
statsContainer.innerHTML = '<div class="monitor-empty">加载中...</div>';
|
||||
}
|
||||
if (execContainer) {
|
||||
execContainer.innerHTML = '<div class="monitor-empty">加载中...</div>';
|
||||
}
|
||||
|
||||
const statusFilter = document.getElementById('monitor-status-filter');
|
||||
if (statusFilter) {
|
||||
statusFilter.value = 'all';
|
||||
}
|
||||
|
||||
// 重置分页状态
|
||||
monitorState.pagination = {
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
totalPages: 0
|
||||
};
|
||||
|
||||
refreshMonitorPanel(1);
|
||||
}
|
||||
|
||||
function closeMonitorPanel() {
|
||||
const modal = document.getElementById('monitor-modal');
|
||||
if (modal) {
|
||||
modal.style.display = 'none';
|
||||
// 不再需要关闭功能,因为现在是页面而不是模态框
|
||||
// 如果需要,可以切换回对话页面
|
||||
if (typeof switchPage === 'function') {
|
||||
switchPage('chat');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
// 页面路由管理
|
||||
let currentPage = 'chat';
|
||||
|
||||
// 初始化路由
|
||||
function initRouter() {
|
||||
// 默认显示对话页面
|
||||
switchPage('chat');
|
||||
|
||||
// 从URL hash读取页面(如果有)
|
||||
const hash = window.location.hash.slice(1);
|
||||
if (hash && ['chat', 'mcp-monitor', 'mcp-management', 'settings'].includes(hash)) {
|
||||
switchPage(hash);
|
||||
}
|
||||
}
|
||||
|
||||
// 切换页面
|
||||
function switchPage(pageId) {
|
||||
// 隐藏所有页面
|
||||
document.querySelectorAll('.page').forEach(page => {
|
||||
page.classList.remove('active');
|
||||
});
|
||||
|
||||
// 显示目标页面
|
||||
const targetPage = document.getElementById(`page-${pageId}`);
|
||||
if (targetPage) {
|
||||
targetPage.classList.add('active');
|
||||
currentPage = pageId;
|
||||
|
||||
// 更新URL hash
|
||||
window.location.hash = pageId;
|
||||
|
||||
// 更新导航状态
|
||||
updateNavState(pageId);
|
||||
|
||||
// 页面特定的初始化
|
||||
initPage(pageId);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新导航状态
|
||||
function updateNavState(pageId) {
|
||||
// 移除所有活动状态
|
||||
document.querySelectorAll('.nav-item').forEach(item => {
|
||||
item.classList.remove('active');
|
||||
});
|
||||
|
||||
document.querySelectorAll('.nav-submenu-item').forEach(item => {
|
||||
item.classList.remove('active');
|
||||
});
|
||||
|
||||
// 设置活动状态
|
||||
if (pageId === 'mcp-monitor' || pageId === 'mcp-management') {
|
||||
// MCP子菜单项
|
||||
const mcpItem = document.querySelector('.nav-item[data-page="mcp"]');
|
||||
if (mcpItem) {
|
||||
mcpItem.classList.add('active');
|
||||
// 展开MCP子菜单
|
||||
mcpItem.classList.add('expanded');
|
||||
}
|
||||
|
||||
const submenuItem = document.querySelector(`.nav-submenu-item[data-page="${pageId}"]`);
|
||||
if (submenuItem) {
|
||||
submenuItem.classList.add('active');
|
||||
}
|
||||
} else {
|
||||
// 主菜单项
|
||||
const navItem = document.querySelector(`.nav-item[data-page="${pageId}"]`);
|
||||
if (navItem) {
|
||||
navItem.classList.add('active');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 切换子菜单
|
||||
function toggleSubmenu(menuId) {
|
||||
const sidebar = document.getElementById('main-sidebar');
|
||||
const navItem = document.querySelector(`.nav-item[data-page="${menuId}"]`);
|
||||
|
||||
if (!navItem) return;
|
||||
|
||||
// 检查侧边栏是否折叠
|
||||
if (sidebar && sidebar.classList.contains('collapsed')) {
|
||||
// 折叠状态下显示弹出菜单
|
||||
showSubmenuPopup(navItem, menuId);
|
||||
} else {
|
||||
// 展开状态下正常切换子菜单
|
||||
navItem.classList.toggle('expanded');
|
||||
}
|
||||
}
|
||||
|
||||
// 显示子菜单弹出框
|
||||
function showSubmenuPopup(navItem, menuId) {
|
||||
// 移除其他已打开的弹出菜单
|
||||
const existingPopup = document.querySelector('.submenu-popup');
|
||||
if (existingPopup) {
|
||||
existingPopup.remove();
|
||||
return; // 如果已经打开,点击时关闭
|
||||
}
|
||||
|
||||
const navItemContent = navItem.querySelector('.nav-item-content');
|
||||
const submenu = navItem.querySelector('.nav-submenu');
|
||||
|
||||
if (!submenu) return;
|
||||
|
||||
// 获取菜单位置
|
||||
const rect = navItemContent.getBoundingClientRect();
|
||||
|
||||
// 创建弹出菜单
|
||||
const popup = document.createElement('div');
|
||||
popup.className = 'submenu-popup';
|
||||
popup.style.position = 'fixed';
|
||||
popup.style.left = (rect.right + 8) + 'px';
|
||||
popup.style.top = rect.top + 'px';
|
||||
popup.style.zIndex = '1000';
|
||||
|
||||
// 复制子菜单项到弹出菜单
|
||||
const submenuItems = submenu.querySelectorAll('.nav-submenu-item');
|
||||
submenuItems.forEach(item => {
|
||||
const popupItem = document.createElement('div');
|
||||
popupItem.className = 'submenu-popup-item';
|
||||
popupItem.textContent = item.textContent.trim();
|
||||
|
||||
// 检查是否是当前激活的页面
|
||||
const pageId = item.getAttribute('data-page');
|
||||
if (pageId && document.querySelector(`.nav-submenu-item[data-page="${pageId}"].active`)) {
|
||||
popupItem.classList.add('active');
|
||||
}
|
||||
|
||||
popupItem.onclick = function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
// 获取页面ID并切换
|
||||
const pageId = item.getAttribute('data-page');
|
||||
if (pageId) {
|
||||
switchPage(pageId);
|
||||
}
|
||||
|
||||
// 关闭弹出菜单
|
||||
popup.remove();
|
||||
document.removeEventListener('click', closePopup);
|
||||
};
|
||||
popup.appendChild(popupItem);
|
||||
});
|
||||
|
||||
document.body.appendChild(popup);
|
||||
|
||||
// 点击外部关闭弹出菜单
|
||||
const closePopup = function(e) {
|
||||
if (!popup.contains(e.target) && !navItem.contains(e.target)) {
|
||||
popup.remove();
|
||||
document.removeEventListener('click', closePopup);
|
||||
}
|
||||
};
|
||||
|
||||
// 延迟添加事件监听,避免立即触发
|
||||
setTimeout(() => {
|
||||
document.addEventListener('click', closePopup);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// 初始化页面
|
||||
function initPage(pageId) {
|
||||
switch(pageId) {
|
||||
case 'chat':
|
||||
// 对话页面已由chat.js初始化
|
||||
break;
|
||||
case 'mcp-monitor':
|
||||
// 初始化监控面板
|
||||
if (typeof refreshMonitorPanel === 'function') {
|
||||
refreshMonitorPanel();
|
||||
}
|
||||
break;
|
||||
case 'mcp-management':
|
||||
// 初始化MCP管理
|
||||
if (typeof loadExternalMCPs === 'function') {
|
||||
loadExternalMCPs();
|
||||
}
|
||||
// 加载工具列表(MCP工具配置已移到MCP管理页面)
|
||||
if (typeof loadToolsList === 'function') {
|
||||
// 确保工具分页设置已初始化
|
||||
if (typeof getToolsPageSize === 'function' && typeof toolsPagination !== 'undefined') {
|
||||
toolsPagination.pageSize = getToolsPageSize();
|
||||
}
|
||||
loadToolsList(1, '');
|
||||
}
|
||||
break;
|
||||
case 'settings':
|
||||
// 初始化设置页面
|
||||
if (typeof loadConfig === 'function') {
|
||||
loadConfig();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载完成后初始化路由
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
initRouter();
|
||||
initSidebarState();
|
||||
|
||||
// 监听hash变化
|
||||
window.addEventListener('hashchange', function() {
|
||||
const hash = window.location.hash.slice(1);
|
||||
if (hash && ['chat', 'mcp-monitor', 'mcp-management', 'settings'].includes(hash)) {
|
||||
switchPage(hash);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 切换侧边栏折叠/展开
|
||||
function toggleSidebar() {
|
||||
const sidebar = document.getElementById('main-sidebar');
|
||||
if (sidebar) {
|
||||
sidebar.classList.toggle('collapsed');
|
||||
// 保存折叠状态到localStorage
|
||||
const isCollapsed = sidebar.classList.contains('collapsed');
|
||||
localStorage.setItem('sidebarCollapsed', isCollapsed ? 'true' : 'false');
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化侧边栏状态
|
||||
function initSidebarState() {
|
||||
const sidebar = document.getElementById('main-sidebar');
|
||||
if (sidebar) {
|
||||
const savedState = localStorage.getItem('sidebarCollapsed');
|
||||
if (savedState === 'true') {
|
||||
sidebar.classList.add('collapsed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 导出函数供其他脚本使用
|
||||
window.switchPage = switchPage;
|
||||
window.toggleSubmenu = toggleSubmenu;
|
||||
window.toggleSidebar = toggleSidebar;
|
||||
window.currentPage = function() { return currentPage; };
|
||||
|
||||
+127
-14
@@ -19,8 +19,10 @@ let toolsPagination = {
|
||||
|
||||
// 打开设置
|
||||
async function openSettings() {
|
||||
const modal = document.getElementById('settings-modal');
|
||||
modal.style.display = 'block';
|
||||
// 切换到设置页面
|
||||
if (typeof switchPage === 'function') {
|
||||
switchPage('settings');
|
||||
}
|
||||
|
||||
// 每次打开时清空全局状态映射,重新加载最新配置
|
||||
toolStateMap.clear();
|
||||
@@ -34,27 +36,22 @@ async function openSettings() {
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭设置
|
||||
// 关闭设置(保留函数以兼容旧代码,但现在不需要关闭功能)
|
||||
function closeSettings() {
|
||||
const modal = document.getElementById('settings-modal');
|
||||
modal.style.display = 'none';
|
||||
// 不再需要关闭功能,因为现在是页面而不是模态框
|
||||
// 如果需要,可以切换回对话页面
|
||||
if (typeof switchPage === 'function') {
|
||||
switchPage('chat');
|
||||
}
|
||||
}
|
||||
|
||||
// 点击模态框外部关闭
|
||||
// 点击模态框外部关闭(只保留MCP详情模态框)
|
||||
window.onclick = function(event) {
|
||||
const settingsModal = document.getElementById('settings-modal');
|
||||
const mcpModal = document.getElementById('mcp-detail-modal');
|
||||
const monitorModal = document.getElementById('monitor-modal');
|
||||
|
||||
if (event.target === settingsModal) {
|
||||
closeSettings();
|
||||
}
|
||||
if (event.target === mcpModal) {
|
||||
closeMCPDetail();
|
||||
}
|
||||
if (event.target === monitorModal) {
|
||||
closeMonitorPanel();
|
||||
}
|
||||
}
|
||||
|
||||
// 加载配置
|
||||
@@ -623,6 +620,122 @@ async function applySettings() {
|
||||
}
|
||||
}
|
||||
|
||||
// 保存工具配置(独立函数,用于MCP管理页面)
|
||||
async function saveToolsConfig() {
|
||||
try {
|
||||
// 先保存当前页的状态到全局映射
|
||||
saveCurrentPageToolStates();
|
||||
|
||||
// 获取当前配置(只获取工具部分)
|
||||
const response = await apiFetch('/api/config');
|
||||
if (!response.ok) {
|
||||
throw new Error('获取配置失败');
|
||||
}
|
||||
|
||||
const currentConfig = await response.json();
|
||||
|
||||
// 构建只包含工具配置的配置对象
|
||||
const config = {
|
||||
openai: currentConfig.openai || {},
|
||||
agent: currentConfig.agent || {},
|
||||
tools: []
|
||||
};
|
||||
|
||||
// 收集工具启用状态(与applySettings中的逻辑相同)
|
||||
try {
|
||||
const allToolsMap = new Map();
|
||||
let page = 1;
|
||||
let hasMore = true;
|
||||
const pageSize = 100;
|
||||
|
||||
// 遍历所有页面获取所有工具
|
||||
while (hasMore) {
|
||||
const url = `/api/config/tools?page=${page}&page_size=${pageSize}`;
|
||||
|
||||
const pageResponse = await apiFetch(url);
|
||||
if (!pageResponse.ok) {
|
||||
throw new Error('获取工具列表失败');
|
||||
}
|
||||
|
||||
const pageResult = await pageResponse.json();
|
||||
|
||||
// 将工具添加到映射中
|
||||
pageResult.tools.forEach(tool => {
|
||||
const savedState = toolStateMap.get(tool.name);
|
||||
allToolsMap.set(tool.name, {
|
||||
name: tool.name,
|
||||
enabled: savedState ? savedState.enabled : tool.enabled,
|
||||
is_external: savedState ? savedState.is_external : (tool.is_external || false),
|
||||
external_mcp: savedState ? savedState.external_mcp : (tool.external_mcp || '')
|
||||
});
|
||||
});
|
||||
|
||||
// 检查是否还有更多页面
|
||||
if (page >= pageResult.total_pages) {
|
||||
hasMore = false;
|
||||
} else {
|
||||
page++;
|
||||
}
|
||||
}
|
||||
|
||||
// 将所有工具添加到配置中
|
||||
allToolsMap.forEach(tool => {
|
||||
config.tools.push({
|
||||
name: tool.name,
|
||||
enabled: tool.enabled,
|
||||
is_external: tool.is_external,
|
||||
external_mcp: tool.external_mcp
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn('获取所有工具列表失败,仅使用全局状态映射', error);
|
||||
// 如果获取失败,使用全局状态映射
|
||||
toolStateMap.forEach((toolData, toolName) => {
|
||||
config.tools.push({
|
||||
name: toolName,
|
||||
enabled: toolData.enabled,
|
||||
is_external: toolData.is_external,
|
||||
external_mcp: toolData.external_mcp
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 更新配置
|
||||
const updateResponse = await apiFetch('/api/config', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(config)
|
||||
});
|
||||
|
||||
if (!updateResponse.ok) {
|
||||
const error = await updateResponse.json();
|
||||
throw new Error(error.error || '更新配置失败');
|
||||
}
|
||||
|
||||
// 应用配置
|
||||
const applyResponse = await apiFetch('/api/config/apply', {
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (!applyResponse.ok) {
|
||||
const error = await applyResponse.json();
|
||||
throw new Error(error.error || '应用配置失败');
|
||||
}
|
||||
|
||||
alert('工具配置已成功保存!');
|
||||
|
||||
// 重新加载工具列表以反映最新状态
|
||||
if (typeof loadToolsList === 'function') {
|
||||
await loadToolsList(toolsPagination.page, toolsSearchKeyword);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存工具配置失败:', error);
|
||||
alert('保存工具配置失败: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
function resetPasswordForm() {
|
||||
const currentInput = document.getElementById('auth-current-password');
|
||||
const newInput = document.getElementById('auth-new-password');
|
||||
|
||||
Reference in New Issue
Block a user