From e0efadf298d2b43edec89b431011c1c9422d6afa Mon Sep 17 00:00:00 2001 From: root Date: Fri, 6 Feb 2026 05:30:50 +0000 Subject: [PATCH] feat: add batch pause/resume controls and improve batch toolbar usability --- .../admin/controller/ForwardController.java | 12 ++ .../com/admin/service/ForwardService.java | 4 + .../service/impl/ForwardServiceImpl.java | 31 +++++ vite-frontend/package.json | 8 +- vite-frontend/src/api/index.ts | 4 + vite-frontend/src/layouts/admin.tsx | 14 +- vite-frontend/src/pages/forward.tsx | 124 +++++++++++++----- vite-frontend/src/pages/node.tsx | 10 +- vite-frontend/src/pages/tunnel.tsx | 52 ++++---- 9 files changed, 183 insertions(+), 76 deletions(-) diff --git a/springboot-backend/src/main/java/com/admin/controller/ForwardController.java b/springboot-backend/src/main/java/com/admin/controller/ForwardController.java index 58591e8..b8c55c3 100644 --- a/springboot-backend/src/main/java/com/admin/controller/ForwardController.java +++ b/springboot-backend/src/main/java/com/admin/controller/ForwardController.java @@ -106,6 +106,18 @@ public class ForwardController extends BaseController { return forwardService.batchDeleteForwards(batchDeleteDto); } + @LogAnnotation + @PostMapping("/batch-pause") + public R batchPause(@Validated @RequestBody BatchDeleteDto batchDeleteDto) { + return forwardService.batchPauseForwards(batchDeleteDto); + } + + @LogAnnotation + @PostMapping("/batch-resume") + public R batchResume(@Validated @RequestBody BatchDeleteDto batchDeleteDto) { + return forwardService.batchResumeForwards(batchDeleteDto); + } + @LogAnnotation @PostMapping("/batch-redeploy") public R batchRedeploy(@Validated @RequestBody BatchRedeployDto batchRedeployDto) { diff --git a/springboot-backend/src/main/java/com/admin/service/ForwardService.java b/springboot-backend/src/main/java/com/admin/service/ForwardService.java index f942f26..be53884 100644 --- a/springboot-backend/src/main/java/com/admin/service/ForwardService.java +++ b/springboot-backend/src/main/java/com/admin/service/ForwardService.java @@ -85,6 +85,10 @@ public interface ForwardService extends IService { R updateForwardOrder(Map params); R batchDeleteForwards(BatchDeleteDto batchDeleteDto); + + R batchPauseForwards(BatchDeleteDto batchDeleteDto); + + R batchResumeForwards(BatchDeleteDto batchDeleteDto); R batchRedeployForwards(BatchRedeployDto batchRedeployDto); diff --git a/springboot-backend/src/main/java/com/admin/service/impl/ForwardServiceImpl.java b/springboot-backend/src/main/java/com/admin/service/impl/ForwardServiceImpl.java index d9f42a0..21d8c14 100644 --- a/springboot-backend/src/main/java/com/admin/service/impl/ForwardServiceImpl.java +++ b/springboot-backend/src/main/java/com/admin/service/impl/ForwardServiceImpl.java @@ -1304,6 +1304,37 @@ public class ForwardServiceImpl extends ServiceImpl impl return R.ok(result); } + @Override + @Transactional + public R batchPauseForwards(BatchDeleteDto batchDeleteDto) { + return batchChangeForwardStatus(batchDeleteDto.getIds(), 0, "PauseService"); + } + + @Override + @Transactional + public R batchResumeForwards(BatchDeleteDto batchDeleteDto) { + return batchChangeForwardStatus(batchDeleteDto.getIds(), 1, "ResumeService"); + } + + private R batchChangeForwardStatus(List ids, int targetStatus, String gostMethod) { + BatchOperationResultDto result = new BatchOperationResultDto(); + + for (Long id : ids) { + try { + R changeResult = changeForwardStatus(id, targetStatus, gostMethod); + if (changeResult.getCode() == 0) { + result.incrementSuccess(); + } else { + result.addFailedItem(id, changeResult.getMsg()); + } + } catch (Exception e) { + result.addFailedItem(id, e.getMessage()); + } + } + + return R.ok(result); + } + @Override @Transactional public R batchRedeployForwards(BatchRedeployDto batchRedeployDto) { diff --git a/vite-frontend/package.json b/vite-frontend/package.json index d89bafe..c4016d1 100644 --- a/vite-frontend/package.json +++ b/vite-frontend/package.json @@ -55,7 +55,7 @@ "react-dom": "18.3.1", "react-hot-toast": "^2.5.2", "react-is": "^19.2.4", - "react-router-dom": "6.23.0", + "react-router-dom": "6.30.3", "recharts": "^3.1.1", "sonner": "^2.0.6", "tailwind-variants": "1.0.0", @@ -64,14 +64,14 @@ "devDependencies": { "@eslint/compat": "1.2.8", "@eslint/eslintrc": "3.3.1", - "@eslint/js": "9.25.1", + "@eslint/js": "9.39.2", "@types/node": "^24.3.0", "@types/react": "18.3.3", "@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", - "eslint": "9.25.1", + "eslint": "9.39.2", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.31.0", "eslint-plugin-jsx-a11y": "6.10.2", @@ -84,7 +84,7 @@ "postcss": "8.5.6", "prettier": "3.5.3", "typescript": "5.6.3", - "vite": "5.4.11", + "vite": "5.4.21", "vite-tsconfig-paths": "4.3.2" } } diff --git a/vite-frontend/src/api/index.ts b/vite-frontend/src/api/index.ts index d943379..5b3164f 100644 --- a/vite-frontend/src/api/index.ts +++ b/vite-frontend/src/api/index.ts @@ -131,6 +131,10 @@ export const verifyCaptcha = (data: { captchaId: string; trackData: string }) => // 批量操作接口 export const batchDeleteForwards = (ids: number[]) => Network.post("/forward/batch-delete", { ids }); +export const batchPauseForwards = (ids: number[]) => + Network.post("/forward/batch-pause", { ids }); +export const batchResumeForwards = (ids: number[]) => + Network.post("/forward/batch-resume", { ids }); export const batchDeleteTunnels = (ids: number[]) => Network.post("/tunnel/batch-delete", { ids }); export const batchDeleteNodes = (ids: number[]) => diff --git a/vite-frontend/src/layouts/admin.tsx b/vite-frontend/src/layouts/admin.tsx index 2bf18e8..650e5bb 100644 --- a/vite-frontend/src/layouts/admin.tsx +++ b/vite-frontend/src/layouts/admin.tsx @@ -62,7 +62,7 @@ export default function AdminLayout({ const menuItems: MenuItem[] = [ { path: "/dashboard", - label: "仪表板", + label: "仪表", icon: ( @@ -71,7 +71,7 @@ export default function AdminLayout({ }, { path: "/forward", - label: "转发管理", + label: "转发", icon: ( @@ -136,7 +136,7 @@ export default function AdminLayout({ }, { path: "/config", - label: "网站配置", + label: "设置", icon: ( { + if (selectedIds.size === 0) return; + setBatchLoading(true); + try { + const ids = Array.from(selectedIds); + const res = enable + ? await batchResumeForwards(ids) + : await batchPauseForwards(ids); + if (res.code === 0) { + const result = res.data; + if (result.failCount === 0) { + toast.success( + enable + ? `成功启用 ${result.successCount} 项` + : `成功停用 ${result.successCount} 项`, + ); + } else { + toast.error(`成功 ${result.successCount} 项,失败 ${result.failCount} 项`); + } + setSelectedIds(new Set()); + setSelectMode(false); + loadData(false); + } else { + toast.error(res.msg || (enable ? "启用失败" : "停用失败")); + } + } catch (e: any) { + toast.error(e.message || (enable ? "启用失败" : "停用失败")); + } finally { + setBatchLoading(false); + } + }; + const handleBatchRedeploy = async () => { if (selectedIds.size === 0) return; setBatchLoading(true); @@ -1731,9 +1765,9 @@ export default function ForwardPage() { return (
{/* 页面头部 */} -
+
-
+
{/* 显示模式切换按钮 */} - - - - +
+
+ 已选择 {selectedIds.size} 项 + + + + + + + +
)} diff --git a/vite-frontend/src/pages/node.tsx b/vite-frontend/src/pages/node.tsx index 9933f6f..0b870be 100644 --- a/vite-frontend/src/pages/node.tsx +++ b/vite-frontend/src/pages/node.tsx @@ -1032,11 +1032,11 @@ export default function NodePage() { {/* 批量操作浮动工具栏 */} {selectMode && selectedIds.size > 0 && ( -
- - 已选 {selectedIds.size} 项 - -
+
+
+ + 已选 {selectedIds.size} 项 + diff --git a/vite-frontend/src/pages/tunnel.tsx b/vite-frontend/src/pages/tunnel.tsx index f4334fd..3f24fba 100644 --- a/vite-frontend/src/pages/tunnel.tsx +++ b/vite-frontend/src/pages/tunnel.tsx @@ -854,31 +854,33 @@ export default function TunnelPage() {
{selectMode && selectedIds.size > 0 && ( -
- 已选择 {selectedIds.size} 项 - - - - +
+
+ 已选择 {selectedIds.size} 项 + + + + +
)}