diff --git a/CLAUDE.md b/CLAUDE.md index 9e021f6..77c43d7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,7 +14,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co - 查询执行和结果比对算法 - 配置组管理(CRUD操作) - JSON字段特殊处理和数组比较逻辑 -- `config_groups.db`: SQLite数据库,存储用户保存的配置组 + - 查询历史记录管理 +- `config_groups.db`: SQLite数据库,存储用户保存的配置组和查询历史 **前端 (原生JavaScript + Bootstrap)** - `templates/db_compare.html`: 主界面模板,包含配置表单和结果展示 @@ -25,6 +26,10 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co - 原生数据展示(多种视图模式:格式化、原始、差异对比、树形) - 高级错误处理和用户反馈 +**示例代码** +- `demo/Query.py`: 独立的Cassandra查询比对脚本示例 +- `demo/twcsQuery.py`: 另一个查询示例 + ### 关键功能模块 **数据比对引擎** @@ -32,6 +37,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co - 数组字段的顺序无关比较 - 字段级别的差异统计和分析 - 数据质量评估和建议生成 +- 支持包含和排除特定字段的比较 **用户界面特性** - 分页系统(差异记录和相同记录) @@ -39,12 +45,13 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co - 原生数据展示(JSON语法高亮、树形视图) - 配置导入导出和管理 - 详细的错误诊断和故障排查指南 +- 查询历史记录和复用 ## 开发相关命令 ### 环境设置 ```bash -# 安装依赖 +# 安装依赖(仅需要Flask和cassandra-driver) pip install -r requirements.txt # 运行应用(默认端口5000) @@ -57,13 +64,24 @@ python app.py ### 开发模式 应用默认运行在debug模式,代码修改后自动重启。访问 http://localhost:5000 查看首页,http://localhost:5000/db-compare 使用比对工具。 +### 依赖项 +- Flask==2.3.3 +- cassandra-driver==3.29.1 + ## API架构说明 ### 核心API端点 - `GET /api/default-config`: 获取默认数据库配置 - `POST /api/query`: 执行数据库查询比对(主要功能) -- `GET|POST|DELETE /api/config-groups`: 配置组的CRUD操作 +- `GET /api/config-groups`: 获取所有配置组 +- `POST /api/config-groups`: 创建新配置组 +- `GET /api/config-groups/`: 获取特定配置组 +- `DELETE /api/config-groups/`: 删除配置组 - `POST /api/init-db`: 初始化SQLite数据库 +- `GET /api/query-history`: 获取查询历史 +- `POST /api/query-history`: 保存查询历史 +- `GET /api/query-history/`: 获取特定历史记录 +- `DELETE /api/query-history/`: 删除历史记录 ### 查询比对流程 1. 前端发送配置和Key值列表到 `/api/query` @@ -108,6 +126,8 @@ python app.py - 使用DCAwareRoundRobinPolicy避免负载均衡警告 - 连接超时设置为10秒 - 失败时提供网络连通性测试 +- 支持认证(PlainTextAuthProvider) +- 支持集群配置(cluster_name, datacenter) ### 前端状态管理 - `currentResults`: 存储最新查询结果 @@ -129,4 +149,26 @@ python app.py - 大数据集的分页处理 - 原生数据的延迟加载 - JSON格式化的客户端缓存 -- 搜索和过滤的防抖处理 \ No newline at end of file +- 搜索和过滤的防抖处理 + +### SQLite数据库表结构 + +**config_groups表** +- id: 主键 +- name: 配置组名称(唯一) +- description: 描述 +- pro_config: 生产环境配置(JSON) +- test_config: 测试环境配置(JSON) +- query_config: 查询配置(JSON) +- created_at/updated_at: 时间戳 + +**query_history表** +- id: 主键 +- name: 查询名称 +- description: 描述 +- pro_config/test_config/query_config: 配置(JSON) +- query_keys: 查询的键值(JSON) +- results_summary: 结果摘要(JSON) +- execution_time: 执行时间 +- total_keys/differences_count/identical_count: 统计数据 +- created_at: 时间戳 \ No newline at end of file diff --git a/static/js/app.js b/static/js/app.js index 3c6b428..fd67519 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -600,7 +600,7 @@ function displayDifferences() { 记录缺失
-
@@ -633,7 +633,7 @@ function displayDifferences() { data-bs-toggle="collapse" data-bs-target="#diffCollapse${globalIndex}"> 查看详情 - @@ -762,7 +762,7 @@ function displayIdenticalResults() { data-bs-toggle="collapse" data-bs-target="#collapse${globalIndex}"> 查看详情 - @@ -1171,40 +1171,132 @@ function escapeForJs(str) { .replace(/\0/g, '\\0'); // 空字符 } -// 显示原生数据(简化测试版本) +// 显示原生数据 function showRawData(keyStr) { - console.log('showRawData 开始执行,参数:', keyStr); - - // 添加基本检查 if (!currentResults) { - console.error('没有查询结果数据'); - alert('请先执行查询操作'); + showAlert('warning', '请先执行查询操作'); return; } try { - console.log('开始解析 keyStr:', keyStr); + // 解析key + const key = JSON.parse(keyStr); - // 创建最简单的测试模态框 - const existingModal = document.getElementById('rawDataModal'); - if (existingModal) { - existingModal.remove(); + // 在原生数据中查找对应的记录 + let proData = null; + let testData = null; + + // 查找生产环境数据 + if (currentResults.raw_pro_data) { + proData = currentResults.raw_pro_data.find(item => { + // 比较主键 + return JSON.stringify(item[Object.keys(key)[0]]) === JSON.stringify(key[Object.keys(key)[0]]); + }); } - // 创建基本模态框 - const modalHTML = ` + // 查找测试环境数据 + if (currentResults.raw_test_data) { + testData = currentResults.raw_test_data.find(item => { + // 比较主键 + return JSON.stringify(item[Object.keys(key)[0]]) === JSON.stringify(key[Object.keys(key)[0]]); + }); + } + + // 创建模态框内容 + const modalContent = `