shaogen1995 1 rok pred
rodič
commit
5abdeeba07
38 zmenil súbory, kde vykonal 1563 pridanie a 219 odobranie
  1. 20 1
      code/src/AppM.tsx
  2. BIN
      code/src/assets/img/tab3/icon_intro_active.png
  3. BIN
      code/src/assets/img/tab3/icon_intro_normal.png
  4. 0 3
      code/src/assets/styles/base.css
  5. 5 6
      code/src/assets/styles/base.less
  6. 1 1
      code/src/components/ArcOrBuildInfo/index.tsx
  7. 205 0
      code/src/components/ArcOrBuildInfoM/index.module.scss
  8. 178 0
      code/src/components/ArcOrBuildInfoM/index.tsx
  9. 0 51
      code/src/components/ImageLazy/index.module.scss
  10. 0 40
      code/src/components/ImageLazy/index.tsx
  11. 39 0
      code/src/components/KrpanoCom/index.module.scss
  12. 68 0
      code/src/components/KrpanoCom/index.tsx
  13. 51 11
      code/src/pages/B1CardM/index.module.scss
  14. 42 10
      code/src/pages/B1CardM/index.tsx
  15. 0 38
      code/src/pages/B1Village/index.module.scss
  16. 14 47
      code/src/pages/B1Village/index.tsx
  17. 187 0
      code/src/pages/B1VillageM/index.module.scss
  18. 234 0
      code/src/pages/B1VillageM/index.tsx
  19. 1 0
      code/src/pages/C1Architec/index.module.scss
  20. 155 0
      code/src/pages/C1ArchitecM/index.module.scss
  21. 195 0
      code/src/pages/C1ArchitecM/index.tsx
  22. 3 3
      code/src/pages/C2ArchitecInfo/index.module.scss
  23. 13 3
      code/src/pages/C2ArchitecInfo/index.tsx
  24. 55 0
      code/src/pages/D1BuildM/index.module.scss
  25. 58 0
      code/src/pages/D1BuildM/index.tsx
  26. 10 1
      code/src/pages/Z2Scene/index.module.scss
  27. 9 1
      code/src/store/reducer/layout.ts
  28. 1 0
      code/src/types/api/layot.d.ts
  29. BIN
      静态资源/staticData/C1Architec/bgGuang.png
  30. BIN
      静态资源/staticData/C1Architec/bgM.png
  31. BIN
      静态资源/staticData/C1Architec/img_diwen.png
  32. BIN
      静态资源/staticData/C1Architec/line.png
  33. BIN
      静态资源/staticData/C2ArchitecInfo/bg2.jpg
  34. BIN
      静态资源/staticData/C2ArchitecInfo/icon_back.png
  35. BIN
      静态资源/staticData/C2ArchitecInfo/icon_cancel.png
  36. BIN
      静态资源/staticData/C2ArchitecInfo/tab.png
  37. BIN
      静态资源/staticData/D1Build/btn_subject.png
  38. 19 3
      静态资源/staticData/dataTemp.js

+ 20 - 1
code/src/AppM.tsx

@@ -9,7 +9,7 @@ import NotFound from "./components/NotFound";
 import { baseUrl } from ".";
 import classNames from "classnames";
 import { useSelector } from "react-redux";
-import { RootState } from "./store";
+import store, { RootState } from "./store";
 import { AppTabList } from "./utils/data";
 import screenImg from "@/assets/img/landtip.png";
 import fillTitImg from "@/assets/img/tab2/btn_normal.png";
@@ -17,6 +17,11 @@ import fillTitAcImg from "@/assets/img/tab2/btn_active.png";
 import B1CardM from "./pages/B1CardM";
 
 const A1HomeM = React.lazy(() => import("./pages/A1HomeM"));
+const B1VillageM = React.lazy(() => import("./pages/B1VillageM"));
+const C1ArchitecM = React.lazy(() => import("./pages/C1ArchitecM"));
+const C2ArchitecInfo = React.lazy(() => import("./pages/C2ArchitecInfo"));
+const D1BuildM = React.lazy(() => import("./pages/D1BuildM"));
+const Z2Scene = React.lazy(() => import("./pages/Z2Scene"));
 
 export default function AppM() {
   const setFullFu = useCallback(() => {
@@ -78,6 +83,11 @@ export default function AppM() {
       history.push(pathUrl);
       setTab2Show(false);
     } else setTab2Show(true);
+
+    if (id === 4) {
+      // 往仓库中添加一个信息,处理 单独打开构件页面  无法回跳的问题
+      store.dispatch({ type: "layout/isRouterPushBuild", payload: true });
+    }
   }, []);
 
   const [tab2Show, setTab2Show] = useState(false);
@@ -91,6 +101,15 @@ export default function AppM() {
             {/* 总览 */}
             <Route path="/" exact component={A1HomeM} />
             {/* 村落 */}
+            <Route path="/village" component={B1VillageM} />
+            {/* 建筑 */}
+            <Route path="/architec" component={C1ArchitecM} />
+            {/* 建筑详情 */}
+            <Route path="/architecInfo" component={C2ArchitecInfo} />
+            {/* 构件 */}
+            <Route path="/build" component={D1BuildM} />
+            {/* 场景 */}
+            <Route path="/scene" component={Z2Scene} />
             {/* 找不到页面 */}
             <Route path="*" component={NotFound} />
           </Switch>

BIN
code/src/assets/img/tab3/icon_intro_active.png


BIN
code/src/assets/img/tab3/icon_intro_normal.png


+ 0 - 3
code/src/assets/styles/base.css

@@ -221,9 +221,6 @@ textarea {
   text-align: center;
   line-height: 18px;
 }
-#root #AppM .AppMtab .AppMtabRowAc .AppMtabRowName {
-  text-shadow: 1px 1px var(--themeColor);
-}
 #root .ant-image {
   display: none;
 }

+ 5 - 6
code/src/assets/styles/base.less

@@ -264,12 +264,11 @@ textarea {
         }
       }
 
-      .AppMtabRowAc {
-        .AppMtabRowName {
-
-          text-shadow: 1px 1px var(--themeColor);
-        }
-      }
+      // .AppMtabRowAc {
+      //   .AppMtabRowName {
+      //     text-shadow: 2px 2px var(--themeColor);
+      //   }
+      // }
     }
 
   }

+ 1 - 1
code/src/components/ArcOrBuildInfo/index.tsx

