Update public/index.html
Browse files- public/index.html +131 -29
public/index.html
CHANGED
@@ -331,7 +331,7 @@
|
|
331 |
margin-top: 10px;
|
332 |
font-size: 14px;
|
333 |
}
|
334 |
-
.logout-button {
|
335 |
background: var(--action-button-bg);
|
336 |
border: none;
|
337 |
color: var(--text-color);
|
@@ -340,9 +340,8 @@
|
|
340 |
cursor: pointer;
|
341 |
font-size: 13px;
|
342 |
transition: background 0.2s ease;
|
343 |
-
margin-left: auto;
|
344 |
}
|
345 |
-
.logout-button:hover {
|
346 |
background: var(--action-button-hover);
|
347 |
}
|
348 |
.header-container {
|
@@ -351,6 +350,10 @@
|
|
351 |
align-items: center;
|
352 |
margin-bottom: 20px;
|
353 |
}
|
|
|
|
|
|
|
|
|
354 |
</style>
|
355 |
</head>
|
356 |
<body>
|
@@ -358,7 +361,10 @@
|
|
358 |
<div class="overview">
|
359 |
<div class="header-container">
|
360 |
<div class="overview-title">📊 系统概览</div>
|
361 |
-
<
|
|
|
|
|
|
|
362 |
</div>
|
363 |
<div class="theme-toggle">
|
364 |
主题:
|
@@ -439,44 +445,104 @@
|
|
439 |
|
440 |
// 登录状态管理
|
441 |
function checkLoginStatus() {
|
442 |
-
const
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
447 |
} else {
|
|
|
|
|
448 |
updateActionButtons(false);
|
449 |
}
|
450 |
}
|
451 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
452 |
function login() {
|
453 |
const username = document.getElementById('username').value;
|
454 |
const password = document.getElementById('password').value;
|
455 |
const loginError = document.getElementById('loginError');
|
456 |
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
-
|
464 |
-
|
|
|
|
|
|
|
|
|
465 |
checkLoginStatus();
|
466 |
} else {
|
467 |
-
loginError.textContent = '
|
468 |
loginError.style.display = 'block';
|
469 |
}
|
470 |
-
})
|
471 |
-
|
|
|
|
|
472 |
loginError.style.display = 'block';
|
473 |
-
console.error('获取配置失败,无法验证登录:', err);
|
474 |
});
|
475 |
}
|
476 |
|
477 |
function logout() {
|
478 |
-
localStorage.
|
479 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
480 |
}
|
481 |
|
482 |
function updateActionButtons(isLoggedIn) {
|
@@ -712,14 +778,32 @@
|
|
712 |
|
713 |
async function restartSpace(repoId) {
|
714 |
try {
|
|
|
|
|
|
|
|
|
|
|
|
|
715 |
const encodedRepoId = encodeURIComponent(repoId);
|
716 |
-
const response = await fetch(`/api/proxy/restart/${encodedRepoId}`, {
|
|
|
|
|
|
|
|
|
|
|
717 |
const result = await response.json();
|
718 |
if (result.success) {
|
719 |
alert(`重启成功: ${repoId}`);
|
720 |
} else {
|
721 |
-
|
722 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
723 |
}
|
724 |
} catch (error) {
|
725 |
console.error(`重启失败 (${repoId}):`, error);
|
@@ -729,14 +813,32 @@
|
|
729 |
|
730 |
async function rebuildSpace(repoId) {
|
731 |
try {
|
|
|
|
|
|
|
|
|
|
|
|
|
732 |
const encodedRepoId = encodeURIComponent(repoId);
|
733 |
-
const response = await fetch(`/api/proxy/rebuild/${encodedRepoId}`, {
|
|
|
|
|
|
|
|
|
|
|
734 |
const result = await response.json();
|
735 |
if (result.success) {
|
736 |
alert(`重建成功: ${repoId}`);
|
737 |
} else {
|
738 |
-
|
739 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
740 |
}
|
741 |
} catch (error) {
|
742 |
console.error(`重建失败 (${repoId}):`, error);
|
|
|
331 |
margin-top: 10px;
|
332 |
font-size: 14px;
|
333 |
}
|
334 |
+
.login-button, .logout-button {
|
335 |
background: var(--action-button-bg);
|
336 |
border: none;
|
337 |
color: var(--text-color);
|
|
|
340 |
cursor: pointer;
|
341 |
font-size: 13px;
|
342 |
transition: background 0.2s ease;
|
|
|
343 |
}
|
344 |
+
.login-button:hover, .logout-button:hover {
|
345 |
background: var(--action-button-hover);
|
346 |
}
|
347 |
.header-container {
|
|
|
350 |
align-items: center;
|
351 |
margin-bottom: 20px;
|
352 |
}
|
353 |
+
.auth-buttons {
|
354 |
+
display: flex;
|
355 |
+
gap: 10px;
|
356 |
+
}
|
357 |
</style>
|
358 |
</head>
|
359 |
<body>
|
|
|
361 |
<div class="overview">
|
362 |
<div class="header-container">
|
363 |
<div class="overview-title">📊 系统概览</div>
|
364 |
+
<div class="auth-buttons">
|
365 |
+
<button class="login-button" id="loginButton" onclick="showLoginForm()">登录</button>
|
366 |
+
<button class="logout-button" id="logoutButton" style="display: none;" onclick="logout()">登出</button>
|
367 |
+
</div>
|
368 |
</div>
|
369 |
<div class="theme-toggle">
|
370 |
主题:
|
|
|
445 |
|
446 |
// 登录状态管理
|
447 |
function checkLoginStatus() {
|
448 |
+
const token = localStorage.getItem('authToken');
|
449 |
+
if (token) {
|
450 |
+
fetch('/api/verify-token', {
|
451 |
+
method: 'POST',
|
452 |
+
headers: {
|
453 |
+
'Content-Type': 'application/json',
|
454 |
+
},
|
455 |
+
body: JSON.stringify({ token })
|
456 |
+
})
|
457 |
+
.then(response => response.json())
|
458 |
+
.then(data => {
|
459 |
+
if (data.success) {
|
460 |
+
document.getElementById('loginButton').style.display = 'none';
|
461 |
+
document.getElementById('logoutButton').style.display = 'block';
|
462 |
+
updateActionButtons(true);
|
463 |
+
} else {
|
464 |
+
localStorage.removeItem('authToken');
|
465 |
+
document.getElementById('loginButton').style.display = 'block';
|
466 |
+
document.getElementById('logoutButton').style.display = 'none';
|
467 |
+
updateActionButtons(false);
|
468 |
+
}
|
469 |
+
})
|
470 |
+
.catch(error => {
|
471 |
+
console.error('验证 token 失败:', error);
|
472 |
+
localStorage.removeItem('authToken');
|
473 |
+
document.getElementById('loginButton').style.display = 'block';
|
474 |
+
document.getElementById('logoutButton').style.display = 'none';
|
475 |
+
updateActionButtons(false);
|
476 |
+
});
|
477 |
} else {
|
478 |
+
document.getElementById('loginButton').style.display = 'block';
|
479 |
+
document.getElementById('logoutButton').style.display = 'none';
|
480 |
updateActionButtons(false);
|
481 |
}
|
482 |
}
|
483 |
|
484 |
+
function showLoginForm() {
|
485 |
+
document.getElementById('loginOverlay').style.display = 'flex';
|
486 |
+
document.getElementById('username').value = '';
|
487 |
+
document.getElementById('password').value = '';
|
488 |
+
document.getElementById('loginError').style.display = 'none';
|
489 |
+
}
|
490 |
+
|
491 |
+
function hideLoginForm() {
|
492 |
+
document.getElementById('loginOverlay').style.display = 'none';
|
493 |
+
}
|
494 |
+
|
495 |
function login() {
|
496 |
const username = document.getElementById('username').value;
|
497 |
const password = document.getElementById('password').value;
|
498 |
const loginError = document.getElementById('loginError');
|
499 |
|
500 |
+
fetch('/api/login', {
|
501 |
+
method: 'POST',
|
502 |
+
headers: {
|
503 |
+
'Content-Type': 'application/json',
|
504 |
+
},
|
505 |
+
body: JSON.stringify({ username, password })
|
506 |
+
})
|
507 |
+
.then(response => response.json())
|
508 |
+
.then(data => {
|
509 |
+
if (data.success) {
|
510 |
+
localStorage.setItem('authToken', data.token);
|
511 |
+
hideLoginForm();
|
512 |
checkLoginStatus();
|
513 |
} else {
|
514 |
+
loginError.textContent = data.message || '登录失败';
|
515 |
loginError.style.display = 'block';
|
516 |
}
|
517 |
+
})
|
518 |
+
.catch(error => {
|
519 |
+
console.error('登录请求失败:', error);
|
520 |
+
loginError.textContent = '登录请求失败,请稍后重试';
|
521 |
loginError.style.display = 'block';
|
|
|
522 |
});
|
523 |
}
|
524 |
|
525 |
function logout() {
|
526 |
+
const token = localStorage.getItem('authToken');
|
527 |
+
if (token) {
|
528 |
+
fetch('/api/logout', {
|
529 |
+
method: 'POST',
|
530 |
+
headers: {
|
531 |
+
'Content-Type': 'application/json',
|
532 |
+
},
|
533 |
+
body: JSON.stringify({ token })
|
534 |
+
})
|
535 |
+
.then(response => response.json())
|
536 |
+
.then(data => {
|
537 |
+
localStorage.removeItem('authToken');
|
538 |
+
checkLoginStatus();
|
539 |
+
})
|
540 |
+
.catch(error => {
|
541 |
+
console.error('登出失败:', error);
|
542 |
+
localStorage.removeItem('authToken');
|
543 |
+
checkLoginStatus();
|
544 |
+
});
|
545 |
+
}
|
546 |
}
|
547 |
|
548 |
function updateActionButtons(isLoggedIn) {
|
|
|
778 |
|
779 |
async function restartSpace(repoId) {
|
780 |
try {
|
781 |
+
const token = localStorage.getItem('authToken');
|
782 |
+
if (!token) {
|
783 |
+
alert('请先登录以执行此操作');
|
784 |
+
showLoginForm();
|
785 |
+
return;
|
786 |
+
}
|
787 |
const encodedRepoId = encodeURIComponent(repoId);
|
788 |
+
const response = await fetch(`/api/proxy/restart/${encodedRepoId}`, {
|
789 |
+
method: 'POST',
|
790 |
+
headers: {
|
791 |
+
'Authorization': `Bearer ${token}`
|
792 |
+
}
|
793 |
+
});
|
794 |
const result = await response.json();
|
795 |
if (result.success) {
|
796 |
alert(`重启成功: ${repoId}`);
|
797 |
} else {
|
798 |
+
if (response.status === 401) {
|
799 |
+
alert('登录已过期,请重新登录');
|
800 |
+
localStorage.removeItem('authToken');
|
801 |
+
checkLoginStatus();
|
802 |
+
showLoginForm();
|
803 |
+
} else {
|
804 |
+
alert(`重启失败: ${result.error || '未知错误'}`);
|
805 |
+
console.error(`重启失败 (${repoId}):`, result.error, result.details);
|
806 |
+
}
|
807 |
}
|
808 |
} catch (error) {
|
809 |
console.error(`重启失败 (${repoId}):`, error);
|
|
|
813 |
|
814 |
async function rebuildSpace(repoId) {
|
815 |
try {
|
816 |
+
const token = localStorage.getItem('authToken');
|
817 |
+
if (!token) {
|
818 |
+
alert('请先登录以执行此操作');
|
819 |
+
showLoginForm();
|
820 |
+
return;
|
821 |
+
}
|
822 |
const encodedRepoId = encodeURIComponent(repoId);
|
823 |
+
const response = await fetch(`/api/proxy/rebuild/${encodedRepoId}`, {
|
824 |
+
method: 'POST',
|
825 |
+
headers: {
|
826 |
+
'Authorization': `Bearer ${token}`
|
827 |
+
}
|
828 |
+
});
|
829 |
const result = await response.json();
|
830 |
if (result.success) {
|
831 |
alert(`重建成功: ${repoId}`);
|
832 |
} else {
|
833 |
+
if (response.status === 401) {
|
834 |
+
alert('登录已过期,请重新登录');
|
835 |
+
localStorage.removeItem('authToken');
|
836 |
+
checkLoginStatus();
|
837 |
+
showLoginForm();
|
838 |
+
} else {
|
839 |
+
alert(`重建失败: ${result.error || '未知错误'}`);
|
840 |
+
console.error(`重建失败 (${repoId}):`, result.error, result.details);
|
841 |
+
}
|
842 |
}
|
843 |
} catch (error) {
|
844 |
console.error(`重建失败 (${repoId}):`, error);
|