const { createApp, ref, onMounted, computed } = Vue; createApp({ setup() { const activeTab = ref('dashboard'); const settingsTab = ref('users'); const manageTab = ref('cookies'); const currentWebsite = ref(null); const currentUser = ref(null); const isAdmin = ref(false); const users = ref([]); const websites = ref([]); const dashboardData = ref([]); const websiteCookies = ref([]); const websiteDetections = ref([]); const detections = ref([]); const notifications = ref([]); const stats = ref({ totalWebsites: 0, onlineCount: 0, offlineCount: 0, unknownCount: 0 }); const countdown = ref(5); const adminLoginVisible = ref(false); const adminLoginForm = ref({ password: '' }); const userDialogVisible = ref(false); const userDialogTitle = ref('添加用户'); const userForm = ref({ id: null, name: '', iyuu_token: '', max_fail_count: 3, cookie_cloud_uuid: '', cookie_cloud_password: '', cookie_cloud_api_url: '' }); const websiteDialogVisible = ref(false); const websiteDialogTitle = ref('添加网站'); const websiteFormDialog = ref({ id: null, user_id: null, name: '', url: '', login_check_selector: '', success_text: '', interval_minutes: 30, status: 1 }); const cookieDialogVisible = ref(false); const cookieDialogTitle = ref('添加Cookie'); const cookieForm = ref({ id: null, name: '', value: '', domain: '', path: '/' }); const websiteForm = ref({ id: null, user_id: null, name: '', url: '', login_check_selector: '', success_text: '', interval_minutes: 30 }); const filterWebsiteUser = ref(null); const currentUserWebsites = computed(() => { if (!currentUser.value) return []; return websites.value.filter(w => w.user_id === currentUser.value.id); }); const filteredWebsites = computed(() => { if (!filterWebsiteUser.value) return websites.value; return websites.value.filter(w => w.user_id === filterWebsiteUser.value); }); const checkAdminStatus = async () => { try { const response = await axios.get('/api/admin/status'); isAdmin.value = response.data.logged_in; } catch (error) { isAdmin.value = false; } }; const handleDropdownCommand = async (command) => { if (command === 'login') { showAdminLogin(); } }; const showAdminLogin = () => { adminLoginForm.value = { password: '' }; adminLoginVisible.value = true; }; const adminLogin = async () => { try { const response = await axios.post('/api/admin/login', adminLoginForm.value); if (response.data.success) { isAdmin.value = true; adminLoginVisible.value = false; ElementPlus.ElMessage.success('登录成功'); activeTab.value = 'settings'; settingsTab.value = 'users'; await loadUsersWithWebsites(); } } catch (error) { ElementPlus.ElMessage.error('密码错误'); } }; const handleAdminCommand = async (command) => { if (command === 'settings') { stopAutoRefresh(); activeTab.value = 'settings'; settingsTab.value = 'users'; await loadUsersWithWebsites(); } else if (command === 'dashboard') { activeTab.value = 'dashboard'; await loadDashboard(); startAutoRefresh(); } else if (command === 'logout') { await axios.post('/api/admin/logout'); isAdmin.value = false; activeTab.value = 'dashboard'; ElementPlus.ElMessage.success('已退出'); } }; const loadUsers = async () => { try { const response = await axios.get('/api/users'); users.value = response.data; } catch (error) { console.error('加载用户失败:', error); } }; const loadUsersWithWebsites = async () => { try { const usersRes = await axios.get('/api/users'); const websitesRes = await axios.get('/api/websites'); users.value = usersRes.data; websites.value = websitesRes.data; users.value = users.value.map(user => ({ ...user, website_count: websitesRes.data.filter(w => w.user_id === user.id).length })); } catch (error) { console.error('加载用户失败:', error); } }; const loadWebsites = async () => { try { const response = await axios.get('/api/websites'); websites.value = response.data; } catch (error) { console.error('加载网站失败:', error); } }; const loadDashboard = async () => { try { const usersRes = await axios.get('/api/users'); const websitesRes = await axios.get('/api/websites'); const usersData = usersRes.data; const allWebsites = websitesRes.data; dashboardData.value = usersData.map(user => { const userWebsites = allWebsites.filter(w => w.user_id === user.id); return { id: user.id, name: user.name, websites: userWebsites.map(w => ({ ...w, networkStatus: 'unknown', loginStatus: 'unknown', lastCheckTime: '-' })) }; }); const latestDetectionsRes = await axios.get('/api/detections/latest'); const networkRes = await axios.get('/api/websites/check-network'); const latestDetections = latestDetectionsRes.data; const networkStatus = networkRes.data; let onlineCount = 0, offlineCount = 0, unknownCount = 0, totalWebsites = allWebsites.length; dashboardData.value = dashboardData.value.map(user => { return { ...user, websites: user.websites.map(w => { const detection = latestDetections[w.id]; const net = networkStatus[w.id]; let loginStatus = 'unknown'; let lastCheckTime = '-'; let networkStatusValue = 'unknown'; if (net) { networkStatusValue = net.reachable ? 'online' : 'offline'; } if (detection) { if (detection.status === 1) { loginStatus = 'success'; onlineCount++; } else { loginStatus = 'failed'; offlineCount++; } lastCheckTime = new Date(detection.created_at).toLocaleString(); } else { unknownCount++; } return { ...w, networkStatus: networkStatusValue, loginStatus: loginStatus, lastCheckTime: lastCheckTime }; }) }; }); stats.value = { totalWebsites, onlineCount, offlineCount, unknownCount }; } catch (error) { console.error('加载仪表板失败:', error); } }; const refreshDashboardStatus = async () => { if (activeTab.value !== 'dashboard') return; if (isRefreshing) return; isRefreshing = true; try { const [detectionsRes, networkRes] = await Promise.all([ axios.get('/api/detections/latest'), axios.get('/api/websites/check-network') ]); const latestDetections = detectionsRes.data; const networkStatus = networkRes.data; let onlineCount = 0, offlineCount = 0, unknownCount = 0; dashboardData.value = dashboardData.value.map(user => { return { ...user, websites: user.websites.map(w => { const detection = latestDetections[w.id]; const net = networkStatus[w.id]; let loginStatus = w.loginStatus; let lastCheckTime = w.lastCheckTime; let networkStatusValue = 'unknown'; if (net) { networkStatusValue = net.reachable ? 'online' : 'offline'; } if (detection) { if (detection.status === 1) { loginStatus = 'success'; onlineCount++; } else { loginStatus = 'failed'; offlineCount++; } lastCheckTime = new Date(detection.created_at).toLocaleString(); } else { unknownCount++; } return { ...w, networkStatus: networkStatusValue, loginStatus: loginStatus, lastCheckTime: lastCheckTime }; }) }; }); stats.value = { totalWebsites: onlineCount + offlineCount + unknownCount, onlineCount, offlineCount, unknownCount }; } catch (error) { // 静默失败,不显示错误提示 } finally { isRefreshing = false; if (activeTab.value === 'dashboard') { countdown.value = 5; startCountdown(); } } }; let refreshTimer = null; let countdownTimer = null; let isRefreshing = false; const startAutoRefresh = () => { stopAutoRefresh(); countdown.value = 5; startCountdown(); }; const startCountdown = () => { if (countdownTimer) clearInterval(countdownTimer); countdownTimer = setInterval(() => { countdown.value--; if (countdown.value <= 0) { clearInterval(countdownTimer); countdownTimer = null; refreshDashboardStatus(); } }, 1000); }; const stopAutoRefresh = () => { if (refreshTimer) { clearInterval(refreshTimer); refreshTimer = null; } if (countdownTimer) { clearInterval(countdownTimer); countdownTimer = null; } countdown.value = 5; }; const checkLogin = async (website) => { website.loginStatus = 'checking'; try { const response = await axios.post(`/api/websites/check-login/${website.id}`); if (response.data.success) { website.loginStatus = 'success'; updateStats(website.id, 'success'); ElementPlus.ElMessage.success(response.data.message); } else { website.loginStatus = 'failed'; updateStats(website.id, 'failed'); ElementPlus.ElMessage.error(response.data.message); } website.lastCheckTime = new Date().toLocaleString(); } catch (error) { website.loginStatus = 'failed'; updateStats(website.id, 'failed'); ElementPlus.ElMessage.error('检测失败'); } }; const updateStats = (websiteId, status) => { let onlineCount = 0, offlineCount = 0, unknownCount = 0; dashboardData.value.forEach(user => { user.websites.forEach(w => { if (w.id === websiteId) { if (status === 'success') onlineCount++; else if (status === 'failed') offlineCount++; } else { if (w.loginStatus === 'success') onlineCount++; else if (w.loginStatus === 'failed') offlineCount++; else unknownCount++; } }); }); stats.value = { totalWebsites: onlineCount + offlineCount + unknownCount, onlineCount, offlineCount, unknownCount }; }; const manageWebsite = async (website) => { stopAutoRefresh(); currentWebsite.value = website; websiteForm.value = { ...website }; activeTab.value = 'website_manage'; manageTab.value = 'cookies'; await loadWebsiteCookies(); }; const manageUserWebsites = (user) => { stopAutoRefresh(); currentUser.value = user; activeTab.value = 'user_websites'; }; const loadWebsiteCookies = async () => { if (!currentWebsite.value) return; try { const response = await axios.get(`/api/cookies/websites/${currentWebsite.value.id}`); websiteCookies.value = response.data; } catch (error) { console.error('加载Cookie失败:', error); } }; const loadWebsiteDetections = async () => { if (!currentWebsite.value) return; try { const response = await axios.get(`/api/detections?website_id=${currentWebsite.value.id}`); websiteDetections.value = response.data; } catch (error) { console.error('加载检测记录失败:', error); } }; const showAddUserDialog = () => { userDialogTitle.value = '添加用户'; userForm.value = { id: null, name: '', iyuu_token: '', max_fail_count: 3, cookie_cloud_uuid: '', cookie_cloud_password: '', cookie_cloud_api_url: '' }; userDialogVisible.value = true; }; const editUser = (user) => { userDialogTitle.value = '编辑用户'; userForm.value = { id: user.id, name: user.name, iyuu_token: user.iyuu_token, max_fail_count: user.max_fail_count, cookie_cloud_uuid: user.cookie_cloud_uuid || '', cookie_cloud_password: user.cookie_cloud_password || '', cookie_cloud_api_url: user.cookie_cloud_api_url || '' }; userDialogVisible.value = true; }; const saveUser = async () => { try { if (userForm.value.id) { await axios.put(`/api/users/${userForm.value.id}`, userForm.value); ElementPlus.ElMessage.success('更新成功'); } else { await axios.post('/api/users', userForm.value); ElementPlus.ElMessage.success('添加成功'); } userDialogVisible.value = false; await loadUsersWithWebsites(); } catch (error) { ElementPlus.ElMessage.error('保存失败'); } }; const deleteUser = async (user) => { try { await ElementPlus.ElMessageBox.confirm('确定要删除该用户吗?', '提示', { type: 'warning' }); await axios.delete(`/api/users/${user.id}`); ElementPlus.ElMessage.success('删除成功'); await loadUsersWithWebsites(); } catch (error) { if (error !== 'cancel') { ElementPlus.ElMessage.error('删除失败'); } } }; const showAddWebsiteDialog = () => { websiteDialogTitle.value = '添加网站'; websiteFormDialog.value = { id: null, user_id: filterWebsiteUser.value || users.value[0]?.id, name: '', url: '', login_check_selector: '', success_text: '', interval_minutes: 30, status: 1 }; websiteDialogVisible.value = true; }; const showAddWebsiteDialogForUser = () => { websiteDialogTitle.value = '添加网站'; websiteFormDialog.value = { id: null, user_id: currentUser.value?.id, name: '', url: '', login_check_selector: '', success_text: '', interval_minutes: 30, status: 1 }; websiteDialogVisible.value = true; }; const editWebsite = (website) => { websiteDialogTitle.value = '编辑网站'; websiteFormDialog.value = { ...website }; websiteDialogVisible.value = true; }; const saveWebsite = async () => { try { if (websiteFormDialog.value.id) { await axios.put(`/api/websites/${websiteFormDialog.value.id}`, websiteFormDialog.value); ElementPlus.ElMessage.success('更新成功'); } else { await axios.post('/api/websites', websiteFormDialog.value); ElementPlus.ElMessage.success('添加成功'); } websiteDialogVisible.value = false; await loadWebsites(); await loadUsersWithWebsites(); } catch (error) { ElementPlus.ElMessage.error('保存失败'); } }; const deleteWebsite = async (website) => { try { await ElementPlus.ElMessageBox.confirm('确定要删除该网站吗?', '提示', { type: 'warning' }); await axios.delete(`/api/websites/${website.id}`); ElementPlus.ElMessage.success('删除成功'); await loadWebsites(); await loadUsersWithWebsites(); } catch (error) { if (error !== 'cancel') { ElementPlus.ElMessage.error('删除失败'); } } }; const showAddCookieDialog = () => { cookieDialogTitle.value = '添加Cookie'; cookieForm.value = { id: null, name: '', value: '', domain: currentWebsite.value?.url ? new URL(currentWebsite.value.url).hostname : '', path: '/' }; cookieDialogVisible.value = true; }; const editCookie = (cookie) => { cookieDialogTitle.value = '编辑Cookie'; cookieForm.value = { ...cookie }; cookieDialogVisible.value = true; }; const saveCookie = async () => { try { if (cookieForm.value.id) { await axios.put(`/api/cookies/${cookieForm.value.id}`, cookieForm.value); ElementPlus.ElMessage.success('更新成功'); } else { await axios.post(`/api/cookies/websites/${currentWebsite.value.id}`, cookieForm.value); ElementPlus.ElMessage.success('添加成功'); } cookieDialogVisible.value = false; await loadWebsiteCookies(); } catch (error) { ElementPlus.ElMessage.error('保存失败'); } }; const deleteCookie = async (cookie) => { try { await ElementPlus.ElMessageBox.confirm('确定要删除该Cookie吗?', '提示', { type: 'warning' }); await axios.delete(`/api/cookies/${cookie.id}`); ElementPlus.ElMessage.success('删除成功'); await loadWebsiteCookies(); } catch (error) { if (error !== 'cancel') { ElementPlus.ElMessage.error('删除失败'); } } }; const saveWebsiteSettings = async () => { try { await axios.put(`/api/websites/${currentWebsite.value.id}`, websiteForm.value); ElementPlus.ElMessage.success('保存成功'); } catch (error) { ElementPlus.ElMessage.error('保存失败'); } }; const maskCookieValue = (value) => { if (!value) return ''; return value.length > 30 ? value.substring(0, 30) + '...' : value; }; const loadDetections = async () => { try { const response = await axios.get('/api/detections'); detections.value = response.data; } catch (error) { console.error('加载检测结果失败:', error); } }; const loadNotifications = async () => { try { const response = await axios.get('/api/notifications'); notifications.value = response.data; } catch (error) { console.error('加载通知失败:', error); } }; const viewNotificationDetail = (notification) => { ElementPlus.ElMessageBox.alert(notification.content, notification.title, { confirmButtonText: '确定' }); }; onMounted(async () => { await checkAdminStatus(); await loadUsers(); await loadWebsites(); await loadDashboard(); startAutoRefresh(); }); return { activeTab, settingsTab, manageTab, currentWebsite, currentUser, isAdmin, users, websites, dashboardData, websiteCookies, websiteDetections, detections, notifications, stats, countdown, adminLoginVisible, adminLoginForm, userDialogVisible, userDialogTitle, userForm, websiteDialogVisible, websiteDialogTitle, websiteFormDialog, cookieDialogVisible, cookieDialogTitle, cookieForm, websiteForm, filterWebsiteUser, currentUserWebsites, filteredWebsites, checkAdminStatus, showAdminLogin, adminLogin, handleAdminCommand, handleDropdownCommand, loadUsers, loadUsersWithWebsites, loadWebsites, loadDashboard, refreshDashboardStatus, startAutoRefresh, stopAutoRefresh, checkLogin, manageWebsite, manageUserWebsites, loadWebsiteCookies, loadWebsiteDetections, showAddUserDialog, editUser, saveUser, deleteUser, showAddWebsiteDialog, showAddWebsiteDialogForUser, editWebsite, saveWebsite, deleteWebsite, showAddCookieDialog, editCookie, saveCookie, deleteCookie, saveWebsiteSettings, maskCookieValue, loadDetections, loadNotifications, viewNotificationDetail }; } }).use(ElementPlus).mount('#app');