feat: 添加SFTP空间使用统计功能

- 新增 /api/user/sftp-usage API,递归统计SFTP服务器空间使用情况
- 返回总使用空间、文件数、文件夹数
- 在设置页面显示SFTP空间统计信息
- 支持手动刷新统计数据
- 适配"仅SFTP"和"用户可选"两种权限模式的UI

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-27 13:39:51 +08:00
parent 86ed1f4040
commit 4f9b281039
3 changed files with 203 additions and 29 deletions

View File

@@ -1571,6 +1571,88 @@ app.post('/api/user/update-ftp',
}
);
// 获取SFTP存储空间使用情况
app.get('/api/user/sftp-usage', authMiddleware, async (req, res) => {
let sftp = null;
try {
// 检查用户是否配置了SFTP
if (!req.user.has_ftp_config) {
return res.status(400).json({
success: false,
message: '未配置SFTP服务器'
});
}
// 连接SFTP
sftp = await connectToSFTP(req.user);
// 递归计算目录大小的函数
async function calculateDirSize(dirPath) {
let totalSize = 0;
let fileCount = 0;
let dirCount = 0;
try {
const list = await sftp.list(dirPath);
for (const item of list) {
// 跳过 . 和 .. 目录
if (item.name === '.' || item.name === '..') continue;
const itemPath = dirPath === '/' ? `/${item.name}` : `${dirPath}/${item.name}`;
if (item.type === 'd') {
// 是目录,递归计算
dirCount++;
const subResult = await calculateDirSize(itemPath);
totalSize += subResult.totalSize;
fileCount += subResult.fileCount;
dirCount += subResult.dirCount;
} else {
// 是文件,累加大小
fileCount++;
totalSize += item.size || 0;
}
}
} catch (err) {
// 跳过无法访问的目录
console.warn(`[SFTP统计] 无法访问目录 ${dirPath}: ${err.message}`);
}
return { totalSize, fileCount, dirCount };
}
// 从根目录开始计算
const result = await calculateDirSize('/');
res.json({
success: true,
usage: {
totalSize: result.totalSize,
totalSizeFormatted: formatFileSize(result.totalSize),
fileCount: result.fileCount,
dirCount: result.dirCount
}
});
} catch (error) {
console.error('[SFTP统计] 获取失败:', error);
res.status(500).json({
success: false,
message: '获取SFTP空间使用情况失败: ' + error.message
});
} finally {
if (sftp) {
try {
await sftp.end();
} catch (e) {
// 忽略关闭错误
}
}
}
});
// 修改管理员账号信息(仅管理员可修改用户名)
app.post('/api/admin/update-profile',
authMiddleware,