# Globe v6 修复计划 — 最终版 ## TL;DR (For humans) 两个紧急修复:背面剔除 + 国境线恢复。预计 50 行变更。 --- ## P1. 背面剔除修复 **原因**: `updatePulses` 中 `arcGroup.quaternion` 与 `rotation` 不同步,导致方向判断错误。 **修复**: 用 `localToWorld` 替代 `applyQuaternion` 在 `templates/tianxuan/globe.html` 的 `updatePulses` 函数中: ```javascript // 删除: // var arcQuat = arcGroup.quaternion; // midPt.applyQuaternion(arcQuat); // 在函数开头添加: arcGroup.updateMatrixWorld(true); // 在循环内改为: var midPt = d.curve.getPoint(0.5); arcGroup.localToWorld(midPt); var isFront = midPt.dot(camDir) < -0.08; ``` ## P2. 国境线恢复 ### 步骤 1: 创建 static/tianxuan/world_borders.js 创建文件含 10 国精简轮廓(中国/美国/俄罗斯/加拿大/巴西/澳大利亚/印度/英国/日本/法国)。 每国 10-20 个 [lat,lon] 坐标点。 **重要**: 中国坐标需包含台湾和南海九段线示意。 台湾坐标: 25°N,121°E 左右。 ### 步骤 2: 恢复 globe.html 中的 borderGroup 在 `scene.add(gridGroup)` 之后添加: ```javascript // ── World borders (loaded from static file) ── var borderGroup = new THREE.Group(); var borderMat = new THREE.LineBasicMaterial({ color: 0x88dd88, transparent: true, opacity: 0.3, depthTest: false }); function renderBorders(borders) { if (!borders) return; for (var c = 0; c < borders.length; c++) { var pts = []; for (var p = 0; p < borders[c].length; p++) { var lat = borders[c][p][0], lon = borders[c][p][1]; var phi = (90 - lat) * Math.PI / 180; var theta = (lon + 180) * Math.PI / 180; pts.push(new THREE.Vector3(5.01 * Math.sin(phi) * Math.cos(theta), 5.01 * Math.cos(phi), 5.01 * Math.sin(phi) * Math.sin(theta))); } if (pts.length > 2) { borderGroup.add(new THREE.Line(new THREE.BufferGeometry().setFromPoints(pts), borderMat)); } } } if (typeof worldBorders !== 'undefined') renderBorders(worldBorders); scene.add(borderGroup); ``` ### 步骤 3: 恢复加载脚本 在 three.min.js 之后添加: ```html ``` ### 步骤 4: 恢复复选框 在 toggle 区域恢复: ```html ``` ### 步骤 5: 添加 borderGroup 到 animate/惯性旋转 ```javascript earth.rotation.y += inertiaY; arcGroup.rotation.y += inertiaY; gridGroup.rotation.y += inertiaY; borderGroup.rotation.y += inertiaY; earth.rotation.x += inertiaX; arcGroup.rotation.x += inertiaX; gridGroup.rotation.x += inertiaX; borderGroup.rotation.x += inertiaX; ``` --- ## Todos - [x] 1. 创建 `static/tianxuan/world_borders.js` (10国精简轮廓) - [x] 2. globe.html: 修复背面剔除 (localToWorld) - [x] 3. globe.html: 恢复 borderGroup (渲染 + 加载 + 复选框 + 旋转) - [x] 4. config.yaml: 添加 `":ips": ipv4`, `":ipd": ipv4` - [x] 5. type_classifier.py: 名称模式增加 `:ips` `:ipd` - [x] 6. entity_detector.py: ENTITY_KEYWORDS 增加 `:ips` `:ipd` - [x] 7. views.py globe_view: 列检测增加 `:ips` `:ipd` ## P4. 用户数据列名适配 (`:ips`, `:ipd`) **问题**: 用户的源IP列名是 `:ips`,目标IP列名是 `:ipd`。 当前代码的IP检测靠名称模式匹配 `_ip`/`src_ip`/`dst_ip`,完全匹配不到。 **需要修改的文件**: ### 1. config.yaml — 添加列覆盖 ```yaml columns: ":ips": ipv4 ":ipd": ipv4 ``` ### 2. analysis/type_classifier.py — 名称模式增加 `:ips` `:ipd` 在 `_NAME_TYPE_MAP` 中添加: ```python (re.compile(r'^:ips$|^:ipd$', re.I), DataType.IPv4), ``` ### 3. analysis/entity_aggregator.py — 关键词增加 `:ips` `:ipd` `_DST_IP_KEYWORDS` 和 `_SNI_KEYWORDS` 逻辑可能需要扩展,但更关键的是 entity_detector 的 `ENTITY_KEYWORDS`。 ### 4. analysis/entity_detector.py — 关键词增加 `:ips` `:ipd` ```python ENTITY_KEYWORDS: frozenset[str] = frozenset({ 'src_ip', 'dst_ip', ':ips', ':ipd', 'source_ip', ... }) ``` ### 5. analysis/views.py — globe_view 中的列检测 当前 globe_view 用 `'src_ip' in c.lower()` 检测IP列。 需要增加 `':ips'` 和 `':ipd'` 的检测。 ## 紧急修补 (Traceback截断) **问题**: views.py 中所有 `run.error_message = tb[:500]` 截断到 500 字符,无法调试。 **修复**: 搜索 views.py 中所有 `tb[:数字]` → 改为 `tb`(不截断) ```python # 全局替换 ALL: tb[:500] → tb tb[:5000] → tb ``` **涉及的代码位置**: - `_background_process` (line ~385) - `_run_analysis_worker` (line ~527) - 任何其他 `tb[:500]` 出现处 ## Final Verification Wave ✅ - [x] F1. pytest tests -q → 121 pass - [x] F2. 清理: 删除临时文件 - [x] F3. 完整端到端测试: 启动服务 → 上传 CSV → 预处理 → 手动分析 → 聚类 → 地球 --- ## 依赖 全部独立,可并行执行。