Files
mce/templates/admin/static/js/common.js
Victor_Jay 39d13993ba fix: 设计原则审查修复 — DIP/ISP, LoD, DRY, OCP, URL, 301缓存
- P0 DIP+ISP: 全链路注入接口,消除零接口紧耦合
- P0 URL: auth 301→302,修复登出后浏览器缓存陷阱
- P1 DRY: JWT 认证逻辑收敛至 TokenService+中间件
- P2 DRY: 前后端角色/状态映射统一为 model 常量
- P2 LoD: 新增 SettingsController,router 不再跨层调 repo
- P2 URL: settings ?tab= → /settings/:tab 伪静态
- P3 OCP: 角色权限 map 化,告别硬编码 switch
2026-05-26 21:12:19 +08:00

121 lines
4.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* =====================================================
MetaLab 管理面板 - 通用 JS
单一职责AJAX 封装、Toast 通知、确认弹窗
不包含任何页面特有逻辑
===================================================== */
// --- AJAX 封装 ---
// 注意getCSRFToken() 由共享 utils.js 提供
const api = {
async get(url) {
const res = await fetch(url, {
headers: { 'Accept': 'application/json' }
});
return res.json();
},
async put(url, body) {
const res = await fetch(url, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': getCSRFToken()
},
body: JSON.stringify(body)
});
return res.json();
},
async post(url, body) {
const res = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': getCSRFToken()
},
body: body ? JSON.stringify(body) : undefined
});
return res.json();
}
};
// --- Toast 通知 ---
function showToast(message, type) {
const container = document.querySelector('.toast-container') || createToastContainer();
const toast = document.createElement('div');
toast.className = `toast toast-${type}`;
toast.textContent = message;
container.appendChild(toast);
setTimeout(() => {
toast.style.opacity = '0';
toast.style.transition = 'opacity 0.3s';
setTimeout(() => toast.remove(), 300);
}, 3000);
}
function createToastContainer() {
const el = document.createElement('div');
el.className = 'toast-container';
document.body.appendChild(el);
return el;
}
// --- 确认弹窗 ---
function showConfirm(title, message) {
return new Promise((resolve) => {
const overlay = document.createElement('div');
overlay.className = 'modal-overlay show';
overlay.innerHTML = `
<div class="modal-box">
<h3>${escapeHtml(title)}</h3>
<p>${escapeHtml(message)}</p>
<div class="modal-actions">
<button class="btn btn-outline" id="modalCancel">取消</button>
<button class="btn btn-danger" id="modalConfirm">确认</button>
</div>
</div>`;
document.body.appendChild(overlay);
overlay.querySelector('#modalCancel').onclick = () => {
overlay.remove();
resolve(false);
};
overlay.querySelector('#modalConfirm').onclick = () => {
overlay.remove();
resolve(true);
};
overlay.addEventListener('click', (e) => {
if (e.target === overlay) { overlay.remove(); resolve(false); }
});
});
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// --- 时间格式化 ---
function formatTime(isoStr) {
if (!isoStr) return '—';
const d = new Date(isoStr);
return d.getFullYear() + '-' +
String(d.getMonth() + 1).padStart(2, '0') + '-' +
String(d.getDate()).padStart(2, '0') + ' ' +
String(d.getHours()).padStart(2, '0') + ':' +
String(d.getMinutes()).padStart(2, '0');
}
// --- 角色标签 ---
// 数据源由服务端 model.RoleDisplayNames 注入为 window.__ROLE_NAMES
function roleLabel(role) {
var map = window.__ROLE_NAMES || { user: '普通用户', moderator: '版主', admin: '管理员', owner: '站长' };
return '<span class="role-tag role-' + role + '">' + (map[role] || role) + '</span>';
}
// --- 状态标签 ---
// 数据源由服务端 model.StatusDisplayNames 注入为 window.__STATUS_NAMES
function statusLabel(status) {
var map = window.__STATUS_NAMES || { active: '正常', banned: '已封禁', deleted: '已注销', locked: '已锁定' };
return '<span class="badge badge-' + status + '">' + (map[status] || status) + '</span>';
}