Bläddra i källkod

up-相机管理

shaogen1995 1 år sedan
förälder
incheckning
51a6938fe8

+ 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",
@@ -4587,6 +4588,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",
@@ -5358,6 +5374,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",
@@ -5571,6 +5592,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",
@@ -5702,6 +5743,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",
@@ -5921,6 +5982,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",
@@ -7623,6 +7695,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",
@@ -7790,6 +7870,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",
@@ -8096,6 +8181,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",
@@ -11057,6 +11150,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",
@@ -13322,6 +13426,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",
@@ -13503,6 +13618,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",
@@ -15027,6 +15147,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.10",
       "resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.0.10.tgz",
@@ -15363,6 +15491,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",
@@ -16754,6 +16893,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",
@@ -17128,6 +17283,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",
@@ -20559,6 +20741,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",
@@ -21181,6 +21372,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",
@@ -21359,6 +21555,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",
@@ -21464,6 +21676,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",
@@ -21653,6 +21881,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",
@@ -22960,6 +23193,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",
@@ -23107,6 +23345,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",
@@ -23339,6 +23582,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",
@@ -25649,6 +25897,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",
@@ -27238,6 +27497,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",
@@ -27389,6 +27653,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",
@@ -28499,6 +28768,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.10",
       "resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.0.10.tgz",
@@ -28789,6 +29066,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",
@@ -29881,6 +30166,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",
@@ -30211,6 +30506,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",

+ 31 - 0
src/pages/A1Camera/AddCamera/index.module.scss

@@ -0,0 +1,31 @@
+.AddCamera {
+  position: absolute;
+  z-index: 10;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: #fff;
+  border-radius: 10px;
+  padding: 24px;
+
+  :global {
+    .A1addMain {
+      overflow-y: auto;
+      width: 100%;
+      height: calc(100% - 80px);
+
+      .ant-form {
+        width: 800px;
+      }
+      .A1addBtn {
+        position: absolute;
+        bottom: 0px;
+        left: 50%;
+        transform: translateX(-50%);
+   
+      }
+
+    }
+  }
+}

+ 166 - 0
src/pages/A1Camera/AddCamera/index.tsx

