update:1.优化向导生成逻辑,最后一步不再展开大纲,避免等待时间过久 2.新增章节跳转功能,搜索功能

This commit is contained in:
xiamuceer
2025-11-21 15:49:39 +08:00
parent 697cfc48bb
commit a5c1192809
6 changed files with 201 additions and 105 deletions
+75 -36
View File
@@ -1,12 +1,13 @@
import { useState, useEffect, useRef, useMemo } from 'react';
import { List, Button, Modal, Form, Input, Select, message, Empty, Space, Badge, Tag, Card, Tooltip, InputNumber, Progress, Alert, Radio, Descriptions, Collapse, Popconfirm } from 'antd';
import { EditOutlined, FileTextOutlined, ThunderboltOutlined, LockOutlined, DownloadOutlined, SettingOutlined, FundOutlined, SyncOutlined, CheckCircleOutlined, CloseCircleOutlined, RocketOutlined, StopOutlined, InfoCircleOutlined, CaretRightOutlined, DeleteOutlined } from '@ant-design/icons';
import { List, Button, Modal, Form, Input, Select, message, Empty, Space, Badge, Tag, Card, Tooltip, InputNumber, Progress, Alert, Radio, Descriptions, Collapse, Popconfirm, FloatButton } from 'antd';
import { EditOutlined, FileTextOutlined, ThunderboltOutlined, LockOutlined, DownloadOutlined, SettingOutlined, FundOutlined, SyncOutlined, CheckCircleOutlined, CloseCircleOutlined, RocketOutlined, StopOutlined, InfoCircleOutlined, CaretRightOutlined, DeleteOutlined, BookOutlined } from '@ant-design/icons';
import { useStore } from '../store';
import { useChapterSync } from '../store/hooks';
import { projectApi, writingStyleApi } from '../services/api';
import type { Chapter, ChapterUpdate, ApiError, WritingStyle, AnalysisTask, ExpansionPlanData } from '../types';
import ChapterAnalysis from '../components/ChapterAnalysis';
import { SSELoadingOverlay } from '../components/SSELoadingOverlay';
import FloatingIndexPanel from '../components/FloatingIndexPanel';
const { TextArea } = Input;
@@ -29,6 +30,7 @@ export default function Chapters() {
// 分析任务状态管理
const [analysisTasksMap, setAnalysisTasksMap] = useState<Record<string, AnalysisTask>>({});
const pollingIntervalsRef = useRef<Record<string, number>>({});
const [isIndexPanelVisible, setIsIndexPanelVisible] = useState(false);
// 单章节生成进度状态
const [singleChapterProgress, setSingleChapterProgress] = useState(0);
@@ -847,9 +849,22 @@ export default function Chapters() {
message.error('删除章节失败:' + (error.message || '未知错误'));
}
};
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
const handleChapterSelect = (chapterId: string) => {
const element = document.getElementById(`chapter-item-${chapterId}`);
if (element) {
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
// Optional: add a visual highlight effect
element.style.transition = 'background-color 0.5s ease';
element.style.backgroundColor = '#e6f7ff';
setTimeout(() => {
element.style.backgroundColor = '';
}, 1500);
}
};
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<div style={{
position: 'sticky',
top: 0,
@@ -891,7 +906,7 @@ export default function Chapters() {
</Space>
</div>
<div style={{ flex: 1, overflowY: 'auto' }}>
<div style={{ flex: 1, overflowY: 'auto', minHeight: 0 }}>
{chapters.length === 0 ? (
<Empty description="还没有章节,开始创作吧!" />
) : (
@@ -933,6 +948,7 @@ export default function Chapters() {
dataSource={group.chapters}
renderItem={(item) => (
<List.Item
id={`chapter-item-${item.id}`}
style={{
padding: '16px 0',
borderRadius: 8,
@@ -1000,38 +1016,46 @@ export default function Chapters() {
<List.Item.Meta
avatar={!isMobile && <FileTextOutlined style={{ fontSize: 32, color: '#1890ff' }} />}
title={
<div style={{ display: 'flex', alignItems: 'center', gap: isMobile ? 4 : 8, flexWrap: 'wrap', fontSize: isMobile ? 14 : 16 }}>
<span>
<div style={{
display: 'flex',
flexDirection: isMobile ? 'column' : 'row',
alignItems: isMobile ? 'flex-start' : 'center',
gap: isMobile ? 6 : 12,
width: '100%'
}}>
<span style={{ fontSize: isMobile ? 14 : 16, fontWeight: 500, flexShrink: 0 }}>
{item.chapter_number}{item.title}
</span>
<Tag color={getStatusColor(item.status)}>{getStatusText(item.status)}</Tag>
<Badge count={`${item.word_count || 0}`} style={{ backgroundColor: '#52c41a' }} />
{renderAnalysisStatus(item.id)}
{item.expansion_plan && (
<Tooltip title="已有展开规划,点击信息图标查看详情">
<Tag icon={<CheckCircleOutlined />} color="blue">
</Tag>
</Tooltip>
)}
{!canGenerateChapter(item) && (
<Tooltip title={getGenerateDisabledReason(item)}>
<Tag icon={<LockOutlined />} color="warning">
</Tag>
</Tooltip>
)}
{item.expansion_plan && (
<Tooltip title="查看展开规划详情">
<InfoCircleOutlined
style={{ color: '#1890ff', cursor: 'pointer', fontSize: 16 }}
onClick={(e) => {
e.stopPropagation();
showExpansionPlanModal(item);
}}
/>
</Tooltip>
)}
<Space wrap size={isMobile ? 4 : 8}>
<Tag color={getStatusColor(item.status)}>{getStatusText(item.status)}</Tag>
<Badge count={`${item.word_count || 0}`} style={{ backgroundColor: '#52c41a' }} />
{renderAnalysisStatus(item.id)}
{item.expansion_plan && (
<Tooltip title="已有展开规划,点击信息图标查看详情">
<Tag icon={<CheckCircleOutlined />} color="blue">
</Tag>
</Tooltip>
)}
{!canGenerateChapter(item) && (
<Tooltip title={getGenerateDisabledReason(item)}>
<Tag icon={<LockOutlined />} color="warning">
</Tag>
</Tooltip>
)}
{item.expansion_plan && (
<Tooltip title="查看展开规划详情">
<InfoCircleOutlined
style={{ color: '#1890ff', cursor: 'pointer', fontSize: 16 }}
onClick={(e) => {
e.stopPropagation();
showExpansionPlanModal(item);
}}
/>
</Tooltip>
)}
</Space>
</div>
}
description={
@@ -1630,6 +1654,21 @@ export default function Chapters() {
progress={singleChapterProgress}
message={singleChapterProgressMessage}
/>
<FloatButton
icon={<BookOutlined />}
type="primary"
tooltip="章节目录"
onClick={() => setIsIndexPanelVisible(true)}
style={{ right: isMobile ? 24 : 48, bottom: isMobile ? 80 : 48 }}
/>
<FloatingIndexPanel
visible={isIndexPanelVisible}
onClose={() => setIsIndexPanelVisible(false)}
groupedChapters={groupedChapters}
onChapterSelect={handleChapterSelect}
/>
</div>
);
}
+9 -3
View File
@@ -140,7 +140,7 @@ export default function ProjectWizardNew() {
await wizardStreamApi.generateCompleteOutlineStream(
{
project_id: createdProjectId,
chapter_count: 5, // 开局5章
chapter_count: 3, // 生成3个大纲节点(不展开)
narrative_perspective: values.narrative_perspective,
target_words: values.target_words,
},
@@ -190,7 +190,7 @@ export default function ProjectWizardNew() {
</Title>
<Paragraph type="secondary" style={{ marginBottom: 32 }}>
AI将自动为您生成世界观
AI将自动为您生成世界观
</Paragraph>
<Form
@@ -432,7 +432,13 @@ export default function ProjectWizardNew() {
marginTop: isMobile ? 16 : 24,
marginBottom: isMobile ? 32 : 48,
}}>
{projectTitle}
{projectTitle}
</Paragraph>
<Paragraph type="secondary" style={{
fontSize: isMobile ? 12 : 14,
marginTop: 8,
}}>
💡 "大纲"
</Paragraph>
<Space