SolutionsView.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. <script setup>
  2. import PageHero from "../components/PageHero.vue";
  3. import solutionsBgUrl from "../assets/images/bg.jpg?url";
  4. import Reveal from "../components/motion/Reveal.vue";
  5. import { Icon } from "@iconify/vue";
  6. import { onBeforeUnmount, onMounted, ref } from "vue";
  7. const activeTab = ref("platform");
  8. const tabBarRef = ref(null);
  9. const prefersReducedMotion = () =>
  10. typeof window !== "undefined" &&
  11. window.matchMedia &&
  12. window.matchMedia("(prefers-reduced-motion: reduce)").matches;
  13. const pillars = [
  14. {
  15. key: "platform",
  16. title: "设备升级改造能力",
  17. lead: "油气专属底座,打通“数采—数据—系统—AI”,为全场景应用落地提供稳定支撑。",
  18. icon: "lucide:layers-3",
  19. items: [
  20. {
  21. title: "全景设备升级 适配平台接入",
  22. desc: "依托工业互联网平台底座,提供油气领域全类型设备升级改造服务,针对老旧设备、传统设备,完成仪器仪表升级、PLC控制系统改造或加装,确保改造后设备可无缝接入平台,打通设备与平台的数据联通通道,为后续智能管控奠定基础",
  23. },
  24. {
  25. title: "实时数采远程管控 提升作业便捷度",
  26. desc: "通过设备升级改造,结合平台数采能力,实现现场设备运行数据实时采集、同步上传,打破现场操作局限,支持远程对设备进行控制、参数调试,无需现场值守,降低人工成本,提升设备运维与操作的便捷性、高效性。",
  27. },
  28. {
  29. title: "AI大模型赋能 智能动态调参",
  30. desc: "升级后的设备联动工业互联网平台AI大模型算法,基于实时采集的设备运行数据,进行智能分析、精准研判,自动输出动态调参建议或完成自动调参,优化设备运行状态,确保设备始终处于最佳运行工况,提升运行效率。",
  31. },
  32. {
  33. title: "设备专项赋能 预测性维护",
  34. desc: "针对油气领域部分核心设备,在升级改造基础上,结合平台数据处理与大模型能力,实时监测运行参数,精准预判设备潜在故障、损耗情况,提前触发维护提醒,实现预测性维护,减少停机损失,延长设备使用寿命。",
  35. },
  36. ],
  37. },
  38. {
  39. key: "equipment",
  40. title: "智慧注气",
  41. lead: "围绕设备全生命周期,实现台账、巡检维保、预测维护与实时监控预警的闭环管理。",
  42. icon: "lucide:cpu",
  43. items: [
  44. {
  45. title: "老旧设备升级 筑牢无人值守基础",
  46. desc: "依托工业互联网平台底座,针对油气注气领域老旧设备,开展专项升级改造,加装远程控制器、智能阀门等核心组件,完成设备智能化升级,打破传统人工操作局限,为注气现场无人值守搭建硬件支撑,确保设备可无缝接入平台实现协同管控。",
  47. },
  48. {
  49. title: "实时数据采集 精准把控运行状态",
  50. desc: "升级后的注气设备联动平台数采能力,实时采集现场压力、温度、流量等核心运行参数,同步上传至工业互联网平台,实现参数实时可视化监控,全面掌握注气全流程运行状态,为无人值守下的智能调控提供精准数据支撑。",
  51. },
  52. {
  53. title: "智能动态调参 实现无人管控",
  54. desc: "依托工业互联网平台算法能力,基于实时采集的运行数据,自动分析注气工况,动态调整注入参数,无需人工现场操作,真正实现注气现场无人少人值守,大幅减少人工干预,确保注气过程稳定、高效、精准。",
  55. },
  56. {
  57. title: "降本增效保安全 赋能场景升级",
  58. desc: "通过无人值守模式,大幅减少现场值守人员,降低人力成本;智能动态调参优化注气效率,提升作业产能;减少人员现场作业频次,规避现场安全风险,实现“降本、增效、保安全”三重价值,推动注气场景数字化、智能化转型。",
  59. },
  60. ],
  61. },
  62. {
  63. key: "production",
  64. title: "智慧钻井",
  65. lead: "面向油气生产项目,贯通任务、计划、数据与报表,提升协同效率与过程可控性。",
  66. icon: "lucide:clipboard-check",
  67. items: [
  68. {
  69. title: "数据精准采集 筑牢钻井分析基础",
  70. desc: "依托工业互联网平台数采能力,深度联动录井仪设备,实时采集钻井全流程工况数据,全面记录钻井过程中的各项核心参数,实现数据精准捕捉、实时上传、规范存储,为后续AI分析、钻井优化及完井报告生成,提供完整、可靠的数据支撑。",
  71. },
  72. {
  73. title: "AI大模型深度赋能 精准分析钻井工况",
  74. desc: "基于工业互联网平台AI大模型能力,对采集的录井数据进行深度挖掘、智能分析,精准识别钻井过程中的工况异常、参数偏差等问题,快速研判钻井态势,为钻井作业优化提供科学、精准的数据分析支撑,规避盲目操作风险。",
  75. },
  76. {
  77. title: "钻井参数智能优化 提升钻井作业交通",
  78. desc: "结合AI大模型的工况分析结果,联动工业互联网平台管控能力,为钻井现场提供精准的参数优化建议,指导现场调整钻井参数,优化钻井工艺,有效提升钻速、降低钻井损耗,助力钻井作业提质增效,契合油气勘探开发高效化需求。",
  79. },
  80. {
  81. title: "智能生成完井报告 提升报告编制效率",
  82. desc: "依托平台数据沉淀与AI处理能力,自动汇总钻井全流程录井数据、工况分析结果及优化记录,一键生成标准化完井报告,无需人工繁琐录入,大幅缩短报告编制周期,确保报告数据精准、内容规范,为钻井成果复盘、后续作业提供有力支撑。",
  83. },
  84. ],
  85. },
  86. ];
  87. const deliver = [
  88. { title: "SaaS", desc: "开箱即用,按需订阅,快速试点与复制。" },
  89. { title: "私有化", desc: "数据本地化部署,适配企业安全与合规要求。" },
  90. { title: "混合云", desc: "核心数据本地,弹性算力上云,兼顾成本与性能。" },
  91. ];
  92. function headerOffsetPx() {
  93. const rootStyle = getComputedStyle(document.documentElement);
  94. const headerVar = rootStyle.getPropertyValue("--header-h")?.trim();
  95. const headerH = Number.parseFloat(headerVar || "72") || 72;
  96. const tabH = tabBarRef.value?.getBoundingClientRect?.().height || 0;
  97. return Math.round(headerH + tabH + 16);
  98. }
  99. function scrollToTab(key) {
  100. const el = document.getElementById(`product-${key}`);
  101. if (!el) return;
  102. activeTab.value = key;
  103. const offset = headerOffsetPx();
  104. const y = el.getBoundingClientRect().top + window.scrollY - offset;
  105. window.scrollTo({
  106. top: Math.max(0, y),
  107. behavior: prefersReducedMotion() ? "auto" : "smooth",
  108. });
  109. }
  110. let observer = null;
  111. onMounted(() => {
  112. const offset = headerOffsetPx();
  113. observer = new IntersectionObserver(
  114. (entries) => {
  115. const visible = entries
  116. .filter((e) => e.isIntersecting)
  117. .sort(
  118. (a, b) => (b.intersectionRatio || 0) - (a.intersectionRatio || 0),
  119. )[0];
  120. if (visible?.target?.id)
  121. activeTab.value = visible.target.id.replace("product-", "");
  122. },
  123. {
  124. root: null,
  125. threshold: [0.25, 0.45, 0.6],
  126. rootMargin: `-${offset}px 0px -55% 0px`,
  127. },
  128. );
  129. for (const p of pillars) {
  130. const el = document.getElementById(`product-${p.key}`);
  131. if (el) observer.observe(el);
  132. }
  133. });
  134. onBeforeUnmount(() => {
  135. observer?.disconnect?.();
  136. observer = null;
  137. });
  138. </script>
  139. <template>
  140. <div>
  141. <PageHero
  142. kicker=""
  143. title="油气行业数智产品矩阵"
  144. subtitle="以工业互联网平台为底座,覆盖设备管理、生产管理与QHSE,贯通数采、数据、流程与AI,支撑从勘探开发到生产运营的全场景数字化。"
  145. >
  146. <template #actions>
  147. <RouterLink
  148. class="btn btn-primary"
  149. style="border-radius: 0"
  150. to="/contact"
  151. >获取产品资料</RouterLink
  152. >
  153. </template>
  154. </PageHero>
  155. <section class="section" style="padding-top: 0; margin-top: -10px">
  156. <div>
  157. <div
  158. ref="tabBarRef"
  159. class="tabBar"
  160. role="tablist"
  161. aria-label="产品域导航"
  162. >
  163. <button
  164. v-for="p in pillars"
  165. :key="p.key"
  166. class="tabBtn"
  167. :class="{ 'is-active': activeTab === p.key }"
  168. type="button"
  169. role="tab"
  170. :aria-selected="activeTab === p.key ? 'true' : 'false'"
  171. @click="scrollToTab(p.key)"
  172. >
  173. <span
  174. class="tabText"
  175. style="display: flex; align-items: center; gap: 10px"
  176. ><Icon :icon="p.icon" width="18" height="18" aria-hidden="true" />
  177. <span>{{ p.title }}</span></span
  178. >
  179. </button>
  180. </div>
  181. <div class="productStac container">
  182. <section
  183. v-for="p in pillars"
  184. :id="`product-${p.key}`"
  185. :key="p.key"
  186. class="productSection"
  187. >
  188. <header class="productHead">
  189. <div class="productHeadTop">
  190. <h2 class="productTitle">{{ p.title }}</h2>
  191. </div>
  192. <p class="productLead">{{ p.lead }}</p>
  193. </header>
  194. <div class="productBody">
  195. <div v-for="it in p.items" :key="it.title" class="featureRow">
  196. <div class="featureDot" aria-hidden="true"></div>
  197. <div class="featureMain">
  198. <div class="featureTitle">{{ it.title }}</div>
  199. <div class="muted featureDesc">{{ it.desc }}</div>
  200. </div>
  201. </div>
  202. </div>
  203. </section>
  204. </div>
  205. </div>
  206. </section>
  207. <section
  208. class="section section--soft solutionsBg"
  209. :style="{ '--solutions-bg': `url(${solutionsBgUrl})` }"
  210. >
  211. <div class="container">
  212. <Reveal as="div" class="sectionHead" :delay="0">
  213. <div>
  214. <div class="section-kicker">落地方法</div>
  215. <h2 class="h2">以数据闭环驱动持续改进</h2>
  216. </div>
  217. </Reveal>
  218. <div class="grid grid-4">
  219. <Reveal
  220. v-for="(a, idx) in approach"
  221. :key="a.step"
  222. as="div"
  223. class="card card-pad approachCard hover-lift"
  224. :delay="60 + idx * 70"
  225. >
  226. <div class="approachStep">{{ a.step }}</div>
  227. <div class="approachTitle">{{ a.title }}</div>
  228. <div class="muted">{{ a.desc }}</div>
  229. </Reveal>
  230. </div>
  231. </div>
  232. </section>
  233. </div>
  234. </template>
  235. <style scoped>
  236. .sectionHead {
  237. display: flex;
  238. align-items: flex-end;
  239. justify-content: space-between;
  240. gap: 18px;
  241. margin-bottom: 16px;
  242. }
  243. .solutionTitle {
  244. font-weight: 900;
  245. letter-spacing: -0.02em;
  246. margin-bottom: 6px;
  247. }
  248. .solutionScenes {
  249. margin-top: 12px;
  250. display: grid;
  251. gap: 10px;
  252. }
  253. .scene {
  254. display: flex;
  255. align-items: center;
  256. gap: 10px;
  257. color: var(--slate-700);
  258. font-weight: 600;
  259. }
  260. .dot {
  261. width: 8px;
  262. height: 8px;
  263. border-radius: 50%;
  264. background: var(--brand-600);
  265. }
  266. .approachStep {
  267. color: var(--brand-700);
  268. font-weight: 900;
  269. letter-spacing: -0.02em;
  270. }
  271. .approachTitle {
  272. margin-top: 4px;
  273. font-weight: 900;
  274. margin-bottom: 6px;
  275. }
  276. .solutionsBg {
  277. position: relative;
  278. overflow: hidden;
  279. }
  280. .solutionsBg::before {
  281. content: "";
  282. position: absolute;
  283. inset: 0;
  284. background-image: var(--solutions-bg);
  285. background-size: cover;
  286. background-position: center;
  287. opacity: 0.45;
  288. filter: saturate(0.95);
  289. }
  290. .solutionsBg::after {
  291. content: "";
  292. position: absolute;
  293. inset: 0;
  294. background: linear-gradient(
  295. 180deg,
  296. rgba(248, 250, 252, 0.78),
  297. rgba(248, 250, 252, 0.92)
  298. );
  299. }
  300. .solutionsBg > .container {
  301. position: relative;
  302. z-index: 1;
  303. }
  304. .productsView {
  305. --ink: rgba(2, 6, 23, 0.92);
  306. --tab-bg: rgba(255, 255, 255, 0.92);
  307. }
  308. .sectionHead {
  309. display: flex;
  310. align-items: flex-end;
  311. justify-content: space-between;
  312. gap: 18px;
  313. margin-bottom: 16px;
  314. }
  315. .productStac {
  316. display: flex;
  317. width: 100%;
  318. justify-content: center;
  319. align-items: center;
  320. flex-direction: column;
  321. }
  322. /* Remove PageHero gradients for this page */
  323. :deep(.pageHero) {
  324. border-bottom: none;
  325. }
  326. .tabBar {
  327. position: sticky;
  328. top: var(--header-h);
  329. padding: 0 30px;
  330. z-index: 20;
  331. display: grid;
  332. grid-template-columns: repeat(6, minmax(0, 1fr));
  333. gap: 0px;
  334. background: #eef5f8;
  335. margin: 10px 0 18px;
  336. height: 80px;
  337. border: 0;
  338. border-radius: 0;
  339. }
  340. .tabBtn {
  341. height: 80px;
  342. font-size: 20px;
  343. border: 0;
  344. background: #eef5f8;
  345. box-shadow: var(--tab-shadow);
  346. padding: 0 50px;
  347. display: inline-flex;
  348. align-items: center;
  349. justify-content: center;
  350. gap: 10px;
  351. color: var(--slate-700);
  352. letter-spacing: 0.01em;
  353. cursor: pointer;
  354. transition:
  355. transform 160ms ease,
  356. box-shadow 160ms ease,
  357. color 160ms ease;
  358. }
  359. .tabBtn.is-active {
  360. color: var(--brand-700);
  361. background-color: #fff;
  362. }
  363. .tabBtn:focus-visible {
  364. outline: none;
  365. box-shadow:
  366. 0 0 0 3px rgba(37, 99, 235, 0.24),
  367. var(--tab-shadow-hover);
  368. }
  369. .tabText {
  370. display: inline-block;
  371. white-space: nowrap;
  372. padding-bottom: 10px;
  373. background-image: linear-gradient(currentColor, currentColor);
  374. background-repeat: no-repeat;
  375. background-position: 0 100%;
  376. background-size: 0 2px;
  377. transition: background-size 160ms ease;
  378. }
  379. .tabBtn.is-active .tabText {
  380. background-size: 100% 2px;
  381. }
  382. .productStack {
  383. display: grid;
  384. gap: 26px;
  385. }
  386. .productSection {
  387. scroll-margin-top: calc(var(--header-h) + 84px);
  388. border: 0;
  389. border-radius: 0;
  390. background: transparent;
  391. box-shadow: none;
  392. margin-top: 50px;
  393. }
  394. .productHead {
  395. padding: 18px 18px 14px;
  396. text-align: center;
  397. }
  398. .productHeadTop {
  399. display: flex;
  400. align-items: center;
  401. justify-content: center;
  402. gap: 12px;
  403. }
  404. .productBadge {
  405. font-size: 12px;
  406. font-weight: 900;
  407. letter-spacing: 0.08em;
  408. color: rgba(2, 6, 23, 0.65);
  409. background: rgba(15, 23, 42, 0.04);
  410. border: 1px solid rgba(15, 23, 42, 0.08);
  411. padding: 6px 10px;
  412. border-radius: 999px;
  413. flex: 0 0 auto;
  414. }
  415. .productTitle {
  416. letter-spacing: -0.02em;
  417. color: var(--ink);
  418. font-size: 30px;
  419. line-height: 1.25;
  420. text-align: center;
  421. }
  422. .productLead {
  423. margin-top: 10px;
  424. max-width: 92ch;
  425. text-align: center;
  426. margin-left: auto;
  427. margin-right: auto;
  428. }
  429. .productBody {
  430. padding: 10px 2px 6px;
  431. display: grid;
  432. grid-template-columns: repeat(3, minmax(0, 1fr));
  433. gap: 18px;
  434. }
  435. .featureRow {
  436. display: grid;
  437. grid-template-columns: 22px 1fr;
  438. align-items: start;
  439. gap: 16px;
  440. padding: 22px 22px;
  441. border: 0;
  442. /* border-radius: 18px; */
  443. background: #fff;
  444. box-shadow: 0 16px 42px rgba(2, 6, 23, 0.12);
  445. min-height: 178px;
  446. transition:
  447. transform 180ms ease,
  448. box-shadow 180ms ease;
  449. }
  450. .featureRow:hover {
  451. transform: translateY(-2px);
  452. box-shadow: 0 22px 58px rgba(2, 6, 23, 0.16);
  453. }
  454. .featureDot {
  455. width: 18px;
  456. height: 18px;
  457. border-radius: 999px;
  458. background: linear-gradient(180deg, #22c55e, #16a34a);
  459. box-shadow:
  460. 0 10px 22px rgba(34, 197, 94, 0.25),
  461. inset 0 0 0 2px rgba(255, 255, 255, 0.85);
  462. margin-top: 4px;
  463. }
  464. .featureMain {
  465. min-width: 0;
  466. }
  467. .featureTitle {
  468. letter-spacing: -0.01em;
  469. color: rgba(2, 6, 23, 0.9);
  470. font-size: 22px;
  471. font-weight: 700;
  472. line-height: 1.35;
  473. }
  474. .featureDesc {
  475. margin-top: 10px;
  476. line-height: 1.75;
  477. color: #666666;
  478. text-align: left;
  479. }
  480. .deliverTitle {
  481. font-weight: 900;
  482. margin-bottom: 6px;
  483. }
  484. @media (max-width: 960px) {
  485. .sectionHead {
  486. flex-direction: column;
  487. align-items: flex-start;
  488. gap: 12px;
  489. }
  490. .tabBar {
  491. grid-template-columns: repeat(2, minmax(0, 1fr));
  492. }
  493. .productBody {
  494. grid-template-columns: repeat(2, minmax(0, 1fr));
  495. }
  496. }
  497. @media (max-width: 560px) {
  498. .productBody {
  499. grid-template-columns: 1fr;
  500. }
  501. }
  502. @media (prefers-reduced-motion: reduce) {
  503. .tabBtn {
  504. transition: none !important;
  505. transform: none !important;
  506. }
  507. .tabText {
  508. transition: none !important;
  509. }
  510. .featureRow {
  511. transition: none !important;
  512. transform: none !important;
  513. }
  514. }
  515. :deep(.pageHero) {
  516. background-image: url("../assets/images/bg4.png");
  517. background-size: cover, cover;
  518. background-position: center, center;
  519. background-repeat: no-repeat, no-repeat;
  520. background-blend-mode: overlay;
  521. color: #111;
  522. padding: 80px 0;
  523. }
  524. :deep(.pageHero__subtitle) {
  525. color: #4f5055;
  526. }
  527. </style>