yanghao 2 тижнів тому
батько
коміт
acabf4311a

BIN
src/assets/images/cai.png


BIN
src/assets/images/city.png


BIN
src/assets/images/driveall.png


BIN
src/assets/images/gong.png


BIN
src/assets/images/jingying.png


BIN
src/assets/images/shengc.png


+ 112 - 19
src/views/drive/index.vue

@@ -15,20 +15,24 @@
       </section>
 
       <section class="drive-tabs px-10">
-        <button type="button" class="drive-tab drive-tab--active">
-          全部驾驶舱
+        <button
+          v-for="tab in tabs"
+          :key="tab.value"
+          type="button"
+          class="drive-tab"
+          :class="{ 'drive-tab--active': activeTab === tab.value }"
+          @click="activeTab = tab.value"
+        >
+          <div class="flex items-center gap-2">
+            <img :src="tab.icon" alt="tab icon" class="w-6 h-6" />
+            {{ tab.label }}
+          </div>
         </button>
-        <button type="button" class="drive-tab">经营管理</button>
-        <button type="button" class="drive-tab">生产运营</button>
-        <button type="button" class="drive-tab">财务管理</button>
-        <button type="button" class="drive-tab">供应链管理</button>
-        <button type="button" class="drive-tab">市场营销</button>
-        <button type="button" class="drive-tab">QHSE</button>
       </section>
 
       <section class="drive-grid md:px-20">
         <button
-          v-for="card in driveCards"
+          v-for="card in filteredCards"
           :key="card.title"
           type="button"
           class="drive-card overflow-hidden"
@@ -38,6 +42,13 @@
           }"
           @click="openDrive(card)"
         ></button>
+
+        <div
+          v-if="filteredCards.length === 0"
+          class="text-center py-10 text-gray-400 col-span-2"
+        >
+          暂无相关驾驶舱
+        </div>
       </section>
     </main>
 
@@ -50,7 +61,7 @@
 <script setup lang="ts">
 import Header from "@components/home/header.vue";
 import Footer from "@components/home/Footer.vue";
-import { Icon } from "@iconify/vue";
+import { ref, computed } from "vue";
 
 import { getMCSsoToken } from "@/api/user";
 import { useUserStore } from "@/stores/useUserStore";
@@ -70,8 +81,25 @@ import driveMobile4 from "@/assets/images/供应链驾驶舱.png"; // 供应链
 import driveMobile5 from "@/assets/images/市场驾驶舱.png"; // 市场驾驶舱移动端背景图
 import driveMobile6 from "@/assets/images/QHSE驾驶舱.png"; // QHSE驾驶舱移动端背景图
 
+import all from "@/assets/images/driveall.png";
+import jingying from "@/assets/images/jingying.png";
+import shengc from "@/assets/images/shengc.png";
+import cai from "@/assets/images/cai.png";
+import gong from "@/assets/images/gong.png";
+import city from "@/assets/images/city.png";
+
 const userStore = useUserStore();
 
