/** * Redis比较工具的JavaScript功能 * 支持Redis集群配置、连接测试、数据比较等功能 */ // 全局变量 let currentResults = null; let isQuerying = false; let currentImportTarget = null; // 记录当前导入目标集群 // 页面加载完成后初始化 document.addEventListener('DOMContentLoaded', function() { initializePage(); bindEvents(); loadRedisConfigGroups(); loadRedisQueryHistory(); }); /** * 初始化页面 */ function initializePage() { // 加载默认配置 loadDefaultConfig(); // 绑定节点删除事件 bindNodeEvents(); // 绑定查询模式切换事件 bindQueryModeEvents(); } /** * 绑定事件 */ function bindEvents() { // 查询模式切换 document.querySelectorAll('input[name="queryMode"]').forEach(radio => { radio.addEventListener('change', toggleQueryMode); }); // 节点删除按钮事件委托 document.addEventListener('click', function(e) { if (e.target.closest('.remove-node')) { e.target.closest('.node-input').remove(); } }); } /** * 绑定节点相关事件 */ function bindNodeEvents() { // 初始绑定现有的删除按钮(如果只有一个节点则禁用删除) updateNodeDeleteButtons(); } /** * 绑定查询模式切换事件 */ function bindQueryModeEvents() { const randomMode = document.getElementById('randomMode'); const specifiedMode = document.getElementById('specifiedMode'); randomMode.addEventListener('change', toggleQueryMode); specifiedMode.addEventListener('change', toggleQueryMode); } /** * 切换查询模式 */ function toggleQueryMode() { const randomMode = document.getElementById('randomMode').checked; const randomOptions = document.getElementById('randomOptions'); const specifiedOptions = document.getElementById('specifiedOptions'); if (randomMode) { randomOptions.style.display = 'block'; specifiedOptions.style.display = 'none'; } else { randomOptions.style.display = 'none'; specifiedOptions.style.display = 'block'; } } /** * 添加节点 */ function addNode(clusterId) { const container = document.getElementById(`${clusterId}-nodes`); const nodeInput = document.createElement('div'); nodeInput.className = 'node-input'; nodeInput.innerHTML = ` `; container.appendChild(nodeInput); updateNodeDeleteButtons(); } /** * 更新节点删除按钮状态 */ function updateNodeDeleteButtons() { // 每个集群至少需要一个节点 ['cluster1', 'cluster2'].forEach(clusterId => { const container = document.getElementById(`${clusterId}-nodes`); const nodeInputs = container.querySelectorAll('.node-input'); const deleteButtons = container.querySelectorAll('.remove-node'); deleteButtons.forEach(btn => { btn.disabled = nodeInputs.length <= 1; }); }); } /** * 获取集群配置 */ function getClusterConfig(clusterId) { const name = document.getElementById(`${clusterId}-name`).value; const password = document.getElementById(`${clusterId}-password`).value; const timeout = parseInt(document.getElementById(`${clusterId}-timeout`).value); const maxConn = parseInt(document.getElementById(`${clusterId}-max-conn`).value); // 获取节点列表 const nodes = []; const nodeInputs = document.querySelectorAll(`#${clusterId}-nodes .node-input`); nodeInputs.forEach(nodeInput => { const host = nodeInput.querySelector('.node-host').value.trim(); const port = parseInt(nodeInput.querySelector('.node-port').value); if (host && port) { nodes.push({ host, port }); } }); return { name, nodes, password: password || null, socket_timeout: timeout, socket_connect_timeout: timeout, max_connections_per_node: maxConn }; } /** * 获取查询选项 */ function getQueryOptions() { const randomMode = document.getElementById('randomMode').checked; if (randomMode) { return { mode: 'random', count: parseInt(document.getElementById('sampleCount').value), pattern: document.getElementById('keyPattern').value, source_cluster: document.getElementById('sourceCluster').value }; } else { const keysText = document.getElementById('specifiedKeys').value.trim(); const keys = keysText ? keysText.split('\n').map(k => k.trim()).filter(k => k) : []; return { mode: 'specified', keys: keys }; } } /** * 测试连接 */ async function testConnection(clusterId) { const config = getClusterConfig(clusterId); const clusterName = config.name; if (!config.nodes || config.nodes.length === 0) { showAlert('请至少配置一个Redis节点', 'warning'); return; } try { showLoading(`正在测试${clusterName}连接...`); const response = await fetch('/api/redis/test-connection', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ cluster_config: config, cluster_name: clusterName }) }); const result = await response.json(); hideLoading(); if (result.success) { showAlert(`${clusterName}连接成功!连接耗时: ${result.data.connection_time.toFixed(3)}秒`, 'success'); // 高亮成功的集群配置 document.getElementById(`${clusterId}-config`).classList.add('active'); setTimeout(() => { document.getElementById(`${clusterId}-config`).classList.remove('active'); }, 2000); } else { showAlert(`${clusterName}连接失败: ${result.error}`, 'danger'); } } catch (error) { hideLoading(); showAlert(`连接测试失败: ${error.message}`, 'danger'); } } /** * 执行Redis比较 */ async function executeRedisComparison() { if (isQuerying) { showAlert('查询正在进行中,请稍候...', 'warning'); return; } // 获取配置 const cluster1Config = getClusterConfig('cluster1'); const cluster2Config = getClusterConfig('cluster2'); const queryOptions = getQueryOptions(); // 验证配置 if (!cluster1Config.nodes || cluster1Config.nodes.length === 0) { showAlert('请配置集群1的Redis节点', 'warning'); return; } if (!cluster2Config.nodes || cluster2Config.nodes.length === 0) { showAlert('请配置集群2的Redis节点', 'warning'); return; } if (queryOptions.mode === 'specified' && (!queryOptions.keys || queryOptions.keys.length === 0)) { showAlert('请输入要查询的Key列表', 'warning'); return; } try { isQuerying = true; showLoading('正在执行Redis数据比较,请稍候...'); clearResults(); const response = await fetch('/api/redis/compare', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ cluster1_config: cluster1Config, cluster2_config: cluster2Config, query_options: queryOptions }) }); const result = await response.json(); if (response.ok && result.success !== false) { currentResults = result; displayResults(result); showAlert('Redis数据比较完成!', 'success'); } else { showAlert(`比较失败: ${result.error}`, 'danger'); } } catch (error) { showAlert(`请求失败: ${error.message}`, 'danger'); } finally { isQuerying = false; hideLoading(); } } /** * 显示结果 */ function displayResults(results) { // 显示统计卡片 displayStatsCards(results.stats); // 显示详细结果 displayDifferenceResults(results.different_results || []); displayIdenticalResults(results.identical_results || []); displayMissingResults(results.missing_results || []); displayPerformanceReport(results.performance_report); // 更新标签页计数 updateTabCounts(results); // 显示结果区域 document.getElementById('results').style.display = 'block'; // 滚动到结果区域 document.getElementById('results').scrollIntoView({ behavior: 'smooth' }); } /** * 显示统计卡片 */ function displayStatsCards(stats) { const container = document.getElementById('statsCards'); container.innerHTML = `

