diff --git a/frontend-web/.env.example b/frontend-web/.env.example index 9653a1c4..3564ba7b 100644 --- a/frontend-web/.env.example +++ b/frontend-web/.env.example @@ -14,8 +14,8 @@ # - 本机连 127.0.0.1:8001:复制 .env.development.local.example → .env.development.local # - 内网打包部署:改 .env.network 后执行 pnpm build:network(或改 .env.production 后 pnpm build) # -# 若浏览器直连后端报 CORS,请在 Gateway 配置 CORS_ORIGINS,包含前端源站,例如: -# CORS_ORIGINS=http://127.0.0.1:5173,http://localhost:5173,http://127.0.0.1:5174 +# 若浏览器直连后端报 CORS,请在 Gateway 配置 GATEWAY_CORS_ORIGINS,包含前端源站;无界嵌入时还要加宿主源站,例如: +# GATEWAY_CORS_ORIGINS=http://127.0.0.1:5174,http://localhost:5174,http://127.0.0.1:5183,http://localhost:5183 # --- 开发环境(见 .env.development)--- # VITE_BACKEND_BASE_URL=https://ch1.b.uat.4.cn/deerflow diff --git a/frontend-web/src/App.tsx b/frontend-web/src/App.tsx index 752afc7a..277f3974 100644 --- a/frontend-web/src/App.tsx +++ b/frontend-web/src/App.tsx @@ -22,6 +22,7 @@ import PublicSharePage from "./pages/PublicSharePage"; import PublicLeaderboardPage from "./pages/PublicLeaderboardPage"; import PublicRoundtableSharePage from "./pages/PublicRoundtableSharePage"; import EmbedChatPage from "./pages/EmbedChatPage"; +import EmbedRoundtablePage from "./pages/EmbedRoundtablePage"; import { ChatRuntime } from "./pages/WorkspaceRoutes"; import { NotFoundPage } from "./pages/NotFoundPage"; @@ -96,6 +97,8 @@ export function App() { } /> + {/* Embedded roundtable planning — body only, no sidebars; username login (not wujie ticket) */} + } /> } /> } /> diff --git a/frontend-web/src/core/embed/wujie.ts b/frontend-web/src/core/embed/wujie.ts index e725cba2..368fa2e9 100644 --- a/frontend-web/src/core/embed/wujie.ts +++ b/frontend-web/src/core/embed/wujie.ts @@ -31,11 +31,29 @@ export interface WujieProps { /** 嵌入问答:DeerFlow 本地用户名登录。 */ username?: string; userName?: string; + /** 用户名+密码登录的共享口令(后端开启 username_login.require_password 时校验)。 */ + password?: string; + /** 圆桌规划嵌入:任务名称(注入 Step 1 首条用户消息)。 */ + taskTitle?: string; + /** 圆桌规划嵌入:任务描述(注入 Step 1 首条用户消息)。 */ + taskGoal?: string; + /** 圆桌规划嵌入:指定业务链条 id(直传,跳过业务映射表)。 */ + chainId?: string; + /** 圆桌规划嵌入:业务码(可选回退;后端业务映射表查 chainId)。 */ + businessCode?: string; [key: string]: unknown; } +/** 无界跨实例事件总线(子→父 / 父→子 通信)。 */ +interface WujieBus { + $emit?: (event: string, ...args: unknown[]) => void; + $on?: (event: string, handler: (...args: unknown[]) => void) => void; + $off?: (event: string, handler: (...args: unknown[]) => void) => void; +} + interface WujieRuntime { props?: WujieProps; + bus?: WujieBus; [key: string]: unknown; } @@ -59,6 +77,33 @@ export function readWujieProps(): WujieProps { return window.$wujie?.props ?? {}; } +/** + * 子→父:通过无界事件总线广播一个事件。父页面用 `bus.$on(event, handler)` 监听。 + * 非无界环境 / 总线缺失时静默忽略(返回 false),可安全无条件调用。 + */ +export function emitWujieEvent(event: string, payload?: unknown): boolean { + if (typeof window === "undefined") return false; + const emit = window.$wujie?.bus?.$emit; + if (typeof emit !== "function") return false; + emit(event, payload); + return true; +} + +/** + * 父→子:订阅无界事件总线上的一个事件。返回取消订阅函数(在 effect cleanup 里调用)。 + * 非无界环境 / 总线缺失时返回 no-op,可安全无条件调用。 + */ +export function onWujieEvent( + event: string, + handler: (...args: unknown[]) => void, +): () => void { + if (typeof window === "undefined") return () => {}; + const bus = window.$wujie?.bus; + if (typeof bus?.$on !== "function") return () => {}; + bus.$on(event, handler); + return () => bus.$off?.(event, handler); +} + /** * 全局读取无界父级注入的 props 的 hook。 * diff --git a/frontend-web/src/open-canvas/components/ai-writing/AIWritingForm.tsx b/frontend-web/src/open-canvas/components/ai-writing/AIWritingForm.tsx index 727f4e79..786c4c30 100644 --- a/frontend-web/src/open-canvas/components/ai-writing/AIWritingForm.tsx +++ b/frontend-web/src/open-canvas/components/ai-writing/AIWritingForm.tsx @@ -1,5 +1,5 @@ import { useEffect, useMemo, useState } from 'react'; -import { PenLine } from 'lucide-react'; +import { PenLine, SlidersHorizontal } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Textarea } from '@/components/ui/textarea'; @@ -163,17 +163,19 @@ export function AIWritingForm({ return (
-
-
- -

+
+
+ +

写作配置选项

- + {intent.length} / {MAX_INTENT_LENGTH} 字 @@ -368,7 +370,7 @@ export function AIWritingForm({