忽略本地报错信息文件

This commit is contained in:
2026-06-17 10:20:43 +08:00
parent 6b11144366
commit 090362c32d
191 changed files with 5434 additions and 76452 deletions

View File

@@ -6,6 +6,8 @@ import type { HomeServiceCatalogType, HomeServicePackageType } from '@/types/hom
import type { DeliveryServiceRecordType } from '@/types/delivery.uts'
import {
getServiceOrderStatusText,
isArrivalPendingStatus,
normalizeOrderStatusCode,
normalizeServiceOrderStatus,
type ServiceOrderAddressSnapshotType,
type ServiceEvidenceFileType,
@@ -217,6 +219,7 @@ function shouldBypassEcCareTaskCreate(error: any): boolean {
|| hasMissingColumnError(error, 'service_catalog_id')
|| hasMissingColumnError(error, 'elder_name')
|| hasMissingColumnError(error, 'contact_name')
|| hasMissingColumnError(error, 'contact_phone')
}
function readServiceItems(source: any): Array<DeliveryServiceItemType> {
@@ -256,33 +259,79 @@ function buildDefaultServiceItems(order: DeliveryOrderType): Array<DeliveryServi
names.push('用药情况核对')
names.push('随访结论反馈')
} else {
names.push('上门签到确认')
names.push('服务项目执行')
names.push('服务过程记录')
names.push('完成情况确认')
}
const result = [] as Array<DeliveryServiceItemType>
for (let i = 0; i < names.length; i++) {
result.push({
id: order.id + '-item-' + String(i + 1),
name: names[i],
required: true,
completed: false,
incompleteReason: '',
remark: '',
updatedAt: ''
} as DeliveryServiceItemType)
payload.address_snapshot_json = params.address as any
}
return result
}
async function getCurrentStaffId(): Promise<string> {
const userId = getCurrentUserId()
if (userId == '') {
return ''
function buildEcCareTaskPayloadWithoutAddress(params: CreateServiceOrderParams, userId: string, requestId: string, taskId: string, taskNo: string, createdAt: string, appointmentTime: string | null): any {
return {
id: taskId,
task_no: taskNo,
request_id: requestId,
user_id: userId,
service_catalog_id: params.service.id,
service_name: params.service.name,
service_category: params.service.category,
service_snapshot_json: buildServiceSnapshot(params),
elder_name: params.recipientName,
elder_phone: params.recipientPhone,
elder_age: params.recipientAge,
elder_gender: params.recipientGender,
contact_name: params.contactName,
contact_phone: params.contactPhone,
scheduled_at: appointmentTime,
remark: params.remark,
status: 'ORDER_CREATED',
created_at: createdAt,
updated_at: createdAt
} as any
}
function parseTimeline(item: any): ServiceOrderTimelineItemType {
return {
id: readString(item, 'id'),
orderId: readString(item, 'order_id'),
fromStatus: readString(item, 'from_status'),
toStatus: normalizeServiceOrderStatus(readString(item, 'to_status')),
operatorId: readString(item, 'operator_id'),
operatorRole: readString(item, 'operator_role'),
remark: readString(item, 'remark'),
createdAt: readString(item, 'created_at')
}
}
function parseReview(item: any): ServiceReviewType {
return {
id: readString(item, 'id'),
orderId: readString(item, 'order_id'),
userId: readString(item, 'user_id'),
rating: readNumber(item, 'rating') == 0 ? 5 : readNumber(item, 'rating'),
tags: safeParseArray(safeJsonField(item, 'tags_json')),
content: readString(item, 'content'),
createdAt: readString(item, 'created_at')
}
}
function parseExecutionRecord(item: any): ServiceExecutionRecordType {
return {
id: readString(item, 'id'),
orderId: readString(item, 'order_id'),
assignmentId: readString(item, 'assignment_id'),
checkinTime: readString(item, 'checkin_time'),
checkinLatitude: readNumber(item, 'checkin_latitude'),
checkinLongitude: readNumber(item, 'checkin_longitude'),
checkinAddress: readString(item, 'checkin_address'),
serviceStartedAt: readString(item, 'service_started_at'),
serviceFinishedAt: readString(item, 'service_finished_at'),
actualDurationMinutes: readNumber(item, 'actual_duration_minutes'),
serviceItemsJson: safeJsonField(item, 'service_items_json'),
summary: readString(item, 'summary'),
remark: readString(item, 'remark'),
trackPointsJson: safeJsonField(item, 'track_points_json'),
createdAt: readString(item, 'created_at'),
updatedAt: readString(item, 'updated_at')
}
const profile = await getDeliveryProfileByUserId(userId)
return profile != null ? profile.id : ''
}
function getCurrentWorkerUserId(): string {
@@ -479,6 +528,7 @@ function mapCareTaskToLegacyShape(item: any): any {
appointment_time: readFirstString(item, ['scheduled_at', 'appointment_time']),
remark: readString(item, 'remark'),
status: derivedStatus,
waiting_consumer_confirm: waitingConsumerConfirm,
current_assignment_id: readFirstString(item, ['assignment_id', 'current_assignment_id']),
current_staff_id: readFirstString(item, ['assigned_to', 'current_staff_id']),
accepted_at: readString(item, 'accepted_at'),
@@ -626,7 +676,7 @@ async function getCareTaskDetail(taskId: string): Promise<ServiceOrderType | nul
parsed.dispatchStatus = parsed.currentStaffId != '' ? HOMECARE_DISPATCH_STATUS_ASSIGNED : HOMECARE_DISPATCH_STATUS_PENDING
parsed.dispatchErrorCode = ''
parsed.dispatchErrorMessage = ''
return parsed
return applyArrivalPendingState(parsed)
}
async function tryCreateCareTask(params: CreateServiceOrderParams): Promise<ServiceOrderType | null> {
@@ -748,7 +798,7 @@ async function getLegacyServiceOrderDetail(orderId: string): Promise<ServiceOrde
}
}
}
return parsed
return applyArrivalPendingState(parsed)
}
export function buildAddressSnapshot(address: UserAddress, latitude: number, longitude: number): ServiceOrderAddressSnapshotType {
@@ -768,6 +818,197 @@ export function buildAddressSnapshot(address: UserAddress, latitude: number, lon
}
}
export function getHomecareOrderDisplayStatus(order: ServiceOrderType): string {
if (order.paymentStatus == 1 && order.status == 'created' && isHomecarePaymentExpired(order)) {
return '已超时未支付'
}
if (order.paymentStatus == 1 && order.status == 'created') {
return '待付款'
}
if (order.paymentStatus == 2 && order.dispatchStatus == HOMECARE_DISPATCH_STATUS_PENDING) {
return '待派单'
}
if (order.paymentStatus == 2 && order.dispatchStatus == HOMECARE_DISPATCH_STATUS_DISPATCHING) {
return '正在派单'
}
if (order.paymentStatus == 2 && order.dispatchStatus == HOMECARE_DISPATCH_STATUS_FAILED) {
return '派单未成功'
}
if (order.paymentStatus == 2 && order.dispatchStatus == HOMECARE_DISPATCH_STATUS_ASSIGNED) {
return '已派单'
}
return getServiceOrderStatusText(order.status)
}
function isHomecarePaymentExpired(order: ServiceOrderType): boolean {
if (order.paymentStatus != 1 || order.status != 'created') {
return false
}
const payExpireAt = order.payExpireAt != null ? order.payExpireAt : ''
if (payExpireAt == '') {
return false
}
const expireMs = Date.parse(payExpireAt)
if (isNaN(expireMs)) {
return false
}
return expireMs <= Date.now()
}
export async function dispatchPaidHomecareOrder(orderId: string): Promise<HomecareDispatchResult> {
if (orderId == null || orderId.trim() == '') {
return {
success: false,
code: 'ORDER_ID_REQUIRED',
message: '订单信息异常,请返回后重试',
display_type: 'modal',
retryable: false
}
}
// LEGACY/TODO: rpc_homecare_auto_dispatch 当前只操作 hss_service_orders旧交易链
// 对于 ec_care_tasks 新链UUID 格式订单 ID不要调用旧 RPC避免错误回写旧表。
if (shouldUseCareTaskPath(orderId)) {
return {
success: true,
code: 'SYNC_IN_PROGRESS',
message: '付款成功,服务安排信息正在同步中,请稍后在我的服务中查看。',
display_type: 'toast',
retryable: false,
dispatch_status: HOMECARE_DISPATCH_STATUS_PENDING,
order_id: orderId
}
}
const { data, error } = await supa.rpc('rpc_homecare_auto_dispatch', {
p_order_id: orderId
} as any)
if (error != null) {
console.error('[homecare-dispatch] rpc failed:', error)
return {
success: false,
code: 'RPC_EXECUTION_FAILED',
message: '派单服务暂时异常,请稍后重试',
display_type: 'modal',
retryable: true,
dispatch_status: 'failed',
order_id: orderId
}
}
if (data == null) {
return {
success: false,
code: 'RPC_EMPTY_RESULT',
message: '未获取到派单结果,请稍后重试',
display_type: 'modal',
retryable: true,
dispatch_status: 'failed',
order_id: orderId
}
}
const result = plainObject(data)
const successValue = result['success']
const isSuccess = successValue === true || successValue === 'true' || (typeof successValue === 'boolean' && successValue)
const code = readString(result, 'code')
const message = readString(result, 'message')
const displayType = readString(result, 'display_type')
const retryable = result['retryable'] === true || result['retryable'] === 'true'
const dispatchStatus = readString(result, 'dispatch_status')
if (isSuccess || code == 'DISPATCH_ASSIGNED' || code == 'ALREADY_ASSIGNED' || code == 'ALREADY_ASSIGNED_RECOVERED') {
return {
success: true,
code: code != '' ? code : 'DISPATCH_ASSIGNED',
message: message != '' ? message : '系统已为您匹配服务人员',
display_type: displayType != '' ? displayType : 'none',
retryable: false,
dispatch_status: dispatchStatus != '' ? dispatchStatus : 'assigned',
order_id: readString(result, 'order_id'),
assignment_id: readString(result, 'assignment_id'),
staff_id: readString(result, 'staff_id'),
station_id: readString(result, 'station_id'),
dispatch_distance_km: readNumber(result, 'dispatch_distance_km')
}
}
return {
success: false,
code: code != '' ? code : 'DISPATCH_FAILED',
message: message != '' ? message : '派单失败,请稍后重试',
display_type: displayType != '' ? displayType : 'modal',
retryable: retryable,
dispatch_status: dispatchStatus != '' ? dispatchStatus : 'failed',
order_id: readString(result, 'order_id')
}
}
export function showHomecareDispatchFailureModal(orderId: string, result: HomecareDispatchResult, retryCallback: (id: string) => void): void {
const code = result.code
let title = '操作失败'
let allowRetry = false
if (code == 'ORDER_ID_REQUIRED') {
title = '操作失败'
allowRetry = false
} else if (code == 'UNAUTHENTICATED') {
title = '请重新登录'
allowRetry = false
} else if (code == 'USER_PROFILE_NOT_FOUND') {
title = '账户异常'
allowRetry = false
} else if (code == 'ORDER_NOT_FOUND') {
title = '订单异常'
allowRetry = false
} else if (code == 'ORDER_ACCESS_DENIED') {
title = '无权操作'
allowRetry = false
} else if (code == 'ORDER_NOT_PAID') {
title = '暂不能派单'
allowRetry = false
} else if (code == 'ORDER_STATUS_NOT_DISPATCHABLE') {
title = '暂不能派单'
allowRetry = false
} else if (code == 'NO_ONLINE_STAFF' || code == 'NO_STAFF_IN_SERVICE_STATION' || code == 'NO_QUALIFIED_STAFF' || code == 'NO_NEARBY_STAFF' || code == 'ALL_ELIGIBLE_STAFF_BUSY') {
title = '暂未匹配成功'
allowRetry = true
} else if (code == 'DISPATCH_CONFLICT_RETRY') {
title = '请重新尝试'
allowRetry = true
} else if (code == 'RPC_EXECUTION_FAILED' || code == 'RPC_EMPTY_RESULT') {
title = '派单服务异常'
allowRetry = true
} else {
title = '操作失败'
allowRetry = result.retryable
}
if (!allowRetry) {
uni.showModal({
title: title,
content: result.message,
showCancel: false,
confirmText: '我知道了'
})
return
}
uni.showModal({
title: title,
content: result.message,
showCancel: true,
cancelText: '稍后再试',
confirmText: '重新派单',
success: (res) => {
if (res.confirm) {
retryCallback(orderId)
}
}
})
}
export async function createServiceOrder(params: CreateServiceOrderParams): Promise<ServiceOrderType | null> {
// 当前下单链路分为两层:
// 1) 交易支付层hss_service_orders旧表仍承担套餐价格快照与支付状态
@@ -797,6 +1038,7 @@ export async function createServiceOrder(params: CreateServiceOrderParams): Prom
user_id: userId,
service_id: params.service.id,
service_name: params.service.name,
service_category: params.service.category != '' ? params.service.category : '居家服务',
service_snapshot_json: serviceSnapshot,
service_package_id: params.packageInfo.id,
pricing_snapshot_json: pricingSnapshot,
@@ -805,13 +1047,22 @@ export async function createServiceOrder(params: CreateServiceOrderParams): Prom
total_amount: payableAmount,
service_address_id: normalizeUuidOrNull(params.address.addressId),
address_snapshot_json: params.address as any,
service_lat: params.address.latitude != null ? params.address.latitude : null,
service_lng: params.address.longitude != null ? params.address.longitude : null,
recipient_name: params.recipientName,
recipient_phone: params.recipientPhone,
recipient_age: params.recipientAge,
recipient_gender: params.recipientGender,
elder_name: params.recipientName,
elder_phone: params.recipientPhone,
contact_name: params.contactName,
contact_phone: params.contactPhone,
appointment_time: appointmentTime,
scheduled_at: appointmentTime,
price: payableAmount,
staff_income: payableAmount,
duration_minutes: 90,
request_id: '',
remark: params.remark,
status: 'created',
payment_status: 1,