185 lines
5.8 KiB
Markdown
185 lines
5.8 KiB
Markdown
# 派单失败问题修复指南
|
||
|
||
## 问题概述
|
||
|
||
用户下单支付后,派单返回 `ALL_ELIGIBLE_STAFF_BUSY`(当前可服务人员均在忙),导致无法成功派单。
|
||
|
||
## 根本原因
|
||
|
||
### 原因 1:订单缺少服务经纬度(已修复)
|
||
|
||
**问题**:`createServiceOrder` 函数在创建订单时,没有将地址的经纬度写入 `service_lat` 和 `service_lng` 字段。
|
||
|
||
**影响**:
|
||
- 派单 RPC 无法计算人员距离
|
||
- 距离筛选条件失效
|
||
- 可能匹配到远距离人员
|
||
|
||
**修复**:`serviceOrderService.uts` 第 1181-1182 行新增:
|
||
```typescript
|
||
service_lat: params.address.latitude != null ? params.address.latitude : null,
|
||
service_lng: params.address.longitude != null ? params.address.longitude : null,
|
||
```
|
||
|
||
### 原因 2:时间冲突检查过于严格(待数据库执行)
|
||
|
||
**问题**:原 RPC 函数中,当订单 `scheduled_start_at` 或 `scheduled_end_at` 为 `NULL` 时,时间冲突检查条件会**跳过比较**,但 `NOT EXISTS` 子查询仍然会排除**任何有活跃任务**的人员。
|
||
|
||
**原逻辑**(第 633-655 行):
|
||
```sql
|
||
AND NOT EXISTS (
|
||
SELECT 1
|
||
FROM hss_service_assignments existing_assignment
|
||
JOIN hss_service_orders existing_order
|
||
ON existing_order.id = existing_assignment.order_id
|
||
WHERE existing_assignment.staff_id::TEXT = s.id::TEXT
|
||
AND existing_assignment.deleted_at IS NULL
|
||
AND existing_assignment.status IN ('assigned', 'accepted', ...)
|
||
AND (
|
||
v_order.scheduled_start_at IS NULL -- 如果订单没有时间
|
||
OR v_order.scheduled_end_at IS NULL -- 则跳过比较
|
||
OR ...时间重叠判断...
|
||
)
|
||
)
|
||
```
|
||
|
||
**问题**:当 `v_order.scheduled_start_at IS NULL` 时,整个 `AND` 条件变为 `TRUE`,导致**所有有活跃任务的人员都被排除**。
|
||
|
||
**修复**:新增优化版 RPC `rpc_homecare_auto_dispatch_optimized`,只有当订单有**明确时间范围**时才检查时间冲突。
|
||
|
||
## 修复步骤
|
||
|
||
### 第一步:执行诊断脚本(可选,用于确认问题)
|
||
|
||
在 Supabase SQL Editor 中执行:
|
||
```
|
||
mall_sql/diagnostics/dispatch_failure_diagnosis.sql
|
||
```
|
||
|
||
重点关注:
|
||
1. 问题订单的 `service_lat`/`service_lng` 是否为 `NULL`
|
||
2. 有哪些服务人员在忙(有活跃派单记录)
|
||
|
||
### 第二步:修复历史订单的经纬度
|
||
|
||
在 Supabase SQL Editor 中执行:
|
||
```
|
||
mall_sql/migrations/20260610_fix_service_order_coordinates.sql
|
||
```
|
||
|
||
此脚本会:
|
||
1. 统计有多少订单缺少经纬度
|
||
2. 从 `address_snapshot_json` 中提取经纬度并更新到主表字段
|
||
|
||
### 第三步:部署优化版派单 RPC
|
||
|
||
在 Supabase SQL Editor 中执行:
|
||
```
|
||
mall_sql/migrations/20260610_optimize_dispatch_conflict_check.sql
|
||
```
|
||
|
||
此脚本会创建新的 RPC 函数 `rpc_homecare_auto_dispatch_optimized`。
|
||
|
||
### 第四步:切换使用优化版 RPC ✅ 已完成
|
||
|
||
修改前端调用优化版 RPC 函数。
|
||
|
||
**文件**:`serviceOrderService.uts` 第 1015 行
|
||
|
||
**修改前**:
|
||
```typescript
|
||
const { data, error } = await supa.rpc('rpc_homecare_auto_dispatch', {
|
||
p_order_id: orderId
|
||
} as any)
|
||
```
|
||
|
||
**修改后**:
|
||
```typescript
|
||
const { data, error } = await supa.rpc('rpc_homecare_auto_dispatch_optimized', {
|
||
p_order_id: orderId
|
||
} as any)
|
||
```
|
||
|
||
> ✅ 此步骤已完成,前端已切换使用优化版 RPC。
|
||
|
||
## 验证方法
|
||
|
||
### 1. 检查订单经纬度是否已填充
|
||
|
||
```sql
|
||
SELECT
|
||
id,
|
||
service_lat,
|
||
service_lng,
|
||
address_snapshot_json->>'latitude' as address_lat,
|
||
address_snapshot_json->>'longitude' as address_lng
|
||
FROM public.hss_service_orders
|
||
WHERE id = 'so-1781054320183-35441';
|
||
```
|
||
|
||
### 2. 查看在线服务人员状态
|
||
|
||
```sql
|
||
SELECT
|
||
id,
|
||
online_status,
|
||
station_id,
|
||
current_lat,
|
||
current_lng,
|
||
(SELECT COUNT(*)
|
||
FROM hss_service_assignments sa
|
||
JOIN hss_service_orders so ON so.id = sa.order_id
|
||
WHERE sa.staff_id::TEXT = s.id::TEXT
|
||
AND sa.deleted_at IS NULL
|
||
AND sa.status IN ('assigned', 'accepted', 'departed', 'arrived', 'serving', 'in_service')
|
||
) as active_tasks
|
||
FROM ml_delivery_staff s
|
||
WHERE deleted_at IS NULL
|
||
AND status = 1
|
||
AND COALESCE(is_active, TRUE) = TRUE
|
||
ORDER BY online_status DESC, active_tasks ASC;
|
||
```
|
||
|
||
### 3. 前端测试流程
|
||
|
||
1. 重新下单支付
|
||
2. 查看控制台日志,应看到:
|
||
- `[homecare-dispatch] RPC response:` - RPC 原始返回
|
||
- `[homecare-dispatch] Parsed result:` - 解析后的结果
|
||
- `[confirmPayment] 派单结果:` - 支付页派单结果
|
||
|
||
### 4. 预期结果
|
||
|
||
**修复前**:
|
||
```
|
||
code: "ALL_ELIGIBLE_STAFF_BUSY"
|
||
message: "当前可服务人员均在忙,请稍后重新派单"
|
||
```
|
||
|
||
**修复后**(如果有在线空闲人员):
|
||
```
|
||
code: "DISPATCH_ASSIGNED"
|
||
message: "系统已为您匹配服务人员"
|
||
dispatch_status: "assigned"
|
||
```
|
||
|
||
## 文件清单
|
||
|
||
| 文件 | 说明 |
|
||
|------|------|
|
||
| `services/serviceOrderService.uts` | ✅ 已修改:订单创建时填充经纬度 |
|
||
| `pages/mall/consumer/payment.uvue` | ✅ 已修改:增加派单日志 |
|
||
| `pages/mall/consumer/home-service/order-detail.uvue` | ✅ 已修改:增加派单日志 |
|
||
| `pages/mall/consumer/orders.uvue` | ✅ 已修改:增加派单日志 |
|
||
| `services/serviceOrderService.uts` | ✅ 已修改:区分显示5种失败原因 |
|
||
| `mall_sql/diagnostics/dispatch_failure_diagnosis.sql` | 📋 诊断脚本(可选执行) |
|
||
| `mall_sql/migrations/20260610_fix_service_order_coordinates.sql` | 🔧 修复历史订单经纬度 |
|
||
| `mall_sql/migrations/20260610_optimize_dispatch_conflict_check.sql` | 🔧 优化版派单 RPC |
|
||
|
||
## 后续优化建议
|
||
|
||
1. **订单创建时设置预约时间范围**:将 `appointment_time` 转换为 `scheduled_start_at` 和 `scheduled_end_at`
|
||
2. **服务人员位置实时更新**:确保 delivery 端定期上报当前位置
|
||
3. **派单失败重试策略**:增加指数退避重试,避免频繁调用
|
||
4. **监控告警**:当派单失败率超过阈值时发送告警
|