Files
YGChatCS/pages/goods/components/GoodConfirm/index.vue
2025-08-05 21:36:26 +08:00

236 lines
6.6 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>
<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>