Przeglądaj źródła

首页样式优化

yanghao 2 tygodni temu
rodzic
commit
efe822aefb
1 zmienionych plików z 719 dodań i 399 usunięć
  1. 719 399
      src/views/index.vue

+ 719 - 399
src/views/index.vue

@@ -1,283 +1,218 @@
-<template>
-  <div class="bg-white">
+<template>
+  <div class="portal-home min-h-screen bg-[#eef3f9] text-[#17345f]">
     <Header />
 
-    <section
-      class="relative mt-15 h-[400px] w-full overflow-hidden pt-9 pb-50 md:pb-30"
-    >
-      <div
-        class="absolute inset-0 flex transition-transform duration-700 ease-in-out"
-      >
-        <div class="relative h-full min-w-full">
-          <video
-            class="absolute inset-0 h-full w-full object-cover"
-            autoplay
-            muted
-            loop
-            playsinline
-            :src="bgvideo"
-          >
-            您的浏览器不支持 HTML5 视频。
-          </video>
-        </div>
-      </div>
-
-      <div
-        class="relative z-10 mx-auto mt-5 flex h-full w-full items-center px-20 pt-10"
-      >
-        <div class="max-w-4xl">
-          <h1
-            class="slide-up-fade-in pt-2 text-2xl font-bold leading-tight text-white/90 md:text-4xl"
-          >
-            山东科瑞石油技术门户网站 · DeepOil 智慧经营平台
-          </h1>
-          <p
-            class="slide-up-fade-in mt-3 text-sm leading-relaxed text-white/90 md:text-base md:text-4"
-            style="animation-delay: 0.2s"
-          >
-            连接经营管理、生产指挥与数据智能,打造石油能源行业的一体化数字化平台,
-            为企业提供高效协同、智能决策与可靠的数字化服务。
-          </p>
-          <div
-            class="slide-up-fade-in mt-4 flex gap-3 md:mt-6"
-            style="animation-delay: 0.4s"
-          >
-            <a
-              class="cursor-pointer bg-[#0644a1] px-4 py-2 text-white hover:bg-[#0a53c1]"
-            >
-              了解平台
-            </a>
-            <a
-              class="cursor-pointer bg-white/10 px-4 py-2 text-white hover:bg-white/20"
-            >
-              联系我们
-            </a>
+    <main class="mx-auto max-w-[1500px] px-6 pb-8 pt-24">
+      <section class="hero-banner overflow-hidden rounded-[6px]">
+        <div class="hero-banner__inner">
+          <div class="hero-copy">
+            <div class="hero-script">HELLO</div>
+            <p class="hero-text">{{ heroGreeting }}</p>
+            <div class="hero-progress">
+              <span class="hero-progress__active"></span>
+              <span class="hero-progress__line"></span>
+            </div>
+          </div>
+
+          <div class="hero-visual">
+            <div class="hero-orb hero-orb--cloud">
+              <Icon icon="mdi:cloud-outline" class="text-[54px]" />
+            </div>
+            <div class="hero-orb hero-orb--shield">
+              <Icon icon="mdi:shield-search-outline" class="text-[52px]" />
+            </div>
+            <div class="hero-orb hero-orb--chart">
+              <Icon icon="mdi:chart-areaspline" class="text-[66px]" />
+            </div>
+            <div class="hero-cube hero-cube--one"></div>
+            <div class="hero-cube hero-cube--two"></div>
+            <div class="hero-ring"></div>
           </div>
         </div>
-      </div>
-    </section>
-
-    <section
-      class="mx-auto mt-6 mb-8 flex max-w-[1200px] items-center justify-center gap-3 px-2"
-    ></section>
-
-    <section
-      class="mx-auto mt-5 mb-8 flex w-[95%] flex-col justify-between gap-6 md:flex-row md:px-20"
-    >
-      <div
-        class="flex cursor-pointer items-center gap-3 border border-[#dbeafe] bg-[#eff6ff] w-full text-sm text-[#02409b] px-2 py-3 rounded-md"
-      >
-        <span
-          class="bg-[#2563eb] text-white text-[10px] font-bold inline-block px-2 py-1 rounded-md"
-          >公告</span
-        >
-        <span
-          >关于2026年度“DeepOil 数字化转型”优秀项目评选活动的通知 |
-          集团总部关于办公楼设备维保的说明</span
-        >
-
-        <span>
-          <Icon
-            icon="mdi:chevron-right"
-            class="item-arrow w-5 h-5"
-            color="#0644a1"
-          />
-        </span>
-      </div>
-    </section>
-
-    <section
-      class="mx-auto mt-5 mb-8 flex w-[95%] flex-col justify-between gap-6 md:flex-row md:px-20"
-    >
-      <div class="flex flex-2 flex-col justify-center gap-5">
-        <CardItem
-          v-for="card in cards"
-          :key="card.id"
-          :title="card.title"
-          :id="card.id"
-          :desc="card.desc"
-          :items="card.items"
-          :bg="card.bg"
-        />
-      </div>
-
-      <div class="flex-1">
-        <div
-          class="rounded-lg bg-white p-4 shadow-[0_18px_50px_rgba(26,68,143,0.08)] md:p-5"
-        >
-          <div class="flex items-center justify-between">
-            <div class="flex items-center gap-1">
-              <div
-                class="todo-panel__icon flex h-12 w-12 items-center justify-center rounded-full"
-              >
-                <Icon
-                  icon="mdi:checkbox-marked-circle-outline"
-                  class="item-arrow w-5 h-5"
-                  color="#02409b"
-                />
+      </section>
+
+      <section class="mt-3 grid gap-4 xl:grid-cols-[1.74fr_0.74fr]">
+        <div class="space-y-4">
+          <article
+            v-for="section in portalSections"
+            :key="section.code"
+            class="platform-block"
+            :style="{ minHeight: section.height }"
+          >
+            <div class="platform-block__header">
+              <div class="platform-block__title-wrap">
+                <h2 class="platform-block__title">{{ section.title }}</h2>
+                <span class="platform-block__subtitle">{{ section.subtitle }}</span>
               </div>
