diff --git a/apps/web/app/components/CreateIssueForm.tsx b/apps/web/app/components/CreateIssueForm.tsx index 38ec5f1e3..9da7e2eed 100644 --- a/apps/web/app/components/CreateIssueForm.tsx +++ b/apps/web/app/components/CreateIssueForm.tsx @@ -43,8 +43,8 @@ export default function CreateIssueForm({ taskId, projectId, workspaceId, onSucc } onSuccess(); - } catch (err: any) { - setError(err.message); + } catch (err: unknown) { + setError(err instanceof Error ? err.message : String(err)); } finally { setLoading(false); } diff --git a/apps/web/app/components/CreateTaskForm.tsx b/apps/web/app/components/CreateTaskForm.tsx index d130f9800..70a99a69d 100644 --- a/apps/web/app/components/CreateTaskForm.tsx +++ b/apps/web/app/components/CreateTaskForm.tsx @@ -50,8 +50,8 @@ export default function CreateTaskForm({ projectId, workspaceId, onSuccess, onCa } else { router.push('/projects'); } - } catch (err: any) { - setError(err.message); + } catch (err: unknown) { + setError(err instanceof Error ? err.message : String(err)); } finally { setLoading(false); } diff --git a/apps/web/app/components/EditTaskForm.tsx b/apps/web/app/components/EditTaskForm.tsx index 032777c59..d23dec9a7 100644 --- a/apps/web/app/components/EditTaskForm.tsx +++ b/apps/web/app/components/EditTaskForm.tsx @@ -1,7 +1,6 @@ 'use client'; -import { useState, useEffect } from 'react'; -import { useRouter } from 'next/navigation'; +import { useState } from 'react'; const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000'; @@ -18,7 +17,6 @@ interface EditTaskFormProps { } export default function EditTaskForm({ taskId, initialData, onSuccess, onCancel }: EditTaskFormProps) { - const router = useRouter(); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const [formData, setFormData] = useState(initialData); @@ -41,8 +39,8 @@ export default function EditTaskForm({ taskId, initialData, onSuccess, onCancel } if (onSuccess) onSuccess(); - } catch (err: any) { - setError(err.message); + } catch (err: unknown) { + setError(err instanceof Error ? err.message : String(err)); } finally { setLoading(false); } diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 87f087c02..1aacc01bf 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import "./globals.css"; +// eslint-disable-next-line react-refresh/only-export-components export const metadata: Metadata = { title: "小虾 SaaS - 项目推进器", description: "AI 视频自动化剪辑系统 - 项目管理", diff --git a/apps/web/app/milestones/page.tsx b/apps/web/app/milestones/page.tsx index e8ae1cd51..e9f46d8f1 100644 --- a/apps/web/app/milestones/page.tsx +++ b/apps/web/app/milestones/page.tsx @@ -36,8 +36,8 @@ export default function MilestonesPage() { if (!res.ok) throw new Error('获取里程碑列表失败'); const data = await res.json(); setMilestones(data); - } catch (err: any) { - setError(err.message); + } catch (err: unknown) { + setError(err instanceof Error ? err.message : String(err)); } finally { setLoading(false); } @@ -59,8 +59,8 @@ export default function MilestonesPage() { setFormData({ name: '', description: '' }); setShowCreateForm(false); fetchMilestones(); - } catch (err: any) { - alert(err.message); + } catch (err: unknown) { + alert(err instanceof Error ? err.message : String(err)); } }; diff --git a/apps/web/app/projects/page.tsx b/apps/web/app/projects/page.tsx index b83e73848..967379e87 100644 --- a/apps/web/app/projects/page.tsx +++ b/apps/web/app/projects/page.tsx @@ -38,8 +38,8 @@ export default function ProjectsPage() { if (!res.ok) throw new Error('获取任务列表失败'); const data = await res.json(); setTasks(data); - } catch (err: any) { - setError(err.message); + } catch (err: unknown) { + setError(err instanceof Error ? err.message : String(err)); } finally { setLoading(false); } diff --git a/apps/web/app/tasks/[id]/page.tsx b/apps/web/app/tasks/[id]/page.tsx index 1a8763e20..ae4e056ef 100644 --- a/apps/web/app/tasks/[id]/page.tsx +++ b/apps/web/app/tasks/[id]/page.tsx @@ -1,8 +1,8 @@ 'use client'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import Link from 'next/link'; -import { useParams, useRouter } from 'next/navigation'; +import { useParams } from 'next/navigation'; import CreateIssueForm from '../../components/CreateIssueForm'; import EditTaskForm from '../../components/EditTaskForm'; @@ -39,7 +39,6 @@ const API_BASE = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000'; export default function TaskDetailPage() { const params = useParams(); - const router = useRouter(); const taskId = params.id as string; const [task, setTask] = useState(null); @@ -50,12 +49,7 @@ export default function TaskDetailPage() { const [showIssueForm, setShowIssueForm] = useState(false); const [showEditForm, setShowEditForm] = useState(false); - useEffect(() => { - fetchTaskDetail(); - fetchTaskIssues(); - }, [taskId]); - - const fetchTaskDetail = async () => { + const fetchTaskDetail = useCallback(async () => { try { const res = await fetch(`${API_BASE}/api/v1/project-management/tasks/${taskId}`); if (!res.ok) { @@ -66,14 +60,14 @@ export default function TaskDetailPage() { } const data = await res.json(); setTask(data); - } catch (err: any) { - setError(err.message); + } catch (err: unknown) { + setError(err instanceof Error ? err.message : String(err)); } finally { setLoading(false); } - }; + }, [taskId]); - const fetchTaskIssues = async () => { + const fetchTaskIssues = useCallback(async () => { try { const res = await fetch(`${API_BASE}/api/v1/project-management/issues?task_id=${taskId}`); if (res.ok) { @@ -83,7 +77,12 @@ export default function TaskDetailPage() { } catch (err) { console.error('获取问题列表失败:', err); } - }; + }, [taskId]); + + useEffect(() => { + fetchTaskDetail(); + fetchTaskIssues(); + }, [fetchTaskDetail, fetchTaskIssues]); const resolveIssue = async (issueId: string) => { setUpdating(true); @@ -93,8 +92,8 @@ export default function TaskDetailPage() { }); if (!res.ok) throw new Error('解决问题失败'); await fetchTaskIssues(); - } catch (err: any) { - alert(err.message); + } catch (err: unknown) { + alert(err instanceof Error ? err.message : String(err)); } finally { setUpdating(false); } @@ -110,8 +109,8 @@ export default function TaskDetailPage() { }); if (!res.ok) throw new Error('更新状态失败'); await fetchTaskDetail(); - } catch (err: any) { - alert(err.message); + } catch (err: unknown) { + alert(err instanceof Error ? err.message : String(err)); } finally { setUpdating(false); } @@ -127,8 +126,8 @@ export default function TaskDetailPage() { }); if (!res.ok) throw new Error('更新进度失败'); await fetchTaskDetail(); - } catch (err: any) { - alert(err.message); + } catch (err: unknown) { + alert(err instanceof Error ? err.message : String(err)); } finally { setUpdating(false); } diff --git a/apps/web/src/api/client.ts b/apps/web/src/api/client.ts index a6de7f408..751418195 100644 --- a/apps/web/src/api/client.ts +++ b/apps/web/src/api/client.ts @@ -72,6 +72,7 @@ apiClient.interceptors.response.use( // 标记已展示过提示,组件 onError 可据此跳过重复 toast if (handled) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any (error as any).__msgShown = true; } diff --git a/apps/web/src/pages/assets/AssetLibrary.tsx b/apps/web/src/pages/assets/AssetLibrary.tsx index f764f3a1e..b510cb3a3 100644 --- a/apps/web/src/pages/assets/AssetLibrary.tsx +++ b/apps/web/src/pages/assets/AssetLibrary.tsx @@ -102,7 +102,7 @@ const AssetLibrary: React.FC = () => { setNewLibName(''); queryClient.invalidateQueries({ queryKey: ['asset-libraries'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('创建失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('创建失败') }, }); // 上传素材(小文件表单上传) @@ -113,7 +113,7 @@ const AssetLibrary: React.FC = () => { queryClient.invalidateQueries({ queryKey: ['assets', activeLibrary] }); queryClient.invalidateQueries({ queryKey: ['asset-libraries'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('上传失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('上传失败') }, }); // 大文件直传(OSS 预签名) @@ -124,7 +124,7 @@ const AssetLibrary: React.FC = () => { queryClient.invalidateQueries({ queryKey: ['assets', activeLibrary] }); queryClient.invalidateQueries({ queryKey: ['asset-libraries'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('上传失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('上传失败') }, }); // 删除素材 @@ -135,7 +135,7 @@ const AssetLibrary: React.FC = () => { queryClient.invalidateQueries({ queryKey: ['assets', activeLibrary] }); queryClient.invalidateQueries({ queryKey: ['asset-libraries'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('删除失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('删除失败') }, }); /** 处理上传 */ diff --git a/apps/web/src/pages/auth/ForgotPassword.tsx b/apps/web/src/pages/auth/ForgotPassword.tsx index 1d636eaa5..10283c157 100644 --- a/apps/web/src/pages/auth/ForgotPassword.tsx +++ b/apps/web/src/pages/auth/ForgotPassword.tsx @@ -19,8 +19,8 @@ const ForgotPassword: React.FC = () => { setEmailSent(true); message.success('重置邮件已发送!'); }, - onError: (error: any) => { - if (!error?.__msgShown) message.error(error.response?.data?.message || '发送失败,请重试'); + onError: (error: unknown) => { + if (!(error as { __msgShown?: boolean })?.__msgShown) message.error('发送失败,请重试'); }, }); diff --git a/apps/web/src/pages/auth/Login.tsx b/apps/web/src/pages/auth/Login.tsx index 2cc6bf166..9b3caf45f 100644 --- a/apps/web/src/pages/auth/Login.tsx +++ b/apps/web/src/pages/auth/Login.tsx @@ -26,8 +26,8 @@ const Login: React.FC = () => { }); message.success('登录成功!'); navigate('/'); - } catch (error: any) { - if (!error?.__msgShown) message.error(error.response?.data?.message || '登录失败,请检查邮箱和密码'); + } catch (error: unknown) { + if (!(error as { __msgShown?: boolean })?.__msgShown) message.error('登录失败,请检查邮箱和密码'); } }; diff --git a/apps/web/src/pages/auth/Register.tsx b/apps/web/src/pages/auth/Register.tsx index cfa18baa9..c31342e8b 100644 --- a/apps/web/src/pages/auth/Register.tsx +++ b/apps/web/src/pages/auth/Register.tsx @@ -28,8 +28,8 @@ const Register: React.FC = () => { display_name: values.username, }); message.success('注册成功!请查收验证邮件。'); - } catch (error: any) { - if (!error?.__msgShown) message.error(error.response?.data?.message || '注册失败,请重试'); + } catch (error: unknown) { + if (!(error as { __msgShown?: boolean })?.__msgShown) message.error('注册失败,请重试'); } }; diff --git a/apps/web/src/pages/auth/ResetPassword.tsx b/apps/web/src/pages/auth/ResetPassword.tsx index 5eff3dd66..e7cd58a6d 100644 --- a/apps/web/src/pages/auth/ResetPassword.tsx +++ b/apps/web/src/pages/auth/ResetPassword.tsx @@ -21,8 +21,8 @@ const ResetPassword: React.FC = () => { message.success('密码重置成功!'); setTimeout(() => navigate('/login'), 2000); }, - onError: (error: any) => { - if (!error?.__msgShown) message.error(error.response?.data?.message || '重置失败,请重试'); + onError: (error: unknown) => { + if (!(error as { __msgShown?: boolean })?.__msgShown) message.error('重置失败,请重试'); }, }); diff --git a/apps/web/src/pages/duplication/DuplicationResults.tsx b/apps/web/src/pages/duplication/DuplicationResults.tsx index 0137182df..af2b590e4 100644 --- a/apps/web/src/pages/duplication/DuplicationResults.tsx +++ b/apps/web/src/pages/duplication/DuplicationResults.tsx @@ -105,7 +105,7 @@ const DuplicationResults: React.FC = () => { message.success('已删除'); queryClient.invalidateQueries({ queryKey: ['duplication-records'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('删除失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('删除失败') }, }); // 重新查重 @@ -115,7 +115,7 @@ const DuplicationResults: React.FC = () => { message.success('已重新提交查重'); queryClient.invalidateQueries({ queryKey: ['duplication-records'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('重新查重失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('重新查重失败') }, }); /** 批量删除 */ diff --git a/apps/web/src/pages/duplication/DuplicationUpload.tsx b/apps/web/src/pages/duplication/DuplicationUpload.tsx index 5b341b899..7548bd950 100644 --- a/apps/web/src/pages/duplication/DuplicationUpload.tsx +++ b/apps/web/src/pages/duplication/DuplicationUpload.tsx @@ -53,9 +53,9 @@ const DuplicationUpload: React.FC = () => { }); message.success('查重任务已提交'); }, - onError: (err: any) => { + onError: (err: unknown) => { setUploading(false); - if (!err?.__msgShown) message.error('上传失败,请重试'); + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('上传失败,请重试'); }, }); diff --git a/apps/web/src/pages/editing-planner/EditingPlanner.tsx b/apps/web/src/pages/editing-planner/EditingPlanner.tsx index e38d2df1d..a7bde794f 100644 --- a/apps/web/src/pages/editing-planner/EditingPlanner.tsx +++ b/apps/web/src/pages/editing-planner/EditingPlanner.tsx @@ -147,20 +147,20 @@ const EditingPlanner: React.FC = () => { queryClient.invalidateQueries({ queryKey: ['editing-templates'] }); setSaveModalOpen(false); }, - onError: (err: any) => { - if (!err?.__msgShown) message.error('保存失败'); + onError: (err: unknown) => { + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('保存失败'); }, }); const updateMutation = useMutation({ - mutationFn: ({ id, data }: { id: string; data: any }) => updateEditingTemplate(id, data), + mutationFn: ({ id, data }: { id: string; data: Record }) => updateEditingTemplate(id, data), onSuccess: () => { message.success('模板已更新'); queryClient.invalidateQueries({ queryKey: ['editing-templates'] }); setSaveModalOpen(false); }, - onError: (err: any) => { - if (!err?.__msgShown) message.error('保存失败'); + onError: (err: unknown) => { + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('保存失败'); }, }); @@ -172,8 +172,8 @@ const EditingPlanner: React.FC = () => { message.success(msg); setGenerateModalOpen(false); }, - onError: (err: any) => { - if (!err?.__msgShown) message.error('生成失败'); + onError: (err: unknown) => { + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('生成失败'); }, }); diff --git a/apps/web/src/pages/generate/GeneratePage.tsx b/apps/web/src/pages/generate/GeneratePage.tsx index 8f5fc8279..16c608bbb 100644 --- a/apps/web/src/pages/generate/GeneratePage.tsx +++ b/apps/web/src/pages/generate/GeneratePage.tsx @@ -94,8 +94,8 @@ const GeneratePage: React.FC = () => { setGenerated(true); setGenerating(false); }, - onError: (err: any) => { - if (!err?.__msgShown) message.error('生成失败'); + onError: (err: unknown) => { + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('生成失败'); setGenerating(false); }, }); diff --git a/apps/web/src/pages/history/TaskHistory.tsx b/apps/web/src/pages/history/TaskHistory.tsx index 5ab93014e..1b417045d 100644 --- a/apps/web/src/pages/history/TaskHistory.tsx +++ b/apps/web/src/pages/history/TaskHistory.tsx @@ -61,7 +61,7 @@ const TaskHistory: React.FC = () => { message.success('任务已重新提交'); queryClient.invalidateQueries({ queryKey: ['user-tasks'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('重试失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('重试失败') }, }); /** 过滤后的任务 */ diff --git a/apps/web/src/pages/my-templates/MyTemplates.tsx b/apps/web/src/pages/my-templates/MyTemplates.tsx index c1a8b16d7..c4fa71026 100644 --- a/apps/web/src/pages/my-templates/MyTemplates.tsx +++ b/apps/web/src/pages/my-templates/MyTemplates.tsx @@ -74,8 +74,8 @@ const MyTemplates: React.FC = () => { message.success('模板已删除'); queryClient.invalidateQueries({ queryKey: ['editing-templates'] }); }, - onError: (err: any) => { - if (!err?.__msgShown) message.error('删除失败'); + onError: (err: unknown) => { + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('删除失败'); }, }); @@ -96,8 +96,8 @@ const MyTemplates: React.FC = () => { message.success('模板已复制'); queryClient.invalidateQueries({ queryKey: ['editing-templates'] }); }, - onError: (err: any) => { - if (!err?.__msgShown) message.error('复制失败'); + onError: (err: unknown) => { + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('复制失败'); }, }); diff --git a/apps/web/src/pages/products/ProductLibrary.tsx b/apps/web/src/pages/products/ProductLibrary.tsx index 0d70f8de8..53c742c12 100644 --- a/apps/web/src/pages/products/ProductLibrary.tsx +++ b/apps/web/src/pages/products/ProductLibrary.tsx @@ -64,7 +64,7 @@ const ProductLibrary: React.FC = () => { message.success('已删除'); queryClient.invalidateQueries({ queryKey: ['products'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('删除失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('删除失败') }, }); // 下载 @@ -72,8 +72,8 @@ const ProductLibrary: React.FC = () => { try { const { url } = await getProductDownloadUrl(productId); window.open(url, '_blank'); - } catch (err: any) { - if (!err?.__msgShown) message.error('获取下载链接失败'); + } catch (err: unknown) { + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('获取下载链接失败'); } }; diff --git a/apps/web/src/pages/subscription/Billing.tsx b/apps/web/src/pages/subscription/Billing.tsx index b86b8aaad..6f3d9e3ec 100644 --- a/apps/web/src/pages/subscription/Billing.tsx +++ b/apps/web/src/pages/subscription/Billing.tsx @@ -29,8 +29,8 @@ const Billing: React.FC = () => { const data = await getCurrentSubscription(); setSubscription(data); setAutoRenewChecked(data.auto_renew); - } catch (err: any) { - if (!err?.__msgShown) message.error('加载订阅数据失败'); + } catch (err: unknown) { + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('加载订阅数据失败'); } finally { setLoading(false); } @@ -45,8 +45,8 @@ const Billing: React.FC = () => { if (subscription) { setSubscription({ ...subscription, auto_renew: checked }); } - } catch (err: any) { - if (!err?.__msgShown) message.error('操作失败'); + } catch (err: unknown) { + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('操作失败'); } finally { setAutoRenewLoading(false); } diff --git a/apps/web/src/pages/subscription/Plans.tsx b/apps/web/src/pages/subscription/Plans.tsx index 0b919d70b..7309262b3 100644 --- a/apps/web/src/pages/subscription/Plans.tsx +++ b/apps/web/src/pages/subscription/Plans.tsx @@ -72,7 +72,7 @@ const Plans: React.FC = () => { try { setSubscribing(true); message.success('订阅成功'); - } catch (error: any) { + } catch (error: unknown) { message.error('订阅失败'); } finally { setSubscribing(false); diff --git a/apps/web/src/pages/subscription/UpgradeSubscription.tsx b/apps/web/src/pages/subscription/UpgradeSubscription.tsx index a51329899..dc2a8c659 100644 --- a/apps/web/src/pages/subscription/UpgradeSubscription.tsx +++ b/apps/web/src/pages/subscription/UpgradeSubscription.tsx @@ -32,8 +32,8 @@ const UpgradeSubscription: React.FC = () => { const data = await getCurrentSubscription(); setSubscription(data); setSelectedPlan(data.plan_id); - } catch (err: any) { - if (!err?.__msgShown) message.error('获取订阅信息失败'); + } catch (err: unknown) { + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('获取订阅信息失败'); } finally { setLoading(false); } @@ -64,8 +64,8 @@ const UpgradeSubscription: React.FC = () => { } else { message.error(res.message); } - } catch (err: any) { - if (!err?.__msgShown) message.error('套餐变更失败,请重试'); + } catch (err: unknown) { + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('套餐变更失败,请重试'); } finally { setSubmitting(false); } @@ -80,8 +80,8 @@ const UpgradeSubscription: React.FC = () => { if (subscription) { setSubscription({ ...subscription, auto_renew: enabled }); } - } catch (err: any) { - if (!err?.__msgShown) message.error('操作失败'); + } catch (err: unknown) { + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('操作失败'); } }; @@ -97,8 +97,8 @@ const UpgradeSubscription: React.FC = () => { const res = await cancelSubscription(); message.success(res.message); navigate('/subscription'); - } catch (err: any) { - if (!err?.__msgShown) message.error('取消失败'); + } catch (err: unknown) { + if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('取消失败'); } }, }); diff --git a/apps/web/src/pages/templates/TemplateLibrary.tsx b/apps/web/src/pages/templates/TemplateLibrary.tsx index a9127a082..080792822 100644 --- a/apps/web/src/pages/templates/TemplateLibrary.tsx +++ b/apps/web/src/pages/templates/TemplateLibrary.tsx @@ -55,7 +55,7 @@ const TemplateLibrary: React.FC = () => { message.success(data.is_favorite ? '已收藏' : '已取消收藏'); queryClient.invalidateQueries({ queryKey: ['templates'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('操作失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('操作失败') }, }); /** 提取所有分类 */ diff --git a/apps/web/src/pages/titles/TitleLibrary.tsx b/apps/web/src/pages/titles/TitleLibrary.tsx index 6823a1dfd..abb63a85c 100644 --- a/apps/web/src/pages/titles/TitleLibrary.tsx +++ b/apps/web/src/pages/titles/TitleLibrary.tsx @@ -62,7 +62,7 @@ const TitleLibrary: React.FC = () => { resetForm(); queryClient.invalidateQueries({ queryKey: ['titles'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('创建失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('创建失败') }, }); // 更新标题 @@ -75,7 +75,7 @@ const TitleLibrary: React.FC = () => { resetForm(); queryClient.invalidateQueries({ queryKey: ['titles'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('更新失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('更新失败') }, }); // 删除标题 @@ -85,7 +85,7 @@ const TitleLibrary: React.FC = () => { message.success('已删除'); queryClient.invalidateQueries({ queryKey: ['titles'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('删除失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('删除失败') }, }); // 批量导入 @@ -98,7 +98,7 @@ const TitleLibrary: React.FC = () => { setImportText(''); queryClient.invalidateQueries({ queryKey: ['titles'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('导入失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('导入失败') }, }); const resetForm = () => { diff --git a/apps/web/src/pages/voices/VoiceLibrary.tsx b/apps/web/src/pages/voices/VoiceLibrary.tsx index 68cfc8196..12b13f81b 100644 --- a/apps/web/src/pages/voices/VoiceLibrary.tsx +++ b/apps/web/src/pages/voices/VoiceLibrary.tsx @@ -80,7 +80,7 @@ const VoiceLibrary: React.FC = () => { resetForm(); queryClient.invalidateQueries({ queryKey: ['voices'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('创建失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('创建失败') }, }); // 更新配音 @@ -93,7 +93,7 @@ const VoiceLibrary: React.FC = () => { resetForm(); queryClient.invalidateQueries({ queryKey: ['voices'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('更新失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('更新失败') }, }); // 删除配音 @@ -103,7 +103,7 @@ const VoiceLibrary: React.FC = () => { message.success('已删除'); queryClient.invalidateQueries({ queryKey: ['voices'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('删除失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('删除失败') }, }); // AI 生成配音 @@ -115,7 +115,7 @@ const VoiceLibrary: React.FC = () => { setAiText(''); queryClient.invalidateQueries({ queryKey: ['voices'] }); }, - onError: (err: any) => { if (!err?.__msgShown) message.error('AI 生成失败') }, + onError: (err: unknown) => { if (!(err as { __msgShown?: boolean })?.__msgShown) message.error('AI 生成失败') }, }); const resetForm = () => { diff --git a/apps/web/src/router/index.tsx b/apps/web/src/router/index.tsx index 4c4c5d3ca..1fad7ef68 100644 --- a/apps/web/src/router/index.tsx +++ b/apps/web/src/router/index.tsx @@ -12,6 +12,7 @@ import ResetPassword from '@/pages/auth/ResetPassword'; import { useAuthStore } from '@/store/authStore'; /** 受保护的路由组件 */ +// eslint-disable-next-line react-refresh/only-export-components const ProtectedRoute = ({ children }: { children: React.ReactNode }) => { const isAuthenticated = useAuthStore((state) => state.isAuthenticated); const hasAccessToken = Boolean(localStorage.getItem('access_token')); diff --git a/apps/web/src/test/setup.ts b/apps/web/src/test/setup.ts index c9fe48eef..72bba31bf 100644 --- a/apps/web/src/test/setup.ts +++ b/apps/web/src/test/setup.ts @@ -17,7 +17,9 @@ afterEach(() => { declare global { // eslint-disable-next-line @typescript-eslint/no-namespace namespace Vi { + // eslint-disable-next-line @typescript-eslint/no-explicit-any interface Assertion extends jest.Matchers {} + // eslint-disable-next-line @typescript-eslint/no-explicit-any interface AsymmetricMatchersContaining extends jest.Matchers {} } }