shaogen1995 2 年之前
父節點
當前提交
712f9a8c1b

+ 41 - 0
pc/package-lock.json

@@ -17,8 +17,10 @@
         "@types/react-dom": "^18.0.8",
         "@types/react-dom": "^18.0.8",
         "antd": "^5.4.2",
         "antd": "^5.4.2",
         "axios": "^1.1.3",
         "axios": "^1.1.3",
+        "gsap": "^3.11.5",
         "react": "^18.2.0",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "react-dom": "^18.2.0",
+        "react-lazyimg-component": "^1.0.1",
         "react-redux": "^8.0.4",
         "react-redux": "^8.0.4",
         "react-router-dom": "5.3",
         "react-router-dom": "5.3",
         "react-scripts": "5.0.1",
         "react-scripts": "5.0.1",
@@ -8117,6 +8119,11 @@
       "resolved": "https://registry.npmmirror.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
       "resolved": "https://registry.npmmirror.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
       "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ=="
       "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ=="
     },
     },
+    "node_modules/gsap": {
+      "version": "3.11.5",
+      "resolved": "https://registry.npmmirror.com/gsap/-/gsap-3.11.5.tgz",
+      "integrity": "sha512-Q89nKCLgoX5xUjznh9LcaIUkz54k1voNucT1Rpf9SJNFIQznBwFqt5qUUQbeVInFyN/n18OUJkpeI6CNEDt74w=="
+    },
     "node_modules/gzip-size": {
     "node_modules/gzip-size": {
       "version": "6.0.0",
       "version": "6.0.0",
       "resolved": "https://registry.npmmirror.com/gzip-size/-/gzip-size-6.0.0.tgz",
       "resolved": "https://registry.npmmirror.com/gzip-size/-/gzip-size-6.0.0.tgz",
@@ -8572,6 +8579,11 @@
         "node": ">= 0.4"
         "node": ">= 0.4"
       }
       }
     },
     },
+    "node_modules/intersection-observer": {
+      "version": "0.12.2",
+      "resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz",
+      "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="
+    },
     "node_modules/ipaddr.js": {
     "node_modules/ipaddr.js": {
       "version": "2.0.1",
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
       "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
@@ -14061,6 +14073,17 @@
       "resolved": "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz",
       "resolved": "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz",
       "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
       "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
     },
     },
+    "node_modules/react-lazyimg-component": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/react-lazyimg-component/-/react-lazyimg-component-1.0.1.tgz",
+      "integrity": "sha512-E3RqqLa4m1OO+L5jsiVo8Z8iFH4AkQn+MiZwb3T1J+5yqhd67cnlmjMYgMfa1B63bVecRAI6KNQO9uCVWgU6cg==",
+      "dependencies": {
+        "intersection-observer": "^0.12.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.8.0"
+      }
+    },
     "node_modules/react-redux": {
     "node_modules/react-redux": {
       "version": "8.0.4",
       "version": "8.0.4",
       "resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-8.0.4.tgz",
       "resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-8.0.4.tgz",
@@ -23087,6 +23110,11 @@
       "resolved": "https://registry.npmmirror.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
       "resolved": "https://registry.npmmirror.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
       "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ=="
       "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ=="
     },
     },
+    "gsap": {
+      "version": "3.11.5",
+      "resolved": "https://registry.npmmirror.com/gsap/-/gsap-3.11.5.tgz",
+      "integrity": "sha512-Q89nKCLgoX5xUjznh9LcaIUkz54k1voNucT1Rpf9SJNFIQznBwFqt5qUUQbeVInFyN/n18OUJkpeI6CNEDt74w=="
+    },
     "gzip-size": {
     "gzip-size": {
       "version": "6.0.0",
       "version": "6.0.0",
       "resolved": "https://registry.npmmirror.com/gzip-size/-/gzip-size-6.0.0.tgz",
       "resolved": "https://registry.npmmirror.com/gzip-size/-/gzip-size-6.0.0.tgz",
@@ -23451,6 +23479,11 @@
         "side-channel": "^1.0.4"
         "side-channel": "^1.0.4"
       }
       }
     },
     },
+    "intersection-observer": {
+      "version": "0.12.2",
+      "resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz",
+      "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="
+    },
     "ipaddr.js": {
     "ipaddr.js": {
       "version": "2.0.1",
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
       "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
@@ -27493,6 +27526,14 @@
       "resolved": "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz",
       "resolved": "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz",
       "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
       "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
     },
     },