-              <h3 class="font-bold tracking-[0.02em] text-slate-800">
-                待办中心
-              </h3>
+              <span class="platform-block__watermark">{{ section.code }}</span>
             </div>
-            <a
-              class="text-[12px] font-medium text-[#0644a1] transition hover:text-[#1f52e0]"
-              href="javascript:;"
-            >
-              全部任务
-            </a>
-          </div>
 
-          <div class="mt-3 flex flex-col gap-6">
             <div
-              v-for="task in todoTasks"
-              :key="task.title"
-              class="todo-task-card flex items-start border border-[#f1f5f9] justify-between gap-3 rounded-lg px-7 py-4"
+              v-if="section.apps?.length"
+              class="grid grid-cols-2 gap-4 p-6 md:grid-cols-4"
             >
-              <div class="min-w-0">
-                <div
-                  class="truncate text-sm font-bold leading-[1.45] text-[#334155] md:text-md"
-                >
-                  {{ task.title }}
-                </div>
-                <div
-                  class="mt-3 text-[12px] leading-none text-[#64748b] md:text-[12px]"
-                >
-                  {{ task.meta }}
-                </div>
-              </div>
-              <span
+              <button
+                v-for="(app, appIndex) in section.apps"
+                :key="`${section.code}-${appIndex}-${app.label}`"
+                type="button"
                 :class="[
-                  'mt-1 shrink-0 rounded-sm px-1.5 py-0.5 text-[10px]',
-                  task.tagClass,
+                  'platform-app',
+                  app.active ? 'platform-app--active' : 'platform-app--ghost',
                 ]"
+                @click="handlePortalAppClick(app)"
               >
-                {{ task.tag }}
-              </span>
+                <span class="platform-app__icon">
+                  <img
+                    v-if="app.image"
+                    :src="app.image"
+                    :alt="app.label"
+                    class="h-7 w-7 object-contain"
+                  />
+                  <Icon v-else :icon="app.icon || 'mdi:dots-grid'" class="text-[24px]" />
+                </span>
+                <span>{{ app.label }}</span>
+              </button>
             </div>
-          </div>
+          </article>
+        </div>
 
-          <div class="mt-4 grid grid-cols-2 gap-5">
-            <div
-              v-for="stat in todoStats"
-              :key="stat.label"
-              :class="[
-                'rounded-lg px-6 py-4 text-center shadow-[inset_0_1px_0_rgba(255,255,255,0.65)]',
-                stat.cardClass,
-              ]"
-            >
-              <div
-                class="text-xl font-black text-blue-600"
-                :class="stat.valueClass"
-              >
-                {{ stat.value }}
-              </div>
-              <div
-                class="mt-3 text-[12px] font-semibold"
-                :class="stat.labelClass"
-              >
-                {{ stat.label }}
-              </div>
+        <aside class="space-y-4">
+          <section class="side-card side-card--notice">
+            <div class="side-card__header">
+              <div class="notice-badge">{{ noticeLabel }}</div>
+              <button type="button" class="side-card__more">
+                <Icon icon="mdi:dots-horizontal" class="text-[22px]" />
+              </button>
             </div>
-          </div>
-        </div>
 
-        <div
-          class="rounded-lg mt-4 bg-white p-4 shadow-[0_18px_50px_rgba(26,68,143,0.08)] md:p-4"
-        >
-          <div class="flex items-center justify-between">
-            <div class="flex items-center gap-1">
-              <div
-                class="todo-panel__icon flex h-12 w-12 items-center justify-center rounded-full"
+            <div class="space-y-3 p-4 pt-3">
+              <article
+                v-for="(notice, noticeIndex) in notices"
+                :key="`${notice.title}-${noticeIndex}`"
+                class="notice-item cursor-pointer"
               >
-                <Icon
-                  icon="mdi:newspaper-variant-outline"
-                  class="item-arrow w-5 h-5"
-                  color="#02409b"
-                />
-              </div>
-              <h3 class="font-bold tracking-[0.02em] text-slate-800">
-                新闻中心
-              </h3>
+                <div class="notice-item__title">{{ notice.title }}</div>
+                <div class="notice-item__desc">{{ notice.desc }}</div>
+              </article>
             </div>
