'use client'; /** * 屏2 开新任务(熟手 /tasks/new) * 使用 NewTaskForm + ConfigPreviewPanel + RecentTasksBar + FlywheelBanner */ import { useEffect, useState } from 'react'; import { useRouter } from 'next/navigation'; import { ProgressBar } from '@/components/layout/ProgressBar'; import { FlywheelBanner } from '@/components/FlywheelBanner'; import { ConfigPreviewPanel } from '@/components/tasks/ConfigPreviewPanel'; import { RecentTasksBar } from '@/components/tasks/RecentTasksBar'; import { NewTaskForm } from '@/components/tasks/NewTaskForm'; import { ImportTextModal } from '@/components/tasks/ImportTextModal'; import { api } from '@/lib/api'; import { Product, CreateTaskRequest, Benchmark } from '@/types/index'; import { PaginatedResponse } from '@/types/index'; import { usePreferenceStore } from '@/stores/preferenceStore'; import { getErrorAction } from '@/types/errors'; import { ApiError } from '@/types/index'; export default function NewTaskPage() { const router = useRouter(); const { context, fetchContextByProduct } = usePreferenceStore(); const [products, setProducts] = useState([]); const [selectedProduct, setSelectedProduct] = useState(null); const [benchmarks, setBenchmarks] = useState([]); const [form, setForm] = useState>({ benchmark_ids: [], theme: '', text_count: 8, image_count: 6, track: 'ai', need_product_image: true, }); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(''); const [importOpen, setImportOpen] = useState(false); const [editingProduct, setEditingProduct] = useState(false); // 提升:供右侧「编辑配置」(运营/组长)触发就地编辑 useEffect(() => { loadProducts(); }, []); // 选品变化:拉该产品标杆笔记;切产品时清空已选标杆(避免跨产品串用) useEffect(() => { if (!selectedProduct) { setBenchmarks([]); return; } setForm((f) => ({ ...f, benchmark_ids: [] })); api.get<{ items: Benchmark[] }>(`/api/v1/products/${selectedProduct.id}/benchmarks`) .then((d) => setBenchmarks(d.items || [])) .catch(() => setBenchmarks([])); }, [selectedProduct]); // 选品变化:拉该产品飞轮偏好上下文,驱动顶部 FlywheelBanner useEffect(() => { if (!selectedProduct) return; fetchContextByProduct(selectedProduct.id); }, [selectedProduct?.id]); async function loadProducts() { try { const data = await api.get>('/api/v1/products'); setProducts(data.items); if (data.items.length > 0) setSelectedProduct(data.items[0]); } catch { // ignore } } // #1 内联建品:把新产品并入列表顶部并选中(QuickProductCreate 已含上传产品图) function handleProductCreated(p: Product) { setProducts((list) => [p, ...list.filter((x) => x.id !== p.id)]); setSelectedProduct(p); } function validate(): boolean { if (!selectedProduct) { setError('请选择产品'); return false; } if (!form.theme.trim()) { setError('请填写今天主题'); return false; } // 禁降级:产品入镜但该产品没传参考图 → 拦在前端,引导去上传 if (form.need_product_image && !selectedProduct.image_path) { setError('该产品还没上传参考图,无法生成产品入镜内容。请先到「配置-产品库」上传产品图,或关闭下方「产品入镜」开关。'); return false; } setError(''); return true; } async function handleSubmit(e: React.FormEvent, track: 'ai' | 'import') { e.preventDefault(); if (!validate() || !selectedProduct) return; setSubmitting(true); try { const req: CreateTaskRequest = { product_id: selectedProduct.id, ...form, track }; const data = await api.post<{ id: number }>('/api/v1/tasks', req); router.push(`/tasks/${data.id}/text`); } catch (err) { const apiErr = err as ApiError; setError(apiErr?.message || getErrorAction(apiErr?.code).message); } finally { setSubmitting(false); } } // 轨B:先校验产品/主题,通过后开弹窗让用户贴文案 function openImport(e: React.FormEvent) { e.preventDefault(); if (validate()) setImportOpen(true); } // 弹窗确认:建 import 任务 → 逐条导入候选池 → 跳 text 页 async function handleImportConfirm(contents: string[]) { if (!selectedProduct) return; setSubmitting(true); try { const req: CreateTaskRequest = { product_id: selectedProduct.id, ...form, track: 'import' }; const data = await api.post<{ id: number }>('/api/v1/tasks', req); // 任务已建。逐条导入;某条失败也不丢任务——跳进已建任务的 text 页, // 半成品文案在那里可见可续,避免任务 ID 丢失变成找不回的孤儿任务。 let imported = 0; try { for (const content of contents) { await api.post(`/api/v1/tasks/${data.id}/import-text`, { content }); imported += 1; } } catch (impErr) { const ae = impErr as ApiError; setError(`已导入 ${imported}/${contents.length} 条后中断(${ae?.message || '导入失败'}),已为你保留任务 #${data.id},可在文案页补齐。`); } setImportOpen(false); router.push(`/tasks/${data.id}/text`); } catch (err) { // 建任务本身失败(还没有任务 ID) const apiErr = err as ApiError; setError(apiErr?.message || getErrorAction(apiErr?.code).message); setImportOpen(false); } finally { setSubmitting(false); } } return (
{context && }
{/* 主表单区 */}

开新任务

setForm((f) => ({ ...f, ...patch }))} submitting={submitting} error={error} onSubmitAi={(e) => handleSubmit(e, 'ai')} onSubmitImport={openImport} />
{/* 右侧配置预览面板 */} {selectedProduct && setEditingProduct(true)} />}
setImportOpen(false)} onConfirm={handleImportConfirm} />
); }