Files
nianxx-h5/src/pages/booking/index.vue
duanshuwen 3c177d2087 refactor(booking): clean up toast and payment code
Replace verbose uni.showToast object syntax with shorter direct calls, remove unnecessary setTimeout wrappers around error toast calls, clean up redundant loading state handling, and remove unused WeChat pay and app payment placeholder code.
2026-05-28 07:44:34 +08:00

262 lines
7.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="booking h-screen flex flex-col">
<TopNavBar titleAlign="center" :backgroundColor="$theme - color - 100" backIconColor="#000" :shadow="false">
<template #title>
{{ GOODS_TYPE[orderData.orderType] }}
</template>
</TopNavBar>
<div class="booking-content flex-full border-box p-12 overflow-hidden scroll-y">
<!-- 预约内容 -->
<div class="border-box bg-white p-12 rounded-12 mb-12">
<!-- 酒店类型入住离店日期部分 -->
<DateRangeSection v-if="orderData.orderType == 0" :selectedDate="selectedDate" :showBtn="true"
@click="navigateToDetail(orderData)" />
<div class="font-size-16 font-500 color-000 line-height-24 ellipsis-1">
{{ orderData.commodityName }}
</div>
<div class="border-box border-bottom">
<div class="font-size-12 color-99A0AE line-height-16 pb-12 break-all">
{{ orderData.commodityDescription }}
</div>
<!-- 权益部分 -->
<div class="flex flex-items-center mb-8">
<span class="bg-F7F7F7 border-box rounded-4 font-size-11 color-525866 mr-4 pt-4 pb-4 pl-6 pr-6"
v-for="(item, index) in orderData.commodityFacilityList" :key="index">
{{ item }}
</span>
</div>
</div>
<div class="border-box flex flex-items-center flex-justify-between pt-12">
<span class="font-size-12 color-525866 line-height-18">取消政策及说明</span>
<div class="flex flex-items-center">
<span class="font-size-12 theme-color-500 line-height-16" @click="refundVisible = true">取消政策</span>
<uni-icons type="right" size="15" color="#99A0AE" />
</div>
</div>
</div>
<!-- 非酒店类型 -->
<ContactSection v-if="orderData.orderType != 0" v-model="quantity" :userFormList="userFormList"
v-model:reservationDate="selectedReservationDate" :orderData="orderData" />
<!-- 酒店类型 -->
<UserSection v-if="orderData.orderType == 0" v-model="quantity" :userFormList="userFormList" />
</div>
<!-- 底部 -->
<FooterSection v-if="Object.keys(orderData).length" v-model="quantity" :selectedDate="selectedDate"
:orderData="orderData" @detailClick="detailVisible = true" @payClick="handlePayClick" />
<!-- 取消政策弹窗 -->
<RefundPopup v-model="refundVisible" :orderData="orderData" />
<!-- 明细弹窗 -->
<DetailPopup v-model="detailVisible" :orderData="orderData" />
</div>
</template>
<script setup>
import { ref, watch, nextTick } from "vue";
import { useRouter } from 'vue-router'
import TopNavBar from "@/components/TopNavBar/index.vue";
import DateRangeSection from "@/components/DateRangeSection/index.vue";
import ContactSection from "./components/ConactSection/index.vue";
import UserSection from "./components/UserSection/index.vue";
import RefundPopup from "@/components/RefundPopup/index.vue";
import DetailPopup from "@/components/DetailPopup/index.vue";
import FooterSection from "./components/FooterSection/index.vue";
import { goodsDetail, orderPay } from "@/api/goods";
import { useSelectedDateStore } from "@/store";
import { GOODS_TYPE } from "@/constants/type";
import { ThrottleUtils } from "@/utils/ThrottleUtils";
import { PhoneUtils } from "@/utils/PhoneUtils";
const router = useRouter();
const refundVisible = ref(false);
const detailVisible = ref(false);
const orderData = ref({});
const selectedDate = ref({
startDate: "",
endDate: "",
totalDays: 1,
});
const quantity = ref(1);
const selectedReservationDate = ref("");
// 工具函数
const createEmptyUserForm = () => ({ visitorName: "", contactPhone: "" });
const userFormList = ref([createEmptyUserForm()]);
const isDeleting = ref(false); // 标志位防止删除时watch冲突
// 监听 quantity 变化,动态调整 userFormList
watch(
quantity,
async (newQuantity) => {
// 只有在酒店类型orderType == 0时才动态调整 userFormList
if (orderData.value.orderType !== 0) return;
// 如果正在执行删除操作跳过watch逻辑
if (isDeleting.value) {
isDeleting.value = false;
return;
}
const currentLength = userFormList.value.length;
if (newQuantity > currentLength) {
// 数量增加,添加新的表单项
const newForms = Array.from({ length: newQuantity - currentLength }, () =>
createEmptyUserForm(),
);
userFormList.value.push(...newForms);
} else if (newQuantity < currentLength) {
// 数量减少,删除多余的表单项
userFormList.value.splice(newQuantity);
}
// 等待DOM更新完成
await nextTick();
},
{ immediate: false },
);
// TODO
// onLoad((options) => {
// const { commodityId } = options;
// getGoodsDetail(commodityId);
// });
// onShow(() => {
// const selectedDateStore = useSelectedDateStore();
// selectedDate.value.startDate = selectedDateStore.selectedDate.startDate;
// selectedDate.value.endDate = selectedDateStore.selectedDate.endDate;
// selectedDate.value.totalDays = selectedDateStore.selectedDate.totalDays;
// });
const getGoodsDetail = async (commodityId) => {
const res = await goodsDetail({ commodityId });
console.log("获取商品详情", res);
orderData.value = res.data;
// 取commodityFacilityList前3个
orderData.value.commodityFacilityList = res.data.commodityFacilityList.slice(
0,
3,
);
};
// 跳转商品详情
const navigateToDetail = ({ commodityId }) => {
router.push({
path: "/pages/goods/index",
query: {
commodityId,
},
});
};
// 验证用户姓名
const validateUserForms = () => {
const invalidUsers = userFormList.value.filter((user) => {
return user.visitorName.trim() === "";
});
if (invalidUsers.length) {
showToast("请填写姓名");
return false;
}
return true;
};
// 处理支付点击事件
const handlePayClick = ThrottleUtils.createThrottle(async (goodsData) => {
console.log("处理支付点击事件", userFormList.value);
// 预约日期,酒店类型不需要
if (orderData.value.reservationEnabled) {
if (!selectedReservationDate.value) {
showToast("请选择预约日期");
return;
}
}
// 校验用户姓名
if (!validateUserForms()) {
return;
}
// 校验手机号
if (!PhoneUtils.validatePhone(userFormList.value[0].contactPhone)) {
showToast("请输入正确的手机号");
return;
}
// 购买的商品id
const commodityId = goodsData.commodityId;
// 消费者信息
const consumerInfoEntityList = userFormList.value;
// 购买数量
const purchaseAmount = quantity.value;
// 支付方式 0-微信 1-支付宝 2-云闪付
const payWay = "0";
// 支付渠道 0-app 1-小程序 2-h5
const paySource = "1";
const params = {
commodityId,
purchaseAmount,
payWay,
paySource,
consumerInfoEntityList,
};
// 预约日期,酒店类型不需要
if (orderData.value.reservationEnabled) {
params.reservationDate = selectedReservationDate.value;
}
//酒店类型添加入住时间、离店时间
if (goodsData.orderType == 0 && selectedDate.value) {
const { startDate, endDate } = selectedDate.value;
// 入住时间
params.checkInData = startDate;
// 离店时间
params.checkOutData = endDate;
}
// 点击后立即展示 loading
const res = await orderPay(params);
console.log("确认订单---2:", res);
// 检查接口返回数据
if (!res || !res.data) {
return;
}
const { data } = res;
const { nonceStr, packageVal, paySign, signType, timeStamp } = data;
// 验证支付参数是否完整
if (!nonceStr || !packageVal || !paySign || !signType || !timeStamp) {
return;
}
}, 1000);
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>