Compare commits

3 Commits

Author SHA1 Message Date
duanshuwen
1f3a3c052a feat: 样式调整 2025-10-28 20:39:04 +08:00
duanshuwen
bbd975ffa7 Merge branch 'main' of https://git.nianxx.cn/zoujing/YGChatCS into fix-109 2025-10-28 20:34:52 +08:00
duanshuwen
eed2eea123 feat: 订单支付|商品详情调整 2025-10-28 20:34:18 +08:00
9 changed files with 177 additions and 205 deletions

View File

@@ -28,11 +28,16 @@
<uni-icons fontFamily="znicons" size="20" color="#333"> <uni-icons fontFamily="znicons" size="20" color="#333">
{{ zniconsMap["zn-refund"] }} {{ zniconsMap["zn-refund"] }}
</uni-icons> </uni-icons>
<text class="font-size-14 font-600 color-171717 ml-8">退订规则</text> <text class="font-size-14 font-600 color-171717 ml-8">
{{ refundTitle }}
</text>
</view> </view>
<view class="font-size-14 color-525866 line-height-16"> <view
<!-- {{ commodityPurchaseInstruction.refundContent }} --> class="font-size-14 color-525866 line-height-16 mb-4"
·不予退款12小时以内取消或未入住不予退款 v-for="(item, index) in commodityPurchaseInstruction"
:key="index"
>
{{ item }}
</view> </view>
</view> </view>
</view> </view>
@@ -64,9 +69,22 @@ const emit = defineEmits(["update:modelValue"]);
const popupRef = ref(null); const popupRef = ref(null);
// 获取退款模板 // 获取退款模板
const refundTitle = computed(() => {
if (props.orderData.commodityPurchaseInstruction) {
return (
props.orderData.commodityPurchaseInstruction.refundTitle || "退订规则"
);
}
return "退订规则";
});
const commodityPurchaseInstruction = computed(() => { const commodityPurchaseInstruction = computed(() => {
if (props.orderData.commodityPurchaseInstruction) { if (props.orderData.commodityPurchaseInstruction) {
return props.orderData.commodityPurchaseInstruction; // 以换行符为分隔符,将字符串转换为数组
return props.orderData.commodityPurchaseInstruction.refundContent.split(
"\n"
);
} }
return {}; return {};

View File

@@ -62,7 +62,11 @@
"mp-weixin": { "mp-weixin": {
"appid": "wx5e79df5996572539", "appid": "wx5e79df5996572539",
"setting": { "setting": {
"urlCheck": false "urlCheck": false,
"minified": true
},
"optimization": {
"subPackages": true
}, },
"usingComponents": true, "usingComponents": true,
"requiredPrivateInfos": ["getLocation"], "requiredPrivateInfos": ["getLocation"],

View File

@@ -27,7 +27,7 @@
<view class="right"> <view class="right">
<input <input
class="border-box rounded-8 px-4 py-2 font-size-15 color-000 line-height-20" class="border-box rounded-8 px-4 py-2 font-size-15 color-000 line-height-20"
v-model="userFormList[0].contactPhone" v-model.trim="userFormList[0].contactPhone"
placeholder="请输入联系手机" placeholder="请输入联系手机"
maxlength="11" maxlength="11"
/> />

View File

@@ -19,7 +19,7 @@
<view class="right"> <view class="right">
<input <input
class="border-box rounded-8 px-4 py-2 font-size-15 color-000 line-height-20" class="border-box rounded-8 px-4 py-2 font-size-15 color-000 line-height-20"
v-model="item.visitorName" v-model.trim="item.visitorName"
placeholder="请输入姓名" placeholder="请输入姓名"
maxlength="11" maxlength="11"
/> />
@@ -31,7 +31,7 @@
<view class="right"> <view class="right">
<input <input
class="border-box rounded-8 px-4 py-2 font-size-15 color-000 line-height-20" class="border-box rounded-8 px-4 py-2 font-size-15 color-000 line-height-20"
v-model="userFormList[0].contactPhone" v-model.trim="userFormList[0].contactPhone"
placeholder="请输入联系手机" placeholder="请输入联系手机"
maxlength="11" maxlength="11"
/> />

View File

@@ -102,10 +102,10 @@ import UserSection from "./components/UserSection/index.vue";
import RefundPopup from "@/components/RefundPopup/index.vue"; import RefundPopup from "@/components/RefundPopup/index.vue";
import DetailPopup from "@/components/DetailPopup/index.vue"; import DetailPopup from "@/components/DetailPopup/index.vue";
import FooterSection from "./components/FooterSection/index.vue"; import FooterSection from "./components/FooterSection/index.vue";
import { goodsDetail } from "@/request/api/GoodsApi"; import { goodsDetail, orderPay } from "@/request/api/GoodsApi";
import { useSelectedDateStore } from "@/store"; import { useSelectedDateStore } from "@/store";
import { GOODS_TYPE } from "@/constant/type"; import { GOODS_TYPE } from "@/constant/type";
import { PhoneUtils } from "@/utils"; import { ThrottleUtils, PhoneUtils } from "@/utils";
const refundVisible = ref(false); const refundVisible = ref(false);
const detailVisible = ref(false); const detailVisible = ref(false);
@@ -190,18 +190,113 @@ const navigateToDetail = ({ commodityId }) => {
}); });
}; };
// 处理支付点击事件 // 验证用户姓名
const handlePayClick = (orderData) => { const validateUserForms = () => {
console.log("处理支付点击事件", userFormList.value); const invalidUsers = userFormList.value.filter((user) => {
// 校验手机号 return user.visitorName.trim() === "";
if (!PhoneUtils.validatePhone(userFormList.value[0].contactPhone)) {
uni.showToast({
title: "请输入正确的手机号",
icon: "none",
}); });
if (invalidUsers.length) {
uni.showToast({ title: "请填写住客姓名", icon: "none" });
return false;
}
return true;
};
// 处理支付点击事件
const handlePayClick = ThrottleUtils.createThrottle(async (goodsData) => {
console.log("处理支付点击事件", userFormList.value);
// 判断是酒店类型
if (goodsData.commodityTypeCode === "0") {
// 校验用户姓名
if (!validateUserForms()) {
return; return;
} }
}
// 校验手机号
if (!PhoneUtils.validatePhone(userFormList.value[0].contactPhone)) {
uni.showToast({ title: "请输入正确的手机号", icon: "none" });
return;
}
// 购买的商品id
const commodityId = goodsData.commodityId;
// 消费者信息
const consumerInfoEntityList = userFormList.value;
// 购买数量
const purchaseAmount = consumerInfoEntityList.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" });
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" });
return;
}
// 调用微信支付
uni.requestPayment({
provider: "wxpay",
timeStamp: String(timeStamp), // 确保为字符串类型
nonceStr: String(nonceStr),
package: String(packageVal), // 确保为字符串类型
signType: String(signType),
paySign: String(paySign),
success: () => {
uni.showToast({
title: "支付成功",
icon: "success",
success: () => {
uni.navigateTo({
url: "/pages-order/order/list",
});
},
});
},
fail: () => {
uni.showToast({ title: "支付失败,请重试", icon: "none" });
},
});
}, 1000);
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -11,7 +11,7 @@
</view> </view>
<!-- 设施信息区域 --> <!-- 设施信息区域 -->
<view class="facilities-section"> <view class="facilities-section" v-if="facilitiesList.length">
<view class="facilities-grid"> <view class="facilities-grid">
<view <view
class="facility-item" class="facility-item"

View File

@@ -43,21 +43,24 @@
</scroll-view> </scroll-view>
<!-- 立即抢购 --> <!-- 立即抢购 -->
<view class="footer"> <view class="footer border-top">
<view class="left"> <view
<text class="label">价格</text> class="amt font-size-20 font-bold color-FF3D60 line-height-28 flex flex-items-center mr-8"
<text class="price">{{ calculatedTotalPrice }}</text> >
</view> {{ calculatedTotalPrice }}
<view class="buy-button" @click="showConfirmPopup">立即抢购</view>
</view> </view>
<!-- 商品确认弹窗 --> <view
<GoodConfirm class="btn border-box rounded-10 flex flex-items-center ml-auto pl-8"
ref="goodConfirmRef" @click="navigateToPay(goodsData)"
:goodsData="goodsData" >
@confirm="handleConfirmOrder" <image
@close="handleCloseConfirm" class="icon"
src="https://oss.nianxx.cn/mp/static/version_101/common/btn.png"
/> />
<text class="font-size-16 font-500 color-white">立即预定</text>
</view>
</view>
<!-- 日历组件 --> <!-- 日历组件 -->
<Calender <Calender
@@ -73,12 +76,8 @@
<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 { import { goodsDetail, commodityDailyPriceList } from "@/request/api/GoodsApi";
goodsDetail, import { DateUtils } from "@/utils";
commodityDailyPriceList,
orderPay,
} from "@/request/api/GoodsApi";
import { ThrottleUtils, DateUtils } from "@/utils";
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";
@@ -94,7 +93,6 @@ import { useSelectedDateStore } from "@/store";
const navOpacity = ref(0); const navOpacity = ref(0);
const calendarVisible = ref(false); const calendarVisible = ref(false);
const goodsData = ref({}); const goodsData = ref({});
const goodConfirmRef = ref(null);
// 处理滚动事件 // 处理滚动事件
const handleScroll = (e) => { const handleScroll = (e) => {
@@ -160,135 +158,6 @@ const getGoodsDailyPrice = async (params) => {
priceData.value = res.data; 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 = ThrottleUtils.createThrottle(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/order/list",
});
},
});
},
fail: (err) => {
console.error("支付失败:" + JSON.stringify(err));
uni.showToast({
title: "支付失败,请重试",
icon: "none",
duration: 2000,
});
},
});
}, 1000);
// 处理关闭弹窗
const handleCloseConfirm = () => {
console.log("关闭确认弹窗");
};
const selectedDateStore = useSelectedDateStore(); const selectedDateStore = useSelectedDateStore();
onLoad(({ commodityId = "1950766939442774018" }) => { onLoad(({ commodityId = "1950766939442774018" }) => {
// 从store中获取选中的日期 // 从store中获取选中的日期
@@ -374,6 +243,13 @@ const handleDateSelect = (data) => {
// 日历组件会自动关闭,无需手动设置 // 日历组件会自动关闭,无需手动设置
calendarVisible.value = false; calendarVisible.value = false;
}; };
// 跳转订购
const navigateToPay = ({ commodityId }) => {
uni.navigateTo({
url: `/pages-booking/index?commodityId=${commodityId}`,
});
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -68,7 +68,7 @@ $button-color: #00a6ff;
.goods-content { .goods-content {
border-radius: 28px 28px 0 0; border-radius: 28px 28px 0 0;
background-color: #fff; background-color: #fff;
padding: 12px; padding: 20px 12px;
position: relative; position: relative;
margin-top: -30px; margin-top: -30px;
z-index: 1; z-index: 1;
@@ -81,52 +81,27 @@ $button-color: #00a6ff;
background-color: #fff; background-color: #fff;
box-sizing: border-box; box-sizing: border-box;
padding: 12px 12px 24px; padding: 12px 12px 24px;
// 阴影
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.1);
z-index: 10; z-index: 10;
flex-shrink: 0; // 防止被压缩 flex-shrink: 0; // 防止被压缩
display: flex; display: flex;
align-items: center; align-items: center;
.left { .amt {
display: flex;
align-items: baseline;
}
.label {
font-size: $uni-font-size-base;
color: $uni-text-color;
}
.price {
display: flex;
align-items: baseline;
font-size: 24px;
color: #f55726;
&::before { &::before {
content: "¥"; content: "¥";
font-size: $uni-font-size-sm; font-size: 16px;
font-weight: 500;
} }
} }
.buy-button { .btn {
width: 160px; width: 120px;
background: linear-gradient(179deg, #00a6ff 0%, #0256ff 100%); height: 48px;
color: #fff; background: linear-gradient(90deg, #ff3d60 57%, #ff990c 100%);
border: none; }
padding: 0;
display: flex; .icon {
align-items: center; height: 48px;
justify-content: center; width: 34px;
border-radius: $uni-border-radius-50px;
height: 42px;
font-size: $uni-font-size-base;
font-weight: 500;
position: relative;
overflow: hidden;
transition: all 0.3s ease;
letter-spacing: 0.5px;
margin-left: auto;
} }
} }

View File

@@ -3,6 +3,10 @@
border: 1px solid #e5e8ee; border: 1px solid #e5e8ee;
} }
.border-top {
border-top: 1px solid #e5e8ee;
}
.border-bottom { .border-bottom {
border-bottom: 1px solid #e5e8ee; border-bottom: 1px solid #e5e8ee;
} }