Files
zyt/EXPRESS_TRACKING_FIXES.md
T
2026-04-07 18:13:03 +08:00

366 lines
7.4 KiB
Markdown
Raw 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.
# 物流追踪系统 - 问题修复
## 已修复的问题
### 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账号问题