Replace SCSS variable usages with explicit pixel/hex values for consistent styling across all components Fix broken template syntax including missing class spaces and incorrect closing tags Migrate constant and API imports to centralized @/constants and @/api modules Add new utility classes: IdUtils, CallbackUtils, and TimerUtils Add new chat conversation API endpoints for recent conversations and message lists Add new Discovery page components (FindTabs, QuickQuestions, CardSwiper) and their styles Update app store config to use environment variables for base API and WebSocket URLs Add new selected tab icon assets
217 lines
4.9 KiB
Vue
217 lines
4.9 KiB
Vue
<template>
|
||
<div class="demo-container">
|
||
<div class="demo-header">
|
||
<span class="demo-title">GoodConfirm 组件演示</span>
|
||
</div>
|
||
|
||
<div class="demo-section">
|
||
<div class="section-title">基础用法</div>
|
||
<button class="demo-btn" @click="showConfirm">显示商品确认弹窗</button>
|
||
<button class="demo-btn" @click="setQuantity(5)" style="margin-left: 12px">
|
||
设置5人测试横向滚动
|
||
</button>
|
||
</div>
|
||
|
||
<div class="demo-section">
|
||
<div class="section-title">当前状态</div>
|
||
<div class="status-info">
|
||
<text>Stepper数量: {{ quantity }}</text>
|
||
<text>表单项数量: {{ userFormCount }}</text>
|
||
<text>总价: ¥{{ totalPrice }}</text>
|
||
<span class="debug-info">实时quantity值: {{ quantity }}</span>
|
||
<span class="feature-highlight">✨ 支持横向滚动浏览多个游客信息</span>
|
||
<span class="feature-highlight">🗑️ 支持删除游客信息(至少保留一位)</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="demo-section" v-if="lastOrderData">
|
||
<div class="section-title">最后提交的数据</div>
|
||
<div class="order-data">
|
||
<span>商品: {{ lastOrderData.goodsData.commodityName }}</span>
|
||
<span>数量: {{ lastOrderData.quantity }}</span>
|
||
<span>总价: ¥{{ lastOrderData.totalPrice }}</span>
|
||
<span>用户信息:</span>
|
||
<div class="user-list">
|
||
<div v-for="(user, index) in lastOrderData.userFormList" :key="index" class="user-item">
|
||
<span>游客{{ index + 1 }}: {{ user.name || "未填写" }} -
|
||
{{ user.phone || "未填写" }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<GoodConfirm ref="confirmRef" :goodsData="goodsData" @confirm="handleConfirm" @close="handleClose" />
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed } from "vue";
|
||
import GoodConfirm from "./index.vue";
|
||
|
||
const confirmRef = ref(null);
|
||
const quantity = ref(1);
|
||
const userFormCount = ref(1);
|
||
const lastOrderData = ref(null);
|
||
|
||
const goodsData = ref({
|
||
commodityName: "云从朵花温泉票(成人票)",
|
||
price: 70,
|
||
timeTag: "条件退款",
|
||
commodityPhotoList: [
|
||
{
|
||
photoUrl: "/static/test/mk_img_1.png",
|
||
},
|
||
],
|
||
});
|
||
|
||
const totalPrice = computed(() => {
|
||
return (goodsData.value.price * quantity.value).toFixed(0);
|
||
});
|
||
|
||
const showConfirm = () => {
|
||
confirmRef.value?.showPopup();
|
||
};
|
||
|
||
const handleConfirm = (orderData) => {
|
||
console.log("确认订单:", orderData);
|
||
lastOrderData.value = orderData;
|
||
quantity.value = orderData.quantity;
|
||
userFormCount.value = orderData.userFormList.length;
|
||
|
||
uni.showToast({
|
||
title: "订单确认成功",
|
||
icon: "success",
|
||
});
|
||
};
|
||
|
||
const handleClose = () => {
|
||
console.log("弹窗关闭");
|
||
};
|
||
|
||
const setQuantity = (num) => {
|
||
quantity.value = num;
|
||
userFormCount.value = num;
|
||
// 如果弹窗已打开,需要通过组件内部的quantity来更新
|
||
if (confirmRef.value) {
|
||
// 这里可以通过ref访问组件内部状态,但由于组件封装,我们通过重新打开来演示
|
||
uni.showToast({
|
||
title: `已设置${num}人,请重新打开弹窗查看效果`,
|
||
icon: "none",
|
||
duration: 2000,
|
||
});
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.demo-container {
|
||
padding: 20px;
|
||
background: #f5f5f5;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
.demo-header {
|
||
text-align: center;
|
||
margin-bottom: 30px;
|
||
|
||
.demo-title {
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
}
|
||
|
||
.demo-section {
|
||
background: #fff;
|
||
border-radius: 12px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
|
||
.section-title {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 15px;
|
||
}
|
||
}
|
||
|
||
.demo-btn {
|
||
width: 100%;
|
||
height: 48px;
|
||
background: linear-gradient(135deg, #ff6b35 0%, #ff8f65 100%);
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: 24px;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.2s;
|
||
box-shadow: 0 4px 12px rgba(255, 107, 53, 0.3);
|
||
|
||
&:active {
|
||
transform: translateY(1px);
|
||
box-shadow: 0 2px 8px rgba(255, 107, 53, 0.3);
|
||
}
|
||
|
||
&::after {
|
||
border: none;
|
||
}
|
||
}
|
||
|
||
.status-info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
|
||
text {
|
||
font-size: 14px;
|
||
color: #666;
|
||
padding: 8px 12px;
|
||
background: #f8f9fa;
|
||
border-radius: 6px;
|
||
|
||
&.feature-highlight {
|
||
background: linear-gradient(135deg, #ff6b35 0%, #ff8f65 100%);
|
||
color: white;
|
||
font-weight: bold;
|
||
}
|
||
|
||
&.debug-info {
|
||
background: #e6f7ff;
|
||
color: #1890ff;
|
||
font-weight: bold;
|
||
border: 1px solid #91d5ff;
|
||
}
|
||
}
|
||
}
|
||
|
||
.order-data {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
|
||
text {
|
||
font-size: 14px;
|
||
color: #333;
|
||
line-height: 1.5;
|
||
}
|
||
}
|
||
|
||
.user-list {
|
||
margin-top: 8px;
|
||
padding-left: 12px;
|
||
|
||
.user-item {
|
||
margin-bottom: 4px;
|
||
|
||
text {
|
||
font-size: 13px;
|
||
color: #666;
|
||
}
|
||
}
|
||
}
|
||
</style>
|