+    "react-lazyimg-component": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/react-lazyimg-component/-/react-lazyimg-component-1.0.1.tgz",
+      "integrity": "sha512-E3RqqLa4m1OO+L5jsiVo8Z8iFH4AkQn+MiZwb3T1J+5yqhd67cnlmjMYgMfa1B63bVecRAI6KNQO9uCVWgU6cg==",
+      "requires": {
+        "intersection-observer": "^0.12.0"
+      }
+    },
     "react-redux": {
     "react-redux": {
       "version": "8.0.4",
       "version": "8.0.4",
       "resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-8.0.4.tgz",
       "resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-8.0.4.tgz",

+ 2 - 0
pc/package.json

@@ -12,8 +12,10 @@
     "@types/react-dom": "^18.0.8",
     "@types/react-dom": "^18.0.8",
     "antd": "^5.4.2",
     "antd": "^5.4.2",
     "axios": "^1.1.3",
     "axios": "^1.1.3",
+    "gsap": "^3.11.5",
     "react": "^18.2.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "react-dom": "^18.2.0",
+    "react-lazyimg-component": "^1.0.1",
     "react-redux": "^8.0.4",
     "react-redux": "^8.0.4",
     "react-router-dom": "5.3",
     "react-router-dom": "5.3",
     "react-scripts": "5.0.1",
     "react-scripts": "5.0.1",

+ 22 - 1
pc/src/App.tsx

@@ -4,8 +4,10 @@ import React from "react";
 import SpinLoding from "./components/SpinLoding";
 import SpinLoding from "./components/SpinLoding";
 import AsyncSpinLoding from "./components/AsyncSpinLoding";
 import AsyncSpinLoding from "./components/AsyncSpinLoding";
 import { Router, Route, Switch } from "react-router-dom";
 import { Router, Route, Switch } from "react-router-dom";
-
+import { Image } from "antd";
 import history from "./utils/history";
 import history from "./utils/history";
+import { useSelector } from "react-redux";
+import store, { RootState } from "./store";
 
 
 // 使用 React.lazy 懒加载页面
 // 使用 React.lazy 懒加载页面
 const A1Home = React.lazy(() => import("./pages/A1Home"));
 const A1Home = React.lazy(() => import("./pages/A1Home"));
@@ -13,6 +15,10 @@ const A2Main = React.lazy(() => import("./pages/A2Main"));
 const NotFound = React.lazy(() => import("@/components/NotFound"));
 const NotFound = React.lazy(() => import("@/components/NotFound"));
 
 
 function App() {
 function App() {
+    // 从仓库中获取查看图片的信息
+    const lookBigImg = useSelector(
+      (state: RootState) => state.A0layout.lookBigImg
+    );
   return (
   return (
     <div id="app">
     <div id="app">
       {/* 关于路由 */}
       {/* 关于路由 */}
@@ -31,6 +37,21 @@ function App() {
 
 
       {/* 发送请求的加载组件 */}
       {/* 发送请求的加载组件 */}
       <AsyncSpinLoding />
       <AsyncSpinLoding />
+
+      {/* 所有图片点击预览查看大图 */}
+      <Image
+        preview={{
+          visible: lookBigImg.show,
+          src: lookBigImg.url,
+          onVisibleChange: (value) => {
+            // 清除仓库信息
+            store.dispatch({
+              type: "layout/lookBigImg",
+              payload: { url: "", show: false },
+            });
+          },
+        }}
+      />
     </div>
     </div>
   );
   );
 }
 }

+ 37 - 0
pc/src/ImageLazy/index.module.scss

@@ -0,0 +1,37 @@
+.ImageLazy{
+  position: relative;
+  :global{
+    .lazyBox{
+      width: 100%;
+      height: 100%;
+      position: relative;
+      .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;
+        }
+      }
+    }
+  }
+
+}

+ 93 - 0
pc/src/ImageLazy/index.tsx

@@ -0,0 +1,93 @@
+import React, { useCallback, useEffect, useState } from "react";
+import styles from "./index.module.scss";
+import Lazyimg from "react-lazyimg-component";
+import { baseURL } from "@/utils/http";
+import imgLoding from "@/assets/img/loading.gif";
+import imgErr from "@/assets/img/IMGerror.png";
+import { EyeOutlined } from "@ant-design/icons";
+import store from "@/store";
+
+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) {
+  // 图片占位符
+  const [placeholderUrl, setPlaceholderUrl] = useState(
+    src ? imgLoding : imgErr
+  );
+
+  // 默认不能预览图片,加载成功之后能预览
+  const [lookImg, setLookImg] = useState(false);
+
+  useEffect(() => {
+    if (src) {
+      // 进页面查看图片的加载情况
+      // 创建一个img标签
+      const imgDom = document.createElement("img");
+      imgDom.src = offline ? src : baseURL + src;
+
+      // 不管图片加载成功或者失败,都删除掉,提高性能
+      // 图片加载成功
+      imgDom.onload = function () {
+        setLookImg(true);
+        imgDom.remove();
+      };
+      // 图片加载失败
+      imgDom.onerror = function () {
+        setPlaceholderUrl(imgErr);
+        imgDom.remove();
+      };
+
+      return () => {
+        // 离开页面也删掉掉元素
+        imgDom.remove();
+      };
+    }
+  }, [offline, src]);
+
+  // 点击预览图片
+  const lookBigImg = useCallback(() => {
+    store.dispatch({
+      type: "layout/lookBigImg",
+      payload: { url: offline ? src : baseURL + src, show: true },
+    });
+  }, [offline, src]);
+
+  return (
+    <div className={styles.ImageLazy} style={{ width: width, height: height }}>
+      <div className="lazyBox">
+        <Lazyimg
+          src={src ? (offline ? src : baseURL + src) : ""}
+          width={width}
+          height={height}
+          placeholder={placeholderUrl}
+          alt=""
+        />
+
+        {/* 图片预览 */}
+        {noLook || !lookImg ? null : (
+          <div className="lookImg" onClick={lookBigImg}>
+            <EyeOutlined />
+            &nbsp;
+            <div>预览</div>
+          </div>
+        )}
+      </div>
+    </div>
+  );
+}
+
+const MemoImageLazy = React.memo(ImageLazy);
+
+export default MemoImageLazy;

二進制
pc/src/assets/img/IMGerror.png


二進制
pc/src/assets/img/loading.gif


+ 6 - 3
pc/src/assets/styles/base.css

