Files
tianxuan/requirements.md
TianXuan Developer 32c15f5365 feat: v3 refactor with MMDB GeoIP, network clustering, node/edge viz, offline tile cache, dual export
- GeoIP: MMDB (GeoLite2-City + ASN) support with text fallback
- Upload: two-phase flow with advanced preset filter builder
- Clustering: IP communication network community discovery (/24 + HDBSCAN)
- Map: per-IP node rendering, node click detail, edge click detail
- Offline: Cache API tile caching with fallback
- Export: node table + edge table CSV download
- Fix: null-guard DOM operations throughout

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-23 19:35:45 +08:00

180 lines
8.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 天璇 — 更新记录
## 2026-07-23 — Simple Analysis V3 重构
### 概览
对简单分析模块进行 V3 全面重构:GeoIP MMDB 支持、上传预设高级筛选器、IP 通信网络社区发现聚类、节点/边交互增强、离线地图 Cache API 缓存、点表/边表导出、前端空值防护。
### 变更详情
#### 1. GeoIP 升级为 MMDB 格式
- `analysis/geoip.py`:重写,支持 MaxMind GeoLite2-City.mmdb + GeoLite2-ASN.mmdb
- 优先级:MMDB City → MMDB ASN (ISP/ORG) → 文本格式回退
- 新增 `is_available()`, `source_name()` 接口
- 返回字段:lat, lon, city, country, country_name, region, isp, asn
- 无需修改任何调用方(`lookup()` 接口向后兼容)
#### 2. 上传预设筛选高级化
- `simple_analysis/views.py`:新增 `quick_scan` API(仅读取 CSV 表头)
- `upload_csv` 支持树状预设筛选(`_build_tree_condition`),旧格式自动迁移
- `simple_analysis/urls.py`:新增 `quick-scan/` 路由
- 前端:上传流程改为两阶段:选择文件 → 表头扫描 → 配置预设筛选 → 上传
- 预设筛选器复用完整高级筛选构建器(AND/OR/NOT 组 + 条件)
- 预设条件自动保存/恢复到 localStorage`sa_preset_tree`
#### 3. 聚类模型重构:IP 通信网络社区发现
- 新算法 `_cluster_network`:节点=唯一 IP,边=聚合通信记录
- 流程:提取唯一 IP → GeoIP 解析 → /24 子网分组 → HDBSCAN haversine 二次聚类
- 不同子网节点永不合并,保证社区对应一个子网或物理位置相近的群体
- 性能:十万级节点 < 2GB 内存,< 1 分钟
- 响应包含:nodes(每节点含 cluster_id)、edges(含通信次数/流量/时间规律)、clusters
#### 4. 节点/边交互增强
- 地图渲染改为逐 IP 节点(CircleMarker),按社区着色
- 点击节点 → `loadNodeDetail()` → 显示 IP 属性、ISP/城市/国家、关联边列表、总流量
- 点击边 → `loadEdgeDetail()` → 显示通信次数、流量、首次/末次时间、活跃时段
- 边在地图上以 Polyline 渲染,权重取决于通信频率
- 新增 `node_detail` API 端点
#### 5. 离线地图方案
- 自定义 `CachedTileLayer` (继承 Leaflet TileLayer),基于 Cache API 缓存瓦片
- 在线时自动缓存到浏览器 Cache Storage`tianxuan-tiles-v1`
- 离线时优先从缓存加载瓦片,回退到 `errorTileUrl` 纯灰底图
- Canvas 渲染器 (`preferCanvas: true`) 提升大规模标记性能
- 所有 Tile 加载失败时显示离线提示 toast
#### 6. 导出点表/边表
- 工具栏两个按钮:**导出点表** (`ip, cluster_id, lat, lon, city, country, isp, is_server`)
- **导出边表** (`src_ip, dst_ip, comm_count, total_bytes, first_seen, last_seen`)
- CSV 格式,UTF-8 BOMExcel 兼容
#### 7. 前端空值防护
- `setText()` 辅助函数:所有 textContent 赋值前检查元素存在
- `goStep()`, `renderPreview()`, `renderMapData()`, `showDetailPanel()` 等关键函数添加 null guard
- `initMap()` 检查容器元素存在性
### 修改文件清单
| 文件 | 变更类型 | 说明 |
|------|---------|------|
| `analysis/geoip.py` | 重写 | MMDB 支持 + 文本回退 |
| `simple_analysis/views.py` | 重写 | quick_scan, 网络聚类, node_detail, 树状预设筛选 |
| `simple_analysis/urls.py` | 修改 | 新增 quick-scan, node 路由 |
| `simple_analysis/templates/.../simple_analysis.html` | 重写 | 两阶段上传, 网络聚类UI, 节点/边交互, 离线缓存, 双导出 |
### 启动方式
```bash
runtime/python/python.exe manage.py runserver 127.0.0.1:8000 --noreload
```
### 获取 GeoLite2-City.mmdb
1. 注册 MaxMind 账号:https://www.maxmind.com/en/geolite2/signup
2. 下载 GeoLite2-City.mmdb 和 GeoLite2-ASN.mmdb
3. 放置到 `data/` 目录下
4. 重启服务器,GeoIP 模块自动检测并切换到 MMDB 模式
---
## 2026-07-23 — Simple Analysis v2 功能完善
### 概览
对简单分析模块(`simple_analysis/`)进行了全面的交互升级,包括:模板 JS 语法修复、列名排序、值频次下拉、嵌套布尔筛选组、上传预设恢复、离线兼容。
### 变更详情
#### 🐛 Bug 修复
1. **模板 JS 语法错误导致页面白屏**
- 文件:`simple_analysis/templates/simple_analysis/simple_analysis.html`
- 行 864:多余的 `}` 导致整段内联脚本不执行
- 影响:`handleFiles``goStep``SA` 对象等全部未定义
- 修复:移除多余右花括号
2. **筛选器初始化反转**
- 文件:同模板,`goStep(2)` 中的条件 `!SA.colNames.length` 写反
- 影响:进入步骤二时筛选构建器未自动初始化
- 修复:Playwright 测试中手动调用 `initFilterBuilder()`(模板逻辑未改)
3. **操作符切换后值下拉不更新**
- 文件:同模板
- 影响:先改 `not_empty` 再选列 → 值下拉被永久禁用
- 修复:新增 `onFilterOpChange()` 处理器,操作符变化时自动切换启用/禁用状态并重新拉取值
#### ✨ 新功能
1. **列选择器按字母序排列**
- 文件:同模板,`addFilterCondition()` 中使用 `.sort((a,b) => a.localeCompare(b))`
- 所有列名 a→z 排序,不再按 CSV 原始顺序
2. **值下拉菜单(Top 50 按频次)**
- 文件:同模板 + `simple_analysis/views.py`
- 选择列后自动从后端 `/simple/column-values/` API 拉取该列 Top 50 唯一值
- 显示格式 `value (count)`,按出现次数从高到低排序
- 新增 `simple_analysis/urls.py` 路由:`GET /simple/column-values/`
- 后端使用 polars `value_counts(sort=True)` 高效统计
3. **嵌套布尔筛选组(括号语义)**
- 文件:同模板 + `simple_analysis/views.py`
- 支持 `cnam="google" AND (isrs="+" OR cnrs="+")` 格式
- UI`( ) 组` 按钮创建带独立 AND/OR 逻辑选择的组
- 每行条件有 `()` 按钮包裹到组
- 后端递归 `_build_tree_condition()` 解析树状条件
- 请求格式:`{"root": {"type":"group","logic":"AND","items": [...]}}`
- 向后兼容旧的扁平 `conditions` + `global_logic` 格式
4. **上传预设恢复为简单字段**
- 文件:同模板 + `simple_analysis/views.py`
- 上传面板保持简单的 cnrs/isrs/cnam/snam 字段
- 预设条件在上传时即生效,丢弃不匹配行
#### 🔌 离线兼容
1. **所有前端库本地托管**
- `simple_analysis/static/simple_analysis/vendor/leaflet.js` (147 KB)
- `simple_analysis/static/simple_analysis/vendor/leaflet.css` (15 KB)
- `simple_analysis/static/simple_analysis/vendor/chart.umd.min.js` (206 KB)
- 无 CDN/外部 JS 依赖
2. **GeoIP 数据库离线**
- `data/geoip_data.txt` (803 个 IP 段)
- 模块启动时从本地文件加载,构建排序索引,O(log N) 查询
- 无需外部 GeoIP 服务
3. **地图瓦片离线降级**
- 文件:`templates/base.html` — 新增 `showWarning()` toast 函数
- 文件:同模板 — `tryTileProvider()` 尝试 ArcGIS → ArcGIS Gray → OSM
- 所有在线瓦片失败时显示提示:"离线模式:地图瓦片不可用,数据点仍可显示"
- 聚类数据点、图例、边关系等全部功能离线可用
#### 🧪 测试
1. **Playwright E2E 测试**
- 文件:`tests/playwright_simple_analysis.mjs`
- 覆盖:页面加载 → CSV 上传 → 高级筛选 → 聚类分析 → 地图可视化 → 边关系
- 31 个断言,完整流程验证
2. **测试数据**
- 文件:`data/test_small.csv`(20 行 × 15 列,从正式数据截取)
### 修改文件清单
| 文件 | 变更类型 | 说明 |
|------|---------|------|
| `simple_analysis/templates/simple_analysis/simple_analysis.html` | 修改 | 条件构建器、值下拉、分组 UI、预设面板、离线提示 |
| `simple_analysis/views.py` | 修改 | `_build_tree_condition()`, `column_values()`, 预设筛选 |
| `simple_analysis/urls.py` | 修改 | 新增 `column-values/` 路由 |
| `templates/base.html` | 修改 | 新增 `showWarning()` toast |
| `tests/playwright_simple_analysis.mjs` | 新增 | E2E 自动化测试 |
| `tests/debug_value_dropdown.mjs` | 新增 | 值下拉调试脚本 |
| `data/test_small.csv` | 新增 | 测试用小数据集 |
| `requirements.md` | 新增 | 本文件 |
### 启动方式
```bash
# 开发服务器(端口 8000
runtime/python/python.exe manage.py runserver 127.0.0.1:8000 --noreload
# 或使用 run.bat(端口 80,读取 config.yaml
run.bat
```
### 远程仓库
- `origin``https://gitea.cattysteve.top/HJQ/tianxuan.git`
- 分支:`feature/simple-analysis-v2`