feat: 订单详情布局功能调整

This commit is contained in:
duanshuwen
2025-10-29 21:08:35 +08:00
parent 89cf4f81cd
commit 2b9afb936e
23 changed files with 221 additions and 726 deletions

View File

@@ -21,17 +21,16 @@
}" }"
> >
<view class="flex flex-items-center flex-row flex-shrink-0 mr-8"> <view class="flex flex-items-center flex-row flex-shrink-0 mr-8">
<uni-icons fontFamily="znicons" size="20" color="#333">{{ <uni-icons fontFamily="znicons" size="20" color="#333">
zniconsMap[moduleItem.moduleIcon] {{ zniconsMap[moduleItem.moduleIcon] }}
}}</uni-icons> </uni-icons>
<text class="font-size-14 color-171717 line-height-20">{{ <text class="font-size-14 color-171717 line-height-20">
moduleItem.moduleTitle {{ moduleItem.moduleTitle }}
}}</text> </text>
</view> </view>
<text <text class="flex-full font-size-12 color-525866 line-height-20 mt-4">
class="flex-full font-size-12 color-525866 line-height-20 mt-4" {{ moduleItem.moduleContent }}
>{{ moduleItem.moduleContent }}</text </text>
>
</view> </view>
</view> </view>
</view> </view>

View File

