merge: integrate lightweight dashboard candidate queries

# Conflicts:
#	control-plane/src/task-service.ts
This commit is contained in:
inman committed 2026-09-09 18:54:16 +08:00
commit b11dc7b771
4 files changed
+181 -5

No files matched your search

+50 -5
View File
@@ -4786,12 +4786,25 @@ export class TaskService {
{ key: 'unclassified', label: '其他任务' }
];
const taskBaseSelect = `t.id, t.task_id, t.status, t.business_route_id, t.archived_at,
t.created_at, t.updated_at, t.operation,
t.created_at, t.updated_at,
assignee.id AS actor_id, assignee.username AS actor_username,
assignee.role AS actor_role, assignee.is_active AS actor_is_active,
to_char(timezone('Asia/Shanghai', t.created_at), 'YYYY-MM-DD') AS business_day`;
const taskLegacyOperationSelect = `jsonb_build_object(
'action', t.operation -> 'action',
'data', jsonb_build_object(
'existing_refs', jsonb_build_object(
'kind', t.operation #> '{data,existing_refs,kind}'
),
'target_kind', t.operation #> '{data,target_kind}',
'arrangement', jsonb_build_object(
'mode', t.operation #> '{data,arrangement,mode}'
),
'mode', t.operation #> '{data,mode}'
)
) AS operation`;
const taskDetailSelect = `${taskBaseSelect},
t.original_text_ciphertext, t.message, t.success_receipt, t.success_receipt_at,
t.operation, t.original_text_ciphertext, t.message, t.success_receipt, t.success_receipt_at,
t.error_summary, t.error_summary_at, t.execution_result, t.parse_response,
(SELECT COUNT(*)::int
FROM agent_session_messages input_message
@@ -4800,7 +4813,7 @@ export class TaskService {
AND input_message.role = 'user'
AND input_message.input_source IS DISTINCT FROM 'reparse') AS input_turn_count`;
const taskSearchSelect = `${taskBaseSelect},
t.original_text_ciphertext, t.message, t.success_receipt, t.success_receipt_at,
t.operation, t.original_text_ciphertext, t.message, t.success_receipt, t.success_receipt_at,
t.error_summary, t.error_summary_at,
CASE
WHEN t.status = 'completed'
@@ -4878,8 +4891,40 @@ export class TaskService {
[context.organizationId]
);
const candidateRows = candidateResult.rows as Record<string, unknown>[];
const projectedCandidates = candidateRows.flatMap((row) => {
const projection = operationsDashboardTaskProjection(this.config, row);
let projectedRows = candidateRows.map((row) => ({
row,
projection: operationsDashboardTaskProjection(this.config, row)
}));
if (!search) {
const unresolvedLegacyIds = projectedRows
.filter(({ projection }) => !projection.task.business_route_id)
.map(({ row }) => text(row.id))
.filter(Boolean);
if (unresolvedLegacyIds.length) {
const legacyOperationResult = await dashboardQuery(
'legacy_classification',
`SELECT t.id, ${taskLegacyOperationSelect}
FROM tasks t
WHERE t.organization_id = $1
AND t.id = ANY($2::uuid[])`,
[context.organizationId, unresolvedLegacyIds]
);
const legacyOperationById = new Map(
(legacyOperationResult.rows as Record<string, unknown>[])
.map((row) => [text(row.id), row.operation])
);
projectedRows = projectedRows.map(({ row, projection }) => {
const operation = legacyOperationById.get(text(row.id));
if (operation === undefined) return { row, projection };
const enrichedRow = { ...row, operation };
return {
row: enrichedRow,
projection: operationsDashboardTaskProjection(this.config, enrichedRow)
};
});
}
}
const projectedCandidates = projectedRows.flatMap(({ row, projection }) => {
const routeMatches = !businessRouteId
|| (businessRouteId === 'unclassified'
? !projection.task.business_route_id