接单工单支持任务时限,超时自动判定失败并处置

This commit is contained in:
yml2213
2026-08-01 19:02:57 +08:00
parent 66193c5d59
commit 23ad60a1ef
18 changed files with 681 additions and 61 deletions
@@ -267,17 +267,22 @@ function NotificationPanel({
const [testResult, setTestResult] = useState<AdminNotificationTestResult | null>(null)
const source = notificationConfig.source
const monitorAccounts = scheduledJobs.cloudtentaclesAccounts || []
const jobsWithMergedAccounts = scheduledJobs.source.jobs.map((job) => ({
...job,
config: {
...job.config,
accounts: mergeScheduledJobAccounts(
job.config?.accounts || [],
monitorAccounts,
Number(job.config?.assetThreshold ?? 500),
),
},
}))
const jobsWithMergedAccounts = scheduledJobs.source.jobs.map((job) => {
if (job.type !== 'cloudtentacles_health') {
return job
}
return {
...job,
config: {
...job.config,
accounts: mergeScheduledJobAccounts(
job.config?.accounts || [],
monitorAccounts,
Number(job.config?.assetThreshold ?? 500),
),
},
}
})
async function saveNotification() {
setSavingNotification(true)
@@ -313,18 +318,23 @@ function NotificationPanel({
try {
const payload: AdminScheduledJobsConfig = {
...scheduledJobs.source,
jobs: jobsWithMergedAccounts.map((job) => ({
...job,
config: {
assetThreshold: Number(job.config?.assetThreshold ?? 500),
accounts: (job.config?.accounts || []).map((account) => ({
sourceKey: account.sourceKey,
label: account.label,
enabled: account.enabled !== false,
assetThreshold: Number(account.assetThreshold ?? job.config?.assetThreshold ?? 500),
})),
},
})),
jobs: jobsWithMergedAccounts.map((job) => {
if (job.type !== 'cloudtentacles_health') {
return { ...job }
}
return {
...job,
config: {
assetThreshold: Number(job.config?.assetThreshold ?? 500),
accounts: (job.config?.accounts || []).map((account) => ({
sourceKey: account.sourceKey,
label: account.label,
enabled: account.enabled !== false,
assetThreshold: Number(account.assetThreshold ?? job.config?.assetThreshold ?? 500),
})),
},
}
}),
}
const response = await saveAdminScheduledJobsConfig(payload)
onScheduledJobsChange(response.data)
@@ -587,6 +597,72 @@ function ScheduledJobCard({
onRun: () => void
onChange: (job: AdminScheduledJobItem) => void
}) {
if (job.type === 'work_order_timeout' || job.id === 'work-order-timeout') {
return (
<Card
size="small"
title={
<Space wrap>
<Switch
checked={job.enabled !== false}
onChange={(enabled) => onChange({ ...job, enabled })}
/>
<span>{formatScheduledJobTitle(job)}</span>
<Tag color={job.enabled ? 'green' : 'default'}>
{job.enabled ? '已启用' : '已停用'}
</Tag>
</Space>
}
extra={
<Button icon={<ReloadOutlined />} loading={running} onClick={onRun}>
</Button>
}
>
<Typography.Paragraph type="secondary" style={{ marginBottom: 12 }}>
退 / 退 /
</Typography.Paragraph>
<div className="platform-form-grid">
<NumberField
label="执行间隔(秒)"
value={job.intervalSeconds}
min={1}
onChange={(intervalSeconds) => onChange({ ...job, intervalSeconds })}
/>
<NumberField
label="每次扫描数量"
value={Number(job.config?.scanLimit ?? 50)}
min={1}
onChange={(scanLimit) =>
onChange({ ...job, config: { ...job.config, scanLimit } })
}
/>
</div>
{runtime ? (
<Alert
className="platform-section-gap"
type={
runtime.lastStatus === 'ok' || runtime.lastStatus === 'success'
? 'success'
: runtime.lastStatus
? 'warning'
: 'info'
}
showIcon
message={runtime.lastMessage || '尚未运行'}
description={[
`扫描 ${runtime.lastCheckedCount ?? 0}`,
`处置 ${runtime.lastAsset ?? 0}`,
`跳过 ${runtime.lastFailedCount ?? 0}`,
`上次:${formatAdminDateTime(runtime.lastFinishedAt || runtime.lastRunAt)}`,
`下次:${formatAdminDateTime(runtime.nextRunAt)}`,
].join(' · ')}
/>
) : null}
</Card>
)
}
const accounts = job.config?.accounts || []
const defaultThreshold = Number(job.config?.assetThreshold ?? 500)
@@ -812,6 +888,9 @@ function formatScheduledJobTitle(job: AdminScheduledJobItem) {
if (job.type === 'cloudtentacles_health' || job.id === 'cloudtentacles-health') {
return 'kuaishou-lewan 健康检查'
}
if (job.type === 'work_order_timeout' || job.id === 'work-order-timeout') {
return '接单工单超时扫描'
}
return job.id || job.type || '定时任务'
}