+const tabs = [
+  { label: "全部驾驶舱", value: "all", icon: all },
+  { label: "经营管理", value: "management", icon: jingying },
+  { label: "生产运营", value: "production", icon: shengc },
+  { label: "财务管理", value: "finance", icon: cai },
+  { label: "供应链管理", value: "supply", icon: gong },
+  { label: "市场营销", value: "marketing", icon: city },
+  { label: "QHSE", value: "qhse", icon: gong },
+];
+const activeTab = ref("all");
 type DriveCard = {
   title: string;
   description: string;
@@ -79,6 +107,7 @@ type DriveCard = {
   bgColor: string;
   pcBg: string;
   mobileBg: string;
+  category: string; // 新增分类字段
 };
 
 const driveCards: DriveCard[] = [
@@ -89,6 +118,7 @@ const driveCards: DriveCard[] = [
     bgColor: "#3876e0",
     pcBg: drivePc1,
     mobileBg: driveMobile1,
+    category: "management", // 对应经营管理
   },
   {
     title: "生产驾驶舱",
@@ -97,6 +127,7 @@ const driveCards: DriveCard[] = [
     bgColor: "#0f766e",
     pcBg: drivePc2,
     mobileBg: driveMobile2,
+    category: "production", // 对应生产运营
   },
   {
     title: "财务驾驶舱",
@@ -105,6 +136,7 @@ const driveCards: DriveCard[] = [
     bgColor: "#ca8a04",
     pcBg: drivePc3,
     mobileBg: driveMobile3,
+    category: "finance", // 对应财务管理
   },
   {
     title: "供应链驾驶舱",
@@ -113,6 +145,7 @@ const driveCards: DriveCard[] = [
     bgColor: "#7c3aed",
     pcBg: drivePc4,
     mobileBg: driveMobile4,
+    category: "supply", // 对应供应链管理
   },
   {
     title: "市场驾驶舱",
@@ -121,6 +154,7 @@ const driveCards: DriveCard[] = [
     bgColor: "#16a34a",
     pcBg: drivePc5,
     mobileBg: driveMobile5,
+    category: "marketing", // 对应市场营销
   },
   {
     title: "QHSE驾驶舱",
@@ -129,9 +163,17 @@ const driveCards: DriveCard[] = [
     bgColor: "#dc2626",
     pcBg: drivePc6,
     mobileBg: driveMobile6,
+    category: "qhse", // 对应 QHSE
   },
 ];
 
+const filteredCards = computed(() => {
+  if (activeTab.value === "all") {
+    return driveCards;
+  }
+  return driveCards.filter((card) => card.category === activeTab.value);
+});
+
 const openDrive = async (option: DriveCard) => {
   if (userStore.getUser.username && getAccessToken()) {
     const res = await getMCSsoToken();
@@ -240,7 +282,7 @@ const openDrive = async (option: DriveCard) => {
   grid-template-columns: repeat(7, minmax(0, 1fr));
   gap: 0;
   margin: 0 auto;
-  padding: 12px 18px;
+  padding: 0px 0px;
   width: 90%;
   border: 1px solid rgba(79, 110, 208, 0.16);
   border-radius: 10px;
@@ -257,6 +299,9 @@ const openDrive = async (option: DriveCard) => {
   font-size: 18px;
   font-weight: 700;
   cursor: pointer;
+  display: flex;
+  justify-content: center;
+  align-items: center;
 }
 
 .drive-tab:last-child {
@@ -264,21 +309,41 @@ const openDrive = async (option: DriveCard) => {
 }
 
 .drive-tab--active {
-  color: #fff;
+  color: #fff !important;
+
+  background: linear-gradient(
+    360deg,
+    #003be0 0%,
+    rgba(10, 65, 227, 0.6) 10%,
+    #001c71 40%,
+    #000c33 80%
+  ) !important;
+
+  padding-bottom: 22px;
+  padding-top: 22px;
+  border-radius: 0;
+
   position: relative;
 }
 
-.drive-tab--active::after {
+.drive-tab--active::before {
   content: "";
   position: absolute;
   left: 50%;
-  bottom: -12px;
-  width: 72px;
-  height: 4px;
-  border-radius: 999px;
+  bottom: -2px;
+  width: 100%;
+  height: 2px;
   transform: translateX(-50%);
-  background: linear-gradient(90deg, #8f65ff 0%, #4d82ff 100%);
-  box-shadow: 0 0 18px rgba(97, 111, 255, 0.85);
+  border-radius: 999px;
+  background: linear-gradient(
+    to right,
+    #5887f8 0%,
+    #69b5f8 30%,
+    #fff 50%,
+    #69b5f8 70%,
+    #5887f8 100%
+  );
+  box-shadow: 0 0 12px rgba(112, 120, 255, 0.95);
 }
 
 .drive-grid {
@@ -409,4 +474,32 @@ const openDrive = async (option: DriveCard) => {
     object-position: 68% center;
   }
 }
+
+@media (max-width: 768px) {
+  .drive-tabs {
+    display: flex; /* 改为 flex 布局 */
+    overflow-x: auto; /* 允许横向滚动 */
+    white-space: nowrap; /* 防止文字换行 */
+    padding: 12px;
+    gap: 10px; /* 增加间距 */
+    /* 移除原有的 grid 相关属性 */
+    grid-template-columns: unset;
+    width: 100%;
+  }
+
+  .drive-tab {
+    flex-shrink: 0; /* 防止按钮被压缩 */
+    border-right: none; /* 移除右侧边框,改用间距或底部指示器 */
+    padding: 0 16px; /* 增加左右内边距 */
+  }
+}
+
+/* 优化横向滚动条 */
+.drive-tabs::-webkit-scrollbar {
+  height: 1px;
+}
+.drive-tabs::-webkit-scrollbar-thumb {
+  background-color: var(--color-border-default);
+  border-radius: 2px;
+}
 </style>

+ 41 - 13
src/views/index.vue

@@ -92,9 +92,10 @@
             <!-- <div class="nav-title">统一入口,快速直达</div> -->
 
             <!-- 中间搜索框 -->
-            <div class="search-container">
+            <div class="search-container hidden! md:flex!">
               <Icon icon="mdi:magnify" class="search-icon" />
               <input
+                v-model="searchKeyword"
                 type="text"
                 placeholder="搜索应用、流程、数据..."
                 class="search-input"
@@ -147,7 +148,7 @@
             </div>
           </div>
           <article
-            v-for="section in portalSections"
+            v-for="section in filteredSections"
             :key="section.code"
             class="platform-block rounded-sm md:flex"
             :style="{ minHeight: section.height }"
@@ -416,7 +417,7 @@
               <!-- <div class="text-sm">需要帮助?</div> -->
               <div class="text-[10px]">遇到系统操作问题,需要帮助</div>
               <div
-                class="bg-white text-sm text-center text-[#004098] py-1 px-2 rounded-full mt-2 w-[30%] cursor-pointer"
+                class="bg-[#79ebfa] text-sm text-center text-[#004098] py-1 px-2 rounded-full mt-2 w-[30%] cursor-pointer"
                 @click="openConsult"
               >
                 立即咨询
@@ -622,13 +623,39 @@ let boldLabes = ref([
   "供应商管理(SRM)",
 ]);
 
-const getGreeting = () => {
-  const hour = new Date().getHours();
-  if (hour < 12) return "早上好";
-  if (hour < 18) return "下午好";
-  return "晚上好";
+const searchKeyword = ref("");
+// 2. 实现搜索处理函数
+const handleSearch = () => {
+  if (!searchKeyword.value.trim()) return;
+  console.log("执行搜索:", searchKeyword.value);
+  // 如果需要跳转到独立搜索页,可以在这里添加 router.push
 };
 
+const filteredSections = computed(() => {
+  const keyword = searchKeyword.value.trim().toLowerCase();
+
+  // 如果没有关键词,返回原始数据
+  if (!keyword) {
+    return portalSections;
+  }
+
+  // 过滤逻辑:遍历每个板块,保留匹配的应用
+  return portalSections
+    .map((section) => {
+      if (!section.apps) return { ...section, apps: [] };
+
+      const matchedApps = section.apps.filter((app) =>
+        app.label.toLowerCase().includes(keyword),
+      );
+
+      return {
+        ...section,
+        apps: matchedApps,
+      };
+    })
+    .filter((section) => section.apps && section.apps.length > 0); // 移除没有匹配应用的空板块
+});
+
 // 添加轮播数据
 const slides = ref([
   {
@@ -945,12 +972,12 @@ async function dingTalkAutoLogin() {
 
 const getTagClass = (tag: string) => {
   return tag === "0"
-    ? "bg-[#dbe8ff] text-[#3f74ff]"
+    ? "bg-[#2e1e6d] text-[#3f74ff]"
     : tag === "1"
-      ? "bg-[#ffe1e3] text-[#ff5d66]"
+      ? "bg-[#2e1e6d] text-[#ff5d66]"
       : tag === "2"
-        ? "bg-[#dfe8f3] text-[#6f7f94]"
-        : "bg-[#dbe8ff] text-[#3f74ff]";
+        ? "bg-[#2e1e6d] text-[#6f7f94]"
+        : "bg-[#2e1e6d] text-[#3f74ff]";
 };
 
 const getTagName = (tag: string) => {
@@ -1555,8 +1582,9 @@ onUnmounted(() => {
   align-items: center;
   border-radius: 999px;
   padding: 2px 8px;
+
   font-size: 11px;
-  font-weight: 600;
+
   white-space: nowrap;
 }