Procházet zdrojové kódy

首页排版调整

肖栋 před 1 týdnem
rodič
revize
2f3c21f715

+ 43 - 0
src/components/layout/AppHeader.vue

@@ -0,0 +1,43 @@
+<template>
+  <header class="app-header">
+    <h1 class="app-header-title">前期研究前置报告计划管理系统</h1>
+    <div class="app-header-right">
+      <!-- 右侧样式后续提供 -->
+    </div>
+  </header>
+</template>
+
+<script setup>
+defineOptions({
+  name: "AppHeader",
+});
+</script>
+
+<style scoped lang="scss">
+.app-header {
+  box-sizing: border-box;
+  flex-shrink: 0;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 17px 40px;
+  background: linear-gradient(135deg, #238be5 60%);
+  box-shadow: 0px 4px 12px 0px rgba(34, 125, 205, 0.1);
+  border-radius: 0;
+}
+
+.app-header-title {
+  margin: 0;
+  font-family: PingFang SC, PingFang SC;
+  font-weight: 600;
+  font-size: 28px;
+  color: #ffffff;
+  line-height: 39px;
+  letter-spacing: 2px;
+  text-align: left;
+}
+
+.app-header-right {
+  flex-shrink: 0;
+}
+</style>

+ 103 - 0
src/components/layout/AppSidebar.vue

@@ -0,0 +1,103 @@
+<template>
+  <aside class="app-sidebar">
+    <div
+      v-for="group in menuGroups"
+      :key="group.key"
+      class="app-sidebar-group"
+    >
+      <div class="app-sidebar-group-title">{{ group.label }}</div>
+      <button
+        v-for="item in group.children"
+        :key="item.key"
+        type="button"
+        class="app-sidebar-item"
+        :class="{ 'is-active': item.key === activeKey }"
+        @click="handleClick(item)"
+      >
+        {{ item.label }}
+      </button>
+    </div>
+  </aside>
+</template>
+
+<script setup>
+import { computed } from "vue";
+import { useRoute, useRouter } from "vue-router";
+
+defineOptions({
+  name: "AppSidebar",
+});
+
+const route = useRoute();
+const router = useRouter();
+
+const menuGroups = [
+  {
+    key: "project",
+    label: "项目管理",
+    children: [
+      { key: "overview", label: "项目概览", routeName: "overview" },
+      { key: "detail", label: "项目明细", routeName: "projectDetail" },
+      { key: "map", label: "一张图", routeName: "oneMap" },
+      { key: "plan", label: "总体计划", routeName: "overallPlan" },
+    ],
+  },
+  {
+    key: "settings",
+    label: "设置",
+    children: [
+      { key: "permission", label: "权限管理", routeName: "permission" },
+    ],
+  },
+];
+
+const activeKey = computed(() => {
+  const name = route.name;
+  for (const group of menuGroups) {
+    const matched = group.children.find((item) => item.routeName === name);
+    if (matched) return matched.key;
+  }
+  return "overview";
+});
+
+const handleClick = (item) => {
+  if (!item.routeName || item.routeName === route.name) return;
+  router.push({ name: item.routeName });
+};
+</script>
+
+<style scoped lang="scss">
+.app-sidebar {
+  box-sizing: border-box;
+  flex-shrink: 0;
+  width: 220px;
+  background: #e8edf3;
+  color: #16213a;
+}
+
+.app-sidebar-group {
+  display: flex;
+  flex-direction: column;
+}
+
+.app-sidebar-group-title {
+  padding: 16px 16px 8px;
+  font-size: 12px;
+  color: #808695;
+}
+
+.app-sidebar-item {
+  margin: 0;
+  padding: 12px 16px;
+  border: none;
+  background: transparent;
+  text-align: left;
+  cursor: pointer;
+  color: inherit;
+
+  &.is-active {
+    background: #d6e6f8;
+    color: #2382e7;
+  }
+}
+</style>

+ 42 - 0
src/layouts/MainLayout.vue

@@ -0,0 +1,42 @@
+<template>
+  <div class="main-layout">
+    <AppHeader />
+    <div class="main-layout-body">
+      <AppSidebar />
+      <main class="main-layout-content">
+        <router-view />
+      </main>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import AppHeader from "@/components/layout/AppHeader.vue";
+import AppSidebar from "@/components/layout/AppSidebar.vue";
+
+defineOptions({
+  name: "MainLayout",
+});
+</script>
+
+<style scoped lang="scss">
+.main-layout {
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+  min-height: 100vh;
+}
+
+.main-layout-body {
+  display: flex;
+  flex: 1;
+  min-height: 0;
+}
+
+.main-layout-content {
+  flex: 1;
+  min-width: 0;
+  box-sizing: border-box;
+  background: #f4f7fa;
+}
+</style>

+ 17 - 0
src/pages/empty/index.vue

@@ -0,0 +1,17 @@
+<template>
+  <div class="page-empty"></div>
+</template>
+
+<script setup>
+defineOptions({
+  name: "EmptyPage",
+});
+</script>
+
+<style scoped lang="scss">
+.page-empty {
+  box-sizing: border-box;
+  width: 100%;
+  min-height: 100%;
+}
+</style>

+ 20 - 0
src/pages/home/overview.vue

@@ -0,0 +1,20 @@
+<template>
+  <div class="page-overview">内容展示</div>
+</template>
+
+<script setup>
+defineOptions({
+  name: "ProjectOverview",
+});
+</script>
+
+<style scoped lang="scss">
+.page-overview {
+  box-sizing: border-box;
+  width: 100%;
+  min-height: 100%;
+  padding: 16px;
+  background: #ffffff;
+  color: #16213a;
+}
+</style>

+ 2 - 0
src/pages/login/index.vue

@@ -61,7 +61,9 @@ const goAfterLogin = () => {
   const redirect = router.currentRoute.value.query.redirect;
   if (redirect) {
     router.replace(String(redirect));
+    return;
   }
+  router.replace({ name: "overview" });
 };
 
 const handleLogin = async () => {

+ 49 - 6
src/router/index.js

@@ -2,10 +2,6 @@ import { createRouter, createWebHistory } from "vue-router";
 
 const routes = [
   {
-    path: "/",
-    redirect: "/login",
-  },
-  {
     path: "/login",
     name: "login",
     component: () => import("@/pages/login/index.vue"),
@@ -14,8 +10,55 @@ const routes = [
     },
   },
   {
+    path: "/",
+    component: () => import("@/layouts/MainLayout.vue"),
+    redirect: "/overview",
+    children: [
+      {
+        path: "overview",
+        name: "overview",
+        component: () => import("@/pages/home/overview.vue"),
+        meta: {
+          title: "项目概览",
+        },
+      },
+      {
+        path: "project-detail",
+        name: "projectDetail",
+        component: () => import("@/pages/empty/index.vue"),
+        meta: {
+          title: "项目明细",
+        },
+      },
+      {
+        path: "one-map",
+        name: "oneMap",
+        component: () => import("@/pages/empty/index.vue"),
+        meta: {
+          title: "一张图",
+        },
+      },
+      {
+        path: "overall-plan",
+        name: "overallPlan",
+        component: () => import("@/pages/empty/index.vue"),
+        meta: {
+          title: "总体计划",
+        },
+      },
+      {
+        path: "permission",
+        name: "permission",
+        component: () => import("@/pages/empty/index.vue"),
+        meta: {
+          title: "权限管理",
+        },
+      },
+    ],
+  },
+  {
     path: "/:pathMatch(.*)*",
-    redirect: "/login",
+    redirect: "/overview",
   },
 ];
 
@@ -28,7 +71,7 @@ const router = createRouter({
 });
 
 router.afterEach((to) => {
-  const defaultTitle = "尚云 MCP";
+  const defaultTitle = "前期研究前置报告计划管理系统";
   const title = to.meta && to.meta.title ? to.meta.title : defaultTitle;
   document.title = title;
 });