2025-11-11 21:39:12 +08:00
|
|
|
|
// 自定义JavaScript函数
|
|
|
|
|
|
|
2025-11-16 19:06:49 +08:00
|
|
|
|
// 设置前端域名全局变量
|
|
|
|
|
|
if (typeof FRONTEND_DOMAIN !== 'undefined') {
|
|
|
|
|
|
window.FRONTEND_DOMAIN = FRONTEND_DOMAIN;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-11 21:39:12 +08:00
|
|
|
|
// 显示加载动画
|
|
|
|
|
|
function showLoading() {
|
|
|
|
|
|
const loadingElement = document.getElementById('loading');
|
|
|
|
|
|
if (loadingElement) {
|
|
|
|
|
|
loadingElement.style.display = 'block';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 隐藏加载动画
|
|
|
|
|
|
function hideLoading() {
|
|
|
|
|
|
const loadingElement = document.getElementById('loading');
|
|
|
|
|
|
if (loadingElement) {
|
|
|
|
|
|
loadingElement.style.display = 'none';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化日期
|
|
|
|
|
|
function formatDate(dateString) {
|
|
|
|
|
|
if (!dateString) return '-';
|
|
|
|
|
|
const date = new Date(dateString);
|
|
|
|
|
|
return date.toLocaleDateString('zh-CN') + ' ' + date.toLocaleTimeString('zh-CN');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化文件大小
|
|
|
|
|
|
function formatFileSize(bytes) {
|
|
|
|
|
|
if (bytes === 0) return '0 Bytes';
|
|
|
|
|
|
const k = 1024;
|
|
|
|
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
|
|
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
|
|
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
2025-11-15 23:57:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-12 11:35:14 +08:00
|
|
|
|
// 显示通知 - 统一的消息弹窗函数
|
|
|
|
|
|
function showNotification(message, type = 'info') {
|
|
|
|
|
|
// 创建通知元素
|
|
|
|
|
|
const alertDiv = document.createElement('div');
|
|
|
|
|
|
const alertType = type === 'error' ? 'danger' : type;
|
|
|
|
|
|
alertDiv.className = `alert alert-${alertType} alert-dismissible fade show`;
|
|
|
|
|
|
alertDiv.innerHTML = `
|
|
|
|
|
|
${message}
|
|
|
|
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
|
|
|
|
`;
|
|
|
|
|
|
alertDiv.style.marginBottom = '10px';
|
|
|
|
|
|
|
|
|
|
|
|
// 插入到通知容器中
|
|
|
|
|
|
const container = document.getElementById('notification-container') || document.querySelector('main');
|
|
|
|
|
|
if (container) {
|
|
|
|
|
|
container.insertBefore(alertDiv, container.firstChild);
|
|
|
|
|
|
|
|
|
|
|
|
// 自动隐藏
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
if (alertDiv.parentNode) {
|
|
|
|
|
|
alertDiv.remove();
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 5000);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 如果找不到容器,使用console输出作为备选方案
|
|
|
|
|
|
console.log(`[${type.toUpperCase()}] ${message}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-15 23:57:05 +08:00
|
|
|
|
// API请求函数 - 添加认证支持
|
|
|
|
|
|
function apiRequest(url, options = {}) {
|
2025-11-16 19:06:49 +08:00
|
|
|
|
// 自动构建完整的API URL
|
2025-11-15 23:57:05 +08:00
|
|
|
|
let fullUrl = url;
|
2025-11-16 19:06:49 +08:00
|
|
|
|
|
|
|
|
|
|
// 检查是否配置了前端域名
|
|
|
|
|
|
const frontendDomain = window.FRONTEND_DOMAIN || '';
|
|
|
|
|
|
|
2025-11-22 20:32:49 +08:00
|
|
|
|
// 修复URL构建逻辑,避免重复域名问题
|
2025-11-16 19:06:49 +08:00
|
|
|
|
if (url.startsWith('/')) {
|
2025-11-22 20:32:49 +08:00
|
|
|
|
// 如果是绝对路径,则使用配置的域名或当前主机
|
|
|
|
|
|
if (frontendDomain && !url.startsWith(frontendDomain)) {
|
|
|
|
|
|
// 确保frontendDomain不包含路径部分
|
|
|
|
|
|
let cleanDomain = frontendDomain;
|
|
|
|
|
|
try {
|
|
|
|
|
|
const urlObj = new URL(frontendDomain.startsWith('http') ? frontendDomain : 'http://' + frontendDomain);
|
|
|
|
|
|
cleanDomain = urlObj.origin;
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
// 如果解析失败,使用原始值
|
|
|
|
|
|
if (frontendDomain.includes('/')) {
|
|
|
|
|
|
cleanDomain = frontendDomain.split('/')[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
fullUrl = cleanDomain + url;
|
|
|
|
|
|
} else if (!frontendDomain) {
|
|
|
|
|
|
fullUrl = window.location.origin + url;
|
|
|
|
|
|
}
|
2025-11-16 19:06:49 +08:00
|
|
|
|
} else if (!url.startsWith('http')) {
|
|
|
|
|
|
// 如果不是完整URL且不以http开头,则添加API前缀
|
2025-11-22 20:32:49 +08:00
|
|
|
|
if (frontendDomain) {
|
|
|
|
|
|
// 确保frontendDomain不包含路径部分
|
|
|
|
|
|
let cleanDomain = frontendDomain;
|
|
|
|
|
|
try {
|
|
|
|
|
|
const urlObj = new URL(frontendDomain.startsWith('http') ? frontendDomain : 'http://' + frontendDomain);
|
|
|
|
|
|
cleanDomain = urlObj.origin;
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
// 如果解析失败,使用原始值
|
|
|
|
|
|
if (frontendDomain.includes('/')) {
|
|
|
|
|
|
cleanDomain = frontendDomain.split('/')[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
fullUrl = cleanDomain + '/api/v1/' + url;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
fullUrl = window.location.origin + '/api/v1/' + url;
|
|
|
|
|
|
}
|
2025-11-15 23:57:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置默认选项
|
|
|
|
|
|
const defaultOptions = {
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
|
},
|
|
|
|
|
|
credentials: 'same-origin' // 确保发送cookies进行认证
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 合并选项
|
|
|
|
|
|
const mergedOptions = {
|
|
|
|
|
|
...defaultOptions,
|
|
|
|
|
|
...options,
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
...defaultOptions.headers,
|
|
|
|
|
|
...options.headers
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 显示加载动画
|
|
|
|
|
|
showLoading();
|
|
|
|
|
|
|
|
|
|
|
|
// 发起请求
|
|
|
|
|
|
return fetch(fullUrl, mergedOptions)
|
|
|
|
|
|
.then(response => {
|
|
|
|
|
|
// 隐藏加载动画
|
|
|
|
|
|
hideLoading();
|
|
|
|
|
|
|
|
|
|
|
|
// 检查响应状态
|
|
|
|
|
|
if (response.status === 401) {
|
|
|
|
|
|
// 未授权,重定向到登录页面
|
|
|
|
|
|
window.location.href = '/login';
|
|
|
|
|
|
throw new Error('未授权访问');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return response.json().catch(() => ({}));
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
// 隐藏加载动画
|
|
|
|
|
|
hideLoading();
|
|
|
|
|
|
|
|
|
|
|
|
// 处理网络错误
|
|
|
|
|
|
console.error('API请求失败:', error);
|
|
|
|
|
|
throw error;
|
|
|
|
|
|
});
|
2025-11-11 21:39:12 +08:00
|
|
|
|
}
|