优化多账号选择
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { query } from '../db/client.js'
|
||||
import { TASK_STATUS } from '../domain/task-status.js'
|
||||
import { maskCode } from '../utils/masking.js'
|
||||
import { parseTaskContext } from '../utils/task-json.js'
|
||||
import { normalizeTimestampIso } from '../utils/time.js'
|
||||
@@ -6,6 +7,12 @@ import { normalizeTimestampIso } from '../utils/time.js'
|
||||
type QueryExecutor = (text: string, params?: unknown[]) => Promise<{ rows: unknown[] }>
|
||||
type JsonRecord = Record<string, any>
|
||||
|
||||
export type KuaishouCloudSourceLoadStat = {
|
||||
sourceKey: string
|
||||
activeCount: number
|
||||
redeemingCount: number
|
||||
}
|
||||
|
||||
export type KuaishouCloudTaskStateSyncInput = {
|
||||
taskId: number | string
|
||||
executorKey?: unknown
|
||||
@@ -86,6 +93,49 @@ export async function syncKuaishouCloudTaskStateForTask(
|
||||
)
|
||||
}
|
||||
|
||||
export async function listKuaishouCloudSourceLoadStats(
|
||||
sourceKeys: unknown[] = [],
|
||||
executor: QueryExecutor = query,
|
||||
): Promise<KuaishouCloudSourceLoadStat[]> {
|
||||
const candidates = normalizeStringArray(sourceKeys)
|
||||
if (candidates.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
const activeStatuses = [
|
||||
TASK_STATUS.WAITING_BINDING,
|
||||
TASK_STATUS.ROLE_CONFIRMED,
|
||||
TASK_STATUS.REDEEMING,
|
||||
TASK_STATUS.DISPATCHED_PENDING_RETURN,
|
||||
]
|
||||
const result = await executor(
|
||||
`
|
||||
SELECT
|
||||
kcts.source_key,
|
||||
COUNT(*) FILTER (WHERE ft.task_status = ANY($2::text[])) AS active_count,
|
||||
COUNT(*) FILTER (WHERE ft.task_status = $3) AS redeeming_count
|
||||
FROM fulfillment_tasks ft
|
||||
JOIN kuaishou_cloud_task_states kcts ON kcts.task_id = ft.id
|
||||
WHERE ft.executor_key = 'kuaishou_ct_assisted'
|
||||
AND kcts.source_key = ANY($1::text[])
|
||||
AND ft.task_status = ANY($2::text[])
|
||||
GROUP BY kcts.source_key
|
||||
`,
|
||||
[candidates, activeStatuses, TASK_STATUS.REDEEMING],
|
||||
)
|
||||
|
||||
return result.rows
|
||||
.map((row) => {
|
||||
const source = asRecord(row)
|
||||
return {
|
||||
sourceKey: String(source.source_key || '').trim(),
|
||||
activeCount: Number(source.active_count || 0) || 0,
|
||||
redeemingCount: Number(source.redeeming_count || 0) || 0,
|
||||
}
|
||||
})
|
||||
.filter((row) => row.sourceKey)
|
||||
}
|
||||
|
||||
function resolveKuaishouCloudFlow(contextJson: unknown): JsonRecord | null {
|
||||
const context = parseTaskContext({ context_json: contextJson })
|
||||
const flow = asRecord(context.kuaishouCloudFulfillment)
|
||||
@@ -93,13 +143,32 @@ function resolveKuaishouCloudFlow(contextJson: unknown): JsonRecord | null {
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): JsonRecord {
|
||||
return value && typeof value === 'object' && !Array.isArray(value) ? value as JsonRecord : {}
|
||||
return value && typeof value === 'object' && !Array.isArray(value) ? (value as JsonRecord) : {}
|
||||
}
|
||||
|
||||
function normalizeStatus(value: unknown): string {
|
||||
return String(value || 'pending').trim() || 'pending'
|
||||
}
|
||||
|
||||
function normalizeStringArray(value: unknown): string[] {
|
||||
if (Array.isArray(value)) {
|
||||
return Array.from(new Set(value.map((item) => String(item || '').trim()).filter(Boolean)))
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
return Array.from(
|
||||
new Set(
|
||||
value
|
||||
.split(',')
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
function pickFirstNonEmpty(values: unknown[]): string {
|
||||
for (const value of values) {
|
||||
const normalized = String(value || '').trim()
|
||||
|
||||
Reference in New Issue
Block a user