feat(order): add order detail and list pages with components for order management

- Implemented order detail page with components for displaying order status, user info, and refund options.
- Created order list page with pagination and order cards for displaying all orders.
- Added styles for order detail and list pages.
- Developed a prompt document outlining component requirements for the order management system.
- Introduced a new Card component for quick booking with a responsive design.
- Enhanced Tabs component for better navigation between different categories.
- Integrated z-paging for efficient data loading and management in order and quick booking lists.
- Added service order card component for displaying service requests with call functionality.
- Updated main CSS for improved viewport handling.
This commit is contained in:
duanshuwen
2026-05-26 15:38:33 +08:00
parent fa76435e38
commit ad93ca5e8e
194 changed files with 17069 additions and 2 deletions

View File

@@ -0,0 +1,233 @@
<template>
<div class="demo-container">
<div class="demo-header">
<spanclass="demo-title">GoodConfirm 组件演示</text>
</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>
<spanclass="debug-info">实时quantity值: {{ quantity }}</text>
<spanclass="feature-highlight"> 支持横向滚动浏览多个游客信息</text>
<spanclass="feature-highlight"
>🗑 支持删除游客信息至少保留一位</text
>
</div>
</div>
<div class="demo-section" v-if="lastOrderData">
<div class="section-title">最后提交的数据</div>
<div class="order-data">
<text>商品: {{ lastOrderData.goodsData.commodityName }}</text>
<text>数量: {{ lastOrderData.quantity }}</text>
<text>总价: ¥{{ lastOrderData.totalPrice }}</text>
<text>用户信息:</text>
<div class="user-list">
<div
v-for="(user, index) in lastOrderData.userFormList"
:key="index"
class="user-item"
>
<text
>游客{{ index + 1 }}: {{ user.name || "未填写" }} -
{{ user.phone || "未填写" }}</text
>
</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>