Files
YGChatCS/pages/goods/index.vue

322 lines
8.6 KiB
Vue

<template>
<view class="goods-container">
<TopNavBar title="商品详情" />
<!-- 滚动区域 -->
<scroll-view class="content-wrapper" scroll-y>
<ImageSwiper
:border-radius="0"
:height="300"
:images="goodsData.commodityPhotoList"
thumbnailBottom="36px"
/>
<view class="goods-content">
<!-- 商品信息组件 -->
<GoodInfo :goodsData="goodsData" />
<!-- 地址区域 -->
<LocationCard :orderData="goodsData" />
<!-- 日期选择区域 -->
<DateSelector
v-if="goodsData.commodityTypeCode === '0'"
@showCalendar="showCalendar"
:checkInDate="selectedDate.startDate"
:checkOutDate="selectedDate.endDate"
:checkInDay="''"
:checkOutDay="''"
:nights="selectedDate.totalDays"
/>
<view v-if="goodsData.commodityPurchaseInstruction" class="use-notice">
<ModuleTitle
:title="goodsData.commodityPurchaseInstruction.templateTitle"
/>
<view
class="use-notice-content"
v-for="(moduleItem, index) in goodsData.commodityPurchaseInstruction
.commodityPurchaseInstructionModuleEntityList"
:key="index"
>
<view
class="module-item"
:class="{
'border-bottom':
index <
goodsData.commodityPurchaseInstruction
.commodityPurchaseInstructionModuleEntityList.length -
1,
}"
>
<view class="module-icon">
<uni-icons fontFamily="znicons" size="20" color="#333">{{
zniconsMap[moduleItem.moduleIcon]
}}</uni-icons>
<text class="module-title">{{ moduleItem.moduleTitle }}</text>
</view>
<text class="module-desc">{{ moduleItem.moduleContent }}</text>
</view>
</view>
</view>
<zero-markdown-view
v-else
:markdown="goodsData.commodityTip"
:aiMode="true"
/>
</view>
</scroll-view>
<!-- 立即抢购 -->
<view class="footer">
<view class="left">
<text class="label">价格:</text>
<text class="price">{{ goodsData.specificationPrice || 399 }}</text>
</view>
<view class="buy-button" @click="showConfirmPopup">立即抢购</view>
</view>
<!-- 商品确认弹窗 -->
<GoodConfirm
ref="goodConfirmRef"
:goodsData="goodsData"
@confirm="handleConfirmOrder"
@close="handleCloseConfirm"
/>
<!-- 日历组件 -->
<Calender
:visible="calendarVisible"
:price-data="priceData"
mode="range"
@close="handleCalendarClose"
@range-select="handleDateSelect"
/>
</view>
</template>
<script setup>
import { ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import {
goodsDetail,
commodityDailyPriceList,
orderPay,
} from "@/request/api/GoodsApi";
import TopNavBar from "@/components/TopNavBar/index.vue";
import ImageSwiper from "@/components/ImageSwiper/index.vue";
import GoodInfo from "./components/GoodInfo/index.vue";
import ModuleTitle from "@/components/ModuleTitle/index.vue";
import GoodConfirm from "./components/GoodConfirm/index.vue";
import Calender from "@/components/Calender/index.vue";
import { zniconsMap } from "@/static/fonts/znicons.js";
import LocationCard from "@/components/LocationCard/index.vue";
import DateSelector from "./components/DateSelector/index.vue";
const calendarVisible = ref(false);
const goodsData = ref({});
const goodConfirmRef = ref(null);
// 格式化日期为 yyyy-mm-dd 格式
const formatDate = (date) => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
};
// 获取今天和明天的日期
const today = new Date();
const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1);
const selectedDate = ref({
startDate: formatDate(today),
endDate: formatDate(tomorrow),
totalDays: 1,
});
const priceData = ref([]);
// 获取商品详情数据
const goodsInfo = async (params) => {
const res = await goodsDetail(params);
goodsData.value = res.data;
// 判断是酒店类型订单再获取获取商品日价格及库存
if (goodsData.value.commodityTypeCode === "0") {
getGoodsDailyPrice({
commodityId: goodsData.value.commodityId,
});
}
};
// 获取商品日价格及库存
const getGoodsDailyPrice = async (params) => {
const res = await commodityDailyPriceList(params);
priceData.value = res.data;
};
// 显示确认弹窗
const showConfirmPopup = () => {
// 当商品类型为"0"时,需要校验入住和离店日期
if (goodsData.value.commodityTypeCode === "0") {
// 检查是否已选择日期
if (
!selectedDate.value ||
!selectedDate.value.startDate ||
!selectedDate.value.endDate
) {
calendarVisible.value = true;
uni.showToast({
title: "请先选择入住和离店日期",
icon: "none",
duration: 2000,
});
return;
}
}
// 校验通过或非住宿类商品,显示确认弹窗
goodConfirmRef.value?.showPopup();
};
// 处理确认订单
const handleConfirmOrder = async (orderData) => {
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,
};
//酒店类型添加入住时间、离店时间
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);
// 检查接口返回数据
if (!res || !res.data) {
uni.showToast({
title: "订单创建失败,请重试",
icon: "none",
duration: 2000,
});
return;
}
const { data } = res;
const { nonceStr, packageVal, paySign, signType, timeStamp } = data;
// 验证支付参数是否完整
if (!nonceStr || !packageVal || !paySign || !signType || !timeStamp) {
console.error("支付参数不完整:", {
nonceStr: !!nonceStr,
packageVal: !!packageVal,
paySign: !!paySign,
signType: !!signType,
timeStamp: !!timeStamp,
});
uni.showToast({
title: "支付参数错误,请重试",
icon: "none",
duration: 2000,
});
return;
}
// 调用微信支付
uni.requestPayment({
provider: "wxpay",
timeStamp: String(timeStamp), // 确保为字符串类型
nonceStr: String(nonceStr),
package: String(packageVal), // 确保为字符串类型
signType: String(signType),
paySign: String(paySign),
success: (res) => {
console.log("支付成功:" + JSON.stringify(res));
uni.showToast({
title: "支付成功",
icon: "success",
duration: 2000,
success: () => {
uni.navigateTo({
url: "/pages/order/list",
});
},
});
},
fail: (err) => {
console.error("支付失败:" + JSON.stringify(err));
uni.showToast({
title: "支付失败,请重试",
icon: "none",
duration: 2000,
});
},
});
};
// 处理关闭弹窗
const handleCloseConfirm = () => {
console.log("关闭确认弹窗");
};
onLoad(({ commodityId = "1950766939442774018" }) => {
goodsInfo({ commodityId });
});
// 显示日历弹窗
const showCalendar = () => (calendarVisible.value = true);
const handleCalendarClose = () => (calendarVisible.value = false);
const handleDateSelect = (data) => {
console.log("选择的日期:", data);
// 保存选择的日期范围
selectedDate.value = {
startDate: data.startDate,
endDate: data.endDate,
totalDays: data.totalDays,
};
// 日历组件会自动关闭,无需手动设置
calendarVisible.value = false;
};
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
@font-face {
font-family: znicons;
src: url("@/static/fonts/znicons.ttf");
}
</style>