@@ -0,0 +1,166 @@
+import React, { useCallback, useEffect, useRef, useState } from "react";
+import styles from "./index.module.scss";
+import { A1addType, options1 } from "../data";
+import { Button, Form, FormInstance, Input, Popconfirm, Select } from "antd";
+import {
+  A1_APIadd,
+  A1_APIgetInfo,
+  A1_APIgetUserList,
+} from "@/store/action/A1Camera";
+import { getTokenInfo } from "@/utils/storage";
+import TextArea from "antd/es/input/TextArea";
+import { MessageFu } from "@/utils/message";
+
+type Props = {
+  openInfo: A1addType;
+  closeFu: () => void;
+  upTableFu: () => void;
+  addTableFu: () => void;
+};
+
+function AddCamera({ openInfo, closeFu, upTableFu, addTableFu }: Props) {
+  // 表单的ref
+  const FormBoxRef = useRef<FormInstance>(null);
+
+  // 获取用户列表的所有用户,用于表单的  项目经理 的下拉
+  const [pmList, setPmList] = useState(
+    [] as { value: number; label: string }[]
+  );
+
+  const getUserListFu = useCallback(async () => {
+    const res = await A1_APIgetUserList({
+      pageSize: 99999,
+      pageNum: 1,
+    });
+    if (res.code === 0) {
+      setPmList(
+        res.data.records.map((v: any) => ({
+          value: v.id,
+          label: `${v.userName} - ${v.roleName}${
+            v.realName ? " - " + v.realName : ""
+          }`,
+        }))
+      );
+    }
+  }, []);
+
+  // 通过id获取详情
+  const getInfoFu = useCallback(async (id: number) => {
+    const res = await A1_APIgetInfo(id);
+    if (res.code === 0) {
+      FormBoxRef.current?.setFieldsValue(res.data);
+    }
+  }, []);
+
+  useEffect(() => {
+    getUserListFu();
+
+    if (openInfo.txt === "新增") {
+      FormBoxRef.current?.setFieldsValue({
+        status: "使用中",
+        pmUserId: getTokenInfo().user.id,
+      });
+    } else getInfoFu(openInfo.id);
+  }, [getInfoFu, getUserListFu, openInfo]);
+
+  // 没有通过校验
+  const onFinishFailed = useCallback(() => {}, []);
+
+  // 通过校验点击确定
+  const onFinish = useCallback(
+    async (value: any) => {
+      const res = await A1_APIadd({
+        ...value,
+        id: openInfo.txt === "新增" ? null : openInfo.id,
+        typeIn: "pc",
+      });
+      if (res.code === 0) {
+        MessageFu.success(openInfo.txt + "成功!");
+        openInfo.txt === "新增" ? addTableFu() : upTableFu();
+        closeFu();
+      }
+    },
+    [addTableFu, closeFu, openInfo.id, openInfo.txt, upTableFu]
+  );
+
+  return (
+    <div className={styles.AddCamera}>
+      <div className="A1addMain">
+        <Form
+          scrollToFirstError={true}
+          ref={FormBoxRef}
+          labelCol={{ span: 3 }}
+          name="basic"
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}
+          autoComplete="off"
+        >
+          <Form.Item
+            label="SN编码"
+            name="cameraSn"
+            rules={[{ required: true, message: "请输入SN编码!" }]}
+            getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
+          >
+            <Input maxLength={20} showCount placeholder="请输入内容" />
+          </Form.Item>
+
+          <Form.Item
+            label="相机工况"
+            name="status"
+            rules={[{ required: true, message: "请选择相机工况!" }]}
+          >
+            <Select
+              style={{ width: 300 }}
+              placeholder="请选择"
+              options={options1.filter((v) => v.label !== "全部")}
+            />
+          </Form.Item>
+
+          <Form.Item
+            label="项目经理"
+            name="pmUserId"
+            rules={[{ required: true, message: "请选择项目经理!" }]}
+          >
+            <Select
+              style={{ width: 300 }}
+              placeholder="请选择"
+              options={pmList}
+            />
+          </Form.Item>
+
+          <Form.Item label="备注" name="remark">
+            <TextArea
+              style={{ width: 600 }}
+              autoSize
+              placeholder="请输入内容"
+              showCount
+              maxLength={200}
+            />
+          </Form.Item>
+
+          {/* 确定和取消按钮 */}
+          <br />
+          <Form.Item className="A1addBtn">
+            <Button type="primary" htmlType="submit">
+              提交
+            </Button>
+            &emsp;
+            <Popconfirm
+              title="放弃编辑后,信息将不会保存!"
+              okText="放弃"
+              cancelText="取消"
+              onConfirm={closeFu}
+              okButtonProps={{ loading: false }}
+            >
+              <Button>取消</Button>
+            </Popconfirm>
+          </Form.Item>
+        </Form>
+      </div>
+    </div>
+  );
+}
+
+const MemoAddCamera = React.memo(AddCamera);
+
+export default MemoAddCamera;

+ 112 - 0
src/pages/A1Camera/LogCamera/index.module.scss

@@ -0,0 +1,112 @@
+.LogCamera {
+  position: absolute;
+  z-index: 10;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: #fff;
+  border-radius: 10px;
+  padding: 24px;
+
+  :global {
+    .A1Ltop {
+      display: flex;
+      align-items: center;
+      margin-bottom: 20px;
+      position: relative;
+
+      &>div {
+        font-weight: 700;
+        font-size: 24px;
+      }
+
+      &>span {
+        font-size: 14px;
+        color: #ff4d4f;
+      }
+
+      .A1LtopBack {
+        position: absolute;
+        right: 0;
+        top: 0;
+      }
+    }
+
+    .A1Ltable {
+      border-radius: 10px;
+      margin-top: 15px;
+      height: calc(100% - 32px);
+      background-color: #fff;
+
+      .ant-table-body {
+        height: 670px;
+        overflow-y: auto !important;
+        overflow-y: overlay !important;
+
+      }
+    }
+  }
+}
+
+// 表单弹窗
+.LogCameraModal {
+  :global {
+    .ant-modal-close {
+      display: none;
+    }
+
+    .ant-modal {
+      width: 800px !important;
+    }
+
+    .A1LMmain {
+      margin-top: 20px;
+      padding-right: 40px;
+
+      .A1LMrow {
+        display: flex;
+        align-items: center;
+        margin-bottom: 20px;
+
+        .A1LMrow1 {
+          width: 100px;
+          text-align: right;
+
+          &>span {
+            color: #ff4d4f;
+          }
+
+        }
+
+        .A1LMrow2 {
+          width: calc(100% - 100px);
+
+          .A1LMrow2tit {
+            position: relative;
+            top: -3px;
+            opacity: 0;
+            color: #ff4d4f;
+            transition: all .3s;
+          }
+
+          .A1LMrow2titShow {
+            opacity: 1;
+            top: 0;
+          }
+        }
+
+
+      }
+
+      .A1LMrowLast {
+        margin-top: -16px;
+      }
+
+      .A1LMbtn {
+        margin-top: 20px;
+        text-align: center;
+      }
+    }
+  }
+}

