Przeglądaj źródła

wip: 响应式适配 案例

Lee 5 dni temu
rodzic
commit
cb08b4233f

+ 5 - 0
app/assets/icons/menu.svg

@@ -0,0 +1,5 @@
+<svg width="46" height="46" viewBox="0 0 46 46" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7.61841 11.4517H38.2851" stroke="#333333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M7.61841 22.9517H38.2851" stroke="#333333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M7.61841 34.4517H38.2851" stroke="#333333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

BIN
app/assets/images/banner-mobile.png


+ 2 - 2
app/assets/scss/vars.scss

@@ -47,8 +47,8 @@
 %landing-container {
   width: 100%;
   margin: 0 auto;
-  padding-left: 20px;
-  padding-right: 20px;
+  padding-left: 40px;
+  padding-right: 40px;
 
   @media screen and (min-width: 768px) {
     padding-left: 240px;

+ 1 - 1
app/components/Footer.vue

@@ -3,7 +3,7 @@
  * @Description: AppFooter
 -->
 <template>
-  <footer class="bg-black text-white py-60px sm:pt-130px sm:pb-60px">
+  <footer class="bg-black text-white py-60px lt-sm:py-40px sm:pt-130px sm:pb-60px">
     <div class="footer-container">
       <!-- 顶部区域:链接列表 + 联系方式 -->
       <div class="flex flex-col sm:flex-row justify-between items-start gap-60px sm:gap-0">

+ 63 - 57
app/components/Header.vue

@@ -2,7 +2,7 @@
  * @Author: LiZhiWei
  * @Date: 2026-01-13 15:41:49
  * @LastEditors: LiZhiWei
- * @LastEditTime: 2026-01-15 14:49:14
+ * @LastEditTime: 2026-01-19 09:33:54
  * @Description: 
 -->
 <!--
@@ -11,13 +11,10 @@
 -->
 <template>
   <header class="landing-header" :class="{ 'is-scrolled': y > 0 }">
-    <div class="landing-container h-60px sm:h-80px flex items-center justify-between gap-16px">
-      <i class="i-custom-logo w-100px h-20px sm:w-128px sm:h-26px"></i>
-
-      <!-- Mobile Menu Button -->
-      <button class="sm:hidden p-8px text-gray-600" @click="isMobileMenuOpen = !isMobileMenuOpen">
-        <div class="i-carbon-menu text-24px"></div>
-      </button>
+    <div
+      class="landing-container h-80px flex items-center justify-between gap-16px lt-sm:h-128px lt-xs:px-15px"
+    >
+      <i class="i-custom-logo w-160px h-32px lt-sm:w-213px lt-sm:h-64px"></i>
 
       <nav
         class="hidden sm:flex items-center gap-20px xl:gap-52px text-16px xl:text-16px text-#334155 h-full"
@@ -83,7 +80,7 @@
         <NuxtLink to="/" class="nav-link flex items-center">联系合作</NuxtLink>
       </nav>
 
-      <div class="flex items-center gap-30px">
+      <div class="flex items-center gap-30px lt-sm:hidden">
         <span class="flex items-center gap-14px hidden sm:flex">
           <i class="i-custom-telephone wh-28px"></i>
           <span class="font-s-28px font-bold text-#28292E d-din-pro-600-semibold">
@@ -97,63 +94,68 @@
           <span class="lh-20px">申请试用</span>
         </button>
       </div>
+
+      <button class="sm:hidden text-#334155" @click="isMobileMenuOpen = !isMobileMenuOpen">
+        <i v-if="!isMobileMenuOpen" class="i-custom-menu lt-sm:wh-48px"></i>
+        <i v-else class="i-ep-close lt-sm:wh-48px"></i>
+      </button>
     </div>
+  </header>
 
-    <!-- Mobile Menu Overlay -->
-    <div
-      v-if="isMobileMenuOpen"
-      class="fixed inset-0 top-60px bg-white z-90 sm:hidden flex flex-col p-20px animate-fade-in-down"
-    >
-      <nav class="flex flex-col gap-20px text-16px text-#334155 font-500">
-        <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
-          首页
-        </NuxtLink>
-        <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
-          产品中心
-        </NuxtLink>
-        <div class="py-10px border-b border-gray-100">
-          <div class="mb-10px">解决方案</div>
-          <div class="pl-16px flex flex-col gap-10px text-14px text-gray-500">
-            <div v-for="(cat, idx) in solutionCategories" :key="idx">
-              <div class="font-600 text-gray-700 mb-4px">{{ cat.name }}</div>
-              <div class="pl-8px flex flex-col gap-6px">
-                <div v-for="(item, i) in cat.items" :key="i" class="py-2px">
-                  {{ item.title }}
-                </div>
+  <!-- Mobile Menu Overlay -->
+  <div
+    v-if="isMobileMenuOpen"
+    class="fixed inset-0 top-80px lt-sm:top-128px lt-xs:top-60px bg-white z-90 sm:hidden flex flex-col p-20px animate-fade-in-down"
+  >
+    <nav class="flex flex-col gap-20px text-16px text-#334155 font-500">
+      <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
+        首页
+      </NuxtLink>
+      <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
+        产品中心
+      </NuxtLink>
+      <div class="py-10px border-b border-gray-100">
+        <div class="mb-10px">解决方案</div>
+        <div class="pl-16px flex flex-col gap-10px text-14px text-gray-500">
+          <div v-for="(cat, idx) in solutionCategories" :key="idx">
+            <div class="font-600 text-gray-700 mb-4px">{{ cat.name }}</div>
+            <div class="pl-8px flex flex-col gap-6px">
+              <div v-for="(item, i) in cat.items" :key="i" class="py-2px">
+                {{ item.title }}
               </div>
             </div>
           </div>
         </div>
-        <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
-          客户案例
-        </NuxtLink>
-        <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
-          关于绘家
-        </NuxtLink>
-        <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
-          联系合作
-        </NuxtLink>
-      </nav>
+      </div>
+      <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
+        客户案例
+      </NuxtLink>
+      <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
+        关于绘家
+      </NuxtLink>
+      <NuxtLink to="/" class="py-10px border-b border-gray-100" @click="isMobileMenuOpen = false">
+        联系合作
+      </NuxtLink>
+    </nav>
 
-      <div class="mt-auto pt-20px border-t border-gray-100">
-        <div class="flex items-center gap-10px mb-20px justify-center">
-          <i class="i-custom-telephone wh-24px"></i>
-          <span class="font-s-20px font-bold text-#28292E">400-600-7709</span>
-        </div>
-        <button
-          class="btn-primary text-white font-medium w-full h-44px rounded-8px text-16px"
-          @click="
-            () => {
-              openConsultation()
-              isMobileMenuOpen = false
-            }
-          "
-        >
-          申请试用
-        </button>
+    <div class="mt-auto pt-20px border-t border-gray-100">
+      <div class="flex items-center gap-10px mb-20px justify-center">
+        <i class="i-custom-telephone wh-24px"></i>
+        <span class="font-s-20px font-bold text-#28292E">400-600-7709</span>
       </div>
+      <button
+        class="btn-primary text-white font-medium w-full h-44px rounded-8px text-16px"
+        @click="
+          () => {
+            openConsultation()
+            isMobileMenuOpen = false
+          }
+        "
+      >
+        申请试用
+      </button>
     </div>
-  </header>
+  </div>
 </template>
 
 <script setup lang="ts">
@@ -237,6 +239,10 @@
     &.is-scrolled {
       @apply bg-white/80 backdrop-blur-12px shadow-[0_4px_20px_rgba(0,0,0,0.05)] border-b border-white/10;
     }
+
+    @media (max-width: 767px) {
+      @apply bg-white/80 backdrop-blur-12px shadow-[0_4px_20px_rgba(0,0,0,0.05)] border-b border-white/10;
+    }
   }
 
   .nav-link {

+ 48 - 15
app/constants/common.ts

@@ -301,12 +301,13 @@ export const historyYears: HistoryYear[] = [
     year: '2019',
     events: [
       {
-        month: '2019-03',
-        content: '绘家科技正式注册成立,确立“以物业管理系统为核心,以业主服务为目标”的发展战略。',
+        month: '2019-06',
+        content:
+          '绘管家v2上线,实现突破:达成首笔线上缴费714.9元,开出首张电子发票,落地项目超100个。',
       },
       {
-        month: '2019-11',
-        content: '绘家云V1.0版本上线,实现收费、工单、巡检等基础物业管理功能。',
+        month: '2019-10',
+        content: '绘管家亮相2019国际物业管理产业博览会,品牌影响力初步彰显。',
       },
     ],
   },
@@ -314,8 +315,12 @@ export const historyYears: HistoryYear[] = [
     year: '2020',
     events: [
       {
-        month: '2020-08',
-        content: '创始团队在社区信息化领域进行早期技术积累。',
+        month: '2020-02',
+        content: '绘服务用户数破10万,在线缴费金额突破5000万元。',
+      },
+      {
+        month: '2020-05',
+        content: '绘管家App正式上线,服务触达更便捷。',
       },
     ],
   },
@@ -324,7 +329,11 @@ export const historyYears: HistoryYear[] = [
     events: [
       {
         month: '2021-06',
-        content: '研发出国内领先的移动物业管理终端。',
+        content: '签约物业企业超100家,落地项目增至300余个。',
+      },
+      {
+        month: '2021-10',
+        content: '绘服务在线缴费金额突破1亿元大关。',
       },
     ],
   },
@@ -332,8 +341,12 @@ export const historyYears: HistoryYear[] = [
     year: '2022',
     events: [
       {
-        month: '2022-10',
-        content: '推出基于SaaS架构的智慧社区云平台雏形。',
+        month: '2022-05',
+        content: '收银台v3版本上线,收费流程一站式体验流程闭环。',
+      },
+      {
+        month: '2022-08',
+        content: '参与承办《海南智慧社区研讨会》,积极助力行业发展。',
       },
     ],
   },
@@ -341,8 +354,12 @@ export const historyYears: HistoryYear[] = [
     year: '2023',
     events: [
       {
-        month: '2023-12',
-        content: '荣获行业“最具潜力智慧社区服务商”奖项。',
+        month: '2023-05',
+        content: '在线缴费突破3亿元,绘服务v2、绘管家APP v2同步发布。',
+      },
+      {
+        month: '2023-09',
+        content: '数字化电子发票功能上线,提升服务合规性。',
       },
     ],
   },
@@ -351,7 +368,15 @@ export const historyYears: HistoryYear[] = [
     events: [
       {
         month: '2024-05',
-        content: '绘家云V2.0版本上线,引入AI安防监控和智能物联。',
+        content: '账单/流水系统v3上线,绘服务支付宝小程序、物业大厅同步推出。',
+      },
+      {
+        month: '2024-09',
+        content: '实现机械表智能化升级,支持欠费提醒、在线预缴等实用功能。',
+      },
+      {
+        month: '2024-12',
+        content: '累计开具电子发票超150万张,涉及金额达6亿元以上。',
       },
     ],
   },
@@ -359,8 +384,16 @@ export const historyYears: HistoryYear[] = [
     year: '2025',
     events: [
       {
-        month: '2025-08',
-        content: '业务覆盖全国30+城市,服务项目突破500个。',
+        month: '2025-03',
+        content: '资产管理v3上线,增加资产生涯系统,完善债权归属。',
+      },
+      {
+        month: '2025-09',
+        content: '落地项目突破800个,在线缴费金额攀升至8亿元。',
+      },
+      {
+        month: '2025-12-18',
+        content: '绘家科技正式启航,迈向智慧生活服务新征程。',
       },
     ],
   },
@@ -369,7 +402,7 @@ export const historyYears: HistoryYear[] = [
     events: [
       {
         month: '2026-01',
-        content: '完成A轮融资,持续加大研发投入,深耕行业数字化。',
+        content: '长路仍在前方,这是我们共同续写的序章。请相信,所有美好终将与我们相遇,未来可期',
       },
     ],
   },

+ 410 - 110
app/pages/index/index.vue

@@ -1,45 +1,38 @@
 <!--
  * @Author: LiZhiWei
  * @LastEditors: LiZhiWei
- * @LastEditTime: 2026-01-16 11:58:37
+ * @LastEditTime: 2026-01-19 12:12:17
  * @Description: 
 -->
 <template>
   <div class="landing">
     <section class="hero">
-      <div class="hero-content flex items-center pb-48px pt-200px">
-        <div class="text-left">
-          <div class="font-s-48px font-semibold text-#000000">智慧社区整体解决方案</div>
-          <p class="font-s-18px text-#091221/70">
+      <div class="hero-content flex items-center pb-48px pt-200px lt-sm:pt-80px">
+        <div class="text-left w-full lt-sm:text-center">
+          <div class="hero-title">智慧社区整体解决方案</div>
+          <div class="hero-subtitle">
             绘家科技助力物业管理数字化转型,提升服务品质与业主满意度。
-          </p>
+          </div>
 
-          <div class="mt-35px flex items-center gap-48px">
+          <div
+            class="mt-35px flex items-center gap-48px lt-sm:justify-center lt-sm:mt-20px lt-sm:gap-76px"
+          >
             <div class="metric">
               <div class="metric-value">300+</div>
-              <div class="metric-label">设备接入</div>
+              <div class="metric-label">服务客户</div>
             </div>
             <div class="metric">
               <div class="metric-value">800+</div>
-              <div class="metric-label">业务流程</div>
+              <div class="metric-label">管理小区</div>
             </div>
             <div class="metric">
-              <div class="metric-value">60w+</div>
-              <div class="metric-label">服务人群</div>
+              <div class="metric-value">50w+</div>
+              <div class="metric-label">管理房屋</div>
             </div>
           </div>
-          <div class="mt-35px flex flex-wrap items-center gap-16px">
-            <button
-              class="btn-primary w-127px h-56px! rounded-8px text-white font-s-18px pf-sc-semibold"
-            >
-              查看方案
-            </button>
-            <button
-              class="btn-outline w-127px h-56px! border-[1px] border-#0F67F8! font-s-18px font-semibold text-#0F67F8! bg-white rounded-8px hover:opacity-80"
-              @click="openConsultation"
-            >
-              立即咨询
-            </button>
+          <div class="hero-actions">
+            <button class="btn-primary hero-btn-primary">查看方案</button>
+            <button class="hero-btn-outline" @click="openConsultation">免费咨询</button>
           </div>
         </div>
       </div>
@@ -48,61 +41,66 @@
     <section
       id="solution"
       ref="solutionRef"
-      class="solution h-744px pt-120px transition-all duration-1000 ease-out"
+      class="solution py-120px transition-all duration-1000 ease-out"
       :class="[isSolutionVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-100px']"
     >
       <div class="text-center mb-45px">
-        <div class="font-s-36px font-semibold text-#000000 mb-4px lh-60px">
+        <div
+          class="font-s-36px font-semibold text-#000000 mb-4px lh-60px lt-sm:font-s-48px lt-sm:lh-60px"
+        >
           物业管理正面临这些挑战
         </div>
-        <div class="font-s-16px text-#091221/70 lh-30px">
+        <div
+          class="font-s-16px text-#091221/70 lh-30px lt-sm:font-s-24px lt-sm:px-110px lt-sm:mt-16px lt-sm:lh-40px"
+        >
           传统物业管理模式效率低下、成本高昂、服务体验差,急需数字化转型
         </div>
       </div>
 
-      <div class="flex h-365px w-full gap-24px">
+      <div class="solution-list" ref="solutionListRef" @scroll="handleSolutionScroll">
         <div
           v-for="(solution, index) in solutions"
           :key="solution.id"
-          class="relative flex h-full cursor-pointer overflow-hidden rounded-16px transition-[flex,background-color] duration-500 ease-in-out"
+          class="solution-card"
           :class="[
             index === activeIndex
-              ? 'flex-[1_1_0%] bg-[linear-gradient(0deg,#E5E9F5_0%,#EFF2FB_100%)]'
-              : 'flex-[0_0_220px] bg-[linear-gradient(180deg,#E8F6FD_50.48%,#A5D7FD_100%)]',
+              ? 'active bg-[linear-gradient(0deg,#E5E9F5_0%,#EFF2FB_100%)]'
+              : 'bg-[linear-gradient(180deg,#E8F6FD_50.48%,#A5D7FD_100%)] lt-sm:bg-[linear-gradient(0deg,#E5E9F5_0%,#EFF2FB_100%)]',
           ]"
           @mouseenter="activeIndex = index"
         >
           <!-- Hover State Content -->
           <div
-            class="h-full w-700px pt-40px px-48px absolute left-0 top-0 transition-all ease-in-out"
+            class="solution-card-hover"
             :class="[
               index === activeIndex
                 ? 'opacity-100 translate-y-0 duration-500'
-                : 'opacity-0 translate-y-20px pointer-events-none duration-300',
+                : 'opacity-0 translate-y-20px pointer-events-none duration-300 mobile-show',
             ]"
           >
             <div