@@ -66,7 +66,7 @@ const props = defineProps({
default: true, default: true,
}, },
// 背景颜色 // 背景颜色
backgroundColor: { background: {
type: String, type: String,
default: "#d9eeff", default: "#d9eeff",
}, },
@@ -131,7 +131,7 @@ const navBarClass = computed(() => {
// 计算导航栏样式 // 计算导航栏样式
const navBarStyle = computed(() => { const navBarStyle = computed(() => {
return { return {
backgroundColor: props.backgroundColor, background: props.background,
zIndex: props.zIndex, zIndex: props.zIndex,
}; };
}); });

View File

@@ -0,0 +1,80 @@
<template>
<view
class="footer bg-white border-box flex flex-items-center flex-justify-between p-12"
>
<button
v-if="shouldShowButton"
class="left border-none border-box bg-white rounded-10 flex flex-items-center flex-justify-center font-size-14 font-500 color-525866 mr-12"
>
取消订单
</button>
<button
:class="[
'right border-none rounded-10 flex flex-full flex-items-center flex-justify-center font-size-14 font-500',
{
'bg-FF3D60 color-white': statusCode === '0',
'bg-color-f5f7fa color-525866': statusCode === '2',
},
]"
>
{{ buttonText }}
</button>
</view>
</template>
<script setup>
import { defineProps, computed, ref, defineEmits } from "vue";
const props = defineProps({
orderData: {
type: Object,
required: true,
default: () => ({
orderId: "",
paySerialNumber: "",
payWay: "", // 支付方式 0-微信 1-支付宝 2-云闪付
payAmt: "",
orderStatus: "0", // 订单状态 0-待支付 1-待确认 2-待使用 3-已取消 4-退款中 5-已关闭 6-已完成
orderType: "0", // 0-酒店订单, 1-门票订单, 2-餐饮
}),
},
});
const statusCode = computed(() => props.orderData.orderStatus);
// 按钮文案逻辑,订单状态 0-待支付 1-待确认 2-待使用 3-已取消 4-退款中 5-已关闭 6-已完成
const buttonText = computed(() => {
switch (statusCode.value) {
case "0": // 待支付状态
return "立即支付";
case "2": // 待使用状态
return "申请退款";
case "3": // 已取消状态
case "5": // 已关闭状态
case "6": // 已完成状态
return "再次预定";
}
});
// 是否显示按钮(待支付、待使用、已取消、已关闭、已完成)
const shouldShowButton = computed(() => {
return ["0", "2", "3", "5", "6"].includes(statusCode.value);
});
</script>
<style lang="scss" scoped>
.footer {
border-radius: 12px 12px 0 0;
padding-bottom: 88rpx;
}
.left,
.right {
height: 48px;
}
.left {
border: 1px solid #e5e8ee;
width: 104px;
}
</style>

View File

@@ -1,41 +1,28 @@
<template> <template>
<view class="goods-info mb-12"> <view class="border-box bg-white p-12 rounded-12 mb-12">
<view class="hotel-header"> <!-- 酒店类型入住离店日期部分 -->
<image class="hotel-icon" :src="orderTypeIcon"></image> <DateRangeSection
<text class="hotel-name">{{ orderData.storeName }}</text> v-if="orderData.commodityTypeCode === '0'"
:selectedDate="selectedDate"
/>
<view class="font-size-16 font-500 color-000 line-height-24 ellipsis-1">
{{ orderData.commodityName }}
</view> </view>
<view class="goods-detail">
<image <view class="border-box border-bottom">
v-if="shouldShowImage" <view class="font-size-12 color-99A0AE line-height-16 pb-12">
class="goods-image" {{ orderData.commodityDescription }}
:src="commodityCoverPhoto"
lazy-load
></image>
<view class="goods-description">
<text class="goods-title">{{ commodityName }}</text>
<!-- 门店地址 -->
<LocationInfo :orderData="orderData" />
<!-- 酒店类型 -->
<template v-if="orderData.orderType === '0'">
<view class="in-date" v-if="checkInData">
入住时间{{ checkInData }}
</view>
<view class="out-date" v-if="checkOutData">
离店时间{{ checkOutData }}
</view>
</template>
</view> </view>
</view>
<view class="included-services" v-if="hasServices"> <!-- 权益部分 -->
<text class="services-title">包含服务</text> <view class="flex flex-items-center mb-8">
<view <text
v-for="item in formattedServiceList" class="bg-F7F7F7 border-box rounded-4 font-size-11 color-525866 mr-4 pt-4 pb-4 pl-6 pr-6"
:key="item.key" v-for="(item, index) in orderData.commodityFacilityList"
class="service-item" :key="index"
> >
<text class="service-name"> · {{ item.displayTitle }} </text> {{ item }}
<text class="service-quantity">
{{ item.displayAmount }}
</text> </text>
</view> </view>
</view> </view>
@@ -44,82 +31,29 @@
<script setup> <script setup>
import { defineProps, computed } from "vue"; import { defineProps, computed } from "vue";
import LocationInfo from "@/components/LocationInfo/index.vue"; import DateRangeSection from "@/components/DateRangeSection/index.vue";
import iconHouse from "./images/icon_house.png";
import iconFood from "./images/food.png";
import iconTicket from "./images/ticket.png";
const props = defineProps({ const props = defineProps({
orderData: { orderData: {
type: Object, type: Object,
required: true, required: true,
default: () => ({ default: () => ({}),
id: "",
commodityServiceList: [],
orderStatus: "0", // 订单状态 0-待支付 1-待确认 2-待使用 3-已取消 4-退款中 5-已退款 6-已完成
orderType: "0", // 0-酒店订单, 1-门票订单, 2-餐饮
}),
}, },
}); });
// 计算属性:商品名称 const selectedDate = computed(() => {
const commodityName = computed(() => { // 计算总天数
return props.orderData.commodityName || "未知商品"; const startDate = props.orderData.checkInData || "";
const endDate = props.orderData.checkOutData || "";
const timeStamp = 1000 * 60 * 60 * 24;
const totalDays = (new Date(endDate) - new Date(startDate)) / timeStamp;
return {
startDate,
endDate,
totalDays,
};
}); });
// 计算属性:商品封面图片
const commodityCoverPhoto = computed(() => {
return props.orderData.commodityCoverPhoto || "";
});
// 计算属性:入住时间
const checkInData = computed(() => props.orderData.checkInData || "");
// 计算属性:离店时间
const checkOutData = computed(() => props.orderData.checkOutData || "");
// 计算属性:服务列表
const serviceList = computed(() => props.orderData.commodityServiceList || []);
// 计算属性:是否有服务
const hasServices = computed(() => serviceList.value.length);
// 计算属性:格式化的服务列表(预处理数据,减少模板中的计算)
const formattedServiceList = computed(() => {
return serviceList.value.map((item, index) => ({
...item,
key: item.id || item.serviceTitle || `service-${index}`,
displayTitle: item.serviceTitle || "未知服务",
displayAmount: formatServiceAmount(item.serviceAmount),
}));
});
// 计算属性:是否显示商品图片
const shouldShowImage = computed(() => {
return !!commodityCoverPhoto.value;
});
// 计算属性:根据订单类型动态显示图标
const orderTypeIcon = computed(() => {
const orderType = props.orderData.orderType;
switch (orderType) {
case "0":
return iconHouse; // 酒店订单
case "1":
return iconTicket; // 门票订单
case "2":
return iconFood; // 餐饮订单
default:
return iconHouse; // 默认显示酒店图标
}
});
// 格式化服务数量
const formatServiceAmount = (amount) => {
if (!amount) return "";
return typeof amount === "number" ? `×${amount}` : amount;
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -1,14 +0,0 @@
## 商品信息组件
组件名称:商品信息组件
## 提示词:
使用 uniapp + vue3 组合式 api 开发微信小程序,要求如下:
1、按照提供的图片高度还原交互设计
2、要求布局样式结构简洁明了class 命名请按照模块名称来命名,例如:.goods-info
3、可以使用 uniapp 内置的组件
## 备注
仅供学习、交流使用,请勿用于商业用途。

View File

@@ -1,141 +0,0 @@
// ===== SASS变量定义 =====
// 颜色系统
$color-white: #fff;
$color-primary: #333;
$color-secondary: #666;
$color-placeholder: pink;
// 字体大小
$font-size-xs: 12px;
$font-size-sm: 14px;
$font-size-base: 16px;
// 字体粗细
$font-weight-normal: 400;
$font-weight-medium: 500;
$font-weight-bold: 600;
// 间距系统
$spacing-xs: 8px;
$spacing-sm: 10px;
$spacing-md: 12px;
$spacing-lg: 15px;
$spacing-xl: 16px;
$spacing-xxl: 20px;
// 圆角
$border-radius-sm: 8px;
$border-radius-md: 10px;
// 尺寸
$icon-size-sm: 24px;
$image-size-md: 65px;
// ===== SASS混合器 =====
@mixin flex-center {
display: flex;
align-items: center;
}
@mixin flex-between {
display: flex;
justify-content: space-between;
}
@mixin text-style($size, $color: $color-primary, $weight: $font-weight-normal) {
font-size: $size;
color: $color;
font-weight: $weight;
}
@mixin card-container {
background-color: $color-white;
border-radius: $border-radius-md;
padding: $spacing-md $spacing-xl $spacing-xxl;
}
// ===== 主要样式 =====
.goods-info {
@include card-container;
// 酒店头部信息
.hotel-header {
@include flex-center;
margin-bottom: $spacing-sm;
.hotel-icon {
width: $icon-size-sm;
height: $icon-size-sm;
margin-right: $spacing-xs;
}
.hotel-name {
@include text-style($font-size-xs, $color-primary, $font-weight-medium);
}
}
// 商品详情区域
.goods-detail {
display: flex;
margin-bottom: $spacing-xxl;
.goods-image {
background-color: $color-placeholder;
width: $image-size-md;
height: $image-size-md;
border-radius: $border-radius-sm;
margin-right: $spacing-lg;
flex-shrink: 0;
}
.goods-description {
flex: 1;
min-width: 0; // 防止flex子项溢出
.goods-title {
display: block;
@include text-style($font-size-sm, $color-primary, $font-weight-medium);
margin-bottom: $spacing-xs;
line-height: 1.4;
}
.in-date,
.out-date {
@include text-style($font-size-xs, $color-secondary);
margin-top: 8px;
}
}
}
// 包含服务区域
.included-services {
margin-top: $spacing-sm;
.services-title {
display: block;
@include text-style($font-size-xs, $color-primary, $font-weight-medium);
margin-bottom: $spacing-md;
}
.service-item {
@include flex-between;
align-items: center;
margin-bottom: $spacing-sm;
&:last-child {
margin-bottom: 0;
}
.service-name {
@include text-style($font-size-sm, $color-primary);
flex: 1;
}
.service-quantity {
@include text-style($font-size-xs, $color-secondary);
flex-shrink: 0;
margin-left: $spacing-xs;
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -1,38 +1,25 @@
<template> <template>
<view class="order-info"> <view class="bg-white border-box rounded-10 p-12">
<view class="order-item"> <view class="flex mb-8 font-size-12">
<text class="label">订单号</text> <text class="w-60 color-99A0AE">订单</text>
<text class="value">{{ orderData.orderId }}</text> <text class="color-525866">{{ orderData.orderId }}</text>
</view> </view>
<view class="order-item"> <view class="flex mb-8 font-size-12">
<text class="label">流水号</text> <text class="w-60 color-99A0AE">下单时间</text>
<text class="value">{{ orderData.paySerialNumber }}</text> <text class="color-525866">{{ orderData.createTime }}</text>
</view> </view>
<view class="order-item"> <view class="flex font-size-12">
<text class="label">支付方式</text> <text class="w-60 color-99A0AE">支付状态</text>
<text class="value">{{ payWayText }}</text> <text
</view> :class="[
<!-- 在已退款状态显示 --> {
<view v-if="orderData.orderStatus === '4'" class="order-item"> 'color-FF3D60': statusCode === '0',
<text class="label">退款单号</text> 'color-21B466': statusCode === '1',
<text class="value">{{ orderData.refundOrderNo }}</text> },
</view> ]"
<view class="line"></view> >
<view class="order-item amount"> {{ payStatusText }}
<text class="label">实际支付金额</text> </text>
<text class="value">{{ formattedAmount }}</text>
</view>
<!-- 根据订单状态动态显示按钮 -->
<button
v-if="shouldShowButton"
:class="['reserve-button', { loading: isLoading }]"
:disabled="isLoading"
@click="handleButtonClick(orderData)"
>
{{ isLoading ? "处理中..." : buttonText }}
</button>
<view class="feedback">
<text @click="openFeedback">投诉反馈</text>
</view> </view>
</view> </view>
</template> </template>
@@ -42,10 +29,9 @@ import { defineProps, computed, ref, defineEmits } from "vue";
import { orderPayNow } from "@/request/api/OrderApi"; import { orderPayNow } from "@/request/api/OrderApi";
// 支付方式映射常量 // 支付方式映射常量
const PAY_WAY_MAP = { const PAY_STATUS_MAP = {
0: "微信", 0: "未支付",
1: "支付", 1: "支付",
2: "云闪付",
}; };
// 加载状态 // 加载状态
@@ -68,11 +54,10 @@ const props = defineProps({
}), }),
}, },
}); });
const statusCode = computed(() => props.orderData.orderStatus);
// 使用计算属性缓存支付方式文本 // 使用计算属性缓存支付方式文本
const payWayText = computed(() => { const payStatusText = computed(() => PAY_STATUS_MAP[statusCode.value]);
return PAY_WAY_MAP[props.orderData.payWay] || "未知支付方式";
});
// 格式化金额显示 // 格式化金额显示
const formattedAmount = computed(() => { const formattedAmount = computed(() => {
@@ -80,27 +65,6 @@ const formattedAmount = computed(() => {
return amount ? `${parseFloat(amount).toFixed(2)}` : "0.00"; return amount ? `${parseFloat(amount).toFixed(2)}` : "0.00";
}); });
// 按钮文案逻辑,订单状态 0-待支付 1-待确认 2-待使用 3-已取消 4-退款中 5-已关闭 6-已完成
const buttonText = computed(() => {
const status = props.orderData.orderStatus;
switch (status) {
case "0": // 待支付状态
return "立即支付";
case "2": // 待使用状态
return "申请退款";
case "3": // 已取消状态
case "5": // 已关闭状态
case "6": // 已完成状态
return "再次预定";
}
});
// 是否显示按钮(待支付、待使用、已取消、已关闭、已完成)
const shouldShowButton = computed(() => {
const status = props.orderData.orderStatus;
return ["0", "2", "3", "5", "6"].includes(status);
});
// 处理按钮点击事件 // 处理按钮点击事件
const handleButtonClick = async (orderData) => { const handleButtonClick = async (orderData) => {
if (isLoading.value) return; // 防止重复点击 if (isLoading.value) return; // 防止重复点击
@@ -195,14 +159,6 @@ const handleButtonClick = async (orderData) => {
isLoading.value = false; isLoading.value = false;
} }
}; };
// 投诉电话
const openFeedback = () => {
const phoneNumber = props.orderData.complaintHotline;
uni.makePhoneCall({ phoneNumber });
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss"></style>
@import "./styles/index.scss";
</style>

View File

@@ -1,14 +0,0 @@
## 订单信息组件
组件名称:订单信息组件
## 提示词:
使用 uniapp + vue3 组合式 api 开发微信小程序,要求如下:
1、按照提供的图片高度还原交互设计
2、要求布局样式结构简洁明了class 命名请按照模块名称来命名,例如:.order-info
3、可以使用 uniapp 内置的组件
## 备注
仅供学习、交流使用,请勿用于商业用途。

View File

@@ -1,156 +0,0 @@
// 颜色系统
$order-bg-color: #fff;
$text-color-primary: #333;
$text-color-secondary: #666;
$text-color-accent: #ff5722;
$button-color: #00a6ff;
$button-disabled-color: #ccc;
$border-color: #ececec;
$shadow-color: rgba(0, 0, 0, 0.08);
// 尺寸和间距
$order-border-radius: 10px;
$order-padding: 16px 18px;
$spacing-small: 8px;
$spacing-medium: 10px;
$spacing-large: 20px;
$button-height: 42px;
// 字体系统
$font-size-small: 12px;
$font-size-medium: 14px;
$font-size-large: 18px;
$font-weight-normal: 400;
$font-weight-medium: 500;
$font-weight-semibold: 600;
// 过渡动画
$transition-fast: 0.2s ease;
$transition-normal: 0.3s ease;
.order-info {
background-color: $order-bg-color;
border-radius: $order-border-radius;
padding: $order-padding;
box-shadow: 0 2px 8px $shadow-color;
transition: box-shadow $transition-normal;
&:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}
// 订单项样式,优化布局和视觉层次
.order-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: $spacing-small;
padding: 4px 0;
transition: background-color $transition-fast;
.label {
font-size: $font-size-small;
color: $text-color-secondary;
font-weight: $font-weight-normal;
flex-shrink: 0;
line-height: 1.4;
}
.value {
font-size: $font-size-small;
color: $text-color-primary;
font-weight: $font-weight-normal;
text-align: right;
word-break: break-word;
overflow-wrap: break-word;
line-height: 1.4;
max-width: 60%;
}
// 金额特殊样式,增强视觉重点
&.amount {
.label {
color: $text-color-primary;
font-weight: $font-weight-medium;
font-size: $font-size-medium;
}
.value {
color: $text-color-accent;
font-size: $font-size-large;
font-weight: $font-weight-semibold;
max-width: none;
// 货币符号样式
&::before {
content: "¥";
margin-right: 2px;
font-size: 11px;
}
}
}
}
.line {
border-bottom: 1px solid $border-color;
margin: $spacing-medium 0;
height: 0;
opacity: 0.6;
transition: opacity $transition-fast;
&:hover {
opacity: 1;
}
}
.reserve-button {
width: 100%;
background: linear-gradient(179deg, #00a6ff 0%, #0256ff 100%);
color: #fff;
border: none;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: $uni-border-radius-50px;
height: $button-height;
font-size: $font-size-medium;
font-weight: $font-weight-medium;
margin-top: $spacing-large;
position: relative;
overflow: hidden;
letter-spacing: 0.5px;
&:disabled {
background: $button-disabled-color;
cursor: not-allowed;
transform: none;
box-shadow: none;
&::before {
display: none;
}
}
// 加载状态样式
&.loading {
background: $button-disabled-color;
cursor: not-allowed;
transform: none;
box-shadow: none;
position: relative;
&::before {
display: none;
}
}
}
.feedback {
text-align: center;
font-size: $font-size-medium;
color: $text-color-primary;
font-weight: $font-weight-normal;
margin-top: $spacing-medium;
}
}

View File

@@ -1,5 +1,7 @@
<template> <template>
<view class="order-qrcode"> <view
class="bg-white border-box rounded-12 flex flex-items-center flex-justify-center p-20 mb-12"
>
<Qrcode <Qrcode
:size="size" :size="size"
:unit="unit" :unit="unit"
@@ -30,6 +32,4 @@ const props = defineProps({
}); });
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss"></style>
@import "./styles/index.scss";
</style>

