shaogen1995 11 hónapja
szülő
commit
1d44eea116
38 módosított fájl, 896 hozzáadás és 357 törlés
  1. 151 4
      Code/public/myData/myData.js
  2. 4 0
      Code/src/App.tsx
  3. 1 1
      Code/src/assets/styles/base.css
  4. 1 1
      Code/src/assets/styles/base.less
  5. 13 0
      Code/src/components/LazyImg/index.module.scss
  6. 22 0
      Code/src/components/LazyImg/index.tsx
  7. 0 230
      Code/src/pages/A1home/index copy.tsx
  8. 20 0
      Code/src/pages/A1home/index.module.scss
  9. 72 3
      Code/src/pages/A1home/index.tsx
  10. 163 0
      Code/src/pages/A2visit/PanoVideo/Hot1/index.module.scss
  11. 136 0
      Code/src/pages/A2visit/PanoVideo/Hot1/index.tsx
  12. 12 0
      Code/src/pages/A2visit/PanoVideo/Hot2/index.module.scss
  13. 13 0
      Code/src/pages/A2visit/PanoVideo/Hot2/index.tsx
  14. 8 0
      Code/src/pages/A2visit/PanoVideo/index.module.scss
  15. 31 0
      Code/src/pages/A2visit/PanoVideo/index.tsx
  16. 74 3
      Code/src/pages/A2visit/index.module.scss
  17. 112 75
      Code/src/pages/A2visit/index.tsx
  18. 4 0
      Code/src/pages/A3banquet/index.module.scss
  19. 13 0
      Code/src/pages/A3banquet/index.tsx
  20. 4 0
      Code/src/pages/B1more/index.module.scss
  21. 14 0
      Code/src/pages/B1more/index.tsx
  22. 15 9
      Code/src/types/api/layot.d.ts
  23. 9 2
      Code/src/types/declaration.d.ts
  24. 4 0
      Code/src/utils/utilsSome.ts
  25. 0 29
      Code/src/utils/xhrVideo.ts
  26. BIN
      资源/staticData/HH/home/move.png
  27. BIN
      资源/staticData/HH/visit/back.png
  28. BIN
      资源/staticData/HH/visit/bichuyuan.png
  29. 0 0
      资源/staticData/HH/visit/end.mp4
  30. BIN
      资源/staticData/HH/visit/h1fllo.png
  31. BIN
      资源/staticData/HH/visit/hot/1.jpg
  32. BIN
      资源/staticData/HH/visit/hot/2.jpg
  33. BIN
      资源/staticData/HH/visit/hot/3.jpg
  34. BIN
      资源/staticData/HH/visit/hot1bj.png
  35. BIN
      资源/staticData/HH/visit/icon-more.png
  36. BIN
      资源/staticData/HH/visit/icon-walk.png
  37. BIN
      资源/staticData/HH/visit/icon-you-red.png
  38. BIN
      资源/staticData/HH/visit/icon-zuo-red.png

+ 151 - 4
Code/public/myData/myData.js

