Explorar el Código

业务订单 --还差查看

shaogen1995 hace 1 año
padre
commit
70804114e1
Se han modificado 35 ficheros con 2532 adiciones y 191 borrados
  1. 390 0
      package-lock.json
  2. 2 0
      package.json
  3. 0 43
      src/assets/styles/base.css
  4. 49 67
      src/assets/styles/base.less
  5. 46 0
      src/components/MyPopconfirm.tsx
  6. 2 2
      src/components/UpXlsx.tsx
  7. 72 0
      src/components/Z3upFiles/index.module.scss
  8. 210 0
      src/components/Z3upFiles/index.tsx
  9. 183 0
      src/components/ZRichTexts/index.module.scss
  10. 222 0
      src/components/ZRichTexts/index.tsx
  11. 12 0
      src/pages/A1Camera/A1Look/index.module.scss
  12. 13 0
      src/pages/A1Camera/A1Look/index.tsx
  13. 17 8
      src/pages/A1Camera/AddCamera/index.tsx
  14. 1 1
      src/pages/A1Camera/data.ts
  15. 4 1
      src/pages/A1Camera/index.module.scss
  16. 6 6
      src/pages/A1Camera/index.tsx
  17. 103 0
      src/pages/A2Abusiness/AddBusiness/index.module.scss
  18. 376 0
      src/pages/A2Abusiness/AddBusiness/index.tsx
  19. 24 0
      src/pages/A2Abusiness/data.ts
  20. 49 0
      src/pages/A2Abusiness/index.module.scss
  21. 477 0
      src/pages/A2Abusiness/index.tsx
  22. 4 0
      src/pages/A2Blogistics/index.module.scss
  23. 13 0
      src/pages/A2Blogistics/index.tsx
  24. 4 6
      src/pages/B1Plan/index.module.scss
  25. 3 4
      src/pages/B3Push/index.module.scss
  26. 6 4
      src/pages/B4JsonPush/index.module.scss
  27. 40 24
      src/pages/C1User/AddUser/city.ts
  28. 14 0
      src/pages/Layout/data.ts
  29. 45 0
      src/store/action/A2Abusiness.ts
  30. 27 0
      src/store/reducer/A2Abusiness.ts
  31. 15 13
      src/store/reducer/index.ts
  32. 26 0
      src/types/api/A2Abusiness.ts
  33. 13 12
      src/types/declaration.d.ts
  34. 1 0
      src/types/index.d.ts
  35. 63 0
      src/utils/authFilesLook.ts

+ 390 - 0
package-lock.json

@@ -19,6 +19,8 @@
         "antd": "^5.8.3",
         "antd-mobile": "^5.30.0",
         "axios": "^1.1.3",
+        "braft-editor": "^2.3.9",
+        "braft-utils": "^3.0.13",
         "dayjs": "^1.11.7",
         "js-base64": "^3.7.3",
         "js-export-excel": "^1.1.4",
@@ -5475,6 +5477,88 @@
         "node": ">=8"
       }
     },
+    "node_modules/braft-convert": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmmirror.com/braft-convert/-/braft-convert-2.3.0.tgz",
+      "integrity": "sha512-5km+dLHk8iYDv2iEYDrDQ2ld/ZoUx66QLql0qdm5PqZEcNXc8dBHGLORfzeu3iMw1jLeAiHxtdY5+ypuIhczVg==",
+      "dependencies": {
+        "draft-convert": "^2.0.0",
+        "draft-js": "^0.10.3"
+      },
+      "peerDependencies": {
+        "react": "^16.0.0"
+      }
+    },
+    "node_modules/braft-convert/node_modules/draft-convert": {
+      "version": "2.1.13",
+      "resolved": "https://registry.npmmirror.com/draft-convert/-/draft-convert-2.1.13.tgz",
+      "integrity": "sha512-/h/n4JCfyO8aWby7wKBkccHdsuVbbDyHWXi/B3Zf2pN++lN1lDOIVt5ulXCcbH2Y5YJEFzMJw/YGfN+R0axxxg==",
+      "dependencies": {
+        "@babel/runtime": "^7.5.5",
+        "immutable": "~3.7.4",
+        "invariant": "^2.2.1"
+      },
+      "peerDependencies": {
+        "draft-js": ">=0.7.0",
+        "react": "^15.0.2 || ^16.0.0-rc || ^16.0.0 || ^17.0.0 || ^18.0.0",
+        "react-dom": "^15.0.2 || ^16.0.0-rc || ^16.0.0 || ^17.0.0 || ^18.0.0"
+      }
+    },
+    "node_modules/braft-editor": {
+      "version": "2.3.9",
+      "resolved": "https://registry.npmmirror.com/braft-editor/-/braft-editor-2.3.9.tgz",
+      "integrity": "sha512-mqdPk/zI2dhFK8tW/A4Qj/AkkARLh5L/niNw+iif5wFqb6zh15rMlrShgz1nWO/QXyAKr8XtDgxiBbR0zWwtRg==",
+      "dependencies": {
+        "@babel/runtime": "^7.0.0",
+        "braft-convert": "^2.3.0",
+        "braft-finder": "^0.0.19",
+        "braft-utils": "^3.0.8",
+        "draft-convert": "^2.0.0",
+        "draft-js": "^0.10.3",
+        "draft-js-multidecorators": "^1.0.0",
+        "draftjs-utils": "^0.9.4",
+        "immutable": "~3.7.4"
+      },
+      "peerDependencies": {
+        "react": "^15.0.2|| ^16.0.0-rc || ^16.0.0",
+        "react-dom": "^15.0.2|| ^16.0.0-rc || ^16.0.0"
+      }
+    },
+    "node_modules/braft-editor/node_modules/braft-finder": {
+      "version": "0.0.19",
+      "resolved": "https://registry.npmmirror.com/braft-finder/-/braft-finder-0.0.19.tgz",
+      "integrity": "sha512-0kzI6/KbomJJhYX1hpjn4edCKhblyUyWdUrsgBmOrwy0vrj+pPkm69+Uf8Uj6KGAULM6LF0ooC++p7fqUGgFHw==",
+      "peerDependencies": {
+        "react": "^16.4.1",
+        "react-dom": "^16.4.1"
+      }
+    },
+    "node_modules/braft-editor/node_modules/draft-convert": {
+      "version": "2.1.13",
+      "resolved": "https://registry.npmmirror.com/draft-convert/-/draft-convert-2.1.13.tgz",
+      "integrity": "sha512-/h/n4JCfyO8aWby7wKBkccHdsuVbbDyHWXi/B3Zf2pN++lN1lDOIVt5ulXCcbH2Y5YJEFzMJw/YGfN+R0axxxg==",
+      "dependencies": {
+        "@babel/runtime": "^7.5.5",
+        "immutable": "~3.7.4",
+        "invariant": "^2.2.1"
+      },
+      "peerDependencies": {
+        "draft-js": ">=0.7.0",
+        "react": "^15.0.2 || ^16.0.0-rc || ^16.0.0 || ^17.0.0 || ^18.0.0",
+        "react-dom": "^15.0.2 || ^16.0.0-rc || ^16.0.0 || ^17.0.0 || ^18.0.0"
+      }
+    },
+    "node_modules/braft-utils": {
+      "version": "3.0.13",
+      "resolved": "https://registry.npmmirror.com/braft-utils/-/braft-utils-3.0.13.tgz",
+      "integrity": "sha512-92YNlc5RW3mNMo0zbWhnqz8PWr21AAPPhnfn3ZUoXM9+wBIuJQe6UyvOas+MEG9UOGFrvTDPbq60P3fdEhyMQQ==",
+      "peerDependencies": {
+        "braft-convert": "^2.1.4",
+        "draft-js": "^0.10.5",
+        "draftjs-utils": "^0.9.4",
+        "immutable": "~3.7.4"
+      }
+    },
     "node_modules/browser-process-hrtime": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
@@ -6741,6 +6825,37 @@
       "resolved": "https://registry.npmmirror.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
       "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
     },
+    "node_modules/draft-js": {
+      "version": "0.10.5",
+      "resolved": "https://registry.npmmirror.com/draft-js/-/draft-js-0.10.5.tgz",
+      "integrity": "sha512-LE6jSCV9nkPhfVX2ggcRLA4FKs6zWq9ceuO/88BpXdNCS7mjRTgs0NsV6piUCJX9YxMsB9An33wnkMmU2sD2Zg==",
+      "dependencies": {
+        "fbjs": "^0.8.15",
+        "immutable": "~3.7.4",
+        "object-assign": "^4.1.0"
+      },
+      "peerDependencies": {
+        "react": "^0.14.0 || ^15.0.0-rc || ^16.0.0-rc || ^16.0.0",
+        "react-dom": "^0.14.0 || ^15.0.0-rc || ^16.0.0-rc || ^16.0.0"
+      }
+    },
+    "node_modules/draft-js-multidecorators": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/draft-js-multidecorators/-/draft-js-multidecorators-1.0.0.tgz",
+      "integrity": "sha512-7qdy+YQol5iq38AoEerhgSJWhCzxvZLn1x5ODfUlGfWlg0SrZ9AXJbaxHVIjdSIZNrbVIm+WANujNxMqCmDSZQ==",
+      "dependencies": {
+        "immutable": "*"
+      }
+    },
+    "node_modules/draftjs-utils": {
+      "version": "0.9.4",
+      "resolved": "https://registry.npmmirror.com/draftjs-utils/-/draftjs-utils-0.9.4.tgz",
+      "integrity": "sha512-KYjABSbGpJrwrwmxVj5UhfV37MF/p0QRxKIyL+/+QOaJ8J9z1FBKxkblThbpR0nJi9lxPQWGg+gh+v0dAsSCCg==",
+      "peerDependencies": {
+        "draft-js": "^0.10.x",
+        "immutable": "3.x.x || 4.x.x"
+      }
+    },
     "node_modules/duplexer": {
       "version": "0.1.2",
       "resolved": "https://registry.npmmirror.com/duplexer/-/duplexer-0.1.2.tgz",
@@ -6799,6 +6914,14 @@
         "node": ">= 0.8"
       }
     },
+    "node_modules/encoding": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmmirror.com/encoding/-/encoding-0.1.13.tgz",
+      "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+      "dependencies": {
+        "iconv-lite": "^0.6.2"
+      }
+    },
     "node_modules/enhanced-resolve": {
       "version": "5.10.0",
       "resolved": "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz",
@@ -7844,6 +7967,34 @@
         "bser": "2.1.1"
       }
     },
+    "node_modules/fbjs": {
+      "version": "0.8.18",
+      "resolved": "https://registry.npmmirror.com/fbjs/-/fbjs-0.8.18.tgz",
+      "integrity": "sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==",
+      "dependencies": {
+        "core-js": "^1.0.0",
+        "isomorphic-fetch": "^2.1.1",
+        "loose-envify": "^1.0.0",
+        "object-assign": "^4.1.0",
+        "promise": "^7.1.1",
+        "setimmediate": "^1.0.5",
+        "ua-parser-js": "^0.7.30"
+      }
+    },
+    "node_modules/fbjs/node_modules/core-js": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmmirror.com/core-js/-/core-js-1.2.7.tgz",
+      "integrity": "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==",
+      "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js."
+    },
+    "node_modules/fbjs/node_modules/promise": {
+      "version": "7.3.1",
+      "resolved": "https://registry.npmmirror.com/promise/-/promise-7.3.1.tgz",
+      "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+      "dependencies": {
+        "asap": "~2.0.3"
+      }
+    },
     "node_modules/file-entry-cache": {
       "version": "6.0.1",
       "resolved": "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -8792,6 +8943,14 @@
       "resolved": "https://registry.npmmirror.com/immer/-/immer-9.0.16.tgz",
       "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ=="
     },
+    "node_modules/immutable": {
+      "version": "3.7.6",
+      "resolved": "https://registry.npmmirror.com/immutable/-/immutable-3.7.6.tgz",
+      "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
     "node_modules/import-fresh": {
       "version": "3.3.0",
       "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -8880,6 +9039,14 @@
       "resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz",
       "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="
     },
+    "node_modules/invariant": {
+      "version": "2.2.4",
+      "resolved": "https://registry.npmmirror.com/invariant/-/invariant-2.2.4.tgz",
+      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+      "dependencies": {
+        "loose-envify": "^1.0.0"
+      }
+    },
     "node_modules/ipaddr.js": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
@@ -9209,6 +9376,15 @@
       "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz",
       "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
     },
