fix: 修复路由和页面加载问题

v3
veypi 1 week ago
parent e5308f9471
commit 983a5651a3

@ -13,7 +13,7 @@ import (
type ListRequest struct {
Page int `json:"page" src:"query" default:"1"`
PageSize int `json:"page_size" src:"query" default:"20"`
Keyword string `json:"keyword" src:"query"`
Keyword string `json:"keyword" src:"query" default:""`
}
type ListResponse struct {

@ -28,7 +28,7 @@ export default async ($env) => {
try {
await vbase.refresh();
} catch (e) {
vbase.logout(to.fullPath);
vbase.logout('/login?redirect=' + encodeURIComponent(to.fullPath));
return false;
}
}
@ -37,7 +37,7 @@ export default async ($env) => {
try {
await vbase.fetchUser();
} catch (e) {
vbase.logout(to.fullPath);
vbase.logout('/login?redirect=' + encodeURIComponent(to.fullPath));
return false;
}
}
@ -50,11 +50,6 @@ export default async ($env) => {
return false;
}
}
} else if (isGuest) {
if (!vbase.isExpired()) {
next('/');
return false;
}
}
next();

@ -157,12 +157,12 @@
// Define Menu Items
menuItems = [
{label: $t('nav.dashboard'), icon: "<i class='fas fa-tachometer-alt'></i>", path: "/"},
{label: $t('nav.org'), icon: "<i class='fas fa-sitemap'></i>", path: "/org"},
{label: $t('nav.profile'), icon: "<i class='fas fa-user'></i>", path: "/profile"},
{label: () => $t('nav.dashboard'), icon: "<i class='fas fa-tachometer-alt'></i>", path: "/"},
{label: () => $t('nav.org'), icon: "<i class='fas fa-sitemap'></i>", path: "/org"},
{label: () => $t('nav.profile'), icon: "<i class='fas fa-user'></i>", path: "/profile"},
// Admin only items would be filtered here ideally
{label: $t('nav.users'), icon: "<i class='fas fa-users-cog'></i>", path: "/users"},
{label: $t('nav.oauth'), icon: "<i class='fas fa-key'></i>", path: "/oauth/apps"},
{label: () => $t('nav.users'), icon: "<i class='fas fa-users-cog'></i>", path: "/users"},
{label: () => $t('nav.oauth'), icon: "<i class='fas fa-key'></i>", path: "/oauth/apps"},
];
currentRouteName = "";
@ -186,34 +186,12 @@
};
</script>
<script>
$watch(() => $env.$route.path, () => {
// Update breadcrumb or active item
// v-sidebar handles active state via path matching usually
// We can update title based on route name
// For now just simple mapping or rely on $route
// $data.currentRouteName = $env.$route.name || $env.$route.path
// Simple implementation:
const path = $env.$route.path;
$router.onChange(() => {
const path = $router.current.path;
console.log(path)
const item = $data.menuItems.find(i => i.path === path);
$data.currentRouteName = item ? item.label : path;
});
// Watch global state for user/org changes
$watch(() => [$env.$vbase.user, $env.$i18n.locale], () => {
$data.user = $env.$vbase.user;
// Re-generate menu items when locale changes
$data.menuItems = [
{label: $t('nav.dashboard'), icon: "<i class='fas fa-tachometer-alt'></i>", path: "/"},
{label: $t('nav.org'), icon: "<i class='fas fa-sitemap'></i>", path: "/org"},
{label: $t('nav.profile'), icon: "<i class='fas fa-user'></i>", path: "/profile"},
// Admin only items would be filtered here ideally
{label: $t('nav.users'), icon: "<i class='fas fa-users-cog'></i>", path: "/users"},
{label: $t('nav.oauth'), icon: "<i class='fas fa-key'></i>", path: "/oauth/apps"},
];
});
$watch(() => $env.$vbase.currentOrg, () => {
$data.currentOrg = $env.$vbase.currentOrg;
});
</script>
</html>

@ -73,7 +73,6 @@
</head>
<body>
123
<h2 class="login-title">{{ $t('auth.login') }}</h2>
<div v-if="error" class="error-msg">{{ error }}</div>
@ -106,7 +105,8 @@
error = "";
try {
await $env.$vbase.login(username, password);
$router.push('/');
const redirect = $router.query.redirect || '/';
$router.push(redirect);
} catch (err) {
error = err.message || "Login failed";
}

@ -1,5 +1,6 @@
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Dashboard">
<title>{{ $t('nav.dashboard') }}</title>
@ -9,11 +10,13 @@
flex-direction: column;
gap: 20px;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
}
.stat-card {
background: #fff;
padding: 20px;
@ -23,15 +26,18 @@
flex-direction: column;
gap: 10px;
}
.stat-title {
font-size: 14px;
color: var(--text-color-secondary);
}
.stat-value {
font-size: 24px;
font-weight: bold;
color: var(--color-primary);
}
.chart-container {
background: #fff;
padding: 20px;
@ -41,6 +47,7 @@
}
</style>
</head>
<body>
<div class="dashboard-container">
<h1>{{ $t('nav.dashboard') }}</h1>
@ -112,4 +119,5 @@
// Run after mount
$data.initChart();
</script>
</html>

@ -1,7 +1,7 @@
const routes = [
// Public
{ path: '/login', component: '/page/auth/login.html', layout: 'public', meta: { guest: true } },
{ path: '/register', component: '/page/auth/register.html', layout: 'public', meta: { guest: true } },
{ path: '/login', component: '/page/auth/login.html', layout: 'public' },
{ path: '/register', component: '/page/auth/register.html', layout: 'public' },
// Dashboard (Default Layout)
{

@ -61,7 +61,10 @@ class VBase {
const resData = await response.json();
if (!response.ok) {
throw resData || new Error(`Request failed: ${response.status}`);
// Include resData in the error so caller can access the response body
const error = new Error(resData.message || `Request failed: ${response.status}`);
Object.assign(error, resData);
throw error;
}
if (resData.code && resData.code !== 200) {
@ -75,10 +78,10 @@ class VBase {
async login(username, password) {
try {
const data = await this.request('POST', '/api/auth/login', { username, password });
if (data.access) {
this.token = data.access;
if (data.refresh) this.refreshToken = data.refresh;
await this.fetchUser();
if (data.access_token) {
this.token = data.access_token;
if (data.refresh_token) this.refreshToken = data.refresh_token;
this.user = data.user; // Set user directly from login response
return true;
}
return false;
@ -106,10 +109,10 @@ class VBase {
async refresh() {
if (!this.refreshToken) throw new Error("No refresh token");
try {
const data = await this.request('POST', '/api/auth/refresh', { refresh: this.refreshToken });
if (data.access) {
this.token = data.access;
if (data.refresh) this.refreshToken = data.refresh;
const data = await this.request('POST', '/api/auth/refresh', { refresh_token: this.refreshToken });
if (data.access_token) {
this.token = data.access_token;
if (data.refresh_token) this.refreshToken = data.refresh_token;
return true;
}
return false;
@ -205,7 +208,7 @@ class VBase {
originalRequest.headers['Authorization'] = headers['Authorization'];
return axiosInstance(originalRequest);
} catch (e) {
this.logout(window.location.pathname);
this.logout('/login?redirect=' + encodeURIComponent(window.location.pathname));
return Promise.reject(e);
}
}

Loading…
Cancel
Save