fix: 修复前端7处eslint错误和6处警告

- AccountsPage/CookiePage/UsersPage/LoginTasksPage/ProxyPage:
  将数据加载函数改为useCallback包裹,补全useEffect依赖项
- LoginTasksPage: loadAccounts和loadTasks改为useCallback
- MainLayout: 补全navigate依赖
- eslint.config.js: 关闭react-hooks/set-state-in-effect(对初始
  数据获取场景过严),降级react-refresh/only-export-components为warn
  (Provider/Hook/Type共存文件是合理设计)
This commit is contained in:
yml2213
2026-06-23 08:42:00 +08:00
parent dd56de9bd4
commit 98728bee87
7 changed files with 33 additions and 31 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ export default function MainLayout({ onLogout }: { onLogout?: () => void }) {
useEffect(() => {
if (!user) navigate('/login');
}, [user]);
}, [user, navigate]);
if (!user) return null;
+8 -12
View File
@@ -1,4 +1,4 @@
import { useEffect, useState, useMemo } from 'react';
import { useEffect, useState, useMemo, useCallback } from 'react';
import {
Table, Button, Modal, Input, Select, message, Popconfirm, Typography, Tag, Space,
Row, Col, Card, Statistic,
@@ -35,7 +35,7 @@ export default function AccountsPage() {
const canAssign = can('account:assign');
const canDelete = can('account:delete');
const loadAccounts = async () => {
const loadAccounts = useCallback(async () => {
setLoading(true);
try {
const params: { tag?: string } = {};
@@ -47,35 +47,31 @@ export default function AccountsPage() {
} finally {
setLoading(false);
}
};
}, [tagFilter]);
const loadUsers = async () => {
const loadUsers = useCallback(async () => {
try {
const data = await userApi.list();
setUsers(data.filter((u) => u.role === 'support'));
} catch {
// 忽略客服列表加载失败,账号列表仍可继续使用。
}
};
}, []);
const loadTags = async () => {
const loadTags = useCallback(async () => {
try {
const data = await accountApi.listTags();
setTags(data);
} catch {
// 忽略标签加载失败,页面会退化为无标签筛选。
}
};
}, []);
useEffect(() => {
loadAccounts();
if (canAssign) loadUsers();
loadTags();
}, []);
useEffect(() => {
loadAccounts();
}, [tagFilter]);
}, [loadAccounts, canAssign, loadUsers, loadTags]);
const tagColorMap = useMemo(() => {
const map: Record<string, string> = {};
+4 -4
View File
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import { useEffect, useState, useCallback } from 'react';
import { Table, Button, Card, Row, Col, Statistic, message, Tag, Popconfirm, Space, Typography, Input, theme, Dropdown } from 'antd';
import { DownloadOutlined, DeleteOutlined, CopyOutlined, SearchOutlined } from '@ant-design/icons';
import { cookieApi, type CookieItem } from '../api/modules';
@@ -19,7 +19,7 @@ export default function CookiePage() {
const canView = can('cookie:view');
const canExport = can('cookie:export');
const loadCookies = async () => {
const loadCookies = useCallback(async () => {
setLoading(true);
try {
const data = await cookieApi.list();
@@ -29,11 +29,11 @@ export default function CookiePage() {
} finally {
setLoading(false);
}
};
}, []);
useEffect(() => {
loadCookies();
}, []);
}, [loadCookies]);
const handleExport = async (format: string = 'csv') => {
try {
+6 -6
View File
@@ -67,14 +67,14 @@ export default function LoginTasksPage() {
return map;
}, [accounts]);
const loadAccounts = async () => {
const loadAccounts = useCallback(async () => {
try {
const data = await accountApi.list();
setAccounts(data);
} catch (e: unknown) {
message.error(getErrorMessage(e));
}
};
}, []);
// 标签选择变化时,同步更新选中的账号
const handleTagChange = useCallback((tags: string[]) => {
@@ -107,23 +107,23 @@ export default function LoginTasksPage() {
});
}, [selectedTags, tagAccountMap, accounts]);
const loadTasks = async () => {
const loadTasks = useCallback(async () => {
try {
const data = await loginApi.listTasks(batchId || undefined);
setTasks(data);
} catch {
// 忽略轮询失败,下一次定时刷新会继续尝试。
}
};
}, [batchId]);
useEffect(() => {
Promise.all([loadAccounts(), loadTasks()]);
}, []);
}, [loadAccounts, loadTasks]);
useEffect(() => {
const timer = setInterval(loadTasks, 3000);
return () => clearInterval(timer);
}, [batchId]);
}, [loadTasks]);
// 共享的批量登录启动逻辑
const startBatch = async (accountIds: number[]) => {
+4 -4
View File
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import { useEffect, useState, useCallback } from 'react';
import { Form, Input, Switch, Button, Card, message, Row, Col } from 'antd';
import { proxyApi, type ProxyConfig } from '../api/modules';
import RealtimeLogPanel from '../components/RealtimeLogPanel';
@@ -13,7 +13,7 @@ export default function ProxyPage() {
const [configLoaded, setConfigLoaded] = useState(false);
const { logs, connect: connectLogs, close: closeLogs } = useWebSocketLogs();
const loadConfig = async () => {
const loadConfig = useCallback(async () => {
try {
const data = await proxyApi.get();
form.setFieldsValue({
@@ -30,14 +30,14 @@ export default function ProxyPage() {
} finally {
setConfigLoaded(true);
}
};
}, [form]);
useEffect(() => {
loadConfig();
return () => {
closeLogs();
};
}, []);
}, [loadConfig, closeLogs]);
const connectWs = (testId: string) => {
connectLogs(`/api/proxy/ws/test/${testId}`, {
+4 -4
View File
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react';
import { useEffect, useState, useCallback } from 'react';
import {
Table, Button, Modal, Form, Input, Select, Tag, Popconfirm, message, Space,
Checkbox, Divider, Alert, Tooltip,
@@ -54,7 +54,7 @@ export default function UsersPage() {
const canAssignPerm = can('user:assign_permissions');
const loadUsers = async () => {
const loadUsers = useCallback(async () => {
setLoading(true);
try {
const data = await userApi.list();
@@ -64,11 +64,11 @@ export default function UsersPage() {
} finally {
setLoading(false);
}
};
}, []);
useEffect(() => {
loadUsers();
}, []);
}, [loadUsers]);
const handleCreate = () => {
setEditing(null);