-              class="font-s-22px text-#000000 pf-sc-semibold transition-all"
+              class="font-s-22px text-#000000 pf-sc-semibold transition-all lt-sm:font-s-32px"
               :class="[
                 index === activeIndex
                   ? 'opacity-100 translate-y-0 delay-100 duration-500'
                   : 'opacity-0 translate-y-20px delay-0 duration-200',
               ]"
             >
-              {{ solution.hoverTitle }}
+              <span class="lt-sm:hidden">{{ solution.hoverTitle }}</span>
+              <span>{{ solution.title }}解决方案</span>
             </div>
             <div
-              class="font-s-14px lh-24px mt-8px text-#091221/70 pf-sc-regular whitespace-nowrap transition-all"
+              class="font-s-14px lh-24px mt-8px text-#091221/70 pf-sc-regular text-overflow transition-all lt-sm:font-s-24px lt-sm:mt-8px lt-sm:lh-normal"
               :class="[
                 index === activeIndex
                   ? 'opacity-100 translate-y-0 delay-150 duration-500'
                   : 'opacity-0 translate-y-20px delay-0 duration-200',
               ]"
             >
-              {{ solution.hoverDesc }}
+              <span>{{ solution.hoverDesc }}</span>
             </div>
             <div
-              class="mt-24px flex flex-col gap-8px transition-all"
+              class="mt-24px flex flex-col gap-8px transition-all lt-sm:mt-48px"
               :class="[
                 index === activeIndex
                   ? 'opacity-100 translate-y-0 delay-200 duration-500'
