上传源代码版本

This commit is contained in:
Im-Jenisson
2026-06-01 16:30:29 +08:00
commit b2a9b7d3c2
462 changed files with 104365 additions and 0 deletions

View File

@@ -0,0 +1,185 @@
# 视图逻辑修复方案总结
## 📌 问题回顾
用户反馈数据库视图查询结果大部分为0
```
2026-05-15 | 0 | 3592 | 0 | 3315 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2026-05-16 20:21:40
```
仅有 `DailyShouldReplaceCount`(3592) 和 `CumulativeTotalReplaceCount`(3315) 有数据其他指标全是0。
## 🔍 根本原因分析
### 问题1硬编码NOW()导致的日期比较错误
**原视图SQL片段**
```sql
CAST(CONVERT_TZ(r.CreatedAt, '+00:00', '-05:00') AS DATE) = CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)
```
**问题**:每次查询都与当前时间比较,而不是与查询参数的日期比较。
**影响**
- 查询2026-05-15的数据时条件自动比较为"2026-05-15是否等于今天"
- 由于2026-05-15不等于今天的日期所以大部分WHERE条件都返回FALSE
- 导致除了依赖其他条件的指标外,大部分指标都被过滤掉了
### 问题2JOIN关联逻辑不合理
**原视图**使用 `OR` 条件进行关联:
```sql
r.BillOfLadingNumber = ahf.HandoverNumber OR r.MasterPackageNumber = ahf.HandoverNumber
```
虽然这个关联本身可以工作,但与硬编码的时间比较配合,导致很多联接行被意外过滤。
### 问题3时区转换过度使用
多次重复的 `CONVERT_TZ()` 调用导致:
- SQL语句复杂性增加
- 性能下降
- 维护困难
## ✨ 修复方案
### 采用方案存储过程Stored Procedure
**关键改进**
1. **参数化日期输入**
- 从硬编码 `NOW()` 改为接受 `p_date` 参数
- 支持查询任意历史日期
2. **简化时区转换**
- 在存储过程开始时一次性计算日期范围v_date_start, v_date_end
- 后续查询直接使用这些变量,避免重复转换
3. **优化JOIN逻辑**
- 使用临时表 `temp_qualified_arrivals` 预先计算标签率≥80%的交接单
- 后续查询直接JOIN临时表提高查询效率
4. **清晰的指标计算**
- 每个指标独立计算使用SELECT...INTO语句
- 便于调试和验证
### 存储过程核心逻辑
```sql
CREATE PROCEDURE sp_GetDailyMetricsSummary(IN p_date DATE)
-- 1. 计算UTC-5时区的日期范围
SET v_date_start = CONVERT_TZ(CONCAT(DATE(p_date), ' 00:00:00'), '-05:00', '+00:00');
SET v_date_end = CONVERT_TZ(CONCAT(DATE(p_date), ' 23:59:59'), '-05:00', '+00:00');
-- 2. 创建临时表存储标签率≥80%的交接单
CREATE TEMPORARY TABLE temp_qualified_arrivals AS
SELECT ... FROM arrival_handover_forms ... HAVING labeled_orders / total_orders >= 0.8;
-- 3. 基于临时表和时间范围计算各项指标
SELECT COUNT(...) INTO v_daily_should_replace_count ...
SELECT COUNT(...) INTO v_daily_success_count ...
-- ... 其他指标 ...
-- 4. 返回所有指标结果
SELECT ... AS MetricsDate, v_daily_new_replace_count AS DailyNewReplaceCount, ...
```
## 📊 预期改进
### 性能改进
- **原方案**11个独立异步查询耗时15-30秒
- **新方案**:单个存储过程调用,目标<1秒
- **性能提升**15-30倍
### 正确性改进
- **原问题**大多数指标返回0
- **修复后**各指标返回合理的非零值
- **根本原因**移除了硬编码的NOW()导致的日期比较错误
### 灵活性改进
- **原方案**视图固定查询当前日期
- **新方案**可查询任意历史日期
- **支持**报表趋势分析等需要历史数据的功能
## 🔧 实现变更
### 1. 数据库变更
📄 文件`database/migrations/002_create_sp_daily_metrics_summary.sql`
- 创建存储过程 `sp_GetDailyMetricsSummary`
- 接收参数`p_date DATE`
- 返回13个指标列
### 2. 应用层变更
📄 文件`src/BLL/Services/MetricsCalculationService.cs`
- 第462行修改 `GetDailySummaryAsync()` 方法
- `SELECT * FROM v_DailyMetricsSummary WHERE MetricsDate = '{date}'`
- 改为 `CALL sp_GetDailyMetricsSummary('{date:yyyy-MM-dd}')`
### 3. 降级方案保留
- 保留原有的 `GetDailySummaryAsync_Original()` 方法
- 如果存储过程调用失败自动降级到11个独立查询
- 确保系统可用性
## 📝 验证步骤
### 数据库层验证
1. 执行存储过程创建脚本
2. 执行 `CALL sp_GetDailyMetricsSummary('2026-05-15')`
3. 验证返回数据
- DailyShouldReplaceCount 3592
- CumulativeTotalReplaceCount 3315
- 其他指标 > 0 ✅
### 应用层验证
1. 重新编译并运行后端服务
2. 调用 API`GET /api/metrics/daily-dashboard?date=2026-05-15`
3. 验证JSON响应包含所有指标
### 前端验证
1. 打开仪表盘:`http://localhost:5002/metrics-dashboard-summary.html`
2. 选择日期 2026-05-15
3. 验证显示的指标正确性
### 性能验证
1. 使用浏览器开发者工具查看API响应时间
2. 应该 < 1000ms1秒
## 🎯 后续可选优化
1. **缓存层**添加Redis缓存避免频繁查询相同日期
2. **物化视图**定期生成历史数据快照
3. **分析表**预生成常用报表的汇总数据
4. **分区**按日期分区arrival_handover_forms表
## 📋 关键指标定义(业务规则)
### DailyShouldReplaceCount
- 当日到仓且标签率80%的订单总数
- 业务含义当天应该执行的换单操作数
### DailySuccessCount
- 当日成功扫描的订单数Result=0
- 业务含义当天完成的换单操作数
### CumulativeTotalReplaceCount
- 截至前一天未成功扫描的订单数
- 业务含义历史待处理的订单数
### BeforeNoonArrivedCount / AfternoonArrivedCount
- 按16:00时间点划分的到仓订单
- 业务含义区分早班和晚班处理的订单
### 完成率计算
- DailyCompletionRate = DailySuccessCount / DailyShouldReplaceCount * 100%
- 指标类型百分比,≥95%为绿色85-95%为黄色<85%为红色
## ✅ 完成检查清单
- [x] 分析根本原因
- [x] 设计解决方案
- [x] 编写存储过程SQL
- [x] 修改应用层代码
- [x] 准备执行说明文档
- [ ] **用户执行**在数据库中创建存储过程
- [ ] **测试**验证存储过程返回正确数据
- [ ] **集成**前端调用验证
- [ ] **性能**确认查询时间<1秒