198 lines
4.6 KiB
Vue
198 lines
4.6 KiB
Vue
<template>
|
|
<div class="order-list-page">
|
|
<!-- 搜索栏 -->
|
|
<van-search
|
|
v-model="searchKeyword"
|
|
placeholder="搜索订单编号、客户名称"
|
|
@search="handleSearch"
|
|
@clear="handleClear"
|
|
/>
|
|
|
|
<!-- 下拉刷新 -->
|
|
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
|
|
<!-- 订单列表 -->
|
|
<van-list
|
|
v-model:loading="loading"
|
|
:finished="finished"
|
|
finished-text="没有更多了"
|
|
@load="onLoad"
|
|
>
|
|
<div v-for="order in orderList" :key="order.id" class="order-item" @click="goToDetail(order.id)">
|
|
<div class="order-header">
|
|
<div class="order-code">{{ order.orderCode }}</div>
|
|
<div class="status-tag pending">
|
|
待审批
|
|
</div>
|
|
</div>
|
|
|
|
<div class="order-info">
|
|
<div class="info-row">
|
|
<span class="label">项目名称:</span>
|
|
<span class="value">{{ order.projectName }}</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="label">客户名称:</span>
|
|
<span class="value">{{ order.customerName }}</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="label">订单金额:</span>
|
|
<span class="value amount">{{ formatAmount(order.shipmentAmount) }}</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="label">创建时间:</span>
|
|
<span class="value">{{ formatDate(order.createTime, 'YYYY-MM-DD HH:mm') }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 空状态 -->
|
|
<div v-if="!loading && orderList.length === 0" class="empty-state">
|
|
<van-empty description="暂无订单数据" />
|
|
</div>
|
|
</van-list>
|
|
</van-pull-refresh>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, onMounted } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { storeToRefs } from 'pinia'
|
|
import { useOrderStore } from '@/store/order'
|
|
import { formatOrderStatus, formatAmount, formatDate } from '@/utils'
|
|
import type { OrderStatus } from '@/types'
|
|
|
|
const router = useRouter()
|
|
const orderStore = useOrderStore()
|
|
const { orderList, loading, finished } = storeToRefs(orderStore)
|
|
|
|
// 搜索相关
|
|
const searchKeyword = ref('')
|
|
const refreshing = ref(false)
|
|
|
|
// 获取状态样式类
|
|
const getStatusClass = (status: OrderStatus) => {
|
|
const classMap = {
|
|
'0': 'pending',
|
|
'1': 'approved',
|
|
'2': 'rejected'
|
|
}
|
|
return classMap[status] || 'pending'
|
|
}
|
|
|
|
// 加载数据
|
|
const onLoad = async () => {
|
|
try {
|
|
await orderStore.loadOrderList()
|
|
} catch (error) {
|
|
console.error('加载订单列表失败:', error)
|
|
}
|
|
}
|
|
|
|
// 下拉刷新
|
|
const onRefresh = async () => {
|
|
try {
|
|
await orderStore.loadOrderList(true)
|
|
refreshing.value = false
|
|
} catch (error) {
|
|
refreshing.value = false
|
|
console.error('刷新失败:', error)
|
|
}
|
|
}
|
|
|
|
// 搜索处理
|
|
const handleSearch = async () => {
|
|
try {
|
|
await orderStore.searchOrders(searchKeyword.value.trim())
|
|
} catch (error) {
|
|
console.error('搜索失败:', error)
|
|
}
|
|
}
|
|
|
|
// 清空搜索
|
|
const handleClear = async () => {
|
|
searchKeyword.value = ''
|
|
try {
|
|
await orderStore.searchOrders('')
|
|
} catch (error) {
|
|
console.error('清空搜索失败:', error)
|
|
}
|
|
}
|
|
|
|
// 跳转到详情页
|
|
const goToDetail = (id: number) => {
|
|
router.push(`/detail/${id}`)
|
|
}
|
|
|
|
onMounted(() => {
|
|
// 重置状态并加载数据
|
|
orderStore.resetListState()
|
|
onLoad()
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.order-list-page {
|
|
min-height: 100vh;
|
|
background-color: var(--background-color-secondary);
|
|
}
|
|
|
|
.order-item {
|
|
background: var(--background-color-primary);
|
|
margin-bottom: var(--spacing-sm);
|
|
padding: var(--spacing-lg);
|
|
cursor: pointer;
|
|
transition: background-color 0.2s;
|
|
|
|
&:active {
|
|
background-color: var(--background-color-tertiary);
|
|
}
|
|
}
|
|
|
|
.order-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: var(--spacing-md);
|
|
}
|
|
|
|
.order-code {
|
|
font-size: 16px;
|
|
font-weight: 500;
|
|
color: var(--text-color-primary);
|
|
}
|
|
|
|
.order-info {
|
|
.info-row {
|
|
display: flex;
|
|
margin-bottom: var(--spacing-sm);
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.label {
|
|
width: 80px;
|
|
color: var(--text-color-secondary);
|
|
font-size: 14px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.value {
|
|
flex: 1;
|
|
color: var(--text-color-primary);
|
|
font-size: 14px;
|
|
word-break: break-all;
|
|
|
|
&.amount {
|
|
color: var(--error-color);
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.empty-state {
|
|
padding: 60px var(--spacing-lg);
|
|
}
|
|
</style> |