소스 검색

架子已经搭好

xsh 3 년 전
부모
커밋
a57779c40f

+ 9 - 0
babel.config.js

@@ -1,5 +1,14 @@
 module.exports = {
   presets: [
     '@vue/cli-plugin-babel/preset'
+  ],
+  plugins: [
+    [
+
+      "import",
+
+      { libraryName: "ant-design-vue", libraryDirectory: "es", "style":'css' }
+
+    ]
   ]
 }

+ 373 - 19
package-lock.json

@@ -4,6 +4,28 @@
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
+    "@ant-design/colors": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-3.2.2.tgz",
+      "integrity": "sha512-YKgNbG2dlzqMhA9NtI3/pbY16m3Yl/EeWBRa+lB1X1YaYxHrxNexiQYCLTWO/uDvAjLFMEDU+zR901waBtMtjQ==",
+      "requires": {
+        "tinycolor2": "^1.4.1"
+      }
+    },
+    "@ant-design/icons": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-2.1.1.tgz",
+      "integrity": "sha512-jCH+k2Vjlno4YWl6g535nHR09PwCEmTBKAG6VqF+rhkrSPRLfgpU2maagwbZPLjaHuU5Jd1DFQ2KJpQuI6uG8w=="
+    },
+    "@ant-design/icons-vue": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@ant-design/icons-vue/-/icons-vue-2.0.0.tgz",
+      "integrity": "sha512-2c0QQE5hL4N48k5NkPG5sdpMl9YnvyNhf0U7YkdZYDlLnspoRU7vIA0UK9eHBs6OpFLcJB6o8eJrIl2ajBskPg==",
+      "requires": {
+        "@ant-design/colors": "^3.1.0",
+        "babel-runtime": "^6.26.0"
+      }
+    },
     "@babel/code-frame": {
       "version": "7.14.5",
       "resolved": "https://registry.nlark.com/@babel/code-frame/download/@babel/code-frame-7.14.5.tgz",
@@ -175,7 +197,6 @@
       "version": "7.15.4",
       "resolved": "https://registry.nlark.com/@babel/helper-module-imports/download/@babel/helper-module-imports-7.15.4.tgz?cache=0&sync_timestamp=1630619202866&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fhelper-module-imports%2Fdownload%2F%40babel%2Fhelper-module-imports-7.15.4.tgz",
       "integrity": "sha1-4YAH0jBjLeoZtHhTuYRHbntOED8=",
-      "dev": true,
       "requires": {
         "@babel/types": "^7.15.4"
       }
@@ -264,8 +285,7 @@
     "@babel/helper-validator-identifier": {
       "version": "7.14.9",
       "resolved": "https://registry.nlark.com/@babel/helper-validator-identifier/download/@babel/helper-validator-identifier-7.14.9.tgz",
-      "integrity": "sha1-ZlTRcbICT22O4VG/JQlpmRkTHUg=",
-      "dev": true
+      "integrity": "sha1-ZlTRcbICT22O4VG/JQlpmRkTHUg="
     },
     "@babel/helper-validator-option": {
       "version": "7.14.5",
@@ -1061,7 +1081,6 @@
       "version": "7.15.4",
       "resolved": "https://registry.nlark.com/@babel/runtime/download/@babel/runtime-7.15.4.tgz?cache=0&sync_timestamp=1630618785994&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40babel%2Fruntime%2Fdownload%2F%40babel%2Fruntime-7.15.4.tgz",
       "integrity": "sha1-/RfRa/34eObdAtGXU6OfqKjZyEo=",
-      "dev": true,
       "requires": {
         "regenerator-runtime": "^0.13.4"
       }
@@ -1098,7 +1117,6 @@
       "version": "7.15.6",
       "resolved": "https://registry.nlark.com/@babel/types/download/@babel/types-7.15.6.tgz",
       "integrity": "sha1-mavcSCGLKIHAWN0KerBbmcm+dY8=",
-      "dev": true,
       "requires": {
         "@babel/helper-validator-identifier": "^7.14.9",
         "to-fast-properties": "^2.0.0"
@@ -1170,6 +1188,15 @@
       "integrity": "sha1-K1o6s/kYzKSKjHVMCBaOPwPrphs=",
       "dev": true
     },
+    "@simonwep/pickr": {
+      "version": "1.7.4",
+      "resolved": "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.7.4.tgz",
+      "integrity": "sha512-fq7jgKJT21uWGC1mARBHvvd1JYlEf93o7SuVOB4Lr0x/2UPuNC9Oe9n/GzVeg4oVtqMDfh1wIEJpsdOJEZb+3g==",
+      "requires": {
+        "core-js": "^3.6.5",
+        "nanopop": "^2.1.0"
+      }
+    },
     "@soda/friendly-errors-webpack-plugin": {
       "version": "1.8.0",
       "resolved": "https://registry.npm.taobao.org/@soda/friendly-errors-webpack-plugin/download/@soda/friendly-errors-webpack-plugin-1.8.0.tgz",
@@ -2136,6 +2163,14 @@
       "integrity": "sha1-DeiJpgEgOQmw++B7iTjcIdLpZ7w=",
       "dev": true
     },
+    "add-dom-event-listener": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz",
+      "integrity": "sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==",
+      "requires": {
+        "object-assign": "4.x"
+      }
+    },
     "address": {
       "version": "1.1.2",
       "resolved": "https://registry.npm.taobao.org/address/download/address-1.1.2.tgz",
@@ -2216,6 +2251,50 @@
         "color-convert": "^1.9.0"
       }
     },
+    "ant-design-vue": {
+      "version": "1.7.8",
+      "resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-1.7.8.tgz",
+      "integrity": "sha512-F1hmiS9vwbyfuFvlamdW5l9bHKqRlj9wHaGDIE41NZMWXyWy8qL0UFa/+I0Wl8gQWZCqODW5pN6Yfoyn85At3A==",
+      "requires": {
+        "@ant-design/icons": "^2.1.1",
+        "@ant-design/icons-vue": "^2.0.0",
+        "@simonwep/pickr": "~1.7.0",
+        "add-dom-event-listener": "^1.0.2",
+        "array-tree-filter": "^2.1.0",
+        "async-validator": "^3.0.3",
+        "babel-helper-vue-jsx-merge-props": "^2.0.3",
+        "babel-runtime": "6.x",
+        "classnames": "^2.2.5",
+        "component-classes": "^1.2.6",
+        "dom-align": "^1.10.4",
+        "dom-closest": "^0.2.0",
+        "dom-scroll-into-view": "^2.0.0",
+        "enquire.js": "^2.1.6",
+        "intersperse": "^1.0.0",
+        "is-mobile": "^2.2.1",
+        "is-negative-zero": "^2.0.0",
+        "ismobilejs": "^1.0.0",
+        "json2mq": "^0.2.0",
+        "lodash": "^4.17.5",
+        "moment": "^2.21.0",
+        "mutationobserver-shim": "^0.3.2",
+        "node-emoji": "^1.10.0",
+        "omit.js": "^1.0.0",
+        "raf": "^3.4.0",
+        "resize-observer-polyfill": "^1.5.1",
+        "shallow-equal": "^1.0.0",
+        "shallowequal": "^1.0.2",
+        "vue-ref": "^2.0.0",
+        "warning": "^4.0.0"
+      },
+      "dependencies": {
+        "async-validator": {
+          "version": "3.5.2",
+          "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-3.5.2.tgz",
+          "integrity": "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ=="
+        }
+      }
+    },
     "any-promise": {
       "version": "1.3.0",
       "resolved": "https://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz",
@@ -2277,6 +2356,11 @@
       "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
       "dev": true
     },
+    "array-tree-filter": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz",
+      "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw=="
+    },
     "array-union": {
       "version": "1.0.2",
       "resolved": "https://registry.npm.taobao.org/array-union/download/array-union-1.0.2.tgz?cache=0&sync_timestamp=1614624262896&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Farray-union%2Fdownload%2Farray-union-1.0.2.tgz",
@@ -2488,6 +2572,15 @@
         "object.assign": "^4.1.0"
       }
     },
+    "babel-plugin-import": {
+      "version": "1.13.3",
+      "resolved": "https://registry.npmjs.org/babel-plugin-import/-/babel-plugin-import-1.13.3.tgz",
+      "integrity": "sha512-1qCWdljJOrDRH/ybaCZuDgySii4yYrtQ8OJQwrcDqdt0y67N30ng3X3nABg6j7gR7qUJgcMa9OMhc4AGViDwWw==",
+      "requires": {
+        "@babel/helper-module-imports": "^7.0.0",
+        "@babel/runtime": "^7.0.0"
+      }
+    },
     "babel-plugin-polyfill-corejs2": {
       "version": "0.2.2",
       "resolved": "https://registry.nlark.com/babel-plugin-polyfill-corejs2/download/babel-plugin-polyfill-corejs2-0.2.2.tgz?cache=0&sync_timestamp=1622023904181&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fbabel-plugin-polyfill-corejs2%2Fdownload%2Fbabel-plugin-polyfill-corejs2-0.2.2.tgz",
@@ -3204,6 +3297,11 @@
         }
       }
     },
+    "classnames": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
+      "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
+    },
     "clean-css": {
       "version": "4.2.3",
       "resolved": "https://registry.nlark.com/clean-css/download/clean-css-4.2.3.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fclean-css%2Fdownload%2Fclean-css-4.2.3.tgz",
@@ -3466,12 +3564,25 @@
       "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
       "dev": true
     },
+    "component-classes": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/component-classes/-/component-classes-1.2.6.tgz",
+      "integrity": "sha1-xkI5TDYYpNiwuJGe/Mu9kw5c1pE=",
+      "requires": {
+        "component-indexof": "0.0.3"
+      }
+    },
     "component-emitter": {
       "version": "1.3.0",
       "resolved": "https://registry.npm.taobao.org/component-emitter/download/component-emitter-1.3.0.tgz",
       "integrity": "sha1-FuQHD7qK4ptnnyIVhT7hgasuq8A=",
       "dev": true
     },
