优化接单工单筛选布局
This commit is contained in:
@@ -28,7 +28,6 @@ import {
|
||||
saveAdminWorkProductRule,
|
||||
saveAdminWorkerLevel,
|
||||
submitAdminWorkOrderMaterial,
|
||||
syncAdminWorkerOrdersFromSource,
|
||||
unpublishAdminWorkOrder,
|
||||
updateAdminWorkOrder,
|
||||
updateAdminWorkOrderSharing,
|
||||
@@ -304,22 +303,6 @@ router.post(
|
||||
}),
|
||||
)
|
||||
|
||||
router.post(
|
||||
'/worker-platform/source-orders/sync',
|
||||
requireAdminRoles(['admin', 'operator']),
|
||||
createJsonHandler((req) => syncAdminWorkerOrdersFromSource(req.body || {}), {
|
||||
successMessage: '源订单同步完成',
|
||||
errorMessage: '同步源订单失败',
|
||||
scope: '[admin/worker-platform/source-orders/sync]',
|
||||
audit: (_req, data) => ({
|
||||
action: 'work_order_source_synced',
|
||||
targetType: 'source_order',
|
||||
targetId: '',
|
||||
data: data && typeof data === 'object' ? (data as Record<string, unknown>) : {},
|
||||
}),
|
||||
}),
|
||||
)
|
||||
|
||||
router.post(
|
||||
'/worker-platform/orders/:workOrderId/material',
|
||||
requireAdminRoles(['admin', 'operator', 'support']),
|
||||
|
||||
@@ -2,8 +2,6 @@ import crypto from 'node:crypto'
|
||||
|
||||
import { runtimeConfig } from '../../config/runtime.js'
|
||||
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
||||
import { listOrderItemsByOrderId } from '../../repositories/order-item-repo.js'
|
||||
import { findLatestOrderByAnyPlatformOrderId, getOrderById } from '../../repositories/order-repo.js'
|
||||
import {
|
||||
acceptWorkOrderAndSettle,
|
||||
addWorkerWalletCredit,
|
||||
@@ -688,16 +686,6 @@ export async function submitAdminWorkOrderMaterial(
|
||||
return { order: mapWorkOrderAdmin(updated || workOrder), complete }
|
||||
}
|
||||
|
||||
export async function syncAdminWorkerOrdersFromSource(payload: JsonObject = {}) {
|
||||
const order = await resolveSourceOrder(payload)
|
||||
const orderItems = await listOrderItemsByOrderId(order.id)
|
||||
const result = await syncWorkerOrdersForSourceOrder(order, orderItems, {
|
||||
source: 'admin_manual_sync',
|
||||
autoOnly: false,
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
export async function createAdminMockWorkOrder(payload: JsonObject = {}) {
|
||||
const defaults = await ensureWorkerPlatformDefaults()
|
||||
const now = nowIso()
|
||||
@@ -1149,34 +1137,3 @@ export async function syncWorkerOrdersForSourceOrder(
|
||||
skippedCount: skipped.length,
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveSourceOrder(payload: JsonObject): Promise<OrderRow> {
|
||||
const orderId = normalizeOptionalId(payload.orderId || payload.sourceOrderId)
|
||||
if (orderId) {
|
||||
const order = await getOrderById(orderId)
|
||||
if (order) {
|
||||
return order
|
||||
}
|
||||
throw createHttpError('源订单不存在', {
|
||||
statusCode: 404,
|
||||
errorCode: 'source_order_not_found',
|
||||
})
|
||||
}
|
||||
|
||||
const platformOrderId = String(payload.platformOrderId || payload.orderNo || '').trim()
|
||||
if (!platformOrderId) {
|
||||
throw createHttpError('请填写源订单号', {
|
||||
statusCode: 400,
|
||||
errorCode: 'source_order_no_required',
|
||||
})
|
||||
}
|
||||
|
||||
const order = await findLatestOrderByAnyPlatformOrderId(platformOrderId)
|
||||
if (!order) {
|
||||
throw createHttpError('未找到源订单,请确认订单号是否正确', {
|
||||
statusCode: 404,
|
||||
errorCode: 'source_order_not_found',
|
||||
})
|
||||
}
|
||||
return order
|
||||
}
|
||||
|
||||
@@ -61,7 +61,6 @@ import {
|
||||
saveAdminWorkProductRule,
|
||||
saveAdminWorkerLevel,
|
||||
submitAdminWorkOrderMaterial,
|
||||
syncAdminWorkerOrdersFromSource,
|
||||
unpublishAdminWorkOrder,
|
||||
updateAdminWorkOrderSharing,
|
||||
} from '@/services/admin'
|
||||
@@ -165,4 +164,3 @@ function SummaryCards() {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ import {
|
||||
saveAdminWorkProductRule,
|
||||
saveAdminWorkerLevel,
|
||||
submitAdminWorkOrderMaterial,
|
||||
syncAdminWorkerOrdersFromSource,
|
||||
unpublishAdminWorkOrder,
|
||||
updateAdminWorkOrderSharing,
|
||||
} from '@/services/admin'
|
||||
@@ -259,4 +258,3 @@ export default function CategoriesPanel() {
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ import {
|
||||
saveAdminWorkProductRule,
|
||||
saveAdminWorkerLevel,
|
||||
submitAdminWorkOrderMaterial,
|
||||
syncAdminWorkerOrdersFromSource,
|
||||
unpublishAdminWorkOrder,
|
||||
updateAdminWorkOrderSharing,
|
||||
} from '@/services/admin'
|
||||
|
||||
@@ -61,7 +61,6 @@ import {
|
||||
saveAdminWorkProductRule,
|
||||
saveAdminWorkerLevel,
|
||||
submitAdminWorkOrderMaterial,
|
||||
syncAdminWorkerOrdersFromSource,
|
||||
unpublishAdminWorkOrder,
|
||||
updateAdminWorkOrderSharing,
|
||||
} from '@/services/admin'
|
||||
@@ -299,4 +298,3 @@ export default function LevelsPanel() {
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,6 @@ import {
|
||||
saveAdminWorkProductRule,
|
||||
saveAdminWorkerLevel,
|
||||
submitAdminWorkOrderMaterial,
|
||||
syncAdminWorkerOrdersFromSource,
|
||||
unpublishAdminWorkOrder,
|
||||
updateAdminWorkOrderSharing,
|
||||
} from '@/services/admin'
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
FormOutlined,
|
||||
PlusOutlined,
|
||||
ReloadOutlined,
|
||||
SearchOutlined,
|
||||
SendOutlined,
|
||||
SyncOutlined,
|
||||
TeamOutlined,
|
||||
WarningOutlined,
|
||||
} from '@ant-design/icons'
|
||||
@@ -66,7 +66,6 @@ import {
|
||||
saveAdminWorkProductRule,
|
||||
saveAdminWorkerLevel,
|
||||
submitAdminWorkOrderMaterial,
|
||||
syncAdminWorkerOrdersFromSource,
|
||||
unpublishAdminWorkOrder,
|
||||
updateAdminWorkOrder,
|
||||
updateAdminWorkOrderSharing,
|
||||
@@ -115,6 +114,8 @@ export default function WorkOrdersPanel() {
|
||||
const navigate = useNavigate()
|
||||
const queryClient = useQueryClient()
|
||||
const [status, setStatus] = useState('')
|
||||
const [keyword, setKeyword] = useState('')
|
||||
const [keywordInput, setKeywordInput] = useState('')
|
||||
const [page, setPage] = useState(1)
|
||||
const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE)
|
||||
const [detailOrder, setDetailOrder] = useState<WorkOrder | null>(null)
|
||||
@@ -147,8 +148,8 @@ export default function WorkOrdersPanel() {
|
||||
}>()
|
||||
|
||||
const ordersQuery = useQuery({
|
||||
queryKey: ['admin-worker-platform-orders', status, page, pageSize],
|
||||
queryFn: () => fetchAdminWorkOrders({ status, page, pageSize }),
|
||||
queryKey: ['admin-worker-platform-orders', status, keyword, page, pageSize],
|
||||
queryFn: () => fetchAdminWorkOrders({ status, keyword, page, pageSize }),
|
||||
})
|
||||
const ordersPagination = ordersQuery.data?.data.pagination
|
||||
const categoriesQuery = useQuery({
|
||||
@@ -295,18 +296,16 @@ export default function WorkOrdersPanel() {
|
||||
setMaterialScreenshots([])
|
||||
}
|
||||
|
||||
async function submitSourceSync(values: { platformOrderId?: string }) {
|
||||
try {
|
||||
const result = await syncAdminWorkerOrdersFromSource({
|
||||
platformOrderId: String(values.platformOrderId || '').trim(),
|
||||
})
|
||||
message.success(
|
||||
`同步完成,新增 ${result.data.createdCount} 个,跳过 ${result.data.skippedCount} 个`,
|
||||
)
|
||||
await refreshAll()
|
||||
} catch (error) {
|
||||
message.error(error instanceof Error ? error.message : '同步失败')
|
||||
function searchOrders() {
|
||||
setKeyword(keywordInput.trim())
|
||||
setPage(1)
|
||||
}
|
||||
|
||||
function clearOrderFilters() {
|
||||
setKeywordInput('')
|
||||
setKeyword('')
|
||||
setStatus('')
|
||||
setPage(1)
|
||||
}
|
||||
|
||||
function openMaterialModal(row: WorkOrder) {
|
||||
@@ -636,32 +635,17 @@ export default function WorkOrdersPanel() {
|
||||
|
||||
return (
|
||||
<section className="platform-panel-stack">
|
||||
<Card title="从源订单同步" bordered={false}>
|
||||
<Form layout="inline" onFinish={submitSourceSync}>
|
||||
<Form.Item
|
||||
label="平台订单号"
|
||||
name="platformOrderId"
|
||||
rules={[{ required: true, message: '请输入平台订单号' }]}
|
||||
>
|
||||
<Card title="订单搜索与筛选" bordered={false}>
|
||||
<div className="worker-orders-toolbar">
|
||||
<Space wrap className="filter-form worker-orders-search-controls">
|
||||
<Input
|
||||
placeholder="用户填写链接 A 的订单号"
|
||||
style={{ width: 260 }}
|
||||
allowClear
|
||||
value={keywordInput}
|
||||
placeholder="订单号、工单号或商品名"
|
||||
style={{ width: 280 }}
|
||||
onChange={(event) => setKeywordInput(event.target.value)}
|
||||
onPressEnter={searchOrders}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button type="primary" icon={<SyncOutlined />} htmlType="submit">
|
||||
同步
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
<Card title="生成本地接单工单 Mock" bordered={false}>
|
||||
<MockWorkOrderForm onCreated={refreshAll} />
|
||||
</Card>
|
||||
<Card
|
||||
title="接单工单"
|
||||
extra={
|
||||
<Space>
|
||||
<Select
|
||||
value={status}
|
||||
style={{ width: 150 }}
|
||||
@@ -681,6 +665,21 @@ export default function WorkOrdersPanel() {
|
||||
setPage(1)
|
||||
}}
|
||||
/>
|
||||
<Button type="primary" icon={<SearchOutlined />} onClick={searchOrders}>
|
||||
查询
|
||||
</Button>
|
||||
<Button onClick={clearOrderFilters}>清空筛选</Button>
|
||||
</Space>
|
||||
<div className="worker-orders-mock">
|
||||
<Typography.Text type="secondary">本地 Mock</Typography.Text>
|
||||
<MockWorkOrderForm onCreated={refreshAll} />
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card
|
||||
title="接单工单"
|
||||
extra={
|
||||
<Space>
|
||||
<Button
|
||||
icon={<ReloadOutlined />}
|
||||
loading={ordersQuery.isFetching}
|
||||
@@ -709,7 +708,6 @@ export default function WorkOrdersPanel() {
|
||||
scroll={{ x: 1240 }}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<Drawer
|
||||
title={
|
||||
detailOrder
|
||||
@@ -1320,6 +1318,7 @@ function MockWorkOrderForm({ onCreated }: { onCreated: () => Promise<void> }) {
|
||||
|
||||
return (
|
||||
<Form
|
||||
className="worker-order-mock-form"
|
||||
layout="inline"
|
||||
initialValues={{
|
||||
productName: '指挥官秘钥1个',
|
||||
@@ -1328,23 +1327,24 @@ function MockWorkOrderForm({ onCreated }: { onCreated: () => Promise<void> }) {
|
||||
}}
|
||||
onFinish={submit}
|
||||
>
|
||||
<Form.Item label="订单号" name="platformOrderId">
|
||||
<Input placeholder="留空自动生成" style={{ width: 180 }} />
|
||||
<Form.Item className="worker-order-mock-field-order" label="订单号" name="platformOrderId">
|
||||
<Input placeholder="留空自动生成" />
|
||||
</Form.Item>
|
||||
<Form.Item label="商品" name="productName">
|
||||
<Input style={{ width: 220 }} />
|
||||
<Form.Item className="worker-order-mock-field-product" label="商品" name="productName">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label="接单金额" name="rewardAmount">
|
||||
<Form.Item className="worker-order-mock-field-amount" label="接单金额" name="rewardAmount">
|
||||
<InputNumber min={0.01} step={1} addonAfter="元" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
className="worker-order-mock-field-complete"
|
||||
label="资料完整"
|
||||
name="materialComplete"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Form.Item className="worker-order-mock-action">
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
|
||||
@@ -61,7 +61,6 @@ import {
|
||||
saveAdminWorkProductRule,
|
||||
saveAdminWorkerLevel,
|
||||
submitAdminWorkOrderMaterial,
|
||||
syncAdminWorkerOrdersFromSource,
|
||||
unpublishAdminWorkOrder,
|
||||
updateAdminWorkOrderSharing,
|
||||
} from '@/services/admin'
|
||||
@@ -355,4 +354,3 @@ export default function WorkersPanel() {
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -199,18 +199,6 @@ export function createAdminMockWorkOrder(payload: {
|
||||
)
|
||||
}
|
||||
|
||||
export function syncAdminWorkerOrdersFromSource(payload: {
|
||||
platformOrderId?: string
|
||||
orderId?: number
|
||||
}) {
|
||||
return apiPost<{
|
||||
created: WorkOrder[]
|
||||
skipped: Array<{ orderItemId: number; reason: string }>
|
||||
createdCount: number
|
||||
skippedCount: number
|
||||
}>('/api/v1/admin/worker-platform/source-orders/sync', payload)
|
||||
}
|
||||
|
||||
export function submitAdminWorkOrderMaterial(
|
||||
workOrderId: number,
|
||||
fields: Record<string, string>,
|
||||
|
||||
@@ -1462,6 +1462,58 @@ select {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.worker-orders-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.worker-orders-search-controls {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.worker-orders-mock {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding-left: 24px;
|
||||
border-left: 1px solid #edf0f5;
|
||||
}
|
||||
|
||||
.worker-orders-mock > .ant-typography {
|
||||
flex: 0 0 auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.worker-order-mock-form {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px 12px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.worker-order-mock-form .ant-form-item {
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.worker-order-mock-field-order .ant-input {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.worker-order-mock-field-product .ant-input {
|
||||
width: 190px;
|
||||
}
|
||||
|
||||
.worker-order-mock-field-amount .ant-input-number {
|
||||
width: 116px;
|
||||
}
|
||||
|
||||
.worker-order-detail-stack {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
@@ -1728,6 +1780,19 @@ select {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.worker-orders-toolbar {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.worker-orders-mock {
|
||||
padding-top: 12px;
|
||||
padding-left: 0;
|
||||
border-top: 1px solid #edf0f5;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.kuaishou-industry-split {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user