feat(private-detail): 新增取消预订按钮+阶梯退款弹窗
This commit is contained in:
@@ -63,8 +63,43 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="booking.status === 'pending_pay'" class="fixed-action-bar">
|
<view v-if="booking.status === 'pending_pay' || (booking.status === 'booked' && booking.can_cancel)" class="fixed-action-bar">
|
||||||
<button class="primary-button action-btn" @tap="goPay">去支付</button>
|
<button v-if="booking.status === 'booked' && booking.can_cancel" class="ghost-button action-btn" @tap="onCancelBooking">取消预订</button>
|
||||||
|
<button v-if="booking.status === 'pending_pay'" class="primary-button action-btn" @tap="goPay">去支付</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="refundPopupVisible" class="refund-popup-mask" @tap="closeRefundPopup">
|
||||||
|
<view class="refund-popup" @tap.stop>
|
||||||
|
<view class="refund-popup-header">
|
||||||
|
<text class="refund-popup-title">取消预订</text>
|
||||||
|
<text class="refund-popup-close" @tap="closeRefundPopup">×</text>
|
||||||
|
</view>
|
||||||
|
<view class="refund-popup-body" v-if="refundQuote">
|
||||||
|
<view class="refund-rules">
|
||||||
|
<view class="refund-rules-header">
|
||||||
|
<text>距开始时间</text>
|
||||||
|
<text>退款比例</text>
|
||||||
|
<text>说明</text>
|
||||||
|
</view>
|
||||||
|
<view v-for="(rule, idx) in refundQuote.rules" :key="idx" class="refund-rule-row" :class="{ active: rule.description === refundQuote.applicable_tier_description }">
|
||||||
|
<text>{{ formatHoursBefore(rule.hours_before_start) }}</text>
|
||||||
|
<text>{{ rule.refund_percentage }}%</text>
|
||||||
|
<text>{{ rule.description }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="refund-amount-box">
|
||||||
|
<text class="refund-amount-label">本次退款金额</text>
|
||||||
|
<text class="refund-amount-value">¥{{ refundQuote.refund_amount }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="refund-tips">
|
||||||
|
<text>{{ refundQuote.applicable_tier_description || '当前不可取消' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="refund-popup-footer">
|
||||||
|
<button class="ghost-button refund-btn" @tap="closeRefundPopup">再想想</button>
|
||||||
|
<button class="primary-button refund-btn" @tap="confirmCancelBooking" :disabled="refundLoading">确认取消</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -94,6 +129,49 @@ onLoad(async (query) => {
|
|||||||
const goPay = () => {
|
const goPay = () => {
|
||||||
uni.navigateTo({ url: `/pages/comprehensive/pay/index?order_id=${booking.value.order_id}` })
|
uni.navigateTo({ url: `/pages/comprehensive/pay/index?order_id=${booking.value.order_id}` })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const refundPopupVisible = ref(false)
|
||||||
|
const refundQuote = ref(null)
|
||||||
|
const refundLoading = ref(false)
|
||||||
|
|
||||||
|
const onCancelBooking = async () => {
|
||||||
|
try {
|
||||||
|
const data = await bookingApi.getPrivateBookingRefundQuote(bookingId.value)
|
||||||
|
refundQuote.value = data
|
||||||
|
refundPopupVisible.value = true
|
||||||
|
} catch {
|
||||||
|
uni.showToast({ title: '获取退款信息失败', icon: 'none' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeRefundPopup = () => {
|
||||||
|
refundPopupVisible.value = false
|
||||||
|
refundQuote.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmCancelBooking = async () => {
|
||||||
|
if (refundLoading.value) return
|
||||||
|
refundLoading.value = true
|
||||||
|
try {
|
||||||
|
await bookingApi.cancelPrivateBooking(bookingId.value)
|
||||||
|
refundPopupVisible.value = false
|
||||||
|
const amount = refundQuote.value?.refund_amount || '0'
|
||||||
|
uni.showToast({ title: `取消成功,退款¥${amount}`, icon: 'none' })
|
||||||
|
booking.value = await bookingApi.getPrivateBookingDetail(bookingId.value)
|
||||||
|
} catch {
|
||||||
|
uni.showToast({ title: '取消失败,请稍后重试', icon: 'none' })
|
||||||
|
} finally {
|
||||||
|
refundLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatHoursBefore = (hours) => {
|
||||||
|
const h = Number(hours)
|
||||||
|
if (h >= 24) return '>24小时'
|
||||||
|
if (h >= 12) return '12-24小时'
|
||||||
|
if (h >= 0) return '0-12小时'
|
||||||
|
return `${h}小时`
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -198,4 +276,138 @@ const goPay = () => {
|
|||||||
.action-btn {
|
.action-btn {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.refund-popup-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 999;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-popup {
|
||||||
|
width: 100%;
|
||||||
|
background: $bg-color-soft;
|
||||||
|
border-radius: $border-radius-lg $border-radius-lg 0 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-popup-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: $spacing-md $spacing-lg;
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 1rpx solid $bg-color-hover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-popup-title {
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 900;
|
||||||
|
color: $text-color-main;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-popup-close {
|
||||||
|
font-size: 40rpx;
|
||||||
|
color: $text-color-muted;
|
||||||
|
padding: 0 $spacing-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-popup-body {
|
||||||
|
padding: $spacing-md $spacing-lg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-rules {
|
||||||
|
margin-bottom: $spacing-md;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: $border-radius-base;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-rules-header {
|
||||||
|
display: flex;
|
||||||
|
padding: $spacing-sm $spacing-md;
|
||||||
|
background: $bg-color-hover;
|
||||||
|
font-size: 22rpx;
|
||||||
|
font-weight: 800;
|
||||||
|
color: $text-color-muted;
|
||||||
|
|
||||||
|
text {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&:first-child { flex: 0.8; }
|
||||||
|
&:last-child { flex: 1.4; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-rule-row {
|
||||||
|
display: flex;
|
||||||
|
padding: $spacing-sm $spacing-md;
|
||||||
|
border-bottom: 1rpx solid $bg-color-hover;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: $text-color-muted;
|
||||||
|
|
||||||
|
text {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&:first-child { flex: 0.8; }
|
||||||
|
&:last-child { flex: 1.4; text-align: left; }
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: rgba(64, 158, 255, 0.08);
|
||||||
|
color: $color-primary;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-rule-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-amount-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: $spacing-md;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: $border-radius-base;
|
||||||
|
margin-bottom: $spacing-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-amount-label {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: $text-color-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-amount-value {
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-weight: 900;
|
||||||
|
color: $color-danger;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-tips {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: $text-color-muted;
|
||||||
|
margin-bottom: $spacing-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-popup-footer {
|
||||||
|
display: flex;
|
||||||
|
gap: $spacing-md;
|
||||||
|
padding: $spacing-md $spacing-lg $spacing-lg;
|
||||||
|
padding-bottom: calc(#{$spacing-lg} + env(safe-area-inset-bottom));
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refund-btn {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user