mi-assessment/uniapp/pages/order/list/index.vue
2026-02-20 14:57:43 +08:00

439 lines
11 KiB
Vue

<script setup>
/**
* 我的订单页面
* 展示用户所有已支付或退款的订单
*/
import { ref, computed, onMounted } from 'vue'
import { onShow, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'
import { useUserStore } from '@/store/user.js'
import { useAuth } from '@/composables/useAuth.js'
import { getOrderList } from '@/api/order.js'
import Empty from '@/components/Empty/index.vue'
import Loading from '@/components/Loading/index.vue'
const userStore = useUserStore()
const { checkLogin } = useAuth()
// 订单状态常量
const ORDER_STATUS = {
PENDING_PAYMENT: 1, // 待支付
PAID: 2, // 已支付
COMPLETED: 3, // 已完成(已测评)
REFUNDING: 4, // 退款中
REFUNDED: 5, // 已退款
CANCELLED: 6, // 已取消
GENERATING: 7, // 测评生成中
PENDING_ASSESSMENT: 8 // 待测评
}
// 状态
const loading = ref(false)
const refreshing = ref(false)
const orderList = ref([])
const page = ref(1)
const pageSize = ref(10)
const total = ref(0)
const noMore = ref(false)
// 计算属性
const isEmpty = computed(() => !loading.value && orderList.value.length === 0)
const hasMore = computed(() => orderList.value.length < total.value)
/**
* 获取订单状态文本
*/
function getStatusText(status) {
const statusMap = {
[ORDER_STATUS.PENDING_PAYMENT]: '待支付',
[ORDER_STATUS.PAID]: '已支付',
[ORDER_STATUS.COMPLETED]: '已测评',
[ORDER_STATUS.REFUNDING]: '退款中',
[ORDER_STATUS.REFUNDED]: '已退款',
[ORDER_STATUS.CANCELLED]: '已取消',
[ORDER_STATUS.GENERATING]: '测评生成中',
[ORDER_STATUS.PENDING_ASSESSMENT]: '待测评'
}
return statusMap[status] || '未知状态'
}
/**
* 获取订单状态样式类
*/
function getStatusClass(status) {
const classMap = {
[ORDER_STATUS.PENDING_PAYMENT]: 'status-pending',
[ORDER_STATUS.PAID]: 'status-paid',
[ORDER_STATUS.COMPLETED]: 'status-completed',
[ORDER_STATUS.REFUNDING]: 'status-refunding',
[ORDER_STATUS.REFUNDED]: 'status-refunded',
[ORDER_STATUS.CANCELLED]: 'status-cancelled',
[ORDER_STATUS.GENERATING]: 'status-generating',
[ORDER_STATUS.PENDING_ASSESSMENT]: 'status-pending-assessment'
}
return classMap[status] || ''
}
/**
* 格式化日期
*/
function formatDate(dateStr) {
if (!dateStr) return ''
const date = new Date(dateStr)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
/**
* 格式化金额
*/
function formatAmount(amount) {
if (amount === undefined || amount === null) return '0.00'
return Number(amount).toFixed(2)
}
/**
* 加载订单列表
*/
async function loadOrderList(isRefresh = false) {
if (loading.value) return
if (isRefresh) {
page.value = 1
noMore.value = false
}
loading.value = true
try {
const res = await getOrderList({
page: page.value,
pageSize: pageSize.value
})
if (res.code === 0 && res.data) {
const list = res.data.list || []
total.value = res.data.total || 0
if (isRefresh) {
orderList.value = list
} else {
orderList.value = [...orderList.value, ...list]
}
// 判断是否还有更多
noMore.value = orderList.value.length >= total.value
} else {
uni.showToast({
title: res.message || '获取订单失败',
icon: 'none'
})
}
} catch (error) {
console.error('获取订单列表失败:', error)
uni.showToast({
title: '网络错误,请重试',
icon: 'none'
})
} finally {
loading.value = false
refreshing.value = false
uni.stopPullDownRefresh()
}
}
/**
* 下拉刷新
*/
onPullDownRefresh(() => {
refreshing.value = true
loadOrderList(true)
})
/**
* 上拉加载更多
*/
onReachBottom(() => {
if (!noMore.value && !loading.value) {
page.value++
loadOrderList()
}
})
/**
* 查看测评结果
*/
function viewResult(order) {
uni.navigateTo({
url: `/pages/assessment/result/index?recordId=${order.recordId}`
})
}
/**
* 开始测评
*/
function startAssessment(order) {
uni.navigateTo({
url: `/pages/assessment/questions/index?orderId=${order.id}&typeId=${order.productId}`
})
}
/**
* 判断是否显示查看结果按钮
*/
function showViewResultBtn(status) {
return status === ORDER_STATUS.COMPLETED
}
/**
* 判断是否显示开始测评按钮
*/
function showStartBtn(status) {
return status === ORDER_STATUS.PENDING_ASSESSMENT
}
/**
* 页面显示时检查登录状态并加载数据
*/
onShow(() => {
userStore.restoreFromStorage()
if (checkLogin()) {
loadOrderList(true)
}
})
/**
* 页面加载
*/
onMounted(() => {
userStore.restoreFromStorage()
})
</script>
<template>
<view class="order-list-page">
<!-- 页面加载中 -->
<Loading type="page" :loading="loading && orderList.length === 0" />
<!-- 订单列表 -->
<view class="order-list" v-if="!isEmpty">
<view
class="order-card"
v-for="order in orderList"
:key="order.id"
>
<!-- 订单头部 -->
<view class="order-header">
<view class="order-date">{{ formatDate(order.createTime) }}</view>
<view class="order-status" :class="getStatusClass(order.status)">
{{ getStatusText(order.status) }}
</view>
</view>
<!-- 订单内容 -->
<view class="order-content">
<view class="order-info-row">
<text class="info-label">订单编号</text>
<text class="info-value">{{ order.orderNo || '--' }}</text>
</view>
<view class="order-info-row">
<text class="info-label">测评项目</text>
<text class="info-value">{{ order.productName || '--' }}</text>
</view>
<view class="order-info-row">
<text class="info-label">测评金额</text>
<text class="info-value amount">¥{{ formatAmount(order.amount) }}</text>
</view>
</view>
<!-- 订单操作按钮 -->
<view class="order-actions" v-if="showViewResultBtn(order.status) || showStartBtn(order.status)">
<view
class="action-btn primary"
v-if="showViewResultBtn(order.status)"
@click="viewResult(order)"
>
查看测评结果
</view>
<view
class="action-btn primary"
v-if="showStartBtn(order.status)"
@click="startAssessment(order)"
>
开始测评
</view>
</view>
</view>
<!-- 加载更多 -->
<Loading
type="more"
:loading="loading && orderList.length > 0"
:noMore="noMore"
noMoreText="没有更多订单了"
/>
</view>
<!-- 空状态 -->
<Empty
v-if="isEmpty"
text="暂无订单记录"
:showButton="false"
/>
</view>
</template>
<style lang="scss" scoped>
@import '@/styles/variables.scss';
.order-list-page {
min-height: 100vh;
background-color: $bg-color;
padding: $spacing-lg;
padding-bottom: calc(#{$spacing-lg} + env(safe-area-inset-bottom));
}
// 订单列表
.order-list {
.order-card {
background-color: $bg-white;
border-radius: $border-radius-lg;
margin-bottom: $spacing-lg;
overflow: hidden;
// 订单头部
.order-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: $spacing-md $spacing-lg;
border-bottom: 1rpx solid $border-light;
.order-date {
font-size: $font-size-md;
color: $text-color;
}
.order-status {
font-size: $font-size-sm;
padding: 4rpx 16rpx;
border-radius: $border-radius-sm;
// 已测评 - 绿色
&.status-completed {
color: $success-color;
background-color: rgba(82, 196, 26, 0.1);
}
// 测评生成中 - 蓝色
&.status-generating {
color: $primary-color;
background-color: rgba(74, 144, 226, 0.1);
}
// 待测评 - 橙色
&.status-pending-assessment {
color: $warning-color;
background-color: rgba(250, 173, 20, 0.1);
}
// 已支付 - 蓝色
&.status-paid {
color: $primary-color;
background-color: rgba(74, 144, 226, 0.1);
}
// 待支付 - 灰色
&.status-pending {
color: $text-placeholder;
background-color: rgba(153, 153, 153, 0.1);
}
// 退款中 - 橙色
&.status-refunding {
color: $warning-color;
background-color: rgba(250, 173, 20, 0.1);
}
// 已退款 - 灰色
&.status-refunded {
color: $text-secondary;
background-color: rgba(102, 102, 102, 0.1);
}
// 已取消 - 灰色
&.status-cancelled {
color: $text-placeholder;
background-color: rgba(153, 153, 153, 0.1);
}
}
}
// 订单内容
.order-content {
padding: $spacing-md $spacing-lg;
.order-info-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: $spacing-xs 0;
.info-label {
font-size: $font-size-md;
color: $text-secondary;
}
.info-value {
font-size: $font-size-md;
color: $text-color;
&.amount {
color: $error-color;
font-weight: $font-weight-medium;
}
}
}
}
// 订单操作按钮
.order-actions {
display: flex;
justify-content: flex-end;
padding: $spacing-md $spacing-lg;
border-top: 1rpx solid $border-light;
.action-btn {
min-width: 180rpx;
height: 64rpx;
line-height: 64rpx;
text-align: center;
font-size: $font-size-sm;
border-radius: 32rpx;
margin-left: $spacing-md;
&.primary {
background-color: $primary-color;
color: $text-white;
&:active {
opacity: 0.8;
}
}
&.outline {
border: 1rpx solid $primary-color;
color: $primary-color;
background-color: transparent;
&:active {
background-color: rgba(74, 144, 226, 0.1);
}
}
}
}
}
}
</style>