fix: 修复多处TypeScript类型错误(Inspiration、ExpansionPlanEditor、sseClient等)

This commit is contained in:
xiamuceer-j
2026-01-14 14:33:43 +08:00
parent aeb78fddd2
commit 7ba2b2e5fa
31 changed files with 347 additions and 192 deletions
+8 -2
View File
@@ -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);
+34 -20
View File
@@ -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 || '启动生成失败');
}
};
+15 -13
View File
@@ -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'
});
}
+37 -35
View File
@@ -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>
{/* 重新开始按钮 - 只在对话进行中显示 */}
+1
View File
@@ -83,6 +83,7 @@ export default function Organizations() {
} finally {
setLoading(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [projectId]);
const loadCharacters = useCallback(async () => {
+3 -1
View File
@@ -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>
+1
View File
@@ -61,6 +61,7 @@ export default function Relationships() {
if (projectId) {
loadData();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [projectId]);
const loadData = async () => {
+19 -3
View File
@@ -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;
// 移动端:使用下拉菜单
+1 -1
View File
@@ -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,
+1
View File
@@ -53,6 +53,7 @@ export default function WritingStyles() {
// 加载风格列表 - 如果有项目则加载项目风格(包含默认标记),否则加载用户风格
useEffect(() => {
loadStyles();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentProject?.id]);
const loadStyles = async () => {