236 lines
6.6 KiB
Vue
236 lines
6.6 KiB
Vue
<template>
|
||
<uni-popup
|
||
ref="popup"
|
||
type="bottom"
|
||
background-color="#fff"
|
||
border-radius="12px 12px 0 0"
|
||
mask-background-color="rgba(0,0,0,0.5)"
|
||
:safe-area="false"
|
||
>
|
||
<view class="good-container">
|
||
<!-- 头部区域 -->
|
||
<view class="header">
|
||
<view class="header-title">填写信息</view>
|
||
<view class="close-btn" @click="closePopup">
|
||
<uni-icons type="closeempty" size="24" color="#333" />
|
||
</view>
|
||
</view>
|
||
<!-- 商品信息区域 -->
|
||
<scroll-view
|
||
class="good-content"
|
||
:scroll-y="true"
|
||
:show-scrollbar="false"
|
||
>
|
||
<view class="wrapper">
|
||
<view class="good-info-wrapper">
|
||
<!-- 轮播图区域 -->
|
||
<ImageSwiper
|
||
:images="goodsData.commodityPhotoList"
|
||
:height="130"
|
||
:border-radius="0"
|
||
:showThumbnails="false"
|
||
/>
|
||
|
||
<!-- 商品信息区域 -->
|
||
<view class="goods-info">
|
||
<view class="goods-details">
|
||
<view class="goods-title">{{
|
||
goodsData.commodityName || "商品名称"
|
||
}}</view>
|
||
<view class="goods-price">
|
||
<text class="currency">¥</text>
|
||
<text class="price">
|
||
{{ goodsData.specificationPrice || 399 }}
|
||
</text>
|
||
</view>
|
||
<view
|
||
class="goods-service-list"
|
||
v-if="
|
||
goodsData.commodityServiceList &&
|
||
goodsData.commodityServiceList.length
|
||
"
|
||
>
|
||
<view class="service-title">包含服务</view>
|
||
<view
|
||
class="goods-service-item"
|
||
v-for="item in goodsData.commodityServiceList"
|
||
:key="item.serviceTitle"
|
||
>
|
||
<text class="service-label">{{ item.serviceTitle }}</text>
|
||
<text class="service-value">{{ item.serviceAmount }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 数量选择区域 -->
|
||
<view class="quantity-section">
|
||
<ModuleTitle
|
||
:title="
|
||
goodsData.commodityTypeCode === '0' ? '订房信息' : '游客信息'
|
||
"
|
||
/>
|
||
|
||
<Stepper v-model="quantity" />
|
||
</view>
|
||
|
||
<!-- 游客信息区域 -->
|
||
<scroll-view
|
||
class="user-form-list"
|
||
:scroll-x="true"
|
||
:show-scrollbar="false"
|
||
>
|
||
<FormCard
|
||
v-for="(item, index) in userFormList"
|
||
:title="
|
||
goodsData.commodityTypeCode === '0'
|
||
? `房间${index + 1}`
|
||
: `游客${index + 1}`
|
||
"
|
||
:form="item"
|
||
:showDeleteIcon="userFormList.length > 1"
|
||
:key="index"
|
||
@update:name="(value) => updateUserForm(index, 'name', value)"
|
||
@update:phone="(value) => updateUserForm(index, 'phone', value)"
|
||
@delete="() => deleteUserForm(index)"
|
||
/>
|
||
</scroll-view>
|
||
|
||
<!-- 总价区域 -->
|
||
<SumCard
|
||
:referencePrice="goodsData.specificationPrice"
|
||
:discount="totalPrice"
|
||
/>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<!-- 底部按钮区域 -->
|
||
<view class="footer">
|
||
<view class="left">
|
||
<text class="total-count">共{{ quantity }}间,合计:</text>
|
||
<text class="total-price">{{ totalPrice }}</text>
|
||
</view>
|
||
|
||
<view class="confirm-btn" @click="confirmOrder">立即支付</view>
|
||
</view>
|
||
</view>
|
||
</uni-popup>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, watch, defineProps, defineEmits } from "vue";
|
||
import ImageSwiper from "@/components/ImageSwiper/index.vue";
|
||
import ModuleTitle from "@/components/ModuleTitle/index.vue";
|
||
import Stepper from "@/components/Stepper/index.vue";
|
||
import FormCard from "@/components/FormCard/index.vue";
|
||
import SumCard from "@/components/SumCard/index.vue";
|
||
|
||
// Props定义
|
||
const props = defineProps({
|
||
goodsData: {
|
||
type: Object,
|
||
default: () => ({
|
||
commodityTypeCode: "0", // 商品类型 0-酒店 1-门票 2-餐饮
|
||
}),
|
||
},
|
||
});
|
||
|
||
// Emits定义
|
||
const emits = defineEmits(["confirm", "close"]);
|
||
|
||
// 响应式数据
|
||
const popup = ref(null);
|
||
const quantity = ref(1);
|
||
const userFormList = ref([{ name: "", phone: "" }]); // 初始化一个表单项
|
||
const isDeleting = ref(false); // 标志位,防止删除时watch冲突
|
||
|
||
// 计算属性
|
||
const totalPrice = computed(() => {
|
||
const price = props.goodsData.specificationPrice || 399;
|
||
return (price * quantity.value).toFixed(0);
|
||
});
|
||
|
||
// 监听 quantity 变化,动态调整 userFormList
|
||
watch(
|
||
quantity,
|
||
(newQuantity, oldQuantity) => {
|
||
// 如果正在执行删除操作,跳过watch逻辑
|
||
if (isDeleting.value) {
|
||
isDeleting.value = false;
|
||
return;
|
||
}
|
||
|
||
const currentLength = userFormList.value.length;
|
||
|
||
if (newQuantity > currentLength) {
|
||
// 数量增加,添加新的表单项
|
||
for (let i = currentLength; i < newQuantity; i++) {
|
||
userFormList.value.push({ name: "", phone: "" });
|
||
}
|
||
} else if (newQuantity < currentLength) {
|
||
// 数量减少,删除多余的表单项
|
||
userFormList.value.splice(newQuantity);
|
||
}
|
||
},
|
||
{ immediate: false }
|
||
);
|
||
|
||
// 方法定义
|
||
const showPopup = () => {
|
||
popup.value?.open();
|
||
};
|
||
|
||
const closePopup = () => {
|
||
popup.value?.close();
|
||
emits("close");
|
||
};
|
||
|
||
const updateUserForm = (index, field, value) => {
|
||
if (userFormList.value[index]) {
|
||
userFormList.value[index][field] = value;
|
||
}
|
||
};
|
||
|
||
const deleteUserForm = (index) => {
|
||
// 确保至少保留一个表单项
|
||
if (userFormList.value.length <= 1) {
|
||
uni.showToast({
|
||
title: "至少需要一位游客信息",
|
||
icon: "none",
|
||
duration: 2000,
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 设置删除标志位,防止watch监听器干扰
|
||
isDeleting.value = true;
|
||
|
||
// 删除指定索引的表单项
|
||
userFormList.value.splice(index, 1);
|
||
|
||
// 同步更新quantity
|
||
quantity.value = userFormList.value.length;
|
||
};
|
||
|
||
const confirmOrder = () => {
|
||
const orderData = {
|
||
goodsData: props.goodsData,
|
||
quantity: quantity.value,
|
||
totalPrice: totalPrice.value,
|
||
userFormList: userFormList.value,
|
||
};
|
||
emits("confirm", orderData);
|
||
closePopup();
|
||
};
|
||
|
||
// 暴露方法给父组件
|
||
defineExpose({
|
||
showPopup,
|
||
closePopup,
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
@import "./styles/index.scss";
|
||
</style> |