-            <a
-              class="text-[12px] font-medium text-[#0644a1] transition hover:text-[#1f52e0]"
-              href="javascript:;"
-            >
-              查看更多
-            </a>
-          </div>
-
-          <div class="mt-5 flex flex-col gap-7">
-            <a
-              v-for="news in newsList"
-              :key="news.title"
-              href="javascript:;"
-              class="news-item flex items-center gap-4 rounded-2xl px-2 py-1 transition duration-200 hover:bg-[#f8fbff]"
-            >
-              <div class="news-thumb relative h-[60px] w-[80px] shrink-0">
+          </section>
+
+          <section class="side-card side-card--content" :style="{ minHeight: '190px' }">
+            <div class="panel-title">{{ todoPanelTitle }}</div>
+            <div class="space-y-3 p-4 pt-2">
+              <article
+                v-for="task in todoTasks"
+                :key="task.title"
+                class="todo-item"
+              >
+                <div class="flex min-w-0 items-start justify-between gap-3">
+                  <div class="min-w-0">
+                    <div class="truncate text-[14px] font-semibold text-[#3a5173]">
+                      {{ task.title }}
+                    </div>
+                    <div class="mt-2 text-[12px] text-[#8a9ab0]">{{ task.meta }}</div>
+                  </div>
+                  <span :class="['todo-item__tag', task.tagClass]">{{ task.tag }}</span>
+                </div>
+              </article>
+            </div>
+          </section>
+
+          <section class="side-card side-card--content" :style="{ minHeight: '180px' }">
+            <div class="panel-title">{{ newsPanelTitle }}</div>
+            <div class="space-y-3 p-4 pt-2">
+              <article
+                v-for="news in newsList"
+                :key="news.title"
+                class="news-mini cursor-pointer"
+              >
                 <img
                   :src="news.image"
                   :alt="news.title"
-                  class="h-full w-full rounded-[12px] object-cover"
+                  class="h-[54px] w-[72px] rounded-[8px] object-cover"
                 />
-              </div>
-              <div class="min-w-0 flex-1">
-                <div
-                  class="text-xs font-bold text-slate-700 line-clamp-2 leading-snug"
-                >
-                  {{ news.title }}
+                <div class="min-w-0 flex-1">
+                  <div class="line-clamp-2 text-[13px] font-semibold leading-[1.45] text-[#41597d]">
+                    {{ news.title }}
+                  </div>
+                  <div class="mt-2 text-[12px] text-[#9cadc0]">{{ news.date }}</div>
                 </div>
-                <div class="mt-4 text-[12px] text-[#98a7bb]">
-                  {{ news.date }}
-                </div>
-              </div>
-            </a>
-          </div>
-        </div>
-      </div>
-    </section>
+              </article>
+            </div>
+          </section>
 
-    <Footer />
+          <section class="side-card side-card--placeholder" :style="{ minHeight: '78px' }">
+            <div class="placeholder-panel">
+              <div class="placeholder-panel__title">{{ quickEntryTitle }}</div>
+            </div>
+          </section>
+        </aside>
+      </section>
+    </main>
   </div>
 </template>
 
 <script setup lang="ts">
-import { onMounted, onUnmounted, ref } from "vue";
+import { onMounted } from "vue";
 import * as authUtil from "@/utils/auth";
 import * as dd from "dingtalk-jsapi";
-import { getUnreadNotifyMessageCount } from "@/api/user";
 import Header from "@components/home/header.vue";
-import CardItem from "@components/home/CardItem.vue";
-import Footer from "@components/home/Footer.vue";
-import img1 from "@/assets/images/1.jpg";
-import img2 from "@/assets/images/2.jpg";
-import img3 from "@/assets/images/3.jpg";
-import caiwu from "@/assets/images/caiwu.png";
-import banner1 from "@/assets/images/banner1.jpg";
-import banner2 from "@/assets/images/model.jpeg";
-import bgvideo from "@/assets/bg.mp4";
-import bg2 from "@/assets/images/e4.png";
-import g1 from "@/assets/images/g1.png";
 import { useRouter } from "vue-router";
 import axios from "axios";
-import { useUserStore } from "@/stores/useUserStore";
 import { Icon } from "@iconify/vue";
