Initial commit

This commit is contained in:
2026-07-07 13:29:22 +08:00
commit 3fdd9ec927
154 changed files with 56566 additions and 0 deletions
+246
View File
@@ -0,0 +1,246 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>服务器磁盘目录容量监控 | Dashboard</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Microsoft YaHei", system-ui, -apple-system, sans-serif;
}
body {
background-color: #f4f7fa;
padding: 24px;
color: #2d3748;
}
.dashboard-card {
background: #ffffff;
border-radius: 12px;
box-shadow: 0 2px 16px rgba(0, 30, 80, 0.08);
padding: 24px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
border-bottom: 1px solid #e2e8f0;
padding-bottom: 16px;
flex-wrap: wrap;
gap:16px;
}
.card-title {
font-size: 18px;
font-weight: 600;
color: #1a202c;
}
.card-desc {
font-size: 13px;
color: #718096;
margin-top: 4px;
}
.filter-box{
display:flex;
align-items:center;
gap:10px;
}
.filter-box label{
font-size:14px;
}
#ipSelect{
padding:6px 10px;
border:1px solid #cbd5e0;
border-radius:6px;
font-size:14px;
min-width:200px;
}
#exportBtn{
padding:6px 14px;
background:#2b6cb0;
color:#fff;
border:none;
border-radius:6px;
cursor:pointer;
font-size:14px;
}
#exportBtn:hover{
background:#2c5282;
}
table {
width: 100%;
border-collapse: collapse;
margin-top:10px;
}
thead tr {
background-color: #2b6cb0;
color: #fff;
}
th, td {
padding: 14px 16px;
text-align: left;
font-size: 14px;
}
th {
font-weight: 500;
}
tbody tr {
border-bottom: 1px solid #edf2f7;
transition: background 0.2s;
}
tbody tr:hover {
background-color: #f7fafc;
}
.num-big {
color: #c53030;
font-weight: 500;
}
.loading {
text-align: center;
padding: 40px;
color: #718096;
}
</style>
</head>
<body>
<div class="dashboard-card">
<div class="card-header">
<div>
<h2 class="card-title">用户目录磁盘占用统计</h2>
<div class="card-desc">多服务器 /serverhome 目录容量实时采集,支持按实例IP筛选、导出表格</div>
</div>
<div class="filter-box">
<label>筛选实例IP</label>
<select id="ipSelect">
<option value="all">全部实例</option>
</select>
<button id="exportBtn">导出当前表格CSV</button>
</div>
</div>
<table>
<thead>
<tr>
<th>实例IP</th>
<th>用户名</th>
<th>目录路径</th>
<th>占用容量</th>
</tr>
</thead>
<tbody id="diskTableBody">
<tr>
<td colspan="4" class="loading">数据加载中...</td>
</tr>
</tbody>
</table>
</div>
<script>
let sourceData = [];
let currentFilterIp = "all";
const ipSelect = document.getElementById('ipSelect');
const tbody = document.getElementById('diskTableBody');
const exportBtn = document.getElementById('exportBtn');
// 拉取全量数据
fetch('/api/df.php', {
headers: {
"Accept": "application/json;charset=utf-8"
}
})
.then(res => res.json())
.then(ret => {
if(ret.code !== 0){
tbody.innerHTML = `<tr><td colspan="4" class="loading">接口异常:${ret.msg}</td></tr>`;
return;
}
sourceData = ret.list;
if(sourceData.length === 0){
tbody.innerHTML = `<tr><td colspan="4" class="loading">暂无磁盘指标数据</td></tr>`;
return;
}
// 提取所有不重复IP写入下拉框
const ipSet = new Set();
sourceData.forEach(item=>ipSet.add(item.instance_ip));
ipSet.forEach(ip=>{
let opt = document.createElement('option');
opt.value = ip;
opt.innerText = ip;
ipSelect.appendChild(opt);
})
// 初始渲染全部
renderTable("all");
})
.catch(err => {
tbody.innerHTML = `<tr><td colspan="4" class="loading">接口请求失败:${err}</td></tr>`;
})
// 筛选切换事件
ipSelect.addEventListener('change', function(){
currentFilterIp = this.value;
renderTable(currentFilterIp);
})
// 渲染表格
function renderTable(filterIp){
tbody.innerHTML = "";
let showList = [];
if(filterIp === "all"){
showList = sourceData;
}else{
showList = sourceData.filter(item=>item.instance_ip === filterIp);
}
if(showList.length === 0){
tbody.innerHTML = `<tr><td colspan="4" class="loading">该实例下无目录数据</td></tr>`;
return;
}
showList.forEach(row => {
let tr = document.createElement('tr');
tr.innerHTML = `
<td>${row.instance_ip}</td>
<td>${row.username}</td>
<td>${row.directory}</td>
<td class="num-big">${row.size_gb}GB</td>
`;
tbody.appendChild(tr);
})
}
// 导出CSV
exportBtn.addEventListener('click', function(){
let showList = [];
if(currentFilterIp === "all"){
showList = sourceData;
}else{
showList = sourceData.filter(item=>item.instance_ip === currentFilterIp);
}
if(showList.length === 0){
alert("无数据可导出");
return;
}
// CSV表头
let csvContent = "\uFEFF实例IP,用户名,目录路径,占用容量(GB)\n";
showList.forEach(item=>{
const line = [
`"${item.instance_ip}"`,
`"${item.username}"`,
`"${item.directory}"`,
`"${item.size_gb}GB"`
];
csvContent += line.join(",") + "\n";
});
// 下载文件
const blob = new Blob([csvContent], {type:"text/csv;charset=utf-8"});
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "磁盘目录容量_"+new Date().getTime()+".csv";
a.click();
URL.revokeObjectURL(url);
})
</script>
</body>
</html>