+    "component-indexof": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/component-indexof/-/component-indexof-0.0.3.tgz",
+      "integrity": "sha1-EdCRMSI5648yyPJa6csAL/6NPCQ="
+    },
     "compressible": {
       "version": "2.0.18",
       "resolved": "https://registry.npm.taobao.org/compressible/download/compressible-2.0.18.tgz",
@@ -3632,6 +3743,15 @@
       "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
       "dev": true
     },
+    "copy-anything": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.3.tgz",
+      "integrity": "sha512-GK6QUtisv4fNS+XcI7shX0Gx9ORg7QqIznyfho79JTnX1XhLiyZHfftvGiziqzRiEi/Bjhgpi+D2o7HxJFPnDQ==",
+      "dev": true,
+      "requires": {
+        "is-what": "^3.12.0"
+      }
+    },
     "copy-concurrently": {
       "version": "1.0.5",
       "resolved": "https://registry.nlark.com/copy-concurrently/download/copy-concurrently-1.0.5.tgz",
@@ -4526,6 +4646,19 @@
         "esutils": "^2.0.2"
       }
     },
+    "dom-align": {
+      "version": "1.12.2",
+      "resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.2.tgz",
+      "integrity": "sha512-pHuazgqrsTFrGU2WLDdXxCFabkdQDx72ddkraZNih1KsMcN5qsRSTR9O4VJRlwTPCPb5COYg3LOfiMHHcPInHg=="
+    },
+    "dom-closest": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/dom-closest/-/dom-closest-0.2.0.tgz",
+      "integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=",
+      "requires": {
+        "dom-matches": ">=1.0.1"
+      }
+    },
     "dom-converter": {
       "version": "0.2.0",
       "resolved": "https://registry.npm.taobao.org/dom-converter/download/dom-converter-0.2.0.tgz",
@@ -4535,6 +4668,16 @@
         "utila": "~0.4"
       }
     },
+    "dom-matches": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/dom-matches/-/dom-matches-2.0.0.tgz",
+      "integrity": "sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw="
+    },
+    "dom-scroll-into-view": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-2.0.1.tgz",
+      "integrity": "sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w=="
+    },
     "dom-serializer": {
       "version": "0.2.2",
       "resolved": "https://registry.nlark.com/dom-serializer/download/dom-serializer-0.2.2.tgz?cache=0&sync_timestamp=1621256918158&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdom-serializer%2Fdownload%2Fdom-serializer-0.2.2.tgz",
@@ -4751,6 +4894,11 @@
         }
       }
     },
+    "enquire.js": {
+      "version": "2.1.6",
+      "resolved": "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz",
+      "integrity": "sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ="
+    },
     "entities": {
       "version": "2.2.0",
       "resolved": "https://registry.nlark.com/entities/download/entities-2.2.0.tgz",
@@ -6294,6 +6442,13 @@
       "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=",
       "dev": true
     },
+    "image-size": {
+      "version": "0.5.5",
+      "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
+      "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
+      "dev": true,
+      "optional": true
+    },
     "import-cwd": {
       "version": "2.1.0",
       "resolved": "https://registry.nlark.com/import-cwd/download/import-cwd-2.1.0.tgz",
@@ -6550,6 +6705,11 @@
         "side-channel": "^1.0.4"
       }
     },
+    "intersperse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/intersperse/-/intersperse-1.0.0.tgz",
+      "integrity": "sha1-8lYfsc/vn1J3zDNHoiiGtDUaUYE="
+    },
     "ip": {
       "version": "1.1.5",
       "resolved": "https://registry.nlark.com/ip/download/ip-1.1.5.tgz",
@@ -6770,11 +6930,15 @@
         "is-extglob": "^2.1.1"
       }
     },
+    "is-mobile": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-2.2.2.tgz",
+      "integrity": "sha512-wW/SXnYJkTjs++tVK5b6kVITZpAZPtUrt9SF80vvxGiF/Oywal+COk1jlRkiVq15RFNEQKQY31TkV24/1T5cVg=="
+    },
     "is-negative-zero": {
       "version": "2.0.1",
       "resolved": "https://registry.npm.taobao.org/is-negative-zero/download/is-negative-zero-2.0.1.tgz?cache=0&sync_timestamp=1607123422635&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-negative-zero%2Fdownload%2Fis-negative-zero-2.0.1.tgz",
-      "integrity": "sha1-PedGwY3aIxkkGlNnWQjY92bxHCQ=",
-      "dev": true
+      "integrity": "sha1-PedGwY3aIxkkGlNnWQjY92bxHCQ="
     },
     "is-number": {
       "version": "3.0.0",
@@ -6896,6 +7060,12 @@
       "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
       "dev": true
     },
+    "is-what": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz",
+      "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==",
+      "dev": true
+    },
     "is-windows": {
       "version": "1.0.2",
       "resolved": "https://registry.npm.taobao.org/is-windows/download/is-windows-1.0.2.tgz",
@@ -6920,6 +7090,11 @@
       "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
       "dev": true
     },
+    "ismobilejs": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-1.1.1.tgz",
+      "integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw=="
+    },
     "isobject": {
       "version": "3.0.1",
       "resolved": "https://registry.nlark.com/isobject/download/isobject-3.0.1.tgz",
@@ -6956,8 +7131,7 @@
     "js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.nlark.com/js-tokens/download/js-tokens-4.0.0.tgz",
-      "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=",
-      "dev": true
+      "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk="
     },
     "js-yaml": {
       "version": "3.14.1",
@@ -7017,6 +7191,14 @@
       "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
       "dev": true
     },
+    "json2mq": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz",
+      "integrity": "sha1-tje9O6nqvhIsg+lyBIOusQ0skEo=",
+      "requires": {
+        "string-convert": "^0.2.0"
+      }
+    },
     "json3": {
       "version": "3.3.3",
       "resolved": "https://registry.npm.taobao.org/json3/download/json3-3.3.3.tgz",
@@ -7065,6 +7247,12 @@
       "integrity": "sha1-B8BQNKbDSfoG4k+jWqdttFgM5N0=",
       "dev": true
     },
+    "klona": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz",
+      "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==",
+      "dev": true
+    },
     "launch-editor": {
       "version": "2.2.1",
       "resolved": "https://registry.npm.taobao.org/launch-editor/download/launch-editor-2.2.1.tgz",
@@ -7084,6 +7272,67 @@
         "launch-editor": "^2.2.1"
       }
     },
+    "less": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/less/-/less-4.1.1.tgz",
+      "integrity": "sha512-w09o8tZFPThBscl5d0Ggp3RcrKIouBoQscnOMgFH3n5V3kN/CXGHNfCkRPtxJk6nKryDXaV9aHLK55RXuH4sAw==",
+      "dev": true,
+      "requires": {
+        "copy-anything": "^2.0.1",
+        "errno": "^0.1.1",
+        "graceful-fs": "^4.1.2",
+        "image-size": "~0.5.0",
+        "make-dir": "^2.1.0",
+        "mime": "^1.4.1",
+        "needle": "^2.5.2",
+        "parse-node-version": "^1.0.1",
+        "source-map": "~0.6.0",
+        "tslib": "^1.10.0"
+      },
+      "dependencies": {
+        "make-dir": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+          "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "pify": "^4.0.1",
+            "semver": "^5.6.0"
+          }
+        },
+        "mime": {
+          "version": "1.6.0",
+          "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+          "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+          "dev": true,
+          "optional": true
+        },
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true,
+          "optional": true
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "less-loader": {
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-10.0.1.tgz",
+      "integrity": "sha512-Crln//HpW9M5CbtdfWm3IO66Cvx1WhZQvNybXgfB2dD/6Sav9ppw+IWqs/FQKPBFO4B6X0X28Z0WNznshgwUzA==",
+      "dev": true,
+      "requires": {
+        "klona": "^2.0.4"
+      }
+    },
     "levn": {
       "version": "0.3.0",
       "resolved": "https://registry.nlark.com/levn/download/levn-0.3.0.tgz",
@@ -7191,8 +7440,7 @@
     "lodash": {
       "version": "4.17.21",
       "resolved": "https://registry.nlark.com/lodash/download/lodash-4.17.21.tgz?cache=0&sync_timestamp=1618847150612&other_urls=https%3A%2F%2Fregistry.nlark.com%2Flodash%2Fdownload%2Flodash-4.17.21.tgz",
-      "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw=",
-      "dev": true
+      "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw="
     },
     "lodash.debounce": {
       "version": "4.0.8",
@@ -7251,6 +7499,14 @@
       "integrity": "sha1-AF/eL15uRwaPk1/yhXPhJe9y8Zc=",
       "dev": true
     },
+    "loose-envify": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+      "requires": {
+        "js-tokens": "^3.0.0 || ^4.0.0"
+      }
+    },
     "lower-case": {
       "version": "1.1.4",
       "resolved": "https://registry.npm.taobao.org/lower-case/download/lower-case-1.1.4.tgz?cache=0&sync_timestamp=1606867514181&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flower-case%2Fdownload%2Flower-case-1.1.4.tgz",
@@ -7559,6 +7815,11 @@
         "minimist": "^1.2.5"
       }
     },
+    "moment": {
+      "version": "2.29.1",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
+      "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
+    },
     "move-concurrently": {
       "version": "1.0.1",
       "resolved": "https://registry.nlark.com/move-concurrently/download/move-concurrently-1.0.1.tgz",
@@ -7595,6 +7856,11 @@
       "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
       "dev": true
     },
+    "mutationobserver-shim": {
+      "version": "0.3.7",
+      "resolved": "https://registry.npmjs.org/mutationobserver-shim/-/mutationobserver-shim-0.3.7.tgz",
+      "integrity": "sha512-oRIDTyZQU96nAiz2AQyngwx1e89iApl2hN5AOYwyxLUB47UYsU3Wv9lJWqH5y/QdiYkc5HQLi23ZNB3fELdHcQ=="
+    },
     "mute-stream": {
       "version": "0.0.8",
       "resolved": "https://registry.npm.taobao.org/mute-stream/download/mute-stream-0.0.8.tgz",
@@ -7638,12 +7904,41 @@
         "to-regex": "^3.0.1"
       }
     },
