index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. <template>
  2. <div class="drive-page">
  3. <Header />
  4. <main class="drive-main">
  5. <section class="drive-hero">
  6. <div class="drive-hero__copy pl-5">
  7. <p class="drive-hero__eyebrow">DASHBOARD PORTAL</p>
  8. <p class="drive-hero__title">驾驶舱门户</p>
  9. <p class="drive-hero__desc">选择一个驾驶舱,快速进入对应业务看板。</p>
  10. </div>
  11. <div class="drive-hero__visual">
  12. <el-image :src="banner" class="drive-hero__image" />
  13. </div>
  14. </section>
  15. <section class="drive-tabs px-10">
  16. <button
  17. v-for="tab in tabs"
  18. :key="tab.value"
  19. type="button"
  20. class="drive-tab"
  21. :class="{ 'drive-tab--active': activeTab === tab.value }"
  22. @click="activeTab = tab.value"
  23. >
  24. <div class="flex items-center gap-2">
  25. <img :src="tab.icon" alt="tab icon" class="w-6 h-6" />
  26. {{ tab.label }}
  27. </div>
  28. </button>
  29. </section>
  30. <section class="drive-grid md:px-20">
  31. <button
  32. v-for="card in filteredCards"
  33. :key="card.title"
  34. type="button"
  35. class="drive-card overflow-hidden"
  36. :style="{
  37. '--bg-image': `url(${card.pcBg})`,
  38. '--mobile-bg-image': `url(${card.mobileBg})`,
  39. }"
  40. @click="openDrive(card)"
  41. ></button>
  42. <div
  43. v-if="filteredCards.length === 0"
  44. class="text-center py-10 text-gray-400 col-span-2"
  45. >
  46. 暂无相关驾驶舱
  47. </div>
  48. </section>
  49. </main>
  50. <div class="mt-[500px] md:mt-[300px]">
  51. <Footer />
  52. </div>
  53. </div>
  54. </template>
  55. <script setup lang="ts">
  56. import Header from "@components/home/header.vue";
  57. import Footer from "@components/home/Footer.vue";
  58. import { ref, computed } from "vue";
  59. import { getMCSsoToken } from "@/api/user";
  60. import { useUserStore } from "@/stores/useUserStore";
  61. import { getAccessToken } from "@/utils/auth";
  62. import banner from "@/assets/images/drivebannere.png";
  63. import drivePc1 from "@/assets/images/dr1.png"; // 经营驾驶舱pc端背景图
  64. import drivePc2 from "@/assets/images/生产pc.png"; // 生产驾驶舱pc端背景图
  65. import drivePc3 from "@/assets/images/财务pc.png"; // 财务驾驶舱pc端背景图
  66. import drivePc4 from "@/assets/images/供应链pc.png"; // 供应链驾驶舱pc端背景图
  67. import drivePc5 from "@/assets/images/市场pc.png"; // 市场驾驶舱pc端背景图
  68. import drivePc6 from "@/assets/images/qhsepc.png"; // QHSE驾驶舱pc端背景图
  69. import driveMobile1 from "@/assets/images/mobile.png"; // 经营驾驶舱移动端背景图
  70. import driveMobile2 from "@/assets/images/生产驾驶舱.png"; // 生产驾驶舱移动端背景图
  71. import driveMobile3 from "@/assets/images/财务驾驶舱.png"; // 财务驾驶舱移动端背景图
  72. import driveMobile4 from "@/assets/images/供应链驾驶舱.png"; // 供应链驾驶舱移动端背景图
  73. import driveMobile5 from "@/assets/images/市场驾驶舱.png"; // 市场驾驶舱移动端背景图
  74. import driveMobile6 from "@/assets/images/QHSE驾驶舱.png"; // QHSE驾驶舱移动端背景图
  75. import all from "@/assets/images/driveall.png";
  76. import jingying from "@/assets/images/jingying.png";
  77. import shengc from "@/assets/images/shengc.png";
  78. import cai from "@/assets/images/cai.png";
  79. import gong from "@/assets/images/gong.png";
  80. import city from "@/assets/images/city.png";
  81. const userStore = useUserStore();
  82. const tabs = [
  83. { label: "全部驾驶舱", value: "all", icon: all },
  84. { label: "经营管理", value: "management", icon: jingying },
  85. { label: "生产运营", value: "production", icon: shengc },
  86. { label: "财务管理", value: "finance", icon: cai },
  87. { label: "供应链管理", value: "supply", icon: gong },
  88. { label: "市场营销", value: "marketing", icon: city },
  89. { label: "QHSE", value: "qhse", icon: gong },
  90. ];
  91. const activeTab = ref("all");
  92. type DriveCard = {
  93. title: string;
  94. description: string;
  95. url: string;
  96. bgColor: string;
  97. pcBg: string;
  98. mobileBg: string;
  99. category: string; // 新增分类字段
  100. };
  101. const driveCards: DriveCard[] = [
  102. {
  103. title: "经营驾驶舱",
  104. description: "查看经营分析、经营指标与执行情况。",
  105. url: "https://report.deepoil.cc/webroot/decision/v10/entry/access/9fb42908-894a-4373-a6be-ce046a42851d?preview=true&page_number=1",
  106. bgColor: "#3876e0",
  107. pcBg: drivePc1,
  108. mobileBg: driveMobile1,
  109. category: "management", // 对应经营管理
  110. },
  111. {
  112. title: "生产驾驶舱",
  113. description: "查看生产运营态势、核心指标与执行情况。",
  114. url: "https://report.deepoil.cc/webroot/decision/v10/entry/access/dbc9cf73-81ce-43f1-9923-45cdfa5d5d3a?preview=true&page_number=1",
  115. bgColor: "#0f766e",
  116. pcBg: drivePc2,
  117. mobileBg: driveMobile2,
  118. category: "production", // 对应生产运营
  119. },
  120. {
  121. title: "财务驾驶舱",
  122. description: "查看财务分析、预算执行与经营数据表现。",
  123. url: "https://report.deepoil.cc/webroot/decision/v10/entry/access/e836fb5b-092c-4d64-a324-3beeb4fac0cc?preview=true&page_number=1",
  124. bgColor: "#ca8a04",
  125. pcBg: drivePc3,
  126. mobileBg: driveMobile3,
  127. category: "finance", // 对应财务管理
  128. },
  129. {
  130. title: "供应链驾驶舱",
  131. description: "查看供应链分析、物料需求与执行。",
  132. url: "#",
  133. bgColor: "#7c3aed",
  134. pcBg: drivePc4,
  135. mobileBg: driveMobile4,
  136. category: "supply", // 对应供应链管理
  137. },
  138. {
  139. title: "市场驾驶舱",
  140. description: "查看市场分析、销售数据与执行情况。",
  141. url: "#",
  142. bgColor: "#16a34a",
  143. pcBg: drivePc5,
  144. mobileBg: driveMobile5,
  145. category: "marketing", // 对应市场营销
  146. },
  147. {
  148. title: "QHSE驾驶舱",
  149. description: "查看安全、健康、环境与质量数据。",
  150. url: "#",
  151. bgColor: "#dc2626",
  152. pcBg: drivePc6,
  153. mobileBg: driveMobile6,
  154. category: "qhse", // 对应 QHSE
  155. },
  156. ];
  157. const filteredCards = computed(() => {
  158. if (activeTab.value === "all") {
  159. return driveCards;
  160. }
  161. return driveCards.filter((card) => card.category === activeTab.value);
  162. });
  163. const openDrive = async (option: DriveCard) => {
  164. if (userStore.getUser.username && getAccessToken()) {
  165. const res = await getMCSsoToken();
  166. if (res) {
  167. window.open(`${option.url}&ssoToken=${res}`, "_blank");
  168. }
  169. }
  170. };
  171. </script>
  172. <style scoped>
  173. .drive-page {
  174. min-height: 100vh;
  175. background:
  176. radial-gradient(circle at 50% 0%, rgba(30, 74, 255, 0.18), transparent 28%),
  177. radial-gradient(
  178. circle at 82% 18%,
  179. rgba(151, 66, 255, 0.16),
  180. transparent 18%
  181. ),
  182. linear-gradient(180deg, #000613 0%, #000613 100%);
  183. }
  184. .drive-main {
  185. max-width: 100vw;
  186. margin: 0 auto;
  187. padding-top: 50px;
  188. }
  189. .drive-hero {
  190. position: relative;
  191. min-height: 220px;
  192. overflow: hidden;
  193. background:
  194. linear-gradient(180deg, rgba(2, 8, 25, 0.55), rgba(2, 8, 25, 0.86)), #000613;
  195. box-shadow:
  196. 0 24px 60px rgba(0, 0, 0, 0.42),
  197. inset 0 1px 0 rgba(255, 255, 255, 0.04);
  198. }
  199. .drive-hero::before {
  200. content: "";
  201. position: absolute;
  202. inset: 0;
  203. background: linear-gradient(
  204. 90deg,
  205. rgba(0, 6, 19, 0.8) 0%,
  206. rgba(0, 6, 19, 0.24) 40%,
  207. rgba(0, 6, 19, 0.08) 100%
  208. );
  209. z-index: 1;
  210. }
  211. .drive-hero__copy {
  212. position: absolute;
  213. z-index: 2;
  214. left: 56px;
  215. top: 54px;
  216. max-width: 560px;
  217. }
  218. .drive-hero__eyebrow {
  219. margin: 0 0 16px;
  220. color: #6d77ff;
  221. font-size: 14px;
  222. font-weight: 700;
  223. letter-spacing: 0.22em;
  224. }
  225. .drive-hero__title {
  226. margin: 0;
  227. color: #f5f8ff;
  228. font-size: clamp(20px, 5vw, 50px);
  229. font-weight: 900;
  230. line-height: 1.08;
  231. text-shadow: 0 10px 24px rgba(0, 0, 0, 0.45);
  232. }
  233. .drive-hero__desc {
  234. margin: 20px 0 0;
  235. color: #5c6dc8;
  236. font-size: 18px;
  237. line-height: 1.8;
  238. }
  239. .drive-hero__visual {
  240. position: absolute;
  241. inset: 0;
  242. }
  243. .drive-hero__image {
  244. width: 100%;
  245. height: 100%;
  246. }
  247. .drive-hero__image :deep(img) {
  248. width: 100%;
  249. height: 100%;
  250. object-fit: cover;
  251. filter: saturate(1.1) contrast(1.05);
  252. }
  253. .drive-tabs {
  254. display: grid;
  255. grid-template-columns: repeat(7, minmax(0, 1fr));
  256. gap: 0;
  257. margin: 0 auto;
  258. padding: 0px 0px;
  259. width: 90%;
  260. border: 1px solid rgba(79, 110, 208, 0.16);
  261. border-radius: 10px;
  262. background: #070e24;
  263. box-shadow: 0 16px 34px rgba(0, 0, 0, 0.2);
  264. }
  265. .drive-tab {
  266. height: 58px;
  267. border: 0;
  268. border-right: 1px solid rgba(255, 255, 255, 0.06);
  269. background: transparent;
  270. color: rgba(220, 229, 255, 0.78);
  271. font-size: 18px;
  272. font-weight: 700;
  273. cursor: pointer;
  274. display: flex;
  275. justify-content: center;
  276. align-items: center;
  277. }
  278. .drive-tab:last-child {
  279. border-right: 0;
  280. }
  281. .drive-tab--active {
  282. color: #fff !important;
  283. background: linear-gradient(
  284. 360deg,
  285. #003be0 0%,
  286. rgba(10, 65, 227, 0.6) 10%,
  287. #001c71 40%,
  288. #000c33 80%
  289. ) !important;
  290. padding-bottom: 22px;
  291. padding-top: 22px;
  292. border-radius: 0;
  293. position: relative;
  294. }
  295. .drive-tab--active::before {
  296. content: "";
  297. position: absolute;
  298. left: 50%;
  299. bottom: -2px;
  300. width: 100%;
  301. height: 2px;
  302. transform: translateX(-50%);
  303. border-radius: 999px;
  304. background: linear-gradient(
  305. to right,
  306. #5887f8 0%,
  307. #69b5f8 30%,
  308. #fff 50%,
  309. #69b5f8 70%,
  310. #5887f8 100%
  311. );
  312. box-shadow: 0 0 12px rgba(112, 120, 255, 0.95);
  313. }
  314. .drive-grid {
  315. display: grid;
  316. grid-template-columns: repeat(2, minmax(0, 1fr));
  317. gap: 22px;
  318. margin-top: 30px;
  319. }
  320. .drive-card {
  321. position: relative;
  322. display: flex;
  323. align-items: center;
  324. justify-content: center;
  325. width: 100%;
  326. height: 140px;
  327. /* 使用 CSS 变量动态绑定背景图 */
  328. background-image: var(--bg-image);
  329. background-size: contain;
  330. background-position: center;
  331. background-repeat: no-repeat;
  332. text-align: center;
  333. cursor: pointer;
  334. transition:
  335. transform 0.2s ease,
  336. box-shadow 0.2s ease,
  337. border-color 0.2s ease;
  338. overflow: hidden;
  339. /* margin-top: -50px; */
  340. }
  341. .drive-card:hover {
  342. transform: translateY(-4px);
  343. border-color: rgba(115, 145, 255, 0.42);
  344. box-shadow: 0 28px 54px rgba(0, 0, 0, 0.42);
  345. }
  346. /* 补充缺失的内容样式,确保文字能显示在背景图上 */
  347. .drive-card__content {
  348. position: relative;
  349. z-index: 1;
  350. min-width: 0;
  351. flex: 1;
  352. /* 根据原设计可能需要调整文字颜色或背景遮罩以确保可读性 */
  353. }
  354. .drive-card__title {
  355. margin: 0;
  356. color: #f4f7ff;
  357. font-size: 28px;
  358. font-weight: 700;
  359. text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
  360. }
  361. .drive-card__text {
  362. margin: 10px 0 0;
  363. color: rgba(191, 203, 235, 0.82);
  364. font-size: 16px;
  365. line-height: 1.7;
  366. text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
  367. }
  368. .drive-card__arrow {
  369. position: relative;
  370. z-index: 1;
  371. color: rgba(210, 220, 248, 0.82);
  372. font-size: 34px;
  373. flex-shrink: 0;
  374. transition:
  375. transform 0.2s ease,
  376. color 0.2s ease;
  377. }
  378. .drive-card:hover .drive-card__arrow {
  379. color: #ffffff;
  380. transform: translate(2px, -2px);
  381. }
  382. @media (max-width: 768px) {
  383. .drive-main {
  384. padding: 50px 0px 56px;
  385. margin-top: 0;
  386. }
  387. .drive-hero {
  388. min-height: 260px;
  389. }
  390. .drive-hero__copy {
  391. left: 20px;
  392. right: 20px;
  393. top: 24px;
  394. }
  395. .drive-tabs {
  396. grid-template-columns: repeat(2, minmax(0, 1fr));
  397. }
  398. .drive-grid {
  399. grid-template-columns: 1fr;
  400. gap: 16px;
  401. padding-left: 0;
  402. }
  403. .drive-card {
  404. min-height: 100px;
  405. height: 100px; /* 修正原代码中 height: 0px 的问题,确保卡片有高度 */
  406. width: 100%; /* 修正原代码中 width: 100vw 可能导致溢出问题,通常用 100% */
  407. padding: 0;
  408. margin-top: 0;
  409. /* 使用 CSS 变量动态绑定移动端背景图 */
  410. background-image: var(--mobile-bg-image);
  411. background-size: contain;
  412. background-position: center center;
  413. }
  414. .drive-card__title {
  415. font-size: 20px;
  416. }
  417. .drive-hero__image :deep(img) {
  418. object-fit: cover;
  419. object-position: 68% center;
  420. }
  421. }
  422. @media (max-width: 768px) {
  423. .drive-tabs {
  424. display: flex; /* 改为 flex 布局 */
  425. overflow-x: auto; /* 允许横向滚动 */
  426. white-space: nowrap; /* 防止文字换行 */
  427. padding: 12px;
  428. gap: 10px; /* 增加间距 */
  429. /* 移除原有的 grid 相关属性 */
  430. grid-template-columns: unset;
  431. width: 100%;
  432. }
  433. .drive-tab {
  434. flex-shrink: 0; /* 防止按钮被压缩 */
  435. border-right: none; /* 移除右侧边框,改用间距或底部指示器 */
  436. padding: 0 16px; /* 增加左右内边距 */
  437. }
  438. }
  439. /* 优化横向滚动条 */
  440. .drive-tabs::-webkit-scrollbar {
  441. height: 1px;
  442. }
  443. .drive-tabs::-webkit-scrollbar-thumb {
  444. background-color: var(--color-border-default);
  445. border-radius: 2px;
  446. }
  447. </style>