From 77649c76ec1c3afcb93e9963243d637665b3a307 Mon Sep 17 00:00:00 2001
From: liujie <1793218484@qq.com>
Date: 星期五, 21 八月 2026 16:56:28 +0800
Subject: [PATCH] update
---
mingdaojingjiang_uniapp/mingdaojingjiang_uniapp/pages/order-serving/index.vue | 232 ++++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 185 insertions(+), 47 deletions(-)
diff --git a/mingdaojingjiang_uniapp/mingdaojingjiang_uniapp/pages/order-serving/index.vue b/mingdaojingjiang_uniapp/mingdaojingjiang_uniapp/pages/order-serving/index.vue
index 52c83b4..ca7a30c 100644
--- a/mingdaojingjiang_uniapp/mingdaojingjiang_uniapp/pages/order-serving/index.vue
+++ b/mingdaojingjiang_uniapp/mingdaojingjiang_uniapp/pages/order-serving/index.vue
@@ -6,20 +6,20 @@
<view class="status-panel">
<text class="status-title">讲解中</text>
<text class="countdown-text">{{ countdownText }}</text>
- <view class="team-badge" :style="familyBadgeStyle">
- <text class="team-badge__text">家庭号 {{ familyGroup.number }}</text>
+ <view v-if="order.familyNo" class="team-badge" :style="familyBadgeStyle">
+ <text class="team-badge__text">家庭号 {{ order.familyNo }}</text>
</view>
</view>
<view class="detail-card">
<view class="guide-row">
<view class="guide-avatar">
- <image class="guide-avatar__icon" src="/static/ui-icons/user-blue.svg" mode="aspectFit" />
+ <image class="guide-avatar__icon" :src="order.guideAvatar || '/static/ui-icons/user-blue.svg'" mode="aspectFill" />
</view>
<view class="guide-main">
- <text class="guide-name">导游 · 赵四</text>
+ <text class="guide-name">导游 · {{ order.guideName }}</text>
<view class="guide-stars">
- <text v-for="item in 5" :key="item" class="guide-star">★</text>
+ <text v-for="item in 5" :key="item" class="guide-star" :class="{ 'guide-star--inactive': item > guideStarCount }">★</text>
</view>
</view>
<view class="phone-action" @tap="handleCallGuide">
@@ -42,7 +42,7 @@
<view class="price-row">
<view class="unit-block">
- <text class="unit-price">¥{{ order.unitPrice }}/人</text>
+ <text class="unit-price">¥{{ order.unitPrice }}{{ order.unit }}</text>
<text class="quantity">x{{ order.quantity }}</text>
</view>
<text class="total-price">¥{{ order.total }}</text>
@@ -68,34 +68,45 @@
</template>
<script setup>
-import { computed, onBeforeUnmount, ref } from 'vue'
+import { computed, ref } from 'vue'
+import { onHide, onLoad, onShow, onUnload } from '@dcloudio/uni-app'
import AppNav from '@/components/app-nav/app-nav.vue'
+import { getTourOrder } from '@/services/order'
+import { resolveProfileAssetUrl } from '@/services/profile'
import { useLoginGuard } from '@/utils/auth-guard'
useLoginGuard('/pages/order-serving/index')
-const order = {
- id: 'MJ20260612003',
- scenic: '青城山景区',
- service: '拼团·快讲',
- duration: '30分钟',
- meetingPoint: '青城山正门汇合',
- unitPrice: 36,
- quantity: 4,
- total: '366.00'
-}
+const ORDER_POLL_INTERVAL = 3000
-const familyGroup = {
- number: 1,
- color: '#278BFF'
-}
+const orderId = ref('')
+const orderDetail = ref({})
+const remainingSeconds = ref(0)
+let countdownTimer = null
+let orderPollTimer = null
+let orderRefreshing = false
+let pageActive = false
+let redirecting = false
+let loadErrorShown = false
-const remainingSeconds = ref(30 * 60 * 60)
-const timer = setInterval(() => {
- if (remainingSeconds.value > 0) {
- remainingSeconds.value -= 1
- }
-}, 1000)
+const order = computed(() => ({
+ id: orderDetail.value.id || orderId.value,
+ scenic: orderDetail.value.scenicName || '-',
+ service: formatServiceTitle(orderDetail.value.packageName, orderDetail.value.orderType),
+ duration: orderDetail.value.durationMinutes ? `${orderDetail.value.durationMinutes}分钟` : '-',
+ meetingPoint: orderDetail.value.meetingPointName || '-',
+ unitPrice: formatAmount(orderDetail.value.unitPrice),
+ unit: String(orderDetail.value.orderType || '').startsWith('GROUP_') ? '/人' : '/团',
+ quantity: Number(orderDetail.value.peopleCount || 1),
+ total: formatAmount(orderDetail.value.paymentAmount ?? orderDetail.value.amount),
+ familyNo: orderDetail.value.familyNo || '',
+ guideName: orderDetail.value.guideName || '未分配',
+ guideMobile: orderDetail.value.guideMobile || '',
+ guideAvatar: resolveProfileAssetUrl(orderDetail.value.guideAvatar),
+ guideRating: Number(orderDetail.value.guideRating || 0)
+}))
+
+const guideStarCount = computed(() => Math.max(0, Math.min(5, Math.round(order.value.guideRating))))
const countdownText = computed(() => {
const hours = Math.floor(remainingSeconds.value / 3600)
@@ -105,36 +116,159 @@
})
const familyBadgeStyle = computed(() => ({
- backgroundColor: familyGroup.color
+ backgroundColor: '#278BFF'
}))
-const detailRows = [
- { label: '下单时间', value: '2026-06-04 11:31:02' },
- { label: '接单时间', value: '2026-06-04 11:31:02' },
- { label: '支付金额', value: '¥366.00' },
- { label: '支付流水号', value: '46145113464411' },
- { label: '讲解开始时间', value: '2026-06-04 11:31:02' },
- { label: '讲解结束时间', value: '-' }
-]
+const detailRows = computed(() => [
+ { label: '下单时间', value: formatDateTime(orderDetail.value.placedAt) },
+ { label: '接单时间', value: formatDateTime(orderDetail.value.acceptedAt) },
+ { label: '支付金额', value: `¥${formatAmount(orderDetail.value.paymentAmount ?? orderDetail.value.amount)}` },
+ { label: '支付流水号', value: orderDetail.value.paymentOrderNo || '-' },
+ { label: '讲解开始时间', value: formatDateTime(orderDetail.value.serviceStartedAt) },
+ { label: '讲解结束时间', value: formatDateTime(orderDetail.value.completedAt) }
+])
-onBeforeUnmount(() => {
- clearInterval(timer)
+onLoad((options = {}) => {
+ orderId.value = options.orderId || options.id || ''
})
+
+onShow(() => {
+ pageActive = true
+ redirecting = false
+ startOrderPolling()
+ startCountdown()
+})
+
+onHide(() => {
+ pageActive = false
+ clearTimers()
+})
+
+onUnload(() => {
+ pageActive = false
+ clearTimers()
+})
+
+function startOrderPolling() {
+ if (!orderId.value) {
+ uni.showToast({ title: '订单参数缺失', icon: 'none' })
+ return
+ }
+
+ clearInterval(orderPollTimer)
+ refreshOrderStatus()
+ orderPollTimer = setInterval(refreshOrderStatus, ORDER_POLL_INTERVAL)
+}
+
+async function refreshOrderStatus() {
+ if (!pageActive || !orderId.value || orderRefreshing || redirecting) return
+
+ orderRefreshing = true
+ try {
+ const detail = await getTourOrder(orderId.value)
+ if (!pageActive) return
+ orderDetail.value = detail
+ loadErrorShown = false
+ syncCountdown(detail)
+ redirectForOrderStatus(detail && detail.status)
+ } catch (error) {
+ if (!loadErrorShown) {
+ loadErrorShown = true
+ uni.showToast({ title: error.message || '订单状态更新失败', icon: 'none' })
+ }
+ console.warn('讲解中订单状态查询失败', error)
+ } finally {
+ orderRefreshing = false
+ }
+}
+
+function syncCountdown(detail) {
+ const durationSeconds = Math.max(0, Number(detail && detail.durationMinutes) || 0) * 60
+ const startedAt = parseDateTime(detail && detail.serviceStartedAt)
+ const elapsedSeconds = startedAt ? Math.max(0, Math.floor((Date.now() - startedAt) / 1000)) : 0
+ remainingSeconds.value = Math.max(0, durationSeconds - elapsedSeconds)
+}
+
+function startCountdown() {
+ clearInterval(countdownTimer)
+ countdownTimer = setInterval(() => {
+ if (remainingSeconds.value > 0) remainingSeconds.value -= 1
+ }, 1000)
+}
+
+function redirectForOrderStatus(status) {
+ const routeMap = {
+ PENDING_PAYMENT: '/pages/order-pending-pay/index',
+ PENDING_ACCEPT: '/pages/order-waiting/index',
+ PENDING_MEETING: '/pages/order-pending-guide/index',
+ COMPLETED: '/pages/order-pending-review/index',
+ CANCELLED: '/pages/order-canceled/index',
+ REFUNDED: '/pages/order-canceled/index'
+ }
+ const target = routeMap[status]
+ if (!target || redirecting) return
+
+ redirecting = true
+ clearTimers()
+ uni.redirectTo({
+ url: `${target}?orderId=${orderId.value}`,
+ fail() {
+ redirecting = false
+ if (pageActive) {
+ startOrderPolling()
+ startCountdown()
+ }
+ }
+ })
+}
+
+function clearTimers() {
+ if (countdownTimer) {
+ clearInterval(countdownTimer)
+ countdownTimer = null
+ }
+ if (orderPollTimer) {
+ clearInterval(orderPollTimer)
+ orderPollTimer = null
+ }
+}
+
+function parseDateTime(value) {
+ if (!value) return 0
+ const timestamp = new Date(String(value).replace(' ', 'T')).getTime()
+ return Number.isFinite(timestamp) ? timestamp : 0
+}
function formatTime(value) {
return String(value).padStart(2, '0')
}
+function formatAmount(value) {
+ const amount = Number(value || 0)
+ return Number.isFinite(amount) ? amount.toFixed(2) : '0.00'
+}
+
+function formatDateTime(value) {
+ return value ? String(value).replace('T', ' ').slice(0, 19) : '-'
+}
+
+function formatServiceTitle(packageName, orderType) {
+ if (packageName) return String(packageName).replace(/\s*·\s*/g, '·')
+ const serviceTitleMap = {
+ GROUP_QUICK: '拼团·快讲',
+ GROUP_PREMIUM: '拼团·精讲',
+ PRIVATE_QUICK: '包团·快讲',
+ PRIVATE_PREMIUM: '包团·精讲'
+ }
+ return serviceTitleMap[orderType] || '讲解服务'
+}
+
function handleCallGuide() {
- uni.showActionSheet({
- itemList: ['拨打导游电话'],
- success() {
- uni.showToast({
- title: '电话联系开发中',
- icon: 'none'
- })
- }
- })
+ if (!order.value.guideMobile) {
+ uni.showToast({ title: '暂无导游联系电话', icon: 'none' })
+ return
+ }
+ uni.makePhoneCall({ phoneNumber: order.value.guideMobile })
}
</script>
@@ -256,6 +390,10 @@
line-height: 1;
}
+.guide-star--inactive {
+ color: #d8dde6;
+}
+
.phone-action {
display: flex;
flex-direction: column;
--
Gitblit v1.7.1