+    "nanopop": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/nanopop/-/nanopop-2.1.0.tgz",
+      "integrity": "sha512-jGTwpFRexSH+fxappnGQtN9dspgE2ipa1aOjtR24igG0pv6JCxImIAmrLRHX+zUF5+1wtsFVbKyfP51kIGAVNw=="
+    },
     "natural-compare": {
       "version": "1.4.0",
       "resolved": "https://registry.npm.taobao.org/natural-compare/download/natural-compare-1.4.0.tgz",
       "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
       "dev": true
     },
+    "needle": {
+      "version": "2.9.1",
+      "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz",
+      "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "debug": "^3.2.6",
+        "iconv-lite": "^0.4.4",
+        "sax": "^1.2.4"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        }
+      }
+    },
     "negotiator": {
       "version": "0.6.2",
       "resolved": "https://registry.npm.taobao.org/negotiator/download/negotiator-0.6.2.tgz",
@@ -7671,6 +7966,14 @@
         "lower-case": "^1.1.1"
       }
     },
+    "node-emoji": {
+      "version": "1.11.0",
+      "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz",
+      "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==",
+      "requires": {
+        "lodash": "^4.17.21"
+      }
+    },
     "node-forge": {
       "version": "0.10.0",
       "resolved": "https://registry.npm.taobao.org/node-forge/download/node-forge-0.10.0.tgz?cache=0&sync_timestamp=1599010726129&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-forge%2Fdownload%2Fnode-forge-0.10.0.tgz",
@@ -7809,8 +8112,7 @@
     "object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.nlark.com/object-assign/download/object-assign-4.1.1.tgz?cache=0&sync_timestamp=1618847240432&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fobject-assign%2Fdownload%2Fobject-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
-      "dev": true
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
     },
     "object-copy": {
       "version": "0.1.0",
@@ -7929,6 +8231,14 @@
       "integrity": "sha1-Cb6jND1BhZ69RGKS0RydTbYZCE4=",
       "dev": true
     },
+    "omit.js": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/omit.js/-/omit.js-1.0.2.tgz",
+      "integrity": "sha512-/QPc6G2NS+8d4L/cQhbk6Yit1WTB6Us2g84A7A/1+w9d/eRGHyEqC5kkQtHVoHZ5NFWGG7tUGgrhVZwgZanKrQ==",
+      "requires": {
+        "babel-runtime": "^6.23.0"
+      }
+    },
     "on-finished": {
       "version": "2.3.0",
       "resolved": "https://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz",
@@ -8159,6 +8469,12 @@
         "lines-and-columns": "^1.1.6"
       }
     },
+    "parse-node-version": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
+      "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
+      "dev": true
+    },
     "parse5": {
       "version": "5.1.1",
       "resolved": "https://registry.nlark.com/parse5/download/parse5-5.1.1.tgz",
@@ -8275,8 +8591,7 @@
     "performance-now": {
       "version": "2.1.0",
       "resolved": "https://registry.nlark.com/performance-now/download/performance-now-2.1.0.tgz",
-      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
-      "dev": true
+      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
     },
     "picomatch": {
       "version": "2.3.0",
@@ -9115,6 +9430,14 @@
       "integrity": "sha1-M0WUG0FTy50ILY7uTNogFqmu9/Y=",
       "dev": true
     },
+    "raf": {
+      "version": "3.4.1",
+      "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
+      "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
+      "requires": {
+        "performance-now": "^2.1.0"
+      }
+    },
     "randombytes": {
       "version": "2.1.0",
       "resolved": "https://registry.nlark.com/randombytes/download/randombytes-2.1.0.tgz",
@@ -9207,8 +9530,7 @@
     "regenerator-runtime": {
       "version": "0.13.9",
       "resolved": "https://registry.nlark.com/regenerator-runtime/download/regenerator-runtime-0.13.9.tgz?cache=0&sync_timestamp=1626993001371&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.13.9.tgz",
-      "integrity": "sha1-iSV0Kpj/2QgUmI11Zq0wyjsmO1I=",
-      "dev": true
+      "integrity": "sha1-iSV0Kpj/2QgUmI11Zq0wyjsmO1I="
     },
     "regenerator-transform": {
       "version": "0.14.5",
@@ -9790,6 +10112,16 @@
         "safe-buffer": "^5.0.1"
       }
     },
+    "shallow-equal": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz",
+      "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA=="
+    },
+    "shallowequal": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
+      "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
+    },
     "shebang-command": {
       "version": "1.2.0",
       "resolved": "https://registry.nlark.com/shebang-command/download/shebang-command-1.2.0.tgz",
@@ -10291,6 +10623,11 @@
       "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
       "dev": true
     },
+    "string-convert": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz",
+      "integrity": "sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c="
+    },
     "string-width": {
       "version": "4.2.2",
       "resolved": "https://registry.nlark.com/string-width/download/string-width-4.2.2.tgz",
@@ -10686,6 +11023,11 @@
       "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
       "dev": true
     },
+    "tinycolor2": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz",
+      "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA=="
+    },
     "tmp": {
       "version": "0.0.33",
       "resolved": "https://registry.nlark.com/tmp/download/tmp-0.0.33.tgz",
@@ -10704,8 +11046,7 @@
     "to-fast-properties": {
       "version": "2.0.0",
       "resolved": "https://registry.nlark.com/to-fast-properties/download/to-fast-properties-2.0.0.tgz?cache=0&sync_timestamp=1628418893613&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fto-fast-properties%2Fdownload%2Fto-fast-properties-2.0.0.tgz",
-      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
-      "dev": true
+      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
     },
     "to-object-path": {
       "version": "0.3.0",
@@ -11234,6 +11575,11 @@
         }
       }
     },
+    "vue-ref": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/vue-ref/-/vue-ref-2.0.0.tgz",
+      "integrity": "sha512-uKNKpFOVeWNqS2mrBZqnpLyXJo5Q+vnkex6JvpENvhXHFNBW/SJTP8vJywLuVT3DpxwXcF9N0dyIiZ4/NpTexQ=="
+    },
     "vue-router": {
       "version": "3.5.2",
       "resolved": "https://registry.nlark.com/vue-router/download/vue-router-3.5.2.tgz?cache=0&sync_timestamp=1628495505697&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvue-router%2Fdownload%2Fvue-router-3.5.2.tgz",
@@ -11278,6 +11624,14 @@
       "resolved": "https://registry.nlark.com/vuex/download/vuex-3.6.2.tgz",
       "integrity": "sha1-I2vAhqhww655lG8QfxbeWdWJXnE="
     },