${stats.total_keys}

总Key数量

${stats.identical_count}

相同数据

${stats.identical_percentage}%

${stats.different_count}

差异数据

${stats.different_percentage}%

${stats.missing_in_cluster1 + stats.missing_in_cluster2 + stats.both_missing}

缺失数据

${stats.missing_percentage}%
`; } /** * 显示差异结果 */ function displayDifferenceResults(differences) { const container = document.getElementById('differenceResults'); if (differences.length === 0) { container.innerHTML = '
未发现数据差异
'; return; } let html = ''; differences.forEach((diff, index) => { html += `
Key: ${diff.key}
${currentResults.clusters.cluster1_name}:
${formatRedisValue(diff.cluster1_value)}
${currentResults.clusters.cluster2_name}:
${formatRedisValue(diff.cluster2_value)}
${diff.message}
`; }); container.innerHTML = html; } /** * 显示相同结果 */ function displayIdenticalResults(identical) { const container = document.getElementById('identicalResults'); if (identical.length === 0) { container.innerHTML = '
没有相同的数据
'; return; } let html = ''; identical.forEach((item, index) => { html += `
Key: ${item.key}
值:
${formatRedisValue(item.value)}
数据一致
`; }); container.innerHTML = html; } /** * 显示缺失结果 */ function displayMissingResults(missing) { const container = document.getElementById('missingResults'); if (missing.length === 0) { container.innerHTML = '
没有缺失的数据
'; return; } let html = ''; missing.forEach((item, index) => { html += `
Key: ${item.key}
${item.message}
${item.cluster1_value !== undefined ? `
${currentResults.clusters.cluster1_name}:
${formatRedisValue(item.cluster1_value)}
` : ''} ${item.cluster2_value !== undefined ? `
${currentResults.clusters.cluster2_name}:
${formatRedisValue(item.cluster2_value)}
` : ''}
`; }); container.innerHTML = html; } /** * 显示性能报告 */ function displayPerformanceReport(performanceReport) { const container = document.getElementById('performanceReport'); const connections = performanceReport.connections || {}; const operations = performanceReport.operations || {}; let html = `
性能统计报告
连接统计
`; Object.entries(connections).forEach(([clusterName, status]) => { const statusClass = status.success ? 'success' : 'danger'; const statusText = status.success ? '成功' : '失败'; html += ` `; }); html += `
集群 状态 耗时
${clusterName} ${statusText} ${status.connect_time.toFixed(3)}s
操作统计
`; if (operations.scan_time > 0) { html += ``; } Object.entries(operations.queries || {}).forEach(([operation, duration]) => { html += ``; }); if (operations.comparison_time > 0) { html += ``; } html += `
操作 耗时
扫描Keys${operations.scan_time.toFixed(3)}s
${operation}${duration.toFixed(3)}s
数据比对${operations.comparison_time.toFixed(3)}s
总耗时 ${performanceReport.total_time.toFixed(3)}s
`; container.innerHTML = html; } /** * 更新标签页计数 */ function updateTabCounts(results) { document.getElementById('diff-count').textContent = (results.different_results || []).length; document.getElementById('identical-count').textContent = (results.identical_results || []).length; document.getElementById('missing-count').textContent = (results.missing_results || []).length; } /** * 格式化Redis值显示 */ function formatRedisValue(value) { if (value === null) { return '(null)'; } if (value === undefined) { return '(undefined)'; } // 如果是字符串且看起来像JSON,尝试格式化 if (typeof value === 'string') { try { const parsed = JSON.parse(value); return JSON.stringify(parsed, null, 2); } catch (e) { // 不是JSON,直接返回 return value; } } return String(value); } /** * 加载默认配置 */ async function loadDefaultConfig() { try { const response = await fetch('/api/redis/default-config'); const config = await response.json(); // 这里可以根据需要设置默认值,当前HTML已经包含了合理的默认值 } catch (error) { console.warn('加载默认配置失败:', error); } } /** * 清空结果 */ function clearResults() { document.getElementById('results').style.display = 'none'; currentResults = null; } /** * 显示加载状态 */ function showLoading(message = '正在处理...') { const loadingElement = document.querySelector('.loading'); const messageElement = loadingElement.querySelector('span'); messageElement.textContent = message; loadingElement.style.display = 'block'; } /** * 隐藏加载状态 */ function hideLoading() { document.querySelector('.loading').style.display = 'none'; } /** * 显示提示消息 */ function showAlert(message, type = 'info') { // 移除现有的alert const existingAlert = document.querySelector('.alert-custom'); if (existingAlert) { existingAlert.remove(); } // 创建新的alert const alertDiv = document.createElement('div'); alertDiv.className = `alert alert-${type} alert-dismissible fade show alert-custom`; alertDiv.innerHTML = ` ${message} `; // 插入到页面顶部 const container = document.querySelector('.container'); container.insertBefore(alertDiv, container.firstChild); // 5秒后自动消失 setTimeout(() => { if (alertDiv.parentNode) { alertDiv.remove(); } }, 5000); } /** * Redis配置管理功能 */ // 加载Redis配置组列表 async function loadRedisConfigGroups() { try { const response = await fetch('/api/redis/config-groups'); const result = await response.json(); const select = document.getElementById('redisConfigGroupSelect'); select.innerHTML = ''; if (result.success && result.data) { result.data.forEach(group => { const option = document.createElement('option'); option.value = group.id; option.textContent = `${group.name} - ${group.description || '无描述'}`; select.appendChild(option); }); } } catch (error) { console.error('加载Redis配置组失败:', error); } } // 显示保存Redis配置对话框 function showSaveRedisConfigDialog() { // 生成默认名称 const timestamp = new Date().toLocaleString('zh-CN'); document.getElementById('redisConfigGroupName').value = `Redis配置_${timestamp}`; document.getElementById('redisConfigGroupDescription').value = ''; new bootstrap.Modal(document.getElementById('saveRedisConfigModal')).show(); } // 保存Redis配置组 async function saveRedisConfigGroup() { const name = document.getElementById('redisConfigGroupName').value.trim(); const description = document.getElementById('redisConfigGroupDescription').value.trim(); if (!name) { showAlert('请输入配置组名称', 'warning'); return; } const cluster1Config = getClusterConfig('cluster1'); const cluster2Config = getClusterConfig('cluster2'); const queryOptions = getQueryOptions(); if (!cluster1Config.nodes || cluster1Config.nodes.length === 0) { showAlert('请配置集群1信息', 'warning'); return; } if (!cluster2Config.nodes || cluster2Config.nodes.length === 0) { showAlert('请配置集群2信息', 'warning'); return; } try { const response = await fetch('/api/redis/config-groups', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: name, description: description, cluster1_config: cluster1Config, cluster2_config: cluster2Config, query_options: queryOptions }) }); const result = await response.json(); if (result.success) { showAlert(result.message, 'success'); bootstrap.Modal.getInstance(document.getElementById('saveRedisConfigModal')).hide(); loadRedisConfigGroups(); // 重新加载配置组列表 } else { showAlert(result.error, 'danger'); } } catch (error) { showAlert(`保存失败: ${error.message}`, 'danger'); } } // 加载选定的Redis配置组 async function loadSelectedRedisConfigGroup() { const groupId = document.getElementById('redisConfigGroupSelect').value; if (!groupId) { showAlert('请选择配置组', 'warning'); return; } try { const response = await fetch(`/api/redis/config-groups/${groupId}`); const result = await response.json(); if (result.success && result.data) { const config = result.data; // 加载集群1配置 loadClusterConfig('cluster1', config.cluster1_config); // 加载集群2配置 loadClusterConfig('cluster2', config.cluster2_config); // 加载查询选项 loadQueryOptions(config.query_options); showAlert(`配置组 "${config.name}" 加载成功`, 'success'); } else { showAlert(result.error, 'danger'); } } catch (error) { showAlert(`加载失败: ${error.message}`, 'danger'); } } // 加载集群配置到界面 function loadClusterConfig(clusterId, config) { // 设置集群名称 document.getElementById(`${clusterId}-name`).value = config.name || ''; // 设置密码 document.getElementById(`${clusterId}-password`).value = config.password || ''; // 设置超时和连接数 document.getElementById(`${clusterId}-timeout`).value = config.socket_timeout || 3; document.getElementById(`${clusterId}-max-conn`).value = config.max_connections_per_node || 16; // 清空现有节点 const container = document.getElementById(`${clusterId}-nodes`); container.innerHTML = ''; // 添加节点 if (config.nodes && config.nodes.length > 0) { config.nodes.forEach(node => { const nodeInput = document.createElement('div'); nodeInput.className = 'node-input'; nodeInput.innerHTML = ` `; container.appendChild(nodeInput); }); } else { // 添加默认节点 addNode(clusterId); } updateNodeDeleteButtons(); } // 加载查询选项 function loadQueryOptions(queryOptions) { if (queryOptions.mode === 'random') { document.getElementById('randomMode').checked = true; document.getElementById('sampleCount').value = queryOptions.count || 100; document.getElementById('keyPattern').value = queryOptions.pattern || '*'; document.getElementById('sourceCluster').value = queryOptions.source_cluster || 'cluster2'; } else { document.getElementById('specifiedMode').checked = true; document.getElementById('specifiedKeys').value = (queryOptions.keys || []).join('\n'); } toggleQueryMode(); } // 显示Redis配置管理对话框 function showManageRedisConfigDialog() { loadRedisConfigGroupsForManagement(); new bootstrap.Modal(document.getElementById('manageRedisConfigModal')).show(); } // 为管理界面加载Redis配置组 async function loadRedisConfigGroupsForManagement() { try { const response = await fetch('/api/redis/config-groups'); const result = await response.json(); const container = document.getElementById('redisConfigGroupList'); if (result.success && result.data && result.data.length > 0) { let html = '
'; html += ''; result.data.forEach(group => { html += ` `; }); html += '
名称描述创建时间操作
${group.name} ${group.description || '无描述'} ${new Date(group.created_at).toLocaleString('zh-CN')}
'; container.innerHTML = html; } else { container.innerHTML = '
暂无Redis配置组
'; } } catch (error) { document.getElementById('redisConfigGroupList').innerHTML = '
加载失败: ' + error.message + '
'; } } // 通过ID加载Redis配置组 async function loadRedisConfigGroupById(groupId) { try { const response = await fetch(`/api/redis/config-groups/${groupId}`); const result = await response.json(); if (result.success && result.data) { const config = result.data; // 加载配置 loadClusterConfig('cluster1', config.cluster1_config); loadClusterConfig('cluster2', config.cluster2_config); loadQueryOptions(config.query_options); // 关闭管理对话框 bootstrap.Modal.getInstance(document.getElementById('manageRedisConfigModal')).hide(); showAlert(`配置组 "${config.name}" 加载成功`, 'success'); } else { showAlert(result.error, 'danger'); } } catch (error) { showAlert(`加载失败: ${error.message}`, 'danger'); } } // 删除Redis配置组 async function deleteRedisConfigGroup(groupId, groupName) { if (!confirm(`确定要删除配置组 "${groupName}" 吗?此操作不可恢复。`)) { return; } try { const response = await fetch(`/api/redis/config-groups/${groupId}`, { method: 'DELETE' }); const result = await response.json(); if (result.success) { showAlert(result.message, 'success'); loadRedisConfigGroupsForManagement(); // 重新加载列表 loadRedisConfigGroups(); // 重新加载下拉框 } else { showAlert(result.error, 'danger'); } } catch (error) { showAlert(`删除失败: ${error.message}`, 'danger'); } } // 显示Redis配置导入对话框 function showImportRedisConfigDialog(targetCluster) { currentImportTarget = targetCluster; document.getElementById('redisConfigImportText').value = ''; new bootstrap.Modal(document.getElementById('importRedisConfigModal')).show(); } // 导入Redis配置 async function importRedisConfig() { const configText = document.getElementById('redisConfigImportText').value.trim(); if (!configText) { showAlert('请输入配置内容', 'warning'); return; } try { const response = await fetch('/api/redis/import-config', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ config_text: configText }) }); const result = await response.json(); if (result.success && result.data) { // 将配置应用到目标集群 loadClusterConfig(currentImportTarget, result.data); bootstrap.Modal.getInstance(document.getElementById('importRedisConfigModal')).hide(); showAlert(result.message, 'success'); } else { showAlert(result.error, 'danger'); } } catch (error) { showAlert(`导入失败: ${error.message}`, 'danger'); } } /** * Redis查询历史管理功能 */ // 加载Redis查询历史 async function loadRedisQueryHistory() { try { const response = await fetch('/api/redis/query-history'); const result = await response.json(); const select = document.getElementById('redisHistorySelect'); select.innerHTML = ''; if (result.success && result.data) { result.data.forEach(history => { const option = document.createElement('option'); option.value = history.id; option.textContent = `${history.name} - ${new Date(history.created_at).toLocaleString('zh-CN')}`; select.appendChild(option); }); } } catch (error) { console.error('加载Redis查询历史失败:', error); } } // 显示保存Redis查询历史对话框 function showSaveRedisHistoryDialog() { if (!currentResults) { showAlert('请先执行Redis比较查询', 'warning'); return; } // 生成默认名称 const timestamp = new Date().toLocaleString('zh-CN'); document.getElementById('redisHistoryName').value = `Redis查询_${timestamp}`; document.getElementById('redisHistoryDescription').value = `Redis比较结果 - 总计${currentResults.stats.total_keys}个Key,发现${currentResults.stats.different_count}处差异`; new bootstrap.Modal(document.getElementById('saveRedisHistoryModal')).show(); } // 保存Redis查询历史 async function saveRedisQueryHistory() { if (!currentResults) { showAlert('没有可保存的查询结果', 'warning'); return; } const name = document.getElementById('redisHistoryName').value.trim(); const description = document.getElementById('redisHistoryDescription').value.trim(); if (!name) { showAlert('请输入历史记录名称', 'warning'); return; } try { const response = await fetch('/api/redis/query-history', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: name, description: description, cluster1_config: getClusterConfig('cluster1'), cluster2_config: getClusterConfig('cluster2'), query_options: getQueryOptions(), query_keys: currentResults.query_options?.keys || [], results_summary: currentResults.stats, execution_time: currentResults.performance_report?.total_time || 0, total_keys: currentResults.stats.total_keys, different_count: currentResults.stats.different_count, identical_count: currentResults.stats.identical_count, missing_count: currentResults.stats.missing_in_cluster1 + currentResults.stats.missing_in_cluster2, raw_results: { identical_results: currentResults.identical_results, different_results: currentResults.different_results, missing_results: currentResults.missing_results, performance_report: currentResults.performance_report } }) }); const result = await response.json(); if (result.success) { showAlert(result.message, 'success'); bootstrap.Modal.getInstance(document.getElementById('saveRedisHistoryModal')).hide(); loadRedisQueryHistory(); // 重新加载历史记录列表 } else { showAlert(result.error, 'danger'); } } catch (error) { showAlert(`保存失败: ${error.message}`, 'danger'); } } // 加载选定的Redis查询历史 async function loadSelectedRedisHistory() { const historyId = document.getElementById('redisHistorySelect').value; if (!historyId) { showAlert('请选择历史记录', 'warning'); return; } try { const response = await fetch(`/api/redis/query-history/${historyId}`); const result = await response.json(); if (result.success && result.data) { const history = result.data; // 加载配置 loadClusterConfig('cluster1', history.cluster1_config); loadClusterConfig('cluster2', history.cluster2_config); loadQueryOptions(history.query_options); // 如果有原始结果,直接显示 if (history.raw_results) { const displayResults = { stats: history.results_summary, identical_results: history.raw_results.identical_results || [], different_results: history.raw_results.different_results || [], missing_results: history.raw_results.missing_results || [], performance_report: history.raw_results.performance_report || {}, clusters: { cluster1_name: history.cluster1_config.name, cluster2_name: history.cluster2_config.name } }; currentResults = displayResults; displayResults(displayResults); showAlert(`历史记录 "${history.name}" 加载成功`, 'success'); } else { showAlert(`历史记录 "${history.name}" 配置加载成功,但没有结果数据`, 'info'); } } else { showAlert(result.error, 'danger'); } } catch (error) { showAlert(`加载失败: ${error.message}`, 'danger'); } } // 显示Redis查询历史管理对话框 function showManageRedisHistoryDialog() { loadRedisHistoryForManagement(); new bootstrap.Modal(document.getElementById('manageRedisHistoryModal')).show(); } // 为管理界面加载Redis查询历史 async function loadRedisHistoryForManagement() { try { const response = await fetch('/api/redis/query-history'); const result = await response.json(); const container = document.getElementById('redisHistoryList'); if (result.success && result.data && result.data.length > 0) { let html = '
'; html += ''; result.data.forEach(history => { html += ` `; }); html += '
名称描述Key数量差异数执行时间创建时间操作
${history.name} ${history.description || '无描述'} ${history.total_keys} ${history.different_count} ${history.execution_time.toFixed(3)}s ${new Date(history.created_at).toLocaleString('zh-CN')}
'; container.innerHTML = html; } else { container.innerHTML = '
暂无Redis查询历史
'; } } catch (error) { document.getElementById('redisHistoryList').innerHTML = '
加载失败: ' + error.message + '
'; } } // 通过ID加载Redis查询历史 async function loadRedisHistoryById(historyId) { try { const response = await fetch(`/api/redis/query-history/${historyId}`); const result = await response.json(); if (result.success && result.data) { const history = result.data; // 加载配置 loadClusterConfig('cluster1', history.cluster1_config); loadClusterConfig('cluster2', history.cluster2_config); loadQueryOptions(history.query_options); // 如果有原始结果,直接显示 if (history.raw_results) { const displayResults = { stats: history.results_summary, identical_results: history.raw_results.identical_results || [], different_results: history.raw_results.different_results || [], missing_results: history.raw_results.missing_results || [], performance_report: history.raw_results.performance_report || {}, clusters: { cluster1_name: history.cluster1_config.name, cluster2_name: history.cluster2_config.name } }; currentResults = displayResults; displayResults(displayResults); } // 关闭管理对话框 bootstrap.Modal.getInstance(document.getElementById('manageRedisHistoryModal')).hide(); showAlert(`历史记录 "${history.name}" 加载成功`, 'success'); } else { showAlert(result.error, 'danger'); } } catch (error) { showAlert(`加载失败: ${error.message}`, 'danger'); } } // 删除Redis查询历史 async function deleteRedisHistory(historyId, historyName) { if (!confirm(`确定要删除历史记录 "${historyName}" 吗?此操作不可恢复。`)) { return; } try { const response = await fetch(`/api/redis/query-history/${historyId}`, { method: 'DELETE' }); const result = await response.json(); if (result.success) { showAlert(result.message, 'success'); loadRedisHistoryForManagement(); // 重新加载列表 loadRedisQueryHistory(); // 重新加载下拉框 } else { showAlert(result.error, 'danger'); } } catch (error) { showAlert(`删除失败: ${error.message}`, 'danger'); } } /** * Redis查询日志功能 */ // 显示Redis查询日志对话框 function showRedisQueryLogsDialog() { loadRedisQueryLogs(); new bootstrap.Modal(document.getElementById('redisQueryLogsModal')).show(); } // 加载Redis查询日志 async function loadRedisQueryLogs() { try { const response = await fetch('/api/query-logs?limit=1000'); const result = await response.json(); const container = document.getElementById('redisQueryLogs'); if (result.success && result.data && result.data.length > 0) { // 过滤Redis相关的日志 const redisLogs = result.data.filter(log => log.message.toLowerCase().includes('redis') || log.query_type === 'redis' ); if (redisLogs.length > 0) { let html = ''; redisLogs.forEach(log => { const levelClass = log.level === 'ERROR' ? 'text-danger' : log.level === 'WARNING' ? 'text-warning' : 'text-info'; html += `
[${log.timestamp}] ${log.level} ${log.message}
`; }); container.innerHTML = html; } else { container.innerHTML = '
暂无Redis查询日志
'; } } else { container.innerHTML = '
暂无查询日志
'; } } catch (error) { document.getElementById('redisQueryLogs').innerHTML = '
加载日志失败: ' + error.message + '
'; } } // 刷新Redis查询日志 function refreshRedisQueryLogs() { loadRedisQueryLogs(); showAlert('查询日志已刷新', 'info'); } // 清空Redis查询日志 async function clearRedisQueryLogs() { if (!confirm('确定要清空所有查询日志吗?此操作不可恢复。')) { return; } try { const response = await fetch('/api/query-logs', { method: 'DELETE' }); const result = await response.json(); if (result.success) { showAlert(result.message, 'success'); loadRedisQueryLogs(); // 重新加载日志 } else { showAlert(result.error, 'danger'); } } catch (error) { showAlert(`清空日志失败: ${error.message}`, 'danger'); } }