@@ -110,19 +108,23 @@
               ]"
             >
               <div v-for="item in solution.hoverItems" :key="item.title" class="flex flex-col">
-                <div class="flex gap-8px items-center font-s-14px">
-                  <i class="i-custom-check-one wh-18px"></i>
-                  <span class="text-#091221 pf-sc-semibold">
-                    {{ item.title }}
-                  </span>
-                  <span class="text-#091221/70 pf-sc-regular">
-                    {{ item.itemDesc }}
-                  </span>
+                <div class="flex gap-8px items-center font-s-14px lt-sm:font-s-24px lt-sm:gap-12px">
+                  <i class="i-custom-check-one wh-18px lt-sm:wh-32px"></i>
+                  <div
+                    class="flex items-center gap-8px lt-sm:flex-col lt-sm:items-start lt-sm:gap-8px"
+                  >
+                    <span class="text-#091221 pf-sc-semibold">
+                      {{ item.title }}
+                    </span>
+                    <span class="text-#091221/70 pf-sc-regular line-clamp-1">
+                      {{ item.itemDesc }}
+                    </span>
+                  </div>
                 </div>
               </div>
             </div>
             <button
-              class="mt-56px h-48px! w-268px! bg-#0F67F8 text-white pf-sc-regular rounded-8px px-16px flex items-center justify-between hover:opacity-80 transition-all"
+              class="mt-56px h-48px w-268px bg-#0F67F8 text-white pf-sc-regular rounded-8px px-16px flex items-center justify-between hover:opacity-80 transition-all"
               :class="[
                 index === activeIndex
                   ? 'opacity-100 translate-y-0 delay-300 duration-500'
