Files
nianxx-h5/src/pages/goods/index.vue
duanshuwen 479c5175ec refactor(goods): clean up components, update imports and add album page
- replace scoped SCSS styles with inline utility classes for goods components
- move LocationCard to goods subdirectory and update relative imports
- fix DebounceUtils import path in FooterSection
- update goods index page: replace scroll wrapper, switch to vue-router composable, replace uni modal with vant showDialog
- add new album page component
- remove unused PNG assets, old README and deprecated style files
- update global type declarations for vant showDialog
2026-05-27 22:17:57 +08:00

248 lines
7.7 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>
<div class="goods-container">
<TopNavBar :title="navOpacity < 0.5 ? '' : '商品详情'" :background="`rgba(217, 238, 255, ${navOpacity})`"
:titleColor="navOpacity < 0.5 ? '#ffffff' : '#000000'"
:backIconColor="navOpacity < 0.5 ? '#ffffff' : '#000000'" />
<!-- 滚动区域 -->
<div class="content-wrapper" @scroll="handleScroll">
<imgSwiper :border-radius="0" :height="300" :images="goodsData.commodityPhotoList" thumbnailBottom="42px" />
<div 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
" :goodsData="goodsData" />
<!-- 商品设施组件 -->
<GoodFacility v-if="
goodsData.commodityEquipment &&
goodsData.commodityEquipment.length
" :goodsData="goodsData" />
<!-- 商品详情组件 -->
<GoodDetail :goodsData="goodsData" />
</div>
</div>
<!-- 立即抢购 -->
<div class="footer border-top">
<div class="amt font-size-20 font-bold color-FF3D60 line-height-28 flex flex-items-center mr-8">
{{ calculatedTotalPrice }}
</div>
<div class="btn border-box rounded-10 flex flex-items-center ml-auto pl-8" @click="navigateToPay(goodsData)">
<img class="icon" src="https://oss.nianxx.cn/mp/static/version_101/common/btn.png" />
<span class="font-size-16 font-500 color-white">立即预定</span>
</div>
</div>
<!-- 日历组件 -->
<Calender :visible="calendarVisible" mode="range" :range-require-price="true" :price-data="priceData"
@close="handleCalendarClose" @range-select="handleDateSelect" />
</div>
</template>
<script setup>
import { ref } from "vue";
import { useRouter } from 'vue-router'
import { goodsDetail, commodityDailyPriceList } from "@/api/goods";
import { DateUtils } from "@/utils/dateUtils";
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 router = useRouter()
// 导航栏透明度 - 默认透明,随滚动变为不透明
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") {
showDialog({
title: "温馨提示",
message: "您选的商品暂不可预订,请重新选择。",
}).then(() => {
router.back()
}).catch(() => {
});
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;
};
// TODO
// 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 }) => {
router.push({
name: "booking",
query: {
commodityId,
},
})
};
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>