297 lines
8.1 KiB
Markdown
297 lines
8.1 KiB
Markdown
# Supabase Auth ID 与业务用户 ID 映射修复
|
||
|
||
## 问题根因
|
||
|
||
前端和后端混用了两套 ID:
|
||
|
||
| ID 类型 | 来源 | 示例 | 用途 |
|
||
| -------------------- | -------------------------------- | -------------------------------------- | ----------------- |
|
||
| **Supabase Auth ID** | `session.user.id` / `auth.uid()` | `311860b5-d99f-478f-b1ac-3ef1cc55ae07` | Supabase 认证系统 |
|
||
| **业务用户 ID** | `public.ak_users.id` | `2a97a39f-4efc-40c6-a065-55a2484e3784` | 所有业务表 |
|
||
|
||
**所有业务表都应该使用业务用户 ID**:
|
||
|
||
- `ec_care_tasks.assigned_to`
|
||
- `hc_dispatch_assignments.worker_id`
|
||
- `hc_worker_locations.worker_id`
|
||
- `hc_evidence_files.uploader_id`
|
||
- `hss_service_orders.current_staff_id`
|
||
|
||
## 数据库映射关系
|
||
|
||
```sql
|
||
-- ak_users 表结构
|
||
SELECT id, auth_id, username, email, role, user_type, status
|
||
FROM public.ak_users;
|
||
|
||
-- 示例数据
|
||
-- id: 2a97a39f-4efc-40c6-a065-55a2484e3784 (业务用户 ID)
|
||
-- auth_id: 311860b5-d99f-478f-b1ac-3ef1cc55ae07 (Supabase Auth ID)
|
||
-- username: 居家服务员
|
||
-- email: homecare_worker@test.com
|
||
-- role: delivery
|
||
```
|
||
|
||
## 修改文件清单
|
||
|
||
### 1. 新增文件
|
||
|
||
#### `utils/akUserMapping.uts`
|
||
|
||
- **作用**:管理 Supabase Auth ID 到业务用户 ID 的映射
|
||
- **核心函数**:
|
||
- `loadCurrentAkUser()` - 登录后加载 ak_users 映射
|
||
- `getCurrentAkUserId()` - 获取当前业务用户 ID
|
||
- `getCurrentAkUser()` - 获取当前业务用户完整信息
|
||
- `getCurrentAuthUserId()` - 获取当前 Supabase Auth ID
|
||
- `debugCurrentUser()` - 调试输出当前用户信息
|
||
|
||
### 2. 修改文件
|
||
|
||
#### `utils/homecareAuth.uts`
|
||
|
||
**修改前**:
|
||
|
||
```uts
|
||
const session = supa.getSession()
|
||
const workerId = session != null && session.user != null ? session.user.getString('id') : ''
|
||
```
|
||
|
||
**修改后**:
|
||
|
||
```uts
|
||
import { getCurrentAkUserId } from '@/utils/akUserMapping.uts'
|
||
|
||
const workerId = await getCurrentAkUserId()
|
||
```
|
||
|
||
**原因**:签到预校验 RPC 需要业务用户 ID,不是 Supabase Auth ID
|
||
|
||
#### `pages/user/login.uvue`
|
||
|
||
**新增**:
|
||
|
||
```uts
|
||
import { loadCurrentAkUser } from '@/utils/akUserMapping.uts'
|
||
|
||
// 登录成功后
|
||
await loadCurrentAkUser()
|
||
```
|
||
|
||
**原因**:登录后立即加载 ak_users 映射,存储到本地缓存
|
||
|
||
#### `pages/mall/delivery/orders/checkin.uvue`
|
||
|
||
**新增**:
|
||
|
||
```uts
|
||
import { debugCurrentUser } from '@/utils/akUserMapping.uts'
|
||
|
||
// 预校验前
|
||
debugCurrentUser()
|
||
```
|
||
|
||
**原因**:调试输出当前 ak_user 信息,方便排查问题
|
||
|
||
#### `types/delivery.uts`
|
||
|
||
**新增字段**:
|
||
|
||
```uts
|
||
export type DeliveryOrderType = {
|
||
// ... existing fields ...
|
||
acceptedBy: string // 接单人员 ID(业务用户 ID)
|
||
acceptedByName: string // 接单人员姓名
|
||
// ... existing fields ...
|
||
}
|
||
```
|
||
|
||
#### `api/delivery.uts`
|
||
|
||
**修改**:在 `mapRpcOrderItemCompat` 函数中添加接单人员信息提取:
|
||
|
||
```uts
|
||
// 从 statusLog 中提取接单人员信息
|
||
order.acceptedBy = ''
|
||
order.acceptedByName = ''
|
||
const statusLog = order.statusLog
|
||
for (let i = 0; i < statusLog.length; i++) {
|
||
if (statusLog[i].toStatus == 'accepted' || statusLog[i].toStatus == 'pending_accept') {
|
||
order.acceptedBy = statusLog[i].operatorId != '' ? statusLog[i].operatorId : order.deliveryStaffId
|
||
order.acceptedByName = statusLog[i].operatorRole != '' ? statusLog[i].operatorRole : order.deliveryStaffName
|
||
break
|
||
}
|
||
}
|
||
```
|
||
|
||
#### `pages/mall/delivery/orders/index.uvue`
|
||
|
||
**新增**:订单卡片上显示接单人员
|
||
|
||
```html
|
||
<text v-if="item.acceptedByName != ''" class="meta-text accepted-by"
|
||
>接单人:{{ item.acceptedByName }}</text
|
||
>
|
||
```
|
||
|
||
#### `pages/mall/delivery/orders/detail.uvue`
|
||
|
||
**新增**:服务人员信息卡片
|
||
|
||
```html
|
||
<view class="card">
|
||
<text class="section-title">服务人员</text>
|
||
<text class="row-text">配送员:{{ order.deliveryStaffName }}</text>
|
||
<text v-if="order.acceptedByName != ''" class="row-text"
|
||
>接单人:{{ order.acceptedByName }} (ID: {{ order.acceptedBy }})</text
|
||
>
|
||
<text v-if="order.acceptTime != ''" class="row-text"
|
||
>接单时间:{{ formatDateTime(order.acceptTime) }}</text
|
||
>
|
||
</view>
|
||
```
|
||
|
||
## 数据流
|
||
|
||
### 登录流程
|
||
|
||
```
|
||
1. 用户输入邮箱/密码登录
|
||
↓
|
||
2. Supabase Auth 验证,返回 session (authUserId = 311860b5...)
|
||
↓
|
||
3. 调用 loginDelivery() 获取 token 和用户信息
|
||
↓
|
||
4. 调用 loadCurrentAkUser():
|
||
- 从 session 获取 authUserId
|
||
- 查询 ak_users WHERE auth_id = authUserId
|
||
- 获取业务用户 ID (akUserId = 2a97a39f...)
|
||
- 存储到本地缓存
|
||
↓
|
||
5. 登录完成
|
||
```
|
||
|
||
### 签到流程
|
||
|
||
```
|
||
1. 用户点击"距离预校验"
|
||
↓
|
||
2. checkinPrecheck() 调用 getCurrentAkUserId()
|
||
- 从缓存读取 akUserId
|
||
- 如果缓存不存在,自动加载
|
||
↓
|
||
3. 调用 RPC rpc_homecare_checkin_precheck:
|
||
p_worker_id = akUserId (2a97a39f...)
|
||
↓
|
||
4. 后端验证:
|
||
- 查询 ec_care_tasks WHERE id = workOrderId
|
||
- 检查 assigned_to = p_worker_id
|
||
- 如果匹配,返回 canCheckin = true
|
||
↓
|
||
5. 签到成功
|
||
```
|
||
|
||
## 测试步骤
|
||
|
||
### 1. 清除旧缓存
|
||
|
||
在微信开发者工具中:
|
||
|
||
```
|
||
控制台 -> Storage -> 清除所有缓存
|
||
```
|
||
|
||
### 2. 重新登录
|
||
|
||
1. 打开配送端
|
||
2. 使用测试账号登录:
|
||
- 账号:`homecare_worker@test.com`
|
||
- 密码:`Homecare123!`
|
||
3. 登录成功后,控制台应该显示:
|
||
```
|
||
[akUserMapping] 加载业务用户成功: {
|
||
authUserId: '311860b5-d99f-478f-b1ac-3ef1cc55ae07',
|
||
akUserId: '2a97a39f-4efc-40c6-a065-55a2484e3784',
|
||
username: '居家服务员',
|
||
role: 'delivery'
|
||
}
|
||
```
|
||
|
||
### 3. 测试签到
|
||
|
||
1. 进入"待接单"列表
|
||
2. 点击任意订单接单
|
||
3. 进入订单详情
|
||
4. 点击"到达签到"
|
||
5. 点击"距离预校验"
|
||
6. 控制台应该显示:
|
||
```
|
||
[akUserMapping] ========== 当前用户调试信息 ==========
|
||
[akUserMapping] authUserId: 311860b5-d99f-478f-b1ac-3ef1cc55ae07
|
||
[akUserMapping] akUserId: 2a97a39f-4efc-40c6-a065-55a2484e3784
|
||
[akUserMapping] profile: { id: '2a97a39f...', ... }
|
||
[akUserMapping] ======================================
|
||
[CHECKIN RPC] workerId (ak_user_id): 2a97a39f-4efc-40c6-a065-55a2484e3784
|
||
```
|
||
7. 如果 `workerId` 显示的是 `2a97a39f...` 而不是 `311860b5...`,说明修复成功
|
||
|
||
### 4. 验证订单列表
|
||
|
||
1. 订单卡片上应该显示接单人员姓名
|
||
2. 例如:`接单人:居家服务员`
|
||
|
||
## 验收标准
|
||
|
||
- [ ] 登录后 storage 中同时存在:
|
||
- `auth_user_id` = `311860b5...`
|
||
- `ak_user_id` = `2a97a39f...`
|
||
- [ ] `checkin.uvue` 获取定位时使用 gcj02
|
||
- [ ] precheck 调用时 `p_worker_id` 传 `ak_user_id`(2a97a39f...)
|
||
- [ ] 后端返回 `reasonCode` 不再是 `WORKER_NOT_MATCHED`
|
||
- [ ] 数据库 `hc_worker_locations.worker_id` 写入的是 `2a97a39f...`,不是 `311860b5...`
|
||
- [ ] 正式签到 submit 成功后,`hc_work_order_confirmations` 生成 ARRIVAL / PENDING 记录
|
||
- [ ] 现场图片 `hc_evidence_files.uploader_id` 使用 `ak_users.id`
|
||
- [ ] 订单列表显示接单人员姓名
|
||
|
||
## 注意事项
|
||
|
||
1. **不要使用 `session.user.id` 作为业务用户 ID**
|
||
- 错误:`session.user.id` → `311860b5...`
|
||
- 正确:`getCurrentAkUserId()` → `2a97a39f...`
|
||
|
||
2. **所有业务表都使用业务用户 ID**
|
||
- `ec_care_tasks.assigned_to` = `2a97a39f...`
|
||
- `hc_dispatch_assignments.worker_id` = `2a97a39f...`
|
||
|
||
3. **如果 ak_users 映射加载失败**
|
||
- 不影响登录流程
|
||
- 但签到功能会失败
|
||
- 需要联系管理员在 `ak_users.auth_id` 字段绑定 Supabase Auth ID
|
||
|
||
4. **配送员 vs 居家服务员**
|
||
- 配送员:负责配送医药商城的药品、器械
|
||
- 居家服务员:负责居家医疗服务
|
||
- 当前 `ak_users` 中 username 是"居家服务员",role = delivery 只是 delivery 端角色
|
||
- 不等于商城配送员
|
||
|
||
## 回滚方案
|
||
|
||
如果修复后出现问题,可以:
|
||
|
||
1. 清除本地缓存:
|
||
|
||
```
|
||
微信开发者工具 -> Storage -> 清除所有缓存
|
||
```
|
||
|
||
2. 回滚代码:
|
||
|
||
```bash
|
||
git checkout HEAD -- utils/akUserMapping.uts
|
||
git checkout HEAD -- utils/homecareAuth.uts
|
||
git checkout HEAD -- pages/user/login.uvue
|
||
git checkout HEAD -- pages/mall/delivery/orders/checkin.uvue
|
||
```
|
||
|
||
3. 重新编译
|