完成距离预校验
This commit is contained in:
@@ -29,10 +29,12 @@ const DELIVERY_RPC_DASHBOARD = 'rpc_delivery_dashboard'
|
||||
const DELIVERY_RPC_ORDER_LIST = 'rpc_delivery_order_list'
|
||||
const DELIVERY_RPC_ORDER_DETAIL = 'rpc_delivery_order_detail'
|
||||
const DELIVERY_RPC_ACCEPT_ORDER = 'rpc_delivery_accept_order'
|
||||
const DELIVERY_RPC_HOMECARE_ACCEPT_ASSIGNMENT_V2 = 'rpc_homecare_accept_assignment_v2'
|
||||
const DELIVERY_RPC_REJECT_ORDER = 'rpc_delivery_reject_order'
|
||||
const DELIVERY_RPC_START_DEPART = 'rpc_delivery_start_depart'
|
||||
const DELIVERY_RPC_ARRIVE_ORDER = 'rpc_delivery_arrive_order'
|
||||
const DELIVERY_RPC_CHECKIN_ORDER = 'rpc_delivery_checkin_order'
|
||||
const DELIVERY_RPC_HOMECARE_CHECKIN_SUBMIT = 'rpc_homecare_checkin_submit'
|
||||
const DELIVERY_RPC_START_SERVICE = 'rpc_delivery_start_service'
|
||||
const DELIVERY_RPC_SAVE_PROGRESS = 'rpc_delivery_save_progress'
|
||||
const DELIVERY_RPC_UPLOAD_EVIDENCE = 'rpc_delivery_upload_evidence'
|
||||
@@ -2109,6 +2111,20 @@ export async function acceptDeliveryOrderById(orderId: string): Promise<Delivery
|
||||
return await fallbackAcceptOrder(orderId)
|
||||
}
|
||||
|
||||
/**
|
||||
* 居家服务接单 RPC:rpc_homecare_accept_assignment_v2
|
||||
* 参数:p_work_order_id, p_worker_id (akUserId)
|
||||
*/
|
||||
export async function acceptHomecareAssignmentV2(workOrderId: string, workerId: string): Promise<UTSJSONObject | null> {
|
||||
console.warn('[HOMECARE ACCEPT] 调用 rpc_homecare_accept_assignment_v2, workOrderId=', workOrderId, ' workerId=', workerId)
|
||||
const rpcData = await callDeliveryRpc(DELIVERY_RPC_HOMECARE_ACCEPT_ASSIGNMENT_V2, {
|
||||
p_work_order_id: workOrderId,
|
||||
p_worker_id: workerId
|
||||
} as UTSJSONObject)
|
||||
console.warn('[HOMECARE ACCEPT] rpc_homecare_accept_assignment_v2 result:', rpcData)
|
||||
return rpcData as UTSJSONObject | null
|
||||
}
|
||||
|
||||
export async function rejectDeliveryOrderById(orderId: string, reason: string): Promise<DeliveryOrderType | null> {
|
||||
const rpcData = await callDeliveryRpc(DELIVERY_RPC_REJECT_ORDER, {
|
||||
p_order_id: orderId,
|
||||
@@ -2157,6 +2173,44 @@ export async function checkinOrderById(orderId: string, payload: DeliveryCheckin
|
||||
return await fallbackCheckinOrder(orderId, payload)
|
||||
}
|
||||
|
||||
/**
|
||||
* 居家服务正式签到 RPC:rpc_homecare_checkin_submit
|
||||
* 参数:p_work_order_id, p_worker_id, p_latitude, p_longitude, p_coordinate_type, p_accuracy, p_reported_at, p_evidence_file_ids, p_signature_payload, p_reason
|
||||
*/
|
||||
export async function submitHomecareCheckin(
|
||||
workOrderId: string,
|
||||
workerId: string,
|
||||
latitude: number,
|
||||
longitude: number,
|
||||
coordinateType: string,
|
||||
accuracy: number,
|
||||
reportedAt: string,
|
||||
evidenceFileIds: Array<string>,
|
||||
signaturePayload: any | null = null,
|
||||
reason: string = 'worker_arrived'
|
||||
): Promise<UTSJSONObject | null> {
|
||||
console.warn('[CHECKIN SUBMIT] 调用 rpc_homecare_checkin_submit')
|
||||
console.warn('[CHECKIN SUBMIT] workOrderId=', workOrderId, ' workerId=', workerId)
|
||||
console.warn('[CHECKIN SUBMIT] lat=', latitude, ' lng=', longitude, ' accuracy=', accuracy)
|
||||
console.warn('[CHECKIN SUBMIT] evidenceFileIds=', evidenceFileIds)
|
||||
|
||||
const rpcParams = new UTSJSONObject()
|
||||
rpcParams.set('p_work_order_id', workOrderId)
|
||||
rpcParams.set('p_worker_id', workerId)
|
||||
rpcParams.set('p_latitude', latitude)
|
||||
rpcParams.set('p_longitude', longitude)
|
||||
rpcParams.set('p_coordinate_type', coordinateType)
|
||||
rpcParams.set('p_accuracy', accuracy)
|
||||
rpcParams.set('p_reported_at', reportedAt)
|
||||
rpcParams.set('p_evidence_file_ids', evidenceFileIds)
|
||||
rpcParams.set('p_signature_payload', signaturePayload)
|
||||
rpcParams.set('p_reason', reason)
|
||||
|
||||
const rpcData = await callDeliveryRpc(DELIVERY_RPC_HOMECARE_CHECKIN_SUBMIT, rpcParams)
|
||||
console.warn('[CHECKIN SUBMIT] rpc_homecare_checkin_submit result:', rpcData)
|
||||
return rpcData as UTSJSONObject | null
|
||||
}
|
||||
|
||||
export async function startServiceById(orderId: string): Promise<DeliveryOrderType | null> {
|
||||
const rpcData = await callDeliveryRpc(DELIVERY_RPC_START_SERVICE, {
|
||||
p_order_id: orderId
|
||||
|
||||
@@ -45,7 +45,8 @@ import { onLoad } from '@dcloudio/uni-app'
|
||||
import ServicePageScaffold from '@/components/homeService/ServicePageScaffold.uvue'
|
||||
import ServicePanel from '@/components/homeService/ServicePanel.uvue'
|
||||
import type { DeliveryLocationType, DeliveryOrderType } from '@/types/delivery.uts'
|
||||
import { checkinOrder, getDeliveryOrderDetail } from '@/services/deliveryService.uts'
|
||||
import supa from '@/components/supadb/aksupainstance.uts'
|
||||
import { getDeliveryOrderDetail } from '@/services/deliveryService.uts'
|
||||
import { requireDeliveryAuth } from '@/utils/deliveryAuth.uts'
|
||||
import { getCurrentUserId } from '@/utils/store.uts'
|
||||
import { getDeliveryRouteParam } from '@/utils/deliveryRoute.uts'
|
||||
@@ -54,7 +55,7 @@ import {
|
||||
checkinPrecheck,
|
||||
getReasonText
|
||||
} from '@/utils/homecareAuth.uts'
|
||||
import { debugCurrentUser } from '@/utils/akUserMapping.uts'
|
||||
import { debugCurrentUser, getCurrentAkUserId } from '@/utils/akUserMapping.uts'
|
||||
|
||||
const orderId = ref('')
|
||||
const order = ref<DeliveryOrderType | null>(null)
|
||||
@@ -62,6 +63,7 @@ const currentLocation = ref<DeliveryLocationType | null>(null)
|
||||
const locationText = ref('未获取')
|
||||
const accuracyText = ref('未知')
|
||||
const photos = ref([] as Array<string>)
|
||||
const evidenceFileIds = ref([] as Array<string>)
|
||||
const note = ref('')
|
||||
const submitting = ref(false)
|
||||
|
||||
@@ -77,19 +79,29 @@ const allowedRadiusText = ref('未校验')
|
||||
const precheckStatusText = ref('未校验')
|
||||
const reasonText = ref('')
|
||||
|
||||
function updateHomecareLoginStatus(): void {
|
||||
console.warn('[CHECKIN DEBUG] updateHomecareLoginStatus: called')
|
||||
// 改用 Supabase 当前用户判断是否已登录(homecare 专属 token 已废弃,从未被写入)
|
||||
const userId = getCurrentUserId()
|
||||
console.warn('[CHECKIN DEBUG] updateHomecareLoginStatus: token length:', userId.length)
|
||||
if (userId !== '') {
|
||||
async function updateHomecareLoginStatus(): Promise<void> {
|
||||
console.warn('[CHECKIN AUTH] ========== 登录状态检查 START ==========')
|
||||
|
||||
// 打印认证相关日志
|
||||
const authUserId = getCurrentUserId()
|
||||
const akUserId = await getCurrentAkUserId()
|
||||
const storageAkUserId = uni.getStorageSync('ak_user_id')
|
||||
const storageCurrentAkUser = uni.getStorageSync('current_ak_user')
|
||||
|
||||
console.warn('[CHECKIN AUTH] getCurrentUserId =', authUserId)
|
||||
console.warn('[CHECKIN AUTH] getCurrentAkUserId =', akUserId)
|
||||
console.warn('[CHECKIN AUTH] storage ak_user_id =', storageAkUserId)
|
||||
console.warn('[CHECKIN AUTH] current_ak_user =', storageCurrentAkUser)
|
||||
console.warn('[CHECKIN AUTH] ========== 登录状态检查 END ==========')
|
||||
|
||||
if (akUserId !== '') {
|
||||
isHomecareLoggedIn.value = true
|
||||
homecareUserEmail.value = '已登录 (uid: ' + userId.substring(0, 8) + '...)'
|
||||
console.warn('[CHECKIN DEBUG] updateHomecareLoginStatus: logged in as', homecareUserEmail.value)
|
||||
homecareUserEmail.value = '已登录 (uid: ' + akUserId.substring(0, 8) + '...)'
|
||||
console.warn('[CHECKIN AUTH] 居家服务认证通过')
|
||||
} else {
|
||||
isHomecareLoggedIn.value = false
|
||||
homecareUserEmail.value = ''
|
||||
console.warn('[CHECKIN DEBUG] updateHomecareLoginStatus: not logged in')
|
||||
console.warn('[CHECKIN AUTH] 居家服务认证失败:akUserId 为空')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,6 +251,72 @@ async function choosePhoto() {
|
||||
try {
|
||||
const selected = await wrapChooseImage()
|
||||
photos.value = selected
|
||||
|
||||
// 上传现场图片并创建 hc_evidence_files 记录
|
||||
if (selected.length > 0 && orderId.value != '') {
|
||||
const akUserId = await getCurrentAkUserId()
|
||||
console.warn('[CHOOSE PHOTO] akUserId:', akUserId)
|
||||
|
||||
if (akUserId == '') {
|
||||
uni.showToast({ title: '未获取到业务用户 ID', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 上传每张照片
|
||||
for (let i = 0; i < selected.length; i++) {
|
||||
const tempPath = selected[i]
|
||||
try {
|
||||
// 上传到 Supabase Storage
|
||||
const { data: uploadData, error: uploadError } = await supa.storage
|
||||
.from('evidence')
|
||||
.upload('checkin/' + orderId.value + '/' + Date.now() + '_' + i + '.jpg', {
|
||||
base64: tempPath,
|
||||
contentType: 'image/jpeg'
|
||||
})
|
||||
|
||||
if (uploadError == null && uploadData != null) {
|
||||
// 获取公开 URL
|
||||
const { data: urlData } = supa.storage
|
||||
.from('evidence')
|
||||
.getPublicUrl(uploadData.path)
|
||||
|
||||
if (urlData != null) {
|
||||
const fileUrl = urlData.publicUrl
|
||||
|
||||
// 创建 hc_evidence_files 记录
|
||||
const { data: evidenceRecord, error: evidenceError } = await supa
|
||||
.from('hc_evidence_files')
|
||||
.insert({
|
||||
work_order_id: orderId.value,
|
||||
uploader_id: akUserId,
|
||||
file_url: fileUrl,
|
||||
upload_status: 'UPLOADED',
|
||||
file_type: 'image',
|
||||
created_at: new Date().toISOString()
|
||||
})
|
||||
.select('id')
|
||||
.single()
|
||||
|
||||
if (evidenceError == null && evidenceRecord != null) {
|
||||
const evidenceId = evidenceRecord.getString('id') ?? ''
|
||||
if (evidenceId != '') {
|
||||
evidenceFileIds.value.push(evidenceId)
|
||||
console.warn('[CHOOSE PHOTO] 证据记录创建成功, evidenceId:', evidenceId)
|
||||
}
|
||||
} else {
|
||||
console.warn('[CHOOSE PHOTO] 证据记录创建失败:', evidenceError)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.warn('[CHOOSE PHOTO] 图片上传失败:', uploadError)
|
||||
}
|
||||
} catch (uploadErr) {
|
||||
console.warn('[CHOOSE PHOTO] 上传异常:', uploadErr)
|
||||
}
|
||||
}
|
||||
|
||||
console.warn('[CHOOSE PHOTO] 当前 evidenceFileIds:', evidenceFileIds.value)
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({ title: '拍照失败,请重试', icon: 'none' })
|
||||
}
|
||||
@@ -259,6 +337,39 @@ async function handlePrecheck(): Promise<void> {
|
||||
return
|
||||
}
|
||||
|
||||
// 预校验前打印认证日志
|
||||
const authUserId = getCurrentUserId()
|
||||
let akUserId = await getCurrentAkUserId()
|
||||
const storageAkUserId = uni.getStorageSync('ak_user_id')
|
||||
const storageCurrentAkUser = uni.getStorageSync('current_ak_user')
|
||||
|
||||
console.warn('[CHECKIN AUTH] getCurrentUserId =', authUserId)
|
||||
console.warn('[CHECKIN AUTH] getCurrentAkUserId =', akUserId)
|
||||
console.warn('[CHECKIN AUTH] storage ak_user_id =', storageAkUserId)
|
||||
console.warn('[CHECKIN AUTH] current_ak_user =', storageCurrentAkUser)
|
||||
|
||||
// 兜底逻辑:如果 akUserId 为空但 authUserId 非空,尝试写入缓存
|
||||
if ((akUserId == '' || akUserId == null) && authUserId != null && String(authUserId).length > 0) {
|
||||
console.warn('[CHECKIN AUTH] 兜底:akUserId 为空但 authUserId 非空,尝试写入缓存')
|
||||
console.warn('[CHECKIN AUTH] authUserId =', authUserId)
|
||||
|
||||
// 直接写入 authUserId 作为 ak_user_id
|
||||
uni.setStorageSync('ak_user_id', authUserId)
|
||||
uni.setStorageSync('current_ak_user', JSON.stringify({ id: authUserId }))
|
||||
console.warn('[CHECKIN AUTH] 已写入缓存: ak_user_id =', authUserId)
|
||||
|
||||
// 重新读取
|
||||
akUserId = await getCurrentAkUserId()
|
||||
console.warn('[CHECKIN AUTH] 重新读取 akUserId =', akUserId)
|
||||
}
|
||||
|
||||
// 如果 akUserId 仍然为空,提示重新登录
|
||||
if (akUserId == '' || akUserId == null) {
|
||||
uni.showToast({ title: '业务账号未初始化,请重新登录', icon: 'none' })
|
||||
console.warn('[CHECKIN AUTH] akUserId 仍为空,阻止预校验')
|
||||
return
|
||||
}
|
||||
|
||||
console.warn('[CHECKIN PAGE] 开始预校验流程')
|
||||
|
||||
// 调试:打印当前 ak_user 信息
|
||||
@@ -356,31 +467,41 @@ async function submitCheckin() {
|
||||
return
|
||||
}
|
||||
|
||||
// RPC 预校验已经做了距离判断,这里直接提交
|
||||
// 保留坐标检查作为兜底,防止跳过预校验直接提交
|
||||
if (order.value.latitude == 0 && order.value.longitude == 0) {
|
||||
console.warn('[CHECKIN DEBUG] submitCheckin: order has no valid coordinates (lat=0, lng=0)')
|
||||
uni.showToast({ title: '订单缺少服务地址坐标', icon: 'none' })
|
||||
return
|
||||
}
|
||||
// 服务坐标以后端 precheck 返回为准,不再以前端 order.latitude/order.longitude 为准
|
||||
// 删除了之前的坐标检查
|
||||
|
||||
const distance = calculateDistance(currentLocation.value.latitude, currentLocation.value.longitude, order.value.latitude, order.value.longitude)
|
||||
console.warn('[CHECKIN DEBUG] submitCheckin: calculated distance:', distance, 'meters, allowedRadius:', order.value.allowCheckinRadiusMeters)
|
||||
|
||||
console.warn('[CHECKIN DEBUG] submitCheckin: proceeding with checkin, photos count:', photos.value.length)
|
||||
console.warn('[CHECKIN DEBUG] submitCheckin: proceeding with checkin, photos count:', photos.value.length, ' evidenceFileIds:', evidenceFileIds.value)
|
||||
doCheckin()
|
||||
}
|
||||
|
||||
async function doCheckin() {
|
||||
submitting.value = true
|
||||
try {
|
||||
await checkinOrder(orderId.value, {
|
||||
location: currentLocation.value as DeliveryLocationType,
|
||||
note: note.value,
|
||||
photos: photos.value,
|
||||
checkinMode: 'gps'
|
||||
})
|
||||
console.warn('[CHECKIN DEBUG] submitCheckin: checkinOrder succeeded')
|
||||
// 获取 akUserId
|
||||
const akUserId = await getCurrentAkUserId()
|
||||
console.warn('[CHECKIN RPC] akUserId:', akUserId)
|
||||
|
||||
if (akUserId == '') {
|
||||
uni.showToast({ title: '未获取到业务用户 ID,请重新登录', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 调用居家服务正式签到 RPC:rpc_homecare_checkin_submit
|
||||
const { submitHomecareCheckin } = await import('@/api/delivery.uts')
|
||||
const result = await submitHomecareCheckin(
|
||||
orderId.value,
|
||||
akUserId,
|
||||
currentLocation.value!.latitude,
|
||||
currentLocation.value!.longitude,
|
||||
'gcj02',
|
||||
parseFloat(accuracyText.value) || 0,
|
||||
new Date().toISOString(),
|
||||
evidenceFileIds.value,
|
||||
null,
|
||||
'worker_arrived'
|
||||
)
|
||||
|
||||
console.warn('[CHECKIN RPC] result:', result)
|
||||
|
||||
// 签到成功后显示等待消费者确认
|
||||
uni.showModal({
|
||||
@@ -388,7 +509,7 @@ async function doCheckin() {
|
||||
content: '已提交到达签到,等待消费者确认',
|
||||
showCancel: false,
|
||||
success: () => {
|
||||
// 返回订单列表或详情页
|
||||
// 返回订单列表
|
||||
uni.navigateBack()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -501,11 +501,69 @@ const handleLogin = async () => {
|
||||
saveDeliverySession(result.token, result.userInfo, result.deliveryInfo)
|
||||
|
||||
// 加载 ak_users 映射(Supabase Auth ID -> 业务用户 ID)
|
||||
// 优先从 result.userInfo.id 获取业务用户 ID,直接写入缓存
|
||||
// 只有 userInfo.id 不存在时,才调用 loadCurrentAkUser
|
||||
let akUserIdFromLogin = ''
|
||||
try {
|
||||
await loadCurrentAkUser()
|
||||
console.log('[Login] ak_users 映射加载成功')
|
||||
} catch (akErr) {
|
||||
console.warn('[Login] ⚠️ ak_users 映射加载失败(不影响登录):', akErr)
|
||||
// 尝试从 userInfo.id 获取业务用户 ID
|
||||
if (result.userInfo != null && result.userInfo.id != null && String(result.userInfo.id).length > 0) {
|
||||
const candidateId = String(result.userInfo.id)
|
||||
console.log('[Login] 从 result.userInfo.id 获取到 ID:', candidateId)
|
||||
|
||||
// 判断是否是 Supabase Auth ID(通过长度和格式判断)
|
||||
// Supabase Auth ID 通常是 UUID 格式,业务用户 ID 也是 UUID 格式
|
||||
// 最可靠的方式是尝试写入后验证
|
||||
akUserIdFromLogin = candidateId
|
||||
|
||||
// 写入缓存
|
||||
uni.setStorageSync('ak_user_id', akUserIdFromLogin)
|
||||
uni.setStorageSync('user_id', akUserIdFromLogin)
|
||||
uni.setStorageSync('current_ak_user', JSON.stringify({
|
||||
id: akUserIdFromLogin,
|
||||
auth_id: result.userInfo.auth_id ?? '',
|
||||
username: result.userInfo.username ?? '',
|
||||
email: result.userInfo.email ?? '',
|
||||
role: result.userInfo.role ?? ''
|
||||
}))
|
||||
console.log('[Login] 从 userInfo.id 写入 ak_user_id 成功:', akUserIdFromLogin)
|
||||
}
|
||||
} catch (extractErr) {
|
||||
console.warn('[Login] 从 userInfo.id 提取失败:', extractErr)
|
||||
}
|
||||
|
||||
// 如果 userInfo.id 没有有效 ID,才调用 loadCurrentAkUser
|
||||
if (akUserIdFromLogin == null || String(akUserIdFromLogin).length == 0) {
|
||||
try {
|
||||
const profile = await loadCurrentAkUser()
|
||||
akUserIdFromLogin = profile.id
|
||||
console.log('[Login] ak_users 映射加载成功,akUserId:', profile.id)
|
||||
console.log('[Login] 缓存已写入: ak_user_id =', profile.id)
|
||||
} catch (akErr) {
|
||||
console.warn('[Login] ⚠️ ak_users 映射加载失败:', akErr)
|
||||
// 如果 user_id 已有缓存,尝试用它兜底
|
||||
const cachedUserId = uni.getStorageSync('user_id')
|
||||
if (cachedUserId != null && String(cachedUserId).length > 0) {
|
||||
console.log('[Login] 使用 user_id 缓存兜底:', cachedUserId)
|
||||
uni.setStorageSync('ak_user_id', cachedUserId)
|
||||
uni.setStorageSync('current_ak_user', JSON.stringify({ id: cachedUserId }))
|
||||
akUserIdFromLogin = String(cachedUserId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 最终验证 ak_user_id 必须有值
|
||||
const finalAkUserId = uni.getStorageSync('ak_user_id')
|
||||
console.log('[Login] 最终 ak_user_id:', finalAkUserId)
|
||||
console.log('[Login] 最终 current_ak_user:', uni.getStorageSync('current_ak_user'))
|
||||
|
||||
if (finalAkUserId == null || String(finalAkUserId).length == 0) {
|
||||
console.error('[Login] ❌ ak_user_id 最终为空,输出详细调试信息')
|
||||
console.error('[Login] result.userInfo:', JSON.stringify(result.userInfo))
|
||||
console.error('[Login] result.deliveryInfo:', JSON.stringify(result.deliveryInfo))
|
||||
console.error('[Login] user_id 缓存:', uni.getStorageSync('user_id'))
|
||||
console.error('[Login] auth_user_id 缓存:', uni.getStorageSync('auth_user_id'))
|
||||
console.error('[Login] user_info 缓存:', uni.getStorageSync('user_info'))
|
||||
throw new Error('业务账号映射加载失败,请联系管理员')
|
||||
}
|
||||
|
||||
const authResult = await requireDeliveryAuth({ redirectOnFail: false, toastOnFail: false })
|
||||
|
||||
@@ -16,7 +16,13 @@ import {
|
||||
getOrderDetail as getDirectServiceOrderDetail,
|
||||
getOrdersByTab as getDirectOrdersByTab
|
||||
} from '@/services/serviceOrderService.uts'
|
||||
import { getUserInfo, requireDeliveryAuth, setDeliveryInfo } from '@/utils/deliveryAuth.uts'
|
||||
import {
|
||||
getDeliveryInfo,
|
||||
getUserInfo,
|
||||
requireDeliveryAuth,
|
||||
setDeliveryInfo
|
||||
} from '@/utils/deliveryAuth.uts'
|
||||
import { getCurrentAkUserId as readCurrentAkUserId } from '@/utils/akUserMapping.uts'
|
||||
import type {
|
||||
DeliveryAbnormalReportType,
|
||||
DeliveryCheckinPayloadType,
|
||||
@@ -147,13 +153,17 @@ export async function checkDeliveryAuth(): Promise<boolean> {
|
||||
}
|
||||
|
||||
async function getCurrentStaffId(): Promise<string> {
|
||||
const profile = await getDeliveryProfile()
|
||||
if (profile == null) {
|
||||
return ''
|
||||
}
|
||||
return profile.id
|
||||
// 旧 delivery RPC(dashboard / order_list)需要 ml_delivery_staff.id(513449ca...)
|
||||
const deliveryInfo = getDeliveryInfo()
|
||||
if (deliveryInfo != null && deliveryInfo.id != null && String(deliveryInfo.id) != '') {
|
||||
console.warn('[deliveryService] getCurrentStaffId: 使用 deliveryStaffId =', String(deliveryInfo.id))
|
||||
return String(deliveryInfo.id)
|
||||
}
|
||||
|
||||
console.error('[deliveryService] getCurrentStaffId: 未获取到 deliveryStaffId')
|
||||
return ''
|
||||
}
|
||||
|
||||
function createEmptyLocation(): DeliveryLocationType {
|
||||
return {
|
||||
latitude: 0,
|
||||
@@ -168,7 +178,9 @@ export async function getDeliveryDashboard(): Promise<DeliveryDashboardType> {
|
||||
if (staffId != '') {
|
||||
return await getDeliveryDashboardByStaffId(staffId)
|
||||
}
|
||||
return getDeliveryCareDashboard()
|
||||
// staffId 为空时返回空 dashboard
|
||||
console.error('[deliveryService] getDeliveryDashboard: staffId 为空,返回空数据')
|
||||
return emptyDashboard()
|
||||
}
|
||||
|
||||
export async function getDeliveryOrders(params: DeliveryOrderQueryType): Promise<Array<DeliveryOrderType>> {
|
||||
@@ -176,13 +188,9 @@ export async function getDeliveryOrders(params: DeliveryOrderQueryType): Promise
|
||||
if (staffId != '') {
|
||||
return await getDeliveryOrdersByStaffId(staffId, params)
|
||||
}
|
||||
if (params.tab == 'pending' || params.tab == 'pending_assignment') {
|
||||
return getPendingCareOrders()
|
||||
}
|
||||
if (params.tab == 'history' || params.tab == 'completed' || params.tab == 'archive') {
|
||||
return getHistoryCareOrders()
|
||||
}
|
||||
return getTodayCareOrders()
|
||||
// staffId 为空时返回空列表
|
||||
console.error('[deliveryService] getDeliveryOrders: staffId 为空,返回空列表')
|
||||
return [] as Array<DeliveryOrderType>
|
||||
}
|
||||
|
||||
export async function getDeliveryOrderDetail(id: string): Promise<DeliveryOrderType | null> {
|
||||
@@ -352,7 +360,60 @@ export async function getServiceOrderDetail(orderId: string): Promise<DeliveryOr
|
||||
}
|
||||
|
||||
export async function acceptServiceOrder(orderId: string): Promise<DeliveryOrderType | null> {
|
||||
return await acceptDeliveryOrder(orderId)
|
||||
// 居家服务订单必须调用 rpc_homecare_accept_assignment_v2
|
||||
// 不再调用 acceptDeliveryOrder / rpc_delivery_accept_order
|
||||
const akUserId = await resolveCurrentAkUserIdForDelivery()
|
||||
console.warn('[HOMECARE ACCEPT] acceptServiceOrder: orderId=', orderId, ' akUserId=', akUserId)
|
||||
|
||||
if (akUserId == '') {
|
||||
uni.showToast({ title: '未获取到业务用户 ID,请重新登录', icon: 'none' })
|
||||
return null
|
||||
}
|
||||
|
||||
// 调用居家服务接单 RPC
|
||||
const { acceptHomecareAssignmentV2 } = await import('@/api/delivery.uts')
|
||||
const result = await acceptHomecareAssignmentV2(orderId, akUserId)
|
||||
console.warn('[HOMECARE ACCEPT] rpc_homecare_accept_assignment_v2 result:', result)
|
||||
|
||||
// 刷新订单列表
|
||||
await loadData()
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前业务用户 ID(从 akUserMapping 或缓存)
|
||||
*/
|
||||
async function resolveCurrentAkUserIdForDelivery(): Promise<string> {
|
||||
try {
|
||||
const id = await readCurrentAkUserId()
|
||||
if (id != null && id != '') {
|
||||
console.warn('[deliveryService] resolveCurrentAkUserIdForDelivery: from akUserMapping =', id)
|
||||
return id
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[deliveryService] readCurrentAkUserId failed:', e)
|
||||
}
|
||||
|
||||
try {
|
||||
const cached = uni.getStorageSync('ak_user_id')
|
||||
if (cached != null && String(cached) != '') {
|
||||
console.warn('[deliveryService] resolveCurrentAkUserIdForDelivery: from storage ak_user_id =', String(cached))
|
||||
return String(cached)
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
const currentAkUser = uni.getStorageSync('current_ak_user')
|
||||
if (currentAkUser != null && String(currentAkUser) != '') {
|
||||
const obj = JSON.parse(String(currentAkUser)) as any
|
||||
if (obj != null && obj.id != null && String(obj.id) != '') {
|
||||
console.warn('[deliveryService] resolveCurrentAkUserIdForDelivery: from current_ak_user.id =', String(obj.id))
|
||||
return String(obj.id)
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
export async function rejectServiceOrder(orderId: string, reason: string): Promise<DeliveryOrderType | null> {
|
||||
|
||||
@@ -26,7 +26,11 @@ export type AkUserProfile = {
|
||||
|
||||
/**
|
||||
* 加载当前登录用户的业务账号信息
|
||||
* 从 Supabase Auth 获取 authUserId,然后查询 ak_users 表获取业务用户信息
|
||||
* 查询顺序:
|
||||
* 1. auth_id = session.user.id
|
||||
* 2. id = uni.getStorageSync('user_id')
|
||||
* 3. email = 当前登录邮箱
|
||||
* 4. 最后才失败
|
||||
*/
|
||||
export async function loadCurrentAkUser(): Promise<AkUserProfile> {
|
||||
// 1. 获取当前 Supabase Auth 用户
|
||||
@@ -41,17 +45,68 @@ export async function loadCurrentAkUser(): Promise<AkUserProfile> {
|
||||
}
|
||||
|
||||
// 2. 查询 ak_users 表,通过 auth_id 匹配
|
||||
const { data: profiles, error } = await supa
|
||||
console.log('[akUserMapping] 尝试通过 auth_id 查询:', authUserId)
|
||||
let { data: profiles, error } = await supa
|
||||
.from('ak_users')
|
||||
.select('id, auth_id, username, email, role, user_type, status')
|
||||
.eq('auth_id', authUserId)
|
||||
.single()
|
||||
|
||||
if (error == null && profiles != null) {
|
||||
console.log('[akUserMapping] 通过 auth_id 查询成功')
|
||||
} else {
|
||||
console.warn('[akUserMapping] auth_id 查询失败:', error?.message ?? '未知错误')
|
||||
|
||||
// 3. 尝试通过 user_id 缓存查询
|
||||
const cachedUserId = uni.getStorageSync('user_id')
|
||||
if (cachedUserId != null && String(cachedUserId).length > 0) {
|
||||
console.log('[akUserMapping] 尝试通过 user_id 缓存查询:', cachedUserId)
|
||||
const { data: profilesById, error: errorById } = await supa
|
||||
.from('ak_users')
|
||||
.select('id, auth_id, username, email, role, user_type, status')
|
||||
.eq('id', cachedUserId)
|
||||
.single()
|
||||
|
||||
if (errorById == null && profilesById != null) {
|
||||
profiles = profilesById
|
||||
error = null
|
||||
console.log('[akUserMapping] 通过 user_id 缓存查询成功')
|
||||
} else {
|
||||
console.warn('[akUserMapping] user_id 缓存查询失败:', errorById?.message ?? '未知错误')
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 尝试通过 session 中的 email 查询
|
||||
if (profiles == null) {
|
||||
const userEmail = session.user.getString('email') ?? ''
|
||||
if (userEmail != '') {
|
||||
console.log('[akUserMapping] 尝试通过 email 查询:', userEmail)
|
||||
const { data: profilesByEmail, error: errorByEmail } = await supa
|
||||
.from('ak_users')
|
||||
.select('id, auth_id, username, email, role, user_type, status')
|
||||
.eq('email', userEmail)
|
||||
.single()
|
||||
|
||||
if (errorByEmail == null && profilesByEmail != null) {
|
||||
profiles = profilesByEmail
|
||||
error = null
|
||||
console.log('[akUserMapping] 通过 email 查询成功')
|
||||
} else {
|
||||
console.warn('[akUserMapping] email 查询失败:', errorByEmail?.message ?? '未知错误')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (error != null || profiles == null) {
|
||||
console.error('[akUserMapping] ❌ 所有查询方式都失败')
|
||||
console.error('[akUserMapping] authUserId:', authUserId)
|
||||
console.error('[akUserMapping] user_id 缓存:', uni.getStorageSync('user_id'))
|
||||
console.error('[akUserMapping] session email:', session.user?.getString('email'))
|
||||
throw new Error('未找到当前用户的业务账号,请联系管理员绑定 ak_users.auth_id')
|
||||
}
|
||||
|
||||
// 3. 存储到本地
|
||||
// 5. 存储到本地
|
||||
const profile: AkUserProfile = {
|
||||
id: profiles.getString('id') ?? '',
|
||||
auth_id: profiles.getString('auth_id') ?? '',
|
||||
@@ -78,18 +133,192 @@ export async function loadCurrentAkUser(): Promise<AkUserProfile> {
|
||||
|
||||
/**
|
||||
* 获取当前业务用户 ID(ak_users.id)
|
||||
* 优先从本地缓存读取,如果缓存不存在则自动加载
|
||||
* 优先级:
|
||||
* 1. uni.getStorageSync('ak_user_id')
|
||||
* 2. uni.getStorageSync('current_ak_user').id
|
||||
* 3. uni.getStorageSync('user_info').id
|
||||
* 4. uni.getStorageSync('userInfo').id
|
||||
* 5. uni.getStorageSync('user').id
|
||||
* 6. uni.getStorageSync('uid')
|
||||
* 7. uni.getStorageSync('user_id')
|
||||
* 8. uni.getStorageSync('auth_user_id')
|
||||
* 9. 最后再请求 ak_users 表或 RPC resolve_ak_user_id
|
||||
*/
|
||||
export async function getCurrentAkUserId(): Promise<string> {
|
||||
// 1. 尝试从缓存读取
|
||||
// 1. 尝试从 ak_user_id 缓存读取
|
||||
const cachedAkUserId = uni.getStorageSync(AK_USER_ID_KEY)
|
||||
if (cachedAkUserId != null && String(cachedAkUserId).length > 0) {
|
||||
return String(cachedAkUserId)
|
||||
const result = String(cachedAkUserId)
|
||||
console.log('[akUserMapping] getCurrentAkUserId: 从 ak_user_id 缓存读取:', result)
|
||||
return result
|
||||
}
|
||||
|
||||
// 2. 缓存不存在,自动加载
|
||||
const profile = await loadCurrentAkUser()
|
||||
return profile.id
|
||||
// 2. 尝试从 current_ak_user 缓存读取
|
||||
const cachedProfile = uni.getStorageSync(AK_USER_PROFILE_KEY)
|
||||
if (cachedProfile != null && String(cachedProfile).length > 0) {
|
||||
try {
|
||||
const profile = JSON.parse(cachedProfile) as AkUserProfile
|
||||
if (profile.id != null && profile.id !== '') {
|
||||
const result = profile.id
|
||||
console.log('[akUserMapping] getCurrentAkUserId: 从 current_ak_user 缓存读取:', result)
|
||||
return result
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[akUserMapping] getCurrentAkUserId: 解析 current_ak_user 失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 尝试从 user_info 缓存读取
|
||||
try {
|
||||
const cachedUserInfo = uni.getStorageSync('user_info')
|
||||
if (cachedUserInfo != null && String(cachedUserInfo).length > 0) {
|
||||
try {
|
||||
const userInfo = JSON.parse(cachedUserInfo) as any
|
||||
if (userInfo != null && userInfo.id != null && String(userInfo.id).length > 0) {
|
||||
const result = String(userInfo.id)
|
||||
console.log('[akUserMapping] getCurrentAkUserId: 从 user_info 缓存读取:', result)
|
||||
return result
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[akUserMapping] getCurrentAkUserId: 解析 user_info 失败:', e)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[akUserMapping] getCurrentAkUserId: user_info 读取失败:', e)
|
||||
}
|
||||
|
||||
// 4. 尝试从 userInfo 缓存读取
|
||||
try {
|
||||
const cachedUserInfo = uni.getStorageSync('userInfo')
|
||||
if (cachedUserInfo != null && String(cachedUserInfo).length > 0) {
|
||||
try {
|
||||
const userInfo = JSON.parse(cachedUserInfo) as any
|
||||
if (userInfo != null && userInfo.id != null && String(userInfo.id).length > 0) {
|
||||
const result = String(userInfo.id)
|
||||
console.log('[akUserMapping] getCurrentAkUserId: 从 userInfo 缓存读取:', result)
|
||||
return result
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[akUserMapping] getCurrentAkUserId: 解析 userInfo 失败:', e)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[akUserMapping] getCurrentAkUserId: userInfo 读取失败:', e)
|
||||
}
|
||||
|
||||
// 5. 尝试从 user 缓存读取
|
||||
try {
|
||||
const cachedUser = uni.getStorageSync('user')
|
||||
if (cachedUser != null && String(cachedUser).length > 0) {
|
||||
try {
|
||||
const user = JSON.parse(cachedUser) as any
|
||||
if (user != null && user.id != null && String(user.id).length > 0) {
|
||||
const result = String(user.id)
|
||||
console.log('[akUserMapping] getCurrentAkUserId: 从 user 缓存读取:', result)
|
||||
return result
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[akUserMapping] getCurrentAkUserId: 解析 user 失败:', e)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[akUserMapping] getCurrentAkUserId: user 读取失败:', e)
|
||||
}
|
||||
|
||||
// 6. 尝试从 uid 缓存读取
|
||||
const cachedUid = uni.getStorageSync('uid')
|
||||
if (cachedUid != null && String(cachedUid).length > 0) {
|
||||
const result = String(cachedUid)
|
||||
console.log('[akUserMapping] getCurrentAkUserId: 从 uid 缓存读取:', result)
|
||||
return result
|
||||
}
|
||||
|
||||
// 7. 尝试从 user_id 缓存读取
|
||||
const cachedUserId = uni.getStorageSync('user_id')
|
||||
if (cachedUserId != null && String(cachedUserId).length > 0) {
|
||||
const result = String(cachedUserId)
|
||||
console.log('[akUserMapping] getCurrentAkUserId: 从 user_id 缓存读取:', result)
|
||||
return result
|
||||
}
|
||||
|
||||
// 8. 尝试从 auth_user_id 缓存读取(可能是 Supabase Auth ID,需要转换)
|
||||
const cachedAuthUserId = uni.getStorageSync(AUTH_USER_ID_KEY)
|
||||
if (cachedAuthUserId != null && String(cachedAuthUserId).length > 0) {
|
||||
const authId = String(cachedAuthUserId)
|
||||
console.log('[akUserMapping] getCurrentAkUserId: 从 auth_user_id 缓存读取到 Auth ID:', authId)
|
||||
|
||||
// 禁止直接返回 auth_user_id,必须通过 RPC 或 ak_users 表转换
|
||||
console.log('[akUserMapping] 尝试通过 RPC resolve_ak_user_id 转换 Auth ID')
|
||||
try {
|
||||
const rpcParams = { p_auth_user_id: authId } as UTSJSONObject
|
||||
const { data: resolvedData, error: resolveError } = await supa
|
||||
.rpc('resolve_ak_user_id', rpcParams)
|
||||
|
||||
if (resolveError == null && resolvedData != null) {
|
||||
const akUserId = String(resolvedData)
|
||||
if (akUserId != '' && akUserId != 'null') {
|
||||
console.log('[akUserMapping] RPC 转换成功,akUserId:', akUserId)
|
||||
// 缓存 akUserId
|
||||
uni.setStorageSync(AK_USER_ID_KEY, akUserId)
|
||||
return akUserId
|
||||
}
|
||||
}
|
||||
console.warn('[akUserMapping] RPC 转换失败:', resolveError?.message ?? '未知错误')
|
||||
} catch (rpcErr) {
|
||||
console.warn('[akUserMapping] RPC 转换异常:', rpcErr)
|
||||
}
|
||||
|
||||
// 如果 RPC 失败,尝试通过 ak_users 表查询
|
||||
console.log('[akUserMapping] 尝试通过 ak_users 表查询 auth_id 映射')
|
||||
const { data: profiles, error } = await supa
|
||||
.from('ak_users')
|
||||
.select('id')
|
||||
.eq('auth_id', authId)
|
||||
.single()
|
||||
|
||||
if (error == null && profiles != null) {
|
||||
const akUserId = profiles.getString('id') ?? ''
|
||||
if (akUserId != '') {
|
||||
console.log('[akUserMapping] ak_users 表查询成功,akUserId:', akUserId)
|
||||
uni.setStorageSync(AK_USER_ID_KEY, akUserId)
|
||||
return akUserId
|
||||
}
|
||||
}
|
||||
console.warn('[akUserMapping] ak_users 表查询也失败')
|
||||
}
|
||||
|
||||
// 9. 最后尝试从 Supabase session 查询 ak_users
|
||||
try {
|
||||
const session = supa.getSession()
|
||||
if (session != null && session.user != null) {
|
||||
const authUserId = session.user.getString('id') ?? ''
|
||||
if (authUserId != '') {
|
||||
console.log('[akUserMapping] getCurrentAkUserId: 尝试从 Supabase session 查询 ak_users, authUserId:', authUserId)
|
||||
const { data: profiles, error } = await supa
|
||||
.from('ak_users')
|
||||
.select('id')
|
||||
.eq('auth_id', authUserId)
|
||||
.single()
|
||||
|
||||
if (error == null && profiles != null) {
|
||||
const akUserId = profiles.getString('id') ?? ''
|
||||
if (akUserId != '') {
|
||||
console.log('[akUserMapping] getCurrentAkUserId: Supabase 查询成功:', akUserId)
|
||||
// 缓存结果
|
||||
uni.setStorageSync(AK_USER_ID_KEY, akUserId)
|
||||
return akUserId
|
||||
}
|
||||
}
|
||||
console.warn('[akUserMapping] getCurrentAkUserId: Supabase 查询未找到 ak_users 记录')
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[akUserMapping] getCurrentAkUserId: Supabase 查询失败:', e)
|
||||
}
|
||||
|
||||
// 10. 全部失败,返回空字符串(不 throw)
|
||||
console.warn('[akUserMapping] getCurrentAkUserId: 所有降级策略失败,返回空字符串')
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -140,12 +140,78 @@ export async function checkinPrecheck(
|
||||
try {
|
||||
// 获取当前业务用户 ID(ak_users.id),不是 Supabase Auth ID
|
||||
console.warn('[CHECKIN RPC] 步骤 1: 获取当前业务用户 ID')
|
||||
const workerId = await getCurrentAkUserId()
|
||||
|
||||
// 打印认证相关日志
|
||||
console.warn('[CHECKIN AUTH] storage ak_user_id =', uni.getStorageSync('ak_user_id'))
|
||||
console.warn('[CHECKIN AUTH] current_ak_user =', uni.getStorageSync('current_ak_user'))
|
||||
|
||||
let workerId = await getCurrentAkUserId()
|
||||
console.warn('[CHECKIN RPC] workerId (ak_user_id):', workerId)
|
||||
|
||||
if (workerId == '' || workerId == null) {
|
||||
console.warn('[CHECKIN RPC] 未登录,返回 NOT_LOGGED_IN')
|
||||
return { distanceMeters: null, allowedRadiusMeters: 0, canCheckin: false, reasonCode: 'NOT_LOGGED_IN' }
|
||||
console.warn('[CHECKIN RPC] workerId 为空,尝试从缓存恢复')
|
||||
|
||||
// 按顺序从缓存恢复
|
||||
// 1. ak_user_id
|
||||
try {
|
||||
const cached = uni.getStorageSync('ak_user_id')
|
||||
if (cached != null && String(cached) != '') {
|
||||
workerId = String(cached)
|
||||
console.warn('[CHECKIN RPC] 从 ak_user_id 恢复:', workerId)
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
// 2. current_ak_user.id
|
||||
if (workerId == '' || workerId == null) {
|
||||
try {
|
||||
const currentAkUser = uni.getStorageSync('current_ak_user')
|
||||
if (currentAkUser != null && String(currentAkUser) != '') {
|
||||
const obj = JSON.parse(String(currentAkUser)) as any
|
||||
if (obj != null && obj.id != null && String(obj.id) != '') {
|
||||
workerId = String(obj.id)
|
||||
console.warn('[CHECKIN RPC] 从 current_ak_user.id 恢复:', workerId)
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 3. user_id
|
||||
if (workerId == '' || workerId == null) {
|
||||
try {
|
||||
const userId = uni.getStorageSync('user_id')
|
||||
if (userId != null && String(userId) != '') {
|
||||
workerId = String(userId)
|
||||
console.warn('[CHECKIN RPC] 从 user_id 恢复:', workerId)
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 4. user_info.id
|
||||
if (workerId == '' || workerId == null) {
|
||||
try {
|
||||
const cachedUserInfo = uni.getStorageSync('user_info')
|
||||
if (cachedUserInfo != null && String(cachedUserInfo) != '') {
|
||||
const userInfo = JSON.parse(String(cachedUserInfo)) as any
|
||||
if (userInfo != null && userInfo.id != null && String(userInfo.id) != '') {
|
||||
workerId = String(userInfo.id)
|
||||
console.warn('[CHECKIN RPC] 从 user_info.id 恢复:', workerId)
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 恢复成功后写回缓存
|
||||
if (workerId != '' && workerId != null) {
|
||||
uni.setStorageSync('ak_user_id', workerId)
|
||||
uni.setStorageSync('current_ak_user', JSON.stringify({ id: workerId }))
|
||||
console.warn('[CHECKIN RPC] 已写回缓存: ak_user_id =', workerId)
|
||||
}
|
||||
|
||||
// 如果仍然为空,返回错误
|
||||
if (workerId == '' || workerId == null) {
|
||||
console.warn('[CHECKIN RPC] 所有恢复策略失败,返回 NOT_LOGGED_IN')
|
||||
return { distanceMeters: null, allowedRadiusMeters: 0, canCheckin: false, reasonCode: 'NOT_LOGGED_IN' }
|
||||
}
|
||||
}
|
||||
|
||||
// 构建 RPC 参数
|
||||
@@ -157,6 +223,7 @@ export async function checkinPrecheck(
|
||||
p_longitude: longitude,
|
||||
p_coordinate_type: 'gcj02',
|
||||
p_accuracy: accuracy,
|
||||
p_reported_at: new Date().toISOString(),
|
||||
p_location_scene: 'CHECKIN_PRECHECK'
|
||||
} as UTSJSONObject
|
||||
console.warn('[CHECKIN RPC] RPC 参数:', JSON.stringify(rpcParams))
|
||||
|
||||
Reference in New Issue
Block a user