refactor(spec): 拆分 easytier-rdp.json 为 easytier.json + rdp.json
遵守针对性+完整性原则:
- EasyTier section 的 ?/§ 只显示 EasyTier 内容
- RDP section 的 ?/§ 只显示 RDP 内容
- ai_spec.related_models 互相引用对方
- human_help.related 引用对方入口
dashboard.html:
- EasyTier 按钮调用 showModuleHelp('easytier', ...)
- RDP 按钮调用 showModuleHelp('rdp', ...)
- _renderSpecModal 新增 related_modules 显示, 每个 related 模块可点击跳转
This commit is contained in:
@@ -1,81 +0,0 @@
|
||||
{
|
||||
"module": "easytier-rdp",
|
||||
"version": "1.0",
|
||||
"purpose": "EasyTier VPN 网络开关 + RDP 远程桌面隧道开关。允许从外网通过 ags.yoin.fun 控制内网 EasyTier 和 RDP 访问。",
|
||||
"ui_location": "I Tab (Infrastructure) → EasyTier VPN section + RDP Remote Desktop section",
|
||||
|
||||
"human_help": {
|
||||
"title": "EasyTier VPN + RDP 远程桌面",
|
||||
"description": [
|
||||
"EasyTier 是一个 P2P VPN 组网工具,用于连接 Windows(192.168.1.16) 和 Linux 246(192.168.1.246)。",
|
||||
"Turn On/Off 按钮控制两台机器上的 EasyTier 进程。",
|
||||
"RDP Enable/Disable 按钮控制 SSH 反向隧道,开启后可通过 47.115.32.206:8080 从外网远程桌面到 Windows。"
|
||||
],
|
||||
"usage": [
|
||||
"1. 点击 Turn On 启动 EasyTier VPN(两台机器都启动)",
|
||||
"2. 点击 Turn Off 关闭 EasyTier VPN",
|
||||
"3. 点击 Enable 启动 RDP 隧道(需先确保 EasyTier 已连接,否则 SSH 可能不通)",
|
||||
"4. 点击 Disable 关闭 RDP 隧道",
|
||||
"5. RDP 连接方式:mstsc /v:47.115.32.206:8080"
|
||||
],
|
||||
"troubleshooting": [
|
||||
"如果 Turn On 返回失败:检查 Windows xmpp_bot (5802) 是否运行",
|
||||
"如果 RDP Enable 返回失败:检查 SSH 到 246 是否可用(EasyTier VPN 需先连接)",
|
||||
"如果隧道状态一直 pending:检查 246 的 SSH GatewayPortsyes 是否配置"
|
||||
]
|
||||
},
|
||||
|
||||
"ai_spec": {
|
||||
"apis": [
|
||||
{"method": "GET", "path": "/api/easytier", "returns": "status{windows,246} + virtual_ips{windows,246}", "proxied_to": "xmpp_bot /easytier action=status"},
|
||||
{"method": "POST", "path": "/api/easytier/toggle", "body": "{action: start|stop}", "returns": "{ok, message}", "proxied_to": "xmpp_bot /easytier action=start|stop"},
|
||||
{"method": "GET", "path": "/api/rdp", "returns": "rdp_enabled + tunnel_running + public_endpoint", "proxied_to": "xmpp_bot /rdp action=status"},
|
||||
{"method": "POST", "path": "/api/rdp/toggle", "body": "{action: start|stop}", "returns": "{ok, message}", "proxied_to": "xmpp_bot /rdp action=start|stop"}
|
||||
],
|
||||
"dependencies": [
|
||||
"xmpp_bot on Windows 192.168.1.16:5802 (HTTP bridge with /easytier and /rdp endpoints)",
|
||||
"XMPP_BRIDGE_URL env var (default: http://192.168.1.16:5802) — set in systemd service",
|
||||
"_bridge_post() helper in dashboard.py — proxies POST to xmpp_bot with X-Api-Key header",
|
||||
"_BRIDGE_KEY = 'xxm_bridge_8f3a2c' — API key for xmpp_bot HTTP bridge",
|
||||
"port_open() helper in dashboard.py — socket-based port check for tunnel status"
|
||||
],
|
||||
"architecture": {
|
||||
"flow": "Dashboard(246:5803) → _bridge_post() → xmpp_bot(Windows:5802) → subprocess/system",
|
||||
"easytier_mechanism": "xmpp_bot receives POST /easytier {action} → starts/stops easytier-core process on respective machine",
|
||||
"rdp_mechanism": "xmpp_bot receives POST /rdp {action} → starts/stops SSH reverse tunnel: ssh -R 0.0.0.0:8080:localhost:3389 root@47.115.32.206"
|
||||
},
|
||||
"constraints": [
|
||||
"VPN IP: Windows=10.144.144.3, 246=10.144.144.1 (NOT .2 — .2 was wrong in old code)",
|
||||
"RDP SSH reverse tunnel: ssh -R 0.0.0.0:8080:localhost:3389 root@47.115.32.206",
|
||||
"GatewayPorts yes required in /etc/ssh/sshd_config on 47.115.32.206 (Aliyun)",
|
||||
"xmpp_bot must be running on Windows with /rdp and /easytier HTTP endpoints (API key: xxm_bridge_8f3a2c)",
|
||||
"dashboard.py runs on 246 (Linux), xmpp_bot runs on Windows — they communicate over LAN HTTP"
|
||||
],
|
||||
"tests": [
|
||||
{"id": "ET01", "name": "EasyTier toggle start returns ok", "endpoint": "POST /api/easytier/toggle {action:start}"},
|
||||
{"id": "ET02", "name": "EasyTier toggle stop returns ok", "endpoint": "POST /api/easytier/toggle {action:stop}"},
|
||||
{"id": "RDP01", "name": "RDP toggle start returns ok", "endpoint": "POST /api/rdp/toggle {action:start}"},
|
||||
{"id": "RDP02", "name": "RDP toggle stop returns ok", "endpoint": "POST /api/rdp/toggle {action:stop}"},
|
||||
{"id": "ET-RDP01", "name": "EasyTier status returns virtual_ips", "endpoint": "GET /api/easytier"},
|
||||
{"id": "ET-RDP02", "name": "RDP status returns public_endpoint 47.115.32.206:8080", "endpoint": "GET /api/rdp"}
|
||||
],
|
||||
"must_not": [
|
||||
"不要把 proxy 调用改成 local subprocess(dashboard 在 Linux,EasyTier/RDP 在 Windows)",
|
||||
"不要重写整个 fI() 函数来改 EasyTier/RDP 部分 — 用 create-once/update-state pattern",
|
||||
"不要把 VPN IP 从 .3 改成 .2 — .3 是正确的",
|
||||
"不要删除 _bridge_post() helper 或 _BRIDGE_KEY — 它们是 proxy 的核心",
|
||||
"不要在 fI() 里用 fill('infra',h) — 这会清空整个 ct-infra 导致闪烁"
|
||||
],
|
||||
"known_issues": [
|
||||
"如果 xmpp_bot (5802) 停了,所有 EasyTier/RDP 操作都会失败 — 检查 Windows pythonw.exe 进程",
|
||||
"如果 246 上 SSH 到 Windows 不通,RDP 隧道无法启动 — 先确保 EasyTier VPN 连接",
|
||||
"EasyTier status 246 字段可能显示 unknown — 这是正常的,因为 246 的 EasyTier 状态不一定通过 xmpp_bot 返回"
|
||||
],
|
||||
"related_files": [
|
||||
"gateway/scripts/dashboard.py — /api/easytier*, /api/rdp*, _bridge_post(), port_open()",
|
||||
"gateway/scripts/templates/dashboard.html — fI() function creates ET/RDP sections",
|
||||
"xmpp_agent_core.py — /easytier and /rdp HTTP endpoints (lines ~780, ~794)",
|
||||
"/etc/systemd/system/agentsmeeting-dashboard.service — XMPP_BRIDGE_URL env var"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"module": "easytier",
|
||||
"version": "1.0",
|
||||
"purpose": "EasyTier VPN 网络开关。控制 Windows(192.168.1.16) 和 Linux 246(192.168.1.246) 上的 EasyTier VPN 进程,让两台机器组成 P2P 内网。",
|
||||
"ui_location": "I Tab (Infrastructure) → EasyTier VPN section",
|
||||
|
||||
"human_help": {
|
||||
"title": "EasyTier VPN",
|
||||
"description": [
|
||||
"EasyTier 是一个 P2P VPN 组网工具,用于连接 Windows(192.168.1.16) 和 Linux 246(192.168.1.246) 两台机器。",
|
||||
"开启后两台机器通过虚拟网卡通信:Windows 获得 10.144.144.3,246 获得 10.144.144.1。",
|
||||
"RDP 远程桌面隧道依赖 EasyTier VPN 先连通,请先确保这里显示 Connected 再操作 RDP。"
|
||||
],
|
||||
"usage": [
|
||||
"1. 点击 Turn On 启动 EasyTier VPN(两台机器都启动)",
|
||||
"2. 点击 Turn Off 关闭 EasyTier VPN",
|
||||
"3. 状态显示 Connected 表示两台机器都已加入 VPN 网络"
|
||||
],
|
||||
"troubleshooting": [
|
||||
"如果 Turn On 返回失败:检查 Windows xmpp_bot (pythonw.exe, port 5802) 是否运行",
|
||||
"如果状态显示 Off 但实际已启动:等待 1-2 秒再刷新,或检查 246 上 easytier-core 进程"
|
||||
],
|
||||
"related": "RDP Remote Desktop 依赖本 VPN 通道,参见 RDP section 的帮助"
|
||||
},
|
||||
|
||||
"ai_spec": {
|
||||
"apis": [
|
||||
{"method": "GET", "path": "/api/easytier", "returns": "status{windows,246} + virtual_ips{windows,246}", "proxied_to": "xmpp_bot /easytier action=status"},
|
||||
{"method": "POST", "path": "/api/easytier/toggle", "body": "{action: start|stop}", "returns": "{ok, message}", "proxied_to": "xmpp_bot /easytier action=start|stop"}
|
||||
],
|
||||
"dependencies": [
|
||||
"xmpp_bot on Windows 192.168.1.16:5802 (HTTP bridge with /easytier endpoint)",
|
||||
"XMPP_BRIDGE_URL env var (default: http://192.168.1.16:5802) — set in systemd service",
|
||||
"_bridge_post() helper in dashboard.py — proxies POST to xmpp_bot with X-Api-Key header",
|
||||
"_BRIDGE_KEY = 'xxm_bridge_8f3a2c' — API key for xmpp_bot HTTP bridge"
|
||||
],
|
||||
"architecture": {
|
||||
"flow": "Dashboard(246:5803) → _bridge_post() → xmpp_bot(Windows:5802) → starts/stops easytier-core process on respective machine",
|
||||
"mechanism": "xmpp_bot receives POST /easytier {action} → starts/stops easytier-core process"
|
||||
},
|
||||
"constraints": [
|
||||
"VPN IP: Windows=10.144.144.3, 246=10.144.144.1 (NOT .2 — .2 was wrong in old code, 已修正)",
|
||||
"xmpp_bot must be running on Windows with /easytier HTTP endpoint (API key: xxm_bridge_8f3a2c)",
|
||||
"dashboard.py runs on 246 (Linux), xmpp_bot runs on Windows — 通信走 LAN HTTP,不是 local subprocess"
|
||||
],
|
||||
"must_not": [
|
||||
"不要把 proxy 调用改成 local subprocess(dashboard 在 Linux,EasyTier 在 Windows)",
|
||||
"不要把 VPN IP 从 .3 改成 .2 — .3 是正确的 Windows IP",
|
||||
"不要删除 _bridge_post() helper 或 _BRIDGE_KEY — 它们是 proxy 的核心",
|
||||
"不要在 fI() 里用 fill('infra',h) — 这会清空整个 ct-infra 区域导致 EasyTier/RDP 元素闪烁"
|
||||
],
|
||||
"related_modules": [
|
||||
{"module": "rdp", "relation": "RDP 远程桌面隧道依赖 EasyTier VPN 连接,启动 RDP 前应确保 EasyTier Connected"}
|
||||
],
|
||||
"tests": [
|
||||
{"id": "ET01", "name": "EasyTier toggle start returns ok", "endpoint": "POST /api/easytier/toggle {action:start}"},
|
||||
{"id": "ET02", "name": "EasyTier toggle stop returns ok", "endpoint": "POST /api/easytier/toggle {action:stop}"},
|
||||
{"id": "ET03", "name": "EasyTier status returns virtual_ips with windows=10.144.144.3", "endpoint": "GET /api/easytier"}
|
||||
],
|
||||
"known_issues": [
|
||||
"如果 xmpp_bot (5802) 停了,EasyTier 操作会失败 — 检查 Windows pythonw.exe 进程",
|
||||
"EasyTier status 246 字段可能显示 unknown — 因为 246 的 EasyTier 状态不一定通过 xmpp_bot 返回"
|
||||
],
|
||||
"related_files": [
|
||||
"gateway/scripts/dashboard.py — /api/easytier*, _bridge_post()",
|
||||
"gateway/scripts/templates/dashboard.html — fI() function creates EasyTier section (id=easytier-section)",
|
||||
"gateway/scripts/specs/easytier.json — 本 spec 文件",
|
||||
"gateway/scripts/specs/rdp.json — 关联模块 RDP 的 spec",
|
||||
"xmpp_agent_core.py — /easytier HTTP endpoint (line ~780)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"module": "rdp",
|
||||
"version": "1.0",
|
||||
"purpose": "RDP 远程桌面隧道开关。通过 SSH 反向隧道将 Windows 3389 端口暴露到 Aliyun 公网 IP,实现从外网远程桌面到 Windows。",
|
||||
"ui_location": "I Tab (Infrastructure) → RDP Remote Desktop section",
|
||||
|
||||
"human_help": {
|
||||
"title": "RDP Remote Desktop",
|
||||
"description": [
|
||||
"通过 SSH 反向隧道把 Windows 的 RDP 端口(3389)暴露到 Aliyun 公网服务器(47.115.32.206:8080)。",
|
||||
"开启后在外网可用 mstsc /v:47.115.32.206:8080 远程桌面到 Windows。",
|
||||
"本功能依赖 EasyTier VPN 先连通 — SSH 到 246 的连接走 VPN 内网(10.144.144.1)。",
|
||||
"请先确保 EasyTier VPN 已 Connected,再点击 Enable。"
|
||||
],
|
||||
"usage": [
|
||||
"1. 先在 EasyTier VPN section 点击 Turn On,确认 Connected",
|
||||
"2. 回到本 section 点击 Enable 启动 SSH 反向隧道",
|
||||
"3. 在外网电脑运行 mstsc /v:47.115.32.206:8080 连接远程桌面",
|
||||
"4. 不用时点击 Disable 关闭隧道"
|
||||
],
|
||||
"troubleshooting": [
|
||||
"如果 Enable 返回失败:检查 EasyTier VPN 是否 Connected(RDP 依赖 VPN 内网 SSH)",
|
||||
"如果隧道状态一直 pending:检查 246 的 /etc/ssh/sshd_config 是否有 GatewayPorts yes",
|
||||
"如果 mstsc 连不上:检查 Aliyun 安全组是否放行 8080/TCP",
|
||||
"如果 timeout:从外网执行 Test-NetConnection 47.115.32.206 -Port 8080 看端口是否真的 listening"
|
||||
],
|
||||
"related": "依赖 EasyTier VPN 内网通道,参见 EasyTier VPN section 的帮助"
|
||||
},
|
||||
|
||||
"ai_spec": {
|
||||
"apis": [
|
||||
{"method": "GET", "path": "/api/rdp", "returns": "rdp_enabled + tunnel_running + public_endpoint(47.115.32.206:8080)", "proxied_to": "xmpp_bot /rdp action=status"},
|
||||
{"method": "POST", "path": "/api/rdp/toggle", "body": "{action: start|stop}", "returns": "{ok, message}", "proxied_to": "xmpp_bot /rdp action=start|stop"}
|
||||
],
|
||||
"dependencies": [
|
||||
"xmpp_bot on Windows 192.168.1.16:5802 — /rdp HTTP endpoint",
|
||||
"_bridge_post() + _BRIDGE_KEY in dashboard.py — proxy 机制同 EasyTier",
|
||||
"port_open() helper in dashboard.py — 检查 SSH 隧道端口 8080 是否监听",
|
||||
"EasyTier VPN 必须先 Connected — SSH 到 246 走 VPN 内网 10.144.144.1"
|
||||
],
|
||||
"architecture": {
|
||||
"flow": "Dashboard(246:5803) → _bridge_post() → xmpp_bot(Windows:5802) → 启动 SSH reverse tunnel",
|
||||
"rdp_mechanism": "xmpp_bot receives POST /rdp {action} → 执行 ssh -R 0.0.0.0:8080:localhost:3389 root@47.115.32.206 把 Windows 3389 转发到 Aliyun 公网",
|
||||
"public_endpoint": "47.115.32.206:8080 (Aliyun 公网)"
|
||||
},
|
||||
"constraints": [
|
||||
"RDP SSH 反向隧道命令: ssh -R 0.0.0.0:8080:localhost:3389 root@47.115.32.206",
|
||||
"GatewayPorts yes 必须配置在 47.115.32.206 (Aliyun) 的 /etc/ssh/sshd_config — 否则只 listen 127.0.0.1 外网连不进来",
|
||||
"EasyTier VPN 必须先 Connected — 否则 Windows SSH 到 246 不通,隧道无法建立",
|
||||
"xmpp_bot 必须运行在 Windows (pythonw.exe, port 5802) — 它是实际执行 SSH 命令的一方",
|
||||
"RDP 端口固定 3389 (Windows 默认),隧道端口固定 8080"
|
||||
],
|
||||
"must_not": [
|
||||
"不要在 EasyTier VPN 未 Connected 时启 RDP — 会因为 SSH 不通而失败",
|
||||
"不要用 SSH 端口转发替代 SSH 反向隧道 — 这是 -R (reverse) 不是 -L (local)",
|
||||
"不要把 public_endpoint 从 47.115.32.206:8080 改成其他 — 这是 Aliyun 公网入口",
|
||||
"不要把 tunnel_running 判断从 port_open(8080) 改成依赖 xmpp_bot 的 tunnel 字段 — xmpp_bot 不报告隧道状态,只能从 246 主动 probe",
|
||||
"不要重写整个 fI() 函数 — 用 create-once/update-state pattern 修改 RDP section"
|
||||
],
|
||||
"related_modules": [
|
||||
{"module": "easytier", "relation": "RDP 隧道依赖 EasyTier VPN 内网通道。启动 RDP 前必须确保 EasyTier Connected"}
|
||||
],
|
||||
"tests": [
|
||||
{"id": "RDP01", "name": "RDP toggle start returns ok", "endpoint": "POST /api/rdp/toggle {action:start}"},
|
||||
{"id": "RDP02", "name": "RDP toggle stop returns ok", "endpoint": "POST /api/rdp/toggle {action:stop}"},
|
||||
{"id": "RDP03", "name": "RDP status returns public_endpoint 47.115.32.206:8080", "endpoint": "GET /api/rdp"},
|
||||
{"id": "RDP04", "name": "After enable, port 8080 on Aliyun is listening (Test-NetConnection)", "endpoint": "external TCP check 47.115.32.206:8080"}
|
||||
],
|
||||
"known_issues": [
|
||||
"如果 Enable 后 status 一直 Tunnel pending:检查 /etc/ssh/sshd_config GatewayPorts yes,检查 Aliyun 安全组 8080/TCP",
|
||||
"如果 mstsc 从外网连不上:检查 Aliyun 安全组 — 需要 8080/TCP 入方向放行",
|
||||
"如果隧道断了但 status 显示 Connected:这是 stale state — port_open() 会重检 8080 端口下次刷新自动修正"
|
||||
],
|
||||
"related_files": [
|
||||
"gateway/scripts/dashboard.py — /api/rdp*, _bridge_post(), port_open()",
|
||||
"gateway/scripts/templates/dashboard.html — fI() function creates RDP section (id=rdp-section)",
|
||||
"gateway/scripts/specs/rdp.json — 本 spec 文件",
|
||||
"gateway/scripts/specs/easytier.json — 关联模块 EasyTier 的 spec",
|
||||
"xmpp_agent_core.py — /rdp HTTP endpoint (line ~794)",
|
||||
"/etc/ssh/sshd_config on 47.115.32.206 — GatewayPorts yes 配置"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -109,6 +109,7 @@ function _renderSpecModal(spec,type){
|
||||
if(hh.description){h+='<h4>说明</h4><ul>';hh.description.forEach(function(d){h+='<li>'+esc(d)+'</li>'});h+='</ul>';}
|
||||
if(hh.usage){h+='<h4>使用方法</h4><ul>';hh.usage.forEach(function(d){h+='<li>'+esc(d)+'</li>'});h+='</ul>';}
|
||||
if(hh.troubleshooting){h+='<h4>常见问题</h4><ul>';hh.troubleshooting.forEach(function(d){h+='<li>'+esc(d)+'</li>'});h+='</ul>';}
|
||||
if(hh.related){h+='<h4>关联模块</h4><p>'+esc(hh.related)+'</p>';}
|
||||
}else{
|
||||
var ai=spec.ai_spec||{};
|
||||
h+='<h3>§ AI Spec — '+esc(spec.module||'')+'</h3>';
|
||||
@@ -119,6 +120,7 @@ function _renderSpecModal(spec,type){
|
||||
if(ai.must_not){h+='<h4>禁止行为</h4><ul>';ai.must_not.forEach(function(d){h+='<li style="color:var(--red)">'+esc(d)+'</li>'});h+='</ul>';}
|
||||
if(ai.tests){h+='<h4>测试用例</h4><ul>';ai.tests.forEach(function(t){h+='<li><code>'+esc(t.id)+'</code> '+esc(t.name)+'</li>'});h+='</ul>';}
|
||||
if(ai.related_files){h+='<h4>相关文件</h4><ul>';ai.related_files.forEach(function(f){h+='<li><code>'+esc(f)+'</code></li>'});h+='</ul>';}
|
||||
if(ai.related_modules&&ai.related_modules.length){h+='<h4>关联模块</h4><ul>';ai.related_modules.forEach(function(m){h+='<li><span class="help-btn" style="cursor:pointer;margin-right:6px" onclick="showModuleHelp(\''+esc(m.module)+'\',\'ai\')">§</span><code>'+esc(m.module)+'</code> — '+esc(m.relation)+'</li>'});h+='</ul>';}
|
||||
}
|
||||
box.innerHTML=h;
|
||||
}
|
||||
@@ -191,7 +193,7 @@ async function fI(){
|
||||
var et=document.getElementById('easytier-section');
|
||||
if(!et){
|
||||
et=document.createElement('div');et.id='easytier-section';et.className='ps';et.style.marginTop='16px';
|
||||
et.innerHTML='<h2>EasyTier VPN<span class="help-btn" onclick="showModuleHelp(\'easytier-rdp\',\'human\')" title="使用说明">?</span><span class="help-btn ai" onclick="showModuleHelp(\'easytier-rdp\',\'ai\')" title="AI Spec">§</span></h2><div class=psv><div class=i><span class="d" id=et-w></span>Windows <span id=et-w-ip></span></div><div class=i><span class="d" id=et-246></span>246 <span id=et-246-ip></span></div></div><div style="margin-top:8px;display:flex;gap:8px;align-items:center"><button class="btn s" id=btn-et-on>Turn On</button><button class="btn x" id=btn-et-off>Turn Off</button><span id=et-status style="font-size:12px;color:var(--dim)">-</span></div>';
|
||||
et.innerHTML='<h2>EasyTier VPN<span class="help-btn" onclick="showModuleHelp(\'easytier\',\'human\')" title="使用说明">?</span><span class="help-btn ai" onclick="showModuleHelp(\'easytier\',\'ai\')" title="AI Spec">§</span></h2><div class=psv><div class=i><span class="d" id=et-w></span>Windows <span id=et-w-ip></span></div><div class=i><span class="d" id=et-246></span>246 <span id=et-246-ip></span></div></div><div style="margin-top:8px;display:flex;gap:8px;align-items:center"><button class="btn s" id=btn-et-on>Turn On</button><button class="btn x" id=btn-et-off>Turn Off</button><span id=et-status style="font-size:12px;color:var(--dim)">-</span></div>';
|
||||
ci.appendChild(et);
|
||||
document.getElementById('btn-et-on').onclick=function(){fetch('/api/easytier/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'start'})}).then(function(){fI()}).catch(function(){toast('ET Fail','err')})};
|
||||
document.getElementById('btn-et-off').onclick=function(){fetch('/api/easytier/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'stop'})}).then(function(){fI()}).catch(function(){toast('ET Fail','err')})};
|
||||
@@ -210,7 +212,7 @@ async function fI(){
|
||||
var rd=document.getElementById('rdp-section');
|
||||
if(!rd){
|
||||
rd=document.createElement('div');rd.id='rdp-section';rd.className='ps';rd.style.marginTop='16px';
|
||||
rd.innerHTML='<h2>RDP Remote Desktop<span class="help-btn" onclick="showModuleHelp(\'easytier-rdp\',\'human\')" title="使用说明">?</span><span class="help-btn ai" onclick="showModuleHelp(\'easytier-rdp\',\'ai\')" title="AI Spec">§</span></h2><div class=psv><div class=i><span class="d" id=rdp-st></span>RDP <span id=rdp-info></span></div><div class=i><span class="d" id=rdp-tun></span>Tunnel</div></div><div style="margin-top:8px;display:flex;gap:8px;align-items:center"><button class="btn s" id=btn-rdp-on>Enable</button><button class="btn x" id=btn-rdp-off>Disable</button><span id=rdp-status-txt style="font-size:12px;color:var(--dim)">-</span></div>';
|
||||
rd.innerHTML='<h2>RDP Remote Desktop<span class="help-btn" onclick="showModuleHelp(\'rdp\',\'human\')" title="使用说明">?</span><span class="help-btn ai" onclick="showModuleHelp(\'rdp\',\'ai\')" title="AI Spec">§</span></h2><div class=psv><div class=i><span class="d" id=rdp-st></span>RDP <span id=rdp-info></span></div><div class=i><span class="d" id=rdp-tun></span>Tunnel</div></div><div style="margin-top:8px;display:flex;gap:8px;align-items:center"><button class="btn s" id=btn-rdp-on>Enable</button><button class="btn x" id=btn-rdp-off>Disable</button><span id=rdp-status-txt style="font-size:12px;color:var(--dim)">-</span></div>';
|
||||
ci.appendChild(rd);
|
||||
document.getElementById('btn-rdp-on').onclick=function(){fetch('/api/rdp/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'start'})}).then(function(){fI()}).catch(function(){toast('RDP Fail','err')})};
|
||||
document.getElementById('btn-rdp-off').onclick=function(){fetch('/api/rdp/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'stop'})}).then(function(){fI()}).catch(function(){toast('RDP Fail','err')})};
|
||||
|
||||
Reference in New Issue
Block a user