@@ -130,13 +132,13 @@
               ]"
               @click="openConsultation"
             >
-              <span class="font-s-16px">立即咨询</span>
-              <i class="i-custom-arrow-right wh-18px"></i>
+              <span class="font-s-16px lt-sm:font-s-26px">立即咨询</span>
+              <i class="i-custom-arrow-right wh-18px lt-sm:wh-28px"></i>
             </button>
             <img
               :src="solution.hoverImg"
               alt=""
-              class="wh-280px absolute bottom--37px right-0 transition-all ease-out"
+              class="wh-280px lt-sm:wh-264px absolute bottom--37px lt-sm:bottom--26px right-0 transition-all ease-out"
               :class="[
                 index === activeIndex
                   ? 'opacity-100 scale-100 delay-100 duration-700'
@@ -147,7 +149,7 @@
 
           <!-- Normal State Content -->
           <div
-            class="h-full w-220px pt-40px px-24px absolute left-0 top-0 transition-all ease-in-out"
+            class="solution-card-normal"
             :class="[
               index === activeIndex
                 ? 'opacity-0 pointer-events-none duration-300'
@@ -196,6 +198,16 @@
           </div>
         </div>
       </div>
+
+      <div class="solution-dots lt-sm:flex hidden">
+        <div
+          v-for="(_, index) in solutions"
+          :key="index"
+          class="dot"
+          :class="{ active: index === activeIndex }"
+          @click="scrollToSolution(index)"
+        ></div>
+      </div>
     </section>
     <section
       id="ability"
@@ -203,24 +215,25 @@
       class="ability transition-all duration-1000 ease-out"
       :class="[isAbilityVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-100px']"
     >
-      <div class="font-s-36px text-#000000 pf-sc-semibold flex-center lh-60px">
+      <div
+        class="font-s-36px text-#000000 pf-sc-semibold flex-center lh-60px lt-sm:font-s-48px lt-sm:lh-60px"
+      >
         一体化智慧解决方案
       </div>
-      <div class="font-s-16px text-#091221/70 pf-sc-regular lh-30px flex-center mt-4px">
-        我们的一体化智慧解决方案整合了智能收费、智能运维、智能监控等多个功能模块,实现了物业管理的全流程数字化管理。
+      <div
+        class="font-s-16px text-#091221/70 pf-sc-regular lh-30px flex-center mt-4px lt-sm:font-s-24px lt-sm:lh-40px lt-sm:text-center lt-sm:px-60px"
+      >
+        绘家科技提供从软件到硬件的完整解决方案,覆盖物业管理的全场景需求
       </div>
-      <div class="mt-24px flex-center flex-col">
-        <div class="relative flex items-center rounded-14px border border-#ECEFF6 bg-#F6F8FD p-6px">
+      <div class="mt-24px flex-center flex-col lt-sm:mt-40px">
+        <div class="ability-tabs">
           <!-- 滑块背景 -->
-          <div
-            class="absolute w-136px h-[calc(100%-12px)] transition-all duration-300 ease-out rounded-8px bg-#0F67F8"
-            :style="abilityTabIndicatorStyle"
-          ></div>
+          <div class="ability-tab-indicator" :style="abilityTabIndicatorStyle"></div>
 
           <div
             v-for="tab in abilityTabs"
             :key="tab.title"
-            class="relative z-1 cursor-pointer py-14px px-20px text-center font-s-16px transition-colors duration-300 pf-sc-regular"
+            class="ability-tab-item"
             :class="[
               activeAbilityTab.id === tab.id ? 'text-white' : 'text-#091221 hover:text-#0F67F8',
             ]"
@@ -229,27 +242,29 @@
             {{ tab.title }}
           </div>
         </div>
-        <div class="tab-content pt-45px">
+        <div class="tab-content pt-45px lt-sm:pt-40px lt-sm:w-full">
           <Transition name="tab-fade" mode="out-in">
-            <div :key="activeAbilityTab.id" class="grid grid-cols-3 gap-24px">
+            <div :key="activeAbilityTab.id" class="grid grid-cols-3 gap-24px lt-sm:grid-cols-2">
               <div
                 v-for="ability in abilities[activeAbilityTab.id]"
                 :key="ability.title"
-                class="group relative flex flex-col rounded-16px border border-#ECEFF6 bg-[linear-gradient(0deg,_#FFFFFF_0%,_rgba(255,255,255,0.6)_100%)] p-24px transition-all duration-300 hover:border-#0F67F8/30 hover:shadow-[0_8px_24px_rgba(15,103,248,0.08)]"
+                class="ability-card"
               >
-                <i :class="ability.icon" class="wh-48px"></i>
-                <div class="mt-16px font-s-18px font-semibold text-#091221 pf-sc-semibold">
+                <i :class="ability.icon" class="wh-48px lt-sm:wh-78px"></i>
+                <div
+                  class="mt-16px font-s-18px lt-sm:font-s-32px font-semibold text-#091221 pf-sc-semibold"
+                >
                   {{ ability.title }}
                 </div>
