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

7.4 KiB
Raw Blame History

物流追踪系统 - 问题修复

已修复的问题

1. 命令未注册错误

问题:

[InvalidArgumentException]
There are no commands defined in the "express" namespace.

原因: 命令未在 server/config/console.php 中注册。

解决方案: 已在 server/config/console.php 中添加命令注册:

'commands' => [
    // ... 其他命令
    'express:auto-update' => 'app\command\ExpressAutoUpdate',
],

验证:

cd server
php think express:auto-update

2. 已签收订单过滤优化

问题: 定时任务可能会处理已签收的快递,浪费查询次数。

解决方案: 优化了 ExpressTrackingService::autoUpdateBatch() 方法的查询条件:

$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: 拒签

自动停止更新机制

触发条件

当快递状态变为以下任一状态时,系统会自动停止更新:

// 在 ExpressTrackingService::queryAndUpdate() 中
if (ExpressTracking::isFinalState($tracking->current_state)) {
    $tracking->is_signed = 1;
    $tracking->sign_time = $now;
    $tracking->auto_update = 0; // 自动停止更新
}

终态判断

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() 方法中,查询时就排除了终态订单:

->where('is_signed', 0)
->whereNotIn('current_state', ['3', '4', '14'])

第二层:更新时自动停止

queryAndUpdate() 方法中,当检测到签收时自动停止:

if (ExpressTracking::isFinalState($tracking->current_state)) {
    $tracking->auto_update = 0;
    $tracking->save();
}

测试验证

1. 测试命令注册

cd server
php think list

# 应该能看到:
# express
#   express:auto-update  自动更新物流追踪信息

2. 测试过滤逻辑

cd server
php test_express_auto_update.php

# 查看输出,确认过滤规则正确

3. 测试实际执行

cd server
php think express:auto-update

# 应该看到:
# 开始自动更新物流信息...
# 更新完成!
# 总数: X
# 成功: X
# 失败: 0
# 耗时: X秒

性能优化

查询优化

通过添加过滤条件,减少了不必要的查询:

优化前:

  • 查询所有 auto_update = 1 的记录
  • 包括已签收的快递
  • 浪费查询次数

优化后:

  • 只查询未签收且未到达终态的记录
  • 自动排除已签收的快递
  • 节省查询次数和API费用

索引建议

确保以下字段有索引:

-- 复合索引(最重要)
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. 监控自动更新执行情况

# 查看定时任务日志
tail -f server/runtime/log/info.log | grep "Auto update"

# 查看错误日志
tail -f server/runtime/log/error.log | grep "express"

2. 统计查询情况

-- 查看自动更新的记录数
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. 查询日志分析

-- 查看最近的查询记录
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. 或还没到更新时间

检查:

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

修复:

-- 手动修复已签收但未停止更新的记录
UPDATE zyt_express_tracking
SET auto_update = 0
WHERE current_state IN ('3', '4', '14')
AND auto_update = 1;

Q3: 如何手动停止某个快递的自动更新?

A:

UPDATE zyt_express_tracking
SET auto_update = 0
WHERE tracking_number = 'JD0230761381812';

或通过代码:

$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账号问题