@@ -92,7 +92,7 @@ function ArcOrBuildInfo({ info, type }: Props) {
           frameBorder="0"
         ></iframe>
         {/* 进入室内按钮 */}
-        {type === "C2ArchitecInfo" ? (
+        {type === "C2ArchitecInfo"&&info.code ? (
           <div
             hidden={full}
             className="C2rToScene"

+ 205 - 0
code/src/components/ArcOrBuildInfoM/index.module.scss

@@ -0,0 +1,205 @@
+.ArcOrBuildInfoM {
+  width: 100%;
+  height: 100%;
+  background-size: 100% 100%;
+  position: relative;
+
+  :global {
+    .AMback {
+      position: absolute;
+      top: 20px;
+      left: 20px;
+      z-index: 10;
+    }
+
+    .AMtop {
+      width: 100%;
+      height: calc(100% - 120px);
+      position: relative;
+
+      .AMtopName {
+        pointer-events: none;
+        width: 100%;
+        position: absolute;
+        top: 24px;
+        font-size: 24px;
+        letter-spacing: 2px;
+        color: var(--themeColor2);
+        text-align: center;
+      }
+
+      iframe {
+        width: 100%;
+        height: 100%;
+      }
+
+      .AMtopBtn {
+        position: absolute;
+        z-index: 3;
+        right: 15px;
+        bottom: 30px;
+        width: 30px;
+
+        .AMtopBtnRow {
+          margin-bottom: 30px;
+          width: 30px;
+          height: 30px;
+          background-size: 100% 100%;
+        }
+
+        .AMtopBtnRow1 {
+          background-image: url('../../assets/img/tab3/icon_intro_normal.png');
+        }
+
+        .AMtopBtnRow1Ac {
+          background-image: url('../../assets/img/tab3/icon_intro_active.png');
+        }
+
+        .AMtopBtnRow2 {
+          background-image: url('../../assets/img/tab3/icon_zoomin.png');
+        }
+
+        .AMtopBtnRow3 {
+          background-image: url('../../assets/img/tab3/icon_zoomout.png');
+        }
+
+        .AMtopBtnRow4 {
+          background-image: url('../../assets/img/tab3/icon_rorate.png');
+        }
+
+        .AMtopBtnRow5 {
+          background-image: url('../../assets/img/tab3/icon_fullscreen.png');
+        }
+
+        .AMtopBtnRow5Ac {
+          background-image: url('../../assets/img/tab3/icon_esc.png');
+        }
+      }
+    }
+
+    .AMtopFull {
+      position: absolute;
+      height: 100%;
+      z-index: 20;
+    }
+
+    .AMtopFull2 {
+      position: absolute;
+      height: 100%;
+    }
+
+    .AMbtn {
+      width: 100%;
+      height: 100px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+
+      .AMbtnRow {
+        margin: 0 6px;
+        width: 54px;
+        height: 54px;
+        background-image: url('../../assets/img/tab2/btn_normal.png');
+        background-size: 100% 100%;
+        position: relative;
+
+        &>div {
+          position: absolute;
+          top: 50%;
+          left: 55%;
+          transform: translate(-50%, -50%);
+          width: 30px;
+          z-index: 3;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          flex-wrap: wrap;
+          color: var(--themeColor2);
+          text-shadow: 1px 1px black;
+          text-align: center;
+          line-height: 16px;
+        }
+      }
+
+      .AMtoVr {
+        width: 120px;
+        height: 40px;
+        background-image: url('../../assets/img/tab2/btn_m.png');
+        background-size: 100% 100%;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        color: var(--themeColor);
+        font-size: 16px;
+        font-weight: 700;
+
+        &>p {
+          font-size: 18px;
+          position: relative;
+        }
+      }
+    }
+
+    .AMtxt {
+      border-radius: 40px 40px 0 0;
+      overflow: hidden;
+      opacity: 0;
+      pointer-events: none;
+      position: absolute;
+      bottom: -200px;
+      left: 0;
+      width: 100%;
+      z-index: 40;
+      height: auto;
+      min-height: 200px;
+      background-size: 100% 100%;
+      transition: all .3s;
+      color: var(--themeColor);
+      text-align: center;
+      padding-bottom: 20px;
+      max-height: 100%;
+      overflow-y: auto;
+
+      &>h3 {
+        height: 60px;
+        line-height: 60px;
+        font-size: 24px;
+        letter-spacing: 4px;
+        position: relative;
+
+        .AMtxtClose {
+          position: absolute;
+          right: 20px;
+          top: 50%;
+          transform: translateY(-50%);
+
+        }
+      }
+
+      .AMtxtLine {
+        width: 100%;
+        padding: 0 20px;
+        margin-bottom: 15px;
+        margin-top: -10px;
+      }
+
+      .AMtxtCon {
+        width: 100%;
+        padding: 0 16px 0 20px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        letter-spacing: 2px;
+        text-align: left;
+
+      }
+
+    }
+
+    .AMtxtAc {
+      bottom: 0;
+      opacity: 1;
+      pointer-events: auto;
+    }
+  }
+}

+ 178 - 0
code/src/components/ArcOrBuildInfoM/index.tsx

@@ -0,0 +1,178 @@
+/* eslint-disable jsx-a11y/iframe-has-title */
+
+import React, { useMemo, useRef, useState } from "react";
+import styles from "./index.module.scss";
+import { baseUrl } from "@/index";
+import { InfoRowType } from "@/types";
+import history from "@/utils/history";
+import { SwapRightOutlined } from "@ant-design/icons";
+import classNames from "classnames";
+
+const iconArr = [
+  { id: 2, name: "放大" },
+  { id: 3, name: "缩小" },
+  { id: 4, name: "复位" },
+];
+
+type Props = {
+  info: InfoRowType;
+  type: "C2ArchitecInfo" | "D2BuildInfo";
+};
+
+function ArcOrBuildInfoM({ info, type }: Props) {
+  // 模型的ref
+  const ifrRefNew = useRef<any>(null);
+
+  const modelChangeFu = (val: number) => {
+    const dom = ifrRefNew.current;
+
+    if (dom && dom.contentWindow && dom.contentWindow.webview) {
+      if (val === 2) dom.contentWindow.webview.zoomIn(); // 放大
+      else if (val === 3) dom.contentWindow.webview.zoomOut(); // 缩小
+      else dom.contentWindow.webview.resetView(); // 复位
+    }
+  };
+
+  // 文字介绍
+  const [txtShow, setTxtShow] = useState(false);
+
+  // 全屏
+  const [full, setFull] = useState(false);
+
+  // 是否没有大场景也没有构件
+  const isFullBox = useMemo(() => {
+    let flag = false;
+    if (
+      !info.code &&
+      (!info.isBuild || (info.isBuild && info.isBuild.length === 0))
+    ) {
+      flag = true;
+    }
+    return flag;
+  }, [info.code, info.isBuild]);
+
+  return (
+    <div
+      className={styles.ArcOrBuildInfoM}
+      style={{ backgroundImage: `url(${baseUrl}/C2ArchitecInfo/bg2.jpg)` }}
+    >
+      {/* 返回按钮 */}
+      <div className="AMback" onClick={() => history.go(-1)} hidden={full}>
+        <img src={`${baseUrl}/C2ArchitecInfo/icon_back.png`} alt="" />
+      </div>
+
+      {/* 主体模型 */}
+      <div
+        className={classNames(
+          "AMtop",
+          full ? "AMtopFull" : "",
+          isFullBox ? "AMtopFull2" : ""
+        )}
+      >
+        {/* 名字 */}
+        <div className="AMtopName">{info.name}</div>
+        {/* 模型 */}
+        <iframe
+          ref={ifrRefNew}
+          src={`/model.html?m=${info.id}&n=new&r=${type}`}
+          frameBorder="0"
+        ></iframe>
+        {/* 右侧按钮 */}
+        <div className="AMtopBtn">
+          {/* 打开介绍 */}
+          <div
+            hidden={!info.txt}
+            className={classNames(
+              "AMtopBtnRow AMtopBtnRow1",
+              txtShow ? "AMtopBtnRow1Ac" : ""
+            )}
+            onClick={() => setTxtShow(!txtShow)}
+          ></div>
+          {iconArr.map((v) => (
+            <div
+              onClick={() => modelChangeFu(v.id)}
+              className={`AMtopBtnRow AMtopBtnRow${v.id}`}
+              key={v.id}
+            ></div>
+          ))}
+          {/* 全屏 */}
+          <div
+            hidden={isFullBox}
+            onClick={() => {
+              const dom = ifrRefNew.current;
+              if (dom && dom.contentWindow && dom.contentWindow.modelLoding)
+                setFull(!full);
+            }}
+            className={classNames(
+              "AMtopBtnRow AMtopBtnRow5",
+              full ? "AMtopBtnRow5Ac" : ""
+            )}
+          ></div>
+        </div>
+      </div>
+
+      {/* 底部按钮 */}
+      <div className="AMbtn" hidden={full}>
+        {info.isBuild ? (
+          <>
+            {info.isBuild.map((v) => (
+              <div
+                className="AMbtnRow"
+                key={v.id}
+                onClick={() => history.push(`/buildInfo?id=${v.id}`)}
+              >
+                <div>
+                  {v.name[0]}&emsp;{v.name[1]}
+                </div>
+              </div>
+            ))}
+          </>
+        ) : null}
+
+        {/* 去大场景 */}
+        {type === "C2ArchitecInfo" && info.code ? (
+          <div
+            className="AMtoVr"
+            onClick={() => history.push(`/scene?id=${info.code}`)}
+          >
+            室内VR
+            <p>
+              <SwapRightOutlined />
+            </p>
+          </div>
+        ) : null}
+      </div>
+
+      {/* 文字介绍 */}
+      <div
+        className={classNames("AMtxt", txtShow ? "AMtxtAc" : "")}
+        style={{ backgroundImage: `url(${baseUrl}/C2ArchitecInfo/tab.png)` }}
+      >
+        <h3>
+          简介 {/* 右侧关闭按钮 */}
+          <img
+            onClick={() => setTxtShow(false)}
+            className="AMtxtClose"
+            src={`${baseUrl}/C2ArchitecInfo/icon_cancel.png`}
+            alt=""
+          />
+        </h3>
+        <div className="AMtxtLine">
+          <img src={`${baseUrl}/C1Architec/line.png`} alt="" />
+        </div>
+
+        <div className="AMtxtCon">
+          <div
+            dangerouslySetInnerHTML={{
+              __html: info.txt ? info.txt : "暂无介绍",
+            }}
+          ></div>
+        </div>
+      </div>
+    </div>
+  );
+}
+
+const MemoArcOrBuildInfoM = React.memo(ArcOrBuildInfoM);
+
+export default MemoArcOrBuildInfoM;

+ 0 - 51
code/src/components/ImageLazy/index.module.scss

@@ -1,51 +0,0 @@
-.ImageLazy {
-  position: relative;
-
-  :global {
-    .lazyBox {
-      width: 100%;
-      height: 100%;
-      position: relative;
-
-      .adm-image {
-        width: 100%;
-        height: 100%;
-
-        img {
-          width: 100%;
-          height: 100%;
-        }
-      }
-
-      .lookImg {
-        cursor: pointer;
-        transition: opacity .3s;
-        opacity: 0;
-        pointer-events: none;
-        position: absolute;
-        top: 0;
-        left: 0;
-        width: 100%;
-        height: 100%;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        font-size: 18px;
-        color: #fff;
-        background-color: rgba(0, 0, 0, .6);
-
-        &>div {
-          font-size: 14px;
-        }
-      }
-
-      &:hover {
-        .lookImg {
-          opacity: 1;
-          pointer-events: auto;
-        }
-      }
-    }
-  }
-
-}

+ 0 - 40
code/src/components/ImageLazy/index.tsx

@@ -1,40 +0,0 @@
-import React from "react";
-import styles from "./index.module.scss";
-import imgLoding from "@/assets/img/loading.gif";
-import imgErr from "@/assets/img/IMGerror.png";
-import { Image } from "antd-mobile";
-import { baseUrl } from "@/index";
-
-type Props = {
-  width?: number | string;
-  height?: number | string;
-  src: string;
-  noLook?: boolean;
-  offline?: boolean;
-};
-
-function ImageLazy({
-  width = 100,
-  height = 100,
-  src,
-  noLook,
-  offline = false,
-}: Props) {
-  return (
-    <div className={styles.ImageLazy} style={{ width: width, height: height }}>
-      <div className="lazyBox">
-        <Image
-          lazy
-          src={src ? (offline ? src : baseUrl + src) : ""}
-          placeholder={<img src={imgLoding} alt="" />}
-          fallback={<img src={imgErr} alt="" />}
-          fit="cover"
-        />
-      </div>
-    </div>
-  );
-}
-
-const MemoImageLazy = React.memo(ImageLazy);
-
-export default MemoImageLazy;

+ 39 - 0
code/src/components/KrpanoCom/index.module.scss

@@ -0,0 +1,39 @@
+.villageKrpano {
+  width: 100%;
+  height: 100%;
+
+  :global {
+    .hotspot {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+    }
+
+    .hotspotLabel {
+      width: 316px;
+      height: 68px;
+      text-align: center;
+      line-height: 68px;
+      font-size: 32px;
+      color: #fce9ac;
+      background: url("../../assets/img/btn_normal@2x.png") no-repeat center / contain;
+    }
+
+    .hotspotPointer {
+      margin-top: 15px;
+      width: 122px;
+      height: 124px;
+      background: url("../../assets/img/icon_address_normal@2x.png") no-repeat center / contain;
+    }
+
+    .hotspotActive .hotspotLabel {
+      color: #5c4b32;
+      background-image: url("../../assets/img/btn_active@2x.png");
+    }
+
+    .hotspotActive .hotspotPointer {
+      background-image: url("../../assets/img/icon_address_active@2x.png");
+    }
+  }
+}

+ 68 - 0
code/src/components/KrpanoCom/index.tsx

@@ -0,0 +1,68 @@
+import React, { useState } from "react";
+import styles from "./index.module.scss";
+import { HotSpot, Krpano } from "@dage/krpano";
+import { Tab2InfoType } from "@/types";
+import classNames from "classnames";
+
+type Props = {
+  curScene: string;
+  curVillage: Tab2InfoType[];
+  infoInd: number;
+  setInfoInd: (index: number) => void;
+  scale: number;
+};
+
+function KrpanoCom({
+  curScene,
+  curVillage,
+  infoInd,
+  setInfoInd,
+  scale,
+}: Props) {
+  const [hotspotHoverName, setHotspotHoverName] = useState("");
+
+  return (
+    <Krpano
+      className={styles.villageKrpano}
+      xml="/scene.xml"
+      currentScene={curScene}
+    >
+      {curVillage.map((item, index) => {
+        const name = `hotspot${item.id}`;
+
+        return (
+          <HotSpot
+            key={name}
+            name={name}
+            type="text"
+            atv={item.atv}
+            ath={item.ath}
+            scale={scale}
+            edge="top"
+            bg={false}
+            distorted={true}
+            onClick={() => setInfoInd(index)}
+            onOver={() => setHotspotHoverName(name)}
+            onOut={() => setHotspotHoverName("")}
+          >
+            <div
+              className={classNames(
+                name === hotspotHoverName || index === infoInd
+                  ? "hotspotActive"
+                  : "",
+                "hotspot"
+              )}
+            >
+              <span className="hotspotLabel">{item.label}</span>
+              <div className="hotspotPointer" />
+            </div>
+          </HotSpot>
+        );
+      })}
+    </Krpano>
+  );
+}
+
+const MemoKrpanoCom = React.memo(KrpanoCom);
+
+export default MemoKrpanoCom;

+ 51 - 11
code/src/pages/B1CardM/index.module.scss

@@ -38,10 +38,6 @@
         pointer-events: none;
         position: absolute;
         z-index: 3;
-        // top: -8%;
-        // left: -12%;
-        // width: 124%;
-        // height: 116%;
         top: 0%;
         left: 0%;
         width: 100%;
@@ -49,12 +45,7 @@
         background-size: 100% 100%;
       }
 
-      .slideBacAc {
-        // top: -5%;
-        // left: -5%;
-        // width: 110%;
-        // height: 110%;
-      }
+
 
       p {
         padding: 0 14%;
@@ -75,7 +66,56 @@
       }
     }
 
-    .swiper-slide-active {}
+    // .swiper-slide-active {}
+
+    .B1Cname {
+      position: absolute;
+      top: 8%;
+      left: 50%;
+      transform: translateX(-50%);
+      z-index: 10;
+      color: var(--themeColor2);
+      font-size: 24px;
+      letter-spacing: 2px;
+      font-weight: 700;
+    }
+
+    .B1Cbtn {
+      position: absolute;
+      bottom: 30px;
+      left: 50%;
+      z-index: 10;
+      transform: translateX(-50%);
+      width: 200px;
+      height: 50px;
+
+      &>img {
+        width: 100%;
+        height: 100%;
+        object-fit: fill;
+      }
+
+      &>div {
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100%;
+        color: var(--themeColor);
+        letter-spacing: 2px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        font-size: 20px;
+        font-weight: 700;
+
+        &>p {
+          font-size: 24px;
+          position: relative;
+          top: 4px;
+        }
+      }
+    }
 
   }
 }

+ 42 - 10
code/src/pages/B1CardM/index.tsx

@@ -1,13 +1,14 @@
-import React, { useEffect, useState } from "react";
+import React, { useEffect, useMemo, useState } from "react";
 import styles from "./index.module.scss";
 import { baseUrl } from "@/index";
-
-import Swiper from "./swiperCard/swiper-bundle.min.js";
-
-import "./swiperCard/swiper-bundle.min.css";
 import { useSelector } from "react-redux";
 import { RootState } from "@/store";
 import classNames from "classnames";
+import btnImg from "@/assets/img/tab2/btn_m.png";
+import { SwapRightOutlined } from "@ant-design/icons";
+
+import Swiper from "./swiperCard/swiper-bundle.min.js";
+import "./swiperCard/swiper-bundle.min.css";
 
 type Props = {
   closeFu: () => void;
@@ -45,6 +46,17 @@ function B1CardM({ closeFu, clickCardFu }: Props) {
     });
   }, []);
 
