Initial commit: finish basic WebUI interface

This commit is contained in:
2026-03-09 21:17:22 +08:00
parent d2a2a4de36
commit 2f6cfe7704
23 changed files with 5028 additions and 1 deletions

205
src/views/Sessions.vue Normal file
View File

@@ -0,0 +1,205 @@
<template>
<div class="sessions-page">
<div class="page-header">
<h2>Session Management</h2>
</div>
<div class="sessions-grid">
<div v-for="session in sessions" :key="session.ID" class="session-card">
<div class="card-header">
<div class="session-icon">🔑</div>
<div class="session-info">
<div class="session-user">{{ session.username }}</div>
<div class="session-id">{{ session.ID }}</div>
</div>
</div>
<div class="card-body">
<div class="info-row">
<span class="label">User ID:</span>
<span class="value">{{ session.userID }}</span>
</div>
<div class="info-row">
<span class="label">Create Time:</span>
<span class="value">{{ formatDate(session.expireAt) }}</span>
</div>
<div class="info-row">
<span class="label">Expire Time:</span>
<span class="value">{{ formatDate(session.expireAt) }}</span>
</div>
</div>
<div class="card-footer">
<button class="action-btn delete-btn" @click="deleteSession(session.ID)">
Delete Session
</button>
</div>
</div>
</div>
<div v-if="sessions.length === 0" class="empty-state">
<p>No active sessions</p>
</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import { sessionApi } from '../api/index.js';
import { showNotification, formatDate } from '../utils/functions.js';
export default {
name: 'Sessions',
setup() {
const sessions = ref([]);
const loadSessions = async () => {
try {
const result = await sessionApi.listSessions();
sessions.value = result.data;
} catch (error) {
showNotification('Load session list failed', 'error');
}
};
const deleteSession = async (sessionId) => {
if (!confirm('Are you sure you want to delete this session? This will force the user to re-login.')) return;
try {
await sessionApi.removeSession(sessionId);
showNotification('Session deleted successfully', 'success');
await loadSessions();
} catch (error) {
showNotification(error.message || 'Delete session failed', 'error');
}
};
onMounted(() => {
loadSessions();
});
return {
sessions,
deleteSession,
formatDate
};
}
};
</script>
<style scoped>
.sessions-page {
padding: 24px;
}
.page-header {
margin-bottom: 24px;
}
.page-header h2 {
font-size: 24px;
color: var(--text-color);
margin: 0;
transition: color 0.3s;
}
.sessions-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 20px;
}
.session-card {
background: var(--card-bg);
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition: background-color 0.3s;
}
.card-header {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 16px;
}
.session-icon {
width: 48px;
height: 48px;
border-radius: 50%;
background: linear-gradient(135deg, var(--primary-color) 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
}
.session-info {
flex: 1;
}
.session-user {
font-size: 16px;
font-weight: 600;
color: var(--text-color);
margin-bottom: 4px;
transition: color 0.3s;
}
.session-id {
font-size: 12px;
color: #999;
font-family: monospace;
}
.card-body {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 16px;
}
.info-row {
display: flex;
justify-content: space-between;
font-size: 14px;
}
.info-row .label {
color: #666;
}
.info-row .value {
color: var(--text-color);
font-weight: 500;
transition: color 0.3s;
}
.card-footer {
display: flex;
gap: 8px;
}
.action-btn {
flex: 1;
padding: 8px 16px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s;
}
.delete-btn {
background: #ff4d4f;
color: white;
}
.delete-btn:hover {
background: #f04142;
}
.empty-state {
text-align: center;
padding: 60px 20px;
color: #999;
font-size: 16px;
}
</style>