466 lines
10 KiB
Vue
466 lines
10 KiB
Vue
<template>
|
|
<view class="order-detail-page page-container">
|
|
<!-- 订单状态 -->
|
|
<view class="status-card cyber-card">
|
|
<view class="status-icon">{{ getStatusIcon(order.status) }}</view>
|
|
<view class="status-text">{{ getStatusText(order.status) }}</view>
|
|
<view v-if="order.status === 3" class="status-desc">
|
|
服务进行中,请耐心等待选手完成服务
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 选手信息 (已接单) -->
|
|
<view v-if="order.playerName" class="player-card cyber-card">
|
|
<view class="card-title">服务选手</view>
|
|
<view class="player-info">
|
|
<image :src="order.playerAvatar" class="player-avatar" />
|
|
<view class="player-detail">
|
|
<text class="player-name">{{ order.playerName }}</text>
|
|
<text class="player-status">{{ order.status === 3 ? '服务中...' : '已接单' }}</text>
|
|
</view>
|
|
<button class="contact-btn" @click="contactPlayer">联系选手</button>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 服务信息 -->
|
|
<view class="service-card cyber-card">
|
|
<view class="card-title">服务信息</view>
|
|
<view class="service-content">
|
|
<image :src="order.serviceCover" class="service-cover" mode="aspectFill" />
|
|
<view class="service-info">
|
|
<text class="service-name">{{ order.serviceName }}</text>
|
|
<text class="service-category">{{ order.categoryName }}</text>
|
|
</view>
|
|
<view class="service-price">
|
|
<text class="price-symbol">¥</text>
|
|
<text class="price-value">{{ order.actualPrice }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 游戏信息 -->
|
|
<view class="info-card cyber-card">
|
|
<view class="card-title">游戏信息</view>
|
|
<view class="info-row">
|
|
<text class="label">游戏ID</text>
|
|
<text class="value">{{ order.gameInfo?.gameId }}</text>
|
|
</view>
|
|
<view class="info-row">
|
|
<text class="label">区服</text>
|
|
<text class="value">{{ order.gameInfo?.server }}</text>
|
|
</view>
|
|
<view v-if="order.gameInfo?.currentRank" class="info-row">
|
|
<text class="label">段位</text>
|
|
<text class="value">{{ order.gameInfo?.currentRank }}</text>
|
|
</view>
|
|
<view v-if="order.remark" class="info-row">
|
|
<text class="label">备注</text>
|
|
<text class="value">{{ order.remark }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 订单流转 -->
|
|
<view class="flow-card cyber-card">
|
|
<view class="card-title">订单流转</view>
|
|
<view class="flow-list">
|
|
<view v-for="(item, index) in orderFlow" :key="index" class="flow-item">
|
|
<view class="flow-dot" :class="{ active: index === 0 }"></view>
|
|
<view class="flow-line" v-if="index < orderFlow.length - 1"></view>
|
|
<view class="flow-content">
|
|
<text class="flow-status">{{ item.status }}</text>
|
|
<text class="flow-desc">{{ item.desc }}</text>
|
|
<text class="flow-time">{{ item.time }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 订单信息 -->
|
|
<view class="order-info-card cyber-card">
|
|
<view class="card-title">订单信息</view>
|
|
<view class="info-row">
|
|
<text class="label">订单号</text>
|
|
<text class="value">{{ order.orderNo }}</text>
|
|
</view>
|
|
<view class="info-row">
|
|
<text class="label">创建时间</text>
|
|
<text class="value">{{ order.createTime }}</text>
|
|
</view>
|
|
<view v-if="order.payTime" class="info-row">
|
|
<text class="label">支付时间</text>
|
|
<text class="value">{{ order.payTime }}</text>
|
|
</view>
|
|
<view v-if="order.finishTime" class="info-row">
|
|
<text class="label">完成时间</text>
|
|
<text class="value">{{ order.finishTime }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 底部操作栏 -->
|
|
<view class="bottom-bar">
|
|
<button v-if="order.status === 0" class="action-btn btn-cancel" @click="handleCancel">取消订单</button>
|
|
<button v-if="order.status === 0" class="action-btn btn-primary" @click="handlePay">立即支付</button>
|
|
|
|
<button v-if="order.status === 4" class="action-btn btn-outline" @click="handleRefund">申请退款</button>
|
|
<button v-if="order.status === 4" class="action-btn btn-primary" @click="handleConfirm">确认完成</button>
|
|
|
|
<button v-if="order.status === 5" class="action-btn btn-primary" @click="handleEvaluate">去评价</button>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onLoad } from '@dcloudio/uni-app'
|
|
import { getOrderById, getOrderFlowById, OrderStatus } from '../../mock'
|
|
|
|
const order = ref({})
|
|
const orderFlow = ref([])
|
|
|
|
onLoad((options) => {
|
|
if (options.id) {
|
|
const orderData = getOrderById(parseInt(options.id))
|
|
if (orderData) {
|
|
order.value = orderData
|
|
orderFlow.value = getOrderFlowById(orderData.id)
|
|
}
|
|
}
|
|
})
|
|
|
|
const getStatusIcon = (status) => {
|
|
const icons = {
|
|
0: '⏰',
|
|
1: '👀',
|
|
2: '✅',
|
|
3: '🎮',
|
|
4: '⭐',
|
|
5: '✨',
|
|
6: '💬',
|
|
9: '❌'
|
|
}
|
|
return icons[status] || '📦'
|
|
}
|
|
|
|
const getStatusText = (status) => {
|
|
const statusObj = Object.values(OrderStatus).find(s => s.code === status)
|
|
return statusObj ? statusObj.text : '未知状态'
|
|
}
|
|
|
|
const contactPlayer = () => {
|
|
uni.showToast({ title: '联系选手', icon: 'none' })
|
|
}
|
|
|
|
const handleCancel = () => {
|
|
uni.showModal({
|
|
title: '提示',
|
|
content: '确定要取消订单吗?',
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
uni.showToast({ title: '订单已取消', icon: 'none' })
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
const handlePay = () => {
|
|
uni.showToast({ title: '跳转支付...', icon: 'none' })
|
|
}
|
|
|
|
const handleRefund = () => {
|
|
uni.showModal({
|
|
title: '申请退款',
|
|
content: '请说明退款原因',
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
uni.showToast({ title: '退款申请已提交', icon: 'none' })
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
const handleConfirm = () => {
|
|
uni.showModal({
|
|
title: '确认完成',
|
|
content: '确认服务已完成?',
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
uni.showToast({ title: '已确认完成', icon: 'success' })
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
const handleEvaluate = () => {
|
|
uni.navigateTo({
|
|
url: `/pages/order/evaluate?orderId=${order.value.id}`
|
|
})
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.order-detail-page {
|
|
padding: 24rpx;
|
|
padding-bottom: 180rpx;
|
|
}
|
|
|
|
.status-card {
|
|
padding: 48rpx 32rpx;
|
|
text-align: center;
|
|
margin-bottom: 24rpx;
|
|
}
|
|
|
|
.status-icon {
|
|
font-size: 120rpx;
|
|
margin-bottom: 20rpx;
|
|
}
|
|
|
|
.status-text {
|
|
font-size: 36rpx;
|
|
font-weight: bold;
|
|
color: #00ffff;
|
|
margin-bottom: 16rpx;
|
|
}
|
|
|
|
.status-desc {
|
|
font-size: 26rpx;
|
|
color: #a0a4c4;
|
|
}
|
|
|
|
.player-card,
|
|
.service-card,
|
|
.info-card,
|
|
.flow-card,
|
|
.order-info-card {
|
|
padding: 32rpx;
|
|
margin-bottom: 24rpx;
|
|
}
|
|
|
|
.card-title {
|
|
font-size: 30rpx;
|
|
font-weight: bold;
|
|
color: #ffffff;
|
|
margin-bottom: 28rpx;
|
|
}
|
|
|
|
.player-info {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 20rpx;
|
|
}
|
|
|
|
.player-avatar {
|
|
width: 96rpx;
|
|
height: 96rpx;
|
|
border-radius: 50%;
|
|
border: 2px solid rgba(0, 255, 255, 0.3);
|
|
}
|
|
|
|
.player-detail {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12rpx;
|
|
}
|
|
|
|
.player-name {
|
|
font-size: 30rpx;
|
|
font-weight: bold;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.player-status {
|
|
font-size: 24rpx;
|
|
color: #00ff88;
|
|
}
|
|
|
|
.contact-btn {
|
|
padding: 16rpx 32rpx;
|
|
background: transparent;
|
|
border: 1px solid #00ffff;
|
|
border-radius: 8rpx;
|
|
font-size: 26rpx;
|
|
color: #00ffff;
|
|
}
|
|
|
|
.service-content {
|
|
display: flex;
|
|
gap: 24rpx;
|
|
align-items: center;
|
|
}
|
|
|
|
.service-cover {
|
|
width: 160rpx;
|
|
height: 120rpx;
|
|
border-radius: 12rpx;
|
|
}
|
|
|
|
.service-info {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12rpx;
|
|
}
|
|
|
|
.service-name {
|
|
font-size: 28rpx;
|
|
font-weight: bold;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.service-category {
|
|
padding: 4rpx 16rpx;
|
|
background: rgba(0, 255, 255, 0.1);
|
|
border: 1px solid rgba(0, 255, 255, 0.3);
|
|
border-radius: 6rpx;
|
|
font-size: 22rpx;
|
|
color: #00ffff;
|
|
align-self: flex-start;
|
|
}
|
|
|
|
.service-price {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-end;
|
|
}
|
|
|
|
.price-symbol {
|
|
font-size: 24rpx;
|
|
color: #00ffff;
|
|
}
|
|
|
|
.price-value {
|
|
font-size: 36rpx;
|
|
font-weight: bold;
|
|
color: #00ffff;
|
|
}
|
|
|
|
.info-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 20rpx 0;
|
|
border-bottom: 1px solid rgba(0, 255, 255, 0.1);
|
|
|
|
&:last-child {
|
|
border-bottom: none;
|
|
}
|
|
}
|
|
|
|
.info-row .label {
|
|
font-size: 26rpx;
|
|
color: #7a7e9d;
|
|
}
|
|
|
|
.info-row .value {
|
|
font-size: 26rpx;
|
|
color: #ffffff;
|
|
text-align: right;
|
|
flex: 1;
|
|
margin-left: 40rpx;
|
|
}
|
|
|
|
.flow-list {
|
|
position: relative;
|
|
}
|
|
|
|
.flow-item {
|
|
position: relative;
|
|
display: flex;
|
|
gap: 24rpx;
|
|
padding-left: 48rpx;
|
|
padding-bottom: 40rpx;
|
|
|
|
&:last-child {
|
|
padding-bottom: 0;
|
|
}
|
|
}
|
|
|
|
.flow-dot {
|
|
position: absolute;
|
|
left: 0;
|
|
top: 4rpx;
|
|
width: 24rpx;
|
|
height: 24rpx;
|
|
background: rgba(122, 126, 157, 0.5);
|
|
border: 2px solid rgba(122, 126, 157, 0.8);
|
|
border-radius: 50%;
|
|
|
|
&.active {
|
|
background: rgba(0, 255, 255, 0.3);
|
|
border-color: #00ffff;
|
|
box-shadow: 0 0 10px rgba(0, 255, 255, 0.5);
|
|
}
|
|
}
|
|
|
|
.flow-line {
|
|
position: absolute;
|
|
left: 11rpx;
|
|
top: 28rpx;
|
|
bottom: 0;
|
|
width: 2px;
|
|
background: linear-gradient(180deg, rgba(0, 255, 255, 0.3) 0%, transparent 100%);
|
|
}
|
|
|
|
.flow-content {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8rpx;
|
|
}
|
|
|
|
.flow-status {
|
|
font-size: 28rpx;
|
|
font-weight: bold;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.flow-desc {
|
|
font-size: 24rpx;
|
|
color: #a0a4c4;
|
|
}
|
|
|
|
.flow-time {
|
|
font-size: 22rpx;
|
|
color: #7a7e9d;
|
|
}
|
|
|
|
.bottom-bar {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
display: flex;
|
|
gap: 24rpx;
|
|
padding: 24rpx;
|
|
background: rgba(10, 14, 39, 0.98);
|
|
border-top: 1px solid rgba(0, 255, 255, 0.2);
|
|
backdrop-filter: blur(20rpx);
|
|
}
|
|
|
|
.action-btn {
|
|
flex: 1;
|
|
height: 88rpx;
|
|
line-height: 88rpx;
|
|
text-align: center;
|
|
font-size: 30rpx;
|
|
font-weight: bold;
|
|
border-radius: 12rpx;
|
|
|
|
&.btn-primary {
|
|
background: linear-gradient(135deg, #00ffff 0%, #0099ff 100%);
|
|
color: #0a0e27;
|
|
border: none;
|
|
}
|
|
|
|
&.btn-outline {
|
|
background: transparent;
|
|
border: 1px solid #00ffff;
|
|
color: #00ffff;
|
|
}
|
|
|
|
&.btn-cancel {
|
|
background: rgba(122, 126, 157, 0.2);
|
|
border: 1px solid rgba(122, 126, 157, 0.4);
|
|
color: #7a7e9d;
|
|
}
|
|
}
|
|
</style>
|