diff --git a/apps/backend/src/repositories/worker-platform-repo.test.ts b/apps/backend/src/repositories/worker-platform-repo.test.ts
index 90c07db8..9fb00175 100644
--- a/apps/backend/src/repositories/worker-platform-repo.test.ts
+++ b/apps/backend/src/repositories/worker-platform-repo.test.ts
@@ -2,6 +2,7 @@ import assert from 'node:assert/strict'
import test from 'node:test'
import {
+ buildWorkOrderWhere,
resolveOutstandingDepositAmount,
shouldApplyAutomaticWorkerLevel,
} from './worker-platform/index.js'
@@ -58,3 +59,29 @@ test('automatic worker level changes only move to a higher threshold', () => {
false,
)
})
+
+test('指定打手的运营状态统计保留可见范围和拼单汇总关联', () => {
+ const query = buildWorkOrderWhere({
+ workerSharingId: 3,
+ useOperationalStatus: true,
+ })
+
+ assert.match(query.joins, /worker_visible/)
+ assert.match(query.joins, /operational_share_summary/)
+ assert.match(query.joins, /LEFT JOIN LATERAL/)
+ assert.ok(
+ query.joins.indexOf('worker_visible') < query.joins.indexOf('operational_share_summary'),
+ )
+ assert.deepEqual(query.params, [3])
+})
+
+test('未指定打手的运营状态统计使用一次全表拼单汇总', () => {
+ const query = buildWorkOrderWhere({ useOperationalStatus: true })
+
+ assert.match(query.joins, /GROUP BY wos\.work_order_id/)
+ assert.match(
+ query.joins,
+ /operational_share_summary ON operational_share_summary\.work_order_id = wo\.id/,
+ )
+ assert.doesNotMatch(query.joins, /worker_visible/)
+})
diff --git a/apps/backend/src/repositories/worker-platform/work-order-repo.ts b/apps/backend/src/repositories/worker-platform/work-order-repo.ts
index 606fe5b6..d9d1c962 100644
--- a/apps/backend/src/repositories/worker-platform/work-order-repo.ts
+++ b/apps/backend/src/repositories/worker-platform/work-order-repo.ts
@@ -4371,7 +4371,7 @@ async function getWorkOrderByIdWithClient(
return result.rows[0] || null
}
-function buildWorkOrderWhere({
+export function buildWorkOrderWhere({
statuses = [],
workOrderId = 0,
keyword = '',
@@ -4386,30 +4386,18 @@ function buildWorkOrderWhere({
}: ListInput) {
const filters: string[] = []
const params: unknown[] = []
- let joins = ''
+ const joins: string[] = []
let workerSharePlaceholder = ''
- if (useOperationalStatus) {
- joins += `
- LEFT JOIN (
- SELECT
- wos.work_order_id,
- SUM(wos.quantity) FILTER (WHERE wos.status != 'cancelled') AS active_share_quantity,
- COUNT(*) FILTER (WHERE wos.status = 'joined') AS pending_share_count
- FROM work_order_shares wos
- GROUP BY wos.work_order_id
- ) operational_share_summary ON operational_share_summary.work_order_id = wo.id`
- }
-
if (excludeFilledSharing) {
- joins += `
+ joins.push(`
LEFT JOIN (
SELECT
wos.work_order_id,
SUM(wos.quantity) FILTER (WHERE wos.status != 'cancelled') AS active_share_quantity
FROM work_order_shares wos
GROUP BY wos.work_order_id
- ) filter_share_summary ON filter_share_summary.work_order_id = wo.id`
+ ) filter_share_summary ON filter_share_summary.work_order_id = wo.id`)
}
// 先从打手的整单、历史单和拼单记录组成可见工单集合,再关联工单详情。
@@ -4417,7 +4405,7 @@ function buildWorkOrderWhere({
if (workerSharingId) {
params.push(workerSharingId)
workerSharePlaceholder = `$${params.length}`
- joins = `
+ joins.push(`
INNER JOIN (
SELECT assigned.id AS work_order_id
FROM work_orders assigned
@@ -4443,7 +4431,32 @@ function buildWorkOrderWhere({
) worker_visible ON worker_visible.work_order_id = wo.id
LEFT JOIN work_order_shares worker_share
ON worker_share.work_order_id = wo.id
- AND worker_share.worker_id = ${workerSharePlaceholder}`
+ AND worker_share.worker_id = ${workerSharePlaceholder}`)
+ }
+
+ if (useOperationalStatus) {
+ if (workerSharingId) {
+ // 已限定打手时只汇总其候选工单,利用 work_order_id 索引避免扫描整张拼单表。
+ joins.push(`
+ LEFT JOIN LATERAL (
+ SELECT
+ SUM(wos.quantity) FILTER (WHERE wos.status != 'cancelled') AS active_share_quantity,
+ COUNT(*) FILTER (WHERE wos.status = 'joined') AS pending_share_count
+ FROM work_order_shares wos
+ WHERE wos.work_order_id = wo.id
+ ) operational_share_summary ON TRUE`)
+ } else {
+ // 无打手范围时一次聚合全部拼单,避免对每笔工单重复执行关联子查询。
+ joins.push(`
+ LEFT JOIN (
+ SELECT
+ wos.work_order_id,
+ SUM(wos.quantity) FILTER (WHERE wos.status != 'cancelled') AS active_share_quantity,
+ COUNT(*) FILTER (WHERE wos.status = 'joined') AS pending_share_count
+ FROM work_order_shares wos
+ GROUP BY wos.work_order_id
+ ) operational_share_summary ON operational_share_summary.work_order_id = wo.id`)
+ }
}
const normalizedStatuses = [
...new Set(statuses.map((item) => String(item || '').trim()).filter(Boolean)),
@@ -4529,7 +4542,7 @@ function buildWorkOrderWhere({
)`)
}
return {
- joins,
+ joins: joins.join('\n'),
whereClause: filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '',
params,
}
diff --git a/apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx b/apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx
index 9ca46fd9..b46bb6f7 100644
--- a/apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx
+++ b/apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx
@@ -1091,6 +1091,14 @@ export default function WorkOrdersPanel() {
{canViewStatistics ? (
) : null}
+ {ordersQuery.isError ? (
+
+ ) : null}