+    "node_modules/isomorphic-fetch": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmmirror.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+      "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==",
+      "dependencies": {
+        "node-fetch": "^1.0.1",
+        "whatwg-fetch": ">=0.10.0"
+      }
+    },
     "node_modules/istanbul-lib-coverage": {
       "version": "3.2.0",
       "resolved": "https://registry.npmmirror.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
@@ -11775,6 +11951,23 @@
         "tslib": "^2.0.3"
       }
     },
+    "node_modules/node-fetch": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-1.7.3.tgz",
+      "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+      "dependencies": {
+        "encoding": "^0.1.11",
+        "is-stream": "^1.0.1"
+      }
+    },
+    "node_modules/node-fetch/node_modules/is-stream": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-1.1.0.tgz",
+      "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/node-forge": {
       "version": "1.3.1",
       "resolved": "https://registry.npmmirror.com/node-forge/-/node-forge-1.3.1.tgz",
@@ -15326,6 +15519,11 @@
         "node": ">= 0.8.0"
       }
     },
+    "node_modules/setimmediate": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz",
+      "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
+    },
     "node_modules/setprototypeof": {
       "version": "1.2.0",
       "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -16246,6 +16444,28 @@
         "node": ">=4.2.0"
       }
     },
+    "node_modules/ua-parser-js": {
+      "version": "0.7.38",
+      "resolved": "https://registry.npmmirror.com/ua-parser-js/-/ua-parser-js-0.7.38.tgz",
+      "integrity": "sha512-fYmIy7fKTSFAhG3fuPlubeGaMoAd6r0rSnfEsO5nEY55i26KSLt9EH7PLQiiqPUhNqYIJvSkTy1oArIcXAbPbA==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/ua-parser-js"
+        },
+        {
+          "type": "paypal",
+          "url": "https://paypal.me/faisalman"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/faisalman"
+        }
+      ],
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/unbox-primitive": {
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
@@ -21462,6 +21682,67 @@
         "fill-range": "^7.0.1"
       }
     },
+    "braft-convert": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmmirror.com/braft-convert/-/braft-convert-2.3.0.tgz",
+      "integrity": "sha512-5km+dLHk8iYDv2iEYDrDQ2ld/ZoUx66QLql0qdm5PqZEcNXc8dBHGLORfzeu3iMw1jLeAiHxtdY5+ypuIhczVg==",
+      "requires": {
+        "draft-convert": "^2.0.0",
+        "draft-js": "^0.10.3"
+      },
+      "dependencies": {
+        "draft-convert": {
+          "version": "2.1.13",
+          "resolved": "https://registry.npmmirror.com/draft-convert/-/draft-convert-2.1.13.tgz",
+          "integrity": "sha512-/h/n4JCfyO8aWby7wKBkccHdsuVbbDyHWXi/B3Zf2pN++lN1lDOIVt5ulXCcbH2Y5YJEFzMJw/YGfN+R0axxxg==",
+          "requires": {
+            "@babel/runtime": "^7.5.5",
+            "immutable": "~3.7.4",
+            "invariant": "^2.2.1"
+          }
+        }
+      }
+    },
+    "braft-editor": {
+      "version": "2.3.9",
+      "resolved": "https://registry.npmmirror.com/braft-editor/-/braft-editor-2.3.9.tgz",
+      "integrity": "sha512-mqdPk/zI2dhFK8tW/A4Qj/AkkARLh5L/niNw+iif5wFqb6zh15rMlrShgz1nWO/QXyAKr8XtDgxiBbR0zWwtRg==",
+      "requires": {
+        "@babel/runtime": "^7.0.0",
+        "braft-convert": "^2.3.0",
+        "braft-finder": "^0.0.19",
+        "braft-utils": "^3.0.8",
+        "draft-convert": "^2.0.0",
+        "draft-js": "^0.10.3",
+        "draft-js-multidecorators": "^1.0.0",
+        "draftjs-utils": "^0.9.4",
+        "immutable": "~3.7.4"
+      },
+      "dependencies": {
+        "braft-finder": {
+          "version": "0.0.19",
+          "resolved": "https://registry.npmmirror.com/braft-finder/-/braft-finder-0.0.19.tgz",
+          "integrity": "sha512-0kzI6/KbomJJhYX1hpjn4edCKhblyUyWdUrsgBmOrwy0vrj+pPkm69+Uf8Uj6KGAULM6LF0ooC++p7fqUGgFHw==",
+          "requires": {}
+        },
+        "draft-convert": {
+          "version": "2.1.13",
+          "resolved": "https://registry.npmmirror.com/draft-convert/-/draft-convert-2.1.13.tgz",
+          "integrity": "sha512-/h/n4JCfyO8aWby7wKBkccHdsuVbbDyHWXi/B3Zf2pN++lN1lDOIVt5ulXCcbH2Y5YJEFzMJw/YGfN+R0axxxg==",
+          "requires": {
+            "@babel/runtime": "^7.5.5",
+            "immutable": "~3.7.4",
+            "invariant": "^2.2.1"
+          }
+        }
+      }
+    },
+    "braft-utils": {
+      "version": "3.0.13",
+      "resolved": "https://registry.npmmirror.com/braft-utils/-/braft-utils-3.0.13.tgz",
+      "integrity": "sha512-92YNlc5RW3mNMo0zbWhnqz8PWr21AAPPhnfn3ZUoXM9+wBIuJQe6UyvOas+MEG9UOGFrvTDPbq60P3fdEhyMQQ==",
+      "requires": {}
+    },
     "browser-process-hrtime": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
@@ -22459,6 +22740,30 @@
       "resolved": "https://registry.npmmirror.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
       "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
     },
+    "draft-js": {
+      "version": "0.10.5",
+      "resolved": "https://registry.npmmirror.com/draft-js/-/draft-js-0.10.5.tgz",
+      "integrity": "sha512-LE6jSCV9nkPhfVX2ggcRLA4FKs6zWq9ceuO/88BpXdNCS7mjRTgs0NsV6piUCJX9YxMsB9An33wnkMmU2sD2Zg==",
+      "requires": {
+        "fbjs": "^0.8.15",
+        "immutable": "~3.7.4",
+        "object-assign": "^4.1.0"
+      }
+    },
+    "draft-js-multidecorators": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/draft-js-multidecorators/-/draft-js-multidecorators-1.0.0.tgz",
+      "integrity": "sha512-7qdy+YQol5iq38AoEerhgSJWhCzxvZLn1x5ODfUlGfWlg0SrZ9AXJbaxHVIjdSIZNrbVIm+WANujNxMqCmDSZQ==",
+      "requires": {
+        "immutable": "*"
+      }
+    },
+    "draftjs-utils": {
+      "version": "0.9.4",
+      "resolved": "https://registry.npmmirror.com/draftjs-utils/-/draftjs-utils-0.9.4.tgz",
+      "integrity": "sha512-KYjABSbGpJrwrwmxVj5UhfV37MF/p0QRxKIyL+/+QOaJ8J9z1FBKxkblThbpR0nJi9lxPQWGg+gh+v0dAsSCCg==",
+      "requires": {}
+    },
     "duplexer": {
       "version": "0.1.2",
       "resolved": "https://registry.npmmirror.com/duplexer/-/duplexer-0.1.2.tgz",
@@ -22502,6 +22807,14 @@
       "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz",
       "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
     },
+    "encoding": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmmirror.com/encoding/-/encoding-0.1.13.tgz",
+      "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+      "requires": {
+        "iconv-lite": "^0.6.2"
+      }
+    },
     "enhanced-resolve": {
       "version": "5.10.0",
       "resolved": "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz",
@@ -23328,6 +23641,35 @@
         "bser": "2.1.1"
       }
     },
+    "fbjs": {
+      "version": "0.8.18",
+      "resolved": "https://registry.npmmirror.com/fbjs/-/fbjs-0.8.18.tgz",
+      "integrity": "sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==",
+      "requires": {
+        "core-js": "^1.0.0",
+        "isomorphic-fetch": "^2.1.1",
+        "loose-envify": "^1.0.0",
+        "object-assign": "^4.1.0",
+        "promise": "^7.1.1",
+        "setimmediate": "^1.0.5",
+        "ua-parser-js": "^0.7.30"
+      },
+      "dependencies": {
+        "core-js": {
+          "version": "1.2.7",
+          "resolved": "https://registry.npmmirror.com/core-js/-/core-js-1.2.7.tgz",
+          "integrity": "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA=="
+        },
+        "promise": {
+          "version": "7.3.1",
+          "resolved": "https://registry.npmmirror.com/promise/-/promise-7.3.1.tgz",
+          "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+          "requires": {
+            "asap": "~2.0.3"
+          }
+        }
+      }
+    },
     "file-entry-cache": {
       "version": "6.0.1",
       "resolved": "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -24065,6 +24407,11 @@
       "resolved": "https://registry.npmmirror.com/immer/-/immer-9.0.16.tgz",
       "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ=="
     },
+    "immutable": {
+      "version": "3.7.6",
+      "resolved": "https://registry.npmmirror.com/immutable/-/immutable-3.7.6.tgz",
+      "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw=="
+    },
     "import-fresh": {
       "version": "3.3.0",
       "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -24134,6 +24481,14 @@
       "resolved": "https://registry.npmmirror.com/intersection-observer/-/intersection-observer-0.12.2.tgz",
       "integrity": "sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg=="
     },
+    "invariant": {
+      "version": "2.2.4",
+      "resolved": "https://registry.npmmirror.com/invariant/-/invariant-2.2.4.tgz",
+      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+      "requires": {
+        "loose-envify": "^1.0.0"
+      }
+    },
     "ipaddr.js": {
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
@@ -24385,6 +24740,15 @@
       "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz",
       "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
     },
+    "isomorphic-fetch": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmmirror.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+      "integrity": "sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==",
+      "requires": {
+        "node-fetch": "^1.0.1",
+        "whatwg-fetch": ">=0.10.0"
+      }
+    },
     "istanbul-lib-coverage": {
       "version": "3.2.0",
       "resolved": "https://registry.npmmirror.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
@@ -26387,6 +26751,22 @@
         "tslib": "^2.0.3"
       }
     },
+    "node-fetch": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-1.7.3.tgz",
+      "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+      "requires": {
+        "encoding": "^0.1.11",
+        "is-stream": "^1.0.1"
+      },
+      "dependencies": {
+        "is-stream": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmmirror.com/is-stream/-/is-stream-1.1.0.tgz",
+          "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ=="
+        }
+      }
+    },
     "node-forge": {
       "version": "1.3.1",
       "resolved": "https://registry.npmmirror.com/node-forge/-/node-forge-1.3.1.tgz",
@@ -28926,6 +29306,11 @@
         "send": "0.18.0"
       }
     },
+    "setimmediate": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz",
+      "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
+    },
     "setprototypeof": {
       "version": "1.2.0",
       "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -29662,6 +30047,11 @@
       "resolved": "https://registry.npmmirror.com/typescript/-/typescript-4.8.4.tgz",
       "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ=="
     },
