From ecc01976cde4786b91096428244b03ac453f3d29 Mon Sep 17 00:00:00 2001 From: iwvw <2285740204@qq.com> Date: Tue, 6 Jan 2026 13:23:37 +0800 Subject: [PATCH 01/11] =?UTF-8?q?fix:=20=E6=A0=B7=E5=BC=8F=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/css/dns.css | 2 +- src/css/refined-mobile.css | 1 + src/css/totp.css | 15 ++++++++------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/css/dns.css b/src/css/dns.css index d5483c2..c8db9f8 100644 --- a/src/css/dns.css +++ b/src/css/dns.css @@ -26,7 +26,7 @@ /* Zones */ .zones-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(324px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; margin-bottom: 16px; } diff --git a/src/css/refined-mobile.css b/src/css/refined-mobile.css index 443fd00..d1f68dc 100644 --- a/src/css/refined-mobile.css +++ b/src/css/refined-mobile.css @@ -1275,6 +1275,7 @@ html.single-page-mode [class*='-sec-tabs'] { } .panel-header { + padding-bottom: 3px; flex-direction: column !important; align-items: stretch !important; gap: 12px !important; diff --git a/src/css/totp.css b/src/css/totp.css index b689250..7725b1f 100644 --- a/src/css/totp.css +++ b/src/css/totp.css @@ -90,7 +90,7 @@ .totp-card { background: var(--card-bg); - border: 1px solid var(--border-color); + border: 1px solid var(--card-accent, var(--totp-primary)); border-radius: 10px; padding: 12px 12px 6px 12px; cursor: pointer; @@ -540,7 +540,7 @@ } /* 主题色输入框样式 */ -.totp-modal .totp-advanced-content > .form-group { +.totp-modal .totp-advanced-content>.form-group { margin-top: 12px; } @@ -617,11 +617,11 @@ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); } -.toggle-checkbox:checked + .toggle-switch { +.toggle-checkbox:checked+.toggle-switch { background: var(--totp-primary); } -.toggle-checkbox:checked + .toggle-switch::after { +.toggle-checkbox:checked+.toggle-switch::after { left: 20px; } @@ -718,6 +718,7 @@ /* ==================== 响应式 - 手机端列表布局 ==================== */ @media (max-width: 768px) { + /* 列表布局 */ .totp-cards-grid { display: flex; @@ -822,7 +823,7 @@ gap: 8px; } - .totp-tab-content .panel-header > div:last-child { + .totp-tab-content .panel-header>div:last-child { flex-wrap: wrap; width: 100%; } @@ -991,6 +992,6 @@ } /* 分隔线 */ -.totp-context-menu-item + .totp-context-menu-item.danger { +.totp-context-menu-item+.totp-context-menu-item.danger { border-top: 1px solid var(--border-color); -} +} \ No newline at end of file From a5c593dc1973dddabc0893805a01a430d7284808 Mon Sep 17 00:00:00 2001 From: iwvw <2285740204@qq.com> Date: Tue, 6 Jan 2026 14:43:20 +0800 Subject: [PATCH 02/11] =?UTF-8?q?fix:=20=E5=9E=83=E5=9C=BE=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- diagnose_db.js | 43 ------------------------------------------- diagnose_result.txt | Bin 2422 -> 0 bytes docker-compose.yml | 1 + 3 files changed, 1 insertion(+), 43 deletions(-) delete mode 100644 diagnose_db.js delete mode 100644 diagnose_result.txt diff --git a/diagnose_db.js b/diagnose_db.js deleted file mode 100644 index eabe392..0000000 --- a/diagnose_db.js +++ /dev/null @@ -1,43 +0,0 @@ -const db = require('./src/db/database'); -const fs = require('fs'); - -try { - console.log('正在分析数据库中的消息大小...'); - const database = db.getDatabase(); - - // 获取最近的 20 条消息 - const messages = database.prepare(` - SELECT id, role, length(content) as len, substr(content, 1, 100) as preview - FROM chat_messages - ORDER BY id DESC - LIMIT 20 - `).all(); - - console.log('ID\t| Role\t| Size(KB)\t| Preview'); - console.log('----------------------------------------------------'); - - let base64Count = 0; - - messages.forEach(msg => { - const sizeKB = (msg.len / 1024).toFixed(2); - const isBase64 = msg.preview.includes('data:image') || msg.preview.includes('base64'); - if (isBase64 && msg.len > 1000) base64Count++; - - // 简单的颜色标记 - const mark = (msg.len > 10240) ? '(!)' : ' '; - - console.log(`${msg.id}\t| ${msg.role}\t| ${sizeKB} KB${mark}\t| ${msg.preview.replace(/\n/g, ' ')}...`); - }); - - console.log('----------------------------------------------------'); - console.log(`分析完成。在大约最后 20 条消息中,发现 ${base64Count} 条疑似 Base64 图片记录。`); - - if (base64Count > 0) { - console.log('建议:这证实了数据库中确实存储了 Base64 数据。'); - } else { - console.log('提示:最近的消息似乎没有巨大的 Base64 数据。可能之前的记录导致了数据库膨胀。'); - } - -} catch (e) { - console.error('分析失败:', e); -} diff --git a/diagnose_result.txt b/diagnose_result.txt deleted file mode 100644 index 5d086891c20dcf28ff981dc2505498d0a67bb36e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2422 zcmd6pe{7RQ7{_mB38|nE`NOc;>}7GL8;rHx*cc#V><5e)`(t!%-?v@YbzS$id;7kY zmTleMcM@cfERmFZyO~8WCM0U?VjOJQL|sJrl_(I5f<%)Jm4*NVl*kgv=5y@`5X9&o zqPe`+_wL?%?w;>`p65C{^Mkc&*6TOo^QISt&+w)|xxJ`)xY@8>C0{k(?i|7y7dNVP zLK#{Co>su}3_~S`UH|seh6g50*l@e6)4_7INRqpz9uzAEh#pf}9tEIp8;rS8ds2&h^mq!{s}>bP zN$roQxfS-YHL0#2>Qp~D4Q=u)$iB&mP;(=Vm>C#zO3=pK!M>Wd%;*kVy>wFAWnbN( zpyMr0ze>Jh+^imoR?dDOv2mwOF{*SXMy;J$B97yI`VWk?_|zL!{>*3@*vOV?THuGH zui7HMs{?Px`@~W~w4JWA;x*nub87Zc|AfVk1G*S>jGu7!?j6*xaRlYUwwA<{RKb4R zu9B}C3#@59^XxymZc3Hu^X)F~XNOYUf^#(%!xsF!M$u*Cu9=jg6>p4N3^MmZ>v-4M z;51XgHzs}f1fMhA4)?+tQ|JVaQLHCX|GJrQJIxM7H_j%!Vfp<%zgmfBE7}8cA$6l^ zl&?--vITQGS}A4(55!sKoHXICGi|1|)Y9&GJ@+^#dTZy@3nl3d+^4bzMyVtn_p8jH zE|d+Y(TN0LBpV`xwA`oz>TI<9ffgCt6B!!G-6jLg;>u*U$HpKSH>sJAv#7m@Y!ea#Pe1L-5KZ&~YsB{zzG3?=m?w|DGRg-6kr%5g4k zBtSBjsH>Nzn32G#x@YCf^;Q0Ng7c#x{s^C?-)BC7ciQ`tc~OO~3^*qjJ95D)g%-HSH1%Key&Q7*36zF4$zpH4=6qkKg=A-2GId1nh&Y5HDE>scAnLFTz;On5uxv#y+O z%x$1a*4wYY!|L!NYmB)GeJv~<*Ekxt_4YNeRgv(QJloig@@eqs(cTU#(! zPA`S|F{(k>ub1jO<>fmfzD=HvZAy{w?sA<3O5gKo>1E8#4wd|yQ7P(#hPn*HA*^ij z`psBr8E8C;Bd*Qr&!fKHCs>jZcN(ohh4ogL(EE+&LA6UB3w3VnG4}uGS*`?#D+az+ SL5^#FfV; Date: Tue, 6 Jan 2026 15:22:49 +0800 Subject: [PATCH 03/11] =?UTF-8?q?fix:=20=E5=8E=86=E5=8F=B2=E9=81=97?= =?UTF-8?q?=E7=95=99=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- README.md | 4 +- docs/ARCHITECTURE.md | 6 +- docs/CONTRIBUTING.md | 4 +- eslint.config.js | 2 +- modules/_template/README.md | 111 +- modules/antigravity-api/router.js | 2 +- .../cloudflare-api.js | 0 .../models.js | 0 .../router.js | 2 +- .../schema.sql | 0 .../storage.js | 0 modules/cloudflare-dns/router_utf8.js | 1595 ----------------- modules/cron-api/service.js | 2 +- modules/{fly-api => flyio-api}/models.js | 0 modules/{fly-api => flyio-api}/router.js | 2 +- modules/{fly-api => flyio-api}/schema.sql | 0 modules/{fly-api => flyio-api}/storage.js | 0 modules/gemini-cli-api/gemini-client.js | 2 +- modules/gemini-cli-api/router.js | 2 +- .../gemini-cli-api/utils/stream-processor.js | 2 +- modules/openai-api/router.js | 2 +- .../agent-service.js | 0 .../credentials-router.js | 0 .../models.js | 0 .../monitor-service.js | 2 +- .../protocol.js | 0 .../router.js | 0 .../schema.sql | 0 .../ssh-service.js | 0 .../storage.js | 0 modules/uptime-api/monitor-service.js | 2 +- package-lock.json | 26 + package.json | 9 +- server.js | 24 +- src/css/{dns.css => cloudflare.css} | 0 src/db/models/index.js | 4 +- src/js/main.js | 6 +- src/js/modules/{dns.js => cloudflare.js} | 106 +- src/js/modules/dashboard.js | 6 +- src/js/modules/fly.js | 26 +- src/js/modules/r2.js | 12 +- src/js/modules/workers.js | 14 +- src/js/store.js | 2 +- src/routes/index.js | 18 +- src/services/log-service.js | 2 +- src/services/metrics-service.js | 4 +- src/utils/logger.js | 34 +- 48 files changed, 276 insertions(+), 1761 deletions(-) rename modules/{cloudflare-dns => cloudflare-api}/cloudflare-api.js (100%) rename modules/{cloudflare-dns => cloudflare-api}/models.js (100%) rename modules/{cloudflare-dns => cloudflare-api}/router.js (99%) rename modules/{cloudflare-dns => cloudflare-api}/schema.sql (100%) rename modules/{cloudflare-dns => cloudflare-api}/storage.js (100%) delete mode 100644 modules/cloudflare-dns/router_utf8.js rename modules/{fly-api => flyio-api}/models.js (100%) rename modules/{fly-api => flyio-api}/router.js (99%) rename modules/{fly-api => flyio-api}/schema.sql (100%) rename modules/{fly-api => flyio-api}/storage.js (100%) rename modules/{server-management => server-api}/agent-service.js (100%) rename modules/{server-management => server-api}/credentials-router.js (100%) rename modules/{server-management => server-api}/models.js (100%) rename modules/{server-management => server-api}/monitor-service.js (99%) rename modules/{server-management => server-api}/protocol.js (100%) rename modules/{server-management => server-api}/router.js (100%) rename modules/{server-management => server-api}/schema.sql (100%) rename modules/{server-management => server-api}/ssh-service.js (100%) rename modules/{server-management => server-api}/storage.js (100%) rename src/css/{dns.css => cloudflare.css} (100%) rename src/js/modules/{dns.js => cloudflare.js} (93%) diff --git a/.gitignore b/.gitignore index 590e551..b97b576 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,7 @@ accounts.json password.json sessions.json antigravity-accounts-*.json - +docs/MODULE_NAMING.md # ==================== # 用户数据 & 数据库 # ==================== diff --git a/README.md b/README.md index aa99d51..561ff2e 100644 --- a/README.md +++ b/README.md @@ -109,8 +109,8 @@ api-monitor/ │ ├── services/ # 业务服务 │ └── utils/ # 工具函数 ├── modules/ # 可插拔业务模块 -│ ├── server-management/ # 服务器/SSH/Docker -│ ├── cloudflare-dns/ # Cloudflare DNS +│ ├── server-api/ # 服务器/SSH/Docker +│ ├── cloudflare-api/ # Cloudflare DNS │ ├── antigravity-api/ # Antigravity Agent │ ├── music-api/ # 网易云音乐代理 │ └── ... # 更多模块 diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index a08c315..383271a 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -58,13 +58,13 @@ api-monitor/ │ ├── services/ # 业务服务 │ └── utils/ # 工具函数 ├── modules/ # 可插拔业务模块 (13个) -│ ├── server-management/ # 服务器/SSH/Docker -│ ├── cloudflare-dns/ # Cloudflare DNS +│ ├── server-api/ # 服务器/SSH/Docker +│ ├── cloudflare-api/ # Cloudflare DNS │ ├── antigravity-api/ # Antigravity Agent │ ├── gemini-cli-api/ # Gemini CLI │ ├── zeabur-api/ # Zeabur PaaS │ ├── koyeb-api/ # Koyeb PaaS -│ ├── fly-api/ # Fly.io +│ ├── flyio-api/ # Fly.io │ ├── music-api/ # 网易云音乐代理 │ ├── totp-api/ # 2FA 管理 │ └── ... diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index ea90bf4..af73c7c 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -56,6 +56,7 @@ npm run format ``` **类型 (type)**: + - `feat`: 新功能 - `fix`: 修复 bug - `docs`: 文档更新 @@ -66,6 +67,7 @@ npm run format - `chore`: 构建/工具变更 **示例**: + ``` feat(music): 添加歌词同步功能 @@ -107,7 +109,7 @@ api-monitor/ │ └── utils/ # 工具函数 ├── modules/ # 功能模块 │ ├── music-api/ # 音乐 API -│ ├── cloudflare-dns/# DNS 管理 +│ ├── cloudflare-api/# DNS 管理 │ └── ... ├── agent-go/ # Go Agent 源码 └── test/ # 测试文件 diff --git a/eslint.config.js b/eslint.config.js index b238739..a36fbaa 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -160,7 +160,7 @@ module.exports = [ 'plugin/**', // 浏览器扩展使用特殊 API 'src/js/modules/template.js', // 模板文件 'src/*_snippet*.js', // 代码片段 - 'modules/cloudflare-dns/router_utf8.js', // 备份文件 + ], }, ]; diff --git a/modules/_template/README.md b/modules/_template/README.md index 5d8eb39..84ad13a 100644 --- a/modules/_template/README.md +++ b/modules/_template/README.md @@ -1,49 +1,86 @@ -# 模块开发模板使用指南 +# 模块开发模板 本目录提供了一个标准化的模块开发模板,用于快速扩展项目功能。 -## 快速开始 +## 📁 模块结构规范 + +### 后端模块目录 (`modules/{module-name}/`) + +``` +modules/{module-name}/ +├── router.js # [必须] Express 路由定义 +├── storage.js # [必须] 数据访问层 (若使用 JSON 存储可合并到 router) +├── models.js # [可选] 数据模型类 (简单模块可省略) +├── schema.sql # [可选] 数据库表定义 (若使用 SQLite) +├── service.js # [可选] 外部 API 调用封装 (或 {module}-api.js) +└── utils.js # [可选] 工具函数 +``` + +### 命名约定 + +| 类型 | 规范 | 示例 | +|------|------|------| +| 目录名 | `{product/feature}-api` | `zeabur-api`, `totp-api` | +| 路由文件 | `router.js` | 统一命名 | +| 服务文件 | `service.js` 或 `{module}-api.js` | `koyeb-api.js` | +| 存储文件 | `storage.js` | 统一命名 | +| 模型文件 | `models.js` | 统一命名 | + +⚠️ **例外情况**: + +- `server-management` 和 `cloudflare-dns` 是历史遗留命名,暂不重命名 + +--- + +## 🚀 快速开始 ### 1. 后端部分 (Backend) -1. **复制模板**: 复制 `modules/_template` 文件夹并重命名为你的模块名 (例如 `my-service-api`)。 -2. **配置数据库**: - * 修改 `schema.sql`,定义你的表结构。 - * 在 `src/db/database.js` 中添加新表的初始化逻辑(或者手动在 SQLite 中运行 SQL)。 -3. **定义模型**: - * 修改 `models.js`,将 `{{module_name}}` 替换为实际表名。 - * 在 `src/db/models/index.js` 中导出你的新模型。 -4. **实现存储层**: 修改 `storage.js` 中的逻辑。 -5. **实现 API 服务**: 在 `service.js` 中实现与外部第三方 API 的交互。 -6. **注册路由**: - * 修改 `router.js` 中的路由定义。 - * 在 `src/routes/index.js` 的 `moduleRouteMap` 中添加你的模块路由映射。 +1. **复制模板**: 复制 `modules/_template` 文件夹并重命名为你的模块名 (如 `my-service-api`)。 + +2. **配置数据库**: + - 修改 `schema.sql`,定义表结构 + - 在 `src/db/database.js` 添加表初始化逻辑 + +3. **定义模型**: + - 修改 `models.js`,将 `{{module_name}}` 替换为实际表名 + - 在 `src/db/models/index.js` 导出新模型 + +4. **实现存储层**: 修改 `storage.js` 中的逻辑 + +5. **实现 API 服务**: 在 `service.js` 中实现与外部 API 的交互 + +6. **注册路由**: + - 修改 `router.js` 中的路由定义 + - 在 `src/routes/index.js` 的 `moduleRouteMap` 添加映射 ### 2. 前端部分 (Frontend) -1. **样式**: - * 复制 `src/css/template.css` 为 `src/css/your-module.css`。 - * 在 `src/index.html` 中引入该 CSS 文件。 -2. **模板**: - * 复制 `src/templates/template.html` 为 `src/templates/your-module.html`。 - * 在 `src/index.html` 的 templates 区域引入该文件(或通过 `template-loader.js` 加载)。 -3. **逻辑**: - * 复制 `src/js/modules/template.js` 为 `src/js/modules/your-module.js`。 - * 在 `src/js/main.js` 中导入并混入 (mixin) 你的模块方法。 -4. **导航**: - * 在 `src/index.html` 的侧边栏导航中添加指向你模块的链接。 - -## 关键变量替换 - -在模板文件中,请全局替换以下占位符: - -* `{{module_name}}`: 模块名称 (小写,下划线分隔),如 `my_service`。 -* `{{ModuleName}}`: 模块名称 (大驼峰),如 `MyService`。 -* `{{module_prefix}}`: 数据库 ID 前缀,如 `ms`。 -* `{{MODULE_ENV_VAR}}`: 环境变量名称,如 `MY_SERVICE_TOKEN`。 -* `{{module_title}}`: UI 显示的中文标题。 - -## 集成检查清单 +1. **样式**: 复制 `src/css/template.css` 为 `src/css/{module}.css` + +2. **模板**: 复制 `src/templates/template.html` 为 `src/templates/{module}.html` + +3. **逻辑**: 复制 `src/js/modules/template.js` 为 `src/js/modules/{module}.js` + +4. **导航**: 在 `src/index.html` 侧边栏添加导航链接 + +--- + +## 🔤 占位符替换 + +在模板文件中,全局替换以下占位符: + +| 占位符 | 说明 | 示例 | +|--------|------|------| +| `{{module_name}}` | 数据库表名 (下划线) | `my_service` | +| `{{ModuleName}}` | 类名 (大驼峰) | `MyService` | +| `{{module_prefix}}` | ID 前缀 | `ms` | +| `{{MODULE_ENV_VAR}}` | 环境变量名 | `MY_SERVICE_TOKEN` | +| `{{module_title}}` | 中文标题 | `我的服务` | + +--- + +## ✅ 集成检查清单 - [ ] `schema.sql` 已执行 (数据库表已创建) - [ ] `src/db/models/index.js` 已导出新模型 diff --git a/modules/antigravity-api/router.js b/modules/antigravity-api/router.js index 54c1c17..5e71586 100644 --- a/modules/antigravity-api/router.js +++ b/modules/antigravity-api/router.js @@ -7,7 +7,7 @@ const axios = require('axios'); const crypto = require('crypto'); const fs = require('fs'); const { createLogger } = require('../../src/utils/logger'); -const logger = createLogger('AntiG-Service'); +const logger = createLogger('AntiG'); const { requireAuth } = require('../../src/middleware/auth'); const { getSession, getSessionById } = require('../../src/services/session'); diff --git a/modules/cloudflare-dns/cloudflare-api.js b/modules/cloudflare-api/cloudflare-api.js similarity index 100% rename from modules/cloudflare-dns/cloudflare-api.js rename to modules/cloudflare-api/cloudflare-api.js diff --git a/modules/cloudflare-dns/models.js b/modules/cloudflare-api/models.js similarity index 100% rename from modules/cloudflare-dns/models.js rename to modules/cloudflare-api/models.js diff --git a/modules/cloudflare-dns/router.js b/modules/cloudflare-api/router.js similarity index 99% rename from modules/cloudflare-dns/router.js rename to modules/cloudflare-api/router.js index f6ecefb..ad565cb 100644 --- a/modules/cloudflare-dns/router.js +++ b/modules/cloudflare-api/router.js @@ -8,7 +8,7 @@ const storage = require('./storage'); const cfApi = require('./cloudflare-api'); const { createLogger } = require('../../src/utils/logger'); -const logger = createLogger('CF-DNS'); +const logger = createLogger('Cloudflare'); // ==================== 璐﹀彿绠$悊 ==================== diff --git a/modules/cloudflare-dns/schema.sql b/modules/cloudflare-api/schema.sql similarity index 100% rename from modules/cloudflare-dns/schema.sql rename to modules/cloudflare-api/schema.sql diff --git a/modules/cloudflare-dns/storage.js b/modules/cloudflare-api/storage.js similarity index 100% rename from modules/cloudflare-dns/storage.js rename to modules/cloudflare-api/storage.js diff --git a/modules/cloudflare-dns/router_utf8.js b/modules/cloudflare-dns/router_utf8.js deleted file mode 100644 index 105ef51..0000000 --- a/modules/cloudflare-dns/router_utf8.js +++ /dev/null @@ -1,1595 +0,0 @@ -/** - * Cloudflare DNS 管理 - API 路由 - */ - -const express = require('express'); -const router = express.Router(); -const storage = require('./storage'); -const cfApi = require('./cloudflare-api'); -const { createLogger } = require('../../src/utils/logger'); - -const logger = createLogger('CF-DNS'); - -// ==================== 账号管理 ==================== - -/** - * 获取所有账号(隐藏 API Token�? - */ -router.get('/accounts', (req, res) => { - try { - const accounts = storage.getAccounts(); - // 隐藏敏感信息 - const safeAccounts = accounts.map(a => ({ - id: a.id, - name: a.name, - email: a.email, - createdAt: a.createdAt, - lastUsed: a.lastUsed, - hasToken: !!a.apiToken - })); - res.json(safeAccounts); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 导出所有账号(包含 API Token,用于备份) - */ -router.get('/accounts/export', (req, res) => { - try { - const accounts = storage.getAccounts(); - // 返回完整信息用于导出 - const exportAccounts = accounts.map(a => ({ - name: a.name, - email: a.email, - apiToken: a.apiToken - })); - res.json({ - success: true, - accounts: exportAccounts - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 添加账号 - */ -router.post('/accounts', async (req, res) => { - try { - const { name, apiToken, email, skipVerify } = req.body; - - if (!name || !apiToken) { - return res.status(400).json({ error: '名称�?API Token 必填' }); - } - - // 验证 Token(除非明确跳过验证,用于数据导入�? - if (!skipVerify) { - // 根据是否�?email 选择验证方式 - const auth = email - ? { email, key: apiToken } // Global API Key - : apiToken; // API Token - - const verification = await cfApi.verifyToken(auth); - if (!verification.valid) { - return res.status(400).json({ error: `Token 无效: ${verification.error}` }); - } - } - - const account = storage.addAccount({ name, apiToken, email }); - res.json({ - success: true, - account: { - id: account.id, - name: account.name, - email: account.email, - createdAt: account.createdAt - } - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 更新账号 - */ -router.put('/accounts/:id', async (req, res) => { - try { - const { id } = req.params; - const { name, apiToken, email } = req.body; - - // 如果更新 Token,先验证 - if (apiToken) { - // 根据是否�?email 选择验证方式 - const auth = email - ? { email, key: apiToken } // Global API Key - : apiToken; // API Token - - const verification = await cfApi.verifyToken(auth); - if (!verification.valid) { - return res.status(400).json({ error: `Token 无效: ${verification.error}` }); - } - } - - const updated = storage.updateAccount(id, { name, apiToken, email }); - if (!updated) { - return res.status(404).json({ error: '账号不存�? }); - } - - res.json({ success: true }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 删除账号 - */ -router.delete('/accounts/:id', (req, res) => { - try { - const { id } = req.params; - const deleted = storage.deleteAccount(id); - if (!deleted) { - return res.status(404).json({ error: '账号不存�? }); - } - res.json({ success: true }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 验证账号 Token - */ -router.post('/accounts/:id/verify', async (req, res) => { - try { - const { id } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - // 根据账号配置选择认证方式 - const auth = account.email - ? { email: account.email, key: account.apiToken } // Global API Key - : account.apiToken; // API Token - - const verification = await cfApi.verifyToken(auth); - res.json(verification); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 获取账号�?API Token(用于显示) - */ -router.get('/accounts/:id/token', (req, res) => { - try { - const { id } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - res.json({ - success: true, - apiToken: account.apiToken - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -// ==================== Zone 管理 ==================== - -/** - * 获取账号下的所有域�? - */ -router.get('/accounts/:id/zones', async (req, res) => { - try { - const { id } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(id); - - // 根据账号配置选择认证方式 - const auth = account.email - ? { email: account.email, key: account.apiToken } - : account.apiToken; - - const { zones, resultInfo } = await cfApi.listZones(auth); - - res.json({ - zones: zones.map(z => ({ - id: z.id, - name: z.name, - status: z.status, - paused: z.paused, - type: z.type, - nameServers: z.name_servers, - createdOn: z.created_on, - modifiedOn: z.modified_on - })), - pagination: resultInfo - }); - } catch (e) { - logger.error(`获取域名列表失败 (ID: ${req.params.id}):`, e.message); - res.status(500).json({ error: e.message }); - } -}); - -/** - * 创建域名 (添加�?Zone) - */ -router.post('/accounts/:id/zones', async (req, res) => { - try { - const { id } = req.params; - const { name, jumpStart } = req.body; - - if (!name) { - return res.status(400).json({ error: '域名不能为空' }); - } - - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(id); - - // 获取 Cloudflare Account ID - const cfAccountId = await cfApi.getAccountId(account.apiToken); - - // 创建新域�? - const zone = await cfApi.createZone(account.apiToken, name, { - account: { id: cfAccountId }, - jump_start: jumpStart !== undefined ? jumpStart : false - }); - - logger.info(`域名创建成功: ${name} (Zone ID: ${zone.id})`); - - res.json({ - success: true, - zone: { - id: zone.id, - name: zone.name, - status: zone.status, - nameServers: zone.name_servers, - createdOn: zone.created_on - } - }); - } catch (e) { - logger.error(`创建域名失败:`, e.message); - res.status(500).json({ error: e.message }); - } -}); - -/** - * 删除域名 (删除 Zone) - */ -router.delete('/accounts/:accountId/zones/:zoneId', async (req, res) => { - try { - const { accountId, zoneId } = req.params; - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - const result = await cfApi.deleteZone(account.apiToken, zoneId); - - logger.info(`域名删除成功: Zone ID ${zoneId}`); - - res.json({ - success: true, - result - }); - } catch (e) { - logger.error(`删除域名失败:`, e.message); - res.status(500).json({ error: e.message }); - } -}); - -// ==================== DNS 记录管理 ==================== - -/** - * 获取域名�?DNS 记录 - */ -router.get('/accounts/:accountId/zones/:zoneId/records', async (req, res) => { - try { - const { accountId, zoneId } = req.params; - const { type, name, page } = req.query; - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - - // 根据账号配置选择认证方式 - const auth = account.email - ? { email: account.email, key: account.apiToken } - : account.apiToken; - - const { records, resultInfo } = await cfApi.listDnsRecords( - auth, - zoneId, - { type, name, page } - ); - - res.json({ - records: records.map(r => ({ - id: r.id, - type: r.type, - name: r.name, - content: r.content, - proxied: r.proxied, - ttl: r.ttl, - priority: r.priority, - createdOn: r.created_on, - modifiedOn: r.modified_on - })), - pagination: resultInfo - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 创建 DNS 记录 - */ -router.post('/accounts/:accountId/zones/:zoneId/records', async (req, res) => { - try { - const { accountId, zoneId } = req.params; - const { type, name, content, ttl, proxied, priority } = req.body; - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - // 验证记录 - const validation = cfApi.validateDnsRecord({ type, name, content, priority }); - if (!validation.valid) { - return res.status(400).json({ error: validation.errors.join(', ') }); - } - - storage.touchAccount(accountId); - const record = await cfApi.createDnsRecord( - account.apiToken, - zoneId, - { type, name, content, ttl, proxied, priority } - ); - - res.json({ - success: true, - record: { - id: record.id, - type: record.type, - name: record.name, - content: record.content, - proxied: record.proxied, - ttl: record.ttl - } - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 更新 DNS 记录 - */ -router.put('/accounts/:accountId/zones/:zoneId/records/:recordId', async (req, res) => { - try { - const { accountId, zoneId, recordId } = req.params; - const { type, name, content, ttl, proxied, priority } = req.body; - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - const record = await cfApi.updateDnsRecord( - account.apiToken, - zoneId, - recordId, - { type, name, content, ttl, proxied, priority } - ); - - res.json({ - success: true, - record: { - id: record.id, - type: record.type, - name: record.name, - content: record.content, - proxied: record.proxied, - ttl: record.ttl - } - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 删除 DNS 记录 - */ -router.delete('/accounts/:accountId/zones/:zoneId/records/:recordId', async (req, res) => { - try { - const { accountId, zoneId, recordId } = req.params; - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - await cfApi.deleteDnsRecord(account.apiToken, zoneId, recordId); - - res.json({ success: true }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 快速切�?DNS 记录内容 - */ -router.post('/accounts/:accountId/zones/:zoneId/switch', async (req, res) => { - try { - const { accountId, zoneId } = req.params; - const { type, name, newContent } = req.body; - - if (!type || !name || !newContent) { - return res.status(400).json({ error: 'type, name, newContent 必填' }); - } - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - const updated = await cfApi.switchDnsContent( - account.apiToken, - zoneId, - type, - name, - newContent - ); - - res.json({ - success: true, - updated: updated.length, - records: updated.map(r => ({ - id: r.id, - name: r.name, - content: r.content - })) - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 批量创建 DNS 记录 - */ -router.post('/accounts/:accountId/zones/:zoneId/batch', async (req, res) => { - try { - const { accountId, zoneId } = req.params; - const { records } = req.body; - - if (!records || !Array.isArray(records)) { - return res.status(400).json({ error: '需要提�?records 数组' }); - } - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - const { results, errors } = await cfApi.batchCreateDnsRecords( - account.apiToken, - zoneId, - records - ); - - res.json({ - success: errors.length === 0, - created: results.length, - failed: errors.length, - results, - errors - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -// ==================== 缓存管理 ==================== - -/** - * 清除域名的所有缓�? - */ -router.post('/accounts/:accountId/zones/:zoneId/purge', async (req, res) => { - try { - const { accountId, zoneId } = req.params; - const { purge_everything } = req.body; - - logger.info(`收到清除缓存请求 - Account: ${accountId}, Zone: ${zoneId}, Body:`, req.body); - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - - // 根据账号配置选择认证方式 - const auth = account.email - ? { email: account.email, key: account.apiToken } // Global API Key - : account.apiToken; // API Token - - logger.info(`使用认证方式: ${account.email ? 'Global API Key' : 'API Token'}`); - - // 调用 Cloudflare API 清除缓存 - logger.info(`调用 Cloudflare API 清除缓存...`); - const result = await cfApi.purgeCache(auth, zoneId, { purge_everything }); - - logger.info(`缓存已清除成�?(Zone: ${zoneId})`); - - res.json({ - success: true, - message: '缓存已清�?, - result - }); - } catch (e) { - logger.error(`清除缓存失败:`, e.message, e.stack); - res.status(500).json({ error: e.message, details: e.stack }); - } -}); - -// ==================== SSL/TLS 管理 ==================== - -/** - * 获取域名的SSL/TLS信息 - */ -router.get('/accounts/:accountId/zones/:zoneId/ssl', async (req, res) => { - try { - const { accountId, zoneId } = req.params; - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - - // 认证方式选择 - const auth = account.email - ? { email: account.email, key: account.apiToken } - : account.apiToken; - - // 并行获取多个SSL相关信息 - const [settings, certificates, verification] = await Promise.all([ - cfApi.getSslSettings(auth, zoneId), - cfApi.getSslCertificates(auth, zoneId), - cfApi.getSslVerification(auth, zoneId) - ]); - - logger.info(`获取SSL信息成功 (Zone: ${zoneId})`); - - res.json({ - success: true, - ssl: { - mode: settings.value, - modifiedOn: settings.modified_on, - editable: settings.editable, - certificates: certificates.map(cert => ({ - id: cert.id, - type: cert.type, - hosts: cert.hosts, - status: cert.status, - validityDays: cert.validity_days, - certificateAuthority: cert.certificate_authority, - primary: cert.primary - })), - verification: verification - } - }); - } catch (e) { - logger.error(`获取SSL信息失败:`, e.message); - res.status(500).json({ error: e.message }); - } -}); - -/** - * 修改域名的SSL模式 - */ -router.patch('/accounts/:accountId/zones/:zoneId/ssl', async (req, res) => { - try { - const { accountId, zoneId } = req.params; - const { mode } = req.body; - - if (!mode || !['off', 'flexible', 'full', 'strict'].includes(mode)) { - return res.status(400).json({ error: '无效的SSL模式' }); - } - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - - const auth = account.email - ? { email: account.email, key: account.apiToken } - : account.apiToken; - - const result = await cfApi.updateSslMode(auth, zoneId, mode); - - logger.info(`SSL模式已更�?(Zone: ${zoneId}, Mode: ${mode})`); - - res.json({ - success: true, - ssl: { - mode: result.value, - modifiedOn: result.modified_on - } - }); - } catch (e) { - logger.error(`更新SSL模式失败:`, e.message); - res.status(500).json({ error: e.message }); - } -}); - -// ==================== Analytics 分析 ==================== - -/** - * 获取域名的Analytics数据 - */ -router.get('/accounts/:accountId/zones/:zoneId/analytics', async (req, res) => { - try { - const { accountId, zoneId } = req.params; - const { timeRange = '24h' } = req.query; - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - - const auth = account.email - ? { email: account.email, key: account.apiToken } - : account.apiToken; - - const analytics = await cfApi.getSimpleAnalytics(auth, zoneId, timeRange); - - logger.info(`获取Analytics成功 (Zone: ${zoneId}, Range: ${timeRange})`); - - res.json({ - success: true, - analytics, - timeRange - }); - } catch (e) { - logger.error(`获取Analytics失败:`, e.message); - res.status(500).json({ error: e.message }); - } -}); - -// ==================== DNS 模板管理 ==================== - -/** - * 获取所有模�? - */ -router.get('/templates', (req, res) => { - try { - const templates = storage.getTemplates(); - res.json(templates); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 添加模板 - */ -router.post('/templates', (req, res) => { - try { - const { name, type, content, proxied, ttl, priority, description } = req.body; - - if (!name || !type || !content) { - return res.status(400).json({ error: '名称、类型、内容必�? }); - } - - const template = storage.addTemplate({ - name, type, content, proxied, ttl, priority, description - }); - - res.json({ success: true, template }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 更新模板 - */ -router.put('/templates/:id', (req, res) => { - try { - const { id } = req.params; - const updated = storage.updateTemplate(id, req.body); - - if (!updated) { - return res.status(404).json({ error: '模板不存�? }); - } - - res.json({ success: true, template: updated }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 删除模板 - */ -router.delete('/templates/:id', (req, res) => { - try { - const { id } = req.params; - const deleted = storage.deleteTemplate(id); - - if (!deleted) { - return res.status(404).json({ error: '模板不存�? }); - } - - res.json({ success: true }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 应用模板到域�? - */ -router.post('/templates/:templateId/apply', async (req, res) => { - try { - const { templateId } = req.params; - const { accountId, zoneId, recordName } = req.body; - - if (!accountId || !zoneId || !recordName) { - return res.status(400).json({ error: 'accountId, zoneId, recordName 必填' }); - } - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - const templates = storage.getTemplates(); - const template = templates.find(t => t.id === templateId); - if (!template) { - return res.status(404).json({ error: '模板不存�? }); - } - - storage.touchAccount(accountId); - const record = await cfApi.createDnsRecord( - account.apiToken, - zoneId, - { - type: template.type, - name: recordName, - content: template.content, - ttl: template.ttl, - proxied: template.proxied, - priority: template.priority - } - ); - - res.json({ - success: true, - record: { - id: record.id, - type: record.type, - name: record.name, - content: record.content - } - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -// ==================== 实用功能 ==================== - -/** - * 获取支持的记录类�? - */ -router.get('/record-types', (req, res) => { - res.json(cfApi.getSupportedRecordTypes()); -}); - -/** - * 导出账号(包含完整数据,用于备份�? - */ -router.get('/export/accounts', (req, res) => { - try { - const accounts = storage.getAccounts(); - res.json(accounts); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 批量导入账号(直接覆盖数据库�? - */ -router.post('/import/accounts', (req, res) => { - try { - const { accounts, overwrite } = req.body; - - if (!accounts || !Array.isArray(accounts)) { - return res.status(400).json({ error: '需要提�?accounts 数组' }); - } - - if (overwrite) { - // 直接覆盖所有账�? - storage.saveAccounts(accounts); - } else { - // 追加账号 - accounts.forEach(account => { - storage.addAccount(account); - }); - } - - res.json({ success: true, count: accounts.length }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 批量导入模板(直接覆盖数据库�? - */ -router.post('/import/templates', (req, res) => { - try { - const { templates, overwrite } = req.body; - - if (!templates || !Array.isArray(templates)) { - return res.status(400).json({ error: '需要提�?templates 数组' }); - } - - if (overwrite) { - // 直接覆盖所有模�? - storage.saveTemplates(templates); - } else { - // 追加模板 - templates.forEach(template => { - storage.addTemplate(template); - }); - } - - res.json({ success: true, count: templates.length }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -// ==================== Workers 管理 ==================== - -/** - * 获取账号�?Cloudflare Account ID - */ -router.get('/accounts/:id/cf-account-id', async (req, res) => { - try { - const { id } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - const cfAccountId = await cfApi.getAccountId(account.apiToken); - res.json({ success: true, cfAccountId }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 获取账号下的所�?Workers - */ -router.get('/accounts/:id/workers', async (req, res) => { - try { - const { id } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(id); - - // 先获�?CF Account ID - const cfAccountId = await cfApi.getAccountId(account.apiToken); - const workers = await cfApi.listWorkers(account.apiToken, cfAccountId); - logger.info(`获取�?${workers.length} �?Workers (Account: ${cfAccountId})`); - - // 获取子域名信�? - const subdomain = await cfApi.getWorkersSubdomain(account.apiToken, cfAccountId); - - res.json({ - workers: workers.map(w => ({ - id: w.id, - name: w.id, // Worker �?id 就是名称 - createdOn: w.created_on, - modifiedOn: w.modified_on, - etag: w.etag - })), - subdomain: subdomain?.subdomain || null, - cfAccountId - }); - } catch (e) { - logger.error(`获取 Workers 列表失败:`, e.message); - res.status(500).json({ error: e.message }); - } -}); - -/** - * 获取 Worker 脚本内容 - */ -router.get('/accounts/:id/workers/:scriptName', async (req, res) => { - try { - const { id, scriptName } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - const cfAccountId = await cfApi.getAccountId(account.apiToken); - const worker = await cfApi.getWorkerScript(account.apiToken, cfAccountId, scriptName); - - res.json({ - success: true, - worker: { - name: worker.name, - script: worker.script, - meta: worker.meta - } - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 创建或更�?Worker 脚本 - */ -router.put('/accounts/:id/workers/:scriptName', async (req, res) => { - try { - const { id, scriptName } = req.params; - const { script, bindings, compatibility_date } = req.body; - - logger.info(`保存 Worker: ${scriptName}, 脚本长度: ${script?.length || 0}`); - - if (!script) { - return res.status(400).json({ error: '脚本内容不能为空' }); - } - - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(id); - const cfAccountId = await cfApi.getAccountId(account.apiToken); - logger.info(`CF Account ID: ${cfAccountId}`); - - const result = await cfApi.putWorkerScript( - account.apiToken, - cfAccountId, - scriptName, - script, - { bindings, compatibility_date } - ); - - res.json({ - success: true, - worker: result - }); - } catch (e) { - logger.error(`保存 Worker 失败:`, e.message, e.stack); - res.status(500).json({ error: e.message }); - } -}); - -/** - * 删除 Worker 脚本 - */ -router.delete('/accounts/:id/workers/:scriptName', async (req, res) => { - try { - const { id, scriptName } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(id); - const cfAccountId = await cfApi.getAccountId(account.apiToken); - await cfApi.deleteWorkerScript(account.apiToken, cfAccountId, scriptName); - - res.json({ success: true }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 启用/禁用 Worker (子域访问) - */ -router.post('/accounts/:id/workers/:scriptName/toggle', async (req, res) => { - try { - const { id, scriptName } = req.params; - const { enabled } = req.body; - - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(id); - const cfAccountId = await cfApi.getAccountId(account.apiToken); - const result = await cfApi.setWorkerEnabled(account.apiToken, cfAccountId, scriptName, enabled); - - res.json({ success: true, result }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 获取域名�?Worker 路由 - */ -router.get('/accounts/:accountId/zones/:zoneId/workers/routes', async (req, res) => { - try { - const { accountId, zoneId } = req.params; - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - const routes = await cfApi.listWorkerRoutes(account.apiToken, zoneId); - - res.json({ - routes: routes.map(r => ({ - id: r.id, - pattern: r.pattern, - script: r.script - })) - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 创建 Worker 路由 - */ -router.post('/accounts/:accountId/zones/:zoneId/workers/routes', async (req, res) => { - try { - const { accountId, zoneId } = req.params; - const { pattern, script } = req.body; - - if (!pattern || !script) { - return res.status(400).json({ error: 'pattern �?script 必填' }); - } - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - const route = await cfApi.createWorkerRoute(account.apiToken, zoneId, pattern, script); - - res.json({ - success: true, - route: { - id: route.id, - pattern: route.pattern, - script: route.script - } - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 更新 Worker 路由 - */ -router.put('/accounts/:accountId/zones/:zoneId/workers/routes/:routeId', async (req, res) => { - try { - const { accountId, zoneId, routeId } = req.params; - const { pattern, script } = req.body; - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - const route = await cfApi.updateWorkerRoute(account.apiToken, zoneId, routeId, pattern, script); - - res.json({ - success: true, - route: { - id: route.id, - pattern: route.pattern, - script: route.script - } - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 删除 Worker 路由 - */ -router.delete('/accounts/:accountId/zones/:zoneId/workers/routes/:routeId', async (req, res) => { - try { - const { accountId, zoneId, routeId } = req.params; - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(accountId); - await cfApi.deleteWorkerRoute(account.apiToken, zoneId, routeId); - - res.json({ success: true }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 获取 Worker 统计信息 - */ -router.get('/accounts/:id/workers/:scriptName/analytics', async (req, res) => { - try { - const { id, scriptName } = req.params; - const { since } = req.query; - - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - const cfAccountId = await cfApi.getAccountId(account.apiToken); - const analytics = await cfApi.getWorkerAnalytics(account.apiToken, cfAccountId, scriptName, since); - - res.json({ success: true, analytics }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -// ==================== Workers 自定义域名管�?==================== - -/** - * 获取 Worker 的自定义域名列表 - */ -router.get('/accounts/:id/workers/:scriptName/domains', async (req, res) => { - try { - const { id, scriptName } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - const cfAccountId = await cfApi.getAccountId(account.apiToken); - const domains = await cfApi.listWorkerDomains(account.apiToken, cfAccountId, scriptName); - - res.json({ - success: true, - domains: domains.map(d => ({ - id: d.id, - hostname: d.hostname, - service: d.service, - environment: d.environment, - zoneId: d.zone_id, - zoneName: d.zone_name - })) - }); - } catch (e) { - logger.error(`获取 Worker 域名失败:`, e.message); - res.status(500).json({ error: e.message }); - } -}); - -/** - * 添加 Worker 自定义域�? - */ -router.post('/accounts/:id/workers/:scriptName/domains', async (req, res) => { - try { - const { id, scriptName } = req.params; - const { hostname, environment } = req.body; - - if (!hostname) { - return res.status(400).json({ error: '请输入域�? }); - } - - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(id); - const cfAccountId = await cfApi.getAccountId(account.apiToken); - const result = await cfApi.addWorkerDomain(account.apiToken, cfAccountId, scriptName, hostname, environment || 'production'); - - res.json({ success: true, domain: result }); - } catch (e) { - logger.error(`添加 Worker 域名失败:`, e.message); - res.status(500).json({ error: e.message }); - } -}); - -/** - * 删除 Worker 自定义域�? - */ -router.delete('/accounts/:id/workers/:scriptName/domains/:domainId', async (req, res) => { - try { - const { id, scriptName, domainId } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(id); - const cfAccountId = await cfApi.getAccountId(account.apiToken); - await cfApi.deleteWorkerDomain(account.apiToken, cfAccountId, domainId); - - res.json({ success: true }); - } catch (e) { - logger.error(`删除 Worker 域名失败:`, e.message); - res.status(500).json({ error: e.message }); - } -}); - -// ==================== Pages 管理路由 ==================== - - -/** - * 获取 Pages 项目列表 - */ -router.get('/accounts/:id/pages', async (req, res) => { - try { - const { id } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - storage.touchAccount(id); - const cfAccountId = await cfApi.getAccountId(account.apiToken); - const projects = await cfApi.listPagesProjects(account.apiToken, cfAccountId); - - logger.info(`获取�?${projects.length} �?Pages 项目 (Account: ${cfAccountId})`); - - res.json({ - projects: projects.map(p => ({ - name: p.name, - subdomain: p.subdomain, - domains: p.domains || [], - createdOn: p.created_on, - productionBranch: p.production_branch, - latestDeployment: p.latest_deployment ? { - id: p.latest_deployment.id, - url: p.latest_deployment.url, - status: p.latest_deployment.latest_stage?.status || 'unknown', - createdOn: p.latest_deployment.created_on - } : null - })), - cfAccountId - }); - } catch (e) { - logger.error(`获取 Pages 项目失败:`, e.message); - res.status(500).json({ error: e.message }); - } -}); - -/** - * 获取 Pages 项目的部署列�? - */ -router.get('/accounts/:id/pages/:projectName/deployments', async (req, res) => { - try { - const { id, projectName } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - const cfAccountId = await cfApi.getAccountId(account.apiToken); - const deployments = await cfApi.listPagesDeployments(account.apiToken, cfAccountId, projectName); - - res.json({ - success: true, - deployments: (deployments || []).map(d => { - // 防御性处理:防止 d 为空或字段缺�? - if (!d) return null; - return { - id: d.id, - url: d.url, - environment: d.environment, - status: (d.latest_stage && d.latest_stage.status) ? d.latest_stage.status : 'unknown', - createdOn: d.created_on, - source: d.source, - buildConfig: d.build_config - }; - }).filter(d => d !== null) // 过滤掉无效项 - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 删除 Pages 部署 - */ -router.delete('/accounts/:id/pages/:projectName/deployments/:deploymentId', async (req, res) => { - try { - const { id, projectName, deploymentId } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - const cfAccountId = await cfApi.getAccountId(account.apiToken); - await cfApi.deletePagesDeployment(account.apiToken, cfAccountId, projectName, deploymentId); - - res.json({ success: true }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 获取 Pages 项目的自定义域名 - */ -router.get('/accounts/:id/pages/:projectName/domains', async (req, res) => { - try { - const { id, projectName } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - const cfAccountId = await cfApi.getAccountId(account.apiToken); - const domains = await cfApi.listPagesDomains(account.apiToken, cfAccountId, projectName); - - res.json({ - success: true, - domains: domains.map(d => ({ - id: d.id, - name: d.name, - status: d.status, - validationStatus: d.validation_data?.status || null, - createdOn: d.created_on - })) - }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 添加 Pages 自定义域�? - */ -router.post('/accounts/:id/pages/:projectName/domains', async (req, res) => { - try { - const { id, projectName } = req.params; - const { domain } = req.body; - - if (!domain) { - return res.status(400).json({ error: '请输入域�? }); - } - - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - const cfAccountId = await cfApi.getAccountId(account.apiToken); - const result = await cfApi.addPagesDomain(account.apiToken, cfAccountId, projectName, domain); - - res.json({ success: true, domain: result.result }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 删除 Pages 自定义域�? - */ -router.delete('/accounts/:id/pages/:projectName/domains/:domain', async (req, res) => { - try { - const { id, projectName, domain } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - const cfAccountId = await cfApi.getAccountId(account.apiToken); - await cfApi.deletePagesDomain(account.apiToken, cfAccountId, projectName, domain); - - res.json({ success: true }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -/** - * 删除 Pages 项目 - */ -router.delete('/accounts/:id/pages/:projectName', async (req, res) => { - try { - const { id, projectName } = req.params; - const account = storage.getAccountById(id); - if (!account) { - return res.status(404).json({ error: '账号不存�? }); - } - - const cfAccountId = await cfApi.getAccountId(account.apiToken); - await cfApi.deletePagesProject(account.apiToken, cfAccountId, projectName); - - res.json({ success: true }); - } catch (e) { - res.status(500).json({ error: e.message }); - } -}); - -// ==================== R2 �洢���� ==================== - -/** - * ��ȡ R2 �洢Ͱ�б� - */ -router.get('/accounts/:accountId/r2/buckets', async (req, res) => { - try { - const { accountId } = req.params; - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '�˺Ų�����' }); - } - - const auth = account.email ? { email: account.email, key: account.apiToken } : account.apiToken; - const cfAccountId = await cfApi.getAccountId(account.apiToken); - - const buckets = await cfApi.listR2Buckets(auth, cfAccountId); - res.json({ success: true, buckets }); - } catch (e) { - logger.error(��ȡ R2 �洢Ͱʧ��:, e.message); - res.status(500).json({ error: e.message }); - } -}); - -/** - * ���� R2 �洢Ͱ - */ -router.post('/accounts/:accountId/r2/buckets', async (req, res) => { - try { - const { accountId } = req.params; - const { name, location } = req.body; - - if (!name) { - return res.status(400).json({ error: 'Ͱ���Ʊ���' }); - } - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '�˺Ų�����' }); - } - - const auth = account.email ? { email: account.email, key: account.apiToken } : account.apiToken; - const cfAccountId = await cfApi.getAccountId(account.apiToken); - - const bucket = await cfApi.createR2Bucket(auth, cfAccountId, name, location); - res.json({ success: true, bucket }); - } catch (e) { - logger.error(���� R2 �洢Ͱʧ��:, e.message); - res.status(500).json({ error: e.message }); - } -}); - -/** - * ɾ�� R2 �洢Ͱ - */ -router.delete('/accounts/:accountId/r2/buckets/:bucketName', async (req, res) => { - try { - const { accountId, bucketName } = req.params; - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '�˺Ų�����' }); - } - - const auth = account.email ? { email: account.email, key: account.apiToken } : account.apiToken; - const cfAccountId = await cfApi.getAccountId(account.apiToken); - - await cfApi.deleteR2Bucket(auth, cfAccountId, bucketName); - res.json({ success: true }); - } catch (e) { - logger.error(ɾ�� R2 �洢Ͱʧ��:, e.message); - res.status(500).json({ error: e.message }); - } -}); - -/** - * �г� R2 ���� - */ -router.get('/accounts/:accountId/r2/buckets/:bucketName/objects', async (req, res) => { - try { - const { accountId, bucketName } = req.params; - const { prefix, cursor, limit, delimiter } = req.query; - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '�˺Ų�����' }); - } - - const auth = account.email ? { email: account.email, key: account.apiToken } : account.apiToken; - const cfAccountId = await cfApi.getAccountId(account.apiToken); - - const result = await cfApi.listR2Objects(auth, cfAccountId, bucketName, { - prefix, cursor, limit, delimiter - }); - - res.json({ success: true, ...result }); - } catch (e) { - logger.error(�г� R2 ����ʧ��:, e.message); - res.status(500).json({ error: e.message }); - } -}); - -/** - * ɾ�� R2 ���� - */ -router.delete('/accounts/:accountId/r2/buckets/:bucketName/objects/:objectKey', async (req, res) => { - try { - const { accountId, bucketName, objectKey } = req.params; - - const account = storage.getAccountById(accountId); - if (!account) { - return res.status(404).json({ error: '�˺Ų�����' }); - } - - const auth = account.email ? { email: account.email, key: account.apiToken } : account.apiToken; - const cfAccountId = await cfApi.getAccountId(account.apiToken); - - await cfApi.deleteR2Object(auth, cfAccountId, bucketName, objectKey); - res.json({ success: true }); - } catch (e) { - logger.error(ɾ�� R2 ����ʧ��:, e.message); - res.status(500).json({ error: e.message }); - } -}); - - -module.exports = router; diff --git a/modules/cron-api/service.js b/modules/cron-api/service.js index be84fd6..11001ca 100644 --- a/modules/cron-api/service.js +++ b/modules/cron-api/service.js @@ -3,7 +3,7 @@ const { exec } = require('child_process'); const { CronTask, CronLog } = require('./models'); const axios = require('axios'); const { createLogger } = require('../../src/utils/logger'); -const logger = createLogger('CronService'); +const logger = createLogger('Cron'); class CronService { constructor() { diff --git a/modules/fly-api/models.js b/modules/flyio-api/models.js similarity index 100% rename from modules/fly-api/models.js rename to modules/flyio-api/models.js diff --git a/modules/fly-api/router.js b/modules/flyio-api/router.js similarity index 99% rename from modules/fly-api/router.js rename to modules/flyio-api/router.js index fa8decc..4c16eaf 100644 --- a/modules/fly-api/router.js +++ b/modules/flyio-api/router.js @@ -7,7 +7,7 @@ const router = express.Router(); const storage = require('./storage'); const axios = require('axios'); const { createLogger } = require('../../src/utils/logger'); -const logger = createLogger('Fly.io'); +const logger = createLogger('Fly'); logger.info('Module Loaded'); diff --git a/modules/fly-api/schema.sql b/modules/flyio-api/schema.sql similarity index 100% rename from modules/fly-api/schema.sql rename to modules/flyio-api/schema.sql diff --git a/modules/fly-api/storage.js b/modules/flyio-api/storage.js similarity index 100% rename from modules/fly-api/storage.js rename to modules/flyio-api/storage.js diff --git a/modules/gemini-cli-api/gemini-client.js b/modules/gemini-cli-api/gemini-client.js index 302a9b9..d716c0b 100644 --- a/modules/gemini-cli-api/gemini-client.js +++ b/modules/gemini-cli-api/gemini-client.js @@ -1,7 +1,7 @@ const axios = require('axios'); const { HttpsProxyAgent } = require('https-proxy-agent'); const { createLogger } = require('../../src/utils/logger'); -const logger = createLogger('Gemini-Client'); +const logger = createLogger('GCLI-Client'); const AntigravityRequester = require('../antigravity-api/antigravity-requester'); const path = require('path'); let storage; diff --git a/modules/gemini-cli-api/router.js b/modules/gemini-cli-api/router.js index 56052a4..53c5023 100644 --- a/modules/gemini-cli-api/router.js +++ b/modules/gemini-cli-api/router.js @@ -6,7 +6,7 @@ const client = require('./gemini-client'); const StreamProcessor = require('./utils/stream-processor'); const { requireAuth } = require('../../src/middleware/auth'); const { createLogger } = require('../../src/utils/logger'); -const logger = createLogger('GCLI-Service'); +const logger = createLogger('GCLI'); const streamProcessor = new StreamProcessor(client); diff --git a/modules/gemini-cli-api/utils/stream-processor.js b/modules/gemini-cli-api/utils/stream-processor.js index 20134dc..e66a6e0 100644 --- a/modules/gemini-cli-api/utils/stream-processor.js +++ b/modules/gemini-cli-api/utils/stream-processor.js @@ -1,6 +1,6 @@ const { Readable } = require('stream'); const { createLogger } = require('../../../src/utils/logger'); -const logger = createLogger('Gemini-Stream'); +const logger = createLogger('GCLI-Stream'); class StreamProcessor { constructor(client) { diff --git a/modules/openai-api/router.js b/modules/openai-api/router.js index 422a2b8..2277072 100644 --- a/modules/openai-api/router.js +++ b/modules/openai-api/router.js @@ -9,7 +9,7 @@ const openaiApi = require('./openai-api'); const { proxyLimiter } = require('../../src/middleware/rateLimit'); const { validate, chatCompletionSchema } = require('../../src/middleware/validation'); const { createLogger } = require('../../src/utils/logger'); -const logger = createLogger('OpenAI-Service'); +const logger = createLogger('OpenAI'); // ==================== 端点管理 ==================== diff --git a/modules/server-management/agent-service.js b/modules/server-api/agent-service.js similarity index 100% rename from modules/server-management/agent-service.js rename to modules/server-api/agent-service.js diff --git a/modules/server-management/credentials-router.js b/modules/server-api/credentials-router.js similarity index 100% rename from modules/server-management/credentials-router.js rename to modules/server-api/credentials-router.js diff --git a/modules/server-management/models.js b/modules/server-api/models.js similarity index 100% rename from modules/server-management/models.js rename to modules/server-api/models.js diff --git a/modules/server-management/monitor-service.js b/modules/server-api/monitor-service.js similarity index 99% rename from modules/server-management/monitor-service.js rename to modules/server-api/monitor-service.js index 285d08a..a862c17 100644 --- a/modules/server-management/monitor-service.js +++ b/modules/server-api/monitor-service.js @@ -7,7 +7,7 @@ const cron = require('node-cron'); const { ServerAccount, ServerMonitorLog, ServerMonitorConfig } = require('./models'); const { createLogger } = require('../../src/utils/logger'); -const logger = createLogger('ServerMonitor'); +const logger = createLogger('Monitor'); class MonitorService { constructor() { diff --git a/modules/server-management/protocol.js b/modules/server-api/protocol.js similarity index 100% rename from modules/server-management/protocol.js rename to modules/server-api/protocol.js diff --git a/modules/server-management/router.js b/modules/server-api/router.js similarity index 100% rename from modules/server-management/router.js rename to modules/server-api/router.js diff --git a/modules/server-management/schema.sql b/modules/server-api/schema.sql similarity index 100% rename from modules/server-management/schema.sql rename to modules/server-api/schema.sql diff --git a/modules/server-management/ssh-service.js b/modules/server-api/ssh-service.js similarity index 100% rename from modules/server-management/ssh-service.js rename to modules/server-api/ssh-service.js diff --git a/modules/server-management/storage.js b/modules/server-api/storage.js similarity index 100% rename from modules/server-management/storage.js rename to modules/server-api/storage.js diff --git a/modules/uptime-api/monitor-service.js b/modules/uptime-api/monitor-service.js index 51233a0..2f16489 100644 --- a/modules/uptime-api/monitor-service.js +++ b/modules/uptime-api/monitor-service.js @@ -9,7 +9,7 @@ const https = require('https'); const storage = require('./storage'); const { createLogger } = require('../../src/utils/logger'); -const logger = createLogger('UptimeService'); +const logger = createLogger('Uptime'); // 全局定时器映射: monitorId -> IntervalID const intervals = {}; diff --git a/package-lock.json b/package-lock.json index 377bf19..5fb94cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,6 +55,7 @@ "artplayer": "^5.3.0", "bezier-easing": "^2.1.0", "concurrently": "^9.2.1", + "cross-env": "^10.1.0", "deep-freeze": "^0.0.1", "dompurify": "^3.3.1", "eslint": "^9.39.2", @@ -171,6 +172,13 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/@epic-web/invariant": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz", + "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==", + "dev": true, + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.27.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", @@ -3776,6 +3784,24 @@ "node": ">=10.0.0" } }, + "node_modules/cross-env": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz", + "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@epic-web/invariant": "^1.0.0", + "cross-spawn": "^7.0.6" + }, + "bin": { + "cross-env": "dist/bin/cross-env.js", + "cross-env-shell": "dist/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", diff --git a/package.json b/package.json index b0b8115..40c1215 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,10 @@ "description": "Multi-api monitoring dashboard", "main": "server.js", "scripts": { - "start": "node server.js", - "dev:server": "node server.js", - "dev:client": "vite", - "dev": "concurrently --names \"SERVER,VITE\" --prefix-colors \"cyan,yellow\" \"npm run dev:server\" \"npm run dev:client\"", + "start": "cross-env DOTENV_CONFIG_QUIET=1 node server.js", + "dev:server": "cross-env DOTENV_CONFIG_QUIET=1 node server.js", + "dev:client": "cross-env DOTENV_CONFIG_QUIET=1 vite", + "dev": "cross-env DOTENV_CONFIG_QUIET=1 concurrently --names \"SERVER,VITE\" --prefix-colors \"cyan,yellow\" \"npm run dev:server\" \"npm run dev:client\"", "build": "vite build", "preview": "vite preview", "lint": "eslint .", @@ -66,6 +66,7 @@ "artplayer": "^5.3.0", "bezier-easing": "^2.1.0", "concurrently": "^9.2.1", + "cross-env": "^10.1.0", "deep-freeze": "^0.0.1", "dompurify": "^3.3.1", "eslint": "^9.39.2", diff --git a/server.js b/server.js index 7b1d448..103f12f 100644 --- a/server.js +++ b/server.js @@ -8,8 +8,20 @@ const http = require('http'); const { createLogger, logger: globalLogger } = require('./src/utils/logger'); const logger = createLogger('Server'); -// 打印简易启动标识 (Logo 移至 logger 记录) -logger.info('>>> Gravity Engineering System v0.1.2 <<<'); +// 打印 Logo +console.log(`\x1b[36m + ______ _______ ______ ______ ______ __ + / \\ / \\ / | / \\ / \\ / | +/$$$$$$ |$$$$$$$ |$$$$$$/ /$$$$$$ |/$$$$$$ | $$ | +$$ |__$$ |$$ |__$$ | $$ | $$ | _$$/ $$ | $$ | $$ | +$$ $$ |$$ $$/ $$ | $$ |/ |$$ | $$ | $$ | +$$$$$$$$ |$$$$$$$/ $$ | $$ |$$$$ |$$ | $$ | $$/ +$$ | $$ |$$ | _$$ |_ $$ \\__$$ |$$ \\__$$ | __ +$$ | $$ |$$ | / $$ | $$ $$/ $$ $$/ / | +$$/ $$/ $$/ $$$$$$/ $$$$$$/ $$$$$$/ $$/ +\x1b[0m\x1b[33m +>>> Gravity Engineering System v0.1.2 <<<\x1b[0m +`); // 导入中间件 const { configureHelmet, apiSecurityHeaders, corsConfig } = require('./src/middleware/security'); @@ -46,11 +58,11 @@ const PORT = process.env.PORT || 3000; // 初始化 WebSocket 服务 const logWss = logService.init(server); const metricsWss = metricsService.init(server); -const sshService = require('./modules/server-management/ssh-service'); +const sshService = require('./modules/server-api/ssh-service'); const sshWss = sshService.init(server); // 初始化 Agent Socket.IO 服务 -const agentService = require('./modules/server-management/agent-service'); +const agentService = require('./modules/server-api/agent-service'); agentService.initSocketIO(server); // 统一处理 WebSocket 升级请求 @@ -386,7 +398,7 @@ server.listen(PORT, '0.0.0.0', () => { // 启动主机监控服务 try { - const monitorService = require('./modules/server-management/monitor-service'); + const monitorService = require('./modules/server-api/monitor-service'); monitorService.start(); } catch (error) { logger.warn('主机监控服务启动失败:', error.message); @@ -396,7 +408,7 @@ server.listen(PORT, '0.0.0.0', () => { try { const uptimeService = require('./modules/uptime-api/monitor-service'); // 注入 Socket.IO (复用 AgentService 的 IO 实例) - const agentService = require('./modules/server-management/agent-service'); + const agentService = require('./modules/server-api/agent-service'); if (agentService.io) { uptimeService.setIO(agentService.io); } diff --git a/src/css/dns.css b/src/css/cloudflare.css similarity index 100% rename from src/css/dns.css rename to src/css/cloudflare.css diff --git a/src/db/models/index.js b/src/db/models/index.js index eb26853..16d0e3e 100644 --- a/src/db/models/index.js +++ b/src/db/models/index.js @@ -8,7 +8,7 @@ const { CloudflareDnsTemplate, CloudflareZone, CloudflareDnsRecord, -} = require('../../../modules/cloudflare-dns/models'); +} = require('../../../modules/cloudflare-api/models'); const { OpenAIEndpoint, OpenAIHealthHistory } = require('../../../modules/openai-api/models'); const { SystemConfig, Session, UserSettings, OperationLog } = require('./System'); const { @@ -17,7 +17,7 @@ const { ServerMonitorConfig, ServerCredential, ServerSnippet, -} = require('../../../modules/server-management/models'); +} = require('../../../modules/server-api/models'); module.exports = { // Zeabur 模块 diff --git a/src/js/main.js b/src/js/main.js index 4bf5343..146cf41 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -26,7 +26,7 @@ async function loadLazyCSS() { console.log('[System] Loading lazy CSS resources...'); const styles = [ import('../css/projects.css'), - import('../css/dns.css'), + import('../css/cloudflare.css'), import('../css/tables.css'), import('../css/tabs.css'), import('../css/settings.css'), @@ -82,7 +82,7 @@ import { paasMethods } from './modules/paas.js'; import { koyebMethods } from './modules/koyeb.js'; import { flyMethods } from './modules/fly.js'; import { selfHMethods, selfHComputed } from './modules/self-h.js'; -import { dnsMethods } from './modules/dns.js'; +import { cloudflareMethods } from './modules/cloudflare.js'; import { r2Methods } from './modules/r2.js'; import { openaiMethods } from './modules/openai.js'; import { antigravityMethods } from './modules/antigravity.js'; @@ -1599,7 +1599,7 @@ const app = createApp({ ...koyebMethods, ...flyMethods, ...selfHMethods, - ...dnsMethods, + ...cloudflareMethods, ...r2Methods, ...openaiMethods, ...antigravityMethods, diff --git a/src/js/modules/dns.js b/src/js/modules/cloudflare.js similarity index 93% rename from src/js/modules/dns.js rename to src/js/modules/cloudflare.js index 68deb65..d18f028 100644 --- a/src/js/modules/dns.js +++ b/src/js/modules/cloudflare.js @@ -34,7 +34,7 @@ async function loadMonaco() { // 缓存 key 常量(定义在模块级别,避免 Vue 警告) const DNS_ACCOUNTS_CACHE_KEY = 'dns_accounts_cache'; -export const dnsMethods = { +export const cloudflareMethods = { // 从本地缓存加载账号数据(立即显示) loadFromDnsAccountsCache() { try { @@ -108,7 +108,7 @@ export const dnsMethods = { */ async loadDnsAccounts(silent = false) { try { - const response = await fetch('/api/cf-dns/accounts', { + const response = await fetch('/api/cloudflare/accounts', { headers: store.getAuthHeaders(), }); const data = await response.json(); @@ -144,7 +144,7 @@ export const dnsMethods = { account.apiToken = null; } else { // 显示 token - 从主机获取 - const response = await fetch(`/api/cf-dns/accounts/${account.id}/token`, { + const response = await fetch(`/api/cloudflare/accounts/${account.id}/token`, { headers: store.getAuthHeaders(), }); const data = await response.json(); @@ -196,7 +196,7 @@ export const dnsMethods = { if (!confirmed) return; try { - const response = await fetch(`/api/cf-dns/accounts/${account.id}`, { + const response = await fetch(`/api/cloudflare/accounts/${account.id}`, { method: 'DELETE', headers: store.getAuthHeaders(), }); @@ -245,7 +245,7 @@ export const dnsMethods = { store.dnsLoadingZones = true; try { - const response = await fetch(`/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones`, { + const response = await fetch(`/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones`, { headers: store.getAuthHeaders(), }); @@ -325,7 +325,7 @@ export const dnsMethods = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/purge`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/purge`, { method: 'POST', headers: store.getAuthHeaders(), @@ -358,7 +358,7 @@ export const dnsMethods = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/ssl`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/ssl`, { headers: store.getAuthHeaders() } ); @@ -404,7 +404,7 @@ export const dnsMethods = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/ssl`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/ssl`, { method: 'PATCH', headers: store.getAuthHeaders(), @@ -444,7 +444,7 @@ export const dnsMethods = { }); const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/analytics?timeRange=${timeRange}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/analytics?timeRange=${timeRange}`, { headers: store.getAuthHeaders() } ); @@ -506,7 +506,7 @@ export const dnsMethods = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records`, { headers: store.getAuthHeaders() } ); @@ -557,8 +557,8 @@ export const dnsMethods = { try { const url = this.dnsEditingRecord - ? `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records/${this.dnsEditingRecord.id}` - : `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records`; + ? `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records/${this.dnsEditingRecord.id}` + : `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records`; const response = await fetch(url, { method: this.dnsEditingRecord ? 'PUT' : 'POST', @@ -595,7 +595,7 @@ export const dnsMethods = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records/${record.id}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records/${record.id}`, { method: 'DELETE', headers: store.getAuthHeaders(), @@ -656,7 +656,7 @@ export const dnsMethods = { for (const recordId of store.dnsSelectedRecords) { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records/${recordId}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records/${recordId}`, { method: 'DELETE', headers: store.getAuthHeaders(), @@ -699,7 +699,7 @@ export const dnsMethods = { try { // 使用正确的 API 端点 /switch const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/switch`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/switch`, { method: 'POST', headers: store.getAuthHeaders(), @@ -730,7 +730,7 @@ export const dnsMethods = { async loadDnsTemplates() { try { - const response = await fetch('/api/cf-dns/templates', { + const response = await fetch('/api/cloudflare/templates', { headers: store.getAuthHeaders(), }); const data = await response.json(); @@ -777,8 +777,8 @@ export const dnsMethods = { try { const url = this.dnsEditingTemplate - ? `/api/cf-dns/templates/${this.dnsEditingTemplate.id}` - : '/api/cf-dns/templates'; + ? `/api/cloudflare/templates/${this.dnsEditingTemplate.id}` + : '/api/cloudflare/templates'; const response = await fetch(url, { method: this.dnsEditingTemplate ? 'PUT' : 'POST', @@ -814,7 +814,7 @@ export const dnsMethods = { if (!confirmed) return; try { - const response = await fetch(`/api/cf-dns/templates/${template.id}`, { + const response = await fetch(`/api/cloudflare/templates/${template.id}`, { method: 'DELETE', headers: store.getAuthHeaders(), }); @@ -843,7 +843,7 @@ export const dnsMethods = { this.dnsAccountFormSuccess = ''; try { - const response = await fetch('/api/cf-dns/accounts', { + const response = await fetch('/api/cloudflare/accounts', { method: 'POST', headers: store.getAuthHeaders(), body: JSON.stringify(this.dnsAccountForm), @@ -869,7 +869,7 @@ export const dnsMethods = { async verifyDnsAccount(account) { try { - const response = await fetch(`/api/cf-dns/accounts/${account.id}/verify`, { + const response = await fetch(`/api/cloudflare/accounts/${account.id}/verify`, { method: 'POST', headers: store.getAuthHeaders(), }); @@ -907,7 +907,7 @@ export const dnsMethods = { updateData.apiToken = this.dnsEditAccountForm.apiToken; } - const response = await fetch(`/api/cf-dns/accounts/${this.dnsEditingAccount.id}`, { + const response = await fetch(`/api/cloudflare/accounts/${this.dnsEditingAccount.id}`, { method: 'PUT', headers: store.getAuthHeaders(), body: JSON.stringify(updateData), @@ -991,7 +991,7 @@ export const dnsMethods = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records/${record.id}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records/${record.id}`, { method: 'PUT', headers: store.getAuthHeaders(), @@ -1065,7 +1065,7 @@ export const dnsMethods = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records/${record.id}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/records/${record.id}`, { method: 'PUT', headers: store.getAuthHeaders(), @@ -1193,7 +1193,7 @@ export const dnsMethods = { for (const record of importedData.records) { try { const response = await fetch( - `/api/cf-dns/accounts/${this.dnsSelectedAccountId}/zones/${this.dnsSelectedZoneId}/records`, + `/api/cloudflare/accounts/${this.dnsSelectedAccountId}/zones/${this.dnsSelectedZoneId}/records`, { method: 'POST', headers: this.getAuthHeaders(), @@ -1242,7 +1242,7 @@ export const dnsMethods = { } // 从主机获取包含 API Token 的完整账号数据 - const response = await fetch('/api/cf-dns/accounts/export', { + const response = await fetch('/api/cloudflare/accounts/export', { headers: this.getAuthHeaders(), }); @@ -1332,7 +1332,7 @@ export const dnsMethods = { continue; } - const response = await fetch('/api/cf-dns/accounts', { + const response = await fetch('/api/cloudflare/accounts', { method: 'POST', headers: this.getAuthHeaders(), body: JSON.stringify(account), @@ -1388,7 +1388,7 @@ export const dnsMethods = { } try { - const response = await fetch(`/api/cf-dns/accounts/${store.dnsSelectedAccountId}/workers`, { + const response = await fetch(`/api/cloudflare/accounts/${store.dnsSelectedAccountId}/workers`, { headers: store.getAuthHeaders(), }); const data = await response.json(); @@ -1435,7 +1435,7 @@ export const dnsMethods = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(scriptName)}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(scriptName)}`, { method: 'DELETE', headers: store.getAuthHeaders(), @@ -1568,7 +1568,7 @@ export default { try { // 获取脚本内容 const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(worker.name)}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(worker.name)}`, { headers: store.getAuthHeaders(), } @@ -1668,7 +1668,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(name)}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(name)}`, { method: 'PUT', headers: { @@ -1715,7 +1715,7 @@ export default { } try { - const response = await fetch(`/api/cf-dns/accounts/${store.dnsSelectedAccountId}/pages`, { + const response = await fetch(`/api/cloudflare/accounts/${store.dnsSelectedAccountId}/pages`, { headers: store.getAuthHeaders(), }); const data = await response.json(); @@ -1748,7 +1748,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/pages/${encodeURIComponent(project.name)}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/pages/${encodeURIComponent(project.name)}`, { method: 'DELETE', headers: store.getAuthHeaders(), @@ -1778,7 +1778,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/pages/${encodeURIComponent(project.name)}/deployments`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/pages/${encodeURIComponent(project.name)}/deployments`, { headers: store.getAuthHeaders() } ); const data = await response.json(); @@ -1848,7 +1848,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/workers/routes`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/workers/routes`, { headers: store.getAuthHeaders() } ); const data = await response.json(); @@ -1890,7 +1890,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/workers/routes/${route.id}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/workers/routes/${route.id}`, { method: 'DELETE', headers: store.getAuthHeaders(), @@ -1929,7 +1929,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/workers/routes`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}/workers/routes`, { method: 'POST', headers: store.getAuthHeaders(), @@ -1969,7 +1969,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/pages/${encodeURIComponent(project.name)}/domains`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/pages/${encodeURIComponent(project.name)}/domains`, { headers: store.getAuthHeaders() } ); const data = await response.json(); @@ -2008,7 +2008,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/pages/${encodeURIComponent(this.selectedPagesProjectForDomains.name)}/domains`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/pages/${encodeURIComponent(this.selectedPagesProjectForDomains.name)}/domains`, { method: 'POST', headers: store.getAuthHeaders(), @@ -2046,7 +2046,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/pages/${encodeURIComponent(this.selectedPagesProjectForDomains.name)}/domains/${encodeURIComponent(domain.name)}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/pages/${encodeURIComponent(this.selectedPagesProjectForDomains.name)}/domains/${encodeURIComponent(domain.name)}`, { method: 'DELETE', headers: store.getAuthHeaders(), @@ -2101,7 +2101,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(worker.name)}/domains`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(worker.name)}/domains`, { headers: store.getAuthHeaders() } ); const data = await response.json(); @@ -2140,7 +2140,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(this.selectedWorkerForDomains.name)}/domains`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(this.selectedWorkerForDomains.name)}/domains`, { method: 'POST', headers: store.getAuthHeaders(), @@ -2178,7 +2178,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(this.selectedWorkerForDomains.name)}/domains/${domain.id}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(this.selectedWorkerForDomains.name)}/domains/${domain.id}`, { method: 'DELETE', headers: store.getAuthHeaders(), @@ -2231,7 +2231,7 @@ export default { this.zoneFormError = ''; try { - const response = await fetch(`/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones`, { + const response = await fetch(`/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones`, { method: 'POST', headers: { ...store.getAuthHeaders(), @@ -2290,7 +2290,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${store.dnsSelectedZoneId}`, { method: 'DELETE', headers: store.getAuthHeaders(), @@ -2344,7 +2344,7 @@ export default { } try { - const response = await fetch(`/api/cf-dns/accounts/${store.dnsSelectedAccountId}/tunnels`, { + const response = await fetch(`/api/cloudflare/accounts/${store.dnsSelectedAccountId}/tunnels`, { headers: store.getAuthHeaders(), }); const data = await response.json(); @@ -2388,7 +2388,7 @@ export default { store.tunnelSaving = true; try { - const response = await fetch(`/api/cf-dns/accounts/${store.dnsSelectedAccountId}/tunnels`, { + const response = await fetch(`/api/cloudflare/accounts/${store.dnsSelectedAccountId}/tunnels`, { method: 'POST', headers: { ...store.getAuthHeaders(), @@ -2428,7 +2428,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/tunnels/${tunnel.id}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/tunnels/${tunnel.id}`, { method: 'DELETE', headers: store.getAuthHeaders(), @@ -2453,7 +2453,7 @@ export default { async getTunnelToken(tunnel) { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/tunnels/${tunnel.id}/token`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/tunnels/${tunnel.id}/token`, { headers: store.getAuthHeaders() } ); const data = await response.json(); @@ -2515,7 +2515,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/tunnels/${tunnel.id}/configuration`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/tunnels/${tunnel.id}/configuration`, { headers: store.getAuthHeaders() } ); const data = await response.json(); @@ -2588,7 +2588,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/tunnels/${store.selectedTunnelForConfig.id}/configuration`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/tunnels/${store.selectedTunnelForConfig.id}/configuration`, { method: 'PUT', headers: { @@ -2640,7 +2640,7 @@ export default { // 否则调用 API 获取 const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/tunnels/${tunnel.id}/connections`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/tunnels/${tunnel.id}/connections`, { headers: store.getAuthHeaders() } ); const data = await response.json(); @@ -2691,7 +2691,7 @@ export default { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/tunnels/${tunnel.id}/connections`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/tunnels/${tunnel.id}/connections`, { method: 'DELETE', headers: store.getAuthHeaders(), diff --git a/src/js/modules/dashboard.js b/src/js/modules/dashboard.js index cfdecfa..4354c9f 100644 --- a/src/js/modules/dashboard.js +++ b/src/js/modules/dashboard.js @@ -255,7 +255,7 @@ export const dashboardMethods = { const updateFly = async () => { try { - const res = await fetch('/api/fly/proxy/apps', { headers: store.getAuthHeaders() }); + const res = await fetch('/api/flyio/proxy/apps', { headers: store.getAuthHeaders() }); if (res.ok) { const data = await res.json(); let appCount = 0; @@ -288,7 +288,7 @@ export const dashboardMethods = { */ async fetchDnsSummary() { try { - const res = await fetch('/api/cf-dns/zones', { headers: store.getAuthHeaders() }); + const res = await fetch('/api/cloudflare/zones', { headers: store.getAuthHeaders() }); if (res.ok) { const data = await res.json(); if (data.success && Array.isArray(data.data)) { @@ -332,7 +332,7 @@ export const dashboardMethods = { } } else { // 无心跳数据,暂时视为未知,计入 up 避免误报 - up++; + up++; } } }); diff --git a/src/js/modules/fly.js b/src/js/modules/fly.js index 5a85840..69676b0 100644 --- a/src/js/modules/fly.js +++ b/src/js/modules/fly.js @@ -45,7 +45,7 @@ export const flyMethods = { // 加载 Fly.io 账号列表(用于管理) async loadFlyManagedAccounts() { try { - const response = await fetch('/api/fly/accounts', { + const response = await fetch('/api/flyio/accounts', { headers: store.getAuthHeaders(), }); @@ -78,7 +78,7 @@ export const flyMethods = { store.flyRefreshProgress = 100; try { - const response = await fetch('/api/fly/proxy/apps', { + const response = await fetch('/api/flyio/proxy/apps', { headers: store.getAuthHeaders(), }); @@ -149,7 +149,7 @@ export const flyMethods = { store.flyAddingAccount = true; try { - const response = await fetch('/api/fly/accounts', { + const response = await fetch('/api/flyio/accounts', { method: 'POST', headers: store.getAuthHeaders(), body: JSON.stringify({ @@ -198,7 +198,7 @@ export const flyMethods = { if (!confirmed) return; try { - const response = await fetch(`/api/fly/accounts/${id}`, { + const response = await fetch(`/api/flyio/accounts/${id}`, { method: 'DELETE', headers: store.getAuthHeaders(), }); @@ -297,7 +297,7 @@ export const flyMethods = { if (!confirmed) return; try { - const response = await fetch(`/api/fly/apps/${app.name}/redeploy`, { + const response = await fetch(`/api/flyio/apps/${app.name}/redeploy`, { method: 'POST', headers: store.getAuthHeaders(), body: JSON.stringify({ accountId: account.id }), @@ -340,7 +340,7 @@ export const flyMethods = { } try { - const response = await fetch(`/api/fly/apps/${app.name}/rename`, { + const response = await fetch(`/api/flyio/apps/${app.name}/rename`, { method: 'POST', headers: store.getAuthHeaders(), body: JSON.stringify({ @@ -382,7 +382,7 @@ export const flyMethods = { if (!confirmed) return; try { - const response = await fetch(`/api/fly/apps/${app.name}`, { + const response = await fetch(`/api/flyio/apps/${app.name}`, { method: 'DELETE', headers: store.getAuthHeaders(), body: JSON.stringify({ accountId: account.id }), @@ -412,7 +412,7 @@ export const flyMethods = { if (name === null) return; // 取消操作 try { - const response = await fetch('/api/fly/apps', { + const response = await fetch('/api/flyio/apps', { method: 'POST', headers: store.getAuthHeaders(), body: JSON.stringify({ @@ -443,7 +443,7 @@ export const flyMethods = { app.showMachines = true; try { - const response = await fetch(`/api/fly/apps/${app.name}/machines?accountId=${account.id}`, { + const response = await fetch(`/api/flyio/apps/${app.name}/machines?accountId=${account.id}`, { headers: store.getAuthHeaders(), }); const result = await response.json(); @@ -466,7 +466,7 @@ export const flyMethods = { source: 'fly', fetcher: async () => { try { - const response = await fetch(`/api/fly/apps/${app.name}/events?accountId=${account.id}`, { + const response = await fetch(`/api/flyio/apps/${app.name}/events?accountId=${account.id}`, { headers: store.getAuthHeaders(), }); const result = await response.json(); @@ -550,7 +550,7 @@ export const flyMethods = { // 逐个添加账号以进行验证 for (const acc of importedData.accounts) { - await fetch('/api/fly/accounts', { + await fetch('/api/flyio/accounts', { method: 'POST', headers: store.getAuthHeaders(), body: JSON.stringify({ @@ -580,7 +580,7 @@ export const flyMethods = { source: 'fly', fetcher: async () => { try { - const response = await fetch(`/api/fly/apps/${app.name}/config?accountId=${account.id}`, { + const response = await fetch(`/api/flyio/apps/${app.name}/config?accountId=${account.id}`, { headers: store.getAuthHeaders(), }); const result = await response.json(); @@ -661,7 +661,7 @@ export const flyMethods = { for (const acc of accounts) { try { - const response = await fetch('/api/fly/accounts', { + const response = await fetch('/api/flyio/accounts', { method: 'POST', headers: store.getAuthHeaders(), body: JSON.stringify({ diff --git a/src/js/modules/r2.js b/src/js/modules/r2.js index 29b1b01..bcd0550 100644 --- a/src/js/modules/r2.js +++ b/src/js/modules/r2.js @@ -15,7 +15,7 @@ export const r2Methods = { store.r2LoadingBuckets = true; try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/r2/buckets`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/r2/buckets`, { headers: store.getAuthHeaders(), } @@ -57,7 +57,7 @@ export const r2Methods = { store.r2SelectedObjects = []; // 清空选择 try { // 使用 delimiter='/' 来实现文件夹模拟 - let url = `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/r2/buckets/${store.r2SelectedBucketName}/objects?delimiter=/`; + let url = `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/r2/buckets/${store.r2SelectedBucketName}/objects?delimiter=/`; if (store.r2CurrentPrefix) { url += `&prefix=${encodeURIComponent(store.r2CurrentPrefix)}`; } @@ -146,7 +146,7 @@ export const r2Methods = { if (!name) return; try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/r2/buckets`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/r2/buckets`, { method: 'POST', headers: { @@ -188,7 +188,7 @@ export const r2Methods = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/r2/buckets/${bucketName}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/r2/buckets/${bucketName}`, { method: 'DELETE', headers: store.getAuthHeaders(), @@ -226,7 +226,7 @@ export const r2Methods = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/r2/buckets/${store.r2SelectedBucketName}/objects/${encodeURIComponent(objectKey)}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/r2/buckets/${store.r2SelectedBucketName}/objects/${encodeURIComponent(objectKey)}`, { method: 'DELETE', headers: store.getAuthHeaders(), @@ -361,7 +361,7 @@ export const r2Methods = { for (const key of [...store.r2SelectedObjects]) { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/r2/buckets/${store.r2SelectedBucketName}/objects/${encodeURIComponent(key)}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/r2/buckets/${store.r2SelectedBucketName}/objects/${encodeURIComponent(key)}`, { method: 'DELETE', headers: store.getAuthHeaders(), diff --git a/src/js/modules/workers.js b/src/js/modules/workers.js index 8b57f1f..e7ce30b 100644 --- a/src/js/modules/workers.js +++ b/src/js/modules/workers.js @@ -32,7 +32,7 @@ const workersModule = { this.workersLoading = true; try { - const response = await fetch(`/api/cf-dns/accounts/${store.dnsSelectedAccountId}/workers`, { + const response = await fetch(`/api/cloudflare/accounts/${store.dnsSelectedAccountId}/workers`, { headers: store.getAuthHeaders(), }); const data = await response.json(); @@ -63,7 +63,7 @@ const workersModule = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(scriptName)}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(scriptName)}`, { headers: store.getAuthHeaders() } ); const data = await response.json(); @@ -91,7 +91,7 @@ const workersModule = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(scriptName)}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(scriptName)}`, { method: 'PUT', headers: { @@ -133,7 +133,7 @@ const workersModule = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(scriptName)}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/workers/${encodeURIComponent(scriptName)}`, { method: 'DELETE', headers: store.getAuthHeaders(), @@ -220,7 +220,7 @@ const workersModule = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${zoneId}/workers/routes`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${zoneId}/workers/routes`, { headers: store.getAuthHeaders() } ); const data = await response.json(); @@ -241,7 +241,7 @@ const workersModule = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${zoneId}/workers/routes`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${zoneId}/workers/routes`, { method: 'POST', headers: { @@ -275,7 +275,7 @@ const workersModule = { try { const response = await fetch( - `/api/cf-dns/accounts/${store.dnsSelectedAccountId}/zones/${zoneId}/workers/routes/${routeId}`, + `/api/cloudflare/accounts/${store.dnsSelectedAccountId}/zones/${zoneId}/workers/routes/${routeId}`, { method: 'DELETE', headers: store.getAuthHeaders(), diff --git a/src/js/store.js b/src/js/store.js index 91873f4..dcce195 100644 --- a/src/js/store.js +++ b/src/js/store.js @@ -44,7 +44,7 @@ export const MODULE_CONFIG = { description: 'Zeabur / Koyeb / Fly.io 平台监控', }, dns: { - name: 'DNS', + name: 'Cloudflare', shortName: 'CF', icon: 'fa-globe', description: 'Cloudflare DNS / Workers / Pages 管理', diff --git a/src/routes/index.js b/src/routes/index.js index f9a548d..8fbb7d9 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -255,8 +255,8 @@ function registerRoutes(app) { // 3. Agent 公开接口 (不需要认证,必须在 /api/server 模块之前挂载) const agentPublicRouter = express.Router(); - const agentService = require('../../modules/server-management/agent-service'); - const { serverStorage } = require('../../modules/server-management/storage'); + const agentService = require('../../modules/server-api/agent-service'); + const { serverStorage } = require('../../modules/server-api/storage'); // Agent 数据推送 (由远程 Agent 调用) agentPublicRouter.post('/push', (req, res) => { @@ -674,7 +674,7 @@ function registerRoutes(app) { try { const { serverId } = req.params; const server = serverStorage.getById(serverId); - const sshService = require('../../modules/server-management/ssh-service'); + const sshService = require('../../modules/server-api/ssh-service'); if (!server) return res.status(404).json({ success: false, error: '主机不存在' }); @@ -740,7 +740,7 @@ function registerRoutes(app) { try { const { serverId } = req.params; const server = serverStorage.getById(serverId); - const sshService = require('../../modules/server-management/ssh-service'); + const sshService = require('../../modules/server-api/ssh-service'); if (!server) return res.status(404).json({ success: false, error: '主机不存在' }); @@ -794,14 +794,18 @@ function registerRoutes(app) { const moduleRouteMap = { 'zeabur-api': '/api/zeabur', 'koyeb-api': '/api/koyeb', - 'cloudflare-dns': '/api/cf-dns', - 'fly-api': '/api/fly', + 'cloudflare-api': '/api/cloudflare', + 'flyio-api': '/api/flyio', 'openai-api': '/api/openai', 'openlist-api': '/api/openlist', - 'server-management': '/api/server', + 'server-api': '/api/server', 'antigravity-api': '/api/antigravity', 'gemini-cli-api': '/api/gemini-cli', 'ai-chat-api': '/api/ai-chat', + 'totp-api': '/api/totp', + 'uptime-api': '/api/uptime', + 'cron-api': '/api/cron', + // music-api 在下方单独挂载(无需认证) }; if (fs.existsSync(modulesDir)) { diff --git a/src/services/log-service.js b/src/services/log-service.js index 23af386..3ed8007 100644 --- a/src/services/log-service.js +++ b/src/services/log-service.js @@ -10,7 +10,7 @@ const { requireAuth } = require('../middleware/auth'); const fs = require('fs'); const path = require('path'); -const logger = createLogger('LogService'); +const logger = createLogger('Log'); const router = express.Router(); /** diff --git a/src/services/metrics-service.js b/src/services/metrics-service.js index cabc62f..b219f98 100644 --- a/src/services/metrics-service.js +++ b/src/services/metrics-service.js @@ -130,8 +130,8 @@ function sendMetricsUpdate(ws) { */ function collectMetrics() { try { - const agentService = require('../../modules/server-management/agent-service'); - const { serverStorage } = require('../../modules/server-management/storage'); + const agentService = require('../../modules/server-api/agent-service'); + const { serverStorage } = require('../../modules/server-api/storage'); const servers = serverStorage.getAll(); const metricsData = []; diff --git a/src/utils/logger.js b/src/utils/logger.js index 54396d9..8a69962 100644 --- a/src/utils/logger.js +++ b/src/utils/logger.js @@ -309,7 +309,27 @@ function renderTerminal(level, module, timestamp, traceId, message, data) { // 固定宽度定义,确保完美对齐 const COL_TIME = 13; // HH:mm:ss.SSS const COL_LEVEL = 6; // ERROR - const COL_MODULE = 13; // [ModuleName] + const COL_MODULE = 14; // [ModuleName] - 增加到14字符以容纳更长的模块名 + + // 模块名规范化映射 (长名 -> 短名) + const MODULE_NAME_MAP = { + 'cronservice': 'Cron', + 'cronservic': 'Cron', + 'servermonitor': 'Monitor', + 'servermoni': 'Monitor', + 'uptimeservice': 'Uptime', + 'uptimeserv': 'Uptime', + 'antigravity-service': 'AntiG', + 'antig-serv': 'AntiG', + 'gemini-cli-service': 'GeminiCLI', + 'gcli-servi': 'GeminiCLI', + 'gcli-service': 'GeminiCLI', + 'logservice': 'Log', + 'metricsservice': 'Metrics', + 'sshservice': 'SSH', + 'agentservice': 'Agent', + 'musicservice': 'Music', + }; // 1. 时间戳 const timeStr = useColor @@ -319,8 +339,16 @@ function renderTerminal(level, module, timestamp, traceId, message, data) { // 2. 级别 const levelStr = colorFn(level.padEnd(COL_LEVEL)); - // 3. 模块名 (动态配色) - const rawModule = (module || 'core').substring(0, 10); + // 3. 模块名 (规范化 + 动态配色) + let rawModule = (module || 'Core'); + // 尝试从映射表获取规范化名称 + const normalizedKey = rawModule.toLowerCase().replace(/[-_\s]/g, ''); + if (MODULE_NAME_MAP[normalizedKey]) { + rawModule = MODULE_NAME_MAP[normalizedKey]; + } else if (rawModule.length > 11) { + // 如果仍然过长,截断但保留首字母大写 + rawModule = rawModule.substring(0, 11); + } const formattedModule = `[${rawModule}]`.padEnd(COL_MODULE); const moduleColorFn = getModuleColor(module); const moduleStr = moduleColorFn(formattedModule); From 84858e2d7ed8741bf348c813a303d8a879bb56ce Mon Sep 17 00:00:00 2001 From: iwvw <2285740204@qq.com> Date: Tue, 6 Jan 2026 15:50:02 +0800 Subject: [PATCH 04/11] =?UTF-8?q?fix:=20=E5=8E=86=E5=8F=B2=E9=81=97?= =?UTF-8?q?=E7=95=99=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- agent-go/README.md | 14 +++++------ agent-go/main.go | 1 + src/css/ssh-ide.css | 57 ++++----------------------------------------- src/index.html | 13 ----------- 4 files changed, 13 insertions(+), 72 deletions(-) diff --git a/agent-go/README.md b/agent-go/README.md index e122f44..0cf660d 100644 --- a/agent-go/README.md +++ b/agent-go/README.md @@ -4,11 +4,11 @@ ## 特性 -- 🚀 **高性能**: Go 语言编写,单二进制部署,资源占用低 -- 📊 **实时监控**: CPU、内存、磁盘、网络流量实时采集 -- 🔗 **Socket.IO**: 与 Dashboard 实时通信 -- 🔄 **自动重连**: 断线自动重连,稳定可靠 -- 🐧 **跨平台**: 支持 Linux、Windows、macOS +- **高性能**: Go 语言编写,单二进制部署,资源占用低 +- **实时监控**: CPU、内存、磁盘、网络流量实时采集 +- **Socket.IO**: 与 Dashboard 实时通信 +- **自动重连**: 断线自动重连,稳定可靠 +- **跨平台**: 支持 Linux、Windows、macOS ## 构建 @@ -46,7 +46,7 @@ GOOS=windows GOARCH=amd64 go build -o agent-windows-amd64.exe | 参数 | 说明 | 默认值 | |------|------|--------| -| `-s, --server` | Dashboard 地址 | http://localhost:3000 | +| `-s, --server` | Dashboard 地址 | | | `--id` | 主机 ID (必需) | - | | `-k` | Agent 密钥 (必需) | - | | `-i` | 上报间隔 (毫秒) | 1500 | @@ -99,6 +99,6 @@ GOOS=windows GOARCH=amd64 go build -o agent-windows-amd64.exe - [gorilla/websocket](https://github.com/gorilla/websocket) - WebSocket 客户端 - [shirou/gopsutil](https://github.com/shirou/gopsutil) - 系统信息采集 -## License +## 许可证 MIT diff --git a/agent-go/main.go b/agent-go/main.go index 76ad1f1..829515e 100644 --- a/agent-go/main.go +++ b/agent-go/main.go @@ -517,6 +517,7 @@ func (a *AgentClient) heartbeat() { // Socket.IO 中只有服务端发送 ping (2),客户端只需响应 pong (3) // 我们在 handleMessage 中已经处理了 ping 响应 // 这个 goroutine 只是为了监听 stopChan + // 这下应该不会错了(应该 <-a.stopChan } diff --git a/src/css/ssh-ide.css b/src/css/ssh-ide.css index 96ceeac..99fdfa8 100644 --- a/src/css/ssh-ide.css +++ b/src/css/ssh-ide.css @@ -1,28 +1,21 @@ -/* ==================== SSH 缁堢 - VS Code 椋庢牸鍒嗗睆璁捐 ==================== */ - -/* 缁堢瀛愰〉闈㈠鍣?*/ -.ssh-terminal-sub-page { +.ssh-terminal-sub-page { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; height: calc(100vh - 180px); - /* 固定高度 */ min-height: 300px; - /* 最小高度保证可见 */ padding: 0; background: transparent; overflow: hidden; } -/* 涓诲鍣?*/ .ssh-ide-layout { display: flex; flex-direction: column; width: 100%; max-width: 1400px; height: 100%; - /* 填满父容器高度 */ background: var(--bg-primary); border-radius: 12px; overflow: hidden; @@ -42,7 +35,6 @@ border: none; } -/* ==================== 椤堕儴宸ュ叿鏍?==================== */ .ssh-top-bar { display: flex; justify-content: space-between; @@ -57,7 +49,6 @@ z-index: 200; } -/* 浼氳瘽鏍囩瀹瑰櫒 */ .ssh-session-tabs { display: flex; align-items: center; @@ -72,7 +63,6 @@ display: none; } -/* 浼氳瘽鏍囩 - 涓庢搷浣滄寜閽鏍肩粺涓€ */ .ssh-session-tab { display: flex; align-items: center; @@ -102,7 +92,6 @@ border-color: var(--border-color); } -/* 宸插垎灞忔爣璇?*/ .ssh-session-tab.is-split::after { content: ''; width: 6px; @@ -113,7 +102,6 @@ flex-shrink: 0; } -/* 鑱氬悎缁勬爣绛?*/ .ssh-session-tab.is-group { background: rgba(var(--primary-rgb), 0.08); border: 1px dashed rgba(var(--primary-rgb), 0.4); @@ -132,7 +120,6 @@ white-space: nowrap; } -/* 鎿嶄綔鎸夐挳鍖?*/ .ssh-header-actions { display: flex; align-items: center; @@ -141,7 +128,6 @@ z-index: 300; } -/* 蹇€熻繛鎺ヤ笅鎷夎彍鍗曞畾浣?*/ .ssh-header-actions .ssh-quick-connect-wrapper { position: relative; } @@ -156,7 +142,6 @@ z-index: 99999; } -/* 鎿嶄綔鎸夐挳 */ .ssh-icon-btn { display: flex; align-items: center; @@ -187,7 +172,6 @@ color: #ef4444; } -/* ==================== 缁堢涓诲鍣?==================== */ .ssh-main-container { display: flex; flex: 1; @@ -198,7 +182,6 @@ background: var(--bg-primary); } -/* 缁堢鍖呰鍣?- 鏍稿績甯冨眬 */ .ssh-terminal-wrapper { flex: 1; height: 100%; @@ -209,21 +192,18 @@ flex-direction: column; } -/* ==================== 1px 宸ヤ笟妗嗘灦甯冨眬 ==================== */ -/* 鍗曞睆妯″紡 */ .ssh-terminal-wrapper.layout-single { display: block !important; } -.ssh-terminal-wrapper.layout-single > .ssh-terminal-instance { +.ssh-terminal-wrapper.layout-single>.ssh-terminal-instance { position: absolute; inset: 0; border: none; margin: 0; } -/* 姘村钩鍒嗗睆 (宸﹀彸) */ .ssh-terminal-wrapper.layout-split-h { display: grid !important; grid-template-columns: 1fr 1fr; @@ -231,7 +211,6 @@ gap: 0; } -/* 鍨傜洿鍒嗗睆 (涓婁笅) */ .ssh-terminal-wrapper.layout-split-v { display: grid !important; grid-template-columns: 1fr; @@ -239,7 +218,6 @@ gap: 0; } -/* 缃戞牸甯冨眬 (3-9 灞? */ .ssh-terminal-wrapper.layout-grid { display: grid !important; grid-template-columns: 1fr 1fr; @@ -247,7 +225,6 @@ gap: 0; } -/* 绾靛悜涓夊垎灞?*/ .ssh-terminal-wrapper.layout-grid-v { display: grid !important; grid-template-columns: 1fr; @@ -255,19 +232,16 @@ gap: 0; } -/* 鏍规嵁绐楁牸鏁伴噺璋冩暣缃戞牸 */ .ssh-terminal-wrapper.layout-grid[data-pane-count='3'] { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; } -.ssh-terminal-wrapper.layout-grid[data-pane-count='3'][data-split-side='right'] - > .ssh-terminal-instance:first-child { +.ssh-terminal-wrapper.layout-grid[data-pane-count='3'][data-split-side='right']>.ssh-terminal-instance:first-child { grid-row: span 2; } -.ssh-terminal-wrapper.layout-grid[data-pane-count='3'][data-split-side='left'] - > .ssh-terminal-instance:last-child { +.ssh-terminal-wrapper.layout-grid[data-pane-count='3'][data-split-side='left']>.ssh-terminal-instance:last-child { grid-row: span 2; } @@ -284,22 +258,16 @@ grid-template-rows: repeat(3, 1fr); } -/* ==================== 缁堢瀹炰緥 - 1px 鐙珛妗嗘灦 ==================== */ .ssh-terminal-instance { display: flex; flex-direction: column; flex: 1; - /* 填充可用空间 */ background: var(--bg-primary); position: relative; min-height: 150px; - /* 确保最小可见高度 */ min-width: 200px; overflow: hidden; - /* 防止内容溢出 */ - /* 1px 宸ヤ笟妗嗘灦 */ border: 1px solid var(--border-color); - /* 杈规閲嶅彔娑堥櫎 */ margin-right: -1px; margin-bottom: -1px; } @@ -314,7 +282,6 @@ border-color: var(--primary-color); } -/* ==================== 绐楁牸鏍囬鏍?- 鎷栨嫿鎶婃墜 ==================== */ .ssh-instance-header { height: 28px; min-height: 28px; @@ -381,12 +348,10 @@ color: #ef4444; } -/* ==================== 缁堢鍐呭鍖?- 鍐呭祵鑷€傚簲 ==================== */ .ssh-slot { flex: 1; width: 100%; height: 100%; - /* 填充父容器 */ overflow: hidden; display: flex; flex-direction: column; @@ -401,7 +366,6 @@ div[id^='ssh-terminal-'] { flex-direction: column !important; } -/* xterm 内嵌适配 */ .terminal.xterm { height: 100% !important; padding: 4px 0 0 6px !important; @@ -410,14 +374,12 @@ div[id^='ssh-terminal-'] { .xterm-viewport { background-color: var(--bg-primary) !important; overflow-y: auto !important; - /* 确保可滚动 */ } .xterm-screen { padding: 0 !important; } -/* ==================== 鎷栨嫿鎰熷簲绯荤粺 ==================== */ .instance-drop-overlay { position: absolute; inset: 0; @@ -431,12 +393,10 @@ div[id^='ssh-terminal-'] { pointer-events: auto; } -/* 鎷栨嫿鍖哄煙 */ .drop-zone { position: absolute; pointer-events: auto; z-index: 101; - /* debug: background: rgba(255,0,0,0.1); */ } .drop-zone.pos-top { @@ -474,7 +434,6 @@ div[id^='ssh-terminal-'] { right: 30%; } -/* 鎷栨嫿棰勮鎸囩ず鍣?*/ .instance-drop-indicator { position: absolute; background: rgba(var(--primary-rgb), 0.15); @@ -524,7 +483,6 @@ div[id^='ssh-terminal-'] { background: rgba(var(--primary-rgb), 0.1); } -/* 鍏ㄥ眬鎷栨嫿鎻愮ず */ .global-drop-hint { position: absolute; z-index: 1000; @@ -539,7 +497,6 @@ div[id^='ssh-terminal-'] { display: block; } -/* ==================== 浠g爜鐗囨渚ц竟鏍?==================== */ .ssh-snippets-sidebar { width: 220px; background: var(--bg-secondary); @@ -603,7 +560,6 @@ div[id^='ssh-terminal-'] { display: flex; } -/* ==================== 閫氱敤鎸夐挳 ==================== */ .mini-btn-primary { background: transparent; color: var(--primary-color); @@ -621,7 +577,6 @@ div[id^='ssh-terminal-'] { border-color: var(--primary-color); } -/* ==================== 鍝嶅簲寮?==================== */ @media (max-width: 768px) { .ssh-top-bar { padding: 0 8px; @@ -646,7 +601,6 @@ div[id^='ssh-terminal-'] { } } -/* ==================== 涓绘満璇︽儏鏍峰紡 ==================== */ .server-details-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); @@ -710,7 +664,6 @@ div[id^='ssh-terminal-'] { background: var(--danger-color); } -/* Docker 鍒楄〃 */ .docker-containers-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); @@ -725,4 +678,4 @@ div[id^='ssh-terminal-'] { border-radius: 8px; display: flex; gap: 6px; -} +} \ No newline at end of file diff --git a/src/index.html b/src/index.html index 3532e5d..0d6f9c2 100644 --- a/src/index.html +++ b/src/index.html @@ -2,7 +2,6 @@ -