Cài đặt quota cho các thành viên
This commit is contained in:
@@ -422,6 +422,69 @@ html, body {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* Storage Progress Bar */
|
||||
.storage-info {
|
||||
margin-top: 25px;
|
||||
padding: 15px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.storage-info label {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
color: #aaa;
|
||||
}
|
||||
.progress-container {
|
||||
height: 8px;
|
||||
background: #444;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.progress-bar {
|
||||
height: 100%;
|
||||
background: #28a745;
|
||||
width: 0%;
|
||||
transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
#storage-text {
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
display: block;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.top-files-section {
|
||||
margin-top: 15px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
.top-files-section h4 {
|
||||
font-size: 13px;
|
||||
color: #ffd700;
|
||||
margin-bottom: 10px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.top-file-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 6px 0;
|
||||
font-size: 12px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.03);
|
||||
}
|
||||
.top-file-name {
|
||||
color: #eee;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 180px;
|
||||
}
|
||||
.top-file-size { color: #888; font-family: monospace; }
|
||||
|
||||
/* Dashboard List Styles */
|
||||
.dashboard-list {
|
||||
display: flex;
|
||||
|
||||
+95
-10
@@ -133,23 +133,107 @@ function applySystemSettings() {
|
||||
if (logoutBtn) logoutBtn.innerText = t.logout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hàm định dạng dung lượng file cho Frontend
|
||||
*/
|
||||
function formatBytes(bytes, decimals = 2) {
|
||||
if (!bytes || bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tải và hiển thị thống kê các tệp tin lớn nhất
|
||||
*/
|
||||
async function loadMediaStats() {
|
||||
const token = localStorage.getItem('jwt');
|
||||
const statsContainer = document.getElementById('media-library-stats');
|
||||
if (!statsContainer) return;
|
||||
|
||||
try {
|
||||
const res = await fetch(`${API_BASE_URL}/me/assets/top-large`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const topFiles = await res.json();
|
||||
|
||||
if (topFiles && topFiles.length > 0) {
|
||||
let html = `
|
||||
<div class="top-files-section">
|
||||
<h4><i class="fas fa-database"></i> Tệp tin chiếm dụng lớn nhất</h4>
|
||||
<div class="top-files-list">
|
||||
`;
|
||||
topFiles.forEach(file => {
|
||||
const fileName = file.scene?.name || file.scene?.title || 'Ảnh chưa gắn Scene';
|
||||
html += `
|
||||
<div class="top-file-item">
|
||||
<span class="top-file-name">● ${fileName}</span>
|
||||
<span class="top-file-size">${formatBytes(file.fileSize)}</span>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
html += `</div></div>`;
|
||||
statsContainer.innerHTML = html;
|
||||
} else {
|
||||
statsContainer.innerHTML = '';
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Không thể nạp thống kê media:", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cập nhật nội dung tab Hồ sơ với thông tin người dùng
|
||||
*/
|
||||
function updateProfileTabContent() {
|
||||
async function updateProfileTabContent() {
|
||||
const token = localStorage.getItem('jwt');
|
||||
const username = localStorage.getItem('username');
|
||||
const role = localStorage.getItem('role');
|
||||
|
||||
if (username) {
|
||||
const avatar = document.getElementById('profile-avatar-initials');
|
||||
const userDisplay = document.getElementById('profile-username-display');
|
||||
const statusDisplay = document.getElementById('profile-status-display');
|
||||
const userInput = document.getElementById('profile-username');
|
||||
const avatar = document.getElementById('profile-avatar-initials');
|
||||
const userDisplay = document.getElementById('profile-username-display');
|
||||
const statusDisplay = document.getElementById('profile-status-display');
|
||||
const userInput = document.getElementById('profile-username');
|
||||
|
||||
if (avatar) avatar.innerText = username.charAt(0).toUpperCase();
|
||||
if (userDisplay) userDisplay.innerText = username;
|
||||
if (statusDisplay) statusDisplay.innerText = role || 'Thành viên';
|
||||
if (userInput) userInput.value = username;
|
||||
if (avatar && username) avatar.innerText = username.charAt(0).toUpperCase();
|
||||
if (userDisplay) userDisplay.innerText = username;
|
||||
if (statusDisplay) statusDisplay.innerText = role || 'Thành viên';
|
||||
if (userInput) userInput.value = username;
|
||||
|
||||
// Lấy dữ liệu dung lượng thực tế từ server
|
||||
try {
|
||||
const res = await fetch(`${API_BASE_URL}/me/profile`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
if (data.storage) {
|
||||
const { used, quota } = data.storage;
|
||||
const progress = document.getElementById('storage-progress-bar');
|
||||
const text = document.getElementById('storage-text');
|
||||
|
||||
if (progress && text) {
|
||||
const usedMB = (used / (1024 * 1024)).toFixed(1);
|
||||
const quotaMB = quota === -1 ? '∞' : (quota / (1024 * 1024)).toFixed(0);
|
||||
text.innerText = `${usedMB} MB / ${quotaMB} MB`;
|
||||
|
||||
if (quota !== -1) {
|
||||
const percent = Math.min((used / quota) * 100, 100);
|
||||
progress.style.width = percent + '%';
|
||||
// Đổi màu thanh tiến trình dựa trên mức độ sử dụng
|
||||
if (percent > 90) progress.style.background = '#dc3545'; // Đỏ (sắp hết)
|
||||
else if (percent > 75) progress.style.background = '#ffc107'; // Vàng (cảnh báo)
|
||||
else progress.style.background = '#28a745'; // Xanh (an toàn)
|
||||
} else {
|
||||
progress.style.width = '100%';
|
||||
progress.style.background = '#007bff'; // Màu xanh dương cho không giới hạn
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Không thể tải thông tin dung lượng:", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1953,6 +2037,7 @@ function openDashboardTab(tabName) {
|
||||
loadMyScenes();
|
||||
}
|
||||
if (tabName === 'media-library') {
|
||||
loadMediaStats();
|
||||
loadMyAssets();
|
||||
}
|
||||
if (tabName === 'user-management') {
|
||||
|
||||
Reference in New Issue
Block a user