View File

@@ -1,18 +0,0 @@
.order-qrcode {
background-color: $uni-bg-color;
border-radius: 10px;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
padding: 18px;
margin-bottom: 12px;
text {
font-size: $uni-font-size-sm;
color: #666666;
line-height: 17px;
margin-top: 4px;
}
}

View File

@@ -2,7 +2,7 @@
<view <view
class="border-box font-size-24 color-171717 line-height-32 font-500 pt-12 pb-12" class="border-box font-size-24 color-171717 line-height-32 font-500 pt-12 pb-12"
> >
{{ statusText }} {{ currentStatusText }}
</view> </view>
</template> </template>
@@ -11,34 +11,13 @@ import { defineProps, computed } from "vue";
// 订单状态配置映射 // 订单状态配置映射
const ORDER_STATUS_CONFIG = { const ORDER_STATUS_CONFIG = {
0: { 0: "待支付",
text: "待支付", 1: "待确认",
description: "请尽快完成支付", 2: "待使用",
}, 3: "已取消",
1: { 4: "退款中",
text: "待确认", 5: "已退款",
description: "商家正在确认您的订单", 6: "已完成",
},
2: {
text: "待使用",
description: "预订成功,订单待使用",
},
3: {
text: "已取消",
description: "订单已取消",
},
4: {
text: "退款中",
description: "商家退款正在处理中,请耐心等待",
},
5: {
text: "已退款",
description: "款项预计1-7个工作日退回至原支付账户",
},
6: {
text: "已完成",
description: "订单已完成,感谢您的使用",
},
}; };
const props = defineProps({ const props = defineProps({
@@ -56,22 +35,12 @@ const props = defineProps({
}, },
}); });
// 当前状态配置 // 当前状态
const currentStatusConfig = computed(() => { const currentStatusText = computed(() => {
return ( return (
ORDER_STATUS_CONFIG[props.orderData.orderStatus] || ORDER_STATUS_CONFIG["0"] ORDER_STATUS_CONFIG[props.orderData.orderStatus] || ORDER_STATUS_CONFIG["0"]
); );
}); });
// 状态文本
const statusText = computed(() => {
return currentStatusConfig.value.text;
});
// 状态描述
const statusDescription = computed(() => {
return currentStatusConfig.value.description;
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -1,45 +1,24 @@
<template> <template>
<view class="user-info mb-12" v-if="hasConsumerData"> <view
<view class="user-info-title">{{ infoTitle }}</view> class="bg-white border-box rounded-10 p-12 mb-12"
<view v-if="hasConsumerData"
v-for="(item, index) in consumerList" >
:key="getConsumerKey(item, index)" <view v-for="(item, index) in consumerList" :key="index">
class="user-info-group" <view class="flex mb-8 font-size-12">
> <text class="w-60 color-99A0AE">住客姓名</text>
<view class="user-info-item"> <text class="color-525866">{{ item.visitorName }}</text>
<text class="label">{{ contactLabel }}</text>
<text class="value">{{ item.visitorName || "未填写" }}</text>
</view>
<view class="user-info-item">
<text class="label">联系电话</text>
<text class="value">{{ formatPhone(item.contactPhone) }}</text>
</view> </view>
</view> </view>
<view class="flex font-size-12">
<text class="w-60 color-99A0AE">联系电话</text>
<text class="color-525866">{{ contactPhone }}</text>
</view>
</view> </view>
</template> </template>
<script setup> <script setup>
import { defineProps, computed } from "vue"; import { defineProps, computed } from "vue";
// 订单类型常量
const ORDER_TYPES = {
HOTEL: "0", // 酒店订单
TICKET: "1", // 门票订单
DINING: "2", // 餐饮订单
};
// 信息配置映射
const INFO_CONFIG = {
[ORDER_TYPES.HOTEL]: {
title: "订房信息",
contactLabel: "联系房客:",
},
default: {
title: "游客信息",
contactLabel: "联系游客:",
},
};
const props = defineProps({ const props = defineProps({
orderData: { orderData: {
type: Object, type: Object,
@@ -53,44 +32,14 @@ const props = defineProps({
}, },
}); });
// 使用计算属性缓存信息标题
const infoTitle = computed(() => {
const config = INFO_CONFIG[props.orderData.orderType] || INFO_CONFIG.default;
return config.title;
});
// 使用计算属性缓存联系人标签
const contactLabel = computed(() => {
const config = INFO_CONFIG[props.orderData.orderType] || INFO_CONFIG.default;
return config.contactLabel;
});
// 使用计算属性处理用户信息列表,提供更好的响应性和缓存 // 使用计算属性处理用户信息列表,提供更好的响应性和缓存
const consumerList = computed(() => { const consumerList = computed(() => props.orderData.consumerInfoList || []);
return props.orderData.consumerInfoList || [];
}); // 联系电话
const contactPhone = computed(() => consumerList.value[0]?.contactPhone);
// 检查是否有用户数据 // 检查是否有用户数据
const hasConsumerData = computed(() => { const hasConsumerData = computed(() => consumerList.value.length);
return consumerList.value.length > 0;
});
// 生成更稳定的key值优先使用唯一标识
const getConsumerKey = (item, index) => {
return item.id || item.visitorName || `consumer-${index}`;
};
// 格式化电话号码显示
const formatPhone = (phone) => {
if (!phone) return "未填写";
// 简单的电话号码格式化,中间部分用*号隐藏
if (phone.length === 11) {
return phone.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
}
return phone;
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss"></style>
@import "./styles/index.scss";
</style>

View File

@@ -1,14 +0,0 @@
## 游客信息组件
组件名称:游客信息组件
## 提示词:
使用 uniapp + vue3 组合式 api 开发微信小程序,要求如下:
1、按照提供的图片高度还原交互设计
2、要求布局样式结构简洁明了class 命名请按照模块名称来命名,例如:.user-info
3、可以使用 uniapp 内置的组件
## 备注
仅供学习、交流使用,请勿用于商业用途。

View File

@@ -1,28 +0,0 @@
.user-info {
background-color: #fff;
border-radius: 10px;
padding: 16px 18px;
}
.user-info-title {
font-size: $uni-font-size-lg;
font-weight: 600;
margin-bottom: 14px;
}
.user-info-item {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.label {
font-size: $uni-font-size-base;
color: #666;
margin-right: 8px;
}
.value {
font-size: $uni-font-size-base;
color: $uni-text-color;
}

View File

@@ -1,14 +1,10 @@
<template> <template>
<view class="order-detail-page"> <view class="order-detail-page flex flex-col h-screen">
<TopNavBar <TopNavBar titleAlign="center" background="#D9EEFF" title="订单详情" />
titleAlign="center"
:backgroundColor="backgroundColor"
:shadow="shadow"
title="订单详情"
fixed
/>
<view class="order-detail-wrapper"> <view
class="order-detail-wrapper border-box flex-full overflow-hidden scroll-y"
>
<OrderStatusInfo :orderData="orderData" /> <OrderStatusInfo :orderData="orderData" />
<OrderQrcode <OrderQrcode
v-if="orderData.orderStatus === '2'" v-if="orderData.orderStatus === '2'"
@@ -17,27 +13,30 @@
:val="orderData.orderId" :val="orderData.orderId"
/> />
<GoodsInfo :orderData="orderData" /> <GoodsInfo :orderData="orderData" />
<UserInfo :orderData="orderData" />
<NoticeInfo :orderData="orderData" />
<OrderInfo
:orderData="orderData"
@show-refund-popup="showRefundPopup"
@pay-success="handlePaySuccess"
/>
<!-- 退款状态显示 --> <UserInfo :orderData="orderData" />
<RefundPopup
v-model="refundVisible" <OrderInfo :orderData="orderData" />
:orderData="orderData"
@confirm="handleRefundConfirm"
/>
</view> </view>
<FooterSection
:orderData="orderData"
@show-refund-popup="showRefundPopup"
@pay-success="handlePaySuccess"
/>
</view> </view>
<!-- 退款状态显示 -->
<RefundPopup
v-model="refundVisible"
:orderData="orderData"
@confirm="handleRefundConfirm"
/>
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref } from "vue";
import { onLoad, onPageScroll } from "@dcloudio/uni-app"; import { onLoad } from "@dcloudio/uni-app";
import { userOrderDetail, orderRefund } from "@/request/api/OrderApi"; import { userOrderDetail, orderRefund } from "@/request/api/OrderApi";
import TopNavBar from "@/components/TopNavBar/index.vue"; import TopNavBar from "@/components/TopNavBar/index.vue";
import OrderQrcode from "./components/OrderQrcode/index.vue"; import OrderQrcode from "./components/OrderQrcode/index.vue";
@@ -46,6 +45,7 @@ import GoodsInfo from "./components/GoodsInfo/index.vue";
import UserInfo from "./components/UserInfo/index.vue"; import UserInfo from "./components/UserInfo/index.vue";
import NoticeInfo from "./components/NoticeInfo/index.vue"; import NoticeInfo from "./components/NoticeInfo/index.vue";
import OrderInfo from "./components/OrderInfo/index.vue"; import OrderInfo from "./components/OrderInfo/index.vue";
import FooterSection from "./components/FooterSection/index.vue";
import RefundPopup from "@/components/RefundPopup/index.vue"; import RefundPopup from "@/components/RefundPopup/index.vue";
const refundVisible = ref(false); const refundVisible = ref(false);
@@ -60,22 +60,6 @@ const getOrderDetail = async (orderId) => {
console.log(res); console.log(res);
}; };
// 监听页面滚动事件
const backgroundColor = ref("transparent");
const shadow = ref(false);
onPageScroll(({ scrollTop }) => {
console.log("🚀 ~ scrollTop:", scrollTop);
// 当滚动到顶部时,显示返回按钮
if (scrollTop <= 0) {
backgroundColor.value = "transparent";
shadow.value = false;
} else {
backgroundColor.value = "#ffffff";
shadow.value = true;
}
});
// 显示退款弹窗 // 显示退款弹窗
const showRefundPopup = () => { const showRefundPopup = () => {
refundVisible.value = true; refundVisible.value = true;

View File

@@ -1,4 +1,4 @@
.order-detail-wrapper { .order-detail-wrapper {
background: linear-gradient(180deg, #d9eeff 0%, #f5f7fa 100%); background: linear-gradient(180deg, #d9eeff 0%, #f5f7fa 100%);
padding: 88px 15px; padding: 0 12px 40px;
} }

View File

@@ -27,6 +27,10 @@
background-color: #eef8ff; background-color: #eef8ff;
} }
.bg-FF3D60 {
background-color: #ff3d60;
}
.bg-liner { .bg-liner {
background: linear-gradient(205deg, #8ae3fc 0%, rgba(138, 227, 252, 0) 20%), background: linear-gradient(205deg, #8ae3fc 0%, rgba(138, 227, 252, 0) 20%),
linear-gradient(155deg, #fef7e1 0%, rgba(254, 247, 225, 0) 20%), linear-gradient(155deg, #fef7e1 0%, rgba(254, 247, 225, 0) 20%),

View File

@@ -17,4 +17,8 @@
.border-none { .border-none {
border: none; border: none;
&::after {
display: none !important;
}
} }

View File

@@ -1,8 +1,4 @@
// 弹性布局 // 弹性布局
.flex {
display: flex;
}
.flex-items-center { .flex-items-center {
align-items: center; align-items: center;
} }

View File

@@ -9,6 +9,11 @@
.w-50 { .w-50 {
width: 50%; width: 50%;
} }
.w-60 {
width: 60px;
}
.w-80 { .w-80 {
width: 80px; width: 80px;
} }