DeliveryOrderList.vue
7.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
<template>
<div>
<a-card title="配送订单" :bordered="false" class="list-table-card">
<div class="list-toolbar">
<div class="list-toolbar-left">
<a-select v-if="isAdmin" v-model:value="filterCityId" placeholder="租户" allowClear class="list-filter" @change="handleAdminCityChange">
<a-select-option v-for="item in cityList" :key="item.id" :value="item.id">{{ item.name }}</a-select-option>
</a-select>
<a-input v-if="isAdmin" v-model:value="filterAppKey" placeholder="接入方 AppKey" class="list-search appkey-search" @pressEnter="handleAppKeySearch" />
<a-select v-model:value="filterStatus" placeholder="状态" allowClear class="list-filter" @change="handleStatusChange">
<a-select-option :value="2">待接单</a-select-option>
<a-select-option :value="3">已接单</a-select-option>
<a-select-option :value="4">配送中</a-select-option>
<a-select-option :value="6">已完成</a-select-option>
<a-select-option :value="10">已取消</a-select-option>
</a-select>
<a-input-search v-model:value="keyword" placeholder="外部订单号" @search="handleKeywordSearch" class="list-search" />
</div>
</div>
<a-table
:dataSource="list"
:columns="columns"
:loading="loading"
rowKey="id"
:pagination="pagination"
@change="handleTableChange"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'cityName'">
{{ getCityName(record.cityId) }}
</template>
<template v-if="column.key === 'status'">
<a-tag :color="statusColor[record.status]">{{ statusMap[record.status] }}</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openDetail(record)">详情</a>
<a-popconfirm v-if="record.status === 2 && canOperate" title="确认取消该配送订单?" @confirm="cancelOrder(record)">
<a style="color:red">取消</a>
</a-popconfirm>
<span v-else-if="isAdmin && record.status === 2 && !canOperate">选择租户后可取消</span>
</a-space>
</template>
</template>
</a-table>
</a-card>
<a-modal v-model:open="queryVisible" title="配送订单详情" :footer="null" :confirmLoading="detailLoading">
<div v-if="queryResult" class="soft-page-stack">
<div class="soft-note-card">
<strong>配送订单详情</strong>
<p>这里展示后台可查看的配送单核心状态和计费结果,便于运营快速核对。</p>
</div>
<a-descriptions :column="1" bordered size="small">
<a-descriptions-item label="配送订单ID">{{ queryResult.deliveryOrderId }}</a-descriptions-item>
<a-descriptions-item label="配送订单号">{{ queryResult.orderNo }}</a-descriptions-item>
<a-descriptions-item label="外部订单号">{{ queryResult.outOrderNo }}</a-descriptions-item>
<a-descriptions-item label="状态">{{ statusMap[queryResult.status] }}</a-descriptions-item>
<a-descriptions-item label="配送费">¥{{ queryResult.totalFee }}</a-descriptions-item>
<a-descriptions-item label="距离">{{ queryResult.distance }} km</a-descriptions-item>
<a-descriptions-item label="预计时间">{{ queryResult.estimatedMinutes }} 分钟</a-descriptions-item>
</a-descriptions>
</div>
</a-modal>
</div>
</template>
<script setup lang="ts">
import { computed, ref, onMounted } from 'vue'
import { message } from 'ant-design-vue'
import type { TablePaginationConfig } from 'ant-design-vue'
import { riderApi } from '@/api'
import { useRoleCityList } from '@/composables/useRoleCityList'
const PAGE_SIZE = 20
const loading = ref(false)
const detailLoading = ref(false)
const list = ref<any[]>([])
const total = ref(0)
const currentPage = ref(1)
const pageSize = ref(PAGE_SIZE)
const filterCityId = ref<number | undefined>()
const filterAppKey = ref('')
const filterStatus = ref<number | undefined>()
const keyword = ref('')
const queryVisible = ref(false)
const queryResult = ref<any>(null)
const { isAdmin, cityList, loadCities, getCityName } = useRoleCityList()
const canOperate = computed(() => !isAdmin.value || !!filterCityId.value)
const statusMap: Record<number, string> = {
2: '待接单', 3: '已接单', 4: '配送中', 6: '已完成', 7: '退款申请',
8: '退款成功', 9: '退款拒绝', 10: '已取消'
}
const statusColor: Record<number, string> = {
2: 'blue', 3: 'cyan', 4: 'processing', 6: 'green',
7: 'orange', 8: 'green', 9: 'red', 10: 'red'
}
const columns = computed(() => {
const base = [
{ title: 'ID', dataIndex: 'id', width: 80 },
{ title: '外部订单号', dataIndex: 'outOrderNo' },
{ title: '接入方', dataIndex: 'appKey', ellipsis: true },
{ title: '收件人', dataIndex: 'recipName' },
{ title: '配送费', dataIndex: 'moneyDelivery' },
{ title: '状态', key: 'status' },
{ title: '操作', key: 'action' },
]
if (!isAdmin.value) {
return base
}
return [
{ title: '租户', key: 'cityName' },
...base,
]
})
const pagination = computed<TablePaginationConfig>(() => ({
current: currentPage.value,
pageSize: pageSize.value,
total: total.value,
showSizeChanger: false,
showTotal: (count) => `共 ${count} 条`,
}))
function resetToFirstPage() {
currentPage.value = 1
}
function handleStatusChange() {
resetToFirstPage()
loadList()
}
function handleKeywordSearch() {
resetToFirstPage()
loadList()
}
function handleAppKeySearch() {
resetToFirstPage()
loadList()
}
function handleTableChange(page: TablePaginationConfig) {
const nextPage = page.current ?? 1
if (nextPage === currentPage.value) {
return
}
currentPage.value = nextPage
loadList()
}
async function loadList() {
loading.value = true
try {
const res: any = await riderApi.deliveryOrderList({
cityId: filterCityId.value,
appKey: filterAppKey.value || undefined,
status: filterStatus.value,
outOrderNo: keyword.value || undefined,
page: currentPage.value
})
const data = res?.data ?? {}
list.value = Array.isArray(data.list) ? data.list : []
total.value = Number(data.total ?? 0)
currentPage.value = Number(data.page ?? currentPage.value)
pageSize.value = Number(data.pageSize ?? PAGE_SIZE)
if (!list.value.length && total.value > 0 && currentPage.value > 1) {
currentPage.value -= 1
await loadList()
}
} finally { loading.value = false }
}
function handleAdminCityChange() {
if (!filterCityId.value) {
queryVisible.value = false
queryResult.value = null
}
resetToFirstPage()
loadList()
}
async function openDetail(record: any) {
detailLoading.value = true
queryResult.value = null
queryVisible.value = true
try {
const res: any = await riderApi.deliveryOrderDetail(record.id)
queryResult.value = res.data
} finally { detailLoading.value = false }
}
async function cancelOrder(record: any) {
await riderApi.deliveryOrderCancel(record.id)
message.success('取消成功')
if (queryVisible.value && queryResult.value?.deliveryOrderId === record.id) {
queryVisible.value = false
queryResult.value = null
}
await loadList()
}
onMounted(async () => {
await loadCities()
await loadList()
})
</script>