lanxin пре 1 дан
родитељ
комит
0becf9646e
71 измењених фајлова са 1640 додато и 499 уклоњено
  1. 26 7
      bigScene/hot/src/views/Home.vue
  2. 3 3
      bigScene/scene/public/css/oldVer/main0.css
  3. BIN
      bigScene/scene/public/images/auto-suspend.png
  4. BIN
      bigScene/scene/public/images/auto.png
  5. BIN
      bigScene/scene/public/images/dollhouse.png
  6. BIN
      bigScene/scene/public/images/dollhouse_active.png
  7. BIN
      bigScene/scene/public/images/floor.png
  8. BIN
      bigScene/scene/public/images/floor_active.png
  9. BIN
      bigScene/scene/public/images/inside.png
  10. BIN
      bigScene/scene/public/images/inside_active.png
  11. 2 2
      bigScene/scene/public/js/Hot.js
  12. BIN
      bigScene/scene/src/assets/img/like.png
  13. BIN
      bigScene/scene/src/assets/img/likeAc.png
  14. BIN
      bigScene/scene/src/assets/img/shareBtn.png
  15. 13 11
      bigScene/scene/src/assets/styles/base.css
  16. 12 0
      bigScene/scene/src/assets/styles/base.less
  17. 80 13
      bigScene/scene/src/pages/A2main/index.module.scss
  18. 8 1
      bigScene/scene/src/pages/A2main/index.tsx
  19. 34 21
      bigScene/scene/src/pages/A3hotList/index.module.scss
  20. 1 0
      pano/src/components/Pano/index.tsx
  21. 82 2
      project/public/three/data.js
  22. 47 3
      project/src/App.tsx
  23. BIN
      project/src/assets/img/A0_home_1_M.jpg
  24. BIN
      project/src/assets/img/A0_home_2_M.jpg
  25. BIN
      project/src/assets/img/A0_home_3_M.jpg
  26. BIN
      project/src/assets/img/A0_home_btn_M.png
  27. BIN
      project/src/assets/img/A0_home_title_M.png
  28. BIN
      project/src/assets/img/A7_animation_bg.jpg
  29. BIN
      project/src/assets/img/A7_animation_btn.png
  30. BIN
      project/src/assets/img/back1.png
  31. BIN
      project/src/assets/img/close_M.png
  32. BIN
      project/src/assets/img/landtip.png
  33. BIN
      project/src/assets/img/topBar_bg_M.png
  34. 32 0
      project/src/assets/styles/base.css
  35. 37 0
      project/src/assets/styles/base.less
  36. 44 0
      project/src/components/TopBarM/index.module.scss
  37. 28 0
      project/src/components/TopBarM/index.tsx
  38. 9 0
      project/src/components/Zback/index.module.scss
  39. 4 2
      project/src/components/Zback/index.tsx
  40. 2 0
      project/src/components/Zvideo/index.module.scss
  41. 25 4
      project/src/components/Zvideo/index.tsx
  42. 63 0
      project/src/pages/A0baseM/index.module.scss
  43. 77 0
      project/src/pages/A0baseM/index.tsx
  44. 1 1
      project/src/pages/A1home/index.tsx
  45. 93 0
      project/src/pages/A1homeM/PanoHot/Swiper2/index.module.scss
  46. 54 0
      project/src/pages/A1homeM/PanoHot/Swiper2/index.tsx
  47. 109 0
      project/src/pages/A1homeM/PanoHot/index.module.scss
  48. 77 0
      project/src/pages/A1homeM/PanoHot/index.tsx
  49. 112 0
      project/src/pages/A1homeM/index.module.scss
  50. 81 0
      project/src/pages/A1homeM/index.tsx
  51. 1 1
      project/src/pages/A2scene/index.tsx
  52. 1 1
      project/src/pages/A4member/index.tsx
  53. 125 0
      project/src/pages/A7animationM/Swiper3/index.module.scss
  54. 68 0
      project/src/pages/A7animationM/Swiper3/index.tsx
  55. 41 0
      project/src/pages/A7animationM/index.module.scss
  56. 41 0
      project/src/pages/A7animationM/index.tsx
  57. 2 0
      project/src/types/declaration.d.ts
  58. 205 427
      project/yarn.lock
  59. BIN
      静态文件/myData/media/jianzhu.mp4
  60. BIN
      静态文件/myData/media/siji.mp4
  61. BIN
      静态文件/myData/mobile/1.png
  62. BIN
      静态文件/myData/mobile/10.png
  63. BIN
      静态文件/myData/mobile/11.png
  64. BIN
      静态文件/myData/mobile/2.png
  65. BIN
      静态文件/myData/mobile/3.png
  66. BIN
      静态文件/myData/mobile/4.png
  67. BIN
      静态文件/myData/mobile/5.png
  68. BIN
      静态文件/myData/mobile/6.png
  69. BIN
      静态文件/myData/mobile/7.png
  70. BIN
      静态文件/myData/mobile/8.png
  71. BIN
      静态文件/myData/mobile/9.png

+ 26 - 7
bigScene/hot/src/views/Home.vue

