feat: 商品详情支付交互调试

This commit is contained in:
duanshuwen
2025-08-06 21:43:08 +08:00
parent 5292ede3c5
commit e482ea5393
10 changed files with 673 additions and 137 deletions

View File

@@ -66,11 +66,7 @@
<!-- 数量选择区域 -->
<view class="quantity-section">
<ModuleTitle
:title="
goodsData.commodityTypeCode === '0' ? '订房信息' : '游客信息'
"
/>
<ModuleTitle :title="sectionTitle" />
<Stepper v-model="quantity" />
</view>
@@ -83,11 +79,7 @@
>
<FormCard
v-for="(item, index) in userFormList"
:title="
goodsData.commodityTypeCode === '0'
? `房间${index + 1}`
: `游客${index + 1}`
"
:title="userCardTitle(index)"
:form="item"
:showDeleteIcon="userFormList.length > 1"
:key="index"
@@ -119,59 +111,119 @@
</template>
<script setup>
import { ref, computed, watch, defineProps, defineEmits } from "vue";
import { ref, computed, watch, onMounted, nextTick } 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";
// 工具函数
const showToast = (title, icon = "none", duration = 2000) => {
uni.showToast({ title, icon, duration });
};
const isValidUserForm = (user) => {
return (
user &&
typeof user.name === "string" &&
user.name.trim() !== "" &&
typeof user.phone === "string" &&
user.phone.trim() !== ""
);
};
// 常量定义
const COMMODITY_TYPES = {
HOTEL: "0",
TICKET: "1",
DINING: "2",
};
const DEFAULT_PRICE = 399;
const MIN_USER_COUNT = 1;
// Props定义
const props = defineProps({
goodsData: {
type: Object,
default: () => ({
commodityTypeCode: "0", // 商品类型 0-酒店 1-门票 2-餐饮
commodityTypeCode: "0",
specificationPrice: "",
commodityName: "",
commodityPhotoList: [],
commodityServiceList: [],
}),
validator: (value) => {
return value && typeof value === "object";
},
},
});
// Emits定义
const emits = defineEmits(["confirm", "close"]);
// 工具函数
const createEmptyUserForm = () => {
return { name: "", phone: "" };
};
// 响应式数据
const popup = ref(null);
const quantity = ref(1);
const userFormList = ref([{ name: "", phone: "" }]); // 初始化一个表单项
const quantity = ref(MIN_USER_COUNT);
const userFormList = ref([createEmptyUserForm()]); // 初始化一个表单项
const isDeleting = ref(false); // 标志位防止删除时watch冲突
// 计算属性
const totalPrice = computed(() => {
const price = props.goodsData.specificationPrice || 399;
const price = props.goodsData?.specificationPrice || DEFAULT_PRICE;
return (price * quantity.value).toFixed(0);
});
const isHotelType = computed(() => {
return props.goodsData?.commodityTypeCode === COMMODITY_TYPES.HOTEL;
});
const sectionTitle = computed(() => {
return isHotelType.value ? "订房信息" : "游客信息";
});
const userCardTitle = computed(() => {
return (index) =>
isHotelType.value ? `房间${index + 1}` : `游客${index + 1}`;
});
// 监听 quantity 变化,动态调整 userFormList
watch(
quantity,
(newQuantity, oldQuantity) => {
async (newQuantity) => {
// 如果正在执行删除操作跳过watch逻辑
if (isDeleting.value) {
isDeleting.value = false;
return;
}
// 确保数量不小于最小值
if (newQuantity < MIN_USER_COUNT) {
quantity.value = MIN_USER_COUNT;
return;
}
const currentLength = userFormList.value.length;
if (newQuantity > currentLength) {
// 数量增加,添加新的表单项
for (let i = currentLength; i < newQuantity; i++) {
userFormList.value.push({ name: "", phone: "" });
}
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 }
);
@@ -187,19 +239,33 @@ const closePopup = () => {
};
const updateUserForm = (index, field, value) => {
if (userFormList.value[index]) {
userFormList.value[index][field] = value;
if (!userFormList.value[index]) {
return;
}
if (!["name", "phone"].includes(field)) {
return;
}
userFormList.value[index][field] = value?.toString().trim() || "";
};
const deleteUserForm = (index) => {
// 参数验证
if (
typeof index !== "number" ||
index < 0 ||
index >= userFormList.value.length
) {
return;
}
// 确保至少保留一个表单项
if (userFormList.value.length <= 1) {
uni.showToast({
title: "至少需要一位游客信息",
icon: "none",
duration: 2000,
});
if (userFormList.value.length <= MIN_USER_COUNT) {
const message = isHotelType.value
? "至少需要一个房间信息"
: "至少需要一位游客信息";
showToast(message);
return;
}
@@ -213,21 +279,71 @@ const deleteUserForm = (index) => {
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();
const validateUserForms = () => {
const invalidUsers = userFormList.value.filter((user, index) => {
return !isValidUserForm(user);
});
if (invalidUsers.length > 0) {
const message = isHotelType.value
? "请填写完整的房客信息"
: "请填写完整的游客信息";
showToast(message);
return false;
}
return true;
};
// 暴露方法给父组件
const confirmOrder = () => {
try {
// 校验用户信息是否填写完整
if (!validateUserForms()) {
return;
}
// 构建订单数据
const orderData = {
goodsData: props.goodsData,
quantity: quantity.value,
totalPrice: parseFloat(totalPrice.value),
userFormList: userFormList.value.map((user) => ({
name: user.name.trim(),
phone: user.phone.trim(),
})),
commodityType: props.goodsData?.commodityTypeCode,
timestamp: Date.now(),
};
// 触发确认事件
emits("confirm", orderData);
// 关闭弹窗
closePopup();
} catch (error) {
showToast("订单处理失败,请重试");
}
};
// 生命周期钩子
onMounted(() => {
// 初始化用户表单列表
if (userFormList.value.length === 0) {
userFormList.value.push(createEmptyUserForm());
}
});
// 暴露给父组件的方法
defineExpose({
showPopup,
closePopup,
resetForm: () => {
userFormList.value = [createEmptyUserForm()];
quantity.value = MIN_USER_COUNT;
},
validateForms: validateUserForms,
getUserFormList: () => userFormList.value,
getTotalPrice: () => totalPrice.value,
});
</script>

View File

@@ -66,7 +66,7 @@ import Calender from "@/components/Calender/index.vue";
const calendarVisible = ref(false);
const goodsData = ref({});
const goodConfirmRef = ref(null);
const selectedDate = ref("");
const selectedDate = ref();
const priceData = ref([]);
// 获取商品详情数据
@@ -117,25 +117,40 @@ const showConfirmPopup = () => {
// 处理确认订单
const handleConfirmOrder = async (orderData) => {
console.log("确认订单:", orderData);
// const commodityId = orderData.commodityId;
// const purchaseAmount = orderData.purchaseAmount;
// const checkInData = orderData.checkInData;
// const checkOutData = orderData.checkOutData;
// const consumerInfoEntityList = orderData.consumerInfoEntityList;
// const payWay = "0";
// const paySource = "1";
console.log("确认订单---1:", orderData);
const { goodsData } = orderData;
// 购买的商品id
const commodityId = goodsData.commodityId;
// 消费者信息
const consumerInfoEntityList = orderData.userFormList;
// 购买数量
const purchaseAmount = orderData.userFormList.length;
// 支付方式 0-微信 1-支付宝 2-云闪付
const payWay = "0";
// 支付渠道 0-app 1-小程序 2-h5
const paySource = "1";
// const params = {
// commodityId,
// purchaseAmount,
// payWay,
// paySource,
// consumerInfoEntityList,
// checkInData,
// checkOutData,
// };
// const res = await orderPay(params);
const params = {
commodityId,
purchaseAmount,
payWay,
paySource,
consumerInfoEntityList,
};
//酒店类型添加入住时间、离店时间
if (goodsData.commodityTypeCode === "0" && selectedDate.value) {
const { startDate, endDate } = selectedDate.value;
// 入住时间
params.checkInData = startDate;
// 离店时间
params.checkOutData = endDate;
}
// 购买数量
const res = await orderPay(params);
console.log("确认订单---2:", res);
// 仅作为示例,非真实参数信息。
// uni.requestPayment({