|
|
@@ -0,0 +1,466 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import OrderDetailStatus from '../components/orderDetailStatus.vue'
|
|
|
+import { columns as creditTypeColumns } from '../attractionsReservation/reservation-data'
|
|
|
+import { orderStatus } from './orderDetail-data'
|
|
|
+import { StaticUrl } from '@/config'
|
|
|
+import router from '@/router'
|
|
|
+
|
|
|
+definePage({
|
|
|
+ name: 'attractions-order-detail',
|
|
|
+ islogin: false,
|
|
|
+ style: {
|
|
|
+ navigationBarTitleText: '订单详情',
|
|
|
+ navigationStyle: 'custom',
|
|
|
+ },
|
|
|
+})
|
|
|
+const { statusBarHeight, MenuButtonHeight, opcity } = storeToRefs(useSysStore())
|
|
|
+const orderNumber = ref('')
|
|
|
+const orderInfo = ref<Api.ScenicOrderDetailVo>()
|
|
|
+const orderPopup = ref(false)
|
|
|
+const refundNum = ref(1)
|
|
|
+const refundReason = ref('')
|
|
|
+const ispay = ref('')
|
|
|
+
|
|
|
+const statusValue = computed(() => orderInfo.value?.hbOrderStatus ?? 0)
|
|
|
+
|
|
|
+/** 当前状态配置 */
|
|
|
+const currentStatus = computed(() => {
|
|
|
+ return orderStatus.find(item => item.value === statusValue.value) || orderStatus[0]
|
|
|
+})
|
|
|
+
|
|
|
+/** 有凭证码的游客列表 */
|
|
|
+const voucherPeoples = computed(() => {
|
|
|
+ return orderInfo.value?.peoples?.filter(p => p.voucherCode) ?? []
|
|
|
+})
|
|
|
+
|
|
|
+/** 是否展示凭证区域 */
|
|
|
+const hasVoucher = computed(() => voucherPeoples.value.length > 0)
|
|
|
+
|
|
|
+const swiperCurrent = ref(0)
|
|
|
+function onSwiperChange(e: any) {
|
|
|
+ swiperCurrent.value = e.detail.current
|
|
|
+}
|
|
|
+
|
|
|
+/** 证件类型文本 */
|
|
|
+function creditTypeText(type?: number) {
|
|
|
+ return creditTypeColumns.value.find(item => item.value === type)?.label ?? '身份证'
|
|
|
+}
|
|
|
+
|
|
|
+async function getData(orderNo: string) {
|
|
|
+ const res = await Apis.attractions.orderDetail({ data: { orderNumber: orderNo } })
|
|
|
+ orderInfo.value = res.data
|
|
|
+}
|
|
|
+
|
|
|
+function handleRefundMinus() {
|
|
|
+ if (refundNum.value > 1)
|
|
|
+ refundNum.value--
|
|
|
+}
|
|
|
+
|
|
|
+function handleRefundPlus() {
|
|
|
+ const maxNum = orderInfo.value?.scenicOrder?.num ?? 1
|
|
|
+ if (refundNum.value < maxNum)
|
|
|
+ refundNum.value++
|
|
|
+}
|
|
|
+
|
|
|
+function handleGoPay() {
|
|
|
+ router.push({
|
|
|
+ name: 'attractions-order-pay',
|
|
|
+ params: {
|
|
|
+ productName: orderInfo.value?.scenicOrder?.productName || '',
|
|
|
+ num: String(orderInfo.value?.scenicOrder?.num) || '',
|
|
|
+ orderNo: orderInfo.value?.orderNumber || '',
|
|
|
+ },
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+function handleRebook() {
|
|
|
+ router.push({
|
|
|
+ name: 'attractions-detail',
|
|
|
+ params: {
|
|
|
+ productNo: String(orderInfo.value?.scenicOrder?.productNo),
|
|
|
+ },
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+/** 是否显示取消/退款按钮 */
|
|
|
+const showCancelOrRefundButton = computed(() => {
|
|
|
+ const status = statusValue.value
|
|
|
+ const cancelState = orderInfo.value?.cancelRecords?.cancelState
|
|
|
+ const isChangeask = orderInfo.value?.scenicOrder?.isChangeask
|
|
|
+
|
|
|
+ // 必须允许退改申请
|
|
|
+ if (isChangeask !== 1)
|
|
|
+ return false
|
|
|
+
|
|
|
+ // 状态为0(待支付)时可以取消订单
|
|
|
+ if (status === 0)
|
|
|
+ return true
|
|
|
+
|
|
|
+ // 状态为60(已退款)或80(已完成)时不显示
|
|
|
+ if (status === 60 || status === 80)
|
|
|
+ return false
|
|
|
+
|
|
|
+ // 其他状态:没有退款申请或申请已通过时可以再次申请
|
|
|
+ return cancelState == null || cancelState === 1
|
|
|
+})
|
|
|
+
|
|
|
+const isCancel = computed(() => statusValue.value === 0)
|
|
|
+
|
|
|
+/** 取消订单 / 申请退款 */
|
|
|
+async function handleCancelOrder() {
|
|
|
+ orderPopup.value = false
|
|
|
+ useGlobalMessage().confirm({
|
|
|
+ title: '提示',
|
|
|
+ msg: `确定要${isCancel.value ? '取消订单' : '退款'}吗?`,
|
|
|
+ success: async () => {
|
|
|
+ if (isCancel.value) {
|
|
|
+ await Apis.attractions.cancelOrder({
|
|
|
+ data: {
|
|
|
+ orderNumber: orderInfo.value?.orderNumber || '',
|
|
|
+ cancelNum: refundNum.value,
|
|
|
+ cancelMemo: refundReason.value || undefined,
|
|
|
+ },
|
|
|
+ })
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ await Apis.xsb.applyRefund({
|
|
|
+ data: {
|
|
|
+ businessType: 2,
|
|
|
+ buyerDesc: refundReason.value || undefined,
|
|
|
+ orderNumber: orderInfo.value?.orderNumber || '',
|
|
|
+ },
|
|
|
+ })
|
|
|
+ }
|
|
|
+ refundNum.value = 1
|
|
|
+ refundReason.value = ''
|
|
|
+ useGlobalToast().show({ msg: '操作成功' })
|
|
|
+ await getData(orderNumber.value)
|
|
|
+ },
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+onLoad((options: any) => {
|
|
|
+ orderNumber.value = options.orderNo
|
|
|
+ ispay.value = options.ispay
|
|
|
+ getData(options.orderNo)
|
|
|
+})
|
|
|
+onMounted(() => {
|
|
|
+ opcity.value = 0
|
|
|
+})
|
|
|
+
|
|
|
+onPageScroll((e) => {
|
|
|
+ const calculatedOpacity = e.scrollTop / 100
|
|
|
+ opcity.value = Math.min(1, Math.max(0.1, calculatedOpacity))
|
|
|
+})
|
|
|
+
|
|
|
+function orderDetailBack() {
|
|
|
+ const vrIndex = 'subPack-attractions/commonTab/index'
|
|
|
+ const pages = getCurrentPages()
|
|
|
+ const targetPageIndex = pages.findIndex(page => page.route === vrIndex)
|
|
|
+ if (ispay.value === 'true') {
|
|
|
+ if (targetPageIndex !== -1) {
|
|
|
+ const delta = pages.length - targetPageIndex - 1
|
|
|
+ router.back({ delta, animationType: 'fade-out' })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ router.back()
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <view class="order-detail-page">
|
|
|
+ <wd-navbar
|
|
|
+ title="景区门票"
|
|
|
+ :custom-style="`background-color: rgba(226, 255, 145, ${opcity})`"
|
|
|
+ :bordered="false"
|
|
|
+ :z-index="9999"
|
|
|
+ safe-area-inset-top
|
|
|
+ left-arrow
|
|
|
+ fixed
|
|
|
+ @click-left="orderDetailBack"
|
|
|
+ />
|
|
|
+ <view :style="{ height: `${(Number(statusBarHeight) || 44) + MenuButtonHeight + 30}px` }" />
|
|
|
+ <view v-if="orderInfo" class="px-24rpx">
|
|
|
+ <view class="rounded-16rpx bg-#FFF p-24rpx">
|
|
|
+ <OrderDetailStatus v-if="!hasVoucher || orderInfo.hbOrderStatus == 60" :status="statusValue" @pay="handleGoPay" @rebook="handleRebook" />
|
|
|
+ <view class="flex items-center justify-between gap-50rpx text-32rpx font-bold">
|
|
|
+ <view>{{ orderInfo.scenicOrder?.productName }}</view>
|
|
|
+ <view class="w-100rpx text-24rpx text-#9ED605" @click="router.push({ name: 'attractions-detail', params: { productNo: String(orderInfo.scenicOrder?.productNo) } })">
|
|
|
+ 详情
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view v-if="hasVoucher && orderInfo.hbOrderStatus != 60" class="text-center">
|
|
|
+ <view class="mt-24rpx h-2rpx w-full bg-#F0F0F0" />
|
|
|
+ <view class="mt-24rpx flex items-center justify-center gap-10rpx">
|
|
|
+ <wd-icon :name="currentStatus.icon" size="20px" :color="currentStatus.color" />
|
|
|
+ <text class="text-32rpx font-bold" :style="{ color: currentStatus.color }">
|
|
|
+ {{ currentStatus.label }}
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <swiper
|
|
|
+ :style="{ height: '340rpx' }"
|
|
|
+ :current="swiperCurrent"
|
|
|
+ :indicator-dots="false"
|
|
|
+ @change="onSwiperChange"
|
|
|
+ >
|
|
|
+ <swiper-item v-for="(people, idx) in voucherPeoples" :key="idx" class="flex flex-col items-center justify-center">
|
|
|
+ <view class="flex items-center justify-center">
|
|
|
+ <QCode class="mb-20rpx rounded-16rpx" :text="people.voucherCode || ''" :qwidth="80" :qr-key="`qr-${idx}`" />
|
|
|
+ </view>
|
|
|
+ <view class="text-28rpx font-bold">
|
|
|
+ {{ people.voucherCode }}
|
|
|
+ </view>
|
|
|
+ <view class="mt-8rpx text-24rpx text-#AAAAAA">
|
|
|
+ ({{ people.voucherStatus === 1 ? '已核销' : '未核销' }})
|
|
|
+ </view>
|
|
|
+ </swiper-item>
|
|
|
+ </swiper>
|
|
|
+ <view class="text-24rpx text-#AAAAAA">
|
|
|
+ {{ currentStatus.desc }}
|
|
|
+ </view>
|
|
|
+ <view class="mt-24rpx flex items-center justify-center gap-10rpx" @click="router.push({ name: 'attractions-tabbar', params: { tabbar: '1' } })">
|
|
|
+ <text class="text-28rpx">
|
|
|
+ 查看订单列表
|
|
|
+ </text>
|
|
|
+ <wd-icon name="chevron-right" size="20px" />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-20rpx rounded-16rpx bg-#FFF p-24rpx">
|
|
|
+ <view class="mt-28rpx flex items-center justify-between">
|
|
|
+ <view class="text-28rpx text-#AAAAAA">
|
|
|
+ 订单编号
|
|
|
+ </view>
|
|
|
+ <view class="text-28rpx font-bold">
|
|
|
+ {{ orderInfo.orderNumber }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-28rpx flex items-center justify-between">
|
|
|
+ <view class="text-28rpx text-#AAAAAA">
|
|
|
+ 下单时间
|
|
|
+ </view>
|
|
|
+ <view class="text-28rpx font-bold">
|
|
|
+ {{ orderInfo.createTime }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-28rpx flex items-center justify-between">
|
|
|
+ <view class="text-28rpx text-#AAAAAA">
|
|
|
+ 游玩时间
|
|
|
+ </view>
|
|
|
+ <view class="text-28rpx font-bold">
|
|
|
+ {{ orderInfo.scenicOrder?.travelDate }} 当天
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view v-if="orderInfo.scenicOrder?.orderMemo" class="mt-28rpx rounded-16rpx bg-#F1F1F1 p-24rpx text-28rpx text-#AAAAAA">
|
|
|
+ 备注:{{ orderInfo.scenicOrder?.orderMemo }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-20rpx rounded-16rpx bg-#FFF p-24rpx">
|
|
|
+ <view class="flex items-center justify-between">
|
|
|
+ <view class="text-bold text-28rpx">
|
|
|
+ 订单总金额
|
|
|
+ </view>
|
|
|
+ <view class="text-bold text-32rpx text-#FF4A39">
|
|
|
+ <text class="text-24rpx">
|
|
|
+ ¥
|
|
|
+ </text>
|
|
|
+ {{ orderInfo.orderMoney }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view v-if="orderInfo.offsetPoints" class="mt-20rpx flex items-center justify-between text-24rpx">
|
|
|
+ <view>积分扣减</view>
|
|
|
+ <view class="text-#FF4A39">
|
|
|
+ ¥{{ orderInfo.offsetPoints }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-20rpx flex items-center justify-between text-24rpx">
|
|
|
+ <view>微信支付</view>
|
|
|
+ <view class="text-#FF4A39">
|
|
|
+ ¥{{ orderInfo.actualTotal }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-20rpx rounded-16rpx bg-#FFF p-24rpx">
|
|
|
+ <view class="text-28rpx font-bold">
|
|
|
+ 联系人资料
|
|
|
+ </view>
|
|
|
+ <view class="mt-24rpx flex items-center gap-92rpx">
|
|
|
+ <view class="text-24rpx">
|
|
|
+ 联系人
|
|
|
+ </view>
|
|
|
+ <view class="text-bold text-24rpx">
|
|
|
+ {{ orderInfo.scenicOrder?.linkMan }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-24rpx h-2rpx w-full bg-#F0F0F0" />
|
|
|
+ <view class="mt-24rpx flex items-center gap-92rpx">
|
|
|
+ <view class="text-24rpx">
|
|
|
+ 手机号码
|
|
|
+ </view>
|
|
|
+ <view class="text-bold text-24rpx">
|
|
|
+ {{ orderInfo.scenicOrder?.linkPhone }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <!-- 游客信息 -->
|
|
|
+ <view v-for="(people, idx) in orderInfo.peoples" :key="idx" class="mt-20rpx rounded-16rpx bg-#FFF p-24rpx">
|
|
|
+ <view class="text-28rpx font-bold">
|
|
|
+ 游客信息{{ (orderInfo.peoples?.length ?? 0) > 1 ? ` ${idx + 1}` : '' }}
|
|
|
+ </view>
|
|
|
+ <view class="mt-24rpx flex items-center gap-92rpx">
|
|
|
+ <view class="text-24rpx">
|
|
|
+ 游客姓名
|
|
|
+ </view>
|
|
|
+ <view class="text-bold text-24rpx">
|
|
|
+ {{ people.linkMan }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-24rpx h-2rpx w-full bg-#F0F0F0" />
|
|
|
+ <view class="mt-24rpx flex items-center gap-92rpx">
|
|
|
+ <view class="text-24rpx">
|
|
|
+ 证件类型
|
|
|
+ </view>
|
|
|
+ <view class="text-bold text-24rpx">
|
|
|
+ {{ creditTypeText(people.linkCreditType) }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-24rpx h-2rpx w-full bg-#F0F0F0" />
|
|
|
+ <view class="mt-24rpx flex items-center gap-92rpx">
|
|
|
+ <view class="text-24rpx">
|
|
|
+ 证件号码
|
|
|
+ </view>
|
|
|
+ <view class="text-bold text-24rpx">
|
|
|
+ {{ people.linkCreditNo }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view v-if="orderInfo.cancelRecords?.cancelId" class="mt-20rpx rounded-16rpx bg-#FFF p-24rpx">
|
|
|
+ <view class="text-28rpx font-bold">
|
|
|
+ 退款申请
|
|
|
+ </view>
|
|
|
+ <view class="mt-28rpx flex items-center justify-between">
|
|
|
+ <view class="text-28rpx text-#AAAAAA">
|
|
|
+ 申请时间
|
|
|
+ </view>
|
|
|
+ <view class="text-28rpx font-bold">
|
|
|
+ {{ orderInfo.cancelRecords?.createTime }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-28rpx flex items-center justify-between">
|
|
|
+ <view class="text-28rpx text-#AAAAAA">
|
|
|
+ 申请说明
|
|
|
+ </view>
|
|
|
+ <view class="text-28rpx font-bold">
|
|
|
+ {{ orderInfo.cancelRecords?.cancelReason || '--' }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-28rpx flex items-center justify-between">
|
|
|
+ <view class="text-28rpx text-#AAAAAA">
|
|
|
+ 处理状态
|
|
|
+ </view>
|
|
|
+ <view v-if="orderInfo.cancelRecords" class="text-28rpx font-bold">
|
|
|
+ <text v-if="orderInfo.cancelRecords?.cancelState === 0">
|
|
|
+ 申请中
|
|
|
+ </text>
|
|
|
+ <text v-if="orderInfo.cancelRecords?.cancelState === 1">
|
|
|
+ 通过
|
|
|
+ </text>
|
|
|
+ <text v-if="orderInfo.cancelRecords?.cancelState === 2">
|
|
|
+ 拒绝
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="h-220rpx" />
|
|
|
+ <view
|
|
|
+ class="fixed bottom-0 left-0 z-100 box-border h-174rpx w-full flex items-center gap-28rpx bg-#FFF px-24rpx"
|
|
|
+ style="border-top: 2rpx solid #EEEEEE;"
|
|
|
+ >
|
|
|
+ <view class="flex items-center gap-40rpx">
|
|
|
+ <view @click="router.replace({ name: 'attractions-tabbar' })">
|
|
|
+ <image
|
|
|
+ :src="`${StaticUrl}/goods-home.png`"
|
|
|
+ class="h44rpx w44rpx"
|
|
|
+ />
|
|
|
+ <view class="text-20rpx">
|
|
|
+ 首页
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="relative">
|
|
|
+ <image
|
|
|
+ :src="`${StaticUrl}/goods-kf.png`"
|
|
|
+ class="h44rpx w44rpx"
|
|
|
+ />
|
|
|
+ <Zcontact>
|
|
|
+ <view class="text-20rpx">
|
|
|
+ 客服
|
|
|
+ </view>
|
|
|
+ </Zcontact>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <wd-button v-if="showCancelOrRefundButton" custom-class="w-546rpx" block size="large" @click="orderPopup = true">
|
|
|
+ {{ isCancel ? '取消订单' : '退款申请' }}
|
|
|
+ </wd-button>
|
|
|
+ </view>
|
|
|
+ <Zpopup v-model="orderPopup" :showfooter="false" :zindex="9999" bg="#fff">
|
|
|
+ <view>
|
|
|
+ <view class="mt-28rpx text-center text-32rpx font-bold">
|
|
|
+ {{ isCancel ? '取消订单' : '退款申请' }}
|
|
|
+ </view>
|
|
|
+ <view class="px-24rpx">
|
|
|
+ <view class="mt-30rpx flex items-center justify-between">
|
|
|
+ <view class="text-28rpx">
|
|
|
+ 退款数量
|
|
|
+ </view>
|
|
|
+ <view v-if="isCancel" class="flex items-center gap-24rpx">
|
|
|
+ <view
|
|
|
+ class="h-36rpx w-36rpx rounded-50% bg-#F0F0F0 text-center text-28rpx text-#AAAAAA font-600 line-height-[36rpx]"
|
|
|
+ @click="handleRefundMinus"
|
|
|
+ >
|
|
|
+ -
|
|
|
+ </view>
|
|
|
+ <view class="text-24rpx font-400">
|
|
|
+ {{ refundNum }}
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ class="h-36rpx w-36rpx rounded-50% bg-#E8FFA7 text-center text-28rpx text-#9ED605 font-600 line-height-[36rpx]"
|
|
|
+ @click="handleRefundPlus"
|
|
|
+ >
|
|
|
+ +
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view v-else class="text-24rpx font-400">
|
|
|
+ {{ orderInfo?.scenicOrder?.num ?? 0 }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-26rpx">
|
|
|
+ <view class="text-28rpx">
|
|
|
+ 退款申请说明
|
|
|
+ </view>
|
|
|
+ <view class="mt-20rpx rounded-16rpx bg-#F1F1F1">
|
|
|
+ <textarea
|
|
|
+ v-model="refundReason"
|
|
|
+ class="h-120rpx w-full rounded-16rpx p-24rpx"
|
|
|
+ placeholder-style="color: #AAAAAA; font-size: 24rpx;"
|
|
|
+ placeholder="请仔细填写,提交后进入审核期,不可重复提交"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="mt-26rpx h-2rpx w-full bg-#EEEEEE" />
|
|
|
+ <view class="flex items-center justify-center">
|
|
|
+ <wd-button custom-class="w-702rpx mt-10rpx" block size="large" @click="handleCancelOrder">
|
|
|
+ 确认提交
|
|
|
+ </wd-button>
|
|
|
+ </view>
|
|
|
+ <view class="h-60rpx" />
|
|
|
+ </view>
|
|
|
+ </Zpopup>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+</style>
|