feat: list group buy orders for dispatch
This commit is contained in:
40
admin-web/src/api/groupBuyApi.test.ts
Normal file
40
admin-web/src/api/groupBuyApi.test.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
import { filterPendingDeliveryGroupBuyOrders, groupBuyOrderDispatchLabel } from './groupBuyApi'
|
||||||
|
import type { GroupBuyOrder } from '../types'
|
||||||
|
|
||||||
|
describe('group buy dispatch helpers', () => {
|
||||||
|
it('keeps only group buy orders waiting for delivery', () => {
|
||||||
|
const orders = [
|
||||||
|
groupBuyOrder({ id: 1, status: 'PENDING_DELIVERY' }),
|
||||||
|
groupBuyOrder({ id: 2, status: 'DELIVERING' }),
|
||||||
|
groupBuyOrder({ id: 3, status: 'PENDING_PICKUP' })
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(filterPendingDeliveryGroupBuyOrders(orders).map((item) => item.id)).toEqual([1])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('builds a readable dispatch label', () => {
|
||||||
|
expect(groupBuyOrderDispatchLabel(groupBuyOrder({
|
||||||
|
orderNo: 'GB00000001',
|
||||||
|
groupBuyTitle: 'Today eggs',
|
||||||
|
quantity: 2,
|
||||||
|
amountCent: 5980
|
||||||
|
}))).toBe('GB00000001 Today eggs x2 ¥59.80')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function groupBuyOrder(overrides: Partial<GroupBuyOrder>): GroupBuyOrder {
|
||||||
|
return {
|
||||||
|
id: 1,
|
||||||
|
orderNo: 'GB00000001',
|
||||||
|
groupBuyId: 1,
|
||||||
|
groupBuyTitle: 'Today eggs',
|
||||||
|
quantity: 1,
|
||||||
|
priceCent: 2990,
|
||||||
|
amountCent: 2990,
|
||||||
|
deliveryMethod: 'IMMEDIATE',
|
||||||
|
status: 'PENDING_DELIVERY',
|
||||||
|
offlinePayStatus: 'UNPAID',
|
||||||
|
...overrides
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,22 @@
|
|||||||
import type { GroupBuy } from '../types'
|
import type { GroupBuy, GroupBuyOrder } from '../types'
|
||||||
import { apiGet, apiPost, apiPut } from './http'
|
import { apiGet, apiPost, apiPut } from './http'
|
||||||
|
|
||||||
export function listGroupBuys() {
|
export function listGroupBuys() {
|
||||||
return apiGet<GroupBuy[]>('/api/admin/group-buys')
|
return apiGet<GroupBuy[]>('/api/admin/group-buys')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function listGroupBuyOrders(groupBuyId: number) {
|
||||||
|
return apiGet<GroupBuyOrder[]>(`/api/admin/group-buys/${groupBuyId}/orders`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function filterPendingDeliveryGroupBuyOrders(orders: GroupBuyOrder[]) {
|
||||||
|
return orders.filter((order) => order.status === 'PENDING_DELIVERY')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function groupBuyOrderDispatchLabel(order: GroupBuyOrder) {
|
||||||
|
return `${order.orderNo} ${order.groupBuyTitle} x${order.quantity} ¥${(order.amountCent / 100).toFixed(2)}`
|
||||||
|
}
|
||||||
|
|
||||||
export function createGroupBuy(data: Partial<GroupBuy>) {
|
export function createGroupBuy(data: Partial<GroupBuy>) {
|
||||||
return apiPost<GroupBuy>('/api/admin/group-buys', data)
|
return apiPost<GroupBuy>('/api/admin/group-buys', data)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,22 @@ export interface GroupBuy {
|
|||||||
pickupAddress?: string
|
pickupAddress?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GroupBuyOrder {
|
||||||
|
id: number
|
||||||
|
orderNo: string
|
||||||
|
groupBuyId: number
|
||||||
|
groupBuyTitle: string
|
||||||
|
coverUrl?: string
|
||||||
|
quantity: number
|
||||||
|
priceCent: number
|
||||||
|
amountCent: number
|
||||||
|
deliveryMethod: string
|
||||||
|
status: string
|
||||||
|
offlinePayStatus: string
|
||||||
|
remark?: string
|
||||||
|
createdAt?: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface SecondGoods {
|
export interface SecondGoods {
|
||||||
id: number
|
id: number
|
||||||
title: string
|
title: string
|
||||||
|
|||||||
@@ -3,6 +3,12 @@ import { onMounted, reactive, ref } from 'vue'
|
|||||||
import { Plus, Refresh, Van } from '@element-plus/icons-vue'
|
import { Plus, Refresh, Van } from '@element-plus/icons-vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { listGoodsOrders, listExpressOrders } from '../api/orderApi'
|
import { listGoodsOrders, listExpressOrders } from '../api/orderApi'
|
||||||
|
import {
|
||||||
|
filterPendingDeliveryGroupBuyOrders,
|
||||||
|
groupBuyOrderDispatchLabel,
|
||||||
|
listGroupBuyOrders,
|
||||||
|
listGroupBuys
|
||||||
|
} from '../api/groupBuyApi'
|
||||||
import {
|
import {
|
||||||
assignExpressOrder,
|
assignExpressOrder,
|
||||||
assignGoodsOrder,
|
assignGoodsOrder,
|
||||||
@@ -11,7 +17,7 @@ import {
|
|||||||
listDeliveryOrders,
|
listDeliveryOrders,
|
||||||
listDeliveryUsers
|
listDeliveryUsers
|
||||||
} from '../api/deliveryApi'
|
} from '../api/deliveryApi'
|
||||||
import type { DeliveryOrder, DeliveryUser, ExpressOrder, GoodsOrder } from '../types'
|
import type { DeliveryOrder, DeliveryUser, ExpressOrder, GoodsOrder, GroupBuyOrder } from '../types'
|
||||||
import { statusText } from '../utils/format'
|
import { statusText } from '../utils/format'
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@@ -19,22 +25,28 @@ const riders = ref<DeliveryUser[]>([])
|
|||||||
const tasks = ref<DeliveryOrder[]>([])
|
const tasks = ref<DeliveryOrder[]>([])
|
||||||
const goodsOrders = ref<GoodsOrder[]>([])
|
const goodsOrders = ref<GoodsOrder[]>([])
|
||||||
const expressOrders = ref<ExpressOrder[]>([])
|
const expressOrders = ref<ExpressOrder[]>([])
|
||||||
|
const groupBuyOrders = ref<GroupBuyOrder[]>([])
|
||||||
const riderForm = reactive({ userId: 3, name: '', phone: '', enabled: true })
|
const riderForm = reactive({ userId: 3, name: '', phone: '', enabled: true })
|
||||||
const dispatchForm = reactive({ goodsOrderId: undefined as number | undefined, expressOrderId: undefined as number | undefined, groupBuyOrderId: undefined as number | undefined, riderId: undefined as number | undefined })
|
const dispatchForm = reactive({ goodsOrderId: undefined as number | undefined, expressOrderId: undefined as number | undefined, groupBuyOrderId: undefined as number | undefined, riderId: undefined as number | undefined })
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
const [riderRows, taskRows, goodsRows, expressRows] = await Promise.all([
|
const [riderRows, taskRows, goodsRows, expressRows, groupBuyRows] = await Promise.all([
|
||||||
listDeliveryUsers(),
|
listDeliveryUsers(),
|
||||||
listDeliveryOrders(),
|
listDeliveryOrders(),
|
||||||
listGoodsOrders({ status: 'PENDING_DELIVERY' }),
|
listGoodsOrders({ status: 'PENDING_DELIVERY' }),
|
||||||
listExpressOrders('PENDING_PICKUP')
|
listExpressOrders('PENDING_PICKUP'),
|
||||||
|
listGroupBuys()
|
||||||
])
|
])
|
||||||
|
const groupOrderRows = groupBuyRows.length
|
||||||
|
? ([] as GroupBuyOrder[]).concat(...await Promise.all(groupBuyRows.map((item) => listGroupBuyOrders(item.id))))
|
||||||
|
: []
|
||||||
riders.value = riderRows
|
riders.value = riderRows
|
||||||
tasks.value = taskRows
|
tasks.value = taskRows
|
||||||
goodsOrders.value = goodsRows
|
goodsOrders.value = goodsRows
|
||||||
expressOrders.value = expressRows
|
expressOrders.value = expressRows
|
||||||
|
groupBuyOrders.value = filterPendingDeliveryGroupBuyOrders(groupOrderRows)
|
||||||
if (!dispatchForm.riderId && riderRows[0]) dispatchForm.riderId = riderRows[0].id
|
if (!dispatchForm.riderId && riderRows[0]) dispatchForm.riderId = riderRows[0].id
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error(error instanceof Error ? error.message : '加载失败')
|
ElMessage.error(error instanceof Error ? error.message : '加载失败')
|
||||||
@@ -113,7 +125,9 @@ onMounted(load)
|
|||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="团购订单">
|
<el-tab-pane label="团购订单">
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<el-input-number v-model="dispatchForm.groupBuyOrderId" :min="1" />
|
<el-select v-model="dispatchForm.groupBuyOrderId" placeholder="待配送团购订单" style="width: 320px">
|
||||||
|
<el-option v-for="item in groupBuyOrders" :key="item.id" :label="groupBuyOrderDispatchLabel(item)" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
<el-button type="primary" :icon="Van" @click="dispatch('group')">派单</el-button>
|
<el-button type="primary" :icon="Van" @click="dispatch('group')">派单</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
|||||||
Reference in New Issue
Block a user