feat: halo-dev/halo#1119 (#264)

pull/267/head
Ryan Wang 2020-11-02 22:35:48 +08:00 committed by GitHub
parent bc5e14576d
commit 701e37940e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1348 additions and 599 deletions

161
package-lock.json generated
View File

@ -6,21 +6,21 @@
"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==",
"resolved": "https://registry.npm.taobao.org/@ant-design/colors/download/@ant-design/colors-3.2.2.tgz?cache=0&sync_timestamp=1596611369344&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40ant-design%2Fcolors%2Fdownload%2F%40ant-design%2Fcolors-3.2.2.tgz",
"integrity": "sha1-WtQ9YZ6RHzSI66wwPWBuZqhCOQM=",
"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=="
"resolved": "https://registry.npm.taobao.org/@ant-design/icons/download/@ant-design/icons-2.1.1.tgz?cache=0&sync_timestamp=1596529338545&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40ant-design%2Ficons%2Fdownload%2F%40ant-design%2Ficons-2.1.1.tgz",
"integrity": "sha1-e5wI3/1PXUHbZn2dvl4BB9C9mko="
},
"@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==",
"resolved": "https://registry.npm.taobao.org/@ant-design/icons-vue/download/@ant-design/icons-vue-2.0.0.tgz?cache=0&sync_timestamp=1598869253063&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40ant-design%2Ficons-vue%2Fdownload%2F%40ant-design%2Ficons-vue-2.0.0.tgz",
"integrity": "sha1-A1f1AQpATp80qHpLQbKgjfaR284=",
"requires": {
"@ant-design/colors": "^3.1.0",
"babel-runtime": "^6.26.0"
@ -1342,18 +1342,18 @@
"dev": true
},
"@simonwep/pickr": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/@simonwep/pickr/-/pickr-1.7.2.tgz",
"integrity": "sha512-XHmQKS1k1gUvB4kOj9W3DTpT5SQWDovSm3KuOtmlkHmezkF/WzyraPIk+vwroxESdugfqanJZFvgdj9lzHcEKw==",
"version": "1.7.4",
"resolved": "https://registry.npm.taobao.org/@simonwep/pickr/download/@simonwep/pickr-1.7.4.tgz",
"integrity": "sha1-sU/NlFiQOIuHDNbbTWx41THyUUE=",
"requires": {
"core-js": "^3.6.5",
"nanopop": "^1.3.0"
"nanopop": "^2.1.0"
},
"dependencies": {
"core-js": {
"version": "3.6.5",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz",
"integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA=="
"resolved": "https://registry.npm.taobao.org/core-js/download/core-js-3.6.5.tgz?cache=0&sync_timestamp=1589682726446&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcore-js%2Fdownload%2Fcore-js-3.6.5.tgz",
"integrity": "sha1-c5XcJzrzf7LlDpvT2f6EEoUjHRo="
}
}
},
@ -2464,8 +2464,8 @@
},
"loader-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
"resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-2.0.0.tgz",
"integrity": "sha1-5MrOW4FtQloWa18JfhDNErNgZLA=",
"dev": true,
"optional": true,
"requires": {
@ -2604,9 +2604,9 @@
}
},
"vue-loader-v16": {
"version": "npm:vue-loader@16.0.0-beta.8",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.0.0-beta.8.tgz",
"integrity": "sha512-oouKUQWWHbSihqSD7mhymGPX1OQ4hedzAHyvm8RdyHh6m3oIvoRF+NM45i/bhNOlo8jCnuJhaSUf/6oDjv978g==",
"version": "npm:vue-loader@16.0.0-beta.9",
"resolved": "https://registry.npm.taobao.org/vue-loader/download/vue-loader-16.0.0-beta.9.tgz?cache=0&sync_timestamp=1603783106162&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-loader%2Fdownload%2Fvue-loader-16.0.0-beta.9.tgz",
"integrity": "sha1-UlEsthwpaCfJnA1UOYvvhL5ESPw=",
"dev": true,
"optional": true,
"requires": {
@ -2617,8 +2617,8 @@
"dependencies": {
"chalk": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
"resolved": "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz",
"integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=",
"dev": true,
"optional": true,
"requires": {
@ -3016,8 +3016,8 @@
},
"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==",
"resolved": "https://registry.npm.taobao.org/add-dom-event-listener/download/add-dom-event-listener-1.1.0.tgz",
"integrity": "sha1-apLbOg3Qq8JU4JXA8dwUrLuq4xA=",
"requires": {
"object-assign": "4.x"
}
@ -3113,9 +3113,9 @@
}
},
"ant-design-vue": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-1.6.5.tgz",
"integrity": "sha512-FzLrK+JuJUq+g4vd+UjFFi13ZdSsb11EZFapisFXilJxpc1LxqyunZu5AP4nr9vFLs3J4UX2A6q+Rp/Fi6JrLg==",
"version": "1.7.1",
"resolved": "https://registry.npm.taobao.org/ant-design-vue/download/ant-design-vue-1.7.1.tgz",
"integrity": "sha1-55d/kjl+/rEXM71hMcFv2rz554Q=",
"requires": {
"@ant-design/icons": "^2.1.1",
"@ant-design/icons-vue": "^2.0.0",
@ -3229,8 +3229,8 @@
},
"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=="
"resolved": "https://registry.npm.taobao.org/array-tree-filter/download/array-tree-filter-2.1.0.tgz",
"integrity": "sha1-hzrAD+yDdJ8lWsjdCDgUtPYykZA="
},
"array-union": {
"version": "1.0.2",
@ -3359,8 +3359,8 @@
},
"async-validator": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-3.4.0.tgz",
"integrity": "sha512-VrFk4eYiJAWKskEz115iiuCf9O0ftnMMPXrOFMqyzGH2KxO7YwncKyn/FgOOP+0MDHMfXL7gLExagCutaZGigA=="
"resolved": "https://registry.npm.taobao.org/async-validator/download/async-validator-3.4.0.tgz",
"integrity": "sha1-hxs+WUEkv0xOt7zRqeeLRPOwnK4="
},
"asynckit": {
"version": "0.4.0",
@ -3498,8 +3498,8 @@
},
"babel-helper-vue-jsx-merge-props": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-2.0.3.tgz",
"integrity": "sha512-gsLiKK7Qrb7zYJNgiXKpXblxbV5ffSwR0f5whkPAaBAR4fhi6bwRZxX9wBlIc5M/v8CCkXUbXZL4N/nSE97cqg=="
"resolved": "https://registry.npm.taobao.org/babel-helper-vue-jsx-merge-props/download/babel-helper-vue-jsx-merge-props-2.0.3.tgz",
"integrity": "sha1-Iq69OzOQIyjlEyk6jkmSs4T58bY="
},
"babel-jest": {
"version": "26.3.0",
@ -4906,8 +4906,8 @@
},
"classnames": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
"resolved": "https://registry.npm.taobao.org/classnames/download/classnames-2.2.6.tgz",
"integrity": "sha1-Q5Nb/90pHzJtrQogUwmzjQD2UM4="
},
"clean-css": {
"version": "4.2.3",
@ -5375,7 +5375,7 @@
},
"component-classes": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/component-classes/-/component-classes-1.2.6.tgz",
"resolved": "https://registry.npm.taobao.org/component-classes/download/component-classes-1.2.6.tgz",
"integrity": "sha1-xkI5TDYYpNiwuJGe/Mu9kw5c1pE=",
"requires": {
"component-indexof": "0.0.3"
@ -5389,7 +5389,7 @@
},
"component-indexof": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/component-indexof/-/component-indexof-0.0.3.tgz",
"resolved": "https://registry.npm.taobao.org/component-indexof/download/component-indexof-0.0.3.tgz",
"integrity": "sha1-EdCRMSI5648yyPJa6csAL/6NPCQ="
},
"compressible": {
@ -6507,12 +6507,12 @@
},
"dom-align": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.0.tgz",
"integrity": "sha512-YkoezQuhp3SLFGdOlr5xkqZ640iXrnHAwVYcDg8ZKRUtO7mSzSC2BA5V0VuyAwPSJA4CLIc6EDDJh4bEsD2+zA=="
"resolved": "https://registry.npm.taobao.org/dom-align/download/dom-align-1.12.0.tgz?cache=0&sync_timestamp=1589854754211&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdom-align%2Fdownload%2Fdom-align-1.12.0.tgz",
"integrity": "sha1-VvtxVt8LkQmYMDZNLUj4iWP1opw="
},
"dom-closest": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/dom-closest/-/dom-closest-0.2.0.tgz",
"resolved": "https://registry.npm.taobao.org/dom-closest/download/dom-closest-0.2.0.tgz",
"integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=",
"requires": {
"dom-matches": ">=1.0.1"
@ -6535,13 +6535,13 @@
},
"dom-matches": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-matches/-/dom-matches-2.0.0.tgz",
"resolved": "https://registry.npm.taobao.org/dom-matches/download/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=="
"resolved": "https://registry.npm.taobao.org/dom-scroll-into-view/download/dom-scroll-into-view-2.0.1.tgz",
"integrity": "sha1-DezIUigB/Y0/HGujVadNOCxfmJs="
},
"dom-serializer": {
"version": "0.2.2",
@ -9118,7 +9118,7 @@
},
"intersperse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/intersperse/-/intersperse-1.0.0.tgz",
"resolved": "https://registry.npm.taobao.org/intersperse/download/intersperse-1.0.0.tgz",
"integrity": "sha1-8lYfsc/vn1J3zDNHoiiGtDUaUYE="
},
"invariant": {
@ -9323,12 +9323,12 @@
},
"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=="
"resolved": "https://registry.npm.taobao.org/is-mobile/download/is-mobile-2.2.2.tgz?cache=0&sync_timestamp=1592980494392&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-mobile%2Fdownload%2Fis-mobile-2.2.2.tgz",
"integrity": "sha1-9snF1Q7gElTOBec5vdg18e1OmVQ="
},
"is-negative-zero": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz",
"resolved": "https://registry.npm.taobao.org/is-negative-zero/download/is-negative-zero-2.0.0.tgz",
"integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE="
},
"is-number": {
@ -9485,8 +9485,8 @@
},
"ismobilejs": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-1.1.1.tgz",
"integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw=="
"resolved": "https://registry.npm.taobao.org/ismobilejs/download/ismobilejs-1.1.1.tgz",
"integrity": "sha1-xWygro5Sskyg8iul7zIVot27qg4="
},
"isobject": {
"version": "3.0.1",
@ -10427,7 +10427,7 @@
},
"json2mq": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz",
"resolved": "https://registry.npm.taobao.org/json2mq/download/json2mq-0.2.0.tgz",
"integrity": "sha1-tje9O6nqvhIsg+lyBIOusQ0skEo=",
"requires": {
"string-convert": "^0.2.0"
@ -11618,9 +11618,9 @@
}
},
"moment": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz",
"integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ=="
"version": "2.29.1",
"resolved": "https://registry.npm.taobao.org/moment/download/moment-2.29.1.tgz",
"integrity": "sha1-sr52n6MZQL6e7qZGnAdeNQBvo9M="
},
"move-concurrently": {
"version": "1.0.1",
@ -11659,8 +11659,8 @@
},
"mutationobserver-shim": {
"version": "0.3.7",
"resolved": "https://registry.npmjs.org/mutationobserver-shim/-/mutationobserver-shim-0.3.7.tgz",
"integrity": "sha512-oRIDTyZQU96nAiz2AQyngwx1e89iApl2hN5AOYwyxLUB47UYsU3Wv9lJWqH5y/QdiYkc5HQLi23ZNB3fELdHcQ=="
"resolved": "https://registry.npm.taobao.org/mutationobserver-shim/download/mutationobserver-shim-0.3.7.tgz",
"integrity": "sha1-i/YzsMCwKRoRByVe0ywTCIqMW/M="
},
"mute-stream": {
"version": "0.0.8",
@ -11706,9 +11706,9 @@
}
},
"nanopop": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/nanopop/-/nanopop-1.3.0.tgz",
"integrity": "sha512-DQDhHyPhKLKrXOjVkChsAoWh/WpKuVINDKl4qvFbguqokRJWQBSNSlPzMS+Xy3yBQKeQ39rICMB2asDvdUiVxw=="
"version": "2.1.0",
"resolved": "https://registry.npm.taobao.org/nanopop/download/nanopop-2.1.0.tgz?cache=0&sync_timestamp=1598256090184&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnanopop%2Fdownload%2Fnanopop-2.1.0.tgz",
"integrity": "sha1-I0dlE87iQFiIr9LopLVAZrcLnmA="
},
"native-request": {
"version": "1.0.7",
@ -12074,8 +12074,8 @@
},
"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==",
"resolved": "https://registry.npm.taobao.org/omit.js/download/omit.js-1.0.2.tgz",
"integrity": "sha1-kaFPDrqEBm36AVvzDkdMR/MLyFg=",
"requires": {
"babel-runtime": "^6.23.0"
}
@ -13497,8 +13497,8 @@
},
"raf": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
"resolved": "https://registry.npm.taobao.org/raf/download/raf-3.4.1.tgz?cache=0&sync_timestamp=1586264003311&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fraf%2Fdownload%2Fraf-3.4.1.tgz",
"integrity": "sha1-B0LpmkplUvRF1z4+4DKK8P8e3jk=",
"requires": {
"performance-now": "^2.1.0"
}
@ -13924,8 +13924,8 @@
},
"resize-observer-polyfill": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
"resolved": "https://registry.npm.taobao.org/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz",
"integrity": "sha1-DpAg3T0hAkRY1OvSfiPkAmmBBGQ="
},
"resolve": {
"version": "1.17.0",
@ -14339,13 +14339,13 @@
},
"shallow-equal": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz",
"integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA=="
"resolved": "https://registry.npm.taobao.org/shallow-equal/download/shallow-equal-1.2.1.tgz",
"integrity": "sha1-TBar+lYEOqINBQMk76aJQLDaedo="
},
"shallowequal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
"resolved": "https://registry.npm.taobao.org/shallowequal/download/shallowequal-1.1.0.tgz",
"integrity": "sha1-GI1SHelbkIdAT9TctosT3wrk5/g="
},
"shebang-command": {
"version": "1.2.0",
@ -14610,6 +14610,11 @@
"is-plain-obj": "^1.0.0"
}
},
"sortablejs": {
"version": "1.12.0",
"resolved": "https://registry.npm.taobao.org/sortablejs/download/sortablejs-1.12.0.tgz?cache=0&sync_timestamp=1601884638047&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsortablejs%2Fdownload%2Fsortablejs-1.12.0.tgz",
"integrity": "sha1-7m1+zjWYwq8P6xVZ2YWV5eo3y9Y="
},
"source-list-map": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
@ -14908,7 +14913,7 @@
},
"string-convert": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz",
"resolved": "https://registry.npm.taobao.org/string-convert/download/string-convert-0.2.1.tgz",
"integrity": "sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c="
},
"string-length": {
@ -15439,9 +15444,9 @@
"integrity": "sha512-YHsqn1zksQ4CKVvArN7MIUtGx0eV/yl15vzdiwNFwAnOQQwL1+pNSLW4ISVWUN+PrzcnX4ojLgS4kgVCmue7Pw=="
},
"tinycolor2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz",
"integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g="
"version": "1.4.2",
"resolved": "https://registry.npm.taobao.org/tinycolor2/download/tinycolor2-1.4.2.tgz",
"integrity": "sha1-P2pNEHGtB2dtf6Ry4frECnGdiAM="
},
"tmp": {
"version": "0.0.33",
@ -16166,8 +16171,8 @@
},
"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=="
"resolved": "https://registry.npm.taobao.org/vue-ref/download/vue-ref-2.0.0.tgz",
"integrity": "sha1-SDCE1zKr7RHaeWd4qCZqOvDqGpw="
},
"vue-router": {
"version": "3.4.3",
@ -16269,6 +16274,14 @@
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
"dev": true
},
"vuedraggable": {
"version": "2.24.2",
"resolved": "https://registry.npm.taobao.org/vuedraggable/download/vuedraggable-2.24.2.tgz",
"integrity": "sha1-zZj67JmQUjhGnptNI1+6Wln7faI=",
"requires": {
"sortablejs": "^1.10.1"
}
},
"vuejs-logger": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/vuejs-logger/-/vuejs-logger-1.5.4.tgz",
@ -16321,8 +16334,8 @@
},
"warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"resolved": "https://registry.npm.taobao.org/warning/download/warning-4.0.3.tgz",
"integrity": "sha1-Fungd+uKhtavfWSqHgX9hbRnjKM=",
"requires": {
"loose-envify": "^1.0.0"
}
@ -17205,4 +17218,4 @@
}
}
}
}
}

