Files
YGChatCS/src/pages/goods/index.vue
T
duanshuwen 4e3a39e3c1 fix: correct scroll-view props and event bindings
update scroll-view component syntax in goods, ChatLongAnswer and Discovery pages
2026-07-25 11:18:25 +08:00

237 lines
7.7 KiB
Vue

<template>
<view class="goods-container bg-[#f5f5f5]">
<TopNavBar :title="navOpacity < 0.5 ? '' : '商品详情'" :background="`rgba(217, 238, 255, ${navOpacity})`"
:titleColor="navOpacity < 0.5 ? '#ffffff' : '#000000'"
:backIconColor="navOpacity < 0.5 ? '#ffffff' : '#000000'" />
<!-- 滚动区域 -->
<scroll-view class="content-wrapper" scroll-y @scroll="handleScroll">
<ImageSwiper :border-radius="0" :height="300" :images="goodsData.commodityPhotoList" thumbnailBottom="42px" />
<view class="goods-content">
<!-- 商品信息组件 -->
<GoodInfo :goodsData="goodsData" />
<!-- 地址区域 -->
<LocationCard :orderData="goodsData" />
<!-- 日期选择区域 -->
<DateSelector v-if="goodsData.orderType == 0" @showCalendar="showCalendar" :checkInDate="selectedDate.startDate"
:checkOutDate="selectedDate.endDate" :checkInDay="''" :checkOutDay="''" :nights="selectedDate.totalDays" />
<!-- 商品套餐组件 -->
<GoodPackage
v-if="goodsData.orderType != 0 && goodsData.commodityPackageConfig && goodsData.commodityPackageConfig.length > 0"
:goodsData="goodsData" />
<!-- 商品设施组件 -->
<GoodFacility v-if="goodsData.commodityEquipment && goodsData.commodityEquipment.length > 0"
:goodsData="goodsData" />
<!-- 商品详情组件 -->
<GoodDetail :goodsData="goodsData" />
</view>
</scroll-view>
<!-- 立即抢购 -->
<view class="footer border-top">
<view class="amt text-[20px] font-bold text-[#ff3d60] line-height-28 flex items-center mr-[8px]">
{{ calculatedTotalPrice }}
</view>
<view class="btn rounded-[10px] flex items-center ml-auto pl-[8px]" @click="navigateToPay(goodsData)">
<image class="icon" src="https://oss.nianxx.cn/mp/static/version_101/common/btn.png" />
<text class="text-[16px] font-[500] text-white">立即预定</text>
</view>
</view>
<!-- 日历组件 -->
<Calender :visible="calendarVisible" mode="range" :range-require-price="true" :price-data="priceData"
@close="handleCalendarClose" @range-select="handleDateSelect" />
</view>
</template>
<script setup>
import { ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import { goodsDetail, commodityDailyPriceList } from "@/request/api/GoodsApi";
import { DateUtils } from "@/utils";
import TopNavBar from "@/components/TopNavBar/index.vue";
import ImageSwiper from "@/components/ImageSwiper/index.vue";
import GoodInfo from "./components/GoodInfo/index.vue";
import Calender from "@/components/Calender/index.vue";
import LocationCard from "@/components/LocationCard/index.vue";
import DateSelector from "./components/DateSelector/index.vue";
import GoodDetail from "@/components/GoodDetail/index.vue";
import GoodFacility from "./components/GoodFacility/index.vue";
import GoodPackage from "./components/GoodPackage/index.vue";
import { useSelectedDateStore } from "@/store";
// 导航栏透明度 - 默认透明,随滚动变为不透明
const navOpacity = ref(0);
const calendarVisible = ref(false);
const goodsData = ref({});
// 处理滚动事件
const handleScroll = (e) => {
const scrollTop = e.detail.scrollTop;
// 设置一个阈值,当滚动超过200px时,导航栏完全不透明
const threshold = 200;
// 计算透明度,范围从0到1
navOpacity.value = Math.min(scrollTop / threshold, 1);
};
const selectedDate = ref({
startDate: DateUtils.formatDate(), // 当天日期
endDate: DateUtils.formatDate(new Date(Date.now() + 24 * 60 * 60 * 1000)), // 第二天日期
totalDays: 1,
});
const priceData = ref([])
// 计算的总价格
const calculatedTotalPrice = ref(0);
// 获取商品详情数据
const goodsInfo = async (params) => {
const res = await goodsDetail(params);
goodsData.value = res.data;
// 初始化计算价格
calculatedTotalPrice.value = goodsData.value.specificationPrice || 0;
// 判断是酒店类型订单再获取获取商品日价格及库存
if (goodsData.value.orderType == 0) {
configGoodsData();
getGoodsDailyPrice({
commodityId: goodsData.value.commodityId,
});
}
if (goodsData.value.commodityStatus !== "1") {
uni.showModal({
title: "温馨提示",
content: "您选的商品暂不可预订,请重新选择。",
success: (res) => {
if (res.confirm) {
uni.navigateBack({ delta: 1 });
}
},
});
return;
}
};
const configGoodsData = () => {
goodsData.value.startDate = selectedDate.value.startDate;
goodsData.value.endDate = selectedDate.value.endDate;
goodsData.value.totalDays = selectedDate.value.totalDays;
goodsData.value.calculatedTotalPrice = calculatedTotalPrice.value;
};
// 获取商品日价格及库存
const getGoodsDailyPrice = async (params) => {
const res = await commodityDailyPriceList(params);
priceData.value = res.data;
};
const selectedDateStore = useSelectedDateStore();
onLoad(({ commodityId = "1950766939442774018" }) => {
// 从store中获取选中的日期
selectedDate.value = selectedDateStore.selectedDate;
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,
};
selectedDateStore.setData(selectedDate.value);
// 根据商品类型计算价格
if (goodsData.value.orderType == 0) {
// 酒店类型:计算dateRange总价格,排除最后一天(同一天除外)
if (data.dateRange && Array.isArray(data.dateRange)) {
// 获取默认价格作为回退值
const defaultPrice = Number(goodsData.value.specificationPrice) || 0;
// 检查价格是否有效的函数
const isValidPrice = (price) => {
return (
price !== null &&
price !== undefined &&
price !== "" &&
price !== "-" &&
!isNaN(Number(price)) &&
Number(price) > 0
);
};
// 如果是同一天(数组长度为1),使用该天的价格
if (data.dateRange.length === 1) {
const dayPrice = data.dateRange[0].price;
calculatedTotalPrice.value = isValidPrice(dayPrice)
? Number(dayPrice)
: defaultPrice;
console.log(
"同一天选择,价格:",
calculatedTotalPrice.value,
"(原价格:",
dayPrice,
")"
);
} else {
// 多天选择,排除最后一天
const dateRangeExcludingLast = data.dateRange.slice(0, -1);
calculatedTotalPrice.value = dateRangeExcludingLast.reduce(
(total, dateItem) => {
const dayPrice = dateItem.price;
const priceToAdd = isValidPrice(dayPrice)
? Number(dayPrice)
: defaultPrice;
return total + priceToAdd;
},
0
);
console.log(
"酒店类型计算总价格(排除最后一天):",
calculatedTotalPrice.value
);
}
configGoodsData();
}
} else {
// 非酒店类型:如果没有dateRange,使用默认价格
calculatedTotalPrice.value = goodsData.value.specificationPrice || 0;
}
// 日历组件会自动关闭,无需手动设置
calendarVisible.value = false;
};
// 跳转订购
const navigateToPay = ({ commodityId }) => {
uni.navigateTo({
url: `/pages-booking/index?commodityId=${commodityId}`,
});
};
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>