shaogen1995 2 years ago
parent
commit
2294250968
40 changed files with 2077 additions and 92 deletions
  1. 318 0
      后台管理/package-lock.json
  2. 1 0
      后台管理/package.json
  3. BIN
      后台管理/src/assets/img/bg.jpg
  4. BIN
      后台管理/src/assets/img/bg.png
  5. BIN
      后台管理/src/assets/img/inco1.png
  6. BIN
      后台管理/src/assets/img/inco2.png
  7. BIN
      后台管理/src/assets/img/inco3.png
  8. BIN
      后台管理/src/assets/img/inco4.png
  9. BIN
      后台管理/src/assets/img/inco5.png
  10. BIN
      后台管理/src/assets/img/logo.png
  11. 2 1
      后台管理/src/assets/styles/base.css
  12. 2 1
      后台管理/src/assets/styles/base.less
  13. 1 1
      后台管理/src/index.tsx
  14. 26 0
      后台管理/src/pages/A1Order/A1Look/index.module.scss
  15. 92 0
      后台管理/src/pages/A1Order/A1Look/index.tsx
  16. 32 3
      后台管理/src/pages/A1Order/index.module.scss
  17. 376 5
      后台管理/src/pages/A1Order/index.tsx
  18. 133 0
      后台管理/src/pages/A2Gallery/A2Edit/index.module.scss
  19. 290 0
      后台管理/src/pages/A2Gallery/A2Edit/index.tsx
  20. 65 0
      后台管理/src/pages/A2Gallery/A2Modal/index.module.scss
  21. 233 0
      后台管理/src/pages/A2Gallery/A2Modal/index.tsx
  22. 31 0
      后台管理/src/pages/A2Gallery/index.module.scss
  23. 182 0
      后台管理/src/pages/A2Gallery/index.tsx
  24. 5 0
      后台管理/src/pages/A3Fliqlo/index.module.scss
  25. 13 0
      后台管理/src/pages/A3Fliqlo/index.tsx
  26. 1 1
      后台管理/src/pages/A4User/index.module.scss
  27. 1 1
      后台管理/src/pages/A5Log/index.module.scss
  28. 16 32
      后台管理/src/pages/Layout/index.module.scss
  29. 15 5
      后台管理/src/pages/Layout/index.tsx
  30. 44 31
      后台管理/src/pages/Login/index.module.scss
  31. 7 5
      后台管理/src/pages/Login/index.tsx
  32. 32 0
      后台管理/src/store/action/A1Order.ts
  33. 54 0
      后台管理/src/store/action/A2Gallery.ts
  34. 28 0
      后台管理/src/store/reducer/A1Order.ts
  35. 32 0
      后台管理/src/store/reducer/A2Gallery.ts
  36. 4 0
      后台管理/src/store/reducer/index.ts
  37. 13 0
      后台管理/src/types/api/A1Order.d.ts
  38. 20 0
      后台管理/src/types/api/A2Gallery.ts
  39. 2 0
      后台管理/src/types/index.d.ts
  40. 6 6
      后台管理/src/utils/http.ts

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

@@ -21,6 +21,7 @@
         "axios": "^1.1.3",
         "dayjs": "^1.11.7",
         "js-base64": "^3.7.3",
+        "js-export-excel": "^1.1.4",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "react-redux": "^8.0.4",
@@ -4559,6 +4560,21 @@
         "node": ">=8.9"
       }
     },
+    "node_modules/adler-32": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/adler-32/-/adler-32-1.2.0.tgz",
+      "integrity": "sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==",
+      "dependencies": {
+        "exit-on-epipe": "~1.0.1",
+        "printj": "~1.1.0"
+      },
+      "bin": {
+        "adler32": "bin/adler32.njs"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/agent-base": {
       "version": "6.0.2",
       "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz",
@@ -5313,6 +5329,11 @@
         "node": ">=8"
       }
     },
+    "node_modules/blob.js": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/blob.js/-/blob.js-1.0.1.tgz",
+      "integrity": "sha512-TkPuWPeCHBbN+LWFg7BlXdSh6stRxwmAbuirKfiiHTMmo/uQfKFQMx2jrxVUkueKRiG+Tc7Os1Zn618Yc0MZpg=="
+    },
     "node_modules/bluebird": {
       "version": "3.7.2",
       "resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz",
@@ -5526,6 +5547,26 @@
         "node": ">=4"
       }
     },
+    "node_modules/cfb": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz",
+      "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
+      "dependencies": {
+        "adler-32": "~1.3.0",
+        "crc-32": "~1.2.0"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/cfb/node_modules/adler-32": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz",
+      "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/chalk": {
       "version": "2.4.2",
       "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz",
@@ -5657,6 +5698,26 @@
         "node": ">= 4.0"
       }
     },
+    "node_modules/codepage": {
+      "version": "1.14.0",
+      "resolved": "https://registry.npmmirror.com/codepage/-/codepage-1.14.0.tgz",
+      "integrity": "sha512-iz3zJLhlrg37/gYRWgEPkaFTtzmnEv1h+r7NgZum2lFElYQPi0/5bnmuDfODHxfp0INEfnRqyfyeIJDbb7ahRw==",
+      "dependencies": {
+        "commander": "~2.14.1",
+        "exit-on-epipe": "~1.0.1"
+      },
+      "bin": {
+        "codepage": "bin/codepage.njs"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/codepage/node_modules/commander": {
+      "version": "2.14.1",
+      "resolved": "https://registry.npmmirror.com/commander/-/commander-2.14.1.tgz",
+      "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw=="
+    },
     "node_modules/collect-v8-coverage": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
@@ -5876,6 +5937,17 @@
         "node": ">=10"
       }
     },
+    "node_modules/crc-32": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz",
+      "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
+      "bin": {
+        "crc32": "bin/crc32.njs"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/cross-spawn": {
       "version": "7.0.3",
       "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -7578,6 +7650,14 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/exit-on-epipe": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz",
+      "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/expect": {
       "version": "27.5.1",
       "resolved": "https://registry.npmmirror.com/expect/-/expect-27.5.1.tgz",
@@ -7745,6 +7825,11 @@
         "webpack": "^4.0.0 || ^5.0.0"
       }
     },
+    "node_modules/file-saver": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmmirror.com/file-saver/-/file-saver-1.3.8.tgz",
+      "integrity": "sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg=="
+    },
     "node_modules/filelist": {
       "version": "1.0.4",
       "resolved": "https://registry.npmmirror.com/filelist/-/filelist-1.0.4.tgz",
@@ -8051,6 +8136,14 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/frac": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz",
+      "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/fraction.js": {
       "version": "4.2.0",
       "resolved": "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.2.0.tgz",
@@ -11012,6 +11105,17 @@
       "resolved": "https://registry.npmmirror.com/js-cookie/-/js-cookie-2.2.1.tgz",
       "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
     },
+    "node_modules/js-export-excel": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmmirror.com/js-export-excel/-/js-export-excel-1.1.4.tgz",
+      "integrity": "sha512-19m7e3Gnn4CRfHXoFrLYj4fFfJ/KpvI7HRRn25p4GXYD+AlTV+1oU24NH6S904Ksi44tSx7futxhouOPAQ22oQ==",
+      "dependencies": {
+        "blob.js": "^1.0.1",
+        "file-saver": "^1.3.3",
+        "script-loader": "0.7.2",
+        "xlsx": "0.16.3"
+      }
+    },
     "node_modules/js-sdsl": {
       "version": "4.1.5",
       "resolved": "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.1.5.tgz",
@@ -13272,6 +13376,17 @@
         "node": ">=10"
       }
     },
+    "node_modules/printj": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/printj/-/printj-1.1.2.tgz",
+      "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==",
+      "bin": {
+        "printj": "bin/printj.njs"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/process-nextick-args": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -13453,6 +13568,11 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/raw-loader": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmmirror.com/raw-loader/-/raw-loader-0.5.1.tgz",
+      "integrity": "sha512-sf7oGoLuaYAScB4VGr0tzetsYlS8EJH6qnTCfQ/WVEa89hALQ4RQfCKt5xCyPQKPDUbVUAIP1QsxAwfAjlDp7Q=="
+    },
     "node_modules/rc-align": {
       "version": "4.0.15",
       "resolved": "https://registry.npmmirror.com/rc-align/-/rc-align-4.0.15.tgz",
@@ -14964,6 +15084,14 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/script-loader": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmmirror.com/script-loader/-/script-loader-0.7.2.tgz",
+      "integrity": "sha512-UMNLEvgOAQuzK8ji8qIscM3GIrRCWN6MmMXGD4SD5l6cSycgGsCo0tX5xRnfQcoghqct0tjHjcykgI1PyBE2aA==",
+      "dependencies": {
+        "raw-loader": "~0.5.1"
+      }
+    },
     "node_modules/scroll-into-view-if-needed": {
       "version": "3.0.6",
       "resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.0.6.tgz",
@@ -15294,6 +15422,17 @@
       "resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz",
       "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
     },
