refactor(components): move status indicator from topbar to sidebar

Relocate the online status indicator component from the top navigation bar to the sidebar for better layout organization. Remove unused code and update styling to match sidebar theme.
This commit is contained in:
2026-04-05 21:31:44 +08:00
parent c53854722d
commit 928998f255
2 changed files with 60 additions and 39 deletions

View File

@@ -12,6 +12,12 @@
<span class="menu-text">{{ item.title }}</span> <span class="menu-text">{{ item.title }}</span>
</router-link> </router-link>
</div> </div>
<div class="status-info">
<div class="status-item">
<span :class="['status-dot', { online: isOnline }]"></span>
<span class="status-text">{{ isOnline ? 'Online' : 'Offline' }}</span>
</div>
</div>
<div class="theme-toggle"> <div class="theme-toggle">
<button @click="toggleTheme" class="theme-button"> <button @click="toggleTheme" class="theme-button">
<span class="theme-icon"><i :class="isDarkMode ? 'fas fa-sun' : 'fas fa-moon'" aria-hidden="true"></i></span> <span class="theme-icon"><i :class="isDarkMode ? 'fas fa-sun' : 'fas fa-moon'" aria-hidden="true"></i></span>
@@ -22,8 +28,9 @@
</template> </template>
<script> <script>
import { computed, inject } from 'vue'; import { ref, computed, inject, onMounted, onBeforeUnmount } from 'vue';
import { getCookie } from '../utils/functions.js'; import { getCookie } from '../utils/functions.js';
import { systemApi } from '../api/index.js';
export default { export default {
name: 'SideBar', name: 'SideBar',
@@ -31,6 +38,8 @@ export default {
const userType = getCookie('user-type') || 'visitor'; const userType = getCookie('user-type') || 'visitor';
const isDarkMode = inject('isDarkMode'); const isDarkMode = inject('isDarkMode');
const toggleTheme = inject('toggleTheme'); const toggleTheme = inject('toggleTheme');
const isOnline = ref(false);
let statusInterval;
const allMenuItems = [ const allMenuItems = [
{ path: '/instances', title: 'Instance Management', icon: 'fas fa-box', permission: ['superuser', 'admin', 'visitor'] }, { path: '/instances', title: 'Instance Management', icon: 'fas fa-box', permission: ['superuser', 'admin', 'visitor'] },
@@ -45,10 +54,31 @@ export default {
return allMenuItems.filter(item => item.permission.includes(userType)); return allMenuItems.filter(item => item.permission.includes(userType));
}); });
const checkStatus = async () => {
try {
const result = await systemApi.getStatus();
isOnline.value = result.data.Status === 'Online';
} catch (error) {
isOnline.value = false;
}
};
onMounted(() => {
checkStatus();
statusInterval = setInterval(checkStatus, 60000);
});
onBeforeUnmount(() => {
if (statusInterval) {
clearInterval(statusInterval);
}
});
return { return {
menuItems, menuItems,
isDarkMode, isDarkMode,
toggleTheme toggleTheme,
isOnline
}; };
} }
}; };
@@ -156,4 +186,32 @@ export default {
.theme-text { .theme-text {
font-weight: 500; font-weight: 500;
} }
.status-info {
padding: 16px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.status-item {
display: flex;
align-items: center;
gap: 8px;
}
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: #ff4d4f;
}
.status-dot.online {
background: #52c41a;
}
.status-text {
font-size: 14px;
color: var(--sidebar-text);
font-weight: 500;
}
</style> </style>

View File

@@ -15,10 +15,6 @@
</div> </div>
</div> </div>
<div class="topbar-right"> <div class="topbar-right">
<div class="status-info">
<span :class="['status-dot', { online: isOnline }]"></span>
<span class="status-text">{{ isOnline ? 'Online' : 'Offline' }}</span>
</div>
<div class="version-info" v-if="softwareInfo"> <div class="version-info" v-if="softwareInfo">
<span>v{{ softwareInfo.Version }}</span> <span>v{{ softwareInfo.Version }}</span>
</div> </div>
@@ -88,7 +84,6 @@ export default {
emits: ['search'], emits: ['search'],
setup(props, { emit }) { setup(props, { emit }) {
const searchQuery = ref(''); const searchQuery = ref('');
const isOnline = ref(false);
const softwareInfo = ref(null); const softwareInfo = ref(null);
const username = ref(getCookie('username') || 'User'); const username = ref(getCookie('username') || 'User');
const menuVisible = ref(false); const menuVisible = ref(false);
@@ -103,15 +98,6 @@ export default {
}); });
const router = useRouter(); const router = useRouter();
const checkStatus = async () => {
try {
const result = await systemApi.getStatus();
isOnline.value = result.data.Status === 'Online';
} catch (error) {
isOnline.value = false;
}
};
const getSoftwareInfo = async () => { const getSoftwareInfo = async () => {
try { try {
const result = await systemApi.getSoftwareInfo(); const result = await systemApi.getSoftwareInfo();
@@ -207,9 +193,7 @@ export default {
}; };
onMounted(() => { onMounted(() => {
checkStatus();
getSoftwareInfo(); getSoftwareInfo();
setInterval(checkStatus, 60000);
document.addEventListener('click', closeMenu); document.addEventListener('click', closeMenu);
}); });
@@ -219,7 +203,6 @@ export default {
return { return {
searchQuery, searchQuery,
isOnline,
softwareInfo, softwareInfo,
username, username,
handleSearch, handleSearch,
@@ -312,27 +295,7 @@ export default {
gap: 24px; gap: 24px;
} }
.status-info {
display: flex;
align-items: center;
gap: 8px;
}
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: #ff4d4f;
}
.status-dot.online {
background: #52c41a;
}
.status-text {
font-size: 14px;
color: var(--text-color);
}
.version-info { .version-info {
font-size: 14px; font-size: 14px;