+    "ua-parser-js": {
+      "version": "0.7.38",
+      "resolved": "https://registry.npmmirror.com/ua-parser-js/-/ua-parser-js-0.7.38.tgz",
+      "integrity": "sha512-fYmIy7fKTSFAhG3fuPlubeGaMoAd6r0rSnfEsO5nEY55i26KSLt9EH7PLQiiqPUhNqYIJvSkTy1oArIcXAbPbA=="
+    },
     "unbox-primitive": {
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz",

+ 2 - 0
package.json

@@ -14,6 +14,8 @@
     "antd": "^5.8.3",
     "antd-mobile": "^5.30.0",
     "axios": "^1.1.3",
+    "braft-editor": "^2.3.9",
+    "braft-utils": "^3.0.13",
     "dayjs": "^1.11.7",
     "js-base64": "^3.7.3",
     "js-export-excel": "^1.1.4",

+ 0 - 43
src/assets/styles/base.css

@@ -96,49 +96,6 @@ textarea {
 #root .ant-btn-text.ant-btn-dangerous {
   color: #ff4d4d;
 }
-#root .ant-pagination .ant-pagination-item {
-  border-radius: 50%;
-  border: 1px solid #999;
-  background-color: transparent !important;
-}
-#root .ant-pagination .ant-pagination-item-active {
-  background-color: var(--themeColor) !important;
-}
-#root .ant-pagination .ant-pagination-item-active a {
-  color: #fff !important;
-}
-#root .ant-pagination .ant-pagination-item:hover {
-  background-color: var(--themeColor) !important;
-}
-#root .ant-pagination .ant-pagination-item:hover a {
-  color: #fff !important;
-}
-#root .ant-pagination-prev {
-  border-radius: 50% !important;
-  border: 1px solid #999;
-}
-#root .ant-pagination-prev:hover {
-  background-color: var(--themeColor);
-}
-#root .ant-pagination-prev:hover button {
-  color: #fff;
-}
-#root .ant-pagination-next {
-  border-radius: 50% !important;
-  border: 1px solid #999;
-}
-#root .ant-pagination-next:hover {
-  background-color: var(--themeColor);
-}
-#root .ant-pagination-next:hover button {
-  color: #fff;
-}
-#root .ant-pagination-disabled {
-  border: 1px solid #ccc;
-}
-#root .ant-pagination-disabled:hover {
-  background-color: transparent;
-}
 #root .tableImgAuto {
   display: flex;
   justify-content: center;

+ 49 - 67
src/assets/styles/base.less

@@ -11,7 +11,8 @@ html {
 }
 
 body {
-  font: 1em/1.4 'Microsoft Yahei', 'PingFang SC', 'Avenir', 'Segoe UI', 'Hiragino Sans GB', 'STHeiti', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei', sans-serif;
+  font: 1em/1.4 'Microsoft Yahei', 'PingFang SC', 'Avenir', 'Segoe UI', 'Hiragino Sans GB',
+    'STHeiti', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei', sans-serif;
   height: 100%;
   color: black;
 }
@@ -53,17 +54,12 @@ textarea {
   --themeColor: #00b3ec;
 }
 
-
-
-
-
 /* 找不到页面 */
 .noFindPage {
   opacity: 0;
-  transition: opacity .5s;
+  transition: opacity 0.5s;
 }
 
-
 /* 兼容360浏览器的下拉框 */
 .ant-select-selector {
   position: relative;
@@ -72,9 +68,8 @@ textarea {
   transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
 }
 
-
 // 气泡框闪烁问题
-.ant-popconfirm{
+.ant-popconfirm {
   width: 240px;
 }
 
@@ -124,66 +119,61 @@ textarea {
   }
 
   /* antd分页器样式 */
-  .ant-pagination .ant-pagination-item {
-    border-radius: 50%;
-    border: 1px solid #999;
-    background-color: transparent !important;
-  }
-
-  .ant-pagination .ant-pagination-item-active {
-    background-color: var(--themeColor) !important;
-  }
-
-
-  .ant-pagination .ant-pagination-item-active a {
-    color: #fff !important;
-  }
-
-  .ant-pagination .ant-pagination-item:hover {
-    background-color: var(--themeColor) !important;
-  }
-
-  .ant-pagination .ant-pagination-item:hover a {
-    color: #fff !important;
-  }
+  // .ant-pagination .ant-pagination-item {
+  //   border-radius: 50%;
+  //   border: 1px solid #999;
+  //   background-color: transparent !important;
+  // }
 
-  .ant-pagination-prev {
-    border-radius: 50% !important;
-    border: 1px solid #999;
-  }
+  // .ant-pagination .ant-pagination-item-active {
+  //   background-color: var(--themeColor) !important;
+  // }
 
-  .ant-pagination-prev:hover {
-    background-color: var(--themeColor);
-  }
+  // .ant-pagination .ant-pagination-item-active a {
+  //   color: #fff !important;
+  // }
 
-  .ant-pagination-prev:hover button {
-    color: #fff;
-  }
+  // .ant-pagination .ant-pagination-item:hover {
+  //   background-color: var(--themeColor) !important;
+  // }
 
+  // .ant-pagination .ant-pagination-item:hover a {
+  //   color: #fff !important;
+  // }
 
+  // .ant-pagination-prev {
+  //   border-radius: 50% !important;
+  //   border: 1px solid #999;
+  // }
 
-  .ant-pagination-next {
-    border-radius: 50% !important;
-    border: 1px solid #999;
-  }
+  // .ant-pagination-prev:hover {
+  //   background-color: var(--themeColor);
+  // }
 
+  // .ant-pagination-prev:hover button {
+  //   color: #fff;
+  // }
 
-  .ant-pagination-next:hover {
-    background-color: var(--themeColor);
-  }
+  // .ant-pagination-next {
+  //   border-radius: 50% !important;
+  //   border: 1px solid #999;
+  // }
 
-  .ant-pagination-next:hover button {
-    color: #fff;
-  }
+  // .ant-pagination-next:hover {
+  //   background-color: var(--themeColor);
+  // }
 
-  .ant-pagination-disabled {
-    border: 1px solid #ccc;
-  }
+  // .ant-pagination-next:hover button {
+  //   color: #fff;
+  // }
 
-  .ant-pagination-disabled:hover {
-    background-color: transparent;
-  }
+  // .ant-pagination-disabled {
+  //   border: 1px solid #ccc;
+  // }
 
+  // .ant-pagination-disabled:hover {
+  //   background-color: transparent;
+  // }
 
   /* 表格的图片居中 */
   .tableImgAuto {
@@ -202,7 +192,6 @@ textarea {
     text-align: center !important;
   }
 
-
   // 树型 表格 定制化
   #A2Table3 {
     .ant-table-row-expand-icon {
@@ -216,28 +205,21 @@ textarea {
     }
   }
 
-  
   .tableNumBox {
     position: absolute;
     bottom: 20px;
     right: 20px;
 
-    &>span {
+    & > span {
       color: var(--themeColor);
     }
   }
-
-
 }
 
-
-
 [hidden] {
   display: none !important;
 }
 
-
-
 #upInput {
   display: none;
 }
@@ -288,4 +270,4 @@ textarea {
   -webkit-box-shadow: inset 0 0 5px transparent;
   border-radius: 10px;
   background: transparent;
-}
+}

+ 46 - 0
src/components/MyPopconfirm.tsx

@@ -0,0 +1,46 @@
+import React, { useMemo } from "react";
+import { Button, Popconfirm } from "antd";
+
+type Props = {
+  txtK: "删除" | "取消" | "重置密码" | "退出登录";
+  onConfirm: () => void;
+  Dom?: React.ReactNode;
+  loc?: "bottom";
+};
+
+function MyPopconfirm({ txtK, onConfirm, Dom, loc }: Props) {
+  const txt = useMemo(() => {
+    const obj = {
+      删除: ["删除后无法恢复,是否删除?", "删除"],
+      取消: ["放弃编辑后,信息将不会保存!", "放弃"],
+      重置密码: ["密码重制后为123456,是否重置?", "重置"],
+      退出登录: ["确定退出吗?", "确定"],
+    };
+    return Reflect.get(obj, txtK) || ["", ""];
+  }, [txtK]);
+
+  return (
+    <Popconfirm
+      placement={loc}
+      title={txt[0]}
+      okText={txt[1]}
+      cancelText="取消"
+      onConfirm={onConfirm}
+      okButtonProps={{ loading: false }}
+    >
+      {Dom ? (
+        Dom
+      ) : txtK === "删除" ? (
+        <Button size="small" type="text" danger>
+          {txtK}
+        </Button>
+      ) : (
+        <Button>{txtK}</Button>
+      )}
+    </Popconfirm>
+  );
+}
+
+const MemoMyPopconfirm = React.memo(MyPopconfirm);
+
+export default MemoMyPopconfirm;

+ 2 - 2
src/components/UpXlsx.tsx

@@ -7,7 +7,7 @@ import { forwardRef, useImperativeHandle } from 'react'
 
 type Props = {
   url: string
-  xlsxResInfoFu: () => void
+  xlsxResInfoFu: (info: any) => void
   ref: any //当前自己的ref,给父组件调用
 }
 
@@ -54,7 +54,7 @@ function UpXlsx({ url, xlsxResInfoFu }: Props, ref: any) {
               duration: 0,
               placement: 'top'
             })
