Files
uni-fans-score/pages/order/details.vue
T

446 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="return-container">
<!-- 订单信息卡片 -->
<view class="order-card">
<view class="order-header">
<text class="title">{{ orderStatusText }}</text>
<text class="order-no">订单号{{ orderInfo.orderNo || '-' }}</text>
</view>
<view class="device-info">
<view class="device-left">
<view class="device-name">共享风扇</view>
<view class="device-id">设备号{{ orderInfo.deviceNo || '-' }}</view>
</view>
<view class="device-right">
<view class="payment-badge wx-score" v-if="orderInfo.payWay === 'wx_score_pay'">
<image src="/static/images/wxpayflag.png" mode="aspectFit" class="badge-icon"></image>
<view class="badge-text">
<text>微信支付分</text>
<text class="divider">|</text>
<text class="highlight">免押租借</text>
</view>
</view>
<!-- 会员订单标识 -->
<view class="payment-badge member" v-else-if="orderInfo.payWay === 'wx_member_pay'">
<text class="badge-text">会员订单</text>
</view>
<!-- 微信支付押金标识 -->
<view class="payment-badge deposit" v-else-if="orderInfo.payWay === 'wx_pay'">
<text class="badge-text">押金租借</text>
</view>
</view>
</view>
<view class="time-info">
<!-- <view class="time-item">
<text class="label">创建时间</text>
<text class="value">{{ orderInfo.createTime || '-' }}</text>
</view> -->
<view class="time-item">
<text class="label">开始时间</text>
<text class="value">{{ orderInfo.startTime || '-' }}</text>
</view>
<view class="time-item" v-if="orderInfo.endTime">
<text class="label">结束时间</text>
<text class="value">{{ orderInfo.endTime }}</text>
</view>
<view class="time-item" v-if="orderInfo.phone">
<text class="label">联系电话</text>
<text class="value">{{ orderInfo.phone }}</text>
</view>
</view>
</view>
<!-- 费用信息卡片 -->
<view class="notice-card">
<view class="notice-title">费用信息</view>
<view class="notice-list">
<view class="notice-item" v-if="orderInfo.depositAmount">
<view class="dot"></view>
<text>押金:¥{{ orderInfo.depositAmount }}</text>
</view>
<view class="notice-item" v-if="orderInfo.packageTime && orderInfo.packagePrice">
<view class="dot"></view>
<text>套餐:¥{{ orderInfo.packagePrice }} / {{ formatTime(orderInfo.packageTime) }}</text>
</view>
<view class="notice-item">
<view class="dot"></view>
<text>合计:¥{{ orderInfo.payAmount || 0 }}</text>
</view>
</view>
</view>
<!-- 底部操作栏 -->
<!-- <view class="bottom-bar">
<view class="action-item secondary" v-if="orderInfo.orderStatus == 'waiting_for_payment'" @click="handleCancelOrder">取消订单</view>
<view class="action-item primary" v-if="orderInfo.orderStatus == 'waiting_for_payment'" @click="handlePayment">立即支付</view>
<view class="action-item primary" v-else-if="orderInfo.orderStatus == 'in_used'" @click="navigateToReturn">归还设备</view>
</view> -->
</view>
</template>
<script setup>
import { ref, computed } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { queryById, cancelOrder, confirmPaymentAndRent } from '@/config/user.js';
const orderId = ref('');
const orderInfo = ref({});
const orderStatusText = computed(() => {
const status = orderInfo.value.orderStatus;
switch(status) {
case 'waiting_for_payment': return '待支付';
case 'in_used': return '使用中';
case 'used_done': return '已完成';
case 'order_cancelled': return '已取消';
default: return '使用中';
}
});
onLoad(async (options) => {
if (options && options.orderId) {
orderId.value = options.orderId;
await loadOrderDetails();
} else {
uni.showToast({
title: '订单信息不存在',
icon: 'none'
});
setTimeout(() => {
uni.navigateBack();
}, 1500);
}
});
const loadOrderDetails = async () => {
try {
uni.showLoading({ title: '加载中' });
const res = await queryById(orderId.value);
if (res.code === 200 && res.data) {
orderInfo.value = res.data;
if (orderInfo.value.createTime) {
orderInfo.value.createTime = formatDateTime(new Date(orderInfo.value.createTime));
}
if (orderInfo.value.startTime) {
orderInfo.value.startTime = formatDateTime(new Date(orderInfo.value.startTime));
}
if (orderInfo.value.endTime) {
orderInfo.value.endTime = formatDateTime(new Date(orderInfo.value.endTime));
}
} else {
throw new Error('获取订单详情失败');
}
uni.hideLoading();
} catch (error) {
uni.hideLoading();
uni.showToast({
title: error.message || '获取订单详情失败',
icon: 'none'
});
}
};
const formatDateTime = (date) => {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
const hour = date.getHours().toString().padStart(2, '0');
const minute = date.getMinutes().toString().padStart(2, '0');
return `${year}-${month}-${day} ${hour}:${minute}`;
};
const formatTime = (minutes) => {
if (!minutes) return '';
const mins = parseInt(minutes);
if (mins < 60) {
return `${mins}分钟`;
} else {
const hours = Math.floor(mins / 60);
const remainingMins = mins % 60;
return remainingMins > 0 ? `${hours}小时${remainingMins}分钟` : `${hours}小时`;
}
};
const handleCancelOrder = () => {
uni.showModal({
title: '确认取消',
content: '确定要取消此订单吗?',
success: async (res) => {
if (res.confirm) {
try {
uni.showLoading({ title: '处理中' });
const result = await cancelOrder({ orderId: orderId.value });
if (result.code === 200) {
uni.hideLoading();
uni.showToast({ title: '订单已取消', icon: 'success' });
await loadOrderDetails();
} else {
throw new Error(result.msg || '取消订单失败');
}
} catch (error) {
uni.hideLoading();
uni.showToast({ title: error.message || '取消订单失败', icon: 'none' });
}
}
}
});
};
const handlePayment = async () => {
try {
uni.showLoading({ title: '处理中' });
const res = await confirmPaymentAndRent(orderId.value);
if (res.code === 200) {
uni.hideLoading();
uni.showToast({ title: '支付成功', icon: 'success' });
await loadOrderDetails();
} else {
throw new Error(res.msg || '支付失败');
}
} catch (error) {
uni.hideLoading();
uni.showToast({ title: error.message || '支付失败', icon: 'none' });
}
};
const navigateToReturn = () => {
uni.navigateTo({
url: `/pages/return/index?deviceId=${orderInfo.value.deviceNo}&orderId=${orderId.value}`
});
};
</script>
<style lang="scss" scoped>
.return-container {
min-height: 100vh;
background: #f7f8fa;
padding: 30rpx;
padding-bottom: 180rpx;
box-sizing: border-box;
.order-card {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
.order-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
padding-bottom: 16rpx;
border-bottom: 1rpx solid #f0f0f0;
.title {
font-size: 30rpx;
font-weight: bold;
color: #333;
}
.order-no {
font-size: 24rpx;
color: #999;
}
}
.device-info {
margin-bottom: 24rpx;
display: flex;
justify-content: space-between;
align-items: flex-start;
.device-left {
flex: 1;
margin-right: 20rpx;
.device-name {
font-size: 32rpx;
font-weight: 500;
color: #333;
margin-bottom: 8rpx;
}
.device-id {
font-size: 26rpx;
color: #999;
margin-bottom: 0;
}
}
.device-right {
.payment-badge {
display: inline-flex;
align-items: center;
padding: 6rpx 12rpx;
border-radius: 8rpx;
white-space: nowrap;
&.wx-score {
background: rgba(7, 193, 96, 0.08);
.badge-icon {
width: 32rpx;
height: 26rpx;
margin-right: 8rpx;
}
.badge-text {
font-size: 22rpx;
color: #07c160;
display: flex;
align-items: center;
.divider {
margin: 0 6rpx;
}
.highlight {
font-weight: 500;
}
}
}
&.member {
background: rgba(25, 118, 210, 0.08);
.badge-text {
font-size: 22rpx;
color: #1976D2;
font-weight: 500;
}
}
&.deposit {
background: #f5f5f5;
.badge-text {
font-size: 22rpx;
color: #666;
font-weight: 500;
}
}
}
}
}
.time-info {
background: #f9f9f9;
border-radius: 16rpx;
padding: 20rpx;
.time-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
.label {
font-size: 26rpx;
color: #666;
}
.value {
font-size: 26rpx;
color: #333;
&.highlight {
color: #ff6b6b;
font-weight: bold;
}
}
}
}
}
.notice-card {
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
.notice-title {
font-size: 30rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.notice-list {
.notice-item {
display: flex;
align-items: flex-start;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
.dot {
width: 12rpx;
height: 12rpx;
background: #07c160;
border-radius: 50%;
margin-top: 10rpx;
margin-right: 16rpx;
flex-shrink: 0;
}
text {
font-size: 26rpx;
color: #666;
line-height: 1.5;
}
}
}
}
.bottom-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 20rpx 30rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
background: #fff;
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.04);
z-index: 10;
display: flex;
justify-content: space-between;
gap: 20rpx;
.action-item {
height: 88rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
border-radius: 44rpx;
flex: 1;
&.primary {
background: #07c160;
color: #fff;
&:active {
opacity: 0.8;
}
}
&.secondary {
background: #f5f5f5;
color: #333;
border: 1rpx solid #e0e0e0;
&:active {
opacity: 0.8;
}
}
}
}
}
</style>