View File

@ -20,7 +20,7 @@
"test:unit": "vue-cli-service test:unit"
},
"dependencies": {
"ant-design-vue": "^1.6.5",
"ant-design-vue": "^1.7.1",
"axios": "^0.19.2",
"dayjs": "^1.8.36",
"enquire.js": "^2.1.6",
@ -40,6 +40,7 @@
"vue-filepond": "^6.0.3",
"vue-ls": "^3.2.1",
"vue-router": "^3.4.3",
"vuedraggable": "^2.24.2",
"vuejs-logger": "^1.5.4",
"vuex": "^3.5.1"
},
@ -150,4 +151,4 @@
"last 2 versions",
"not ie <= 10"
]
}
}

View File

@ -18,6 +18,16 @@ menuApi.listTree = () => {
})
}
menuApi.listTreeByTeam = team => {
return service({
url: `${baseUrl}/team/tree_view`,
params: {
team: team
},
method: 'get'
})
}
menuApi.create = menu => {
return service({
url: baseUrl,
@ -26,6 +36,22 @@ menuApi.create = menu => {
})
}
menuApi.createBatch = menus => {
return service({
url: `${baseUrl}/batch`,
data: menus,
method: 'post'
})
}
menuApi.updateBatch = menus => {
return service({
url: `${baseUrl}/batch`,
data: menus,
method: 'put'
})
}
menuApi.delete = menuId => {
return service({
url: `${baseUrl}/${menuId}`,
@ -33,6 +59,14 @@ menuApi.delete = menuId => {
})
}
menuApi.deleteBatch = menuIds => {
return service({
url: `${baseUrl}/batch`,
data: menuIds,
method: 'delete'
})
}
menuApi.get = menuId => {
return service({
url: `${baseUrl}/${menuId}`,

View File

@ -12,37 +12,37 @@ export default {
props: {
type: {
type: String,
default: 'primary'
default: 'primary',
},
icon: {
type: String,
default: null
default: null,
},
loading: {
type: Boolean,
default: false
default: false,
},
errored: {
type: Boolean,
default: false
default: false,
},
text: {
type: String,
default: ''
default: '',
},
loadedText: {
type: String,
default: ''
default: '',
},
erroredText: {
type: String,
default: ''
}
default: '',
},
},
data() {
return {
loaded: false,
hasError: false
hasError: false,
}
},
watch: {
@ -56,9 +56,9 @@ export default {
this.loaded = false
this.hasError = false
this.$emit('callback')
}, 800)
}, 400)
}
}
},
},
computed: {
computedType() {
@ -78,12 +78,12 @@ export default {
return this.hasError ? this.erroredText : this.loadedText
}
return this.text
}
},
},
methods: {
handleClick() {
this.$emit('click')
}
}
},
},
}
</script>

