优化任务账号名称展示
This commit is contained in:
@@ -4,6 +4,7 @@ import { listOrderItemsByOrderId } from '../../repositories/order-item-repo.js'
|
|||||||
import { getOrderById, listOrders } from '../../repositories/order-repo.js'
|
import { getOrderById, listOrders } from '../../repositories/order-repo.js'
|
||||||
import { getTaskById, listTasks, listTasksByOrderId } from '../../repositories/task-repo.js'
|
import { getTaskById, listTasks, listTasksByOrderId } from '../../repositories/task-repo.js'
|
||||||
import { listTaskEventsByTaskId } from '../../repositories/task-event-repo.js'
|
import { listTaskEventsByTaskId } from '../../repositories/task-event-repo.js'
|
||||||
|
import { listCloudtentaclesSources } from '../platforms/cloudtentacles/source-config-service.js'
|
||||||
import { createHttpError } from '../../utils/http.js'
|
import { createHttpError } from '../../utils/http.js'
|
||||||
import { formatFenToAmount, normalizeFen } from '../../utils/money.js'
|
import { formatFenToAmount, normalizeFen } from '../../utils/money.js'
|
||||||
import { normalizeDateQuery, normalizePage, normalizePageSize, safeParseJson } from './admin-query-utils.js'
|
import { normalizeDateQuery, normalizePage, normalizePageSize, safeParseJson } from './admin-query-utils.js'
|
||||||
@@ -171,7 +172,10 @@ export async function getAdminTaskDetail(
|
|||||||
const viewerContext = createAdminViewerContext(session)
|
const viewerContext = createAdminViewerContext(session)
|
||||||
const claimUrl = claimToken ? buildClaimUrl(claimToken.token) : ''
|
const claimUrl = claimToken ? buildClaimUrl(claimToken.token) : ''
|
||||||
const screenshotUrl = await resolveAdminTaskScreenshotUrl(task, viewerContext)
|
const screenshotUrl = await resolveAdminTaskScreenshotUrl(task, viewerContext)
|
||||||
const kuaishouCloudFulfillment = mapKuaishouCloudFulfillmentContext(taskContext.kuaishouCloudFulfillment)
|
const kuaishouCloudFulfillment = mapKuaishouCloudFulfillmentContext(
|
||||||
|
taskContext.kuaishouCloudFulfillment,
|
||||||
|
{ cloudSourceLabelMap: buildCloudSourceLabelMap() },
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
task: mapAdminTaskListItem({
|
task: mapAdminTaskListItem({
|
||||||
@@ -248,6 +252,20 @@ export async function getAdminTaskDetail(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildCloudSourceLabelMap() {
|
||||||
|
const labelMap = new Map<string, string>()
|
||||||
|
|
||||||
|
for (const source of listCloudtentaclesSources().sources) {
|
||||||
|
const key = String(source.key || '').trim()
|
||||||
|
if (!key) continue
|
||||||
|
|
||||||
|
const label = String(source.label || source.username || key).trim() || key
|
||||||
|
labelMap.set(key, label)
|
||||||
|
}
|
||||||
|
|
||||||
|
return labelMap
|
||||||
|
}
|
||||||
|
|
||||||
export async function getAdminTaskScreenshotPath(
|
export async function getAdminTaskScreenshotPath(
|
||||||
taskId: AdminEntityIdInput,
|
taskId: AdminEntityIdInput,
|
||||||
session: AdminViewerSessionInput | null = null,
|
session: AdminViewerSessionInput | null = null,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import assert from 'node:assert/strict'
|
|||||||
import {
|
import {
|
||||||
canViewerCloseTask,
|
canViewerCloseTask,
|
||||||
createAdminViewerContext,
|
createAdminViewerContext,
|
||||||
|
mapKuaishouCloudFulfillmentContext,
|
||||||
resolveAdminTaskScreenshotUrl,
|
resolveAdminTaskScreenshotUrl,
|
||||||
} from './admin-read-shared-helpers.js'
|
} from './admin-read-shared-helpers.js'
|
||||||
|
|
||||||
@@ -37,3 +38,24 @@ test('canViewerCloseTask allows support to close active task but not redeemed ta
|
|||||||
assert.equal(canViewerCloseTask({ task_status: 'link_generated' }, viewerContext), true)
|
assert.equal(canViewerCloseTask({ task_status: 'link_generated' }, viewerContext), true)
|
||||||
assert.equal(canViewerCloseTask({ task_status: 'redeemed' }, viewerContext), false)
|
assert.equal(canViewerCloseTask({ task_status: 'redeemed' }, viewerContext), false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('mapKuaishouCloudFulfillmentContext exposes cloud account display labels', () => {
|
||||||
|
const flow = mapKuaishouCloudFulfillmentContext(
|
||||||
|
{
|
||||||
|
binding: {
|
||||||
|
cloudSourceKeys: [' account_a ', 'account_b'],
|
||||||
|
resolvedSourceKey: 'account_b',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cloudSourceLabelMap: new Map([
|
||||||
|
['account_a', '白班账号'],
|
||||||
|
['account_b', '夜班账号'],
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.deepEqual(flow?.binding.cloudSourceKeys, ['account_a', 'account_b'])
|
||||||
|
assert.deepEqual(flow?.binding.cloudSourceLabels, ['白班账号', '夜班账号'])
|
||||||
|
assert.equal(flow?.binding.resolvedSourceLabel, '夜班账号')
|
||||||
|
})
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ import type { AdminViewerSessionInput } from '../../types/admin/read-inputs.js'
|
|||||||
import type { OrderItemRow, TaskRow } from '../../types/repository/rows.js'
|
import type { OrderItemRow, TaskRow } from '../../types/repository/rows.js'
|
||||||
|
|
||||||
type JsonRecord = Record<string, any>
|
type JsonRecord = Record<string, any>
|
||||||
|
type CloudSourceLabelMap = Map<string, string> | Record<string, string>
|
||||||
|
|
||||||
|
type KuaishouCloudFulfillmentMapOptions = {
|
||||||
|
cloudSourceLabelMap?: CloudSourceLabelMap
|
||||||
|
}
|
||||||
|
|
||||||
type TaskLike = Partial<TaskRow> & {
|
type TaskLike = Partial<TaskRow> & {
|
||||||
state_json?: string | JsonRecord
|
state_json?: string | JsonRecord
|
||||||
@@ -55,7 +60,10 @@ export function mapManualDispatchContext(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapKuaishouCloudFulfillmentContext(value: unknown): JsonRecord | null {
|
export function mapKuaishouCloudFulfillmentContext(
|
||||||
|
value: unknown,
|
||||||
|
options: KuaishouCloudFulfillmentMapOptions = {},
|
||||||
|
): JsonRecord | null {
|
||||||
if (!value || typeof value !== 'object') {
|
if (!value || typeof value !== 'object') {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -68,6 +76,10 @@ export function mapKuaishouCloudFulfillmentContext(value: unknown): JsonRecord |
|
|||||||
const dispatch = record.dispatch && typeof record.dispatch === 'object' ? record.dispatch : {}
|
const dispatch = record.dispatch && typeof record.dispatch === 'object' ? record.dispatch : {}
|
||||||
const returnNumber = record.returnNumber && typeof record.returnNumber === 'object' ? record.returnNumber : {}
|
const returnNumber = record.returnNumber && typeof record.returnNumber === 'object' ? record.returnNumber : {}
|
||||||
const consume = record.consume && typeof record.consume === 'object' ? record.consume : {}
|
const consume = record.consume && typeof record.consume === 'object' ? record.consume : {}
|
||||||
|
const cloudSourceKeys = Array.isArray(binding.cloudSourceKeys)
|
||||||
|
? binding.cloudSourceKeys.map((value: unknown) => String(value || '').trim()).filter(Boolean)
|
||||||
|
: []
|
||||||
|
const resolvedSourceKey = String(binding.resolvedSourceKey || '').trim()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
flowType: String(record.flowType || '').trim(),
|
flowType: String(record.flowType || '').trim(),
|
||||||
@@ -84,10 +96,14 @@ export function mapKuaishouCloudFulfillmentContext(value: unknown): JsonRecord |
|
|||||||
},
|
},
|
||||||
binding: {
|
binding: {
|
||||||
prepareStatus: String(binding.prepareStatus || 'pending').trim() || 'pending',
|
prepareStatus: String(binding.prepareStatus || 'pending').trim() || 'pending',
|
||||||
cloudSourceKeys: Array.isArray(binding.cloudSourceKeys)
|
cloudSourceKeys,
|
||||||
? binding.cloudSourceKeys.map((value: unknown) => String(value || '').trim()).filter(Boolean)
|
cloudSourceLabels: cloudSourceKeys.map((sourceKey: string) =>
|
||||||
: [],
|
resolveCloudSourceLabel(sourceKey, options.cloudSourceLabelMap),
|
||||||
resolvedSourceKey: String(binding.resolvedSourceKey || '').trim(),
|
),
|
||||||
|
resolvedSourceKey,
|
||||||
|
resolvedSourceLabel: resolvedSourceKey
|
||||||
|
? resolveCloudSourceLabel(resolvedSourceKey, options.cloudSourceLabelMap)
|
||||||
|
: '',
|
||||||
skuId: Number(binding.skuId || 0) || 0,
|
skuId: Number(binding.skuId || 0) || 0,
|
||||||
skuName: String(binding.skuName || '').trim(),
|
skuName: String(binding.skuName || '').trim(),
|
||||||
vnKey: String(binding.vnKey || '').trim(),
|
vnKey: String(binding.vnKey || '').trim(),
|
||||||
@@ -140,6 +156,17 @@ export function mapKuaishouCloudFulfillmentContext(value: unknown): JsonRecord |
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveCloudSourceLabel(sourceKey: string, labelMap: CloudSourceLabelMap | undefined) {
|
||||||
|
const key = String(sourceKey || '').trim()
|
||||||
|
if (!key) return ''
|
||||||
|
|
||||||
|
const label = labelMap instanceof Map
|
||||||
|
? labelMap.get(key)
|
||||||
|
: labelMap?.[key]
|
||||||
|
|
||||||
|
return String(label || key).trim() || key
|
||||||
|
}
|
||||||
|
|
||||||
export function mapRedeemResolutionContext(value: unknown): JsonRecord | null {
|
export function mapRedeemResolutionContext(value: unknown): JsonRecord | null {
|
||||||
if (!value || typeof value !== 'object') {
|
if (!value || typeof value !== 'object') {
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -127,7 +127,9 @@ export interface AdminTaskDetail {
|
|||||||
binding: {
|
binding: {
|
||||||
prepareStatus: string
|
prepareStatus: string
|
||||||
cloudSourceKeys: string[]
|
cloudSourceKeys: string[]
|
||||||
|
cloudSourceLabels: string[]
|
||||||
resolvedSourceKey: string
|
resolvedSourceKey: string
|
||||||
|
resolvedSourceLabel: string
|
||||||
skuId: number
|
skuId: number
|
||||||
skuName: string
|
skuName: string
|
||||||
vnKey: string
|
vnKey: string
|
||||||
|
|||||||
@@ -34,6 +34,30 @@ const emit = defineEmits<{
|
|||||||
copyBindUrl: [url: string]
|
copyBindUrl: [url: string]
|
||||||
openBindUrl: [url: string]
|
openBindUrl: [url: string]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
function formatCloudSourcePriority(flow: KuaishouCloudFlow) {
|
||||||
|
return formatAccountNames(flow.binding.cloudSourceLabels, flow.binding.cloudSourceKeys)
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatResolvedCloudSource(flow: KuaishouCloudFlow) {
|
||||||
|
return flow.binding.resolvedSourceLabel || flow.binding.resolvedSourceKey || '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatAccountNames(labels: string[] | undefined, keys: string[] | undefined) {
|
||||||
|
const displayNames = Array.isArray(labels)
|
||||||
|
? labels.map((value) => String(value || '').trim()).filter(Boolean)
|
||||||
|
: []
|
||||||
|
|
||||||
|
if (displayNames.length > 0) {
|
||||||
|
return displayNames.join(' / ')
|
||||||
|
}
|
||||||
|
|
||||||
|
const fallbackKeys = Array.isArray(keys)
|
||||||
|
? keys.map((value) => String(value || '').trim()).filter(Boolean)
|
||||||
|
: []
|
||||||
|
|
||||||
|
return fallbackKeys.length > 0 ? fallbackKeys.join(' / ') : '-'
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -222,13 +246,11 @@ const emit = defineEmits<{
|
|||||||
<div class="flow-meta-list flow-meta-list--two-column">
|
<div class="flow-meta-list flow-meta-list--two-column">
|
||||||
<div>
|
<div>
|
||||||
<span>账号优先级</span>
|
<span>账号优先级</span>
|
||||||
<strong>{{
|
<strong>{{ formatCloudSourcePriority(flow) }}</strong>
|
||||||
flow.binding.cloudSourceKeys?.length ? flow.binding.cloudSourceKeys.join(' / ') : '-'
|
|
||||||
}}</strong>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>实际使用账号</span>
|
<span>实际使用账号</span>
|
||||||
<strong>{{ flow.binding.resolvedSourceKey || '-' }}</strong>
|
<strong>{{ formatResolvedCloudSource(flow) }}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>cloud SKU</span>
|
<span>cloud SKU</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user