@@ -31,7 +31,8 @@ ul {
   list-style: none;
   list-style: none;
 }
 }
 body {
 body {
-  overflow: hidden;
+  overflow: auto;
+  overflow-y: overlay;
 }
 }
 /* 文本域取消下拉 */
 /* 文本域取消下拉 */
 textarea {
 textarea {
@@ -61,7 +62,8 @@ textarea {
   height: 100vh;
   height: 100vh;
   min-width: 1600px;
   min-width: 1600px;
   min-height: 900px;
   min-height: 900px;
-  overflow: hidden;
+  overflow: auto;
+  overflow-y: overlay;
 }
 }
 #root a {
 #root a {
   color: var(--themeColor);
   color: var(--themeColor);
@@ -69,6 +71,7 @@ textarea {
 #root #app {
 #root #app {
   width: 100%;
   width: 100%;
   height: 100%;
   height: 100%;
+  overflow: hidden;
 }
 }
 #root #app > div {
 #root #app > div {
   width: 100%;
   width: 100%;
@@ -76,7 +79,7 @@ textarea {
 }
 }
 #root .myscroll::-webkit-scrollbar {
 #root .myscroll::-webkit-scrollbar {
   /*滚动条整体样式*/
   /*滚动条整体样式*/
-  width: 5px;
+  width: 3px;
   /*高宽分别对应横竖滚动条的尺寸*/
   /*高宽分别对应横竖滚动条的尺寸*/
   height: 1px;
   height: 1px;
 }
 }

+ 6 - 3
pc/src/assets/styles/base.less

@@ -38,7 +38,8 @@ ul {
 }
 }
 
 
 body {
 body {
-  overflow: hidden;
+  overflow: auto;
+  overflow-y: overlay;
 }
 }
 
 
 /* 文本域取消下拉 */
 /* 文本域取消下拉 */
