修复展示错误

This commit is contained in:
2025-08-11 14:07:10 +08:00
parent eabca97350
commit 0b1dc6b8ca
2 changed files with 164 additions and 24 deletions

View File

@@ -279,6 +279,11 @@ def compare_json_arrays(array1, array2):
def format_json_for_display(value):
"""格式化JSON用于显示"""
# 处理None值
if value is None:
return "null"
# 处理非字符串类型
if not isinstance(value, str):
return str(value)

View File

@@ -911,11 +911,14 @@ function displayDifferences() {
// 保存当前搜索框的值
const currentSearchValue = document.getElementById('differenceSearch')?.value || '';
if (!filteredDifferenceResults.length) {
if (!filteredDifferenceResults || !filteredDifferenceResults.length) {
differencesContainer.innerHTML = '<p class="text-success"><i class="fas fa-check"></i> 未发现差异</p>';
return;
}
// 调试日志:检查差异数据
console.log('差异数据:', filteredDifferenceResults);
// 按主键分组差异
const groupedDifferences = groupDifferencesByKey(filteredDifferenceResults);
const totalGroups = Object.keys(groupedDifferences).length;
@@ -995,10 +998,19 @@ function displayDifferences() {
`;
// 显示当前页的主键组
currentPageKeys.forEach((key, groupIndex) => {
const diffs = groupedDifferences[key];
currentPageKeys.forEach((keyStr, groupIndex) => {
const diffs = groupedDifferences[keyStr];
const globalIndex = startIndex + groupIndex + 1;
// 将字符串化的key解析回对象
let keyObj;
try {
keyObj = JSON.parse(keyStr);
} catch (e) {
// 如果解析失败,假设它本身就是一个简单值
keyObj = keyStr;
}
html += `
<div class="card mb-3 border-primary">
<div class="card-header bg-primary bg-opacity-10">
@@ -1012,14 +1024,14 @@ function displayDifferences() {
data-bs-toggle="collapse" data-bs-target="#keyGroup${globalIndex}">
<i class="fas fa-chevron-down"></i> 展开/收起
</button>
<button class="btn btn-sm btn-outline-info ms-2" onclick='showDifferenceRawData(${JSON.stringify(JSON.stringify(key))})'>
<button class="btn btn-sm btn-outline-info ms-2" onclick='showDifferenceRawData(${JSON.stringify(JSON.stringify(keyObj))})'>
<i class="fas fa-code"></i> 原生数据
</button>
</div>
</div>
<p class="mb-0 mt-2"><strong>主键:</strong> ${formatCompositeKey(key)}</p>
<p class="mb-0 mt-2"><strong>主键:</strong> ${formatCompositeKey(keyObj)}</p>
</div>
<div class="collapse show" id="keyGroup${globalIndex}">
<div class="collapse" id="keyGroup${globalIndex}">
<div class="card-body">
`;
@@ -1039,6 +1051,18 @@ function displayDifferences() {
const jsonClass = isJson ? 'json-field' : '';
const fieldId = `field_${globalIndex}_${diffIndex}`;
// 调试:打印差异数据
console.log(`差异 ${diff.field}:`, {
pro_value: diff.pro_value,
test_value: diff.test_value,
is_json: diff.is_json,
is_array: diff.is_array
});
// 确保值存在
const proValue = diff.pro_value !== undefined && diff.pro_value !== null ? diff.pro_value : '无数据';
const testValue = diff.test_value !== undefined && diff.test_value !== null ? diff.test_value : '无数据';
html += `
<div class="mb-3 border-start border-3 border-danger ps-3">
<div class="d-flex justify-content-between align-items-start mb-2">
@@ -1060,7 +1084,7 @@ function displayDifferences() {
<small class="text-success fw-bold">生产环境</small>
</div>
<div class="card-body p-2">
<pre class="field-value mb-0 ${jsonClass}" style="max-height: 200px; overflow-y: auto;">${escapeHtml(diff.pro_value)}</pre>
<pre class="field-value mb-0 ${jsonClass}" style="max-height: 200px; overflow-y: auto;">${escapeHtml(proValue)}</pre>
</div>
</div>
</div>
@@ -1070,7 +1094,7 @@ function displayDifferences() {
<small class="text-info fw-bold">测试环境</small>
</div>
<div class="card-body p-2">
<pre class="field-value mb-0 ${jsonClass}" style="max-height: 200px; overflow-y: auto;">${escapeHtml(diff.test_value)}</pre>
<pre class="field-value mb-0 ${jsonClass}" style="max-height: 200px; overflow-y: auto;">${escapeHtml(testValue)}</pre>
</div>
</div>
</div>
@@ -1115,8 +1139,21 @@ function displayDifferences() {
// HTML转义函数防止XSS
function escapeHtml(text) {
// 处理undefined和null值
if (text === undefined || text === null) {
return '<span class="text-muted">无数据</span>';
}
// 确保是字符串
const str = String(text);
// 如果是空字符串
if (str === '') {
return '<span class="text-muted">空值</span>';
}
const div = document.createElement('div');
div.textContent = text;
div.textContent = str;
return div.innerHTML;
}
@@ -1671,6 +1708,7 @@ function showRawData(keyStr) {
try {
// 解析key
const key = JSON.parse(keyStr);
console.log('查找原始数据key:', key);
// 在原生数据中查找对应的记录
let proData = null;
@@ -1682,15 +1720,40 @@ function showRawData(keyStr) {
// 支持复合主键比较
if (typeof key === 'object' && !Array.isArray(key)) {
// 复合主键情况:比较所有主键字段
return Object.keys(key).every(keyField =>
JSON.stringify(item[keyField]) === JSON.stringify(key[keyField])
);
const matches = Object.keys(key).every(keyField => {
const itemValue = item[keyField];
const keyValue = key[keyField];
// 如果都是undefined或null认为匹配
if (itemValue == null && keyValue == null) {
return true;
}
// 转换为字符串进行比较
const itemStr = String(itemValue);
const keyStr = String(keyValue);
// 直接比较字符串
return itemStr === keyStr;
});
if (matches) {
console.log('找到生产环境数据:', item);
}
return matches;
} else {
// 单主键情况:保持原有逻辑
const keyField = Object.keys(key)[0];
return JSON.stringify(item[keyField]) === JSON.stringify(key[keyField]);
// 单主键情况(兼容旧代码)
return false;
}
});
// 如果没找到,输出调试信息
if (!proData) {
console.log('未找到生产数据查找的key:', key);
console.log('可用的数据:', currentResults.raw_pro_data.map(item => ({
statusid: item.statusid
})));
}
}
// 查找测试环境数据
@@ -1699,17 +1762,44 @@ function showRawData(keyStr) {
// 支持复合主键比较
if (typeof key === 'object' && !Array.isArray(key)) {
// 复合主键情况:比较所有主键字段
return Object.keys(key).every(keyField =>
JSON.stringify(item[keyField]) === JSON.stringify(key[keyField])
);
const matches = Object.keys(key).every(keyField => {
const itemValue = item[keyField];
const keyValue = key[keyField];
// 如果都是undefined或null认为匹配
if (itemValue == null && keyValue == null) {
return true;
}
// 转换为字符串进行比较
const itemStr = String(itemValue);
const keyStr = String(keyValue);
// 直接比较字符串
return itemStr === keyStr;
});
if (matches) {
console.log('找到测试环境数据:', item);
}
return matches;
} else {
// 单主键情况:保持原有逻辑
const keyField = Object.keys(key)[0];
return JSON.stringify(item[keyField]) === JSON.stringify(key[keyField]);
// 单主键情况(兼容旧代码)
return false;
}
});
// 如果没找到,输出调试信息
if (!testData) {
console.log('未找到测试数据查找的key:', key);
console.log('可用的数据:', currentResults.raw_test_data.map(item => ({
statusid: item.statusid
})));
}
}
console.log('查找结果 - 生产数据:', proData, '测试数据:', testData);
// 创建模态框内容
const modalContent = `
<div class="modal fade" id="rawDataModal" tabindex="-1">
@@ -1833,14 +1923,47 @@ function showRawData(keyStr) {
// 延迟渲染对比视图和树形视图
setTimeout(() => {
renderDiffView(proData, testData);
renderTreeView('proTreeView', proData);
renderTreeView('testTreeView', testData);
console.log('开始渲染视图,生产数据:', proData, '测试数据:', testData);
// 渲染对比视图
try {
renderDiffView(proData, testData);
console.log('对比视图渲染完成');
} catch (e) {
console.error('对比视图渲染失败:', e);
}
// 渲染树形视图
try {
renderTreeView('proTreeView', proData);
renderTreeView('testTreeView', testData);
console.log('树形视图渲染完成');
} catch (e) {
console.error('树形视图渲染失败:', e);
}
// 为格式化视图添加同步滚动
setupSyncScroll('formatted');
// 为树形视图添加同步滚动
setupSyncScroll('tree');
// 添加标签页切换事件监听器,确保切换时重新渲染
const tabButtons = document.querySelectorAll('#rawDataTabs button[data-bs-toggle="tab"]');
tabButtons.forEach(button => {
button.addEventListener('shown.bs.tab', (event) => {
const targetId = event.target.getAttribute('data-bs-target');
console.log('切换到标签页:', targetId);
if (targetId === '#diff') {
// 重新渲染对比视图
renderDiffView(proData, testData);
} else if (targetId === '#tree') {
// 重新渲染树形视图
renderTreeView('proTreeView', proData);
renderTreeView('testTreeView', testData);
}
});
});
}, 100);
} catch (error) {
@@ -1875,6 +1998,12 @@ function showDifferenceRawData(keyStr) {
function renderDiffView(proData, testData) {
const diffViewContainer = document.getElementById('diffView');
// 确保容器存在
if (!diffViewContainer) {
console.error('对比视图容器不存在');
return;
}
if (!proData && !testData) {
diffViewContainer.innerHTML = '<p class="text-muted text-center">无数据可对比</p>';
return;
@@ -2256,6 +2385,12 @@ function normalizeValue(value) {
function renderTreeView(containerId, data) {
const container = document.getElementById(containerId);
// 确保容器存在
if (!container) {
console.error('树形视图容器不存在:', containerId);
return;
}
if (!data) {
container.innerHTML = '<p class="text-muted">无数据</p>';
return;