+ 287 - 0
src/pages/A1Camera/LogCamera/index.tsx

@@ -0,0 +1,287 @@
+import React, { useCallback, useEffect, useMemo, useState } from "react";
+import styles from "./index.module.scss";
+import { Button, DatePicker, Input, Modal, Popconfirm, Table } from "antd";
+import {
+  A1_APIaddBySn,
+  A1_APIgetInfoBySn,
+  A1_APIgetListBySn,
+  A1_APIremoveBySn,
+} from "@/store/action/A1Camera";
+import dayjs from "dayjs";
+import { MessageFu } from "@/utils/message";
+import classNames from "classnames";
+
+const { RangePicker } = DatePicker;
+
+type TableType = {
+  cameraSn: string;
+  createTime: string;
+  creatorId: number;
+  creatorName: string;
+  dept: string;
+  endTime: string;
+  id: number;
+  startTime: string;
+  updateTime: string;
+  user: string;
+};
+
+type Props = {
+  closeFu: () => void;
+  logSn: string;
+};
+
+function LogCamera({ logSn, closeFu }: Props) {
+  const [tableList, setTableList] = useState([] as TableType[]);
+
+  const getListFu = useCallback(async () => {
+    const res = await A1_APIgetListBySn(logSn);
+    if (res.code === 0) {
+      setTableList(res.data);
+    }
+  }, [logSn]);
+
+  useEffect(() => {
+    getListFu();
+  }, [getListFu]);
+
+  // 点击外面表格的删除
+  const delByIdFu = useCallback(
+    async (id: number) => {
+      const res = await A1_APIremoveBySn(id);
+      if (res.code === 0) {
+        MessageFu.success("删除成功!");
+        getListFu();
+      }
+    },
+    [getListFu]
+  );
+
+  const columns = useMemo(() => {
+    return [
+      {
+        title: "领用部门",
+        render: (item: TableType) => (item.dept ? item.dept : "(空)"),
+      },
+      {
+        title: "领用人员",
+        render: (item: TableType) => (item.user ? item.user : "(空)"),
+      },
+      {
+        title: "领用日期",
+        render: (item: TableType) => `${item.startTime} 至 ${item.endTime}`,
+      },
+      {
+        title: "操作",
+        render: (item: TableType) => (
+          <>
+            <Button
+              size="small"
+              type="text"
+              onClick={() => setModelId(item.id)}
+            >
+              编辑
+            </Button>
+            <Popconfirm
+              title="删除后无法恢复,是否删除?"
+              okText="删除"
+              cancelText="取消"
+              onConfirm={() => delByIdFu(item.id)}
+              okButtonProps={{ loading: false }}
+            >
+              <Button size="small" type="text" danger>
+                删除
+              </Button>
+            </Popconfirm>
+          </>
+        ),
+      },
+    ];
+  }, [delByIdFu]);
+
+  // 表单弹窗
+  const [modelId, setModelId] = useState(0);
+
+  // modelId 改变的时候 把表单里面的数据 初始化
+
+  const getInfoBySnFu = useCallback(async (id: number) => {
+    const res = await A1_APIgetInfoBySn(id);
+    if (res.code === 0) {
+      const { dept, user, startTime, endTime } = res.data;
+      // console.log(123, res);
+      setDept(dept);
+      setUser(user);
+      setTime([startTime, endTime]);
+    }
+  }, []);
+
+  useEffect(() => {
+    if (modelId === 0) {
+      setDept("");
+      setUser("");
+      setTime(null);
+      setIsOk(false);
+    } else if (modelId > 0) getInfoBySnFu(modelId);
+  }, [getInfoBySnFu, modelId]);
+
+  // 表单信息
+  const [dept, setDept] = useState("");
+  const [user, setUser] = useState("");
+  const [time, setTime] = useState<null | string[]>(null);
+
+  const [isOk, setIsOk] = useState(false);
+
+  // 点击确定
+  const btnOkFu = useCallback(async () => {
+    setIsOk(true);
+    if (!dept && !user) return;
+    const res = await A1_APIaddBySn({
+      cameraSn: logSn,
+      dept,
+      user,
+      startTime: time![0],
+      endTime: time![1],
+      id: modelId > 0 ? modelId : null,
+    });
+
+    if (res.code === 0) {
+      MessageFu.success(modelId > 0 ? "编辑成功!" : "新增成功!");
+      getListFu();
+      setModelId(0);
+    }
+  }, [dept, getListFu, logSn, modelId, time, user]);
+
+  return (
+    <div className={styles.LogCamera}>
+      <div className="A1Ltop">
+        <div>{logSn} - 领用记录</div>&emsp;&emsp;
+        <Button
+          type="primary"
+          onClick={() => setModelId(-1)}
+          disabled={tableList.length >= 20}
+        >
+          登记领用信息
+        </Button>
+        &emsp;&emsp;
+        <span hidden={tableList.length < 20}>最多只能添加20条记录</span>
+        <div className="A1LtopBack" onClick={closeFu}>
+          <Button>返回</Button>
+        </div>
+      </div>
+      <div className="A1Ltable">
+        <Table
+          scroll={{ y: 670 }}
+          dataSource={tableList}
+          columns={columns}
+          rowKey="id"
+          pagination={false}
+        />
+      </div>
+
+      {/* 新增和编辑领用信息的弹窗 */}
+      <Modal
+        wrapClassName={styles.LogCameraModal}
+        open={!!modelId}
+        title={`${modelId > 0 ? "编辑" : "登记"}领用信息`}
+        footer={
+          [] // 设置footer为空,去掉 取消 确定默认按钮
+        }
+      >
+        <div className="A1LMmain">
+          <div className="A1LMrow">
+            <div className="A1LMrow1">领用部门:</div>
+            <div className="A1LMrow2">
+              <Input
+                value={dept}
+                onChange={(e) => setDept(e.target.value.replace(/\s+/g, ""))}
+                maxLength={20}
+                showCount
+                placeholder="请输入内容,如采集部门等"
+              />
+            </div>
+          </div>
+
+          <div className="A1LMrow">
+            <div className="A1LMrow1">领用人员:</div>
+            <div className="A1LMrow2">
+              <Input
+                value={user}
+                onChange={(e) => setUser(e.target.value.replace(/\s+/g, ""))}
+                maxLength={20}
+                showCount
+                placeholder="请输入内容,如人员姓名,联系方式等"
+              />
+            </div>
+          </div>
+
+          <div className="A1LMrow">
+            <div className="A1LMrow1">
+              <span>* </span> 领用日期:
+            </div>
+            <div className="A1LMrow2">
+              <RangePicker
+                value={
+                  time
+                    ? [
+                        dayjs(time[0], "YYYY-MM-DD"),
+                        dayjs(time[1], "YYYY-MM-DD"),
+                      ]
+                    : null
+                }
+                onChange={(e) => {
+                  if (e && e.length && e.length > 1) {
+                    const str1 = dayjs(e[0]).format("YYYY-MM-DD");
+                    const str2 = dayjs(e[1]).format("YYYY-MM-DD");
+                    setTime([str1, str2]);
+                  } else setTime(null);
+                }}
+              />
+            </div>
+          </div>
+
+          <div className="A1LMrow A1LMrowLast">
+            <div className="A1LMrow1"></div>
+            <div className="A1LMrow2">
+              <div
+                className={classNames(
+                  "A1LMrow2tit",
+                  !time && isOk ? "A1LMrow2titShow" : ""
+                )}
+              >
+                请选择领用日期!
+              </div>
+              <div
+                className={classNames(
+                  "A1LMrow2tit",
+                  !dept && !user && isOk ? "A1LMrow2titShow" : ""
+                )}
+              >
+                部门和人员至少填入一项
+              </div>
+            </div>
+          </div>
+
+          <div className="A1LMbtn">
+            <Button type="primary" onClick={btnOkFu}>
+              提交
+            </Button>
+            &emsp;
+            <Popconfirm
+              title="放弃编辑后,信息将不会保存!"
+              okText="放弃"
+              cancelText="取消"
+              onConfirm={() => setModelId(0)}
+              okButtonProps={{ loading: false }}
+            >
+              <Button>取消</Button>
+            </Popconfirm>
+          </div>
+        </div>
+      </Modal>
+    </div>
+  );
+}
+
+const MemoLogCamera = React.memo(LogCamera);
+
+export default MemoLogCamera;