@@ -26,11 +26,158 @@ const myDataTemp = {
   visit: {
     // 开场动画视频名字
     videoSta: 'visit/base.mp4',
-    // 视频数组
-    video: [
+    // 过度视频
+    videos: ['visit/1.mp4'],
+    // 最后的过长动画路径+名字
+    lastVideo: 'visit/end.mp4',
+    // 热点
+    hot: [
       {
-        sort: 1, //排序
-        name: 'visit/1.mp4' //名字
+        // 热点名字
+        name: '热点1',
+        // 热点大小
+        size: 1,
+        // 垂直方向
+        atv: 5,
+        // 水平方向
+        ath: 0,
+        data: [
+          {
+            // 名字
+            name: '稽首',
+            // 文本内容
+            txt: `
+            <h3>双膝跪地,双手扶地,</h3>
+            <h2>头向下至地,稽留一段时间。</h2>
+            <br/>
+            <p>《周礼》把跪与其他肢体动作结合所形成的礼仪动作称为"拜",</p>
+            <p>"拜"共有九种,九拜的共同之处即都有跪的动作,</p>
+            <p>凡拜必跪,不跪不为拜。</p>
+            `,
+            // 图片路径+名字
+            imgArr: ['visit/hot/1.jpg', 'visit/hot/2.jpg', 'visit/hot/3.jpg']
+          },
+          {
+            // 名字
+            name: '顿首',
+            // 文本内容
+            txt: `
+            <h3>双膝跪地,双手扶地,</h3>
+            <h2>头向下至地,稽留一段时间。</h2>
+            <br/>
+            <p>《周礼》把跪与其他肢体动作结合所形成的礼仪动作称为"拜",</p>
+            <p>"拜"共有九种,九拜的共同之处即都有跪的动作,</p>
+            <p>凡拜必跪,不跪不为拜。</p>
+            `,
+            // 图片路径+名字
+            imgArr: ['visit/hot/1.jpg', 'visit/hot/2.jpg']
+          },
+          {
+            // 名字
+            name: '空首',
+            // 文本内容
+            txt: `
+            <h3>双膝跪地,双手扶地,</h3>
+            <h2>头向下至地,稽留一段时间。</h2>
+            <br/>
+            <p>《周礼》把跪与其他肢体动作结合所形成的礼仪动作称为"拜",</p>
+            <p>"拜"共有九种,九拜的共同之处即都有跪的动作,</p>
+            <p>凡拜必跪,不跪不为拜。</p>
+            `,
+            // 图片路径+名字
+            imgArr: ['visit/hot/1.jpg']
+          },
+          {
+            // 名字
+            name: '稽首',
+            // 文本内容
+            txt: `
+            <h3>双膝跪地,双手扶地,</h3>
+            <h2>头向下至地,稽留一段时间。</h2>
+            <br/>
+            <p>《周礼》把跪与其他肢体动作结合所形成的礼仪动作称为"拜",</p>
+            <p>"拜"共有九种,九拜的共同之处即都有跪的动作,</p>
+            <p>凡拜必跪,不跪不为拜。</p>
+            `,
+            // 图片路径+名字
+            imgArr: ['visit/hot/1.jpg', 'visit/hot/2.jpg', 'visit/hot/3.jpg']
+          },
+          {
+            // 名字
+            name: '顿首',
+            // 文本内容
+            txt: `
+            <h3>双膝跪地,双手扶地,</h3>
+            <h2>头向下至地,稽留一段时间。</h2>
+            <br/>
+            <p>《周礼》把跪与其他肢体动作结合所形成的礼仪动作称为"拜",</p>
+            <p>"拜"共有九种,九拜的共同之处即都有跪的动作,</p>
+            <p>凡拜必跪,不跪不为拜。</p>
+            `,
+            // 图片路径+名字
+            imgArr: ['visit/hot/1.jpg', 'visit/hot/2.jpg']
+          },
+          {
+            // 名字
+            name: '空首',
+            // 文本内容
+            txt: `
+            <h3>双膝跪地,双手扶地,</h3>
+            <h2>头向下至地,稽留一段时间。</h2>
+            <br/>
+            <p>《周礼》把跪与其他肢体动作结合所形成的礼仪动作称为"拜",</p>
+            <p>"拜"共有九种,九拜的共同之处即都有跪的动作,</p>
+            <p>凡拜必跪,不跪不为拜。</p>
+            `,
+            // 图片路径+名字
+            imgArr: ['visit/hot/1.jpg']
+          },
+          {
+            // 名字
+            name: '稽首',
+            // 文本内容
+            txt: `
+            <h3>双膝跪地,双手扶地,</h3>
+            <h2>头向下至地,稽留一段时间。</h2>
+            <br/>
+            <p>《周礼》把跪与其他肢体动作结合所形成的礼仪动作称为"拜",</p>
+            <p>"拜"共有九种,九拜的共同之处即都有跪的动作,</p>
+            <p>凡拜必跪,不跪不为拜。</p>
+            `,
+            // 图片路径+名字
+            imgArr: ['visit/hot/1.jpg', 'visit/hot/2.jpg', 'visit/hot/3.jpg']
+          },
+          {
+            // 名字
+            name: '顿首',
+            // 文本内容
+            txt: `
+            <h3>双膝跪地,双手扶地,</h3>
+            <h2>头向下至地,稽留一段时间。</h2>
+            <br/>
+            <p>《周礼》把跪与其他肢体动作结合所形成的礼仪动作称为"拜",</p>
+            <p>"拜"共有九种,九拜的共同之处即都有跪的动作,</p>
+            <p>凡拜必跪,不跪不为拜。</p>
+            `,
+            // 图片路径+名字
+            imgArr: ['visit/hot/1.jpg', 'visit/hot/2.jpg']
+          },
+          {
+            // 名字
+            name: '空首',
+            // 文本内容
+            txt: `
+            <h3>双膝跪地,双手扶地,</h3>
+            <h2>头向下至地,稽留一段时间。</h2>
+            <br/>
+            <p>《周礼》把跪与其他肢体动作结合所形成的礼仪动作称为"拜",</p>
+            <p>"拜"共有九种,九拜的共同之处即都有跪的动作,</p>
+            <p>凡拜必跪,不跪不为拜。</p>
+            `,
+            // 图片路径+名字
+            imgArr: ['visit/hot/1.jpg']
+          }
+        ]
       }
     ]
   }

+ 4 - 0
Code/src/App.tsx

@@ -11,6 +11,8 @@ import { useSelector } from 'react-redux'
 import { isLoc } from './utils/http'
 const A1home = React.lazy(() => import('./pages/A1home'))
 const A2visit = React.lazy(() => import('./pages/A2visit'))
+const A3banquet = React.lazy(() => import('./pages/A3banquet'))
+const B1more = React.lazy(() => import('./pages/B1more'))
 const Text = React.lazy(() => import('./pages/Text'))
 
 export default function App() {
@@ -76,6 +78,8 @@ export default function App() {
           <Switch>
             <Route path='/' component={A1home} exact />
             <Route path='/visit' component={A2visit} exact />
+            <Route path='/banquet' component={A3banquet} exact />
+            <Route path='/more' component={B1more} exact />
             <Route path='/text' component={Text} exact />
             <Route path='*' component={NotFound} />
           </Switch>

+ 1 - 1
Code/src/assets/styles/base.css

@@ -10,7 +10,7 @@
 :root {
   --themeColor: #cc1424;
   --themeColor2: #272727;
-  --fontNum: 14px;
+  --fontNum: 16px;
 }
 html {
   height: 100%;

+ 1 - 1
Code/src/assets/styles/base.less

@@ -11,7 +11,7 @@
 :root {
   --themeColor: #cc1424;
   --themeColor2: #272727;
-  --fontNum: 14px;
+  --fontNum: 16px;
 }
 
 html {

+ 13 - 0
Code/src/components/LazyImg/index.module.scss

@@ -0,0 +1,13 @@
+.LazyImg {
+  :global {
+    .lodingTxt {
+      font-size: 30px;
+      width: 100%;
+      height: 100%;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      color: #eacf60;
+    }
+  }
+}

+ 22 - 0
Code/src/components/LazyImg/index.tsx

@@ -0,0 +1,22 @@
+import React from 'react'
+import styles from './index.module.scss'
+import { Image } from 'antd-mobile'
+
+type Props = {
+  src: string
+}
+
+function LazyImg({ src }: Props) {
+  return (
+    <Image
+      className={styles.LazyImg}
+      lazy
+      src={src}
+      placeholder={<div className='lodingTxt'>加载中...</div>}
+    />
+  )
+}
+
+const MemoLazyImg = React.memo(LazyImg)
+
+export default MemoLazyImg

+ 0 - 230
Code/src/pages/A1home/index copy.tsx

@@ -1,230 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
-import styles from './index.module.scss'
-import { myData } from '@/utils/http'
-import { domDelOwnFu, videoLodingNumFu } from '@/utils/xhrVideo'
-import classNames from 'classnames'
-import useMove from '@/components/ownUse/useMove'
-import useDataUrl from '@/components/ownUse/useDataUrl'
-import history from '@/utils/history'
-
-function A1home() {
-  const { dataUrlSame } = useDataUrl()
-
-  const { touchstart, touchmove, touchend } = useMove()
-
-  // 动画视频的ref
-  const videoRef = useRef<HTMLVideoElement>(null)
-
-  // 当前视频索引
-  const [videoInd, setVideoInd] = useState(-1)
-
-  useEffect(() => {
-    if (videoInd > -1) {
-      setTimeout(() => {
-        if (videoRef.current) {
-          videoRef.current.currentTime = 0
-          videoRef.current.play()
-        }
-      }, 100)
-    }
-  }, [videoInd])
-
-  const [loding, setLoding] = useState(0)
-
-  const lodingRef = useRef(0)
-
-  useEffect(() => {
-    lodingRef.current = loding
-  }, [loding])
-
-  useEffect(() => {
-    if (loding >= 100) {
-      setVideoInd(0)
-      // 0.5s之后删除自己
-      setTimeout(() => {
-        domDelOwnFu('.A1base')
-      }, 500)
-    }
-  }, [loding])
-
-  const lodingIng = useRef(0)
-
-  // 5个动画视频的总长度
-  const lodingNumRef = useRef(0)
-
-  // 加载完成之后的bolo地址
-  const videoSrcArrRef = useRef<{ sort: number; name: string }[]>([])
-
-  const [videoSrcArr, setVideoSrcArr] = useState<string[]>([])
-
-  // 通过blob预加载 src为原视频的视频地址
-  const videoLodingFu = useCallback((src: string, sort: number) => {
-    return new Promise((resolve, reject) => {
-      const req = new XMLHttpRequest()
-      req.open('GET', src, true)
-      req.responseType = 'blob'
-
-      req.onprogress = function (event) {
-        if (lodingNumRef.current) {
-          const num = lodingIng.current + event.loaded
-
-          let percent = (num / lodingNumRef.current) * 100
-
-          percent = Number(percent.toFixed(0))
-
-          if (lodingRef.current < percent) setLoding(percent)
-        }
-      }
-
-      req.onload = function (event) {
-        lodingIng.current += event.total
-        if (this.status === 200) {
-          const videoBlob = this.response
-          const blobSrc = URL.createObjectURL(videoBlob)
-          videoSrcArrRef.current.push({ sort, name: blobSrc })
-          if (videoSrcArrRef.current.length === myData.home.videos.length) {
-            videoSrcArrRef.current = videoSrcArrRef.current.sort((a, b) => a.sort - b.sort)
-            setVideoSrcArr(videoSrcArrRef.current.map(v => v.name))
-
-            // 存到仓库
-          }
-        }
-      }
-      req.send()
-    })
-  }, [])
-
-  const getVideoNum = useCallback(() => {
-    // const aaaa = [
-    //   { sort: 1, name: 'https://houseoss.4dkankan.com/project/henan/1.mp4' },
-    //   { sort: 2, name: 'https://houseoss.4dkankan.com/project/henan/2.mp4' },
-    //   { sort: 3, name: 'https://houseoss.4dkankan.com/project/henan/3.mp4' },
-    //   { sort: 4, name: 'https://houseoss.4dkankan.com/project/henan/2.mp4' },
-    //   { sort: 5, name: 'https://houseoss.4dkankan.com/project/henan/1.mp4' }
-    // ]
-    // aaaa.forEach(async v => {
-    //   const temp = await videoLodingNumFu(`${v.name}`)
-    //   lodingNumRef.current += temp
-    //   await videoLodingFu(`${v.name}`, v.sort)
-    // })
-    // myData.home.videos.forEach(async v => {
-    //   const temp = await videoLodingNumFu(`${dataUrlSame}/${v.name}`)
-    //   lodingNumRef.current += temp
-    //   await videoLodingFu(`${dataUrlSame}/${v.name}`, v.sort)
-    // })
-  }, [dataUrlSame, videoLodingFu])
-
-  useEffect(() => {
-    if (dataUrlSame) {
-      getVideoNum()
-    }
-  }, [dataUrlSame, getVideoNum])
-
-  // 视频播完 或者 点击下一步
-  const videoEndFu = useCallback(
-    (num: number) => {
-      // 这个页面只能往下滑
-      if (num === -1) return
-
-      if (videoInd === myData.home.videos.length - 2 && num === 1) return
-      if (videoInd === 0 && num === -1) return
-      setVideoInd(videoInd + num)
-    },
-    [videoInd]
-  )
-  const onSwipeChange = useCallback(
-    (val: number) => {
-      videoEndFu(val)
-    },
-    [videoEndFu]
-  )
-
-  // 是否滑到了倒数第二个
-  const isLastButOne = useMemo(() => {
-    let flag = false
-    if (videoInd === myData.home.videos.length - 2) flag = true
-    return flag
-  }, [videoInd])
-
-  // 是否到了最后一个
-  const isLastVideo = useMemo(() => {
-    let flag = false
-    if (videoInd === myData.home.videos.length - 1) flag = true
-    return flag
-  }, [videoInd])
-
-  return (
-    <div className={styles.A1home}>
-      {/* 加载页面 */}
-      <div className={classNames('A1base', videoInd < 0 ? '' : 'A1baseHide')}>
-        <img src={`${dataUrlSame}/logo.png`} alt='' />
-
-        <div className='A1loding'>{loding}%</div>
-      </div>
-
-      {/* 5个视频动画页面 */}
-      {videoInd > -1 && videoSrcArr.length ? (
-        <>
-          {isLastVideo ? (
-            <div className='A1videoLast'>
-              <video
-                ref={videoRef}
-                src={videoSrcArr[videoSrcArr.length - 1]}
-                playsInline
-                muted
-                webkit-playsinline='true'
-                x5-video-player-type='h5'
-                onEnded={() => history.push('/visit')}
-              />
-              <div
-                className='A1videoLastBtn'
-                style={{ backgroundImage: `url(${dataUrlSame}/quan.png)` }}
-                onClick={() => history.push('/visit')}
-              >
-                跳 过
-              </div>
-            </div>
-          ) : (
-            <div
-              className='A1video'
-              onTouchStart={e => touchstart(e.touches[0].pageY)}
-              onTouchMove={e => touchmove(e.touches[0].pageY)}
-              onTouchEnd={() => touchend(val => onSwipeChange(val), 'mobile')}
-              onMouseDown={e => touchstart(e.pageY)}
-              onMouseMove={e => touchmove(e.pageY)}
-              onMouseUp={() => touchend(val => onSwipeChange(val), 'pc')}
-            >
-              <video
-                ref={videoRef}
-                src={videoSrcArr[videoInd]}
-                playsInline
-                muted
-                webkit-playsinline='true'
-                x5-video-player-type='h5'
-                // onEnded={() => videoEndFu(1)}
-                loop={videoInd === videoSrcArr.length - 2}
-              />
-              {isLastButOne ? (
-                <>
-                  <img className='A1videoBtnLogo' src={`${dataUrlSame}/logo.png`} alt='' />
-                  <img
-                    className='A1videoBtn'
-                    onClick={() => setVideoInd(videoSrcArr.length - 1)}
-                    src={`${dataUrlSame}/nextLast.png`}
-                    alt=''
-                  />
-                </>
-              ) : (
-                <img onClick={() => videoEndFu(1)} src={`${dataUrlSame}/next.png`} alt='' />
-              )}
-            </div>
-          )}
-        </>
-      ) : null}
-    </div>
-  )
-}
-
-const MemoA1home = React.memo(A1home)
-
-export default MemoA1home

+ 20 - 0
Code/src/pages/A1home/index.module.scss

@@ -30,6 +30,7 @@
         color: #733c00;
       }
       .A1lodingBtn {
+        cursor: pointer;
         width: 100px;
         height: auto;
         bottom: 40px;
@@ -50,6 +51,25 @@
           font-size: 16px;
         }
       }
+      // 序列帧动画
+      .A1move {
+        width: 100%;
+        height: auto;
+        position: absolute;
+        // pointer-events: none;
+        bottom: 0;
+        left: 50%;
+        transform: translateX(-50%);
+        overflow: hidden;
+        & > img {
+          position: relative;
+          left: 0;
+          width: auto;
+          max-width: 30000000px;
+          max-height: 10000px;
+          object-fit: fill;
+        }
+      }
     }
     .A1baseHide {
       opacity: 0;

+ 72 - 3
Code/src/pages/A1home/index.tsx

@@ -4,10 +4,65 @@ import useDataUrl from '@/components/ownUse/useDataUrl'
 import useMove from '@/components/ownUse/useMove'
 import { myData } from '@/utils/http'
 import classNames from 'classnames'
-import { domDelOwnFu } from '@/utils/xhrVideo'
 import history from '@/utils/history'
+import { domDelOwnFu } from '@/utils/utilsSome'
 
 function A1home() {
+  // 有关序列帧动画
+  const [pageSize, setPageSize] = useState({
+    width: 0,
+    height: 0
+  })
+
+  const timerr = useRef(-1)
+
+  const pageSizeChange = useCallback(() => {
+    const width = document.documentElement.clientWidth
+    const height = document.documentElement.clientHeight
+
+    setPageSize({
+      width: width,
+      height: height
+    })
+
+    // 看看是否已经插入的 script
+    const ruDom = document.querySelector('#myStyle')
+    if (ruDom) ruDom.remove()
+    clearTimeout(timerr.current)
+
+    timerr.current = window.setTimeout(() => {
+      const zhen = 144
+
+      // console.log(imgWidth, imgWidth / num);
+      const styleStr = `.A1move img {
+               animation: tab2MoveImg 1s steps(${zhen}) infinite;
+             }
+             @keyframes tab2MoveImg {
+               100% {
+                 left: -${width * zhen}px;
+               }
+             }`
+      const styletDom = document.createElement('style')
+      styletDom.type = 'text/css'
+      styletDom.id = 'myStyle'
+      styletDom.innerHTML = styleStr
+      document.querySelector('html')?.appendChild(styletDom)
+    }, 100)
+  }, [])
+
+  useEffect(() => {
+    // pageSizeChange()
+
+    setTimeout(() => {
+      pageSizeChange()
+    }, 1000)
+
+    window.addEventListener('resize', pageSizeChange, false)
+    return () => {
+      window.removeEventListener('resize', pageSizeChange)
+    }
+  }, [pageSizeChange])
+
   const { dataUrlSame } = useDataUrl()
 
   const { touchstart, touchmove, touchend } = useMove()
@@ -15,7 +70,7 @@ function A1home() {
   // 动画视频的ref
   const videoRef = useRef<HTMLVideoElement>(null)
 
-  const [loding, setLoding] = useState(100)
+  const [loding, setLoding] = useState(0)
 
   const timeRR = useRef(-1)
 
@@ -32,6 +87,8 @@ function A1home() {
 
   // 点击开始
   const btnStartFu = useCallback(() => {
+    window.removeEventListener('resize', pageSizeChange)
+
     setLoding(110)
     // 自动播放视频
     setTimeout(() => {
@@ -44,7 +101,7 @@ function A1home() {
     setTimeout(() => {
       domDelOwnFu('.A1base')
     }, 500)
-  }, [])
+  }, [pageSizeChange])
 
   const [ind, setInd] = useState(0)
 
@@ -110,6 +167,18 @@ function A1home() {
         ) : (
           <div className='A1loding'>{loding}%</div>
         )}
+
+        {/* 序列帧动画 */}
+        {/* 1688x335 */}
+        {pageSize.width ? (
+          <div className='A1move'>
+            <img
+              src={`${dataUrlSame}home/move.png`}
+              style={{ height: (pageSize.width / 1688) * 335 }}
+              alt=''
+            />
+          </div>
+        ) : null}
       </div>
 
       {/* 5个动画视频 */}

+ 163 - 0
Code/src/pages/A2visit/PanoVideo/Hot1/index.module.scss

@@ -0,0 +1,163 @@
+.Hot1 {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 20;
+  background-size: 100% 100%;
+  transition: all 0.3s;
+  padding: 8% 12% 5% 12%;
+  :global {
+    .hot1Box {
+      width: 100%;
+      height: 100%;
+      position: relative;
+      // 主体
+      .hot1Main {
+        display: flex;
+        justify-content: space-between;
+        height: 84%;
+        & > div {
+          width: 48%;
+        }
+        .h1Mll {
+          overflow: hidden;
+          border: 1px solid #eacf60;
+          position: relative;
+
+          // 左右箭头
+          .h1MllIcon {
+            width: 20px;
+            position: absolute;
+            z-index: 10;
+            top: 50%;
+            transform: translateY(-50%);
+            cursor: pointer;
+            left: 5%;
+          }
+
+          .h1Mllyou {
+            left: auto;
+            right: 5%;
+          }
+
+          .h1MllCo {
+            height: 100%;
+            display: flex;
+            transition: transform 0.3s;
+          }
+
+          .h1MllRow {
+            height: 100%;
+            display: flex;
+            align-items: center;
+            padding: 10px;
+
+            .adm-image {
+              width: 100%;
+              height: 100%;
+              border: 1px solid #eacf60;
+              img {
+                width: 100%;
+                height: 100%;
+                object-fit: cover !important;
+              }
+            }
+          }
+        }
+        .h1Mrr {
+          height: 96%;
+          overflow-y: auto;
+          position: relative;
+          padding-bottom: 15px;
+          &::-webkit-scrollbar {
+            display: none;
+          }
+
+          .h1MrrTxt {
+            position: absolute;
+            top: 50%;
+            left: 0;
+            width: 100%;
+            transform: translateY(-50%);
+            max-height: 100%;
+
+            & > h1 {
+              color: #eacf60;
+              font-size: 40px;
+              font-weight: 400;
+              margin-bottom: 1%;
+            }
+            & > div {
+              color: #fffddc;
+            }
+            h3 {
+              font-size: 18px;
+              font-weight: 400;
+            }
+            h2 {
+              font-size: 20px;
+              font-weight: 400;
+            }
+            p {
+              font-size: 16px;
+            }
+          }
+        }
+      }
+
+      // 返回按钮
+      .h1Mback {
+        position: absolute;
+        z-index: 10;
+        top: 0;
+        right: 0;
+        width: 36px;
+        height: auto;
+        cursor: pointer;
+      }
+
+      // 底部
+      .h1Floo {
+        position: absolute;
+        bottom: 0;
+        left: 50%;
+        transform: translateX(-50%);
+        width: 80%;
+        height: 10%;
+        background-size: 100% 100%;
+        border: 1px dashed #ccc;
+        border-radius: 4px;
+        display: flex;
+        max-height: 50px;
+        .h1FlooRow {
+          cursor: pointer;
+          flex: 1;
+          font-size: 18px;
+          height: 100%;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          color: #fffddc;
+          opacity: 0.8;
+        }
+        .h1FlooRowShow {
+          opacity: 1;
+          color: #eacf60;
+          position: relative;
+        }
+        .h1FlooRowShowImg {
+          max-width: 1000px;
+          height: 180%;
+          width: auto;
+          position: absolute;
+          left: 46%;
+          top: 54%;
+          transform: translate(-50%, -50%);
+          max-height: 70px;
+        }
+      }
+    }
+  }
+}

+ 136 - 0
Code/src/pages/A2visit/PanoVideo/Hot1/index.tsx

@@ -0,0 +1,136 @@
+import React, { useCallback, useEffect, useMemo, useState } from 'react'
+import styles from './index.module.scss'
+import useDataUrl from '@/components/ownUse/useDataUrl'
+import { VisitHotDataType } from '@/types'
+import classNames from 'classnames'
+import LazyImg from '@/components/LazyImg'
+
+type Props = {
+  closeFu: () => void
+  data: VisitHotDataType
+}
+
+function Hot1({ closeFu, data }: Props) {
+  const [opShow, setOpShow] = useState(false)
+
+  useEffect(() => {
+    setTimeout(() => {
+      setOpShow(true)
+    }, 300)
+  }, [])
+
+  const { dataUrlSame } = useDataUrl()
+
+  // 底部选中
+  const [flooInd, setFlooInd] = useState(0)
+
+  // 点击切换底部
+  const flooIndFu = useCallback((ind: number) => {
+    setImgAc(0)
+    const dom = document.querySelector('.h1Mrr')
+    if (dom) dom.scrollTop = 0
+    setFlooInd(ind)
+  }, [])
+
+  // 图片切换
+  const [imgAc, setImgAc] = useState(0)
+
+  const acData = useMemo(() => {
+    return data[flooInd] || []
+  }, [data, flooInd])
+
+  return (
+    <div
+      className={styles.Hot1}
+      style={{
+        backgroundImage: `url(${dataUrlSame}visit/hot1bj.png)`,
+        opacity: opShow ? 1 : 0
+      }}
+    >
+      <div className='hot1Box'>
+        {/* 主体 */}
+        <div className='hot1Main'>
+          {/* 左边 */}
+          <div className='h1Mll'>
+            {/* 左右箭头 */}
+            <img
+              onClick={() => setImgAc(imgAc - 1)}
+              hidden={acData.imgArr.length <= 1}
+              style={{
+                opacity: imgAc === 0 ? 0.5 : 1,
+                pointerEvents: imgAc === 0 ? 'none' : 'auto'
+              }}
+              className='h1MllIcon'
+              src={`${dataUrlSame}visit/icon-zuo-red.png`}
+              alt=''
+            />
+            <img
+              onClick={() => setImgAc(imgAc + 1)}
+              hidden={acData.imgArr.length <= 1}
+              style={{
+                opacity: imgAc === acData.imgArr.length - 1 ? 0.5 : 1,
+                pointerEvents: imgAc === acData.imgArr.length - 1 ? 'none' : 'auto'
+              }}
+              className='h1MllIcon h1Mllyou'
+              src={`${dataUrlSame}visit/icon-you-red.png`}
+              alt=''
+            />
+
+            <div
+              className='h1MllCo'
+              style={{
+                transform: `translateX(-${(100 / acData.imgArr.length) * imgAc}%)`,
+                width: `${100 * acData.imgArr.length}%`
+              }}
+            >
+              {acData.imgArr.map((url, index) => (
+                <div
+                  className='h1MllRow'
+                  key={index}
+                  style={{ width: 100 / acData.imgArr.length + '%' }}
+                >
+                  <LazyImg src={dataUrlSame + url} />
+                </div>
+              ))}
+            </div>
+          </div>
+          {/* 右边 */}
+          <div className='h1Mrr'>
+            <div className='h1MrrTxt'>
+              <h1>{acData.name}</h1>
+              <div dangerouslySetInnerHTML={{ __html: acData.txt }}></div>
+            </div>
+          </div>
+
+          {/* 返回按钮 */}
+          <img className='h1Mback' onClick={closeFu} src={`${dataUrlSame}visit/back.png`} alt='' />
+        </div>
+
+        {/* 底部 */}
+        <div className='h1Floo' style={{ backgroundImage: `url(${dataUrlSame}visit/h1fllo.png)` }}>
+          {data.map((item, index) => (
+            <div
+              onClick={() => flooIndFu(index)}
+              className={classNames('h1FlooRow', flooInd === index ? 'h1FlooRowShow' : '')}
+              key={index}
+            >
+              {item.name}
+
+              {flooInd === index ? (
+                <img
+                  className='h1FlooRowShowImg'
+                  src={`${dataUrlSame}visit/bichuyuan.png`}
+                  alt=''
+                />
+              ) : null}
+            </div>
+          ))}
+        </div>
+      </div>
+    </div>
+  )
+}
+
+const MemoHot1 = React.memo(Hot1)
+
+export default MemoHot1

+ 12 - 0
Code/src/pages/A2visit/PanoVideo/Hot2/index.module.scss

@@ -0,0 +1,12 @@
+.Hot1 {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 20;
+  background-color: red;
+  opacity: 0.5;
+  :global {
+  }
+}

+ 13 - 0
Code/src/pages/A2visit/PanoVideo/Hot2/index.tsx

@@ -0,0 +1,13 @@
+import React from 'react'
+import styles from './index.module.scss'
+function Hot1() {
+  return (
+    <div className={styles.Hot1}>
+      <h1>Hot1</h1>
+    </div>
+  )
+}
+
+const MemoHot1 = React.memo(Hot1)
+
+export default MemoHot1

+ 8 - 0
Code/src/pages/A2visit/PanoVideo/index.module.scss

@@ -0,0 +1,8 @@
+.PanoVideo {
+  width: 100%;
+  height: 100%;
+
+  font-size: 20px;
+  // :global {
+  // }
+}

+ 31 - 0
Code/src/pages/A2visit/PanoVideo/index.tsx

@@ -0,0 +1,31 @@
+import React, { useMemo, useState } from 'react'
+import styles from './index.module.scss'
+import Hot1 from './Hot1'
+import Hot2 from './Hot2'
+import { myData } from '@/utils/http'
+function PanoVideo() {
+  // 0为 第一种模式的热点 其他为第二种
+  const [ind, setInd] = useState(-1)
+
+  const data = useMemo(() => {
+    if (ind !== -1) return myData.visit.hot[ind].data
+    else return []
+  }, [ind])
+
+  return (
+    <div className={styles.PanoVideo}>
+      {/* 待完善 */}
+      全景视频
+      {myData.visit.hot.map((item, index) => (
+        <div key={index} onClick={() => setInd(index)}>
+          {item.name}
+        </div>
+      ))}
+      {ind === -1 ? null : ind === 0 ? <Hot1 data={data} closeFu={() => setInd(-1)} /> : <Hot2 />}
+    </div>
+  )
+}
+
+const MemoPanoVideo = React.memo(PanoVideo)
+
+export default MemoPanoVideo

+ 74 - 3
Code/src/pages/A2visit/index.module.scss

@@ -9,7 +9,7 @@
       width: 100%;
       height: 100%;
       position: absolute;
-      z-index: 10;
+      z-index: 11;
       opacity: 1;
       transition: opacity 0.5s;
       & > img {
@@ -82,10 +82,81 @@
       pointer-events: none;
     }
 
-    .A2panoVideo {
+    // 全景视频盒子
+    .pvBox {
+      width: 100%;
+      height: 100%;
+      position: relative;
+      opacity: 1;
+      transition: opacity 0.5s;
+      .pvBtn {
+        position: absolute;
+        right: 20px;
+        top: 50%;
+        transform: translateY(-50%);
+        cursor: pointer;
+        width: 120px;
+        height: auto;
+        z-index: 10;
+        & > img {
+          width: 100%;
+        }
+        & > div {
+          position: absolute;
+          top: 0;
+          left: 0;
+          width: 100%;
+          height: 100%;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          color: #fffddc;
+          font-size: 16px;
+          & > span {
+            padding-left: 5px;
+            font-size: 14px;
+          }
+        }
+      }
+      .pvRRbtn {
+        position: absolute;
+        right: 25px;
+        bottom: 25px;
+        z-index: 10;
+        display: flex;
+        justify-content: space-between;
+        width: 105px;
+        & > img {
+          width: 50px;
+          height: auto;
+          cursor: pointer;
+        }
+      }
+    }
+    .pvBoxHide {
+      opacity: 0;
+    }
+
+    // 最后一个长视频
+    .A2last {
       width: 100%;
       height: 100%;
-      background-color: red;
+      position: relative;
+      .A1videoLastBtn {
+        position: absolute;
+        width: 50px;
+        height: 50px;
+        cursor: pointer;
+        bottom: 20px;
+        right: 20px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        color: #733c00;
+        background-size: 100% 100%;
+        font-size: 20px;
+        padding-bottom: 4px;
+      }
     }
   }
 }

+ 112 - 75
Code/src/pages/A2visit/index.tsx

@@ -3,78 +3,46 @@ import styles from './index.module.scss'
 import classNames from 'classnames'
 import useDataUrl from '@/components/ownUse/useDataUrl'
 import { myData } from '@/utils/http'
-import { domDelOwnFu, videoLodingNumFu } from '@/utils/xhrVideo'
+import { domDelOwnFu } from '@/utils/utilsSome'
+import PanoVideo from './PanoVideo'
+import history from '@/utils/history'
+import { ArrowRightOutlined } from '@ant-design/icons'
 
 function A2visit() {
   const { dataUrlSame } = useDataUrl()
 
+  // 初始视频
+  const A2baseVideo = useRef<HTMLVideoElement>(null)
+
+  useEffect(() => {
+    setTimeout(() => {
+      if (A2baseVideo.current) {
+        A2baseVideo.current.play()
+      }
+    }, 100)
+  }, [])
+
   // 动画视频的ref
   const videoRef = useRef<HTMLVideoElement>(null)
 
   // 当前视频索引
   const [videoInd, setVideoInd] = useState(-1)
 
-  const [loding, setLoding] = useState(0)
-
-  const lodingIng = useRef(0)
-
-  // 动画视频的总长度
-  const lodingNumRef = useRef(0)
+  // 待完善
+  const [loding, setLoding] = useState(100)
 
-  // 加载完成之后的bolo地址
-  const videoSrcArrRef = useRef<{ sort: number; name: string }[]>([])
-
-  const [videoSrcArr, setVideoSrcArr] = useState<string[]>([])
-
-  // 通过blob预加载 src为原视频的视频地址
-  const videoLodingFu = useCallback((src: string, sort: number) => {
-    return new Promise((resolve, reject) => {
-      const req = new XMLHttpRequest()
-      req.open('GET', src, true)
-      req.responseType = 'blob'
-
-      req.onprogress = function (event) {
-        if (lodingNumRef.current) {
-          const num = lodingIng.current + event.loaded
-
-          let percent = (num / lodingNumRef.current) * 100
-
-          percent = Number(percent.toFixed(0))
-
-          setLoding(percent)
-        }
-      }
-
-      req.onload = function (event) {
-        lodingIng.current += event.total
-        if (this.status === 200) {
-          const videoBlob = this.response
-          const blobSrc = URL.createObjectURL(videoBlob)
-          videoSrcArrRef.current.push({ sort, name: blobSrc })
-          if (videoSrcArrRef.current.length === myData.visit.video.length) {
-            videoSrcArrRef.current = videoSrcArrRef.current.sort((a, b) => a.sort - b.sort)
-            setVideoSrcArr(videoSrcArrRef.current.map(v => v.name))
-          }
-        }
-      }
-      req.send()
-    })
-  }, [])
-
-  const getVideoNum = useCallback(() => {
-    myData.visit.video.forEach(async v => {
-      const temp = await videoLodingNumFu(`${dataUrlSame}/${v.name}`)
-      lodingNumRef.current += temp
-
-      await videoLodingFu(`${dataUrlSame}/${v.name}`, v.sort)
-    })
-  }, [dataUrlSame, videoLodingFu])
+  const timeRR = useRef(-1)
 
   useEffect(() => {
-    if (dataUrlSame) {
-      getVideoNum()
-    }
-  }, [dataUrlSame, getVideoNum])
+    clearInterval(timeRR.current)
+    timeRR.current = window.setInterval(() => {
+      if (loding >= 100) {
+        clearInterval(timeRR.current)
+        return
+      }
+      setLoding(loding + 1)
+    }, 30)
+  }, [loding])
 
   // 开始之后的过度动画
   const [overVideo, setOverVideo] = useState(true)
@@ -89,8 +57,11 @@ function A2visit() {
     }
   }, [overVideo])
 
-  // 点击开始
+  // 点击继续
   const btnStart = useCallback(() => {
+    // 待完善-后面删除
+    setOverVideo(false)
+
     if (loding >= 100) {
       // 播放已经加载好的视频
       setVideoInd(0)
@@ -106,6 +77,27 @@ function A2visit() {
     }
   }, [loding])
 
+  // 点击 跳下一个章节
+
+  const [lastVideo, setLastVideo] = useState(false)
+
+  const videoRefLast = useRef<HTMLVideoElement>(null)
+
+  const lastVideoFu = useCallback(() => {
+    setLastVideo(true)
+
+    setTimeout(() => {
+      if (videoRefLast.current) {
+        videoRefLast.current.play()
+      }
+    }, 100)
+
+    // 0.5s之后删除自己
+    setTimeout(() => {
+      domDelOwnFu('.pvBox')
+    }, 500)
+  }, [])
+
   return (
     <div className={styles.A2visit}>
       {/* 加载页面 */}
@@ -114,7 +106,7 @@ function A2visit() {
         <div className='A2baseBtn'>
           <img src={`${dataUrlSame}visit/btn.png`} alt='' />
           <div className='A2Btxt' onClick={btnStart}>
-            {loding >= 100 ? '点击开始' : '加载中'}
+            {loding >= 100 ? '点击继续' : '加载中'}
           </div>
           {loding >= 100 ? null : (
             <div className='A2Bxian'>
@@ -126,33 +118,78 @@ function A2visit() {
         </div>
 
         <video
+          ref={A2baseVideo}
           src={`${dataUrlSame}/${myData.visit.videoSta}`}
           playsInline
           muted
           webkit-playsinline='true'
           x5-video-player-type='h5'
-          autoPlay
           loop
         />
       </div>
 
       {/* 过度动画页面 */}
-      {videoInd === 0 ? (
-        <div className={classNames('A2base2', overVideo ? '' : 'A2baseHide2')}>
-          <video
-            ref={videoRef}
-            src={videoSrcArr[videoInd]}
-            playsInline
-            muted
-            webkit-playsinline='true'
-            x5-video-player-type='h5'
-            onEnded={() => setOverVideo(false)}
+      <div hidden={loding < 100} className={classNames('A2base2', overVideo ? '' : 'A2baseHide2')}>
+        <video
+          ref={videoRef}
+          playsInline
+          muted
+          webkit-playsinline='true'
+          x5-video-player-type='h5'
+          src={dataUrlSame + myData.visit.videos[videoInd < 0 ? 0 : videoInd]}
+          onEnded={() => setOverVideo(false)}
+        >
+          <source type='video/mp4' />
+          Your browser does not support the video tag.
+        </video>
+      </div>
+
+      {/* 全景视频 */}
+      <div className={classNames('pvBox', lastVideo ? 'pvBoxHide' : '')} hidden={overVideo}>
+        <PanoVideo />
+        {/* 跳到下一章 */}
+        <div className='pvBtn'>
+          <img src={`${dataUrlSame}visit/btn.png`} alt='' />
+          <div onClick={lastVideoFu}>
+            行拜谒礼
+            <ArrowRightOutlined />
+          </div>
+        </div>
+
+        <div className='pvRRbtn'>
+          {/* 漫游 待完善 */}
+          <img src={`${dataUrlSame}visit/icon-walk.png`} alt='' />
+          {/* 更多 跳新页面 */}
+          <img
+            onClick={() => history.push('/more')}
+            src={`${dataUrlSame}visit/icon-more.png`}
+            alt=''
           />
         </div>
-      ) : null}
+      </div>
 
-      {/* 全景视频 */}
-      {overVideo ? null : <div className='A2panoVideo'>全景视频</div>}
+      {/* 最后一个过长动画 */}
+      <div className='A2last'>
+        <video
+          ref={videoRefLast}
+          playsInline
+          muted
+          webkit-playsinline='true'
+          x5-video-player-type='h5'
+          src={dataUrlSame + myData.visit.lastVideo}
+          onEnded={() => history.push('/banquet')}
+        >
+          <source type='video/mp4' />
+          Your browser does not support the video tag.
+        </video>
+        <div
+          className='A1videoLastBtn'
+          style={{ backgroundImage: `url(${dataUrlSame}home/quan.png)` }}
+          onClick={() => history.push('/banquet')}
+        >
+          跳过
+        </div>
+      </div>
     </div>
   )
 }

+ 4 - 0
Code/src/pages/A3banquet/index.module.scss

@@ -0,0 +1,4 @@
+.A3banquet {
+  :global {
+  }
+}

+ 13 - 0
Code/src/pages/A3banquet/index.tsx

@@ -0,0 +1,13 @@
+import React from 'react'
+import styles from './index.module.scss'
+function A3banquet() {
+  return (
+    <div className={styles.A3banquet}>
+      <h1>A3banquet</h1>
+    </div>
+  )
+}
+
+const MemoA3banquet = React.memo(A3banquet)
+
+export default MemoA3banquet

+ 4 - 0
Code/src/pages/B1more/index.module.scss

@@ -0,0 +1,4 @@
+.B1more {
+  :global {
+  }
+}

+ 14 - 0
Code/src/pages/B1more/index.tsx

@@ -0,0 +1,14 @@
+import React from 'react'
+import styles from './index.module.scss'
+function B1more() {
+  return (
+    <div className={styles.B1more}>
+      <h1>更多</h1>
+      {/* 待完善 */}
+    </div>
+  )
+}
+
+const MemoB1more = React.memo(B1more)
+
+export default MemoB1more

+ 15 - 9
Code/src/types/api/layot.d.ts

@@ -1,12 +1,18 @@
 export type LookDomType = {
-  src: string;
-  type: "video" | "audio" | "model" | "";
-  flag?: boolean;
-};
+  src: string
+  type: 'video' | 'audio' | 'model' | ''
+  flag?: boolean
+}
 
 export type FileImgListType = {
-  id: number;
-  fileName: string;
-  filePath: string;
-  type: "img" | "video" | "doc";
-};
+  id: number
+  fileName: string
+  filePath: string
+  type: 'img' | 'video' | 'doc'
+}
+
+export type VisitHotDataType = {
+  name: string
+  txt: string
+  imgArr: string[]
+}[]

+ 9 - 2
Code/src/types/declaration.d.ts

@@ -10,7 +10,6 @@ declare module 'braft-utils'
 // public/myData.js 里面的一些数据的类型
 declare const baseUrlLoc: string
 declare const baseUrlAtl: string
-// 数据类型待完善
 declare const myDataTemp: MyDataType
 
 type MyDataType = {
@@ -22,6 +21,14 @@ type MyDataType = {
   }
   visit: {
     videoSta: string
-    video: { sort: number; name: string }[]
+    videos: string[]
+    lastVideo: string
+    hot: {
+      name: string
+      size: number
+      atv: number
+      ath: number
+      data: VisitHotDataType
+    }[]
   }
 }

+ 4 - 0
Code/src/utils/utilsSome.ts

@@ -0,0 +1,4 @@
+export const domDelOwnFu = (classNmae: string) => {
+  const dom = document.querySelector(classNmae)
+  if (dom) dom.remove()
+}

+ 0 - 29
Code/src/utils/xhrVideo.ts

@@ -1,29 +0,0 @@
-/**
- *
- * @param src 视频路径
- * @returns Promise - 视频的总长度
- */
-
-export const videoLodingNumFu = (src: string): Promise<number> => {
-  return new Promise((resolve, reject) => {
-    const req = new XMLHttpRequest()
-    req.open('HEAD', src, true)
-    req.onreadystatechange = function () {
-      if (req.readyState === 4) {
-        if (req.status === 200) {
-          const contentLength = req.getResponseHeader('Content-Length')
-          if (contentLength) {
-            const videoLength = parseInt(contentLength, 10)
-            resolve(videoLength)
-          }
-        }
-      }
-    }
-    req.send()
-  })
-}
-
-export const domDelOwnFu = (classNmae: string) => {
-  const dom = document.querySelector(classNmae)
-  if (dom) dom.remove()
-}

BIN
资源/staticData/HH/home/move.png


BIN
资源/staticData/HH/visit/back.png


BIN
资源/staticData/HH/visit/bichuyuan.png


资源/staticData/HH/visit/2.mp4 → 资源/staticData/HH/visit/end.mp4


BIN
资源/staticData/HH/visit/h1fllo.png


BIN
资源/staticData/HH/visit/hot/1.jpg


BIN
资源/staticData/HH/visit/hot/2.jpg


BIN
资源/staticData/HH/visit/hot/3.jpg


BIN
资源/staticData/HH/visit/hot1bj.png


BIN
资源/staticData/HH/visit/icon-more.png


BIN
资源/staticData/HH/visit/icon-walk.png


BIN
资源/staticData/HH/visit/icon-you-red.png


BIN
资源/staticData/HH/visit/icon-zuo-red.png