feat: manage group buy order readiness
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { filterPendingDeliveryGroupBuyOrders, groupBuyOrderDispatchLabel } from './groupBuyApi'
|
||||
import {
|
||||
buildGroupBuyOrderActionPath,
|
||||
filterPendingDeliveryGroupBuyOrders,
|
||||
groupBuyOrderDispatchLabel
|
||||
} from './groupBuyApi'
|
||||
import type { GroupBuyOrder } from '../types'
|
||||
|
||||
describe('group buy dispatch helpers', () => {
|
||||
@@ -21,6 +25,11 @@ describe('group buy dispatch helpers', () => {
|
||||
amountCent: 5980
|
||||
}))).toBe('GB00000001 Today eggs x2 ¥59.80')
|
||||
})
|
||||
|
||||
it('builds admin action paths for group buy orders', () => {
|
||||
expect(buildGroupBuyOrderActionPath(1, 'confirm')).toBe('/api/admin/group-buy-orders/1/confirm')
|
||||
expect(buildGroupBuyOrderActionPath(1, 'ready')).toBe('/api/admin/group-buy-orders/1/ready')
|
||||
})
|
||||
})
|
||||
|
||||
function groupBuyOrder(overrides: Partial<GroupBuyOrder>): GroupBuyOrder {
|
||||
|
||||
@@ -17,6 +17,18 @@ export function groupBuyOrderDispatchLabel(order: GroupBuyOrder) {
|
||||
return `${order.orderNo} ${order.groupBuyTitle} x${order.quantity} ¥${(order.amountCent / 100).toFixed(2)}`
|
||||
}
|
||||
|
||||
export function buildGroupBuyOrderActionPath(id: number, action: 'confirm' | 'ready') {
|
||||
return `/api/admin/group-buy-orders/${id}/${action}`
|
||||
}
|
||||
|
||||
export function confirmGroupBuyOrder(id: number) {
|
||||
return apiPut<GroupBuyOrder>(buildGroupBuyOrderActionPath(id, 'confirm'))
|
||||
}
|
||||
|
||||
export function markGroupBuyOrderReady(id: number) {
|
||||
return apiPut<GroupBuyOrder>(buildGroupBuyOrderActionPath(id, 'ready'))
|
||||
}
|
||||
|
||||
export function createGroupBuy(data: Partial<GroupBuy>) {
|
||||
return apiPost<GroupBuy>('/api/admin/group-buys', data)
|
||||
}
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { Check, Close, Plus, Refresh, VideoPlay } from '@element-plus/icons-vue'
|
||||
import { Check, Close, Plus, Refresh, Tickets, VideoPlay } from '@element-plus/icons-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import {
|
||||
closeGroupBuy,
|
||||
completeGroupBuy,
|
||||
confirmGroupBuyOrder,
|
||||
createGroupBuy,
|
||||
listGroupBuyOrders,
|
||||
listGroupBuys,
|
||||
markGroupBuyOrderReady,
|
||||
startGroupBuy
|
||||
} from '../api/groupBuyApi'
|
||||
import type { GroupBuy } from '../types'
|
||||
import type { GroupBuy, GroupBuyOrder } from '../types'
|
||||
import { statusText, yuan } from '../utils/format'
|
||||
|
||||
const loading = ref(false)
|
||||
const orderLoading = ref(false)
|
||||
const rows = ref<GroupBuy[]>([])
|
||||
const orders = ref<GroupBuyOrder[]>([])
|
||||
const activeGroupBuy = ref<GroupBuy | null>(null)
|
||||
const dialog = ref(false)
|
||||
const orderDialog = ref(false)
|
||||
const form = reactive({
|
||||
title: '',
|
||||
coverUrl: '',
|
||||
@@ -37,6 +44,24 @@ async function load() {
|
||||
}
|
||||
}
|
||||
|
||||
async function openOrders(row: GroupBuy) {
|
||||
activeGroupBuy.value = row
|
||||
orderDialog.value = true
|
||||
await loadOrders(row.id)
|
||||
}
|
||||
|
||||
async function loadOrders(groupBuyId = activeGroupBuy.value?.id) {
|
||||
if (!groupBuyId) return
|
||||
orderLoading.value = true
|
||||
try {
|
||||
orders.value = await listGroupBuyOrders(groupBuyId)
|
||||
} catch (error) {
|
||||
ElMessage.error(error instanceof Error ? error.message : '加载失败')
|
||||
} finally {
|
||||
orderLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function save() {
|
||||
try {
|
||||
await createGroupBuy(form)
|
||||
@@ -58,6 +83,17 @@ async function run(action: () => Promise<GroupBuy>) {
|
||||
}
|
||||
}
|
||||
|
||||
async function runOrder(action: () => Promise<GroupBuyOrder>) {
|
||||
try {
|
||||
await action()
|
||||
ElMessage.success('操作成功')
|
||||
await loadOrders()
|
||||
await load()
|
||||
} catch (error) {
|
||||
ElMessage.error(error instanceof Error ? error.message : '操作失败')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(load)
|
||||
</script>
|
||||
|
||||
@@ -79,18 +115,46 @@ onMounted(load)
|
||||
<template #default="{ row }">{{ statusText(row.status) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="endTime" label="截单时间" min-width="170" />
|
||||
<el-table-column label="操作" width="260" fixed="right">
|
||||
<el-table-column label="操作" width="330" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<div class="table-action">
|
||||
<el-button size="small" :icon="VideoPlay" @click="run(() => startGroupBuy(row.id))">开始</el-button>
|
||||
<el-button size="small" :icon="Close" @click="run(() => closeGroupBuy(row.id))">截单</el-button>
|
||||
<el-button size="small" :icon="Check" @click="run(() => completeGroupBuy(row.id))">完成</el-button>
|
||||
<el-button size="small" :icon="Tickets" @click="openOrders(row)">订单</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="orderDialog" :title="activeGroupBuy ? `${activeGroupBuy.title} 订单` : '团购订单'" width="760px">
|
||||
<div class="toolbar">
|
||||
<el-button :icon="Refresh" :loading="orderLoading" @click="loadOrders()">刷新</el-button>
|
||||
</div>
|
||||
<el-table :data="orders" border v-loading="orderLoading">
|
||||
<el-table-column prop="orderNo" label="订单号" min-width="140" />
|
||||
<el-table-column prop="quantity" label="数量" width="80" />
|
||||
<el-table-column label="金额" width="110">
|
||||
<template #default="{ row }">{{ yuan(row.amountCent) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="配送" width="110">
|
||||
<template #default="{ row }">{{ row.deliveryMethod === 'SELF_PICKUP' ? '自提' : '配送' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="130">
|
||||
<template #default="{ row }">{{ statusText(row.status) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="190" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<div class="table-action">
|
||||
<el-button v-if="row.status === 'PENDING_CONFIRM'" size="small" :icon="Check" @click="runOrder(() => confirmGroupBuyOrder(row.id))">确认</el-button>
|
||||
<el-button v-if="row.status === 'CONFIRMED'" size="small" type="primary" :icon="Check" @click="runOrder(() => markGroupBuyOrderReady(row.id))">备货完成</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="dialog" title="新建团购" width="560px">
|
||||
<el-form label-width="90px">
|
||||
<el-form-item label="标题"><el-input v-model="form.title" /></el-form-item>
|
||||
|
||||
Reference in New Issue
Block a user