Files
Nexus/web/app.js
T
Your Name f9045a8404 refactor: 仓库结构扁平化 + PHP前端合并到Nexus仓库
- 将 Nexus/Nexus/* 移到仓库根目录(消除双层嵌套)
- 删除旧的多层空壳目录 (server/, web/, agent/, deploy/, docs/)
- 将PHP前端 (web/) 合并进Nexus仓库 — 统一管理
- 部署时 git clone Nexus 仓库即可,不再需要两个仓库

目录结构:
  server/     ← Python FastAPI后端
  web/        ← PHP前端 (install.php, config.php, etc)
  deploy/     ← Supervisor + Shell健康检查
  docs/       ← 部署文档
  tests/      ← 测试
  .env        ← 不在git中 (install.php生成)
  .gitignore  ← 排除 .env, SECRETS.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 17:24:21 +08:00

87 lines
2.1 KiB
JavaScript

/**
* MultiSync - Frontend JavaScript
*/
/**
* Show a toast notification
*/
function showToast(message, type = 'success') {
const toast = document.createElement('div');
toast.className = `toast ${type}`;
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => {
toast.style.animation = 'slideIn 0.3s ease reverse';
setTimeout(() => toast.remove(), 300);
}, 3000);
}
/**
* Confirm dialog with callback
*/
function confirmAction(message, callback) {
if (confirm(message)) {
callback();
}
}
/**
* Format bytes to human readable
*/
function formatBytes(bytes, decimals = 2) {
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(decimals)) + ' ' + sizes[i];
}
/**
* Format duration in seconds to human readable
*/
function formatDuration(seconds) {
if (seconds < 60) return `${seconds}秒`;
if (seconds < 3600) return `${Math.floor(seconds/60)}${seconds%60}秒`;
return `${Math.floor(seconds/3600)}${Math.floor((seconds%3600)/60)}分`;
}
/**
* API proxy for AJAX calls
*/
async function apiCall(endpoint, method = 'GET', data = null) {
const options = {
method,
headers: {
'Content-Type': 'application/json',
},
};
if (data) {
options.body = JSON.stringify(data);
}
try {
const response = await fetch(`api_proxy.php?action=${endpoint}`, options);
return await response.json();
} catch (error) {
console.error('API call failed:', error);
showToast('请求失败: ' + error.message, 'error');
throw error;
}
}
/**
* Loading state management
*/
function setLoading(element, loading) {
if (loading) {
element.disabled = true;
element.dataset.originalText = element.innerHTML;
element.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 处理中...';
} else {
element.disabled = false;
element.innerHTML = element.dataset.originalText || element.innerHTML;
}
}