+import { getMCSsoToken, ssoLogin, zentaoSsoLogin } from "@/api/user";
+import { useUserStore } from "@/stores/useUserStore";
+import { getAccessToken } from "@/utils/auth";
+import banner1 from "@/assets/images/banner1.jpg";
+import banner2 from "@/assets/images/model.jpeg";
+import img3 from "@/assets/images/3.jpg";
+import oaimage from "@/assets/images/oa.jpg";
+import crmimage from "@/assets/images/crm.jpg";
+import ehrimage from "@/assets/images/ehr.jpg";
+import scmimage from "@/assets/images/scm.png";
+import erpimage from "@/assets/images/fm.jpg";
+import driveimage from "@/assets/images/drive.jpg";
+import pmsimage from "@/assets/images/pms.jpeg";
+import zhonghangimage from "@/assets/images/中航.png";
+import lianyouimage from "@/assets/images/lianyou.jpeg";
+import qhseimage from "@/assets/images/qhse.jpg";
+import zuanjingimage from "@/assets/images/zuanjing.jpeg";
+import yalieimage from "@/assets/images/yalie.png";
+import zhuqiimage from "@/assets/images/zhuqi.png";
+import pmimage from "@/assets/images/pm.jpg";
+import dataimage from "@/assets/images/data.jpg";
+import thinkimage from "@/assets/images/think.jpg";
+import aiimage from "@/assets/images/ai.png";
+import agentimage from "@/assets/images/agent.jpeg";
+import videoimage from "@/assets/images/video.png";
+import youimage from "@/assets/images/youcnag.png";
+import fileagent from "@/assets/images/fileagent.png";
+import zhiduagent from "@/assets/images/zhiduagent.png";
+import jishuimage2 from "@/assets/images/jishuimage.png";
+
+type PortalApp = {
+  label: string;
+  icon?: string;
+  image?: string;
+  active?: boolean;
+};
 
-const router = useRouter();
-const userStore = useUserStore();
-
-const bgImages = [banner1, caiwu, banner2];
-const currentBgIndex = ref(0);
-let bgInterval: number | null = null;
+type PortalSection = {
+  code: string;
+  title: string;
+  subtitle: string;
+  height: string;
+  apps?: PortalApp[];
+};
 
