diff --git a/.helloagents/CHANGELOG.md b/.helloagents/CHANGELOG.md index 4664e65..a922860 100644 --- a/.helloagents/CHANGELOG.md +++ b/.helloagents/CHANGELOG.md @@ -1,5 +1,19 @@ # CHANGELOG +## [0.6.2] - 2026-04-27 + +### 新增 +- **[admin-frontend]**: 为节点管理新增可控“自动上线”能力;节点可单独或批量开启后台托管,`sync:server-auto-online` 会按在线状态自动同步前台显示,在线 / 待同步时显示,离线时隐藏,未开启自动上线的节点继续保持手动显隐控制 — by yinjianm + - 方案: [202604272338_admin-frontend-node-auto-online](archive/2026-04/202604272338_admin-frontend-node-auto-online/) + - 决策: admin-frontend-node-auto-online#D001(自动上线使用独立字段与独立同步服务) + +## [0.6.1] - 2026-04-27 + +### 快速修改 +- **[admin-frontend]**: 修复独立 admin 前端容器内 `/upload/rest/upload` 返回 404 的问题;`Caddyfile` 现在会把 `/upload/*` 去掉 `/upload` 前缀后反向代理到 `XBOARD_UPLOAD_UPSTREAM`,默认对齐开发环境的图片上传服务 — by yinjianm + - 类型: 快速修改(无方案包) + - 文件: admin-frontend/Caddyfile:1-28 + ## [0.6.0] - 2026-04-27 ### 新增 diff --git a/.helloagents/archive/2026-04/202604272338_admin-frontend-node-auto-online/.status.json b/.helloagents/archive/2026-04/202604272338_admin-frontend-node-auto-online/.status.json new file mode 100644 index 0000000..1fb387b --- /dev/null +++ b/.helloagents/archive/2026-04/202604272338_admin-frontend-node-auto-online/.status.json @@ -0,0 +1,11 @@ +{ + "status": "completed", + "completed": 9, + "failed": 0, + "pending": 0, + "total": 9, + "done": 9, + "percent": 100, + "current": "节点自动上线功能已实现,前端构建通过,PHP 验证待具备 PHP 的环境补跑", + "updated_at": "2026-04-27 23:52:00" +} diff --git a/.helloagents/plan/202604272338_admin-frontend-node-auto-online/proposal.md b/.helloagents/archive/2026-04/202604272338_admin-frontend-node-auto-online/proposal.md similarity index 100% rename from .helloagents/plan/202604272338_admin-frontend-node-auto-online/proposal.md rename to .helloagents/archive/2026-04/202604272338_admin-frontend-node-auto-online/proposal.md diff --git a/.helloagents/plan/202604272338_admin-frontend-node-auto-online/tasks.md b/.helloagents/archive/2026-04/202604272338_admin-frontend-node-auto-online/tasks.md similarity index 61% rename from .helloagents/plan/202604272338_admin-frontend-node-auto-online/tasks.md rename to .helloagents/archive/2026-04/202604272338_admin-frontend-node-auto-online/tasks.md index d11a245..7117fbf 100644 --- a/.helloagents/plan/202604272338_admin-frontend-node-auto-online/tasks.md +++ b/.helloagents/archive/2026-04/202604272338_admin-frontend-node-auto-online/tasks.md @@ -1,9 +1,11 @@ # 任务清单: admin-frontend-node-auto-online +> **@status:** completed | 2026-04-27 23:56 + ```yaml @feature: admin-frontend-node-auto-online @created: 2026-04-27 -@status: in_progress +@status: completed @mode: R2 @workflow: INTERACTIVE @complexity: complex @@ -12,14 +14,14 @@ ## LIVE_STATUS ```json -{"status":"in_progress","completed":0,"failed":0,"pending":8,"total":8,"percent":0,"current":"方案包已创建,准备进入开发实施","updated_at":"2026-04-27 23:38:00"} +{"status":"completed","completed":9,"failed":0,"pending":0,"total":9,"percent":100,"current":"节点自动上线功能已实现,前端构建通过,PHP 验证待具备 PHP 的环境补跑","updated_at":"2026-04-27 23:52:00"} ``` ## 进度概览 | 完成 | 失败 | 跳过 | 总数 | |------|------|------|------| -| 0 | 0 | 0 | 8 | +| 9 | 0 | 0 | 9 | --- @@ -27,25 +29,25 @@ ### 1. 后端数据与同步机制 -- [ ] 1.1 新增 `database/migrations/*_add_auto_online_to_v2_server_table.php` +- [√] 1.1 新增 `database/migrations/*_add_auto_online_to_v2_server_table.php` - 预期变更: 为 `v2_server` 增加 `auto_online` 布尔字段,默认 `false`,down 可回滚字段。 - 完成标准: 迁移文件存在,字段名、默认值和回滚逻辑明确。 - 验证方式: `php -l database/migrations/*_add_auto_online_to_v2_server_table.php` - depends_on: [] -- [ ] 1.2 修改 `app/Models/Server.php` +- [√] 1.2 修改 `app/Models/Server.php` - 预期变更: 增加 `auto_online` 属性注释和 boolean cast,保持现有在线状态访问器与墙状态关系不变。 - 完成标准: `Server` JSON/API 输出包含 `auto_online`,现有 `gfwChecks()` 不被移除。 - 验证方式: `php -l app/Models/Server.php` - depends_on: [1.1] -- [ ] 1.3 新增 `app/Services/ServerAutoOnlineService.php` +- [√] 1.3 新增 `app/Services/ServerAutoOnlineService.php` - 预期变更: 封装自动上线同步逻辑,只处理 `auto_online=true` 的节点,在线/待同步写 `show=true`,离线写 `show=false`。 - 完成标准: 服务返回同步统计,跳过未托管节点,不引入生产外部副作用。 - 验证方式: `php -l app/Services/ServerAutoOnlineService.php` - depends_on: [1.2] -- [ ] 1.4 新增命令并接入调度 `app/Console/Commands/SyncServerAutoOnline.php`, `app/Console/Kernel.php` +- [√] 1.4 新增命令并接入调度 `app/Console/Commands/SyncServerAutoOnline.php`, `app/Console/Kernel.php` - 预期变更: 新增 `sync:server-auto-online` 命令,每 5 分钟调度,使用 `onOneServer()` 与 `withoutOverlapping()`。 - 完成标准: 命令可调用服务并输出统计,调度不影响现有任务。 - 验证方式: `php -l app/Console/Commands/SyncServerAutoOnline.php`; `php -l app/Console/Kernel.php` @@ -53,7 +55,7 @@ ### 2. 后端 API 契约 -- [ ] 2.1 修改 `app/Http/Requests/Admin/ServerSave.php` 与 `app/Http/Controllers/V2/Admin/Server/ManageController.php` +- [√] 2.1 修改 `app/Http/Requests/Admin/ServerSave.php` 与 `app/Http/Controllers/V2/Admin/Server/ManageController.php` - 预期变更: `save`、`update`、`batchUpdate` 支持 `auto_online`,批量更新保持字段显式传入才更新。 - 完成标准: 手动显隐字段 `show` 和自动上线字段 `auto_online` 可独立保存。 - 验证方式: `php -l app/Http/Requests/Admin/ServerSave.php`; `php -l app/Http/Controllers/V2/Admin/Server/ManageController.php` @@ -61,13 +63,13 @@ ### 3. 管理端前端 -- [ ] 3.1 修改 `admin-frontend/src/types/api.d.ts`, `admin-frontend/src/utils/nodeEditorOptions.ts`, `admin-frontend/src/utils/nodeEditorMapper.ts` +- [√] 3.1 修改 `admin-frontend/src/types/api.d.ts`, `admin-frontend/src/utils/nodeEditorOptions.ts`, `admin-frontend/src/utils/nodeEditorMapper.ts` - 预期变更: 类型、表单模型、默认值、编辑回填和保存 payload 支持 `auto_online`。 - 完成标准: 新建默认关闭,编辑能正确回填,保存能提交布尔值。 - 验证方式: `npm run build` - depends_on: [2.1] -- [ ] 3.2 修改 `admin-frontend/src/views/nodes/NodeEditorDialog.vue`, `NodeBatchEditDialog.vue`, `NodesView.vue`, `admin-frontend/src/utils/nodes.ts` +- [√] 3.2 修改 `admin-frontend/src/views/nodes/NodeEditorDialog.vue`, `NodeBatchEditDialog.vue`, `NodesView.vue`, `admin-frontend/src/utils/nodes.ts` - 预期变更: 编辑弹窗和批量修改弹窗增加自动上线开关;节点表格展示自动托管状态;现有墙状态检测 UI 保持可用。 - 完成标准: 管理员可单节点和批量设置 `auto_online`;未开启批量字段时不覆盖。 - 验证方式: `npm run build` @@ -75,11 +77,17 @@ ### 4. 知识库与验收 -- [ ] 4.1 更新 `.helloagents/context.md`, `.helloagents/modules/*`, `.helloagents/CHANGELOG.md` +- [√] 4.1 新增 `tests/Unit/ServerAutoOnlineServiceTest.php` + - 预期变更: 覆盖自动上线服务只同步托管节点、在线显示、离线隐藏、手动节点不受影响。 + - 完成标准: 测试用例能表达核心业务边界。 + - 验证方式: `php artisan test --filter=ServerAutoOnlineServiceTest` + - depends_on: [1.3] + +- [√] 4.2 更新 `.helloagents/context.md`, `.helloagents/modules/*`, `.helloagents/CHANGELOG.md` - 预期变更: 同步记录节点自动上线能力、后端命令和管理端节点页行为。 - 完成标准: 知识库反映代码事实,CHANGELOG 包含方案链接和决策 ID。 - 验证方式: 人工检查文档条目与本次改动一致。 - - depends_on: [1.4, 2.1, 3.2] + - depends_on: [1.4, 2.1, 3.2, 4.1] --- @@ -88,6 +96,10 @@ | 时间 | 任务 | 状态 | 备注 | |------|------|------|------| | 2026-04-27 23:38 | DESIGN | in_progress | 用户选择方案 A,方案包创建并进入开发实施 | +| 2026-04-27 23:45 | DEVELOP | in_progress | 完成后端 auto_online 字段、服务、命令和 API 扩展 | +| 2026-04-27 23:48 | DEVELOP | in_progress | 完成管理端节点表格、编辑弹窗与批量修改自动上线开关 | +| 2026-04-27 23:50 | VERIFY | warning | `npm run build` 通过;当前环境缺少 php,PHP 语法检查和 PHPUnit 未执行 | +| 2026-04-27 23:52 | KB | completed | context、admin-frontend 模块索引和 CHANGELOG 已同步 | --- @@ -95,3 +107,4 @@ - 当前工作树已有节点墙状态检测相关未提交改动,本任务必须保留并兼容这些改动。 - 按上级工具约束,本轮不调度子代理,复杂任务由主代理直接实施并在验收中说明。 +- PHP 命令在当前环境不可用,需在具备 PHP/Composer 的环境补跑 `php -l` 与 `php artisan test --filter=ServerAutoOnlineServiceTest`。 diff --git a/.helloagents/archive/_index.md b/.helloagents/archive/_index.md index 3a7ef24..9c71e17 100644 --- a/.helloagents/archive/_index.md +++ b/.helloagents/archive/_index.md @@ -7,6 +7,7 @@ | 时间戳 | 名称 | 类型 | 涉及模块 | 决策 | 结果 | |--------|------|------|---------|------|------| +| 202604272338 | admin-frontend-node-auto-online | - | - | - | ✅完成 | | 202604272325 | node-gfw-check | implementation | node-gfw-check,admin-frontend,mi-node | node-gfw-check#D001,#D002 | ✅完成 | | 202604272310 | ticket-chat-image-dnd-paste-upload | implementation | admin-frontend | ticket-chat-image-dnd-paste-upload#D001 | ✅完成 | | 202604250018 | admin-frontend-user-activity-status-filter | implementation | admin-frontend,backend | admin-frontend-user-activity-status-filter#D001,#D002,#D003 | ✅完成 | diff --git a/.helloagents/context.md b/.helloagents/context.md index 4d6da77..65be8c7 100644 --- a/.helloagents/context.md +++ b/.helloagents/context.md @@ -12,6 +12,7 @@ - `admin-frontend` 现支持通过 `ADMIN_BUILD_OUT_DIR` 覆写构建输出目录:仓内默认仍写到 `../public/assets/admin`,容器构建可切到独立 `dist` - 前端容器化运行采用 `admin-frontend/Dockerfile`(`Node 20 + Caddy` 多阶段构建),静态站点入口重定向到 `/assets/admin/` - 前端容器会通过 `XBOARD_BACKEND_UPSTREAM` 把 `/api` 反向代理到后端 `web` 服务;compose 分支当前默认值为 `http://web:7001` +- 前端容器会通过 `XBOARD_UPLOAD_UPSTREAM` 把 `/upload/*` 去掉 `/upload` 前缀后反向代理到图片上传服务,默认值为 `https://pic.535888.xyz` - GHCR 前端镜像发布工作流位于 `.github/workflows/admin-frontend-docker-publish.yml`,镜像名为 `ghcr.io//xboard-admin-frontend` - 管理端 API 通过 `window.settings.secure_path` 或 `VITE_ADMIN_PATH` 解析 `/api/v2/{secure_path}` 前缀 - 登录接口复用 `/api/v2/passport/auth/login` @@ -47,6 +48,10 @@ - `server/manage/update` - `server/manage/copy` - `server/manage/drop` + - `server/manage/batchDelete` + - `server/manage/checkGfw` + - `server/manage/resetTraffic` + - `server/manage/batchResetTraffic` - 管理端套餐管理现已接入: - `plan/fetch` - `plan/save` @@ -106,7 +111,8 @@ - 管理端路由使用 Hash 模式 - 管理端当前业务路由包含 `/dashboard`、`/users`、`/tickets`、`/nodes`、`/node-groups`、`/node-routes`、`/subscriptions/plans`、`/subscriptions/orders`、`/subscriptions/coupons`、`/subscriptions/gift-cards`、`/system/config`、`/system/notices`、`/system/payments`、`/system/plugins`、`/system/themes` 与 `/system/knowledge` -- `#/nodes` 当前已升级为真实节点工作台:支持搜索、在线 / 离线筛选、父/子节点筛选、分页浏览、显隐切换、复制、单节点置顶、仅对已勾选节点生效的批量修改 / 批量删除,以及 11 种协议的新增 / 编辑弹窗和排序对话框 +- `#/nodes` 当前已升级为真实节点工作台:支持搜索、在线 / 离线筛选、父/子节点筛选、墙状态筛选、分页浏览、显隐切换、自动上线托管开关、复制、单节点置顶、仅对已勾选节点生效的批量修改 / 批量删除,以及 11 种协议的新增 / 编辑弹窗和排序对话框 +- 节点自动上线由后端 `sync:server-auto-online` 定时命令执行,只处理 `auto_online=1` 的节点:在线 / 待同步时自动 `show=1`,离线时自动 `show=0`;未开启自动上线的节点继续保持手动显隐控制 - Bearer Token 存储于 `sessionStorage/localStorage` - `admin-frontend` 的视觉方向当前以 Apple 风格为基线,优先纯色分区、系统字体栈和低装饰成本 diff --git a/.helloagents/modules/_index.md b/.helloagents/modules/_index.md index fdcf5d0..2039b7c 100644 --- a/.helloagents/modules/_index.md +++ b/.helloagents/modules/_index.md @@ -2,7 +2,7 @@ | 模块名 | 说明 | 最近更新 | |--------|------|----------| -| [admin-frontend](admin-frontend.md) | 管理端前端登录、布局、仪表盘、用户管理、节点管理与管理 API 封装 | 2026-04-25 | +| [admin-frontend](admin-frontend.md) | 管理端前端登录、布局、仪表盘、用户管理、节点管理与管理 API 封装 | 2026-04-27 | | [node-gfw-check](node-gfw-check.md) | 节点墙状态检测任务、父/子节点继承规则、mi-node 检测上报链路 | 2026-04-27 | | [order-payment](order-payment.md) | 订单支付成功快照、第三方回调元信息透传与后台支付成功信息展示 | 2026-04-25 | | [subscription-protocols](subscription-protocols.md) | 用户订阅导出入口、协议适配器与 Stash / Clash 系列兼容过滤 | 2026-04-24 | diff --git a/.helloagents/modules/admin-frontend.md b/.helloagents/modules/admin-frontend.md index 1d8601a..4c2b45f 100644 --- a/.helloagents/modules/admin-frontend.md +++ b/.helloagents/modules/admin-frontend.md @@ -12,6 +12,7 @@ - 默认构建输出仍为主仓 `public/assets/admin`;当 `ADMIN_BUILD_OUT_DIR` 存在时,构建输出需切换到外部指定目录,供容器镜像独立打包 - 独立容器运行时通过 `Caddyfile` 把根路径重定向到 `/assets/admin/`,避免当前 `base: '/assets/admin/'` 资源前缀失效 - 独立容器运行时会把 `/api` 反向代理到 `XBOARD_BACKEND_UPSTREAM`,compose 分支默认指向 `http://web:7001`,确保前端静态容器仍能直连 Laravel 后端 +- 独立容器运行时会把 `/upload/*` 去掉 `/upload` 前缀后反向代理到 `XBOARD_UPLOAD_UPSTREAM`,默认指向 `https://pic.535888.xyz`,保持与 Vite 开发代理一致的图片上传路径 - 前端 GHCR 发布链路与 Laravel 主应用发布链路分离,避免把静态前端构建耦合进现有 PHP 镜像工作流 - 登录成功后优先跳转 `redirect` 指定路由,否则回到 `/dashboard` - 受保护路由在未登录时会自动附加 `redirect` 查询参数 @@ -40,7 +41,8 @@ - 节点新增 / 编辑 / 批量修改保存 `group_ids / route_ids` 时统一向后端提交字符串 ID,后端 `Server::whereGroupId()` 同时兼容历史字符串与数字 JSON 值,避免权限组保存后订阅侧无法命中节点 - TUIC 表单默认以 V5 / V4 版本选择、`h3 / h2 / http/1.1` ALPN 选项和 `native / quic` UDP Relay Mode 对齐后端协议模板;AnyTLS Padding Scheme 默认值与 `Server` 模型完整模板保持一致 - 节点排序采用本地草稿 + 上移 / 下移模式,保存时向 `server/manage/sort` 提交 `{ id, order }[]` 顺序 payload -- 节点列表现支持本地分页、在线 / 离线筛选、父/子节点筛选,以及跨分页稳定勾选;批量修改 / 批量删除仅作用于已勾选节点,其中批量修改可统一更新 `host / group_ids / rate` +- 节点列表现支持本地分页、在线 / 离线筛选、父/子节点筛选,以及跨分页稳定勾选;批量修改 / 批量删除仅作用于已勾选节点,其中批量修改可统一更新 `host / group_ids / rate / auto_online` +- 节点管理页新增“自动上线”托管开关;开启后后台 `sync:server-auto-online` 会按节点在线状态自动同步 `show`,在线 / 待同步时显示、离线时隐藏,未开启的节点仍保持手动显隐控制 - 节点管理页现支持墙状态展示、墙状态筛选与关键词搜索;父节点可通过行级或批量操作发起检测,子节点不单独检测并显示“随父节点”的继承状态 - 节点行级菜单现已补齐“置顶节点”,会复用当前排序结果生成新的顺序 payload 并提交到 `server/manage/sort` - 权限组管理页使用真实后端 `server/group/fetch`、`server/group/save` 与 `server/group/drop`,支持关键字搜索、新增/编辑中央弹窗、删除确认,以及从节点数量列跳转到 `#/nodes?group={id}` 的筛选联动 @@ -96,7 +98,7 @@ - 依赖 `src/utils/notices.ts` 负责公告表单转换、内容摘要、排序与显示字段归一化 - 依赖 `src/utils/systemConfig.ts` 负责系统配置字段元信息、默认值、回填与保存序列化 - 依赖 `src/utils/routes.ts` 负责路由动作映射、匹配规则序列化、节点引用摘要与搜索过滤 -- 依赖 `src/utils/nodes.ts` 负责节点在线状态、父/子节点、墙状态 meta、搜索文本和筛选逻辑 +- 依赖 `src/utils/nodes.ts` 负责节点在线状态、自动上线统计、父/子节点、墙状态 meta、搜索文本和筛选逻辑 - 依赖 `src/views/tickets/useTicketReplyImages.ts` 收敛工单回复区图片点击上传、拖拽上传、粘贴上传、文件校验和 Markdown 插入 - 依赖 Laravel 后端 `TicketService::reply()` 提供工单“再次回复自动重开”的统一业务语义 - 依赖 Laravel 注入的 `window.settings` diff --git a/.helloagents/plan/202604272338_admin-frontend-node-auto-online/.status.json b/.helloagents/plan/202604272338_admin-frontend-node-auto-online/.status.json deleted file mode 100644 index 640b86c..0000000 --- a/.helloagents/plan/202604272338_admin-frontend-node-auto-online/.status.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "status": "in_progress", - "completed": 0, - "failed": 0, - "pending": 8, - "total": 8, - "done": 0, - "percent": 0, - "current": "方案包已创建,准备进入开发实施", - "updated_at": "2026-04-27 23:38:00" -} diff --git a/admin-frontend/Caddyfile b/admin-frontend/Caddyfile index 0ed0e0e..9e3e7bb 100644 --- a/admin-frontend/Caddyfile +++ b/admin-frontend/Caddyfile @@ -7,6 +7,14 @@ reverse_proxy {$XBOARD_BACKEND_UPSTREAM:http://web:7001} } + @upload path /upload /upload/* + handle @upload { + uri strip_prefix /upload + reverse_proxy {$XBOARD_UPLOAD_UPSTREAM:https://pic.535888.xyz} { + header_up Host {upstream_hostport} + } + } + redir / /assets/admin/ 308 redir /assets/admin /assets/admin/ 308 diff --git a/admin-frontend/src/types/api.d.ts b/admin-frontend/src/types/api.d.ts index 8b387ba..d0dbe09 100644 --- a/admin-frontend/src/types/api.d.ts +++ b/admin-frontend/src/types/api.d.ts @@ -880,6 +880,7 @@ export interface AdminNodeItem { route_ids?: Array | null tags?: string[] | null show: boolean + auto_online?: boolean enabled?: boolean parent_id?: number | null rate?: number | null @@ -939,6 +940,7 @@ export interface AdminNodeGfwCheckResult { export interface AdminNodeUpdatePayload { id: number show?: boolean | number + auto_online?: boolean enabled?: boolean machine_id?: number | null } @@ -948,6 +950,7 @@ export interface AdminNodeBatchUpdatePayload { host?: string rate?: number group_ids?: string[] + auto_online?: boolean } export interface AdminNodeSavePayload { @@ -968,6 +971,7 @@ export interface AdminNodeSavePayload { rate_time_ranges?: AdminNodeRateTimeRange[] protocol_settings?: Record show?: boolean | number + auto_online?: boolean } declare global { diff --git a/admin-frontend/src/utils/nodeEditorMapper.ts b/admin-frontend/src/utils/nodeEditorMapper.ts index 5e54f68..ad3c2bd 100644 --- a/admin-frontend/src/utils/nodeEditorMapper.ts +++ b/admin-frontend/src/utils/nodeEditorMapper.ts @@ -171,6 +171,7 @@ export function toNodeFormModel(node?: AdminNodeItem | null): NodeFormModel { form.serverPort = toStringValue(node.server_port) form.parentId = node.parent_id ?? null form.show = toBooleanValue(node.show, true) + form.autoOnline = toBooleanValue(node.auto_online) form.enabled = toBooleanValue(node.enabled, true) form.tlsMode = Number(protocolSettings.tls ?? 0) form.tlsServerName = toStringValue(tlsSettings.server_name || tlsObject.server_name) @@ -491,5 +492,6 @@ export function toNodeSavePayload(form: NodeFormModel): AdminNodeSavePayload { rate_time_ranges: form.rateTimeEnable ? buildRateRanges(form) : [], protocol_settings: buildProtocolSettings(form), show: form.show ? 1 : 0, + auto_online: form.autoOnline, } } diff --git a/admin-frontend/src/utils/nodeEditorOptions.ts b/admin-frontend/src/utils/nodeEditorOptions.ts index 9966adb..dd68019 100644 --- a/admin-frontend/src/utils/nodeEditorOptions.ts +++ b/admin-frontend/src/utils/nodeEditorOptions.ts @@ -31,6 +31,7 @@ export interface NodeFormModel { serverPort: string parentId: number | null show: boolean + autoOnline: boolean enabled: boolean tlsMode: number tlsServerName: string @@ -241,6 +242,7 @@ export function createEmptyNodeForm(): NodeFormModel { serverPort: '', parentId: null, show: true, + autoOnline: false, enabled: true, tlsMode: 0, tlsServerName: '', diff --git a/admin-frontend/src/utils/nodes.ts b/admin-frontend/src/utils/nodes.ts index 4a3c6b9..cbd0634 100644 --- a/admin-frontend/src/utils/nodes.ts +++ b/admin-frontend/src/utils/nodes.ts @@ -199,6 +199,7 @@ function buildNodeSearchText(node: AdminNodeItem): string { node.port, node.server_port, getNodeTypeLabel(node.type), + node.auto_online ? '自动上线 自动托管 auto online' : '', getNodeGfwMeta(node).searchText, ...getNodeGroupNames(node), ] @@ -277,3 +278,7 @@ export function countOnlineNodes(nodes: AdminNodeItem[]): number { export function countVisibleNodes(nodes: AdminNodeItem[]): number { return nodes.filter((node) => Boolean(node.show)).length } + +export function countAutoOnlineNodes(nodes: AdminNodeItem[]): number { + return nodes.filter((node) => Boolean(node.auto_online)).length +} diff --git a/admin-frontend/src/views/nodes/NodeBatchEditDialog.scss b/admin-frontend/src/views/nodes/NodeBatchEditDialog.scss index 9cab9b8..afcaa30 100644 --- a/admin-frontend/src/views/nodes/NodeBatchEditDialog.scss +++ b/admin-frontend/src/views/nodes/NodeBatchEditDialog.scss @@ -50,6 +50,12 @@ align-items: flex-start; } + .batch-switch-card--nested { + padding: 12px 14px; + border-radius: 16px; + background: #ffffff; + } + .batch-switch-card strong { display: block; margin-bottom: 4px; diff --git a/admin-frontend/src/views/nodes/NodeBatchEditDialog.vue b/admin-frontend/src/views/nodes/NodeBatchEditDialog.vue index d64c599..ddf9708 100644 --- a/admin-frontend/src/views/nodes/NodeBatchEditDialog.vue +++ b/admin-frontend/src/views/nodes/NodeBatchEditDialog.vue @@ -7,6 +7,7 @@ interface NodeBatchEditPayload { host?: string rate?: number group_ids?: string[] + auto_online?: boolean } const props = defineProps<{ @@ -28,9 +29,16 @@ const form = reactive({ rate: 1, updateGroups: false, groupIds: [] as number[], + updateAutoOnline: false, + autoOnline: true, }) -const hasEnabledField = computed(() => form.updateHost || form.updateRate || form.updateGroups) +const hasEnabledField = computed(() => ( + form.updateHost + || form.updateRate + || form.updateGroups + || form.updateAutoOnline +)) function resetForm() { form.updateHost = false @@ -39,6 +47,8 @@ function resetForm() { form.rate = 1 form.updateGroups = false form.groupIds = [] + form.updateAutoOnline = false + form.autoOnline = true } function closeDialog() { @@ -65,6 +75,7 @@ function handleSubmit() { host: form.updateHost ? form.host.trim() : undefined, rate: form.updateRate ? Number(form.rate) : undefined, group_ids: form.updateGroups ? [...new Set(form.groupIds.map((item) => String(item)))] : undefined, + auto_online: form.updateAutoOnline ? form.autoOnline : undefined, }) } @@ -159,11 +170,29 @@ watch( class="full-width" /> + +
+ + + +
+ + + +