// MeshRay 前端应用 - 原生 Vue3 + Element Plus const { createApp, ref, reactive, onMounted } = Vue; // 注册所有 Element Plus 图标 const icons = {}; for (const [key, value] of Object.entries(ElementPlusIconsVue)) { icons[key] = value; } const app = createApp({ setup() { // 当前页面 const currentPage = ref('dashboard'); // 登录状态 const isLoggedIn = ref(false); const loggingIn = ref(false); // 登录表单 const loginForm = reactive({ username: '', password: '' }); // Token 存储 let authToken = localStorage.getItem('meshray_token') || ''; // 检查是否已登录 if (authToken) { isLoggedIn.value = true; // 可以在这里验证 token 是否有效 } // 统计数据 const stats = reactive({ networkCount: 0, deviceCount: 0, onlineDevices: 0, pendingApprovals: 0 }); // 组网列表 const networks = ref([]); // 对话框控制 const showCreateNetworkDialog = ref(false); // 新组网表单 const newNetwork = reactive({ name: '', subnet_ipv4: '10.0.0.0/24', listen_port: 51820, mesh_mode: 'enhanced' }); // API 基础 URL const API_BASE = '/api/v1'; // 加载统计数据 const loadStats = async () => { try { const response = await fetch(`${API_BASE}/dashboard/stats`); if (response.ok) { const result = await response.json(); if (result.data) { stats.networkCount = result.data.network_count || 0; stats.deviceCount = result.data.device_count || 0; stats.onlineDevices = result.data.online_devices || 0; stats.pendingApprovals = result.data.pending_approvals || 0; } } } catch (error) { console.error('加载统计数据失败:', error); } }; // 加载组网列表 const loadNetworks = async () => { try { const response = await fetch(`${API_BASE}/networks`); if (response.ok) { const result = await response.json(); networks.value = result.data || []; } } catch (error) { console.error('加载组网列表失败:', error); } }; // 创建组网 const createNetwork = async () => { try { const response = await fetch(`${API_BASE}/networks`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(newNetwork) }); if (response.ok) { const result = await response.json(); ElementPlus.ElMessage.success('组网创建成功'); showCreateNetworkDialog.value = false; // 重置表单 newNetwork.name = ''; newNetwork.subnet_ipv4 = '10.0.0.0/24'; newNetwork.listen_port = 51820; // 刷新列表 await loadNetworks(); await loadStats(); } else { const result = await response.json(); ElementPlus.ElMessage.error(result.error || '创建失败'); } } catch (error) { console.error('创建组网失败:', error); ElementPlus.ElMessage.error('创建失败'); } }; // 查看组网详情 const viewNetwork = (network) => { ElementPlus.ElMessageBox.alert( `组网名称:${network.name}\n` + `子网:${network.subnet_ipv4}\n` + `模式:${network.mesh_mode === 'enhanced' ? '增强' : '原生'}`, '组网详情', { confirmButtonText: '确定' } ); }; // 生成 MeshSeed const generateMeshSeed = (network) => { ElementPlus.ElMessageBox.prompt( '请输入 MeshSeed 有效期(小时)', '生成 MeshSeed', { confirmButtonText: '生成', cancelButtonText: '取消', inputPattern: /^\d+$/, inputErrorMessage: '请输入有效的数字' } ).then(async ({ value }) => { try { const hours = parseInt(value); const expiresAt = new Date(Date.now() + hours * 3600 * 1000).toISOString(); const response = await fetch(`${API_BASE}/networks/${network.id}/mesh-seed`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ max_uses: 10, expires_at: expiresAt, ddns_enabled: false }) }); if (response.ok) { const result = await response.json(); const seedUrl = result.data?.seed_url || result.data?.seed; if (seedUrl) { ElementPlus.ElMessageBox.alert( `MeshSeed 生成成功:

` + ``, 'MeshSeed', { dangerouslyUseHTMLString: true, confirmButtonText: '复制并关闭' } ); } } else { const result = await response.json(); ElementPlus.ElMessage.error(result.error || '生成失败'); } } catch (error) { console.error('生成 MeshSeed 失败:', error); ElementPlus.ElMessage.error('生成失败'); } }).catch(() => {}); }; // 删除组网 const deleteNetwork = async (network) => { try { await ElementPlus.ElMessageBox.confirm( `确定要删除组网 "${network.name}" 吗?此操作不可恢复。`, '警告', { confirmButtonText: '删除', cancelButtonText: '取消', type: 'warning' } ); const response = await fetch(`${API_BASE}/networks/${network.id}`, { method: 'DELETE' }); if (response.ok) { ElementPlus.ElMessage.success('删除成功'); await loadNetworks(); await loadStats(); } else { const result = await response.json(); ElementPlus.ElMessage.error(result.error || '删除失败'); } } catch (error) { if (error !== 'cancel') { console.error('删除组网失败:', error); ElementPlus.ElMessage.error('删除失败'); } } }; // 组件挂载时加载数据 onMounted(() => { if (isLoggedIn.value) { loadStats(); loadNetworks(); } }); // 处理登录 const handleLogin = async () => { if (!loginForm.username || !loginForm.password) { ElementPlus.ElMessage.warning('请输入用户名和密码'); return; } loggingIn.value = true; try { const response = await fetch(`${API_BASE}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: loginForm.username, password: loginForm.password }) }); const result = await response.json(); if (response.ok && result.data) { // 保存 token authToken = result.data.token || result.data.access_token; localStorage.setItem('meshray_token', authToken); isLoggedIn.value = true; ElementPlus.ElMessage.success('登录成功'); // 加载数据 await loadStats(); await loadNetworks(); } else { ElementPlus.ElMessage.error(result.error || '登录失败'); } } catch (error) { console.error('登录错误:', error); ElementPlus.ElMessage.error('登录失败,请检查网络连接'); } finally { loggingIn.value = false; } }; // 处理退出 const handleLogout = () => { ElementPlus.ElMessageBox.confirm( '确定要退出登录吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' } ).then(() => { // 清除 token localStorage.removeItem('meshray_token'); authToken = ''; isLoggedIn.value = false; // 重置表单 loginForm.username = ''; loginForm.password = ''; ElementPlus.ElMessage.success('已退出登录'); }).catch(() => {}); }; return { currentPage, isLoggedIn, loggingIn, loginForm, stats, networks, showCreateNetworkDialog, newNetwork, handleLogin, handleLogout, createNetwork, viewNetwork, generateMeshSeed, deleteNetwork }; } }); // 使用 Element Plus app.use(ElementPlus); // 注册所有图标 for (const [key, component] of Object.entries(icons)) { app.component(key, component); } // 挂载应用 app.mount('#app');