update:1.修复1-N模式下,手动创建大纲后,再手动创建章节无法找到大纲问题 2.更新章节管理-编辑内容/批量生成 增加默认字数缓存

This commit is contained in:
xiamuceer
2026-01-05 14:26:58 +08:00
parent 3fa23a1698
commit 6e603ee1a9
+56 -31
View File
@@ -14,8 +14,37 @@ import ChapterReader from '../components/ChapterReader';
const { TextArea } = Input;
// localStorage 缓存键名
const WORD_COUNT_CACHE_KEY = 'chapter_default_word_count';
const DEFAULT_WORD_COUNT = 3000;
// 从 localStorage 读取缓存的字数
const getCachedWordCount = (): number => {
try {
const cached = localStorage.getItem(WORD_COUNT_CACHE_KEY);
if (cached) {
const value = parseInt(cached, 10);
if (!isNaN(value) && value >= 500 && value <= 10000) {
return value;
}
}
} catch (error) {
console.warn('读取字数缓存失败:', error);
}
return DEFAULT_WORD_COUNT;
};
// 保存字数到 localStorage
const setCachedWordCount = (value: number): void => {
try {
localStorage.setItem(WORD_COUNT_CACHE_KEY, String(value));
} catch (error) {
console.warn('保存字数缓存失败:', error);
}
};
export default function Chapters() {
const { currentProject, chapters, setCurrentChapter, setCurrentProject } = useStore();
const { currentProject, chapters, outlines, setCurrentChapter, setCurrentProject } = useStore();
const [modal, contextHolder] = Modal.useModal();
const [isModalOpen, setIsModalOpen] = useState(false);
const [isEditorOpen, setIsEditorOpen] = useState(false);
@@ -28,7 +57,7 @@ export default function Chapters() {
const contentTextAreaRef = useRef<any>(null);
const [writingStyles, setWritingStyles] = useState<WritingStyle[]>([]);
const [selectedStyleId, setSelectedStyleId] = useState<number | undefined>();
const [targetWordCount, setTargetWordCount] = useState<number>(3000);
const [targetWordCount, setTargetWordCount] = useState<number>(getCachedWordCount);
const [availableModels, setAvailableModels] = useState<Array<{ value: string, label: string }>>([]);
const [selectedModel, setSelectedModel] = useState<string | undefined>();
const [batchSelectedModel, setBatchSelectedModel] = useState<string | undefined>(); // 批量生成的模型选择
@@ -940,13 +969,13 @@ export default function Chapters() {
// 设置批量生成的模型选择状态
setBatchSelectedModel(defaultModel || undefined);
// 重置表单并设置初始值
// 重置表单并设置初始值(使用缓存的字数)
batchForm.setFieldsValue({
startChapterNumber: firstIncompleteChapter.chapter_number,
count: 5,
enableAnalysis: false,
styleId: selectedStyleId,
targetWordCount: 3000,
targetWordCount: getCachedWordCount(),
});
setBatchGenerateVisible(true);
@@ -997,27 +1026,14 @@ export default function Chapters() {
tooltip="one-to-many模式下,章节必须关联到大纲"
>
<Select placeholder="请选择所属大纲">
{sortedChapters.length > 0 && (() => {
// 从现有章节中提取大纲信息
const outlineMap = new Map();
sortedChapters.forEach(ch => {
if (ch.outline_id && ch.outline_title) {
outlineMap.set(ch.outline_id, {
id: ch.outline_id,
title: ch.outline_title,
order: ch.outline_order || 0
});
}
});
const uniqueOutlines = Array.from(outlineMap.values())
.sort((a, b) => a.order - b.order);
return uniqueOutlines.map(outline => (
{/* 直接使用 store 中的 outlines 数据,而不是从现有章节中提取 */}
{[...outlines]
.sort((a, b) => a.order_index - b.order_index)
.map(outline => (
<Select.Option key={outline.id} value={outline.id}>
{outline.order}{outline.title}
{outline.order_index}{outline.title}
</Select.Option>
));
})()}
))}
</Select>
</Form.Item>
@@ -1555,7 +1571,7 @@ export default function Chapters() {
{!isMobile && (
<Tag color="blue">
{currentProject.outline_mode === 'one-to-one'
? '传统模式:章节由大纲一对一管理,请在大纲页面操作'
? '传统模式:章节由大纲管理,请在大纲页面操作'
: '细化模式:章节可在大纲页面展开'}
</Tag>
)}
@@ -1993,7 +2009,7 @@ export default function Chapters() {
name="title"
tooltip={
currentProject.outline_mode === 'one-to-one'
? "章节标题由大纲管理,建议在大纲页面统一修改"
? "章节标题由大纲管理,在大纲页面修改"
: "一对多模式下可以修改章节标题"
}
rules={
@@ -2011,7 +2027,7 @@ export default function Chapters() {
<Form.Item
label="章节序号"
name="chapter_number"
tooltip="章节序号由大纲的顺序决定,无法修改。请在大纲页面使用上移/下移功能调整顺序"
tooltip="章节序号不允许修改,请删除对应大纲,重新生成"
>
<Input type="number" placeholder="章节排序序号" disabled />
</Form.Item>
@@ -2161,7 +2177,7 @@ export default function Chapters() {
}}>
<Form.Item
label="目标字数"
tooltip="AI生成章节时的目标字数,实际可能略有偏差"
tooltip="AI生成章节时的目标字数,实际可能略有偏差(修改后会自动记住)"
style={{ flex: 1, marginBottom: isMobile ? 16 : 0 }}
>
<InputNumber
@@ -2169,7 +2185,11 @@ export default function Chapters() {
max={10000}
step={100}
value={targetWordCount}
onChange={(value) => setTargetWordCount(value || 3000)}
onChange={(value) => {
const newValue = value || DEFAULT_WORD_COUNT;
setTargetWordCount(newValue);
setCachedWordCount(newValue);
}}
disabled={isGenerating}
style={{ width: '100%' }}
formatter={(value) => `${value}`}
@@ -2353,7 +2373,7 @@ export default function Chapters() {
count: 5,
enableAnalysis: true, // 强制启用同步分析
styleId: selectedStyleId,
targetWordCount: 3000,
targetWordCount: getCachedWordCount(),
model: selectedModel,
}}
>
@@ -2425,7 +2445,7 @@ export default function Chapters() {
<Form.Item
label="目标字数"
tooltip="AI生成章节时的目标字数,实际生成字数可能略有偏差"
tooltip="AI生成章节时的目标字数,实际生成字数可能略有偏差(修改后会自动记住)"
>
<Form.Item
name="targetWordCount"
@@ -2440,10 +2460,15 @@ export default function Chapters() {
style={{ width: '100%' }}
formatter={(value) => `${value}`}
parser={(value) => value?.replace(' 字', '') as any}
onChange={(value) => {
if (value) {
setCachedWordCount(value);
}
}}
/>
</Form.Item>
<div style={{ color: '#666', fontSize: 12, marginTop: 4 }}>
500-100003000
500-10000
</div>
</Form.Item>