fix: 修复订单列表不能查看的问题
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="page" :style="{ paddingTop: navBarHeight }">
|
||||
<view class="page" :style="{ '--status-bar': statusBarHeight + 'px' }">
|
||||
<CustomNavBar title="订单管理" show-back />
|
||||
|
||||
<!-- Summary stats bar -->
|
||||
@@ -106,14 +106,14 @@
|
||||
</view>
|
||||
<view class="info-right">
|
||||
<text class="info-label">下单时间</text>
|
||||
<text class="info-value">{{ formatDate(order.createdAt) }}</text>
|
||||
<text class="info-value">{{ formatDateTime(order.createdAt) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Paid time if available -->
|
||||
<view v-if="order.paidAt && order.status === OrderStatus.PAID" class="info-row">
|
||||
<text class="info-label">支付时间</text>
|
||||
<text class="info-value">{{ formatDate(order.paidAt) }}</text>
|
||||
<text class="info-value">{{ formatDateTime(order.paidAt) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -133,19 +133,21 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import CustomNavBar from '../../components/CustomNavBar.vue'
|
||||
import { getSystemLayout } from '../../utils/system'
|
||||
import { useAdminStore } from '../../stores/admin'
|
||||
import { formatPrice, formatDate } from '../../utils/format'
|
||||
import { formatPrice, formatDateTime } from '../../utils/format'
|
||||
import { OrderStatus } from '@mp-pilates/shared'
|
||||
import type { OrderWithDetails } from '@mp-pilates/shared'
|
||||
|
||||
const adminStore = useAdminStore()
|
||||
|
||||
const navBarHeight = ref('64px')
|
||||
// 动态计算顶部模块高度
|
||||
const statusBarHeight = ref(0)
|
||||
|
||||
onMounted(() => {
|
||||
navBarHeight.value = `${getSystemLayout().navBarHeight}px`
|
||||
const windowInfo = uni.getWindowInfo()
|
||||
statusBarHeight.value = windowInfo.statusBarHeight ?? 20
|
||||
})
|
||||
|
||||
const filters = [
|
||||
@@ -165,6 +167,21 @@ const totalCount = ref<number | null>(null)
|
||||
const paidCount = ref<number | null>(null)
|
||||
const pendingCount = ref<number | null>(null)
|
||||
|
||||
// 每个 tab 单独缓存数据
|
||||
const orderCache: Record<string, { items: OrderWithDetails[]; total: number; page: number; hasMore: boolean }> = {}
|
||||
|
||||
function getCacheKey(filter: string): string {
|
||||
return filter || 'all'
|
||||
}
|
||||
|
||||
function getCachedData(filter: string) {
|
||||
return orderCache[getCacheKey(filter)]
|
||||
}
|
||||
|
||||
function setCachedData(filter: string, data: { items: OrderWithDetails[]; total: number; page: number; hasMore: boolean }) {
|
||||
orderCache[getCacheKey(filter)] = data
|
||||
}
|
||||
|
||||
const LIMIT = 20
|
||||
|
||||
function statusLabel(s: string) {
|
||||
@@ -191,23 +208,45 @@ function statusAccentClass(s: string) {
|
||||
}
|
||||
|
||||
async function loadOrders(reset = false) {
|
||||
const filter = activeFilter.value
|
||||
|
||||
// 如果有缓存且是重置(切换tab),直接用缓存数据
|
||||
if (reset) {
|
||||
const cached = getCachedData(filter)
|
||||
if (cached) {
|
||||
orders.value = [...cached.items]
|
||||
hasMore.value = cached.hasMore
|
||||
page.value = cached.page
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 初始加载或下拉刷新,需要请求接口
|
||||
if (loading.value) return
|
||||
if (reset) page.value = 1
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const params: { page: number; limit: number; status?: string } = {
|
||||
page: page.value,
|
||||
limit: LIMIT,
|
||||
}
|
||||
if (activeFilter.value) params.status = activeFilter.value
|
||||
if (filter) params.status = filter
|
||||
const result = await adminStore.fetchAdminOrders(params)
|
||||
if (reset) {
|
||||
orders.value = [...result.items]
|
||||
} else {
|
||||
orders.value.push(...result.items)
|
||||
}
|
||||
hasMore.value = orders.value.length < result.total
|
||||
totalCount.value = result.total
|
||||
|
||||
const newItems = reset ? [...result.items] : [...orders.value, ...result.items]
|
||||
const newHasMore = newItems.length < result.total
|
||||
|
||||
// 缓存数据
|
||||
setCachedData(filter, {
|
||||
items: newItems,
|
||||
total: result.total,
|
||||
page: page.value,
|
||||
hasMore: newHasMore,
|
||||
})
|
||||
|
||||
orders.value = newItems
|
||||
hasMore.value = newHasMore
|
||||
} catch {
|
||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||
} finally {
|
||||
@@ -216,30 +255,79 @@ async function loadOrders(reset = false) {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSummaryCounts() {
|
||||
// 初始加载所有分类的数据
|
||||
async function loadAllFiltersData() {
|
||||
loading.value = true
|
||||
try {
|
||||
const [allResult, paidResult, pendingResult] = await Promise.all([
|
||||
adminStore.fetchAdminOrders({ page: 1, limit: 1 }),
|
||||
adminStore.fetchAdminOrders({ page: 1, limit: 1, status: OrderStatus.PAID }),
|
||||
adminStore.fetchAdminOrders({ page: 1, limit: 1, status: OrderStatus.PENDING }),
|
||||
// 并行请求所有分类(第一页数据)
|
||||
const [allResult, paidResult, pendingResult, refundedResult] = await Promise.all([
|
||||
adminStore.fetchAdminOrders({ page: 1, limit: LIMIT }),
|
||||
adminStore.fetchAdminOrders({ page: 1, limit: LIMIT, status: OrderStatus.PAID }),
|
||||
adminStore.fetchAdminOrders({ page: 1, limit: LIMIT, status: OrderStatus.PENDING }),
|
||||
adminStore.fetchAdminOrders({ page: 1, limit: LIMIT, status: OrderStatus.REFUNDED }),
|
||||
])
|
||||
|
||||
// 缓存全部
|
||||
setCachedData('', {
|
||||
items: [...allResult.items],
|
||||
total: allResult.total,
|
||||
page: 1,
|
||||
hasMore: allResult.items.length < allResult.total,
|
||||
})
|
||||
totalCount.value = allResult.total
|
||||
|
||||
// 缓存已支付
|
||||
setCachedData(OrderStatus.PAID, {
|
||||
items: [...paidResult.items],
|
||||
total: paidResult.total,
|
||||
page: 1,
|
||||
hasMore: paidResult.items.length < paidResult.total,
|
||||
})
|
||||
paidCount.value = paidResult.total
|
||||
|
||||
// 缓存待支付
|
||||
setCachedData(OrderStatus.PENDING, {
|
||||
items: [...pendingResult.items],
|
||||
total: pendingResult.total,
|
||||
page: 1,
|
||||
hasMore: pendingResult.items.length < pendingResult.total,
|
||||
})
|
||||
pendingCount.value = pendingResult.total
|
||||
|
||||
// 缓存已退款
|
||||
setCachedData(OrderStatus.REFUNDED, {
|
||||
items: [...refundedResult.items],
|
||||
total: refundedResult.total,
|
||||
page: 1,
|
||||
hasMore: refundedResult.items.length < refundedResult.total,
|
||||
})
|
||||
|
||||
// 设置当前 tab 的数据
|
||||
orders.value = [...allResult.items]
|
||||
hasMore.value = allResult.items.length < allResult.total
|
||||
} catch {
|
||||
// non-critical, ignore
|
||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
refreshing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function selectFilter(value: string) {
|
||||
activeFilter.value = value
|
||||
totalCount.value = null
|
||||
loadOrders(true)
|
||||
// 切换 tab 直接从缓存读取
|
||||
const cached = getCachedData(value)
|
||||
if (cached) {
|
||||
orders.value = [...cached.items]
|
||||
hasMore.value = cached.hasMore
|
||||
page.value = cached.page
|
||||
}
|
||||
}
|
||||
|
||||
async function onRefresh() {
|
||||
refreshing.value = true
|
||||
await Promise.all([loadOrders(true), loadSummaryCounts()])
|
||||
// 下拉刷新重新请求所有分类的数据
|
||||
await loadAllFiltersData()
|
||||
}
|
||||
|
||||
function loadMore() {
|
||||
@@ -249,8 +337,7 @@ function loadMore() {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadOrders(true)
|
||||
loadSummaryCounts()
|
||||
loadAllFiltersData()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -266,13 +353,18 @@ onMounted(() => {
|
||||
|
||||
/* ── Stats bar ──────────────────────────────── */
|
||||
.stats-bar {
|
||||
position: fixed;
|
||||
top: calc(var(--status-bar) + 44px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 96rpx;
|
||||
background: #FFFFFF;
|
||||
padding: 28rpx 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-bottom: 1rpx solid rgba(180, 160, 130, 0.2);
|
||||
box-shadow: 0 2rpx 12rpx rgba(180, 160, 130, 0.08);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
@@ -309,9 +401,13 @@ onMounted(() => {
|
||||
|
||||
/* ── Filter pills ───────────────────────────── */
|
||||
.filter-wrap {
|
||||
position: fixed;
|
||||
top: calc(var(--status-bar) + 92px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #FAF8F5;
|
||||
border-bottom: 1rpx solid rgba(180, 160, 130, 0.15);
|
||||
flex-shrink: 0;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.filter-scroll { overflow: hidden; }
|
||||
@@ -364,7 +460,11 @@ onMounted(() => {
|
||||
|
||||
/* ── List ───────────────────────────────────── */
|
||||
.list-scroll {
|
||||
flex: 1;
|
||||
position: fixed;
|
||||
top: calc(var(--status-bar) + 144px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user