-type Card = {
-  name: string;
+type NoticeItem = {
   title: string;
   desc: string;
-  bg: string;
-  items: Array<{ label: string; tag?: "新" | "热" }>;
-  id: string;
+};
+
+type SidePanel = {
+  title: string;
+  height: string;
 };
 
 type TodoTask = {
@@ -287,82 +222,87 @@ type TodoTask = {
   tagClass: string;
 };
 
-type TodoStat = {
-  value: number;
-  label: string;
-  cardClass: string;
-  valueClass: string;
-  labelClass: string;
-};
-
 type NewsItem = {
   title: string;
   date: string;
   image: string;
 };
 
-const cardBgs = [bg2, g1, bg2];
+const router = useRouter();
+const userStore = useUserStore();
+const heroGreeting = "早上好,保持热爱,奔赴目标!";
+const noticeLabel = "公告";
+const todoPanelTitle = "待办中心";
+const newsPanelTitle = "新闻中心";
+const quickEntryTitle = "快捷入口";
 
-const cards: Card[] = [
+const portalSections: PortalSection[] = [
   {
-    name: "device",
-    title: "数字运营平台",
-    desc: "集成财务、研发、客户、人力等关键业务数据,为管理者提供全局态势感知和战略决策支撑。",
-    id: "management",
-    bg: img1,
-    items: [
-      { label: "OA办公" },
-      { label: "客户管理(CRM)" },
-      { label: "人力资源(EHR)" },
-      { label: "供应商管理(SRM)" },
-      { label: "财务管理(FM)" },
-      { label: "经营驾驶舱(MC)", tag: "新" },
-      { label: "项目管理(PM)" },
-      { label: "技术研发管理" },
-      { label: "组织资产管理" },
-      { label: "风控合规管理" },
-      { label: "战略解码与执行" },
-      { label: "研发需求管理" },
+    code: "数",
+    title: "数字化运营平台",
+    subtitle: "高效协同 · 战略洞察",
+    height: "220px",
+    apps: [
+      {
+        label: "OA办公",
+        image: oaimage,
+        active: true,
+      },
+      { label: "客户管理(CRM)", image: crmimage },
+      { label: "人力资源(EHR)", image: ehrimage },
+      { label: "供应商管理(SRM)", image: scmimage },
+      { label: "财务管理(FM)", image: erpimage },
+      { label: "经营驾驶舱(MC)", image: driveimage },
+      { label: "项目管理(PM)", image: pmimage },
+      { label: "研发需求管理", image: jishuimage2 },
     ],
   },
   {
-    name: "scene",
+    code: "智",
     title: "智慧指挥平台",
-    desc: "深入工业场景,为中小企业数字化升级赋能。",
-    id: "command",
-    bg: img2,
-    items: [
-      { label: "设备管理(PMS)" },
-      { label: "中航北斗" },
-      { label: "质量安全管理(QHSE)" },
-      { label: "智慧炼油" },
-      { label: "智慧注气" },
-      { label: "智能钻井" },
-      { label: "智慧压裂" },
-      { label: "数字油藏" },
-      { label: "视频中心(VCS)" },
+    subtitle: "高效协同 · 战略洞察",
+    height: "210px",
+    apps: [
+      { label: "设备管理(PMS)", image: pmsimage, active: true },
+      { label: "中航北斗", image: zhonghangimage },
+      { label: "质量安全管理(QHSE)", image: qhseimage },
+      { label: "智慧炼油", image: lianyouimage },
+      { label: "智慧注气", image: zhuqiimage },
+      { label: "智能钻井", image: zuanjingimage },
+      { label: "智慧压裂", image: yalieimage },
+      { label: "视频中心(VCS)", image: videoimage },
     ],
   },
   {
-    name: "factory",
+    code: "CB",
     title: "Chat BI平台",
-    desc: "工厂上云,高效协同,提升生产效率和产品质量。",
-    id: "chatbi",
-    bg: img3,
-    items: [
-      { label: "全局数据治理(数据中台)", tag: "热" },
-      { label: "智能决策" },
-      { label: "行业AI大模型", tag: "新" },
-      { label: "AI智能体(智能交互)", tag: "新" },
-      { label: "工艺文件智能体" },
-      { label: "集团制度智能体" },
+    subtitle: "高效协同 · 战略洞察",
+    height: "160px",
+    apps: [
+      { label: "全局数据治理(数据中台)", image: dataimage, active: true },
+      { label: "智能决策", image: thinkimage },
+      { label: "行业AI大模型", image: aiimage },
+      { label: "AI智能体(智能交互)", image: agentimage },
+      { label: "工艺文件智能体", image: fileagent },
+      { label: "集团制度智能体", image: zhiduagent },
     ],
   },
 ];
 
+const notices: NoticeItem[] = [
+  {
+    title: "集团总部关于办公楼设备维保的说明",
+    desc: "关于 2026 年度“DeepOil 数字化转型”优秀项目评选活动的通知",
+  },
+  {
+    title: "集团总部关于办公楼设备维保的说明",
+    desc: "关于 2026 年度“DeepOil 数字化转型”优秀项目评选活动的通知",
+  },
+];
+
 const todoTasks: TodoTask[] = [
   {
-    title: "项目立项审批 - QHSE升级",
+    title: "项目立项审批 - QHSE 升级",
     meta: "发起人:李智慧 · 2小时前",
     tag: "紧急",
     tagClass: "bg-[#ffe1e3] text-[#ff5d66]",
@@ -381,23 +321,6 @@ const todoTasks: TodoTask[] = [
   },
 ];
 
-const todoStats: TodoStat[] = [
-  {
-    value: 8,
-    label: "待办流程",
-    cardClass: "bg-[#dfeafc]",
-    valueClass: "text-[#2867ff]",
-    labelClass: "text-[#204cbe]",
-  },
-  {
-    value: 12,
-    label: "本周已办",
-    cardClass: "bg-[#e5f7ea]",
-    valueClass: "text-[#0cb34f]",
-    labelClass: "text-[#04753a]",
-  },
-];
-
 const newsList: NewsItem[] = [
   {
     title: "科瑞石油成功交付首套自动化钻机",
@@ -416,6 +339,102 @@ const newsList: NewsItem[] = [
   },
 ];
 
+const sidePanels: SidePanel[] = [];
+
+const protectedOpen = (url: string) => {
+  if (userStore.getUser.username && getAccessToken()) {
+    window.open(url, "_blank");
+  } else {
+    router.push({ path: "/login" });
+  }
+};
+
+const handlePortalAppClick = async (app: PortalApp) => {
+  if (!app.label) return;
+
+  if (app.label === "OA办公") {
+    if (userStore.getUser.username && getAccessToken()) {
+      const res = await ssoLogin({ username: userStore.getUser.username });
+      if (res) {
+        window.open(
+          `https://yfoa.keruioil.com/wui/index.html?ssoToken=${res}#/main`,
+          "_blank",
+        );
+      }
+    } else {
+      router.push({ path: "/login" });
+    }
+  }
+
+  if (app.label === "客户管理(CRM)") {
+    protectedOpen(
+      `https://crm-tencent.xiaoshouyi.com/global/sso/callback/00APEB9EEEA9B2E338B686B7ECFA8585808C.action?token=${getAccessToken()}`,
+    );
+  }
+
+  if (app.label === "设备管理(PMS)") {
+    protectedOpen(
+      `${import.meta.env.VITE_PMS_URL}/portalLogin?username=${userStore.getUser.username}`,
+    );
+  }
+
+  if (app.label === "中航北斗") {
+    protectedOpen("https://zhbdgps.cn");
+  }
+
+  if (app.label === "智慧炼油") {
+    protectedOpen(
+      `${import.meta.env.VITE_PMS_URL}/portalLogin?username=${userStore.getUser.username}&source=zhly`,
+    );
+  }
+
+  if (app.label === "智慧注气") {
+    protectedOpen(
+      `${import.meta.env.VITE_PMS_URL}/portalLogin?username=${userStore.getUser.username}&source=znzq`,
+    );
+  }
+
+  if (app.label === "视频中心(VCS)") {
+    protectedOpen(
+      `${import.meta.env.VITE_PMS_URL}/portalLogin?username=${userStore.getUser.username}&source=spzx`,
+    );
+  }
+
+  if (app.label === "质量安全管理(QHSE)") {
+    protectedOpen(
+      `${import.meta.env.VITE_PMS_URL}/portalLogin?username=${userStore.getUser.username}&source=qhse`,
+    );
+  }
+
+  if (app.label === "经营驾驶舱(MC)") {
+    if (userStore.getUser.username && getAccessToken()) {
+      const res = await getMCSsoToken();
+      if (res) {
+        window.open(
+          `https://report.deepoil.cc/webroot/decision/v10/entry/access/9fb42908-894a-4373-a6be-ce046a42851d?preview=true&page_number=1&ssoToken=${res}`,
+          "_blank",
+        );
+      }
+    } else {
+      router.push({ path: "/login" });
+    }
+  }
+
+  if (app.label === "研发需求管理") {
+    if (userStore.getUser.username && getAccessToken()) {
+      const res = await zentaoSsoLogin({ username: userStore.getUser.username });
+      if (res) {
+        window.open(
+          `http://project.deepoil.cc/zentao/api.php?m=user&f=apilogin&account=${res.jobNumber}&code=${res.code}&time=${res.timestamp}&token=${res.token}`,
+          "_blank",
+        );
+      }
+    } else {
+      router.push({ path: "/login" });
+    }
+  }
+};
+
 async function loginWithDingTalk() {
   const ddCorpId = import.meta.env.VITE_DD_CORPID;
   const ddClientId = import.meta.env.VITE_DD_CLIENTID;
@@ -444,7 +463,6 @@ async function loginWithDingTalk() {
           },
         )
         .then((response) => {
-          console.log("钉钉免登返回结果", response.data.data);
           authUtil.setToken(response.data.data);
           router.push({
             path: "/login",
@@ -454,139 +472,441 @@ async function loginWithDingTalk() {
     fail: (err: any) => {
       console.log("err :>> ", err);
     },
-    complete: () => {
-      console.log("11 :>> ", 11);
-    },
   });
 }
 
 function dingTalkAutoLogin() {
   const ua = window.navigator.userAgent.toLowerCase();
 
-  console.log("ua>>>>>>>>>>>>>>>>>>>>>>> ", ua);
-
   if (ua.includes("dingtalk") || ua.includes("dingtalkwork")) {
     loginWithDingTalk();
   }
 }
 
-const unreadCount = ref(0);
-
-const getUnreadCount = async () => {
-  getUnreadNotifyMessageCount().then((data) => {
-    unreadCount.value = data;
-  });
-};
-
 onMounted(() => {
   dingTalkAutoLogin();
-
-  void bgImages;
-  void currentBgIndex;
-  void cardBgs;
-  void unreadCount;
-  void getUnreadCount;
-});
-
-onUnmounted(() => {
-  if (bgInterval) {
-    clearInterval(bgInterval);
-  }
 });
 </script>
 
 <style scoped>
-::-webkit-scrollbar {
-  width: 5px;
+.portal-home {
+  --portal-blue: #2f6fdb;
+  --portal-blue-dark: #1b57bc;
+  --portal-blue-soft: #d7e7ff;
+  --portal-panel: #deebfb;
+  --portal-panel-soft: #edf5ff;
+  --portal-line: #a8c4f2;
 }
 
-::-webkit-scrollbar-thumb {
-  border-radius: 5px;
+.hero-banner {
+  position: relative;
+  min-height: 220px;
+  background:
+    linear-gradient(90deg, rgba(255, 255, 255, 0.96) 0%, rgba(241, 247, 255, 0.92) 36%, rgba(223, 237, 255, 0.95) 100%);
+  box-shadow: inset 0 0 0 1px rgba(190, 212, 243, 0.5);
 }
 
-::-webkit-scrollbar-track {
-  background-color: transparent;
+.hero-banner::before {
+  content: "";
+  position: absolute;
+  inset: 0;
+  background:
+    linear-gradient(140deg, rgba(206, 223, 247, 0.25) 0%, transparent 28%),
+    radial-gradient(circle at 74% 24%, rgba(83, 146, 255, 0.14), transparent 18%),
+    radial-gradient(circle at 88% 16%, rgba(255, 255, 255, 0.94), transparent 14%);
+  pointer-events: none;
 }
 
-::-webkit-scrollbar-thumb {
-  background-color: #0a5f73;
+.hero-banner__inner {
+  position: relative;
+  z-index: 1;
+  display: grid;
+  min-height: 220px;
+  grid-template-columns: minmax(260px, 1fr) minmax(360px, 1.3fr);
+  align-items: center;
+  gap: 24px;
+  padding: 22px 36px 18px 58px;
 }
 
-::-webkit-scrollbar-thumb:hover {
-  background-color: #30459c;
+.hero-copy {
+  padding-top: 10px;
 }
 
-.slide-up-fade-in {
-  opacity: 0;
-  transform: translateY(20px);
-  animation: slideUpFadeIn 0.8s forwards ease-out;
+.hero-script {
+  color: #0c4eb5;
+  font-size: 68px;
+  font-style: italic;
+  font-weight: 500;
+  letter-spacing: 0.04em;
+  line-height: 1;
+  font-family: "Comic Sans MS", "Segoe Script", cursive;
 }
 
-@keyframes slideUpFadeIn {
-  to {
-    opacity: 1;
-    transform: translateY(0);
-  }
+.hero-text {
+  margin-top: 18px;
+  color: #5f6f83;
+  font-size: 24px;
+  letter-spacing: 0.1em;
 }
 
-.todo-panel {
-  background:
-    radial-gradient(
-      circle at top left,
-      rgba(47, 103, 255, 0.06),
-      transparent 28%
-    ),
-    linear-gradient(180deg, #ffffff 0%, #fbfdff 100%);
+.hero-progress {
+  margin-top: 48px;
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.hero-progress__active {
+  height: 4px;
+  width: 56px;
+  border-radius: 999px;
+  background: #1f67d1;
+}
+
+.hero-progress__line {
+  height: 3px;
+  width: 64px;
+  border-radius: 999px;
+  background: rgba(49, 113, 207, 0.18);
 }
 
-.todo-panel__icon-check {
+.hero-visual {
   position: relative;
-  width: 22px;
-  height: 22px;
-  border: 3px solid #2f67ff;
-  border-radius: 9999px;
+  min-height: 180px;
+}
+
+.hero-orb,
+.hero-cube,
+.hero-ring {
+  position: absolute;
+}
+
+.hero-orb {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 1px solid rgba(175, 205, 250, 0.88);
+  border-radius: 28px;
+  background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(226, 239, 255, 0.95));
+  color: #65a4ff;
+  box-shadow:
+    0 18px 35px rgba(65, 122, 206, 0.14),
+    inset 0 1px 0 rgba(255, 255, 255, 0.88);
 }
 
-.todo-panel__icon-check::after {
+.hero-orb::after {
   content: "";
   position: absolute;
-  left: 6px;
-  top: 2px;
-  width: 6px;
-  height: 11px;
-  border-right: 3px solid #2f67ff;
-  border-bottom: 3px solid #2f67ff;
-  transform: rotate(45deg);
+  inset: auto 16px 10px;
+  height: 10px;
+  border-radius: 999px;
+  background: rgba(93, 154, 255, 0.12);
+  filter: blur(8px);
 }
 
-.todo-task-card {
-  background: #f8fafc;
-  box-shadow: 0 10px 24px rgba(30, 81, 171, 0.04);
+.hero-orb--cloud {
+  left: 10%;
+  top: 28px;
+  height: 106px;
+  width: 126px;
+  transform: rotate(-10deg);
 }
 
-.news-item {
-  text-decoration: none;
+.hero-orb--shield {
+  left: 46%;
+  top: 64px;
+  height: 118px;
+  width: 120px;
+  transform: rotate(8deg);
 }
 
-.news-thumb__overlay {
-  position: absolute;
-  inset: 0;
+.hero-orb--chart {
+  right: 4%;
+  top: 0;
+  height: 138px;
+  width: 150px;
+  transform: rotate(6deg);
+}
+
+.hero-cube {
+  border: 1px solid rgba(171, 199, 243, 0.8);
+  background: linear-gradient(180deg, rgba(255, 255, 255, 0.94), rgba(226, 239, 255, 0.9));
+  box-shadow: 0 18px 35px rgba(65, 122, 206, 0.1);
+}
+
+.hero-cube--one {
+  left: 26%;
+  top: -2px;
+  height: 46px;
+  width: 46px;
+  transform: rotate(36deg);
+}
+
+.hero-cube--two {
+  left: 33%;
+  top: 18px;
+  height: 34px;
+  width: 34px;
+  transform: rotate(32deg);
+}
+
+.hero-ring {
+  left: 13%;
+  top: 108px;
+  height: 42px;
+  width: 128px;
+  border-radius: 999px;
+  border: 10px solid rgba(83, 146, 255, 0.1);
+}
+
+.platform-block {
+  overflow: hidden;
+  background: linear-gradient(180deg, #dce9fb 0%, #d9e8fb 100%);
+  box-shadow: inset 0 0 0 1px rgba(184, 207, 239, 0.85);
+}
+
+.platform-block__header {
   display: flex;
-  flex-direction: column;
   align-items: center;
-  justify-content: center;
-  gap: 4px;
-  border-radius: 18px;
-  background: linear-gradient(
-    180deg,
-    rgba(70, 87, 109, 0.34) 0%,
-    rgba(70, 87, 109, 0.56) 100%
-  );
-  color: #ffffff;
+  justify-content: space-between;
+  min-height: 44px;
+  padding: 0 24px 0 34px;
+  background: linear-gradient(90deg, #316fd8 0%, #82aef0 100%);
+}
+
+.platform-block__title-wrap {
+  display: flex;
+  align-items: baseline;
+  gap: 28px;
+}
+
+.platform-block__title {
+  color: #fff;
   font-size: 18px;
   font-weight: 700;
+  letter-spacing: 0.03em;
+}
+
+.platform-block__subtitle {
+  color: rgba(255, 255, 255, 0.95);
+  font-size: 13px;
+  font-weight: 600;
+}
+
+.platform-block__watermark {
+  color: rgba(255, 255, 255, 0.4);
+  font-size: 44px;
+  font-weight: 800;
   line-height: 1;
-  text-transform: lowercase;
-  letter-spacing: 0.02em;
+  letter-spacing: 0.04em;
+}
+
+.platform-app {
+  display: flex;
+  min-height: 34px;
+  align-items: center;
+  justify-content: flex-start;
+  gap: 12px;
+  border-radius: 8px;
+  padding: 0 18px;
+  font-size: 14px;
+  font-weight: 600;
+  transition:
+    transform 0.2s ease,
+    box-shadow 0.2s ease,
+    background 0.2s ease;
+}
+
+.platform-app:hover {
+  transform: translateY(-1px);
+}
+
+.platform-app--active {
+  background: linear-gradient(180deg, #3979e0 0%, #326fd8 100%);
+  color: #fff;
+  box-shadow: 0 8px 18px rgba(42, 103, 198, 0.28);
+}
+
+.platform-app--ghost {
+  background: rgba(255, 255, 255, 0.66);
+  color: #53719b;
+}
+
+.platform-app__icon {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  color: currentColor;
+}
+
+.side-card {
+  overflow: hidden;
+  background: rgba(245, 250, 255, 0.95);
+  box-shadow: inset 0 0 0 1px rgba(226, 237, 249, 0.95);
+}
+
+.side-card--content {
+  padding-top: 10px;
+}
+
+.side-card__header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  min-height: 32px;
+  padding-right: 10px;
+  background: linear-gradient(90deg, rgba(236, 244, 255, 0.95), rgba(226, 239, 255, 0.92));
+  border-bottom: 1px solid rgba(195, 214, 239, 0.9);
+}
+
+.notice-badge {
+  position: relative;
+  display: inline-flex;
+  align-items: center;
+  height: 32px;
+  min-width: 64px;
+  padding: 0 18px 0 16px;
+  background: linear-gradient(180deg, #1661c9 0%, #0f53b4 100%);
+  color: #fff;
+  font-size: 14px;
+  font-weight: 700;
+}
+
+.notice-badge::after {
+  content: "";
+  position: absolute;
+  top: 0;
+  right: -15px;
+  border-top: 16px solid transparent;
+  border-bottom: 16px solid transparent;
+  border-left: 15px solid #0f53b4;
+}
+
+.side-card__more {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  border: 0;
+  background: transparent;
+  color: #0f53b4;
+  cursor: pointer;
+}
+
+.notice-item {
+  background: #fff;
+  padding: 12px 14px;
+  box-shadow: inset 0 0 0 1px rgba(230, 237, 246, 0.95);
+}
+
+.notice-item__title,
+.notice-item__desc {
+  color: #4f5f76;
+  font-size: 13px;
+  line-height: 1.5;
+}
+
+.panel-title {
+  padding: 0 16px;
+  color: #2f4d79;
+  font-size: 15px;
+  font-weight: 700;
+}
+
+.todo-item {
+  background: rgba(255, 255, 255, 0.88);
+  padding: 12px 14px;
+  box-shadow: inset 0 0 0 1px rgba(228, 236, 246, 0.95);
+}
+
+.todo-item__tag {
+  display: inline-flex;
+  align-items: center;
+  border-radius: 999px;
+  padding: 2px 8px;
+  font-size: 11px;
+  font-weight: 600;
+  white-space: nowrap;
+}
+
+.news-mini {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  background: rgba(255, 255, 255, 0.88);
+  padding: 10px 12px;
+  box-shadow: inset 0 0 0 1px rgba(228, 236, 246, 0.95);
+}
+
+.placeholder-panel {
+  display: flex;
+  height: 100%;
+  align-items: center;
+  justify-content: center;
+  color: #aec5e5;
+  font-size: 16px;
+  font-weight: 600;
+  letter-spacing: 0.08em;
+}
+
+.placeholder-panel__title {
+  opacity: 0.55;
+}
+
+@media (max-width: 1279px) {
+  .hero-banner__inner {
+    grid-template-columns: 1fr;
+    padding: 28px 28px 20px;
+  }
+
+  .hero-script {
+    font-size: 52px;
+  }
+
+  .hero-text {
+    font-size: 18px;
+  }
+
+  .hero-progress {
+    margin-top: 28px;
+  }
+
+  .hero-visual {
+    min-height: 220px;
+  }
+}
+
+@media (max-width: 767px) {
+  .platform-block__header {
+    padding: 0 16px 0 18px;
+  }
+
+  .platform-block__title-wrap {
+    gap: 12px;
+    flex-wrap: wrap;
+  }
+
+  .platform-block__title {
+    font-size: 16px;
+  }
+
+  .platform-block__subtitle {
+    font-size: 12px;
+  }
+
+  .platform-block__watermark {
+    font-size: 34px;
+  }
+
+  .hero-banner__inner {
+    padding: 24px 18px 20px;
+  }
+
+  .hero-script {
+    font-size: 44px;
+  }
+
+  .hero-progress {
+    margin-top: 22px;
+  }
 }
 </style>