@@ -77,7 +78,8 @@ textarea {
   height: 100vh;
   height: 100vh;
   min-width: 1600px;
   min-width: 1600px;
   min-height: 900px;
   min-height: 900px;
-  overflow: hidden;
+  overflow: auto;
+  overflow-y: overlay;
 
 
   a {
   a {
     color: var(--themeColor);
     color: var(--themeColor);
@@ -86,6 +88,7 @@ textarea {
   #app {
   #app {
     width: 100%;
     width: 100%;
     height: 100%;
     height: 100%;
+    overflow: hidden;
 
 
     &>div {
     &>div {
       width: 100%;
       width: 100%;
@@ -95,7 +98,7 @@ textarea {
 
 
   .myscroll::-webkit-scrollbar {
   .myscroll::-webkit-scrollbar {
     /*滚动条整体样式*/
     /*滚动条整体样式*/
-    width: 5px;
+    width: 3px;
     /*高宽分别对应横竖滚动条的尺寸*/
     /*高宽分别对应横竖滚动条的尺寸*/
     height: 1px;
     height: 1px;
   }
   }

+ 28 - 3
pc/src/index.tsx

@@ -3,12 +3,37 @@ import store from "./store/index";
 import { Provider } from "react-redux";
 import { Provider } from "react-redux";
 import { createRoot } from "react-dom/client";
 import { createRoot } from "react-dom/client";
 
 
+import { ConfigProvider } from "antd";
+
+// 兼容360浏览器
+import {
+  StyleProvider,
+  legacyLogicalPropertiesTransformer,
+} from "@ant-design/cssinjs";
+
+import "dayjs/locale/zh-cn";
+import locale from "antd/locale/zh_CN";
+
 const container = document.getElementById("root") as HTMLElement;
 const container = document.getElementById("root") as HTMLElement;
 
 
 const root = createRoot(container);
 const root = createRoot(container);
 
 
 root.render(
 root.render(
-  <Provider store={store}>
-    <App />
-  </Provider>
+  <ConfigProvider
+    locale={locale}
+    theme={{
+      token: {
+        colorPrimary: "#c8b992",
+      },
+    }}
+  >
+    <Provider store={store}>
+      <StyleProvider
+        hashPriority="high"
+        transformers={[legacyLogicalPropertiesTransformer]}
+      >
+        <App />
+      </StyleProvider>
+    </Provider>
+  </ConfigProvider>
 );
 );

+ 251 - 0
pc/src/pages/A2Main/GoodsSw/index.module.scss

@@ -0,0 +1,251 @@
+.GoodsSw {
+  height: calc(100% - 100px);
+
+  :global {
+    .noInfo {
+      height: calc(100% - 100px);
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      color: var(--themeColor);
+      font-size: 40px;
+      padding-top: 100px;
+    }
+
+    .goddsBox {
+      height: calc(100% - 100px);
+
+
+
+
+      // 第一个自动播发的盒子
+      .goddsSwBox {
+        height: calc(50% - 20px);
+        border-bottom: 1px solid rgba(231, 219, 188, 0.50);
+        position: relative;
+        width: 100%;
+        overflow-x: auto;
+
+        &::-webkit-scrollbar {
+          /*滚动条整体样式*/
+          width: 0px;
+          /*高宽分别对应横竖滚动条的尺寸*/
+          height: 0px;
+        }
+
+
+
+        .goddsSw {
+          display: flex;
+          // position: absolute;
+          // left: 0;
+          // top: 0;
+          height: 100%;
+
+          .goddsRow {
+            width: 25vw;
+            color: #fff;
+            padding: 0 10px 0 90px;
+            display: flex;
+            height: 100%;
+
+            .name {
+              width: 40px;
+              margin-right: 20px;
+              word-wrap: break-word;
+              writing-mode: vertical-lr;
+              writing-mode: tb-lr;
+              font-size: 16px;
+              color: #C8B992;
+              padding-top: 20px;
+              letter-spacing: 3px;
+              position: relative;
+
+              &::before {
+                content: '';
+                position: absolute;
+                top: 0;
+                left: 7.5px;
+                width: 8px;
+                height: 8px;
+                border-radius: 50%;
+                background-color: #C8B992;
+              }
+            }
+
+            .goddsImg {
+              cursor: pointer;
+
+              width: calc(100% - 80px);
+              height: calc(100% - 80px);
+              position: relative;
+
+              &::before {
+                content: '';
+                position: absolute;
+                bottom: -80px;
+                left: 50%;
+                transform: translateX(-50%);
+                background: linear-gradient(rgba(231, 219, 188, 0), rgba(231, 219, 188, 1));
+                width: 1px;
+                height: 90px;
+              }
+            }
+          }
+        }
+
+
+      }
+
+
+
+      .goddsSwBox2 {
+        overflow-y: hidden;
+        border-bottom: none;
+        border-top: 1px solid rgba(231, 219, 188, 0.50);
+
+        margin-top: 40px;
+
+        .goddsSw {
+
+          .goddsRow {
+            padding: 0 90px 0 10px;
+
+            .name {
+              position: relative;
+              top: 80px;
+            }
+
+            .goddsImg {
+              top: 80px;
+
+              &::before {
+                bottom: auto;
+                top: -80px;
+                background: linear-gradient(rgba(231, 219, 188, 1), rgba(231, 219, 188, 0));
+              }
+            }
+          }
+        }
+      }
+
+
+    }
+
+    .searchBox {
+      height: 100px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+
+      .searRow {
+        margin: 20px;
+
+
+
+        .ant-select-selector {
+          border-radius: 0 6px 0px 6px;
+          background-color: transparent;
+          color: var(--themeColor);
+          border: 1px solid var(--themeColor);
+
+          .ant-select-selection-search-input::-webkit-input-placeholder {
+            /* WebKit browsers */
+            color: var(--themeColor);
+          }
+
+          .ant-select-selection-search-input:-moz-placeholder {
+            /* Mozilla Firefox 4 to 18 */
+            color: var(--themeColor);
+          }
+
+          .ant-select-selection-search-input::-moz-placeholder {
+            /* Mozilla Firefox 19+ */
+            color: var(--themeColor);
+          }
+
+          .ant-select-selection-search-input:-ms-input-placeholder {
+            /* Internet Explorer 10+ */
+            color: var(--themeColor);
+          }
+
+          .ant-select-selection-item {
+            color: var(--themeColor);
+          }
+
+          .ant-select-selection-placeholder {
+            color: var(--themeColor);
+          }
+
+        }
+
+        .ant-select-arrow {
+          color: var(--themeColor);
+        }
+
+        .anticon-down {
+          color: var(--themeColor);
+        }
+      }
+
+      .ant-input-affix-wrapper {
+        border-radius: 0 6px 0px 6px;
+        background-color: transparent;
+        color: var(--themeColor);
+        border: 1px solid var(--themeColor);
+
+        .ant-input {
+          background-color: transparent;
+          color: var(--themeColor);
+
+          &::-webkit-input-placeholder {
+            /* WebKit browsers */
+            color: var(--themeColor);
+          }
+
+          &:-moz-placeholder {
+            /* Mozilla Firefox 4 to 18 */
+            color: var(--themeColor);
+          }
+
+          &::-moz-placeholder {
+            /* Mozilla Firefox 19+ */
+            color: var(--themeColor);
+          }
+
+          &:-ms-input-placeholder {
+            /* Internet Explorer 10+ */
+            color: var(--themeColor);
+          }
+        }
+
+        .ant-input-clear-icon {
+          color: var(--themeColor);
+        }
+      }
+
+    }
+
+    // 藏品详情
+    .goodsInfoBox {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      background-color: aqua;
+      opacity: 0;
+      pointer-events: none;
+      transition: all .3s;
+
+      &>div {
+        color: #fff;
+      }
+    }
+
+    .goodsInfoBoxAc {
+      opacity: .6;
+      pointer-events: auto;
+    }
+  }
+}

+ 345 - 0
pc/src/pages/A2Main/GoodsSw/index.tsx

@@ -0,0 +1,345 @@
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
+import styles from "./index.module.scss";
+import { useDispatch, useSelector } from "react-redux";
+import { A2_APIgetGoodsList, A2_APIgetSelectData } from "@/store/action/A2Main";
+import { A2GoodsType, A2getGoodsDataType } from "@/types";
+import { RootState } from "@/store";
+import ImageLazy from "@/ImageLazy";
+import { Input, Select } from "antd";
+import classNames from "classnames";
+
+function GoodsSw() {
+  const dispatch = useDispatch();
+
+  useEffect(() => {
+    // 发送请求拿到下拉框数据
+    dispatch(A2_APIgetSelectData("age"));
+    dispatch(A2_APIgetSelectData("texture"));
+  }, [dispatch]);
+
+  // 获取下拉数据
+  const selectData = useSelector((state: RootState) => state.A2Main.selectData);
+
+  // 第一次不显示暂无信息
+  const [flagOne, setFlagOne] = useState(false);
+
+  useEffect(() => {
+    window.setTimeout(() => {
+      setFlagOne(true);
+    }, 500);
+  }, []);
+
+  // 发送请求函数
+  const [getData, setGetData] = useState<A2getGoodsDataType>({
+    dictAge: "",
+    dictTexture: "",
+    searchKey: "",
+    pageNum: 1,
+    pageSize: 9999,
+  });
+
+  const getListFu = useCallback(async () => {
+    await dispatch(A2_APIgetGoodsList(getData));
+  }, [dispatch, getData]);
+
+  // 从仓库获取数据
+  const goodsListAll = useSelector(
+    (state: RootState) => state.A2Main.goodsList
+  );
+
+  // 分为上下2个模块
+  const list1 = useMemo(() => {
+    const arr = [] as A2GoodsType[];
+    goodsListAll.forEach((v, i) => {
+      if (i % 2 === 0) arr.push(v);
+    });
+    return arr;
+  }, [goodsListAll]);
+
+  // 下面的数组
+  const list2 = useMemo(() => {
+    const arr = [] as A2GoodsType[];
+    goodsListAll.forEach((v, i) => {
+      if (i % 2 !== 0) arr.push(v);
+    });
+    return arr;
+  }, [goodsListAll]);
+
+  useEffect(() => {
+    // 发送请求
+    getListFu();
+  }, [getListFu]);
+
+  // 名称的输入
+  const nameTime = useRef(-1);
+  const nameChange = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>) => {
+      clearTimeout(nameTime.current);
+      nameTime.current = window.setTimeout(() => {
+        setGetData({
+          ...getData,
+          searchKey: e.target.value,
+        });
+      }, 500);
+    },
+    [getData]
+  );
+
+  // -----点击了单个藏品打开的页面----------
+  const [open, setOpen] = useState(false);
+  const openRef = useRef(false);
+
+  // 第一个盒子的总宽度
+  const goddsSw1 = useMemo(() => {
+    return window.innerWidth * 0.25 * list1.length;
+  }, [list1.length]);
+
+  // 4个定时器
+  const timeS1 = useRef(-1);
+  const timeS2 = useRef(-1);
+  const time1 = useRef(-1);
+  const time2 = useRef(-1);
+
+  // 上面的开始自动滚动
+  const scroolFu1 = useCallback(
+    (dom: HTMLDivElement, num: number, time: number) => {
+      clearTimeout(timeS1.current);
+      timeS1.current = window.setTimeout(() => {
+        clearInterval(time1.current);
+        let numAuto = num;
+        time1.current = window.setInterval(() => {
+          numAuto += 1;
+
+          if (dom.scrollLeft + dom.clientWidth >= dom.scrollWidth) {
+            numAuto = 0;
+          }
+          dom.scrollLeft = numAuto;
+        }, 20);
+      }, time);
+    },
+    []
+  );
+
+  // 清理第一个定时器
+  const colseTime1 = useCallback(() => {
+    clearTimeout(timeS1.current);
+    clearInterval(time1.current);
+    const dom = document.querySelector("#goddsSwBox1") as HTMLDivElement;
+    if (dom && list1.length > 4 && !open) {
+      scroolFu1(dom, dom.scrollLeft, 3000);
+    }
+  }, [list1.length, open, scroolFu1]);
+
+  // 下面的开始自动滚动
+  const scroolFu2 = useCallback(
+    (dom: HTMLDivElement, num: number, time: number) => {
+      clearTimeout(timeS2.current);
+      timeS2.current = window.setTimeout(() => {
+        clearInterval(time2.current);
+        let numAuto = num;
+        dom.scrollLeft = numAuto;
+        time2.current = window.setInterval(() => {
+          numAuto -= 1;
+          if (numAuto <= 0) {
+            numAuto = dom.scrollWidth - dom.clientWidth;
+          }
+          dom.scrollLeft = numAuto;
+        }, 20);
+      }, time);
+    },
+    []
+  );
+
+  // 清理第二个定时器
+  const closeTime2 = useCallback(() => {
+    clearTimeout(timeS2.current);
+    clearInterval(time2.current);
+    const dom = document.querySelector("#goddsSwBox2") as HTMLDivElement;
+    if (dom && list2.length > 4 && !open) {
+      scroolFu2(dom, dom.scrollLeft, 3000);
+    }
+  }, [list2.length, open, scroolFu2]);
+
+  // 上面的数组改变了数据
+  useEffect(() => {
+    if (list1.length > 4) {
+      const dom = document.querySelector("#goddsSwBox1") as HTMLDivElement;
+      // 监听鼠标滚轮
+      dom.onwheel = (e) => {
+        e.preventDefault();
+        const num = dom.scrollLeft;
+        dom.scrollLeft = num + e.deltaY;
+        colseTime1();
+      };
+      // 开启定时器
+      scroolFu1(dom, 0, 1000);
+    } else colseTime1();
+  }, [colseTime1, list1.length, scroolFu1]);
+
+  // 下面的数组改变了数据
+  useEffect(() => {
+    if (list2.length > 4) {
+      const dom = document.querySelector("#goddsSwBox2") as HTMLDivElement;
+      // 监听鼠标滚轮
+      dom.onwheel = (e) => {
+        e.preventDefault();
+        const num = dom.scrollLeft;
+        dom.scrollLeft = num + e.deltaY;
+        closeTime2();
+      };
+      // 开启定时器
+      scroolFu2(dom, dom.scrollWidth - dom.clientWidth, 1000);
+    } else closeTime2();
+  }, [closeTime2, list2.length, scroolFu2]);
+
+  // 第二个盒子的总宽度
+  const goddsSw2 = useMemo(() => {
+    return window.innerWidth * 0.25 * list2.length;
+  }, [list2.length]);
+
+  // 点击藏品
+  const clickGoodFu = useCallback((id: number) => {
+    openRef.current = true;
+    setOpen(true);
+
+    console.log(123, id);
+  }, []);
+
+  // 打开了单个文物详情页,关闭之后的逻辑
+  useEffect(() => {
+    if (open) {
+      clearTimeout(timeS1.current);
+      clearInterval(time1.current);
+      clearTimeout(timeS2.current);
+      clearInterval(time2.current);
+    } else if (openRef.current) {
+      const dom1 = document.querySelector("#goddsSwBox1") as HTMLDivElement;
+      const dom2 = document.querySelector("#goddsSwBox2") as HTMLDivElement;
+      scroolFu1(dom1, dom1.scrollLeft, 3000);
+      scroolFu2(dom2, dom2.scrollLeft, 3000);
+    }
+  }, [open, scroolFu1, scroolFu2]);
+
+  // 离开页面的时候清理4个定时器
+  useEffect(() => {
+    return () => {
+      clearTimeout(timeS1.current);
+      clearTimeout(timeS2.current);
+      clearInterval(time1.current);
+      clearInterval(time2.current);
+    };
+  }, []);
+
+  return (
+    <div className={styles.GoodsSw}>
+      {/* 轮播图主体 */}
+
+      {goodsListAll.length <= 0 ? (
+        <div className="noInfo" hidden={!flagOne}>
+          暂无更多内容
+        </div>
+      ) : (
+        <div className="goddsBox">
+          {/* 第一个自动播发的盒子 */}
+          <div
+            id="goddsSwBox1"
+            className="goddsSwBox"
+            onClick={() => colseTime1()}
+            // onMouseLeave={() => auto1Fu()}
+          >
+            <div className="goddsSw" style={{ width: goddsSw1 + "px" }}>
+              {list1.map((v) => (
+                <div key={v.id} className="goddsRow" title={v.name}>
+                  <div className="name">
+                    {v.name.length > 10
+                      ? v.name.substring(0, 10) + "..."
+                      : v.name}
+                  </div>
+                  <div className="goddsImg" onClick={() => clickGoodFu(v.id)}>
+                    <ImageLazy
+                      src={v.thumb}
+                      width="100%"
+                      height="100%"
+                      noLook
+                    />
+                  </div>
+                </div>
+              ))}
+            </div>
+          </div>
+          {/* 第二个自动播放的盒子 */}
+          <div
+            id="goddsSwBox2"
+            className="goddsSwBox goddsSwBox2"
+            onClick={() => closeTime2()}
+            // onMouseLeave={() => auto2Fu()}
+          >
+            <div className="goddsSw" style={{ width: goddsSw2 + "px" }}>
+              {list2.map((v) => (
+                <div key={v.id} className="goddsRow" title={v.name}>
+                  <div className="name">
+                    {v.name.length > 10
+                      ? v.name.substring(0, 10) + "..."
+                      : v.name}
+                  </div>
+                  <div className="goddsImg" onClick={() => clickGoodFu(v.id)}>
+                    <ImageLazy
+                      src={v.thumb}
+                      width="100%"
+                      height="100%"
+                      noLook
+                    />
+                  </div>
+                </div>
+              ))}
+            </div>
+          </div>
+        </div>
+      )}
+
+      {/* 下面的筛选框 */}
+      <div className="searchBox">
+        <div className="searRow">
+          <Select
+            placeholder="种类"
+            style={{ width: 150 }}
+            options={selectData["texture"]}
+            onChange={(e) => setGetData({ ...getData, dictTexture: e })}
+          />
+        </div>
+        <div className="searRow">
+          <Select
+            placeholder="年代"
+            style={{ width: 150 }}
+            options={selectData["age"]}
+            onChange={(e) => setGetData({ ...getData, dictAge: e })}
+          />
+        </div>
+        <div className="searRow">
+          <Input
+            maxLength={25}
+            style={{ width: 220 }}
+            placeholder="请输入关键词"
+            allowClear
+            onChange={(e) => nameChange(e)}
+          />
+        </div>
+      </div>
+
+      {/* 当个藏品详情盒子 */}
+      <div className={classNames("goodsInfoBox", open ? "goodsInfoBoxAc" : "")}>
+        <div onClick={() => setOpen(false)}>关闭</div>
+      </div>
+    </div>
+  );
+}
+
+const MemoGoodsSw = React.memo(GoodsSw);
+
+export default MemoGoodsSw;

+ 68 - 0
pc/src/pages/A2Main/KnowLedge/index.module.scss

@@ -0,0 +1,68 @@
+.KnowLedge {
+  height: calc(100% - 100px);
+
+  :global {
+    .knowMain {
+      margin: 0 auto;
+      width: 1100px;
+      height: 100%;
+      padding: 30px 0 0 100px;
+    }
+
+    .knowTop {
+      display: flex;
+      padding-left: 20px;
+
+      .knowTopRow {
+        cursor: pointer;
+        width: 110px;
+        height: 50px;
+        text-align: center;
+        line-height: 48px;
+        border: 1px solid var(--themeColor);
+        color: var(--themeColor);
+        border-radius: 0 10px 0 10px;
+        font-size: 18px;
+        margin-right: 40px;
+
+        &:hover {
+          color: #4A403D;
+          background-color: var(--themeColor);
+        }
+      }
+
+      .knowTopRowAc {
+        color: #4A403D;
+        background-color: var(--themeColor);
+      }
+    }
+
+    .knowCon {
+      margin-top: 30px;
+      width: 100%;
+      height: calc(100% - 100px);
+      overflow-y: auto;
+      padding-right: 100px;
+
+      .knowConRow {
+        padding-left: 20px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+        cursor: pointer;
+        height: 70px;
+        line-height: 70px;
+        font-size: 20px;
+        color: #fff;
+
+        &:hover {
+          color: #4a403d;
+          font-size: 22px;
+          background-color: var(--themeColor);
+          border-radius: 0 10px 0 10px;
+
+        }
+      }
+    }
+  }
+}

+ 73 - 0
pc/src/pages/A2Main/KnowLedge/index.tsx

@@ -0,0 +1,73 @@
+import React, { useCallback, useEffect, useState } from "react";
+import styles from "./index.module.scss";
+import classNames from "classnames";
+import { A2_APIgetKnowData } from "@/store/action/A2Main";
+import { A2KnowListType } from "@/types";
+
+const list = [
+  { id: 1, name: "全部", type: "" },
+  { id: 2, name: "历史", type: "历史" },
+  { id: 3, name: "军事", type: "军事" },
+  { id: 4, name: "人物", type: "人物" },
+  // { id: 5, name: "其他", type: "其他" },
+];
+
+function KnowLedge() {
+  const [acId, setAcId] = useState("");
+
+  const [data, setData] = useState<A2KnowListType[]>([]);
+
+  const getListFu = useCallback(async (type: string) => {
+    const res = await A2_APIgetKnowData(type);
+    setData(res.data);
+  }, []);
+
+  useEffect(() => {
+    getListFu(acId);
+  }, [acId, getListFu]);
+
+  const cutTabFu = useCallback((type: string) => {
+    setAcId(type);
+    const dom = document.querySelector(".knowCon") as HTMLDivElement;
+    if (dom) dom.scrollTop = 0;
+  }, []);
+
+  return (
+    <div className={styles.KnowLedge}>
+      <div className="knowMain">
+        <div className="knowTop">
+          {list.map((v) => (
+            <div
+              onClick={() => cutTabFu(v.type)}
+              className={classNames(
+                "knowTopRow",
+                acId === v.type ? "knowTopRowAc" : ""
+              )}
+              key={v.id}
+            >
+              {v.name}
+            </div>
+          ))}
+        </div>
+        {/* 主体 */}
+
+        <div className="knowCon myscroll">
+          {data.map((v) => (
+            <div
+              className="knowConRow"
+              title={v.name}
+              key={v.id}
+              onClick={() => window.open(v.link)}
+            >
+              {v.name}
+            </div>
+          ))}
+        </div>
+      </div>
+    </div>
+  );
+}
+
+const MemoKnowLedge = React.memo(KnowLedge);
+
+export default MemoKnowLedge;

+ 3 - 3
pc/src/pages/A2Main/SwiperCom/index.tsx

@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useRef, useState } from "react";
+import React, { useCallback, useEffect, useState } from "react";
 import styles from "./index.module.scss";
 import styles from "./index.module.scss";
 import { Swiper, SwiperSlide } from "swiper/react";
 import { Swiper, SwiperSlide } from "swiper/react";
 import classNames from "classnames";
 import classNames from "classnames";
@@ -41,7 +41,7 @@ function SwiperCom({ data, type }: Props) {
   );
   );
 
 
   // swiper实例
   // swiper实例
-  const mySwiperRef = useRef<any>(null);
+  // const mySwiperRef = useRef<any>(null);
   return (
   return (
     <div className={styles.SwiperCom}>
     <div className={styles.SwiperCom}>
       <Swiper
       <Swiper
@@ -52,7 +52,7 @@ function SwiperCom({ data, type }: Props) {
           "SwiperComBox",
           "SwiperComBox",
           data.length <= 6 ? "SwiperComBoxCen" : ""
           data.length <= 6 ? "SwiperComBoxCen" : ""
         )}
         )}
-        onSwiper={(swiper) => (mySwiperRef.current = swiper)}
+        // onSwiper={(swiper) => (mySwiperRef.current = swiper)}
       >
       >
         {data.map((v) => (
         {data.map((v) => (
           <SwiperSlide key={v.id}>
           <SwiperSlide key={v.id}>

+ 1 - 0
pc/src/pages/A2Main/index.module.scss

@@ -5,6 +5,7 @@
 
 
   :global {
   :global {
     .logo {
     .logo {
+      cursor: pointer;
       position: absolute;
       position: absolute;
       z-index: 10;
       z-index: 10;
       top: 20px;
       top: 20px;

+ 8 - 1
pc/src/pages/A2Main/index.tsx

@@ -5,6 +5,9 @@ import classNames from "classnames";
 import SwiperCom from "./SwiperCom";
 import SwiperCom from "./SwiperCom";
 import VideoBox from "./VideoBox";
 import VideoBox from "./VideoBox";
 import { A2SwType } from "@/types";
 import { A2SwType } from "@/types";
+import GoodsSw from "./GoodsSw";
+import history from "@/utils/history";
+import KnowLedge from "./KnowLedge";
 
 
 const incoArr = [
 const incoArr = [
   {
   {
@@ -79,7 +82,7 @@ function A2Main() {
   return (
   return (
     <div className={styles.A2Main}>
     <div className={styles.A2Main}>
       {/* 左上方logo */}
       {/* 左上方logo */}
-      <div className="logo">
+      <div className="logo" title="首页" onClick={() => history.push("/")}>
         <img src={LogoImg} alt="" />
         <img src={LogoImg} alt="" />
       </div>
       </div>
       {/* 底部轮播图 */}
       {/* 底部轮播图 */}
@@ -113,6 +116,10 @@ function A2Main() {
           {/* 轮播图主体 */}
           {/* 轮播图主体 */}
           {[1, 2, 3].includes(type) ? (
           {[1, 2, 3].includes(type) ? (
             <SwiperCom type={type} data={swData} />
             <SwiperCom type={type} data={swData} />
+          ) : type === 4 ? (
+            <GoodsSw />
+          ) : type === 5 ? (
+            <KnowLedge />
           ) : null}
           ) : null}
         </div>
         </div>
       </div>
       </div>

+ 60 - 0
pc/src/store/action/A2Main.ts

@@ -0,0 +1,60 @@
+import http from "@/utils/http";
+import store, { AppDispatch } from "..";
+import { A2SelectType, A2getGoodsDataType } from "@/types";
+
+/**
+ * 获文物列表数据
+ */
+export const A2_APIgetGoodsList = (data: A2getGoodsDataType) => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post("show/goods/pageList", data);
+    if (res.code === 0) {
+      dispatch({
+        type: "main/goodsList",
+        payload: res.data.records,
+      });
+    }
+  };
+};
+
+/**
+ * 获取下拉框列表
+ */
+export const A2_APIgetSelectData = (type: "age" | "texture") => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.get(`/show/dict/list?type=${type}`);
+    if (res.code === 0) {
+      const obj = store.getState().A2Main.selectData;
+      let newObj = {} as A2SelectType;
+      const data = res.data.map((v: any) => ({ value: v.name, label: v.name }));
+      data.unshift({
+        value: "",
+        label: type === "age" ? "全部年代" : "全部种类",
+      });
+
+      if (type === "age") {
+        newObj = {
+          ...obj,
+          age: data,
+        };
+      } else {
+        newObj = {
+          ...obj,
+          texture: data,
+        };
+      }
+
+      dispatch({
+        type: "main/goodsSelect",
+        payload: newObj,
+      });
+    }
+  };
+};
+
+/**
+ * 获取知识列表
+ */
+export const A2_APIgetKnowData = (type: string) => {
+  return http.get(`show/getKnowledge?tagType=${type}`);
+};

+ 19 - 3
pc/src/store/reducer/A2Main.ts

@@ -1,4 +1,4 @@
-import { A2VideoType } from "@/types";
+import { A2GoodsType, A2SelectType, A2VideoType } from "@/types";
 
 
 // 初始化状态
 // 初始化状态
 const initState = {
 const initState = {
@@ -8,16 +8,32 @@ const initState = {
     title: "",
     title: "",
     txt: "",
     txt: "",
   },
   },
+  // 文物列表数据
+  goodsList: [] as A2GoodsType[],
+  // 下拉框数据
+  selectData: {
+    texture: [],
+    age: [],
+  } as A2SelectType,
 };
 };
 
 
 // 定义 action 类型
 // 定义 action 类型
-type Props = { type: "main/lookVideo"; payload: A2VideoType };
-
+type Props =
+  | { type: "main/lookVideo"; payload: A2VideoType }
+  | { type: "main/goodsList"; payload: A2GoodsType[] }
+  | { type: "main/goodsSelect"; payload: A2SelectType };
 // 频道 reducer
 // 频道 reducer
 export default function loginReducer(state = initState, action: Props) {
 export default function loginReducer(state = initState, action: Props) {
   switch (action.type) {
   switch (action.type) {
+    // 历史查看视频
     case "main/lookVideo":
     case "main/lookVideo":
       return { ...state, videoInfo: action.payload };
       return { ...state, videoInfo: action.payload };
+    // 文物列表数据
+    case "main/goodsList":
+      return { ...state, goodsList: action.payload };
+    // 下拉框数据
+    case "main/goodsSelect":
+      return { ...state, selectData: action.payload };
     default:
     default:
       return state;
       return state;
   }
   }

+ 12 - 2
pc/src/store/reducer/layout.ts

@@ -8,16 +8,26 @@ const initState = {
     type: "info",
     type: "info",
     duration: 3,
     duration: 3,
   } as MessageType,
   } as MessageType,
+  // 所有图片点击预览查看大图
+  lookBigImg: {
+    url: "",
+    show: false,
+  },
 };
 };
 
 
 // 定义 action 类型
 // 定义 action 类型
-type Props = { type: "layout/message"; payload: MessageType };
-
+type Props =
+  | { type: "layout/message"; payload: MessageType }
+  | { type: "layout/lookBigImg"; payload: { url: string; show: boolean } };
 // 频道 reducer
 // 频道 reducer
 export default function loginReducer(state = initState, action: Props) {
 export default function loginReducer(state = initState, action: Props) {
   switch (action.type) {
   switch (action.type) {
+    // antd轻提示(兼容360浏览器)
     case "layout/message":
     case "layout/message":
       return { ...state, message: action.payload };
       return { ...state, message: action.payload };
+    // 所有图片点击预览查看大图
+    case "layout/lookBigImg":
+      return { ...state, lookBigImg: action.payload };
     default:
     default:
       return state;
       return state;
   }
   }

+ 48 - 7
pc/src/types/store/A2Main.d.ts

@@ -1,12 +1,53 @@
-export type A2SwType ={
-  id:number
-  name:string
-  path:string
-  info?:{ title: string, txt: string }
-}
+export type A2SwType = {
+  id: number;
+  name: string;
+  path: string;
+  info?: { title: string; txt: string };
+};
 
 
 export type A2VideoType = {
 export type A2VideoType = {
   id: number;
   id: number;
   title: string;
   title: string;
   txt: string;
   txt: string;
-}
+};
+
+export type A2GoodsType = {
+  creatorId: number;
+  creatorName: string;
+  description: string;
+  dictAge: string;
+  dictLevel: string;
+  dictSource: string;
+  dictTexture: string;
+  id: number;
+  isBarrage: 0 | 1;
+  name: string;
+  num: string;
+  tagCountry: string;
+  tagType: string;
+  thumb: string;
+};
+
+export type A2getGoodsDataType = {
+  dictAge: string;
+  dictTexture: string;
+  searchKey: string;
+  pageNum: 1;
+  pageSize: 9999;
+};
+
+export type A2SelectItemType = {
+  value: number | "";
+  label: string;
+};
+
+export type A2SelectType = {
+  texture: A2SelectItemType[];
+  age: A2SelectItemType[];
+};
+
+export type A2KnowListType = {
+  id: number;
+  link: string;
+  name: string;
+};