-            xlsxResInfoFu()
+            xlsxResInfoFu(res.data)
           }
           fileDomInitialFu()
         } catch (error) {

+ 72 - 0
src/components/Z3upFiles/index.module.scss

@@ -0,0 +1,72 @@
+.Z3upFiles {
+  position: relative;
+  width: 100%;
+  height: 100%;
+
+  :global {
+
+    .Z3files {
+      width: 500px;
+      // padding-top: 6px;
+
+      .Z3filesRow {
+        display: flex;
+        margin-top: 5px;
+        justify-content: space-between;
+        align-items: center;
+        font-size: 16px;
+        border-bottom: 1px dashed #999;
+        padding-bottom: 5px;
+
+        .Z3files1 {
+          width: calc(100% - 130px);
+          overflow: hidden;
+          text-overflow: ellipsis;
+          white-space: nowrap;
+        }
+
+        .Z3files2 {
+          display: flex;
+          width: 120px;
+          justify-content: flex-end;
+
+          &>span {
+            cursor: pointer;
+          }
+
+          a {
+            color: black;
+          }
+        }
+      }
+    }
+
+    .fileTit {
+      margin-top: 14px;
+      font-size: 14px;
+      color: rgb(126, 124, 124);
+
+      .noUpThumb {
+        position: relative;
+        overflow: hidden;
+        opacity: 0;
+        transition: top .2s;
+        color: #ff4d4f;
+        top: -10px;
+      }
+
+
+
+      .noUpThumbAc {
+        top: 0;
+        opacity: 1;
+      }
+    }
+
+    .lookNone {
+      position: relative;
+      top: 4px;
+      left: 10px;
+    }
+  }
+}

+ 210 - 0
src/components/Z3upFiles/index.tsx

@@ -0,0 +1,210 @@
+import React, { useCallback, useRef, useState } from 'react'
+import styles from './index.module.scss'
+import { FileImgListType } from '@/types'
+import { API_upFile } from '@/store/action/layout'
+import { MessageFu } from '@/utils/message'
+import { fileDomInitialFu } from '@/utils/domShow'
+import { forwardRef, useImperativeHandle } from 'react'
+import { Button, Popconfirm } from 'antd'
+import { EyeOutlined, UploadOutlined, CloseOutlined, DownloadOutlined } from '@ant-design/icons'
+import classNames from 'classnames'
+import { baseURL } from '@/utils/http'
+import { authFilesLookFu } from '@/utils/authFilesLook'
+
+type Props = {
+  max: number //最多传多少个文件
+  isLook: boolean //是否是查看
+  ref: any //当前自己的ref,给父组件调用
+  fileCheck: boolean
+  dirCode: string //文件的code码
+  myUrl: string
+  fromData?: any
+  accept?: string
+  // result:成果 | list:清单
+  type?: string
+  tips?: string
+  // 文件大小
+  size?: number
+  topType: string
+}
+
+function Z3upFiles(
+  {
+    max,
+    isLook,
+    type = 'doc',
+    fileCheck,
+    dirCode,
+    myUrl,
+    fromData,
+    accept = '.zip',
+    tips = '最多5个附件',
+    size = 100,
+    topType
+  }: Props,
+  ref: any
+) {
+  const [fileList, setFileList] = useState<FileImgListType[]>([])
+
+  const myInput = useRef<HTMLInputElement>(null)
+
+  // 上传文件
+  const handeUpPhoto = useCallback(
+    async (e: React.ChangeEvent<HTMLInputElement>) => {
+      if (e.target.files) {
+        // 拿到files信息
+        const filesInfo = e.target.files[0]
+
+        // 校验格式
+        if (!filesInfo.name.includes('.zip') && accept !== '*') {
+          e.target.value = ''
+          return MessageFu.warning(`只支持zip格式!`)
+        }
+
+        // 校验大小
+        if (size && filesInfo.size > size * 1024 * 1024) {
+          e.target.value = ''
+          return MessageFu.warning(`最大支持${size}M!`)
+        }
+
+        // 创建FormData对象
+        const fd = new FormData()
+        // 把files添加进FormData对象(‘photo’为后端需要的字段)
+        fd.append('type', type)
+        fd.append('dirCode', dirCode)
+        fd.append('file', filesInfo)
+        fd.append('isDb', 'true')
+        fd.append('orderType', topType)
+
+        if (fromData) {
+          for (const k in fromData) {
+            if (fromData[k]) fd.append(k, fromData[k])
+          }
+        }
+
+        e.target.value = ''
+
+        try {
+          const res = await API_upFile(fd, myUrl)
+          if (res.code === 0) {
+            MessageFu.success('上传成功!')
+            // console.log('------', res.data)
+
+            setFileList([...fileList, res.data])
+          }
+          fileDomInitialFu()
+        } catch (error) {
+          fileDomInitialFu()
+        }
+      }
+    },
+    [accept, dirCode, fileList, fromData, myUrl, size, topType, type]
+  )
+
+  // 列表删除某一个文件 待完善
+  const delImgListFu = useCallback(
+    (id: number) => {
+      const newItems = fileList.filter(v => v.id !== id)
+      setFileList(newItems)
+    },
+    [fileList, setFileList]
+  )
+
+  // 让父组件调用,拿到 附件信息
+  const sonFilesIdRes = useCallback(() => {
+    return fileList.map(v => v.id)
+  }, [fileList])
+
+  // 让父组件调用 回显数据
+  const sonFilesShowFu = useCallback((arr: any) => {
+    console.log(123, arr)
+
+    setFileList(arr)
+  }, [])
+
+  // 可以让父组件调用子组件的方法
+  useImperativeHandle(ref, () => ({
+    sonFilesIdRes,
+    sonFilesShowFu
+  }))
+
+  return (
+    <div className={styles.Z3upFiles}>
+      <input
+        id='upInput'
+        type='file'
+        accept={accept}
+        ref={myInput}
+        onChange={e => handeUpPhoto(e)}
+      />
+      <div className='Z3Btn'>
+        {fileList.length < max && !isLook ? (
+          <>
+            <Button
+              onClick={() => myInput.current?.click()}
+              icon={<UploadOutlined rev={undefined} />}
+            >
+              上传
+            </Button>
+            {tips}
+          </>
+        ) : null}
+
+        <div className='Z3files'>
+          {fileList.map(v => (
+            <div className='Z3filesRow' key={v.id}>
+              <div className='Z3files1' title={v.fileName}>
+                {v.fileName}
+              </div>
+              <div className='Z3files2'>
+                {authFilesLookFu(v.fileName, '') ? (
+                  <>
+                    <EyeOutlined
+                      rev={undefined}
+                      title='查看'
+                      onClick={() => authFilesLookFu(v.fileName, v.filePath)}
+                    />
+                    &emsp;
+                  </>
+                ) : null}
+                <a
+                  title='下载'
+                  href={baseURL + v.filePath}
+                  download={v.fileName}
+                  target='_blank'
+                  rel='noreferrer'
+                >
+                  <DownloadOutlined rev={undefined} />
+                </a>
+                &emsp;
+                <Popconfirm
+                  title='删除后无法恢复,是否删除?'
+                  okText='删除'
+                  cancelText='取消'
+                  onConfirm={() => delImgListFu(v.id)}
+                  okButtonProps={{ loading: false }}
+                >
+                  <CloseOutlined rev={undefined} title='删除' hidden={isLook} />
+                </Popconfirm>
+              </div>
+            </div>
+          ))}
+        </div>
+
+        <div className='fileTit' hidden={isLook}>
+          <div
+            className={classNames(
+              'noUpThumb',
+              fileList.length <= 0 && fileCheck ? 'noUpThumbAc' : ''
+            )}
+          >
+            请上传附件!
+          </div>
+        </div>
+      </div>
+      {isLook && fileList.length <= 0 ? <div className='lookNone'>(空)</div> : null}
+    </div>
+  )
+}
+
+export default forwardRef(Z3upFiles)

+ 183 - 0
src/components/ZRichTexts/index.module.scss

@@ -0,0 +1,183 @@
+.ZRichTexts {
+  width: 1000px;
+
+  :global {
+    // 正文
+    .formRightZW {
+      width: 700px;
+      top: -3px;
+      position: relative;
+      display: flex;
+      align-items: center;
+      height: 32px;
+
+      .formRightZWRR {
+        display: flex;
+      }
+    }
+
+    // 从查看进来
+    .formRightZWLook {
+      .ant-checkbox-wrapper {
+        pointer-events: none;
+      }
+    }
+
+    .txtBox {
+      width: 100%;
+
+      a {
+        color: #fff !important;
+      }
+
+      // 隐藏媒体功能
+      .control-item.media {
+        display: none;
+      }
+
+      .bf-container {
+        height: 100%;
+      }
+
+      .bf-content {
+        height: 300px;
+        padding-bottom: 0px;
+      }
+
+      .bf-controlbar {
+        position: relative;
+
+        .upImgBox {
+          position: absolute;
+          bottom: 13px;
+          right: 15px;
+          cursor: pointer;
+          color: var(--themeColor);
+          // display: none;
+        }
+
+        .upImgBoxNo {
+          display: none;
+        }
+      }
+
+      .zztxtRow {
+        margin-bottom: 20px;
+        border: 1px solid #ccc;
+
+        .zztxtRow1 {
+          padding: 0 20px;
+          height: 40px;
+          display: flex;
+          align-items: center;
+          justify-content: space-between;
+          background-color: #e8e8e8;
+
+          .zztxtRow1_1 {
+            display: flex;
+            align-items: center;
+
+            .zztxtRow1_1_1 {
+              font-weight: 700;
+              font-size: 16px;
+              margin-right: 20px;
+            }
+
+            .zztxtRow1_1_2 {
+              display: flex;
+              align-items: center;
+              width: 580px;
+              height: 32px;
+            }
+          }
+        }
+
+        .zztxtRow1_2 {
+          display: flex;
+          align-items: center;
+
+          .anticon {
+            cursor: pointer;
+            font-size: 18px;
+          }
+
+          .zztxtRow1_2Icon {
+            position: relative;
+            top: 2px;
+          }
+
+          .zztxtRow1_2IconNo {
+            pointer-events: none;
+            opacity: 0.2;
+          }
+        }
+      }
+
+      .zztxtRowErr {
+        border-color: #ff4d4f;
+      }
+    }
+
+    // 从查看进来
+    .txtBoxLook {
+      .button-remove {
+        display: none !important;
+      }
+      .bf-controlbar {
+        pointer-events: auto !important;
+        display: flex;
+        justify-content: flex-end;
+        button {
+          display: none;
+          &:last-child {
+            display: inline-block;
+          }
+        }
+        div {
+          display: none;
+        }
+        .separator-line {
+          display: none;
+        }
+      }
+    }
+
+    .noUpThumb {
+      position: relative;
+      overflow: hidden;
+      opacity: 0;
+      transition: top 0.2s;
+      color: #ff4d4f;
+      top: -20px;
+      height: 0;
+    }
+
+    .noUpThumbAc {
+      height: auto;
+      top: -10px;
+      opacity: 1;
+    }
+
+    .bf-media .bf-image {
+      float: initial !important;
+      display: block;
+      margin: 0px auto;
+      text-align: center;
+
+      // 不让拖动放大缩小图片(会报错)
+      .bf-csize-icon {
+        display: none !important;
+      }
+
+      img {
+        max-width: 500px;
+        max-height: 300px;
+      }
+    }
+    .bf-container.fullscreen {
+      width: 100%;
+      height: 100%;
+      position: absolute;
+    }
+  }
+}

+ 222 - 0
src/components/ZRichTexts/index.tsx

@@ -0,0 +1,222 @@
+import React, { useCallback, useMemo, useRef, useState } from 'react'
+import styles from './index.module.scss'
+
+// 引入编辑器组件
+
+// 安装---npm install braft-editor --save --force
+// npm install braft-utils --save --force
+import { ContentUtils } from 'braft-utils'
+import BraftEditor from 'braft-editor'
+// 引入编辑器样式
+import 'braft-editor/dist/index.css'
+
+import classNames from 'classnames'
+import { MessageFu } from '@/utils/message'
+import { fileDomInitialFu } from '@/utils/domShow'
+import { baseURL } from '@/utils/http'
+
+import { forwardRef, useImperativeHandle } from 'react'
+import { API_upFile } from '@/store/action/layout'
+import { Button } from 'antd'
+
+export type SectionArrType = {
+  id: number
+  txt: any
+}
+
+type Props = {
+  check: boolean //表单校验,为fasle表示不校验
+  dirCode: string //文件的code码
+  isLook: boolean //是否是查看进来
+  ref: any //当前自己的ref,给父组件调用
+  myUrl: string //上传的api地址
+  topType: string
+}
+
+function ZRichTexts({ check, dirCode, isLook, myUrl, topType }: Props, ref: any) {
+  const [sectionArr, setSectionArr] = useState<SectionArrType[]>([
+    {
+      id: Date.now(),
+      txt: BraftEditor.createEditorState('')
+    }
+  ])
+
+  // 判断 富文本是否为空
+  const isTxtFlag = useMemo(() => {
+    let flag = false
+
+    // 不是按章节发布,检查第一个富文本
+    const txt = sectionArr[0].txt.toHTML()
+
+    const txtRes = txt.replaceAll(' ', '').replaceAll('</p><p>', '')
+
+    if (txtRes === '') flag = true
+
+    if (txtRes.split('></p>').length - 1 === 1 && !txtRes.includes('class="media-')) flag = true
+
+    return flag
+  }, [sectionArr])
+
+  const myInput = useRef<HTMLInputElement>(null)
+
+  // 上传图片、视频
+  const handeUpPhoto = useCallback(
+    async (e: React.ChangeEvent<HTMLInputElement>) => {
+      if (e.target.files) {
+        // 拿到files信息
+        const filesInfo = e.target.files[0]
+
+        let type = ['image/jpeg', 'image/png']
+        let size = 5
+        let txt = '图片只支持png、jpg和jpeg格式!'
+        let txt2 = '图片最大支持5M!'
+        // 校验格式
+        if (!type.includes(filesInfo.type)) {
+          e.target.value = ''
+          return MessageFu.warning(txt)
+        }
+
+        // 校验大小
+        if (filesInfo.size > size * 1024 * 1024) {
+          e.target.value = ''
+          return MessageFu.warning(txt2)
+        }
+
+        // 创建FormData对象
+        const fd = new FormData()
+        // 把files添加进FormData对象(‘photo’为后端需要的字段)
+        fd.append('type', 'img')
+        fd.append('dirCode', dirCode)
+        fd.append('file', filesInfo)
+        fd.append('orderType', topType)
+
+        e.target.value = ''
+
+        try {
+          const res = await API_upFile(fd, myUrl)
+          if (res.code === 0) {
+            MessageFu.success('上传成功!')
+            // 在光标位置插入图片
+            const newTxt = ContentUtils.insertMedias(sectionArr[0].txt, [
+              {
+                type: 'IMAGE',
+                url: baseURL + res.data.filePath
+              }
+            ])
+            const arr = [...sectionArr]
+            arr[0].txt = newTxt
+            setSectionArr(arr)
+          }
+          fileDomInitialFu()
+        } catch (error) {
+          fileDomInitialFu()
+        }
+      }
+    },
+    [dirCode, myUrl, sectionArr, topType]
+  )
+
+  // 让父组件调用的 回显 富文本
+  const ritxtShowFu = useCallback((val: any) => {
+    if (val) {
+      if (val.txtArr) {
+        const arr = val.txtArr.map((v: any) => ({
+          ...v,
+          txt: BraftEditor.createEditorState(v.txt)
+        }))
+        setSectionArr(arr)
+      }
+    }
+  }, [])
+
+  // 让父组件调用的返回 富文本信息 和 表单校验 isTxtFlag为ture表示未通过校验
+  const fatherBtnOkFu = useCallback(() => {
+    const arr: any[] = []
+
+    sectionArr.forEach((v, i) => {
+      arr.push({
+        ...v,
+        txt: v.txt.toHTML()
+      })
+    })
+
+    const obj = {
+      isSection: 'no',
+      txtArr: arr
+    }
+
+    return { val: obj, flag: isTxtFlag }
+  }, [isTxtFlag, sectionArr])
+
+  // 可以让父组件调用子组件的方法
+  useImperativeHandle(ref, () => ({
+    ritxtShowFu,
+    fatherBtnOkFu
+  }))
+
+  // 单个富文本是否输入完整
+  const isOneTxtFlag = useCallback((txt: any) => {
+    let flag = false
+    const txtRes: string = txt.toHTML()
+    const txtRes2 = txtRes.replaceAll(' ', '').replaceAll('</p><p>', '')
+
+    if (txtRes2 === '') flag = true
+
+    if (txtRes2.split('></p>').length - 1 === 1 && !txtRes2.includes('class="media-')) flag = true
+
+    return flag
+  }, [])
+
+  return (
+    <div className={styles.ZRichTexts}>
+      <input
+        id='upInput'
+        type='file'
+        accept='.png,.jpg,.jpeg'
+        ref={myInput}
+        onChange={e => handeUpPhoto(e)}
+      />
+
+      <div className={classNames('formRightZW', isLook ? 'formRightZWLook' : '')}>
+        <div className='formRightZWRR'>
+          <div hidden={isLook}>
+            <Button
+              onClick={() => {
+                myInput.current?.click()
+              }}
+            >
+              上传图片
+            </Button>
+          </div>
+        </div>
+      </div>
+
+      <div className={classNames('txtBox', isLook ? 'txtBoxLook' : '')}>
+        {sectionArr.map((item, index) => (
+          <div
+            className={classNames('zztxtRow', isOneTxtFlag(item.txt) && check ? 'zztxtRowErr' : '')}
+            key={item.id}
+          >
+            {/* 主体 */}
+            <BraftEditor
+              readOnly={isLook}
+              placeholder='请输入内容'
+              value={item.txt}
+              onChange={e => {
+                const arr = [...sectionArr]
+                arr[index].txt = e
+                setSectionArr(arr)
+              }}
+              imageControls={['remove']}
+            />
+          </div>
+        ))}
+      </div>
+      <div className={classNames('noUpThumb', check && isTxtFlag ? 'noUpThumbAc' : '')}>
+        {`请输入!`}
+      </div>
+    </div>
+  )
+}
+
+export default forwardRef(ZRichTexts)

+ 12 - 0
src/pages/A1Camera/A1Look/index.module.scss

@@ -0,0 +1,12 @@
+.AAAAA {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  z-index: 10;
+  border-radius: 10px;
+  background-color: #fff;
+  :global {
+  }
+}

+ 13 - 0
src/pages/A1Camera/A1Look/index.tsx

@@ -0,0 +1,13 @@
+import React from 'react'
+import styles from './index.module.scss'
+function A1Look() {
+  return (
+    <div className={styles.A1Look}>
+      <h1>A1Look</h1>
+    </div>
+  )
+}
+
+const MemoA1Look = React.memo(A1Look)
+
+export default MemoA1Look

+ 17 - 8
src/pages/A1Camera/AddCamera/index.tsx

@@ -15,10 +15,11 @@ type Props = {
   openInfo: A1addType
   closeFu: () => void
   upTableFu: () => void
-  addTableFu: () => void
+  addTableFu: (info?: any) => void
+  isLoc?: boolean //从业务订单的 新增/编辑-相机清单-新增 进来
 }
 
-function AddCamera({ openInfo, closeFu, upTableFu, addTableFu }: Props) {
+function AddCamera({ openInfo, closeFu, upTableFu, addTableFu, isLoc }: Props) {
   // 表单的ref
   const FormBoxRef = useRef<FormInstance>(null)
 
@@ -45,19 +46,27 @@ function AddCamera({ openInfo, closeFu, upTableFu, addTableFu }: Props) {
   // 通过校验点击确定
   const onFinish = useCallback(
     async (value: any) => {
-      const res = await A1_APIadd({
+      const obj = {
         ...value,
         id: openInfo.txt === '新增' ? null : openInfo.id,
         cameraType,
         typeIn: 'pc'
-      })
-      if (res.code === 0) {
-        MessageFu.success(openInfo.txt + '成功!')
-        openInfo.txt === '新增' ? addTableFu() : upTableFu()
+      }
+
+      if (isLoc) {
+        MessageFu.success('新增成功!')
+        addTableFu(obj)
         closeFu()
+      } else {
+        const res = await A1_APIadd(obj)
+        if (res.code === 0) {
+          MessageFu.success(openInfo.txt + '成功!')
+          openInfo.txt === '新增' ? addTableFu() : upTableFu()
+          closeFu()
+        }
       }
     },
-    [addTableFu, cameraType, closeFu, openInfo.id, openInfo.txt, upTableFu]
+    [addTableFu, cameraType, closeFu, isLoc, openInfo.id, openInfo.txt, upTableFu]
   )
 
   return (

+ 1 - 1
src/pages/A1Camera/data.ts

@@ -100,5 +100,5 @@ export const typeInOptions = [
 // 新增编辑的 type
 export type A1addType = {
   id: number
-  txt: '' | '新增' | '编辑'
+  txt: '' | '新增' | '编辑' | '查看'
 }

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

@@ -28,9 +28,12 @@
       background-color: #fff;
 
       .ant-table-body {
-        height: 530px;
+        height: 510px;
         overflow-y: auto !important;
         overflow-y: overlay !important;
+        .ant-table-cell {
+          padding: 8px !important;
+        }
       }
     }
   }

+ 6 - 6
src/pages/A1Camera/index.tsx

@@ -1,6 +1,6 @@
 import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
 import styles from './index.module.scss'
-import { Button, Cascader, Input, notification, Popconfirm, Select, Table } from 'antd'
+import { Button, Cascader, Input, Popconfirm, Select, Table } from 'antd'
 import {
   A1addType,
   TableSelectType,
@@ -148,8 +148,7 @@ function A1Camera() {
             sheetData: res.data.records.map((item: A1ListType) => ({
               cameraType: item.cameraType ? (item.cameraType === 'KK' ? '看看' : '看见') : '空',
               cameraSn: item.cameraSn,
-              myCity:
-                !item.zlProvince && !item.zlCity ? '(空)' : `${item.zlProvince}-${item.zlCity}`,
+              myCity: !item.zlProvince && !item.zlCity ? '空' : `${item.zlProvince}-${item.zlCity}`,
               zlUser: item.zlUser || '空',
               zlPhone: item.zlPhone || '空',
               statusSale: item.statusSale || '空',
@@ -295,8 +294,9 @@ function A1Camera() {
   const leftTitle = useMemo(() => {
     const obj = {
       '': '相机列表',
-      新增: '新增相机',
-      编辑: '编辑相机'
+      新增: '相机列表-新增',
+      编辑: '相机列表-编辑',
+      查看: '相机列表-查看'
     }
     return obj[openInfo.txt]
   }, [openInfo.txt])
@@ -441,7 +441,7 @@ function A1Camera() {
       {/* 表格主体 */}
       <div className='tableMain'>
         <Table
-          scroll={{ y: 530 }}
+          scroll={{ y: 510 }}
           dataSource={A1TableList.list}
           columns={columns}
           rowKey='id'

+ 103 - 0
src/pages/A2Abusiness/AddBusiness/index.module.scss

@@ -0,0 +1,103 @@
+.AddBusiness {
+  position: absolute;
+  z-index: 10;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: #fff;
+  border-radius: 10px;
+  padding: 24px;
+
+  :global {
+    .A2AaddMain {
+      overflow-y: auto;
+      width: 100%;
+      height: 100%;
+
+      .A2Atit {
+        width: calc(100% - 30px);
+        font-weight: 700;
+        color: var(--themeColor);
+        font-size: 18px;
+        padding: 12px 0;
+        border-top: 1px solid #ccc;
+      }
+
+      .A2Atit2 {
+        & > div {
+          width: 1000px;
+          display: flex;
+          justify-content: space-between;
+          .ant-btn {
+            margin-left: 15px;
+          }
+        }
+      }
+      .tableListBox {
+        width: 1000px;
+        position: relative;
+        padding-bottom: 40px;
+        .tableNumBox {
+          right: 0 !important;
+          bottom: 10px !important;
+        }
+      }
+
+      .ant-form {
+        // width: 800px;
+        .ant-row {
+          width: 1000px;
+          .ant-form-item-label {
+            width: 110px;
+          }
+        }
+      }
+      .A2AaddBtn {
+        position: absolute;
+        top: 50%;
+        left: 1200px;
+        transform: translateY(-50%);
+        .ant-row {
+          width: auto;
+        }
+      }
+      .formBox {
+        display: flex;
+        margin-bottom: 24px;
+        .formBoxLL {
+          width: 110px;
+          text-align: right;
+          & > span {
+            color: #ff4d4f;
+          }
+        }
+        .formBoxRR {
+          width: calc(100% - 110px);
+          .ant-btn {
+            margin-right: 20px;
+          }
+        }
+      }
+      .formBox2 {
+        margin-bottom: -10px;
+      }
+    }
+    .A2AtableBoxAdd {
+      position: absolute;
+      top: 0;
+      left: 0;
+      z-index: 100;
+      width: 100%;
+      height: 100%;
+      padding: 100px 200px;
+      background-color: rgba(0, 0, 0, 0.6);
+      border-radius: 10px;
+      & > div {
+        position: relative;
+        width: 100%;
+        height: 100%;
+      }
+    }
+  }
+}

+ 376 - 0
src/pages/A2Abusiness/AddBusiness/index.tsx

@@ -0,0 +1,376 @@
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import styles from './index.module.scss'
+import { A1addType } from '@/pages/A1Camera/data'
+import { Button, DatePicker, Form, FormInstance, Input, Select, Table, Tag, Tooltip } from 'antd'
+import { A2A_APIadd, A2A_APIgetInfo } from '@/store/action/A2Abusiness'
+import { MessageFu } from '@/utils/message'
+import ZRichTexts from '@/components/ZRichTexts'
+import Z3upFiles from '@/components/Z3upFiles'
+import MyPopconfirm from '@/components/MyPopconfirm'
+import { mapDataAll3 } from '@/pages/C1User/AddUser/city'
+import UpXlsx from '@/components/UpXlsx'
+import AddCamera from '@/pages/A1Camera/AddCamera'
+import dayjs from 'dayjs'
+
+type Props = {
+  topType: string
+  openInfo: A1addType
+  closeFu: () => void
+  upTableFu: () => void
+  addTableFu: () => void
+}
+type TableListType = {
+  cameraSn: string
+  cameraType: string
+  id: number
+  remark: string
+}
+
+function AddBusiness({ topType, openInfo, closeFu, upTableFu, addTableFu }: Props) {
+  // 表格数据
+  const [tableList, setTableList] = useState<TableListType[]>([])
+
+  // 点击表格里面新增的数据
+  const [tableAdd, setTableAdd] = useState<A1addType>({ id: 0, txt: '' })
+
+  const getListFu = useCallback(
+    (info: any) => {
+      const arr = info.camera || []
+      setTableList([...arr, ...tableList])
+    },
+    [tableList]
+  )
+
+  // 表格点击删除
+  const delTableFu = useCallback(
+    (id: number) => {
+      setTableList(tableList.filter(v => v.id !== id))
+    },
+    [tableList]
+  )
+
+  const columns = useMemo(() => {
+    return [
+      {
+        title: '相机类型',
+        render: (item: TableListType) =>
+          item.cameraType ? (item.cameraType === 'KK' ? '看看' : '看见') : '(空)'
+      },
+      {
+        title: 'SN码',
+        render: (item: TableListType) => (
+          <>
+            {item.cameraSn}
+            {item.id ? (
+              ''
+            ) : (
+              <Tooltip title='此SN编码未录入在相机列表中'>
+                &nbsp;
+                <Tag>new</Tag>
+              </Tooltip>
+            )}
+          </>
+        )
+      },
+      {
+        title: '备注',
+        render: (item: TableListType) => item.remark || '(空)'
+      },
+      {
+        title: '操作',
+        render: (item: TableListType) => (
+          <MyPopconfirm txtK='删除' onConfirm={() => delTableFu(item.id)} />
+        )
+      }
+    ]
+  }, [delTableFu])
+
+  // 表单的ref
+  const FormBoxRef = useRef<FormInstance>(null)
+
+  // 通过id获取详情
+  const getInfoFu = useCallback(async (id: number) => {
+    const res = await A2A_APIgetInfo(id)
+    if (res.code === 0) {
+      const data = res.data
+
+      // 回显 合同附件
+      listFilesRef.current.sonFilesShowFu(data.files)
+
+      // 设置富文本
+      ZRichTextsRef1.current?.ritxtShowFu(JSON.parse(data.rtf))
+
+      // 回显表格
+      setTableList(data.cameras)
+
+      const obj = {
+        ...data,
+        city: data.zlProvince + '-' + data.zlCity,
+        dateStart: dayjs(data.dateStart),
+        dateEnd: data.dateEnd ? dayjs(data.dateEnd) : null
+      }
+
+      FormBoxRef.current?.setFieldsValue(obj)
+    }
+  }, [])
+
+  // 拿来占位,不然会报错
+  const onChange = useCallback((value: string) => {
+    // console.log(`selected ${value}`)
+  }, [])
+
+  const onSearch = useCallback((value: string) => {
+    // console.log(`search ${value}`)
+  }, [])
+
+  // 没有通过校验
+  const onFinishFailed = useCallback(() => {}, [])
+
+  // 通过校验点击确定
+  const onFinish = useCallback(
+    async (value: any) => {
+      // 附件
+      const listFilesRes = listFilesRef.current.sonFilesIdRes()
+
+      // 日期处理
+      const dateStart = dayjs(value.dateStart).format('YYYY-MM-DD')
+      let dateEnd = ''
+
+      if (value.dateEnd) dateEnd = dayjs(value.dateEnd).format('YYYY-MM-DD')
+
+      // 城市处理
+      const zlProvince = value.city.split('-')[0]
+      const zlCity = value.city.split('-')[1]
+
+      // 富文本
+      const rtf = ZRichTextsRef1.current?.fatherBtnOkFu() || { flag: true }
+
+      const obj = {
+        ...value,
+        id: openInfo.txt === '新增' ? null : openInfo.id,
+        fileIds: listFilesRes.join(','),
+        rtf: JSON.stringify(rtf.val || ''),
+        cameras: tableList,
+        dateStart,
+        dateEnd,
+        zlProvince,
+        zlCity,
+        type: topType
+      }
+
+      // if (1 + 1 === 2) {
+      //   console.log(obj)
+
+      //   return
+      // }
+
+      const res = await A2A_APIadd(obj)
+      if (res.code === 0) {
+        MessageFu.success(openInfo.txt + '成功!')
+        openInfo.txt === '新增' ? addTableFu() : upTableFu()
+        closeFu()
+      }
+    },
+    [addTableFu, closeFu, openInfo.id, openInfo.txt, tableList, topType, upTableFu]
+  )
+
+  useEffect(() => {
+    if (openInfo.txt === '新增') {
+    } else getInfoFu(openInfo.id)
+  }, [getInfoFu, openInfo])
+
+  // 富文本的ref
+  const ZRichTextsRef1 = useRef<any>(null)
+
+  // 合同附件的ref
+  const listFilesRef = useRef<any>(null)
+
+  // 上传xlsx 的ref
+  const upXlsxRef = useRef<any>(null)
+
+  return (
+    <div className={styles.AddBusiness}>
+      <div className='A2AaddMain'>
+        <Form
+          scrollToFirstError={true}
+          ref={FormBoxRef}
+          // labelCol={{ span: 4 }}
+          name='basicWai'
+          onFinish={onFinish}
+          onFinishFailed={onFinishFailed}
+          autoComplete='off'
+        >
+          <div className='A2Atit'>订单信息</div>
+
+          <Form.Item
+            label='钉钉审批编号'
+            name='dingNum'
+            rules={[{ required: true, message: '请输入内容!' }]}
+            getValueFromEvent={e => e.target.value.replace(/\s+/g, '')}
+          >
+            <Input maxLength={20} showCount placeholder='请输入内容' />
+          </Form.Item>
+
+          <div className='formBox formBox2'>
+            <div className='formBoxLL'>合同附件:</div>
+            <div className='formBoxRR'>
+              <Z3upFiles
+                max={5}
+                accept='*'
+                isLook={openInfo.txt === '查看'}
+                ref={listFilesRef}
+                fileCheck={false}
+                dirCode='A2business'
+                myUrl='cms/order/upload'
+                topType={topType}
+              />
+            </div>
+          </div>
+
+          <Form.Item
+            label='租凭日期'
+            name='dateStart'
+            rules={[{ required: true, message: '请选择日期!' }]}
+          >
+            <DatePicker placeholder='请选择日期' />
+          </Form.Item>
+
+          <Form.Item label='预计归还日期' name='dateEnd'>
+            <DatePicker placeholder='请选择日期' />
+          </Form.Item>
+
+          <div className='formBox'>
+            <div className='formBoxLL'>备注:</div>
+            <div className='formBoxRR'>
+              <ZRichTexts
+                check={false}
+                dirCode='A2business'
+                isLook={openInfo.txt === '查看'}
+                ref={ZRichTextsRef1}
+                myUrl='cms/order/upload'
+                topType={topType}
+              />
+            </div>
+          </div>
+
+          <div className='A2Atit'>租凭方信息</div>
+
+          <Form.Item
+            label='租赁方名称'
+            name='zlName'
+            rules={[{ required: true, message: '请输入内容!' }]}
+            getValueFromEvent={e => e.target.value.replace(/\s+/g, '')}
+          >
+            <Input maxLength={20} showCount placeholder='请输入内容' />
+          </Form.Item>
+
+          <Form.Item
+            label='城市:'
+            name='city'
+            rules={[{ required: true, message: '请选择城市!' }]}
+          >
+            <Select
+              style={{ width: 400 }}
+              showSearch
+              placeholder='请选择城市'
+              optionFilterProp='label'
+              onChange={onChange}
+              onSearch={onSearch}
+              options={mapDataAll3}
+            />
+          </Form.Item>
+
+          <Form.Item
+            label='负责人'
+            name='zlUser'
+            rules={[{ required: true, message: '请输入内容!' }]}
+            getValueFromEvent={e => e.target.value.replace(/\s+/g, '')}
+          >
+            <Input maxLength={20} showCount placeholder='请输入内容' />
+          </Form.Item>
+
+          <Form.Item
+            label='联系方式'
+            name='zlPhone'
+            rules={[{ required: true, message: '请输入内容!' }]}
+            getValueFromEvent={e => e.target.value.replace(/\s+/g, '')}
+          >
+            <Input maxLength={20} showCount placeholder='请输入内容' />
+          </Form.Item>
+          {/* 确定和取消按钮 */}
+          <Form.Item className='A2AaddBtn'>
+            <Button type='primary' htmlType='submit'>
+              提交
+            </Button>
+            <br />
+            <br />
+            <MyPopconfirm txtK='取消' onConfirm={closeFu} />
+          </Form.Item>
+        </Form>
+
+        <div className='A2Atit A2Atit2'>
+          <div>
+            <div>相机清单</div>
+            <div>
+              <a href='/xlsx/相机列表导入模板.xlsx' download>
+                <Button type='primary'>下载模块</Button>
+              </a>
+              <UpXlsx
+                url='cms/order/upload/excel'
+                ref={upXlsxRef}
+                xlsxResInfoFu={info => getListFu(info)}
+              />
+
+              <Button type='primary' onClick={() => upXlsxRef.current?.myInputClickFu()}>
+                批量导入
+              </Button>
+              <Button
+                type='primary'
+                onClick={() => {
+                  if (tableList.length >= 200) return MessageFu.warning('最多支持200条数据!')
+                  setTableAdd({ id: -1, txt: '新增' })
+                }}
+              >
+                新增
+              </Button>
+            </div>
+          </div>
+        </div>
+
+        {/* --------------表格-------------- */}
+        <div className='tableListBox'>
+          <Table
+            size='small'
+            dataSource={tableList}
+            columns={columns}
+            rowKey='cameraSn'
+            pagination={false}
+          />
+          {/*  右下角的列表数量 */}
+          <div className='tableNumBox'>
+            共 <span>{tableList.length}</span> 条数据
+          </div>
+        </div>
+      </div>
+
+      {/* 点击表格里面的新增 出来的页面 */}
+      {tableAdd.id ? (
+        <div className='A2AtableBoxAdd'>
+          <div>
+            <AddCamera
+              isLoc={true}
+              openInfo={tableAdd}
+              closeFu={() => setTableAdd({ id: 0, txt: '' })}
+              upTableFu={() => {}}
+              addTableFu={info => setTableList([info, ...tableList])}
+            />
+          </div>
+        </div>
+      ) : null}
+    </div>
+  )
+}
+
+const MemoAddBusiness = React.memo(AddBusiness)
+
+export default MemoAddBusiness

+ 24 - 0
src/pages/A2Abusiness/data.ts

@@ -0,0 +1,24 @@
+export type A2AFromDataType = {
+  num: string //订单编号
+  dingNum: string //钉钉审批编号
+  dateStart: string //租赁开始日期 - yyyy-mm-dd
+  dateEnd: string //租赁结束日期 - yyyy-mm-dd
+  zlName: string //租赁方名称
+
+  siteArr: string[] | undefined
+  zlProvince: string
+  zlCity: string //所在地区 省/市
+
+  zlUser: string //负责人
+  zlPhone: string //联系方式
+  pageSize: number
+  pageNum: number
+}
+
+export const A2AtopTypeArr = [
+  { name: '租赁', key: 'ZL' },
+  { name: '销售', key: 'XS' },
+  { name: '报修', key: 'BX' },
+  { name: '定损', key: 'DS' },
+  { name: '维修', key: 'WX' }
+]

+ 49 - 0
src/pages/A2Abusiness/index.module.scss

@@ -0,0 +1,49 @@
+.A2Abusiness {
+  position: relative;
+  :global {
+    .A2Atop {
+      border-radius: 10px;
+      background-color: #fff;
+      padding: 15px 24px 1px 24px;
+
+      .A2AtopSon {
+        display: flex;
+        margin-bottom: 15px;
+
+        .ant-btn {
+          margin-right: 15px;
+        }
+
+        .A2AtopRow {
+          margin-right: 20px;
+        }
+      }
+      .A2AtopSon2 {
+        justify-content: space-between;
+        & > div {
+          display: flex;
+        }
+        .ant-btn {
+          margin-left: 15px;
+          margin-right: 0px;
+        }
+      }
+    }
+
+    .tableMain {
+      border-radius: 10px;
+      margin-top: 15px;
+      height: calc(100% - 175px);
+      background-color: #fff;
+
+      .ant-table-body {
+        height: 510px;
+        overflow-y: auto !important;
+        overflow-y: overlay !important;
+        .ant-table-cell {
+          padding: 8px !important;
+        }
+      }
+    }
+  }
+}

+ 477 - 0
src/pages/A2Abusiness/index.tsx

@@ -0,0 +1,477 @@
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
+import styles from './index.module.scss'
+import { useDispatch, useSelector } from 'react-redux'
+import { A2AFromDataType, A2AtopTypeArr } from './data'
+import { A2A_APIgetlist, A2A_APIgetlistDerive, A2A_APIremove } from '@/store/action/A2Abusiness'
+import { RootState } from '@/store'
+import { MessageFu } from '@/utils/message'
+import ExportJsonExcel from 'js-export-excel'
+import dayjs from 'dayjs'
+import { A2AListType } from '@/types'
+import { A1addType } from '../A1Camera/data'
+import { Button, Cascader, DatePicker, Input, Popconfirm, Table } from 'antd'
+import { mapDataAll2 } from '../C1User/AddUser/city'
+import AddBusiness from './AddBusiness'
+
+const { RangePicker } = DatePicker
+
+const tableSelectBase: A2AFromDataType = {
+  num: '',
+  dingNum: '',
+  dateStart: '',
+  dateEnd: '',
+  zlName: '',
+
+  siteArr: undefined,
+  zlProvince: '',
+  zlCity: '', //所在地区 省/市
+
+  zlUser: '', //城市负责人
+  zlPhone: '', //联系方式
+  pageSize: 10,
+  pageNum: 1
+}
+
+function A2Abusiness() {
+  const dispatch = useDispatch()
+
+  // 顶部的type 按钮
+  const [topType, setTopType] = useState('ZL')
+
+  // 筛选和分页
+  const [tableSelect, setTableSelect] = useState(tableSelectBase)
+
+  const tableSelectRef = useRef({} as A2AFromDataType)
+
+  useEffect(() => {
+    tableSelectRef.current = { ...tableSelect }
+  }, [tableSelect])
+
+  // 点击搜索的 时间戳
+  const [timeKey, setTimeKey] = useState(-1)
+
+  // 发送接口的函数
+  const getListFu = useCallback(() => {
+    const objTemp: any = {}
+
+    if (tableSelectRef.current.siteArr) {
+      const temp = tableSelectRef.current.siteArr
+      objTemp.zlProvince = temp[0] || ''
+      objTemp.zlCity = temp[1] || ''
+    }
+
+    const obj = {
+      ...tableSelectRef.current,
+      ...objTemp,
+      type: topType
+    }
+    dispatch(A2A_APIgetlist(obj))
+  }, [dispatch, topType])
+
+  useEffect(() => {
+    getListFu()
+  }, [getListFu, timeKey])
+
+  // 输入框的改变
+  const txtChangeFu = useCallback(
+    (txt: string, key: 'num' | 'dingNum' | 'zlName' | 'zlUser' | 'zlPhone') => {
+      setTableSelect({ ...tableSelect, [key]: txt })
+    },
+    [tableSelect]
+  )
+
+  // 点击搜索
+  const clickSearch = useCallback(() => {
+    setTableSelect({ ...tableSelect, pageNum: 1 })
+    setTimeout(() => {
+      setTimeKey(Date.now())
+    }, 50)
+  }, [tableSelect])
+
+  // 点击重置
+  const [inputKey, setInputKey] = useState(1)
+  const resetSelectFu = useCallback(() => {
+    // 把2个输入框和时间选择器清空
+    setInputKey(Date.now())
+    setTableSelect(tableSelectBase)
+    setTimeout(() => {
+      setTimeKey(Date.now())
+    }, 50)
+  }, [])
+
+  // 从仓库获取列表
+  const A2ATableList = useSelector((state: RootState) => state.A2Abusiness.A2ATableList)
+  // 页码变化
+  const paginationChange = useCallback(
+    () => (pageNum: number, pageSize: number) => {
+      setTableSelect({ ...tableSelect, pageNum, pageSize })
+      setTimeout(() => {
+        setTimeKey(Date.now())
+      }, 50)
+    },
+    [tableSelect]
+  )
+
+  // 点击删除
+  const delByIdFu = useCallback(
+    async (id: number) => {
+      const res = await A2A_APIremove(id)
+      if (res.code === 0) {
+        MessageFu.success('删除成功!')
+        getListFu()
+      }
+    },
+    [getListFu]
+  )
+
+  // 点击导出
+  const deriveFu = useCallback(async () => {
+    if (A2ATableList.total > 30000)
+      return MessageFu.warning('只支持导出最多30000条数据。请增加筛选条件,并重新尝试')
+
+    if (A2ATableList.list.length === 0) return MessageFu.warning('当前搜索条件没有数据!')
+    const name = '业务订单' + dayjs(new Date()).format('YYYY-MM-DD HH:mm')
+
+    const objTemp: any = {}
+
+    if (tableSelectRef.current.siteArr) {
+      const temp = tableSelectRef.current.siteArr
+      objTemp.zlProvince = temp[0] || ''
+      objTemp.zlCity = temp[1] || ''
+    }
+
+    const res = await A2A_APIgetlistDerive({
+      ...tableSelect,
+      ...objTemp,
+      pageNum: 1,
+      pageSize: 99999,
+      type: topType
+    })
+
+    if (res.code === 0) {
+      if (res.data.records.length <= 0) return MessageFu.warning('当前搜索条件没有数据!')
+
+      const option = {
+        fileName: name,
+        datas: [
+          {
+            sheetData: res.data.records.map((item: A2AListType) => ({
+              num: item.num || '空',
+              dingNum: item.dingNum || '空',
+              dateStart: item.dateStart || '空',
+              dateEnd: item.dateEnd || '空',
+              zlName: item.zlName || '空',
+              myCity: !item.zlProvince && !item.zlCity ? '空' : `${item.zlProvince}-${item.zlCity}`,
+              zlUser: item.zlUser || '空',
+              zlPhone: item.zlPhone || '空',
+              pcs: item.pcs || '空',
+              creatorName: item.creatorName || '空',
+              updateTime: item.updateTime || '空'
+            })),
+            sheetName: name,
+            sheetFilter: [
+              'num',
+              'dingNum',
+              'dateStart',
+              'dateEnd',
+              'zlName',
+              'myCity',
+              'zlUser',
+              'zlPhone',
+              'pcs',
+              'creatorName',
+              'updateTime'
+            ],
+            sheetHeader: [
+              '订单编号',
+              '钉钉审批号',
+              '租赁日期',
+              '预计归还日期',
+              '租赁方名称',
+              '地区',
+              '负责人',
+              '联系方式',
+              '设备台数',
+              '编辑人',
+              '更新日期'
+            ],
+            columnWidths: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
+          }
+        ]
+      }
+
+      const toExcel = new ExportJsonExcel(option) //new
+      toExcel.saveExcel() //保存
+    }
+  }, [A2ATableList.list.length, A2ATableList.total, tableSelect, topType])
+
+  const columns = useMemo(() => {
+    return [
+      {
+        title: '订单编号',
+        render: (item: A2AListType) => item.num || '(空)'
+      },
+      {
+        title: '钉钉审批号',
+        render: (item: A2AListType) => item.dingNum || '(空)'
+      },
+      {
+        title: '租赁日期',
+        render: (item: A2AListType) => item.dateStart || '(空)'
+      },
+      {
+        title: '预计归还日期',
+        render: (item: A2AListType) => item.dateEnd || '(空)'
+      },
+      {
+        title: '租赁方名称',
+        render: (item: A2AListType) => item.zlName || '(空)'
+      },
+      {
+        title: '地区',
+        render: (item: A2AListType) =>
+          !item.zlProvince && !item.zlCity ? '(空)' : `${item.zlProvince}-${item.zlCity}`
+      },
+      {
+        title: '负责人',
+        render: (item: A2AListType) => item.zlUser || '(空)'
+      },
+      {
+        title: '联系方式',
+        render: (item: A2AListType) => item.zlPhone || '(空)'
+      },
+      {
+        title: '设备台数',
+        render: (item: A2AListType) => item.pcs || '(空)'
+      },
+
+      {
+        title: '编辑人',
+        render: (item: A2AListType) => item.creatorName || '(空)'
+      },
+      {
+        title: '更新日期',
+        render: (item: A2AListType) => item.updateTime || '(空)'
+      },
+
+      {
+        title: '操作',
+        render: (item: A2AListType) => (
+          <>
+            <Button size='small' type='text' onClick={() => setLookId(item.id)}>
+              查看
+            </Button>
+            <Button
+              size='small'
+              type='text'
+              onClick={() => setOpenInfo({ id: item.id, txt: '编辑' })}
+            >
+              编辑
+            </Button>
+            <Popconfirm
+              title='删除后无法恢复,是否删除?'
+              okText='删除'
+              cancelText='取消'
+              onConfirm={() => delByIdFu(item.id)}
+              okButtonProps={{ loading: false }}
+            >
+              <Button size='small' type='text' danger>
+                删除
+              </Button>
+            </Popconfirm>
+          </>
+        )
+      }
+    ]
+  }, [delByIdFu])
+
+  // 点击新增和编辑的数据
+  const [openInfo, setOpenInfo] = useState<A1addType>({ id: 0, txt: '' })
+
+  // 左上角的 title
+  const leftTitle = useMemo(() => {
+    const obj = {
+      '': '业务订单',
+      新增: '业务订单-新增',
+      编辑: '业务订单-编辑',
+      查看: '业务订单-查看'
+    }
+    return obj[openInfo.txt]
+  }, [openInfo.txt])
+
+  // 时间选择器改变
+  const timeChange = (date: any, dateString: any) => {
+    let dateStart = ''
+    let dateEnd = ''
+    if (dateString[0] && dateString[1]) {
+      dateStart = dateString[0] + ' 00:00:00'
+      dateEnd = dateString[1] + ' 23:59:59'
+    }
+    setTableSelect({ ...tableSelect, dateStart, dateEnd })
+  }
+
+  // 查看 待完善
+  const [lookId, setLookId] = useState(0)
+
+  return (
+    <div className={styles.A2Abusiness}>
+      <div className='pageTitle'>
+        {leftTitle}
+        {openInfo.id ? `(${A2AtopTypeArr.find(v => v.key === topType)!.name})` : ''}
+      </div>
+      {/* 顶部筛选 */}
+      <div className='A2Atop'>
+        <div className='A2AtopSon'>
+          {A2AtopTypeArr.map(item => (
+            <Button
+              key={item.key}
+              onClick={() => setTopType(item.key)}
+              type={item.key === topType ? 'primary' : 'default'}
+            >
+              {item.name}
+            </Button>
+          ))}
+        </div>
+
+        <div className='A2AtopSon'>
+          <div className='A2AtopRow'>
+            <span>订单编号:</span>
+            <Input
+              key={inputKey}
+              maxLength={12}
+              style={{ width: 190 }}
+              placeholder='请输入内容,最多12字'
+              allowClear
+              onChange={e => txtChangeFu(e.target.value, 'num')}
+            />
+          </div>
+
+          <div className='A2AtopRow'>
+            <span>钉钉审批号:</span>
+            <Input
+              key={inputKey}
+              maxLength={30}
+              style={{ width: 190 }}
+              placeholder='请输入内容,最多30字'
+              allowClear
+              onChange={e => txtChangeFu(e.target.value, 'dingNum')}
+            />
+          </div>
+
+          <div className='A2AtopRow'>
+            <span>租凭日期:</span>
+            <RangePicker key={inputKey} onChange={timeChange} />
+          </div>
+
+          <div className='A2AtopRow'>
+            <span>租凭方名称:</span>
+            <Input
+              key={inputKey}
+              maxLength={20}
+              style={{ width: 190 }}
+              placeholder='请输入内容,最多20字'
+              allowClear
+              onChange={e => txtChangeFu(e.target.value, 'zlName')}
+            />
+          </div>
+        </div>
+
+        <div className='A2AtopSon A2AtopSon2'>
+          <div>
+            <div className='A2AtopRow'>
+              <span>地区:</span>
+              <Cascader
+                changeOnSelect
+                style={{ width: 240 }}
+                options={mapDataAll2}
+                value={tableSelect.siteArr}
+                placeholder='全部'
+                onChange={e =>
+                  setTableSelect({
+                    ...tableSelect,
+                    siteArr: e as string[]
+                  })
+                }
+              />
+            </div>
+
+            <div className='A2AtopRow'>
+              <span>负责人:</span>
+              <Input
+                key={inputKey}
+                maxLength={20}
+                style={{ width: 198 }}
+                placeholder='请输入内容,最多20字'
+                allowClear
+                onChange={e => txtChangeFu(e.target.value, 'zlUser')}
+              />
+            </div>
+
+            <div className='A2AtopRow'>
+              <span>联系方式:</span>
+              <Input
+                key={inputKey}
+                maxLength={20}
+                style={{ width: 190 }}
+                placeholder='请输入内容,最多20字'
+                allowClear
+                onChange={e => txtChangeFu(e.target.value, 'zlPhone')}
+              />
+            </div>
+          </div>
+
+          <div>
+            <Button onClick={resetSelectFu}>重置</Button>
+            <Button type='primary' onClick={clickSearch}>
+              查询
+            </Button>
+            <Button type='primary' onClick={() => setOpenInfo({ id: -1, txt: '新增' })}>
+              新增
+            </Button>
+            <Button type='primary' onClick={deriveFu}>
+              导出表格
+            </Button>
+          </div>
+        </div>
+      </div>
+      {/* 表格主体 */}
+      <div className='tableMain'>
+        <Table
+          scroll={{ y: 510 }}
+          dataSource={A2ATableList.list}
+          columns={columns}
+          rowKey='id'
+          pagination={{
+            showQuickJumper: true,
+            position: ['bottomCenter'],
+            showSizeChanger: true,
+            current: tableSelect.pageNum,
+            pageSize: tableSelect.pageSize,
+            total: A2ATableList.total,
+            onChange: paginationChange()
+          }}
+        />
+      </div>
+
+      {/*  右下角的列表数量 */}
+      <div className='tableNumBox'>
+        共 <span>{A2ATableList.total}</span> 条数据
+      </div>
+
+      {/* 新增 编辑 查看 出来的页面 */}
+      {openInfo.id ? (
+        <AddBusiness
+          topType={topType}
+          openInfo={openInfo}
+          closeFu={() => setOpenInfo({ id: 0, txt: '' })}
+          upTableFu={getListFu}
+          addTableFu={resetSelectFu}
+        />
+      ) : null}
+    </div>
+  )
+}
+
+const MemoA2Abusiness = React.memo(A2Abusiness)
+
+export default MemoA2Abusiness

+ 4 - 0
src/pages/A2Blogistics/index.module.scss

@@ -0,0 +1,4 @@
+.A2Blogistics {
+  :global {
+  }
+}

+ 13 - 0
src/pages/A2Blogistics/index.tsx

@@ -0,0 +1,13 @@
+import React from 'react'
+import styles from './index.module.scss'
+function A2Blogistics() {
+  return (
+    <div className={styles.A2Blogistics}>
+      <h1>A2Blogistics</h1>
+    </div>
+  )
+}
+
+const MemoA2Blogistics = React.memo(A2Blogistics)
+
+export default MemoA2Blogistics

+ 4 - 6
src/pages/B1Plan/index.module.scss

@@ -9,7 +9,7 @@
       display: flex;
       align-items: center;
 
-      &>div {
+      & > div {
         margin-left: 4px;
         font-size: 14px;
         color: #999;
@@ -45,7 +45,7 @@
         justify-content: space-between;
         margin-top: 15px;
 
-        &>div {
+        & > div {
           display: flex;
         }
       }
@@ -106,14 +106,12 @@
             right: 0px;
             bottom: 5px;
 
-            &>span {
+            & > span {
               color: var(--themeColor);
             }
           }
         }
       }
-
-
     }
   }
-}
+}

+ 3 - 4
src/pages/B3Push/index.module.scss

@@ -1,7 +1,7 @@
 .B3Push {
   :global {
     .pageTitle {
-      &>span {
+      & > span {
         font-size: 14px;
         color: #999;
       }
@@ -30,7 +30,7 @@
         display: flex;
         justify-content: space-between;
 
-        &>div {
+        & > div {
           display: flex;
         }
       }
@@ -46,8 +46,7 @@
         height: 578px;
         overflow-y: auto !important;
         overflow-y: overlay !important;
-
       }
     }
   }
-}
+}

+ 6 - 4
src/pages/B4JsonPush/index.module.scss

@@ -1,7 +1,7 @@
 .B4JsonPush {
   :global {
     .pageTitle {
-      &>span {
+      & > span {
         font-size: 14px;
         color: #999;
       }
@@ -30,7 +30,7 @@
         display: flex;
         justify-content: space-between;
 
-        &>div {
+        & > div {
           display: flex;
         }
       }
@@ -46,8 +46,10 @@
         height: 578px;
         overflow-y: auto !important;
         overflow-y: overlay !important;
-
+        .ant-table-cell {
+          padding: 12px 8px !important;
+        }
       }
     }
   }
-}
+}

+ 40 - 24
src/pages/C1User/AddUser/city.ts

@@ -1,41 +1,57 @@
 type Props = {
-  value: string;
-  label: string;
+  value: string
+  label: string
   children: {
-    value: string;
-    label: string;
-  }[];
-};
+    value: string
+    label: string
+  }[]
+}
 
-const temp1: Props[] = [];
-const temp2: Props[] = [];
+type sonProps = {
+  value: string
+  label: string
+}
 
-myCityTemp.forEach((v) => {
+const temp1: Props[] = []
+const temp2: Props[] = []
+const temp3: sonProps[] = []
+
+myCityTemp.forEach(v => {
   const obj1 = {
     value: v.name,
     label: v.name,
-    children: v.city.map((v2) => ({
+    children: v.city.map(v2 => ({
       value: v2.name,
       label: v2.name,
-      children: v2.districtAndCounty.map((v3) => ({
+      children: v2.districtAndCounty.map(v3 => ({
         value: v3,
-        label: v3,
-      })),
-    })),
-  };
+        label: v3
+      }))
+    }))
+  }
 
   const obj2 = {
     value: v.name,
     label: v.name,
-    children: v.city.map((v2) => ({
+    children: v.city.map(v2 => ({
       value: v2.name,
-      label: v2.name,
-    })),
-  };
+      label: v2.name
+    }))
+  }
+
+  temp1.push(obj1)
+  temp2.push(obj2)
+})
 
-  temp1.push(obj1);
-  temp2.push(obj2);
-});
+temp2.forEach(item1 => {
+  item1.children.forEach(item2 => {
+    temp3.push({
+      value: item1.value + '-' + item2.value,
+      label: item1.label + '-' + item2.label
+    })
+  })
+})
 
-export const mapDataAll1 = temp1;
-export const mapDataAll2 = temp2;
+export const mapDataAll1 = temp1
+export const mapDataAll2 = temp2
+export const mapDataAll3 = temp3

+ 14 - 0
src/pages/Layout/data.ts

@@ -14,6 +14,20 @@ const tabLeftArr: RouterType = [
         done: false
       },
       {
+        id: '1.3',
+        name: '业务订单',
+        path: '/business',
+        Com: React.lazy(() => import('../A2Abusiness')),
+        done: false
+      },
+      {
+        id: '1.4',
+        name: '物流订单',
+        path: '/logistics',
+        Com: React.lazy(() => import('../A2Blogistics')),
+        done: false
+      },
+      {
         id: '1.2',
         name: '机房管理',
         path: '/psychz',

+ 45 - 0
src/store/action/A2Abusiness.ts

@@ -0,0 +1,45 @@
+import http from '@/utils/http'
+import { AppDispatch } from '..'
+/**
+ * 获取 业务订单 表格列表(存到仓库)
+ */
+export const A2A_APIgetlist = (data: any) => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.post('cms/order/pageList', data)
+    if (res.code === 0) {
+      const obj = {
+        list: res.data.records,
+        total: res.data.total
+      }
+      dispatch({ type: 'A2A/getList', payload: obj })
+    }
+  }
+}
+
+/**
+ * 获取 业务订单 表格列表(导出表格)
+ */
+export const A2A_APIgetlistDerive = (data: any) => {
+  return http.post('cms/order/pageList', data)
+}
+
+/**
+ * 业务订单 删除单个表格数据
+ */
+export const A2A_APIremove = (id: number) => {
+  return http.get(`cms/order/remove/${id}`)
+}
+
+/**
+ * 业务订单 新增/修改
+ */
+export const A2A_APIadd = (data: any) => {
+  return http.post('cms/order/save', data)
+}
+
+/**
+ * 业务订单 通过id获取详情
+ */
+export const A2A_APIgetInfo = (id: number) => {
+  return http.get(`cms/order/detail/${id}`)
+}

+ 27 - 0
src/store/reducer/A2Abusiness.ts

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

+ 15 - 13
src/store/reducer/index.ts

@@ -1,29 +1,31 @@
 // 导入合并reducer的依赖
-import { combineReducers } from "redux";
+import { combineReducers } from 'redux'
 
 // 导入 登录 模块的 reducer
-import A0Layout from "./layout";
-import A1Camera from "./A1Camera";
-import A2Psychz from "./A2Psychz";
-import B1Plan from "./B1Plan";
-import B2Scene from "./B2Scene";
-import B3Push from "./B3Push";
-import B4JsonPush from "./B4JsonPush";
-import C1User from "./C1User";
-import C2Log from "./C2Log";
+import A0Layout from './layout'
+import A1Camera from './A1Camera'
+import A2Abusiness from './A2Abusiness'
+import A2Psychz from './A2Psychz'
+import B1Plan from './B1Plan'
+import B2Scene from './B2Scene'
+import B3Push from './B3Push'
+import B4JsonPush from './B4JsonPush'
+import C1User from './C1User'
+import C2Log from './C2Log'
 
 // 合并 reducer
 const rootReducer = combineReducers({
   A0Layout,
   A1Camera,
+  A2Abusiness,
   A2Psychz,
   B1Plan,
   B2Scene,
   B3Push,
   B4JsonPush,
   C1User,
-  C2Log,
-});
+  C2Log
+})
 
 // 默认导出
