后端迁移后台管理任务读辅助
This commit is contained in:
+102
-43
@@ -1,5 +1,3 @@
|
||||
// @ts-check
|
||||
|
||||
import { getTaskById } from '../../repositories/task-repo.js'
|
||||
import { listTaskInventoryBindingSummariesByTaskIds } from '../../repositories/task-inventory-binding-repo.js'
|
||||
import { createHttpError } from '../../utils/http.js'
|
||||
@@ -11,13 +9,60 @@ import {
|
||||
parseTaskContext,
|
||||
} from './admin-read-shared-helpers.js'
|
||||
|
||||
/** @typedef {import('../../types/admin-read-models.js').AdminTaskBindingSummary} AdminTaskBindingSummary */
|
||||
/** @typedef {import('../../types/admin-read-models.js').AdminTaskListItem} AdminTaskListItem */
|
||||
/** @typedef {import('../../types/repository-rows.js').TaskEventRow} TaskEventRow */
|
||||
/** @typedef {import('../../types/repository-rows.js').TaskInventoryBindingRow} TaskInventoryBindingRow */
|
||||
/** @typedef {import('../../types/repository-rows.js').TaskRow} TaskRow */
|
||||
import type {
|
||||
AdminAgisoAutoDeliveryStatus,
|
||||
AdminTaskBindingSummary,
|
||||
AdminTaskListItem,
|
||||
} from '../../types/admin-read-models.js'
|
||||
import type { AdminTaskActionPayload } from '../../types/admin-write-models.js'
|
||||
import type {
|
||||
OrderRow,
|
||||
TaskEventRow,
|
||||
TaskInventoryBindingRow,
|
||||
TaskInventoryBindingSummaryRow,
|
||||
TaskRow,
|
||||
} from '../../types/repository-rows.js'
|
||||
import type { AdminViewerContext } from './admin-read-shared-helpers.js'
|
||||
|
||||
export function mapAdminTaskSummary(task, bindingSummary = createEmptyTaskBindingSummary()) {
|
||||
type JsonRecord = Record<string, any>
|
||||
|
||||
type TaskBindingState = {
|
||||
systemBindingStatus: string
|
||||
userBindingStatus: string
|
||||
}
|
||||
|
||||
type TaskInventoryBindingLike = TaskInventoryBindingRow & {
|
||||
inventory_item_status?: string
|
||||
}
|
||||
|
||||
type OrderBindingSummary = {
|
||||
totalTaskCount: number
|
||||
systemBoundTaskCount: number
|
||||
completedBindingTaskCount: number
|
||||
totalBindingCount: number
|
||||
reservedBindingCount: number
|
||||
consumedBindingCount: number
|
||||
releasedBindingCount: number
|
||||
systemBindingStatus: string
|
||||
userBindingStatus: string
|
||||
}
|
||||
|
||||
type OrderAgisoAutoDeliverySummary = AdminAgisoAutoDeliveryStatus & {
|
||||
sourceTaskId: number | null
|
||||
sourceTaskNo: string
|
||||
totalTaskCount: number
|
||||
deliveredTaskCount: number
|
||||
}
|
||||
|
||||
type OrderAgisoAutoDeliveryCandidate = AdminAgisoAutoDeliveryStatus & {
|
||||
sourceTaskId: number | null
|
||||
sourceTaskNo: string
|
||||
}
|
||||
|
||||
export function mapAdminTaskSummary(
|
||||
task: TaskRow,
|
||||
bindingSummary: AdminTaskBindingSummary = createEmptyTaskBindingSummary(),
|
||||
): JsonRecord {
|
||||
const binding = buildTaskBindingState(task)
|
||||
const taskContext = parseTaskContext(task)
|
||||
|
||||
@@ -42,7 +87,7 @@ export function mapAdminTaskSummary(task, bindingSummary = createEmptyTaskBindin
|
||||
}
|
||||
}
|
||||
|
||||
export function mapTaskActionPayload(task) {
|
||||
export function mapTaskActionPayload(task: any): AdminTaskActionPayload {
|
||||
const inventoryItemId = getTaskPrimaryInventoryItemId(task)
|
||||
const primaryClaimTokenId = getTaskPrimaryClaimTokenId(task)
|
||||
|
||||
@@ -60,7 +105,7 @@ export function mapTaskActionPayload(task) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getRequiredTask(taskId) {
|
||||
export async function getRequiredTask(taskId: number | string): Promise<TaskRow> {
|
||||
const task = await getTaskById(Number(taskId))
|
||||
|
||||
if (!task) {
|
||||
@@ -73,11 +118,11 @@ export async function getRequiredTask(taskId) {
|
||||
return task
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TaskRow} task
|
||||
* @returns {AdminTaskListItem}
|
||||
*/
|
||||
export function mapAdminTaskListItem(task, bindingSummary = createEmptyTaskBindingSummary(), viewerContext = createAdminViewerContext()) {
|
||||
export function mapAdminTaskListItem(
|
||||
task: TaskRow,
|
||||
bindingSummary: AdminTaskBindingSummary = createEmptyTaskBindingSummary(),
|
||||
viewerContext: AdminViewerContext = createAdminViewerContext(),
|
||||
): AdminTaskListItem {
|
||||
const binding = buildTaskBindingState(task)
|
||||
const taskContext = parseTaskContext(task)
|
||||
|
||||
@@ -114,8 +159,7 @@ export function mapAdminTaskListItem(task, bindingSummary = createEmptyTaskBindi
|
||||
}
|
||||
}
|
||||
|
||||
/** @param {TaskEventRow} event */
|
||||
export function mapAdminTaskEvent(event) {
|
||||
export function mapAdminTaskEvent(event: TaskEventRow): JsonRecord {
|
||||
const payload = safeParseJson(event.payload_json)
|
||||
|
||||
return {
|
||||
@@ -126,8 +170,7 @@ export function mapAdminTaskEvent(event) {
|
||||
}
|
||||
}
|
||||
|
||||
/** @returns {AdminTaskBindingSummary} */
|
||||
export function createEmptyTaskBindingSummary() {
|
||||
export function createEmptyTaskBindingSummary(): AdminTaskBindingSummary {
|
||||
return {
|
||||
totalBindingCount: 0,
|
||||
reservedBindingCount: 0,
|
||||
@@ -137,11 +180,11 @@ export function createEmptyTaskBindingSummary() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getTaskBindingSummaryMap(taskIds = []) {
|
||||
export async function getTaskBindingSummaryMap(taskIds: Array<number | string> = []): Promise<Map<number, AdminTaskBindingSummary>> {
|
||||
const rows = await listTaskInventoryBindingSummariesByTaskIds(taskIds)
|
||||
const output = new Map()
|
||||
const output = new Map<number, AdminTaskBindingSummary>()
|
||||
|
||||
for (const row of rows) {
|
||||
for (const row of rows as TaskInventoryBindingSummaryRow[]) {
|
||||
output.set(Number(row.task_id), {
|
||||
totalBindingCount: Number(row.total_binding_count || 0),
|
||||
reservedBindingCount: Number(row.reserved_binding_count || 0),
|
||||
@@ -156,11 +199,16 @@ export async function getTaskBindingSummaryMap(taskIds = []) {
|
||||
return output
|
||||
}
|
||||
|
||||
export function getTaskBindingSummary(summaryMap, taskId) {
|
||||
export function getTaskBindingSummary(
|
||||
summaryMap: Map<number, AdminTaskBindingSummary>,
|
||||
taskId: number | string,
|
||||
): AdminTaskBindingSummary {
|
||||
return summaryMap.get(Number(taskId)) || createEmptyTaskBindingSummary()
|
||||
}
|
||||
|
||||
export function createTaskBindingSummaryFromBindings(bindings = []) {
|
||||
export function createTaskBindingSummaryFromBindings(
|
||||
bindings: Array<Partial<TaskInventoryBindingRow>> | null | undefined = [],
|
||||
): AdminTaskBindingSummary {
|
||||
const normalizedBindings = Array.isArray(bindings) ? bindings : []
|
||||
const roleKeys = Array.from(new Set(normalizedBindings
|
||||
.map((binding) => String(binding?.role_key || '').trim())
|
||||
@@ -175,7 +223,11 @@ export function createTaskBindingSummaryFromBindings(bindings = []) {
|
||||
}
|
||||
}
|
||||
|
||||
export function mapAdminTaskInventoryBinding(binding, task, viewerContext = createAdminViewerContext()) {
|
||||
export function mapAdminTaskInventoryBinding(
|
||||
binding: TaskInventoryBindingLike,
|
||||
task: TaskRow,
|
||||
viewerContext: AdminViewerContext = createAdminViewerContext(),
|
||||
): JsonRecord {
|
||||
const metadata = safeParseJson(binding.metadata_json)
|
||||
|
||||
return {
|
||||
@@ -200,7 +252,10 @@ export function mapAdminTaskInventoryBinding(binding, task, viewerContext = crea
|
||||
}
|
||||
}
|
||||
|
||||
export function buildOrderBindingSummary(tasks, taskBindingSummaryMap = new Map()) {
|
||||
export function buildOrderBindingSummary(
|
||||
tasks: TaskRow[] | null | undefined,
|
||||
taskBindingSummaryMap: Map<number, AdminTaskBindingSummary> = new Map(),
|
||||
): OrderBindingSummary {
|
||||
const normalizedTasks = Array.isArray(tasks) ? tasks : []
|
||||
const totalTaskCount = normalizedTasks.length
|
||||
const taskBindings = normalizedTasks.map((task) => buildTaskBindingState(task))
|
||||
@@ -260,7 +315,10 @@ export function buildOrderBindingSummary(tasks, taskBindingSummaryMap = new Map(
|
||||
}
|
||||
}
|
||||
|
||||
export function buildOrderAgisoAutoDeliverySummary(order, tasks = []) {
|
||||
export function buildOrderAgisoAutoDeliverySummary(
|
||||
order: Partial<OrderRow> | null | undefined,
|
||||
tasks: TaskRow[] = [],
|
||||
): OrderAgisoAutoDeliverySummary | null {
|
||||
if (String(order?.provider || '').trim() !== 'agiso' || String(order?.platform || '').trim() !== 'xianyu') {
|
||||
return null
|
||||
}
|
||||
@@ -268,7 +326,7 @@ export function buildOrderAgisoAutoDeliverySummary(order, tasks = []) {
|
||||
const normalizedTasks = Array.isArray(tasks) ? tasks.filter(Boolean) : []
|
||||
const totalTaskCount = normalizedTasks.length
|
||||
const deliveredTaskCount = normalizedTasks.filter((task) => String(task?.delivery_status || '').trim() === 'delivered').length
|
||||
const latest = normalizedTasks.reduce((best, task) => {
|
||||
const latest = normalizedTasks.reduce<OrderAgisoAutoDeliveryCandidate | null>((best, task) => {
|
||||
const autoDelivery = mapAgisoAutoDeliveryContext(parseTaskContext(task).agisoAutoDelivery)
|
||||
|
||||
if (!autoDelivery) {
|
||||
@@ -314,7 +372,7 @@ export function buildOrderAgisoAutoDeliverySummary(order, tasks = []) {
|
||||
}
|
||||
}
|
||||
|
||||
function canReleaseTaskInventoryBinding(task, binding) {
|
||||
function canReleaseTaskInventoryBinding(task: TaskRow | null | undefined, binding: TaskInventoryBindingLike | null | undefined): boolean {
|
||||
if (!task || !binding) {
|
||||
return false
|
||||
}
|
||||
@@ -326,7 +384,7 @@ function canReleaseTaskInventoryBinding(task, binding) {
|
||||
return !['redeemed', 'expired'].includes(String(task.task_status || '').trim())
|
||||
}
|
||||
|
||||
function buildTaskBindingState(task) {
|
||||
function buildTaskBindingState(task: TaskRow | null | undefined): TaskBindingState {
|
||||
const normalizedStatus = String(task?.task_status || '').trim()
|
||||
|
||||
if (!normalizedStatus) {
|
||||
@@ -407,32 +465,33 @@ function buildTaskBindingState(task) {
|
||||
return { systemBindingStatus: 'pending_binding', userBindingStatus: 'not_started' }
|
||||
}
|
||||
|
||||
function isTaskSystemBound(task) {
|
||||
function isTaskSystemBound(task: TaskRow | null | undefined): boolean {
|
||||
return Boolean(task && (getTaskPrimaryInventoryItemId(task) || getTaskPrimaryClaimTokenId(task)))
|
||||
}
|
||||
|
||||
function mapAgisoAutoDeliveryContext(value) {
|
||||
function mapAgisoAutoDeliveryContext(value: unknown): AdminAgisoAutoDeliveryStatus | null {
|
||||
if (!value || typeof value !== 'object') {
|
||||
return null
|
||||
}
|
||||
|
||||
const record = value as JsonRecord
|
||||
return {
|
||||
status: String(value.status || '').trim(),
|
||||
trigger: String(value.trigger || '').trim(),
|
||||
reason: String(value.reason || '').trim(),
|
||||
platformOrderId: String(value.platformOrderId || '').trim(),
|
||||
responseStatus: Number(value.responseStatus || 0),
|
||||
errorMessage: String(value.errorMessage || '').trim(),
|
||||
requestId: String(value.requestId || '').trim(),
|
||||
updatedAt: value.updatedAt || null,
|
||||
status: String(record.status || '').trim(),
|
||||
trigger: String(record.trigger || '').trim(),
|
||||
reason: String(record.reason || '').trim(),
|
||||
platformOrderId: String(record.platformOrderId || '').trim(),
|
||||
responseStatus: Number(record.responseStatus || 0),
|
||||
errorMessage: String(record.errorMessage || '').trim(),
|
||||
requestId: String(record.requestId || '').trim(),
|
||||
updatedAt: record.updatedAt || null,
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeRecord(value) {
|
||||
function normalizeRecord(value: unknown): JsonRecord {
|
||||
return value && typeof value === 'object' && !Array.isArray(value) ? value : {}
|
||||
}
|
||||
|
||||
function maskCode(value) {
|
||||
function maskCode(value: unknown): string {
|
||||
const text = String(value || '').trim()
|
||||
if (!text) {
|
||||
return ''
|
||||
@@ -443,6 +502,6 @@ function maskCode(value) {
|
||||
return `${text.slice(0, 4)}****${text.slice(-4)}`
|
||||
}
|
||||
|
||||
function getTaskRetryCount(task) {
|
||||
function getTaskRetryCount(task: TaskRow | null | undefined): number {
|
||||
return Number(task?.attempt_count || 0)
|
||||
}
|
||||
Reference in New Issue
Block a user