From efd5a107b9b81386cd707a6e4e4e62a952e7779b Mon Sep 17 00:00:00 2001 From: root Date: Fri, 6 Feb 2026 06:09:17 +0000 Subject: [PATCH] fix: migrate frontend to Vite 7 and resolve lint warnings --- .github/workflows/ci-build.yml | 2 +- vite-frontend/package.json | 8 +- vite-frontend/src/App.tsx | 4 +- vite-frontend/src/api/network.ts | 4 - vite-frontend/src/components/navbar.tsx | 8 +- vite-frontend/src/config/site.ts | 2 +- vite-frontend/src/layouts/admin.tsx | 7 +- vite-frontend/src/layouts/h5-simple.tsx | 2 +- vite-frontend/src/layouts/h5.tsx | 2 +- vite-frontend/src/pages/change-password.tsx | 3 +- vite-frontend/src/pages/config.tsx | 6 +- vite-frontend/src/pages/dashboard.tsx | 29 +- vite-frontend/src/pages/forward.tsx | 597 +++++++++++--------- vite-frontend/src/pages/index.tsx | 7 +- vite-frontend/src/pages/limit.tsx | 136 +++-- vite-frontend/src/pages/node.tsx | 41 +- vite-frontend/src/pages/profile.tsx | 3 +- vite-frontend/src/pages/tunnel.tsx | 65 ++- vite-frontend/src/pages/user.tsx | 50 +- vite-frontend/src/types/tac.d.ts | 13 +- vite-frontend/src/utils/auth.ts | 6 +- vite-frontend/src/utils/jwt.ts | 2 +- vite-frontend/src/utils/panel.ts | 2 +- 23 files changed, 550 insertions(+), 449 deletions(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index aa4f18f..4d11043 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -19,7 +19,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '20.19.0' - name: Install dependencies run: npm install --legacy-peer-deps diff --git a/vite-frontend/package.json b/vite-frontend/package.json index c4016d1..471f91d 100644 --- a/vite-frontend/package.json +++ b/vite-frontend/package.json @@ -45,7 +45,7 @@ "@react-aria/visually-hidden": "3.8.25", "@react-types/shared": "3.30.0", "@tailwindcss/postcss": "4.1.11", - "@tailwindcss/vite": "4.1.11", + "@tailwindcss/vite": "^4.1.18", "@types/react-beautiful-dnd": "^13.1.8", "axios": "^1.11.0", "clsx": "2.1.1", @@ -70,7 +70,7 @@ "@types/react-dom": "18.3.0", "@typescript-eslint/eslint-plugin": "8.31.1", "@typescript-eslint/parser": "8.31.1", - "@vitejs/plugin-react": "4.4.1", + "@vitejs/plugin-react": "^5.1.3", "eslint": "9.39.2", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.31.0", @@ -84,7 +84,7 @@ "postcss": "8.5.6", "prettier": "3.5.3", "typescript": "5.6.3", - "vite": "5.4.21", - "vite-tsconfig-paths": "4.3.2" + "vite": "^7.3.1", + "vite-tsconfig-paths": "^6.0.5" } } diff --git a/vite-frontend/src/App.tsx b/vite-frontend/src/App.tsx index 4d5bbdd..bc642d1 100644 --- a/vite-frontend/src/App.tsx +++ b/vite-frontend/src/App.tsx @@ -148,9 +148,7 @@ function App() { if (cachedAppName && cachedAppName !== document.title) { document.title = cachedAppName; } - } catch (error) { - console.warn("检查标题更新失败:", error); - } + } catch {} }; // 延迟检查,避免阻塞初始渲染 diff --git a/vite-frontend/src/api/network.ts b/vite-frontend/src/api/network.ts index 0ea6734..53486e9 100644 --- a/vite-frontend/src/api/network.ts +++ b/vite-frontend/src/api/network.ts @@ -98,8 +98,6 @@ const Network = { resolve(response.data); }) .catch(function (error: any) { - console.error("GET请求错误:", error); - // 检查是否是401错误(token失效) if (error.response && error.response.status === 401) { handleTokenExpired(); @@ -146,8 +144,6 @@ const Network = { resolve(response.data); }) .catch(function (error: any) { - console.error("POST请求错误:", error); - // 检查是否是401错误(token失效) if (error.response && error.response.status === 401) { handleTokenExpired(); diff --git a/vite-frontend/src/components/navbar.tsx b/vite-frontend/src/components/navbar.tsx index 17ba3e3..b7b0c02 100644 --- a/vite-frontend/src/components/navbar.tsx +++ b/vite-frontend/src/components/navbar.tsx @@ -33,9 +33,7 @@ export const Navbar = () => { // 同步更新siteConfig siteConfig.name = cachedAppName; } - } catch (error) { - console.warn("检查配置更新失败:", error); - } + } catch {} }; // 延迟执行,避免阻塞初始渲染 @@ -50,9 +48,7 @@ export const Navbar = () => { setAppName(cachedAppName); siteConfig.name = cachedAppName; } - } catch (error) { - console.warn("更新配置失败:", error); - } + } catch {} }; window.addEventListener("configUpdated", handleConfigUpdate); diff --git a/vite-frontend/src/config/site.ts b/vite-frontend/src/config/site.ts index be054e3..bb89220 100644 --- a/vite-frontend/src/config/site.ts +++ b/vite-frontend/src/config/site.ts @@ -126,7 +126,7 @@ export const getCachedConfigs = async (): Promise> => { return configs; } - } catch (error) { + } catch { // API失败时返回缓存的数据 if (hasCachedData) { return cachedConfigs; diff --git a/vite-frontend/src/layouts/admin.tsx b/vite-frontend/src/layouts/admin.tsx index 650e5bb..23c8f9d 100644 --- a/vite-frontend/src/layouts/admin.tsx +++ b/vite-frontend/src/layouts/admin.tsx @@ -260,9 +260,8 @@ export default function AdminLayout({ } else { toast.error(response.msg || "密码修改失败"); } - } catch (error) { + } catch { toast.error("修改密码时发生错误"); - console.error("修改密码错误:", error); } finally { setPasswordLoading(false); } @@ -289,8 +288,10 @@ export default function AdminLayout({ > {/* 移动端遮罩层 */} {isMobile && mobileMenuVisible && ( -
)} diff --git a/vite-frontend/src/layouts/h5-simple.tsx b/vite-frontend/src/layouts/h5-simple.tsx index e4d1b29..7f77735 100644 --- a/vite-frontend/src/layouts/h5-simple.tsx +++ b/vite-frontend/src/layouts/h5-simple.tsx @@ -17,7 +17,7 @@ export default function H5SimpleLayout({ React.useEffect(() => { try { window.scrollTo({ top: 0, left: 0, behavior: "auto" }); - } catch (e) { + } catch { window.scrollTo(0, 0); } document.body.scrollTop = 0; diff --git a/vite-frontend/src/layouts/h5.tsx b/vite-frontend/src/layouts/h5.tsx index 533e1e5..db3f202 100644 --- a/vite-frontend/src/layouts/h5.tsx +++ b/vite-frontend/src/layouts/h5.tsx @@ -108,7 +108,7 @@ export default function H5Layout({ children }: { children: React.ReactNode }) { useEffect(() => { try { window.scrollTo({ top: 0, left: 0, behavior: "auto" }); - } catch (e) { + } catch { window.scrollTo(0, 0); } document.body.scrollTop = 0; diff --git a/vite-frontend/src/pages/change-password.tsx b/vite-frontend/src/pages/change-password.tsx index 4a470f8..99d09cb 100644 --- a/vite-frontend/src/pages/change-password.tsx +++ b/vite-frontend/src/pages/change-password.tsx @@ -89,8 +89,7 @@ export default function ChangePasswordPage() { } else { toast.error(response.msg || "账号密码修改失败"); } - } catch (error) { - console.error("修改账号密码错误:", error); + } catch { toast.error("修改账号密码时发生错误"); } finally { setLoading(false); diff --git a/vite-frontend/src/pages/config.tsx b/vite-frontend/src/pages/config.tsx index c46ad5f..9879cad 100644 --- a/vite-frontend/src/pages/config.tsx +++ b/vite-frontend/src/pages/config.tsx @@ -121,7 +121,7 @@ const getInitialConfigs = (): Record => { initialConfigs[key] = cachedValue; } }); - } catch (error) {} + } catch {} return initialConfigs; }; @@ -172,7 +172,7 @@ export default function ConfigPage() { setHasChanges(false); } else { } - } catch (error) { + } catch { // 只有在没有缓存数据时才显示错误 if (!hasInitialData) { toast.error("加载配置出错,请重试"); @@ -250,7 +250,7 @@ export default function ConfigPage() { } else { toast.error("保存配置失败: " + response.msg); } - } catch (error) { + } catch { toast.error("保存配置出错,请重试"); } finally { setSaving(false); diff --git a/vite-frontend/src/pages/dashboard.tsx b/vite-frontend/src/pages/dashboard.tsx index ca83a61..f66bab2 100644 --- a/vite-frontend/src/pages/dashboard.tsx +++ b/vite-frontend/src/pages/dashboard.tsx @@ -207,8 +207,7 @@ export default function DashboardPage() { } else { toast.error(res.msg || "获取套餐信息失败"); } - } catch (error) { - console.error("获取套餐信息失败:", error); + } catch { toast.error("获取套餐信息失败"); } finally { setLoading(false); @@ -648,7 +647,7 @@ export default function DashboardPage() { try { await navigator.clipboard.writeText(text); toast.success(`已复制`); - } catch (error) { + } catch { toast.error("复制失败"); } }; @@ -661,7 +660,7 @@ export default function DashboardPage() { ), ); await copyToClipboard(addressItem.address); - } catch (error) { + } catch { toast.error("复制失败"); } finally { setAddressList((prev) => @@ -1189,14 +1188,15 @@ export default function DashboardPage() { {forward.name}
- - hasMultipleIps(forward.inIp) && showAddressModal( forward.inIp, forward.inPort, @@ -1205,17 +1205,20 @@ export default function DashboardPage() { } > {formatInAddress(forward.inIp, forward.inPort)} - +
↓
- - hasMultipleRemoteAddresses( + disabled={ + !hasMultipleRemoteAddresses( forward.remoteAddr, - ) && + ) + } + title={formatRemoteAddress(forward.remoteAddr)} + type="button" + onClick={() => showRemoteAddressModal( forward.remoteAddr, "出口地址", @@ -1223,7 +1226,7 @@ export default function DashboardPage() { } > {formatRemoteAddress(forward.remoteAddr)} - +
diff --git a/vite-frontend/src/pages/forward.tsx b/vite-frontend/src/pages/forward.tsx index a6df3aa..4f3f846 100644 --- a/vite-frontend/src/pages/forward.tsx +++ b/vite-frontend/src/pages/forward.tsx @@ -224,8 +224,11 @@ export default function ForwardPage() { const [selectMode, setSelectMode] = useState(false); const [selectedIds, setSelectedIds] = useState>(new Set()); const [batchDeleteModalOpen, setBatchDeleteModalOpen] = useState(false); - const [batchChangeTunnelModalOpen, setBatchChangeTunnelModalOpen] = useState(false); - const [batchTargetTunnelId, setBatchTargetTunnelId] = useState(null); + const [batchChangeTunnelModalOpen, setBatchChangeTunnelModalOpen] = + useState(false); + const [batchTargetTunnelId, setBatchTargetTunnelId] = useState( + null, + ); const [batchLoading, setBatchLoading] = useState(false); useEffect(() => { @@ -268,9 +271,7 @@ export default function ForwardPage() { // 同步到localStorage try { localStorage.setItem("forward-order", JSON.stringify(dbOrder)); - } catch (error) { - console.warn("无法保存排序到localStorage:", error); - } + } catch {} } else { // 使用本地存储的顺序 const savedOrder = localStorage.getItem("forward-order"); @@ -296,9 +297,7 @@ export default function ForwardPage() { } } } - } catch (error) { - console.warn("无法保存显示模式到localStorage:", error); - } + } catch {} }; // 加载所有数据 @@ -347,9 +346,7 @@ export default function ForwardPage() { // 同步到localStorage try { localStorage.setItem("forward-order", JSON.stringify(dbOrder)); - } catch (error) { - console.warn("无法保存排序到localStorage:", error); - } + } catch {} } else { // 使用本地存储的顺序 const savedOrder = localStorage.getItem("forward-order"); @@ -384,10 +381,8 @@ export default function ForwardPage() { if (tunnelsRes.code === 0) { setTunnels(tunnelsRes.data || []); } else { - console.warn("获取隧道列表失败:", tunnelsRes.msg); } - } catch (error) { - console.error("加载数据失败:", error); + } catch { toast.error("加载数据失败"); } finally { setLoading(false); @@ -566,8 +561,7 @@ export default function ForwardPage() { } } } - } catch (error) { - console.error("删除失败:", error); + } catch { toast.error("删除失败"); } finally { setDeleteLoading(false); @@ -628,8 +622,7 @@ export default function ForwardPage() { } else { toast.error(res.msg || "操作失败"); } - } catch (error) { - console.error("提交失败:", error); + } catch { toast.error("操作失败"); } finally { setSubmitLoading(false); @@ -679,14 +672,13 @@ export default function ForwardPage() { ); toast.error(res.msg || "操作失败"); } - } catch (error) { + } catch { // 操作失败,恢复UI状态 setForwards((prev) => prev.map((f) => f.id === forward.id ? { ...f, serviceRunning: !targetState } : f, ), ); - console.error("服务开关操作失败:", error); toast.error("网络错误,操作失败"); } }; @@ -720,8 +712,7 @@ export default function ForwardPage() { ], }); } - } catch (error) { - console.error("诊断失败:", error); + } catch { toast.error("网络错误,请重试"); setDiagnosisResult({ forwardName: forward.name, @@ -914,7 +905,7 @@ export default function ForwardPage() { try { await navigator.clipboard.writeText(text); toast.success(`已复制${label}`); - } catch (error) { + } catch { toast.error("复制失败"); } }; @@ -928,7 +919,7 @@ export default function ForwardPage() { ), ); await copyToClipboard(addressItem.address, "地址"); - } catch (error) { + } catch { toast.error("复制失败"); } finally { setAddressList((prev) => @@ -1001,8 +992,7 @@ export default function ForwardPage() { const exportText = exportLines.join("\n"); setExportData(exportText); - } catch (error) { - console.error("导出失败:", error); + } catch { toast.error("导出失败"); } finally { setExportLoading(false); @@ -1145,7 +1135,7 @@ export default function ForwardPage() { ...prev, ]); } - } catch (error) { + } catch { setImportResults((prev) => [ { line, @@ -1161,8 +1151,7 @@ export default function ForwardPage() { // 导入完成后刷新转发列表 await loadData(false); - } catch (error) { - console.error("导入失败:", error); + } catch { toast.error("导入过程中发生错误"); } finally { setImportLoading(false); @@ -1234,9 +1223,7 @@ export default function ForwardPage() { // 保存到localStorage try { localStorage.setItem("forward-order", JSON.stringify(newOrder)); - } catch (error) { - console.warn("无法保存排序到localStorage:", error); - } + } catch {} // 持久化到数据库 try { @@ -1267,8 +1254,7 @@ export default function ForwardPage() { } else { toast.error("保存排序失败:" + (response.msg || "未知错误")); } - } catch (error) { - console.error("保存排序到数据库失败:", error); + } catch { toast.error("保存排序失败,请重试"); } } @@ -1283,6 +1269,7 @@ export default function ForwardPage() { const toggleSelect = (id: number) => { const newSet = new Set(selectedIds); + if (newSet.has(id)) { newSet.delete(id); } else { @@ -1293,6 +1280,7 @@ export default function ForwardPage() { const selectAll = () => { const allIds = sortedForwards.map((f) => f.id); + setSelectedIds(new Set(allIds)); }; @@ -1305,12 +1293,16 @@ export default function ForwardPage() { setBatchLoading(true); try { const res = await batchDeleteForwards(Array.from(selectedIds)); + if (res.code === 0) { const result = res.data; + if (result.failCount === 0) { toast.success(`成功删除 ${result.successCount} 项`); } else { - toast.error(`成功 ${result.successCount} 项,失败 ${result.failCount} 项`); + toast.error( + `成功 ${result.successCount} 项,失败 ${result.failCount} 项`, + ); } setSelectedIds(new Set()); setSelectMode(false); @@ -1334,8 +1326,10 @@ export default function ForwardPage() { const res = enable ? await batchResumeForwards(ids) : await batchPauseForwards(ids); + if (res.code === 0) { const result = res.data; + if (result.failCount === 0) { toast.success( enable @@ -1343,7 +1337,9 @@ export default function ForwardPage() { : `成功停用 ${result.successCount} 项`, ); } else { - toast.error(`成功 ${result.successCount} 项,失败 ${result.failCount} 项`); + toast.error( + `成功 ${result.successCount} 项,失败 ${result.failCount} 项`, + ); } setSelectedIds(new Set()); setSelectMode(false); @@ -1363,12 +1359,16 @@ export default function ForwardPage() { setBatchLoading(true); try { const res = await batchRedeployForwards(Array.from(selectedIds)); + if (res.code === 0) { const result = res.data; + if (result.failCount === 0) { toast.success(`成功重新下发 ${result.successCount} 项`); } else { - toast.error(`成功 ${result.successCount} 项,失败 ${result.failCount} 项`); + toast.error( + `成功 ${result.successCount} 项,失败 ${result.failCount} 项`, + ); } setSelectedIds(new Set()); setSelectMode(false); @@ -1391,12 +1391,16 @@ export default function ForwardPage() { forwardIds: Array.from(selectedIds), targetTunnelId: batchTargetTunnelId, }); + if (res.code === 0) { const result = res.data; + if (result.failCount === 0) { toast.success(`成功换隧道 ${result.successCount} 项`); } else { - toast.error(`成功 ${result.successCount} 项,失败 ${result.failCount} 项`); + toast.error( + `成功 ${result.successCount} 项,失败 ${result.failCount} 项`, + ); } setSelectedIds(new Set()); setSelectMode(false); @@ -1501,11 +1505,6 @@ export default function ForwardPage() { // 可拖拽的转发卡片组件 const SortableForwardCard = ({ forward }: { forward: Forward }) => { - // 确保 forward 对象有效 - if (!forward || !forward.id) { - return null; - } - const { attributes, listeners, @@ -1543,9 +1542,9 @@ export default function ForwardPage() {
{selectMode && ( toggleSelect(forward.id)} - className="mr-2" /> )}
@@ -1560,12 +1559,12 @@ export default function ForwardPage() { {viewMode === "direct" && (
handleServiceToggle(forward)} /> @@ -1599,12 +1598,17 @@ export default function ForwardPage() {
{/* 地址信息 */}
-
showAddressModal(forward.inIp, forward.inPort, '入口端口')} + type="button" + onClick={() => + showAddressModal(forward.inIp, forward.inPort, "入口端口") + } >
@@ -1623,22 +1627,27 @@ export default function ForwardPage() { viewBox="0 0 24 24" > )}
-
+ -
showAddressModal(forward.remoteAddr, null, '目标地址')} + type="button" + onClick={() => + showAddressModal(forward.remoteAddr, null, "目标地址") + } >
@@ -1657,42 +1666,42 @@ export default function ForwardPage() { viewBox="0 0 24 24" > )}
-
+
{/* 统计信息 */}
{strategyDisplay.text}
↑{formatFlow(forward.inFlow || 0)}
↓{formatFlow(forward.outFlow || 0)} @@ -1705,7 +1714,11 @@ export default function ForwardPage() { color="primary" size="sm" startContent={ - + } @@ -1719,8 +1732,16 @@ export default function ForwardPage() { color="warning" size="sm" startContent={ - - + + } variant="flat" @@ -1733,9 +1754,21 @@ export default function ForwardPage() { color="danger" size="sm" startContent={ - - - + + + } variant="flat" @@ -1766,24 +1799,24 @@ export default function ForwardPage() {
{/* 页面头部 */}
-
+
{/* 显示模式切换按钮 */} {/* 导出按钮 */} -
@@ -1832,7 +1865,9 @@ export default function ForwardPage() { {selectMode && selectedIds.size > 0 && (
- 已选择 {selectedIds.size} 项 + + 已选择 {selectedIds.size} 项 + @@ -1840,43 +1875,43 @@ export default function ForwardPage() { 清空
@@ -1927,10 +1962,10 @@ export default function ForwardPage() {
用户 @@ -1943,6 +1978,7 @@ export default function ForwardPage() {
@@ -1954,10 +1990,10 @@ export default function ForwardPage() { viewBox="0 0 24 24" >
@@ -1969,9 +2005,9 @@ export default function ForwardPage() {
{ tunnelGroup.forwards.filter( @@ -1983,7 +2019,6 @@ export default function ForwardPage() {
} - className="shadow-none border border-divider" >
{tunnelGroup.forwards.map((forward) => @@ -2010,10 +2045,10 @@ export default function ForwardPage() { viewBox="0 0 24 24" >
@@ -2033,9 +2068,9 @@ export default function ForwardPage() { forwards.length > 0 ? ( {}} // 添加空的 onDragStart 处理器 + sensors={sensors} + onDragEnd={handleDragEnd} + onDragStart={() => {}} // 添加空的 onDragStart 处理器 >
@@ -2086,11 +2121,11 @@ export default function ForwardPage() { {/* 新增/编辑模态框 */} {(onClose) => ( @@ -2107,28 +2142,37 @@ export default function ForwardPage() {
setForm(prev => ({ ...prev, name: e.target.value }))} + isInvalid={!!errors.name} + label="转发名称" + placeholder="请输入转发名称" + value={form.name} + variant="bordered" + onChange={(e) => + setForm((prev) => ({ ...prev, name: e.target.value })) + } /> { - const value = e.target.value; - setForm(prev => ({ - ...prev, - inPort: value ? parseInt(value) : null - })); - }} + errorMessage={errors.inPort} + isInvalid={!!errors.inPort} + label="入口端口" + placeholder="留空则自动分配可用端口" + type="number" + value={form.inPort !== null ? form.inPort.toString() : ""} + variant="bordered" + onChange={(e) => { + const value = e.target.value; + + setForm((prev) => ({ + ...prev, + inPort: value ? parseInt(value) : null, + })); + }} />