feat: 商品详情交互开发
This commit is contained in:
@@ -1,83 +1,107 @@
|
||||
<template>
|
||||
<uni-popup ref="popup" type="bottom">
|
||||
<view class="good-confirm-container">
|
||||
<!-- 头部标题栏 -->
|
||||
<uni-popup
|
||||
ref="popup"
|
||||
type="bottom"
|
||||
background-color="#E9F3F7"
|
||||
border-radius="12px 12px 0 0"
|
||||
mask-background-color="rgba(0,0,0,0.5)"
|
||||
:safe-area="false"
|
||||
>
|
||||
<view class="good-container">
|
||||
<!-- 头部区域 -->
|
||||
<view class="header">
|
||||
<view class="header-title">确认订单</view>
|
||||
<view class="header-title">填写信息</view>
|
||||
<view class="close-btn" @click="closePopup">
|
||||
<uni-icons type="closeempty" size="20" color="#666"></uni-icons>
|
||||
<uni-icons type="closeempty" size="24" color="#333" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 商品信息区域 -->
|
||||
<view class="goods-info">
|
||||
<view class="goods-image">
|
||||
<image
|
||||
:src="
|
||||
goodsData.commodityPhotoList?.[0]?.photoUrl ||
|
||||
'/static/test/mk_img_1.png'
|
||||
"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
</view>
|
||||
<view class="goods-details">
|
||||
<view class="goods-title">{{
|
||||
goodsData.commodityName || "商品名称"
|
||||
}}</view>
|
||||
<view class="goods-price">
|
||||
<text class="currency">¥</text>
|
||||
<text class="price">{{ goodsData.price || 399 }}</text>
|
||||
</view>
|
||||
<view class="goods-tag" v-if="goodsData.timeTag">
|
||||
{{ goodsData.timeTag }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 数量选择区域 -->
|
||||
<view class="quantity-section">
|
||||
<view class="quantity-label">购买数量</view>
|
||||
<view class="quantity-control">
|
||||
<view
|
||||
class="quantity-btn"
|
||||
:class="{ disabled: quantity <= 1 }"
|
||||
@click="decreaseQuantity"
|
||||
>
|
||||
<uni-icons type="minus" size="16" color="#666"></uni-icons>
|
||||
</view>
|
||||
<view class="quantity-input">
|
||||
<input
|
||||
type="number"
|
||||
v-model="quantity"
|
||||
@input="handleQuantityInput"
|
||||
:disabled="false"
|
||||
<scroll-view
|
||||
class="good-content"
|
||||
:scroll-y="true"
|
||||
:show-scrollbar="false"
|
||||
>
|
||||
<view class="wrapper">
|
||||
<view class="good-info-wrapper">
|
||||
<!-- 轮播图区域 -->
|
||||
<ImageSwiper
|
||||
:images="goodsData.commodityPhotoList"
|
||||
:height="130"
|
||||
:border-radius="0"
|
||||
:showThumbnails="false"
|
||||
/>
|
||||
</view>
|
||||
<view class="quantity-btn" @click="increaseQuantity">
|
||||
<uni-icons type="plus" size="16" color="#666"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 总价区域 -->
|
||||
<view class="total-section">
|
||||
<view class="total-label">合计</view>
|
||||
<view class="total-price">
|
||||
<text class="currency">¥</text>
|
||||
<text class="price">{{ totalPrice }}</text>
|
||||
<!-- 商品信息区域 -->
|
||||
<view class="goods-info">
|
||||
<view class="goods-details">
|
||||
<view class="goods-title">{{
|
||||
goodsData.commodityName || "商品名称"
|
||||
}}</view>
|
||||
<view class="goods-price">
|
||||
<text class="currency">¥</text>
|
||||
<text class="price">{{ goodsData.price || 399 }}</text>
|
||||
</view>
|
||||
<view class="goods-service-list">
|
||||
<view class="service-title">包含服务</view>
|
||||
<view class="goods-service-item">
|
||||
<text class="service-label">随时可退</text>
|
||||
<text class="service-value">1份</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 数量选择区域 -->
|
||||
<view class="quantity-section">
|
||||
<ModuleTitle title="游客信息" />
|
||||
|
||||
<Stepper v-model="quantity" />
|
||||
</view>
|
||||
|
||||
<!-- 游客信息区域 -->
|
||||
<scroll-view
|
||||
class="user-form-list"
|
||||
:scroll-x="true"
|
||||
:show-scrollbar="false"
|
||||
>
|
||||
<FormCard
|
||||
v-for="(item, index) in userFormList"
|
||||
:title="`游客${index + 1}`"
|
||||
:form="item"
|
||||
:showDeleteIcon="userFormList.length > 1"
|
||||
:key="index"
|
||||
@update:name="(value) => updateUserForm(index, 'name', value)"
|
||||
@update:phone="(value) => updateUserForm(index, 'phone', value)"
|
||||
@delete="() => deleteUserForm(index)"
|
||||
/>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 总价区域 -->
|
||||
<SumCard />
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部按钮区域 -->
|
||||
<view class="footer">
|
||||
<button class="confirm-btn" @click="confirmOrder">确认购买</button>
|
||||
<view class="left">
|
||||
<text class="total-count">共{{ quantity }}间,合计:</text>
|
||||
<text class="total-price">{{ totalPrice }}</text>
|
||||
</view>
|
||||
|
||||
<view class="confirm-btn" @click="confirmOrder">立即支付</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, defineProps, defineEmits } from "vue";
|
||||
import { ref, computed, watch, defineProps, defineEmits } from "vue";
|
||||
import ImageSwiper from "@/components/ImageSwiper/index.vue";
|
||||
import ModuleTitle from "@/components/ModuleTitle/index.vue";
|
||||
import Stepper from "@/components/Stepper/index.vue";
|
||||
import FormCard from "@/components/FormCard/index.vue";
|
||||
import SumCard from "@/components/SumCard/index.vue";
|
||||
|
||||
// Props定义
|
||||
const props = defineProps({
|
||||
@@ -93,6 +117,8 @@ const emits = defineEmits(["confirm", "close"]);
|
||||
// 响应式数据
|
||||
const popup = ref(null);
|
||||
const quantity = ref(1);
|
||||
const userFormList = ref([{ name: "", phone: "" }]); // 初始化一个表单项
|
||||
const isDeleting = ref(false); // 标志位,防止删除时watch冲突
|
||||
|
||||
// 计算属性
|
||||
const totalPrice = computed(() => {
|
||||
@@ -100,6 +126,31 @@ const totalPrice = computed(() => {
|
||||
return (price * quantity.value).toFixed(0);
|
||||
});
|
||||
|
||||
// 监听 quantity 变化,动态调整 userFormList
|
||||
watch(
|
||||
quantity,
|
||||
(newQuantity, oldQuantity) => {
|
||||
// 如果正在执行删除操作,跳过watch逻辑
|
||||
if (isDeleting.value) {
|
||||
isDeleting.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const currentLength = userFormList.value.length;
|
||||
|
||||
if (newQuantity > currentLength) {
|
||||
// 数量增加,添加新的表单项
|
||||
for (let i = currentLength; i < newQuantity; i++) {
|
||||
userFormList.value.push({ name: "", phone: "" });
|
||||
}
|
||||
} else if (newQuantity < currentLength) {
|
||||
// 数量减少,删除多余的表单项
|
||||
userFormList.value.splice(newQuantity);
|
||||
}
|
||||
},
|
||||
{ immediate: false }
|
||||
);
|
||||
|
||||
// 方法定义
|
||||
const showPopup = () => {
|
||||
popup.value?.open();
|
||||
@@ -110,23 +161,31 @@ const closePopup = () => {
|
||||
emits("close");
|
||||
};
|
||||
|
||||
const increaseQuantity = () => {
|
||||
quantity.value++;
|
||||
};
|
||||
|
||||
const decreaseQuantity = () => {
|
||||
if (quantity.value > 1) {
|
||||
quantity.value--;
|
||||
const updateUserForm = (index, field, value) => {
|
||||
if (userFormList.value[index]) {
|
||||
userFormList.value[index][field] = value;
|
||||
}
|
||||
};
|
||||
|
||||
const handleQuantityInput = (e) => {
|
||||
const value = parseInt(e.detail.value);
|
||||
if (value && value > 0) {
|
||||
quantity.value = value;
|
||||
} else {
|
||||
quantity.value = 1;
|
||||
const deleteUserForm = (index) => {
|
||||
// 确保至少保留一个表单项
|
||||
if (userFormList.value.length <= 1) {
|
||||
uni.showToast({
|
||||
title: "至少需要一位游客信息",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置删除标志位,防止watch监听器干扰
|
||||
isDeleting.value = true;
|
||||
|
||||
// 删除指定索引的表单项
|
||||
userFormList.value.splice(index, 1);
|
||||
|
||||
// 同步更新quantity
|
||||
quantity.value = userFormList.value.length;
|
||||
};
|
||||
|
||||
const confirmOrder = () => {
|
||||
@@ -134,6 +193,7 @@ const confirmOrder = () => {
|
||||
goodsData: props.goodsData,
|
||||
quantity: quantity.value,
|
||||
totalPrice: totalPrice.value,
|
||||
userFormList: userFormList.value,
|
||||
};
|
||||
emits("confirm", orderData);
|
||||
closePopup();
|
||||
|
||||
Reference in New Issue
Block a user