-export default rootReducer;
+export default rootReducer

+ 26 - 0
src/types/api/A2Abusiness.ts

@@ -0,0 +1,26 @@
+export type A2AListType = {
+  cameraIds: string
+  cameras?: any
+  createTime: string
+  creatorId: number
+  creatorName: string
+  dateEnd: string
+  dateStart: string
+  dingNum: string
+  fileIds: string
+  files?: any
+  id: number
+  num: string
+  pcs: number
+  price?: any
+  rtf: string
+  rtfDesc: string
+  type: string
+  updateTime: string
+  user: string
+  zlCity: string
+  zlName: string
+  zlPhone: string
+  zlProvince: string
+  zlUser: string
+}

+ 13 - 12
src/types/declaration.d.ts

@@ -1,14 +1,15 @@
-declare module "history";
-declare module "*.scss";
-declare module "*.png";
-declare module "*.jpg";
-declare module "*.gif";
-declare module "*.svg";
-declare module "js-export-excel";
+declare module 'history'
+declare module '*.scss'
+declare module '*.png'
+declare module '*.jpg'
+declare module '*.gif'
+declare module '*.svg'
+declare module 'js-export-excel'
+declare module 'braft-utils'
 declare const myCityTemp: {
-  name: string;
+  name: string
   city: {
-    name: string;
-    districtAndCounty: string[];
-  }[];
-}[];
+    name: string
+    districtAndCounty: string[]
+  }[]
+}[]