+    "node_modules/ssf": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz",
+      "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
+      "dependencies": {
+        "frac": "~1.1.2"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/stable": {
       "version": "0.1.8",
       "resolved": "https://registry.npmmirror.com/stable/-/stable-0.1.8.tgz",
@@ -16685,6 +16824,22 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/wmf": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz",
+      "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/word": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmmirror.com/word/-/word-0.3.0.tgz",
+      "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/word-wrap": {
       "version": "1.2.3",
       "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.3.tgz",
@@ -17059,6 +17214,33 @@
         }
       }
     },
+    "node_modules/xlsx": {
+      "version": "0.16.3",
+      "resolved": "https://registry.npmmirror.com/xlsx/-/xlsx-0.16.3.tgz",
+      "integrity": "sha512-LInZ1OK6vpe+Em8XDZ5gDH3WixARwxI7UWc+3chLeafI6gUwECEgL43k4Tjbs1uRfkxpM7wQFy5DLE0hFBRqRw==",
+      "dependencies": {
+        "adler-32": "~1.2.0",
+        "cfb": "^1.1.4",
+        "codepage": "~1.14.0",
+        "commander": "~2.17.1",
+        "crc-32": "~1.2.0",
+        "exit-on-epipe": "~1.0.1",
+        "ssf": "~0.11.2",
+        "wmf": "~1.0.1",
+        "word": "~0.3.0"
+      },
+      "bin": {
+        "xlsx": "bin/xlsx.njs"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/xlsx/node_modules/commander": {
+      "version": "2.17.1",
+      "resolved": "https://registry.npmmirror.com/commander/-/commander-2.17.1.tgz",
+      "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
+    },
     "node_modules/xml-name-validator": {
       "version": "3.0.0",
       "resolved": "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
@@ -20465,6 +20647,15 @@
         "regex-parser": "^2.2.11"
       }
     },
+    "adler-32": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/adler-32/-/adler-32-1.2.0.tgz",
+      "integrity": "sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==",
+      "requires": {
+        "exit-on-epipe": "~1.0.1",
+        "printj": "~1.1.0"
+      }
+    },
     "agent-base": {
       "version": "6.0.2",
       "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz",
@@ -21075,6 +21266,11 @@
       "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz",
       "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
     },
+    "blob.js": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/blob.js/-/blob.js-1.0.1.tgz",
+      "integrity": "sha512-TkPuWPeCHBbN+LWFg7BlXdSh6stRxwmAbuirKfiiHTMmo/uQfKFQMx2jrxVUkueKRiG+Tc7Os1Zn618Yc0MZpg=="
+    },
     "bluebird": {
       "version": "3.7.2",
       "resolved": "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz",
@@ -21253,6 +21449,22 @@
       "resolved": "https://registry.npmmirror.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz",
       "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw=="
     },
+    "cfb": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz",
+      "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
+      "requires": {
+        "adler-32": "~1.3.0",
+        "crc-32": "~1.2.0"
+      },
+      "dependencies": {
+        "adler-32": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz",
+          "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A=="
+        }
+      }
+    },
     "chalk": {
       "version": "2.4.2",
       "resolved": "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz",
@@ -21358,6 +21570,22 @@
         "q": "^1.1.2"
       }
     },
+    "codepage": {
+      "version": "1.14.0",
+      "resolved": "https://registry.npmmirror.com/codepage/-/codepage-1.14.0.tgz",
+      "integrity": "sha512-iz3zJLhlrg37/gYRWgEPkaFTtzmnEv1h+r7NgZum2lFElYQPi0/5bnmuDfODHxfp0INEfnRqyfyeIJDbb7ahRw==",
+      "requires": {
+        "commander": "~2.14.1",
+        "exit-on-epipe": "~1.0.1"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "2.14.1",
+          "resolved": "https://registry.npmmirror.com/commander/-/commander-2.14.1.tgz",
+          "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw=="
+        }
+      }
+    },
     "collect-v8-coverage": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
@@ -21547,6 +21775,11 @@
         "yaml": "^1.10.0"
       }
     },
+    "crc-32": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz",
+      "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="
+    },
     "cross-spawn": {
       "version": "7.0.3",
       "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -22854,6 +23087,11 @@
       "resolved": "https://registry.npmmirror.com/exit/-/exit-0.1.2.tgz",
       "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ=="
     },
+    "exit-on-epipe": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz",
+      "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw=="
+    },
     "expect": {
       "version": "27.5.1",
       "resolved": "https://registry.npmmirror.com/expect/-/expect-27.5.1.tgz",
@@ -23001,6 +23239,11 @@
         "schema-utils": "^3.0.0"
       }
     },
+    "file-saver": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmmirror.com/file-saver/-/file-saver-1.3.8.tgz",
+      "integrity": "sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg=="
+    },
     "filelist": {
       "version": "1.0.4",
       "resolved": "https://registry.npmmirror.com/filelist/-/filelist-1.0.4.tgz",
@@ -23233,6 +23476,11 @@
       "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz",
       "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
     },
+    "frac": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz",
+      "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA=="
+    },
     "fraction.js": {
       "version": "4.2.0",
       "resolved": "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.2.0.tgz",
@@ -25543,6 +25791,17 @@
       "resolved": "https://registry.npmmirror.com/js-cookie/-/js-cookie-2.2.1.tgz",
       "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
     },
+    "js-export-excel": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmmirror.com/js-export-excel/-/js-export-excel-1.1.4.tgz",
+      "integrity": "sha512-19m7e3Gnn4CRfHXoFrLYj4fFfJ/KpvI7HRRn25p4GXYD+AlTV+1oU24NH6S904Ksi44tSx7futxhouOPAQ22oQ==",
+      "requires": {
+        "blob.js": "^1.0.1",
+        "file-saver": "^1.3.3",
+        "script-loader": "0.7.2",
+        "xlsx": "0.16.3"
+      }
+    },
     "js-sdsl": {
       "version": "4.1.5",
       "resolved": "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.1.5.tgz",
@@ -27127,6 +27386,11 @@
         }
       }
     },
+    "printj": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/printj/-/printj-1.1.2.tgz",
+      "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ=="
+    },
     "process-nextick-args": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -27278,6 +27542,11 @@
         }
       }
     },
+    "raw-loader": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmmirror.com/raw-loader/-/raw-loader-0.5.1.tgz",
+      "integrity": "sha512-sf7oGoLuaYAScB4VGr0tzetsYlS8EJH6qnTCfQ/WVEa89hALQ4RQfCKt5xCyPQKPDUbVUAIP1QsxAwfAjlDp7Q=="
+    },
     "rc-align": {
       "version": "4.0.15",
       "resolved": "https://registry.npmmirror.com/rc-align/-/rc-align-4.0.15.tgz",
@@ -28376,6 +28645,14 @@
       "resolved": "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz",
       "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA=="
     },
+    "script-loader": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmmirror.com/script-loader/-/script-loader-0.7.2.tgz",
+      "integrity": "sha512-UMNLEvgOAQuzK8ji8qIscM3GIrRCWN6MmMXGD4SD5l6cSycgGsCo0tX5xRnfQcoghqct0tjHjcykgI1PyBE2aA==",
+      "requires": {
+        "raw-loader": "~0.5.1"
+      }
+    },
     "scroll-into-view-if-needed": {
       "version": "3.0.6",
       "resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.0.6.tgz",
@@ -28660,6 +28937,14 @@
       "resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz",
       "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
     },
+    "ssf": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz",
+      "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
+      "requires": {
+        "frac": "~1.1.2"
+      }
+    },
     "stable": {
       "version": "0.1.8",
       "resolved": "https://registry.npmmirror.com/stable/-/stable-0.1.8.tgz",
@@ -29752,6 +30037,16 @@
         "is-typed-array": "^1.1.9"
       }
     },
+    "wmf": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz",
+      "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw=="
+    },
+    "word": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmmirror.com/word/-/word-0.3.0.tgz",
+      "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA=="
+    },
     "word-wrap": {
       "version": "1.2.3",
       "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.3.tgz",
@@ -30082,6 +30377,29 @@
       "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
       "requires": {}
     },