-                <div class="mt-8px flex-1 font-s-14px text-#091221/70 pf-sc-regular">
-                  {{ ability.desc }}
-                </div>
                 <div
-                  class="mt-24px flex items-center gap-8px font-s-16px pf-sc-regular text-#0F67F8 transition-colors hover:text-#0A50FF cursor-pointer"
+                  class="mt-8px flex-1 font-s-14px lt-sm:font-s-24px lt-sm:mt-16px text-#091221/70 pf-sc-regular"
                 >
+                  {{ ability.desc }}
+                </div>
+                <div class="ability-card-link">
                   查看详情
                   <i
-                    class="i-custom-arrow-right-c color-#0F67F8 wh-18px transition-transform group-hover:translate-x-4px"
+                    class="i-custom-arrow-right-c color-#0F67F8 wh-18px lt-sm:wh-28px transition-transform group-hover:translate-x-4px"
                   ></i>
                 </div>
               </div>
@@ -261,57 +276,80 @@
     <section
       id="cases"
       ref="casesRef"
-      class="cases pt-120px pb-46px transition-all duration-1000 ease-out"
+      class="cases pt-120px pb-46px transition-all duration-1000 ease-out lt-sm:pt-120px lt-sm:pb-60px lt-sm:px-32px"
       :class="[isCasesVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-100px']"
     >
-      <div class="text-center mb-60px">
-        <div class="font-s-36px font-semibold text-#000000 pf-sc-semibold mb-4px lh-60px">
+      <div class="text-center mb-60px lt-sm:mb-60px lt-sm:px-32px">
+        <div
+          class="font-s-36px font-semibold text-#000000 pf-sc-semibold mb-4px lh-60px lt-sm:font-s-48px lt-sm:mb-16px"
+        >
           知识产权和案例
         </div>
-        <div class="font-s-16px text-#091221/70 pf-sc-regular lh-30px">
+        <div
+          class="font-s-16px text-#091221/70 pf-sc-regular lh-30px lt-sm:font-s-24px lt-sm:lh-40px"
+        >
           绘家科技凭借强大的技术实力和丰富的实践经验,为客户提供卓越的智慧社区解决方案
         </div>
       </div>
 
-      <div class="flex gap-24px">
+      <div class="cases-list" ref="casesListRef" @scroll="handleCaseScroll">
         <div
-          v-for="caseItem in cases"
+          v-for="(caseItem, index) in cases"
           :key="caseItem.title"
-          class="group flex-1 overflow-hidden rounded-16px bg-#F6F8FD p-32px transition-all duration-300"
+          class="cases-card"
+          :class="{ active: index === activeCaseIndex }"
         >
-          <div class="flex flex-col">
-            <img :src="caseItem.img" class="w-full h-218px rounded-12px" alt="" />
-            <div class="font-s-18px font-semibold text-#091221 pf-sc-semibold mt-24px">
+          <div class="flex flex-col h-full">
+            <img
+              :src="caseItem.img"
+              class="w-full h-218px rounded-12px lt-sm:h-320px lt-sm:rounded-24px"
+              alt=""
+            />
+            <div
+              class="font-s-18px font-semibold text-#091221 pf-sc-semibold mt-24px lt-sm:font-s-32px lt-sm:mt-32px"
+            >
               {{ caseItem.title }}
             </div>
-            <div class="mt-8px font-s-14px lh-24px text-#091221/70 pf-sc-regular">
+            <div
+              class="mt-8px font-s-14px lh-24px text-#091221/70 pf-sc-regular lt-sm:font-s-24px lt-sm:lh-36px lt-sm:mt-16px"
+            >
               {{ caseItem.desc }}
             </div>
-            <div class="mt-24px flex flex-col gap-8px">
+            <div class="mt-24px flex flex-col gap-8px lt-sm:mt-32px lt-sm:gap-16px flex-1">
               <div
                 v-for="point in caseItem.points"
                 :key="point.title"
-                class="flex items-center gap-8px"
+                class="flex items-center gap-8px lt-sm:gap-12px"
               >
-                <i class="i-custom-check-one wh-20px mt-2px"></i>
-                <div class="font-s-14px font-semibold text-#091221 pf-sc-semibold">
+                <i class="i-custom-check-one wh-20px mt-2px lt-sm:wh-32px"></i>
+                <div
+                  class="font-s-14px font-semibold text-#091221 pf-sc-semibold lt-sm:font-s-24px"
+                >
                   {{ point.title }}
                 </div>
-                <div class="font-s-14px text-#091221/70 pf-sc-regular">
+                <div class="font-s-14px text-#091221/70 pf-sc-regular lt-sm:font-s-24px">
                   {{ point.itemDesc }}
                 </div>
               </div>
             </div>
 
-            <button
-              class="mt-56px flex items-center justify-between gap-8px rounded-8px bg-white px-16px py-15px font-s-16px text-#0F67F8 transition-all hover:bg-#0F67F8 hover:text-white"
-            >
+            <button class="cases-btn">
               {{ caseItem.btnText }}
-              <i class="i-custom-arrow-right-c wh-18px"></i>
+              <i class="i-custom-arrow-right-c wh-18px lt-sm:wh-32px lt-sm:text-white"></i>
             </button>
           </div>
         </div>
       </div>
+
+      <div class="cases-dots lt-sm:flex hidden">
+        <div
+          v-for="(_, index) in cases"
+          :key="index"
+          class="dot"
+          :class="{ active: index === activeCaseIndex }"
+          @click="scrollToCase(index)"
+        ></div>
+      </div>
     </section>
     <section
       id="partnership"
@@ -330,21 +368,13 @@
       <div class="relative flex flex-col gap-0px -mt-24px">
         <!-- 第一行 -->
         <InspiraMarquee class="[--duration:80s] [--gap:24px] mb--31px">
-          <div
-            v-for="partner in partnersRow1"
-            :key="partner"
-            class="flex-center h-80px w-200px bg-white rounded-8px shadow-[0_2px_8px_2px_rgba(0,0,0,0.06)] px-24px"
-          >
+          <div v-for="partner in partnersRow1" :key="partner" class="partner-item">
             <img :src="partner" alt="" class="wh-full object-contain" />
           </div>
         </InspiraMarquee>
         <!-- 第二行 -->
         <InspiraMarquee reverse class="[--duration:80s] [--delay:-20s] [--gap:24px]">
