c4e2783120
- Add projects + proxy nav items to sidebar - Rewrite projects.html with MD3 cards + tabs + mgmt-cards - Rewrite proxy.html with MD3 form + mgmt-cards - CSS: button ripple, card elevation, page fade, tab slide, input glow, nav dot, status pulse, log entry fade, shimmer, scrollbar, badge bounce, card hover mouse-glow (428 lines)
61 lines
4.7 KiB
HTML
61 lines
4.7 KiB
HTML
<!DOCTYPE html>
|
|
<div>
|
|
<h2 style="margin-bottom:16px">📦 项目管理</h2>
|
|
|
|
<div class="tabs">
|
|
<div class="tab active" onclick="showTab(event,'running')">运行中</div>
|
|
<div class="tab" onclick="showTab(event,'add')">+ 添加项目</div>
|
|
<div class="tab" onclick="showTab(event,'git')">Git 部署</div>
|
|
</div>
|
|
|
|
<div id="tab-running">
|
|
<div id="project-list" style="display:flex;flex-direction:column;gap:12px">加载中...</div>
|
|
</div>
|
|
|
|
<div id="tab-add" style="display:none">
|
|
<div class="card outlined" style="max-width:500px">
|
|
<h3 style="margin-bottom:12px">添加新项目</h3>
|
|
<div class="input-group"><span class="label">项目名称</span><input class="input" id="proj-name" placeholder="如: my-app"></div>
|
|
<div class="input-group"><span class="label">启动命令</span><input class="input" id="proj-cmd" placeholder="如: python3 main.py"></div>
|
|
<div class="input-group"><span class="label">工作目录</span><input class="input" id="proj-cwd" value="."></div>
|
|
<div class="input-group"><span class="label">端口 (可选)</span><input class="input" id="proj-port" type="number" placeholder="5000" style="width:120px"></div>
|
|
<div class="input-group"><span class="label">代理路径 (可选)</span><input class="input" id="proj-proxy" placeholder="如: /myapp" style="width:200px"></div>
|
|
<button class="btn btn-filled" onclick="addProject()" style="margin-top:8px">启动项目</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="tab-git" style="display:none">
|
|
<div class="card outlined" style="max-width:500px">
|
|
<h3 style="margin-bottom:12px">从 Git 部署</h3>
|
|
<div class="input-group"><span class="label">Git URL</span><input class="input" id="git-url" placeholder="https://git.yeij.top/user/repo.git"></div>
|
|
<div class="input-group"><span class="label">分支</span><input class="input" id="git-branch" value="main" style="width:160px"></div>
|
|
<button class="btn btn-filled" onclick="deployGit()" style="margin-top:8px">克隆并部署</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
var projects=[];
|
|
function showTab(e,t){document.querySelectorAll("#tab-running,#tab-add,#tab-git").forEach(el=>el.style.display="none");document.getElementById("tab-"+t).style.display="block";document.querySelectorAll(".tab").forEach(el=>el.classList.remove("active"));e.target.classList.add("active")}
|
|
async function refresh(){
|
|
try{var r=await fetch("/SenSu/api/projects");var d=await r.json();projects=d.projects;var h="";for(var p of projects){var cls=p.status==="running"?"status-running":p.status==="error"?"status-error":"status-stopped";h+='<div class="mgmt-card"><div class="status-dot '+cls+'"></div><div class="info"><b>'+p.name+'</b><br><small>'+p.status+" PID:"+(p.pid||"-")+" :"+(p.port||"-")+" "+(p.uptime?p.uptime+"s":"")+(p.proxy?" → "+p.proxy:"")+'</small></div><div class="actions"><button class="btn btn-sm btn-danger" onclick="stopP(this,'+JSON.stringify(p.name)+')">停止</button><button class="btn btn-sm btn-outlined" onclick="logsP(this,'+JSON.stringify(p.name)+')">日志</button><button class="btn btn-sm btn-text" onclick="cmdP(this,'+JSON.stringify(p.name)+')">命令</button></div></div><div class="log-box" id="logs-'+p.name+'"></div>'}document.getElementById("project-list").innerHTML=h||"暂无项目"}catch(e){console.error(e)}
|
|
}
|
|
async function addProject(){
|
|
var n=document.getElementById("proj-name").value,cmd=document.getElementById("proj-cmd").value;
|
|
if(!n||!cmd){alert("请填写名称和命令");return}
|
|
await fetch("/SenSu/api/projects/run",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:n,cmd:cmd.split(" "),cwd:document.getElementById("proj-cwd").value,port:parseInt(document.getElementById("proj-port").value)||0,proxy_path:document.getElementById("proj-proxy").value})});
|
|
refresh()
|
|
}
|
|
async function deployGit(){
|
|
var u=document.getElementById("git-url").value,b=document.getElementById("git-branch").value;
|
|
if(!u){alert("请填写 Git URL");return}
|
|
var n=u.split("/").pop().replace(".git","");
|
|
await fetch("/SenSu/api/projects/run",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:n,cmd:["git","clone","-b",b,u,n],cwd:"data/projects"})});
|
|
refresh()
|
|
}
|
|
async function stopP(el,n){await fetch("/SenSu/api/projects/"+n+"/stop",{method:"POST"});refresh()}
|
|
async function logsP(el,n){var b=document.getElementById("logs-"+n);b.style.display=b.style.display==="none"?"block":"none";if(b.style.display==="block"){var r=await fetch("/SenSu/api/projects/"+n+"/logs?tail=30");var d=await r.json();b.innerHTML=d.logs.join("<br>")||"(无日志)"}}
|
|
async function cmdP(el,n){var t=prompt("命令: "+n);if(t)await fetch("/SenSu/api/projects/"+n+"/stdin",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:t})})}
|
|
setInterval(refresh,4000);refresh();
|
|
</script>
|