fix: 修复多处TypeScript类型错误(Inspiration、ExpansionPlanEditor、sseClient等)
This commit is contained in:
@@ -10,7 +10,13 @@ export default function AuthCallback() {
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
const [showAnnouncement, setShowAnnouncement] = useState(false);
|
||||
const [showPasswordModal, setShowPasswordModal] = useState(false);
|
||||
const [passwordStatus, setPasswordStatus] = useState<any>(null);
|
||||
interface PasswordStatus {
|
||||
has_password: boolean;
|
||||
has_custom_password: boolean;
|
||||
username: string;
|
||||
default_password: string;
|
||||
}
|
||||
const [passwordStatus, setPasswordStatus] = useState<PasswordStatus | null>(null);
|
||||
const [newPassword, setNewPassword] = useState('');
|
||||
const [confirmPassword, setConfirmPassword] = useState('');
|
||||
const [settingPassword, setSettingPassword] = useState(false);
|
||||
@@ -187,7 +193,7 @@ export default function AuthCallback() {
|
||||
setShowAnnouncement(true);
|
||||
}, 500);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
message.error('密码设置失败,请重试');
|
||||
} finally {
|
||||
setSettingPassword(false);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { Button, Modal, Form, Input, Select, message, Row, Col, Empty, Tabs, Card, Tag, Space, Divider, Typography, InputNumber } from 'antd';
|
||||
import { ThunderboltOutlined, PlusOutlined, EditOutlined, DeleteOutlined, TrophyOutlined } from '@ant-design/icons';
|
||||
import { useParams } from 'react-router-dom';
|
||||
@@ -46,26 +46,26 @@ export default function Careers() {
|
||||
const [aiProgress, setAiProgress] = useState(0);
|
||||
const [aiMessage, setAiMessage] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (projectId) {
|
||||
fetchCareers();
|
||||
}
|
||||
}, [projectId]);
|
||||
|
||||
const fetchCareers = async () => {
|
||||
const fetchCareers = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response: any = await api.get('/careers', {
|
||||
const response = await api.get('/careers', {
|
||||
params: { project_id: projectId }
|
||||
});
|
||||
}) as { main_careers?: Career[]; sub_careers?: Career[] };
|
||||
setMainCareers(response.main_careers || []);
|
||||
setSubCareers(response.sub_careers || []);
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
console.error('获取职业列表失败:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
}, [projectId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (projectId) {
|
||||
fetchCareers();
|
||||
}
|
||||
}, [projectId, fetchCareers]);
|
||||
|
||||
const handleOpenModal = (career?: Career) => {
|
||||
if (career) {
|
||||
@@ -81,7 +81,18 @@ export default function Careers() {
|
||||
setIsModalOpen(true);
|
||||
};
|
||||
|
||||
const handleSubmit = async (values: any) => {
|
||||
interface CareerFormValues {
|
||||
name: string;
|
||||
type: 'main' | 'sub';
|
||||
description?: string;
|
||||
category?: string;
|
||||
stages?: string;
|
||||
requirements?: string;
|
||||
special_abilities?: string;
|
||||
worldview_rules?: string;
|
||||
}
|
||||
|
||||
const handleSubmit = async (values: CareerFormValues) => {
|
||||
try {
|
||||
// 解析阶段数据
|
||||
const stagesText = values.stages || '';
|
||||
@@ -124,8 +135,9 @@ export default function Careers() {
|
||||
setIsModalOpen(false);
|
||||
form.resetFields();
|
||||
fetchCareers();
|
||||
} catch (error: any) {
|
||||
message.error(error.response?.data?.detail || '操作失败');
|
||||
} catch (error: unknown) {
|
||||
const axiosError = error as { response?: { data?: { detail?: string } } };
|
||||
message.error(axiosError.response?.data?.detail || '操作失败');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -139,14 +151,15 @@ export default function Careers() {
|
||||
await api.delete(`/careers/${id}`);
|
||||
message.success('职业删除成功');
|
||||
fetchCareers();
|
||||
} catch (error: any) {
|
||||
message.error(error.response?.data?.detail || '删除失败');
|
||||
} catch (error: unknown) {
|
||||
const axiosError = error as { response?: { data?: { detail?: string } } };
|
||||
message.error(axiosError.response?.data?.detail || '删除失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleAIGenerate = async (values: any) => {
|
||||
const handleAIGenerate = async (values: { main_career_count: number; sub_career_count: number }) => {
|
||||
setIsAIModalOpen(false);
|
||||
setAiGenerating(true);
|
||||
setAiProgress(0);
|
||||
@@ -193,9 +206,10 @@ export default function Careers() {
|
||||
setAiGenerating(false);
|
||||
message.error('连接中断,生成失败');
|
||||
};
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
setAiGenerating(false);
|
||||
message.error(err.message || '启动生成失败');
|
||||
const error = err as Error;
|
||||
message.error(error.message || '启动生成失败');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { Card, Spin, Alert, Button, Space, Switch, Drawer, message, Progress } from 'antd';
|
||||
import {
|
||||
@@ -75,13 +75,7 @@ const ChapterReader: React.FC = () => {
|
||||
const [analysisProgress, setAnalysisProgress] = useState(0);
|
||||
const [navigation, setNavigation] = useState<NavigationData | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (chapterId) {
|
||||
loadChapterData();
|
||||
}
|
||||
}, [chapterId]);
|
||||
|
||||
const loadChapterData = async () => {
|
||||
const loadChapterData = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
@@ -130,13 +124,20 @@ const ChapterReader: React.FC = () => {
|
||||
} else {
|
||||
setAnnotationsData(null);
|
||||
}
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
console.error('加载章节数据失败:', err);
|
||||
setError(err.response?.data?.detail || err.message || '加载失败');
|
||||
const error = err as { response?: { data?: { detail?: string } }; message?: string };
|
||||
setError(error.response?.data?.detail || error.message || '加载失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
}, [chapterId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (chapterId) {
|
||||
loadChapterData();
|
||||
}
|
||||
}, [chapterId, loadChapterData]);
|
||||
|
||||
const handleAnnotationClick = (annotation: MemoryAnnotation) => {
|
||||
setActiveAnnotationId(annotation.id);
|
||||
@@ -211,10 +212,11 @@ const ChapterReader: React.FC = () => {
|
||||
}
|
||||
}, 30000);
|
||||
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
setAnalyzing(false);
|
||||
const error = err as { response?: { data?: { detail?: string } } };
|
||||
message.error({
|
||||
content: err.response?.data?.detail || '触发分析失败',
|
||||
content: error.response?.data?.detail || '触发分析失败',
|
||||
key: 'analyze'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Card, Input, Button, Space, Typography, message, Spin, Modal } from 'antd';
|
||||
import { SendOutlined, ArrowLeftOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||
@@ -102,8 +102,18 @@ const Inspiration: React.FC = () => {
|
||||
|
||||
// ==================== 缓存管理函数 ====================
|
||||
|
||||
// 清除缓存
|
||||
const clearCache = useCallback(() => {
|
||||
try {
|
||||
localStorage.removeItem(CACHE_KEY);
|
||||
console.log('🗑️ 缓存已清除');
|
||||
} catch (error) {
|
||||
console.error('清除缓存失败:', error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 保存到缓存
|
||||
const saveToCache = () => {
|
||||
const saveToCache = useCallback(() => {
|
||||
try {
|
||||
// 只在对话阶段保存,生成阶段不保存
|
||||
if (currentStep === 'generating' || currentStep === 'complete') {
|
||||
@@ -130,10 +140,10 @@ const Inspiration: React.FC = () => {
|
||||
} catch (error) {
|
||||
console.error('保存缓存失败:', error);
|
||||
}
|
||||
};
|
||||
}, [currentStep, messages, wizardData, initialIdea, selectedOptions, lastFailedRequest]);
|
||||
|
||||
// 从缓存恢复
|
||||
const restoreFromCache = (): boolean => {
|
||||
const restoreFromCache = useCallback((): boolean => {
|
||||
try {
|
||||
const cached = localStorage.getItem(CACHE_KEY);
|
||||
if (!cached) {
|
||||
@@ -174,17 +184,7 @@ const Inspiration: React.FC = () => {
|
||||
clearCache();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 清除缓存
|
||||
const clearCache = () => {
|
||||
try {
|
||||
localStorage.removeItem(CACHE_KEY);
|
||||
console.log('🗑️ 缓存已清除');
|
||||
} catch (error) {
|
||||
console.error('清除缓存失败:', error);
|
||||
}
|
||||
};
|
||||
}, [clearCache]);
|
||||
|
||||
// ==================== 组件挂载时恢复缓存 ====================
|
||||
|
||||
@@ -193,7 +193,7 @@ const Inspiration: React.FC = () => {
|
||||
restoreFromCache();
|
||||
setCacheLoaded(true);
|
||||
}
|
||||
}, []);
|
||||
}, [cacheLoaded, restoreFromCache]);
|
||||
|
||||
// ==================== 自动保存:状态变化时保存 ====================
|
||||
|
||||
@@ -206,7 +206,7 @@ const Inspiration: React.FC = () => {
|
||||
}, 500);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [messages, currentStep, wizardData, initialIdea, selectedOptions, lastFailedRequest, cacheLoaded]);
|
||||
}, [messages, currentStep, wizardData, initialIdea, selectedOptions, lastFailedRequest, cacheLoaded, saveToCache]);
|
||||
|
||||
// 自动滚动到底部
|
||||
const scrollToBottom = () => {
|
||||
@@ -259,7 +259,7 @@ const Inspiration: React.FC = () => {
|
||||
};
|
||||
setMessages(prev => [...prev, aiMessage]);
|
||||
setLastFailedRequest(null);
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
console.error('重试失败:', error);
|
||||
message.error('重试失败,请稍后再试');
|
||||
} finally {
|
||||
@@ -307,7 +307,7 @@ const Inspiration: React.FC = () => {
|
||||
const step = targetMessage.step as 'title' | 'description' | 'theme' | 'genre';
|
||||
|
||||
// 构建上下文
|
||||
const context: any = {
|
||||
const context: Partial<WizardData> & { initial_idea?: string } = {
|
||||
initial_idea: initialIdea,
|
||||
title: wizardData.title,
|
||||
description: wizardData.description,
|
||||
@@ -339,9 +339,11 @@ const Inspiration: React.FC = () => {
|
||||
setMessages(prev => [...prev, aiMessage]);
|
||||
|
||||
message.success('已根据您的反馈重新生成选项');
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
console.error('优化选项失败:', error);
|
||||
message.error(error.response?.data?.detail || '优化失败,请重试');
|
||||
const errMsg = error instanceof Error ? error.message : '优化失败,请重试';
|
||||
const axiosError = error as { response?: { data?: { detail?: string } } };
|
||||
message.error(axiosError.response?.data?.detail || errMsg);
|
||||
} finally {
|
||||
setRefining(false);
|
||||
}
|
||||
@@ -406,9 +408,11 @@ const Inspiration: React.FC = () => {
|
||||
} else {
|
||||
await handleCustomInput(userInput);
|
||||
}
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
console.error('发送消息失败:', error);
|
||||
message.error(error.response?.data?.detail || '生成失败,请重试');
|
||||
const errMsg = error instanceof Error ? error.message : '生成失败,请重试';
|
||||
const axiosError = error as { response?: { data?: { detail?: string } } };
|
||||
message.error(axiosError.response?.data?.detail || errMsg);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -575,9 +579,11 @@ const Inspiration: React.FC = () => {
|
||||
setWizardData(updatedData);
|
||||
|
||||
await generateNextStep(updatedData);
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
console.error('选择选项失败:', error);
|
||||
message.error(error.response?.data?.detail || '生成失败,请重试');
|
||||
const errMsg = error instanceof Error ? error.message : '生成失败,请重试';
|
||||
const axiosError = error as { response?: { data?: { detail?: string } } };
|
||||
message.error(axiosError.response?.data?.detail || errMsg);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -625,9 +631,11 @@ const Inspiration: React.FC = () => {
|
||||
|
||||
setWizardData(updatedData);
|
||||
await generateNextStep(updatedData);
|
||||
} catch (error: any) {
|
||||
} catch (error: unknown) {
|
||||
console.error('处理自定义输入失败:', error);
|
||||
message.error(error.response?.data?.detail || '处理失败,请重试');
|
||||
const errMsg = error instanceof Error ? error.message : '处理失败,请重试';
|
||||
const axiosError = error as { response?: { data?: { detail?: string } } };
|
||||
message.error(axiosError.response?.data?.detail || errMsg);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -1050,7 +1058,7 @@ const Inspiration: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
minHeight: '100vh',
|
||||
minHeight: '100dvh',
|
||||
background: 'var(--color-bg-base)',
|
||||
}}>
|
||||
{contextHolder}
|
||||
@@ -1118,7 +1126,7 @@ const Inspiration: React.FC = () => {
|
||||
color: '#fff',
|
||||
}}
|
||||
>
|
||||
{isMobile ? '返回' : '返回项目列表'}
|
||||
{isMobile ? '返回' : '返回首页'}
|
||||
</Button>
|
||||
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
@@ -1133,12 +1141,6 @@ const Inspiration: React.FC = () => {
|
||||
>
|
||||
✨ 灵感模式
|
||||
</Title>
|
||||
<Text style={{
|
||||
color: 'rgba(255,255,255,0.85)',
|
||||
fontSize: isMobile ? 12 : 14,
|
||||
}}>
|
||||
通过对话快速创建你的小说项目
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
{/* 重新开始按钮 - 只在对话进行中显示 */}
|
||||
|
||||
@@ -83,6 +83,7 @@ export default function Organizations() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [projectId]);
|
||||
|
||||
const loadCharacters = useCallback(async () => {
|
||||
|
||||
@@ -39,6 +39,7 @@ export default function ProjectWizardNew() {
|
||||
setResumeProjectId(projectId);
|
||||
handleResumeGeneration(projectId);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchParams]);
|
||||
|
||||
// 恢复未完成项目的生成
|
||||
@@ -320,7 +321,7 @@ export default function ProjectWizardNew() {
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
minHeight: '100vh',
|
||||
minHeight: '100dvh',
|
||||
background: 'var(--color-bg-base)',
|
||||
}}>
|
||||
{/* 顶部标题栏 - 固定不滚动 */}
|
||||
@@ -358,6 +359,7 @@ export default function ProjectWizardNew() {
|
||||
color: '#fff',
|
||||
textShadow: '0 2px 4px rgba(0,0,0,0.1)',
|
||||
}}>
|
||||
<RocketOutlined style={{ marginRight: 8 }} />
|
||||
项目创建向导
|
||||
</Title>
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ export default function Relationships() {
|
||||
if (projectId) {
|
||||
loadData();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [projectId]);
|
||||
|
||||
const loadData = async () => {
|
||||
|
||||
@@ -90,7 +90,16 @@ export default function UserManagement() {
|
||||
}, []);
|
||||
|
||||
// 添加用户
|
||||
const handleCreate = async (values: any) => {
|
||||
interface CreateUserValues {
|
||||
username: string;
|
||||
display_name: string;
|
||||
password?: string;
|
||||
avatar_url?: string;
|
||||
trust_level?: number;
|
||||
is_admin?: boolean;
|
||||
}
|
||||
|
||||
const handleCreate = async (values: CreateUserValues) => {
|
||||
try {
|
||||
const res = await adminApi.createUser(values);
|
||||
message.success('用户创建成功');
|
||||
@@ -134,7 +143,14 @@ export default function UserManagement() {
|
||||
setEditModalVisible(true);
|
||||
};
|
||||
|
||||
const handleUpdate = async (values: any) => {
|
||||
interface UpdateUserValues {
|
||||
display_name: string;
|
||||
avatar_url?: string;
|
||||
trust_level?: number;
|
||||
is_admin?: boolean;
|
||||
}
|
||||
|
||||
const handleUpdate = async (values: UpdateUserValues) => {
|
||||
if (!currentUser) return;
|
||||
|
||||
try {
|
||||
@@ -290,7 +306,7 @@ export default function UserManagement() {
|
||||
key: 'action',
|
||||
width: isMobile ? 80 : 300,
|
||||
fixed: 'right' as const,
|
||||
render: (_: any, record: UserWithStatus) => {
|
||||
render: (_: unknown, record: UserWithStatus) => {
|
||||
const isActive = record.is_active !== false;
|
||||
|
||||
// 移动端:使用下拉菜单
|
||||
|
||||
@@ -58,7 +58,7 @@ export default function WorldSetting() {
|
||||
// 可以在这里显示生成的内容片段(可选)
|
||||
console.log('生成片段:', chunk);
|
||||
},
|
||||
onResult: (result: any) => {
|
||||
onResult: (result: { time_period: string; location: string; atmosphere: string; rules: string }) => {
|
||||
// 保存新生成的数据
|
||||
const newData = {
|
||||
time_period: result.time_period,
|
||||
|
||||
@@ -53,6 +53,7 @@ export default function WritingStyles() {
|
||||
// 加载风格列表 - 如果有项目则加载项目风格(包含默认标记),否则加载用户风格
|
||||
useEffect(() => {
|
||||
loadStyles();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [currentProject?.id]);
|
||||
|
||||
const loadStyles = async () => {
|
||||
|
||||
Reference in New Issue
Block a user