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