Compare commits

...

2 Commits

Author SHA1 Message Date
duanshuwen
9ca2d72256 Merge branch 'main' of https://git.brother7.cn/zoujing/YGChatCS into main 2025-08-05 08:20:40 +08:00
duanshuwen
a6bd06e06c feat: 商品详情交互开发 2025-08-04 21:31:11 +08:00
7 changed files with 182 additions and 40 deletions

View File

@ -1,5 +1,10 @@
<template> <template>
<uni-popup ref="popup" type="bottom" @maskClick="handleMaskClick"> <uni-popup
ref="popup"
type="bottom"
:safe-area="false"
@maskClick="handleMaskClick"
>
<!-- 弹窗主体 --> <!-- 弹窗主体 -->
<view class="calendar-popup" @tap.stop> <view class="calendar-popup" @tap.stop>
<!-- 头部区域 --> <!-- 头部区域 -->
@ -7,7 +12,7 @@
<view class="header-content"> <view class="header-content">
<text class="header-title">日历选择</text> <text class="header-title">日历选择</text>
<text class="header-subtitle" <text class="header-subtitle"
>选择入住和离店日期以下价格为单晚参考价</text >选择住宿日期以下价格为单晚参考价</text
> >
</view> </view>
<view class="header-close" @tap="handleClose"> <view class="header-close" @tap="handleClose">
@ -269,8 +274,12 @@ const getDateLabel = (dateStr) => {
return props.customLabels[dateStr]; return props.customLabels[dateStr];
} }
// / // /
if (props.mode === "range") { if (props.mode === "range") {
if (dateStr === rangeStart.value && dateStr === rangeEnd.value) {
// "/"
return "住/离";
}
if (dateStr === rangeStart.value) { if (dateStr === rangeStart.value) {
return "入住"; return "入住";
} }
@ -343,26 +352,26 @@ const handleRangeSelection = (dateInfo) => {
rangeEnd.value = dateInfo.date; rangeEnd.value = dateInfo.date;
isRangeSelecting.value = false; isRangeSelecting.value = false;
// //
if (new Date(rangeStart.value) > new Date(rangeEnd.value)) { if (new Date(rangeStart.value) > new Date(rangeEnd.value)) {
[rangeStart.value, rangeEnd.value] = [rangeEnd.value, rangeStart.value]; [rangeStart.value, rangeEnd.value] = [rangeEnd.value, rangeStart.value];
} }
// 28 // 280
const daysBetween = calculateDaysBetween(rangeStart.value, rangeEnd.value); const daysBetween = calculateDaysBetween(rangeStart.value, rangeEnd.value);
if (daysBetween > 28) { if (daysBetween > 28) {
// 使uni.showToast // 使uni.showToast
uni.showToast({ uni.showToast({
title: '预定时间不能超过28天', title: "预定时间不能超过28天",
icon: 'none', icon: "none",
duration: 3000 duration: 3000,
}); });
// //
rangeStart.value = null; rangeStart.value = null;
rangeEnd.value = null; rangeEnd.value = null;
isRangeSelecting.value = false; isRangeSelecting.value = false;
return; return;
} }

View File

@ -39,13 +39,25 @@
}}</view> }}</view>
<view class="goods-price"> <view class="goods-price">
<text class="currency">¥</text> <text class="currency">¥</text>
<text class="price">{{ goodsData.price || 399 }}</text> <text class="price">
{{ goodsData.specificationPrice || 399 }}
</text>
</view> </view>
<view class="goods-service-list"> <view
class="goods-service-list"
v-if="
goodsData.commodityServiceList &&
goodsData.commodityServiceList.length
"
>
<view class="service-title">包含服务</view> <view class="service-title">包含服务</view>
<view class="goods-service-item"> <view
<text class="service-label">随时可退</text> class="goods-service-item"
<text class="service-value">1</text> v-for="item in goodsData.commodityServiceList"
:key="item.serviceTitle"
>
<text class="service-label">{{ item.serviceTitle }}</text>
<text class="service-value">{{ item.serviceAmount }}</text>
</view> </view>
</view> </view>
</view> </view>
@ -54,7 +66,11 @@
<!-- 数量选择区域 --> <!-- 数量选择区域 -->
<view class="quantity-section"> <view class="quantity-section">
<ModuleTitle title="游客信息" /> <ModuleTitle
:title="
goodsData.commodityTypeCode === '0' ? '订房信息' : '游客信息'
"
/>
<Stepper v-model="quantity" /> <Stepper v-model="quantity" />
</view> </view>
@ -67,7 +83,11 @@
> >
<FormCard <FormCard
v-for="(item, index) in userFormList" v-for="(item, index) in userFormList"
:title="`游客${index + 1}`" :title="
goodsData.commodityTypeCode === '0'
? `房间${index + 1}`
: `游客${index + 1}`
"
:form="item" :form="item"
:showDeleteIcon="userFormList.length > 1" :showDeleteIcon="userFormList.length > 1"
:key="index" :key="index"
@ -78,7 +98,7 @@
</scroll-view> </scroll-view>
<!-- 总价区域 --> <!-- 总价区域 -->
<SumCard /> <SumCard :referencePrice="goodsData.specificationPrice" :discount="totalPrice" />
</view> </view>
</scroll-view> </scroll-view>
@ -107,7 +127,9 @@ import SumCard from "@/components/SumCard/index.vue";
const props = defineProps({ const props = defineProps({
goodsData: { goodsData: {
type: Object, type: Object,
default: () => ({}), default: () => ({
commodityTypeCode: "0", // 0- 1- 2-
}),
}, },
}); });

