import { useState } from 'react' import { useTranslation } from 'react-i18next' import { FileText } from 'lucide-react' import { useProjectStore } from '../../stores/project-store' import { useWorkflowStore } from '../../stores/workflow-store' import { toast } from '../ui/Toast' import { Dialog, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, } from '../ui/Dialog' import { Button } from '../ui/Button' import { Input } from '../ui/Input' import { Label } from '../ui/Label' import { Textarea } from '../ui/Textarea' import type { DirectoryWorkflowParams } from '../../services/workflows/directory-workflow' interface Props { isOpen: boolean onClose: () => void /** 已有蓝图章节数(影响「追加」模式的默认值) */ existingCount: number onConfirm: (params: DirectoryWorkflowParams) => void } /** 蓝图生成配置弹框 — 选择生成范围和模式 */ export default function DirectoryConfigDialog({ isOpen, onClose, existingCount, onConfirm }: Props) { const { t } = useTranslation('dialogs') const currentProject = useProjectStore(s => s.currentProject) // 范围选择 const [rangeMode, setRangeMode] = useState<'front' | 'range' | 'full'>('front') // 覆盖/追加模式选择 (仅当 existingCount > 0 时有效) const [overwriteMode, setOverwriteMode] = useState<'append' | 'full'>('append') const [frontN, setFrontN] = useState(50) const [rangeStart, setRangeStart] = useState(existingCount + 1) const [rangeEnd, setRangeEnd] = useState(existingCount + 50) // 节奏指导 const [pacingGuidance, setPacingGuidance] = useState('') const isBatchRunning = useWorkflowStore(s => s.isTypeRunning('batch_generate')) if (!currentProject) return null const total = currentProject.novelConfig.totalChapters const handleConfirm = () => { // 防重复:同类型工作流正在运行 if (isBatchRunning) { toast.warning(t('directoryConfig.taskRunning')) return } let params: DirectoryWorkflowParams if (rangeMode === 'full') { params = { mode: overwriteMode === 'full' ? 'full' : 'append', count: 0 } } else if (rangeMode === 'front') { if (existingCount > 0 && overwriteMode === 'append') { params = { mode: 'append', startChapter: existingCount + 1, count: Number(frontN) || 50 } } else { params = { mode: 'full', count: Number(frontN) || 50 } } } else { const start = Number(rangeStart) || 1 const end = Math.max(start, Number(rangeEnd) || start) params = { mode: 'append', startChapter: start, count: Math.max(1, end - start + 1) } } onConfirm({ ...params, pacingGuidance: pacingGuidance.trim() || undefined }) onClose() toast.info(t('directoryConfig.submitted')) } return ( !v && onClose()}> {t('directoryConfig.title')} {existingCount > 0 ? t('directoryConfig.existingBlueprints', { count: existingCount }) : t('directoryConfig.totalChaptersInfo', { total })}
setRangeMode('front')} label={ {t('directoryConfig.batchGenerate')} setFrontN(e.target.value === '' ? '' : parseInt(e.target.value))} onBlur={() => { const v = Number(frontN) if (!v || v < 1) setFrontN(50) else setFrontN(Math.min(total, v)) }} className="w-16 h-6 text-xs px-2 py-0" onClick={e => e.stopPropagation()} /> {t('directoryConfig.chapters')} } /> setRangeMode('range')} label={ {t('directoryConfig.specifyRange')} setRangeStart(e.target.value === '' ? '' : parseInt(e.target.value))} onBlur={() => { const v = Number(rangeStart) if (!v || v < 1) setRangeStart(1) else if (v > existingCount + 1) setRangeStart(existingCount + 1) }} className="w-16 h-6 text-xs px-2 py-0" onClick={e => e.stopPropagation()} /> {t('directoryConfig.toChapter')} setRangeEnd(e.target.value === '' ? '' : parseInt(e.target.value))} onBlur={() => { const v = Number(rangeEnd) const start = Number(rangeStart) || 1 if (!v || v < start) setRangeEnd(start) }} className="w-16 h-6 text-xs px-2 py-0" onClick={e => e.stopPropagation()} /> {t('directoryConfig.chapters')} } /> setRangeMode('full')} label={t('directoryConfig.fullGenerate', { total })} />
{existingCount > 0 && (

{t('directoryConfig.existingDataHandling')}

setOverwriteMode('append')} label={t('directoryConfig.appendMode', { from: existingCount + 1 })} /> setOverwriteMode('full')} label={t('directoryConfig.overwriteMode')} />
)} {/* 节奏/风格指导(可选) */}