yanghao před 2 týdny
rodič
revize
75a9ba5515
3 změnil soubory, kde provedl 240 přidání a 3 odebrání
  1. 14 2
      src/components/home/header.vue
  2. 14 1
      src/router/index.ts
  3. 212 0
      src/views/drive/index.vue

+ 14 - 2
src/components/home/header.vue

@@ -25,7 +25,11 @@
               >流程门户</a
             >
           </li>
-          <li><a class="hover:text-[#02409b] cursor-pointer">驾驶舱门户</a></li>
+          <li>
+            <a class="hover:text-[#02409b] cursor-pointer" @click="goDrive"
+              >驾驶舱门户</a
+            >
+          </li>
           <li><a class="hover:text-[#02409b] cursor-pointer">报表门户</a></li>
         </ul>
       </nav>
@@ -311,7 +315,11 @@
               >流程门户</a
             >
           </li>
-          <li><a class="hover:text-[#02409b] cursor-pointer">驾驶舱门户</a></li>
+          <li>
+            <a class="hover:text-[#02409b] cursor-pointer" @click="goDrive"
+              >驾驶舱门户</a
+            >
+          </li>
           <li><a class="hover:text-[#02409b] cursor-pointer">报表门户</a></li>
         </ul>
         <div class="flex items-center gap-3 mt-3">
@@ -535,6 +543,10 @@ const goFlow = () => {
   router.push({ path: "/flow" });
 };
 
