feat: 订单详情布局功能调整
This commit is contained in:
@@ -21,17 +21,16 @@
|
||||
}"
|
||||
>
|
||||
<view class="flex flex-items-center flex-row flex-shrink-0 mr-8">
|
||||
<uni-icons fontFamily="znicons" size="20" color="#333">{{
|
||||
zniconsMap[moduleItem.moduleIcon]
|
||||
}}</uni-icons>
|
||||
<text class="font-size-14 color-171717 line-height-20">{{
|
||||
moduleItem.moduleTitle
|
||||
}}</text>
|
||||
<uni-icons fontFamily="znicons" size="20" color="#333">
|
||||
{{ zniconsMap[moduleItem.moduleIcon] }}
|
||||
</uni-icons>
|
||||
<text class="font-size-14 color-171717 line-height-20">
|
||||
{{ moduleItem.moduleTitle }}
|
||||
</text>
|
||||
</view>
|
||||
<text
|
||||
class="flex-full font-size-12 color-525866 line-height-20 mt-4"
|
||||
>{{ moduleItem.moduleContent }}</text
|
||||
>
|
||||
<text class="flex-full font-size-12 color-525866 line-height-20 mt-4">
|
||||
{{ moduleItem.moduleContent }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -66,7 +66,7 @@ const props = defineProps({
|
||||
default: true,
|
||||
},
|
||||
// 背景颜色
|
||||
backgroundColor: {
|
||||
background: {
|
||||
type: String,
|
||||
default: "#d9eeff",
|
||||
},
|
||||
@@ -131,7 +131,7 @@ const navBarClass = computed(() => {
|
||||
// 计算导航栏样式
|
||||
const navBarStyle = computed(() => {
|
||||
return {
|
||||
backgroundColor: props.backgroundColor,
|
||||
background: props.background,
|
||||
zIndex: props.zIndex,
|
||||
};
|
||||
});
|
||||
|
||||
80
src/pages-order/order/components/FooterSection/index.vue
Normal file
80
src/pages-order/order/components/FooterSection/index.vue
Normal 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>
|
||||
@@ -1,41 +1,28 @@
|
||||
<template>
|
||||
<view class="goods-info mb-12">
|
||||
<view class="hotel-header">
|
||||
<image class="hotel-icon" :src="orderTypeIcon"></image>
|
||||
<text class="hotel-name">{{ orderData.storeName }}</text>
|
||||
<view class="border-box bg-white p-12 rounded-12 mb-12">
|
||||
<!-- 酒店类型入住离店日期部分 -->
|
||||
<DateRangeSection
|
||||
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 class="goods-detail">
|
||||
<image
|
||||
v-if="shouldShowImage"
|
||||
class="goods-image"
|
||||
: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 class="border-box border-bottom">
|
||||
<view class="font-size-12 color-99A0AE line-height-16 pb-12">
|
||||
{{ orderData.commodityDescription }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="included-services" v-if="hasServices">
|
||||
<text class="services-title">包含服务</text>
|
||||
<view
|
||||
v-for="item in formattedServiceList"
|
||||
:key="item.key"
|
||||
class="service-item"
|
||||
>
|
||||
<text class="service-name"> · {{ item.displayTitle }} </text>
|
||||
<text class="service-quantity">
|
||||
{{ item.displayAmount }}
|
||||
|
||||
<!-- 权益部分 -->
|
||||
<view class="flex flex-items-center mb-8">
|
||||
<text
|
||||
class="bg-F7F7F7 border-box rounded-4 font-size-11 color-525866 mr-4 pt-4 pb-4 pl-6 pr-6"
|
||||
v-for="(item, index) in orderData.commodityFacilityList"
|
||||
:key="index"
|
||||
>
|
||||
{{ item }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -44,82 +31,29 @@
|
||||
|
||||
<script setup>
|
||||
import { defineProps, computed } from "vue";
|
||||
import LocationInfo from "@/components/LocationInfo/index.vue";
|
||||
import iconHouse from "./images/icon_house.png";
|
||||
import iconFood from "./images/food.png";
|
||||
import iconTicket from "./images/ticket.png";
|
||||
import DateRangeSection from "@/components/DateRangeSection/index.vue";
|
||||
|
||||
const props = defineProps({
|
||||
orderData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({
|
||||
id: "",
|
||||
commodityServiceList: [],
|
||||
orderStatus: "0", // 订单状态 0-待支付 1-待确认 2-待使用 3-已取消 4-退款中 5-已退款 6-已完成
|
||||
orderType: "0", // 0-酒店订单, 1-门票订单, 2-餐饮
|
||||
}),
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
// 计算属性:商品名称
|
||||
const commodityName = computed(() => {
|
||||
return props.orderData.commodityName || "未知商品";
|
||||
const selectedDate = computed(() => {
|
||||
// 计算总天数
|
||||
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>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
## 商品信息组件
|
||||
|
||||
组件名称:商品信息组件
|
||||
|
||||
## 提示词:
|
||||
|
||||
使用 uniapp + vue3 组合式 api 开发微信小程序,要求如下:
|
||||
1、按照提供的图片,高度还原交互设计
|
||||
2、要求布局样式结构简洁明了,class 命名请按照模块名称来命名,例如:.goods-info
|
||||
3、可以使用 uniapp 内置的组件
|
||||
|
||||
## 备注
|
||||
|
||||
仅供学习、交流使用,请勿用于商业用途。
|
||||
@@ -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 |
@@ -1,38 +1,25 @@
|
||||
<template>
|
||||
<view class="order-info">
|
||||
<view class="order-item">
|
||||
<text class="label">订单号</text>
|
||||
<text class="value">{{ orderData.orderId }}</text>
|
||||
<view class="bg-white border-box rounded-10 p-12">
|
||||
<view class="flex mb-8 font-size-12">
|
||||
<text class="w-60 color-99A0AE">订单编号</text>
|
||||
<text class="color-525866">{{ orderData.orderId }}</text>
|
||||
</view>
|
||||
<view class="order-item">
|
||||
<text class="label">流水号</text>
|
||||
<text class="value">{{ orderData.paySerialNumber }}</text>
|
||||
<view class="flex mb-8 font-size-12">
|
||||
<text class="w-60 color-99A0AE">下单时间</text>
|
||||
<text class="color-525866">{{ orderData.createTime }}</text>
|
||||
</view>
|
||||
<view class="order-item">
|
||||
<text class="label">支付方式</text>
|
||||
<text class="value">{{ payWayText }}</text>
|
||||
</view>
|
||||
<!-- 在已退款状态显示 -->
|
||||
<view v-if="orderData.orderStatus === '4'" class="order-item">
|
||||
<text class="label">退款单号</text>
|
||||
<text class="value">{{ orderData.refundOrderNo }}</text>
|
||||
</view>
|
||||
<view class="line"></view>
|
||||
<view class="order-item amount">
|
||||
<text class="label">实际支付金额</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 class="flex font-size-12">
|
||||
<text class="w-60 color-99A0AE">支付状态</text>
|
||||
<text
|
||||
:class="[
|
||||
{
|
||||
'color-FF3D60': statusCode === '0',
|
||||
'color-21B466': statusCode === '1',
|
||||
},
|
||||
]"
|
||||
>
|
||||
{{ payStatusText }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -42,10 +29,9 @@ import { defineProps, computed, ref, defineEmits } from "vue";
|
||||
import { orderPayNow } from "@/request/api/OrderApi";
|
||||
|
||||
// 支付方式映射常量
|
||||
const PAY_WAY_MAP = {
|
||||
0: "微信",
|
||||
1: "支付宝",
|
||||
2: "云闪付",
|
||||
const PAY_STATUS_MAP = {
|
||||
0: "未支付",
|
||||
1: "已支付",
|
||||
};
|
||||
|
||||
// 加载状态
|
||||
@@ -68,11 +54,10 @@ const props = defineProps({
|
||||
}),
|
||||
},
|
||||
});
|
||||
const statusCode = computed(() => props.orderData.orderStatus);
|
||||
|
||||
// 使用计算属性缓存支付方式文本
|
||||
const payWayText = computed(() => {
|
||||
return PAY_WAY_MAP[props.orderData.payWay] || "未知支付方式";
|
||||
});
|
||||
const payStatusText = computed(() => PAY_STATUS_MAP[statusCode.value]);
|
||||
|
||||
// 格式化金额显示
|
||||
const formattedAmount = computed(() => {
|
||||
@@ -80,27 +65,6 @@ const formattedAmount = computed(() => {
|
||||
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) => {
|
||||
if (isLoading.value) return; // 防止重复点击
|
||||
@@ -195,14 +159,6 @@ const handleButtonClick = async (orderData) => {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 投诉电话
|
||||
const openFeedback = () => {
|
||||
const phoneNumber = props.orderData.complaintHotline;
|
||||
uni.makePhoneCall({ phoneNumber });
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
## 订单信息组件
|
||||
|
||||
组件名称:订单信息组件
|
||||
|
||||
## 提示词:
|
||||
|
||||
使用 uniapp + vue3 组合式 api 开发微信小程序,要求如下:
|
||||
1、按照提供的图片,高度还原交互设计
|
||||
2、要求布局样式结构简洁明了,class 命名请按照模块名称来命名,例如:.order-info
|
||||
3、可以使用 uniapp 内置的组件
|
||||
|
||||
## 备注
|
||||
|
||||
仅供学习、交流使用,请勿用于商业用途。
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
<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
|
||||
:size="size"
|
||||
:unit="unit"
|
||||
@@ -30,6 +32,4 @@ const props = defineProps({
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
<view
|
||||
class="border-box font-size-24 color-171717 line-height-32 font-500 pt-12 pb-12"
|
||||
>
|
||||
{{ statusText }}
|
||||
{{ currentStatusText }}
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -11,34 +11,13 @@ import { defineProps, computed } from "vue";
|
||||
|
||||
// 订单状态配置映射
|
||||
const ORDER_STATUS_CONFIG = {
|
||||
0: {
|
||||
text: "待支付",
|
||||
description: "请尽快完成支付",
|
||||
},
|
||||
1: {
|
||||
text: "待确认",
|
||||
description: "商家正在确认您的订单",
|
||||
},
|
||||
2: {
|
||||
text: "待使用",
|
||||
description: "预订成功,订单待使用",
|
||||
},
|
||||
3: {
|
||||
text: "已取消",
|
||||
description: "订单已取消",
|
||||
},
|
||||
4: {
|
||||
text: "退款中",
|
||||
description: "商家退款正在处理中,请耐心等待",
|
||||
},
|
||||
5: {
|
||||
text: "已退款",
|
||||
description: "款项预计1-7个工作日退回至原支付账户",
|
||||
},
|
||||
6: {
|
||||
text: "已完成",
|
||||
description: "订单已完成,感谢您的使用",
|
||||
},
|
||||
0: "待支付",
|
||||
1: "待确认",
|
||||
2: "待使用",
|
||||
3: "已取消",
|
||||
4: "退款中",
|
||||
5: "已退款",
|
||||
6: "已完成",
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
@@ -56,22 +35,12 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
// 当前状态配置
|
||||
const currentStatusConfig = computed(() => {
|
||||
// 当前状态
|
||||
const currentStatusText = computed(() => {
|
||||
return (
|
||||
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>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.4 KiB |
@@ -1,45 +1,24 @@
|
||||
<template>
|
||||
<view class="user-info mb-12" v-if="hasConsumerData">
|
||||
<view class="user-info-title">{{ infoTitle }}</view>
|
||||
<view
|
||||
v-for="(item, index) in consumerList"
|
||||
:key="getConsumerKey(item, index)"
|
||||
class="user-info-group"
|
||||
>
|
||||
<view class="user-info-item">
|
||||
<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
|
||||
class="bg-white border-box rounded-10 p-12 mb-12"
|
||||
v-if="hasConsumerData"
|
||||
>
|
||||
<view v-for="(item, index) in consumerList" :key="index">
|
||||
<view class="flex mb-8 font-size-12">
|
||||
<text class="w-60 color-99A0AE">住客姓名</text>
|
||||
<text class="color-525866">{{ item.visitorName }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex font-size-12">
|
||||
<text class="w-60 color-99A0AE">联系电话</text>
|
||||
<text class="color-525866">{{ contactPhone }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
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({
|
||||
orderData: {
|
||||
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(() => {
|
||||
return props.orderData.consumerInfoList || [];
|
||||
});
|
||||
const consumerList = computed(() => props.orderData.consumerInfoList || []);
|
||||
|
||||
// 联系电话
|
||||
const contactPhone = computed(() => consumerList.value[0]?.contactPhone);
|
||||
|
||||
// 检查是否有用户数据
|
||||
const hasConsumerData = computed(() => {
|
||||
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;
|
||||
};
|
||||
const hasConsumerData = computed(() => consumerList.value.length);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
## 游客信息组件
|
||||
|
||||
组件名称:游客信息组件
|
||||
|
||||
## 提示词:
|
||||
|
||||
使用 uniapp + vue3 组合式 api 开发微信小程序,要求如下:
|
||||
1、按照提供的图片,高度还原交互设计
|
||||
2、要求布局样式结构简洁明了,class 命名请按照模块名称来命名,例如:.user-info
|
||||
3、可以使用 uniapp 内置的组件
|
||||
|
||||
## 备注
|
||||
|
||||
仅供学习、交流使用,请勿用于商业用途。
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
<template>
|
||||
<view class="order-detail-page">
|
||||
<TopNavBar
|
||||
titleAlign="center"
|
||||
:backgroundColor="backgroundColor"
|
||||
:shadow="shadow"
|
||||
title="订单详情"
|
||||
fixed
|
||||
/>
|
||||
<view class="order-detail-page flex flex-col h-screen">
|
||||
<TopNavBar titleAlign="center" background="#D9EEFF" title="订单详情" />
|
||||
|
||||
<view class="order-detail-wrapper">
|
||||
<view
|
||||
class="order-detail-wrapper border-box flex-full overflow-hidden scroll-y"
|
||||
>
|
||||
<OrderStatusInfo :orderData="orderData" />
|
||||
<OrderQrcode
|
||||
v-if="orderData.orderStatus === '2'"
|
||||
@@ -17,27 +13,30 @@
|
||||
:val="orderData.orderId"
|
||||
/>
|
||||
<GoodsInfo :orderData="orderData" />
|
||||
<UserInfo :orderData="orderData" />
|
||||
<NoticeInfo :orderData="orderData" />
|
||||
<OrderInfo
|
||||
:orderData="orderData"
|
||||
@show-refund-popup="showRefundPopup"
|
||||
@pay-success="handlePaySuccess"
|
||||
/>
|
||||
|
||||
<!-- 退款状态显示 -->
|
||||
<RefundPopup
|
||||
v-model="refundVisible"
|
||||
:orderData="orderData"
|
||||
@confirm="handleRefundConfirm"
|
||||
/>
|
||||
<UserInfo :orderData="orderData" />
|
||||
|
||||
<OrderInfo :orderData="orderData" />
|
||||
</view>
|
||||
|
||||
<FooterSection
|
||||
:orderData="orderData"
|
||||
@show-refund-popup="showRefundPopup"
|
||||
@pay-success="handlePaySuccess"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 退款状态显示 -->
|
||||
<RefundPopup
|
||||
v-model="refundVisible"
|
||||
:orderData="orderData"
|
||||
@confirm="handleRefundConfirm"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
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 TopNavBar from "@/components/TopNavBar/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 NoticeInfo from "./components/NoticeInfo/index.vue";
|
||||
import OrderInfo from "./components/OrderInfo/index.vue";
|
||||
import FooterSection from "./components/FooterSection/index.vue";
|
||||
import RefundPopup from "@/components/RefundPopup/index.vue";
|
||||
|
||||
const refundVisible = ref(false);
|
||||
@@ -60,22 +60,6 @@ const getOrderDetail = async (orderId) => {
|
||||
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 = () => {
|
||||
refundVisible.value = true;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.order-detail-wrapper {
|
||||
background: linear-gradient(180deg, #d9eeff 0%, #f5f7fa 100%);
|
||||
padding: 88px 15px;
|
||||
padding: 0 12px 40px;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
background-color: #eef8ff;
|
||||
}
|
||||
|
||||
.bg-FF3D60 {
|
||||
background-color: #ff3d60;
|
||||
}
|
||||
|
||||
.bg-liner {
|
||||
background: linear-gradient(205deg, #8ae3fc 0%, rgba(138, 227, 252, 0) 20%),
|
||||
linear-gradient(155deg, #fef7e1 0%, rgba(254, 247, 225, 0) 20%),
|
||||
|
||||
@@ -17,4 +17,8 @@
|
||||
|
||||
.border-none {
|
||||
border: none;
|
||||
|
||||
&::after {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
// 弹性布局
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flex-items-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
.w-50 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.w-60 {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.w-80 {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user