shaogen1995 2 năm trước cách đây
mục cha
commit
f0e7e96e65
47 tập tin đã thay đổi với 8276 bổ sung191 xóa
  1. 71 0
      管理后台/package-lock.json
  2. 1 0
      管理后台/package.json
  3. 6330 0
      管理后台/public/4dage.js
  4. 34 0
      管理后台/public/model.html
  5. 5 4
      管理后台/src/App.tsx
  6. BIN
      管理后台/src/assets/img/inco1.png
  7. BIN
      管理后台/src/assets/img/inco1Ac.png
  8. BIN
      管理后台/src/assets/img/inco2.png
  9. BIN
      管理后台/src/assets/img/inco2Ac.png
  10. BIN
      管理后台/src/assets/img/inco3.png
  11. BIN
      管理后台/src/assets/img/inco3Ac.png
  12. BIN
      管理后台/src/assets/img/inco4.png
  13. BIN
      管理后台/src/assets/img/inco4Ac.png
  14. BIN
      管理后台/src/assets/img/inco5.png
  15. BIN
      管理后台/src/assets/img/inco5Ac.png
  16. BIN
      管理后台/src/assets/img/layoutLeftMain.jpg
  17. BIN
      管理后台/src/assets/img/loginBox.jpg
  18. BIN
      管理后台/src/assets/img/logo.png
  19. BIN
      管理后台/src/assets/img/logo2.png
  20. BIN
      管理后台/src/assets/img/top.jpg
  21. 9 25
      管理后台/src/assets/styles/base.css
  22. 14 26
      管理后台/src/assets/styles/base.less
  23. 65 0
      管理后台/src/components/LookDom/index.module.scss
  24. 52 0
      管理后台/src/components/LookDom/index.tsx
  25. 1 1
      管理后台/src/components/Message/index.tsx
  26. 1 1
      管理后台/src/components/UpAsyncLoding/index.tsx
  27. 4 1
      管理后台/src/components/VideoLook/index.tsx
  28. 0 34
      管理后台/src/components/VideoLookDom/index.module.scss
  29. 0 36
      管理后台/src/components/VideoLookDom/index.tsx
  30. 253 0
      管理后台/src/pages/A1Goods/GoodsAdd/index.module.scss
  31. 834 0
      管理后台/src/pages/A1Goods/GoodsAdd/index.tsx
  32. 48 3
      管理后台/src/pages/A1Goods/index.module.scss
  33. 363 5
      管理后台/src/pages/A1Goods/index.tsx
  34. 3 4
      管理后台/src/pages/A5Log/index.module.scss
  35. 2 2
      管理后台/src/pages/A5Log/index.tsx
  36. 19 37
      管理后台/src/pages/Layout/index.module.scss
  37. 2 1
      管理后台/src/pages/Layout/index.tsx
  38. 71 0
      管理后台/src/store/action/A1Goods.ts
  39. 2 0
      管理后台/src/store/action/layout.ts
  40. 27 0
      管理后台/src/store/reducer/A1Goods.ts
  41. 4 2
      管理后台/src/store/reducer/index.ts
  42. 12 6
      管理后台/src/store/reducer/layout.ts
  43. 38 0
      管理后台/src/types/api/A1Goods.d.ts
  44. 8 1
      管理后台/src/types/api/layot.d.ts
  45. 1 0
      管理后台/src/types/index.d.ts
  46. 1 1
      管理后台/src/utils/domShow.ts
  47. 1 1
      管理后台/src/utils/http.ts

+ 71 - 0
管理后台/package-lock.json

@@ -29,6 +29,7 @@
         "react-redux": "^8.0.4",
         "react-router-dom": "5.3",
         "react-scripts": "5.0.1",
+        "react-sortablejs": "^6.1.4",
         "redux": "^4.2.0",
         "redux-devtools-extension": "^2.13.9",
         "redux-thunk": "^2.4.1",
@@ -4002,6 +4003,12 @@
         "@types/node": "*"
       }
     },
+    "node_modules/@types/sortablejs": {
+      "version": "1.15.1",
+      "resolved": "https://registry.npmmirror.com/@types/sortablejs/-/sortablejs-1.15.1.tgz",
+      "integrity": "sha512-g/JwBNToh6oCTAwNS8UGVmjO7NLDKsejVhvE4x1eWiPTC3uCuNsa/TD4ssvX3du+MLiM+SHPNDuijp8y76JzLQ==",
+      "peer": true
+    },
     "node_modules/@types/stack-utils": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/@types/stack-utils/-/stack-utils-2.0.1.tgz",
@@ -14336,6 +14343,31 @@
         }
       }
     },
+    "node_modules/react-sortablejs": {
+      "version": "6.1.4",
+      "resolved": "https://registry.npmmirror.com/react-sortablejs/-/react-sortablejs-6.1.4.tgz",
+      "integrity": "sha512-fc7cBosfhnbh53Mbm6a45W+F735jwZ1UFIYSrIqcO/gRIFoDyZeMtgKlpV4DdyQfbCzdh5LoALLTDRxhMpTyXQ==",
+      "dependencies": {
+        "classnames": "2.3.1",
+        "tiny-invariant": "1.2.0"
+      },
+      "peerDependencies": {
+        "@types/sortablejs": "1",
+        "react": ">=16.9.0",
+        "react-dom": ">=16.9.0",
+        "sortablejs": "1"
+      }
+    },
+    "node_modules/react-sortablejs/node_modules/classnames": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmmirror.com/classnames/-/classnames-2.3.1.tgz",
+      "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
+    },
+    "node_modules/react-sortablejs/node_modules/tiny-invariant": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz",
+      "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg=="
+    },
     "node_modules/read-cache": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz",
@@ -15107,6 +15139,12 @@
         "websocket-driver": "^0.7.4"
       }
     },
+    "node_modules/sortablejs": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.15.0.tgz",
+      "integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==",
+      "peer": true
+    },
     "node_modules/source-list-map": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/source-list-map/-/source-list-map-2.0.1.tgz",
@@ -19928,6 +19966,12 @@
         "@types/node": "*"
       }
     },
+    "@types/sortablejs": {
+      "version": "1.15.1",
+      "resolved": "https://registry.npmmirror.com/@types/sortablejs/-/sortablejs-1.15.1.tgz",
+      "integrity": "sha512-g/JwBNToh6oCTAwNS8UGVmjO7NLDKsejVhvE4x1eWiPTC3uCuNsa/TD4ssvX3du+MLiM+SHPNDuijp8y76JzLQ==",
+      "peer": true
+    },
     "@types/stack-utils": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/@types/stack-utils/-/stack-utils-2.0.1.tgz",
@@ -27796,6 +27840,27 @@
         "workbox-webpack-plugin": "^6.4.1"
       }
     },
+    "react-sortablejs": {
+      "version": "6.1.4",
+      "resolved": "https://registry.npmmirror.com/react-sortablejs/-/react-sortablejs-6.1.4.tgz",
+      "integrity": "sha512-fc7cBosfhnbh53Mbm6a45W+F735jwZ1UFIYSrIqcO/gRIFoDyZeMtgKlpV4DdyQfbCzdh5LoALLTDRxhMpTyXQ==",
+      "requires": {
+        "classnames": "2.3.1",
+        "tiny-invariant": "1.2.0"
+      },
+      "dependencies": {
+        "classnames": {
+          "version": "2.3.1",
+          "resolved": "https://registry.npmmirror.com/classnames/-/classnames-2.3.1.tgz",
+          "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
+        },
+        "tiny-invariant": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmmirror.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz",
+          "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg=="
+        }
+      }
+    },
     "read-cache": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz",
@@ -28402,6 +28467,12 @@
         "websocket-driver": "^0.7.4"
       }
     },
+    "sortablejs": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmmirror.com/sortablejs/-/sortablejs-1.15.0.tgz",
+      "integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==",
+      "peer": true
+    },
     "source-list-map": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/source-list-map/-/source-list-map-2.0.1.tgz",

+ 1 - 0
管理后台/package.json

@@ -24,6 +24,7 @@
     "react-redux": "^8.0.4",
     "react-router-dom": "5.3",
     "react-scripts": "5.0.1",
+    "react-sortablejs": "^6.1.4",
     "redux": "^4.2.0",
     "redux-devtools-extension": "^2.13.9",
     "redux-thunk": "^2.4.1",

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 6330 - 0
管理后台/public/4dage.js


+ 34 - 0
管理后台/public/model.html

@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="zh">
+
+<head>
+  <meta charset="UTF-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <script src="./4dage.js"></script>
+  <title>Document</title>
+  <style>
+    html {
+      overflow: hidden;
+    }
+  </style>
+</head>
+
+<body>
+  <div id="ui"></div>
+  <script>
+    let url = getQueryVariable("m");
+    fdage.embed(url, {
+    // fdage.embed('https://hnbwg.4dage.com' + url, {
+    // fdage.embed('http://192.168.20.55:8044/api' + url, {
+      transparentBackground: true,
+      width: 800,
+      height: 600,
+      autoStart: true,
+      fullFrame: true,
+      pagePreset: false
+    });
+  </script>
+</body>
+
+</html>

+ 5 - 4
管理后台/src/App.tsx

@@ -10,15 +10,15 @@ import { Image } from "antd";
 import { useSelector } from "react-redux";
 import store, { RootState } from "./store";
 import UpAsyncLoding from "./components/UpAsyncLoding";
