支持批量验收接单订单
This commit is contained in:
@@ -2,6 +2,7 @@ import { Router } from 'express'
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
acceptAdminWorkOrder,
|
acceptAdminWorkOrder,
|
||||||
|
acceptAdminWorkOrders,
|
||||||
assignAdminWorkOrderToWorker,
|
assignAdminWorkOrderToWorker,
|
||||||
unassignAdminWorkOrder,
|
unassignAdminWorkOrder,
|
||||||
creditAdminWorkerWallet,
|
creditAdminWorkerWallet,
|
||||||
@@ -512,6 +513,24 @@ router.post(
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
'/worker-platform/orders/accept-batch',
|
||||||
|
requireAdminRoles(['admin', 'operator']),
|
||||||
|
createJsonHandler((req) => acceptAdminWorkOrders(req.body || {}), {
|
||||||
|
successMessage: '选中订单已验收通过',
|
||||||
|
errorMessage: '批量验收接单订单失败',
|
||||||
|
scope: '[admin/worker-platform/orders/accept-batch]',
|
||||||
|
audit: (req, data) => ({
|
||||||
|
action: 'work_orders_batch_accepted',
|
||||||
|
targetType: 'work_order',
|
||||||
|
targetId: Array.isArray(req.body?.workOrderIds)
|
||||||
|
? req.body.workOrderIds.map((item: unknown) => String(item)).join(',')
|
||||||
|
: '',
|
||||||
|
data: data && typeof data === 'object' ? (data as Record<string, unknown>) : {},
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
'/worker-platform/orders/:workOrderId/deduct-pending-deposit',
|
'/worker-platform/orders/:workOrderId/deduct-pending-deposit',
|
||||||
requireAdminRoles(['admin', 'operator']),
|
requireAdminRoles(['admin', 'operator']),
|
||||||
|
|||||||
@@ -1163,6 +1163,46 @@ export async function acceptAdminWorkOrder(workOrderId: number | string) {
|
|||||||
return { order: mapWorkOrderAdmin(updated || workOrder) }
|
return { order: mapWorkOrderAdmin(updated || workOrder) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function acceptAdminWorkOrders(payload: JsonObject = {}) {
|
||||||
|
const workOrderIds = [
|
||||||
|
...new Set(
|
||||||
|
(Array.isArray(payload.workOrderIds) ? payload.workOrderIds : [])
|
||||||
|
.map((item) => normalizeOptionalId(item))
|
||||||
|
.filter((item): item is number => item !== null),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
if (workOrderIds.length === 0) {
|
||||||
|
throw createHttpError('请至少选择一个待验收订单', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'work_order_batch_accept_required',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const workOrders = await Promise.all(workOrderIds.map((workOrderId) => getRequiredWorkOrder(workOrderId)))
|
||||||
|
if (workOrders.some((workOrder) => workOrder.status !== WORK_ORDER_STATUS.PENDING_ACCEPTANCE)) {
|
||||||
|
throw createHttpError('选中的订单包含非待验收状态,请刷新后重试', {
|
||||||
|
statusCode: 409,
|
||||||
|
errorCode: 'work_order_batch_accept_status_invalid',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const pendingSharingCounts = await Promise.all(
|
||||||
|
workOrders.map((workOrder) => countWorkOrderPendingSharingSubmissions(workOrder.id)),
|
||||||
|
)
|
||||||
|
if (pendingSharingCounts.some((count) => count > 0)) {
|
||||||
|
throw createHttpError('选中的订单存在拼单打手未提交验收资料,暂不能统一验收', {
|
||||||
|
statusCode: 409,
|
||||||
|
errorCode: 'work_order_batch_accept_sharing_pending_submissions',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = []
|
||||||
|
for (const workOrder of workOrders) {
|
||||||
|
results.push(await acceptAdminWorkOrder(workOrder.id))
|
||||||
|
}
|
||||||
|
return { orders: results.map((result) => result.order) }
|
||||||
|
}
|
||||||
|
|
||||||
export async function unassignAdminWorkOrder(workOrderId: number | string) {
|
export async function unassignAdminWorkOrder(workOrderId: number | string) {
|
||||||
const workOrder = await getRequiredWorkOrder(workOrderId)
|
const workOrder = await getRequiredWorkOrder(workOrderId)
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import ImagePreviewList from '@/components/files/ImagePreviewList'
|
|||||||
import PageHeader from '@/components/admin/PageHeader'
|
import PageHeader from '@/components/admin/PageHeader'
|
||||||
import {
|
import {
|
||||||
acceptAdminWorkOrder,
|
acceptAdminWorkOrder,
|
||||||
|
acceptAdminWorkOrders,
|
||||||
assignAdminWorkOrderToWorker,
|
assignAdminWorkOrderToWorker,
|
||||||
createAdminMockWorkOrder,
|
createAdminMockWorkOrder,
|
||||||
unassignAdminWorkOrder,
|
unassignAdminWorkOrder,
|
||||||
@@ -124,6 +125,7 @@ export default function WorkOrdersPanel() {
|
|||||||
const [keywordInput, setKeywordInput] = useState('')
|
const [keywordInput, setKeywordInput] = useState('')
|
||||||
const [page, setPage] = useState(1)
|
const [page, setPage] = useState(1)
|
||||||
const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE)
|
const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE)
|
||||||
|
const [selectedAcceptanceOrderIds, setSelectedAcceptanceOrderIds] = useState<number[]>([])
|
||||||
const [detailOrder, setDetailOrder] = useState<WorkOrder | null>(null)
|
const [detailOrder, setDetailOrder] = useState<WorkOrder | null>(null)
|
||||||
const [problemOrder, setProblemOrder] = useState<WorkOrder | null>(null)
|
const [problemOrder, setProblemOrder] = useState<WorkOrder | null>(null)
|
||||||
const [resolutionOrder, setResolutionOrder] = useState<WorkOrder | null>(null)
|
const [resolutionOrder, setResolutionOrder] = useState<WorkOrder | null>(null)
|
||||||
@@ -176,6 +178,10 @@ export default function WorkOrdersPanel() {
|
|||||||
enabled: Boolean(assignOrder),
|
enabled: Boolean(assignOrder),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectedAcceptanceOrderIds([])
|
||||||
|
}, [status, keyword, page, pageSize])
|
||||||
|
|
||||||
function openAssignModal(row: WorkOrder) {
|
function openAssignModal(row: WorkOrder) {
|
||||||
setAssignOrder(row)
|
setAssignOrder(row)
|
||||||
setAssignWorkerId(undefined)
|
setAssignWorkerId(undefined)
|
||||||
@@ -304,6 +310,27 @@ export default function WorkOrdersPanel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function confirmBatchAcceptance() {
|
||||||
|
const workOrderIds = selectedAcceptanceOrderIds
|
||||||
|
if (workOrderIds.length === 0) {
|
||||||
|
message.warning('请先选择待验收订单')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
modal.confirm({
|
||||||
|
title: `确认验收 ${workOrderIds.length} 个订单?`,
|
||||||
|
content: '验收通过后将结算打手奖励,并按配置处理押金。',
|
||||||
|
okText: '一键验收',
|
||||||
|
cancelText: '取消',
|
||||||
|
onOk: async () => {
|
||||||
|
const succeeded = await runAction(
|
||||||
|
() => acceptAdminWorkOrders(workOrderIds),
|
||||||
|
`已验收 ${workOrderIds.length} 个订单`,
|
||||||
|
)
|
||||||
|
if (succeeded) setSelectedAcceptanceOrderIds([])
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async function submitProblem(values: { note?: string }) {
|
async function submitProblem(values: { note?: string }) {
|
||||||
if (!problemOrder) return
|
if (!problemOrder) return
|
||||||
const succeeded = await runAction(
|
const succeeded = await runAction(
|
||||||
@@ -821,6 +848,16 @@ export default function WorkOrdersPanel() {
|
|||||||
title="接单工单"
|
title="接单工单"
|
||||||
extra={
|
extra={
|
||||||
<Space>
|
<Space>
|
||||||
|
{status === 'pending_acceptance' ? (
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<CheckOutlined />}
|
||||||
|
disabled={selectedAcceptanceOrderIds.length === 0}
|
||||||
|
onClick={confirmBatchAcceptance}
|
||||||
|
>
|
||||||
|
批量验收({selectedAcceptanceOrderIds.length})
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
<Button
|
<Button
|
||||||
icon={<ReloadOutlined />}
|
icon={<ReloadOutlined />}
|
||||||
loading={ordersQuery.isFetching}
|
loading={ordersQuery.isFetching}
|
||||||
@@ -837,6 +874,15 @@ export default function WorkOrdersPanel() {
|
|||||||
loading={ordersQuery.isLoading}
|
loading={ordersQuery.isLoading}
|
||||||
dataSource={ordersQuery.data?.data.items || []}
|
dataSource={ordersQuery.data?.data.items || []}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
|
rowSelection={
|
||||||
|
status === 'pending_acceptance'
|
||||||
|
? {
|
||||||
|
selectedRowKeys: selectedAcceptanceOrderIds,
|
||||||
|
onChange: (selectedRowKeys) =>
|
||||||
|
setSelectedAcceptanceOrderIds(selectedRowKeys.map((item) => Number(item))),
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
pagination={buildAdminTablePagination({
|
pagination={buildAdminTablePagination({
|
||||||
current: ordersPagination?.page || page,
|
current: ordersPagination?.page || page,
|
||||||
pageSize: ordersPagination?.pageSize || pageSize,
|
pageSize: ordersPagination?.pageSize || pageSize,
|
||||||
|
|||||||
@@ -313,6 +313,13 @@ export function acceptAdminWorkOrder(workOrderId: number) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function acceptAdminWorkOrders(workOrderIds: number[]) {
|
||||||
|
return apiPost<{ orders: WorkOrder[] }>(
|
||||||
|
'/api/v1/admin/worker-platform/orders/accept-batch',
|
||||||
|
{ workOrderIds },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function deductAdminWorkOrderPendingDeposit(
|
export function deductAdminWorkOrderPendingDeposit(
|
||||||
workOrderId: number,
|
workOrderId: number,
|
||||||
payload: { amount: number; note: string },
|
payload: { amount: number; note: string },
|
||||||
|
|||||||
Reference in New Issue
Block a user