feat: 商品详情支付交互调试
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user