-import VideoLookDom from "./components/VideoLookDom";
 import MessageCom from "./components/Message";
+import LookDom from "./components/LookDom";
 const Layout = React.lazy(() => import("./pages/Layout"));
 const Login = React.lazy(() => import("./pages/Login"));
 
 export default function App() {
   // 从仓库中获取查看图片的信息
   const lookBigImg = useSelector(
-    (state: RootState) => state.A1Layout.lookBigImg
+    (state: RootState) => state.A0Layout.lookBigImg
   );
 
   return (
@@ -55,8 +55,9 @@ export default function App() {
       {/* 上传附件的进度条元素 */}
       <UpAsyncLoding />
 
-      {/* 点击预览视频组件 */}
-      <VideoLookDom />
+      {/* 点击预览视频、音频、模型组件 */}
+      <LookDom />
+
 
       {/* antd 轻提示 ---兼容360浏览器 */}
       <MessageCom />

BIN
管理后台/src/assets/img/inco1.png


BIN
管理后台/src/assets/img/inco1Ac.png


BIN
管理后台/src/assets/img/inco2.png


BIN
管理后台/src/assets/img/inco2Ac.png


BIN
管理后台/src/assets/img/inco3.png


BIN
管理后台/src/assets/img/inco3Ac.png


BIN
管理后台/src/assets/img/inco4.png


BIN
管理后台/src/assets/img/inco4Ac.png


BIN
管理后台/src/assets/img/inco5.png


BIN
管理后台/src/assets/img/inco5Ac.png


BIN
管理后台/src/assets/img/layoutLeftMain.jpg


BIN
管理后台/src/assets/img/loginBox.jpg


BIN
管理后台/src/assets/img/logo.png


BIN
管理后台/src/assets/img/logo2.png


BIN
管理后台/src/assets/img/top.jpg


+ 9 - 25
管理后台/src/assets/styles/base.css

@@ -37,6 +37,7 @@ body {
 /* 文本域取消下拉 */
 textarea {
   resize: none !important;
+  min-height: 100px !important;
 }
 /* 主题色 */
 :root {
@@ -68,18 +69,15 @@ textarea {
   /* antd图片预览组件 */
   /* antd表格居中 */
 }
-#root a {
-  color: var(--themeColor);
-}
 #root .ant-btn-text {
-  color: #99b8dd;
+  color: var(--themeColor);
 }
 #root .ant-btn-text:disabled {
   cursor: not-allowed;
   color: rgba(0, 0, 0, 0.25);
 }
 #root .ant-btn-text.ant-btn-dangerous {
-  color: var(--themeColor);
+  color: #ff4d4d;
 }
 #root .ant-pagination .ant-pagination-item {
   border-radius: 50%;
@@ -144,14 +142,13 @@ textarea {
   display: none;
 }
 .pageTitle {
-  font-size: 20px;
+  font-size: 18px;
   font-weight: 700;
-  position: relative;
+  position: absolute;
+  z-index: 11;
+  top: -56px;
+  left: -18px;
   padding-left: 40px;
-  height: 50px;
-  line-height: 50px;
-  background-color: #fff;
-  border-radius: 10px;
 }
 .pageTitle::before {
   position: absolute;
@@ -161,7 +158,7 @@ textarea {
   content: '';
   width: 6px;
   height: 20px;
-  background-color: var(--themeColor);
+  background-color: #775755;
 }
 .mySorrl::-webkit-scrollbar {
   /*滚动条整体样式*/
@@ -181,16 +178,3 @@ textarea {
   border-radius: 10px;
   background: transparent;
 }
-.myCoverBox {
-  pointer-events: none;
-  position: absolute;
-  bottom: 0;
-  left: 0;
-  width: 100%;
-  z-index: 10;
-  background-color: rgba(0, 0, 0, 0.6);
-  color: #fff;
-  height: 30px;
-  line-height: 30px;
-  text-align: center;
-}

+ 14 - 26
管理后台/src/assets/styles/base.less

@@ -45,6 +45,7 @@ body {
 /* 文本域取消下拉 */
 textarea {
   resize: none !important;
+  min-height: 100px !important;
 }
 
 /* 主题色 */
@@ -81,13 +82,13 @@ textarea {
   overflow: auto;
   overflow-y: overlay;
 
-  a {
-    color: var(--themeColor);
-  }
+  // a {
+  //   color: var(--themeColor);
+  // }
 
   /* 普通文字按钮的颜色 */
   .ant-btn-text {
-    color: #99b8dd;
+    color: var(--themeColor);
   }
 
   .ant-btn-text:disabled {
@@ -97,7 +98,7 @@ textarea {
 
   /* 按钮的危险颜色 */
   .ant-btn-text.ant-btn-dangerous {
-    color: var(--themeColor);
+    color: #ff4d4d;
   }
 
   /* antd分页器样式 */
@@ -197,15 +198,15 @@ textarea {
 }
 
 // 页面标题
-.pageTitle{
-  font-size: 20px;
+.pageTitle {
+  font-size: 18px;
   font-weight: 700;
-  position: relative;
+  position: absolute;
+  z-index: 11;
+  top: -56px;
+  left: -18px;
   padding-left: 40px;
-  height: 50px;
-  line-height: 50px;
-  background-color: #fff;
-  border-radius: 10px;
+
   &::before {
     position: absolute;
     left: 20px;
@@ -214,7 +215,7 @@ textarea {
     content: '';
     width: 6px;
     height: 20px;
-    background-color: var(--themeColor);
+    background-color: #775755;
   }
 }
 
@@ -238,17 +239,4 @@ textarea {
   -webkit-box-shadow: inset 0 0 5px transparent;
   border-radius: 10px;
   background: transparent;
-}
-.myCoverBox{
-  pointer-events: none;
-  position: absolute;
-  bottom: 0;
-  left: 0;
-  width: 100%;
-  z-index: 10;
-  background-color: rgba(0, 0, 0, 0.6);
-  color: #fff;
-  height: 30px;
-  line-height: 30px;
-  text-align: center;
 }

+ 65 - 0
管理后台/src/components/LookDom/index.module.scss

@@ -0,0 +1,65 @@
+.LookDom {
+  transition: opacity .3s;
+  position: fixed;
+  z-index: 9991;
+  opacity: 0;
+  pointer-events: none;
+  top: 0;
+  left: 0;
+  width: 100vw;
+  height: 100vh;
+  background-color: rgba(0, 0, 0, .6);
+
+  :global {
+    .close {
+      color: #fff;
+      position: absolute;
+      right: 70px;
+      top: 70px;
+      font-size: 30px;
+      cursor: pointer;
+      z-index: 10;
+    }
+
+    .viedoBox {
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      width: 800px;
+      height: 500px;
+
+      video {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+    .audioBox {
+      position: absolute;
+      top: 50%;
+      left: 50%;
+      transform: translate(-50%, -50%);
+      width: 500px;
+      height: 60px;
+
+      audio {
+        width: 100%;
+        height: 100%;
+      }
+    }
+
+    .modelBox {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+
+      iframe {
+        width: 100%;
+        height: 100%;
+      }
+    }
+  }
+}

+ 52 - 0
管理后台/src/components/LookDom/index.tsx

@@ -0,0 +1,52 @@
+/* eslint-disable jsx-a11y/iframe-has-title */
+import React from "react";
+import { CloseCircleOutlined } from "@ant-design/icons";
+import styles from "./index.module.scss";
+import { useSelector } from "react-redux";
+import store, { RootState } from "@/store";
+import { baseURL } from "@/utils/http";
+function LookDom() {
+  const { src, type } = useSelector(
+    (state: RootState) => state.A0Layout.lookDom
+  );
+  return (
+    <div
+      className={styles.LookDom}
+      style={src ? { opacity: 1, pointerEvents: "auto" } : {}}
+    >
+      {src ? (
+        <>
+          {type === "video" ? (
+            <div className="viedoBox">
+              <video autoPlay controls src={baseURL + src}></video>
+            </div>
+          ) : type === "audio" ? (
+            <div className="audioBox">
+              <audio autoPlay controls src={baseURL + src}></audio>
+            </div>
+          ) : (
+            <div className="modelBox">
+              <iframe src={`model.html?m=${src}`}></iframe>
+            </div>
+          )}
+
+          <div
+            className="close"
+            onClick={() =>
+              store.dispatch({
+                type: "layout/lookDom",
+                payload: { src: "", type: "" },
+              })
+            }
+          >
+            <CloseCircleOutlined />
+          </div>
+        </>
+      ) : null}
+    </div>
+  );
+}
+
+const MemoLookDom = React.memo(LookDom);
+
+export default MemoLookDom;

+ 1 - 1
管理后台/src/components/Message/index.tsx

@@ -6,7 +6,7 @@ import { RootState } from "@/store";
 function MessageCom() {
   // 从仓库中获取 antd 轻提示信息
   const messageReducerInfo = useSelector(
-    (state: RootState) => state.A1Layout.message
+    (state: RootState) => state.A0Layout.message
   );
 
   const [messageApi, contextHolder] = message.useMessage();

+ 1 - 1
管理后台/src/components/UpAsyncLoding/index.tsx

@@ -6,7 +6,7 @@ import styles from "./index.module.scss";
 function UpAsyncLoding() {
   // 从仓库中获取取消上传的函数
   const closeUpFile = useSelector(
-    (state: RootState) => state.A1Layout.closeUpFile
+    (state: RootState) => state.A0Layout.closeUpFile
   );
 
   const btnClose = useCallback(() => {

+ 4 - 1
管理后台/src/components/VideoLook/index.tsx

@@ -16,7 +16,10 @@ function VideoLook({ src, width = 100, height = 100 }: Props) {
       <div
         className="videoLookBox"
         onClick={() =>
-          store.dispatch({ type: "layout/lookVideo", payload: src })
+          store.dispatch({
+            type: "layout/lookDom",
+            payload: { src, type: "video" },
+          })
         }
       >
         <div className="videoCover">

+ 0 - 34
管理后台/src/components/VideoLookDom/index.module.scss

@@ -1,34 +0,0 @@
-.VideoLookDom{
-  transition: opacity .3s;
-  position: fixed;
-  z-index: 9991;
-  opacity: 0;
-  pointer-events: none;
-  top: 0;
-  left: 0;
-  width: 100vw;
-  height: 100vh;
-  background-color: rgba(0,0,0,.6);
-  :global{
-    .close{
-      color: #fff;
-      position: absolute;
-      right: 70px;
-      top: 70px;
-      font-size: 30px;
-      cursor: pointer;
-    }
-    .viedoBox{
-      position: absolute;
-      top: 50%;
-      left: 50%;
-      transform: translate(-50%,-50%);
-      width: 800px;
-      height: 500px;
-      video{
-        width: 100%;
-        height: 100%;
-      }
-    }
-  }
-}

+ 0 - 36
管理后台/src/components/VideoLookDom/index.tsx

@@ -1,36 +0,0 @@
-import React from "react";
-import { CloseCircleOutlined } from "@ant-design/icons";
-import styles from "./index.module.scss";
-import { useSelector } from "react-redux";
-import store, { RootState } from "@/store";
-import { baseURL } from "@/utils/http";
-function VideoLookDom() {
-  const videoSrc = useSelector(
-    (state: RootState) => state.A1Layout.videoSrc
-  );
-  return (
-    <div
-      className={styles.VideoLookDom}
-      style={videoSrc ? { opacity: 1, pointerEvents: "auto" } : {}}
-    >
-      <div className="viedoBox">
-        {videoSrc ? (
-          <video autoPlay controls src={baseURL + videoSrc}></video>
-        ) : null}
-      </div>
-
-      <div
-        className="close"
-        onClick={() =>
-          store.dispatch({ type: "layout/lookVideo", payload: "" })
-        }
-      >
-        <CloseCircleOutlined />
-      </div>
-    </div>
-  );
-}
-
-const MemoVideoLookDom = React.memo(VideoLookDom);
-
-export default MemoVideoLookDom;

+ 253 - 0
管理后台/src/pages/A1Goods/GoodsAdd/index.module.scss

@@ -0,0 +1,253 @@
+.GoodsAdd {
+  position: absolute;
+  z-index: 20;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+
+  border-radius: 10px;
+  background-color: #fff;
+
+  :global {
+    .main {
+      margin-top: 5px;
+      width: 1200px;
+      padding: 20px 400px 0 15px;
+      height: 100%;
+      overflow-y: auto;
+      overflow-y: overlay;
+
+      .myformBox0 {
+        margin-top: 0px;
+      }
+
+      .myformBox {
+        .ant-btn-default {
+          width: 100px;
+        }
+
+        display: flex;
+        margin-bottom: 20px;
+
+        .label {
+          width: 100px;
+          text-align: right;
+
+          &>span {
+            position: relative;
+            top: 2px;
+            color: #ff4d4f;
+          }
+        }
+
+      }
+
+      .myformBox2 {
+        align-items: center;
+        height: 32px;
+
+        .label {
+          height: 32px;
+          line-height: 32px;
+        }
+
+        .fileTit {
+          margin-left: 20px;
+          font-size: 14px;
+          color: rgb(126, 124, 124);
+        }
+
+        .fileInfo {
+          height: 32px;
+          line-height: 32px;
+          display: flex;
+          align-items: center;
+          font-size: 16px;
+
+          .clearCover {
+            margin-left: 20px;
+            cursor: pointer;
+            font-size: 16px;
+          }
+
+          &>a {
+            color: black;
+          }
+        }
+
+
+      }
+
+      .myformBox3 {
+        margin-top: 20px;
+
+        .upImgBox {
+          width: 680px;
+
+          .fileImgListBox {
+            display: flex;
+            flex-wrap: wrap;
+            margin-bottom: 10px;
+
+            &>div {
+              cursor: move;
+              margin: 15px 20px 0px 0;
+            }
+          }
+
+          .fileBoxRow_r_img {
+            position: relative;
+
+            .fileImgListLDBox {
+              height: 26px;
+              background-color: rgba(0, 0, 0, .6);
+              color: #fff;
+              display: flex;
+              justify-content: space-around;
+              font-size: 16px;
+
+              &>a {
+                color: #fff;
+              }
+            }
+
+            .clearCover {
+              right: -10px;
+              top: -10px;
+              transform: translate(0, 0);
+              background-color: rgba(0, 0, 0, .8);
+              width: 20px;
+              height: 20px;
+              border-radius: 50%;
+              font-size: 16px;
+              color: #fff;
+            }
+          }
+        }
+
+        .fileTit {
+          font-size: 14px;
+          color: rgb(126, 124, 124);
+        }
+      }
+
+      .fileBoxRow_r {
+        position: relative;
+
+        .fileBoxRow_up {
+          color: #a6a6a6;
+          border-radius: 3px;
+          cursor: pointer;
+          font-size: 30px;
+          width: 100px;
+          height: 100px;
+          border: 1px dashed #797979;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+
+
+        }
+
+        .fileBoxRow_r_img {
+          width: 100px;
+          height: 126px;
+          position: relative;
+
+          .clearCover {
+            cursor: pointer;
+            z-index: 10;
+            position: absolute;
+            width: 50px;
+            height: 50px;
+            top: 50%;
+            transform: translateY(-50%);
+            right: -50px;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            font-size: 20px;
+            color: #333;
+          }
+
+          .clearCover2 {
+            .clearCover2DelBox {
+              position: absolute;
+              right: -10px;
+              top: -10px;
+              transform: translate(0, 0);
+              background-color: rgba(0, 0, 0, 0.8);
+              width: 20px;
+              height: 20px;
+              border-radius: 50%;
+              font-size: 16px;
+              color: #fff;
+              display: flex;
+              justify-content: center;
+              align-items: center;
+            }
+
+            .clearCover2DLBox {
+              width: 100%;
+              background-color: rgba(0, 0, 0, .6);
+              color: #fff;
+              display: flex;
+              justify-content: space-around;
+
+              &>a {
+                color: #fff;
+              }
+
+              font-size: 16px;
+            }
+          }
+        }
+
+        .fileBoxRow_r_tit {
+          height: 46px;
+          margin-top: 5px;
+          font-size: 14px;
+          color: rgb(126, 124, 124);
+
+
+        }
+      }
+
+      .noUpThumb {
+        position: relative;
+        overflow: hidden;
+        opacity: 0;
+        transition: top .2s;
+        color: #ff4d4f;
+        top: -10px;
+      }
+
+      .noUpThumb2 {
+        margin-top: -10px;
+        position: relative;
+        padding-left: 100px;
+        margin-bottom: 12px;
+      }
+
+      .noUpThumbAc {
+        top: 0;
+        opacity: 1;
+      }
+
+      .myformBox {
+        .laseFormRight {
+          .laseFormRightRow {
+            display: flex;
+            align-items: center;
+          }
+
+          .laseFormRightTit {
+            font-size: 14px;
+            color: rgb(126, 124, 124);
+          }
+        }
+      }
+    }
+  }
+}

+ 834 - 0
管理后台/src/pages/A1Goods/GoodsAdd/index.tsx

@@ -0,0 +1,834 @@
+import store, { RootState } from "@/store";
+import {
+  Button,
+  Checkbox,
+  Form,
+  FormInstance,
+  Input,
+  Popconfirm,
+  Select,
+} from "antd";
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
+import { useSelector } from "react-redux";
+import TextArea from "antd/es/input/TextArea";
+import styles from "./index.module.scss";
+import { MessageFu } from "@/utils/message";
+import ImageLazy from "@/components/ImageLazy";
+import classNames from "classnames";
+import {
+  PlusOutlined,
+  EyeOutlined,
+  UploadOutlined,
+  CloseOutlined,
+  DownloadOutlined,
+} from "@ant-design/icons";
+import {
+  getGoodsInfoByIdAPI,
+  getGoodsSaveAPI,
+  goodsUploadAPI,
+} from "@/store/action/A1Goods";
+import { baseURL } from "@/utils/http";
+import { FileImgListType, FileListType, GoodsTableType } from "@/types";
+import { fileDomInitialFu } from "@/utils/domShow";
+import { ReactSortable } from "react-sortablejs";
+
+type Props = {
+  id: number;
+  lookFlag: boolean;
+  closeMoalFu: () => void;
+  addListFu: () => void;
+  editListFu: () => void;
+};
+
+function GoodsAdd({ id, closeMoalFu, addListFu, editListFu, lookFlag }: Props) {
+  // 上传附件的信息
+  const [fileList, setFileList] = useState({
+    model: {} as FileListType,
+    audio: {} as FileListType,
+    video: {} as FileListType,
+  });
+
+  // 附件拖动的拆分数组
+  const [fileImgList, setFileImgList] = useState<FileImgListType>([]);
+
+  // 表单的ref
+  const FormBoxRef = useRef<FormInstance>(null);
+
+  // 文件的dirCode码
+  const [dirCode, setDirCode] = useState("");
+
+  const getInfoInAPIFu = useCallback(async (id: number) => {
+    const res = await getGoodsInfoByIdAPI(id);
+    FormBoxRef.current?.setFieldsValue(res.data.entity);
+    setCover(res.data.entity.thumb);
+
+    if (res.data.entity.type) setTypeCheck(res.data.entity.type.split(","));
+
+    const data: FileListType[] = res.data.file;
+    const obj = {
+      model: {} as FileListType,
+      audio: {} as FileListType,
+      video: {} as FileListType,
+    };
+
+    const fileImgListTemp = [] as FileImgListType;
+
+    data.forEach((v) => {
+      if (v.type === "img") fileImgListTemp.push(v as any);
+      else obj[v.type!] = v;
+    });
+    setFileImgList(fileImgListTemp);
+    setFileList(obj);
+    setDirCode(res.data.entity.dirCode);
+  }, []);
+
+  useEffect(() => {
+    if (id > 0) getInfoInAPIFu(id);
+    else {
+      setDirCode(Date.now() + "");
+      // FormBoxRef.current?.setFieldsValue({ });
+    }
+  }, [getInfoInAPIFu, id]);
+
+  // 从仓库获取下拉列表数据
+  const dictList = useSelector((state: RootState) => state.A0Layout.dictList);
+
+  // 上传封面图的ref
+  const [coverCheck, setCoverCheck] = useState(false);
+  const [cover, setCover] = useState("");
+  const myInput = useRef<HTMLInputElement>(null);
+
+  // 上传封面图
+  const handeUpPhoto = useCallback(
+    async (e: React.ChangeEvent<HTMLInputElement>) => {
+      if (e.target.files) {
+        // 拿到files信息
+        const filesInfo = e.target.files[0];
+        // 校验格式
+        const type = ["image/jpeg", "image/png"];
+        if (!type.includes(filesInfo.type)) {
+          e.target.value = "";
+          return MessageFu.warning("只支持jpg、png格式!");
+        }
+        // 校验大小
+        if (filesInfo.size > 20 * 1024 * 1024) {
+          e.target.value = "";
+          return MessageFu.warning("最大支持20M!");
+        }
+        // 创建FormData对象
+        const fd = new FormData();
+        // 把files添加进FormData对象(‘photo’为后端需要的字段)
+        fd.append("type", "thumb");
+        fd.append("dirCode", dirCode);
+        fd.append("file", filesInfo);
+
+        e.target.value = "";
+
+        try {
+          const res = await goodsUploadAPI(fd);
+          if (res.code === 0) {
+            MessageFu.success("上传成功!");
+            setCover(res.data.filePath);
+          }
+          fileDomInitialFu();
+        } catch (error) {
+          fileDomInitialFu();
+        }
+      }
+    },
+    [dirCode]
+  );
+
+  // 选中附件类型
+  const [typeCheck, setTypeCheck] = useState<any>(["model"]);
+  const [typeOk, setTypeOk] = useState(false);
+
+  const typeCheckArr = useMemo(() => {
+    return [
+      { label: "模型", value: "model" },
+      { label: "图片", value: "img" },
+      { label: "音频", value: "audio" },
+      { label: "视频", value: "video" },
+    ];
+  }, []);
+
+  // 附件信息的校验
+
+  const fileCheckFu = useMemo(() => {
+    let flag = false;
+    if (typeCheck.length === 0) flag = true;
+    if (typeCheck.includes("model") && !fileList.model.id) flag = true;
+    if (typeCheck.includes("img") && fileImgList.length === 0) flag = true;
+    if (typeCheck.includes("audio") && !fileList.audio.id) flag = true;
+    if (typeCheck.includes("video") && !fileList.video.id) flag = true;
+    return flag;
+  }, [
+    fileImgList.length,
+    fileList.audio.id,
+    fileList.model.id,
+    fileList.video.id,
+    typeCheck,
+  ]);
+
+  // 点击上传附件按钮
+  const myInput2 = useRef<HTMLInputElement>(null);
+
+  const [fileOneType, setFileOneType] = useState("");
+
+  useEffect(() => {
+    if (fileOneType) myInput2.current?.click();
+  }, [fileOneType]);
+
+  const upFileFu = useCallback((type: string) => {
+    setFileOneType("");
+    window.setTimeout(() => {
+      setFileOneType(type);
+    }, 100);
+  }, []);
+
+  // 上传附件的处理函数
+  const handeUpPhoto2 = useCallback(
+    async (e: React.ChangeEvent<HTMLInputElement>) => {
+      if (e.target.files) {
+        // 拿到files信息
+        const filesInfo = e.target.files[0];
+
+        let anType = ["image/jpeg", "image/png", "image/gif"];
+        let anTit1 = "只支持png、jpg、gif和jpeg格式!";
+        let anTit2 = "最大支持20M!";
+        let anSize = 20 * 1024 * 1024;
+
+        if (fileOneType === "audio") {
+          anType = ["audio/mpeg"];
+          anTit1 = "只支持mp3格式!";
+          anTit2 = "最大支持10M!";
+          anSize = 10 * 1024 * 1024;
+        } else if (fileOneType === "video") {
+          anType = ["video/mp4"];
+          anTit1 = "只支持mp4格式!";
+          anTit2 = "最大支持500M!";
+          anSize = 500 * 1024 * 1024;
+        } else if (fileOneType === "model") {
+          anType = [""];
+          anTit1 = "只支持4dage格式!";
+          anTit2 = "最大支持500M!";
+          anSize = 500 * 1024 * 1024;
+        }
+
+        // 校验格式
+        if (fileOneType !== "model") {
+          if (!anType.includes(filesInfo.type)) {
+            e.target.value = "";
+            return MessageFu.warning(anTit1);
+          }
+        } else {
+          if (!filesInfo.name.includes(".4dage")) {
+            e.target.value = "";
+            return MessageFu.warning(anTit1);
+          }
+        }
+
+        // 校验大小
+        if (filesInfo.size > anSize) {
+          e.target.value = "";
+          return MessageFu.warning(anTit2);
+        }
+        // 创建FormData对象
+        const fd = new FormData();
+        // 把files添加进FormData对象(‘photo’为后端需要的字段)
+        fd.append("type", fileOneType);
+        fd.append("dirCode", dirCode);
+        fd.append("file", filesInfo);
+
+        e.target.value = "";
+
+        try {
+          const res = await goodsUploadAPI(fd);
+
+          if (res.code === 0) {
+            MessageFu.success("上传成功!");
+            if (fileOneType === "img")
+              setFileImgList([...fileImgList, res.data]);
+            else setFileList({ ...fileList, [fileOneType]: res.data });
+          }
+          fileDomInitialFu();
+        } catch (error) {
+          fileDomInitialFu();
+        }
+      }
+    },
+    [dirCode, fileImgList, fileList, fileOneType]
+  );
+
+  // 附近图片列表删除某一张图片
+  const delImgListFu = useCallback(
+    (id: number) => {
+      const newItems = fileImgList.filter((v) => v.id !== id);
+      setFileImgList(newItems);
+    },
+    [fileImgList]
+  );
+
+  // 没有通过校验
+  const onFinishFailed = useCallback(() => {
+    setCoverCheck(true);
+    setTypeOk(true);
+    return MessageFu.warning("有表单不符号规则!");
+  }, []);
+
+  // 通过校验点击确定
+  const onFinish = useCallback(
+    async (value: GoodsTableType) => {
+      console.log("通过校验,点击确定");
+      setCoverCheck(true);
+      setTypeOk(true);
+      if (typeCheck.length === 0 || cover === "" || fileCheckFu)
+        return MessageFu.warning("有表单不符号规则!");
+
+      const fileIds = [];
+      if (fileList.model.id && typeCheck.includes("model"))
+        fileIds.push(fileList.model.id);
+      if (fileList.audio.id && typeCheck.includes("audio"))
+        fileIds.push(fileList.audio.id);
+      if (fileList.video.id && typeCheck.includes("video"))
+        fileIds.push(fileList.video.id);
+      if (typeCheck.includes("img")) {
+        fileImgList.forEach((v) => {
+          if (v.id) fileIds.push(v.id);
+        });
+      }
+      // 简介的处理
+      const txt = value.description.replaceAll(" ", "").replaceAll("\n", "");
+
+      const obj = {
+        ...value,
+        id: id > 0 ? id : null,
+        dirCode,
+        fileIds: fileIds.join(","),
+        thumb: cover,
+        type: typeCheck.join(","),
+        description: txt ? value.description : "",
+      } as GoodsTableType;
+      const res = await getGoodsSaveAPI(obj);
+      if (res.code === 0) {
+        MessageFu.success(id > 0 ? "编辑成功!" : "新增成功!");
+        closeMoalFu();
+        if (id > 0) editListFu();
+        else addListFu();
+      }
+    },
+    [
+      typeCheck,
+      cover,
+      fileCheckFu,
+      fileList.model.id,
+      fileList.audio.id,
+      fileList.video.id,
+      id,
+      dirCode,
+      fileImgList,
+      closeMoalFu,
+      editListFu,
+      addListFu,
+    ]
+  );
+
+  return (
+    <div className={styles.GoodsAdd}>
+      <div className="main mySorrl">
+        <Form
+          ref={FormBoxRef}
+          name="basic"
+          labelCol={{ span: 3 }}
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}
+          autoComplete="off"
+        >
+          <Form.Item
+            label="名称"
+            name="name"
+            rules={[{ required: true, message: "请输入名称!" }]}
+            getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
+          >
+            <Input maxLength={25} showCount placeholder="请输入内容" />
+          </Form.Item>
+
+          <Form.Item
+            label="登记编号"
+            name="num"
+            getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
+          >
+            <Input maxLength={25} showCount placeholder="请输入内容" />
+          </Form.Item>
+
+          <Form.Item
+            label="类别"
+            name="dictTexture"
+            rules={[{ required: true, message: "请选择类别!" }]}
+          >
+            <Select
+              placeholder="请选择"
+              style={{ width: 400 }}
+              options={dictList["texture"].slice(1)}
+            />
+          </Form.Item>
+
+          <Form.Item
+            label="年代"
+            name="dictAge"
+            rules={[{ required: true, message: "请选择年代!" }]}
+          >
+            <Select
+              placeholder="请选择"
+              style={{ width: 400 }}
+              options={dictList["age"].slice(1)}
+            />
+          </Form.Item>
+
+          <Form.Item
+            label="级别"
+            name="dictLevel"
+            rules={[{ required: true, message: "请选择级别!" }]}
+          >
+            <Select
+              placeholder="请选择"
+              style={{ width: 400 }}
+              options={dictList["level"].slice(1)}
+            />
+          </Form.Item>
+
+          <Form.Item
+            label="来源"
+            name="dictSource"
+            rules={[{ required: true, message: "请选择来源!" }]}
+          >
+            <Select
+              placeholder="请选择"
+              style={{ width: 400 }}
+              options={dictList["source"].slice(1)}
+            />
+          </Form.Item>
+
+          <Form.Item
+            label="简介"
+            name="description"
+            // getValueFromEvent={(e) => e.target.value.trim()}
+          >
+            <TextArea
+              autoSize
+              placeholder="请输入内容"
+              showCount
+              maxLength={200}
+            />
+          </Form.Item>
+
+          {/* -----上传封面图片 */}
+          <div className="myformBox myformBox0">
+            <input
+              id="upInput"
+              type="file"
+              accept=".png,.jpg,.jpeg"
+              ref={myInput}
+              onChange={(e) => handeUpPhoto(e)}
+            />
+            <input
+              id="upInput2"
+              type="file"
+              accept={
+                fileOneType === "img"
+                  ? ".gif,.png,.jpg,.jpeg"
+                  : fileOneType === "audio"
+                  ? ".mp3"
+                  : fileOneType === "model"
+                  ? ".4dage"
+                  : ".mp4"
+              }
+              ref={myInput2}
+              onChange={(e) => handeUpPhoto2(e)}
+            />
+            <div className="label">
+              <span>*</span> 封面图:
+            </div>
+            <div className="fileBoxRow_r">
+              <div
+                hidden={cover !== ""}
+                className="fileBoxRow_up"
+                onClick={() => myInput.current?.click()}
+              >
+                <PlusOutlined />
+              </div>
+              <div className="fileBoxRow_r_img" hidden={cover === ""}>
+                {cover ? (
+                  <ImageLazy width={100} height={100} src={cover} noLook />
+                ) : null}
+
+                <div className="clearCover2">
+                  {/* 封面图预览 删除 下载 */}
+                  <div className="clearCover2DelBox">
+                    <Popconfirm
+                      title="删除后无法恢复,是否删除?"
+                      okText="删除"
+                      cancelText="取消"
+                      onConfirm={() => setCover("")}
+                    >
+                      <CloseOutlined />
+                    </Popconfirm>
+                  </div>
+
+                  <div className="clearCover2DLBox">
+                    <EyeOutlined
+                      onClick={() =>
+                        store.dispatch({
+                          type: "layout/lookBigImg",
+                          payload: { url: baseURL + cover, show: true },
+                        })
+                      }
+                    />
+                    <a
+                      href={baseURL + cover}
+                      download
+                      target="_blank"
+                      rel="noreferrer"
+                    >
+                      <DownloadOutlined />
+                    </a>
+                  </div>
+                </div>
+              </div>
+              <div className="fileBoxRow_r_tit">
+                支持png、jpg和jpeg的图片格式;最大支持20M。
+                <br />
+                <div
+                  className={classNames(
+                    "noUpThumb",
+                    !cover && coverCheck ? "noUpThumbAc" : ""
+                  )}
+                >
+                  请上传封面图!
+                </div>
+              </div>
+            </div>
+          </div>
+
+          {/* 选中文件类型和上传附件 */}
+          <div className="myformBox">
+            <div className="label">
+              <span>*</span> 文件类型:
+            </div>
+            <div className="myformBoxR">
+              <Checkbox.Group
+                options={typeCheckArr}
+                value={typeCheck}
+                onChange={(e) => setTypeCheck(e)}
+                // onChange={(e) => console.log(e)}
+              />
+            </div>
+          </div>
+
+          {/* -----------模型上传 */}
+          <div
+            className="myformBox myformBox2"
+            hidden={!typeCheck.includes("model")}
+          >
+            <div className="label">
+              <span>*</span> 模型:
+            </div>
+            {fileList.model.id ? (
+              <div className="fileInfo">
+                {fileList.model.fileName}
+                {/* 模型预览 */}
+                <div
+                  className="clearCover"
+                  onClick={() =>
+                    store.dispatch({
+                      type: "layout/lookDom",
+                      payload: { src: fileList.model.filePath!, type: "model" },
+                    })
+                  }
+                >
+                  <EyeOutlined />
+                </div>
+                {/* 模型下载 */}
+                <a
+                  href={baseURL + fileList.model.filePath}
+                  download
+                  target="_blank"
+                  className="clearCover"
+                  rel="noreferrer"
+                >
+                  <DownloadOutlined />
+                </a>
+                {/* 模型删除 */}
+                <Popconfirm
+                  title="删除后无法恢复,是否删除?"
+                  okText="删除"
+                  cancelText="取消"
+                  onConfirm={() => setFileList({ ...fileList, model: {} })}
+                >
+                  <div className="clearCover">
+                    <CloseOutlined />
+                  </div>
+                </Popconfirm>
+              </div>
+            ) : (
+              <>
+                <Button
+                  onClick={() => upFileFu("model")}
+                  icon={<UploadOutlined />}
+                >
+                  上传
+                </Button>
+
+                <div className="fileTit">
+                  仅支持4dage格式的模型文件,大小不能超过500M。
+                </div>
+              </>
+            )}
+          </div>
+
+          {/* -----------30张图片上传 */}
+          <div
+            className="myformBox myformBox3"
+            hidden={!typeCheck.includes("img")}
+          >
+            <div className="label">
+              <span>*</span> 图片:
+            </div>
+            <>
+              <div className="fileBoxRow_r">
+                <div className="upImgBox">
+                  <div
+                    hidden={!!fileImgList.length && fileImgList.length >= 30}
+                    className="fileBoxRow_up"
+                    onClick={() => upFileFu("img")}
+                  >
+                    <PlusOutlined />
+                  </div>
+
+                  <ReactSortable
+                    className="fileImgListBox"
+                    list={fileImgList}
+                    setList={setFileImgList}
+                  >
+                    {fileImgList.map((v, i) => (
+                      <div className="fileBoxRow_r_img" key={v.id}>
+                        {v.filePath ? (
+                          <ImageLazy
+                            noLook
+                            width={100}
+                            height={100}
+                            src={v.filePath}
+                          />
+                        ) : null}
+
+                        <Popconfirm
+                          title="删除后无法恢复,是否删除?"
+                          okText="删除"
+                          cancelText="取消"
+                          onConfirm={() => delImgListFu(v.id!)}
+                        >
+                          <div className="clearCover">
+                            <CloseOutlined />
+                          </div>
+                        </Popconfirm>
+                        {/* 下面的预览和下载 */}
+                        <div className="fileImgListLDBox">
+                          <EyeOutlined
+                            onClick={() =>
+                              store.dispatch({
+                                type: "layout/lookBigImg",
+                                payload: {
+                                  url: baseURL + v.filePath,
+                                  show: true,
+                                },
+                              })
+                            }
+                          />
+                          <a
+                            href={baseURL + v.filePath}
+                            download
+                            target="_blank"
+                            rel="noreferrer"
+                          >
+                            <DownloadOutlined />
+                          </a>
+                        </div>
+                      </div>
+                    ))}
+                  </ReactSortable>
+                </div>
+                <div className="fileTit">
+                  {fileImgList.length && fileImgList.length >= 2 ? (
+                    <>
+                      按住鼠标可拖动图片调整顺序。
+                      <br />
+                    </>
+                  ) : null}
+                  支持png、jpg、gif和jpeg的图片格式;最大支持20M;最多支持30张。
+                </div>
+              </div>
+            </>
+          </div>
+
+          {/* -----------音频上传 */}
+          <div
+            className="myformBox myformBox2"
+            hidden={!typeCheck.includes("audio")}
+          >
+            <div className="label">
+              <span>*</span> 音频:
+            </div>
+            {fileList.audio.id ? (
+              <div className="fileInfo">
+                {fileList.audio.fileName}
+                {/* 音频预览 */}
+                <div
+                  className="clearCover"
+                  onClick={() =>
+                    store.dispatch({
+                      type: "layout/lookDom",
+                      payload: { src: fileList.audio.filePath!, type: "audio" },
+                    })
+                  }
+                >
+                  <EyeOutlined />
+                </div>
+                {/* 音频下载 */}
+                <a
+                  href={baseURL + fileList.audio.filePath}
+                  download
+                  target="_blank"
+                  className="clearCover"
+                  rel="noreferrer"
+                >
+                  <DownloadOutlined />
+                </a>
+                {/* 音频删除 */}
+                <Popconfirm
+                  title="删除后无法恢复,是否删除?"
+                  okText="删除"
+                  cancelText="取消"
+                  onConfirm={() => setFileList({ ...fileList, audio: {} })}
+                >
+                  <div className="clearCover">
+                    <CloseOutlined />
+                  </div>
+                </Popconfirm>
+              </div>
+            ) : (
+              <>
+                <Button
+                  onClick={() => upFileFu("audio")}
+                  icon={<UploadOutlined />}
+                >
+                  上传
+                </Button>
+
+                <div className="fileTit">
+                  仅支持MP3格式的音频文件,大小不得超过10MB。
+                </div>
+              </>
+            )}
+          </div>
+
+          {/* -----------视频上传 */}
+          <div
+            className="myformBox myformBox2"
+            hidden={!typeCheck.includes("video")}
+          >
+            <div className="label">
+              <span>*</span> 视频:
+            </div>
+            {fileList.video.id ? (
+              <div className="fileInfo">
+                <div className="upSuccTxt">{fileList.video.fileName}</div>
+                {/* 视频预览 */}
+                <div
+                  className="clearCover"
+                  hidden={!fileList.video.filePath}
+                  onClick={() =>
+                    store.dispatch({
+                      type: "layout/lookDom",
+                      payload: { src: fileList.video.filePath!, type: "video" },
+                    })
+                  }
+                >
+                  <EyeOutlined />
+                </div>
+                {/* 视频下载 */}
+                <a
+                  href={baseURL + fileList.video.filePath}
+                  download
+                  target="_blank"
+                  className="clearCover"
+                  rel="noreferrer"
+                >
+                  <DownloadOutlined />
+                </a>
+                <Popconfirm
+                  title="删除后无法恢复,是否删除?"
+                  okText="删除"
+                  cancelText="取消"
+                  onConfirm={() => setFileList({ ...fileList, video: {} })}
+                >
+                  <div className="clearCover">
+                    <CloseOutlined />
+                  </div>
+                </Popconfirm>
+              </div>
+            ) : (
+              <>
+                <Button
+                  onClick={() => upFileFu("video")}
+                  icon={<UploadOutlined />}
+                >
+                  上传
+                </Button>
+
+                <div className="fileTit">
+                  仅支持MP4格式的视频文件,大小不得超过500MB。
+                </div>
+              </>
+            )}
+          </div>
+
+          <div
+            className={classNames(
+              "noUpThumb noUpThumb2",
+              fileCheckFu && typeOk ? "noUpThumbAc" : ""
+            )}
+          >
+            请至少选择一个文件类型,并上传对应附件!
+          </div>
+
+          {/* 确定和取消按钮 */}
+          <br />
+          <Form.Item wrapperCol={{ offset: 9, span: 16 }}>
+            <Button type="primary" htmlType="submit">
+              提交
+            </Button>
+            &emsp;
+            <Popconfirm
+              title="放弃编辑后,信息将不会保存!"
+              okText="放弃"
+              cancelText="取消"
+              onConfirm={closeMoalFu}
+            >
+              <Button>取消</Button>
+            </Popconfirm>
+          </Form.Item>
+        </Form>
+      </div>
+    </div>
+  );
+}
+
+const MemoGoodsAdd = React.memo(GoodsAdd);
+
+export default MemoGoodsAdd;

+ 48 - 3
管理后台/src/pages/A1Goods/index.module.scss

@@ -1,5 +1,50 @@
-.A1Goods{
-  :global{
-    
+.A1Goods {
+  position: relative;
+
+  :global {
+    .goodsTop {
+      border-radius: 10px;
+      background-color: #fff;
+    }
+
+    .searchBox {
+      padding: 12px 24px 0;
+      display: flex;
+      flex-wrap: wrap;
+      position: relative;
+      width: 1100px;
+
+      .searchRow {
+        margin-bottom: 15px;
+        margin-right: 20px;
+      }
+
+      .searchRow2 {
+        position: absolute;
+        right: 65px;
+        bottom: 15px;
+
+      }
+    }
+
+    .tableBox {
+      border-radius: 10px;
+      overflow: hidden;
+      margin-top: 15px;
+      height: calc(100% - 114px);
+      background-color: #fff;
+
+      .ant-table-body {
+        height: 586px;
+        overflow-y: auto !important;
+        overflow-y: overlay !important;
+
+        .ant-table-row {
+          .ant-table-cell {
+            padding: 8px;
+          }
+        }
+      }
+    }
   }
 }

+ 363 - 5
管理后台/src/pages/A1Goods/index.tsx

@@ -1,12 +1,370 @@
-import React from "react";
+import { RootState } from "@/store";
+import { getGoodsListAPI, goodsRemoveAPI } from "@/store/action/A1Goods";
+import { MessageFu } from "@/utils/message";
+import { Input, Select, DatePicker, Button, Table, Popconfirm } from "antd";
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
+import { useDispatch, useSelector } from "react-redux";
 import styles from "./index.module.scss";
- function A1Goods() {
-  
+import ImageLazy from "@/components/ImageLazy";
+import { GoodsTableType } from "@/types";
+import GoodsAdd from "./GoodsAdd";
+
+const { RangePicker } = DatePicker;
+function A1Goods() {
+  const dispatch = useDispatch();
+
+  // 从仓库获取下拉列表数据
+  const dictList = useSelector((state: RootState) => state.A0Layout.dictList);
+
+  // 从仓库获取表格列表信息
+  const tableInfo = useSelector((state: RootState) => state.A1Goods.tableInfo);
+
+  // 顶部筛选
+  const [tableSelect, setTableSelect] = useState({
+    searchKey: "",
+    num: "",
+    dictTexture: "",
+    dictAge: "",
+    level: "",
+    source: "",
+    startTime: "",
+    endTime: "",
+    pageSize: 10,
+    pageNum: 1,
+  });
+
+  // 封装发送请求的函数
+
+  const getList = useCallback(async () => {
+    const data = {
+      ...tableSelect,
+    };
+    dispatch(getGoodsListAPI(data));
+  }, [dispatch, tableSelect]);
+
+  useEffect(() => {
+    getList();
+  }, [getList]);
+
+  // 名称的输入
+  const nameTime = useRef(-1);
+  const nameChange = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>) => {
+      clearTimeout(nameTime.current);
+      nameTime.current = window.setTimeout(() => {
+        setTableSelect({
+          ...tableSelect,
+          searchKey: e.target.value,
+          pageNum: 1,
+        });
+      }, 500);
+    },
+    [tableSelect]
+  );
+
+  // 登记编号的输入
+  const numTime = useRef(-1);
+  const numChange = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>) => {
+      clearTimeout(numTime.current);
+      numTime.current = window.setTimeout(() => {
+        setTableSelect({
+          ...tableSelect,
+          num: e.target.value,
+          pageNum: 1,
+        });
+      }, 500);
+    },
+    [tableSelect]
+  );
+
+  // 时间选择器改变
+  const timeChange = (date: any, dateString: any) => {
+    let startTime = "";
+    let endTime = "";
+    if (dateString[0] && dateString[1]) {
+      startTime = dateString[0] + " 00:00:00";
+      endTime = dateString[1] + " 23:59:59";
+    }
+    setTableSelect({ ...tableSelect, startTime, endTime, pageNum: 1 });
+  };
+
+  // 点击重置
+  const [inputKey, setInputKey] = useState(1);
+  const resetSelectFu = useCallback(() => {
+    // 把2个输入框和时间选择器清空
+    setInputKey(Date.now());
+    setTableSelect({
+      searchKey: "",
+      num: "",
+      dictTexture: "",
+      dictAge: "",
+      level: "",
+      source: "",
+      startTime: "",
+      endTime: "",
+      pageSize: 10,
+      pageNum: 1,
+    });
+  }, []);
+
+  // ----------关于表格的数据
+
+  // 页码变化
+  const paginationChange = useCallback(
+    () => (pageNum: number, pageSize: number) => {
+      setTableSelect({ ...tableSelect, pageNum, pageSize });
+    },
+    [tableSelect]
+  );
+
+  // 点击删除
+  const delTableFu = useCallback(
+    async (id: number) => {
+      const res = await goodsRemoveAPI(id);
+      if (res.code === 0) {
+        MessageFu.success("删除成功!");
+        getList();
+      }
+    },
+    [getList]
+  );
+
+  // 点击 新增/编辑/查看
+  const openAddPageFu = useCallback((id: number, flag?: boolean) => {
+    if (flag) setLookFlag(true);
+    else setLookFlag(false);
+    setAddId(id);
+  }, []);
+
+  const columns = useMemo(() => {
+    return [
+      {
+        title: "名称",
+        dataIndex: "name",
+      },
+
+      {
+        title: "类别",
+        dataIndex: "dictTexture",
+      },
+      {
+        title: "年代",
+        dataIndex: "dictAge",
+      },
+      {
+        title: "简介",
+        render: (item: GoodsTableType) =>
+          item.description ? (
+            item.description.length >= 25 ? (
+              <span style={{ cursor: "pointer" }} title={item.description}>
+                {item.description.substring(0, 25) + "..."}
+              </span>
+            ) : (
+              item.description
+            )
+          ) : (
+            "(空)"
+          ),
+      },
+      {
+        title: "图片",
+        render: (item: GoodsTableType) => (
+          <div className="tableImgAuto">
+            <ImageLazy width={60} height={60} src={item.thumb!} />
+          </div>
+        ),
+      },
+      {
+        title: "最近编辑时间",
+        dataIndex: "updateTime",
+      },
+
+      {
+        title: "操作",
+        render: (item: GoodsTableType) => (
+          <>
+            <Button
+              size="small"
+              type="text"
+              onClick={() => openAddPageFu(item.id, true)}
+            >
+              查看
+            </Button>
+
+            <Button
+              size="small"
+              type="text"
+              onClick={() => openAddPageFu(item.id)}
+            >
+              编辑
+            </Button>
+            <Popconfirm
+              title="删除后无法恢复,是否删除?"
+              okText="删除"
+              cancelText="取消"
+              onConfirm={() => delTableFu(item.id!)}
+            >
+              <Button size="small" type="text" danger>
+                删除
+              </Button>
+            </Popconfirm>
+          </>
+        ),
+      },
+    ];
+  }, [delTableFu, openAddPageFu]);
+
+  // 新增或者编辑的弹窗
+  const [addId, setAddId] = useState(0);
+  // 查看馆藏的参数
+  const [lookFlag, setLookFlag] = useState(false);
+
   return (
     <div className={styles.A1Goods}>
-      <h1>A1Goods</h1>
+      <div className="pageTitle">
+        {lookFlag
+          ? "查看馆藏"
+          : addId === 0
+          ? "馆藏管理"
+          : addId > 0
+          ? "编辑馆藏"
+          : "新增馆藏"}
+      </div>
+      <div className="goodsTop">
+        {/* 搜索信息 */}
+        <div className="searchBox">
+          <div className="searchRow">
+            <span>名称:</span>
+            <Input
+              key={inputKey}
+              maxLength={25}
+              style={{ width: 240 }}
+              placeholder="请输入关键字"
+              allowClear
+              onChange={(e) => nameChange(e)}
+            />
+          </div>
+
+          <div className="searchRow">
+            <span>登记编号:</span>
+            <Input
+              key={inputKey}
+              maxLength={25}
+              style={{ width: 240 }}
+              placeholder="请输入关键字"
+              allowClear
+              onChange={(e) => numChange(e)}
+            />
+          </div>
+
+          <div className="searchRow">
+            <span>最近编辑日期:</span>
+            <RangePicker
+              style={{ width: 280 }}
+              key={inputKey}
+              onChange={timeChange}
+            />
+          </div>
+
+          <div className="searchRow">
+            <span>类别:</span>
+            <Select
+              placeholder="请选择"
+              style={{ width: 140 }}
+              value={tableSelect.dictTexture}
+              onChange={(e) =>
+                setTableSelect({ ...tableSelect, dictTexture: e, pageNum: 1 })
+              }
+              options={dictList["texture"]}
+            />
+          </div>
+
+          <div className="searchRow">
+            <span>年代:</span>
+            <Select
+              placeholder="请选择"
+              style={{ width: 140 }}
+              value={tableSelect.dictAge}
+              onChange={(e) =>
+                setTableSelect({ ...tableSelect, dictAge: e, pageNum: 1 })
+              }
+              options={dictList["age"]}
+            />
+          </div>
+
+          <div className="searchRow">
+            <span>级别:</span>
+            <Select
+              placeholder="请选择"
+              style={{ width: 140 }}
+              value={tableSelect.level}
+              onChange={(e) =>
+                setTableSelect({ ...tableSelect, level: e, pageNum: 1 })
+              }
+              options={dictList["level"]}
+            />
+          </div>
+
+          <div className="searchRow">
+            <span>来源:</span>
+            <Select
+              placeholder="请选择"
+              style={{ width: 140 }}
+              value={tableSelect.source}
+              onChange={(e) =>
+                setTableSelect({ ...tableSelect, source: e, pageNum: 1 })
+              }
+              options={dictList["source"]}
+            />
+          </div>
+
+          <div className="searchRow2">
+            <Button onClick={resetSelectFu}>重置</Button>
+            &emsp;&emsp;
+            <Button type="primary" onClick={() => openAddPageFu(-1)}>
+              新增
+            </Button>
+          </div>
+        </div>
+      </div>
+      {/* 表格主体 */}
+      <div className="tableBox">
+        <Table
+          scroll={{ y: 586 }}
+          dataSource={tableInfo.list}
+          columns={columns}
+          rowKey="id"
+          pagination={{
+            showQuickJumper: true,
+            position: ["bottomCenter"],
+            showSizeChanger: true,
+            current: tableSelect.pageNum,
+            pageSize: tableSelect.pageSize,
+            total: tableInfo.total,
+            onChange: paginationChange(),
+          }}
+        />
+      </div>
+
+      {/* 新增和编辑的弹窗 */}
+      {addId !== 0 ? (
+        <GoodsAdd
+          id={addId}
+          closeMoalFu={() => openAddPageFu(0)}
+          addListFu={resetSelectFu}
+          editListFu={getList}
+          lookFlag={lookFlag}
+        />
+      ) : null}
     </div>
-  )
+  );
 }
 
 const MemoA1Goods = React.memo(A1Goods);

+ 3 - 4
管理后台/src/pages/A5Log/index.module.scss

@@ -1,12 +1,11 @@
 .A5Log {
   :global {
     .logTop {
-      margin-top: 15px;
       border-radius: 10px;
       background-color: #fff;
 
       .tableSelectBox {
-        padding: 20px 24px;
+        padding: 15px 24px;
         display: flex;
         align-items: center;
 
@@ -19,11 +18,11 @@
     .tableMain {
       border-radius: 10px;
       margin-top: 15px;
-      height: calc(100% - 104px);
+      height: calc(100% - 70px);
       background-color: #fff;
 
       .ant-table-body {
-        height: 608px;
+        height: 630px;
         overflow-y: auto !important;
         overflow-y: overlay !important;
 

+ 2 - 2
管理后台/src/pages/A5Log/index.tsx

@@ -90,7 +90,7 @@ function A5Log() {
 
   return (
     <div className={styles.A5Log}>
-      <div className="pageTitlt">操作日志</div>
+      <div className="pageTitle">操作日志</div>
       <div className="logTop">
         <div className="tableSelectBox">
           <div className="row">
@@ -113,7 +113,7 @@ function A5Log() {
       {/* 表格主体 */}
       <div className="tableMain">
         <Table
-          scroll={{ y: 608 }}
+          scroll={{ y: 630 }}
           dataSource={results.list}
           columns={columns}
           rowKey="id"

+ 19 - 37
管理后台/src/pages/Layout/index.module.scss

@@ -10,15 +10,18 @@
       z-index: 30;
       width: 220px;
       height: 100%;
-      box-shadow: 0px 0px 5px 3px;
-      background-image: url('../../assets/img/layoutLeftMain.jpg');
-      background-size: 100% 100%;
+      background-color: #131c28;
+
 
       .layoutLeftTop {
         height: 60px;
-        background-color: var(--themeColor);
-        padding: 10px;
-        padding-left: 20px;
+        color: #fff;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        &>h3{
+          margin-left: 15px;
+        }
       }
 
       .layoutLeftMain {
@@ -35,7 +38,8 @@
           position: relative;
           margin-top: 25px;
           border-radius: 8px;
-          color: var(--themeColor);
+          color: #fff;
+          opacity: .6;
 
           .tabImg {
             z-index: 3;
@@ -46,35 +50,14 @@
             width: 20px;
           }
 
-          .tabImgAc {
-            z-index: 3;
-            position: absolute;
-            top: 50%;
-            left: 20px;
-            transform: translateY(-50%);
-            width: 20px;
-            display: none;
-          }
-
           &:hover {
-            color: #fff;
-            background-color: var(--themeColor);
-
-            .tabImgAc {
-              display: block;
-            }
+            opacity: 1;
           }
         }
 
-
-
         .active {
-          color: #fff;
           pointer-events: none;
-          background-color: var(--themeColor);
-          .tabImgAc {
-            display: block;
-          }
+          opacity: 1;
         }
       }
 
@@ -88,7 +71,6 @@
 
       .layoutRightTop {
         height: 60px;
-        background-color: var(--themeColor);
         display: flex;
         justify-content: flex-end;
         position: relative;
@@ -105,11 +87,11 @@
           background: url('../../assets/img/user.png') no-repeat left center;
           background-size: 40px 40px;
           font-size: 16px;
-          color: #fff;
+          color: black;
 
           .userInco {
             margin-left: 10px;
-            color: #fff;
+            color: black;
           }
 
           .userInco1 {
@@ -172,13 +154,13 @@
       .layoutRightMain {
         height: calc(100% - 60px);
         padding: 15px 30px 20px;
-        background-image: url('../../assets/img/loginBox.jpg');
-        background-size: 100% 100%;
-
+        background-color: #ecedf1;
         .mainBoxR {
           width: 100%;
           height: 100%;
-          overflow: hidden;
+          // overflow: hidden;
+          position: relative;
+
           &>div {
             width: 100%;
             height: 100%;

+ 2 - 1
管理后台/src/pages/Layout/index.tsx

@@ -23,7 +23,7 @@ import inco2 from "@/assets/img/inco2.png";
 import inco3 from "@/assets/img/inco3.png";
 import inco4 from "@/assets/img/inco4.png";
 import inco5 from "@/assets/img/inco5.png";
-import logonImg from "@/assets/img/logo2.png";
+import logonImg from "@/assets/img/logo.png";
 import { MessageFu } from "@/utils/message";
 
 const NotFound = React.lazy(() => import("@/components/NotFound"));
@@ -138,6 +138,7 @@ function Layout() {
       <div className="layoutLeft">
         <div className="layoutLeftTop">
           <img src={logonImg} alt="" />
+          <h3>盐亭县博物馆</h3>
         </div>
         {/* 左边主体 */}
         <div className="layoutLeftMain">

+ 71 - 0
管理后台/src/store/action/A1Goods.ts

@@ -0,0 +1,71 @@
+import { GoodsTableType } from "@/types";
+import { domShowFu, progressDomFu } from "@/utils/domShow";
+import http from "@/utils/http";
+import axios from "axios";
+import store, { AppDispatch } from "..";
+/**
+ * 获取列表数据
+ */
+export const getGoodsListAPI = (data: any) => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post("cms/goods/pageList", data);
+    if (res.code === 0) {
+      dispatch({
+        type: "goods/getList",
+        payload: { list: res.data.records, total: res.data.total },
+      });
+    }
+  };
+};
+
+/**
+ * 内容-是否显示
+ */
+export const goodsDisplayAPI = (id: number, display: number) => {
+  return http.get(`cms/goods/display/${id}/${display}`);
+};
+
+/**
+ * 删除藏品
+ */
+export const goodsRemoveAPI = (id: number) => {
+  return http.get(`cms/goods/remove/${id}`);
+};
+
+const CancelToken = axios.CancelToken;
+/**
+ * 上传封面图和附件
+ */
+export const goodsUploadAPI = (data: any) => {
+  domShowFu("#UpAsyncLoding", true);
+
+  return http.post("cms/goods/upload", data, {
+    timeout: 0,
+    // 显示进度条
+    onUploadProgress: (e: any) => {
+      const complete = (e.loaded / e.total) * 100 || 0;
+      progressDomFu(complete + "%");
+    },
+    // 取消上传
+    cancelToken: new CancelToken(function executor(c) {
+      store.dispatch({
+        type: "layout/closeUpFile",
+        payload: { fu: c, state: true },
+      });
+    }),
+  });
+};
+
+/**
+ * 新增|编辑
+ */
+export const getGoodsSaveAPI = (data: GoodsTableType) => {
+  return http.post("cms/goods/save", data);
+};
+
+/**
+ * 通过id获取详情
+ */
+export const getGoodsInfoByIdAPI = (id: number) => {
+  return http.get(`cms/goods/detail/${id}`);
+};

+ 2 - 0
管理后台/src/store/action/layout.ts

@@ -27,6 +27,8 @@ export const getDictListAPI = () => {
       const obj = {
         age: [{ label: "全部", value: "", type: "age" }],
         texture: [{ label: "全部", value: "", type: "texture" }],
+        level: [{ label: "全部", value: "", type: "level" }],
+        source: [{ label: "全部", value: "", type: "source" }],
       } as DictListTypeObj;
       list.forEach((v) => {
         if (obj[v.type])

+ 27 - 0
管理后台/src/store/reducer/A1Goods.ts

@@ -0,0 +1,27 @@
+import { GoodsTableType } from "@/types";
+
+// 初始化状态
+const initState = {
+  // 列表数据
+  tableInfo: {
+    list: [] as GoodsTableType[],
+    total: 0,
+  },
+};
+
+// 定义 action 类型
+type Props = {
+  type: "goods/getList";
+  payload: { list: GoodsTableType[]; total: number };
+};
+
+// 频道 reducer
+export default function goodsReducer(state = initState, action: Props) {
+  switch (action.type) {
+    // 获取列表数据
+    case "goods/getList":
+      return { ...state, tableInfo: action.payload };
+    default:
+      return state;
+  }
+}

+ 4 - 2
管理后台/src/store/reducer/index.ts

@@ -3,12 +3,14 @@ import { combineReducers } from 'redux'
 
 
 // 导入 登录 模块的 reducer
-import A1Layout from './layout'
+import A0Layout from './layout'
+import A1Goods from './A1Goods'
 import A5Log from './A5Log'
 
 // 合并 reducer
 const rootReducer = combineReducers({
-  A1Layout,
+  A0Layout,
+  A1Goods,
   A5Log
 })
 

+ 12 - 6
管理后台/src/store/reducer/layout.ts

@@ -1,4 +1,4 @@
-import { DictListTypeObj } from "@/types";
+import { DictListTypeObj, LookDomType } from "@/types";
 import { MessageType } from "@/utils/message";
 
 // 初始化状态
@@ -8,13 +8,18 @@ const initState = {
     url: "",
     show: false,
   },
-  // 视频的src
-  videoSrc: "",
+  // 查看视频、音频、模型
+  lookDom: {
+    src: "",
+    type: "",
+  } as LookDomType,
 
   // 所有的下拉框数据
   dictList: {
     age: [],
     texture: [],
+    level: [],
+    source: [],
   } as DictListTypeObj,
 
   message: {
@@ -32,7 +37,7 @@ const initState = {
 // 定义 action 类型
 type LayoutActionType =
   | { type: "layout/lookBigImg"; payload: { url: string; show: boolean } }
-  | { type: "layout/lookVideo"; payload: string }
+  | { type: "layout/lookDom"; payload: LookDomType }
   | { type: "layout/message"; payload: MessageType }
   | { type: "layout/getDictList"; payload: DictListTypeObj }
   | {
@@ -53,8 +58,9 @@ export default function layoutReducer(
     case "layout/lookBigImg":
       return { ...state, lookBigImg: action.payload };
     // 查看视频
-    case "layout/lookVideo":
-      return { ...state, videoSrc: action.payload };
+    case "layout/lookDom":
+      return { ...state, lookDom: action.payload };
+
     // 所有的下拉框数据
     case "layout/getDictList":
       return { ...state, dictList: action.payload };

+ 38 - 0
管理后台/src/types/api/A1Goods.d.ts

@@ -0,0 +1,38 @@
+export type GoodsTableType = {
+  createTime: string;
+  creatorId: number;
+  creatorName: string;
+  description: string;
+  dictAge: string;
+  dictLevel: string;
+  dictSource: string;
+  dictTexture: string;
+  dirCode: string;
+  display: number;
+  fileIds: string;
+  id: number;
+  isBarrage: number;
+  name: string;
+  num: string;
+  thumb: string;
+  topic: string;
+  type: string;
+  updateTime: string;
+  tagType?: string;
+  tagCountry?: string;
+};
+
+export type FileListType = {
+  fileName?: string;
+  filePath?: string;
+  id?: number;
+  isFrame?: boolean;
+  done?: boolean;
+  type?: "model" | "img" | "audio" | "video";
+};
+
+export type FileImgListType = {
+  id: number;
+  fileName: string;
+  filePath: string;
+}[];

+ 8 - 1
管理后台/src/types/api/layot.d.ts

@@ -2,6 +2,8 @@
 export type DictListTypeObj = {
   age: DictListType[];
   texture: DictListType[];
+  level: DictListType[];
+  source: DictListType[];
 };
 
 export type DictListTypeAPI = {
@@ -21,4 +23,9 @@ export type ImgListType = {
   fileName: string;
   filePath: string;
   id: number;
-};
+};
+
+export type LookDomType ={
+  src: string;
+  type: 'video'|'audio'|'model'|''
+}

+ 1 - 0
管理后台/src/types/index.d.ts

@@ -1,2 +1,3 @@
 export * from './api/layot'
 export * from './api/A5Log'
+export * from './api/A1Goods'

+ 1 - 1
管理后台/src/utils/domShow.ts

@@ -26,7 +26,7 @@ export const fileDomInitialFu = () => {
   progressDomFu("0%");
   // 初始化 上传附件 的状态
   setTimeout(() => {
-    if (store.getState().A1Layout.closeUpFile.state)
+    if (store.getState().A0Layout.closeUpFile.state)
       store.dispatch({
         type: "layout/closeUpFile",
         payload: { fu: () => {}, state: false },

+ 1 - 1
管理后台/src/utils/http.ts

@@ -79,7 +79,7 @@ http.interceptors.response.use(
       domShowFu("#AsyncSpinLoding", false);
       // 如果因为网络原因,response没有,给提示消息
       if (!err.response) {
-        if (store.getState().A1Layout.closeUpFile.state)
+        if (store.getState().A0Layout.closeUpFile.state)
           MessageFu.warning("取消上传!");
         else MessageFu.error("网络繁忙,请稍后重试!");
       } else MessageFu.error("响应错误,请联系管理员!");