feat: 订单详情功能完善

This commit is contained in:
duanshuwen
2025-08-01 21:37:07 +08:00
parent afae470f85
commit 7ff542e57a
8 changed files with 317 additions and 198 deletions

View File

@@ -62,7 +62,12 @@
"urlCheck": false "urlCheck": false
}, },
"usingComponents": true, "usingComponents": true,
"permission" : {} "requiredPrivateInfos": ["getLocation"],
"permission": {
"scope.userLocation": {
"desc": "用于获取当前所在城市信息"
}
}
}, },
"mp-alipay": { "mp-alipay": {
"usingComponents": true "usingComponents": true

Binary file not shown.

After

Width:  |  Height:  |  Size: 782 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

View File

@@ -1,8 +1,8 @@
<template> <template>
<view class="goods-info mb12"> <view class="goods-info mb12">
<view class="hotel-header"> <view class="hotel-header">
<image class="hotel-icon" src="./images/icon_house.png"></image> <image class="hotel-icon" :src="orderTypeIcon"></image>
<text class="hotel-name">{{ orderData.commodityAddress }}</text> <text class="hotel-name">{{ orderData.storeName }}</text>
</view> </view>
<view class="goods-detail"> <view class="goods-detail">
<image <image
@@ -13,9 +13,21 @@
></image> ></image>
<view class="goods-description"> <view class="goods-description">
<text class="goods-title">{{ commodityName }}</text> <text class="goods-title">{{ commodityName }}</text>
<text class="goods-date" v-if="checkInData" <!-- 门店地址 -->
>预定时间{{ checkInData }}</text <view class="store-address" @click="openMap">
> <uni-icons type="location" size="18" color="#999" />
<text>{{ orderData.commodityAddress }}</text>
<uni-icons type="right" size="14" color="#999" />
</view>
<!-- 酒店类型 -->
<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>
<view class="included-services" v-if="hasServices"> <view class="included-services" v-if="hasServices">
@@ -36,6 +48,9 @@
<script setup> <script setup>
import { defineProps, computed } from "vue"; import { defineProps, computed } from "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: {
@@ -45,7 +60,7 @@ const props = defineProps({
id: "", id: "",
commodityServiceList: [], commodityServiceList: [],
orderStatus: "0", // 订单状态 0-待支付 1-待确认 2-待使用 3-已取消 4-退款中 5-已退款 6-已完成 orderStatus: "0", // 订单状态 0-待支付 1-待确认 2-待使用 3-已取消 4-退款中 5-已退款 6-已完成
orderType: undefined, // 0-酒店订单, 1-门票订单, 2-餐饮 orderType: "0", // 0-酒店订单, 1-门票订单, 2-餐饮
}), }),
}, },
}); });
@@ -63,6 +78,9 @@ const commodityCoverPhoto = computed(() => {
// 计算属性:入住时间 // 计算属性:入住时间
const checkInData = computed(() => props.orderData.checkInData || ""); const checkInData = computed(() => props.orderData.checkInData || "");
// 计算属性:离店时间
const checkOutData = computed(() => props.orderData.checkOutData || "");
// 计算属性:服务列表 // 计算属性:服务列表
const serviceList = computed(() => props.orderData.commodityServiceList || []); const serviceList = computed(() => props.orderData.commodityServiceList || []);
@@ -84,11 +102,50 @@ const shouldShowImage = computed(() => {
return !!commodityCoverPhoto.value; 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) => { const formatServiceAmount = (amount) => {
if (!amount) return ""; if (!amount) return "";
return typeof amount === "number" ? `×${amount}` : amount; return typeof amount === "number" ? `×${amount}` : amount;
}; };
// 打开地图
const openMap = () => {
const address = props.orderData.commodityAddress;
const latitude = Number(props.orderData.commodityLatitude);
const longitude = Number(props.orderData.commodityLongitude);
uni.getLocation({
type: "gcj02", //返回可以用于uni.openLocation的经纬度
success: (res) => {
console.log("当前经纬度", latitude, longitude);
uni.openLocation({
latitude: latitude,
longitude: longitude,
address: address,
success: () => {
console.log("success");
},
});
},
});
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -1,77 +1,154 @@
.goods-info { // ===== SASS变量定义 =====
background-color: #fff; // 颜色系统
border-radius: 10px; $color-white: #fff;
padding: 12px 16px 20px; $color-primary: #333;
} $color-secondary: #666;
$color-placeholder: pink;
.hotel-header { // 字体大小
$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; display: flex;
align-items: center; align-items: center;
margin-bottom: 10px;
} }
@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 { .hotel-icon {
width: 24px; width: $icon-size-sm;
height: 24px; height: $icon-size-sm;
margin-right: 8px; margin-right: $spacing-xs;
} }
.hotel-name { .hotel-name {
color: #333; @include text-style($font-size-xs, $color-primary, $font-weight-medium);
font-size: 12px; }
font-weight: 500;
} }
// 商品详情区域
.goods-detail { .goods-detail {
display: flex; display: flex;
margin-bottom: 20px; margin-bottom: $spacing-xxl;
}
.goods-image { .goods-image {
background-color: pink; background-color: $color-placeholder;
width: 65px; width: $image-size-md;
height: 65px; height: $image-size-md;
border-radius: 8px; border-radius: $border-radius-sm;
margin-right: 15px; margin-right: $spacing-lg;
flex-shrink: 0;
} }
.goods-description { .goods-description {
flex: 1; flex: 1;
} min-width: 0; // 防止flex子项溢出
.goods-title { .goods-title {
display: block; display: block;
font-size: 14px; @include text-style($font-size-sm, $color-primary, $font-weight-medium);
font-weight: 500; margin-bottom: $spacing-xs;
margin-bottom: 8px; line-height: 1.4;
} }
.goods-date { .store-address {
font-size: 12px; @include flex-center;
color: #666; @include text-style($font-size-xs, $color-primary);
text {
flex: 1;
padding: 0 6px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
} }
.in-date,
.out-date {
@include text-style($font-size-xs, $color-secondary);
margin-top: 8px;
}
}
}
// 包含服务区域
.included-services { .included-services {
margin-top: 10px; margin-top: $spacing-sm;
}
.services-title { .services-title {
display: block; display: block;
font-size: 12px; @include text-style($font-size-xs, $color-primary, $font-weight-medium);
margin-bottom: 12px; margin-bottom: $spacing-md;
} }
.service-item { .service-item {
display: flex; @include flex-between;
justify-content: space-between; align-items: center;
margin-bottom: 10px; margin-bottom: $spacing-sm;
&:last-child {
margin-bottom: 0;
} }
.service-name { .service-name {
font-size: 14px; @include text-style($font-size-sm, $color-primary);
flex: 1;
} }
.service-quantity { .service-quantity {
font-size: 12px; @include text-style($font-size-xs, $color-secondary);
color: #666; flex-shrink: 0;
margin-left: $spacing-xs;
}
}
}
} }

View File

@@ -75,7 +75,19 @@ const displayItems = computed(() => {
case ORDER_TYPES.HOTEL: case ORDER_TYPES.HOTEL:
return [ return [
{ label: LABELS.ORDER_ID, value: orderData.orderId }, { label: LABELS.ORDER_ID, value: orderData.orderId },
{ label: LABELS.CHECK_IN_TIME, value: orderData.checkInTime }, {
label: LABELS.CHECK_IN_TIME,
value:
orderData.checkInData?.replace(
/(\d{4})-(\d{1,2})-(\d{1,2})/,
"$2月$3日"
) +
"-" +
orderData.checkOutData?.replace(
/(\d{4})-(\d{1,2})-(\d{1,2})/,
"$2月$3日"
),
},
{ label: LABELS.VISITOR_NAME, value: orderData.visitorName }, { label: LABELS.VISITOR_NAME, value: orderData.visitorName },
{ label: LABELS.CONTACT_PHONE, value: orderData.contactPhone }, { label: LABELS.CONTACT_PHONE, value: orderData.contactPhone },
]; ];

View File

@@ -13,7 +13,7 @@
<text class="value">{{ payWayText }}</text> <text class="value">{{ payWayText }}</text>
</view> </view>
<!-- 在已退款状态显示 --> <!-- 在已退款状态显示 -->
<view class="order-item"> <view v-if="orderData.orderStatus === '4'" class="order-item">
<text class="label">退款单号</text> <text class="label">退款单号</text>
<text class="value">{{ orderData.refundOrderNo }}</text> <text class="value">{{ orderData.refundOrderNo }}</text>
</view> </view>
@@ -26,7 +26,9 @@
<button v-if="shouldShowButton" :class="buttonClass"> <button v-if="shouldShowButton" :class="buttonClass">
{{ buttonText }} {{ buttonText }}
</button> </button>
<text class="feedback">投诉反馈</text> <view class="feedback">
<text @click="openFeedback">投诉反馈</text>
</view>
</view> </view>
</template> </template>
@@ -96,6 +98,12 @@ const buttonClass = computed(() => {
return `${baseClass} pre-btn`; // 其他状态添加pre-btn样式 return `${baseClass} pre-btn`; // 其他状态添加pre-btn样式
} }
}); });
// 投诉电话
const openFeedback = () => {
const phoneNumber = props.orderData.complaintHotline;
uni.makePhoneCall({ phoneNumber });
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -147,7 +147,6 @@ $breakpoint-mobile: 480px;
margin-top: $spacing-large; margin-top: $spacing-large;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
box-shadow: 0 2px 8px rgba($button-color, 0.3);
transition: all $transition-normal; transition: all $transition-normal;
letter-spacing: 0.5px; letter-spacing: 0.5px;
@@ -219,49 +218,10 @@ $breakpoint-mobile: 480px;
} }
.feedback { .feedback {
display: block;
text-align: center; text-align: center;
font-size: $font-size-medium; font-size: $font-size-medium;
color: $text-color-primary; color: $text-color-primary;
font-weight: $font-weight-normal; font-weight: $font-weight-normal;
margin-top: $spacing-medium; margin-top: $spacing-medium;
cursor: pointer;
text-decoration: none;
position: relative;
transition: all $transition-fast;
padding: $spacing-small;
border-radius: 4px;
// 下划线动画效果
&::after {
content: "";
position: absolute;
bottom: 4px;
left: 50%;
width: 0;
height: 1px;
background-color: $text-color-accent;
transition: all $transition-normal;
transform: translateX(-50%);
}
&:hover {
color: $text-color-accent;
background-color: rgba($text-color-accent, 0.05);
&::after {
width: 60%;
}
}
&:active {
transform: scale(0.98);
}
// 移动端适配
@media (max-width: $breakpoint-mobile) {
font-size: $font-size-medium - 1px;
padding: $spacing-medium $spacing-small;
}
} }
} }