# 物流追踪系统 - 问题修复 ## 已修复的问题 ### 1. 命令未注册错误 ✅ **问题:** ``` [InvalidArgumentException] There are no commands defined in the "express" namespace. ``` **原因:** 命令未在 `server/config/console.php` 中注册。 **解决方案:** 已在 `server/config/console.php` 中添加命令注册: ```php 'commands' => [ // ... 其他命令 'express:auto-update' => 'app\command\ExpressAutoUpdate', ], ``` **验证:** ```bash cd server php think express:auto-update ``` --- ### 2. 已签收订单过滤优化 ✅ **问题:** 定时任务可能会处理已签收的快递,浪费查询次数。 **解决方案:** 优化了 `ExpressTrackingService::autoUpdateBatch()` 方法的查询条件: ```php $list = ExpressTracking::where('auto_update', 1) ->where('next_update_time', '<=', $now) ->where('is_signed', 0) // 【新增】未签收 ->whereNotIn('current_state', [ // 【新增】排除终态 ExpressTracking::STATE_SIGNED, // 已签收 ExpressTracking::STATE_RETURN_SIGNED, // 退签 ExpressTracking::STATE_REJECTED, // 拒签 ]) ->whereNull('delete_time') ->limit($limit) ->select(); ``` **过滤规则:** | 条件 | 说明 | |------|------| | `auto_update = 1` | 启用自动更新 | | `next_update_time <= now` | 到达更新时间 | | `is_signed = 0` | 未签收 | | `current_state NOT IN (3,4,14)` | 排除终态(已签收、退签、拒签) | | `delete_time IS NULL` | 未删除 | **会被处理的状态:** - 0: 在途 - 1: 揽收 - 2: 疑难 - 5: 派件中 - 6: 退回 - 7: 转投 - 8: 清关 - 10: 待清关 - 11: 清关中 - 12: 已清关 - 13: 清关异常 **不会被处理的状态:** - 3: 已签收 ❌ - 4: 退签 ❌ - 14: 拒签 ❌ --- ## 自动停止更新机制 ### 触发条件 当快递状态变为以下任一状态时,系统会自动停止更新: ```php // 在 ExpressTrackingService::queryAndUpdate() 中 if (ExpressTracking::isFinalState($tracking->current_state)) { $tracking->is_signed = 1; $tracking->sign_time = $now; $tracking->auto_update = 0; // 自动停止更新 } ``` ### 终态判断 ```php public static function isFinalState(string $state): bool { return in_array($state, [ self::STATE_SIGNED, // 3: 已签收 self::STATE_RETURN_SIGNED, // 4: 退签 self::STATE_REJECTED, // 14: 拒签 ], true); } ``` --- ## 双重保护机制 系统采用双重保护,确保已签收的快递不会被重复查询: ### 第一层:查询时过滤 在 `autoUpdateBatch()` 方法中,查询时就排除了终态订单: ```php ->where('is_signed', 0) ->whereNotIn('current_state', ['3', '4', '14']) ``` ### 第二层:更新时自动停止 在 `queryAndUpdate()` 方法中,当检测到签收时自动停止: ```php if (ExpressTracking::isFinalState($tracking->current_state)) { $tracking->auto_update = 0; $tracking->save(); } ``` --- ## 测试验证 ### 1. 测试命令注册 ```bash cd server php think list # 应该能看到: # express # express:auto-update 自动更新物流追踪信息 ``` ### 2. 测试过滤逻辑 ```bash cd server php test_express_auto_update.php # 查看输出,确认过滤规则正确 ``` ### 3. 测试实际执行 ```bash cd server php think express:auto-update # 应该看到: # 开始自动更新物流信息... # 更新完成! # 总数: X # 成功: X # 失败: 0 # 耗时: X秒 ``` --- ## 性能优化 ### 查询优化 通过添加过滤条件,减少了不必要的查询: **优化前:** - 查询所有 `auto_update = 1` 的记录 - 包括已签收的快递 - 浪费查询次数 **优化后:** - 只查询未签收且未到达终态的记录 - 自动排除已签收的快递 - 节省查询次数和API费用 ### 索引建议 确保以下字段有索引: ```sql -- 复合索引(最重要) CREATE INDEX idx_auto_update_query ON zyt_express_tracking(auto_update, next_update_time, is_signed, current_state); -- 单字段索引 CREATE INDEX idx_is_signed ON zyt_express_tracking(is_signed); CREATE INDEX idx_current_state ON zyt_express_tracking(current_state); ``` --- ## 监控建议 ### 1. 监控自动更新执行情况 ```bash # 查看定时任务日志 tail -f server/runtime/log/info.log | grep "Auto update" # 查看错误日志 tail -f server/runtime/log/error.log | grep "express" ``` ### 2. 统计查询情况 ```sql -- 查看自动更新的记录数 SELECT COUNT(*) as count FROM zyt_express_tracking WHERE auto_update = 1 AND is_signed = 0 AND current_state NOT IN ('3', '4', '14') AND delete_time IS NULL; -- 查看已签收的记录数 SELECT COUNT(*) as count FROM zyt_express_tracking WHERE is_signed = 1; -- 查看各状态分布 SELECT current_state, current_state_text, COUNT(*) as count, SUM(auto_update) as auto_update_count FROM zyt_express_tracking WHERE delete_time IS NULL GROUP BY current_state, current_state_text ORDER BY count DESC; ``` ### 3. 查询日志分析 ```sql -- 查看最近的查询记录 SELECT tracking_number, query_type, is_success, error_message, FROM_UNIXTIME(query_time) as query_time FROM zyt_express_query_log ORDER BY query_time DESC LIMIT 20; -- 统计自动查询成功率 SELECT DATE(FROM_UNIXTIME(query_time)) as date, COUNT(*) as total, SUM(is_success) as success, ROUND(SUM(is_success) / COUNT(*) * 100, 2) as success_rate FROM zyt_express_query_log WHERE query_type = 'auto' GROUP BY date ORDER BY date DESC LIMIT 7; ``` --- ## 常见问题 ### Q1: 命令执行后显示 "总数: 0"? **A:** 这是正常的,说明: 1. 没有需要更新的快递记录 2. 或所有快递都已签收 3. 或还没到更新时间 **检查:** ```sql SELECT COUNT(*) as total, SUM(CASE WHEN auto_update = 1 THEN 1 ELSE 0 END) as auto_update_enabled, SUM(CASE WHEN is_signed = 1 THEN 1 ELSE 0 END) as signed, SUM(CASE WHEN next_update_time <= UNIX_TIMESTAMP() THEN 1 ELSE 0 END) as need_update FROM zyt_express_tracking WHERE delete_time IS NULL; ``` ### Q2: 已签收的快递还在被查询? **A:** 检查以下几点: 1. 确认代码已更新到最新版本 2. 检查 `is_signed` 字段是否正确设置 3. 检查 `auto_update` 字段是否为 0 **修复:** ```sql -- 手动修复已签收但未停止更新的记录 UPDATE zyt_express_tracking SET auto_update = 0 WHERE current_state IN ('3', '4', '14') AND auto_update = 1; ``` ### Q3: 如何手动停止某个快递的自动更新? **A:** ```sql UPDATE zyt_express_tracking SET auto_update = 0 WHERE tracking_number = 'JD0230761381812'; ``` 或通过代码: ```php $tracking = ExpressTracking::where('tracking_number', 'JD0230761381812')->find(); $tracking->auto_update = 0; $tracking->save(); ``` --- ## 总结 ### 已修复 1. ✅ 命令注册问题 2. ✅ 已签收订单过滤 3. ✅ 双重保护机制 4. ✅ 性能优化 ### 优势 1. **节省费用** - 不查询已签收的快递 2. **提高效率** - 只处理需要更新的记录 3. **自动停止** - 签收后自动停止更新 4. **双重保护** - 查询和更新两层过滤 ### 下一步 1. ✅ 执行 `php think express:auto-update` 测试 2. ✅ 配置crontab定时任务 3. ✅ 监控执行情况 4. ✅ 查看查询日志 --- ## 相关文档 - `EXPRESS_TRACKING_SYSTEM.md` - 完整系统文档 - `EXPRESS_TRACKING_QUICKSTART.md` - 快速开始指南 - `KUAIDI100_ACCOUNT_ISSUE.md` - 快递100账号问题