+ 24 - 18
src/pages/A1Camera/data.ts

@@ -7,36 +7,42 @@ export type TableSelectType = {
   pageNum: number;
 };
 
-export const options1 =[
+export const options1 = [
   {
-    value:'',
-    label:'全部'
+    value: "",
+    label: "全部",
   },
   {
-    value:'使用中',
-    label:'使用中'
+    value: "使用中",
+    label: "使用中",
   },
   {
-    value:'已回收',
-    label:'已回收'
+    value: "已回收",
+    label: "已回收",
   },
   {
-    value:'检修中',
-    label:'检修中'
+    value: "检修中",
+    label: "检修中",
   },
-]
+];
 
-export const options2 =[
+export const options2 = [
   {
-    value:'',
-    label:'全部'
+    value: "",
+    label: "全部",
   },
   {
-    value:'pc',
-    label:'系统'
+    value: "pc",
+    label: "系统",
   },
   {
-    value:'app',
-    label:'移动端'
+    value: "app",
+    label: "移动端",
   },
-]
+];
+
+// 新增编辑的 type
+export type A1addType = {
+  id: number;
+  txt: "" | "新增" | "编辑";
+};

+ 1 - 0
src/pages/A1Camera/index.module.scss

@@ -1,4 +1,5 @@
 .A1Camera {
+  position: relative;
   :global {
     .A1top {
       display: flex;

+ 131 - 11
src/pages/A1Camera/index.tsx

@@ -7,11 +7,20 @@ import React, {
 } from "react";
 import styles from "./index.module.scss";
 import { Button, Input, Popconfirm, Select, Table } from "antd";
-import { TableSelectType, options1, options2 } from "./data";
+import { A1addType, TableSelectType, options1, options2 } from "./data";
 import { useDispatch, useSelector } from "react-redux";
-import { A1_APIGgetlist } from "@/store/action/A1Camera";
+import {
+  A1_APIgetlist,
+  A1_APIgetlistDerive,
+  A1_APIremove,
+} from "@/store/action/A1Camera";
 import { RootState } from "@/store";
 import { A1ListType } from "@/types";
+import ExportJsonExcel from "js-export-excel";
+import { MessageFu } from "@/utils/message";
+import dayjs from "dayjs";
+import AddCamera from "./AddCamera";
+import LogCamera from "./LogCamera";
 
 function A1Camera() {
   const dispatch = useDispatch();
@@ -44,7 +53,7 @@ function A1Camera() {
       status: tableSelect.status === "全部" ? "" : tableSelect.status,
       typeIn: tableSelect.typeIn === "全部" ? "" : tableSelect.typeIn,
     };
-    dispatch(A1_APIGgetlist(obj));
+    dispatch(A1_APIgetlist(obj));
   }, [dispatch, tableSelect]);
 
   useEffect(() => {
@@ -64,7 +73,68 @@ function A1Camera() {
   );
 
   // 点击删除
-  const delByIdFu = useCallback((id: number) => {}, []);
+  const delByIdFu = useCallback(
+    async (id: number) => {
+      const res = await A1_APIremove(id);
+      if (res.code === 0) {
+        MessageFu.success("删除成功!");
+        getListFu();
+      }
+    },
+    [getListFu]
+  );
+
+  // 点击导出
+  const deriveFu = useCallback(async () => {
+    if (A1TableList.list.length === 0)
+      return MessageFu.warning("当前搜索条件没有数据!");
+    const name = "相机管理" + dayjs(new Date()).format("YYYY-MM-DD HH:mm");
+
+    const res = await A1_APIgetlistDerive({
+      ...tableSelect,
+      status: tableSelect.status === "全部" ? "" : tableSelect.status,
+      typeIn: tableSelect.typeIn === "全部" ? "" : tableSelect.typeIn,
+      pageNum: 1,
+      pageSize: 99999,
+    });
+
+    if (res.code === 0) {
+      const option = {
+        fileName: name,
+        datas: [
+          {
+            sheetData: res.data.records.map((v: A1ListType) => ({
+              ...v,
+              typeIn: v.typeIn === "pc" ? "系统" : "移动端",
+              remark: v.remark ? v.remark : "(空)",
+              pmName: v.id === 1 ? "管理员" : v.pmName || "匿名",
+            })),
+            sheetName: name,
+            sheetFilter: [
+              "cameraSn",
+              "pmName",
+              "status",
+              "typeIn",
+              "updateTime",
+              "remark",
+            ],
+            sheetHeader: [
+              "相机SN码",
+              "项目经理",
+              "相机工况",
+              "录入方式",
+              "最近编辑时间",
+              "备注",
+            ],
+            columnWidths: [10, 10, 10, 10, 10, 20],
+          },
+        ],
+      };
+
+      const toExcel = new ExportJsonExcel(option); //new
+      toExcel.saveExcel(); //保存
+    }
+  }, [A1TableList.list.length, tableSelect]);
 
   const columns = useMemo(() => {
     return [
@@ -74,7 +144,12 @@ function A1Camera() {
       },
       {
         title: "项目经理",
-        render: (item: A1ListType) => (item.pmName ? item.pmName : "(空)"),
+        render: (item: A1ListType) => {
+          if (item.id === 1) return "管理员";
+          else {
+            return item.pmName || "匿名";
+          }
+        },
       },
       {
         title: "相机工况",
@@ -109,10 +184,18 @@ function A1Camera() {
         title: "操作",
         render: (item: A1ListType) => (
           <>
-            <Button size="small" type="text">
-              查看
+            <Button
+              size="small"
+              type="text"
+              onClick={() => setLogSn(item.cameraSn)}
+            >
+              领用记录
             </Button>
-            <Button size="small" type="text">
+            <Button
+              size="small"
+              type="text"
+              onClick={() => setOpenInfo({ id: item.id, txt: "编辑" })}
+            >
               编辑
             </Button>
             <Popconfirm
@@ -147,9 +230,25 @@ function A1Camera() {
     });
   }, []);
 
+  // 点击新增和编辑的数据
+  const [openInfo, setOpenInfo] = useState<A1addType>({ id: 0, txt: "" });
+
+  // 左上角的 title
+  const leftTitle = useMemo(() => {
+    const obj = {
+      "": "相机管理",
+      新增: "新增相机",
+      编辑: "编辑相机",
+    };
+    return obj[openInfo.txt];
+  }, [openInfo.txt]);
+
+  // 点击 领用记录
+  const [logSn, setLogSn] = useState("");
+
   return (
     <div className={styles.A1Camera}>
-      <div className="pageTitle">相机管理</div>
+      <div className="pageTitle">{leftTitle}{logSn?' - 领用记录':''}</div>
       {/* 顶部筛选 */}
       <div className="A1top">
         {/* 左侧输入框 */}
@@ -205,8 +304,16 @@ function A1Camera() {
         {/* 右侧按钮 */}
         <div className="A1top2">
           <Button onClick={resetSelectFu}>重置</Button>&emsp;
-          <Button type="primary">新增</Button>&emsp;
-          <Button type="primary">导出表格</Button>
+          <Button
+            type="primary"
+            onClick={() => setOpenInfo({ id: -1, txt: "新增" })}
+          >
+            新增
+          </Button>
+          &emsp;
+          <Button type="primary" onClick={deriveFu}>
+            导出表格
+          </Button>
         </div>
       </div>
       {/* 表格主体 */}
@@ -227,6 +334,19 @@ function A1Camera() {
           }}
         />
       </div>
+
+      {/* 新增 编辑 查看 出来的页面 */}
+      {openInfo.id ? (
+        <AddCamera
+          openInfo={openInfo}
+          closeFu={() => setOpenInfo({ id: 0, txt: "" })}
+          upTableFu={getListFu}
+          addTableFu={resetSelectFu}
+        />
+      ) : null}
+
+      {/* 领用记录 */}
+      {logSn ? <LogCamera logSn={logSn} closeFu={() => setLogSn("")} /> : null}
     </div>
   );
 }

+ 9 - 0
src/pages/C1User/AddUser/index.tsx

@@ -171,6 +171,7 @@ function AddUser({ openInfo, closeFu, upTableFu, addTableFu }: Props) {
           <Form.Item
             label="真实姓名"
             name="realName"
+            rules={[{ required: true, message: "请输入真实姓名!" }]}
             getValueFromEvent={(e) => e.target.value.replace(/\s+/g, "")}
           >
             <Input
@@ -235,6 +236,14 @@ function AddUser({ openInfo, closeFu, upTableFu, addTableFu }: Props) {
                 >
                   至少添加一个城市 并 选择地点
                 </div>
+                <div
+                  className={classNames(
+                    "e_rowRtit",
+                    cityList.length >= 20 ? "e_rowRtitShow" : ""
+                  )}
+                >
+                  &emsp;&emsp;最多只能添加20个城市
+                </div>
               </div>
             </div>
           ) : null}

+ 67 - 2
src/store/action/A1Camera.ts

@@ -1,9 +1,9 @@
 import http from "@/utils/http";
 import { AppDispatch } from "..";
 /**
- * 获取 相机管理 表格列表
+ * 获取 相机管理 表格列表(存到仓库)
  */
-export const A1_APIGgetlist = (data: any) => {
+export const A1_APIgetlist = (data: any) => {
   return async (dispatch: AppDispatch) => {
     const res = await http.post("cms/camera/pageList", data);
     if (res.code === 0) {
@@ -15,3 +15,68 @@ export const A1_APIGgetlist = (data: any) => {
     }
   };
 };
+
+/**
+ * 获取 相机管理 表格列表(导出表格)
+ */
+export const A1_APIgetlistDerive = (data: any) => {
+  return http.post("cms/camera/pageList", data);
+};
+
+/**
+ * 获取 用户管理 表格列表(项目经理的 表单下拉)
+ */
+export const A1_APIgetUserList = (data: any) => {
+  return http.post("sys/user/pageList", data);
+};
+
+/**
+ * 删除单个表格数据
+ */
+export const A1_APIremove = (id: number) => {
+  return http.get(`cms/camera/remove/${id}`);
+};
+
+/**
+ * 新增/修改
+ */
+export const A1_APIadd = (data: any) => {
+  return http.post("cms/camera/save", data);
+};
+
+/**
+ * 通过id获取详情
+ */
+export const A1_APIgetInfo = (id: number) => {
+  return http.get(`cms/camera/detail/${id}`);
+};
+
+// -------------------sn码   领用信息
+
+/**
+ * 通过sn码获取领用信息列表
+ */
+export const A1_APIgetListBySn = (cameraSn: string) => {
+  return http.get(`cms/cameraUse/getList/${cameraSn}`);
+};
+
+/**
+ * 通过sn码新增 相机领用管理
+ */
+export const A1_APIaddBySn = (data: any) => {
+  return http.post("cms/cameraUse/save", data);
+};
+
+/**
+ * 通过sn码 删除里面的表格信息
+ */
+export const A1_APIremoveBySn = (id: number) => {
+  return http.get(`cms/cameraUse/remove/${id}`);
+};
+
+/**
+ * 通过sn码 获取领用信息详情
+ */
+export const A1_APIgetInfoBySn = (id: number) => {
+  return http.get(`cms/cameraUse/detail/${id}`);
+};

+ 1 - 1
src/store/action/C1User.ts

@@ -1,7 +1,7 @@
 import http from "@/utils/http";
 import { AppDispatch } from "..";
 /**
- * 获取 用户管理 表格列表
+ * 获取 用户管理 表格列表(存到仓库)
  */
 export const C1_APIGgetlist = (data: any) => {
   return async (dispatch: AppDispatch) => {

+ 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.61:8057/api/"
-  //   : "";
   process.env.NODE_ENV === "development"
-    ? "https://sit-tieta3d.4dage.com"
+    ? "http://192.168.20.61:8057/api/"
     : "";
+  // process.env.NODE_ENV === "development"
+  //   ? "https://sit-tieta3d.4dage.com"
+  //   : "";
 
 // 处理  类型“AxiosResponse<any, any>”上不存在属性“code”
 declare module "axios" {
@@ -27,10 +27,10 @@ export const baseUpUrl = baseURL + "/api/";
 // 创建 axios 实例
 const http = axios.create({
   // --------线下的地址不用加/api/
-  // baseURL: baseURL,
+  baseURL: baseURL,
 
   // --------打包或线上环境接口需要加上api/
-  baseURL: baseURL + "/api/",
+  // baseURL: baseURL + "/api/",
   timeout: 5000,
 });