解决 8 处冲突: - app.py:同时挂载 public_embed + html_page_favorites 两个 router - .env:保留 dhk-1 的 CORS 配置(含 5174、ALLOW_ALL=0) - message-list.tsx:并入双方新增(onSetupWriting* 解构 + contentClassName/fitMessageRowsToContent 类型) - WorkspaceRoutes.tsx:采用 master 的路由结构(含 chats_iframe/IframeChatPage),补回 dhk-1 的 BusinessChainEditorPage 导入与 roundtable/chains 路由 - LoginPage.tsx:合并两套登录(master 的 token 换登录 + dhk-1 的 online-ticket),并集依赖数组 - ScheduledTasksPage.tsx:采用 master 的 HTML 定时任务表单(isHtmlTask 分支) - AIWritingForm.tsx:保留 dhk-1 的 useWritingForm 重构,补回 master 的笔记来源 useState;WritingFormContext.materialSource 扩展支持 'notebook' - useAIWritingStream.ts:保留 dhk-1 重构(仅 reducer/helpers,useAIWriting 已移至 AIWritingContext),不并入 master 在此文件的旧实现 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
103 lines
3.8 KiB
TypeScript
103 lines
3.8 KiB
TypeScript
import {
|
|
createContext,
|
|
useCallback,
|
|
useContext,
|
|
useMemo,
|
|
useState,
|
|
type ReactNode,
|
|
} from 'react';
|
|
|
|
import type { SetupWritingApprovalPayload } from '@/components/workspace/messages';
|
|
|
|
/**
|
|
* 写作配置表单的共享状态。
|
|
*
|
|
* 上提到 Context 是为了让「右侧写作助手 Q&A」在用户批准模型建议后,能把建议字段
|
|
* 一次性回填到「左侧写作表单」的输入框(``applyProposal``)。表单与 Q&A 面板共用同一份
|
|
* state,因此 Provider 必须同时包住两侧面板(见 AIWritingPage)。
|
|
*/
|
|
export interface WritingFormValue {
|
|
intent: string;
|
|
setIntent: (v: string) => void;
|
|
showOutline: boolean;
|
|
setShowOutline: (v: boolean) => void;
|
|
outlineText: string;
|
|
setOutlineText: (v: string) => void;
|
|
articleType: string;
|
|
setArticleType: (v: string) => void;
|
|
wordCountInput: string;
|
|
setWordCountInput: (v: string) => void;
|
|
audience: string;
|
|
setAudience: (v: string) => void;
|
|
strictMode: boolean;
|
|
setStrictMode: (v: boolean) => void;
|
|
materialSource: 'knowledge_base' | 'skill' | 'notebook';
|
|
setMaterialSource: (v: 'knowledge_base' | 'skill' | 'notebook') => void;
|
|
modelName: string;
|
|
setModelName: (v: string) => void;
|
|
/** 把模型建议(setup_writing 审批 payload)回填到表单各字段。 */
|
|
applyProposal: (payload: SetupWritingApprovalPayload) => void;
|
|
}
|
|
|
|
const WritingFormContext = createContext<WritingFormValue | null>(null);
|
|
|
|
export function useWritingForm(): WritingFormValue {
|
|
const ctx = useContext(WritingFormContext);
|
|
if (!ctx) {
|
|
throw new Error('useWritingForm must be used within WritingFormProvider');
|
|
}
|
|
return ctx;
|
|
}
|
|
|
|
export function useWritingFormOptional(): WritingFormValue | null {
|
|
return useContext(WritingFormContext);
|
|
}
|
|
|
|
export function WritingFormProvider({ children }: { children: ReactNode }) {
|
|
const [intent, setIntent] = useState('');
|
|
const [showOutline, setShowOutline] = useState(false);
|
|
const [outlineText, setOutlineText] = useState('');
|
|
const [articleType, setArticleType] = useState('analysis');
|
|
const [wordCountInput, setWordCountInput] = useState('800');
|
|
const [audience, setAudience] = useState('普通读者');
|
|
const [strictMode, setStrictMode] = useState(false);
|
|
const [materialSource, setMaterialSource] = useState<'knowledge_base' | 'skill' | 'notebook'>('knowledge_base');
|
|
const [modelName, setModelName] = useState('');
|
|
|
|
const applyProposal = useCallback((payload: SetupWritingApprovalPayload) => {
|
|
if (payload.user_intent?.trim()) setIntent(payload.user_intent.trim());
|
|
if (payload.article_type?.trim()) setArticleType(payload.article_type.trim());
|
|
if (typeof payload.word_count_target === 'number' && payload.word_count_target > 0) {
|
|
setWordCountInput(String(payload.word_count_target));
|
|
}
|
|
if (payload.target_audience?.trim()) setAudience(payload.target_audience.trim());
|
|
if (payload.writing_mode === 'strict') setStrictMode(true);
|
|
else if (payload.writing_mode === 'loose') setStrictMode(false);
|
|
if (payload.material_source === 'skill' || payload.material_source === 'knowledge_base') {
|
|
setMaterialSource(payload.material_source);
|
|
}
|
|
if (payload.outline?.trim()) {
|
|
setOutlineText(payload.outline);
|
|
setShowOutline(true);
|
|
}
|
|
}, []);
|
|
|
|
const value = useMemo<WritingFormValue>(
|
|
() => ({
|
|
intent, setIntent,
|
|
showOutline, setShowOutline,
|
|
outlineText, setOutlineText,
|
|
articleType, setArticleType,
|
|
wordCountInput, setWordCountInput,
|
|
audience, setAudience,
|
|
strictMode, setStrictMode,
|
|
materialSource, setMaterialSource,
|
|
modelName, setModelName,
|
|
applyProposal,
|
|
}),
|
|
[intent, showOutline, outlineText, articleType, wordCountInput, audience, strictMode, materialSource, modelName, applyProposal],
|
|
);
|
|
|
|
return <WritingFormContext.Provider value={value}>{children}</WritingFormContext.Provider>;
|
|
}
|