hookehuyr

feat(订单管理): 添加订单详情弹窗组件及样式

实现订单详情弹窗功能,包含订单信息、商品详情、交易信息和评价展示
重构评价弹窗布局,优化样式和交互体验
......@@ -382,6 +382,189 @@
}
}
/* 订单详情弹窗样式 */
.order-detail-popup {
padding: 40rpx;
height: 100%;
display: flex;
flex-direction: column;
.detail-header {
text-align: center;
margin-bottom: 40rpx;
.detail-title {
font-size: 36rpx;
font-weight: 600;
color: #333;
}
}
.detail-content {
flex: 1;
overflow-y: auto;
.detail-section {
margin-bottom: 40rpx;
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
.section-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
margin-bottom: 24rpx;
display: block;
border-bottom: 1rpx solid #f0f0f0;
padding-bottom: 16rpx;
}
.info-row {
display: flex;
justify-content: space-between;
margin-bottom: 16rpx;
.info-label {
font-size: 28rpx;
color: #666;
}
.info-value {
font-size: 28rpx;
color: #333;
font-weight: 500;
&.status-pending {
color: #f97316;
}
&.status-completed {
color: #10b981;
}
&.status-cancelled {
color: #6b7280;
}
&.price {
color: #f97316;
font-weight: 600;
}
}
}
.product-detail-info {
display: flex;
background: #f8f9fa;
border-radius: 12rpx;
padding: 20rpx;
.product-detail-image {
width: 180rpx;
height: 180rpx;
border-radius: 12rpx;
margin-right: 24rpx;
}
.product-detail-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.product-detail-name {
font-size: 32rpx;
font-weight: 600;
color: #333;
margin-bottom: 8rpx;
}
.product-detail-specs {
font-size: 26rpx;
color: #666;
margin-bottom: 8rpx;
}
.product-detail-battery {
font-size: 26rpx;
color: #666;
margin-bottom: 16rpx;
}
.product-detail-price {
font-size: 32rpx;
font-weight: 600;
color: #ff6b35;
}
}
}
.review-info {
background: #f8f9fa;
border-radius: 12rpx;
padding: 20rpx;
.review-rating {
display: flex;
align-items: center;
margin-bottom: 16rpx;
.rating-label {
font-size: 28rpx;
color: #666;
margin-right: 16rpx;
}
.rating-text {
font-size: 26rpx;
color: #666;
margin-left: 16rpx;
}
}
.review-content {
margin-bottom: 16rpx;
.content-label {
font-size: 28rpx;
color: #666;
margin-bottom: 8rpx;
display: block;
}
.content-text {
font-size: 28rpx;
color: #333;
line-height: 1.5;
}
}
.review-time {
text-align: right;
.time-text {
font-size: 24rpx;
color: #999;
}
}
}
}
}
.detail-footer {
padding-top: 40rpx;
.nut-button {
height: 88rpx;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 600;
}
}
}
/* 响应式适配 */
@media (max-width: 750px) {
.header {
......
<!--
* @Date: 2022-09-19 14:11:06
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-07-03 16:32:53
* @LastEditTime: 2025-07-03 16:56:05
* @FilePath: /jgdl/src/pages/myOrders/index.vue
* @Description: 订单管理页面
-->
......@@ -11,18 +11,10 @@
<!-- 买车/卖车切换 -->
<view id="mode-toggle" class="view-mode-toggle">
<view class="toggle-container">
<view
class="toggle-option"
:class="{ active: viewMode === 'bought' }"
@click="setViewMode('bought')"
>
<view class="toggle-option" :class="{ active: viewMode === 'bought' }" @click="setViewMode('bought')">
我买的车
</view>
<view
class="toggle-option"
:class="{ active: viewMode === 'sold' }"
@click="setViewMode('sold')"
>
<view class="toggle-option" :class="{ active: viewMode === 'sold' }" @click="setViewMode('sold')">
我卖的车
</view>
</view>
......@@ -30,33 +22,17 @@
<!-- 状态筛选标签 -->
<view id="status-tabs" class="status-tabs">
<view
class="tab-item"
:class="{ active: activeTab === 'all' }"
@click="setActiveTab('all')"
>
<view class="tab-item" :class="{ active: activeTab === 'all' }" @click="setActiveTab('all')">
全部
</view>
<view
v-if="viewMode === 'bought'"
class="tab-item"
:class="{ active: activeTab === 'pending' }"
@click="setActiveTab('pending')"
>
<view v-if="viewMode === 'bought'" class="tab-item" :class="{ active: activeTab === 'pending' }"
@click="setActiveTab('pending')">
待支付
</view>
<view
class="tab-item"
:class="{ active: activeTab === 'completed' }"
@click="setActiveTab('completed')"
>
<view class="tab-item" :class="{ active: activeTab === 'completed' }" @click="setActiveTab('completed')">
已完成
</view>
<view
class="tab-item"
:class="{ active: activeTab === 'cancelled' }"
@click="setActiveTab('cancelled')"
>
<view class="tab-item" :class="{ active: activeTab === 'cancelled' }" @click="setActiveTab('cancelled')">
已取消
</view>
</view>
......@@ -65,15 +41,8 @@
<!-- 订单列表 -->
<view class="order-list">
<!-- 滚动列表 -->
<scroll-view
class="order-scroll-view"
:style="scrollStyle"
:scroll-y="true"
@scrolltolower="loadMore"
@scroll="scroll"
:lower-threshold="50"
:enable-flex="false"
>
<scroll-view class="order-scroll-view" :style="scrollStyle" :scroll-y="true" @scrolltolower="loadMore"
@scroll="scroll" :lower-threshold="50" :enable-flex="false">
<!-- 空状态 -->
<view v-if="filteredOrders.length === 0" class="empty-state">
<text class="empty-text">暂无订单</text>
......@@ -81,11 +50,7 @@
<!-- 订单卡片 -->
<view v-else>
<view
v-for="order in filteredOrders"
:key="order.id"
class="order-card"
>
<view v-for="order in filteredOrders" :key="order.id" class="order-card">
<!-- 订单头部信息 -->
<view class="order-header">
<text class="order-date">{{ order.date }}</text>
......@@ -97,12 +62,8 @@
<!-- 车辆信息 -->
<nut-row :gutter="12" class="vehicle-info">
<nut-col :span="6">
<image
:src="order.vehicle.imageUrl"
:alt="order.vehicle.name"
class="vehicle-image"
mode="aspectFill"
/>
<image :src="order.vehicle.imageUrl" :alt="order.vehicle.name" class="vehicle-image"
mode="aspectFill" />
</nut-col>
<nut-col :span="18">
<view class="vehicle-details">
......@@ -120,41 +81,24 @@
<view class="order-actions">
<!-- 买车模式:待支付状态 -->
<template v-if="viewMode === 'bought' && order.status === 'pending'">
<nut-button
type="primary"
size="small"
@click="handlePayment(order)"
>
<nut-button type="primary" size="small" @click="handlePayment(order)">
去支付
</nut-button>
</template>
<!-- 已完成状态 -->
<template v-if="order.status === 'completed'">
<nut-button
type="default"
size="small"
@click="viewOrderDetail(order.id)"
>
<nut-button type="default" size="small" @click="viewOrderDetail(order.id)">
查看详情
</nut-button>
<nut-button
type="primary"
size="small"
@click="rateOrder(order.id)"
class="ml-2"
>
<nut-button type="primary" size="small" @click="rateOrder(order.id)" class="ml-2">
{{ order.review ? '查看评价' : '评价' }}
</nut-button>
</template>
<!-- 已取消状态 -->
<template v-if="order.status === 'cancelled'">
<nut-button
type="default"
size="small"
@click="deleteOrder(order.id)"
>
<nut-button type="default" size="small" @click="deleteOrder(order.id)">
删除订单
</nut-button>
</template>
......@@ -178,45 +122,30 @@
<payCard :visible="show_pay" :data="payData" @close="onPayClose" />
<!-- 评价弹窗 -->
<nut-popup
v-model:visible="showRatePopup"
position="bottom"
:style="{ height: '60%' }"
round
closeable
@close="closeRatePopup"
>
<nut-popup v-model:visible="showRatePopup" position="right" :style="{ width: '100%', height: '100%' }" closeable
close-icon-position="top-right" @close="closeRatePopup">
<view class="rate-popup">
<view class="rate-header">
<text class="rate-title">评价商品</text>
<text class="rate-title">{{ isReadOnlyMode ? '查看评价' : '商品评价' }}</text>
</view>
<view class="rate-content">
<!-- 商品信息 -->
<view class="product-info" v-if="currentRateOrder">
<image
:src="currentRateOrder.vehicle.imageUrl"
class="product-image"
mode="aspectFill"
/>
<!-- 商品信息展示 -->
<view class="product-info">
<image :src="currentRateOrder?.vehicle?.imageUrl" class="product-image" mode="aspectFill" />
<view class="product-details">
<text class="product-name">{{ currentRateOrder.vehicle.name }}</text>
<text class="product-specs">{{ currentRateOrder.vehicle.year }} · {{ currentRateOrder.vehicle.mileage }}</text>
<text class="product-price">¥{{ currentRateOrder.vehicle.price }}</text>
<text class="product-name">{{ currentRateOrder?.vehicle?.name }}</text>
<text class="product-specs">{{ currentRateOrder?.vehicle?.year }} · {{ currentRateOrder?.vehicle?.mileage
}}</text>
<text class="product-price">¥{{ currentRateOrder?.vehicle?.price }}</text>
</view>
</view>
<!-- 评分组件 -->
<view class="rate-score-section">
<text class="score-label">{{ isReadOnlyMode ? '评分' : '请给商品评分' }}</text>
<nut-rate
v-model="rateScore"
:readonly="isReadOnlyMode"
:size="isReadOnlyMode ? '20' : '24'"
active-color="#ff6b35"
void-color="#e5e5e5"
class="rate-stars"
/>
<nut-rate v-model="rateScore" :readonly="isReadOnlyMode" :size="isReadOnlyMode ? '20' : '24'"
active-color="#ff6b35" void-color="#e5e5e5" class="rate-stars" />
<text v-if="isReadOnlyMode" class="score-text">{{ rateScore }}/5分</text>
</view>
......@@ -224,36 +153,118 @@
<view class="rate-input-section">
<text class="input-label">{{ isReadOnlyMode ? '评价内容' : '请输入评价内容' }}</text>
<view class="border border-gray-100">
<nut-textarea
v-model="rateContent"
:placeholder="isReadOnlyMode ? '' : '请输入您的评价内容...'"
:max-length="200"
:rows="4"
:show-word-limit="!isReadOnlyMode"
:readonly="isReadOnlyMode"
:class="{ 'readonly': isReadOnlyMode }"
/>
<nut-textarea v-model="rateContent" :placeholder="isReadOnlyMode ? '' : '请输入您的评价内容...'" :max-length="200"
:rows="4" :show-word-limit="!isReadOnlyMode" :readonly="isReadOnlyMode"
:class="{ 'readonly': isReadOnlyMode }" />
</view>
<text v-if="isReadOnlyMode && currentRateOrder?.review?.date" class="review-date">
评价时间:{{ currentRateOrder.review.date }}
评价时间:{{ currentRateOrder?.review?.date }}
</text>
</view>
</view>
<!-- 提交按钮 -->
<view class="rate-footer" v-if="!isReadOnlyMode">
<nut-button
type="primary"
size="large"
@click="submitRate"
:loading="submittingRate"
block
>
<nut-button type="primary" size="large" @click="submitRate" :loading="submittingRate" block>
提交评价
</nut-button>
</view>
</view>
</nut-popup>
<!-- 订单详情弹窗 -->
<nut-popup v-model:visible="showOrderDetailPopup" position="right" :style="{ width: '100%', height: '100%' }"
closeable close-icon-position="top-right" @close="closeOrderDetailPopup">
<view class="order-detail-popup">
<view class="detail-header">
<text class="detail-title">订单详情</text>
</view>
<view class="detail-content">
<!-- 订单基本信息 -->
<view class="detail-section">
<text class="section-title">订单信息</text>
<view class="info-row">
<text class="info-label">订单编号</text>
<text class="info-value">{{ currentOrderDetail?.id }}</text>
</view>
<view class="info-row">
<text class="info-label">下单时间</text>
<text class="info-value">{{ currentOrderDetail?.date }}</text>
</view>
<view class="info-row">
<text class="info-label">订单状态</text>
<text class="info-value" :class="getStatusClass(currentOrderDetail?.status)">
{{ getStatusText(currentOrderDetail?.status) }}
</text>
</view>
<view class="info-row">
<text class="info-label">订单金额</text>
<text class="info-value price">¥{{ currentOrderDetail?.price }}</text>
</view>
</view>
<!-- 商品信息 -->
<view class="detail-section">
<text class="section-title">商品信息</text>
<view class="product-detail-info">
<image :src="currentOrderDetail?.vehicle?.imageUrl" class="product-detail-image" mode="aspectFill" />
<view class="product-detail-content">
<text class="product-detail-name">{{ currentOrderDetail?.vehicle?.name }}</text>
<text class="product-detail-specs">{{ currentOrderDetail?.vehicle?.year }} · {{
currentOrderDetail?.vehicle?.mileage }}</text>
<text class="product-detail-battery">{{ currentOrderDetail?.vehicle?.batteryCapacity }}</text>
<text class="product-detail-price">¥{{ currentOrderDetail?.vehicle?.price }}</text>
</view>
</view>
</view>
<!-- 交易信息 -->
<view class="detail-section">
<text class="section-title">交易信息</text>
<view class="info-row">
<text class="info-label">{{ viewMode === 'bought' ? '卖家' : '买家' }}</text>
<text class="info-value">{{ viewMode === 'bought' ? '张先生' : '李女士' }}</text>
</view>
<view class="info-row">
<text class="info-label">联系电话</text>
<text class="info-value">{{ viewMode === 'bought' ? '138****5678' : '139****1234' }}</text>
</view>
<view class="info-row">
<text class="info-label">交易地点</text>
<text class="info-value">北京市朝阳区望京SOHO</text>
</view>
</view>
<!-- 评价信息(如果有) -->
<view class="detail-section" v-if="currentOrderDetail?.review">
<text class="section-title">评价信息</text>
<view class="review-info">
<view class="review-rating">
<text class="rating-label">评分:</text>
<nut-rate :model-value="currentOrderDetail?.review?.rating" readonly size="20" active-color="#ff6b35"
void-color="#e5e5e5" />
<text class="rating-text">{{ currentOrderDetail?.review?.rating }}/5分</text>
</view>
<view class="review-content">
<text class="content-label">评价内容:</text>
<text class="content-text">{{ currentOrderDetail?.review?.content }}</text>
</view>
<view class="review-time">
<text class="time-text">评价时间:{{ currentOrderDetail?.review?.date }}</text>
</view>
</view>
</view>
</view>
<!-- 关闭按钮 -->
<view class="detail-footer">
<nut-button type="primary" size="large" @click="closeOrderDetailPopup" block>
关闭
</nut-button>
</view>
</view>
</nut-popup>
</view>
</template>
......@@ -290,6 +301,10 @@ const rateScore = ref(5)
const submittingRate = ref(false)
const isReadOnlyMode = ref(false)
// 订单详情相关状态
const showOrderDetailPopup = ref(false)
const currentOrderDetail = ref(null)
// 模拟订单数据
const boughtOrders = ref([
{
......@@ -452,13 +467,13 @@ const loadMore = () => {
const getStatusText = (status) => {
switch (status) {
case 'pending':
return '待支付'
return '待完成'
case 'completed':
return '已完成'
case 'cancelled':
return '已取消'
default:
return ''
return '未知状态'
}
}
......@@ -516,10 +531,22 @@ const onPayClose = () => {
* 查看订单详情
*/
const viewOrderDetail = (orderId) => {
Taro.showToast({
title: '查看订单详情',
icon: 'none'
})
// 找到对应的订单
const orders = viewMode.value === 'bought' ? boughtOrders.value : soldOrders.value
const order = orders.find(o => o.id === orderId)
if (order) {
currentOrderDetail.value = order
showOrderDetailPopup.value = true
}
}
/**
* 关闭订单详情弹窗
*/
const closeOrderDetailPopup = () => {
showOrderDetailPopup.value = false
currentOrderDetail.value = null
}
/**
......