hookehuyr

feat(订单): 重构订单模块,实现真实API对接

- 修改订单API接口,简化并适配后端接口
- 商品详情页增加卖家判断逻辑,隐藏不相关操作
- 订单列表页重构,对接真实数据并优化分页加载
- 实现订单评价功能,对接真实API
- 优化订单详情展示,显示更多真实数据
/*
* @Date: 2024-01-01 00:00:00
* @Date: 2025-07-03 17:21:45
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-07-09 15:00:24
* @LastEditTime: 2025-07-14 09:34:58
* @FilePath: /jgdl/src/api/orders.js
* @Description: 车辆订单相关API接口
* @Description: 文件描述
*/
import { fn, fetch } from './fn';
import { fn, fetch } from '@/api/fn';
// API 端点定义
const OrderApi = {
// 获取我的订单列表
GET_MY_ORDERS: '/api/orders/my-orders',
// 获取订单详情
GET_ORDER_DETAIL: '/api/orders/detail',
// 删除订单
DELETE_ORDER: '/api/orders/delete',
// 取消订单
CANCEL_ORDER: '/api/orders/cancel',
// 确认收货
CONFIRM_ORDER: '/api/orders/confirm',
// 提交评价
SUBMIT_REVIEW: '/api/orders/review',
// 申请退款
REQUEST_REFUND: '/api/orders/refund',
};
const Api = {
GET_ORDER_LIST: '/srv/?a=order&t=list',
GET_ORDER_DETAIL: '/srv/?a=order&t=detail',
CREATE_ORDER: '/srv/?a=order&t=add',
REVIEW_ORDER: '/srv/?a=order&t=review',
DELETE_ORDER: '/srv/?a=order&t=del',
}
/**
* @description: 获取我的订单列表
* @param {Object} params
* @param {string} params.type - 订单类型 'bought' | 'sold'
* @param {number} params.page - 页码
* @param {number} params.limit - 每页数量
* @param {string} params.status - 订单状态筛选(可选)
* @returns {Promise}
* @description: 获取订单列表
* @param page 页码,从0开始
* @param page_size 每页数量
* @param type 列表类型。buy=我买的,sell=我卖的
* @param status 订单状态(3=待支付, 5=已完成, 7=已取消)
* @returns data{ list[{ id, title, total_amount, status, create_time, payment_time, details{ id, vehicle_id, quantity, vehicle{} } }] }
*/
export const getMyOrdersAPI = (params) => {
// TODO: 替换为真实的API调用
return fn(fetch.get(OrderApi.GET_MY_ORDERS, params));
};
export const getOrderListAPI = (params) => fn(fetch.get(Api.GET_ORDER_LIST, params));
/**
* @description: 获取订单详情
* @param {Object} params
* @param {string} params.orderId - 订单ID
* @returns {Promise}
* @param id 订单ID
* @returns data{ id, title, total_amount, status, create_time, payment_time, details{ id, vehicle_id, quantity, vehicle{ id, title, price, cover_image } } }
*/
export const getOrderDetailAPI = (params) => {
// TODO: 替换为真实的API调用
return fn(fetch.get(OrderApi.GET_ORDER_DETAIL, params));
};
export const getOrderDetailAPI = (params) => fn(fetch.get(Api.GET_ORDER_DETAIL, params));
/**
* @description: 删除订单
* @param {Object} params
* @param {string} params.orderId - 订单ID
* @returns {Promise}
*
* @example
* // 使用示例:
* try {
* const response = await deleteOrderAPI({ orderId: 'ORDER_123' });
* if (response.success) {
* console.log('删除成功:', response.message);
* }
* } catch (error) {
* console.error('删除失败:', error.message);
* }
*
* @apiResponse
* {
* success: true,
* message: '订单删除成功',
* data: null
* }
* @description: 创建订单
* @param vehicle_id 车辆ID
* @param total_amount 总价
* @returns data{ id }
*/
export const deleteOrderAPI = (params) => {
// TODO: 替换为真实的API调用
// 当集成真实API时,请确保:
// 1. 处理网络错误和超时
// 2. 验证用户权限(只能删除自己的订单)
// 3. 检查订单状态(只有特定状态的订单才能删除)
// 4. 返回统一的响应格式
return fn(fetch.delete(OrderApi.DELETE_ORDER, params));
};
export const createOrderAPI = (params) => fn(fetch.post(Api.CREATE_ORDER, params));
/**
* @description: 取消订单
* @param {Object} params
* @param {string} params.orderId - 订单ID
* @param {string} params.reason - 取消原因(可选)
* @returns {Promise}
* @description: 订单评价
* @param detail_id 订单ID
* @param rating 评级(1到5分)
* @param note 评价内容
* @returns data{}
*/
export const cancelOrderAPI = (params) => {
// TODO: 替换为真实的API调用
return fn(fetch.post(OrderApi.CANCEL_ORDER, params));
};
export const reviewOrderAPI = (params) => fn(fetch.post(Api.REVIEW_ORDER, params));
/**
* @description: 确认收货/完成交易
* @param {Object} params
* @param {string} params.orderId - 订单ID
* @returns {Promise}
*/
export const confirmOrderAPI = (params) => {
// TODO: 替换为真实的API调用
return fn(fetch.post(OrderApi.CONFIRM_ORDER, params));
};
/**
* @description: 提交订单评价
* @param {Object} params
* @param {string} params.orderId - 订单ID
* @param {number} params.rating - 评分 (1-5)
* @param {string} params.comment - 评价内容
* @param {Array} params.images - 评价图片(可选)
* @returns {Promise}
*
* @example
* // 使用示例:
* try {
* const response = await submitReviewAPI({
* orderId: 'ORDER_123',
* rating: 5,
* comment: '车况很好,卖家服务态度也很棒!',
* images: ['image1.jpg', 'image2.jpg'] // 可选
* });
* if (response.success) {
* console.log('评价提交成功:', response.message);
* }
* } catch (error) {
* console.error('评价提交失败:', error.message);
* }
*
* @apiResponse
* {
* success: true,
* message: '评价提交成功',
* data: {
* reviewId: 'REVIEW_123',
* createdAt: '2024-01-01T12:00:00Z'
* }
* }
*/
export const submitReviewAPI = (params) => {
// TODO: 替换为真实的API调用
// 当集成真实API时,请确保:
// 1. 验证评分范围(1-5)
// 2. 验证评价内容长度限制
// 3. 处理图片上传(如果有)
// 4. 检查订单状态(只有已完成的订单才能评价)
// 5. 防止重复评价
return fn(fetch.post(OrderApi.SUBMIT_REVIEW, params));
};
/**
* @description: 申请退款
* @param {Object} params
* @param {string} params.orderId - 订单ID
* @param {string} params.reason - 退款原因
* @param {number} params.amount - 退款金额
* @param {Array} params.evidence - 退款凭证(可选)
* @returns {Promise}
* @description: 删除订单
* @param order_id 订单ID
* @returns data{}
*/
export const requestRefundAPI = (params) => {
// TODO: 替换为真实的API调用
return fn(fetch.post(OrderApi.REQUEST_REFUND, params));
};
// 导出所有API
export default {
getMyOrdersAPI,
getOrderDetailAPI,
deleteOrderAPI,
cancelOrderAPI,
confirmOrderAPI,
submitReviewAPI,
requestRefundAPI,
};
export const deleteOrderAPI = (params) => fn(fetch.post(Api.DELETE_ORDER, params));
......
<!--
* @Date: 2022-09-19 14:11:06
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-07-07 16:32:43
* @LastEditTime: 2025-07-14 14:36:50
* @FilePath: /jgdl/src/pages/myOrders/index.vue
* @Description: 订单管理页面
-->
......@@ -11,10 +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 === 'buy' }" @click="setViewMode('buy')">
我买的车
</view>
<view class="toggle-option" :class="{ active: viewMode === 'sold' }" @click="setViewMode('sold')">
<view class="toggle-option" :class="{ active: viewMode === 'sell' }" @click="setViewMode('sell')">
我卖的车
</view>
</view>
......@@ -22,17 +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 === '' }" @click="setActiveTab('')">
全部
</view>
<view v-if="viewMode === 'bought'" class="tab-item" :class="{ active: activeTab === 'pending' }"
@click="setActiveTab('pending')">
<view v-if="viewMode === 'buy'" class="tab-item" :class="{ active: activeTab === 3 }"
@click="setActiveTab(3)">
待支付
</view>
<view class="tab-item" :class="{ active: activeTab === 'completed' }" @click="setActiveTab('completed')">
<view class="tab-item" :class="{ active: activeTab === 5 }" @click="setActiveTab(5)">
已完成
</view>
<view class="tab-item" :class="{ active: activeTab === 'cancelled' }" @click="setActiveTab('cancelled')">
<view class="tab-item" :class="{ active: activeTab === 7 }" @click="setActiveTab(7)">
已取消
</view>
</view>
......@@ -53,7 +53,7 @@
<view v-for="order in filteredOrders" :key="order.id" class="order-card">
<!-- 订单头部信息 -->
<view class="order-header">
<text class="order-date">{{ order.date }}</text>
<text class="order-date">{{ order.created_time }}</text>
<text class="order-status" :class="getStatusClass(order.status)">
{{ getStatusText(order.status) }}
</text>
......@@ -62,17 +62,17 @@
<!-- 车辆信息 -->
<nut-row :gutter="12" class="vehicle-info">
<nut-col :span="6">
<image :src="order.vehicle.imageUrl" :alt="order.vehicle.name" class="vehicle-image"
<image :src="order.details.vehicle.front_photo || DEFAULT_COVER_IMG" :alt="order.details.vehicle.brand + ' ' + order.details.vehicle.model" class="vehicle-image"
mode="aspectFill" />
</nut-col>
<nut-col :span="18">
<view class="vehicle-details">
<text class="vehicle-name">{{ order.vehicle.name }}</text>
<text class="vehicle-name">{{ order.details.vehicle.brand }} {{ order.details.vehicle.model }}</text>
<text class="vehicle-specs">
{{ order.vehicle.year }} | {{ order.vehicle.mileage }}
{{ order.details.vehicle.manufacture_year }}年 | 续航{{ order.details.vehicle.range_km }}km
</text>
<text class="vehicle-battery">{{ order.vehicle.batteryCapacity }}</text>
<text class="vehicle-price">¥{{ order.vehicle.price }}</text>
<text class="vehicle-battery">电池容量:{{ order.details.vehicle.battery_capacity_ah }}Ah</text>
<text class="vehicle-price">¥{{ order.details.vehicle.price }}</text>
</view>
</nut-col>
</nut-row>
......@@ -80,24 +80,24 @@
<!-- 操作按钮 -->
<view class="order-actions">
<!-- 买车模式:待支付状态 -->
<template v-if="viewMode === 'bought' && order.status === 'pending'">
<template v-if="viewMode === 'buy' && order.status === 3">
<nut-button type="primary" size="small" @click="handlePayment(order)" color="orange">
去支付
</nut-button>
</template>
<!-- 已完成状态 -->
<template v-if="order.status === 'completed'">
<template v-if="order.status === 5">
<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" color="orange" plain>
{{ order.review ? '查看评价' : '评价' }}
{{ order.details.review ? '查看评价' : '评价' }}
</nut-button>
</template>
<!-- 已取消状态 -->
<template v-if="order.status === 'cancelled'">
<template v-if="order.status === 7">
<nut-button type="default" size="small" @click="deleteOrder(order.id)"
:loading="deletingOrderId === order.id" :disabled="deletingOrderId === order.id">
{{ deletingOrderId === order.id ? '删除中...' : '删除订单' }}
......@@ -133,12 +133,11 @@
<view class="rate-content">
<!-- 商品信息展示 -->
<view class="product-info">
<image :src="currentRateOrder?.vehicle?.imageUrl" class="product-image" mode="aspectFill" />
<image :src="currentRateOrder?.details?.vehicle?.front_photo || DEFAULT_COVER_IMG" 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?.details?.vehicle?.brand }} {{ currentRateOrder?.details?.vehicle?.model }}</text>
<text class="product-specs">{{ currentRateOrder?.details?.vehicle?.manufacture_year }}年 · 里程: {{ currentRateOrder?.details?.vehicle?.range_km }}km</text>
<text class="product-price">¥ {{ currentRateOrder?.details?.vehicle?.price }}</text>
</view>
</view>
......@@ -158,9 +157,9 @@
: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 }}
</text>
<!-- <text v-if="isReadOnlyMode && currentRateOrder?.details?.review?.date" class="review-date">
评价时间:{{ currentRateOrder?.details?.review?.date }}
</text> -->
</view>
</view>
......@@ -175,7 +174,7 @@
<!-- 订单详情弹窗 -->
<nut-popup v-model:visible="showOrderDetailPopup" position="right" :style="{ width: '100%', height: '100%' }"
closeable close-icon-position="top-right" @close="closeOrderDetailPopup">
@close="closeOrderDetailPopup">
<view class="order-detail-popup">
<view class="detail-header">
<text class="detail-title">订单详情</text>
......@@ -191,7 +190,11 @@
</view>
<view class="info-row">
<text class="info-label">下单时间</text>
<text class="info-value">{{ currentOrderDetail?.date }}</text>
<text class="info-value">{{ currentOrderDetail?.created_time }}</text>
</view>
<view class="info-row">
<text class="info-label">支付时间</text>
<text class="info-value">{{ currentOrderDetail?.payment_time }}</text>
</view>
<view class="info-row">
<text class="info-label">订单状态</text>
......@@ -201,7 +204,7 @@
</view>
<view class="info-row">
<text class="info-label">订单金额</text>
<text class="info-value price">¥{{ currentOrderDetail?.price }}</text>
<text class="info-value price">¥ {{ currentOrderDetail?.total_amount }}</text>
</view>
</view>
......@@ -209,13 +212,13 @@
<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" />
<image :src="currentOrderDetail?.details?.vehicle?.front_photo || DEFAULT_COVER_IMG" 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>
<text class="product-detail-name">{{ currentOrderDetail?.details?.vehicle?.brand }} {{ currentOrderDetail?.details?.vehicle?.model }}</text>
<text class="product-detail-specs">{{ currentOrderDetail?.details?.vehicle?.manufacture_year }}年 · 续航: {{
currentOrderDetail?.details?.vehicle?.range_km }}km/h</text>
<text class="product-detail-battery">电池容量: {{ currentOrderDetail?.details?.vehicle?.battery_capacity_ah }}Ah</text>
<text class="product-detail-price">¥ {{ currentOrderDetail?.details?.vehicle?.price }}</text>
</view>
</view>
</view>
......@@ -224,35 +227,35 @@
<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>
<text class="info-label">{{ viewMode === 'buy' ? '卖家' : '买家' }}</text>
<text class="info-value">{{ viewMode === 'buy' ? currentOrderDetail?.details?.vehicle?.seller?.nickname : currentOrderDetail?.buyer?.nickname }}</text>
</view>
<view class="info-row">
<text class="info-label">联系电话</text>
<text class="info-value">{{ viewMode === 'bought' ? '138****5678' : '139****1234' }}</text>
<text class="info-value">{{ viewMode === 'buy' ? currentOrderDetail?.details?.vehicle?.seller?.phone : currentOrderDetail?.buyer?.phone }}</text>
</view>
<view class="info-row">
<!-- <view class="info-row">
<text class="info-label">交易地点</text>
<text class="info-value">北京市朝阳区望京SOHO</text>
</view>
</view> -->
</view>
<!-- 评价信息(如果有) -->
<view class="detail-section" v-if="currentOrderDetail?.review">
<view class="detail-section" v-if="currentOrderDetail?.details?.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"
<nut-rate :model-value="currentOrderDetail?.details?.review?.rating" readonly size="20" active-color="#ff6b35"
void-color="#e5e5e5" />
<!-- <text class="rating-text">{{ currentOrderDetail?.review?.rating }}/5分</text> -->
<!-- <text class="rating-text">{{ currentOrderDetail?.details?.review?.rating }}/5分</text> -->
</view>
<view class="review-content">
<text class="content-label">评价内容:</text>
<text class="content-text">{{ currentOrderDetail?.review?.content }}</text>
<text class="content-text">{{ currentOrderDetail?.details?.review?.note }}</text>
</view>
<view class="review-time">
<text class="time-text">评价时间:{{ currentOrderDetail?.review?.date }}</text>
<text class="time-text">评价时间:{{ currentOrderDetail?.details?.review?.created_time }}</text>
</view>
</view>
</view>
......@@ -282,24 +285,18 @@
</view>
</template>
</nut-dialog>
<!-- 成功提示 -->
<nut-toast
v-model:visible="toastVisible"
:msg="toastMessage"
:type="toastType"
/>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import Taro from '@tarojs/taro'
// import { deleteOrderAPI, submitReviewAPI } from '@/api/orders' // 预留真实API调用
import './index.less'
import { $ } from '@tarojs/extend'
import payCard from '@/components/payCard.vue'
// NutUI组件已全局注册,无需单独导入Rate
// 导入接口
import { getOrderListAPI, getOrderDetailAPI, reviewOrderAPI } from '@/api/orders'
import { DEFAULT_COVER_IMG } from '@/utils/config'
const scrollStyle = ref({
height: ''
......@@ -310,8 +307,8 @@ const scrollViewRef = ref(null)
const scrollTop = ref(0)
// 页面状态
const activeTab = ref('all')
const viewMode = ref('bought')
const activeTab = ref('')
const viewMode = ref('buy')
const loading = ref(false)
const hasMore = ref(true)
......@@ -334,188 +331,30 @@ const isReadOnlyMode = ref(false)
const showOrderDetailPopup = ref(false)
const currentOrderDetail = ref(null)
// 模拟订单数据 - 我买的车
const boughtOrders = ref([
{
id: 'B001',
price: 3999,
date: '2023-11-15 14:30',
status: 'pending',
vehicle: {
name: '小牛 U1 Pro',
year: '2022年',
mileage: '续航120km',
batteryCapacity: '电池容量:1.5kWh',
price: 3999,
imageUrl: 'https://images.unsplash.com/photo-1558981285-6f0c94958bb6?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
}
},
{
id: 'B002',
price: 5299,
date: '2023-10-28 09:15',
status: 'completed',
vehicle: {
name: '雅迪 DE2',
year: '2023年',
mileage: '续航80km',
batteryCapacity: '电池容量:1.2kWh',
price: 5299,
imageUrl: 'https://images.unsplash.com/photo-1571068316344-75bc76f77890?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
},
review: {
rating: 4,
content: '车子质量不错,续航也够用,就是充电时间有点长。',
date: '2023-10-30 16:20'
}
},
{
id: 'B003',
price: 2899,
date: '2023-09-20 11:30',
status: 'cancelled',
vehicle: {
name: '台铃 小狮子',
year: '2021年',
mileage: '续航65km',
batteryCapacity: '电池容量:1.0kWh',
price: 2899,
imageUrl: 'https://images.unsplash.com/photo-1544191696-15693072b5a5?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
}
},
{
id: 'B004',
price: 4599,
date: '2023-08-15 15:45',
status: 'completed',
vehicle: {
name: '九号 E80C',
year: '2023年',
mileage: '续航80km',
batteryCapacity: '电池容量:1.44kWh',
price: 4599,
imageUrl: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
},
review: {
rating: 5,
content: '非常满意!车况很好,卖家服务态度也很棒,推荐!',
date: '2023-08-18 10:30'
}
},
{
id: 'B005',
price: 1899,
date: '2023-07-22 13:20',
status: 'pending',
vehicle: {
name: '绿源 MH5',
year: '2020年',
mileage: '续航50km',
batteryCapacity: '电池容量:0.9kWh',
price: 1899,
imageUrl: 'https://images.unsplash.com/photo-1571068316344-75bc76f77890?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
}
}
])
// 模拟订单数据 - 我卖的车
const soldOrders = ref([
{
id: 'S001',
price: 3200,
date: '2023-11-10 16:45',
status: 'completed',
vehicle: {
name: '爱玛 小蜜豆',
year: '2021年',
mileage: '续航60km',
batteryCapacity: '电池容量:0.8kWh',
price: 3200,
imageUrl: 'https://images.unsplash.com/photo-1544191696-15693072b5a5?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
},
review: {
rating: 5,
content: '买家很爽快,交易很顺利,车子也很满意!',
date: '2023-11-12 14:20'
}
},
{
id: 'S002',
price: 2800,
date: '2023-10-05 10:30',
status: 'pending',
vehicle: {
name: '小刀 长征版',
year: '2022年',
mileage: '续航70km',
batteryCapacity: '电池容量:1.1kWh',
price: 2800,
imageUrl: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
}
},
{
id: 'S003',
price: 4200,
date: '2023-09-18 14:15',
status: 'cancelled',
vehicle: {
name: '立马 威风',
year: '2023年',
mileage: '续航90km',
batteryCapacity: '电池容量:1.6kWh',
price: 4200,
imageUrl: 'https://images.unsplash.com/photo-1558981285-6f0c94958bb6?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
}
},
{
id: 'S004',
price: 1650,
date: '2023-08-28 09:45',
status: 'completed',
vehicle: {
name: '新日 XC1',
year: '2020年',
mileage: '续航45km',
batteryCapacity: '电池容量:0.7kWh',
price: 1650,
imageUrl: 'https://images.unsplash.com/photo-1571068316344-75bc76f77890?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
}
},
{
id: 'S005',
price: 3800,
date: '2023-07-12 16:20',
status: 'completed',
vehicle: {
name: '哈啰 A80',
year: '2022年',
mileage: '续航85km',
batteryCapacity: '电池容量:1.3kWh',
price: 3800,
imageUrl: 'https://images.unsplash.com/photo-1544191696-15693072b5a5?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
},
review: {
rating: 4,
content: '车子成色不错,买家也很好沟通,交易愉快!',
date: '2023-07-15 11:30'
}
}
])
// 订单数据 - 我买的车
const boughtOrders = ref([])
// 订单数据 - 我卖的车
const soldOrders = ref([])
// 分页相关状态
const currentPage = ref(0)
const pageLimit = ref(10)
/**
* 根据当前视图模式和筛选条件获取过滤后的订单列表
*/
const filteredOrders = computed(() => {
const orders = viewMode.value === 'bought' ? boughtOrders.value : soldOrders.value
const orders = viewMode.value === 'buy' ? boughtOrders.value : soldOrders.value
if (activeTab.value === 'all') {
if (activeTab.value === '') {
return orders
}
return orders.filter(order => {
if (activeTab.value === 'pending') return order.status === 'pending'
if (activeTab.value === 'completed') return order.status === 'completed'
if (activeTab.value === 'cancelled') return order.status === 'cancelled'
if (activeTab.value === 3) return order.status === 3
if (activeTab.value === 5) return order.status === 5
if (activeTab.value === 7) return order.status === 7
return true
})
})
......@@ -526,7 +365,7 @@ const filteredOrders = computed(() => {
const setViewMode = (mode) => {
viewMode.value = mode
// 重置状态筛选标签到全部
activeTab.value = 'all'
activeTab.value = ''
// 重置列表状态和数据
resetListState(true)
}
......@@ -536,8 +375,68 @@ const setViewMode = (mode) => {
*/
const setActiveTab = (tab) => {
activeTab.value = tab
// 重置列表加载状态
resetListState(false)
// 重置列表加载状态并重新加载数据
currentPage.value = 0
loadOrderData(false)
}
/**
* 加载订单数据
* @param {boolean} isLoadMore - 是否为加载更多
*/
const loadOrderData = async (isLoadMore = false) => {
if (loading.value) return
try {
loading.value = true
const type = viewMode.value === 'buy' ? 'buy' : 'sell'
const status = activeTab.value || undefined
const page = isLoadMore ? currentPage.value + 1 : 0
const response = await getOrderListAPI({
type,
status,
page,
limit: pageLimit.value
})
if (response.code && response.data && response.data.list && response.data.list.length > 0) {
// 处理多个订单数据
const newOrders = response.data.list.map(orderData => {
// 处理details数组,取第一个元素作为details对象
return {
...orderData,
details: orderData.details && orderData.details.length > 0 ? orderData.details[0] : null
}
})
const targetOrders = viewMode.value === 'buy' ? boughtOrders : soldOrders
if (isLoadMore) {
targetOrders.value = [...targetOrders.value, ...newOrders]
currentPage.value = page
} else {
targetOrders.value = newOrders
currentPage.value = 0
}
// 判断是否还有更多数据
hasMore.value = newOrders.length === pageLimit.value
} else {
hasMore.value = false
}
} catch (error) {
console.error('加载订单数据失败:', error)
Taro.showToast({
title: '加载失败,请重试',
icon: 'error',
duration: 2000
})
hasMore.value = false
} finally {
loading.value = false
}
}
/**
......@@ -547,18 +446,17 @@ const setActiveTab = (tab) => {
const resetListState = (resetData = false) => {
loading.value = false
hasMore.value = true
currentPage.value = 0
// 重置滚动位置到顶部
scrollTop.value = Math.random() // 使用随机数触发scroll-view重新渲染
if (resetData) {
// 重置已加载的数据索引
loadedBoughtIndex.value = 0
loadedSoldIndex.value = 0
// 重置订单数据到初始状态
boughtOrders.value = boughtOrders.value.slice(0, 5) // 保留前5条初始数据
soldOrders.value = soldOrders.value.slice(0, 5) // 保留前5条初始数据
// 清空订单数据
boughtOrders.value = []
soldOrders.value = []
// 重新加载数据
loadOrderData(false)
}
// 延迟重置scrollTop为0,确保滚动位置正确
......@@ -574,147 +472,14 @@ const scroll = (e) => {
// 可以在这里处理滚动事件
}
// 模拟更多数据池 - 买车订单
const moreBoughtOrders = [
{
id: 'B006',
price: 2299,
date: '2023-06-18 14:30',
status: 'completed',
vehicle: {
name: '小鸟 V1',
year: '2019年',
mileage: '续航55km',
batteryCapacity: '电池容量:0.8kWh',
price: 2299,
imageUrl: 'https://images.unsplash.com/photo-1558981285-6f0c94958bb6?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
},
review: {
rating: 3,
content: '车子还行,就是电池续航有点短,价格还算合理。',
date: '2023-06-20 09:15'
}
},
{
id: 'B007',
price: 3599,
date: '2023-05-25 16:45',
status: 'cancelled',
vehicle: {
name: '速珂 TC Max',
year: '2022年',
mileage: '续航100km',
batteryCapacity: '电池容量:1.8kWh',
price: 3599,
imageUrl: 'https://images.unsplash.com/photo-1571068316344-75bc76f77890?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
}
},
{
id: 'B008',
price: 4899,
date: '2023-04-12 11:20',
status: 'pending',
vehicle: {
name: '小牛 NGT',
year: '2023年',
mileage: '续航130km',
batteryCapacity: '电池容量:2.0kWh',
price: 4899,
imageUrl: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
}
}
]
// 模拟更多数据池 - 卖车订单
const moreSoldOrders = [
{
id: 'S006',
price: 2100,
date: '2023-06-08 13:15',
status: 'completed',
vehicle: {
name: '绿佳 FDT',
year: '2020年',
mileage: '续航50km',
batteryCapacity: '电池容量:0.9kWh',
price: 2100,
imageUrl: 'https://images.unsplash.com/photo-1544191696-15693072b5a5?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
}
},
{
id: 'S007',
price: 3500,
date: '2023-05-20 10:30',
status: 'pending',
vehicle: {
name: '雅迪 G5 Pro',
year: '2022年',
mileage: '续航85km',
batteryCapacity: '电池容量:1.4kWh',
price: 3500,
imageUrl: 'https://images.unsplash.com/photo-1558981285-6f0c94958bb6?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
}
},
{
id: 'S008',
price: 1800,
date: '2023-04-15 15:45',
status: 'cancelled',
vehicle: {
name: '爱玛 麦',
year: '2019年',
mileage: '续航40km',
batteryCapacity: '电池容量:0.6kWh',
price: 1800,
imageUrl: 'https://images.unsplash.com/photo-1571068316344-75bc76f77890?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60'
}
}
]
// 记录已加载的数据索引
const loadedBoughtIndex = ref(0)
const loadedSoldIndex = ref(0)
/**
* 加载更多数据
*/
const loadMore = () => {
if (loading.value || !hasMore.value) return
loading.value = true
// 模拟加载延迟
setTimeout(() => {
const currentOrders = viewMode.value === 'bought' ? boughtOrders : soldOrders
const moreOrders = viewMode.value === 'bought' ? moreBoughtOrders : moreSoldOrders
const loadedIndex = viewMode.value === 'bought' ? loadedBoughtIndex : loadedSoldIndex
// 每次加载2条数据
const batchSize = 2
const startIndex = loadedIndex.value
const endIndex = Math.min(startIndex + batchSize, moreOrders.length)
if (startIndex < moreOrders.length) {
// 添加新数据
const newOrders = moreOrders.slice(startIndex, endIndex)
currentOrders.value.push(...newOrders)
// 更新已加载索引
if (viewMode.value === 'bought') {
loadedBoughtIndex.value = endIndex
} else {
loadedSoldIndex.value = endIndex
}
// 检查是否还有更多数据
hasMore.value = endIndex < moreOrders.length
} else {
// 没有更多数据了
hasMore.value = false
}
loading.value = false
}, 1000)
loadOrderData(true)
}
/**
......@@ -722,11 +487,11 @@ const loadMore = () => {
*/
const getStatusText = (status) => {
switch (status) {
case 'pending':
case 3:
return '待支付'
case 'completed':
case 5:
return '已完成'
case 'cancelled':
case 7:
return '已取消'
default:
return '未知状态'
......@@ -738,27 +503,25 @@ const getStatusText = (status) => {
*/
const getStatusClass = (status) => {
switch (status) {
case 'pending':
case 3:
return 'status-pending'
case 'completed':
case 5:
return 'status-completed'
case 'cancelled':
case 7:
return 'status-cancelled'
default:
return ''
}
}
// 页面导航相关方法可以在需要时添加
/**
* 处理支付
*/
const handlePayment = ({ id, price }) => {
const handlePayment = ({ id, total_amount }) => {
onPay({
id,
remain_time: 1800, // 30分钟
price
price: total_amount
})
}
......@@ -790,12 +553,12 @@ const onPayClose = () => {
*/
const onPaySuccess = ({ orderId }) => {
// 找到对应的订单并更新状态
const orders = viewMode.value === 'bought' ? boughtOrders.value : soldOrders.value
const orders = viewMode.value === 'buy' ? boughtOrders.value : soldOrders.value
const order = orders.find(o => o.id === orderId)
if (order) {
// 更新订单状态为已完成
order.status = 'completed'
order.status = 5
Taro.showToast({
title: '支付成功,订单已更新',
......@@ -808,15 +571,18 @@ const onPaySuccess = ({ orderId }) => {
/**
* 查看订单详情
*/
const viewOrderDetail = (orderId) => {
const viewOrderDetail = async (orderId) => {
// 找到对应的订单
const orders = viewMode.value === 'bought' ? boughtOrders.value : soldOrders.value
const orders = viewMode.value === 'buy' ? boughtOrders.value : soldOrders.value
const order = orders.find(o => o.id === orderId)
if (order) {
currentOrderDetail.value = order
const { code, data } = await getOrderDetailAPI({ id: orderId })
if (code) {
currentOrderDetail.value = { ...data, details: data.details[0] }
showOrderDetailPopup.value = true
}
}
}
/**
......@@ -832,7 +598,7 @@ const closeOrderDetailPopup = () => {
*/
const rateOrder = (orderId) => {
// 找到对应的订单
const orders = viewMode.value === 'bought' ? boughtOrders.value : soldOrders.value
const orders = viewMode.value === 'buy' ? boughtOrders.value : soldOrders.value
const order = orders.find(o => o.id === orderId)
if (order) {
......@@ -882,52 +648,28 @@ const submitRate = async () => {
try {
submittingRate.value = true
// 真实的API调用(当前注释掉,使用模拟数据)
// const response = await submitReviewAPI({
// orderId: currentRateOrder.value.id,
// rating: rateScore.value,
// comment: rateContent.value
// })
// if (response.success) {
// // API提交成功后的处理
// const currentOrders = viewMode.value === 'bought' ? boughtOrders : soldOrders
// const order = currentOrders.value.find(o => o.id === currentRateOrder.value.id)
// if (order) {
// order.review = {
// rating: rateScore.value,
// content: rateContent.value,
// date: new Date().toLocaleString('zh-CN')
// }
// order.status = 'completed'
// }
// Toast.success(response.message || '评价提交成功')
// closeRatePopup()
// } else {
// throw new Error(response.message || '提交失败')
// }
// 模拟API调用延迟(开发阶段使用)
await new Promise(resolve => setTimeout(resolve, 1500))
// 更新本地数据
const currentOrders = viewMode.value === 'bought' ? boughtOrders : soldOrders
const response = await reviewOrderAPI({
detail_id: currentRateOrder.value.id,
rating: rateScore.value,
note: rateContent.value
})
if (response.code) {
// API提交成功后的处理
const currentOrders = viewMode.value === 'buy' ? boughtOrders : soldOrders
const order = currentOrders.value.find(o => o.id === currentRateOrder.value.id)
if (order) {
order.review = {
rating: rateScore.value,
content: rateContent.value,
note: rateContent.value,
date: new Date().toLocaleString('zh-CN')
}
order.status = 'completed'
order.status = 5
}
Taro.showToast({
title: '评价提交成功',
icon: 'success',
duration: 2000
})
Toast.success(response.message || '评价提交成功')
closeRatePopup()
} else {
throw new Error(response.message || '提交失败')
}
} catch (error) {
// console.error('提交评价失败:', error)
......@@ -955,22 +697,6 @@ const showConfirmModal = ref(false)
const pendingDeleteOrderId = ref('')
/**
* Toast提示
*/
const toastVisible = ref(false)
const toastMessage = ref('')
const toastType = ref('success')
/**
* 显示提示信息
*/
const showToast = (message, type = 'success') => {
toastMessage.value = message
toastType.value = type
toastVisible.value = true
}
/**
* 删除订单
* @param {string} orderId - 订单ID
*/
......@@ -999,9 +725,9 @@ const performDeleteOrder = async (orderId) => {
try {
// 真实的API调用(当前注释掉,使用模拟数据)
// const response = await deleteOrderAPI({ orderId })
// if (response.success) {
// if (response.code) {
// // API删除成功后的处理
// const orders = viewMode.value === 'bought' ? boughtOrders : soldOrders
// const orders = viewMode.value === 'buy' ? boughtOrders : soldOrders
// const orderIndex = orders.value.findIndex(order => order.id === orderId)
// if (orderIndex !== -1) {
// orders.value.splice(orderIndex, 1)
......@@ -1015,13 +741,17 @@ const performDeleteOrder = async (orderId) => {
await new Promise(resolve => setTimeout(resolve, 1000))
// 从本地数据中移除订单
const orders = viewMode.value === 'bought' ? boughtOrders : soldOrders
const orders = viewMode.value === 'buy' ? boughtOrders : soldOrders
const orderIndex = orders.value.findIndex(order => order.id === orderId)
if (orderIndex !== -1) {
orders.value.splice(orderIndex, 1)
showToast('订单删除成功', 'success')
Taro.showToast({
title: '订单删除成功',
icon: 'success',
duration: 2000
})
} else {
throw new Error('订单不存在')
}
......@@ -1029,7 +759,11 @@ const performDeleteOrder = async (orderId) => {
} catch (error) {
// console.error('删除订单失败:', error)
showToast('删除订单失败', 'error')
Taro.showToast({
title: '删除订单失败',
icon: 'error',
duration: 2000
})
} finally {
// 清除删除状态
deletingOrderId.value = ''
......@@ -1040,7 +774,9 @@ const performDeleteOrder = async (orderId) => {
// 页面加载时的初始化
onMounted(async () => {
// TODO: 加载订单数据
// 加载订单数据
loadOrderData(false)
// 设置滚动列表可视高度
const windowHeight = wx.getWindowInfo().windowHeight;
setTimeout(async () => {
......@@ -1058,7 +794,3 @@ export default {
name: "OrderManagementPage",
};
</script>
<style lang="less">
/* 样式已移至 index.less 文件 */
</style>
......
<!--
* @Date: 2022-09-19 14:11:06
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-07-11 14:56:02
* @LastEditTime: 2025-07-14 09:34:00
* @FilePath: /jgdl/src/pages/productDetail/index.vue
* @Description: 商品详情页
-->
......@@ -136,7 +136,7 @@
</view>
<!-- 卖家信息 -->
<view class="seller-info bg-white mt-2 p-4 mb-2">
<view v-if="!isCurrentUserSeller" class="seller-info bg-white mt-2 p-4 mb-2">
<text class="text-lg font-medium mb-3 block">卖家信息</text>
<view class="flex items-center justify-between">
<view class="flex items-center">
......@@ -167,7 +167,7 @@
</view>
<!-- 底部按钮 -->
<view class="bottom-actions">
<view v-if="!isCurrentUserSeller" class="bottom-actions">
<nut-row :gutter="10">
<nut-col :span="12">
<nut-button @click="handleContactSeller" block type="default" shape="round"
......@@ -245,17 +245,20 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, computed } from 'vue'
import Taro, { useShareAppMessage } from '@tarojs/taro'
import { Share, Heart1, HeartFill, Message } from '@nutui/icons-vue-taro'
import payCard from '@/components/payCard.vue'
import { useFavorite } from '@/composables/useFavorite'
import avatarImg from '@/assets/images/avatar.png'
// import avatarImg from '@/assets/images/avatar.png'
import { getCurrentPageParam } from "@/utils/weapp"
import { checkPermission, PERMISSION_TYPES } from '@/utils/permission'
// 导入接口
import { getVehicleDetailAPI } from '@/api/car'
import { createOrderAPI } from '@/api/orders'
import { DEFAULT_COVER_IMG } from '@/utils/config'
// 导入用户 store
import { useUserStore } from '@/stores/user'
// 默认头像
const defaultAvatar = 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'
......@@ -288,14 +291,14 @@ const quickTags = ref([
])
// 备用图片数组
const fallbackImages = ref([
avatarImg,
avatarImg,
avatarImg,
avatarImg,
avatarImg
])
const imageLoadErrors = ref(new Set())
// const fallbackImages = ref([
// avatarImg,
// avatarImg,
// avatarImg,
// avatarImg,
// avatarImg
// ])
// const imageLoadErrors = ref(new Set())
// 模拟商品数据
const product = ref({})
......@@ -304,13 +307,23 @@ const product = ref({})
* 轮播图切换事件
* @param {number} index - 当前图片索引
*/
// const onSwiperChange = (index) => {
// currentImageIndex.value = index
// }
const onSwiperChange = (index) => {
currentImageIndex.value = index
}
// 使用收藏功能composables
const { toggleFavorite } = useFavorite()
// 使用用户 store
const userStore = useUserStore()
/**
* 判断当前用户是否为卖家
*/
const isCurrentUserSeller = computed(() => {
return product.value.seller?.id && userStore.userInfo.id && product.value.seller.id === userStore.userInfo.id
})
/**
* 显示微信号弹框
*/
......@@ -406,11 +419,21 @@ const handlePurchase = async () => {
* @param {number} payInfo.remain_time - 剩余时间
* @param {number} payInfo.price - 价格
*/
const onPay = ({ id, remain_time, price }) => {
const onPay = async ({ id, remain_time, price }) => {
try {
const { code, data } = await createOrderAPI({
vehicle_id: id,
total_amount: price
})
if (code) {
show_pay.value = true
payData.value.id = id
payData.value.id = data.id
payData.value.price = price
payData.value.remain_time = remain_time
}
} catch (error) {
console.error('创建订单失败:', error)
}
}
/**
......@@ -471,6 +494,9 @@ function filterEmptyValues(arr) {
}
onMounted(async () => {
// 获取用户信息
await userStore.fetchUserInfo()
// 获取商品详情
let params = getCurrentPageParam();
const { code, data } = await getVehicleDetailAPI({ id: params.id })
......