+    "warning": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+      "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+      "requires": {
+        "loose-envify": "^1.0.0"
+      }
+    },
     "watchpack": {
       "version": "1.7.5",
       "resolved": "https://registry.nlark.com/watchpack/download/watchpack-1.7.5.tgz",

+ 4 - 0
package.json

@@ -8,7 +8,9 @@
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
+    "ant-design-vue": "^1.7.8",
     "axios": "^0.21.4",
+    "babel-plugin-import": "^1.13.3",
     "core-js": "^3.6.5",
     "element-ui": "^2.15.6",
     "vue": "^2.6.11",
@@ -25,6 +27,8 @@
     "compression-webpack-plugin": "^9.0.0",
     "eslint": "^6.7.2",
     "eslint-plugin-vue": "^6.2.2",
+    "less": "^4.1.1",
+    "less-loader": "^10.0.1",
     "vue-template-compiler": "^2.6.11"
   },
   "eslintConfig": {

BIN
src/assets/images/login.png


BIN
src/assets/images/pwd.png


+ 45 - 6
src/components/HeaderElement.vue

@@ -7,8 +7,22 @@
       <el-col :span="4" style="height: 100%">
         <span class="title">数智牧场管理系统</span>
       </el-col>
-      <el-col :span="4" :offset="15" style="height: 100%">
+      <el-col :span="7" :offset="12" style="height: 100%">
         <div class="flex">
+          <div class="user" style="width: 250px;">
+            <div>
+              <el-switch
+                  style="display: block"
+                  v-model="$store.state.mode"
+                  active-color="#13ce66"
+                  inactive-color="#ff4949"
+                  active-text="单一导航"
+                  inactive-text="多级导航"
+                  @change="changeMode">
+              </el-switch>
+            </div>
+          </div>
+          <el-divider direction="vertical"></el-divider>
           <div class="user">
             <div>
               <i class="el-icon-user-solid" style="font-size: 28px"></i>
@@ -31,7 +45,7 @@
                       <li>上次登录: <span class="user-color">厂长</span></li>
                     </ul>
                   </div>
-                <span slot="reference">admin</span>
+                <span slot="reference">{{userName}}</span>
               </el-popover>
             </div>
           </div>
@@ -60,7 +74,7 @@
           <el-divider direction="vertical"></el-divider>
           <div class="user">
             <div style="width: 100%; text-align: center">
-              <i class="guanbi" title="退出登录"></i>
+              <i class="guanbi" @click="logout" title="退出登录"></i>
             </div>
           </div>
         </div>
@@ -70,7 +84,8 @@
 </template>
 
 <script>
-import { mapState, mapMutations } from 'vuex'
+import { mapState, mapActions } from 'vuex'
+import { findUpdate } from '../utils/api';
 export default {
   name: "HeaderElement",
   computed: {
@@ -78,6 +93,7 @@ export default {
   },
   data() {
     return {
+      userName: localStorage.getItem('UserName'),
       colorList: [
         {
           id: 1,
@@ -115,9 +131,32 @@ export default {
     }
   },
   methods: {
-    ...mapMutations(['setColor']),
+    ...mapActions(['setModeAsync', 'setColorAsync']),
     cut(data) {
-      this.setColor(data)
+      this.setColorAsync(data)
+      let params = {
+        id: localStorage.getItem('UserId'),
+        color: data
+      }
+      findUpdate(params).then(res => {
+        console.log(res)
+      })
+    },
+    changeMode(val) {
+      let params = {
+        id: localStorage.getItem('UserId'),
+        mode: val
+      }
+      findUpdate(params).then(res => {
+        console.log(res)
+      })
+      this.setModeAsync(val)
+    },
+    logout() {
+      localStorage.removeItem('UserName');
+      localStorage.removeItem('accessToken');
+      localStorage.removeItem('UserId');
+      this.$router.replace('/login');
     }
   }
 }

+ 107 - 79
src/components/SideMenu.vue

@@ -1,101 +1,111 @@
 <template>
   <div class="sidemenu">
-    <el-menu
-        :style="{width: width + 'px', display: 'inline-block', height: '100%'}"
-        background-color="#464C5B"
-        text-color="#fff"
-        :default-active="activeName"
-        :active-text-color="color">
-      <el-menu-item
-          v-for="(item) in menuList"
-          :class="[item.menuName === activeName && activeName!=='首页' ? 'menuSet' : '']"
-          :index="item.menuName"
-          :key="item.id"
-          @click="jump(item)">
-        <template slot="title">
-          <span>{{item.menuName}}</span>
-        </template>
-      </el-menu-item>
-    </el-menu>
-    <div v-show="isShow" class="subsidemenu">
-      <div class="menu-header">{{selectItem.menuName}}</div>
-      <ul class="menu-item-children">
-        <li
-            v-for="item in selectItem.children"
-            class="menuChildren"
-            :style="{color: item.url == activeUrl ? color : '#999'}"
-            @click="go(item)"
-            :key="item.id">{{item.menuName}}</li>
-      </ul>
+    <div style="height: 100%" v-if="mode">
+      <el-menu
+          :style="{width: width + 'px', display: 'inline-block', height: '100%'}"
+          background-color="#464C5B"
+          text-color="#fff"
+          :default-active="activeName"
+          :active-text-color="color">
+        <el-menu-item
+            v-for="(item) in menuList"
+            :class="[item.title === activeName && activeName!== '首页' ? 'menuSet' : '']"
+            :index="item.title"
+            :key="item.id"
+            @click="jump(item)">
+          <template slot="title">
+            <span>{{item.title}}</span>
+          </template>
+        </el-menu-item>
+      </el-menu>
+      <div v-show="isShow" class="subsidemenu">
+        <div class="menu-header">{{selectItem.title}}</div>
+        <ul class="menu-item-children">
+          <li
+              v-for="item in selectItem.children"
+              class="menuChildren"
+              :style="{color: item.url == activeUrl ? color : '#999'}"
+              @click="go(item)"
+              :key="item.id">{{item.title}}</li>
+        </ul>
+      </div>
+    </div>
+    <div style="height: 100%" v-else>
+      <el-menu
+          router
+          :style="{width: '249px', display: 'inline-block', height: '100%'}"
+          background-color="#464C5B"
+          text-color="#fff"
+          :default-active="routerName"
+          :active-text-color="color">
+          <template v-for="item in menuList">
+            <el-submenu :key="item.id" v-if="item.children.length > 0" :index="item.url">
+              <span slot="title">{{item.title}}</span>
+              <el-menu-item v-for="list in item.children" :key="list.id" :index="list.url">{{list.title}}</el-menu-item>
+            </el-submenu>
+            <el-menu-item :key="item.id" v-else :index="item.url">{{item.title}}</el-menu-item>
+          </template>
+      </el-menu>
     </div>
   </div>
 </template>
 
 <script>
 import { mapState } from 'vuex'
+import { getUserMenu} from "../utils/api";
 export default {
   name: "SideMenu",
   computed: {
-    ...mapState(['color'])
+    ...mapState(['color', 'mode'])
   },
   data() {
     return {
-      menuList: [
-        {
-          id: 1,
-          menuName: '首页',
-          parentId: 0,
-          sort: 1,
-          url: 'dashboard',
-          children: [],
-        },
-        {
-          id: 2,
-          menuName: '生物安全',
-          parentId: 0,
-          sort: 2,
-          url: '',
-          children: [
-            {
-              id: 9,
-              menuName: "人员管理",
-              parentId: 8,
-              sort: 1,
-              url: "userAdmin",
-            },
-            {
-              children: [],
-              id: 10,
-              menuName: "车辆管理",
-              parentId: 8,
-              sort: 2,
-              url: "carAdmin",
-            }
-          ]
-        }
-      ],
+      menuList: [],
       width: 249,
       isShow: false,
       selectItem: {},
       activeUrl: '',
       activeName: '首页',
+      routerName: 'dashboard'
     }
   },
   watch: {
     $route(newVal) {
       let parentName = newVal.meta.parentName;
       let routerName = newVal.meta.permission;
-      this.activeName = parentName;
-      this.activeUrl = routerName
-      var that = this;
-      this.$nextTick(() => {
+      if(this.mode) {
+        this.activeName = parentName;
+        this.activeUrl = routerName
+        var that = this;
+
         that.selectItem = that.getFilter(that.menuList, parentName)[0];
-        if (that.selectItem.children.length > 0) {
-          that.isShow = true;
+          if (that.selectItem.children.length > 0) {
+            that.isShow = true;
+          } else {
+            that.isShow = false;
+          }
+
+      } else {
+        this.routerName = routerName
+      }
+    },
+    mode(newVal) {
+      // 路由地址
+      let routerName = this.$route.meta.permission;
+      // 上级菜单名字
+      let parentName = this.$route.meta.parentName;
+      if(newVal) {
+        this.selectItem = this.getFilter(this.menuList, parentName)[0];
+        if (this.selectItem.children.length > 0) {
+          this.isShow = true;
         } else {
-          that.isShow = false;
+          this.isShow = false;
         }
-      })
+        this.activeUrl = routerName;
+        this.activeName = parentName;
+      } else {
+        this.routerName = routerName;
+      }
     },
     isShow(newVal) {
       if(newVal) {
@@ -106,8 +116,25 @@ export default {
     },
   },
   methods: {
+    init() {
+      let params = {
+        userId: localStorage.getItem('UserId')
+      }
+      let parentName = this.$route.meta.parentName;
+      getUserMenu(params).then(res => {
+        if(res.code === 10000) {
+          this.menuList = res.data;
+          this.selectItem = this.getFilter(this.menuList, parentName)[0];
+          if (this.selectItem.children.length > 0) {
+            this.isShow = true;
+          } else {
+            this.isShow = false;
+          }
+        }
+      })
+    },
     jump(item) {
-      this.activeName = item.menuName;
+      this.activeName = item.title;
       if(item.children.length > 0) {
         // this.width = 100;
         this.isShow = true;
@@ -130,7 +157,7 @@ export default {
     getFilter(list, name) {
      let childrenList = [];
      const targetList = list.filter((item) => {
-        if(item.menuName == name) {
+        if(item.title == name) {
             return true
         } else if(item.children && item.children.length) {
           childrenList = childrenList.concat(this.getFilter(item.children, name));
@@ -142,19 +169,20 @@ export default {
       return targetList.concat(childrenList);
     }
   },
+  created() {
+    this.init()
+  },
   mounted() {
-    // 路由地址
+    // // 路由地址
     let routerName = this.$route.meta.permission;
     // 上级菜单名字
     let parentName = this.$route.meta.parentName;
-    this.selectItem = this.getFilter(this.menuList, parentName)[0];
-    if (this.selectItem.children.length > 0) {
-      this.isShow = true;
+    if(this.mode) {
+      this.activeUrl = routerName;
+      this.activeName = parentName;
     } else {
-      this.isShow = false;
+      this.routerName = routerName;
     }
-    this.activeUrl = routerName;
-    this.activeName = parentName;
   }
 }
 </script>

+ 55 - 0
src/components/TableFooter.vue

@@ -0,0 +1,55 @@
+<template>
+  <div style="margin-top: 20px; height: 50px">
+    <el-pagination background
+                   style="float: right; display: inline-block"
+                   :total="totals"
+                   layout="total, sizes, prev, pager, next, jumper"
+                   @size-change="sizeChange"
+                   @current-change="pageChange"
+                   :page-sizes="sizesArray"
+                   :page-size="size"></el-pagination>
+  </div>
+</template>
+
+<script>
+  export default {
+    name: "TableFooter",
+    data() {
+      return {
+
+      }
+    },
+    props: {
+      totals: {
+        type: Number,
+        default() {
+          return 0;
+        },
+      },
+      sizesArray: {
+        type: Array,
+        default() {
+          return [10, 20, 40, 60, 80, 100];
+        },
+      },
+      size: {
+        type: Number,
+        default() {
+          return 20;
+        },
+      },
+    },
+    methods: {
+      sizeChange(value) {
+        this.$emit('sizeChange', value);
+      },
+      pageChange(value) {
+        this.$emit('pageChange', value);
+      },
+    }
+  }
+</script>
+
+<style scoped>
+
+</style>

+ 4 - 0
src/main.js

@@ -4,8 +4,12 @@ import router from './router'
 import store from './store'
 import ElementUI from 'element-ui'
 import 'element-ui/lib/theme-chalk/index.css';
+import { hasBtnPermission } from './utils/permission';
+import { Modal } from 'ant-design-vue';
 Vue.config.productionTip = false
 Vue.use(ElementUI);
+Vue.use(Modal);
+Vue.prototype.hasPerm = hasBtnPermission
 
 new Vue({
   router,

+ 97 - 4
src/router/ChildrenRouters.js

@@ -26,12 +26,12 @@ const childrenRouters = [
 
   /* 人员管理 */
   {
-    path: '/userAdmin',
-    name: 'UserAdmin',
-    component: () => import('../views/BioSafety/UserAdmin.vue'),
+    path: '/personAdmin',
+    name: 'PersonAdmin',
+    component: () => import('../views/BioSafety/PersonAdmin.vue'),
     meta: {
       title: '人员管理',
-      permission: 'userAdmin',
+      permission: 'personAdmin',
       parentName: '生物安全',
     }
   },
@@ -46,6 +46,99 @@ const childrenRouters = [
       parentName: '生物安全',
     }
   },
+  {
+    path: '/stiflingAdmin',
+    name: 'StiflingAdmin',
+    component: () => import('../views/BioSafety/StiflingAdmin.vue'),
+    meta: {
+      title: '熏蒸监管',
+      permission: 'stiflingAdmin',
+      parentName: '生物安全'
+    }
+  },
+  {
+    path: '/deadPig',
+    name: 'DeadPig',
+    component: () => import('../views/BioSafety/DeadPig.vue'),
+    meta: {
+      title: '死猪管理',
+      permission: 'deadPig',
+      parentName: '生物安全'
+    }
+  },
+
+  /*
+  *
+  * 环境监测
+  *
+  * */
+
+  {
+    path: '/pigHouseEnv',
+    name: 'PigHouseEnv',
+    component: () => import('../views/Env/PigHouseEnv.vue'),
+    meta: {
+      title: '猪舍环境',
+      permission: 'pigHouseEnv',
+      parentName: '环境监测'
+    }
+  },
+  {
+    path: '/drinkWater',
+    name: 'DrinkWater',
+    component: () => import('../views/Env/DrinkWater.vue'),
+    meta: {
+      title: '饮水监测',
+      permission: 'drinkWater',
+      parentName: '环境监测'
+    }
+  },
+  {
+    path: '/electro',
+    name: 'Electro',
+    component: () => import('../views/Env/Electro.vue'),
+    meta: {
+      title: '用电监测',
+      permission: 'electro',
+      parentName: '环境监测'
+    }
+  },
+
+  /*
+  *
+  * 系统管理
+  *
+  * */
+  {
+    path: '/menuAdmin',
+    name: 'MenuAdmin',
+    component: () => import('../views/SystemAdmin/MenuAdmin.vue'),
+    meta: {
+      title: '菜单管理',
+      permission: 'menuAdmin',
+      parentName: '系统管理'
+    }
+  },
+  {
+    path: '/authAdmin',
+    name: 'AuthAdmin',
+    component: () => import('../views/SystemAdmin/AuthAdmin.vue'),
+    meta: {
+      title: '权限管理',
+      permission: 'authAdmin',
+      parentName: '系统管理'
+    }
+  },
+  {
+    path: '/userAdmin',
+    name: 'UserAdmin',
+    component: () => import('../views/SystemAdmin/UserAdmin.vue'),
+    meta: {
+      title: '用户管理',
+      permission: 'userAdmin',
+      parentName: '系统管理'
+    }
+  }
 ]
 
 export default childrenRouters;

+ 8 - 0
src/router/index.js

@@ -13,6 +13,14 @@ const routes = [
     name: 'MainLayout',
     component: () => import('../views/MainLayout.vue'),
     children: mainRouterChildren
+  },
+  {
+    path: '/login',
+    name: 'Login',
+    component: () => import('../views/Login/Login.vue'),
+    meta: {
+      title: '登录',
+    },
   }
 ]
 

+ 19 - 1
src/store/index.js

@@ -5,15 +5,33 @@ Vue.use(Vuex)
 
 export default new Vuex.Store({
   state: {
-    color: '#31C3A6'
+    color: '#31C3A6',
+    mode: true,
+    // 按钮权限
+    buttons: ['menu:add', 'menu:del']
   },
   mutations: {
     setColor(state, data) {
       state.color = data
+    },
+    setMode(state, data){
+      state.mode = data
+    },
+    SET_BUTTONS(state, data) {
+      state.buttons = data
     }
   },
   actions: {
+    setModeAsync(context, data) {
+      context.commit('setMode' ,data)
+    },
+    setColorAsync(context, data) {
+      context.commit('setColor', data)
+    }
   },
   modules: {
+  },
+  getters: {
+    buttons: state => state.buttons
   }
 })

+ 170 - 0
src/utils/api.js

@@ -0,0 +1,170 @@
+import axios from './http';
+
+/**  登录相关   **/
+// 登录
+export function Login(data) {
+  return axios({
+    url: '/my/login',
+    method: 'post',
+    data: data
+  })
+}
+// 根据用户id 拿到默认的 颜色 和 导航栏
+export function findOne(data) {
+  return axios({
+    url: '/account/findOne',
+    method: 'get',
+    params: data
+  })
+}
+
+// 根据id 修改 默认样式 导航
+export function findUpdate(data) {
+  return axios({
+    url: '/account/update',
+    method: 'post',
+    data: data
+  })
+}
+
+/**  系统管理api  **/
+// 获取菜单用户列表
+export function getUserMenu(data) {
+  return axios({
+    url: '/auth/getMyMenu',
+    method: 'post',
+    params: data
+  })
+}
+
+export function getUserMenuAndButon(data) {
+  return axios({
+    url: '/auth/getMyMenuAndButton',
+    method: 'post',
+    params: data,
+  })
+}
+
+// 获取纯菜单(不带按钮)
+export function getMenuList() {
+  return axios({
+    url: '/menu/list1',
+    method: 'post',
+  })
+}
+
+// 获取菜单列表
+export function getMenu() {
+  return axios({
+    url: '/menu/list',
+    method: 'post'
+  })
+}
+
+// 菜单添加
+export function addMenu(data) {
+  return axios({
+    url: '/menu/add',
+    method: 'post',
+    data: data
+  })
+}
+
+// 菜单编辑
+export function editMenu(data) {
+  return axios({
+    url: '/menu/edit',
+    method: 'post',
+    data: data
+  })
+}
+
+// 菜单删除
+export function delMenu(data) {
+  return axios({
+    url: '/menu/remove',
+    method: 'post',
+    params: data
+  })
+}
+
+// 权限列表
+export function getAuth(data) {
+  return axios({
+    url: '/group/list',
+    method: 'post',
+    data: data
+  })
+}
+
+// 权限列表删除
+export function delAuth(data) {
+  return axios({
+    url: '/group/remove',
+    method: 'post',
+    params: data
+  })
+}
+
+// 新增权限组
+export function addAuth(data) {
+  return axios({
+    url: '/group/add',
+    method: 'post',
+    data: data
+  })
+}
+
+// 编辑权限组
+export function editAuth(data) {
+  return axios({
+    url: '/group/edit',
+    method: 'post',
+    data: data
+  })
+}
+
+// 权限分配列表(上次保存的菜单)
+export function getMenuByGroup(data) {
+  return axios({
+    url: '/auth/getMenuByGroup',
+    method: 'get',
+    params: data
+  })
+}
+
+// 权限分配保存
+export function saveGroupMenu(data) {
+  return axios({
+    url: '/auth/saveGroupMenu',
+    method: 'post',
+    data: data
+  })
+}
+
+// 用户分配(上次保存的用户id)
+export function getAcountByGroup(data) {
+  return axios({
+    url: '/auth/getAcountByGroup',
+    method: 'get',
+    params: data
+  })
+}
+
+// 用户分配保存
+export function saveAccountGroup(data) {
+  return axios({
+    url: '/auth/saveAccountGroup',
+    method: 'post',
+    data: data
+  })
+}
+
+// 获取用户列表
+export function getUserList(data) {
+  return axios({
+    url: '/user/list',
+    method: 'post',
+    data: data
+  })
+}

+ 84 - 0
src/utils/http.js

@@ -0,0 +1,84 @@
+import axios from "axios";
+import router from "../router";
+import { Message } from 'element-ui';
+
+// 创建axios实例
+var instance = axios.create({
+  timeout: 1000 * 12,
+  baseURL: 'http://192.168.1.165:8081'
+})
+
+// 请求拦截器
+instance.interceptors.request.use(
+  config => {
+    // 登录流程控制中,根据本地是否存在token判断用户的登录情况
+    // 但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token
+    // 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码
+    // 而后我们可以在响应拦截器中,根据状态码进行一些统一的操作。
+    const token = localStorage.getItem('accessToken')
+    token && (config.headers.accessToken = token)
+    return config
+  },
+  error => Promise.error(error)
+)
+
+// 响应拦截器
+instance.interceptors.response.use(
+  // 请求成功
+  res => res.status === 200 ? Promise.resolve(res.data) : Promise.reject(res),
+  // 请求失败
+  error => {
+    const { response } = error;
+    console.log(response)
+    if (response) {
+      errorHandle(response.status, response.data.message);
+      return Promise.reject(response);
+    }
+  }
+)
+
+/**
+ * 跳转登录页
+ * 携带当前页面路由,以期在登录页面完成登录后返回当前页面
+ */
+const toLogin = () => {
+  router.replace({
+    path: '/login',
+    query: {
+      redirect: router.currentRoute.fullPath
+    }
+  });
+}
+
+/**
+ * 请求失败后的错误统一处理
+ * @param {Number} status 请求失败的状态码
+ */
+
+const errorHandle = (status, other) => {
+  // 状态码判断
+  switch (status) {
+    // 401: 未登录状态,跳转登录页
+    case 401:
+      toLogin();
+      break;
+    // 403 token过期
+    // 清除token并跳转登录页
+    case 403:
+      Message.error('登录过期,请重新登录');
+      localStorage.removeItem('accessToken');
+      localStorage.removeItem('UserName');
+      localStorage.removeItem('UserId');
+      setTimeout(() => {
+        toLogin();
+      }, 1000);
+      break;
+    // 404请求不存在
+    case 404:
+      Message.error('请求的资源不存在');
+      break;
+    default:
+      console.log(other);
+  }}
+
+export default instance

+ 6 - 0
src/utils/permission.js

@@ -0,0 +1,6 @@
+import store from '../store'
+
+export function hasBtnPermission(permission) {
+  const myBtns = store.getters.buttons
+  return myBtns.indexOf(permission) > -1
+}

+ 13 - 0
src/views/BioSafety/DeadPig.vue

@@ -0,0 +1,13 @@
+<template>
+  <div>死猪管理</div>
+</template>
+
+<script>
+export default {
+  name: "DeadPig"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 1 - 1
src/views/BioSafety/UserAdmin.vue

@@ -4,7 +4,7 @@
 
 <script>
 export default {
-  name: "UserAdmin"
+  name: "PersonAdmin"
 }
 </script>
 

+ 15 - 0
src/views/BioSafety/StiflingAdmin.vue

@@ -0,0 +1,15 @@
+<template>
+  <div>
+    熏蒸监管
+  </div>
+</template>
+
+<script>
+export default {
+  name: "StiflingAdmin"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 13 - 0
src/views/Env/DrinkWater.vue

@@ -0,0 +1,13 @@
+<template>
+  <div>饮水监测</div>
+</template>
+
+<script>
+export default {
+  name: "DrinkWater"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 13 - 0
src/views/Env/Electro.vue

@@ -0,0 +1,13 @@
+<template>
+  <div>用电监测</div>
+</template>
+
+<script>
+export default {
+  name: "Electro"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 13 - 0
src/views/Env/PigHouseEnv.vue

@@ -0,0 +1,13 @@
+<template>
+  <div>猪舍环境</div>
+</template>
+
+<script>
+export default {
+  name: "PigHouseEnv"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 121 - 0
src/views/Login/Login.vue

@@ -0,0 +1,121 @@
+<template>
+  <div class="login">
+    <div class="loginLogo"></div>
+    <div class="loginText">
+      <h2>数智牧场综合管理系统</h2>
+      <div class="loginForm">
+        <el-input
+            style="height: 50px; line-height: 50px;"
+            placeholder="请输入登录名"
+            v-model="userName"
+            size="large">
+          <i class="el-icon-user-solid" slot="prefix" style="font-size: 28px; line-height: 50px; margin-left: 5px"></i>
+        </el-input>
+        <div style="height: 20px"></div>
+        <el-input
+            style="height: 50px"
+            placeholder="请输入登录密码"
+            v-model="passWord"
+            type="password"
+            size="large">
+          <i class="pwd" slot="prefix"></i>
+        </el-input>
+        <div style="height: 20px"></div>
+        <el-button @click="onSubmit" style="width: 100%; height: 50px; background-color: #1ABC9C; color: #fff;" >登录</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { Login } from '../../utils/api';
+export default {
+  name: "Login",
+  data() {
+    return {
+      userName: '',
+      passWord: ''
+    }
+  },
+  methods: {
+    onSubmit() {
+      let params = {
+        accountName: this.userName,
+        password: this.passWord
+      }
+      Login(params).then(res => {
+        if(res.code === 10000) {
+          localStorage.setItem('accessToken', res.token);
+          localStorage.setItem('UserName', res.accountName);
+          localStorage.setItem('UserId', res.id);
+          let url = this.$route.query.redirect;
+          if(url) {
+            this.$router.replace(url);
+          } else {
+            this.$router.replace('/');
+          }
+        }
+      })
+    },
+  }
+}
+</script>
+
+<style scoped>
+  /deep/.el-input__inner {
+    height: 50px;
+    line-height: 50px;
+    padding: 0 0 0 50px;
+  }
+  .login {
+    width: 100%;
+    height: 100vh;
+    background-color: #1ABC9C;
+    position: relative;
+  }
+  .loginLogo {
+    width: 100%;
+    height: 400px;
+    background-image: url("../../assets/images/login.png");
+    background-size: 100% 100%;
+    position: absolute;
+    top: 50%;
+    margin: -300px 0 0 0;
+  }
+  .loginText {
+    width: 420px;
+    height: 400px;
+    background-color: #fff;
+    border-radius: 10px;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    margin: -250px 0 0 -210px;
+    box-sizing: border-box;
+    padding: 10px;
+    box-shadow: 0 0 10px rgb(0 0 0 / 35%);
+    text-align: center;
+  }
+  h2 {
+    font-size: 28px;
+    color: #1ABC9C;
+    font-weight: 600;
+  }
+  .loginForm {
+    width: 280px;
+    margin: 60px auto 0;
+    /*height: 300px;*/
+  }
+  .pwd {
+    display: inline-block;
+    width: 28px;
+    height: 50px;
+    font-size: 28px;
+    background-image: url("../../assets/images/pwd.png");
+    background-repeat: no-repeat;
+    background-size: 100% 60%;
+    background-position: 100% 42%;
+    line-height: 50px;
+    margin-left: 5px
+  }
+</style>

+ 26 - 2
src/views/MainLayout.vue

@@ -17,6 +17,8 @@
 <script>
 import HeaderElement from "../components/HeaderElement";
 import SideMenu from "../components/SideMenu";
+import { findOne } from '../utils/api';
+import { mapActions } from 'vuex';
 export default {
   name: "MainLayout",
   components: {
@@ -24,9 +26,27 @@ export default {
     SideMenu
   },
   data() {
-    return {}
+    return {
+      menuList: [],
+    }
   },
-  methods: {},
+  methods: {
+    ...mapActions(['setModeAsync', 'setColorAsync']),
+    init() {
+      let params = {
+        id: localStorage.getItem('UserId'),
+      }
+      findOne(params).then(res => {
+        if(res.code === 10000) {
+          this.setModeAsync(res.data.mode);
+          this.setColorAsync(res.data.color);
+        }
+      })
+    }
+  },
+  mounted() {
+    this.init();
+  }
 }
 </script>
 
@@ -35,4 +55,8 @@ export default {
    padding: 0;
    margin: 0;
  }
+ /deep/.el-main {
+   padding: 0;
+   margin: 0;
+ }
 </style>

+ 481 - 0
src/views/SystemAdmin/AuthAdmin.vue

@@ -0,0 +1,481 @@
+<template>
+  <div class="box">
+    <div class="box-content">
+      <!-- input + button* 2 -->
+      <div style="margin-bottom: 10px">
+        <el-form :inline="true" label-width="80px">
+          <el-form-item>
+            <el-input v-model="keyword"  placeholder="请输入权限组名称"></el-input>
+          </el-form-item>
+          <el-form-item>
+            <el-button @click="search" type="success">搜索</el-button>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" @click="dialogVisible = true">新增权限组</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+      <div>
+        <el-table
+            :data="tableData"
+            border
+            :height="590 + 'px'">
+          <el-table-column
+              prop="id"
+              label="权限组id">
+          </el-table-column>
+          <el-table-column
+              prop="groupName"
+              label="权限组名称">
+          </el-table-column>
+          <el-table-column
+              prop="remark"
+              label="备注">
+          </el-table-column>
+          <el-table-column label="操作">
+            <template slot-scope="scope">
+              <el-button
+                  size="mini"
+                  type="primary"
+                  @click="handleEdit(scope.row)">编辑</el-button>
+              <el-button
+                  size="mini"
+                  type="warning"
+                  @click="handleLimits(scope.row)">权限分配</el-button>
+              <el-button
+                  size="mini"
+                  type="danger"
+                  @click="handleUser(scope.row)">用户分配</el-button>
+              <el-button
+                  size="mini"
+                  type="danger"
+                  @click="del(scope.row)">删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <table-footer
+            :totals="total"
+            :size="size"
+            @sizeChange="sizeChange"
+            @pageChange="pageChange"></table-footer>
+      </div>
+    </div>
+    <!--    // 新增-->
+    <el-dialog
+        :title="showType ? '编辑权限组' : '新增权限组'"
+        :visible.sync="dialogVisible"
+        width="30%">
+      <div>
+        <el-form ref="form" :model="form" label-width="100px">
+          <el-form-item label="权限组名称">
+            <el-input v-model="form.groupName"></el-input>
+          </el-form-item>
+          <el-form-item label="备注">
+            <el-input v-model="form.remark" ></el-input>
+          </el-form-item>
+        </el-form>
+      </div>
+
+      <span slot="footer" class="dialog-footer">
+                <el-button @click="dialogVisible = false">取 消</el-button>
+                <el-button v-if="showType" type="primary" @click="setUpdate">更 新</el-button>
+                <el-button v-else type="primary" @click="onSubmit">新 增</el-button>
+              </span>
+    </el-dialog>
+    <!-- 权限分配   -->
+    <a-modal
+        title="权限分配"
+        :width="600"
+        :visible="dialogLimits"
+        @ok="limitSave"
+        ok-text="确认"
+        cancel-text="取消"
+        @cancel="dialogLimits = false"
+        :destroyOnClose="true">
+      <a-tree
+          v-model="checkedKeys"
+          multiple
+          checkable
+          :auto-expand-parent="autoExpandParent"
+          :expanded-keys="expandedKeys"
+          :tree-data="menuTreeData"
+          :selected-keys="selectedKeys"
+          :replaceFields="replaceFields"
+          @expand="onExpand"
+          @check="onCheck"
+      />
+    </a-modal>
+<!--    <el-dialog-->
+<!--        title="权限分配"-->
+<!--        :visible.sync="dialogLimits"-->
+<!--        width="50%">-->
+<!--      <div>-->
+<!--        <el-tree-->
+<!--            v-if="dialogLimits"-->
+<!--            :data="limitList"-->
+<!--            show-checkbox-->
+<!--            node-key="id"-->
+<!--            default-expand-all-->
+<!--            :default-checked-keys="defaultList"-->
+<!--            :props="defaultProps"-->
+<!--            @check-change="handleCheckChange"-->
+<!--            ref="tree">-->
+<!--        </el-tree>-->
+<!--      </div>-->
+<!--      <span slot="footer" class="dialog-footer">-->
+<!--                <el-button @click="dialogLimits = false">取 消</el-button>-->
+<!--                <el-button type="primary" @click="limitSave">保存</el-button>-->
+<!--              </span>-->
+<!--    </el-dialog>-->
+    <el-dialog
+        title="用户分配"
+        :visible.sync="dialogUsers"
+        width="50%">
+      <div>
+        <el-table
+            :data="userList"
+            ref="multipleTable"
+            tooltip-effect="dark"
+            @selection-change="handleSelectionChange">
+          <el-table-column
+              type="selection"
+              width="55">
+          </el-table-column>
+          <el-table-column
+              prop="id"
+              label="用户ID">
+          </el-table-column>
+          <el-table-column
+              prop="userName"
+              label="用户姓名">
+          </el-table-column>
+        </el-table>
+      </div>
+      <span slot="footer" class="dialog-footer">
+                <el-button @click="dialogUsers = false">取 消</el-button>
+                <el-button type="primary" @click="userSave">保存</el-button>
+              </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { Tree } from 'ant-design-vue';
+import TableFooter from "../../components/TableFooter";
+import { getMenu, getAuth, delAuth, addAuth, editAuth, getMenuByGroup, saveGroupMenu, getAcountByGroup, saveAccountGroup, getUserList } from '../../utils/api';
+export default {
+  name: "AuthAdmin",
+  components: {
+    TableFooter,
+    ATree: Tree
+  },
+  data() {
+    return {
+      tableData: [],
+      showType: false,
+      dialogVisible: false,
+      form: {
+        id: '',
+        groupName: '',
+        remark: '',
+      },
+      dialogLimits: false,
+      // 权限分配list
+      limitList: [],
+      defaultProps: {
+        children: 'children',
+        label: 'title'
+      },
+      autoExpandParent: true,
+      // 默认选择的参数
+      defaultList: [],
+      expandedKeys: [],
+      checkedKeys: [],
+      replaceFields: {
+        key: 'id'
+      },
+      keyword: '',
+      total: 0,
+      size: 20,
+      pageNum: 1,
+      selectId: '',
+      // 用户列表
+      userList: [],
+      dialogUsers: false,
+      userSelect: [],
+      leastChilds: [],
+      commitKeys: [],
+      selectedKeys: [],
+      menuTreeData: [],
+    }
+  },
+  methods: {
+    // 搜索
+    search() {
+      this.init();
+    },
+    // 修改size
+    sizeChange(val) {
+      this.size = val;
+      this.init();
+    },
+    // 修改页数
+    pageChange(val) {
+      this.pageNum= val;
+      this.init();
+    },
+    handleEdit(data) {
+      this.showType = true;
+      this.dialogVisible = true;
+      this.form.remark = data.remark;
+      this.form.groupName = data.groupName;
+      this.form.id = data.id;
+    },
+    // 用户分配
+    handleUser(data) {
+      this.dialogUsers = true;
+      this.selectId = data.id;
+      getAcountByGroup({groupId: data.id})
+          .then(res => {
+            if(res.code === 10006) {
+              this.userSelect = [];
+              this.$nextTick(() => {
+                this.$refs.multipleTable.clearSelection();
+                this.$forceUpdate();
+              });
+            } else {
+              let arr = res.data.split(',');
+              console.log(arr);
+              this.$nextTick(() => {
+                this.$refs.multipleTable.clearSelection();
+                for (let key in this.userList) {
+                  for(let i in arr) {
+                    if(this.userList[key]['id'] == arr[i]) {
+                      this.$refs.multipleTable.toggleRowSelection(this.userList[key], true);
+                    }
+                  }
+                }
+              })
+            }
+          })
+    },
+    // 用户分配选择
+    handleSelectionChange(val) {
+      this.userSelect = val;
+    },
+    // 用户分配保存
+    userSave() {
+      let users = [];
+      this.userSelect.forEach(item => {
+        users.push(item.id);
+      });
+      let str = users.join(',');
+      saveAccountGroup({accountId: str, groupIds: this.selectId})
+          .then(res => {
+            if(res.code === 10001) {
+              this.$message.success(res.message);
+            } else {
+              this.userSelect = [];
+              this.selectId = '';
+              this.$message(res.message);
+            }
+          });
+      this.dialogUsers = false;
+    },
+    // 新增角色
+    onSubmit() {
+      let params = {
+        groupName: this.form.groupName,
+        remark: this.form.remark
+      };
+      addAuth(params)
+          .then(res => {
+            if(res.code === 10000) {
+              this.init();
+              this.$message.success(res.message);
+            } else {
+              this.$message.error(res.message);
+            }
+            this.dialogVisible = false;
+            this.reset();
+          })
+    },
+    // handleCheckChange() {
+    //   // console.log(data, ls, lg)
+    //   this.selectList = [];
+    //   console.log(this.$refs.tree.getCheckedKeys());
+    //   this.selectList = this.$refs.tree.getCheckedKeys().concat(this.$refs.tree.getHalfCheckedKeys());
+    // },
+    onExpand(expandedKeys) {
+      this.expandedKeys = expandedKeys
+      this.autoExpandParent = false
+    },
+
+    onCheck(checkedKeys, info) {
+      this.checkedKeys = checkedKeys;
+      this.commitKeys = checkedKeys.concat(info.halfCheckedKeys)
+      console.log(this.commitKeys);
+    },
+    pickCheckedKeys(data) {
+      for (let i = 0; i < data.length; i++) {
+        if (this.leastChilds.includes(data[i])) {
+          this.checkedKeys.push(data[i])
+        }
+      }
+    },
+    onSelect(selectedKeys) {
+      this.selectedKeys = selectedKeys
+    },
+    // 权限分配
+    handleLimits(data) {
+      this.dialogLimits = true;
+      this.selectId = data.id;
+      this.defaultList = [];
+      getMenuByGroup({groupId: data.id})
+          .then(res => {
+            let arr;
+            if(res.code === 10005) {
+              arr = [];
+            } else {
+              arr = res.data.split(',');
+            }
+            this.defaultList = arr.map(Number);
+            this.pickCheckedKeys(this.defaultList);
+            this.selectList = this.defaultList;
+          })
+    },
+    // 权限分配保存
+    limitSave() {
+      // this.selectList = this.$refs.tree.getCheckedKeys();
+      let menuIds;
+      if(this.commitKeys.length > 0) {
+        menuIds = this.commitKeys.join(',');
+      } else {
+        menuIds = '';
+      }
+      saveGroupMenu( {groupId: this.selectId, menuIds: menuIds})
+          .then(res => {
+            if(res.code === 10001) {
+              this.$message.success(res.message);
+            }
+            this.selectId = '';
+            this.dialogLimits = false;
+            this.selectList = [];
+          });
+    },
+    init() {
+      // 后端分页
+      let params = {
+        pageNum: this.pageNum,
+        pageSize: this.size,
+        searchStr: this.keyword
+      };
+      getAuth(params)
+          .then(res => {
+            this.tableData = res.records;
+            this.total = res.total;
+          })
+    },
+    // 重置
+    reset(){
+      this.form.id = '';
+      this.form.groupName = '';
+      this.form.remark = '';
+      this.pageNum = 1;
+      this.keyword = '';
+      this.showType = false;
+    },
+    // 更新
+    setUpdate() {
+      let params = {
+        groupName: this.form.groupName,
+        remark: this.form.remark,
+        id: this.form.id
+      };
+      editAuth(params)
+          .then(res => {
+            if(res.code ===  10000) {
+              this.init();
+              this.$message.success(res.message);
+            }
+            this.dialogVisible = false;
+            this.reset();
+          });
+    },
+    // 删除
+    del(data) {
+      this.$confirm('此操作将永久删除批量删除, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        delAuth({groupId: data.id})
+            .then(res => {
+              if(res.code === 10000) {
+                this.init();
+                this.$message.success(res.message);
+              }
+            })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        });
+      });
+    },
+    // 菜单列表
+    authInit() {
+      getMenu().then(res => {
+            if(res.code === 10000) {
+              this.menuTreeData = res.data;
+              this.getLeastChilds(res.data)
+              this.menuTreeData.forEach(item => {
+                this.expandedKeys.push(item.id)
+              })
+              // this.expandedMenuKeys(this.roleEntity)
+            }
+          })
+    },
+    getLeastChilds(data) {
+      for (let i = 0; i < data.length; i++) {
+        this.pushLeastChilds(data[i])
+      }
+    },
+    pushLeastChilds(e) {
+      if (e.children.length > 0) {
+        this.getLeastChilds(e.children)
+        return
+      }
+      this.leastChilds.push(e.id)
+    },
+    // 用户列表
+    userInit() {
+      let params = {
+        pageNum: 1,
+        pageSize: 200,
+        searchStr: ''
+      };
+      getUserList(params)
+          .then(res => {
+            if(res.code === 10001) {
+              this.userList = res.data;
+            }
+          });
+    }
+  },
+  mounted() {
+    this.init();
+    this.authInit();
+    this.userInit();
+  }
+}
+</script>
+
+<style scoped>
+.box {
+  width: 100%;
+  height: 100%;
+  box-sizing: border-box;
+  padding: 20px;
+}
+</style>

+ 324 - 0
src/views/SystemAdmin/MenuAdmin.vue

@@ -0,0 +1,324 @@
+<template>
+  <div class="box">
+    <div>
+      <div style="margin-bottom: 10px">
+        <el-button type="primary"  @click="addMenu" v-if="hasPerm('menu:add')">添加菜单</el-button>
+      </div>
+      <div>
+        <el-table
+            :data="tableData"
+            border
+            row-key="id"
+            :height="670 + 'px'"
+            :tree-props="{children: 'children'}"
+            default-expand-all>
+          <el-table-column prop="title" label="菜单名称"></el-table-column>
+          <el-table-column
+              prop="weight"
+              label="菜单层级"
+              :filters="[{ text: '菜单', value: 0 }, { text: '按钮', value: 1 }]"
+              :filter-method="filterTag">
+            <template slot-scope="scope">
+              <el-tag
+                  :type="scope.row.weight === 0 ? 'primary' : 'success'"
+                  disable-transitions>{{scope.row.weight === 0 ? '菜单' : '按钮'}}</el-tag>
+            </template>
+          </el-table-column>
+          <el-table-column prop="url" label="菜单路由"></el-table-column>
+          <!--          <el-table-column prop="remark" label="备注"></el-table-column>-->
+          <el-table-column
+              label="操作"
+              fixed="right">
+            <template slot-scope="scope">
+              <el-button size="mini" type="info" @click="setEdit(scope.row)" style="margin-right: 10px">编辑</el-button>
+<!--              <el-button size="mini" type="primary" style="margin-right: 10px" @click="addChildren(scope.row, scope.$index)">添加子菜单</el-button>-->
+              <el-popconfirm
+                  :title="scope.row.parentId === 0 ? '这是父菜单,删除后,子菜单将不复存在!确定要删除这个菜单吗' : '确定要删除这个菜单吗?'"
+                  @confirm="del(scope.row)"
+              >
+                <el-button size="mini" slot="reference" v-if="hasPerm('menu:del')" type="danger">删除</el-button>
+              </el-popconfirm>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+    </div>
+    <a-modal
+        :title="showType ? '编辑菜单' : '新增菜单'"
+        :width="600"
+        :visible="dialogFormVisible"
+        @ok="add('ruleForm')"
+        @cancel="dialogFormVisible = false"
+        :destroyOnClose="true"
+    >
+      <el-form :model="form" :rules="rules"  ref="ruleForm">
+        <el-form-item  prop="weight" size="mini" label="菜单层级:" :label-width="formLabelWidth">
+          <el-radio-group v-model="form.weight">
+            <el-radio :label="0">菜单</el-radio>
+            <el-radio :label="1">按钮</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item  size="mini" label="菜单名称" :label-width="formLabelWidth" prop="title">
+          <el-input v-model="form.title" autocomplete="off"></el-input>
+        </el-form-item>
+        <el-form-item size="mini" label="父级菜单" :label-width="formLabelWidth">
+          <a-tree-select
+              v-model="form.parentId"
+              style="width: 100%"
+              :dropdownStyle="{ maxHeight: '300px', overflow: 'auto' }"
+              :treeData="menuTreeData"
+              placeholder="请选择父级菜单"
+              treeDefaultExpandAll
+          >
+            <span slot="title" slot-scope="{ id }">{{ id }}
+            </span>
+          </a-tree-select>
+        </el-form-item>
+        <el-form-item  size="mini" v-if="form.weight === 0" label="菜单地址" :label-width="formLabelWidth">
+          <el-input v-model="form.url" autocomplete="off"></el-input>
+        </el-form-item>
+        <el-form-item size="mini" v-else label="权限标识" :label-width="formLabelWidth" prop="permission">
+          <el-input v-model="form.permission" autocomplete="off"></el-input>
+        </el-form-item>
+        <el-form-item size="mini" label="排序" :label-width="formLabelWidth">
+          <el-input v-model="form.sort" autocomplete="off"></el-input>
+        </el-form-item>
+      </el-form>
+<!--      <a-form :form="form">-->
+<!--        <a-form.item label="父级菜单">-->
+<!--          <a-tree-select-->
+<!--              style="width: 100%"-->
+<!--              :dropdownStyle="{ maxHeight: '300px', overflow: 'auto' }"-->
+<!--              :treeData="menuTreeData"-->
+<!--              placeholder="请选择父级菜单"-->
+<!--              treeDefaultExpandAll-->
+<!--          >-->
+<!--            <span slot="title" slot-scope="{ id }">{{ id }}-->
+<!--            </span>-->
+<!--          </a-tree-select>-->
+<!--        </a-form.item>-->
+<!--      </a-form>-->
+    </a-modal>
+<!--    <el-dialog :title="showType ? '编辑菜单' : '新增菜单'" :visible.sync="dialogFormVisible">-->
+<!--      <a-form :form="form" :label-col="{ span: 5}" :warpper-col="{ span: 12 }">-->
+<!--        <a-form-item label="父级菜单">-->
+<!--          <a-tree-select-->
+<!--              style="width: 100%"-->
+<!--              :dropdownStyle="{ maxHeight: '300px', overflow: 'auto' }"-->
+<!--              :treeData="menuTreeData"-->
+<!--              placeholder="请选择父级菜单"-->
+<!--              treeDefaultExpandAll-->
+<!--          >-->
+<!--            <span slot="title" slot-scope="{ id }">{{ id }}-->
+<!--            </span>-->
+<!--          </a-tree-select>-->
+<!--        </a-form-item>-->
+<!--      </a-form>-->
+
+<!--      <el-form :model="form"  ref="ruleForm">-->
+<!--        <el-form-item label="父级菜单" :label-width="formLabelWidth">-->
+<!--          <a-tree-select-->
+<!--              style="width: 100%"-->
+<!--              :dropdownStyle="{ maxHeight: '300px', overflow: 'auto' }"-->
+<!--              :treeData="menuTreeData"-->
+<!--              placeholder="请选择父级菜单"-->
+<!--              treeDefaultExpandAll-->
+<!--          >-->
+<!--                  <span slot="title" slot-scope="{ id }">{{ id }}-->
+<!--                  </span>-->
+<!--          </a-tree-select>-->
+<!--&lt;!&ndash;          <el-input v-model="form.parentId" disabled autocomplete="off"></el-input>&ndash;&gt;-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="菜单排序" :label-width="formLabelWidth">-->
+<!--          <el-input v-model="form.sort"  autocomplete="off"></el-input>-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="菜单名字" :label-width="formLabelWidth" prop="name">-->
+<!--          <el-input v-model="form.name" autocomplete="off"></el-input>-->
+<!--        </el-form-item>-->
+<!--        <el-form-item label="菜单路由" :label-width="formLabelWidth">-->
+<!--          <el-input v-model="form.url" autocomplete="off"></el-input>-->
+<!--        </el-form-item>-->
+<!--      </el-form>-->
+
+<!--      <div slot="footer" class="dialog-footer">-->
+<!--        <el-button @click="dialogFormVisible = false">取 消</el-button>-->
+<!--        <el-button v-if="!showType" type="primary" @click="add('ruleForm')">新 增</el-button>-->
+<!--        <el-button v-else type="primary" @click="setUpdate('ruleForm')">更 新</el-button>-->
+<!--      </div>-->
+<!--    </el-dialog>-->
+  </div>
+</template>
+
+<script>
+import { TreeSelect } from 'ant-design-vue'
+import { getMenu, getMenuList , addMenu, editMenu, delMenu } from '../../utils/api'
+export default {
+  name: "MenuAdmin",
+  components: {
+    // AModal: Modal,
+    // AForm: Form,
+    ATreeSelect: TreeSelect
+  },
+  data() {
+    return {
+      tableData: [],
+      showType: false,
+      dialogFormVisible: false,
+      form: {
+        title: '',
+        parentId: '',
+        url: '',
+        id: '',
+        sort: '',
+        weight: 0,
+        permission: '',
+      },
+      formLabelWidth: '90px',
+      rules: {
+        title: [
+          { required: true, message: '请输入菜单名称', trigger: 'blur' },
+        ],
+        weight: [
+          { required: true, message: '请选择菜单层级', trigger: 'change' }
+        ],
+        menu: [
+          { required: true, message: '请选择父级菜单', trigger: 'change' }
+        ],
+        permission: [
+          { required: true, message: '请输入权限标识', trigger: 'blur' }
+        ]
+      },
+      menuTreeData: [],
+    }
+  },
+  methods: {
+    // 拿到parentId
+    getParentId(val) {
+      this.form.parentId = val;
+    },
+    // 过滤
+    filterTag(value, row) {
+      return row.weight === value;
+    },
+    add(formName) {
+      this.$refs[formName].validate((valid) => {
+        if(valid) {
+          if(this.showType) {
+            this.setUpdate();
+          } else {
+            let params = {
+              parentId: this.form.parentId,
+              title: this.form.title,
+              url: this.form.url,
+              sort: this.form.sort,
+              weight: this.form.weight,
+              permission: this.form.permission,
+            }
+            addMenu(params)
+                .then(res => {
+                  if(res.code === 10000) {
+                    this.init();
+                    this.reset();
+                    this.$message.success(res.message);
+                  }
+                  this.dialogFormVisible = false;
+                })
+          }
+        } else {
+          return false;
+        }
+      })
+      this.dialogFormVisible = false;
+    },
+    setEdit(data) {
+      this.showType = true;
+      this.dialogFormVisible = true;
+      this.form.id = data.id;
+      this.form.title = data.title;
+      this.form.url = data.url;
+      this.form.parentId = data.parentId;
+      this.form.sort = data.sort;
+      this.form.permission = data.permission;
+      this.form.weight = data.weight;
+    },
+    addMenu() {
+      this.dialogFormVisible = true;
+    },
+    del(data) {
+      delMenu({menuId: data.id})
+          .then(res => {
+            if(res.code === 10000) {
+              this.init();
+              this.$message.success(res.message);
+            }
+          })
+    },
+    setUpdate() {
+      let params = {
+        id: this.form.id,
+        url: this.form.url,
+        title: this.form.title,
+        parentId: this.form.parentId,
+        sort: this.form.sort,
+        permission: this.form.permission,
+        weight: this.form.weight,
+      };
+      editMenu(params)
+          .then(res => {
+            if(res.code === 10000) {
+              this.init();
+              this.reset();
+              this.$message.success(res.message);
+            }
+            this.dialogFormVisible = false;
+          })
+    },
+    // 重置
+    reset() {
+      this.form.title = '';
+      this.form.parentId = '';
+      this.form.url = '';
+      this.form.id = '';
+      this.form.sort = '';
+      this.form.weight = 0;
+      this.form.permission = '';
+      this.showType = false;
+    },
+    init() {
+      getMenu()
+          .then(res => {
+            if(res.code === 10000) {
+              this.tableData = res.data;
+            }
+          })
+      getMenuList().then(res => {
+        if(res.code === 10000) {
+          this.menuTreeData = [
+            {
+              id: -1,
+              parentId: 0,
+              title: '顶级',
+              value: 0,
+              pid: 0,
+              weight: 0,
+              children: res.data,
+            }
+          ]
+        }
+      })
+    }
+  },
+  mounted() {
+    this.init();
+  }
+}
+</script>
+
+<style scoped>
+  .box {
+    width: 100%;
+    height: 100%;
+    box-sizing: border-box;
+    padding: 20px;
+  }
+</style>

+ 13 - 0
src/views/SystemAdmin/UserAdmin.vue

@@ -0,0 +1,13 @@
+<template>
+  <div>1111</div>
+</template>
+
+<script>
+export default {
+  name: "UserAdmin"
+}
+</script>
+
+<style scoped>
+
+</style>

+ 7 - 0
vue.config.js

@@ -27,4 +27,11 @@ module.exports = {
     }
 
   },
+  css: {
+    loaderOptions: {
+      less: {
+        javascriptEnabled: true,
+      }
+    }
+  },
 };