/** * API调用工具类 */ class Api { /** * 发送GET请求 * @param {string} url - 请求URL * @param {Object} params - 查询参数 * @returns {Promise} - 响应数据 */ static async get(url, params = {}) { const queryString = Object.keys(params) .filter(key => params[key] !== undefined && params[key] !== null) .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`) .join('&'); const fullUrl = queryString ? `${url}?${queryString}` : url; const response = await fetch(fullUrl, { method: 'GET', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` } }); if (!response.ok) { const error = await response.text(); throw new Error(error || '请求失败'); } let result; try { result = await response.json(); } catch (e) { const error = await response.text(); throw new Error(error || '请求失败'); } if (result && result.code === "999999" && ( result.error === "请先登录" || result.error === "未登录或登录已过期,请重新登录" )) { localStorage.removeItem('token'); showToast('登录已失效,请重新登录', 'danger'); showLoginModal(); throw new Error(result.error); } if (result && result.code && result.code !== "000000") { throw new Error(result.error || '请求失败'); } return result && result.data !== undefined ? result.data : result; } /** * 发送POST请求 * @param {string} url - 请求URL * @param {Object} data - 请求数据 * @returns {Promise} - 响应数据 */ static async post(url, data = {}) { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(data) }); if (!response.ok) { const error = await response.text(); throw new Error(error || '请求失败'); } return response.json(); } /** * 发送PUT请求 * @param {string} url - 请求URL * @param {Object} data - 请求数据 * @returns {Promise} - 响应数据 */ static async put(url, data = {}) { const response = await fetch(url, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(data) }); if (!response.ok) { const error = await response.text(); throw new Error(error || '请求失败'); } return response.json(); } /** * 发送DELETE请求 * @param {string} url - 请求URL * @returns {Promise} - 响应数据 */ static async delete(url) { const response = await fetch(url, { method: 'DELETE', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` } }); if (!response.ok) { const error = await response.text(); throw new Error(error || '请求失败'); } return response.json(); } /** * 上传文件 * @param {string} url - 请求URL * @param {FormData} formData - 表单数据 * @returns {Promise} - 响应数据 */ static async upload(url, formData) { const response = await fetch(url, { method: 'POST', headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: formData }); if (!response.ok) { const error = await response.text(); throw new Error(error || '请求失败'); } return response.json(); } } /** * 显示登录模态框 */ function showLoginModal() { const loginModal = new bootstrap.Modal(document.getElementById('loginModal')); loginModal.show(); } /** * 格式化文件大小 * @param {number} bytes - 字节数 * @returns {string} - 格式化后的文件大小 */ function formatFileSize(bytes) { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } /** * 格式化日期时间 * @param {number} timestamp - 时间戳 * @returns {string} - 格式化后的日期时间 */ function formatDateTime(timestamp) { const date = new Date(timestamp); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } /** * 显示提示消息 * @param {string} message - 消息内容 * @param {string} type - 消息类型(success, danger, warning, info) */ function showToast(message, type = 'success') { if ("未登录或登录已过期" === message) { // 清除本地存储的token localStorage.removeItem('token'); // // 清除分类和资源列表 // document.getElementById('category-list').innerHTML = ''; // document.getElementById('resource-list').innerHTML = ''; // // location.reload(); } // 创建Toast元素 const toastContainer = document.createElement('div'); toastContainer.className = 'toast-container position-fixed top-0 end-0 p-3'; toastContainer.style.zIndex = '9999'; const toastElement = document.createElement('div'); toastElement.className = `toast align-items-center text-white bg-${type} border-0`; toastElement.setAttribute('role', 'alert'); toastElement.setAttribute('aria-live', 'assertive'); toastElement.setAttribute('aria-atomic', 'true'); const toastBody = document.createElement('div'); toastBody.className = 'd-flex'; const messageDiv = document.createElement('div'); messageDiv.className = 'toast-body'; messageDiv.textContent = message; const closeButton = document.createElement('button'); closeButton.type = 'button'; closeButton.className = 'btn-close btn-close-white me-2 m-auto'; closeButton.setAttribute('data-bs-dismiss', 'toast'); closeButton.setAttribute('aria-label', '关闭'); toastBody.appendChild(messageDiv); toastBody.appendChild(closeButton); toastElement.appendChild(toastBody); toastContainer.appendChild(toastElement); document.body.appendChild(toastContainer); // 显示Toast const toast = new bootstrap.Toast(toastElement, { delay: 3000 }); toast.show(); // Toast关闭后移除元素 toastElement.addEventListener('hidden.bs.toast', () => { document.body.removeChild(toastContainer); if ("未登录或登录已过期" === message) { // location.reload(); } }); }