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

541 lines
13 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. **物流信息存储** - 将快递100查询结果存储到数据库
2. **自动更新机制** - 定时自动查询更新物流状态
3. **状态变更检测** - 监控物流状态变化
4. **异常通知** - 签收、异常时自动通知
5. **查询日志** - 记录所有查询请求和响应
### 数据库表结构
| 表名 | 说明 | 用途 |
|------|------|------|
| zyt_express_tracking | 物流追踪主表 | 存储快递单基本信息和当前状态 |
| zyt_express_trace | 物流轨迹明细表 | 存储每条物流轨迹记录 |
| zyt_express_state_log | 状态变更记录表 | 记录状态变化历史 |
| zyt_express_query_log | 查询日志表 | 记录所有查询请求 |
---
## 安装步骤
### 1. 创建数据库表
```bash
# 执行SQL脚本
mysql -u root -p your_database < server/database/migrations/create_express_tracking_tables.sql
```
或在数据库管理工具中执行 `create_express_tracking_tables.sql` 文件。
### 2. 注册定时任务命令
`server/config/console.php` 中添加:
```php
'commands' => [
// ... 其他命令
'express:auto-update' => \app\command\ExpressAutoUpdate::class,
],
```
### 3. 配置crontab定时任务
```bash
# 编辑crontab
crontab -e
# 添加以下行(每10分钟执行一次)
*/10 * * * * cd /path/to/your/server && php think express:auto-update >> /dev/null 2>&1
```
### 4. 测试定时任务
```bash
cd server
php think express:auto-update
```
应该看到输出:
```
开始自动更新物流信息...
更新完成!
总数: 0
成功: 0
失败: 0
耗时: 0.05秒
```
---
## 使用方法
### 1. 创建物流追踪
当订单发货时,创建物流追踪记录:
```php
use app\common\service\ExpressTrackingService;
// 创建追踪记录
$tracking = ExpressTrackingService::createOrUpdate([
'order_id' => 123, // 订单ID
'order_type' => 'prescription', // 订单类型
'tracking_number' => 'JD0230761381812', // 快递单号
'express_company' => 'jd', // 快递公司
'recipient_phone' => '13800138000', // 收件人手机
'recipient_name' => '张三', // 收件人姓名
'recipient_address' => '北京市朝阳区xxx', // 收件地址
]);
// 系统会立即查询一次物流信息并存储
```
### 2. 手动更新物流信息
```php
// 更新指定追踪记录
$result = ExpressTrackingService::queryAndUpdate($trackingId, false);
```
### 3. 获取物流详情
```php
// 获取完整的物流信息(包含轨迹)
$detail = ExpressTrackingService::getDetail($trackingId);
// 返回数据包含:
// - 基本信息
// - 当前状态
// - 所有轨迹记录
// - 状态变更历史
```
### 4. 自动更新配置
```php
// 修改更新间隔(秒)
$tracking->update_interval = 1800; // 30分钟
$tracking->save();
// 停止自动更新
$tracking->auto_update = 0;
$tracking->save();
// 启用自动更新
$tracking->auto_update = 1;
$tracking->next_update_time = time(); // 立即更新
$tracking->save();
```
---
## 集成到现有订单系统
### 修改订单创建/编辑逻辑
`PrescriptionOrderLogic.php` 中:
```php
public static function create(array $params, int $adminId, array $adminInfo)
{
// ... 原有创建逻辑
$order->save();
// 创建物流追踪
if (!empty($params['tracking_number'])) {
ExpressTrackingService::createOrUpdate([
'order_id' => $order->id,
'order_type' => 'prescription',
'tracking_number' => $params['tracking_number'],
'express_company' => $params['express_company'] ?? 'auto',
'recipient_phone' => $order->recipient_phone,
'recipient_name' => $order->recipient_name,
'recipient_address' => $order->shipping_address,
]);
}
return $out;
}
public static function edit(array $params, int $adminId, array $adminInfo)
{
// ... 原有编辑逻辑
// 更新物流追踪
if (array_key_exists('tracking_number', $params)) {
if (!empty($params['tracking_number'])) {
ExpressTrackingService::createOrUpdate([
'order_id' => $order->id,
'order_type' => 'prescription',
'tracking_number' => $params['tracking_number'],
'express_company' => $order->express_company,
'recipient_phone' => $order->recipient_phone,
'recipient_name' => $order->recipient_name,
'recipient_address' => $order->shipping_address,
]);
}
}
return $out;
}
```
### 修改物流查询接口
`PrescriptionOrderLogic.php` 中:
```php
public static function logisticsTrace(int $id, string $expressCompanyOverride, int $adminId, array $adminInfo): ?array
{
// ... 原有逻辑
// 先从数据库获取
$tracking = ExpressTracking::where('order_id', $id)
->where('order_type', 'prescription')
->whereNull('delete_time')
->find();
if ($tracking) {
// 如果距离上次查询超过5分钟,重新查询
if (time() - $tracking->last_query_time > 300) {
ExpressTrackingService::queryAndUpdate($tracking->id, false);
$tracking->refresh();
}
// 返回数据库中的数据
$payload = [
'carrier' => $tracking->express_company,
'carrier_label' => $tracking->express_company_name,
'kuaidi_com' => $tracking->express_company,
'traces' => $tracking->traces->map(function($trace) {
return [
'time' => $trace->trace_time,
'context' => $trace->trace_context,
'status' => $trace->status,
'location' => $trace->location,
];
})->toArray(),
'state' => $tracking->current_state,
'state_text' => $tracking->current_state_text,
'source' => $tracking->data_source,
'hint' => '',
'official_url' => ExpressTrackService::officialUrls($tracking->tracking_number)[$tracking->express_company] ?? '',
'official_urls' => ExpressTrackService::officialUrls($tracking->tracking_number),
'tracking_number' => $tracking->tracking_number,
'express_company_used' => $tracking->express_company,
'is_signed' => $tracking->is_signed,
'sign_time' => $tracking->sign_time,
'estimated_arrival_time' => $tracking->estimated_arrival_time,
];
return $payload;
}
// 如果数据库中没有,走原有逻辑
// ... 原有查询逻辑
}
```
---
## 自动更新机制
### 更新策略
1. **创建时立即查询** - 创建追踪记录时立即查询一次
2. **定时自动更新** - 每10分钟检查一次需要更新的记录
3. **智能更新间隔** - 默认30分钟更新一次
4. **终态停止更新** - 签收、退签、拒签后停止自动更新
### 更新间隔建议
| 物流状态 | 更新间隔 | 说明 |
|---------|---------|------|
| 已下单/待揽收 | 30分钟 | 等待揽收 |
| 已揽收/在途 | 30分钟 | 运输中 |
| 派件中 | 15分钟 | 即将签收,加快更新 |
| 已签收 | 停止 | 终态,无需更新 |
| 疑难/异常 | 60分钟 | 降低频率 |
### 定时任务配置
```bash
# 每10分钟执行一次(推荐)
*/10 * * * * cd /path/to/server && php think express:auto-update
# 每5分钟执行一次(高频)
*/5 * * * * cd /path/to/server && php think express:auto-update
# 每30分钟执行一次(低频)
*/30 * * * * cd /path/to/server && php think express:auto-update
```
---
## 状态变更通知
### 通知触发条件
1. **签收通知** - 快递签收时通知
2. **异常通知** - 出现疑难、拒签等异常时通知
3. **状态变更** - 每次状态变化都会记录
### 通知渠道(可扩展)
#### 1. 企业微信通知
```php
// 在 ExpressTrackingService::sendNotification() 中实现
use app\common\service\WechatWorkService;
WechatWorkService::sendMessage([
'touser' => $userId,
'msgtype' => 'text',
'text' => [
'content' => "【物流通知】\n" .
"快递单号:{$tracking->tracking_number}\n" .
"状态变更:{$log->old_state_text}{$log->new_state_text}\n" .
"最新动态:{$log->change_reason}"
]
]);
```
#### 2. 短信通知
```php
// 对接短信服务商
SmsService::send($tracking->recipient_phone, [
'template' => 'express_status_change',
'params' => [
'tracking_number' => $tracking->tracking_number,
'status' => $log->new_state_text,
]
]);
```
#### 3. 系统内通知
```php
// 创建系统通知记录
NoticeService::create([
'user_id' => $userId,
'title' => '物流状态更新',
'content' => "您的快递 {$tracking->tracking_number}{$log->new_state_text}",
]);
```
---
## 数据统计和分析
### 查询统计
```sql
-- 查询成功率
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
GROUP BY date
ORDER BY date DESC;
-- 平均响应时间
SELECT
query_source,
AVG(response_time) as avg_response_time,
MAX(response_time) as max_response_time
FROM zyt_express_query_log
WHERE is_success = 1
GROUP BY query_source;
```
### 物流状态分布
```sql
-- 当前物流状态分布
SELECT
current_state,
current_state_text,
COUNT(*) as count
FROM zyt_express_tracking
WHERE delete_time IS NULL
GROUP BY current_state, current_state_text
ORDER BY count DESC;
-- 签收率统计
SELECT
DATE(FROM_UNIXTIME(sign_time)) as date,
COUNT(*) as signed_count
FROM zyt_express_tracking
WHERE is_signed = 1
GROUP BY date
ORDER BY date DESC;
```
### 异常统计
```sql
-- 异常快递统计
SELECT
tracking_number,
express_company_name,
current_state_text,
latest_trace_context,
FROM_UNIXTIME(update_time) as update_time
FROM zyt_express_tracking
WHERE current_state IN ('2', '13', '14') -- 疑难、清关异常、拒签
AND delete_time IS NULL
ORDER BY update_time DESC;
```
---
## 性能优化
### 1. 批量更新优化
```php
// 每次处理50条记录
ExpressTrackingService::autoUpdateBatch(50);
// 根据服务器性能调整
// - 性能好:100条
// - 性能一般:50条
// - 性能差:20条
```
### 2. 查询频率控制
```php
// 避免频繁查询同一单号
if (time() - $tracking->last_query_time < 300) {
// 5分钟内不重复查询
return $cachedResult;
}
```
### 3. 索引优化
数据库表已创建必要索引:
- `idx_order_id` - 订单ID索引
- `idx_auto_update` - 自动更新索引
- `idx_tracking_number` - 快递单号索引
### 4. 数据清理
```sql
-- 清理90天前的查询日志
DELETE FROM zyt_express_query_log
WHERE create_time < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 90 DAY));
-- 清理已签收超过30天的轨迹明细
DELETE t FROM zyt_express_trace t
INNER JOIN zyt_express_tracking tr ON t.tracking_id = tr.id
WHERE tr.is_signed = 1
AND tr.sign_time < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY));
```
---
## 监控和告警
### 1. 监控指标
- 自动更新成功率
- 平均响应时间
- 异常快递数量
- 查询失败率
### 2. 告警规则
```php
// 在定时任务中添加告警逻辑
$result = ExpressTrackingService::autoUpdateBatch(50);
if ($result['failed'] > $result['success'] * 0.5) {
// 失败率超过50%,发送告警
AlertService::send('物流自动更新失败率过高', $result);
}
```
---
## 常见问题
### Q1: 定时任务不执行?
**检查步骤:**
1. 确认crontab已配置:`crontab -l`
2. 检查PHP路径:`which php`
3. 检查项目路径是否正确
4. 查看cron日志:`tail -f /var/log/cron`
### Q2: 更新频率太高,快递100余额消耗快?
**解决方案:**
1. 增加更新间隔:`update_interval = 3600`1小时)
2. 减少批量处理数量:`autoUpdateBatch(20)`
3. 签收后立即停止更新
4. 使用智能更新策略
### Q3: 如何查看某个快递的完整历史?
```php
$detail = ExpressTrackingService::getDetail($trackingId);
// 包含:
// - traces: 所有轨迹记录
// - state_logs: 状态变更历史
```
### Q4: 如何手动触发更新?
```php
// 方法1:通过服务类
ExpressTrackingService::queryAndUpdate($trackingId, false);
// 方法2:通过命令行
php think express:auto-update
```
---
## 总结
### 优势
1. **数据持久化** - 所有物流信息存储在数据库,随时查询
2. **自动更新** - 无需手动查询,系统自动追踪
3. **状态监控** - 实时监控物流状态变化
4. **异常通知** - 及时发现和处理异常
5. **数据分析** - 支持物流数据统计分析
### 成本
1. **快递100费用** - 按查询次数计费
2. **服务器资源** - 定时任务占用少量CPU和内存
3. **数据库存储** - 需要额外的存储空间
### 建议
1. **充值快递100** - 确保有足够余额
2. **合理设置更新间隔** - 平衡实时性和成本
3. **定期清理数据** - 避免数据库膨胀
4. **监控运行状态** - 及时发现问题
---
## 相关文档
- `LOGISTICS_INTEGRATION_GUIDE.md` - 物流集成指南
- `KUAIDI100_ACCOUNT_ISSUE.md` - 快递100账号问题
- `JTEXPRESS_SUPPORT_ADDED.md` - 极兔速递支持