-          <div
-            v-for="partner in partnersRow2"
-            :key="partner"
-            class="flex-center h-80px w-200px bg-white rounded-8px shadow-[0_2px_8px_2px_rgba(0,0,0,0.06)] px-24px"
-          >
+          <div v-for="partner in partnersRow2" :key="partner" class="partner-item">
             <img :src="partner" alt="" class="wh-full object-contain" />
           </div>
         </InspiraMarquee>
@@ -433,7 +463,7 @@
                 </div>
                 <div class="h-2px w-34px bg-#0F67F8 mt-11px content-stagger-2 origin-left"></div>
                 <div
-                  class="w-full text-20px lh-35px text-#091221/70 pf-sc-regular mt-26px content-stagger-3"
+                  class="w-full font-s-20px lh-35px text-#091221/70 pf-sc-regular mt-26px content-stagger-3"
                 >
                   {{ currentEventData?.content }}
                 </div>
@@ -531,6 +561,58 @@
   const { openConsultation } = useConsultation()
 
   const activeIndex = ref(0)
+  const solutionListRef = ref<HTMLElement | null>(null)
+
+  const handleSolutionScroll = (e: Event) => {
+    const el = e.target as HTMLElement
+    const scrollLeft = el.scrollLeft
+    const width = el.offsetWidth
+    // 计算当前处于中间的卡片索引
+    // 卡片宽度为 85%,加上 gap 16px
+    const cardWidth = width * 0.85
+    const gap = 16
+    const newIndex = Math.round(scrollLeft / (cardWidth + gap))
+    if (newIndex !== activeIndex.value) {
+      activeIndex.value = newIndex
+    }
+  }
+
+  const scrollToSolution = (index: number) => {
+    if (!solutionListRef.value) return
+    const width = solutionListRef.value.offsetWidth
+    const cardWidth = width * 0.85
+    const gap = 16
+    solutionListRef.value.scrollTo({
+      left: index * (cardWidth + gap),
+      behavior: 'smooth',
+    })
+  }
+
+  const activeCaseIndex = ref(0)
+  const casesListRef = ref<HTMLElement | null>(null)
+
+  const handleCaseScroll = (e: Event) => {
+    const el = e.target as HTMLElement
+    const scrollLeft = el.scrollLeft
+    const width = el.offsetWidth
+    const cardWidth = width * 0.9
+    const gap = 16
+    const newIndex = Math.round(scrollLeft / (cardWidth + gap))
+    if (newIndex !== activeCaseIndex.value) {
+      activeCaseIndex.value = newIndex
+    }
+  }
+
+  const scrollToCase = (index: number) => {
+    if (!casesListRef.value) return
+    const width = casesListRef.value.offsetWidth
+    const cardWidth = width * 0.9
+    const gap = 16
+    casesListRef.value.scrollTo({
+      left: index * (cardWidth + gap),
+      behavior: 'smooth',
+    })
+  }
   const solutionRef = ref<HTMLElement | null>(null)
   const abilityRef = ref<HTMLElement | null>(null)
   const partnershipRef = ref<HTMLElement | null>(null)
@@ -605,7 +687,7 @@
   const abilityTabIndicatorStyle = computed(() => {
     const activeTabIndex = abilityTabs.findIndex((tab) => tab.id === activeAbilityTab.value.id)
     return {
-      transform: `translateX(${activeTabIndex * 136}px)`,
+      transform: `translateX(${activeTabIndex * 100}%)`,
     }
   })
 
@@ -679,6 +761,7 @@
 </script>
 <style scoped lang="scss">
   .landing {
+    @apply lt-sm:pt-120px;
     color: var(--hj-text);
     background: var(--hj-bg);
   }
@@ -693,34 +776,228 @@
       @extend %landing-container;
     }
 
+    .hero-title {
+      @apply font-s-48px font-semibold text-#000000 lt-sm:font-s-58px;
+    }
+
+    .hero-subtitle {
+      @apply font-s-18px text-#091221/70 lt-sm:mt-12px lt-sm:font-s-26px lt-sm:px-25px lt-xs:px-0;
+    }
+
+    .hero-actions {
+      @apply mt-35px flex items-center gap-16px lt-sm:justify-center lt-sm:absolute lt-sm:bottom-80px lt-sm:left-1/2 lt-sm:-translate-x-1/2;
+    }
+
+    .hero-btn-primary {
+      @apply w-127px h-56px rounded-8px text-white font-s-18px pf-sc-semibold lt-sm:w-168px lt-sm:h-71px lt-sm:font-s-24px;
+    }
+
+    .hero-btn-outline {
+      @apply w-127px h-56px bg-white border-#0F67F8 border-1 rounded-8px hover:opacity-80 font-s-18px font-semibold text-#0F67F8 lt-sm:w-168px lt-sm:h-71px lt-sm:font-s-24px;
+    }
+
     .metric {
-      @apply flex items-start flex-col;
+      @apply flex items-start flex-col lt-sm:items-center;
 
       .metric-value {
-        @apply font-s-32px font-semibold text-#0F67F8;
+        @apply font-s-32px font-semibold text-#0F67F8 lt-sm:font-s-52px;
       }
 
       .metric-label {
-        @apply font-s-14px text-#384146;
+        @apply font-s-14px text-#384146 lt-sm:font-s-24px;
       }
     }
