feat(ops-web): add operations console frontend

Vue 3 + Ant Design Vue SPA scaffold for the internal ops console. Ships
the auth, account list, and audit log views that consume the new ops-api
endpoints, plus the nginx/vite/typecheck plumbing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-28 11:33:17 +08:00
parent f63e800f21
commit f5254f6a27
20 changed files with 1830 additions and 7 deletions
+73
View File
@@ -0,0 +1,73 @@
import { createRouter, createWebHistory } from "vue-router";
import { pinia } from "@/stores/pinia";
import { useAuthStore } from "@/stores/auth";
export const router = createRouter({
history: createWebHistory(),
routes: [
{
path: "/login",
name: "login",
component: () => import("@/views/LoginView.vue"),
meta: { title: "登录" },
},
{
path: "/",
component: () => import("@/layouts/AppShell.vue"),
meta: { requiresAuth: true },
children: [
{ path: "", redirect: "/accounts" },
{
path: "accounts",
name: "accounts",
component: () => import("@/views/AccountsView.vue"),
meta: { title: "账号管理" },
},
{
path: "audits",
name: "audits",
component: () => import("@/views/AuditLogsView.vue"),
meta: { title: "审计日志" },
},
{
path: "profile",
name: "profile",
component: () => import("@/views/ProfileView.vue"),
meta: { title: "个人资料" },
},
],
},
{
path: "/:pathMatch(.*)*",
redirect: "/",
},
],
});
router.beforeEach((to) => {
const auth = useAuthStore(pinia);
if (!auth.initialized) {
auth.hydrate();
}
if (to.meta.requiresAuth && !auth.isAuthenticated) {
return {
name: "login",
query: to.fullPath !== "/" ? { redirect: to.fullPath } : undefined,
};
}
if (to.name === "login" && auth.isAuthenticated) {
return { name: "accounts" };
}
return true;
});
router.afterEach((to) => {
if (typeof document !== "undefined") {
const t = (to.meta.title as string | undefined) ?? "运营后台";
document.title = `${t} · 省心推`;
}
});