+    "xlsx": {
+      "version": "0.16.3",
+      "resolved": "https://registry.npmmirror.com/xlsx/-/xlsx-0.16.3.tgz",
+      "integrity": "sha512-LInZ1OK6vpe+Em8XDZ5gDH3WixARwxI7UWc+3chLeafI6gUwECEgL43k4Tjbs1uRfkxpM7wQFy5DLE0hFBRqRw==",
+      "requires": {
+        "adler-32": "~1.2.0",
+        "cfb": "^1.1.4",
+        "codepage": "~1.14.0",
+        "commander": "~2.17.1",
+        "crc-32": "~1.2.0",
+        "exit-on-epipe": "~1.0.1",
+        "ssf": "~0.11.2",
+        "wmf": "~1.0.1",
+        "word": "~0.3.0"
+      },
+      "dependencies": {
+        "commander": {
+          "version": "2.17.1",
+          "resolved": "https://registry.npmmirror.com/commander/-/commander-2.17.1.tgz",
+          "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
+        }
+      }
+    },
     "xml-name-validator": {
       "version": "3.0.0",
       "resolved": "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz",

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

@@ -16,6 +16,7 @@
     "axios": "^1.1.3",
     "dayjs": "^1.11.7",
     "js-base64": "^3.7.3",
+    "js-export-excel": "^1.1.4",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "react-redux": "^8.0.4",

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


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


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


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


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


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


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


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


+ 2 - 1
后台管理/src/assets/styles/base.css

@@ -41,7 +41,8 @@ textarea {
 }
 /* 主题色 */
 :root {
-  --themeColor: #35527D;
+  --themeColor: #2E6F80;
+  --themeColor2: #D2C69A;
 }
 /* 找不到页面 */
 .noFindPage {

+ 2 - 1
后台管理/src/assets/styles/base.less

@@ -50,7 +50,8 @@ textarea {
 
 /* 主题色 */
 :root {
-  --themeColor: #35527D;
+  --themeColor: #2E6F80;
+  --themeColor2: #D2C69A;
 }
 
 

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

@@ -25,7 +25,7 @@ root.render(
     locale={locale}
     theme={{
       token: {
-        colorPrimary: "#35527D",
+        colorPrimary: "#2E6F80",
       },
     }}
   >

+ 26 - 0
后台管理/src/pages/A1Order/A1Look/index.module.scss

@@ -0,0 +1,26 @@
+.A1Look {
+  :global {
+
+
+    .A1MBox {
+      display: flex;
+      margin-top: 30px;
+
+
+      .A1MBoxL {
+        width: 120px;
+        text-align: right;
+
+      }
+
+      .A1MBoxR {
+        width: calc(100% - 140px);
+        margin-left: 20px;
+
+        .infoP {
+          margin-bottom: 10px;
+        }
+      }
+    }
+  }
+}

+ 92 - 0
后台管理/src/pages/A1Order/A1Look/index.tsx

@@ -0,0 +1,92 @@
+import React, { useMemo } from "react";
+import styles from "./index.module.scss";
+import { Modal } from "antd";
+import { A1TableType } from "@/types";
+
+type Props = {
+  data: A1TableType;
+  closeModelFu: () => void;
+};
+
+function A1Look({ data, closeModelFu }: Props) {
+  const infoArr = useMemo(() => {
+    const arr: any = [];
+
+    const arr1 = data.contact.split(",");
+
+    arr1.forEach((v) => {
+      arr.push({
+        name: v.split("-")[0] + " - " + v.split("-")[1],
+        zheng: v.split("-")[2] || "无",
+      });
+    });
+
+    return arr;
+  }, [data.contact]);
+
+  return (
+    <Modal
+      wrapClassName={styles.A1Look}
+      destroyOnClose
+      open={true}
+      title="预约详情"
+      onCancel={closeModelFu}
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      <div className="A1MBox">
+        <div className="A1MBoxL">申请时间:</div>
+        <div className="A1MBoxR">
+          <p>{data.createTime}</p>
+        </div>
+      </div>
+
+      <div className="A1MBox">
+        <div className="A1MBoxL">参观展馆:</div>
+        <div className="A1MBoxR">
+          <p>{data.exhibitionName}</p>
+        </div>
+      </div>
+
+      <div className="A1MBox">
+        <div className="A1MBoxL">所在单位:</div>
+        <div className="A1MBoxR">
+          <p>{data.organ}</p>
+        </div>
+      </div>
+
+      <div className="A1MBox">
+        <div className="A1MBoxL">预约人:</div>
+        <div className="A1MBoxR">
+          {infoArr.map((v: any, i: number) => (
+            <div className="infoP" key={i}>
+              <p>{v.name}</p>
+              <p>{v.zheng}</p>
+            </div>
+          ))}
+        </div>
+      </div>
+
+      <div className="A1MBox">
+        <div className="A1MBoxL">预约时间:</div>
+        <div className="A1MBoxR">
+          <p>{data.bookDay + " " + data.bootTimeScope}</p>
+        </div>
+      </div>
+
+      <div className="A1MBox">
+        <div className="A1MBoxL">备注:</div>
+        <div className="A1MBoxR">
+          <p>{data.description ? data.description : "无"}</p>
+        </div>
+      </div>
+      <br />
+      <br />
+    </Modal>
+  );
+}
+
+const MemoA1Look = React.memo(A1Look);
+
+export default MemoA1Look;

+ 32 - 3
后台管理/src/pages/A1Order/index.module.scss

@@ -1,5 +1,34 @@
-.A1Order{
-  :global{
-    
+.A1Order {
+  :global {
+    .A1Top {
+      border-radius: 10px;
+      padding: 20px 15px 0;
+      background-color: #fff;
+      display: flex;
+      flex-wrap: wrap;
+
+      .A1TopRow {
+        margin-right: 30px;
+        margin-bottom: 20px;
+      }
+    }
+    .tableBox {
+      border-radius: 10px;
+      overflow: hidden;
+      margin-top: 15px;
+      height: calc(100% - 132px);
+      background-color: #fff;
+
+      .ant-table-body {
+        height: 565px;
+        overflow-y: auto !important;
+
+        .ant-table-row {
+          .ant-table-cell {
+            padding: 10px;
+          }
+        }
+      }
+    }
   }
 }

+ 376 - 5
后台管理/src/pages/A1Order/index.tsx

@@ -1,12 +1,383 @@
-import React from "react";
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
 import styles from "./index.module.scss";
- function A1Order() {
-  
+import { useDispatch, useSelector } from "react-redux";
+import { Button, DatePicker, Input, Popconfirm, Select, Table } from "antd";
+import {
+  A1_APIdelById,
+  A1_APIgetList,
+  A1_APIlistExport,
+} from "@/store/action/A1Order";
+import { RootState } from "@/store";
+import { A1TableType } from "@/types";
+import { MessageFu } from "@/utils/message";
+import ExportJsonExcel from "js-export-excel";
+import dayjs from "dayjs";
+import A1Look from "./A1Look";
+import { A2_APIgetListSelect } from "@/store/action/A2Gallery";
+
+const { RangePicker } = DatePicker;
+
+function A1Order() {
+  const dispatch = useDispatch();
+
+  const [fromData, setFromData] = useState({
+    startTime: "",
+    endTime: "",
+    exhibitionName: "",
+    name: "",
+    phone: "",
+    bookDayStart: "",
+    bookDayEnd: "",
+    pageNum: 1,
+    pageSize: 10,
+  });
+
+  // 获取展馆下拉信息
+
+  const [select, setSelect] = useState(
+    [] as { value: string; label: string }[]
+  );
+
+  const getListSelectFu = useCallback(async () => {
+    const res = await A2_APIgetListSelect({
+      pageNum: 1,
+      pageSize: 99999,
+      searchKey: "",
+    });
+    if (res.code === 0) {
+      const data = res.data.records.map((v: any) => ({
+        value: v.name,
+        label: v.name,
+      }));
+      data.unshift({ value: "", label: "全部" });
+      setSelect(data);
+    }
+  }, []);
+
+  useEffect(() => {
+    getListSelectFu();
+  }, [getListSelectFu]);
+
+  // 封装发送接口的函数
+  const getListFu = useCallback(() => {
+    dispatch(A1_APIgetList(fromData));
+  }, [dispatch, fromData]);
+
+  useEffect(() => {
+    getListFu();
+  }, [getListFu]);
+
+  // 申请日期的改变
+  const timeChange1 = useCallback(
+    (_: any, dateString: any) => {
+      let startTime = "";
+      let endTime = "";
+      if (dateString[0] && dateString[1]) {
+        startTime = dateString[0] + " 00:00:00";
+        endTime = dateString[1] + " 23:59:59";
+      }
+      setFromData({ ...fromData, startTime, endTime, pageNum: 1 });
+    },
+    [fromData]
+  );
+
+  // 预约日期的改变
+  const timeChange2 = useCallback(
+    (_: any, dateString: any) => {
+      let bookDayStart = "";
+      let bookDayEnd = "";
+      if (dateString[0] && dateString[1]) {
+        bookDayStart = dateString[0] + " 00:00:00";
+        bookDayEnd = dateString[1] + " 23:59:59";
+      }
+      setFromData({ ...fromData, bookDayStart, bookDayEnd, pageNum: 1 });
+    },
+    [fromData]
+  );
+
+  // 名称的输入
+  const nameTime = useRef(-1);
+  const nameChange = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>) => {
+      clearTimeout(nameTime.current);
+      nameTime.current = window.setTimeout(() => {
+        setFromData({
+          ...fromData,
+          name: e.target.value,
+          pageNum: 1,
+        });
+      }, 500);
+    },
+    [fromData]
+  );
+
+  // 联系电话的输入
+  const phoneTime = useRef(-1);
+  const phoneChange = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>) => {
+      clearTimeout(phoneTime.current);
+      phoneTime.current = window.setTimeout(() => {
+        setFromData({
+          ...fromData,
+          phone: e.target.value,
+          pageNum: 1,
+        });
+      }, 500);
+    },
+    [fromData]
+  );
+
+  // 点击重置
+  const [inputKey, setInputKey] = useState(1);
+  const resetSelectFu = useCallback(() => {
+    // 把2个输入框和时间选择器清空
+    setInputKey(Date.now());
+    setFromData({
+      startTime: "",
+      endTime: "",
+      exhibitionName: "",
+      name: "",
+      phone: "",
+      bookDayStart: "",
+      bookDayEnd: "",
+      pageNum: 1,
+      pageSize: 10,
+    });
+  }, []);
+
+  // 点击删除
+  const delTableFu = useCallback(
+    async (id: number) => {
+      const res = await A1_APIdelById(id);
+      if (res.code === 0) {
+        MessageFu.success("删除成功!");
+        getListFu();
+      }
+    },
+    [getListFu]
+  );
+
+  // 从仓库获取表格数据
+  const tableInfo = useSelector((state: RootState) => state.A1Order.tableInfo);
+  // 页码变化
+  const paginationChange = useCallback(
+    () => (pageNum: number, pageSize: number) => {
+      setFromData({ ...fromData, pageNum, pageSize });
+    },
+    [fromData]
+  );
+
+  const resField = useCallback((val: string) => {
+    let res = ["(空)", "(空)"];
+    if (val) {
+      const str1 = val.split(",")[0] || "";
+      if (str1) {
+        res = str1.split("-");
+      }
+    }
+    return res;
+  }, []);
+
+  const columns = useMemo(() => {
+    return [
+      {
+        title: "申请时间",
+        dataIndex: "createTime",
+      },
+      {
+        title: "参观展馆",
+        dataIndex: "exhibitionName",
+      },
+      {
+        title: "所在单位",
+        dataIndex: "organ",
+      },
+      {
+        title: "姓名",
+        render: (item: A1TableType) => resField(item.contact)[0],
+      },
+      {
+        title: "联系电话",
+        render: (item: A1TableType) => resField(item.contact)[1],
+      },
+      {
+        title: "人数",
+        render: (item: A1TableType) => item.contact.split(",").length,
+      },
+      {
+        title: "预约时间",
+        render: (item: A1TableType) => item.bookDay + " " + item.bootTimeScope,
+      },
+      {
+        title: "操作",
+        render: (item: A1TableType) => (
+          <>
+            <Button size="small" type="text" onClick={() => setLookInfo(item)}>
+              查看
+            </Button>
+            <Popconfirm
+              title="删除后无法恢复,是否删除?"
+              okText="删除"
+              cancelText="取消"
+              onConfirm={() => delTableFu(item.id)}
+            >
+              <Button size="small" type="text" danger>
+                删除
+              </Button>
+            </Popconfirm>
+          </>
+        ),
+      },
+    ];
+  }, [delTableFu, resField]);
+
+  // 点击导出
+  const deriveFu = useCallback(async () => {
+    if (tableInfo.list.length === 0)
+      return MessageFu.warning("当前搜索条件没有数据!");
+    const name = "预约" + dayjs(new Date()).format("YYYY-MM-DD HH:mm");
+
+    const res = await A1_APIlistExport({
+      ...fromData,
+      pageNum: 1,
+      pageSize: 99999,
+    });
+
+    if (res.code === 0) {
+      const option = {
+        fileName: name,
+        datas: [
+          {
+            sheetData: res.data.records.map((v: A1TableType) => {
+              return {
+                ...v,
+                name: resField(v.contact)[0],
+                phone: resField(v.contact)[1],
+                rNum: v.contact.split(",").length,
+                time: v.bookDay + " " + v.bootTimeScope,
+              };
+            }),
+            sheetName: name,
+            sheetFilter: [
+              "createTime",
+              "exhibitionName",
+              "organ",
+              "name",
+              "phone",
+              "rNum",
+              "time",
+              "description",
+            ],
+            sheetHeader: [
+              "申请时间",
+              "参观展馆",
+              "所在单位",
+              "姓名",
+              "联系电话",
+              "人数",
+              "预约时间",
+              "备注",
+            ],
+            columnWidths: [10, 10, 10, 10, 10, 10, 10, 10],
+          },
+        ],
+      };
+
+      const toExcel = new ExportJsonExcel(option); //new
+      toExcel.saveExcel(); //保存
+    }
+  }, [fromData, resField, tableInfo.list.length]);
+
+  // 查看的数据
+  const [lookInfo, setLookInfo] = useState({} as A1TableType);
+
   return (
     <div className={styles.A1Order}>
-      <h1>A1Order</h1>
+      <div className="pageTitle">预约管理</div>
+      <div className="A1Top">
+        <div className="A1TopRow">
+          <span>申请日期:</span>
+          <RangePicker key={inputKey} onChange={timeChange1} />
+        </div>
+        <div className="A1TopRow">
+          <span>参观展馆:</span>
+          <Select
+            placeholder="请选择"
+            style={{ width: 240 }}
+            value={fromData.exhibitionName}
+            onChange={(e) =>
+              setFromData({ ...fromData, exhibitionName: e, pageNum: 1 })
+            }
+            options={select}
+          />
+        </div>
+        <div className="A1TopRow">
+          <span>姓名:</span>
+          <Input
+            key={inputKey}
+            maxLength={50}
+            style={{ width: 200 }}
+            placeholder="请输入关键字"
+            allowClear
+            onChange={(e) => nameChange(e)}
+          />
+        </div>
+        <div className="A1TopRow">
+          <span>联系电话:</span>
+          <Input
+            key={inputKey}
+            maxLength={11}
+            style={{ width: 200 }}
+            placeholder="请输入关键字"
+            allowClear
+            onChange={(e) => phoneChange(e)}
+          />
+        </div>
+        <div className="A1TopRow">
+          <span>预约日期:</span>
+          <RangePicker key={inputKey} onChange={timeChange2} />
+        </div>
+        <Button onClick={resetSelectFu}>重置</Button>
+        &emsp;&emsp;&emsp;&emsp;
+        <Button type="primary" onClick={deriveFu}>
+          导出数据
+        </Button>
+      </div>
+
+      {/* 表格主体 */}
+      <div className="tableBox">
+        <Table
+          scroll={{ y: 565 }}
+          dataSource={tableInfo.list}
+          columns={columns}
+          rowKey="id"
+          pagination={{
+            showQuickJumper: true,
+            position: ["bottomCenter"],
+            showSizeChanger: true,
+            current: fromData.pageNum,
+            pageSize: fromData.pageSize,
+            total: tableInfo.total,
+            onChange: paginationChange(),
+          }}
+        />
+      </div>
+
+      {/* 点击查看 */}
+      {lookInfo.id ? (
+        <A1Look
+          data={lookInfo}
+          closeModelFu={() => setLookInfo({} as A1TableType)}
+        />
+      ) : null}
     </div>
-  )
+  );
 }
 
 const MemoA1Order = React.memo(A1Order);

+ 133 - 0
后台管理/src/pages/A2Gallery/A2Edit/index.module.scss

@@ -0,0 +1,133 @@
+.A2Edit {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 99;
+  padding: 30px 20px;
+  background-color: #fff;
+  border-radius: 10px;
+  overflow-y: auto;
+
+  :global {
+    .A2E_topInfo {
+      width: 800px;
+
+      .A2E_btn {
+        position: fixed;
+        z-index: 998;
+        top: 105px;
+        right: 100px;
+      }
+    }
+
+    // 查看的情况
+    .nolyLookMain {
+
+      .ant-row {
+        pointer-events: none;
+      }
+
+      .ant-form-item-control-input {
+        pointer-events: none;
+
+        .ant-input-affix-wrapper {
+          border: transparent;
+
+          .ant-input-show-count-suffix {
+            opacity: 0;
+          }
+        }
+
+        .ant-select-selector {
+          border: transparent;
+        }
+
+        .ant-select-arrow {
+          opacity: 0;
+        }
+
+        .ant-input {
+          border: transparent;
+        }
+
+        .ant-input-data-count {
+          opacity: 0;
+        }
+
+      }
+
+      .ant-checkbox-group {
+        pointer-events: none;
+      }
+
+      .myformBox3 .upImgBox .fileImgListBox>div {
+        margin: 0px 20px 15px 0;
+        cursor: default;
+      }
+
+      .closeLook {
+        .ant-form-item-control-input {
+          pointer-events: auto;
+        }
+      }
+
+      textarea {
+        min-height: 40px !important;
+      }
+
+      textarea,
+      input {
+        &::-webkit-input-placeholder {
+          color: black;
+        }
+
+        &:-moz-placeholder {
+          color: black;
+        }
+
+        &::-moz-placeholder {
+          color: black;
+        }
+
+        &:-ms-input-placeholder {
+          color: black;
+        }
+      }
+
+      // 下拉框 placeholder 字体颜色
+      .ant-select-selection-placeholder {
+        color: black;
+      }
+    }
+
+    .A2E_flooBox {
+      .A2E_flooTit {
+        display: flex;
+        align-items: center;
+
+        .A2E_flooTitl {
+          width: 100px;
+          text-align: right;
+        }
+      }
+
+      .A2E_table {
+        padding: 0 240px 0 100px;
+
+        border-radius: 10px;
+        margin-top: 15px;
+        background-color: #fff;
+
+        .ant-table-body {
+          .ant-table-row {
+            .ant-table-cell {
+              padding: 10px;
+            }
+          }
+        }
+      }
+    }
+  }
+}

+ 290 - 0
后台管理/src/pages/A2Gallery/A2Edit/index.tsx

@@ -0,0 +1,290 @@
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
+import styles from "./index.module.scss";
+import {
+  A2_APIdelItem,
+  A2_APIeditItem,
+  A2_APIgetInfoById,
+  A2_APIgetList,
+  A2_APIupdateIndex,
+} from "@/store/action/A2Gallery";
+import { A2TableType } from "@/types";
+import { useDispatch, useSelector } from "react-redux";
+import { RootState } from "@/store";
+import { Button, Form, FormInstance, Input, Popconfirm, Table } from "antd";
+import TextArea from "antd/es/input/TextArea";
+import ImageLazy from "@/components/ImageLazy";
+import A2Modal from "../A2Modal";
+import { MessageFu } from "@/utils/message";
+import classNames from "classnames";
+
+type Props = {
+  editInfo: { type: string; id: number };
+  editFu: () => void;
+  closeFu: () => void;
+};
+
+function A2Edit({ editInfo, editFu, closeFu }: Props) {
+  const dispatch = useDispatch();
+
+  // 下面表格数据
+  const inTableInfo = useSelector(
+    (state: RootState) => state.A2Gallery.inTableInfo
+  );
+
+  // 自己的id
+  const [pid, setPid] = useState(0);
+
+  const getInfoByIdFu = useCallback(
+    async (id: number) => {
+      const res = await A2_APIgetInfoById(id);
+      if (res.code === 0) {
+        FormBoxRef.current?.setFieldsValue(res.data);
+        setPid(res.data.id);
+      }
+      dispatch(A2_APIgetList({ parentId: id }, true));
+    },
+    [dispatch]
+  );
+
+  const upTableInfo = useCallback(() => {
+    dispatch(A2_APIgetList({ parentId: editInfo.id }, true));
+  }, [dispatch, editInfo.id]);
+
+  useEffect(() => {
+    getInfoByIdFu(editInfo.id);
+  }, [editInfo.id, getInfoByIdFu]);
+
+  // 表单的ref
+  const FormBoxRef = useRef<FormInstance>(null);
+
+  // 没有通过校验
+  const onFinishFailed = useCallback(() => {}, []);
+
+  // 通过校验点击确定
+  const onFinish = useCallback(
+    async (value: any) => {
+      const res = await A2_APIeditItem({
+        ...value,
+        id: editInfo.id,
+      });
+      if (res.code === 0) {
+        MessageFu.success("提交成功!");
+        editFu();
+        closeFu();
+      }
+    },
+    [closeFu, editFu, editInfo.id]
+  );
+
+  // 点击删除
+  const delTableFu = useCallback(
+    async (id: number) => {
+      const res = await A2_APIdelItem(id);
+      if (res.code === 0) {
+        MessageFu.success("删除成功!");
+        upTableInfo();
+      }
+    },
+    [upTableInfo]
+  );
+
+  // 点击置顶
+  const updateIndexFu = useCallback(
+    async (id: number, pid: number) => {
+      const res = await A2_APIupdateIndex(id, pid);
+      if (res.code === 0) {
+        MessageFu.success("置顶成功!");
+        upTableInfo();
+      }
+    },
+    [upTableInfo]
+  );
+
+  const columns = useMemo(() => {
+    const arr = [
+      {
+        title: "展览名称",
+        dataIndex: "name",
+      },
+      {
+        title: "展览类型",
+        dataIndex: "type",
+      },
+      {
+        title: "封面图",
+        render: (item: A2TableType) => (
+          <div className="tableImgAuto">
+            <ImageLazy width={60} height={60} src={item.thumb} />
+          </div>
+        ),
+      },
+      {
+        title: "标签",
+        render: (item: A2TableType) => (item.tag ? item.tag : "(空)"),
+      },
+      {
+        title: "展览地点",
+        dataIndex: "address",
+      },
+      {
+        title: "跳转链接",
+        render: (item: A2TableType) => (
+          <a href={item.link} target="blank" title={item.link}>
+            {item.link.length >= 50
+              ? item.link.substring(0, 50) + "..."
+              : item.link}
+          </a>
+        ),
+      },
+    ];
+
+    if (editInfo.type === "edit") {
+      arr.push({
+        title: "操作",
+        render: (item: A2TableType) => (
+          <>
+            <Button
+              hidden={item.hasIndex === 1}
+              size="small"
+              type="text"
+              onClick={() => updateIndexFu(item.id, pid)}
+            >
+              置顶
+            </Button>
+            <Button
+              size="small"
+              type="text"
+              onClick={() =>
+                setIsEdit({ type: "edit", id: item.id, info: item, pid })
+              }
+            >
+              编辑
+            </Button>
+            <Popconfirm
+              title="删除后无法恢复,是否删除?"
+              okText="删除"
+              cancelText="取消"
+              onConfirm={() => delTableFu(item.id)}
+            >
+              <Button size="small" type="text" danger>
+                删除
+              </Button>
+            </Popconfirm>
+          </>
+        ),
+      });
+    }
+
+    return arr;
+  }, [delTableFu, editInfo.type, pid, updateIndexFu]);
+
+  // 内部的 新增 、或者 编辑
+  const [isEdit, setIsEdit] = useState({
+    type: "",
+    id: 0,
+    info: {} as A2TableType,
+    pid: 0,
+  });
+
+  return (
+    <div className={styles.A2Edit}>
+      <div className={classNames("A2E_topInfo",editInfo.type==='look'?'nolyLookMain':'')}>
+        <Form
+          scrollToFirstError={true}
+          ref={FormBoxRef}
+          name="basic"
+          labelCol={{ span: 3 }}
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}
+          autoComplete="off"
+        >
+          <Form.Item label="展馆名称" name="name">
+            <Input
+              disabled={editInfo.type === "edit"}
+              maxLength={50}
+              showCount
+            />
+          </Form.Item>
+          <Form.Item label="地址" name="address">
+            <Input placeholder="请输入内容" maxLength={50} showCount />
+          </Form.Item>
+          <Form.Item label="开放时间" name="openTime">
+            <Input placeholder="请输入内容" maxLength={50} showCount />
+          </Form.Item>
+          <Form.Item label="展馆简介" name="description">
+            <TextArea
+              autoSize
+              placeholder="请输入内容"
+              showCount
+              maxLength={500}
+            />
+          </Form.Item>
+          {/* 确定和取消按钮 */}
+          <div className="A2E_btn">
+            {editInfo.type === "look" ? (
+              <Button onClick={closeFu}>关 闭</Button>
+            ) : (
+              <>
+                <Button type="primary" htmlType="submit">
+                  提交
+                </Button>
+                &emsp;&emsp;
+                <Popconfirm
+                  title="放弃编辑后,信息将不会保存!"
+                  okText="放弃"
+                  cancelText="取消"
+                  onConfirm={closeFu}
+                >
+                  <Button>取消</Button>
+                </Popconfirm>
+              </>
+            )}
+          </div>
+        </Form>
+      </div>
+      {/* 展馆管理 */}
+      <div className="A2E_flooBox">
+        <div className="A2E_flooTit" hidden={editInfo.type === "look"}>
+          <div className="A2E_flooTitl">展馆管理:</div>
+          <Button
+            type="primary"
+            onClick={() =>
+              setIsEdit({ type: "add", id: -1, info: {} as A2TableType, pid })
+            }
+          >
+            新增
+          </Button>
+        </div>
+        <div className="A2E_table">
+          <Table
+            dataSource={inTableInfo}
+            columns={columns}
+            rowKey="id"
+            pagination={false}
+          />
+        </div>
+      </div>
+
+      {/* 点击里面的 新增 和 编辑 */}
+      {isEdit.id === 0 ? null : (
+        <A2Modal
+          isEdit={isEdit}
+          inCloseFu={() =>
+            setIsEdit({ type: "", id: 0, info: {} as A2TableType, pid })
+          }
+          inEditFu={() => upTableInfo()}
+        />
+      )}
+    </div>
+  );
+}
+
+const MemoA2Edit = React.memo(A2Edit);
+
+export default MemoA2Edit;

+ 65 - 0
后台管理/src/pages/A2Gallery/A2Modal/index.module.scss

@@ -0,0 +1,65 @@
+.A2Modal {
+  :global {
+    .ant-modal {
+      width: 800px !important;
+    }
+
+    .ant-modal-close {
+      display: none;
+    }
+
+    .Modal_box {
+      border-top: 1px solid #999999;
+      padding-top: 15px;
+      width: 100%;
+
+      .e_row {
+        display: flex;
+        font-size: 14px;
+
+        .e_rowL {
+          width: 94px;
+          text-align: right;
+
+          &>span {
+            color: #ff4d4f;
+            position: relative;
+            top: 3px;
+          }
+        }
+
+        .e_rowR {
+          width: calc(100% - 94px);
+        }
+      }
+
+      .e_rowTag {
+        align-items: center;
+        margin-bottom: 15px;
+        margin-top: 10px;
+
+        .e_rowR {
+          display: flex;
+          align-items: center;
+
+          .A2_Mtag {
+            display: flex;
+            align-items: center;
+            width: 140px;
+            margin-right: 10px;
+
+            .tagClose {
+              cursor: pointer;
+              position: relative;
+              left: -20px;
+            }
+          }
+        }
+      }
+
+      textarea {
+        min-height: 60px !important;
+      }
+    }
+  }
+}

+ 233 - 0
后台管理/src/pages/A2Gallery/A2Modal/index.tsx

@@ -0,0 +1,233 @@
+import React, { useCallback, useEffect, useRef, useState } from "react";
+import styles from "./index.module.scss";
+import {
+  Button,
+  Form,
+  FormInstance,
+  Input,
+  Modal,
+  Popconfirm,
+  Select,
+} from "antd";
+import UpFileOne from "@/components/Z_upFileOne";
+import { A2TableType } from "@/types";
+
+import { PlusCircleOutlined, CloseOutlined } from "@ant-design/icons";
+import TextArea from "antd/es/input/TextArea";
+import { A2_APIeditItem } from "@/store/action/A2Gallery";
+import { MessageFu } from "@/utils/message";
+
+type Props = {
+  isEdit: { type: string; id: number; info: A2TableType; pid: number };
+  inCloseFu: () => void;
+  inEditFu: () => void;
+};
+
+function A2Modal({ isEdit, inCloseFu, inEditFu }: Props) {
+  const FormBoxRef = useRef<FormInstance>(null);
+
+  useEffect(() => {
+    if (isEdit.type === "add") {
+      FormBoxRef.current?.setFieldsValue({
+        type: "基本陈列",
+      });
+    } else {
+      FormBoxRef.current?.setFieldsValue(isEdit.info);
+      setCover(isEdit.info.thumb);
+      if (isEdit.info.tag) setTag(isEdit.info.tag.split(","));
+    }
+  }, [isEdit.info, isEdit.type]);
+
+  // 封面图
+  const [cover, setCover] = useState("");
+
+  // 校验
+  const [fromCheck, setFromCheck] = useState(false);
+
+  // 标签数组
+  const [tag, setTag] = useState([] as string[]);
+  const tagChange = useCallback(
+    (val: string, ind: number) => {
+      const arr = [...tag];
+      arr[ind] = val;
+      setTag(arr);
+    },
+    [tag]
+  );
+
+  // 没有通过校验
+  const onFinishFailed = useCallback(() => {
+    setFromCheck(true);
+    // return MessageFu.warning("有表单不符号规则!");
+  }, []);
+
+  // 通过校验点击确定
+  const onFinish = useCallback(
+    async (values: any) => {
+      setFromCheck(true);
+      if (!cover) return;
+
+      const obj = {
+        ...values,
+        id: isEdit.type === "add" ? null : isEdit.id,
+        parentId: isEdit.pid,
+        thumb: cover,
+        tag: tag.filter((v) => v !== "").join(","),
+      };
+
+      const res = await A2_APIeditItem(obj);
+
+      if (res.code === 0) {
+        MessageFu.success(isEdit.type === "add" ? "新增成功!" : "编辑成功!");
+        inEditFu();
+        inCloseFu();
+      }
+    },
+    [cover, inCloseFu, inEditFu, isEdit.id, isEdit.pid, isEdit.type, tag]
+  );
+
+  return (
+    <Modal
+      wrapClassName={styles.A2Modal}
+      destroyOnClose
+      open={true}
+      title={isEdit.type === "add" ? "新增展览" : "编辑展览"}
+      footer={
+        [] // 设置footer为空,去掉 取消 确定默认按钮
+      }
+    >
+      <div className="Modal_box">
+        <Form
+          scrollToFirstError={true}
+          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={50} showCount placeholder="请输入内容" />
+          </Form.Item>
+
+          <Form.Item
+            label="展览类型"
+            name="type"
+            rules={[{ required: true, message: "请输入展览名称!" }]}
+          >
+            <Select
+              placeholder="请选择"
+              style={{ width: 400 }}
+              options={[
+                { value: "基本陈列", label: "基本陈列" },
+                { value: "临时展览", label: "临时展览" },
+                { value: "专题展览", label: "专题展览" },
+              ]}
+            />
+          </Form.Item>
+
+          {/* 封面图 */}
+          <div className="e_row">
+            <div className="e_rowL">
+              <span>* </span>封面:
+            </div>
+            <div className="e_rowR">
+              <UpFileOne
+                myUrl="cms/exhibition/upload"
+                cover={cover}
+                setCover={(val) => setCover(val)}
+                isLook={false}
+                coverCheck={fromCheck}
+                size={5}
+                dirCode={"inZ"}
+              />
+            </div>
+          </div>
+
+          {/* 标签 */}
+          <div className="e_row e_rowTag">
+            <div className="e_rowL">
+              <span> </span>标签:
+            </div>
+            <div className="e_rowR">
+              <Button
+                onClick={() => setTag([...tag, ""])}
+                type="primary"
+                disabled={tag.some((v) => v === "")}
+                icon={<PlusCircleOutlined />}
+                hidden={tag.length >= 3}
+              />
+              &emsp;
+              {tag.map((v, i) => (
+                <div className="A2_Mtag" key={i}>
+                  <Input
+                    maxLength={6}
+                    placeholder="请输入内容"
+                    value={v}
+                    onChange={(e) => tagChange(e.target.value.trim(), i)}
+                  />
+
+                  <div
+                    className="tagClose"
+                    onClick={() => setTag(tag.filter((v2, i2) => i2 !== i))}
+                  >
+                    <CloseOutlined />
+                  </div>
+                </div>
+              ))}
+            </div>
+          </div>
+
+          <Form.Item
+            label="展览地点"
+            name="address"
+            rules={[{ required: true, message: "请输入展览地点!" }]}
+            getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
+          >
+            <Input maxLength={50} showCount placeholder="请输入内容" />
+          </Form.Item>
+
+          <Form.Item
+            label="跳转链接"
+            name="link"
+            rules={[{ required: true, message: "请输入跳转链接!" }]}
+            getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
+          >
+            <TextArea
+              autoSize
+              placeholder="请输入内容"
+              showCount
+              maxLength={200}
+            />
+          </Form.Item>
+
+          {/* 确定和取消按钮 */}
+          <br />
+          <Form.Item wrapperCol={{ offset: 10, span: 16 }}>
+            <Button type="primary" htmlType="submit">
+              提交
+            </Button>
+            &emsp;
+            <Popconfirm
+              title="放弃编辑后,信息将不会保存!"
+              okText="放弃"
+              cancelText="取消"
+              onConfirm={inCloseFu}
+            >
+              <Button>取消</Button>
+            </Popconfirm>
+          </Form.Item>
+        </Form>
+      </div>
+    </Modal>
+  );
+}
+
+const MemoA2Modal = React.memo(A2Modal);
+
+export default MemoA2Modal;

+ 31 - 0
后台管理/src/pages/A2Gallery/index.module.scss

@@ -0,0 +1,31 @@
+.A2Gallery {
+  position: relative;
+  :global {
+    .pageTop {
+      border-radius: 10px;
+      padding: 20px 15px 20px;
+      background-color: #fff;
+      display: flex;
+      align-items: center;
+    }
+
+    .tableBox {
+      border-radius: 10px;
+      overflow: hidden;
+      margin-top: 15px;
+      height: calc(100% - 80px);
+      background-color: #fff;
+
+      .ant-table-body {
+        height: 565px;
+        overflow-y: auto !important;
+
+        .ant-table-row {
+          .ant-table-cell {
+            padding: 10px;
+          }
+        }
+      }
+    }
+  }
+}

+ 182 - 0
后台管理/src/pages/A2Gallery/index.tsx

@@ -0,0 +1,182 @@
+import React, {
+  useCallback,
+  useEffect,
+  useMemo,
+  useRef,
+  useState,
+} from "react";
+import styles from "./index.module.scss";
+import { Button, Input, Table } from "antd";
+import { useDispatch, useSelector } from "react-redux";
+import store, { RootState } from "@/store";
+import { A2_APIgetList } from "@/store/action/A2Gallery";
+import { A2TableType } from "@/types";
+import A2Edit from "./A2Edit";
+function A2Gallery() {
+  const dispatch = useDispatch();
+
+  const [fromData, setFromData] = useState({
+    pageNum: 1,
+    pageSize: 10,
+    searchKey: "",
+  });
+
+  const getListFu = useCallback(() => {
+    dispatch(A2_APIgetList(fromData));
+  }, [dispatch, fromData]);
+
+  useEffect(() => {
+    getListFu();
+  }, [getListFu]);
+
+  // 名称的输入
+  const nameTime = useRef(-1);
+  const nameChange = useCallback(
+    (e: React.ChangeEvent<HTMLInputElement>) => {
+      clearTimeout(nameTime.current);
+      nameTime.current = window.setTimeout(() => {
+        setFromData({
+          ...fromData,
+          searchKey: e.target.value,
+          pageNum: 1,
+        });
+      }, 500);
+    },
+    [fromData]
+  );
+
+  // 从仓库获取表格数据
+  const tableInfo = useSelector(
+    (state: RootState) => state.A2Gallery.tableInfo
+  );
+  // 页码变化
+  const paginationChange = useCallback(
+    () => (pageNum: number, pageSize: number) => {
+      setFromData({ ...fromData, pageNum, pageSize });
+    },
+    [fromData]
+  );
+
+  const columns = useMemo(() => {
+    return [
+      {
+        title: "展馆名称",
+        dataIndex: "name",
+      },
+      {
+        title: "地址",
+        render: (item: A2TableType) =>
+          item.address ? (
+            item.address.length >= 40 ? (
+              <span style={{ cursor: "pointer" }} title={item.address}>
+                {item.address.substring(0, 40) + "..."}
+              </span>
+            ) : (
+              item.address
+            )
+          ) : (
+            "(空)"
+          ),
+      },
+
+      {
+        title: "展馆介绍",
+        render: (item: A2TableType) =>
+          item.description ? (
+            item.description.length >= 70 ? (
+              <span style={{ cursor: "pointer" }} title={item.description}>
+                {item.description.substring(0, 70) + "..."}
+              </span>
+            ) : (
+              item.description
+            )
+          ) : (
+            "(空)"
+          ),
+      },
+      {
+        title: "操作",
+        render: (item: A2TableType) => (
+          <>
+            <Button
+              size="small"
+              type="text"
+              onClick={() => setEditInfo({ type: "look", id: item.id })}
+            >
+              查看
+            </Button>
+            <Button
+              size="small"
+              type="text"
+              onClick={() => setEditInfo({ type: "edit", id: item.id })}
+            >
+              编辑
+            </Button>
+          </>
+        ),
+      },
+    ];
+  }, []);
+
+  // 打开查看或者编辑
+  const [editInfo, setEditInfo] = useState({ type: "", id: 0 });
+
+  //从编辑/查看页回来的时候 清空 二级的仓库 表格数据,防止闪动
+  const closeFu = useCallback(() => {
+    store.dispatch({ type: "A2/inGetList", payload: [] });
+    setEditInfo({ type: "", id: 0 });
+  }, []);
+
+  return (
+    <div className={styles.A2Gallery}>
+      <div className="pageTitle">
+        {editInfo.type === "look"
+          ? "展馆详情"
+          : editInfo.type === "edit"
+          ? "展馆编辑"
+          : "展馆管理"}
+      </div>
+      <div className="pageTop">
+        <span>展馆名称:</span>
+        <Input
+          maxLength={50}
+          style={{ width: 200 }}
+          placeholder="请输入关键字"
+          allowClear
+          onChange={(e) => nameChange(e)}
+        />
+      </div>
+      {/* 表格主体 */}
+      <div className="tableBox">
+        <Table
+          scroll={{ y: 617 }}
+          dataSource={tableInfo.list}
+          columns={columns}
+          rowKey="id"
+          pagination={{
+            showQuickJumper: true,
+            position: ["bottomCenter"],
+            showSizeChanger: true,
+            current: fromData.pageNum,
+            pageSize: fromData.pageSize,
+            total: tableInfo.total,
+            onChange: paginationChange(),
+          }}
+        />
+      </div>
+
+      {/* 编辑或者查看 */}
+      {editInfo.id ? (
+        <A2Edit
+          editInfo={editInfo}
+          editFu={() => getListFu()}
+          closeFu={closeFu}
+        />
+      ) : null}
+    </div>
+  );
+}
+
+const MemoA2Gallery = React.memo(A2Gallery);
+
+export default MemoA2Gallery;

+ 5 - 0
后台管理/src/pages/A3Fliqlo/index.module.scss

@@ -0,0 +1,5 @@
+.A3Fliqlo{
+  :global{
+    
+  }
+}

+ 13 - 0
后台管理/src/pages/A3Fliqlo/index.tsx

@@ -0,0 +1,13 @@
+import React from "react";
+import styles from "./index.module.scss";
+function A3Fliqlo() {
+  return (
+    <div className={styles.A3Fliqlo}>
+      <div className="pageTitle">屏保管理</div>
+    </div>
+  );
+}
+
+const MemoA3Fliqlo = React.memo(A3Fliqlo);
+
+export default MemoA3Fliqlo;

+ 1 - 1
后台管理/src/pages/A4User/index.module.scss

@@ -1,4 +1,4 @@
-.D1User {
+.A4User {
   :global {
     .selectBox {
       border-radius: 10px;

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

@@ -1,4 +1,4 @@
-.D2Log {
+.A5Log {
   :global {
     .logTop {
       border-radius: 10px;

+ 16 - 32
后台管理/src/pages/Layout/index.module.scss

@@ -10,50 +10,34 @@
       z-index: 30;
       width: 220px;
       height: 100%;
-      background-color: #131c28;
+      background-color: #5C8A96;
 
 
       .layoutLeftTop {
-        height: 60px;
-        color: #fff;
-        display: flex;
-        align-items: center;
-        justify-content: center;
+        text-align: center;
+        padding: 20px 0 20px;
 
-        &>h3 {
-          margin: 0 15px;
-          text-align: center;
+        &>img {
+          width: 100px;
         }
       }
 
       .layoutLeftMain {
-        height: calc(100% - 60px);
-        padding: 20px 20px 20px 50px;
-
         .layoutLRowBox {
+          cursor: pointer;
           font-size: 18px;
           font-weight: 700;
-          margin-bottom: 20px;
-          color: #ccc;
-
-          .layoutLRow {
-            cursor: pointer;
-            padding-left: 38px;
-            font-size: 16px;
-            height: 40px;
-            line-height: 40px;
-            opacity: .4;
-            color: #fff;
-
-            &:first-child {
-              margin-top: 8px;
-            }
-          }
+          color: #fff;
+          text-align: center;
+          height: 60px;
+          line-height: 60px;
 
-          .active {
-            pointer-events: none;
-            opacity: 1;
-          }
+        }
+
+        .active {
+          pointer-events: none;
+          background-color: var(--themeColor2);
+          color: #94844b;
         }
 
 

+ 15 - 5
后台管理/src/pages/Layout/index.tsx

@@ -19,6 +19,7 @@ import { passWordEditAPI } from "@/store/action/layout";
 import { getTokenInfo, removeTokenInfo } from "@/utils/storage";
 import { MessageFu } from "@/utils/message";
 import { RouterType } from "@/types";
+import logoImg from '@/assets/img/logo.png'
 
 const NotFound = React.lazy(() => import("@/components/NotFound"));
 
@@ -31,6 +32,19 @@ function Layout() {
         path: "/",
         Com: React.lazy(() => import("../A1Order")),
       },
+      {
+        id: 2,
+        name: "展馆管理",
+        path: "/gallery",
+        Com: React.lazy(() => import("../A2Gallery")),
+      },
+      {
+        id: 3,
+        name: "屏保管理",
+        path: "/fliqlo",
+        Com: React.lazy(() => import("../A3Fliqlo")),
+      },
+
     ];
     return arr;
   }, []);
@@ -115,11 +129,7 @@ function Layout() {
       {/* 左边 */}
       <div className="layoutLeft">
         <div className="layoutLeftTop">
-          <h3>
-            北京珐琅厂景泰蓝博物馆
-            <br />
-            数字化改造
-          </h3>
+          <img src={logoImg} alt="" />
         </div>
         {/* 左边主体 */}
         <div className="layoutLeftMain">

+ 44 - 31
后台管理/src/pages/Login/index.module.scss

@@ -1,8 +1,8 @@
 .Login {
   width: 100%;
   height: 100%;
-  background-image: url('../../assets/img/bg.png');
-  background-size: cover;
+  background-image: url('../../assets/img/bg.jpg');
+  background-size: 100% 100%;
   position: relative;
 
   &::before {
@@ -12,7 +12,6 @@
     left: 0;
     width: 100%;
     height: 100%;
-    background-color: rgba(0, 0, 0, .4);
   }
 
   :global {
@@ -21,42 +20,53 @@
       border-radius: 6px;
       position: absolute;
       top: 50%;
-      left: 50%;
-      transform: translate(-50%,-50%);
-      width: 600px;
-      padding: 60px;
+      right: 175px;
+      transform: translateY(-50%);
+      width: 560px;
+      padding: 60px 40px 80px;
       text-align: center;
-      background-color: rgba(238, 244, 248, 0.70);
+      background-color: rgba(227, 222, 203, 0.3);
+      backdrop-filter: blur(6px);
+      border-top: 4px solid #aac7d1;
 
-
-      .mainTitle{
-        padding-left: 50px;
-        font-size: 24px;
-        font-weight: 700;
-        color: #131C28;
-        text-align: left;
+      .mainTitle {
+        font-size: 30px;
+        color: #fff;
         position: relative;
-        margin-bottom: 20px;
-        &::before{
-          content: '';
-          position: absolute;
-          top: 0;
-          left: 0;
-          width: 6px;
-          height: 100%;
-          background-color: #131C28;
-        }
+        margin: 20px 0;
+        letter-spacing: 4px;
       }
 
       .inputBox {
         width: 100%;
-        padding:  0 40px;
+        padding: 0 40px;
+
+        input::-webkit-input-placeholder {
+          /* WebKit browsers */
+          color: rgba(255, 255, 255, .6);
+        }
+
+        input:-moz-placeholder {
+          /* Mozilla Firefox 4 to 18 */
+          color: rgba(255, 255, 255, .6);
+        }
+
+        input::-moz-placeholder {
+          /* Mozilla Firefox 19+ */
+          color: rgba(255, 255, 255, .6);
+        }
+
+        input:-ms-input-placeholder {
+          /* Internet Explorer 10+ */
+          color: rgba(255, 255, 255, .6);
+        }
+
         .inputBoxRow {
           width: 100%;
-          margin:0 auto 40px;
+          margin: 0 auto 40px;
 
           .ant-input-suffix .ant-input-password-icon {
-            color: #131C28;
+            color: #fff;
             font-size: 22px;
           }
         }
@@ -86,7 +96,7 @@
 
         input:-webkit-autofill {
           font-size: 18px !important;
-          -webkit-text-fill-color: #131C28 !important;
+          -webkit-text-fill-color: #fff !important;
           background-image: none;
           -webkit-box-shadow: 0 0 0px 1000px transparent inset !important; //填充阴影,可以用来遮住背景色
           background-color: transparent;
@@ -100,9 +110,9 @@
           width: 100%;
           height: 60px;
           border: none;
-          border-bottom: 1px solid #131C28;
+          border-bottom: 1px solid #fff;
           border-radius: 0;
-          color: #131C28;
+          color: #fff;
 
           .ant-input {
             background-color: transparent;
@@ -119,10 +129,13 @@
       .loginBtn {
         margin-top: 50px;
         padding: 0 40px;
+
         .ant-btn {
           font-size: 24px;
           width: 100%;
           height: 50px;
+          background-color: var(--themeColor2);
+          color: #94844B;
         }
       }
 

+ 7 - 5
后台管理/src/pages/Login/index.tsx

@@ -9,6 +9,7 @@ import { setTokenInfo } from "@/utils/storage";
 import history from "@/utils/history";
 import { MessageFu } from "@/utils/message";
 import { userLoginAPI } from "@/store/action/layout";
+import loginLogoImg from "@/assets/img/logo.png";
 
 export default function Login() {
   // 账号密码
@@ -22,7 +23,7 @@ export default function Login() {
   // 点击登录
   const loginClickFu = async () => {
     // 非空判断
-    if (userName === "") return MessageFu.warning("请输入用户名!");
+    if (userName === "") return MessageFu.warning("请输入账号!");
     else if (passWord === "") return MessageFu.warning("请输入密码!");
     const obj = {
       userName,
@@ -35,13 +36,14 @@ export default function Login() {
       setTokenInfo(res.data);
       history.push("/");
     } else if (res.code === 3014)
-      MessageFu.warning("用户名不存在或密码错误,请联系管理员!");
+      MessageFu.warning("账号不存在或密码错误,请联系管理员!");
   };
 
   return (
     <div className={styles.Login}>
       <div className="main">
-        <div className="mainTitle">登 录</div>
+        <img className="loginLogo" src={loginLogoImg} alt="" />
+        <div className="mainTitle">云上展览管理系统</div>
         {/* 账号密码输入框 */}
         <div className="inputBox">
           <div className="inputBoxRow">
@@ -50,7 +52,7 @@ export default function Login() {
               value={userName}
               onChange={(e) => setUserName(e.target.value.trim())}
               prefix={<UserOutlined />}
-              placeholder="请输入用户名"
+              placeholder="请输入账号"
               maxLength={15}
             />
           </div>
@@ -60,7 +62,7 @@ export default function Login() {
               value={passWord}
               onChange={(e) => setPassWord(e.target.value.trim())}
               prefix={<LockOutlined />}
-              placeholder="请输入用户密码"
+              placeholder="请输入密码"
               maxLength={15}
             />
           </div>

+ 32 - 0
后台管理/src/store/action/A1Order.ts

@@ -0,0 +1,32 @@
+import http from "@/utils/http";
+import { AppDispatch } from "..";
+/**
+ * 获取列表
+ */
+export const A1_APIgetList = (data: any) => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post("cms/book/pageList", data);
+    if (res.code === 0) {
+      const obj = {
+        list: res.data.records,
+        total: res.data.total,
+      };
+
+      dispatch({ type: "A1/getList", payload: obj });
+    }
+  };
+};
+
+/**
+ * 导出
+ */
+export const A1_APIlistExport = (data: any) => {
+  return http.post("cms/book/pageList", data);
+};
+
+/**
+ * 删除
+ */
+export const A1_APIdelById = (id: number) => {
+  return http.get(`cms/book/remove/${id}`);
+};

+ 54 - 0
后台管理/src/store/action/A2Gallery.ts

@@ -0,0 +1,54 @@
+import http from "@/utils/http";
+import { AppDispatch } from "..";
+
+/**
+ * 获取列表
+ */
+export const A2_APIgetList = (data: any, flag?: boolean) => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post("cms/exhibition/pageList", data);
+    if (res.code === 0) {
+      const obj = {
+        list: res.data.records,
+        total: res.data.total,
+      };
+      if (flag) dispatch({ type: "A2/inGetList", payload: res.data.records });
+      else dispatch({ type: "A2/getList", payload: obj });
+    }
+  };
+};
+
+/**
+ * 获取列表-A1下拉
+ */
+export const A2_APIgetListSelect = (data: any) => {
+  return http.post("cms/exhibition/pageList", data);
+};
+
+/**
+ * 通过id获取详情
+ */
+export const A2_APIgetInfoById = (id: number) => {
+  return http.get(`cms/exhibition/detail/${id}`);
+};
+
+/**
+ * 新增、修改
+ */
+export const A2_APIeditItem = (data: any) => {
+  return http.post("cms/exhibition/save", data);
+};
+
+/**
+ * 删除
+ */
+export const A2_APIdelItem = (id: number) => {
+  return http.get(`cms/exhibition/remove/${id}`);
+};
+
+/**
+ * 置顶
+ */
+export const A2_APIupdateIndex = (id: number, parentId: number) => {
+  return http.get(`cms/exhibition/updateIndex/${id}/${parentId}`);
+};

+ 28 - 0
后台管理/src/store/reducer/A1Order.ts

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

+ 32 - 0
后台管理/src/store/reducer/A2Gallery.ts

@@ -0,0 +1,32 @@
+import { A2TableType } from "@/types";
+
+// 初始化状态
+const initState = {
+  // 外层列表数据
+  tableInfo: {
+    list: [] as A2TableType[],
+    total: 0,
+  },
+  // 里程数据
+  inTableInfo: [] as A2TableType[],
+};
+
+// 定义 action 类型
+type Props =
+  | { type: "A2/getList"; payload: { list: A2TableType[]; total: number } }
+  | { type: "A2/inGetList"; payload: A2TableType[] };
+
+// 频道 reducer
+export default function A1Reducer(state = initState, action: Props) {
+  switch (action.type) {
+    // 获取列表数据
+    case "A2/getList":
+      return { ...state, tableInfo: action.payload };
+    // 里程获取列表数据
+    case "A2/inGetList":
+      return { ...state, inTableInfo: action.payload };
+
+    default:
+      return state;
+  }
+}

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

@@ -3,12 +3,16 @@ import { combineReducers } from "redux";
 
 // 导入 登录 模块的 reducer
 import A0Layout from "./layout";
+import A1Order from "./A1Order";
+import A2Gallery from "./A2Gallery";
 import A4User from "./A4User";
 import A5Log from "./A5Log";
 
 // 合并 reducer
 const rootReducer = combineReducers({
   A0Layout,
+  A1Order,
+  A2Gallery,
   A4User,
   A5Log,
 });

+ 13 - 0
后台管理/src/types/api/A1Order.d.ts

@@ -0,0 +1,13 @@
+export type A1TableType = {
+  bookDay: string;
+  bootTimeScope: string;
+  contact: string;
+  createTime: string;
+  creatorId?: any;
+  creatorName: string;
+  description: string;
+  exhibitionName: string;
+  id: number;
+  organ: string;
+  updateTime: string;
+};

+ 20 - 0
后台管理/src/types/api/A2Gallery.ts

@@ -0,0 +1,20 @@
+export type A2TableType = {
+	address: string;
+	cityId: number;
+	createTime: string;
+	creatorId?: any;
+	creatorName: string;
+	description: string;
+	display: number;
+	hasIndex?: any;
+	id: number;
+	link: string;
+	name: string;
+	openTime: string;
+	parentId?: any;
+	tag: string;
+	thumb: string;
+	type: string;
+	updateTime: string;
+}
+

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

@@ -1,3 +1,5 @@
 export * from './api/layot'
+export * from './api/A1Order'
+export * from './api/A2Gallery'
 export * from './api/A4User'
 export * from './api/A5Log'

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

@@ -7,12 +7,12 @@ import { domShowFu } from "./domShow";
 // 请求基地址
 export const baseURL =
   // 线下的图片地址需要加上/api/
-  // process.env.NODE_ENV === "development"
-  //   ? "http://192.168.20.55:8050/api/"
-  //   : "";
   process.env.NODE_ENV === "development"
-    ? "https://wxfalangchang.4dage.com"
+    ? "http://192.168.20.55:8052/api/"
     : "";
+  // process.env.NODE_ENV === "development"
+  //   ? "https://wxfalangchang.4dage.com"
+  //   : "";
 
 // 处理  类型“AxiosResponse<any, any>”上不存在属性“code”
 declare module "axios" {
@@ -25,10 +25,10 @@ declare module "axios" {
 // 创建 axios 实例
 const http = axios.create({
   // --------线下的地址不用加/api/
-  // baseURL: baseURL,
+  baseURL: baseURL,
 
   // --------打包或线上环境接口需要加上api/
-  baseURL: baseURL + "/api/",
+  // baseURL: baseURL + "/api/",
   timeout: 5000,
 });