Files
WQ_GUI/ARCHITECTURE.md
duxin 9e433395f4 feat: 波长偏移修正 + 项目架构文档
- BandMathCalculator 支持 wavelength_offset 参数,公式波长统一加减偏移后匹配传感器波段
- WaterQualityIndexCalculator 全链传递偏移量 (band_math → calculate_one → calculate_many)
- WaterIndexCsvProcessor / Step7Handler / DataPreparationStep 传播偏移参数
- Step7/Step10 面板新增 QDoubleSpinBox 波长偏移控件 (±200nm, 默认0)
- 偏移控件去除单位后缀,避免编辑时需手动移动光标
- 新增 ARCHITECTURE.md 完整项目架构文档
2026-06-30 13:13:38 +08:00

453 lines
24 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.

# WQ_GUI 水质遥感分析系统 — 架构文档
> 生成日期2026-06-30 | 分支Mega2.2 | 步骤数13
---
## 一、项目总览
```
src/
├── gui/
│ ├── water_quality_gui.py # V1 入口
│ ├── water_quality_gui_v2.py # V2 入口(当前主力)
│ ├── styles.py # 全局样式 ModernStylesheet
│ ├── core/
│ │ ├── panel_registry.py # 步骤注册表
│ │ ├── panel_factory.py # 惰性加载面板工厂
│ │ ├── pipeline_executor.py # 流水线调度
│ │ ├── event_bus.py # 全局事件总线
│ │ ├── worker_thread.py # 工作线程
│ │ ├── dependency_subscriber.py # 步骤间依赖自动注入
│ │ └── workspace_initializer.py # 工作区初始化
│ ├── panels/
│ │ ├── _step_path_resolver.py # 路径解析(文件系统扫描)
│ │ ├── step1_panel.py ~ step13_report_panel.py # 13个步骤面板
│ │ └── ...
│ └── components/
│ ├── custom_widgets.py # FileSelectWidget / DirSelectWidget
│ ├── data_models.py # PandasTableModel
│ └── chart_dialogs.py # InteractiveViewerDialog 等
├── core/ # 后端处理引擎
│ ├── handlers/ # 步骤处理器14个
│ ├── steps/ # 步骤算法实现
│ ├── algorithms/ # 核心算法
│ └── pipeline/ # 流水线调度器
├── postprocessing/ # 后处理(可视化、地图、报告)
└── new/ # 新架构(部分迁移中)
```
---
## 二、核心架构机制
### 2.1 事件总线 (EventBus)
全局单例 `global_event_bus`,解耦面板之间及面板与调度器的通信:
| 事件名 | 发布者 | 订阅者 | 用途 |
|---|---|---|---|
| `RequestRunSingleStep` | 各面板 `run_btn` | PipelineExecutor | 单步执行 |
| `OutputUpdated` | 面板输出变化时 | 依赖订阅者 | 自动传播输出路径 |
| `PipelineStarted/Finished/Stopped` | PipelineExecutor | 全局 | 流水线生命周期 |
| `StepCompleted` | WorkerThread | 日志/UI | 单步完成通知 |
| `LogMessage` | 各处 | LogManager | 日志写入 |
| `ProgressUpdate` | WorkerThread | 进度条 | 进度更新 |
| `NavigateToTab` | 各处 | QTabWidget | 标签切换 |
| `WorkspaceChanged` | WorkspaceManager | 全局面板 | 工作目录变更 |
### 2.2 面板工厂 (PanelFactory)
惰性加载机制:启动时仅创建占位 Tab首次切换到某 Tab 时才实例化对应 Panel。
核心方法:
- `get_panel(step_id)` → 返回面板实例(已缓存则直接返回)
- `_ensure_loaded(tab_index)` → 实例化、包装 QScrollArea、替换占位 Tab
- `_replay_state_to_panel(panel)` → 新加载的面板回放上游已产生的输出状态
### 2.3 依赖注入系统
`PANEL_REGISTRY` 中每个步骤定义 `dependencies`
```python
dependencies = {
'target_attr': ('upstream_step_id', 'output_type', 'source_attr')
}
```
`DependencySubscriber` 监听 `OutputUpdated` 事件,自动将上游输出路径填入下游面板的对应输入控件。
`_step_path_resolver.py` 则通过文件系统扫描 + 目录映射表实现回退路径发现。
### 2.4 执行流程
```
用户点击 "独立运行步骤"
→ Panel._on_run_single_clicked()
→ EventBus.publish('RequestRunSingleStep', {step_name, config})
→ PipelineExecutor._on_request_run_single_step()
→ WorkerThread(QThread) 启动
→ PipelineScheduler.run_step(step_key, config)
→ BaseStepHandler.execute(ctx, config)
→ 实际算法逻辑
```
---
## 三、13 个步骤详解
### 模块一影像预处理Steps 1-3
---
#### Step 1 — 水域掩膜生成
| 项目 | 详情 |
|---|---|
| **面板文件** | `src/gui/panels/step1_panel.py` |
| **面板类** | `Step1Panel(QWidget)` |
| **后端处理器** | `src/core/handlers/step1_water_mask.py``Step1WaterMaskHandler` |
| **后端算法** | `src/core/steps/water_mask_step.py``WaterMaskStep` |
| **UI 输入** | `mask_file`(FileSelectWidget) / NDWI 阈值模式:`ndwi_threshold`(QLineEdit, 0.0-1.0), `img_file`(FileSelectWidget) |
| **UI 输出** | `output_file`(FileSelectWidget, mode=save), `run_btn` |
| **上游依赖** | 无 |
| **产出类型** | `reference_img`, `water_mask` |
| **关键方法** | `init_ui()``update_ui_state()` 切换掩膜/NDWI 策略;`get_config()` 返回 `{mask_path, use_ndwi, ndwi_threshold, img_path, output_path}` |
| **目录映射** | `→ 1_water_mask` |
#### Step 2 — 耀斑检测
| 项目 | 详情 |
|---|---|
| **面板文件** | `src/gui/panels/step2_panel.py` |
| **面板类** | `Step2Panel(QWidget)` |
| **后端处理器** | `src/core/handlers/step2_glint_detection.py``Step2GlintDetectionHandler` |
| **后端算法** | `src/core/steps/glint_detection_step.py``GlintDetectionStep` |
| **UI 输入** | `img_file`(FileSelectWidget), `water_mask_file`(FileSelectWidget) |
| **UI 参数** | `glint_wave`(QDoubleSpinBox, 300-1000nm), `method`(QComboBox: Otsu/Z-Score/百分位数/IQR/自适应/多波段综合), `max_area`(QSpinBox), `buffer_size`(QSpinBox) |
| **UI 输出** | `output_file`(FileSelectWidget, mode=save), `run_btn` |
| **上游依赖** | `img_file` ← step1.reference_img; `water_mask_file` ← step1.water_mask |
| **产出类型** | `glint_mask` |
| **目录映射** | `→ 2_Glint_Detection` |
#### Step 3 — 去耀斑
| 项目 | 详情 |
|---|---|
| **面板文件** | `src/gui/panels/step3_panel.py` |
| **面板类** | `Step3Panel(QWidget)` |
| **后端处理器** | `src/core/handlers/step3_glint_removal.py``Step3GlintRemovalHandler` |
| **后端算法** | `src/core/steps/glint_removal_step.py``GlintRemovalStep` |
| **UI 输入** | `img_file`(FileSelectWidget), `water_mask_file`(FileSelectWidget) |
| **UI 参数** | `method`(QComboBox: Goodman/Kutser/Hedley/SUGAR), 4 个 StackedWidget 参数页 + `interpolate_zeros`(QCheckBox), `interp_method`(QComboBox) |
| **UI 输出** | `output_file`(FileSelectWidget), `run_btn` |
| **上游依赖** | `img_file` ← step1.reference_img; `water_mask_file` ← step1.water_mask |
| **产出类型** | `deglint_image` |
| **特殊机制** | `img_file.textChanged` → 自动调用 `_update_band_ranges()` 检测波段范围;`method.currentIndexChanged` → 切换参数 StackedWidget 页面 |
| **目录映射** | `→ 3_deglint` |
---
### 模块二特征工程与数据Steps 4-7
---
#### Step 4 — 采样点布局与交互式探索
| 项目 | 详情 |
|---|---|
| **面板文件** | `src/gui/panels/step4_sampling_panel.py` |
| **面板类** | `Step4SamplingPanel(QWidget)` |
| **后端处理器** | `src/core/handlers/step4_sampling.py``Step4SamplingHandler` |
| **UI 输入** | `deglint_img_file`(FileSelectWidget), `water_mask_file`(FileSelectWidget) |
| **UI 参数** | `interval`(QSpinBox, 10-500px), `sample_radius`(QSpinBox, 1-50px), `chunk_size`(QSpinBox, 100-10000px), `use_adaptive_sampling`(QCheckBox) |
| **UI 输出** | `output_file`(FileSelectWidget), `refresh_btn`, `run_btn` |
| **可视化** | Matplotlib 嵌入:`FigureCanvasQTAgg` + 隐藏 `NavigationToolbar2QT`,左右分栏(散点图 + 光谱曲线),自定义工具栏按钮 |
| **交互** | `_on_hover()` 鼠标变小手 + 悬停标注;`_on_click()` 点击高亮 + 光谱绘制 + 再次点击取消选中;三按钮互斥:👆 点选探针 / ✋ 拖拽漫游 / 🔍 框选放大 |
| **上游依赖** | `deglint_img_file` ← step3.deglint_image; `water_mask_file` ← step1.water_mask |
| **产出类型** | `sampling_points` |
| **特殊机制** | `_status_timer` (5000ms) 自动检测 CSV 并重渲染;`draw_idle()` 防 UI 卡死rcParams 中文字体双重保障 |
| **目录映射** | `→ 4_sampling` |
#### Step 5 — 数据清洗
| 项目 | 详情 |
|---|---|
| **面板文件** | `src/gui/panels/step5_clean_panel.py` |
| **面板类** | `Step5CleanPanel(QWidget)` |
| **后端处理器** | `src/core/handlers/step5_process_csv.py``Step5ProcessCsvHandler` |
| **UI 输入** | `csv_file`(FileSelectWidget) |
| **UI 参数** | `preview_rows_spin`(QSpinBox), `preview_table`(QTableView + PandasTableModel), `preview_status_label`(QLabel) |
| **UI 输出** | `output_file`(FileSelectWidget, mode=save), `run_btn` |
| **上游依赖** | 无(独立输入源) |
| **产出类型** | `processed_data` |
| **目录映射** | `→ 5_Data_Cleaning` |
#### Step 6 — 光谱特征提取
| 项目 | 详情 |
|---|---|
| **面板文件** | `src/gui/panels/step6_feature_panel.py` |
| **面板类** | `Step6FeaturePanel(QWidget)` |
| **后端处理器** | `src/core/handlers/step6_extract_spectra.py``Step6ExtractSpectraHandler` |
| **UI 输入** | `deglint_img_file`(FileSelectWidget), `csv_file`(FileSelectWidget), `water_mask_file`(FileSelectWidget), `glint_mask_file`(FileSelectWidget) |
| **UI 参数** | `radius`(QSpinBox, 1-50px), `source_epsg`(QSpinBox, default 4326) |
| **UI 输出** | `output_file`(FileSelectWidget), `run_btn` |
| **上游依赖** | `deglint_img_file` ← step3; `csv_file` ← step5; `water_mask_file` ← step1; `glint_mask_file` ← step2 |
| **产出类型** | `output_file` |
| **目录映射** | `→ 6_Spectral_Feature_Extraction` |
#### Step 7 — 水质指数计算
| 项目 | 详情 |
|---|---|
| **面板文件** | `src/gui/panels/step7_inversion_panel.py` |
| **面板类** | `Step7InversionPanel(QWidget)` |
| **后端处理器** | `src/core/handlers/step7_calc_indices.py``Step7CalcIndicesHandler` |
| **UI 输入** | `formula_file`(FileSelectWidget, 只读), `training_data_widget`(FileSelectWidget) |
| **UI 参数** | `category_combo`(QComboBox 按类别筛选), `formula_list`(NoScrollPassListWidget, checkable), 选择按钮:全选/清空/比值/浓度/重载 |
| **UI 输出** | `output_file`(FileSelectWidget), `run_btn` |
| **上游依赖** | `training_data_widget` ← step6_feature.output_file |
| **产出类型** | `training_spectra_indices` |
| **特殊机制** | `_load_formulas_from_csv()` 从内置公式库加载;`_update_formula_count()` 统计选中数 |
| **目录映射** | `→ 7_Water_Quality_Indices` |
---
### 模块三模型训练与反演Steps 8-10
---
#### Step 8 — 机器学习建模
| 项目 | 详情 |
|---|---|
| **面板文件** | `src/gui/panels/step8_ml_train_panel.py` |
| **面板类** | `Step8MlTrainPanel(QWidget)` |
| **后端处理器** | `src/core/handlers/step8_ml_train.py``Step8MlTrainHandler` |
| **后端算法** | `src/core/steps/modeling_step.py``ModelingStep` |
| **UI 输入** | `training_csv_file`(FileSelectWidget) |
| **UI 参数** | `feature_start`(QComboBox), `cv_folds`(QSpinBox 2-10), 预处理 11 项 CheckBox(None/MMS/SS/SNV/MA/SG/MSC/D1/D2/DT/CT), 模型 15 项 CheckBox(LR/Ridge/Lasso/ElasticNet/PLS/DT/RF/ExtraTrees/XGBoost/LightGBM/CatBoost/GBDT/AdaBoost/SVR/KNN/MLP), 数据划分 3 项 CheckBox(SPXY/KS/Random) |
| **UI 输出** | `output_path`(FileSelectWidget, 目录模式), `run_btn` |
| **上游依赖** | `training_csv_file` ← step7_index.training_spectra_indices |
| **产出类型** | `output_path` |
| **目录映射** | `→ 8_Supervised_Model_Training` |
#### Step 9 — 机器学习预测
| 项目 | 详情 |
|---|---|
| **面板文件** | `src/gui/panels/step9_ml_predict_panel.py` |
| **面板类** | `Step9MlPredictPanel(QWidget)` |
| **后端处理器** | `src/core/handlers/step9_ml_predict.py``Step9MlPredictHandler` |
| **后端算法** | `src/core/steps/prediction_step.py``PredictionStep` |
| **UI 输入** | `sampling_csv_file`(FileSelectWidget), `models_dir_file`(FileSelectWidget, 目录) |
| **UI 参数** | 模型来源:`use_trained_model`/`use_external_model`(QRadioButton), 外部模型 `model_list`(QListWidget, checkable), `metric`(QComboBox: R²/RMSE/MAE), `prediction_column`(QLineEdit) |
| **UI 输出** | `output_file`(FileSelectWidget, 目录), `run_btn` |
| **上游依赖** | `models_dir_file` ← step8_ml_train.output_path |
| **产出类型** | `output_file` |
| **目录映射** | `→ 9_ML_Prediction` |
#### Step 10 — 水色指数反演
| 项目 | 详情 |
|---|---|
| **面板文件** | `src/gui/panels/step10_watercolor_panel.py` |
| **面板类** | `Step10WatercolorPanel(QWidget)` |
| **后端处理器** | `src/core/handlers/step10_qaa_inversion.py``Step10QaaInversionHandler` |
| **后端算法** | `src/core/algorithms/waterindex_inversion.py``WaterIndexCsvProcessor` |
| **UI 输入** | `formula_file`(FileSelectWidget, 只读), `sampling_csv_file`(FileSelectWidget) |
| **UI 参数** | `category_combo`(QComboBox 按水质类别筛选), `formula_list`(NoScrollPassListWidget, checkable), 全选/清空/比值/浓度按钮 |
| **UI 输出** | `output_dir`(FileSelectWidget, 目录), `progress_bar`(QProgressBar), `progress_label`(QLabel), `run_btn` |
| **上游依赖** | `sampling_csv_file` ← step4_sampling.sampling_points |
| **产出类型** | `output_dir` |
| **特殊机制** | 内嵌 `WaterIndexWorker(QThread)` 后台处理 CSV |
| **目录映射** | `→ 10_WaterIndex_CSV` |
---
### 模块四制图与成果汇编Steps 11-13
---
#### Step 11 — 专题图生成
| 项目 | 详情 |
|---|---|
| **面板文件** | `src/gui/panels/step11_map_panel.py` |
| **面板类** | `Step11MapPanel(QWidget)` |
| **后端处理器** | `src/core/handlers/step11_concentration.py``Step11ConcentrationHandler` |
| **后端算法** | CSV 模式: `src/core/steps/mapping_step.py``MappingStep.generate_distribution_map()`GeoTIFF 模式: `src/postprocessing/map.py``ContentMapper.visualize_raster()` |
| **UI 输入** | `render_mode_combo`(QComboBox: CSV插值/GeoTIFF栅格), `batch_mode_combo`(QComboBox: 单个文件/文件夹批量), `prediction_csv_file`(FileSelectWidget), `geotiff_file`(FileSelectWidget), `boundary_file`(FileSelectWidget: *.shp) |
| **UI 参数** | `resolution`(QDoubleSpinBox, 1-1000), `input_crs`/`output_crs`(QLineEdit, EPSG:32651), `show_points`(QCheckBox), `use_diffusion`(QCheckBox) |
| **UI 输出** | `output_dir`(FileSelectWidget), `progress_bar`(QProgressBar), `run_button` |
| **上游依赖** | `prediction_csv_dir_edit` ← step9; `geotiff_dir_edit` ← step10; `boundary_file` ← step1.water_mask |
| **特殊机制** | 两个后台线程:`Step11MapBatchThread`(CSV) / `Step11GeoTIFFBatchThread`(GeoTIFF) |
| **目录映射** | `→ 14_visualization` |
#### Step 12 — 可视化
| 项目 | 详情 |
|---|---|
| **面板文件** | `src/gui/panels/step12_viz_panel.py` |
| **面板类** | `Step12VizPanel(QWidget)` |
| **后端算法** | `src/postprocessing/visualization_reports.py``WaterQualityVisualization`; `src/core/visualization/scatter_plot.py`; `src/postprocessing/point_map.py``SamplingPointMap` |
| **UI 输入** | `work_dir_edit`(QLineEdit), `img_dir_edit`(QLineEdit) |
| **UI 参数** | 6 个 QCheckBox: `gen_scatter`(模型评估散点图), `gen_spectrum`(光谱曲线), `gen_boxplots`(统计图), `gen_mask_glint`(掩膜缩略图), `gen_sampling_map`(采样点地图), `gen_distribution_map`(空间分布图) |
| **UI 输出** | `gen_all_btn`(QPushButton), `scan_btn`(QPushButton), `ImageCategoryTree`(QTreeWidget), `ImageViewerWidget`(带缩放/平移/保存), 筛选: `view_mode_cb` + `chart_filter_cb` |
| **上游依赖** | 无(文件系统自动扫描) |
| **产出类型** | 多种图表 PNG |
| **特殊机制** | `VisualizationWorkerThread(QThread)` 后台批量生成;`ImageCategoryTree` 三视图模式(按水质参数/图表类型/物理文件夹) |
#### Step 13 — 报告生成
| 项目 | 详情 |
|---|---|
| **面板文件** | `src/gui/panels/step13_report_panel.py` |
| **面板类** | `Step13ReportPanel(QWidget)` |
| **后端算法** | `src/postprocessing/report_word.py``WaterQualityReportGenerator` + `ReportGenerationConfig` |
| **UI 输入** | `work_dir_edit`(QLineEdit, 只读), `output_dir_edit`(QLineEdit + 浏览) |
| **UI 参数** | `report_title_edit`(QLineEdit), `enable_ai_cb`(QCheckBox), AI 设置按钮 → `AISettingsDialog` |
| **UI 输出** | `progress_label`(QLabel), `progress_bar`(QProgressBar), `generate_btn`(QPushButton) |
| **上游依赖** | 无(但需要 `main_window` 在构造时注入) |
| **产出类型** | Word 报告 (.docx) |
| **特殊机制** | `ReportWorkerThread(QThread)` 后台生成AI 分析可选(需配置 API Key |
| **目录映射** | `→ reports` |
---
## 四、步骤间数据流转图
```
Step1 水域掩膜 ─── img_file ───────────────┬──► Step2 耀斑检测 ── glint_mask ──► Step6
│ │
├── water_mask ──────────────────────┼──► Step3 去耀斑 ─── deglint ────► Step4
│ │ │ │
│ │ └───────────────────────────┤
│ │ │
│ ├──► Step4 采样 ←────────────────────┘
│ ├──► Step6 特征提取
│ ├──► Step11 专题图 ───► Step12
│ └──► Step12 可视化 Step13
└──► Step11 专题图(边界)
Step4 采样 ── sampling_csv ──► Step10 水色指数 ── output_dir ──► Step11(GeoTIFF)
Step5 清洗 ── csv ──► Step6 特征提取 ── output ──► Step7 指数计算
Step8 机器学习建模
Step9 机器学习预测
Step11 专题图(CSV)
```
---
## 五、自定义组件
### 5.1 文件选择控件
**`FileSelectWidget`** (`src/gui/components/custom_widgets.py`)
| 模式 | 行为 |
|---|---|
| `mode="open"` | `QFileDialog.getOpenFileName()` — 选择已存在文件 |
| `mode="save"` | `QFileDialog.getSaveFileName()` — 选择保存路径 |
| `mode="dir"` | `QFileDialog.getExistingDirectory()` — 选择目录 |
关键方法:`get_path()`, `set_path(path)`, `set_read_only(bool)`, `line_edit.textChanged` 信号
### 5.2 路径解析器
**`_step_path_resolver.py`** — 所有 13 个 Panel 统一通过 `from src.gui.panels._step_path_resolver import ...` 导入
| 函数 | 用途 |
|---|---|
| `resolve_subdir(work_dir, subdir_key)` | 步骤名 → 实际子目录路径 |
| `scan_work_dir_for_input(work_dir, output_type)` | 文件系统扫描发现上游输出 |
| `resolve_step_widget(main_window, step_key, widget_attr)` | 通过 panel_factory 定位上游控件 |
| `get_step_output_path(main_window, step_key, work_dir, widget_attr, fallback_key)` | 获取上游输出路径(含回退) |
### 5.3 全局样式
**`ModernStylesheet`** (`src/gui/styles.py`) — 提供 `get_button_stylesheet('normal'|'primary')`
---
## 六、关键设计模式
| 模式 | 位置 | 说明 |
|---|---|---|
| **惰性加载** | PanelFactory | Tab 切换时才实例化 Panel降低启动时间 |
| **事件总线** | EventBus | Panel ↔ PipelineExecutor 解耦通信 |
| **依赖注入** | DependencySubscriber + PANEL_REGISTRY | 上游输出自动填入下游输入 |
| **文件系统回退** | _step_path_resolver | 当依赖注入失败时,扫描实际文件系统 |
| **独立运行** | 每个 Panel 的 `run_btn` | 不依赖全流水线,可单独执行 |
| **后台线程** | WorkerThread / 各 Panel 内嵌 QThread | 长时间计算不阻塞 GUI |
| **交互模式** | Step4 三按钮互斥 | 点选探针 / 拖拽漫游 / 框选放大 |
---
## 七、文件清单
### 前端面板13 个)
| 文件 | 类 | Step ID |
|---|---|---|
| `step1_panel.py` | `Step1Panel` | `step1` |
| `step2_panel.py` | `Step2Panel` | `step2` |
| `step3_panel.py` | `Step3Panel` | `step3` |
| `step4_sampling_panel.py` | `Step4SamplingPanel` | `step4_sampling` |
| `step5_clean_panel.py` | `Step5CleanPanel` | `step5_clean` |
| `step6_feature_panel.py` | `Step6FeaturePanel` | `step6_feature` |
| `step7_inversion_panel.py` | `Step7InversionPanel` | `step7_index` |
| `step8_ml_train_panel.py` | `Step8MlTrainPanel` | `step8_ml_train` |
| `step9_ml_predict_panel.py` | `Step9MlPredictPanel` | `step9_ml_predict` |
| `step10_watercolor_panel.py` | `Step10WatercolorPanel` | `step10_watercolor` |
| `step11_map_panel.py` | `Step11MapPanel` | `step11_map` |
| `step12_viz_panel.py` | `Step12VizPanel` | `step12_viz` |
| `step13_report_panel.py` | `Step13ReportPanel` | `step13_report` |
### 后端核心14 个 Handler
| 文件 | 类 | Step Key |
|---|---|---|
| `handlers/step1_water_mask.py` | `Step1WaterMaskHandler` | `step1` |
| `handlers/step2_glint_detection.py` | `Step2GlintDetectionHandler` | `step2` |
| `handlers/step3_glint_removal.py` | `Step3GlintRemovalHandler` | `step3` |
| `handlers/step4_sampling.py` | `Step4SamplingHandler` | `step4_sampling` |
| `handlers/step5_process_csv.py` | `Step5ProcessCsvHandler` | `step5_clean` |
| `handlers/step6_extract_spectra.py` | `Step6ExtractSpectraHandler` | `step6_feature` |
| `handlers/step7_calc_indices.py` | `Step7CalcIndicesHandler` | `step7_index` |
| `handlers/step8_ml_train.py` | `Step8MlTrainHandler` | `step8_ml_train` |
| `handlers/step9_ml_predict.py` | `Step9MlPredictHandler` | `step9_ml_predict` |
| `handlers/step10_qaa_inversion.py` | `Step10QaaInversionHandler` | `step10_qaa_inversion` |
| `handlers/step11_concentration.py` | `Step11ConcentrationHandler` | `step11_concentration` |
| `handlers/step12_kriging.py` | `Step12KrigingHandler` | `step12_kriging` |
| `handlers/step13_visualization.py` | `Step13VisualizationHandler` | `step13_visualization` |
| `handlers/step14_report.py` | `Step14ReportHandler` | `step14_report` |
> Handler 注册有 14 个step1-14对应 Panel 有 13 个step1-13。Step12 的 Handler 处理克里金插值Step13 的 Handler 处理可视化Step14 的 Handler 处理报告。
---
## 八、审计修复记录2026-06-30
本轮已修复的全部问题:
| # | 严重度 | 文件 | 问题 | 修复 |
|---|---|---|---|---|
| 1 | 🔴 | `step11_map_panel.py:652` | `mapper` 在 import 之前引用 | 移动 import 至引用上方 |
| 2 | 🟡 | `step12_viz_panel.py:1719` | `get_panel('step1_mask')` key 不存在 | 改为 `'step1'` |
| 3 | 🟡 | `step3_panel.py:384` | `currentData()` 返回 None | 改为 `currentText()` |
| 4 | 🟡 | `step5_clean_panel.py:228/253` | PandasTableModel 从 v1 入口导入 | 改为 `src.gui.components.data_models` |
| 5 | 🟡 | `step3_panel.py:271` | InteractiveViewerDialog 同上 | 改为 `src.gui.components.chart_dialogs` |
| 6 | 🟢 | `step7_inversion_panel.py:9` | `import csv` 未使用 | 移除 |
| 7 | 🟢 | `step5_clean_panel.py:167` | 死方法 `_add_row_with_fixed_label` | 标注废弃 |
| 8 | 🟢 | 全部 12 个 Panel | `_step_path_resolver` 导入风格不一致 | 统一为 `from src.gui.panels._step_path_resolver import ...`,移除 `_HERE`/`sys.path` hack |