忽略本地报错信息文件
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
<text class="summary-title">{{ detail.serviceName }}</text>
|
||||
<text class="summary-case-no">服务单号:{{ detail.caseNo }}</text>
|
||||
</view>
|
||||
<ServiceStatusTag :text="detail.statusText" :tone="detail.statusTone"></ServiceStatusTag>
|
||||
<ServiceStatusTag :text="displayStatusText" :tone="displayStatusTone"></ServiceStatusTag>
|
||||
</view>
|
||||
<text class="summary-desc">{{ detail.summary }}</text>
|
||||
<view class="summary-price-row">
|
||||
@@ -102,13 +102,29 @@
|
||||
<view class="primary-btn" @click="bookAgain">再次预约</view>
|
||||
</view>
|
||||
<view v-else class="action-row">
|
||||
<view v-if="detail.statusText == '派单未成功'" class="secondary-btn" @click="bookAgain">再次预约</view>
|
||||
<view v-if="isArrivalPending" class="secondary-btn" @click="confirmArrival(false, '用户反馈服务人员未实际到达')">未到达 / 有异议</view>
|
||||
<view v-else-if="detail.statusText == '派单未成功'" class="secondary-btn" @click="bookAgain">再次预约</view>
|
||||
<view v-else class="secondary-btn" @click="bookAgain">再次预约</view>
|
||||
<view v-if="detail.status == 'pending_acceptance'" class="primary-btn" @click="goFeedback">去验收反馈</view>
|
||||
<view v-else-if="isArrivalPending" class="primary-btn" @click="confirmArrival(true, '用户确认服务人员已到达')">确认已到达</view>
|
||||
<view v-else-if="consumerViewState.showRescheduleBtn" class="primary-btn" @click="bookAgain">重新选择时间</view>
|
||||
<view v-else-if="detail.statusText == '派单未成功'" class="primary-btn" @click="retryDispatch">重新派单</view>
|
||||
<view v-else class="primary-btn" @click="contactService">联系客服</view>
|
||||
</view>
|
||||
|
||||
<!-- ARRIVAL_PENDING: 确认到达模块 -->
|
||||
<view v-if="isArrivalPending" class="arrival-confirm-card">
|
||||
<view class="arrival-confirm-header">
|
||||
<text class="arrival-confirm-title">等待消费者确认到达</text>
|
||||
</view>
|
||||
<view class="arrival-confirm-desc">
|
||||
<text>服务人员已提交到达签到,请确认其是否已到达服务地点。</text>
|
||||
</view>
|
||||
<view class="arrival-confirm-actions">
|
||||
<view class="arrival-confirm-secondary-btn" @click="confirmArrival(false, '用户反馈服务人员未实际到达')">未到达 / 有异议</view>
|
||||
<view class="arrival-confirm-primary-btn" @click="confirmArrival(true, '用户确认服务人员已到达')">确认已到达</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</ServicePageScaffold>
|
||||
</template>
|
||||
@@ -124,17 +140,81 @@ import ServicePanel from '@/components/homeService/ServicePanel.uvue'
|
||||
import ServiceStatusTag from '@/components/homeService/ServiceStatusTag.uvue'
|
||||
import ServiceTimeline from '@/components/homeService/ServiceTimeline.uvue'
|
||||
import { fetchConsumerHomeServiceCaseDetail } from '@/services/homeServiceService.uts'
|
||||
import { dispatchPaidHomecareOrder, HOMECARE_DISPATCH_STATUS_FAILED, showHomecareDispatchFailureModal } from '@/services/serviceOrderService.uts'
|
||||
import { dispatchPaidHomecareOrder, HOMECARE_DISPATCH_STATUS_FAILED, showHomecareDispatchFailureModal, confirmHomecareArrival } from '@/services/serviceOrderService.uts'
|
||||
import { HomeServiceCaseType } from '@/types/home-service.uts'
|
||||
import { getCurrentUser, getCurrentUserId } from '@/utils/store.uts'
|
||||
import { goToLogin } from '@/utils/utils.uts'
|
||||
|
||||
const ENABLE_ARRIVAL_CONFIRM = false
|
||||
|
||||
const caseId = ref('')
|
||||
const detail = ref<HomeServiceCaseType | null>(null)
|
||||
const consumerOrderTraceId = ref('')
|
||||
|
||||
function normalizeOrderStatusCode(status: string): string {
|
||||
if (status == null) return ''
|
||||
return status.trim().toUpperCase()
|
||||
}
|
||||
|
||||
function isArrivalPendingStatus(status: string): boolean {
|
||||
const s = normalizeOrderStatusCode(status)
|
||||
return s == 'ARRIVAL_PENDING'
|
||||
|| s == 'WAITING_CONSUMER_CONFIRM'
|
||||
|| s == 'WAITING_ARRIVAL_CONFIRM'
|
||||
}
|
||||
|
||||
function consumerLog(step: string, message: string, data: any | null = null) {
|
||||
const tid = consumerOrderTraceId.value
|
||||
if (data == null) {
|
||||
console.log(`[CONSUMER_ORDER_DETAIL_TRACE][${step}][traceId=${tid}][${new Date().toISOString()}] ${message}`)
|
||||
} else {
|
||||
console.log(`[CONSUMER_ORDER_DETAIL_TRACE][${step}][traceId=${tid}][${new Date().toISOString()}] ${message}`, data)
|
||||
}
|
||||
}
|
||||
|
||||
function consumerWarn(step: string, message: string, data: any | null = null) {
|
||||
const tid = consumerOrderTraceId.value
|
||||
if (data == null) {
|
||||
console.warn(`[CONSUMER_ORDER_DETAIL_TRACE][${step}][traceId=${tid}][${new Date().toISOString()}] ${message}`)
|
||||
} else {
|
||||
console.warn(`[CONSUMER_ORDER_DETAIL_TRACE][${step}][traceId=${tid}][${new Date().toISOString()}] ${message}`, data)
|
||||
}
|
||||
}
|
||||
|
||||
function consumerError(step: string, message: string, e: any, extra: any | null = null) {
|
||||
const tid = consumerOrderTraceId.value
|
||||
console.error(`[CONSUMER_ORDER_DETAIL_TRACE][${step}][traceId=${tid}][${new Date().toISOString()}] ${message}`, {
|
||||
errorMessage: e != null ? String(e) : '',
|
||||
errorStack: '',
|
||||
extra: extra
|
||||
})
|
||||
}
|
||||
|
||||
const isArrivalPending = computed<boolean>(() => {
|
||||
if (!ENABLE_ARRIVAL_CONFIRM) return false
|
||||
if (detail.value == null) return false
|
||||
return isArrivalPendingStatus(detail.value.status)
|
||||
|| detail.value.waitingConsumerConfirm == true
|
||||
})
|
||||
|
||||
const displayStatusText = computed<string>(() => {
|
||||
if (detail.value == null) return ''
|
||||
if (isArrivalPending.value) return '等待消费者确认到达'
|
||||
return detail.value.statusText
|
||||
})
|
||||
|
||||
const displayStatusTone = computed<string>(() => {
|
||||
if (detail.value == null) return 'neutral'
|
||||
if (isArrivalPending.value) return 'warning'
|
||||
return detail.value.statusTone
|
||||
})
|
||||
|
||||
async function ensureLogin(): Promise<boolean> {
|
||||
const user = await getCurrentUser()
|
||||
if (user == null || getCurrentUserId() == '') {
|
||||
consumerWarn('C04_AUTH', 'redirect to login because current user is empty', {
|
||||
caseId: caseId.value
|
||||
})
|
||||
goToLogin('/pages/mall/consumer/home-service/order-detail?id=' + caseId.value)
|
||||
return false
|
||||
}
|
||||
@@ -142,14 +222,66 @@ async function ensureLogin(): Promise<boolean> {
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
consumerLog('C03_LOAD_DETAIL', 'loadData start', {
|
||||
caseId: caseId.value
|
||||
})
|
||||
if (caseId.value == '') {
|
||||
consumerWarn('C03_LOAD_DETAIL', 'blocked: caseId empty')
|
||||
return
|
||||
}
|
||||
if (!(await ensureLogin())) {
|
||||
const loginOk = await ensureLogin()
|
||||
consumerLog('C04_AUTH', 'ensureLogin result', {
|
||||
ok: loginOk,
|
||||
userId: getCurrentUserId()
|
||||
})
|
||||
if (!loginOk) {
|
||||
consumerWarn('C04_AUTH', 'blocked: not logged in', {
|
||||
caseId: caseId.value
|
||||
})
|
||||
detail.value = null
|
||||
return
|
||||
}
|
||||
detail.value = await fetchConsumerHomeServiceCaseDetail(caseId.value)
|
||||
try {
|
||||
consumerLog('C05_DETAIL_RPC', 'fetchConsumerHomeServiceCaseDetail request', {
|
||||
caseId: caseId.value
|
||||
})
|
||||
const result = await fetchConsumerHomeServiceCaseDetail(caseId.value)
|
||||
consumerLog('C06_DETAIL_RESULT_RAW', 'fetchConsumerHomeServiceCaseDetail raw result', result)
|
||||
detail.value = result
|
||||
consumerLog('C07_DETAIL_RESULT_PARSED', 'detail parsed', {
|
||||
id: detail.value != null ? detail.value.id : '',
|
||||
orderNo: detail.value != null ? detail.value.caseNo : '',
|
||||
status: detail.value != null ? detail.value.status : '',
|
||||
statusText: detail.value != null ? detail.value.statusText : '',
|
||||
dispatchStatus: '',
|
||||
paymentStatus: detail.value != null && detail.value.paymentStatus != null ? detail.value.paymentStatus : 0,
|
||||
checkinTime: detail.value != null ? detail.value.checkinTime : '',
|
||||
arriveTime: detail.value != null ? detail.value.checkinTime : '',
|
||||
evidenceCount: detail.value != null ? detail.value.evidenceCount : 0,
|
||||
isArrivalPending: isArrivalPending.value,
|
||||
timelineCount: detail.value != null ? detail.value.timeline.length : 0
|
||||
})
|
||||
if (detail.value != null) {
|
||||
consumerLog('C08_STATUS_CHECK', 'detail status resolved after reload', {
|
||||
status: detail.value.status,
|
||||
statusText: detail.value.statusText,
|
||||
checkinTime: detail.value.checkinTime,
|
||||
arriveTime: detail.value.checkinTime,
|
||||
timeline: detail.value.timeline
|
||||
})
|
||||
}
|
||||
if (detail.value != null && ENABLE_ARRIVAL_CONFIRM && isArrivalPending.value == true) {
|
||||
consumerLog('C08_STATUS_CHECK', 'arrival pending detected, confirm card should display', {
|
||||
status: detail.value.status,
|
||||
statusText: detail.value.statusText
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
consumerError('C05_DETAIL_RPC', 'fetchConsumerHomeServiceCaseDetail failed', e, {
|
||||
caseId: caseId.value
|
||||
})
|
||||
detail.value = null
|
||||
}
|
||||
}
|
||||
|
||||
function goFeedback() {
|
||||
@@ -213,6 +345,126 @@ function contactService() {
|
||||
uni.showToast({ title: '即将接入专属客服入口', icon: 'none' })
|
||||
}
|
||||
|
||||
async function confirmArrival(confirm: boolean, reason: string): Promise<void> {
|
||||
consumerLog('C09_CONFIRM_ARRIVAL', 'confirmArrival start', {
|
||||
id: detail.value != null ? detail.value.id : '',
|
||||
status: detail.value != null ? detail.value.status : '',
|
||||
confirm: confirm,
|
||||
reason: reason
|
||||
})
|
||||
if (detail.value == null || detail.value.id == '') {
|
||||
consumerWarn('C09_CONFIRM_ARRIVAL', 'blocked: detail missing', {
|
||||
confirm: confirm,
|
||||
reason: reason
|
||||
})
|
||||
uni.showToast({ title: '订单信息异常', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
uni.showLoading({ title: confirm ? '正在确认' : '正在提交反馈', mask: true })
|
||||
try {
|
||||
consumerLog('C10_CONFIRM_RPC', 'confirmHomecareArrival request', {
|
||||
id: detail.value.id,
|
||||
confirm: confirm,
|
||||
reason: reason
|
||||
})
|
||||
const result = await confirmHomecareArrival(detail.value.id, confirm, reason)
|
||||
consumerLog('C11_CONFIRM_RESULT', 'confirmHomecareArrival result', result)
|
||||
uni.hideLoading()
|
||||
|
||||
if (confirm) {
|
||||
uni.showToast({ title: '已确认到达', icon: 'success' })
|
||||
} else {
|
||||
uni.showToast({ title: '已提交反馈', icon: 'none' })
|
||||
}
|
||||
|
||||
// 重新拉取订单详情
|
||||
await loadData()
|
||||
consumerLog('C12_CONFIRM_RELOAD', 'reload after confirmArrival finished', {
|
||||
status: detail.value != null ? detail.value.status : '',
|
||||
statusText: detail.value != null ? detail.value.statusText : ''
|
||||
})
|
||||
} catch (e) {
|
||||
uni.hideLoading()
|
||||
consumerError('C10_CONFIRM_RPC', 'confirmHomecareArrival failed', e, {
|
||||
id: detail.value != null ? detail.value.id : '',
|
||||
confirm: confirm,
|
||||
reason: reason
|
||||
})
|
||||
uni.showToast({ title: '操作失败,请稍后重试', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
function goHome() {
|
||||
uni.navigateTo({ url: '/pages/mall/consumer/home-service/index' })
|
||||
}
|
||||
|
||||
function getPayExpireMs(caseDetail: HomeServiceCaseType): number {
|
||||
if (caseDetail.payExpireAt == null || caseDetail.payExpireAt == '') {
|
||||
return 0
|
||||
}
|
||||
const parsed = Date.parse(caseDetail.payExpireAt)
|
||||
return isNaN(parsed) ? 0 : parsed
|
||||
}
|
||||
|
||||
function isPaymentTimeExpired(caseDetail: HomeServiceCaseType): boolean {
|
||||
if (caseDetail.paymentStatus != 1 || caseDetail.status != 'created') {
|
||||
return false
|
||||
}
|
||||
const expireMs = getPayExpireMs(caseDetail)
|
||||
if (expireMs <= 0) {
|
||||
return false
|
||||
}
|
||||
return expireMs <= Date.now()
|
||||
}
|
||||
|
||||
const isServicePaymentExpired = computed<boolean>(() => {
|
||||
if (detail.value == null) {
|
||||
return false
|
||||
}
|
||||
return isPaymentTimeExpired(detail.value)
|
||||
})
|
||||
|
||||
let isRetryDispatching = false
|
||||
|
||||
function retryDispatch() {
|
||||
if (isRetryDispatching || detail.value == null) {
|
||||
return
|
||||
}
|
||||
const currentId = detail.value.id
|
||||
isRetryDispatching = true
|
||||
uni.showLoading({ title: '正在重新派单', mask: true })
|
||||
dispatchPaidHomecareOrder(currentId).then((result) => {
|
||||
uni.hideLoading()
|
||||
console.log('[retryDispatch] 派单结果:', JSON.stringify(result))
|
||||
if (result.success) {
|
||||
uni.showToast({ title: '派单成功', icon: 'success' })
|
||||
loadData()
|
||||
return
|
||||
}
|
||||
showHomecareDispatchFailureModal(currentId, result, (id: string) => {
|
||||
retryDispatch()
|
||||
})
|
||||
}).catch((e) => {
|
||||
uni.hideLoading()
|
||||
console.error('[retryDispatch] 重新派单异常:', e)
|
||||
uni.showModal({
|
||||
title: '派单服务异常',
|
||||
content: '派单服务暂时异常,请稍后重试',
|
||||
showCancel: true,
|
||||
cancelText: '稍后再试',
|
||||
confirmText: '重新派单',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
retryDispatch()
|
||||
}
|
||||
}
|
||||
})
|
||||
}).finally(() => {
|
||||
isRetryDispatching = false
|
||||
})
|
||||
}
|
||||
|
||||
function getLatestTimelineRemark(caseDetail: HomeServiceCaseType): string {
|
||||
if (caseDetail.timeline.length > 0) {
|
||||
return caseDetail.timeline[0].description
|
||||
@@ -258,6 +510,11 @@ const consumerViewState = computed(() => {
|
||||
result.exceptionTitle = '服务人员已到达'
|
||||
result.exceptionDesc = '服务人员已到达服务地点,服务正在进行中。'
|
||||
result.statusUpdatedAt = detail.value.serviceTime
|
||||
} else if (isArrivalPending.value) {
|
||||
result.showExceptionPanel = true
|
||||
result.exceptionTitle = '待确认到达'
|
||||
result.exceptionDesc = '服务人员已到达现场并提交签到,请确认是否已到达。'
|
||||
result.statusUpdatedAt = detail.value.serviceTime
|
||||
} else if (status == 'rejected') {
|
||||
result.showExceptionPanel = true
|
||||
result.exceptionTitle = '当前预约暂未安排到服务人员'
|
||||
@@ -310,16 +567,31 @@ function stopDetailRefreshTimer(): void {
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
consumerOrderTraceId.value = Date.now().toString()
|
||||
consumerLog('C01_ROUTE', 'consumer order detail onLoad start', {
|
||||
rawOptions: options,
|
||||
caseId: options != null && options['id'] != null ? String(options['id']) : ''
|
||||
})
|
||||
const id = options['id']
|
||||
if (id != null) {
|
||||
caseId.value = id as string
|
||||
consumerLog('C01_ROUTE', 'caseId resolved', {
|
||||
caseId: caseId.value
|
||||
})
|
||||
loadData().then(() => {
|
||||
startDetailRefreshTimer()
|
||||
})
|
||||
} else {
|
||||
consumerWarn('C01_ROUTE', 'missing caseId, stop load', {
|
||||
rawOptions: options
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
consumerLog('C02_PAGE_SHOW', 'page show, reload detail', {
|
||||
caseId: caseId.value
|
||||
})
|
||||
loadData().then(() => {
|
||||
startDetailRefreshTimer()
|
||||
})
|
||||
@@ -506,4 +778,72 @@ onUnload(() => {
|
||||
font-size: 22rpx;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.dispatch-fail-banner {
|
||||
margin-top: 18rpx;
|
||||
padding: 18rpx 24rpx;
|
||||
background: #fff7ed;
|
||||
border-radius: 16rpx;
|
||||
border-width: 1rpx;
|
||||
border-style: solid;
|
||||
border-color: #fed7aa;
|
||||
}
|
||||
|
||||
.dispatch-fail-text {
|
||||
font-size: 26rpx;
|
||||
color: #c2410c;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
|
||||
.arrival-confirm-card {
|
||||
background: linear-gradient(180deg, #fffbeb 0%, #fef3c7 100%);
|
||||
border-radius: 32rpx;
|
||||
padding: 28rpx;
|
||||
box-shadow: 0 12rpx 24rpx rgba(180, 83, 9, 0.1);
|
||||
margin-bottom: 24rpx;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.arrival-confirm-header {
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.arrival-confirm-title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 700;
|
||||
color: #92400e;
|
||||
}
|
||||
|
||||
.arrival-confirm-desc {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.arrival-confirm-actions {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.arrival-confirm-secondary-btn,
|
||||
.arrival-confirm-primary-btn {
|
||||
flex: 1;
|
||||
padding: 20rpx 0;
|
||||
border-radius: 24rpx;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.arrival-confirm-secondary-btn {
|
||||
background: #ffffff;
|
||||
color: #66788a;
|
||||
border-width: 2rpx;
|
||||
border-style: solid;
|
||||
border-color: #cbd5e1;
|
||||
}
|
||||
|
||||
.arrival-confirm-primary-btn {
|
||||
background: #f59e0b;
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user