+const goDrive = () => {
+  router.push({ path: "/drive" });
+};
+
 const onUserCommand = async (command: string) => {
   if (command === "logout") {
     // await userStore.loginOut();

+ 14 - 1
src/router/index.ts

@@ -11,7 +11,11 @@ import Login from "@/views/login.vue";
 import { getAccessToken } from "@utils/auth";
 import { socialLogin } from "@/api/user";
 import * as authUtil from "@/utils/auth";
-import { isRelogin, manualLogoutKey, reloginCancelKey } from "@/config/axios/service";
+import {
+  isRelogin,
+  manualLogoutKey,
+  reloginCancelKey,
+} from "@/config/axios/service";
 
 import { useUserStoreWithOut } from "@/stores/useUserStore";
 
@@ -74,6 +78,15 @@ const routes: RouteRecordRaw[] = [
       title: "DeepOil 智慧经营平台 | CRM已办列表",
     },
   },
+
+  {
+    path: "/drive",
+    name: "Drive",
+    component: () => import("@/views/drive/index.vue"),
+    meta: {
+      title: "DeepOil 智慧经营平台 | 驾驶舱",
+    },
+  },
 ];
 
 const router = createRouter({

+ 212 - 0
src/views/drive/index.vue

@@ -0,0 +1,212 @@
+<template>
+  <div class="drive-page">
+    <Header />
+
+    <main class="drive-main">
+      <section class="drive-hero">
+        <p class="drive-eyebrow">Dashboard Portal</p>
+        <h1 class="drive-title">驾驶舱门户</h1>
+        <p class="drive-desc">选择一个驾驶舱,快速进入对应业务看板。</p>
+      </section>
+
+      <section class="drive-grid">
+        <button
+          v-for="card in driveCards"
+          :key="card.title"
+          type="button"
+          class="drive-card"
+          @click="openDrive(card.url)"
+        >
+          <div class="drive-card__icon">
+            <Icon :icon="card.icon" />
+          </div>
+          <div class="drive-card__content">
+            <h2 class="drive-card__title">{{ card.title }}</h2>
+            <p class="drive-card__text">{{ card.description }}</p>
+          </div>
+          <div class="drive-card__arrow">
+            <Icon icon="mdi:arrow-top-right" />
+          </div>
+        </button>
+      </section>
+    </main>
+
+    <Footer />
+  </div>
+</template>
+
+<script setup lang="ts">
+import Header from "@components/home/header.vue";
+import Footer from "@components/home/Footer.vue";
+import { Icon } from "@iconify/vue";
+
+type DriveCard = {
+  title: string;
+  description: string;
+  icon: string;
+  url: string;
+};
+
+const driveCards: DriveCard[] = [
+  {
+    title: "生产驾驶舱",
+    description: "查看生产运营态势、核心指标与执行情况。",
+    icon: "mdi:factory",
+    url: "http://172.21.10.42:1080/webroot/decision/v10/entry/access/dbc9cf73-81ce-43f1-9923-45cdfa5d5d3a?preview=true&page_number=1",
+  },
+  {
+    title: "财务驾驶舱",
+    description: "查看财务分析、预算执行与经营数据表现。",
+    icon: "mdi:finance",
+    url: "http://172.21.10.42:1080/webroot/decision/v10/entry/access/e836fb5b-092c-4d64-a324-3beeb4fac0cc?preview=true&page_number=1",
+  },
+];
+
+const openDrive = (url: string) => {
+  window.open(url, "_blank");
+};
+</script>
+
+<style scoped>
+.drive-page {
+  min-height: 100vh;
+  background:
+    radial-gradient(
+      circle at top left,
+      rgba(77, 138, 255, 0.16),
+      transparent 28%
+    ),
+    linear-gradient(180deg, #f4f8fc 0%, #eef3f9 100%);
+  color: #17345f;
+}
+
+.drive-main {
+  max-width: 1200px;
+  margin: 0 auto;
+  padding: 132px 24px 72px;
+  height: 93vh;
+}
+
+.drive-hero {
+  margin-bottom: 40px;
+}
+
+.drive-eyebrow {
+  margin: 0 0 10px;
+  color: #4a78c2;
+  font-size: 13px;
+  font-weight: 700;
+  letter-spacing: 0.18em;
+  text-transform: uppercase;
+}
+
+.drive-title {
+  margin: 0;
+  color: #0f274a;
+  font-size: clamp(30px, 4vw, 42px);
+  font-weight: 700;
+}
+
+.drive-desc {
+  margin: 14px 0 0;
+  max-width: 560px;
+  color: #5e7391;
+  font-size: 16px;
+  line-height: 1.8;
+}
+
+.drive-grid {
+  display: grid;
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+  gap: 24px;
+}
+
+.drive-card {
+  display: flex;
+  align-items: center;
+  gap: 18px;
+  width: 100%;
+  padding: 28px 26px;
+  border: 1px solid rgba(118, 154, 210, 0.18);
+  border-radius: 24px;
+  background: rgba(255, 255, 255, 0.9);
+  box-shadow: 0 18px 40px rgba(33, 77, 145, 0.08);
+  text-align: left;
+  cursor: pointer;
+  transition:
+    transform 0.2s ease,
+    box-shadow 0.2s ease,
+    border-color 0.2s ease;
+}
+
+.drive-card:hover {
+  transform: translateY(-4px);
+  border-color: rgba(47, 111, 219, 0.36);
+  box-shadow: 0 24px 48px rgba(33, 77, 145, 0.14);
+}
+
+.drive-card__icon {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 64px;
+  height: 64px;
+  border-radius: 18px;
+  background: linear-gradient(135deg, #2f6fdb 0%, #6ea2ff 100%);
+  color: #fff;
+  font-size: 30px;
+  flex-shrink: 0;
+  box-shadow: 0 14px 28px rgba(47, 111, 219, 0.24);
+}
+
+.drive-card__content {
+  min-width: 0;
+  flex: 1;
+}
+
+.drive-card__title {
+  margin: 0;
+  color: #17345f;
+  font-size: 24px;
+  font-weight: 700;
+}
+
+.drive-card__text {
+  margin: 10px 0 0;
+  color: #6c809d;
+  font-size: 14px;
+  line-height: 1.7;
+}
+
+.drive-card__arrow {
+  color: #7c93b6;
+  font-size: 26px;
+  flex-shrink: 0;
+  transition:
+    transform 0.2s ease,
+    color 0.2s ease;
+}
+
+.drive-card:hover .drive-card__arrow {
+  color: #2f6fdb;
+  transform: translate(2px, -2px);
+}
+
+@media (max-width: 768px) {
+  .drive-main {
+    padding: 112px 16px 56px;
+  }
+
+  .drive-grid {
+    grid-template-columns: 1fr;
+  }
+
+  .drive-card {
+    padding: 22px 18px;
+  }
+
+  .drive-card__title {
+    font-size: 20px;
+  }
+}
+</style>