feat(ui): extract entity forms into dedicated edit views

Move entity creation and editing from AdminView to separate pages.
Simplify AdminView to focus on system configuration and record deletion.
Add action buttons to list/detail views and protect routes via meta tags.
This commit is contained in:
2026-04-30 15:12:32 +08:00
parent 47b9b25032
commit 3e8265e0c8
15 changed files with 1048 additions and 635 deletions

View File

@@ -1,12 +1,16 @@
import { createRouter, createWebHistory } from 'vue-router';
import PokemonList from '../views/PokemonList.vue';
import PokemonDetail from '../views/PokemonDetail.vue';
import PokemonEdit from '../views/PokemonEdit.vue';
import HabitatList from '../views/HabitatList.vue';
import HabitatDetail from '../views/HabitatDetail.vue';
import HabitatEdit from '../views/HabitatEdit.vue';
import ItemsList from '../views/ItemsList.vue';
import ItemDetail from '../views/ItemDetail.vue';
import ItemEdit from '../views/ItemEdit.vue';
import RecipeList from '../views/RecipeList.vue';
import RecipeDetail from '../views/RecipeDetail.vue';
import RecipeEdit from '../views/RecipeEdit.vue';
import AdminView from '../views/AdminView.vue';
import LoginView from '../views/LoginView.vue';
import RegisterView from '../views/RegisterView.vue';
@@ -18,14 +22,22 @@ export const router = createRouter({
routes: [
{ path: '/', redirect: '/pokemon' },
{ path: '/pokemon', component: PokemonList },
{ path: '/pokemon/new', component: PokemonEdit, meta: { requiresVerified: true } },
{ path: '/pokemon/:id/edit', component: PokemonEdit, meta: { requiresVerified: true } },
{ path: '/pokemon/:id', component: PokemonDetail },
{ path: '/habitats', component: HabitatList },
{ path: '/habitats/new', component: HabitatEdit, meta: { requiresVerified: true } },
{ path: '/habitats/:id/edit', component: HabitatEdit, meta: { requiresVerified: true } },
{ path: '/habitats/:id', component: HabitatDetail },
{ path: '/items', component: ItemsList },
{ path: '/items/new', component: ItemEdit, meta: { requiresVerified: true } },
{ path: '/items/:id/edit', component: ItemEdit, meta: { requiresVerified: true } },
{ path: '/items/:id', component: ItemDetail },
{ path: '/recipes', component: RecipeList },
{ path: '/recipes/new', component: RecipeEdit, meta: { requiresVerified: true } },
{ path: '/recipes/:id/edit', component: RecipeEdit, meta: { requiresVerified: true } },
{ path: '/recipes/:id', component: RecipeDetail },
{ path: '/admin', component: AdminView },
{ path: '/admin', component: AdminView, meta: { requiresVerified: true } },
{ path: '/login', component: LoginView },
{ path: '/register', component: RegisterView },
{ path: '/verify-email', component: VerifyEmailView }
@@ -34,7 +46,7 @@ export const router = createRouter({
});
router.beforeEach(async (to) => {
if (to.path !== '/admin') {
if (!to.matched.some((record) => record.meta.requiresVerified === true)) {
return true;
}
@@ -43,8 +55,8 @@ router.beforeEach(async (to) => {
}
try {
await api.me();
return true;
const response = await api.me();
return response.user.emailVerified ? true : { path: '/login', query: { redirect: to.fullPath } };
} catch {
setAuthToken(null);
return { path: '/login', query: { redirect: to.fullPath } };