import type { ProjectCreateRequest } from "@/lib/api/types"; // 立项向导 5 步(UX §6.2)。表单状态用字符串/数组,提交时归一为 ProjectCreateRequest。 export interface WizardForm { title: string; genre: string; logline: string; sellingPoints: string[]; structure: string; premise: string; protagonist: string; theme: string; } export const WIZARD_STEPS = 5; // 各步标题(与 WIZARD_STEPS 一一对应)。第 5 步为「确认/概览」:回显已填字段供复核后提交。 export const STEP_TITLES = [ "书名 + 题材", "一句话故事 + 卖点 + 结构", "立意 / 总纲", "主角 / 金手指", "确认与提交", ] as const; export const emptyWizardForm: WizardForm = { title: "", genre: "", logline: "", sellingPoints: [], structure: "", premise: "", protagonist: "", theme: "", }; export const GENRES = ["玄幻", "仙侠", "都市", "科幻", "历史", "悬疑"]; export const STRUCTURES = ["三幕", "故事圈", "雪花"]; export const SELLING_POINT_PRESETS = ["逆袭", "打脸", "系统流", "双男主", "群像"]; // 每一步可否前进:仅第 1 步(书名)必填,其余可空着继续(草稿式立项)。 export function canAdvance(step: number, form: WizardForm): boolean { if (step === 1) return form.title.trim().length > 0; return true; } // 整个向导可否提交:书名必填。 export function canSubmit(form: WizardForm): boolean { return form.title.trim().length > 0; } export function clampStep(step: number): number { if (step < 1) return 1; if (step > WIZARD_STEPS) return WIZARD_STEPS; return step; } // 归一为后端请求体(snake_case,空值落 null/省略)。 export function toCreateRequest(form: WizardForm): ProjectCreateRequest { const trim = (s: string): string | null => { const v = s.trim(); return v.length > 0 ? v : null; }; // 立意(premise)与主角/金手指(protagonist)是两个独立输入,但 M1 projects 表只有 // premise 一个字段 → 合并进 premise,二者各占一段,互不覆盖(QA H1:此前共用同一字段)。 const premise = [trim(form.premise), form.protagonist.trim() ? `主角/金手指:${form.protagonist.trim()}` : null] .filter((s): s is string => s !== null) .join("\n\n") || null; return { title: form.title.trim(), genre: trim(form.genre), logline: trim(form.logline), premise, theme: trim(form.theme), selling_points: form.sellingPoints, structure: trim(form.structure), }; }