diff --git a/frontend-web/.env.development b/frontend-web/.env.development index 22563825..05435bf2 100644 --- a/frontend-web/.env.development +++ b/frontend-web/.env.development @@ -5,7 +5,7 @@ VITE_USE_REAL_DATA=true # 任务详情(登录深链 cop-task-detail)数据源:默认真实接口;改成 true 走本地假数据(consumer 外网不可达时调试用)。 -VITE_MOCK_COP_TASK_DETAIL=false +VITE_MOCK_COP_TASK_DETAIL=true # Gateway / DeerFlow API VITE_BACKEND_BASE_URL=http://127.0.0.1:8001 diff --git a/frontend-web/src/open-canvas/components/ai-writing/ResearchSidebar.tsx b/frontend-web/src/open-canvas/components/ai-writing/ResearchSidebar.tsx index d464b872..ba103d88 100644 --- a/frontend-web/src/open-canvas/components/ai-writing/ResearchSidebar.tsx +++ b/frontend-web/src/open-canvas/components/ai-writing/ResearchSidebar.tsx @@ -1,7 +1,22 @@ "use client"; -import { BookOpen, FileText, LayoutGrid, Loader2, Plus, Settings2 } from "lucide-react"; -import { useEffect, useState } from "react"; +import { + BarChart3, + BookOpen, + FileText, + Globe2, + LayoutGrid, + Loader2, + Newspaper, + Plus, + Search, + Settings2, + SlidersHorizontal, + Sparkles, + TrendingUp, +} from "lucide-react"; +import type { LucideIcon } from "lucide-react"; +import { useEffect, useMemo, useState } from "react"; import { useNavigate } from "react-router-dom"; import { useQueryClient } from "@tanstack/react-query"; @@ -22,23 +37,62 @@ import type { ResearchTemplate } from "../../api/ai-writing-research-templates"; import { useWritingForm } from "../../contexts/WritingFormContext"; import { useAIWriting } from "../../contexts/AIWritingContext"; -/** - * 课题研究左栏(需求 0616 #5)。 - * - 上半「研究模板」= 研究模板实体(``useResearchTemplates``);点击一键预填整张写作表单 - * (文章类型 / 大纲 / 搜索来源 / 字数 / 受众 / 严格模式 / 主题)并展开配置。顶部「配置」 - * 入口进入模板配置页维护这些模板。 - * - 下半「笔记本」= 我的空间(``useStudioNotebooks``);点击在右侧内嵌打开该笔记本页。 - */ +type TemplateVisual = { + Icon: LucideIcon; + iconClass: string; + accentClass: string; +}; + +const TEMPLATE_VISUALS: TemplateVisual[] = [ + { + Icon: Globe2, + iconClass: "bg-blue-50 text-blue-600", + accentClass: "bg-blue-500", + }, + { + Icon: Newspaper, + iconClass: "bg-amber-50 text-amber-600", + accentClass: "bg-amber-500", + }, + { + Icon: Sparkles, + iconClass: "bg-violet-50 text-violet-600", + accentClass: "bg-violet-500", + }, + { + Icon: TrendingUp, + iconClass: "bg-rose-50 text-rose-600", + accentClass: "bg-rose-500", + }, + { + Icon: BookOpen, + iconClass: "bg-emerald-50 text-emerald-600", + accentClass: "bg-emerald-500", + }, + { + Icon: BarChart3, + iconClass: "bg-cyan-50 text-cyan-600", + accentClass: "bg-cyan-500", + }, +]; + +function getTemplateVisual(tpl: ResearchTemplate, index: number): TemplateVisual { + const text = `${tpl.name} ${tpl.description ?? ""} ${tpl.article_type_key ?? ""}`; + if (/网摘|网络|热点|摘/.test(text)) return TEMPLATE_VISUALS[0]; + if (/周报|周刊|日报|月报/.test(text)) return TEMPLATE_VISUALS[1]; + if (/要讯|资讯|快讯|简报/.test(text)) return TEMPLATE_VISUALS[2]; + if (/行业|分析|市场|竞争/.test(text)) return TEMPLATE_VISUALS[3]; + if (/政策|解读|法规/.test(text)) return TEMPLATE_VISUALS[4]; + return TEMPLATE_VISUALS[index % TEMPLATE_VISUALS.length]; +} + export function ResearchSidebar({ viewingNotebookId, onOpenNotebook, onOpenAllSpaces, }: { - /** 当前在右侧查看的笔记本 id(高亮用)。 */ viewingNotebookId?: number | null; - /** 点击笔记本 → 在右侧内嵌打开该笔记本页(替换右侧内容)。 */ onOpenNotebook: (notebookId: number) => void; - /** 点击「所有空间」→ 在右侧内嵌打开空间列表页。 */ onOpenAllSpaces: () => void; }) { const navigate = useNavigate(); @@ -62,7 +116,7 @@ export function ResearchSidebar({ } = useWritingForm(); const queryClient = useQueryClient(); - // 新建空间弹窗(与 workspace-nav-studio 同款)。 + const [templateSearch, setTemplateSearch] = useState(""); const [createOpen, setCreateOpen] = useState(false); const [name, setName] = useState(""); const [creating, setCreating] = useState(false); @@ -72,6 +126,16 @@ export function ResearchSidebar({ void refresh(); }, [refresh]); + const filteredTemplates = useMemo(() => { + const keyword = templateSearch.trim().toLowerCase(); + if (!keyword) return templates; + return templates.filter((tpl) => + [tpl.name, tpl.description, tpl.article_type_key] + .filter(Boolean) + .some((value) => String(value).toLowerCase().includes(keyword)), + ); + }, [templates, templateSearch]); + const handleCreate = async () => { const trimmed = name.trim(); if (!trimmed) return; @@ -92,8 +156,6 @@ export function ResearchSidebar({ } }; - // 点击研究模板 → ①回填整张写作表单(保持写作态左栏显示与运行配置一致) - // ②直接以模板预设进入 AI 写作流程(startWriting)。 const handleTemplateClick = (tpl: ResearchTemplate) => { const intent = tpl.topic?.trim() ?? ""; const articleType = tpl.article_type_key || "analysis"; @@ -102,7 +164,6 @@ export function ResearchSidebar({ const wordCount = tpl.word_count > 0 ? tpl.word_count : 800; const writingMode = tpl.strict_mode ? "strict" : "loose"; - // 回填表单上下文(写作态左栏据此展示)。 if (intent) setIntent(intent); if (tpl.article_type_key) setArticleType(tpl.article_type_key); if (outline) { @@ -115,7 +176,6 @@ export function ResearchSidebar({ setStrictMode(tpl.strict_mode); setFormExpanded(true); - // 无主题/意图无法发起写作 → 仅回填表单,由用户补充后手动开始。 if (!intent) return; void startWriting({ userIntent: intent, @@ -130,116 +190,191 @@ export function ResearchSidebar({ }; return ( -