+ 1 - 0
src/types/index.d.ts

@@ -1,5 +1,6 @@
 export * from './api/layot'
 export * from './api/A1Camera'
+export * from './api/A2Abusiness'
 export * from './api/A2Psychz'
 export * from './api/B1Plan'
 export * from './api/B2Scene'

+ 63 - 0
src/utils/authFilesLook.ts

@@ -0,0 +1,63 @@
+import store from '@/store'
+import { baseURL } from './http'
+
+// 查看 权限 图片 /视频 、音频
+export const authFilesLookFu = (name: string, url: string) => {
+  let flag = false
+
+  const nameRes = name ? name : ''
+
+  // pdf和txt 直接新窗口打开
+  const arr0: ('.pdf' | '.txt')[] = ['.pdf', '.txt']
+  arr0.forEach(v => {
+    if (nameRes.toLowerCase().endsWith(v)) {
+      if (url) window.open(baseURL + url)
+      flag = true
+    }
+  })
+
+  // 图片使用 antd的图片预览组件
+  const arr1 = ['.png', '.jpg', '.jpeg', '.gif']
+  arr1.forEach(v => {
+    if (nameRes.toLowerCase().endsWith(v)) {
+      if (url) {
+        store.dispatch({
+          type: 'layout/lookBigImg',
+          payload: {
+            url: baseURL + url,
+            show: true
+          }
+        })
+      }
+
+      flag = true
+    }
+  })
+
+  // 视频和音频 使用自己的封装的组件
+  let type: '' | 'video' | 'audio' = ''
+  const arr2 = ['.mp3', '.wav']
+  arr2.forEach(v => {
+    if (nameRes.toLowerCase().endsWith(v)) {
+      type = 'audio'
+      flag = true
+    }
+  })
+
+  if (nameRes.toLowerCase().endsWith('.mp4')) {
+    type = 'video'
+    flag = true
+  }
+
+  if (type && url) {
+    store.dispatch({
+      type: 'layout/lookDom',
+      payload: {
+        src: url,
+        type
+      }
+    })
+  }
+
+  return flag
+}