GameServicePlatform/pages/order/detail.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>