@@ -369,6 +369,7 @@ export default {
         }
         .videoBox {
           padding: 0px 50px;
+          height: 84%;
           video {
             width: 100%;
             height: 100%;
@@ -510,8 +511,8 @@ export default {
 // 移动端
 @media screen and (max-width: 1000px) {
   .home {
-    background: url("../assets/images/pc/hot_bg_M.png") no-repeat center center;
-    background-size: 100% 100% !important;
+    background: rgba(70, 47, 9, 0.8) ;
+    backdrop-filter: blur(5px);
     .swiper-pagination {
       margin: 10px 0 0;
       gap: 4px;
@@ -530,13 +531,14 @@ export default {
       height: 100%;
       padding: 16% 0 0 0;
       position: absolute;
+      justify-content: space-between;
       .myTitle {
         font-size: 16px;
         margin: 8px 0;
       }
       .mainCon {
         border-radius: 0;
-        height: calc(100% - 300px);
+        height: 60%;
         width: 100%;
         margin-top: 0;
 
@@ -576,11 +578,21 @@ export default {
         }
       }
       .txtBox {
+        position: relative;
+        top: 0;
+        width: 100%;
+        height: 30%;
+        background: linear-gradient(180deg, #A56F2C 0%, #824E0F 41.35%, #4F310C 100%);
+        border-radius: 20px 20px 0 0 ;
+        .myTitle {
+          height: 55px;
+          overflow: auto;
+        }
         .flooTxt {
           margin-top: -5px;
           width: 100%;
           padding: 10px 15px 0px 15px;
-          max-height: 200px;
+          height: calc(100% - 75px);
 
           .flooTxtBox {
             padding: 0;
@@ -598,14 +610,21 @@ export default {
     }
     .flooTabBox {
       width: 100%;
-      bottom: 220px;
-      right: 0;
+      height: 50px;
+      bottom: 30%;
       justify-content: center;
+      gap: 0.5%;
       .tabRow {
         cursor: default;
         // margin: 0 6px;
         // padding: 0 10px;
-        height: 32px;
+        height: 50px;
+        width: 100px;
+        font-size: 14px;
+        & > div{
+
+          line-height: 50px;
+        }
         & > img {
           width: 30px;
         }

+ 3 - 3
bigScene/scene/public/css/oldVer/main0.css

@@ -207,8 +207,8 @@ a {
 }
 @media screen and (max-width: 1000px) {
   .popup-content {
-    width: 90%;
-    height: 80%;
+    width: 100%;
+    height: 100%;
   }
 }
 @media screen and (max-width: 768px) {
@@ -236,7 +236,7 @@ a {
     width: 30px;
     height: 30px;
     position: absolute;
-    top: 11%;
+    top: 30px;
     right: 25px;
   }
 

BIN
bigScene/scene/public/images/auto-suspend.png


BIN
bigScene/scene/public/images/auto.png


BIN
bigScene/scene/public/images/dollhouse.png


BIN
bigScene/scene/public/images/dollhouse_active.png


BIN
bigScene/scene/public/images/floor.png


BIN
bigScene/scene/public/images/floor_active.png


BIN
bigScene/scene/public/images/inside.png


BIN
bigScene/scene/public/images/inside_active.png


+ 2 - 2
bigScene/scene/public/js/Hot.js

@@ -55,8 +55,8 @@ window.initHot = function (model) {
       o = 'en' == manage.number('lang') ? '&lang=' + manage.number('lang') : ''
       ; -1 == r.indexOf('?') ? (src = link + '?time=' + randomTime().getTime() + '&id=' + window.number + o) : (src = link + '&time=' + randomTime().getTime() + '&id=' + window.number + o)
 
-    return src.replace('https://www.4dmodel.com/SuperTwo/hot_online1', './hot')
-    // return src.replace('https://www.4dmodel.com/SuperTwo/hot_online1', 'http://localhost:8080')
+    // return src.replace('https://www.4dmodel.com/SuperTwo/hot_online1', './hot')
+    return src.replace('https://www.4dmodel.com/SuperTwo/hot_online1', 'http://192.168.0.78:8081')
     // return src
   }
   var removeSrcPostMark = function (url) {

BIN
bigScene/scene/src/assets/img/like.png


BIN
bigScene/scene/src/assets/img/likeAc.png


BIN
bigScene/scene/src/assets/img/shareBtn.png


+ 13 - 11
bigScene/scene/src/assets/styles/base.css

@@ -9,15 +9,9 @@ html {
   user-select: none;
 }
 body {
-  font: 1em/1.4 'Microsoft Yahei', 'PingFang SC', 'Avenir', 'Segoe UI', 'Hiragino Sans GB',
-    'STHeiti', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei', sans-serif;
+  font: 1em/1.4 'Microsoft Yahei', 'PingFang SC', 'Avenir', 'Segoe UI', 'Hiragino Sans GB', 'STHeiti', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei', sans-serif;
   height: 100%;
 }
-@font-face {
-  font-family: 'fzFont';
-  /* 自定义字体名称 */
-  src: url('../font/fzFont.TTF') format('truetype');
-}
 a {
   text-decoration: none;
   outline: none;
@@ -58,6 +52,14 @@ textarea {
 [hidden] {
   display: none !important;
 }
+.cad {
+  pointer-events: none;
+}
+#cad path {
+  stroke-width: 0.5;
+  fill: rgba(249, 211, 109, 0.8);
+  stroke: #f9d36d;
+}
 .mySorrlNo::-webkit-scrollbar {
   /*滚动条整体样式*/
   width: 0px;
@@ -141,12 +143,12 @@ body,
   position: relative;
   overflow: hidden;
 }
+.ant-message {
+  z-index: 30010 !important;
+}
 .likeMoveAc {
   animation: likeMoveAc 2s linear forwards;
 }
-.room-label p {
-  color: #FDFBB2;
-}
 @keyframes likeMoveAc {
   0% {
     opacity: 1;
@@ -169,4 +171,4 @@ body,
   html .cad {
     top: 20px;
   }
-}
+}

+ 12 - 0
bigScene/scene/src/assets/styles/base.less

@@ -66,6 +66,14 @@ textarea {
 [hidden] {
   display: none !important;
 }
+.cad{
+  pointer-events: none;
+}
+#cad path {
+  stroke-width: 0.5;
+  fill: rgba(249, 211, 109, 0.8);
+  stroke: rgba(249, 211, 109, 1);
+}
 
 // 滚动条
 .mySorrlNo::-webkit-scrollbar {
@@ -170,6 +178,10 @@ body,
   overflow: hidden;
 }
 
+.ant-message{
+  z-index: 30010 !important;
+}
+
 // 点赞的动画
 .likeMoveAc {
   animation: likeMoveAc 2s linear forwards;

+ 80 - 13
bigScene/scene/src/pages/A2main/index.module.scss

@@ -5,36 +5,36 @@
       display: none !important;
     }
 
-    .sceneTitle{
+    .sceneTitle {
       position: fixed;
       top: 1vh;
-      left:50%;
+      left: 50%;
       transform: translateX(-50%);
       width: 18vw;
       height: 12vh;
-      img{
+      img {
         width: 100%;
         height: 100%;
         object-fit: contain;
       }
     }
 
-    .shareBox{
+    .shareBox {
       position: fixed;
       top: 12vh;
-      left:50%;
+      left: 50%;
       transform: translateX(-50%);
       width: 20vw;
       height: 33vw;
-     
-      .shareBox1{
+
+      .shareBox1 {
         width: 100%;
         height: 90%;
         background-image: url('../../assets/img/shareBoxBg.png');
         background-size: 100% 100%;
         background-repeat: no-repeat;
         background-position: center center;
-        .txt1{
+        .txt1 {
           width: 100%;
           height: 30%;
           color: rgba(249, 211, 109, 1);
@@ -42,23 +42,23 @@
           line-height: 20vh;
           text-align: center;
         }
-        .code{
+        .code {
           width: 100%;
           height: 30%;
           margin-top: 20%;
-          & > img{
+          & > img {
             width: 100%;
             height: 100%;
             object-fit: contain;
           }
         }
       }
-      .closeBox{
+      .closeBox {
         width: 100%;
         height: 10%;
         margin-top: 1vh;
         cursor: pointer;
-        & > img{
+        & > img {
           width: 100%;
           height: 100%;
           object-fit: contain;
@@ -205,7 +205,7 @@
       }
     }
     #thumb-container {
-      width: 100% !important;
+      width: fit-content !important;
       display: flex;
       justify-content: flex-start;
       align-items: center;
@@ -351,6 +351,73 @@
     // 移动端
 
     @media screen and (max-width: 1000px) {
+      .sceneTitle {
+        display: none;
+      }
+      .shareBox {
+        width: 100%;
+        height: 100%;
+        z-index: 30001;
+        top: 0;
+        left: 50%;
+        background-color: rgba(70, 47, 9, 0.8);
+        backdrop-filter: blur(5px);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        flex-direction: column;
+        .shareBox1 {
+          width: 82%;
+          height: 60%;
+          margin: 0 auto;
+          background-size: contain;
+          .txt1{
+            opacity: 0;
+          }
+          .code {
+            & > img {
+              width: 100%;
+              height: 100%;
+              object-fit: contain;
+            }
+          }
+        }
+        .shareBtn{
+          width: 80%;
+          height: 50px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          gap: 20px;
+          & > div{
+            width: 110px;
+            height: 60px;
+            background-image: url(../../assets/img/shareBtn.png);
+            background-size: contain;
+            background-repeat: no-repeat;
+            background-position: center center;
+            cursor: pointer;
+            font-size: 13px;
+            color: rgba(112, 73, 7, 1);
+            line-height: 60px;
+            text-align: center;
+          }
+        }
+        
+        .closeBox{
+          width: 40px;
+          height: 40px;
+          position: absolute;
+          top: 20px;
+          right: 20px;
+          cursor: pointer;
+          & > img {
+            width: 100%;
+            height: 100%;
+            object-fit: contain;
+          }
+        }
+      }
       .hoveImg {
         height: 20px;
         top: 30px;

+ 8 - 1
bigScene/scene/src/pages/A2main/index.tsx

@@ -10,11 +10,12 @@ import classNames from 'classnames'
 import A3hotList from '../A3hotList'
 import { message } from 'antd'
 import http from '@/utils/http'
+import { isMobileFu } from '@/utils/history'
 const imgArrTemp = ['like.png', 'likeAc.png']
 const imgArr = imgArrTemp.map(item => require(`@/assets/img/${item}`))
 
 function A2main() {
-  const SCENE_CODE = 'SG-nlIdX3CyQyJ-06'
+  const SCENE_CODE = 'SG-5DYWOEe2sWy'
   // 漫游的状态
   const { state3d } = useSelector((state: RootState) => state.three)
 
@@ -341,6 +342,12 @@ function A2main() {
               <img src={require('../../assets/img/code.png')} alt='' />
             </div>
           </div>
+        {isMobileFu() && <div className="shareBtn">
+          <div className="copyBtn" onClick={handleShareClick}>复制链接</div>
+          <div className="saveBtn" onClick={() => {
+            window.open(require('../../assets/img/code.png'), '_blank')
+          }}>保存二维码</div>
+          </div>}
           <div className='closeBox' onClick={() => setIsShowShare(false)}>
             <img src={require('../../assets/img/close.png')} alt='' draggable='false' />
           </div>

+ 34 - 21
bigScene/scene/src/pages/A3hotList/index.module.scss

@@ -15,7 +15,7 @@
   :global {
     .A3title {
       width: 50%;
-      padding: 40px 0 10px 0;
+      padding: 40px 0 10px 20px;
       font-size: 1.5vw;
       font-weight: 400;
       color: rgba(249, 211, 109, 1);
@@ -29,7 +29,7 @@
       width: 350px;
       height: 95%;
       color: #ffe3cc;
-      font-size: 1.1vw;
+      font-size: 1vw;
       font-weight: 500;
       overflow: auto;
       padding-bottom: 10vh;
@@ -52,7 +52,7 @@
         align-items: center;
         width: 100%;
         height: fit-content;
-        padding: 4px 3px;
+        padding: 4px 20px;
         cursor: pointer;
         color: rgba(255, 243, 197, 0.8);
         &:hover {
@@ -71,10 +71,8 @@
       border-top: 1px solid rgba(43, 31, 23, 0.1);
       cursor: pointer;
       z-index: 3;
-      &:hover {
-        opacity: 1;
-      }
-      img {
+      
+      & >img {
         position: absolute;
         top: 50%;
         right: 0;
@@ -82,6 +80,9 @@
         width: 100%;
         height: 100%;
         opacity: 0.6;
+        &:hover {
+          opacity: 1;
+        }
       }
     }
   }
@@ -90,35 +91,47 @@
 @media screen and (max-width: 1000px) {
   .A3hotList {
     width: 100%;
-    height: 50%;
-    transform: translate(0, -100%);
+    height: 100%;
+    transform: translate(0, -50%);
+    z-index: 30001;
+    background: rgba(70, 47, 9, 0.8);
+    backdrop-filter: blur(5px);
     :global {
       html .cad {
         z-index: -1;
       }
+      .A3title {
+        padding: 20px 0 10px 30px;
+        font-weight: bold;
+        font-size: 18px;
+      }
       .A3main {
         width: 100%;
         height: 100%;
         padding-bottom: 36px;
-        .A3title {
-          padding: 20px 0 10px 0;
-          font-size: 16px;
-        }
+        
         .A3item {
           font-size: 14px;
-          padding: 10px 3px;
+          padding: 10px 30px;
           &:touch {
             background-color: rgba(163, 143, 116, 1);
           }
         }
-        .A3close {
+        
+      }
+      .A3close {
+        padding: 0;
+        margin: 0;
+        width: 40px;
+        height: 40px;
+        opacity: 1;
+        
+        img {
           width: 100%;
-          height: 40px;
-          border-top: 1px solid rgba(43, 31, 23, 0.1);
-          img {
-            width: 16px;
-            height: 16px;
-          }
+          height: 100%;
+          top: 10px;
+        right: 10px;
+        transform: none;
         }
       }
     }

+ 1 - 0
pano/src/components/Pano/index.tsx

@@ -88,6 +88,7 @@ const Panoramic = ({ openHot }: { openHot: (id: string) => void }) => {
               onClick={() => {
                 setCurrentScene('p2')
                 if (window.parent) {
+                  console.log('setIsHotPano')
                   window.parent.window.setIsHotPano(true)
                 }
               }}

+ 82 - 2
project/public/three/data.js

@@ -1,5 +1,6 @@
 // 本地运行静态资源地址
-const baseOssUrl1 = 'http://192.168.20.55:8080/'
+// const baseOssUrl1 = 'http://192.168.20.55:8080/'
+const baseOssUrl1 = 'http://192.168.0.78:8080/'
 // 部署服务器静态资源地址
 const baseOssUrl2 = './'
 
@@ -197,6 +198,28 @@ const myDataTemp = {
       path: 'life'
     }
   ],
+  siderDataM: [
+    {
+      title: '展馆风采',
+      path: 'home'
+    },
+    {
+      title: '展馆漫游',
+      path: 'scene'
+    },
+    {
+      title: '动画赏析',
+      path: 'animation'
+    },
+    {
+      title: '构件赏析',
+      path: 'view'
+    },
+    {
+      title: '前世今生',
+      path: 'life'
+    }
+  ],
   sceneList: [
     {
       id: 'p1',
@@ -279,7 +302,7 @@ const myDataTemp = {
       modelSrc: 'https://4dscene.4dage.com/culturalrelics/EYWSQBWG/Model2.html?m=eywsq69'
     }
   ],
-  architectureAnimation: 'myData/media/bgVideo.mp4',
+  architectureAnimation: 'myData/media/jianzhu.mp4',
   memberList: [
     {
       name: '台灯',
@@ -414,5 +437,62 @@ const myDataTemp = {
       videoSrc: 'myData/media/bgVideo.mp4',
       desc: '纪录片'
     }
+  ],
+  animationList: [
+    {
+      name: '建筑动画',
+      imgSrc: 'myData/mobile/1.png',
+      videoSrc: 'myData/media/jianzhu.mp4'
+    },
+    {
+      name: '台灯',
+      imgSrc: 'myData/mobile/2.png',
+      videoSrc: 'myData/media/member1.mp4'
+    },
+    {
+      name: '门头',
+      imgSrc: 'myData/mobile/3.png',
+      videoSrc: 'myData/media/member2.mp4'
+    },
+    {
+      name: '壁炉',
+      imgSrc: 'myData/mobile/4.png',
+      videoSrc: 'myData/media/member3.mp4'
+    },
+    {
+      name: '吊灯',
+      imgSrc: 'myData/mobile/5.png',
+      videoSrc: 'myData/media/member4.mp4'
+    },
+    {
+      name: '门把手',
+      imgSrc: 'myData/mobile/6.png',
+      videoSrc: 'myData/media/member5.mp4'
+    },
+    {
+      name: '门厅镜框',
+      imgSrc: 'myData/mobile/7.png',
+      videoSrc: 'myData/media/member6.mp4'
+    },
+    {
+      name: '立柱',
+      imgSrc: 'myData/mobile/8.png',
+      videoSrc: 'myData/media/member7.mp4'
+    },
+    {
+      name: '雕花',
+      imgSrc: 'myData/mobile/9.png',
+      videoSrc: 'myData/media/member8.mp4'
+    },
+    {
+      name: '外墙构件',
+      imgSrc: 'myData/mobile/10.png',
+      videoSrc: 'myData/media/member9.mp4'
+    },
+    {
+      name: '衣帽间',
+      imgSrc: 'myData/mobile/11.png',
+      videoSrc: 'myData/media/member10.mp4'
+    }
   ]
 }

+ 47 - 3
project/src/App.tsx

@@ -1,6 +1,6 @@
 import '@/assets/styles/base.css'
 // 关于路由
-import React from 'react'
+import React, { useEffect } from 'react'
 import { Router, Route, Switch } from 'react-router-dom'
 import history from './utils/history'
 import SpinLoding from './components/SpinLoding'
@@ -11,17 +11,22 @@ import TouchContainer from './components/TouchContainer'
 import AsyncSpinLoding from './components/AsyncSpinLoding'
 import { Image } from 'antd'
 import MessageCom from '@/components/Message'
+import { isMobiileFu } from './utils/history'
+import screenImg from '@/assets/img/landtip.png'
 // import Vconsole from 'vconsole'
 // new Vconsole()
 
 // import { isLoc, myData } from './utils/http'
 const A0base = React.lazy(() => import('./pages/A0base'))
+const A0baseM = React.lazy(() => import('./pages/A0baseM'))
 const Home = React.lazy(() => import('./pages/A1home'))
+const HomeM = React.lazy(() => import('./pages/A1homeM'))
 const Scene = React.lazy(() => import('./pages/A2scene'))
 const Architecture = React.lazy(() => import('./pages/A3architecture'))
 const Member = React.lazy(() => import('./pages/A4member'))
 const View = React.lazy(() => import('./pages/A5view'))
 const Life = React.lazy(() => import('./pages/A6life'))
+const AnimationM = React.lazy(() => import('./pages/A7animationM'))
 declare global {
   //设置全局属性
   interface Window {
@@ -33,19 +38,50 @@ declare global {
 export default function App() {
   const lookBigImg = useSelector((state: RootState) => state.A0Layout.lookBigImg)
 
+  useEffect(() => {
+    if (!isMobiileFu()) return
+
+    const rootDom = document.querySelector('#root') as HTMLDivElement
+    if (!rootDom) return
+
+    const setHeight = () => {
+      rootDom.style.height = document.documentElement.clientHeight + 'px'
+      rootDom.style.maxWidth = '500px'
+      rootDom.style.margin = '0 auto'
+    }
+
+    setHeight()
+
+    let timer: ReturnType<typeof setTimeout> | null = null
+    const debouncedSetHeight = () => {
+      if (timer) clearTimeout(timer)
+      timer = setTimeout(() => {
+        setHeight()
+        timer = null
+      }, 150)
+    }
+
+    window.addEventListener('resize', debouncedSetHeight)
+    return () => {
+      window.removeEventListener('resize', debouncedSetHeight)
+      if (timer) clearTimeout(timer)
+    }
+  }, [])
+
   return (
     <>
       {/* 关于路由 */}
       <Router history={history}>
         <React.Suspense fallback={<SpinLoding />}>
           <Switch>
-            <Route path='/' component={A0base} exact />
-            <Route path='/home' component={Home} exact />
+            <Route path='/' component={isMobiileFu() ? A0baseM : A0base} exact />
+            <Route path='/home' component={isMobiileFu() ? HomeM : Home} exact />
             <Route path='/scene' component={Scene} exact />
             <Route path='/architecture' component={Architecture} exact />
             <Route path='/member' component={Member} exact />
             <Route path='/view/:key' component={View} exact />
             <Route path='/life' component={Life} exact />
+            <Route path='/animation' component={AnimationM} exact />
             <Route path='*' component={NotFound} />
           </Switch>
         </React.Suspense>
@@ -80,6 +116,14 @@ export default function App() {
       ) : null}
 
       <MessageCom />
+
+      {/* 横屏提示 */}
+      {isMobiileFu() ? (
+        <div id='ScreenChange'>
+          <img src={screenImg} alt='' />
+          <p>请在竖屏模式浏览</p>
+        </div>
+      ) : null}
     </>
   )
 }

BIN
project/src/assets/img/A0_home_1_M.jpg


BIN
project/src/assets/img/A0_home_2_M.jpg


BIN
project/src/assets/img/A0_home_3_M.jpg


BIN
project/src/assets/img/A0_home_btn_M.png


BIN
project/src/assets/img/A0_home_title_M.png


BIN
project/src/assets/img/A7_animation_bg.jpg


BIN
project/src/assets/img/A7_animation_btn.png


BIN
project/src/assets/img/back1.png


BIN
project/src/assets/img/close_M.png


BIN
project/src/assets/img/landtip.png


BIN
project/src/assets/img/topBar_bg_M.png


+ 32 - 0
project/src/assets/styles/base.css

@@ -623,3 +623,35 @@ textarea {
     transform: translate(-5845px, 0);
   }
 }
+#ScreenChange {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 10000;
+  background-color: rgba(0, 0, 0, 0.8);
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  opacity: 0;
+  pointer-events: none;
+  transition: all 0.5s;
+}
+#ScreenChange > img {
+  width: 200px;
+}
+#ScreenChange > p {
+  margin-top: 20px;
+  color: #fff;
+  font-size: 18px;
+  height: 40px;
+}
+/*横屏*/
+@media screen and (orientation: landscape) {
+  #ScreenChange {
+    opacity: 1;
+    pointer-events: auto;
+  }
+}

+ 37 - 0
project/src/assets/styles/base.less

@@ -789,3 +789,40 @@ textarea {
     transform: translate(-5845px, 0);
   }
 }
+
+// 横屏 竖屏的切换
+#ScreenChange {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 10000;
+  background-color: rgba(0, 0, 0, 0.8);
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  opacity: 0;
+  pointer-events: none;
+  transition: all 0.5s;
+
+  & > img {
+    width: 200px;
+  }
+
+  & > p {
+    margin-top: 20px;
+    color: #fff;
+    font-size: 18px;
+    height: 40px;
+  }
+}
+
+/*横屏*/
+@media screen and (orientation: landscape) {
+  #ScreenChange {
+    opacity: 1;
+    pointer-events: auto;
+  }
+}

+ 44 - 0
project/src/components/TopBarM/index.module.scss

@@ -0,0 +1,44 @@
+.TopBarM {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 100;
+  width: 100%;
+  height: 45px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  background-image: url(../../assets/img/topBar_bg_M.png);
+  background-size: 100% 100%;
+  background-repeat: no-repeat;
+  background-position: center center;
+  :global {
+    .item {
+      width: 25%;
+      height: 100%;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      .title {
+        width: 100%;
+        height: 100%;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        font-size: 14px;
+        color: rgba(255, 243, 197, 1);
+      }
+    }
+    .itemAc {
+      .title {
+        color: rgba(249, 211, 109, 1);
+        background: linear-gradient(
+          180deg,
+          rgba(255, 230, 162, 0.02) 20.85%,
+          rgba(255, 230, 162, 0.3) 71.15%,
+          rgba(255, 230, 162, 0.6) 100%
+        );
+      }
+    }
+  }
+}

+ 28 - 0
project/src/components/TopBarM/index.tsx

@@ -0,0 +1,28 @@
+import React, { useEffect, useState } from "react";
+import styles from "./index.module.scss";
+import history from "@/utils/history";
+ function TopBarM() {
+  const [activeIndex, setActiveIndex] = useState(0);
+  useEffect(() => {
+    const path = window.location.hash.split('/')[1]
+    const index = myDataTemp.siderDataM.findIndex(item => item.path === path)
+    setActiveIndex(index)
+  }, [])
+  const handleClick = (index: number, path: string) => {
+    const pathRes = path === 'view' ? 'view/three' : path
+    history.push(`/${pathRes}`)
+  }
+  return (
+    <div className={styles.TopBarM}>
+     {myDataTemp.siderDataM.map((item, index) => (
+      <div className={`item ${index === activeIndex ? 'itemAc' : ''}`} key={index} onClick={() => handleClick(index, item.path)}>
+        <div className="title">{item.title}</div>
+      </div>
+     ))}
+    </div>
+  )
+}
+
+const MemoTopBarM = React.memo(TopBarM);
+
+export default MemoTopBarM;

+ 9 - 0
project/src/components/Zback/index.module.scss

@@ -20,3 +20,12 @@
     text-align: center;
   }
 }
+
+.ZbackM{
+  top: 10px;
+  left: 10px;
+  width: 40px;
+  height: 40px;
+  font-size: 16px;
+  cursor: pointer;
+}

+ 4 - 2
project/src/components/Zback/index.tsx

@@ -1,11 +1,13 @@
 import React from "react";
 import styles from "./index.module.scss";
+import { isMobiileFu } from "@/utils/history";
+import classNames from "classnames";
  function Zback({onBack,style}: {onBack: () => void,style?: React.CSSProperties}) {
   
   return (
-    <div className={styles.Zback}  onClick={onBack} style={style}>
+    <div className={classNames(styles.Zback, isMobiileFu() ? styles.ZbackM : '')}  onClick={onBack} style={style}>
       <img src={require("@/assets/img/back.png")} alt="返回" />
-      <div className={styles.backText}>返回</div>
+      {isMobiileFu() ? null : <div className={styles.backText}>返回</div>}
     </div>
   )
 }

+ 2 - 0
project/src/components/Zvideo/index.module.scss

@@ -1,6 +1,7 @@
 .Zvideo {
   width: 100%;
   height: 100%;
+  cursor: pointer;
   :global{
     .custom-media-controller {
       width: 100%;
@@ -26,6 +27,7 @@
         border: none;
         display: flex;
         align-self: center;
+        flex: 0 0 auto;
       }
       .progress {
         width: 70%;

+ 25 - 4
project/src/components/Zvideo/index.tsx

@@ -1,18 +1,39 @@
-import React, { useRef } from 'react'
+import React, { useRef, useCallback } from 'react'
 import styles from './index.module.scss'
 import 'media-chrome'
 import { baseOssUrl } from '@/utils/http'
-function Zvideo({ src, objFit = 'fill' }: { src: string; objFit?: string }) {
+function Zvideo({ src, objFit = 'fill' ,style}: { src: string; objFit?: string,style?: React.CSSProperties }) {
   const videoRef = useRef<HTMLVideoElement>(null)
+
+  const handleTogglePlay = useCallback(() => {
+    const video = videoRef.current
+    if (!video) return
+    if (video.paused) {
+      video.play()
+    } else {
+      video.pause()
+    }
+  }, [])
+
   return (
-    <div className={styles.Zvideo}>
-      <media-controller class='custom-media-controller'>
+    <div
+      className={styles.Zvideo}
+      style={style}
+      onKeyDown={(e) => { if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); handleTogglePlay() } }}
+      role="button"
+      tabIndex={0}
+    >
+      <media-controller class='custom-media-controller' gesturesdisabled={true}>
         <video
           ref={videoRef}
           slot='media'
           src={baseOssUrl + src}
           className='modal-video'
           style={{ objectFit: objFit as any }}
+          onClick={(e) => {
+            e.stopPropagation()
+            handleTogglePlay()
+          }}
         ></video>
         <media-control-bar>
           <media-play-button></media-play-button>

+ 63 - 0
project/src/pages/A0baseM/index.module.scss

@@ -0,0 +1,63 @@
+.A0baseM {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  /* 或你想要的高度 */
+  overflow: hidden;
+}
+
+.slide {
+  position: absolute;
+  inset: 0;
+  width: 100%;
+  height: 100%;
+  object-fit: fill;
+  opacity: 0;
+  transition: opacity 2s ease-in-out;
+  /* 渐变时间和缓动函数 */
+  pointer-events: none;
+}
+
+.slide.active {
+  opacity: 1;
+}
+
+.homeTitle {
+  position: absolute;
+    top: 5%;
+    left: 7%;
+    width: 15%;
+    height: 80%;
+    object-fit: contain;
+  :global {
+    img {
+      width: 100%;
+      object-fit: contain;
+    }
+    .process {
+      padding-top: 10px;
+      padding-left: 2px;
+      height: 30%;
+      font-size: 18px;
+      line-height: 40px;
+      color: rgba(141, 104, 64, 1);
+    }
+  }
+}
+
+.homeBtn {
+  position: absolute;
+  bottom: 7%;
+  left: 50%;
+  transform: translateX(-50%);
+  width: 50%;
+  height: 10%;
+  object-fit: contain;
+  cursor: pointer;
+  :global {
+    img {
+      width: 100%;
+      object-fit: contain;
+    }
+  }
+}

+ 77 - 0
project/src/pages/A0baseM/index.tsx

@@ -0,0 +1,77 @@
+import React, { useEffect, useState, useMemo } from 'react';
+import history from '@/utils/history';
+import styles from './index.module.scss';
+import A0_home_1 from '@/assets/img/A0_home_1_M.jpg';
+import A0_home_2 from '@/assets/img/A0_home_2_M.jpg';
+import A0_home_3 from '@/assets/img/A0_home_3_M.jpg';
+import homeTitle from '@/assets/img/A0_home_title_M.png';
+import homeBtn from '@/assets/img/A0_home_btn_M.png';
+
+function A0baseM() {
+  const [currentIndex, setCurrentIndex] = useState(0);
+  const [progress, setProgress] = useState(0); // 进度 0 ~ 100
+  const [isShowBtn, setIsShowBtn] = useState(false);
+  const images = useMemo(() => [A0_home_1, A0_home_2, A0_home_3], []);
+
+  useEffect(() => {
+    const interval = setInterval(() => {
+      setProgress(prev => {
+        const next = prev + 1; 
+        if (next >= 100) {
+          clearInterval(interval);
+          setTimeout(() => {
+            setIsShowBtn(true);
+          }, 500);
+          return 100;
+        }
+        return next;
+      });
+    }, 50); // 每 50ms 增加 1%
+
+    return () => clearInterval(interval);
+  }, []);
+
+  // 根据进度切换图片
+  useEffect(() => {
+    if (progress >= 65) {
+      setCurrentIndex(2); 
+    } else if (progress >= 30) {
+      setCurrentIndex(1); 
+    } else {
+      setCurrentIndex(0);
+    }
+  }, [progress]);
+
+  return (
+    <div className={styles.A0baseM}>
+      {images.map((src, index) => (
+        <img
+          key={src}
+          src={src}
+          alt={`slide ${index + 1}`}
+          className={`${styles.slide} ${index === currentIndex ? styles.active : ''}`}
+        />
+      ))}
+
+      <div className={styles.homeTitle}>
+        <img
+          src={homeTitle}
+          alt="homeTitle"
+          style={{ opacity: progress / 100 + 0.3 }}
+        />
+       {!isShowBtn && <div className={'process'}>
+          {progress}%
+        </div>}
+      </div>
+
+      {isShowBtn && 
+        <div className={styles.homeBtn} onClick={() => history.push('/home')}>
+          <img src={homeBtn} alt="homeBtn" />
+        </div>}
+    </div>
+  );
+}
+
+const MemoA0baseM = React.memo(A0baseM);
+
+export default MemoA0baseM;

+ 1 - 1
project/src/pages/A1home/index.tsx

@@ -125,7 +125,7 @@ function A1home() {
         <>
           {/* 背景视频 */}
           <video
-            src={`${baseOssUrl}myData/media/bgVideo.mp4`}
+            src={`${baseOssUrl}myData/media/siji.mp4`}
             autoPlay
             loop
             muted

+ 93 - 0
project/src/pages/A1homeM/PanoHot/Swiper2/index.module.scss

@@ -0,0 +1,93 @@
+.SwiperComponent2 {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  :global {
+    .leftArrow,
+    .rightArrow {
+      position: absolute;
+      z-index: 1;
+      top: 55%;
+      left: 1%;
+      width: 40px;
+      height: 40px;
+      object-fit: contain;
+      cursor: pointer;
+      & > img {
+        width: 100%;
+        height: 100%;
+        object-fit: contain;
+      }
+    }
+    .rightArrow {
+      left: auto;
+      right: 1%;
+    }
+    .swiper_container {
+      width: 100%;
+      height: 100%;
+      perspective: 1500px;
+      .swiper-slide-shadow-coverflow {
+        background-image: none;
+      }
+      .swiper-button-arr-custom {
+        width: 50px;
+        height: 65px;
+        &:after {
+          content: '';
+        }
+        & > img {
+          width: 50px;
+          height: 55px;
+          object-fit: cover;
+        }
+      }
+      .itemCard {
+        border-radius: 20px;
+        margin: 0 auto;
+        width: 70%;
+        height: 100%;
+        position: relative;
+        cursor: pointer;
+        transition: transform 0.3s ease;
+        .itemImageImg {
+          margin-top: 13%;
+          width: 100%;
+          height: 100%;
+          object-fit: contain;
+          transition: all 0.3s ease;
+
+          .detailIcon {
+            position: absolute;
+            bottom: 5%;
+            left: 50%;
+            transform: translateX(-50%);
+            width: 20%;
+            height: 20%;
+            object-fit: contain;
+            display: none;
+          }
+        }
+        &.itemCardActive {
+          .itemImage {
+            background-image: url('../../../../assets/img/A6_life_selected.png');
+            background-size: 100% 100%;
+            background-repeat: no-repeat;
+            background-position: center center;
+          }
+          .detailIcon {
+            display: block;
+          }
+        }
+      }
+    }
+    .swiper-pagination {
+      .swiper-pagination-bullet{
+        background-color: rgba(255, 243, 197,1);
+      }
+      .swiper-pagination-bullet-active {
+        background-color: rgba(255, 243, 197, 0.8);
+      }
+    }
+  }
+}

+ 54 - 0
project/src/pages/A1homeM/PanoHot/Swiper2/index.tsx

@@ -0,0 +1,54 @@
+import React, { useRef } from 'react'
+import styles from './index.module.scss'
+import { Swiper, SwiperSlide } from 'swiper/react'
+import 'swiper/css'
+import 'swiper/css/effect-coverflow'
+import 'swiper/css/pagination'
+import 'swiper/css/navigation'
+// import { EffectCoverflow } from 'swiper/modules'
+import {  Pagination } from 'swiper/modules'
+import { baseOssUrl } from '@/utils/http'
+function SwiperComponent2({ activeIndex }: { activeIndex: number }) {
+  const swiperRef = useRef<any>(null)
+  return (
+    <div className={styles.SwiperComponent2}>
+      <Swiper
+        ref={swiperRef}
+        loop={false}
+        loopPreventsSliding={false}
+        effect={'coverflow'}
+        grabCursor={true}
+        centeredSlides={true}
+        slidesPerView={1}
+        pagination={{ el: '.swiper-pagination', clickable: true }}
+        modules={[Pagination]}
+        className='swiper_container'
+        onTransitionEnd={(swiper: any) => {
+          const swiperInternal = swiper as { loopFix: () => void }
+          swiperInternal.loopFix()
+        }}
+      >
+        {myDataTemp.panoHotList[activeIndex]?.imgList?.map((item: string, index: number) => (
+          <SwiperSlide key={index}>
+            <div className={`itemCard ${activeIndex === index ? 'itemCardActive' : ''}`}>
+              <img className='itemImageImg' src={baseOssUrl + item} alt='' />
+            </div>
+          </SwiperSlide>
+        ))}
+      </Swiper>
+
+      <div className='swiper-pagination'></div>
+
+      <div className='leftArrow' onClick={() => swiperRef.current?.swiper?.slidePrev()}>
+        <img src={require('../../../../assets/img/A6_life_left.png')} alt='' />
+      </div>
+      <div className='rightArrow' onClick={() => swiperRef.current?.swiper?.slideNext()}>
+        <img src={require('../../../../assets/img/A6_life_right.png')} alt='' />
+      </div>
+    </div>
+  )
+}
+
+const MemoSwiperComponent2 = React.memo(SwiperComponent2)
+
+export default MemoSwiperComponent2

+ 109 - 0
project/src/pages/A1homeM/PanoHot/index.module.scss

@@ -0,0 +1,109 @@
+  .PanoHot {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: 200;
+    background-color: rgba(70, 47, 9, 0.6);
+    backdrop-filter: blur(5px);
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    .content {
+      width: 100%;
+      height: 25%;
+      border-radius: 10px 10px 0 0;
+      background: linear-gradient(180deg, #A56F2C 0%, #824E0F 41.35%, #4F310C 100%);
+      padding: 20px 20px 10px;
+      .title {
+        width: 100%;
+        height: fit-content;
+        margin-bottom: 10px;
+        font-size: 20px;
+        font-weight: 500;
+        color: rgba(249, 211, 109, 1);
+      }
+      .desc {
+        width: 100%;
+        height: 80%;
+        font-size: 13px;
+        line-height: 1.5;
+        color: rgba(255, 243, 197, 1);
+        overflow: auto;
+        &::-webkit-scrollbar {
+          display: none;
+        }
+      }
+    }
+    .top {
+      width: 100%;
+      height: calc(75% - 100px);
+      .model{
+        padding: 40px 10% 20px;
+        width: 100%;
+        height: 100%;
+        & > iframe {
+          width: 100%;
+          height: 100%;
+          border: none;
+          object-fit: contain;
+        }
+      }
+      .img {
+        width: 100%;
+        height: 100%;
+      }
+      .video {
+        padding: 4% 10%;
+        width: 100%;
+        height: 100%;
+        & > video {
+          width: 100%;
+          height: 100%;
+          object-fit: contain;
+        }
+      }
+    }
+    .bottom {
+      width: 100%;
+      height: 100px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      gap: 0.5%;
+      position: relative;
+      
+      .tab {
+        width:25%;
+        height: 50px;
+        background-image: url('../../../assets/img/A1_home_tab.png');
+        background-size: contain;
+        background-repeat: no-repeat;
+        background-position: center center;
+        cursor: pointer;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        color: rgba(112, 73, 7, 1);
+        font-size: 14px;
+        &.active {
+          color: rgba(255, 243, 197, 1);
+          background-image: url('../../../assets/img/A1_home_tab_ac.png');
+        }
+      }
+    }
+
+    .closeBtn {
+      position: absolute;
+      top: 15px;
+      right: 15px;
+      width: 30px;
+      height: 30px;
+      cursor: pointer;
+      & > img {
+        width: 100% ;
+        height: 100% ;
+      }
+    }
+}

+ 77 - 0
project/src/pages/A1homeM/PanoHot/index.tsx

@@ -0,0 +1,77 @@
+import React, { useEffect, useState } from 'react'
+import styles from './index.module.scss'
+import SwiperComponent2 from './Swiper2'
+import { baseOssUrl } from '@/utils/http'
+function PanoHot({
+  activeIndex,
+  setActiveIndex
+}: {
+  activeIndex: number
+  setActiveIndex: (index: number) => void
+}) {
+  const [type, setType] = useState('')
+
+  useEffect(() => {
+    setType('model')
+  }, [])
+  return (
+    <div className={styles.PanoHot}>
+    
+      <div className={styles.top}>
+        {/* model */}
+        {type === 'model' ? (
+          <div className={styles.model}>
+            <iframe src={myDataTemp.panoHotList[activeIndex]?.modelSrc || ''} title='model' />
+          </div>
+        ) : null}
+        {/* video */}
+        {type === 'video' ? (
+          <div className={styles.video}>
+            <video
+              src={baseOssUrl + myDataTemp.panoHotList[activeIndex]?.videoSrc || ''}
+              controls
+              loop
+            />
+          </div>
+        ) : null}
+        {/* img */}
+        {type === 'img' ? (
+          <div className={styles.img}>
+            <SwiperComponent2 activeIndex={0} />
+          </div>
+        ) : null}
+      </div>
+      <div className={styles.bottom}>
+        <div
+          className={`${styles.tab} ${type === 'model' ? styles.active : ''}`}
+          onClick={() => setType('model')}
+        >
+          模型
+        </div>
+        <div
+          className={`${styles.tab} ${type === 'video' ? styles.active : ''}`}
+          onClick={() => setType('video')}
+        >
+          视频
+        </div>
+        <div
+          className={`${styles.tab} ${type === 'img' ? styles.active : ''}`}
+          onClick={() => setType('img')}
+        >
+          图片
+        </div>
+      </div>
+      <div className={styles.closeBtn} onClick={() => setActiveIndex(-1)}>
+          <img src={require('../../../assets/img/close_M.png')} alt='' />
+        </div>
+      <div className={styles.content}>
+        <div className={styles.title}>{myDataTemp.panoHotList[activeIndex]?.name}</div>
+        <div className={styles.desc}>{myDataTemp.panoHotList[activeIndex]?.desc}</div>
+      </div>
+    </div>
+  )
+}
+
+const MemoPanoHot = React.memo(PanoHot)
+
+export default MemoPanoHot

+ 112 - 0
project/src/pages/A1homeM/index.module.scss

@@ -0,0 +1,112 @@
+.A1home {
+  position: relative;
+  background-color: #ccc;
+
+  .bgVideo {
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: 1;
+  }
+
+  .skipBtn {
+    position: absolute;
+    bottom: 3%;
+    right: 3%;
+    width: 70px;
+    height: 70px;
+    z-index: 1;
+    cursor: pointer;
+    transition: bottom 0.3s ease-in-out;
+    &>img {
+      width: 100%;
+      object-fit: contain;
+    }
+  }
+
+  .skipBtnAc {
+    bottom: 135px;
+  }
+
+  .detailContent {
+    position: absolute;
+    bottom: -150px;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 100%;
+    height: 130px;
+    background-color: rgba(145, 118, 68, 0.8);
+    backdrop-filter: blur(5px);
+    z-index: 1;
+    display: flex;
+    align-items: center;
+    transition: bottom 0.3s ease-in-out;
+
+    &:global(.show) {
+      transition: bottom 0.3s ease-in-out;
+      bottom: 0;
+    }
+
+    .scroll {
+      flex: 1;
+      min-width: 0;
+      height: 100%;
+      overflow-x: auto;
+      scrollbar-width: none;
+      -ms-overflow-style: none;
+
+      .detailItemC {
+        width: fit-content;
+        height: 100%;
+        padding: 6px;
+        padding-bottom: 15px;
+        display: flex;
+        align-items: center;
+        gap: 5px;
+
+        .detailItem {
+          width: 140px; 
+          height: 100%;
+          position: relative;
+          flex-shrink: 0;
+
+          &.active {
+            background-image: url('../../assets/img/A1_home_selected.png');
+            background-size: 100% 100%;
+            background-repeat: no-repeat;
+            background-position: center center;
+
+            .detailItemName {
+              background-image: url('../../assets/img/A1_home_nameBg_ac.png');
+              color: rgba(112, 73, 7, 1);
+            }
+          }
+
+          &>img {
+            padding: 6px;
+            width: 100%;
+            height: 100%;
+            object-fit: cover;
+          }
+
+          .detailItemName {
+            position: absolute;
+            bottom: 6px;
+            left: 50%;
+            transform: translateX(-50%);
+            width: calc(100% - 10px);
+            height: 20%;
+            background-image: url('../../assets/img/A1_home_nameBg.png');
+            background-size: 100% 100%;
+            background-repeat: no-repeat;
+            background-position: center center;
+            color: rgba(255, 243, 197, 1);
+            font-size: 12px;
+            text-align: center;
+            line-height: 2;
+          }
+        }
+      }
+    }
+  }
+}

+ 81 - 0
project/src/pages/A1homeM/index.tsx

@@ -0,0 +1,81 @@
+import React, { useEffect, useRef, useState } from 'react'
+import styles from './index.module.scss'
+import { callIframeFu } from '@/utils/history'
+import PanoHot from './PanoHot'
+import { baseOssUrl } from '@/utils/http'
+import TopBarM from '@/components/TopBarM'
+function A1home() {
+  const [isShowDetail, setIsShowDetail] = useState(false)
+  const [currentSceneIndex, setCurrentSceneIndex] = useState(0)
+  // 是否进入二级页面
+  const [isHotPano, setIsHotPano] = useState(false)
+  const [activeIndex, setActiveIndex] = useState(-1)
+
+  const scrollRef = useRef<HTMLDivElement>(null)
+  const sceneList = myDataTemp.sceneList
+
+  useEffect(() => {
+    window.setIsHotPano = (isHotPano: boolean) => {
+      setIsHotPano(isHotPano)
+    }
+    window.setActiveHotId = (id: string) => {
+      console.log('setActiveHotId222', id)
+      const index = myDataTemp.panoHotList.findIndex((item: any) => item.id === id)
+      if (index !== -1) {
+        setActiveIndex(index)
+      }
+    }
+  }, [])
+
+  const handleItemClick = (item: any, index: number) => {
+    setCurrentSceneIndex(index)
+    callIframeFu('setCurrentScene', item.id)
+  }
+
+  // 鼠标滚轮横向滚动
+  const handleWheel = (e: React.WheelEvent) => {
+    const el = scrollRef.current
+    if (!el) return
+    e.preventDefault()
+    el.scrollLeft += e.deltaY
+  }
+  return (
+    <div className={styles.A1home}>
+      {/* 视频跳过后是全景 */}
+      <iframe
+        id='panoIframe'
+        src='https://houseoss.4dkankan.com/project/gmlx/Pano/index.html'
+        title='pono'
+      ></iframe>
+      {activeIndex !== -1 && <PanoHot activeIndex={activeIndex} setActiveIndex={setActiveIndex} />}
+      {/* 详情按钮-只在二级页面显示 */}
+      {isHotPano && (
+        <div className={`${styles.skipBtn} ${isShowDetail ? styles.skipBtnAc : ''}`} onClick={() => setIsShowDetail(!isShowDetail)}>
+          <img src={require(`@/assets/img/${isShowDetail ? 'detail_ac' : 'detail'}.png`)} alt='' />
+        </div>
+      )}
+      {/* 场景列表=由详情按钮控制 */}
+      <div className={`${styles.detailContent} ${isShowDetail ? 'show' : ''}`}>
+        <div ref={scrollRef} className={styles.scroll} onWheel={handleWheel}>
+          <div className={styles.detailItemC}>
+            {sceneList.map((item, index) => (
+              <div
+                key={item.id}
+                className={`${styles.detailItem} ${currentSceneIndex === index ? styles.active : ''}`}
+                onClick={() => handleItemClick(item, index)}
+              >
+                <img src={baseOssUrl + item.thumbUrl} alt='' />
+                <div className={styles.detailItemName}>{item.name}</div>
+              </div>
+            ))}
+          </div>
+        </div>
+      </div>
+      <TopBarM />
+    </div>
+  )
+}
+
+const MemoA1home = React.memo(A1home)
+
+export default MemoA1home

+ 1 - 1
project/src/pages/A2scene/index.tsx

@@ -6,7 +6,7 @@ import { backPageFu } from "@/utils/history";
   
   return (
     <div className={styles.A2scene}>
-     <iframe src="https://www.4dkankan.com/spg.html?m=SG-djd0YpFBp0O"  title="scene"></iframe>
+     <iframe src="https://houseoss.4dkankan.com/project/gmlx/Bigscene/index.html#/?m=SG-5DYWOEe2sWy"  title="scene"></iframe>
      <Zback onBack={() => backPageFu('/home')}/>
     </div>
   )

+ 1 - 1
project/src/pages/A4member/index.tsx

@@ -103,7 +103,7 @@ function A4Member() {
       {isShowVideo ? (
         <div className={styles.videoBox}>
           <Zvideo
-            src={baseOssUrl + myDataTemp.memberList[currentIndex].videoSrc}
+            src={myDataTemp.memberList[currentIndex].videoSrc}
             objFit='contain'
           />
           <Zback onBack={() => setIsShowVideo(false)} />

+ 125 - 0
project/src/pages/A7animationM/Swiper3/index.module.scss

@@ -0,0 +1,125 @@
+.SwiperComponent {
+  width: 100%;
+  height: 100%;
+  position: relative;
+  padding-top: 70px;
+  :global {
+    .leftArrow,
+    .rightArrow {
+      position: absolute;
+      z-index: 1;
+      top: 50%;
+      left: 1%;
+      width: 5vw;
+      height: 5vw;
+      object-fit: contain;
+      cursor: pointer;
+      & > img {
+        width: 100%;
+        height: 100%;
+        object-fit: contain;
+      }
+    }
+    .rightArrow {
+      left: auto;
+      right: 1%;
+    }
+    .swiper_container {
+      width: 100%;
+      height: 74%;
+      perspective: 1500px;
+      .swiper-slide-shadow-coverflow {
+        background-image: none;
+      }
+      .swiper-button-arr-custom {
+        width: 50px;
+        height: 65px;
+        &:after {
+          content: '';
+        }
+        & > img {
+          width: 50px;
+          height: 55px;
+          object-fit: cover;
+        }
+      }
+      .itemCard {
+        border-radius: 20px;
+        margin: 0 auto;
+        width: 80%;
+        height: 100%;
+        position: relative;
+        cursor: pointer;
+        transition: transform 0.3s ease;
+        display: flex;
+        align-items: center;
+        .itemImage {
+          width: 100%;
+          height: 100%;
+        max-height: 500px;
+          position: relative;
+          .itemName {
+            position: absolute;
+            top: 6%;
+            left: 14%;
+            width: 40px;
+            height: 50%;
+            .up,
+            .down{
+              width: 100%;
+              object-fit: contain;
+            }
+            .name{
+              width: 30px;
+              margin: 0 auto;
+              text-align: center;
+              white-space: pre-line;
+              font-weight: 700;
+              color: rgba(255, 243, 197, 1);
+            transition: color 0.35s ease, text-shadow 0.35s ease;
+            text-shadow:
+              0 0 3px rgba(78, 47, 23, 0.9),
+              0 0 6px rgba(78, 47, 23, 0.7),
+              0 0 10px rgba(78, 47, 23, 0.5),
+              0 0 15px rgba(195, 172, 153, 0.4),
+              2px 2px 4px rgba(0, 0, 0, 0.6);
+            }
+          }
+          .itemImageImg {
+            width: 100%;
+            height: 100%;
+            object-fit: contain;
+            transition: all 0.3s ease;
+          }
+ 
+        }
+      }
+    }
+    .btn{
+      width: 70%;
+      margin: 0 auto;
+      margin-top: 20px;
+      height: 10%;
+      max-height: 60px;
+      text-align: center;
+      & > img {
+        width: 100%;
+        height: 100%;
+        object-fit: contain;
+      }
+    }
+    .swiper-pagination {
+        height: 40px;
+        .swiper-pagination-bullet{
+          margin: 0 8px !important;
+          opacity: 1;
+          background-color: rgba(112, 73, 7, 1);
+        }
+      .swiper-pagination-bullet-active {
+        width: 10px;
+        height: 10px;
+        background-color: rgba(249, 211, 109, 1);
+      }
+    }
+  }
+}

+ 68 - 0
project/src/pages/A7animationM/Swiper3/index.tsx

@@ -0,0 +1,68 @@
+import React, {  useCallback, useRef } from 'react'
+import styles from './index.module.scss'
+import { Swiper, SwiperSlide } from 'swiper/react'
+import 'swiper/css'
+import 'swiper/css/effect-coverflow'
+import 'swiper/css/pagination'
+import 'swiper/css/navigation'
+import { EffectCoverflow, Pagination, Navigation } from 'swiper/modules'
+import { baseOssUrl } from '@/utils/http'
+function Swiper3({ setIsShowVideo, setCurrentIndex }: { setIsShowVideo: (isShow: boolean) => void, setCurrentIndex: (index: number) => void }) {
+  const swiperRef = useRef<any>(null)
+
+  const handleVideoClick = useCallback((index: number) => {
+    // const listLength = myDataTemp.animationList.length
+    // console.log(index,listLength)
+    setCurrentIndex(index)
+    setIsShowVideo(true)
+  }, [setCurrentIndex, setIsShowVideo])
+  return (
+    <div className={styles.SwiperComponent}>
+      <Swiper
+        ref={swiperRef}
+        loop={myDataTemp.lifeList.length > 4 ? true : false}
+        loopPreventsSliding={false}
+        effect={'coverflow'}
+        grabCursor={true}
+        centeredSlides={true}
+        slidesPerView={1}
+        coverflowEffect={{
+          rotate: 0,
+          stretch: 10, // 控制了3d视角的拉伸程度
+          depth: 240, // 控制了3d视角的深度
+          modifier: 3
+        }}
+        pagination={{ el: '.swiper-pagination', clickable: true }}
+        modules={[EffectCoverflow, Pagination, Navigation]}
+        className='swiper_container'
+        onTransitionEnd={(swiper: any) => {
+          const swiperInternal = swiper as { loopFix: () => void }
+          swiperInternal.loopFix()
+        }}
+      >
+        {myDataTemp.animationList.map((item, index) => (
+          <SwiperSlide key={index}>
+            <div className={`itemCard`}>
+              <div className='itemImage'>
+                <div className='itemName'>
+                  <div className="up"><img src={require('../../../assets/img/A4_member_up_ac.png')} alt="" /></div>
+                  <div className="name">{item.name}</div>
+                  <div className="down"><img src={require('../../../assets/img/A4_member_down_ac.png')} alt="" /></div>
+                </div>
+                <img className='itemImageImg' src={baseOssUrl + item?.imgSrc} alt='' />
+              </div>
+            </div>
+          </SwiperSlide>
+        ))}
+      </Swiper>
+        <div className='btn' onClick={() => handleVideoClick(swiperRef.current.swiper.realIndex)}>
+          <img src={require('../../../assets/img/A7_animation_btn.png')} alt="" />
+        </div>
+      <div className='swiper-pagination'></div>
+    </div>
+  )
+}
+
+const MemoSwiper3 = React.memo(Swiper3)
+
+export default MemoSwiper3

+ 41 - 0
project/src/pages/A7animationM/index.module.scss

@@ -0,0 +1,41 @@
+.A7animationM{
+  background-image: url('../../assets/img/A7_animation_bg.jpg');
+  background-size: 100% 100%;
+  background-repeat: no-repeat;
+  background-position: center center;
+  position: relative;
+  .videoBox{
+    width: 100%;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    flex-direction: column;
+    .backBtn{
+      padding: 10px;
+      width: 100%;
+      height: 60px;
+      cursor: pointer;
+      margin-bottom: 30px;
+      &>img{
+        width: 40px;
+        height: 100%;
+        object-fit: contain;
+      }
+    }
+    .title{
+      width: 330px;
+      height: 70px;
+      margin-bottom: 50px;
+      background-image: url('../../assets/img/A6_life_intro_title.png');
+      background-size: 100% 100%;
+      background-repeat: no-repeat;
+      background-position: center center;
+      font-size: 18px;
+      line-height: 65px;
+      font-weight: bold;
+      color: rgba(255, 243, 197, 1);
+      text-align: center;
+    }
+  }
+  
+}

+ 41 - 0
project/src/pages/A7animationM/index.tsx

@@ -0,0 +1,41 @@
+import React, { useState } from 'react'
+import styles from './index.module.scss'
+import Swiper3 from './Swiper3'
+import TopBarM from '@/components/TopBarM'
+import Zvideo from '@/components/Zvideo'
+function A7animationM() {
+  const [isShowVideo, setIsShowVideo] = useState(false)
+  const [currentIndex, setCurrentIndex] = useState(0)
+  return (
+    <div className={styles.A7animationM}>
+      {!isShowVideo ? (
+        <>
+          <TopBarM />
+          <Swiper3 setIsShowVideo={setIsShowVideo} setCurrentIndex={setCurrentIndex} />
+        </>
+      ) : (
+        <div className={styles.videoBox}>
+          <div 
+            className={styles.backBtn}>
+          <img
+            onClick={() => setIsShowVideo(false)}
+            src={require('../../assets/img/back1.png')}
+            alt=''
+          />
+          </div>
+         
+          <div className={styles.title}>{myDataTemp.animationList[currentIndex].name}</div>
+          <Zvideo
+            src={myDataTemp.animationList[currentIndex].videoSrc}
+            objFit='contain'
+            style={{ height: 'auto' }}
+          />
+        </div>
+      )}
+    </div>
+  )
+}
+
+const MemoA7animationM = React.memo(A7animationM)
+
+export default MemoA7animationM

+ 2 - 0
project/src/types/declaration.d.ts

@@ -20,6 +20,7 @@ declare const F_Video: any
 type MyDataType = {
   isLdong: boolean
   siderData: { title: string; path: string }[]
+  siderDataM: { title: string; path: string }[]
   sceneList: { id: string; name: string; thumbUrl: string }[]
   panoHotList: {
     id: string
@@ -39,6 +40,7 @@ type MyDataType = {
     videoSrc: string
   }[]
   lifeList: { name: string; time: string; imgSrc: string; videoSrc?: string; desc: string }[]
+  animationList: { name: string; imgSrc: string; videoSrc: string }[]
 }
 
 declare namespace JSX {

Разлика између датотеке није приказан због своје велике величине
+ 205 - 427
project/yarn.lock


BIN
静态文件/myData/media/jianzhu.mp4


BIN
静态文件/myData/media/siji.mp4


BIN
静态文件/myData/mobile/1.png


BIN
静态文件/myData/mobile/10.png


BIN
静态文件/myData/mobile/11.png


BIN
静态文件/myData/mobile/2.png


BIN
静态文件/myData/mobile/3.png


BIN
静态文件/myData/mobile/4.png


BIN
静态文件/myData/mobile/5.png


BIN
静态文件/myData/mobile/6.png


BIN
静态文件/myData/mobile/7.png


BIN
静态文件/myData/mobile/8.png


BIN
静态文件/myData/mobile/9.png