View File

@ -1,7 +1,5 @@
import Vue from 'vue'
import {
OPTIONS
} from '@/store/mutation-types'
import { OPTIONS } from '@/store/mutation-types'
import optionApi from '@/api/option'
const keys = [
'blog_url',
@ -13,7 +11,8 @@ const keys = [
'post_permalink_type',
'archives_prefix',
'path_suffix',
'default_editor'
'default_editor',
'default_menu_team'
]
const option = {
state: {
@ -26,9 +25,7 @@ const option = {
}
},
actions: {
refreshOptionsCache({
commit
}) {
refreshOptionsCache({ commit }) {
return new Promise((resolve, reject) => {
optionApi
.listAllByKeys(keys)

View File

@ -1,4 +1,3 @@
export function triggerWindowResizeEvent() {
const event = document.createEvent('HTMLEvents')
event.initEvent('resize', true, true)
@ -18,3 +17,18 @@ export function decodeHTML(html) {
elem = null
return output
}
export function deepClone(source) {
if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'deepClone')
}
const targetObj = source.constructor === Array ? [] : {}
Object.keys(source).forEach(keys => {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = deepClone(source[keys])
} else {
targetObj[keys] = source[keys]
}
})
return targetObj
}

View File

@ -2,390 +2,405 @@
<page-view>
<a-row :gutter="12">
<a-col
:xl="10"
:lg="10"
:md="10"
:xl="6"
:lg="6"
:md="6"
:sm="24"
:xs="24"
class="mb-3"
>
<a-card
:title="title"
:bodyStyle="{ padding: '16px' }"
title="分组"
>
<a-form-model
ref="menuForm"
:model="form.model"
:rules="form.rules"
layout="horizontal"
<template slot="extra">
<ReactiveButton
type="default"
@click="handleSetDefaultTeam"
@callback="handleSetDefaultTeamCallback"
:loading="teams.default.saving"
:errored="teams.default.errored"
text="设为默认"
loadedText="设置成功"
erroredText="设置失败"
></ReactiveButton>
</template>
<div class="menu-teams">
<a-spin :spinning="teams.loading">
<a-empty v-if="teams.data.length===0 && !teams.loading" />
<a-menu
class="w-full"
mode="inline"
v-model="selectedTeam"
v-if="teams.data.length>0"
@select="handleSelectedTeam"
>
<a-menu-item
v-for="(team) in teams.data"
:key="team"
>
{{ team===''?'未分组':team }}{{ defaultMenuTeam===team?'(默认)':'' }}
</a-menu-item>
</a-menu>
</a-spin>
</div>
<a-popover
v-model="teams.form.visible"
title="新增分组"
trigger="click"
placement="bottom"
@visibleChange="handleTeamFormVisibleChange"
destroyTooltipOnHide
>
<a-form-model-item
label="名称:"
help="* 页面上所显示的名称"
prop="name"
>
<a-input v-model="form.model.name" />
</a-form-model-item>
<a-form-model-item
label="地址:"
help="* 菜单的地址"
prop="url"
>
<a-input v-model="form.model.url" />
</a-form-model-item>
<a-form-model-item
label="上级菜单:"
prop="parentId"
>
<menu-select-tree
:menus="table.data"
v-model="form.model.parentId"
/>
</a-form-model-item>
<a-form-model-item
label="排序编号:"
prop="priority"
>
<a-input-number
v-model="form.model.priority"
:min="0"
style="width:100%"
/>
</a-form-model-item>
<a-form-model-item
v-show="form.moreField"
label="图标:"
help="* 请根据主题的支持选填"
prop="icon"
>
<a-input v-model="form.model.icon" />
</a-form-model-item>
<a-form-model-item
v-show="form.moreField"
label="分组:"
prop="team"
>
<a-auto-complete
:dataSource="computedTeams"
v-model="form.model.team"
allowClear
/>
</a-form-model-item>
<a-form-model-item
v-show="form.moreField"
label="打开方式:"
prop="target"
>
<a-select
defaultValue="_self"
v-model="form.model.target"
<template slot="content">
<a-form-model
ref="teamForm"
:model="teams.form.model"
:rules="teams.form.rules"
@keyup.enter.native="handleCreateTeam"
>
<a-select-option value="_self">当前窗口</a-select-option>
<a-select-option value="_blank">新窗口</a-select-option>
</a-select>
</a-form-model-item>
<a-form-model-item>
<ReactiveButton
v-if="!isUpdateMode"
type="primary"
@click="handleCreateOrUpdateMenu"
@callback="handleSavedCallback"
:loading="form.saving"
:errored="form.errored"
text="保存"
loadedText="保存成功"
erroredText="保存失败"
></ReactiveButton>
<a-button-group v-else>
<ReactiveButton
type="primary"
@click="handleCreateOrUpdateMenu"
@callback="handleSavedCallback"
:loading="form.saving"
:errored="form.errored"
text="更新"
loadedText="更新成功"
erroredText="更新失败"
></ReactiveButton>
<a-button
type="dashed"
@click="form.model = {}"
v-if="isUpdateMode"
>返回添加</a-button>
</a-button-group>
<a
class="ml-2"
@click="form.moreField = !form.moreField"
>
更多选项
<a-icon :type="form.moreField ? 'up' : 'down'" />
</a>
</a-form-model-item>
</a-form-model>
<a-form-model-item prop="team">
<a-input
v-model="teams.form.model.team"
autoFocus
/>
</a-form-model-item>
<a-form-model-item style="margin-bottom:0">
<a-button
type="primary"
@click="handleCreateTeam"
>
新增
</a-button>
</a-form-model-item>
</a-form-model>
</template>
<a-button
type="primary"
block
class="mt-3"
>
新增分组
</a-button>
</a-popover>
</a-card>
</a-col>
<a-col
:xl="14"
:lg="14"
:md="14"
:xl="18"
:lg="18"
:md="18"
:sm="24"
:xs="24"
class="pb-3"
>
<a-card
title="所有菜单"
:bodyStyle="{ padding: '16px' }"
>
<!-- Mobile -->
<a-list
v-if="isMobile()"
itemLayout="vertical"
size="large"
:pagination="false"
:dataSource="table.data"
:loading="table.loading"
>
<a-list-item
slot="renderItem"
slot-scope="item, index"
:key="index"
>
<template slot="actions">
<a-dropdown
placement="topLeft"
:trigger="['click']"
>
<span>
<a-icon type="bars" />
</span>
<a-menu slot="overlay">
<a-menu-item>
<a
href="javascript:;"
@click="form.model = item"
>编辑</a>
</a-menu-item>
<a-menu-item>
<a-popconfirm
:title="'你确定要删除【' + item.name + '】菜单?'"
@confirm="handleDeleteMenu(item.id)"
okText="确定"
cancelText="取消"
>
<a href="javascript:;">删除</a>
</a-popconfirm>
</a-menu-item>
</a-menu>
</a-dropdown>
</template>
<template slot="extra">
<span>
{{ item.team }}
</span>
</template>
<a-list-item-meta>
<template slot="description">
{{ item.url }}
</template>
<span
slot="title"
style="max-width: 300px;display: block;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;"
>
{{ item.name }}
</span>
</a-list-item-meta>
</a-list-item>
</a-list>
<!-- Desktop -->
<a-table
v-else
:columns="table.columns"
:dataSource="table.data"
:loading="table.loading"
:rowKey="menu => menu.id"
:scrollToFirstRowOnChange="true"
>
<span
slot="action"
slot-scope="text, record"
>
<a
href="javascript:;"
@click="form.model = record"
>编辑</a>
<a-divider type="vertical" />
<a-popconfirm
:title="'你确定要删除【' + record.name + '】菜单?'"
@confirm="handleDeleteMenu(record.id)"
okText="确定"
cancelText="取消"
>
<a href="javascript:;">删除</a>
</a-popconfirm>
<a-card :bodyStyle="{ padding: '16px' }">
<template slot="title">
<span>
{{ menuListTitle }}
</span>
</a-table>
<a-tooltip
slot="action"
title="分组下的菜单为空时,该分组也不会保存"
v-if="list.data.length <= 0"
>
<a-icon
type="info-circle-o"
class="cursor-pointer"
/>
</a-tooltip>
</template>
<template slot="extra">
<a-space>
<ReactiveButton
@click="handleUpdateBatch"
@callback="formBatch.errored=false"
:loading="formBatch.saving"
:errored="formBatch.errored"
text="保存"
loadedText="保存成功"
erroredText="保存失败"
:disabled="list.data.length<=0"
></ReactiveButton>
<a-button
@click="handleOpenCreateMenuForm()"
:disabled="form.visible"
type="primary"
ghost
>
新增
</a-button>
<a-dropdown :trigger="['click']">
<a-menu slot="overlay">
<a-menu-item @click="menuInternalLinkSelector.visible = true">
从系统预设链接添加
</a-menu-item>
<a-menu-item @click="handleDeleteBatch">
删除当前组
</a-menu-item>
</a-menu>
<a-button> 其他
<a-icon type="down" />
</a-button>
</a-dropdown>
</a-space>
</template>
<a-spin :spinning="list.loading">
<MenuForm
v-if="form.visible"
:menu="form.model"
@succeed="handleCreateMenuSucceed()"
@cancel="handleCloseCreateMenuForm()"
/>
<a-empty v-if="list.data.length===0 && !list.loading && !form.visible" />
<MenuTreeNode
v-model="list.data"
:excludedTeams="excludedTeams"
@reload="handleListMenus"
/>
</a-spin>
</a-card>
</a-col>
</a-row>
<MenuInternalLinkSelector
v-model="menuInternalLinkSelector.visible"
:team="teams.selected"
@reload="handleListMenus"
/>
</page-view>
</template>
<script>
import { mixin, mixinDevice } from '@/utils/mixin.js'
import MenuSelectTree from './components/MenuSelectTree'
// components
import { PageView } from '@/layouts'
import draggable from 'vuedraggable'
import MenuTreeNode from './components/MenuTreeNode'
import MenuForm from './components/MenuForm'
import MenuInternalLinkSelector from './components/MenuInternalLinkSelector'
import { deepClone } from '@/utils/util'
import { mapActions, mapGetters } from 'vuex'
// apis
import menuApi from '@/api/menu'
const columns = [
{
title: '名称',
dataIndex: 'name',
ellipsis: true,
scopedSlots: { customRender: 'name' },
},
{
title: '地址',
ellipsis: true,
dataIndex: 'url',
},
{
title: '分组',
ellipsis: true,
dataIndex: 'team',
},
{
title: '排序',
dataIndex: 'priority',
},
{
title: '操作',
key: 'action',
scopedSlots: { customRender: 'action' },
},
]
import optionApi from '@/api/option'
export default {
components: { MenuSelectTree, PageView },
mixins: [mixin, mixinDevice],
components: { PageView, draggable, MenuTreeNode, MenuForm, MenuInternalLinkSelector },
data() {
return {
table: {
columns,
list: {
data: [],
loading: false,
},
form: {
model: {
target: '_self',
},
visible: false,
model: {},
},
formBatch: {
saving: false,
errored: false,
rules: {
name: [
{ required: true, message: '* 菜单名称不能为空', trigger: ['change'] },
{ max: 50, message: '* 菜单名称的字符长度不能超过 50', trigger: ['change'] },
],
url: [
{ required: true, message: '* 菜单地址不能为空', trigger: ['change'] },
{ max: 1023, message: '* 菜单地址的字符长度不能超过 1023', trigger: ['change'] },
],
icon: [{ max: 50, message: '* 菜单图标的字符长度不能超过 50', trigger: ['change'] }],
team: [{ max: 255, message: '* 菜单分组的字符长度不能超过 255', trigger: ['change'] }],
},
moreField: false,
},
teams: {
data: [],
loading: false,
selected: null,
form: {
visible: false,
model: {
team: null,
},
rules: {
team: [{ required: true, message: '分组名称不能为空', trigger: ['change'] }],
},
},
default: {
saving: false,
errored: false,
},
},
menuInternalLinkSelector: {
visible: false,
},
}
},
computed: {
title() {
if (this.isUpdateMode) {
return '修改菜单'
}
return '添加菜单'
},
isUpdateMode() {
return !!this.form.model.id
},
...mapGetters(['options']),
computedTeams() {
return this.teams.data.filter((item) => {
return item !== ''
})
},
computedMenusMoved() {
const menus = deepClone(this.list.data)
return this.handleMenuMoved(0, menus)
},
computedMenusWithoutLevel() {
return this.handleGetMenusWithoutLevel(this.computedMenusMoved, [])
},
computedMenuIds() {
return this.computedMenusWithoutLevel.map((menu) => {
return menu.id
})
},
selectedTeam: {
get() {
return [this.teams.selected]
},
set(value) {
this.teams.selected = value[0]
},
},
menuListTitle() {
return this.teams.selected === '' ? '未分组' : this.teams.selected
},
excludedTeams() {
return this.teams.data.filter((item) => {
return item !== this.teams.selected
})
},
defaultMenuTeam() {
return this.options.default_menu_team ? this.options.default_menu_team : ''
},
},
created() {
this.handleListMenus()
this.handleListTeams()
},
methods: {
handleListMenus() {
this.table.loading = true
...mapActions(['refreshOptionsCache']),
handleListTeams(autoSelectTeam = false) {
this.teams.loading = true
menuApi
.listTree()
.listTeams()
.then((response) => {
this.table.data = response.data.data
this.teams.data = response.data.data
if (!this.teams.selected || autoSelectTeam) {
this.teams.selected = this.teams.data[0]
}
this.handleListMenus()
})
.finally(() => {
setTimeout(() => {
this.table.loading = false
this.teams.loading = false
}, 200)
})
},
handleListTeams() {
menuApi.listTeams().then((response) => {
this.teams.data = response.data.data
})
},
handleDeleteMenu(id) {
handleListMenus() {
this.list.loading = true
menuApi
.delete(id)
.listTreeByTeam(this.teams.selected)
.then((response) => {
this.$message.success('删除成功!')
this.list.data = response.data.data
})
.finally(() => {
this.handleListMenus()
this.handleListTeams()
setTimeout(() => {
this.list.loading = false
}, 200)
})
},
handleCreateOrUpdateMenu() {
handleMenuMoved(pid, menus) {
for (let i = 0; i < menus.length; i++) {
menus[i].priority = i
menus[i].parentId = pid
menus[i].team = this.teams.selected
if (menus[i].children && menus[i].children.length > 0) {
this.handleMenuMoved(menus[i].id, menus[i].children)
}
}
return menus
},
handleGetMenusWithoutLevel(menus, result) {
for (var i = 0; i < menus.length; i++) {
result.push(menus[i])
var children = menus[i].children
if (children.length > 0) {
this.handleGetMenusWithoutLevel(children, result)
}
}
return result
},
handleSelectedTeam({ item, key, selectedKeys }) {
this.teams.selected = key
this.handleCloseCreateMenuForm()
this.handleListMenus()
},
handleUpdateBatch() {
this.formBatch.saving = true
menuApi
.updateBatch(this.computedMenusWithoutLevel)
.catch(() => {
this.formBatch.errored = true
})
.finally(() => {
setTimeout(() => {
this.formBatch.saving = false
this.handleListMenus()
}, 400)
})
},
handleDeleteBatch() {
const _this = this
_this.$refs.menuForm.validate((valid) => {
_this.$confirm({
title: '提示',
content: '确定要删除当前分组以及所有菜单?',
onOk() {
menuApi.deleteBatch(_this.computedMenuIds).finally(() => {
_this.handleListTeams(true)
})
},
})
},
handleTeamFormVisibleChange(visible) {
if (visible) {
this.teams.form.model.team = null
}
},
handleCreateTeam() {
const _this = this
_this.$refs.teamForm.validate((valid) => {
if (valid) {
_this.form.saving = true
if (_this.isUpdateMode) {
menuApi
.update(_this.form.model.id, _this.form.model)
.catch(() => {
_this.form.errored = true
})
.finally(() => {
setTimeout(() => {
_this.form.saving = false
}, 400)
})
} else {
menuApi
.create(_this.form.model)
.catch(() => {
_this.form.errored = true
})
.finally(() => {
setTimeout(() => {
_this.form.saving = false
}, 400)
})
if (!_this.teams.data.includes(_this.teams.form.model.team)) {
_this.teams.data.push(_this.teams.form.model.team)
}
_this.teams.selected = _this.teams.form.model.team
_this.teams.form.visible = false
_this.handleListMenus()
}
})
},
handleSavedCallback() {
const _this = this
if (_this.form.errored) {
_this.form.errored = false
handleOpenCreateMenuForm() {
this.form.visible = true
this.form.model = {
team: this.teams.selected,
target: '_self',
}
},
handleCloseCreateMenuForm() {
this.form.visible = false
this.form.model = {}
},
handleCreateMenuSucceed() {
this.handleCloseCreateMenuForm()
this.handleListMenus()
},
handleSetDefaultTeam() {
this.teams.default.saving = true
optionApi
.save({
default_menu_team: this.teams.selected,
})
.catch(() => {
this.teams.default.errored = true
})
.finally(() => {
setTimeout(() => {
this.teams.default.saving = false
}, 400)
})
},
handleSetDefaultTeamCallback() {
if (this.teams.default.errored) {
this.teams.default.errored = false
} else {
_this.form.model = { target: '_self' }
_this.handleListMenus()
_this.handleListTeams()
this.refreshOptionsCache()
}
},
},

View File

@ -287,8 +287,8 @@
<a-modal
title="提示"
v-model="themeDeleteModal.visible"
:width=416
:closable=false
:width="416"
:closable="false"
destroyOnClose
@ok="handleDeleteTheme(themeDeleteModal.selected.id, themeDeleteModal.deleteSettings)"
@cancel="themeDeleteModal.visible = false"

View File

@ -0,0 +1,213 @@
<template>
<div>
<a-form-model
labelAlign="left"
ref="menuForm"
:model="menuModel"
:rules="form.rules"
@keyup.enter.native="handleCreateOrUpdateMenu"
>
<a-row :gutter="24">
<a-col
:xl="8"
:lg="8"
:md="12"
:sm="12"
:xs="12"
>
<a-form-model-item
label="名称"
prop="name"
help="* 页面上所显示的名称"
>
<a-input
v-model="menuModel.name"
autoFocus
/>
</a-form-model-item>
</a-col>
<a-col
:xl="8"
:lg="8"
:md="12"
:sm="12"
:xs="12"
>
<a-form-model-item
label="地址"
prop="url"
help="* 菜单的地址"
>
<a-input v-model="menuModel.url" />
</a-form-model-item>
</a-col>
<a-col
:xl="8"
:lg="8"
:md="12"
:sm="12"
:xs="12"
>
<a-form-model-item
label="图标"
prop="icon"
help="* 请根据主题的支持情况选填"
>
<a-input v-model="menuModel.icon" />
</a-form-model-item>
</a-col>
<a-col
:xl="8"
:lg="8"
:md="12"
:sm="12"
:xs="12"
>
<a-form-model-item
label="打开方式"
prop="target"
>
<a-radio-group
v-model="menuModel.target"
:options="targets"
/>
</a-form-model-item>
</a-col>
<a-col
:xl="8"
:lg="8"
:md="12"
:sm="12"
:xs="12"
>
<a-form-model-item
label=" "
:colon="false"
>
<a-space>
<ReactiveButton
type="primary"
@click="handleCreateOrUpdateMenu"
@callback="handleSavedCallback"
:loading="form.saving"
:errored="form.errored"
text="保存"
loadedText="保存成功"
erroredText="保存失败"
></ReactiveButton>
<a-button @click="handleCancel"></a-button>
</a-space>
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
</div>
</template>
<script>
import menuApi from '@/api/menu'
const targets = [
{
value: '_self',
label: '当前窗口',
},
{
value: '_blank',
label: '新窗口',
},
]
export default {
name: 'MenuForm',
model: {
prop: 'menu',
event: 'input',
},
props: {
menu: {
type: Object,
default: () => {
return {}
},
},
},
computed: {
menuModel: {
get() {
return this.menu
},
set(value) {
this.$emit('input', value)
},
},
isUpdateMode() {
return !!this.menuModel.id
},
},
data() {
return {
targets,
form: {
rules: {
name: [
{ required: true, message: '* 菜单名称不能为空', trigger: ['change'] },
{ max: 50, message: '* 菜单名称的字符长度不能超过 50', trigger: ['change'] },
],
url: [
{ required: true, message: '* 菜单地址不能为空', trigger: ['change'] },
{ max: 1023, message: '* 菜单地址的字符长度不能超过 1023', trigger: ['change'] },
],
icon: [{ max: 50, message: '* 菜单图标的字符长度不能超过 50', trigger: ['change'] }],
},
saving: false,
errored: false,
},
}
},
methods: {
handleCreateOrUpdateMenu() {
const _this = this
_this.$refs.menuForm.validate((valid) => {
if (valid) {
_this.form.saving = true
if (_this.isUpdateMode) {
menuApi
.update(_this.menuModel.id, _this.menuModel)
.catch(() => {
_this.form.errored = true
})
.finally(() => {
setTimeout(() => {
_this.form.saving = false
}, 400)
})
} else {
menuApi
.create(_this.menuModel)
.catch(() => {
_this.form.errored = true
})
.finally(() => {
setTimeout(() => {
_this.form.saving = false
}, 400)
})
}
}
})
},
handleSavedCallback() {
const _this = this
if (_this.form.errored) {
_this.form.errored = false
} else {
_this.menuModel = { target: '_self' }
_this.$emit('succeed')
}
},
handleCancel() {
this.$emit('cancel')
},
},
}
</script>

View File

@ -0,0 +1,377 @@
<template>
<a-modal
v-model="visible"
title="从系统预设链接添加菜单"
:width="1024"
:bodyStyle="{ padding: '0 24px 24px' }"
>
<template slot="footer">
<a-button @click="handleCancel">
取消
</a-button>
<ReactiveButton
@click="handleCreateBatch"
@callback="handleCreateBatchCallback"
:loading="saving"
:errored="saveErrored"
text="添加"
loadedText="添加成功"
erroredText="添加失败"
:disabled="menus && menus.length <= 0"
></ReactiveButton>
</template>
<a-row :gutter="24">
<a-col :span="12">
<a-spin :spinning="loading">
<div class="custom-tab-wrapper">
<a-tabs default-active-key="1">
<a-tab-pane
key="1"
tab="分类目录"
force-render
>
<a-list item-layout="horizontal">
<a-list-item
v-for="(category,index) in categories"
:key="index"
>
<a-list-item-meta>
<span slot="title">{{ category.name }}</span>
<span slot="description">{{ category.fullPath }}</span>
</a-list-item-meta>
<template slot="actions">
<a
href="javascript:void(0);"
class="text-base"
>
<a-icon
type="plus-circle"
@click="handleInsertPre(category.name,category.fullPath)"
/>
</a>
</template>
</a-list-item>
</a-list>
</a-tab-pane>
<a-tab-pane
key="2"
tab="标签"
>
<a-list item-layout="horizontal">
<a-list-item
v-for="(tag,index) in tags"
:key="index"
>
<a-list-item-meta>
<span slot="title">{{ tag.name }}</span>
<span slot="description">{{ tag.fullPath }}</span>
</a-list-item-meta>
<template slot="actions">
<a
href="javascript:void(0);"
class="text-base"
>
<a-icon
type="plus-circle"
@click="handleInsertPre(tag.name,tag.fullPath)"
/>
</a>
</template>
</a-list-item>
</a-list>
</a-tab-pane>
<a-tab-pane
key="3"
tab="独立页面"
>
<a-list item-layout="horizontal">
<a-list-item
v-for="(item,index) in sheet.independents"
:key="index"
>
<a-list-item-meta>
<span slot="title">{{ item.title }}</span>
<span slot="description">{{ item.fullPath }}</span>
</a-list-item-meta>
<template slot="actions">
<a
href="javascript:void(0);"
class="text-base"
>
<a-icon
type="plus-circle"
@click="handleInsertPre(item.title,item.fullPath)"
/>
</a>
</template>
</a-list-item>
</a-list>
</a-tab-pane>
<a-tab-pane
key="4"
tab="自定义页面"
>
<a-list item-layout="horizontal">
<a-list-item
v-for="(item,index) in sheet.customs.data"
:key="index"
>
<a-list-item-meta>
<span slot="title">{{ item.title }}</span>
<span slot="description">{{ item.fullPath }}</span>
</a-list-item-meta>
<template slot="actions">
<a
href="javascript:void(0);"
class="text-base"
>
<a-icon
type="plus-circle"
@click="handleInsertPre(item.title,item.fullPath)"
/>
</a>
</template>
</a-list-item>
</a-list>
<div class="page-wrapper">
<a-pagination
class="pagination"
:current="sheet.customs.pagination.page"
:total="sheet.customs.pagination.total"
:defaultPageSize="sheet.customs.pagination.size"
:pageSizeOptions="['1', '2', '5', '10', '20', '50', '100']"
showSizeChanger
@showSizeChange="handleSheetPaginationChange"
@change="handleSheetPaginationChange"
showLessItems
/>
</div>
</a-tab-pane>
<a-tab-pane
key="5"
tab="其他"
>
<a-list item-layout="horizontal">
<a-list-item
v-for="(item,index) in otherInternalLinks"
:key="index"
>
<a-list-item-meta>
<span slot="title">{{ item.name }}</span>
<span slot="description">{{ item.url }}</span>
</a-list-item-meta>
<template slot="actions">
<a
href="javascript:void(0);"
class="text-base"
>
<a-icon
type="plus-circle"
@click="handleInsertPre(item.name,item.url)"
/>
</a>
</template>
</a-list-item>
</a-list>
</a-tab-pane>
</a-tabs>
</div>
</a-spin>
</a-col>
<a-col :span="12">
<div class="custom-tab-wrapper">
<a-tabs default-active-key="1">
<a-tab-pane
key="1"
tab="备选"
force-render
>
<a-list item-layout="horizontal">
<a-list-item
v-for="(menu,index) in menus"
:key="index"
>
<a-list-item-meta>
<span slot="title">{{ menu.name }}</span>
<span slot="description">{{ menu.url }}</span>
</a-list-item-meta>
<template slot="actions">
<a
href="javascript:void(0);"
class="text-base"
@click="handleRemovePre(index)"
>
<a-icon type="close-circle" />
</a>
</template>
</a-list-item>
</a-list>
</a-tab-pane>
</a-tabs>
</div>
</a-col>
</a-row>
</a-modal>
</template>
<script>
import categoryApi from '@/api/category'
import tagApi from '@/api/tag'
import menuApi from '@/api/menu'
import sheetApi from '@/api/sheet'
import optionApi from '@/api/option'
export default {
name: 'MenuInternalLinkSelector',
props: {
value: {
type: Boolean,
default: false,
},
team: {
type: String,
default: '',
},
},
data() {
return {
options: {},
categories: [],
tags: [],
menus: [],
sheet: {
independents: [],
customs: {
data: [],
pagination: {
page: 1,
size: 10,
sort: null,
total: 1,
},
queryParam: {
page: 0,
size: 10,
sort: null,
},
},
},
loading: false,
saving: false,
saveErrored: false,
}
},
computed: {
visible: {
get() {
return this.value
},
set(value) {
this.$emit('input', value)
},
},
otherInternalLinks() {
const options = this.options
return [
{
name: '分类目录',
url: `${options.blog_url}/${options.categories_prefix}${options.path_suffix}`,
},
{
name: '标签',
url: `${options.blog_url}/${options.tags_prefix}${options.path_suffix}`,
},
{
name: '文章归档',
url: `${options.blog_url}/${options.archives_prefix}${options.path_suffix}`,
},
{
name: 'RSS',
url: `${options.blog_url}/atom.xml`,
},
{
name: '网站地图',
url: `${options.blog_url}/sitemap.xml`,
},
{
name: '网站地图',
url: `${options.blog_url}/sitemap.html`,
},
]
},
},
watch: {
visible(value) {
if (value) {
this.handleFetchAll()
this.handleListSheets()
}
},
},
methods: {
handleFetchAll() {
this.loading = true
Promise.all([optionApi.listAll(), categoryApi.listAll(true), tagApi.listAll(true), sheetApi.listIndependent()])
.then((response) => {
this.options = response[0].data.data
this.categories = response[1].data.data
this.tags = response[2].data.data
this.sheet.independents = response[3].data.data
})
.finally(() => {
setTimeout(() => {
this.loading = false
}, 200)
})
},
handleListSheets() {
this.sheet.customs.queryParam.page = this.sheet.customs.pagination.page - 1
this.sheet.customs.queryParam.size = this.sheet.customs.pagination.size
this.sheet.customs.queryParam.sort = this.sheet.customs.pagination.sort
sheetApi.list(this.sheet.customs.queryParam).then((response) => {
this.sheet.customs.data = response.data.data.content
this.sheet.customs.pagination.total = response.data.data.total
})
},
handleSheetPaginationChange(page, pageSize) {
this.sheet.customs.pagination.page = page
this.sheet.customs.pagination.size = pageSize
this.handleListSheets()
},
handleInsertPre(name, url) {
this.menus.push({
name: name,
url: url,
team: this.team,
})
},
handleRemovePre(index) {
this.menus.splice(index, 1)
},
handleCancel() {
this.menus = []
this.visible = false
this.$emit('reload')
},
handleCreateBatch() {
this.saving = true
menuApi
.createBatch(this.menus)
.catch(() => {
this.saveErrored = false
})
.finally(() => {
setTimeout(() => {
this.saving = false
}, 400)
})
},
handleCreateBatchCallback() {
if (this.saveErrored) {
this.saveErrored = false
} else {
this.handleCancel()
}
},
},
}
</script>

View File

@ -1,57 +0,0 @@
<template>
<a-tree-select
:treeData="menuTreeData"
placeholder="请选择上级菜单,默认为顶级菜单"
treeDefaultExpandAll
:treeDataSimpleMode="true"
:allowClear="true"
:value="menuIdString"
@change="handleSelectionChange"
>
</a-tree-select>
</template>
<script>
export default {
name: 'MenuSelectTree',
model: {
prop: 'menuId',
event: 'change'
},
props: {
menuId: {
type: Number,
required: true,
default: 0
},
menus: {
type: Array,
required: false,
default: () => []
}
},
computed: {
menuTreeData() {
return this.menus.map(menu => {
return {
id: menu.id,
title: menu.name,
value: menu.id.toString(),
pId: menu.parentId
}
})
},
menuIdString() {
return this.menuId.toString()
}
},
methods: {
handleSelectionChange(value, label, extra) {
this.$log.debug('value: ', value)
this.$log.debug('label: ', label)
this.$log.debug('extra: ', extra)
this.$emit('change', value ? parseInt(value) : 0)
}
}
}
</script>

View File

@ -0,0 +1,221 @@
<template>
<a-list item-layout="horizontal">
<draggable
v-bind="dragOptions"
tag="div"
class="item-container"
:list="list"
:value="value"
@input="emitter"
@start="isDragging = true"
@end="isDragging = false"
handle=".title"
>
<transition-group>
<div
:key="item.id"
v-for="(item) in realValue"
>
<a-list-item class="cursor-pointer menu-item">
<a-list-item-meta>
<span
slot="description"
class="inline-block"
>
<a
:href="item.url"
target="_blank"
class="ant-anchor-link-title"
> {{ item.url }} </a>
</span>
<span
slot="title"
class="title cursor-move inline-block font-bold"
>{{ item.name }}
<a-tooltip title="外部链接">
<a-icon
v-if="item.target==='_blank'"
type="link"
/>
</a-tooltip>
{{ item.formVisible?'(正在编辑)':'' }}
</span>
</a-list-item-meta>
<template slot="actions">
<a
href="javascript:void(0);"
@click="handleDelete(item.id)"
>删除</a>
</template>
<template slot="actions">
<a
href="javascript:void(0);"
@click="handleOpenEditForm(item)"
>
编辑
</a>
</template>
<template
slot="actions"
v-if="excludedTeams && excludedTeams.length>0"
>
<a-dropdown :trigger="['click']">
<a
class="ant-dropdown-link"
@click="e => e.preventDefault()"
>
更多
<a-icon type="down" />
</a>
<a-menu slot="overlay">
<a-sub-menu title="移动到分组">
<a-menu-item
v-for="(team,index) in excludedTeams"
:key="index"
@click="handleMoveMenu(item,team)"
>{{ team===''?'未分组':team }}</a-menu-item>
</a-sub-menu>
<a-sub-menu title="复制到分组">
<a-menu-item
v-for="(team,index) in excludedTeams"
:key="index"
@click="handleCopyMenu(item,team)"
>{{ team===''?'未分组':team }}</a-menu-item>
</a-sub-menu>
</a-menu>
</a-dropdown>
</template>
</a-list-item>
<MenuForm
v-if="item.formVisible"
:menu="item"
@succeed="handleUpdateMenuSucceed(item)"
@cancel="handleCloseCreateMenuForm(item)"
/>
<div
class="a-list-nested"
style="margin-left: 44px;"
>
<MenuTreeNode
:list="item.children"
:excludedTeams="excludedTeams"
@reload="onReloadEmit"
/>
</div>
</div>
</transition-group>
</draggable>
</a-list>
</template>
<script>
// components
import draggable from 'vuedraggable'
import MenuForm from './MenuForm'
// apis
import menuApi from '@/api/menu'
import { deepClone } from '@/utils/util'
export default {
name: 'MenuTreeNode',
components: {
draggable,
MenuForm,
},
props: {
value: {
required: false,
type: Array,
default: null,
},
list: {
required: false,
type: Array,
default: null,
},
excludedTeams: {
required: false,
type: Array,
default: null,
},
},
data() {
return {
isDragging: false,
}
},
computed: {
dragOptions() {
return {
animation: 300,
group: 'description',
disabled: false,
ghostClass: 'ghost',
}
},
realValue() {
return this.value ? this.value : this.list
},
},
methods: {
emitter(value) {
this.$emit('input', value)
},
handleDelete(id) {
const _this = this
_this.$confirm({
title: '提示',
content: '确定要删除当前菜单?',
onOk() {
menuApi.delete(id).finally(() => {
_this.onReloadEmit()
})
},
})
},
handleOpenEditForm(item) {
this.$set(item, 'formVisible', true)
},
handleUpdateMenuSucceed(item) {
this.handleCloseCreateMenuForm(item)
// this.$emit('reload')
},
handleCloseCreateMenuForm(item) {
this.$set(item, 'formVisible', false)
},
handleCopyMenu(item, team) {
const menu = deepClone(item)
menu.team = team
menu.parentId = 0
menu.priority = 0
menu.id = null
menuApi.create(menu).then((response) => {
this.$emit('reload')
})
},
handleMoveMenu(item, team) {
const menu = deepClone(item)
menu.team = team
menu.parentId = 0
menu.priority = 0
menuApi.update(menu.id, menu).then((response) => {
this.$emit('reload')
})
},
onReloadEmit() {
this.$emit('reload')
},
},
}
</script>
<style scoped>
.ghost {
opacity: 0.8;
background: #c8ebfb;
}
::v-deep .ant-list-item-action {
display: none;
}
::v-deep .menu-item:hover .ant-list-item-action {
display: block;
}
</style>

View File

@ -145,16 +145,6 @@
@click="form.model = item"
>编辑</a>
</a-menu-item>
<a-menu-item>
<a-popconfirm
:title="'你确定要添加【' + item.name + '】到菜单?'"
@confirm="handleCreateMenuByCategory(item)"
okText="确定"
cancelText="取消"
>
<a href="javascript:void(0);">添加到菜单</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item>
<a-popconfirm
:title="'你确定要删除【' + item.name + '】分类?'"
@ -216,34 +206,14 @@
@click="form.model = record"
>编辑</a>
<a-divider type="vertical" />
<a-dropdown :trigger="['click']">
<a
href="javascript:void(0);"
class="ant-dropdown-link"
>更多</a>
<a-menu slot="overlay">
<a-menu-item key="1">
<a-popconfirm
:title="'你确定要添加【' + record.name + '】到菜单?'"
@confirm="handleCreateMenuByCategory(record)"
okText="确定"
cancelText="取消"
>
<a href="javascript:void(0);">添加到菜单</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item key="2">
<a-popconfirm
:title="'你确定要删除【' + record.name + '】分类?'"
@confirm="handleDeleteCategory(record.id)"
okText="确定"
cancelText="取消"
>
<a href="javascript:void(0);">删除</a>
</a-popconfirm>
</a-menu-item>
</a-menu>
</a-dropdown>
<a-popconfirm
:title="'你确定要删除【' + record.name + '】分类?'"
@confirm="handleDeleteCategory(record.id)"
okText="确定"
cancelText="取消"
>
<a href="javascript:void(0);">删除</a>
</a-popconfirm>
</span>
</a-table>
</a-card>
@ -262,34 +232,33 @@
import { mixin, mixinDevice } from '@/utils/mixin.js'
import CategorySelectTree from './components/CategorySelectTree'
import categoryApi from '@/api/category'
import menuApi from '@/api/menu'
const columns = [
{
title: '名称',
ellipsis: true,
dataIndex: 'name'
dataIndex: 'name',
},
{
title: '别名',
ellipsis: true,
dataIndex: 'slug'
dataIndex: 'slug',
},
{
title: '描述',
ellipsis: true,
dataIndex: 'description'
dataIndex: 'description',
},
{
title: '文章数',
dataIndex: 'postCount',
scopedSlots: { customRender: 'postCount' }
scopedSlots: { customRender: 'postCount' },
},
{
title: '操作',
key: 'action',
scopedSlots: { customRender: 'action' }
}
scopedSlots: { customRender: 'action' },
},
]
export default {
@ -300,7 +269,7 @@ export default {
table: {
columns,
data: [],
loading: false
loading: false,
},
form: {
model: {},
@ -309,16 +278,16 @@ export default {
rules: {
name: [
{ required: true, message: '* 分类名称不能为空', trigger: ['change'] },
{ max: 255, message: '* 分类名称的字符长度不能超过 255', trigger: ['change'] }
{ max: 255, message: '* 分类名称的字符长度不能超过 255', trigger: ['change'] },
],
slug: [{ max: 255, message: '* 分类别名的字符长度不能超过 255', trigger: ['change'] }],
thumbnail: [{ max: 1023, message: '* 封面图链接的字符长度不能超过 1023', trigger: ['change'] }],
description: [{ max: 100, message: '* 分类描述的字符长度不能超过 100', trigger: ['change'] }]
}
description: [{ max: 100, message: '* 分类描述的字符长度不能超过 100', trigger: ['change'] }],
},
},
thumbnailDrawer: {
visible: false
}
visible: false,
},
}
},
computed: {
@ -330,7 +299,7 @@ export default {
},
isUpdateMode() {
return !!this.form.model.id
}
},
},
created() {
this.handleListCategories()
@ -340,7 +309,7 @@ export default {
this.table.loading = true
categoryApi
.listAll(true)
.then(response => {
.then((response) => {
this.table.data = response.data.data
})
.finally(() => {
@ -352,7 +321,7 @@ export default {
handleDeleteCategory(id) {
categoryApi
.delete(id)
.then(response => {
.then((response) => {
this.$message.success('删除成功!')
this.form.model = {}
})
@ -366,7 +335,7 @@ export default {
*/
handleCreateOrUpdateCategory() {
const _this = this
_this.$refs.categoryForm.validate(valid => {
_this.$refs.categoryForm.validate((valid) => {
if (valid) {
_this.form.saving = true
if (_this.isUpdateMode) {
@ -404,22 +373,13 @@ export default {
_this.handleListCategories()
}
},
handleCreateMenuByCategory(category) {
const menu = {
name: category.name,
url: `${category.fullPath}`
}
menuApi.create(menu).then(response => {
this.$message.success('添加到菜单成功!')
})
},
handleSelectThumbnail(data) {
this.$set(this.form.model, 'thumbnail', encodeURI(data.path))
this.thumbnailDrawer.visible = false
},
handleQueryCategoryPosts(category) {
this.$router.push({ name: 'PostList', query: { categoryId: category.id } })
}
}
},
},
}
</script>

View File

@ -67,16 +67,6 @@
<a href="javascript:;">删除</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item>
<a-popconfirm
:title="'你确定要添加【' + item.title + '】到菜单?'"
@confirm="handleSheetToMenu(item)"
okText="确定"
cancelText="取消"
>
<a href="javascript:void(0);">添加到菜单</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item>
<a
rel="noopener noreferrer"
@ -278,30 +268,10 @@
<a href="javascript:;">删除</a>
</a-popconfirm>
<a-divider type="vertical" />
<a-dropdown :trigger="['click']">
<a
href="javascript:void(0);"
class="ant-dropdown-link"
>更多</a>
<a-menu slot="overlay">
<a-menu-item key="1">
<a
href="javascript:void(0);"
@click="handleShowSheetSettings(sheet)"
>设置</a>
</a-menu-item>
<a-menu-item key="2">
<a-popconfirm
:title="'你确定要添加【' + sheet.title + '】到菜单?'"
@confirm="handleSheetToMenu(sheet)"
okText="确定"
cancelText="取消"
>
<a href="javascript:void(0);">添加到菜单</a>
</a-popconfirm>
</a-menu-item>
</a-menu>
</a-dropdown>
<a
href="javascript:void(0);"
@click="handleShowSheetSettings(sheet)"
>设置</a>
</span>
</a-table>
<div class="page-wrapper">
@ -343,48 +313,47 @@ import { mixin, mixinDevice } from '@/utils/mixin.js'
import SheetSettingDrawer from './SheetSettingDrawer'
import TargetCommentDrawer from '../../comment/components/TargetCommentDrawer'
import sheetApi from '@/api/sheet'
import menuApi from '@/api/menu'
const customColumns = [
{
title: '标题',
dataIndex: 'title',
ellipsis: true,
scopedSlots: { customRender: 'sheetTitle' }
scopedSlots: { customRender: 'sheetTitle' },
},
{
title: '状态',
className: 'status',
dataIndex: 'statusProperty',
scopedSlots: { customRender: 'status' }
scopedSlots: { customRender: 'status' },
},
{
title: '评论量',
dataIndex: 'commentCount',
scopedSlots: { customRender: 'commentCount' }
scopedSlots: { customRender: 'commentCount' },
},
{
title: '访问量',
dataIndex: 'visits',
scopedSlots: { customRender: 'visits' }
scopedSlots: { customRender: 'visits' },
},
{
title: '发布时间',
dataIndex: 'createTime',
scopedSlots: { customRender: 'createTime' }
scopedSlots: { customRender: 'createTime' },
},
{
title: '操作',
width: '180px',
scopedSlots: { customRender: 'action' }
}
scopedSlots: { customRender: 'action' },
},
]
export default {
name: 'CustomSheetList',
mixins: [mixin, mixinDevice],
components: {
SheetSettingDrawer,
TargetCommentDrawer
TargetCommentDrawer,
},
data() {
return {
@ -392,7 +361,7 @@ export default {
page: 1,
size: 10,
sort: null,
total: 1
total: 1,
},
queryParam: {
page: 0,
@ -400,7 +369,7 @@ export default {
sort: null,
keyword: null,
categoryId: null,
status: null
status: null,
},
loading: false,
sheetStatus: sheetApi.sheetStatus,
@ -410,21 +379,21 @@ export default {
sheetSettingVisible: false,
sheetCommentVisible: false,
sheets: [],
menu: {}
menu: {},
}
},
computed: {
formattedSheets() {
return this.sheets.map(sheet => {
return this.sheets.map((sheet) => {
sheet.statusProperty = this.sheetStatus[sheet.status]
return sheet
})
}
},
},
created() {
this.handleListSheets()
},
destroyed: function() {
destroyed() {
if (this.sheetSettingVisible) {
this.sheetSettingVisible = false
}
@ -445,7 +414,7 @@ export default {
this.queryParam.sort = this.pagination.sort
sheetApi
.list(this.queryParam)
.then(response => {
.then((response) => {
this.sheets = response.data.data.content
this.pagination.total = response.data.data.total
})
@ -461,7 +430,7 @@ export default {
handleEditStatusClick(sheetId, status) {
sheetApi
.updateStatus(sheetId, status)
.then(response => {
.then((response) => {
this.$message.success('操作成功!')
})
.finally(() => {
@ -471,36 +440,28 @@ export default {
handleDeleteClick(sheetId) {
sheetApi
.delete(sheetId)
.then(response => {
.then((response) => {
this.$message.success('删除成功!')
})
.finally(() => {
this.handleListSheets()
})
},
handleSheetToMenu(sheet) {
this.menu['name'] = sheet.title
this.menu['url'] = `${sheet.fullPath}`
menuApi.create(this.menu).then(response => {
this.$message.success('添加到菜单成功!')
this.menu = {}
})
},
handleShowSheetSettings(sheet) {
sheetApi.get(sheet.id).then(response => {
sheetApi.get(sheet.id).then((response) => {
this.selectedSheet = response.data.data
this.selectedMetas = this.selectedSheet.metas
this.sheetSettingVisible = true
})
},
handleShowSheetComments(sheet) {
sheetApi.get(sheet.id).then(response => {
sheetApi.get(sheet.id).then((response) => {
this.selectedSheet = response.data.data
this.sheetCommentVisible = true
})
},
handlePreview(sheetId) {
sheetApi.preview(sheetId).then(response => {
sheetApi.preview(sheetId).then((response) => {
window.open(response.data, '_blank')
})
},
@ -529,7 +490,7 @@ export default {
},
onRefreshSheetMetasFromSetting(metas) {
this.selectedMetas = metas
}
}
},
},
}
</script>