View File

@ -8,6 +8,15 @@
<view class="tag-wrapper" v-if="goodsData.timeTag"> <view class="tag-wrapper" v-if="goodsData.timeTag">
<view class="time-tag">{{ goodsData.timeTag || "随时可退" }}</view> <view class="time-tag">{{ goodsData.timeTag || "随时可退" }}</view>
</view> </view>
<!-- 日历ICON酒店订单显示 -->
<uni-icons
class="calender-icon"
v-if="isShowCalendar"
type="calendar"
size="24"
color="#00A6FF"
@click="showCalendar"
/>
</view> </view>
<!-- 地址区域 --> <!-- 地址区域 -->
@ -31,9 +40,12 @@
</template> </template>
<script setup> <script setup>
import { computed, defineProps } from "vue"; import { computed, defineProps, defineEmits } from "vue";
import LocationInfo from "@/components/LocationInfo/index.vue"; import LocationInfo from "@/components/LocationInfo/index.vue";
//
const emits = defineEmits(["showCalendar"]);
// Props // Props
const props = defineProps({ const props = defineProps({
goodsData: { goodsData: {
@ -44,12 +56,23 @@ const props = defineProps({
// - 使computed // - 使computed
const facilitiesList = computed(() => { const facilitiesList = computed(() => {
if (props.goodsData.commodityTag && props.goodsData.commodityTag.length) { if (
return props.goodsData.commodityTag; props.goodsData.commodityFacilityList &&
props.goodsData.commodityFacilityList.length
) {
return props.goodsData.commodityFacilityList;
} }
return []; return [];
}); });
//
const showCalendar = () => emits("showCalendar");
//
const isShowCalendar = computed(() => {
return props.goodsData.commodityTypeCode === "0";
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -1,9 +1,10 @@
.good-info { .good-info {
background: #fff; background: #fff;
margin-bottom: 12px;
// 标题区域 // 标题区域
.title-section { .title-section {
display: flex;
align-items: center;
margin-bottom: 12px; margin-bottom: 12px;
.title { .title {
@ -11,8 +12,10 @@
color: #333; color: #333;
font-weight: 600; font-weight: 600;
line-height: 1.4; line-height: 1.4;
display: block; flex: 0 280px;
margin-bottom: 8px; overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
.tag-wrapper { .tag-wrapper {
@ -27,11 +30,14 @@
border: 1px solid #f55726; border: 1px solid #f55726;
} }
} }
.calender-icon {
margin-left: auto;
}
} }
// 地址区域 // 地址区域
.address-section { .address-section {
margin-bottom: 12px;
padding: 12px 0; padding: 12px 0;
border-top: 1px solid #f0f0f0; border-top: 1px solid #f0f0f0;
border-bottom: 1px solid #f0f0f0; border-bottom: 1px solid #f0f0f0;
@ -52,6 +58,8 @@
// 设施信息区域 // 设施信息区域
.facilities-section { .facilities-section {
margin-top: 12px;
.facilities-grid { .facilities-grid {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);

View File

@ -12,7 +12,7 @@
<view class="goods-content"> <view class="goods-content">
<!-- 商品信息组件 --> <!-- 商品信息组件 -->
<GoodInfo :goodsData="goodsData" /> <GoodInfo :goodsData="goodsData" @showCalendar="showCalendar" />
<ModuleTitle title="购买须知" /> <ModuleTitle title="购买须知" />
@ -36,21 +36,32 @@
@confirm="handleConfirmOrder" @confirm="handleConfirmOrder"
@close="handleCloseConfirm" @close="handleCloseConfirm"
/> />
<!-- 日历组件 -->
<Calender
:visible="calendarVisible"
mode="range"
@close="handleCalendarClose"
@range-select="handleDateSelect"
/>
</view> </view>
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref } from "vue";
import { onLoad } from "@dcloudio/uni-app"; import { onLoad } from "@dcloudio/uni-app";
import { goodsDetail } from "@/request/api/GoodsApi"; import { goodsDetail, orderPay } from "@/request/api/GoodsApi";
import TopNavBar from "@/components/TopNavBar/index.vue"; import TopNavBar from "@/components/TopNavBar/index.vue";
import ImageSwiper from "@/components/ImageSwiper/index.vue"; import ImageSwiper from "@/components/ImageSwiper/index.vue";
import GoodInfo from "./components/GoodInfo/index.vue"; import GoodInfo from "./components/GoodInfo/index.vue";
import ModuleTitle from "@/components/ModuleTitle/index.vue"; import ModuleTitle from "@/components/ModuleTitle/index.vue";
import GoodConfirm from "./components/GoodConfirm/index.vue"; import GoodConfirm from "./components/GoodConfirm/index.vue";
import Calender from "@/components/Calender/index.vue";
const calendarVisible = ref(false);
const goodsData = ref({}); const goodsData = ref({});
const goodConfirmRef = ref(null); const goodConfirmRef = ref(null);
const selectedDate = ref("");
// //
const goodsInfo = async (params) => { const goodsInfo = async (params) => {
@ -61,20 +72,71 @@ const goodsInfo = async (params) => {
// //
const showConfirmPopup = () => { 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(); goodConfirmRef.value?.showPopup();
}; };
// //
const handleConfirmOrder = (orderData) => { const handleConfirmOrder = async (orderData) => {
console.log("确认订单:", 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";
// const params = {
// commodityId,
// purchaseAmount,
// payWay,
// paySource,
// consumerInfoEntityList,
// checkInData,
// checkOutData,
// };
// const res = await orderPay(params);
//
// uni.requestPayment({
// provider: "wxpay",
// timeStamp: String(Date.now()),
// nonceStr: "A1B2C3D4E5",
// package: "prepay_id=wx20180101abcdefg",
// signType: "MD5",
// paySign: "",
// success: (res) => {
// console.log("success:" + JSON.stringify(res));
// },
// fail: (err) => {
// console.log("fail:" + JSON.stringify(err));
// },
// });
uni.showToast({ uni.showToast({
title: "订单确认成功", title: "订单确认成功",
icon: "success", icon: "success",
}); });
//
// uni.navigateTo({
// url: '/pages/order/detail?orderId=' + orderData.orderId
// });
}; };
// //
@ -85,6 +147,25 @@ const handleCloseConfirm = () => {
onLoad(({ commodityId = "1950766939442774018" }) => { onLoad(({ commodityId = "1950766939442774018" }) => {
goodsInfo({ commodityId }); 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> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -4,4 +4,9 @@ const goodsDetail = (args) => {
return request.post("/hotelBiz/commodity/commodityDetail", args); return request.post("/hotelBiz/commodity/commodityDetail", args);
}; };
export { goodsDetail }; // 订单支付
const orderPay = (args) => {
return request.post("/hotelBiz/trade/order", args);
};
export { goodsDetail, orderPay };

View File

@ -19,11 +19,6 @@ const preOrder = (args) => {
return request.post("/hotelBiz/trade/preOrder", args); return request.post("/hotelBiz/trade/preOrder", args);
}; };
// 订单支付
const orderPay = (args) => {
return request.post("/hotelBiz/trade/order", args);
};
// 订单取消 // 订单取消
const orderCancel = (args) => { const orderCancel = (args) => {
return request.post("/hotelBiz/trade/cancelRefund", args); return request.post("/hotelBiz/trade/cancelRefund", args);
@ -44,7 +39,6 @@ export {
userWorkOrderList, userWorkOrderList,
userOrderDetail, userOrderDetail,
preOrder, preOrder,
orderPay,
orderCancel, orderCancel,
orderRefund, orderRefund,
orderPayNow, orderPayNow,