+
+    @screen lt-sm {
+      @apply w-full h-auto;
+      aspect-ratio: 750/880;
+      background-image: url('@/assets/images/banner-mobile.png');
+      background-size: 100% 100%;
+      background-repeat: no-repeat;
+      background-position: center;
+    }
   }
 
   .solution {
     @extend %landing-container;
+    @apply lt-sm:px-0;
+  }
+
+  .solution-list {
+    @apply flex h-365px w-full gap-24px;
+    @screen lt-sm {
+      @apply h-auto gap-16px overflow-x-auto overflow-y-hidden px-24px;
+      scroll-snap-type: x mandatory;
+      scrollbar-width: none; /* Firefox */
+      &::-webkit-scrollbar {
+        display: none; /* Safari and Chrome */
+      }
+    }
+  }
+
+  .solution-card {
+    @apply lt-sm:flex-[0_0_90%] lt-sm:min-h-750px lt-sm:w-630px;
+    position: relative;
+    display: flex;
+    height: 100%;
+    cursor: pointer;
+    overflow: hidden;
+    border-radius: 24px;
+    will-change: transform, opacity;
+    transition:
+      transform 600ms cubic-bezier(0.34, 1.56, 0.64, 1),
+      opacity 600ms ease,
+      flex 600ms ease-in-out,
+      background-color 600ms ease-in-out;
+
+    @media (min-width: 768px) {
+      &.active {
+        flex: 1 1 0%;
+      }
+      &:not(.active) {
+        flex: 0 0 220px;
+      }
+    }
+
+    @screen lt-sm {
+      scroll-snap-align: center;
+
+      &:not(.active) {
+        transform: scale(0.96);
+        opacity: 0.5;
+      }
+
+      &.active {
+        transform: scale(1);
+        opacity: 1;
+      }
+
+      &:first-child {
+        margin-left: 36px;
+      }
+
+      &:last-child {
+        margin-right: 36px;
+      }
+    }
+  }
+
+  .solution-card-hover {
+    @apply h-full w-full pt-40px px-48px absolute left-0 top-0 transition-all ease-in-out;
+    @apply lt-sm:relative lt-sm:pt-40px lt-sm:px-36px lt-sm:pb-32px lt-sm:opacity-100 lt-sm:translate-y-0 lt-sm:pointer-events-auto;
+    &.mobile-show {
+      @apply lt-sm:opacity-100 lt-sm:translate-y-0 lt-sm:pointer-events-auto;
+    }
+    button {
+      @apply lt-sm:w-270px lt-sm:h-95px lt-sm:rounded-16px lt-sm:mt-102px lt-sm:px-;
+    }
+  }
+
+  .solution-card-normal {
+    @apply h-full w-220px pt-40px px-24px absolute left-0 top-0 transition-all ease-in-out;
+    @screen lt-sm {
+      @apply hidden;
+    }
+  }
+
+  .solution-dots {
+    @apply lt-sm:mt-40px flex-center lt-sm:gap-16px;
+    .dot {
+      @apply lt-sm:w-60px lt-sm:h-10px bg-#E5E9F5 rounded-full transition-all cursor-pointer;
+      &.active {
+        @apply bg-#0F67F8;
+      }
+    }
   }
 
   .ability {
-    @apply py-120px;
+    @apply py-120px lt-sm:py-120px lt-sm:px-32px;
     @extend %landing-container;
     background-size: 100% 100%;
     background-image: url('@/assets/images/bg-ability.png');
   }
 
+  .ability-tabs {
+    @apply relative flex items-center rounded-14px border border-#ECEFF6 bg-#F6F8FD p-6px;
+    @apply lt-sm:rounded-16px lt-sm:p-8px;
+    @screen lt-sm {
+      width: calc(100% - 40px);
+    }
+  }
+
+  .ability-tab-indicator {
+    @apply absolute w-136px h-[calc(100%-12px)] transition-all duration-300 ease-out rounded-8px bg-#0F67F8;
+    @apply lt-sm:w-[calc((100%-16px)/3)] lt-sm:h-[calc(100%-16px)] lt-sm:rounded-12px;
+  }
+
+  .ability-tab-item {
+    @apply relative z-1 cursor-pointer py-14px px-20px text-center font-s-16px transition-colors duration-300 pf-sc-regular;
+    @apply lt-sm:flex-1 lt-sm:px-0 lt-sm:py-20px lt-sm:font-s-28px;
+  }
+
+  .ability-card {
+    @apply group relative flex flex-col rounded-16px border border-#ECEFF6 bg-[linear-gradient(0deg,_#FFFFFF_0%,_rgba(255,255,255,0.6)_100%)] p-24px transition-all duration-300 hover:border-#0F67F8/30 hover:shadow-[0_8px_24px_rgba(15,103,248,0.08)];
+    @apply lt-sm:p-24px lt-sm:rounded-24px;
+  }
+
+  .ability-card-link {
+    @apply mt-24px flex items-center gap-8px font-s-16px pf-sc-regular text-#0F67F8 transition-colors hover:text-#0A50FF cursor-pointer;
+    @apply lt-sm:mt-48px lt-sm:font-s-28px;
+  }
+
+  .tab-content {
+    @apply lt-sm:w-full;
+  }
+
   .cases {
+    @apply lt-sm:px-0px;
     @extend %landing-container;
   }
 
+  .cases-list {
+    @apply flex gap-24px;
+    @screen lt-sm {
+      @apply gap-36px overflow-x-auto overflow-y-hidden px-0 pb-10px;
+      scroll-snap-type: x mandatory;
+      scrollbar-width: none;
+      &::-webkit-scrollbar {
+        display: none;
+      }
+    }
+  }
+
+  .cases-card {
+    @apply group flex-1 overflow-hidden rounded-16px bg-#F6F8FD p-32px transition-all duration-300;
+    @screen lt-sm {
+      @apply flex-none w-[calc(100vw-84px)] min-w-[calc(100vw-84px)] p-32px rounded-16px;
+      scroll-snap-align: center;
+      &:first-child {
+        margin-left: 42px;
+      }
+
+      &:last-child {
+        margin-right: 42px;
+      }
+    }
+  }
+
+  .cases-btn {
+    @apply mt-56px flex items-center justify-between gap-8px rounded-8px bg-white px-16px py-15px font-s-16px text-#0F67F8 transition-all hover:bg-#0F67F8 hover:text-white;
+    @screen lt-sm {
+      @apply mt-48px h-96px rounded-8px px-32px font-s-28px bg-#0F67F8 text-white;
+    }
+  }
+
+  .cases-dots {
+    @apply lt-sm:mt-40px lt-sm:flex-center lt-sm:gap-16px;
+    .dot {
+      @apply lt-sm:w-60px lt-sm:h-10px bg-#E5E9F5 rounded-full transition-all cursor-pointer;
+      &.active {
+        @apply bg-#0F67F8;
+      }
+    }
+  }
+
   .partnership {
     @extend %landing-container;
     @media screen and (min-width: 1920px) {
@@ -729,6 +1006,10 @@
     }
   }
 
