fix: optimize agent style workspace rendering
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-05-20 16:05:33 +08:00
parent 31a697f491
commit 65b3e2f191
2 changed files with 77 additions and 16 deletions

View File

@ -9,6 +9,7 @@ import {
useMemo,
useRef,
useState,
type CSSProperties,
type ReactNode,
type SyntheticEvent,
} from "react";
@ -489,6 +490,16 @@ function buildPreviewImageUrl(url: string, width: number) {
return buildImageProxyUrl(url, { width, quality: 86, format: "webp" });
}
const AGENT_DEFERRED_SECTION_STYLE = {
contentVisibility: "auto",
containIntrinsicSize: "1px 760px",
} as CSSProperties;
const AGENT_DEFERRED_RESULTS_STYLE = {
contentVisibility: "auto",
containIntrinsicSize: "1px 900px",
} as CSSProperties;
function handlePreviewImageLoadError(
event: SyntheticEvent<HTMLImageElement, Event>,
originalUrl: string
@ -5381,6 +5392,8 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={buildPreviewImageUrl(attachment.url, 360)}
alt={attachment.name || slot.label}
loading="lazy"
decoding="async"
className="h-full w-full object-cover"
onError={(event) => handlePreviewImageLoadError(event, attachment.url)}
/>
@ -5527,9 +5540,8 @@ export function AgentGenerationWorkspaceDarkV2({
<div className="grid grid-cols-2 gap-3 lg:grid-cols-4">
{visibleAttachmentUploadSlots.map((slot, index) => {
return (
<motion.div
<div
key={slot.label}
whileHover={{ scale: 1.02 }}
className={cn(
"group relative aspect-square overflow-hidden rounded-[24px] transition-all",
attachments[index]
@ -5551,6 +5563,8 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={buildPreviewImageUrl(attachments[index]!.url, 256)}
alt={attachments[index]!.name || slot.label}
loading="lazy"
decoding="async"
className="h-full w-full object-cover"
onError={(event) =>
handlePreviewImageLoadError(event, attachments[index]!.url)
@ -5589,7 +5603,7 @@ export function AgentGenerationWorkspaceDarkV2({
{attachments[index] ? "更换" : "上传"}
</button>
</div>
</motion.div>
</div>
);
})}
</div>
@ -5677,10 +5691,15 @@ export function AgentGenerationWorkspaceDarkV2({
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.06 }}
className="rounded-[28px] border border-white/12 bg-white/[0.04] p-5 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]"
style={AGENT_DEFERRED_SECTION_STYLE}
>
<div className="space-y-6">
{hasBrandStoreStep ? (
<section id="agent-anchor-brand" className="scroll-mt-24 rounded-[24px] border border-white/10 bg-black/20 p-4">
<section
id="agent-anchor-brand"
className="scroll-mt-24 rounded-[24px] border border-white/10 bg-black/20 p-4"
style={AGENT_DEFERRED_SECTION_STYLE}
>
<div className="mb-4 flex flex-col gap-4 border-b border-white/10 pb-4 lg:flex-row lg:items-start lg:justify-between">
<div className="space-y-1">
<div className="flex items-center gap-2">
@ -5699,7 +5718,11 @@ export function AgentGenerationWorkspaceDarkV2({
) : null}
{hasWorkflowStyleStep ? (
<section id="agent-anchor-style" className="scroll-mt-24 rounded-[24px] border border-white/10 bg-black/20 p-5 md:p-6">
<section
id="agent-anchor-style"
className="scroll-mt-24 rounded-[24px] border border-white/10 bg-black/20 p-5 md:p-6"
style={AGENT_DEFERRED_SECTION_STYLE}
>
<div className="mb-5 space-y-1 border-b border-white/10 pb-5">
<div className="flex items-center gap-2">
<span className="rounded-full bg-emerald-500/18 px-2.5 py-1 text-[11px] font-semibold text-emerald-200">
@ -5721,7 +5744,11 @@ export function AgentGenerationWorkspaceDarkV2({
) : null}
{isBusinessModeStepEnabled ? (
<section id="agent-anchor-mode" className="scroll-mt-24 rounded-[24px] border border-white/10 bg-black/20 p-4">
<section
id="agent-anchor-mode"
className="scroll-mt-24 rounded-[24px] border border-white/10 bg-black/20 p-4"
style={AGENT_DEFERRED_SECTION_STYLE}
>
<div className="mb-4 space-y-1 border-b border-white/10 pb-4">
<div className="flex items-center gap-2">
<span className="rounded-full bg-emerald-500/18 px-2.5 py-1 text-[11px] font-semibold text-emerald-200">
@ -5776,6 +5803,8 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={mode.customSvgUrl}
alt={mode.title}
loading="lazy"
decoding="async"
className="h-7 w-7 object-contain"
/>
) : (
@ -5819,7 +5848,11 @@ export function AgentGenerationWorkspaceDarkV2({
) : null}
{hasMaterialStep ? (
<section id="agent-anchor-materials" className="scroll-mt-24 rounded-[24px] border border-white/10 bg-black/20 p-4">
<section
id="agent-anchor-materials"
className="scroll-mt-24 rounded-[24px] border border-white/10 bg-black/20 p-4"
style={AGENT_DEFERRED_SECTION_STYLE}
>
<div className="mb-4 space-y-1 border-b border-white/10 pb-4">
<div className="flex items-center gap-2">
<span className="rounded-full bg-emerald-500/18 px-2.5 py-1 text-[11px] font-semibold text-emerald-200">
@ -5835,7 +5868,11 @@ export function AgentGenerationWorkspaceDarkV2({
</section>
) : null}
<section id="agent-anchor-generate" className="scroll-mt-24 rounded-[24px] border border-white/10 bg-black/20 p-4">
<section
id="agent-anchor-generate"
className="scroll-mt-24 rounded-[24px] border border-white/10 bg-black/20 p-4"
style={AGENT_DEFERRED_SECTION_STYLE}
>
<div className="mb-4 space-y-1 border-b border-white/10 pb-4">
<div className="flex items-center gap-2">
<span className="rounded-full bg-emerald-500/18 px-2.5 py-1 text-[11px] font-semibold text-emerald-200">
@ -6162,6 +6199,7 @@ export function AgentGenerationWorkspaceDarkV2({
initial={{ opacity: 0, scale: 0.98 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: 0.08 }}
style={AGENT_DEFERRED_SECTION_STYLE}
>
<div className="border-b border-white/12 px-5 py-4">
<div className="flex flex-wrap items-start justify-between gap-3">
@ -6388,6 +6426,8 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={buildPreviewImageUrl(primaryPreviewUrl, 360)}
alt={candidate.sceneName || candidate.taskNo || candidate.productModel || "候选整套"}
loading="lazy"
decoding="async"
className="h-full w-full object-contain object-top transition-transform duration-500 group-hover:scale-[1.02]"
onError={(event) =>
handlePreviewImageLoadError(event, primaryPreviewUrl)
@ -6471,6 +6511,7 @@ export function AgentGenerationWorkspaceDarkV2({
initial={{ opacity: 0, scale: 0.98 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ delay: 0.12 }}
style={AGENT_DEFERRED_RESULTS_STYLE}
>
<div className="flex items-center justify-between border-b border-white/12 px-5 py-4">
<div>
@ -6657,6 +6698,8 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={buildPreviewImageUrl(attachment!.url, 400)}
alt={attachment!.name || `输入图 ${index + 1}`}
loading="lazy"
decoding="async"
className="h-full w-full object-cover"
onError={(event) =>
handlePreviewImageLoadError(event, attachment!.url)
@ -6685,6 +6728,8 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={buildPreviewImageUrl(selectedModelAttachment.url, 720)}
alt={selectedModelAttachment.name || "模特图"}
loading="lazy"
decoding="async"
className="h-full w-full object-cover"
onError={(event) =>
handlePreviewImageLoadError(event, selectedModelAttachment.url)
@ -6777,6 +6822,8 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={buildPreviewImageUrl(card.imageUrl, 720)}
alt={card.label}
loading="lazy"
decoding="async"
className="block h-auto w-full"
onError={(event) =>
handlePreviewImageLoadError(event, card.imageUrl || "")
@ -6866,6 +6913,8 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={buildPreviewImageUrl(card.resultUrl, 720)}
alt={`结果图 ${card.index + 1}`}
loading="lazy"
decoding="async"
className="block h-auto w-full cursor-zoom-in"
onError={(event) =>
handlePreviewImageLoadError(event, card.resultUrl!)
@ -7020,6 +7069,8 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={buildPreviewImageUrl(attachment!.url, 400)}
alt={attachment!.name || `输入图 ${index + 1}`}
loading="lazy"
decoding="async"
className="h-full w-full object-cover"
onError={(event) =>
handlePreviewImageLoadError(event, attachment!.url)
@ -7048,6 +7099,8 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={buildPreviewImageUrl(selectedModelAttachment.url, 720)}
alt={selectedModelAttachment.name || "模特图"}
loading="lazy"
decoding="async"
className="h-full w-full object-cover"
onError={(event) =>
handlePreviewImageLoadError(event, selectedModelAttachment.url)
@ -7193,6 +7246,8 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={buildPreviewImageUrl(previewUrl, 640)}
alt={candidate.sceneName || candidate.taskNo || candidate.productModel || "候选整套"}
loading="lazy"
decoding="async"
className="h-full w-full object-cover"
onError={(event) =>
handlePreviewImageLoadError(event, previewUrl)
@ -7277,6 +7332,8 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={buildPreviewImageUrl(card.imageUrl, 720)}
alt={card.label}
loading="lazy"
decoding="async"
className="h-full w-full object-cover"
onError={(event) =>
handlePreviewImageLoadError(event, card.imageUrl || "")
@ -7384,6 +7441,8 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={buildPreviewImageUrl(card.resultUrl, 720)}
alt={`结果图 ${card.index + 1}`}
loading="lazy"
decoding="async"
className="h-full w-full cursor-zoom-in object-cover"
onError={(event) =>
handlePreviewImageLoadError(event, card.resultUrl!)
@ -7551,6 +7610,7 @@ export function AgentGenerationWorkspaceDarkV2({
alt={`${getResultModeLabel(activeResultModeType)} 结果图 ${card.index + 1}`}
className="h-full w-full object-contain p-2"
loading="lazy"
decoding="async"
/>
{isSceneResultCard ? (
<>
@ -7873,6 +7933,7 @@ export function AgentGenerationWorkspaceDarkV2({
<img
src={fullscreenPreview}
alt="预览"
decoding="async"
className="max-h-[95vh] max-w-[95vw] object-contain"
onClick={(e) => e.stopPropagation()}
/>

View File

@ -111,12 +111,12 @@ const VIRTUAL_OPTION_GRID_GAP = 16;
const VIRTUAL_OPTION_GRID_MAX_HEIGHT = 640;
const VIRTUAL_OPTION_GRID_MIN_CARD_HEIGHT = 122;
const VIRTUAL_OPTION_GRID_THRESHOLD = 12;
const WORKFLOW_OPTION_PREVIEW_WIDTH = 360;
const WORKFLOW_OPTION_PREVIEW_QUALITY = 58;
const WORKFLOW_OPTION_PREVIEW_EAGER_COUNT = 4;
const WORKFLOW_OPTION_NEXT_PREVIEW_PREFETCH_COUNT = 6;
const WORKFLOW_OPTION_PREFETCH_CACHE_LIMIT = 48;
const WORKFLOW_OPTION_PREFETCH_BATCH_SIZE = 2;
const WORKFLOW_OPTION_PREVIEW_WIDTH = 320;
const WORKFLOW_OPTION_PREVIEW_QUALITY = 56;
const WORKFLOW_OPTION_PREVIEW_EAGER_COUNT = 2;
const WORKFLOW_OPTION_NEXT_PREVIEW_PREFETCH_COUNT = 3;
const WORKFLOW_OPTION_PREFETCH_CACHE_LIMIT = 30;
const WORKFLOW_OPTION_PREFETCH_BATCH_SIZE = 1;
function isLikelyStoredWorkflowPreview(url: string, sourceUrl?: string | null) {
const source = String(sourceUrl || "").trim();
@ -472,8 +472,8 @@ const StepOptionCard = memo(function StepOptionCard({
handleWorkflowOptionPreviewError(event, option.previewImageUrl)
}
className={cn(
"h-full w-full object-cover transition-transform duration-700",
!disabled && "group-hover:scale-110"
"h-full w-full object-cover transition-transform duration-500",
!disabled && "group-hover:scale-[1.04]"
)}
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/40 to-transparent" />