// 全局变量 let currentResults = null; let currentIdenticalPage = 1; let identicalPageSize = 10; let filteredIdenticalResults = []; let currentDifferencePage = 1; let differencePageSize = 10; let filteredDifferenceResults = []; // 页面加载完成后初始化 document.addEventListener('DOMContentLoaded', function() { loadDefaultConfig(); loadConfigGroups(); // 加载配置组列表 }); // 加载配置组列表 async function loadConfigGroups() { try { const response = await fetch('/api/config-groups'); const result = await response.json(); if (result.success) { const select = document.getElementById('configGroupSelect'); select.innerHTML = ''; result.data.forEach(group => { const option = document.createElement('option'); option.value = group.id; option.textContent = `${group.name} (${group.description || '无描述'})`; select.appendChild(option); }); if (result.data.length === 0) { console.log('暂无配置组,数据库已就绪'); } } else { console.error('加载配置组失败:', result.error); // 如果是数据库问题,显示友好提示 if (result.error && result.error.includes('table')) { showAlert('info', '正在初始化数据库,请稍后再试'); } } } catch (error) { console.error('加载配置组失败:', error); showAlert('warning', '配置组功能暂时不可用,但不影响基本查询功能'); } } // 加载选中的配置组 async function loadSelectedConfigGroup() { const groupId = document.getElementById('configGroupSelect').value; if (!groupId) { showAlert('warning', '请先选择一个配置组'); return; } try { const response = await fetch(`/api/config-groups/${groupId}`); const result = await response.json(); if (result.success) { const config = result.data; // 填充生产环境配置 document.getElementById('pro_cluster_name').value = config.pro_config.cluster_name || ''; document.getElementById('pro_datacenter').value = config.pro_config.datacenter || ''; document.getElementById('pro_hosts').value = (config.pro_config.hosts || []).join(','); document.getElementById('pro_port').value = config.pro_config.port || 9042; document.getElementById('pro_username').value = config.pro_config.username || ''; document.getElementById('pro_password').value = config.pro_config.password || ''; document.getElementById('pro_keyspace').value = config.pro_config.keyspace || ''; document.getElementById('pro_table').value = config.pro_config.table || ''; // 填充测试环境配置 document.getElementById('test_cluster_name').value = config.test_config.cluster_name || ''; document.getElementById('test_datacenter').value = config.test_config.datacenter || ''; document.getElementById('test_hosts').value = (config.test_config.hosts || []).join(','); document.getElementById('test_port').value = config.test_config.port || 9042; document.getElementById('test_username').value = config.test_config.username || ''; document.getElementById('test_password').value = config.test_config.password || ''; document.getElementById('test_keyspace').value = config.test_config.keyspace || ''; document.getElementById('test_table').value = config.test_config.table || ''; // 填充查询配置 document.getElementById('keys').value = (config.query_config.keys || []).join(','); document.getElementById('fields_to_compare').value = (config.query_config.fields_to_compare || []).join(','); document.getElementById('exclude_fields').value = (config.query_config.exclude_fields || []).join(','); showAlert('success', `配置组 "${config.name}" 加载成功`); } else { showAlert('danger', result.error || '加载配置组失败'); } } catch (error) { showAlert('danger', '加载配置组失败: ' + error.message); } } // 显示保存配置组对话框 function showSaveConfigDialog() { const modalContent = `
暂无配置组
'; } else { result.data.forEach(group => { const createdDate = new Date(group.created_at).toLocaleString(); const updatedDate = new Date(group.updated_at).toLocaleString(); configGroupsList += `${group.description || '无描述'}
创建: ${createdDate} | 更新: ${updatedDate}总Key数量
相同记录
差异记录
一致性比例
未发现差异
'; return; } // 计算分页 const totalPages = Math.ceil(filteredDifferenceResults.length / differencePageSize); const startIndex = (currentDifferencePage - 1) * differencePageSize; const endIndex = startIndex + differencePageSize; const currentPageData = filteredDifferenceResults.slice(startIndex, endIndex); let html = `主键: ${JSON.stringify(diff.key)}
${diff.message}
主键: ${JSON.stringify(diff.key)}
差异字段: ${diff.field}
${escapeHtml(diff.pro_value)}
${escapeHtml(diff.test_value)}
没有完全相同的记录
'; return; } // 计算分页 const totalPages = Math.ceil(filteredIdenticalResults.length / identicalPageSize); const startIndex = (currentIdenticalPage - 1) * identicalPageSize; const endIndex = startIndex + identicalPageSize; const currentPageData = filteredIdenticalResults.slice(startIndex, endIndex); let html = `主键: ${JSON.stringify(result.key)}
${escapeHtml(String(proValue))}
${escapeHtml(String(testValue))}
${isProMissing ? '字段不存在' : escapeHtml(JSON.stringify(proValue, null, 2))}
${isTestMissing ? '字段不存在' : escapeHtml(JSON.stringify(testValue, null, 2))}
无字段数据可对比
'; } // 复制全部原生数据 function copyAllRawData() { const proData = document.getElementById('hiddenProData').textContent; const testData = document.getElementById('hiddenTestData').textContent; const allData = `生产环境数据:\n${proData}\n\n测试环境数据:\n${testData}`; navigator.clipboard.writeText(allData).then(() => { showAlert('success', '已复制全部原生数据到剪贴板'); }).catch(err => { showAlert('danger', '复制失败: ' + err.message); }); } // 下载原生数据 function downloadRawData() { const proData = document.getElementById('hiddenProData').textContent; const testData = document.getElementById('hiddenTestData').textContent; const exportData = { timestamp: new Date().toISOString(), production_data: JSON.parse(proData), test_data: JSON.parse(testData) }; const dataStr = JSON.stringify(exportData, null, 2); const dataBlob = new Blob([dataStr], {type: 'application/json'}); const link = document.createElement('a'); link.href = URL.createObjectURL(dataBlob); link.download = `raw_data_${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.json`; link.click(); } // 显示差异数据的原生数据 function showDifferenceRawData(keyStr) { showRawData(keyStr); // 复用相同的原生数据显示逻辑 } // 显示比较总结 function displayComparisonSummary(summary) { const summaryContainer = document.getElementById('comparison-summary'); if (!summary) { summaryContainer.innerHTML = '无总结数据
'; return; } const qualityLevel = summary.data_quality.quality_level; const html = `${qualityLevel.description}
${field}
${count}次
无字段差异统计
' }无字段差异统计
'; return; } let html = '字段名 | 差异次数 | 占比 |
---|---|---|
${field} |
${count} | ${percentage}% |