+  .partner-item {
+    @apply flex-center h-80px w-200px bg-white rounded-8px shadow-[0_2px_8px_2px_rgba(0,0,0,0.06)] px-24px;
+  }
+
   .tab-fade-enter-active {
     transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
   }
@@ -752,10 +1033,29 @@
     animation: card-slide-up 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
   }
 
-  @for $i from 1 through 10 {
-    .grid > div:nth-child(#{$i}) {
-      animation-delay: #{$i * 0.05}s;
-    }
+  .grid > div:nth-child(1) {
+    animation-delay: 0.05s;
+  }
+  .grid > div:nth-child(2) {
+    animation-delay: 0.1s;
+  }
+  .grid > div:nth-child(3) {
+    animation-delay: 0.15s;
+  }
+  .grid > div:nth-child(4) {
+    animation-delay: 0.2s;
+  }
+  .grid > div:nth-child(5) {
+    animation-delay: 0.25s;
+  }
+  .grid > div:nth-child(6) {
+    animation-delay: 0.3s;
+  }
+  .grid > div:nth-child(7) {
+    animation-delay: 0.35s;
+  }
+  .grid > div:nth-child(8) {
+    animation-delay: 0.4s;
   }
 
   @keyframes card-slide-up {

+ 40 - 0
app/plugins/rem.client.ts

@@ -0,0 +1,40 @@
+/*
+ * @Author: LiZhiWei
+ * @Date: 2026-01-19 09:12:33
+ * @LastEditors: LiZhiWei
+ * @LastEditTime: 2026-01-19 09:12:36
+ * @Description:
+ */
+// plugins/rem.client.ts
+export default defineNuxtPlugin((nuxtApp) => {
+  const setRem = () => {
+    const designWidth = 1920 // 我们的设计稿宽度
+    const baseSize = 16 // 我们希望的最大基准值 (1rem = 16px)
+    const clientWidth = document.documentElement.clientWidth
+
+    // 核心计算公式:缩放比例 = 当前视宽 / 设计稿宽度
+    const remSize = (clientWidth / designWidth) * baseSize
+
+    // 【关键】设置字体大小,并限制其在 12px 到 16px 之间
+    // 这意味着:屏幕小于 1920px 时会缩小,大于 1920px 时根字体大小稳定在 16px
+    document.documentElement.style.fontSize = `${Math.min(Math.max(remSize, 12), 16)}px`
+  }
+
+  let timer: NodeJS.Timeout | null = null
+  const setRemDebounced = () => {
+    if (timer) clearTimeout(timer)
+    timer = setTimeout(setRem, 250) // 防抖优化
+  }
+
+  // App 挂载后设置并监听 resize
+  nuxtApp.hook('app:mounted', () => {
+    setRem()
+    window.addEventListener('resize', setRemDebounced)
+  })
+
+  // App 卸载前清理
+  nuxtApp.hook('app:beforeMount', () => {
+    window.removeEventListener('resize', setRemDebounced)
+    if (timer) clearTimeout(timer)
+  })
+})

+ 1 - 1
nuxt.config.ts

@@ -3,7 +3,7 @@
  * @Author: wjc
  * @Date: 2023-10-25 19:39:32
  * @LastEditors: LiZhiWei
- * @LastEditTime: 2026-01-14 15:15:30
+ * @LastEditTime: 2026-01-19 09:24:19
  * @Description:
  */
 import { loadEnv } from 'vite'

Plik diff jest za duży
+ 4 - 0
public/images/logo.svg


+ 56 - 1
uno.config.ts

@@ -2,7 +2,7 @@
  * @Author: wjc
  * @Date: 2023-05-07 20:59:28
  * @LastEditors: LiZhiWei
- * @LastEditTime: 2026-01-15 15:04:36
+ * @LastEditTime: 2026-01-19 09:29:31
  * @Description:
  */
 import {
@@ -30,7 +30,62 @@ export default defineConfig({
       },
     }),
   ],
+  postprocess: (util) => {
+    const pxRE = /(-?[\d.]+px)/g
+    // 检查选择器是否包含移动端变体(lt-sm, lt-xs)
+    const isMobile = util.selector.includes('lt-sm') || util.selector.includes('lt-xs')
+
+    if (isMobile) {
+      util.entries.forEach((i) => {
+        const value = i[1]
+        if (typeof value === 'string' && pxRE.test(value)) {
+          // 移动端:按 750px 设计稿转换 (px / 7.5)
+          i[1] = value.replace(pxRE, (match) => {
+            const px = parseFloat(match)
+            if (isNaN(px)) return match
+            return `${(px / 7.5).toFixed(5)}vw`
+          })
+        }
+      })
+    }
+  },
   transformers: [transformerDirectives(), transformerVariantGroup()],
+  postprocess: (util) => {
+    const pxRE = /(-?[\d.]+px)/g
+    // 检查是否属于移动端变体(通过选择器或媒体查询父级判断)
+    const isMobile =
+      util.selector.includes('lt-sm') ||
+      util.selector.includes('lt-xs') ||
+      (util.parent?.includes('max-width: 767') ?? false) ||
+      (util.parent?.includes('max-width: 479') ?? false)
+
+    if (isMobile) {
+      util.entries.forEach((i) => {
+        const value = i[1]
+        if (typeof value === 'string' && pxRE.test(value)) {
+          // 移动端:强制按 750px 设计稿转换 (px / 7.5)
+          i[1] = value.replace(pxRE, (match) => {
+            const px = parseFloat(match)
+            if (isNaN(px)) return match
+            return `${(px / 7.5).toFixed(5)}vw`
+          })
+        }
+      })
+    } else {
+      // PC 端逻辑:如果你希望 PC 端也转换(按 1920),取消下面注释
+      /*
+      util.entries.forEach((i) => {
+        const value = i[1]
+        if (typeof value === 'string' && pxRE.test(value)) {
+          i[1] = value.replace(pxRE, (match) => {
+            const px = parseFloat(match)
+            return `${(px / 19.2).toFixed(5)}vw`
+          })
+        }
+      })
+      */
+    }
+  },
   rules: [
     [/^m-h-(.+)$/, ([, d]) => ({ 'margin-left': `${d}`, 'margin-right': `${d}` })],
     [/^m-v-(.+)$/, ([, d]) => ({ 'margin-top': `${d}`, 'margin-bottom': `${d}` })],

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików