Files
Genarrative/src/components/custom-world-agent/CustomWorldAgentOperationBanner.tsx
高物 75944b1f1f
Some checks failed
CI / verify (push) Has been cancelled
1
2026-04-20 21:06:48 +08:00

79 lines
2.5 KiB
TypeScript

import { useEffect, useState } from 'react';
import type { CustomWorldAgentOperationRecord } from '../../../packages/shared/src/contracts/customWorldAgent';
type CustomWorldAgentOperationBannerProps = {
operation: CustomWorldAgentOperationRecord | null;
};
export function CustomWorldAgentOperationBanner({
operation,
}: CustomWorldAgentOperationBannerProps) {
const [visibleOperation, setVisibleOperation] =
useState<CustomWorldAgentOperationRecord | null>(operation);
useEffect(() => {
setVisibleOperation(operation);
if (operation?.status !== 'completed') {
return;
}
const timeoutId = window.setTimeout(() => {
setVisibleOperation((current) =>
current?.operationId === operation.operationId ? null : current,
);
}, 1200);
return () => window.clearTimeout(timeoutId);
}, [operation]);
if (!visibleOperation) {
return null;
}
const isFailed = visibleOperation.status === 'failed';
const isRunning =
visibleOperation.status === 'running' || visibleOperation.status === 'queued';
// 操作横幅直接复用平台状态横幅,亮暗主题都从同一套 token 取色。
const bannerToneClass = isFailed
? 'platform-banner--danger'
: isRunning
? 'platform-banner--info'
: 'platform-banner--success';
const progressFillStyle = isFailed
? { background: 'linear-gradient(90deg, #fb7185 0%, #f43f5e 100%)' }
: isRunning
? { background: 'var(--platform-button-primary-fill)' }
: { background: 'linear-gradient(90deg, #86efac 0%, #34d399 100%)' };
return (
<div
className={`platform-remap-surface platform-banner rounded-[1.4rem] px-4 py-4 ${bannerToneClass}`}
>
<div className="flex items-center justify-between gap-3">
<div className="text-sm font-semibold">
{visibleOperation.phaseLabel}
</div>
<div className="text-xs opacity-80">
{Math.max(0, Math.min(100, Math.round(visibleOperation.progress)))}%
</div>
</div>
{visibleOperation.error ? (
<div className="mt-2 text-sm opacity-90">
{visibleOperation.error}
</div>
) : null}
<div className="platform-progress-track mt-3 h-2 overflow-hidden rounded-full">
<div
className="h-full rounded-full transition-[width] duration-300"
style={{
width: `${Math.max(8, Math.min(100, visibleOperation.progress))}%`,
...progressFillStyle,
}}
/>
</div>
</div>
);
}