前端文案挑选页按 A/B/C 三套分组展示

- 后端 _fmt_text 返回 strategy 字段,SSE 与 hydrate 两条路径贯通
- 新建 TextStrategyGroup 组件 + groupByStrategy(A/B/C/未分套排序,旧 NULL 数据归未分套)
- text 页平铺改分组渲染,选中态/改稿回调透传不变
- 复用 ImageStrategyGroup 的 STRATEGY_LABEL,单向依赖无环

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
yangqianqian
2026-06-22 10:29:35 +08:00
parent e095b1162e
commit cb041e8d3a
6 changed files with 85 additions and 15 deletions

View File

@@ -4,7 +4,8 @@ import { useEffect } from 'react';
import { useRouter, useParams } from 'next/navigation';
import { ProgressBar } from '@/components/layout/ProgressBar';
import { FlywheelBannerFromSse } from '@/components/FlywheelBanner';
import { TextCandidateCard, TextCandidateCardSkeleton } from '@/components/tasks/TextCandidateCard';
import { TextCandidateCardSkeleton } from '@/components/tasks/TextCandidateCard';
import { TextStrategyGroup, groupByStrategy } from '@/components/tasks/TextStrategyGroup';
import { SseStatusBar } from '@/components/tasks/SseStatusBar';
import { FatalErrorBanner } from '@/components/tasks/FatalErrorBanner';
import { RejectReasonBanner } from '@/components/tasks/RejectReasonBanner';
@@ -73,20 +74,23 @@ export default function TextSelectionPage() {
</div>
)}
{/* 文案卡网格(谁好谁先冒) */}
<div className="grid grid-cols-2 xl:grid-cols-3 gap-4">
{showSkeleton
? Array.from({ length: 4 }).map((_, i) => <TextCandidateCardSkeleton key={i} />)
: textCandidates.map((c) => (
<TextCandidateCard
key={c.candidate_id}
candidate={c}
selected={selectedTextIds.includes(c.candidate_id)}
onToggle={toggleTextSelection}
onSaveEdit={handleSaveEdit}
/>
))}
</div>
{/* 文案卡:按 A/B/C 三套分组展示(让运营一眼看出三套不同角度);生成中显示骨架 */}
{showSkeleton ? (
<div className="grid grid-cols-2 xl:grid-cols-3 gap-4">
{Array.from({ length: 4 }).map((_, i) => <TextCandidateCardSkeleton key={i} />)}
</div>
) : (
groupByStrategy(textCandidates).map(([strategy, list]) => (
<TextStrategyGroup
key={strategy}
strategy={strategy}
candidates={list}
selectedTextIds={selectedTextIds}
onToggle={toggleTextSelection}
onSaveEdit={handleSaveEdit}
/>
))
)}
{/* 底部操作栏 */}
{textCandidates.length > 0 && (