| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- <template>
- <div>
- <PageHero
- kicker=""
- title="智能注气"
- subtitle="围绕设备全生命周期,实现台账、巡检维保、预测维护与实时监控预警的闭环管理。"
- >
- <template #actions>
- <RouterLink
- class="btn btn-primary"
- style="border-radius: 0"
- to="/contact"
- >获取产品资料</RouterLink
- >
- </template>
- </PageHero>
- <main class="case-content">
- <div class="caseLayout">
- <aside class="timelineCol" aria-label="项目实施时间线">
- <div class="timeline">
- <div class="timelineTrack" aria-hidden="true">
- <div class="timelineRail"></div>
- <div
- class="timelineFill"
- :style="{ transform: `scaleY(${progress})` }"
- ></div>
- </div>
- <ol class="timelineSteps" role="list">
- <li
- v-for="(s, idx) in steps"
- :key="s.key"
- class="timelineStep"
- :data-state="stepState(idx)"
- >
- <button
- type="button"
- class="timelineBtn"
- :aria-current="activeIndex === idx ? 'step' : 'false'"
- @click="scrollToStep(s.key)"
- >
- <span class="dot" aria-hidden="true"></span>
- <span class="stepText">
- <span class="stepTitle">{{ s.title }}</span>
- <span class="stepSub muted">{{ s.sub }}</span>
- </span>
- </button>
- </li>
- </ol>
- </div>
- </aside>
- <div class="contentCol">
- <!-- 项目背景 -->
- <section
- :ref="setStepEl('background')"
- id="step-background"
- class="case-section case-section--odd"
- >
- <div class="case-section__image">
- <img src="../../assets/images/case5.png" alt="设备管理场景" />
- </div>
- <div class="case-section__content">
- <h2>项目背景,突破传统注气瓶颈</h2>
- <p>
- XX
- 注气现场面临设备老旧、自动化程度低的双重困境,依赖大量人员现场值守,作业效率受限,参数调整滞后,且设备故障多为被动抢修,存在较大安全隐患与运维成本,亟需通过智能化改造实现降本增效。
- </p>
- </div>
- </section>
- <!-- 核心落地成果 -->
- <section
- :ref="setStepEl('delivery')"
- id="step-delivery"
- class="case-section case-section--even"
- >
- <div class="case-section__image">
- <img src="../../assets/images/case6.jpg" alt="数字化管控系统" />
- </div>
- <div class="case-section__content">
- <h2>核心打造,打造智能无人底座</h2>
- <p>
- 依托工业互联网平台,对现场老旧设备进行专项升级,加装远程控制器、智能阀门等核心组件,完成设备智能化改造。改造后设备全面接入平台,实现数据互通,为无人少人值守与智能调控奠定坚实硬件基础。
- </p>
- </div>
- </section>
- <!-- 预测性维护赋能 -->
- <section
- :ref="setStepEl('predictive')"
- id="step-predictive"
- class="case-section case-section--odd"
- >
- <div class="case-section__image">
- <img src="../../assets/images/case7.png" alt="预测性维护" />
- </div>
- <div class="case-section__content">
- <h2>智能调参与预测维护,双轮驱动提质增效</h2>
- <p>
- 升级后的设备联动平台
- AI算法,实时采集压力、温度、流量等核心数据,自动分析工况并动态调整注入参数,实现精准高效注气。同时,通过预测性维护技术精准预判设备潜在故障,变被动抢修为主动预防,提升设备管理水平。
- </p>
- </div>
- </section>
- <!-- 量化成效 -->
- <section
- :ref="setStepEl('kpi')"
- id="step-kpi"
- class="case-section case-section--even"
- >
- <div class="case-section__image">
- <img src="../../assets/images/case4.png" alt="量化成效展示" />
- </div>
- <div class="case-section__content">
- <h2>量化成效,实现安全高效转型</h2>
- <p>项目上线后,XX 注气现场管理效能全面跃升,核心成效显著:</p>
- </div>
- </section>
- </div>
- </div>
- </main>
- </div>
- </template>
- <script setup>
- import { computed, onBeforeUnmount, onMounted, ref } from "vue";
- import PageHero from "../../components/PageHero.vue";
- import { Icon } from "@iconify/vue";
- const steps = [
- { key: "background", title: "项目背景", sub: "问题识别与痛点分析" },
- { key: "delivery", title: "落地成果", sub: "系统上线与流程闭环" },
- { key: "predictive", title: "提质增效", sub: "提升设备管理水平" },
- { key: "kpi", title: "量化成效", sub: "指标提升与降本增效" },
- ];
- const activeIndex = ref(0);
- const progress = ref(0);
- const stepEls = ref({});
- const setStepEl = (key) => (el) => {
- if (!el) return;
- stepEls.value = { ...stepEls.value, [key]: el };
- };
- const prefersReducedMotion = () =>
- typeof window !== "undefined" &&
- window.matchMedia &&
- window.matchMedia("(prefers-reduced-motion: reduce)").matches;
- const headerOffset = () => {
- if (typeof window === "undefined") return 72;
- const raw = getComputedStyle(document.documentElement)
- .getPropertyValue("--header-h")
- .trim();
- const n = Number.parseInt(raw, 10);
- return Number.isFinite(n) ? n : 72;
- };
- const clamp01 = (n) => Math.max(0, Math.min(1, n));
- const orderedEls = computed(() =>
- steps.map((s) => stepEls.value[s.key]).filter(Boolean),
- );
- const computeActiveIndex = (y) => {
- let idx = 0;
- for (let i = 0; i < steps.length; i++) {
- const el = stepEls.value[steps[i].key];
- if (!el) continue;
- const top = el.getBoundingClientRect().top + window.scrollY;
- if (y >= top) idx = i;
- }
- return idx;
- };
- const computeProgress = (y) => {
- const els = orderedEls.value;
- if (els.length < 2) return 0;
- const first = els[0];
- const last = els[els.length - 1];
- const start = first.getBoundingClientRect().top + window.scrollY;
- const end = last.getBoundingClientRect().bottom + window.scrollY;
- const span = Math.max(1, end - start);
- return clamp01((y - start) / span);
- };
- let raf = 0;
- const updateFromScroll = () => {
- raf = 0;
- if (typeof window === "undefined") return;
- const y = window.scrollY + headerOffset() + 130;
- activeIndex.value = computeActiveIndex(y);
- progress.value = computeProgress(y);
- };
- const onScroll = () => {
- if (raf) return;
- raf = window.requestAnimationFrame(updateFromScroll);
- };
- const scrollToStep = (key) => {
- const el = document.getElementById(`step-${key}`);
- if (!el) return;
- el.scrollIntoView({
- behavior: prefersReducedMotion() ? "auto" : "smooth",
- block: "start",
- });
- };
- const stepState = (idx) =>
- idx < activeIndex.value
- ? "done"
- : idx === activeIndex.value
- ? "active"
- : "todo";
- onMounted(() => {
- updateFromScroll();
- window.addEventListener("scroll", onScroll, { passive: true });
- window.addEventListener("resize", onScroll, { passive: true });
- });
- onBeforeUnmount(() => {
- window.removeEventListener("scroll", onScroll);
- window.removeEventListener("resize", onScroll);
- if (raf) window.cancelAnimationFrame(raf);
- });
- </script>
- <style scoped>
- .case-content {
- max-width: 1300px;
- margin: 0 auto;
- padding: 60px 20px;
- }
- .caseLayout {
- display: grid;
- grid-template-columns: 280px 1fr;
- gap: 26px;
- align-items: start;
- }
- .timelineCol {
- position: relative;
- height: 100%;
- min-height: 100vh;
- }
- .timeline {
- position: sticky;
- top: calc(var(--header-h) + 24px);
- padding: 10px 10px 12px 0;
- user-select: none;
- max-height: calc(100vh - var(--header-h) - 48px);
- overflow-y: auto;
- }
- .timelineTrack {
- position: absolute;
- left: 18px;
- top: 10px;
- bottom: 12px;
- border-radius: 1px;
- width: 2px;
- }
- .timelineRail {
- position: absolute;
- inset: 0;
- background: rgba(15, 23, 42, 0.12);
- border-radius: 999px;
- }
- .timelineFill {
- position: absolute;
- inset: 0;
- background: linear-gradient(180deg, #1d4ed8, #0ea5e9);
- border-radius: 999px;
- transform: scaleY(0);
- transform-origin: top;
- transition: transform 140ms linear;
- will-change: transform;
- }
- .timelineSteps {
- margin: 0;
- padding: 0 0 0 2px;
- list-style: none;
- display: grid;
- gap: 10px;
- }
- .timelineStep {
- position: relative;
- }
- .timelineBtn {
- width: 100%;
- display: grid;
- grid-template-columns: 42px 1fr;
- gap: 12px;
- align-items: start;
- text-align: left;
- padding: 10px 12px 10px 0;
- background: transparent;
- border: 0;
- cursor: pointer;
- color: inherit;
- }
- .timelineBtn:focus-visible {
- outline: none;
- box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.14);
- border-radius: 12px;
- }
- .dot {
- width: 15px;
- height: 15px;
- border-radius: 999px;
- border: 1px solid rgba(15, 23, 42, 0.16);
- background: rgba(255, 255, 255, 0.92);
- display: grid;
- place-items: center;
- margin-left: 10px;
- margin-top: 2px;
- transition:
- background-color 220ms ease,
- border-color 220ms ease,
- box-shadow 220ms ease;
- }
- .stepText {
- display: grid;
- gap: 3px;
- min-width: 0;
- }
- .stepTitle {
- /* font-weight: 900; */
- letter-spacing: -0.01em;
- line-height: 1.2;
- }
- .stepSub {
- font-size: 12px;
- line-height: 1.35;
- }
- .timelineStep[data-state="active"] .dot {
- transform: scale(1.12);
- border-color: rgba(29, 78, 216, 0.38);
- box-shadow:
- 0 0 0 6px rgba(37, 99, 235, 0.12),
- 0 10px 24px rgba(29, 78, 216, 0.18);
- background: #1d4ed8;
- }
- .timelineStep[data-state="done"] .dot {
- background: linear-gradient(180deg, #1d4ed8, #0ea5e9);
- border-color: transparent;
- box-shadow: 0 4px 12px rgba(29, 78, 216, 0.3);
- }
- .timelineStep[data-state="todo"] .stepTitle {
- color: rgba(2, 6, 23, 0.72);
- }
- .case-section {
- display: flex;
- margin-bottom: 80px;
- position: relative;
- scroll-margin-top: calc(var(--header-h) + 120px);
- }
- .case-section--odd {
- flex-direction: row;
- }
- .case-section--even {
- flex-direction: row-reverse;
- }
- .case-section__image {
- flex: 1;
- min-width: 300px;
- overflow: hidden;
- }
- .case-section__image img {
- width: 100%;
- height: auto;
- display: block;
- }
- .case-section__content {
- flex: 1;
- padding: 30px;
- /*
- box-shadow: 0 10px 40px rgba(15, 23, 42, 0.1); */
- margin-left: 20px;
- margin-right: 20px;
- }
- .case-section--even .case-section__content {
- margin-left: 20px;
- margin-right: 20px;
- }
- .case-section__content h2 {
- /* color: var(--brand-700); */
- font-size: 24px;
- margin-bottom: 16px;
- line-height: 1.3;
- }
- .case-section__content p {
- color: var(--slate-700);
- font-size: 16px;
- line-height: 1.8;
- }
- @media (max-width: 900px) {
- .caseLayout {
- grid-template-columns: 1fr;
- gap: 10px;
- }
- .timelineCol {
- display: none;
- }
- .case-section {
- flex-direction: column;
- }
- .case-section__image {
- order: 1;
- margin-bottom: 20px;
- }
- .case-section__content {
- order: 2;
- margin-left: 0;
- margin-right: 0;
- padding: 20px;
- }
- .case-section--even .case-section__content {
- order: 2;
- }
- }
- @media (max-width: 600px) {
- .case-content {
- padding: 40px 15px;
- }
- .case-section__content {
- padding: 15px;
- }
- }
- :deep(.pageHero) {
- background-image: url("../../assets/images/bg5.jpg");
- background-size: cover, cover;
- background-position: center, center;
- background-repeat: no-repeat, no-repeat;
- background-blend-mode: overlay;
- color: #111;
- border-bottom: none;
- padding: 80px 0;
- }
- :deep(.pageHero__subtitle) {
- color: #4f5055;
- }
- </style>
|