646 lines
13 KiB
Markdown
646 lines
13 KiB
Markdown
# 调试记录
|
||
|
||
## 特殊参数显示问题
|
||
|
||
### 问题描述
|
||
|
||
在数据管理页面中,装备详情对话框的特殊参数部分显示为空行或不显示。
|
||
|
||
### 调试步骤
|
||
|
||
1. 后端数据查询
|
||
|
||
```sql
|
||
# 测试特殊参数查询
|
||
SELECT equipment_id, param_name, param_value, param_unit
|
||
FROM custom_params
|
||
WHERE param_name IS NOT NULL
|
||
AND param_value IS NOT NULL
|
||
LIMIT 5
|
||
```
|
||
|
||
2. 日志记录
|
||
|
||
```python
|
||
logging.info(f"Getting details for equipment ID: {id}")
|
||
logging.info(f"Equipment type: {equipment_type}")
|
||
logging.info(f"Found equipment details: {result['name']}")
|
||
logging.info(f"Custom params: {result.get('custom_params')}")
|
||
```
|
||
|
||
3. 前端调试
|
||
|
||
```javascript
|
||
console.log('Requesting details for row:', row)
|
||
console.log('Details response:', response.data)
|
||
console.log('Custom params:', response.data.custom_params)
|
||
console.log('Selected data:', selectedData.value)
|
||
```
|
||
|
||
### 关键发现
|
||
|
||
1. 数据库查询
|
||
|
||
- 特殊参数表中有数据
|
||
- JSON_ARRAYAGG 返回的格式需要处理
|
||
- 需要过滤掉 NULL 值
|
||
|
||
2. 数据格式
|
||
|
||
- 后端返回的特殊参数是 JSON 字符串
|
||
- 需要在前端解析为数组
|
||
- 确保数组不为空
|
||
|
||
3. 前端渲染
|
||
|
||
- 条件判断需要更严格
|
||
- 需要确保数据类型正确
|
||
- 需要正确格式化显示值
|
||
|
||
### 解决方案
|
||
|
||
1. 后端查询优化
|
||
|
||
```sql
|
||
(
|
||
SELECT JSON_ARRAYAGG(
|
||
JSON_OBJECT(
|
||
'id', csp.id,
|
||
'param_name', csp.param_name,
|
||
'param_value', csp.param_value,
|
||
'param_unit', csp.param_unit,
|
||
'description', csp.description
|
||
)
|
||
)
|
||
FROM custom_params csp
|
||
WHERE csp.equipment_id = e.id
|
||
AND csp.param_name IS NOT NULL
|
||
AND csp.param_value IS NOT NULL
|
||
) as custom_params
|
||
```
|
||
|
||
2. 前端数据处理
|
||
|
||
```javascript
|
||
// 确保 custom_params 是数组
|
||
if (typeof response.data.custom_params === 'string') {
|
||
response.data.custom_params = JSON.parse(response.data.custom_params)
|
||
}
|
||
```
|
||
|
||
3. 渲染条件优化
|
||
|
||
```vue
|
||
<template v-if="selectedData?.custom_params && Array.isArray(selectedData.custom_params) && selectedData.custom_params.length > 0">
|
||
```
|
||
|
||
### 最佳实践
|
||
|
||
1. 数据库查询
|
||
|
||
- 使用子查询而不是 JOIN 获取特殊参数
|
||
- 确保返回格式统一
|
||
- 过滤无效数据
|
||
|
||
2. 数据处理
|
||
|
||
- 统一数据格式
|
||
- 处理空值和异常
|
||
- 保持类型一致
|
||
|
||
3. 前端显示
|
||
|
||
- 严格的条件判断
|
||
- 类型检查
|
||
- 格式化显示
|
||
|
||
4. 调试方法
|
||
|
||
- 使用日志跟踪数据流
|
||
- 检查数据格式和类型
|
||
- 验证每个环节的数据
|
||
|
||
## 编辑对话框问题
|
||
|
||
### 问题描述
|
||
|
||
在数据管理页面中,编辑对话框的成本信息分区和特殊参数分区显示不正确。
|
||
|
||
### 调试步骤
|
||
|
||
1. 检查数据流
|
||
|
||
```javascript
|
||
console.log('Editing row:', row)
|
||
console.log('Edit data response:', response.data)
|
||
console.log('Parsed custom params:', data.custom_params)
|
||
console.log('Edit form data:', editForm.value)
|
||
```
|
||
|
||
2. 检查模板结构
|
||
|
||
```vue
|
||
<!-- 错误的嵌套结构 -->
|
||
<el-form>
|
||
<template>
|
||
<el-divider>成本信息</el-divider>
|
||
</template>
|
||
</el-form>
|
||
|
||
<!-- 正确的结构 -->
|
||
<el-divider>成本信息</el-divider>
|
||
<el-form>
|
||
<!-- 表单项 -->
|
||
</el-form>
|
||
```
|
||
|
||
### 关键发现
|
||
|
||
1. 模板结构问题
|
||
|
||
- el-divider 不应该嵌套在 template 中
|
||
- 每个分区需要独立的 el-form
|
||
- 避免不必要的 template 嵌套
|
||
|
||
2. 数据类型问题
|
||
|
||
- 后端返回的数值是字符串类型
|
||
- el-input-number 组件需要数值类型
|
||
- 需要在前端进行类型转换
|
||
|
||
3. 条件渲染问题
|
||
|
||
- v-if 条件过于严格可能导致内容不显示
|
||
- 某些字段应该始终显示
|
||
- 某些字段只在有值时显示
|
||
|
||
### 解决方案
|
||
|
||
1. 修改模板结构
|
||
|
||
```vue
|
||
<!-- 成本信息 -->
|
||
<el-divider content-position="left">成本信息</el-divider>
|
||
<el-form :model="editForm" label-width="120px">
|
||
<el-form-item label="实际成本(元)">
|
||
<el-input-number v-model="editForm.actual_cost"></el-input-number>
|
||
</el-form-item>
|
||
</el-form>
|
||
```
|
||
|
||
2. 数据类型转换
|
||
|
||
```javascript
|
||
// 转换所有数值类型字段
|
||
Object.keys(data).forEach(key => {
|
||
if (isNumberInput(key) && data[key] !== null && data[key] !== undefined) {
|
||
data[key] = Number(data[key])
|
||
}
|
||
})
|
||
```
|
||
|
||
3. 优化条件渲染
|
||
|
||
```vue
|
||
<!-- 始终显示必要字段 -->
|
||
<el-form-item label="实际成本(元)">
|
||
<el-input-number v-model="editForm.actual_cost"></el-input-number>
|
||
</el-form-item>
|
||
|
||
<!-- 只在有值时显示可选字段 -->
|
||
<el-form-item label="预测成本(元)" v-if="editForm.predicted_cost">
|
||
<el-input-number v-model="editForm.predicted_cost" disabled></el-input-number>
|
||
</el-form-item>
|
||
```
|
||
|
||
### 最佳实践
|
||
|
||
1. 模板结构
|
||
|
||
- 保持清晰的分区结构
|
||
- 避免不必要的嵌套
|
||
- 使用合适的组件层级
|
||
|
||
2. 数据处理
|
||
|
||
- 在获取数据后立即进行类型转换
|
||
- 确保数据类型与组件要求匹配
|
||
- 处理好空值和未定义值
|
||
|
||
3. 条件渲染
|
||
|
||
- 合理使用 v-if 和 v-show
|
||
- 必要字段始终显示
|
||
- 可选字段根据条件显示
|
||
|
||
4. 调试方法
|
||
|
||
- 使用 console.log 跟踪数据流
|
||
- 检查组件的属性要求
|
||
- 验证数据类型和结构
|
||
|
||
## 特征分析功能问题
|
||
|
||
### 问题描述
|
||
|
||
特征分析页面中,第一次点击分析按钮时,图表不显示,只有标题栏。第二次点击才能正常显示图表。
|
||
|
||
### 调试步骤
|
||
|
||
1. 检查数据流
|
||
|
||
```javascript
|
||
console.log('Analysis result:', analysisResult.value)
|
||
console.log('Charts not ready:', {
|
||
importanceChartRef: !!importanceChartRef.value,
|
||
correlationChartRef: !!correlationChartRef.value,
|
||
analysisResult: !!analysisResult.value
|
||
})
|
||
```
|
||
|
||
2. 检查渲染时机
|
||
|
||
```javascript
|
||
// 使用 watch 监听分析结果变化
|
||
watch(() => analysisResult.value, async (newResult) => {
|
||
if (newResult) {
|
||
await nextTick()
|
||
setTimeout(() => {
|
||
renderCharts()
|
||
}, 100)
|
||
}
|
||
}, { deep: true })
|
||
```
|
||
|
||
3. 检查图表实例管理
|
||
|
||
```javascript
|
||
// 销毁旧的图表实例
|
||
if (importanceChart.value) {
|
||
importanceChart.value.dispose()
|
||
}
|
||
if (correlationChart.value) {
|
||
correlationChart.value.dispose()
|
||
}
|
||
```
|
||
|
||
### 关键发现
|
||
|
||
1. 渲染时机问题
|
||
|
||
- DOM 元素可能还未准备好
|
||
- 数据更新后需要等待 DOM 更新
|
||
- 需要正确管理图表实例
|
||
|
||
2. 图表实例管理
|
||
|
||
- 需要保存图表实例的引用
|
||
- 重新渲染前需要销毁旧实例
|
||
- 组件卸载时需要清理实例
|
||
|
||
3. 数据格式问题
|
||
|
||
- 特征名称需要中文映射
|
||
- 相关性数据需要保留2位小数
|
||
- 需要正确处理缺失值
|
||
|
||
### 解决方案
|
||
|
||
1. 优化渲染逻辑
|
||
|
||
```javascript
|
||
// 使用 nextTick 和延时确保 DOM 已更新
|
||
await nextTick()
|
||
setTimeout(() => {
|
||
renderCharts()
|
||
}, 100)
|
||
```
|
||
|
||
2. 完善图表实例管理
|
||
|
||
```javascript
|
||
// 保存图表实例的引用
|
||
const importanceChart = ref(null)
|
||
const correlationChart = ref(null)
|
||
|
||
// 组件卸载时清理
|
||
onUnmounted(() => {
|
||
importanceChart.value?.dispose()
|
||
correlationChart.value?.dispose()
|
||
})
|
||
```
|
||
|
||
3. 优化数据处理
|
||
|
||
```javascript
|
||
// 使用中文特征名
|
||
chinese_feature_names = [self.feature_names_map.get(name, name) for name in feature_names]
|
||
|
||
// 保留2位小数
|
||
correlation_data.append([
|
||
i, j,
|
||
round(correlation_matrix[i][j], 2)
|
||
])
|
||
```
|
||
|
||
### 最佳实践
|
||
|
||
1. 渲染控制
|
||
|
||
- 使用 watch 监听数据变化
|
||
- 使用 nextTick 等待 DOM 更新
|
||
- 添加适当的延时确保渲染
|
||
|
||
2. 实例管理
|
||
|
||
- 保存图表实例引用
|
||
- 及时销毁旧实例
|
||
- 组件卸载时清理
|
||
|
||
3. 数据处理
|
||
|
||
- 统一使用中文特征名
|
||
- 控制数值精度
|
||
- 处理好缺失值
|
||
|
||
4. 调试方法
|
||
|
||
- 添加详细的日志记录
|
||
- 检查 DOM 元素状态
|
||
- 验证数据格式
|
||
|
||
## 页面状态保持问题
|
||
|
||
### 问题描述
|
||
|
||
特征分析<EFBFBD><EFBFBD><EFBFBD>面切换到其他页面后再返回,页面状态(分析结果和图表)会丢失,需要重新分析。
|
||
|
||
### 调试步骤
|
||
|
||
1. 检查路由配置
|
||
|
||
```javascript
|
||
// 错误的配置
|
||
<keep-alive include="AnalysisPage">
|
||
<router-view></router-view>
|
||
</keep-alive>
|
||
|
||
// 正确的配置
|
||
<router-view v-slot="{ Component }">
|
||
<keep-alive>
|
||
<component :is="Component" :key="$route.fullPath" />
|
||
</keep-alive>
|
||
</router-view>
|
||
```
|
||
|
||
2. 检查组件定义
|
||
|
||
```javascript
|
||
// 错误的组件名称定义
|
||
<script setup name="AnalysisPage">
|
||
|
||
// 正确的组件名称定义
|
||
const __name = 'AnalysisPage'
|
||
```
|
||
|
||
### 关键发现
|
||
|
||
1. keep-alive 配置问题
|
||
|
||
- 需要使用 v-slot API
|
||
- 需要使用动态组件
|
||
- 需要添加 key 属性
|
||
|
||
2. 组件定义问题
|
||
|
||
- setup 语法糖不支持直接添加 name
|
||
- 需要使用 __name 或 defineOptions
|
||
|
||
3. 缓存范围问题
|
||
|
||
- 不需要指定 include 属性
|
||
- 缓存所有路由组件更简单
|
||
- 避免组件名称不匹配的问题
|
||
|
||
### 解决方案
|
||
|
||
1. 修改路由视图配置
|
||
|
||
```vue
|
||
<router-view v-slot="{ Component }">
|
||
<keep-alive>
|
||
<component :is="Component" :key="$route.fullPath" />
|
||
</keep-alive>
|
||
</router-view>
|
||
```
|
||
|
||
2. 修改组件定义
|
||
|
||
```javascript
|
||
const __name = 'AnalysisPage'
|
||
```
|
||
|
||
### 最佳实践
|
||
|
||
1. 路由配置
|
||
|
||
- 使用 Vue3 的新 API
|
||
- 保持配置简单清晰
|
||
- 避免不必要的限制
|
||
|
||
2. 组件定义
|
||
|
||
- 使用推荐的方式定义组件名
|
||
- 避免使用已废弃的语法
|
||
- 保持代码一致性
|
||
|
||
3. 状态管理
|
||
|
||
- 合理使用 keep-alive
|
||
- 正确处理组件生命周期
|
||
- 注意清理工作
|
||
|
||
4. 调试方法
|
||
|
||
- 检查组件是否被缓存
|
||
- 验证状态是否保持
|
||
- 确认生命周期钩子的执行
|
||
|
||
## 代码修改最佳实践
|
||
|
||
### 1. 修改前的准备
|
||
|
||
1. 检查相关文件:
|
||
|
||
```
|
||
前端组件修改时检查:
|
||
- 相关的路由配置
|
||
- 父子组件关系
|
||
- 共用的组件和函数
|
||
- API调用
|
||
|
||
后端接口修改时检查:
|
||
- 路由定义
|
||
- 数据库查询
|
||
- 相关的工具类和函数
|
||
- 错误处理
|
||
```
|
||
|
||
2. 保持命名一致性:
|
||
|
||
```
|
||
- 类名:ModelTrainer 而不是 ModelTraining
|
||
- 文件名:train_model.py 对应 ModelTrainer
|
||
- 变量名:保持前后端一致的命名规范
|
||
```
|
||
|
||
3. 添加日志记录:
|
||
|
||
```python
|
||
# 在关键节点添加日志
|
||
logging.info(f"Starting model training for {equipment_type}")
|
||
logging.info(f"Training dataset: {train_dataset_id}")
|
||
logging.error(f"Error in model training: {str(e)}")
|
||
```
|
||
|
||
### 2. 修改过程中
|
||
|
||
1. 错误处理:
|
||
|
||
```python
|
||
try:
|
||
# 主要逻辑
|
||
except Exception as e:
|
||
logging.error(f"Error: {str(e)}")
|
||
logging.error("Detailed traceback:", exc_info=True)
|
||
return jsonify({'error': str(e)}), 500
|
||
```
|
||
|
||
2. 数据验证:
|
||
|
||
```python
|
||
# 验证输入
|
||
if not formData.value.type:
|
||
throw new Error('请选择装备类型')
|
||
if not formData.value.train_dataset_id:
|
||
throw new Error('请选择训练数据集')
|
||
```
|
||
|
||
3. 状态管理:
|
||
|
||
```javascript
|
||
// 重置状态
|
||
formData.value.train_dataset_id = null
|
||
formData.value.validation_dataset_id = null
|
||
trainingResult.value = null
|
||
```
|
||
|
||
### 3. 修改后的验证
|
||
|
||
1. 功能测试:
|
||
|
||
```
|
||
- 验证主要功能
|
||
- 测试边界条件
|
||
- 检查错误处理
|
||
```
|
||
|
||
2. 性能检查:
|
||
|
||
```
|
||
- 检查数据库查询性能
|
||
- 验证前端渲染性能
|
||
- 确认内存使用情况
|
||
```
|
||
|
||
3. 代码质量:
|
||
|
||
```
|
||
- 检查代码风格
|
||
- 确保注释完整
|
||
- 验证类型定义
|
||
```
|
||
|
||
### 4. 文档更新
|
||
|
||
1. 更新调试文档:
|
||
|
||
```
|
||
- 记录问题原因
|
||
- 描述解决方案
|
||
- 添加最佳实践
|
||
```
|
||
|
||
2. 更新设计文档:
|
||
|
||
```
|
||
- 更新接口定义
|
||
- 修改数据结构
|
||
- 补充新功能说明
|
||
```
|
||
|
||
3. 更新注释:
|
||
|
||
```
|
||
- 添加函数说明
|
||
- 说明参数用途
|
||
- 解释复杂逻辑
|
||
```
|
||
|
||
## 模型训练结果
|
||
|
||
从最新的训练结果来看:
|
||
|
||
1. XGBoost 表现最好:
|
||
- 训练集 R² = 0.4346,没有过拟合
|
||
- 验证集 R² = 0.3625,表现最稳定
|
||
- MAE = 0.60,RMSE = 0.61,预测误差较小
|
||
2. LightGBM 表现次之:
|
||
- 训练集 R² = 0.5277,轻微过拟合
|
||
- 验证集 R² = 0.1101,泛化能力一般
|
||
- MAE = 0.55,RMSE = 0.72,预测误差适中
|
||
3. Random Forest:
|
||
- 训练集 R² = 0.7756,存在过拟合
|
||
- 验证集 R² = 0.3189,泛化能力还可以
|
||
- MAE = 0.47,RMSE = 0.63,预测误差较小
|
||
4. GBDT 过拟合严重:
|
||
- 训练集 R² = 0.9700,严重过拟合
|
||
- 验证集 R² = -1.3133,泛化能力很差
|
||
- MAE = 0.96,RMSE = 1.17,预测误差大
|
||
|
||
### 建议
|
||
|
||
1. 使用 XGBoost 作为主要模型
|
||
2. 可以考虑集成 XGBoost 和 Random Forest
|
||
3. 继续调整 LightGBM 的参数
|
||
4. 暂时不使用 GBDT
|
||
|
||
### 数据集存在的问题
|
||
|
||
火箭炮数据集:
|
||
|
||
- Feature length_m missing rate: 0.00%
|
||
- Feature width_m missing rate: 9.09%
|
||
- Feature height_m missing rate: 9.09%
|
||
- Feature weight_kg missing rate: 0.00%
|
||
- Feature max_range_km missing rate: 45.45%
|
||
- Feature firing_angle_horizontal missing rate: 45.45%
|
||
- Feature firing_angle_vertical missing rate: 45.45%
|
||
- Feature rocket_length_m missing rate: 72.73%
|
||
- Feature rocket_diameter_mm missing rate: 0.00%
|
||
- Feature rocket_weight_kg missing rate: 72.73%
|
||
- Feature rate_of_fire missing rate: 54.55%
|
||
|
||
巡飞弹数据集:
|
||
|
||
- Feature length_m missing rate: 27.78%
|
||
- Feature width_m missing rate: 50.00%
|
||
- Feature height_m missing rate: 50.00%
|
||
- Feature weight_kg missing rate: 22.22%
|
||
- Feature max_range_km missing rate: 44.44%
|
||
- Feature wingspan_m missing rate: 50.00%
|
||
- Feature warhead_weight_kg missing rate: 77.78%
|
||
- Feature max_speed_ms missing rate: 77.78%
|
||
- Feature cruise_speed_kmh missing rate: 61.11%
|
||
- Feature flight_time_min missing rate: 33.33%
|