+  // 当前选中的卡片信息
+  const acItem = useMemo(() => {
+    let info = { id: 0, name: "" };
+
+    const infoRes = data.find((v, i) => i === ind);
+
+    if (infoRes) info = { id: infoRes.id, name: infoRes.name };
+
+    return info;
+  }, [data, ind]);
+
   return (
     <div className={styles.B1CardM}>
       {/* 右上角的按钮 */}
@@ -52,11 +64,18 @@ function B1CardM({ closeFu, clickCardFu }: Props) {
         <img src={`${baseUrl}/A1Home/mobile/icon_cancel.png`} alt="" />
       </div>
 
+      {/* 顶部的村落名字 */}
+      <div className="B1Cname">{acItem.name}</div>
+
       {/* 卡片sw */}
       <div className="swiper mySwiper">
         <div className="swiper-wrapper">
           {data.map((v, i) => (
-            <div className="swiper-slide" key={v.id}>
+            <div
+              className="swiper-slide"
+              key={v.id}
+              onClick={() => clickCardFu(v.id)}
+            >
               <img src={`${baseUrl}/B1Village/mobile/${v.id}.jpg`} alt="" />
               <p
                 dangerouslySetInnerHTML={{
@@ -68,10 +87,7 @@ function B1CardM({ closeFu, clickCardFu }: Props) {
               ></p>
               {/* 背景图 */}
               <div
-                className={classNames(
-                  "slideBac",
-                  ind === i ? "slideBacAc" : ""
-                )}
+                className={classNames("slideBac")}
                 style={{
                   backgroundImage: `url(${baseUrl}/B1Village/mobile/${
                     ind === i ? "bacAc" : "bac"
@@ -82,6 +98,22 @@ function B1CardM({ closeFu, clickCardFu }: Props) {
           ))}
         </div>
       </div>
+
+      {/* 底部的按钮 */}
+      <div
+        className="B1Cbtn"
+        onClick={() => {
+          if (acItem.id) clickCardFu(acItem.id);
+        }}
+      >
+        <img src={btnImg} alt="" />
+        <div>
+          点击查看
+          <p>
+            <SwapRightOutlined />
+          </p>
+        </div>
+      </div>
     </div>
   );
 }

+ 0 - 38
code/src/pages/B1Village/index.module.scss

@@ -280,42 +280,4 @@
       pointer-events: auto;
     }
   }
-}
-
-.villageKrpano {
-  width: 100%;
-  height: 100%;
-}
-
-.hotspot {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-}
-
-.hotspotLabel {
-  width: 316px;
-  height: 68px;
-  text-align: center;
-  line-height: 68px;
-  font-size: 32px;
-  color: #fce9ac;
-  background: url("../../assets/img/btn_normal@2x.png") no-repeat center / contain;
-}
-
-.hotspotPointer {
-  margin-top: 15px;
-  width: 122px;
-  height: 124px;
-  background: url("../../assets/img/icon_address_normal@2x.png") no-repeat center / contain;
-}
-
-.hotspotActive .hotspotLabel {
-  color: #5c4b32;
-  background-image: url("../../assets/img/btn_active@2x.png");
-}
-
-.hotspotActive .hotspotPointer {
-  background-image: url("../../assets/img/icon_address_active@2x.png");
 }

+ 14 - 47
code/src/pages/B1Village/index.tsx

@@ -10,16 +10,15 @@ import { useLocation } from "react-router-dom";
 import history from "@/utils/history";
 import { useSelector } from "react-redux";
 import { RootState } from "@/store";
-import { HotSpot, Krpano } from "@dage/krpano";
+
 import classNames from "classnames";
 import { baseUrl } from "@/index";
+import KrpanoCom from "@/components/KrpanoCom";
 function B1Village() {
   const location = useLocation();
 
   const [uId, setUid] = useState("");
 
-  const [hotspotHoverName, setHotspotHoverName] = useState("");
-
   const villageData = useSelector(
     (state: RootState) => state.A0Layout.dataAll.village
   );
@@ -50,7 +49,6 @@ function B1Village() {
   const [infoInd, setInfoInd] = useState(-1);
 
   // 每次索引变化的时候 动态加载 序列帧样式
-
   const setFullFu = useCallback(() => {
     // 看看是否已经插入的 script
     const ruDom = document.querySelector("#myStyle");
@@ -58,6 +56,8 @@ function B1Village() {
 
     clearTimeout(time.current);
     time.current = window.setTimeout(() => {
+      if (infoInd === -1) return;
+
       const num = curVillage[infoInd].zhen;
       // 获取序列帧 外层 盒子的 宽度
       const dom = document.querySelector(".B1imgMove") as HTMLDivElement;
@@ -106,44 +106,15 @@ function B1Village() {
   return (
     <div className={styles.B1Village}>
       {/* 全景相关 */}
-      <Krpano
-        className={styles.villageKrpano}
-        xml="/scene.xml"
-        currentScene={"scene_zlc"}
-      >
-        {curVillage.map((item, index) => {
-          const name = `hotspot${item.id}`;
-
-          return (
-            <HotSpot
-              key={name}
-              name={name}
-              type="text"
-              atv={item.atv}
-              ath={item.ath}
-              scale={0.3}
-              edge="top"
-              bg={false}
-              distorted={true}
-              onClick={() => setInfoInd(index)}
-              onOver={() => setHotspotHoverName(name)}
-              onOut={() => setHotspotHoverName("")}
-            >
-              <div
-                className={classNames(
-                  name === hotspotHoverName || index === infoInd
-                    ? styles.hotspotActive
-                    : "",
-                  styles.hotspot
-                )}
-              >
-                <span className={styles.hotspotLabel}>{item.label}</span>
-                <div className={styles.hotspotPointer} />
-              </div>
-            </HotSpot>
-          );
-        })}
-      </Krpano>
+      {curScene ? (
+        <KrpanoCom
+          scale={0.3}
+          curScene={curScene}
+          curVillage={curVillage}
+          infoInd={infoInd}
+          setInfoInd={(ind) => setInfoInd(ind)}
+        />
+      ) : null}
 
       {/* 点击建筑出来的左侧详情 */}
       <div className={classNames("B1info", infoInd !== -1 ? "B1infoAc" : "")}>
@@ -229,11 +200,7 @@ function B1Village() {
                 ))}
               </div>
               {/* 图片的序列帧 */}
-              <div
-                className="B1imgMove"
-                // onMouseEnter={() => setImgHover(false)}
-                // onMouseLeave={() => setImgHover(true)}
-              >
+              <div className="B1imgMove">
                 {uId ? (
                   <img
                     className={classNames("B1imgMoveMain")}

+ 187 - 0
code/src/pages/B1VillageM/index.module.scss

@@ -0,0 +1,187 @@
+.B1VillageM {
+  position: relative;
+
+  :global {
+    .B1Vinfo {
+      position: absolute;
+      top: 0;
+      left: 0;
+      z-index: 10;
+      width: 100%;
+      height: 100%;
+      background-color: rgba(28, 21, 12, 0.7);
+      backdrop-filter: blur(10px);
+      opacity: 0;
+      pointer-events: none;
+      transition: all .3s;
+
+      .B1Vback {
+        position: absolute;
+        top: 20px;
+        right: 20px;
+        z-index: 10;
+      }
+
+      .B1info {
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100%;
+        opacity: 0;
+        pointer-events: none;
+        padding-top: 20px;
+
+        .B1infoMainName {
+          position: absolute;
+          top: 20px;
+          left: 40px;
+          max-width: 100px;
+        }
+
+        .B1imgMove {
+          width: 100%;
+          height: 50%;
+          position: relative;
+          overflow: hidden;
+
+          // 图片的序列帧
+          .B1imgMoveMain {
+            pointer-events: none;
+            position: absolute;
+            top: 0;
+            left: 0;
+            // max-height: 1000px;
+            object-fit: fill;
+          }
+        }
+
+        // 左右箭头
+        .B1infoAr {
+          position: absolute;
+          top: 50%;
+          left: 4px;
+          width: 30px;
+          height: 30px;
+          background: url('../../assets/img/tab2/icon_left.png') no-repeat center center;
+          background-size: 18px 30px;
+        }
+
+        .B1infoAr2 {
+          left: auto;
+          right: 4px;
+          background: url('../../assets/img/tab2/icon_right.png') no-repeat center center;
+          background-size: 18px 30px;
+        }
+
+        .B1infoArNone {
+          opacity: .5;
+          pointer-events: none;
+        }
+
+        .B1infoTxt {
+          width: 100%;
+          height: 50%;
+          padding: 0 20px;
+
+          .B1infoTxt1 {
+            padding: 20px 20px 15px;
+            display: flex;
+            justify-content: space-around;
+
+            .B1infoTxt1Row {
+              width: 76px;
+              height: 76px;
+              border-radius: 50%;
+              border: 1px solid var(--themeColor2);
+              padding: 6px;
+
+              .B1infoTxt1RowIn {
+                width: 100%;
+                height: 100%;
+                position: relative;
+
+                &>div {
+                  position: absolute;
+                  top: 0;
+                  left: 0;
+                  width: 100%;
+                  height: 100%;
+                  border-radius: 50%;
+                  background-color: rgba(0, 0, 0, .6);
+                  display: flex;
+                  justify-content: center;
+                  align-items: center;
+                  color: var(--themeColor2);
+                }
+              }
+            }
+          }
+
+          .B1infoTxt2 {
+            width: 100%;
+            height: calc(100% - 190px);
+            color: #fff;
+            letter-spacing: 2px;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+
+            &>div {
+              padding: 0 4px;
+              overflow-y: auto;
+              max-width: 100%;
+              max-height: 100%;
+            }
+          }
+
+          .B1infoTxt3 {
+            position: relative;
+            margin: 4px auto 0;
+            z-index: 10;
+            width: 200px;
+            height: 50px;
+
+            &>img {
+              width: 100%;
+              height: 100%;
+              object-fit: fill;
+            }
+
+            &>div {
+              position: absolute;
+              top: 0;
+              left: 0;
+              width: 100%;
+              height: 100%;
+              color: var(--themeColor);
+              letter-spacing: 2px;
+              display: flex;
+              justify-content: center;
+              align-items: center;
+              font-size: 20px;
+              font-weight: 700;
+
+              &>p {
+                font-size: 24px;
+                position: relative;
+                top: 4px;
+              }
+            }
+          }
+        }
+      }
+
+      .B1infoAc {
+        opacity: 1;
+        pointer-events: auto;
+      }
+    }
+
+    .B1VinfoAc {
+      opacity: 1;
+      pointer-events: auto;
+
+    }
+  }
+}

+ 234 - 0
code/src/pages/B1VillageM/index.tsx

@@ -0,0 +1,234 @@
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
+import styles from "./index.module.scss";
+import { useLocation } from "react-router-dom";
+import { useSelector } from "react-redux";
+import { RootState } from "@/store";
+import KrpanoCom from "@/components/KrpanoCom";
+import { baseUrl } from "@/index";
+import classNames from "classnames";
+import history from "@/utils/history";
+import btnImg from "@/assets/img/tab2/btn_m.png";
+import { SwapRightOutlined } from "@ant-design/icons";
+
+function B1VillageM() {
+  const location = useLocation();
+
+  const [uId, setUid] = useState("");
+
+  const villageData = useSelector(
+    (state: RootState) => state.A0Layout.dataAll.village
+  );
+
+  const curScene = useMemo(() => {
+    return (
+      villageData.find((v) => v.id === Number(uId))?.scene ||
+      villageData[0].scene
+    );
+  }, [uId, villageData]);
+
+  //当前村落的 信息
+  const curVillage = useMemo(
+    () =>
+      villageData.find((i) => i.id === Number(uId))?.info ||
+      villageData[0].info,
+    [uId, villageData]
+  );
+
+  useEffect(() => {
+    const query = new URLSearchParams(location.search);
+    const param = query.get("id");
+    // console.log("村落页面获取id", param);
+    setUid(param!);
+  }, [location.search]);
+
+  // 详情 索引
+  const [infoInd, setInfoInd] = useState(-1);
+
+  // 每次索引变化的时候 动态加载 序列帧样式
+  const setFullFu = useCallback(() => {
+    // 看看是否已经插入的 script
+    const ruDom = document.querySelector("#myStyle");
+    if (ruDom) ruDom.remove();
+
+    clearTimeout(time.current);
+    time.current = window.setTimeout(() => {
+      if (infoInd === -1) return;
+
+      const num = curVillage[infoInd].zhen;
+      // 获取序列帧 外层 盒子的 宽度
+      const dom = document.querySelector(".B1imgMove") as HTMLDivElement;
+      if (dom) {
+        const width = dom.getBoundingClientRect().width;
+        const leftNum = "-" + width * num + "px";
+        const styleStr = `.B1VinfoAc .B1imgMoveMain {
+               animation: tab2MoveImg 2.4s steps(${num}) infinite;
+             }
+             @keyframes tab2MoveImg {
+             
+               100% {
+                 left: ${leftNum};
+               }
+             }`;
+
+        const styletDom = document.createElement("style");
+        styletDom.type = "text/css";
+        styletDom.id = "myStyle";
+        styletDom.innerHTML = styleStr;
+        document.querySelector("html")?.appendChild(styletDom);
+      }
+    }, 100);
+  }, [curVillage, infoInd]);
+
+  useEffect(() => {
+    if (infoInd !== -1) setFullFu();
+  }, [infoInd, setFullFu]);
+
+  const time = useRef(-1);
+
+  useEffect(() => {
+    window.addEventListener("resize", setFullFu, true);
+
+    return () => {
+      window.removeEventListener("resize", setFullFu);
+    };
+  }, [setFullFu]);
+
+  // 点击右侧的 场景 或者 构件
+  const rightClickFu = useCallback((id: string, name: string) => {
+    if (name === "室内场景") history.push(`/scene?id=${id}`);
+    else history.push(`/buildInfo?id=${id}`);
+  }, []);
+
+  return (
+    <div
+      className={styles.B1VillageM}
+      style={{ zIndex: infoInd !== -1 ? "40" : "" }}
+    >
+      {/* 全景相关 */}
+      {curScene ? (
+        <KrpanoCom
+          scale={0.5}
+          curScene={curScene}
+          curVillage={curVillage}
+          infoInd={infoInd}
+          setInfoInd={(ind) => setInfoInd(ind)}
+        />
+      ) : null}
+
+      {/* 详情页面 */}
+      <div className={classNames("B1Vinfo", infoInd !== -1 ? "B1VinfoAc" : "")}>
+        {/* 右上角的关闭按钮 */}
+        <div className="B1Vback" onClick={() => setInfoInd(-1)}>
+          <img src={`${baseUrl}/A1Home/mobile/icon_cancel.png`} alt="" />
+        </div>
+
+        {curVillage.map((v, i) => (
+          <div
+            className={classNames("B1info", infoInd === i ? "B1infoAc" : "")}
+            key={v.id}
+          >
+            {/* 大名字 */}
+            {uId ? (
+              <div className="B1infoMainName">
+                <img
+                  src={`${baseUrl}/B1Village/pc/${uId}/name${v.id}.png`}
+                  alt=""
+                />
+              </div>
+            ) : null}
+            {/* 上面的 序列帧 和 左右箭头 */}
+            <div className="B1imgMove">
+              {/* 图片的序列帧 */}
+              {uId ? (
+                <img
+                  className={classNames("B1imgMoveMain")}
+                  style={{
+                    width: v.zhen * 100 + "%",
+                    maxWidth: v.zhen * 100 + "%",
+                  }}
+                  src={`${baseUrl}/B1Village/pc/${uId}/move${v.id}.png`}
+                  alt=""
+                />
+              ) : null}
+
+              {/* 左右箭头 */}
+              <div
+                onClick={() => setInfoInd(infoInd - 1)}
+                className={classNames(
+                  "B1infoAr B1infoAr1",
+                  infoInd === 0 ? "B1infoArNone" : ""
+                )}
+                hidden={curVillage.length <= 1}
+              ></div>
+              <div
+                onClick={() => setInfoInd(infoInd + 1)}
+                className={classNames(
+                  "B1infoAr B1infoAr2",
+                  infoInd >= curVillage.length - 1 ? "B1infoArNone" : ""
+                )}
+                hidden={curVillage.length <= 1}
+              ></div>
+            </div>
+            {/* 下面的信息 */}
+            <div className="B1infoTxt">
+              {/* 场景和构件的选择 */}
+              <div className="B1infoTxt1">
+                {v.buildArr.map((v2) => (
+                  <div
+                    onClick={() => rightClickFu(v2.id, v2.name)}
+                    className="B1infoTxt1Row"
+                    key={v2.id}
+                  >
+                    {uId ? (
+                      <div className="B1infoTxt1RowIn">
+                        <img
+                          src={`${baseUrl}/B1Village/pc/${uId}/${v2.id}.png`}
+                          alt=""
+                        />
+                        <div>{v2.name}</div>
+                      </div>
+                    ) : null}
+                  </div>
+                ))}
+              </div>
+
+              {/* 文字介绍 */}
+              <div className="B1infoTxt2">
+                <div
+                  className="mySorrl"
+                  dangerouslySetInnerHTML={{
+                    __html: v.txt ? v.txt : `暂无介绍`,
+                  }}
+                ></div>
+              </div>
+
+              {/* 底部的按钮 */}
+              <div
+                className="B1infoTxt3"
+                onClick={() => history.push(`/architec?id=${uId}`)}
+              >
+                <img src={btnImg} alt="" />
+                <div>
+                  建筑模型
+                  <p>
+                    <SwapRightOutlined />
+                  </p>
+                </div>
+              </div>
+            </div>
+          </div>
+        ))}
+      </div>
+    </div>
+  );
+}
+
+const MemoB1VillageM = React.memo(B1VillageM);
+
+export default MemoB1VillageM;

+ 1 - 0
code/src/pages/C1Architec/index.module.scss

@@ -152,6 +152,7 @@
             white-space: normal;
             letter-spacing: 2px;
             line-height: 20px;
+            overflow: hidden;
           }
         }
 

+ 155 - 0
code/src/pages/C1ArchitecM/index.module.scss

@@ -0,0 +1,155 @@
+.C1ArchitecM {
+  background-size: 100% 100%;
+  position: relative;
+
+  :global {
+    .C1Aguang {
+      z-index: 20;
+      pointer-events: none;
+      position: absolute;
+      top: -10%;
+      left: 0;
+      width: 100%;
+      height: 80%;
+
+      &>img {
+        width: 100%;
+        object-fit: contain;
+      }
+    }
+
+    .C1Aname {
+      position: absolute;
+      z-index: 30;
+      top: 8%;
+      font-size: 24px;
+      font-weight: 700;
+      letter-spacing: 2px;
+      padding-bottom: 30px;
+      pointer-events: none;
+      text-align: center;
+      color: var(--themeColor);
+      width: 100%;
+
+      &>img {
+        position: absolute;
+        bottom: 0;
+        left: 50%;
+        transform: translateX(-50%);
+        width: 60%;
+        height: 16px;
+      }
+    }
+
+    .C1bs {
+      position: absolute;
+      z-index: 3;
+      right: 10px;
+      top: 20px;
+      background-image: url('../../assets/img/tab3//btn_cunluo.png');
+      background-size: 100% 100%;
+      width: 50px;
+      text-align: center;
+      padding: 16px 5px;
+
+      &>img {
+        display: inline-block;
+        padding: 10px 0 5px;
+        width: 20px;
+
+        &:nth-of-type(2) {
+          padding: 5px 0 10px;
+        }
+      }
+
+      .C1noneImg {
+        opacity: .3;
+        pointer-events: none;
+      }
+
+      &>div {
+        height: calc(100% - 100px);
+        display: flex;
+        flex-direction: column;
+        font-size: 14px;
+        color: var(--themeColor2);
+        text-shadow: 1px 1px black;
+        padding: 0 10px;
+      }
+    }
+
+    .C1bsLong {
+      background-image: url('../../assets/img/tab3//btn_cunluo2.png');
+
+    }
+
+    // 轮播图
+
+    .C1Amain {
+      position: absolute;
+      bottom: 16%;
+      height: calc(76% - 80px);
+      width: 100%;
+
+      .mySwiper {
+        width: 100%;
+        height: 70%;
+        position: relative;
+
+        .C1AmainBac {
+          position: absolute;
+          top: 100px;
+          left: 0;
+          width: 100%;
+          height: calc(100% - 100px);
+          background-color: #655b53;
+          background-size: 100% 100%;
+        }
+
+        .swiper-wrapper {
+          height: 100%;
+          position: relative;
+          z-index: 3;
+          .swiper-slide{
+            position: relative;
+            top: 100px;
+            height: calc(100% - 100px);
+            transition: all .3s;
+            img{
+              position: absolute;
+              bottom: 0;
+              left: 0;
+              width: 100%;
+              height: 100%;
+            }
+          }
+          .swiper-slideBig{
+            top: 10px;
+            height: calc(100% - 10px);
+          }
+        }
+      }
+
+      // 底部介绍
+      .C1Atxt {
+        width: 100%;
+        height: 30%;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        padding: 5px 20px;
+
+        &>div {
+          max-width: 100%;
+          max-height: 100%;
+          overflow-y: auto;
+          padding-right: 4px;
+          color: var(--themeColor);
+          letter-spacing: 2px;
+        }
+      }
+    }
+
+
+  }
+}

+ 195 - 0
code/src/pages/C1ArchitecM/index.tsx

@@ -0,0 +1,195 @@
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
+import styles from "./index.module.scss";
+import { baseUrl } from "@/index";
+import { useLocation } from "react-router-dom";
+import { useSelector } from "react-redux";
+import { RootState } from "@/store";
+import classNames from "classnames";
+import upimg from "@/assets/img/tab3/icon_up.png";
+import downimg from "@/assets/img/tab3/icon_down.png";
+
+import Swiper from "../B1CardM/swiperCard/swiper-bundle.min.js";
+import "../B1CardM/swiperCard/swiper-bundle.min.css";
+import history from "@/utils/history";
+import { InfoRowType } from "@/types";
+
+function C1ArchitecM() {
+  const location = useLocation();
+
+  const [uId, setUid] = useState("");
+
+  const dataObj = useSelector(
+    (state: RootState) => state.A0Layout.dataAll.architec
+  );
+
+  // 总共有多少个村落
+  const cunLength = useMemo(() => {
+    let num = 0;
+    for (const k in dataObj) {
+      if (k) num++;
+    }
+    return num;
+  }, [dataObj]);
+
+  const info = useMemo(() => {
+    const info = dataObj[uId as "key"] || { name: "", data: [] };
+    return info;
+  }, [dataObj, uId]);
+
+  useEffect(() => {
+    const query = new URLSearchParams(location.search);
+    const param = query.get("id");
+    // console.log("建筑页面获取id", param);
+    setUid(param!);
+  }, [location.search]);
+
+  // 初始化 轮播图
+  const swiperRef = useRef<any>(null);
+
+  const initSwiper = useCallback(() => {
+    if (swiperRef.current) swiperRef.current.destroy();
+
+    window.setTimeout(() => {
+      swiperRef.current = new Swiper(".mySwiper", {
+        slidesPerView: 2,
+        centeredSlides: true,
+        // effect: "cards",
+        grabCursor: true,
+        // 初始高亮
+        initialSlide: 0,
+        // loop:true
+        on: {
+          slideChange: function (swiper: any) {
+            setInd(swiper.activeIndex);
+          },
+        },
+      });
+    }, 20);
+  }, []);
+
+  useEffect(() => {
+    initSwiper();
+  }, [initSwiper]);
+
+  // 点击箭头切换村落
+  const cutChangeFu = useCallback(
+    (num: number) => {
+      const id = Number(uId);
+      const numRes = id + num;
+      history.replace(`/architec?id=${numRes}`);
+      // setUid(numRes + "");
+      // 销毁轮播图,再次重新渲染
+      initSwiper();
+      // 索引变成1
+      setInd(0);
+    },
+    [initSwiper, uId]
+  );
+
+  // 当前 轮播图 选中的 数据
+  const [ind, setInd] = useState(0);
+  const acInfo = useMemo(() => {
+    let infoTemp = {} as InfoRowType;
+
+    const infoRes = info.data.find((v, i) => i === ind);
+
+    if (infoRes) infoTemp = infoRes;
+
+    return infoTemp;
+  }, [ind, info.data]);
+
+  return (
+    <div
+      className={styles.C1ArchitecM}
+      style={{ backgroundImage: `url(${baseUrl}/C1Architec/bgM.png)` }}
+    >
+      {/* 光柱 */}
+      <div className="C1Aguang">
+        <img src={`${baseUrl}/C1Architec/bgGuang.png`} alt="" />
+      </div>
+
+      {/* 顶部名字 */}
+      {acInfo.name ? (
+        <div className="C1Aname">
+          {acInfo.name}
+          <img src={`${baseUrl}/C1Architec/line.png`} alt="" />
+        </div>
+      ) : null}
+
+      {/* 右侧的村落切换 */}
+      <div
+        className={classNames(
+          "C1bs",
+          info.name && info.name.length >= 5 ? "C1bsLong" : ""
+        )}
+      >
+        <img
+          className={classNames(Number(uId) === 1 ? "C1noneImg" : "")}
+          src={upimg}
+          alt=""
+          onClick={() => cutChangeFu(-1)}
+        />
+        <div>{info.name}</div>
+        <img
+          className={classNames(Number(uId) === cunLength ? "C1noneImg" : "")}
+          src={downimg}
+          alt=""
+          onClick={() => cutChangeFu(1)}
+        />
+      </div>
+
+      <div className="C1Amain">
+        {/* 轮播图 */}
+        <div className="swiper mySwiper">
+          {/* 轮播图背景 */}
+          <div
+            className="C1AmainBac"
+            style={{
+              backgroundImage: `url(${baseUrl}/C1Architec/img_diwen.png)`,
+            }}
+          ></div>
+
+          <div className="swiper-wrapper">
+            {info.data.map((v, i) => (
+              <div
+                onClick={() => history.push(`/architecInfo?id=${v.id}`)}
+                className={classNames(
+                  "swiper-slide",
+                  i === ind ? "swiper-slideBig" : ""
+                )}
+                key={v.id}
+              >
+                <img
+                  src={`${baseUrl}/C1Architec/pc/${uId}/${v.id}.png`}
+                  alt=""
+                />
+              </div>
+            ))}
+          </div>
+        </div>
+
+        {/* 底部介绍 */}
+        {acInfo.txt ? (
+          <div className="C1Atxt">
+            <div
+              className="mySorrl"
+              dangerouslySetInnerHTML={{
+                __html: acInfo.txt,
+              }}
+            ></div>
+          </div>
+        ) : null}
+      </div>
+    </div>
+  );
+}
+
+const MemoC1ArchitecM = React.memo(C1ArchitecM);
+
+export default MemoC1ArchitecM;

+ 3 - 3
code/src/pages/C2ArchitecInfo/index.module.scss

@@ -1,3 +1,3 @@
-// .C2ArchitecInfo {
-
-// }
+.C2ArchitecInfo {
+  position: relative;
+}

+ 13 - 3
code/src/pages/C2ArchitecInfo/index.tsx

@@ -8,7 +8,8 @@ import { InfoRowType } from "@/types";
 import { useSelector } from "react-redux";
 import { RootState } from "@/store";
 import { MessageFu } from "@/utils/message";
-import history from "@/utils/history";
+import history, { isMobileFu } from "@/utils/history";
+import ArcOrBuildInfoM from "@/components/ArcOrBuildInfoM";
 function C2ArchitecInfo() {
   const location = useLocation();
 
@@ -46,8 +47,17 @@ function C2ArchitecInfo() {
   }, [architec, errFu, location.search]);
 
   return (
-    <div className={styles.C2ArchitecInfo}>
-      {info.id ? <ArcOrBuildInfo info={info} type='C2ArchitecInfo'/> : null}
+    <div
+      className={styles.C2ArchitecInfo}
+      style={{ zIndex: isMobileFu() ? "40" : "0" }}
+    >
+      {info.id ? (
+        isMobileFu() ? (
+          <ArcOrBuildInfoM info={info} type="C2ArchitecInfo" />
+        ) : (
+          <ArcOrBuildInfo info={info} type="C2ArchitecInfo" />
+        )
+      ) : null}
     </div>
   );
 }

+ 55 - 0
code/src/pages/D1BuildM/index.module.scss

@@ -0,0 +1,55 @@
+.D1BuildM {
+  position: relative;
+  z-index: 40;
+  background-size: 100% 100%;
+  background-color: #fff;
+  padding-top: 15px;
+
+  :global {
+    .D1top {
+      width: 100%;
+      height: 40px;
+      padding: 0 15px;
+      display: flex;
+
+      .D1back {
+        width: 40px;
+        height: 40px;
+      }
+    }
+
+    .D1topTab {
+      width: calc(100% - 50px);
+      margin-left: 10px;
+      height: 40px;
+      overflow-x: auto;
+
+      &::-webkit-scrollbar {
+        width: 0px;
+        height: 0px;
+      }
+
+      .D1topTabMain {
+        white-space: nowrap;
+        display: inline-block;
+
+        &>div {
+          display: inline-block;
+          height: 100%;
+          line-height: 40px;
+          margin-right: 15px;
+          padding: 0 15px;
+          color: var(--themeColor);
+          font-size: 16px;
+          border-radius: 20px;
+        }
+
+        .D1topRow {
+          background-color: var(--themeColor2);
+          font-weight: 700;
+        }
+      }
+    }
+
+  }
+}

+ 58 - 0
code/src/pages/D1BuildM/index.tsx

@@ -0,0 +1,58 @@
+import React, { useEffect, useState } from "react";
+import styles from "./index.module.scss";
+import { baseUrl } from "@/index";
+import history from "@/utils/history";
+import { useSelector } from "react-redux";
+import { RootState } from "@/store";
+import classNames from "classnames";
+function D1BuildM() {
+  // 看下是 新页面直接进来 还是通过路由进来
+  const { isRouterPushBuild } = useSelector(
+    (state: RootState) => state.A0Layout
+  );
+
+  // 获取村落数据
+  const tabData = useSelector(
+    (state: RootState) => state.A0Layout.dataAll.village
+  );
+
+  // 当前选中的id
+  const [idAc, setIdAc] = useState(0);
+
+  return (
+    <div
+      className={styles.D1BuildM}
+      style={{ backgroundImage: `url(${baseUrl}/C1Architec/bgM.png)` }}
+    >
+      <div className="D1top">
+        {/* 返回 */}
+        <div
+          className="D1back"
+          onClick={() =>
+            isRouterPushBuild ? history.go(-1) : history.push("/")
+          }
+        >
+          <img src={`${baseUrl}/C2ArchitecInfo/icon_back.png`} alt="" />
+        </div>
+        {/* 右侧tab */}
+        <div className="D1topTab">
+          <div className="D1topTabMain">
+            {[{ id: 0, name: "全部" }, ...tabData].map((v) => (
+              <div
+                onClick={() => setIdAc(v.id)}
+                className={classNames(idAc === v.id ? "D1topRow" : "")}
+                key={v.id}
+              >
+                {v.name}
+              </div>
+            ))}
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+}
+
+const MemoD1BuildM = React.memo(D1BuildM);
+
+export default MemoD1BuildM;

+ 10 - 1
code/src/pages/Z2Scene/index.module.scss

@@ -2,7 +2,7 @@
   position: relative;
   z-index: 40;
   overflow: hidden;
-  
+
   :global {
     iframe {
       width: 100%;
@@ -20,5 +20,14 @@
       background-image: url('../../assets/img/back.png');
       background-size: 100% 100%;
     }
+
+    @media screen and (max-width: 500px) {
+      .Z2back {
+        cursor: default;
+        left: 10px;
+        width: 40px;
+        height: 40px;
+      }
+    }
   }
 }

+ 9 - 1
code/src/store/reducer/layout.ts

@@ -15,13 +15,17 @@ const initState = {
 
   // 顶部tab的展开和收起
   homeTabShow: true,
+
+  // 处理 单独打开构件页面  无法回跳的问题
+  isRouterPushBuild: false,
 };
 
 // 定义 action 类型
 type LayoutActionType =
   | { type: "layout/message"; payload: MessageType }
   | { type: "layout/setDataAll"; payload: DataAllType }
-  | { type: "layout/setHomeTab"; payload: boolean };
+  | { type: "layout/setHomeTab"; payload: boolean }
+  | { type: "layout/isRouterPushBuild"; payload: boolean };
 
 // 频道 reducer
 export default function layoutReducer(
@@ -39,6 +43,10 @@ export default function layoutReducer(
     // 顶部tab的展开和收起
     case "layout/setHomeTab":
       return { ...state, homeTabShow: action.payload };
+
+    // 顶部tab的展开和收起
+    case "layout/isRouterPushBuild":
+      return { ...state, isRouterPushBuild: action.payload };
     default:
       return state;
   }

+ 1 - 0
code/src/types/api/layot.d.ts

@@ -79,6 +79,7 @@ export type InfoRowType = {
     type: "img" | "model";
     loc: "横" | "竖";
   };
+  cid:number
 };
 
 // 搜索列表

BIN
静态资源/staticData/C1Architec/bgGuang.png


BIN
静态资源/staticData/C1Architec/bgM.png


BIN
静态资源/staticData/C1Architec/img_diwen.png


BIN
静态资源/staticData/C1Architec/line.png


BIN
静态资源/staticData/C2ArchitecInfo/bg2.jpg


BIN
静态资源/staticData/C2ArchitecInfo/icon_back.png


BIN
静态资源/staticData/C2ArchitecInfo/icon_cancel.png


BIN
静态资源/staticData/C2ArchitecInfo/tab.png


BIN
静态资源/staticData/D1Build/btn_subject.png


+ 19 - 3
静态资源/staticData/dataTemp.js

@@ -243,7 +243,7 @@ const staticDataTemp = {
         {
           id: '3_6',
           name: '养贤别墅6',
-          txt: '养闲别墅建于1919年,是自立村现存碉楼和庐之一。主人是当地一名私塾教师,后赴南洋谋生。他家里有一个扎小脚的妻子,当时土匪横行乡里,水患不断,为了保护家人的安全,而建了这座楼。'
+          txt: ''
         },
       ]
     },
@@ -253,7 +253,7 @@ const staticDataTemp = {
       data: [
         {
           id: '3_7',
-          name: '养贤别墅1',
+          name: '养贤别墅2-1',
           txt: '养闲别墅建于1919年,是自立村现存碉楼和庐之一。主人是当地一名私塾教师,后赴南洋谋生。他家里有一个扎小脚的妻子,当时土匪横行乡里,水患不断,为了保护家人的安全,而建了这座楼。'
         },
         {
@@ -295,6 +295,10 @@ const staticDataTemp = {
       id: '4_1',
       name: '构件1',
       txt: '&emsp;&emsp;养闲别墅建于1919年,是自立村现存碉楼和庐之一。主人是当地一名私塾教师,后赴南洋谋生。他家里有一个扎小脚的妻子,<br/>当时土匪横行乡里,水患不断,为了保护家人的安全,而建了这座楼。',
+      // 手机端的副标题
+      title2: '马降龙村-卢俊',
+      // 村落id,和上面 home 数据里面的id对应
+      cid: 1,
       // 是否有新旧对比 没有不写
       isOld: {
         name: '旧的',
@@ -307,6 +311,10 @@ const staticDataTemp = {
       id: '4_2',
       name: '构件 l 实打实',
       txt: '&emsp;&emsp;养闲别墅建于1919年,是自立村现存碉楼和庐之一。主人是当地一名私塾教师,后赴南洋谋生。他家里有一个扎小脚的妻子,<br/>当时土匪横行乡里,水患不断,为了保护家人的安全,而建了这座楼。',
+      // 手机端的副标题
+      title2: '马降龙村-卢俊',
+      // 村落id,和上面 home 数据里面的id对应
+      cid: 2,
       // 是否有新旧对比 没有不写
       isOld: {
         name: '旧的',
@@ -319,6 +327,10 @@ const staticDataTemp = {
       id: '4_3',
       name: '构件3',
       txt: '&emsp;&emsp;养闲别墅建于1919年,是自立村现存碉楼和庐之一。主人是当地一名私塾教师,后赴南洋谋生。他家里有一个扎小脚的妻子,<br/>当时土匪横行乡里,水患不断,为了保护家人的安全,而建了这座楼。',
+      // 手机端的副标题
+      title2: '马降龙村-卢俊',
+      // 村落id,和上面 home 数据里面的id对应
+      cid: 3,
       // 是否有新旧对比 没有不写
       isOld: {
         name: '旧的',
@@ -330,7 +342,11 @@ const staticDataTemp = {
     {
       id: '4_4',
       name: '构件4',
-      txt: '&emsp;&emsp;养闲别墅建于1919年,是自立村现存碉楼和庐之一。主人是当地一名私塾教师,后赴南洋谋生。他家里有一个扎小脚的妻子,<br/>当时土匪横行乡里,水患不断,为了保护家人的安全,而建了这座楼。',
+      txt: '',
+      // 手机端的副标题
+      title2: '马降龙村-卢俊',
+      // 村落id,和上面 home 数据里面的id对应
+      cid: 4,
     },
   ]
 };