feat: 优化订单详情滚动交互

This commit is contained in:
duanshuwen
2025-10-05 11:54:09 +08:00
parent 9cc7b48d36
commit e58ded9b84
5 changed files with 112 additions and 111 deletions

View File

@@ -1,22 +1,27 @@
<template> <template>
<view :class="navBarClass" :style="navBarStyle"> <view :class="navBarClass" :style="navBarStyle">
<!-- 状态栏占位 --> <!-- 状态栏占位 -->
<view :style="{ height: statusBarHeight + 'px' }" v-if="!hideStatusBar"></view> <view
:style="{ height: statusBarHeight + 'px' }"
v-if="!hideStatusBar"
></view>
<!-- 导航栏内容 --> <!-- 导航栏内容 -->
<view class="nav-bar-content" :style="{ height: navBarHeight + 'px' }"> <view class="nav-bar-content" :style="{ height: navBarHeight + 'px' }">
<!-- 左侧返回按钮 --> <!-- 左侧返回按钮 -->
<view class="nav-bar-left" @click="handleBack" v-if="showBack"> <view class="nav-bar-left" @click="handleBack" v-if="showBack">
<uni-icons type="left" size="20" :color="backIconColor" /> <uni-icons type="left" size="20" :color="backIconColor" />
</view> </view>
<!-- 中间标题区域 --> <!-- 中间标题区域 -->
<view :class="['nav-bar-center', `nav-bar-center--${titleAlign}`]"> <view :class="['nav-bar-center', `nav-bar-center--${titleAlign}`]">
<slot name="title"> <slot name="title">
<text class="nav-bar-title" :style="{ color: titleColor }">{{ title }}</text> <text class="nav-bar-title" :style="{ color: titleColor }">{{
title
}}</text>
</slot> </slot>
</view> </view>
<!-- 右侧操作区域 --> <!-- 右侧操作区域 -->
<view class="nav-bar-right"> <view class="nav-bar-right">
<slot name="right"></slot> <slot name="right"></slot>
@@ -26,108 +31,114 @@
</template> </template>
<script setup> <script setup>
import { computed, onMounted, ref } from 'vue' import { computed, onMounted, ref } from "vue";
// 定义props // 定义props
const props = defineProps({ const props = defineProps({
// 标题文本 // 标题文本
title: { title: {
type: String, type: String,
default: '' default: "",
}, },
// 是否固定在顶部 // 是否固定在顶部
fixed: { fixed: {
type: Boolean, type: Boolean,
default: false default: false,
},
// 是否添加阴影
shadow: {
type: Boolean,
default: true,
}, },
// 是否显示返回按钮 // 是否显示返回按钮
showBack: { showBack: {
type: Boolean, type: Boolean,
default: true default: true,
}, },
// 背景颜色 // 背景颜色
backgroundColor: { backgroundColor: {
type: String, type: String,
default: '#ffffff' default: "#ffffff",
}, },
// 标题颜色 // 标题颜色
titleColor: { titleColor: {
type: String, type: String,
default: '#333333' default: "#333333",
}, },
// 返回按钮图标颜色 // 返回按钮图标颜色
backIconColor: { backIconColor: {
type: String, type: String,
default: '#333333' default: "#333333",
}, },
// 是否隐藏状态栏占位 // 是否隐藏状态栏占位
hideStatusBar: { hideStatusBar: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
// 自定义z-index // 自定义z-index
zIndex: { zIndex: {
type: Number, type: Number,
default: 999 default: 999,
}, },
// 标题对齐方式 // 标题对齐方式
titleAlign: { titleAlign: {
type: String, type: String,
default: 'center', // 'center' | 'left' default: "center", // 'center' | 'left'
validator: (value) => ['center', 'left'].includes(value) validator: (value) => ["center", "left"].includes(value),
} },
}) });
// 定义emits // 定义emits
const emit = defineEmits(['back']) const emit = defineEmits(["back"]);
// 系统信息 // 系统信息
const statusBarHeight = ref(0) const statusBarHeight = ref(0);
const navBarHeight = ref(44) // 默认导航栏高度 const navBarHeight = ref(44); // 默认导航栏高度
// 获取系统信息 // 获取系统信息
onMounted(() => { onMounted(() => {
const systemInfo = uni.getSystemInfoSync() const systemInfo = uni.getSystemInfoSync();
statusBarHeight.value = systemInfo.statusBarHeight || 0 statusBarHeight.value = systemInfo.statusBarHeight || 0;
// 根据平台设置导航栏高度 // 根据平台设置导航栏高度
if (systemInfo.platform === 'ios') { if (systemInfo.platform === "ios") {
navBarHeight.value = 44 navBarHeight.value = 44;
} else { } else {
navBarHeight.value = 48 navBarHeight.value = 48;
} }
}) });
// 计算导航栏样式类 // 计算导航栏样式类
const navBarClass = computed(() => { const navBarClass = computed(() => {
return [ return [
'top-nav-bar', "top-nav-bar",
{ {
'top-nav-bar--fixed': props.fixed "top-nav-bar--fixed": props.fixed,
} "has-shadow": props.shadow,
] },
}) ];
});
// 计算导航栏样式 // 计算导航栏样式
const navBarStyle = computed(() => { const navBarStyle = computed(() => {
return { return {
backgroundColor: props.backgroundColor, backgroundColor: props.backgroundColor,
zIndex: props.zIndex zIndex: props.zIndex,
} };
}) });
// 处理返回事件 // 处理返回事件
const handleBack = () => { const handleBack = () => {
emit('back') emit("back");
// 如果没有监听back事件默认执行返回上一页 // 如果没有监听back事件默认执行返回上一页
if (!emit('back')) { if (!emit("back")) {
uni.navigateBack({ uni.navigateBack({
delta: 1 delta: 1,
}) });
} }
} };
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@use "./styles/index.scss"; @use "./styles/index.scss";
</style> </style>

View File

@@ -2,7 +2,10 @@
.top-nav-bar { .top-nav-bar {
width: 100%; width: 100%;
background-color: #ffffff; background-color: #ffffff;
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.1);
&.has-shadow {
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.1);
}
&--fixed { &--fixed {
position: fixed; position: fixed;
@@ -44,6 +47,7 @@
.nav-bar-center { .nav-bar-center {
flex: 1; flex: 1;
height: 30px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;

View File

@@ -134,48 +134,8 @@ $transition-normal: 0.3s ease;
margin-top: $spacing-large; margin-top: $spacing-large;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
transition: all $transition-normal;
letter-spacing: 0.5px; letter-spacing: 0.5px;
// 按钮波纹效果
&::before {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(255, 255, 255, 0.3);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
&:hover {
background: linear-gradient(
135deg,
$button-hover-color 0%,
color.scale($button-hover-color, $lightness: -11.9%) 100%
);
transform: translateY(-2px);
box-shadow: 0 4px 16px rgba($button-color, 0.4);
&::before {
width: 300px;
height: 300px;
}
}
&:active {
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba($button-color, 0.3);
}
&:focus {
outline: none;
box-shadow: 0 0 0 3px rgba($button-color, 0.3);
}
&:disabled { &:disabled {
background: $button-disabled-color; background: $button-disabled-color;
cursor: not-allowed; cursor: not-allowed;

View File

@@ -113,9 +113,9 @@ const commodityPurchaseInstruction = computed(() => {
}); });
// 方法定义 // 方法定义
const show = () => popupRef.value.open(); const show = () => popupRef.value && popupRef.value.open();
const hide = () => popupRef.value.close(); const hide = () => popupRef.value && popupRef.value.close();
// 监听modelValue变化 // 监听modelValue变化
watch( watch(

View File

@@ -1,32 +1,45 @@
<template> <template>
<view class="order-detail-wrapper"> <view class="order-detail-page">
<uni-icons type="left" size="20" color="#fff" @click="goBack" /> <TopNavBar
titleAlign="center"
:backgroundColor="backgroundColor"
:backIconColor="backIconColor"
:shadow="shadow"
fixed
>
<template #title>
{{ title }}
</template>
</TopNavBar>
<OrderStatusInfo :orderData="orderData" /> <view class="order-detail-wrapper">
<OrderQrcode <OrderStatusInfo :orderData="orderData" />
v-if="orderData.orderStatus === '2'" <OrderQrcode
size="132" v-if="orderData.orderStatus === '2'"
unit="px" size="132"
:val="orderData.orderId" unit="px"
/> :val="orderData.orderId"
<GoodsInfo :orderData="orderData" /> />
<UserInfo :orderData="orderData" /> <GoodsInfo :orderData="orderData" />
<NoticeInfo :orderData="orderData" /> <UserInfo :orderData="orderData" />
<OrderInfo :orderData="orderData" @show-refund-popup="showRefundPopup" /> <NoticeInfo :orderData="orderData" />
<OrderInfo :orderData="orderData" @show-refund-popup="showRefundPopup" />
<!-- 退款状态显示 --> <!-- 退款状态显示 -->
<RefundPopup <RefundPopup
v-model="refundVisible" v-model="refundVisible"
:orderData="orderData" :orderData="orderData"
@confirm="handleRefundConfirm" @confirm="handleRefundConfirm"
/> />
</view>
</view> </view>
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref } from "vue";
import { onLoad } from "@dcloudio/uni-app"; import { onLoad, onPageScroll } 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 OrderQrcode from "./components/OrderQrcode/index.vue"; import OrderQrcode from "./components/OrderQrcode/index.vue";
import OrderStatusInfo from "./components/OrderStatusInfo/index.vue"; import OrderStatusInfo from "./components/OrderStatusInfo/index.vue";
import GoodsInfo from "./components/GoodsInfo/index.vue"; import GoodsInfo from "./components/GoodsInfo/index.vue";
@@ -45,12 +58,25 @@ onLoad(async ({ orderId }) => {
console.log(res); console.log(res);
}); });
// 返回上一页 // 监听页面滚动事件
const goBack = () => { const backgroundColor = ref("transparent");
uni.navigateBack({ const backIconColor = ref("#fff");
delta: 1, const title = ref("");
}); const shadow = ref(false);
}; onPageScroll(({ scrollTop }) => {
// 当滚动到顶部时,显示返回按钮
if (scrollTop <= 0) {
backgroundColor.value = "transparent";
backIconColor.value = "#fff";
title.value = "";
shadow.value = false;
} else {
backgroundColor.value = "#ffffff";
backIconColor.value = "#333333";
title.value = "订单详情";
shadow.value = true;
}
});
// 显示退款弹窗 // 显示退款弹窗
const showRefundPopup = () => { const showRefundPopup = () => {