From 763df19bfcfd4969dee4f6a624fe2de4edabb4f7 Mon Sep 17 00:00:00 2001 From: Lukas Bachschwell Date: Tue, 3 Dec 2019 19:03:25 +0100 Subject: [PATCH] Initial --- .editorconfig | 14 + .env.development | 14 + .env.production | 6 + .env.staging | 8 + .eslintignore | 4 + .eslintrc.js | 198 ++ .gitignore | 23 + README.md | 217 ++ babel.config.js | 5 + build/index.js | 35 + jest.config.js | 24 + jsconfig.json | 9 + mock/article.js | 116 ++ mock/index.js | 70 + mock/mock-server.js | 68 + mock/remote-search.js | 51 + mock/role/index.js | 98 + mock/role/routes.js | 525 +++++ mock/user.js | 84 + package.json | 106 + plop-templates/component/index.hbs | 26 + plop-templates/component/prompt.js | 55 + plop-templates/utils.js | 9 + plop-templates/view/index.hbs | 26 + plop-templates/view/prompt.js | 55 + plopfile.js | 7 + postcss.config.js | 5 + public/favicon.ico | Bin 0 -> 6362 bytes public/index.html | 19 + src/App.vue | 11 + src/api/article.js | 41 + src/api/qiniu.js | 8 + src/api/remote-search.js | 17 + src/api/role.js | 38 + src/api/user.js | 24 + src/assets/401_images/401.gif | Bin 0 -> 164227 bytes src/assets/404_images/404.png | Bin 0 -> 98071 bytes src/assets/404_images/404_cloud.png | Bin 0 -> 4766 bytes .../custom-theme/fonts/element-icons.ttf | Bin 0 -> 11028 bytes .../custom-theme/fonts/element-icons.woff | Bin 0 -> 6124 bytes src/assets/custom-theme/index.css | 1 + src/assets/logo/join_logo.png | Bin 0 -> 24517 bytes src/assets/logo/joinlogosquare.png | Bin 0 -> 10552 bytes src/components/BackToTop/index.vue | 111 + src/components/Breadcrumb/index.vue | 82 + src/components/Charts/Keyboard.vue | 155 ++ src/components/Charts/LineMarker.vue | 227 +++ src/components/Charts/MixChart.vue | 271 +++ src/components/Charts/mixins/resize.js | 34 + src/components/DndList/index.vue | 166 ++ src/components/DragSelect/index.vue | 61 + src/components/Dropzone/index.vue | 297 +++ src/components/ErrorLog/index.vue | 78 + src/components/GithubCorner/index.vue | 54 + src/components/Hamburger/index.vue | 44 + src/components/HeaderSearch/index.vue | 180 ++ src/components/ImageCropper/index.vue | 1778 +++++++++++++++++ .../ImageCropper/utils/data2blob.js | 19 + .../ImageCropper/utils/effectRipple.js | 39 + src/components/ImageCropper/utils/language.js | 232 +++ src/components/ImageCropper/utils/mimes.js | 7 + src/components/JsonEditor/index.vue | 72 + src/components/Kanban/index.vue | 99 + src/components/MDinput/index.vue | 360 ++++ .../MarkdownEditor/default-options.js | 31 + src/components/MarkdownEditor/index.vue | 118 ++ src/components/Pagination/index.vue | 101 + src/components/PanThumb/index.vue | 142 ++ src/components/RightPanel/index.vue | 145 ++ src/components/Screenfull/index.vue | 60 + src/components/Share/DropdownMenu.vue | 100 + src/components/SizeSelect/index.vue | 57 + src/components/Sticky/index.vue | 91 + src/components/SvgIcon/index.vue | 62 + src/components/TextHoverEffect/Mallki.vue | 113 ++ src/components/ThemePicker/index.vue | 175 ++ .../Tinymce/components/EditorImage.vue | 111 + src/components/Tinymce/dynamicLoadScript.js | 59 + src/components/Tinymce/index.vue | 237 +++ src/components/Tinymce/plugins.js | 7 + src/components/Tinymce/toolbar.js | 6 + src/components/Upload/SingleImage.vue | 134 ++ src/components/Upload/SingleImage2.vue | 130 ++ src/components/Upload/SingleImage3.vue | 157 ++ src/components/UploadExcel/index.vue | 138 ++ src/directive/clipboard/clipboard.js | 49 + src/directive/clipboard/index.js | 13 + src/directive/el-drag-dialog/drag.js | 77 + src/directive/el-drag-dialog/index.js | 13 + src/directive/el-table/adaptive.js | 41 + src/directive/el-table/index.js | 13 + src/directive/permission/index.js | 13 + src/directive/permission/permission.js | 22 + src/directive/sticky.js | 91 + src/directive/waves/index.js | 13 + src/directive/waves/waves.css | 26 + src/directive/waves/waves.js | 72 + src/filters/index.js | 68 + src/icons/index.js | 9 + src/icons/svg/404.svg | 1 + src/icons/svg/bug.svg | 1 + src/icons/svg/chart.svg | 1 + src/icons/svg/clipboard.svg | 1 + src/icons/svg/component.svg | 1 + src/icons/svg/dashboard.svg | 1 + src/icons/svg/documentation.svg | 1 + src/icons/svg/drag.svg | 1 + src/icons/svg/edit.svg | 1 + src/icons/svg/education.svg | 1 + src/icons/svg/email.svg | 1 + src/icons/svg/example.svg | 1 + src/icons/svg/excel.svg | 1 + src/icons/svg/exit-fullscreen.svg | 1 + src/icons/svg/eye-open.svg | 1 + src/icons/svg/eye.svg | 1 + src/icons/svg/form.svg | 1 + src/icons/svg/fullscreen.svg | 1 + src/icons/svg/guide.svg | 1 + src/icons/svg/icon.svg | 1 + src/icons/svg/international.svg | 1 + src/icons/svg/language.svg | 1 + src/icons/svg/link.svg | 1 + src/icons/svg/list.svg | 1 + src/icons/svg/lock.svg | 1 + src/icons/svg/message.svg | 1 + src/icons/svg/money.svg | 1 + src/icons/svg/nested.svg | 1 + src/icons/svg/password.svg | 1 + src/icons/svg/pdf.svg | 1 + src/icons/svg/people.svg | 1 + src/icons/svg/peoples.svg | 1 + src/icons/svg/qq.svg | 1 + src/icons/svg/search.svg | 1 + src/icons/svg/shopping.svg | 1 + src/icons/svg/size.svg | 1 + src/icons/svg/skill.svg | 1 + src/icons/svg/star.svg | 1 + src/icons/svg/tab.svg | 1 + src/icons/svg/table.svg | 1 + src/icons/svg/theme.svg | 1 + src/icons/svg/tree-table.svg | 1 + src/icons/svg/tree.svg | 1 + src/icons/svg/user.svg | 1 + src/icons/svg/wechat.svg | 1 + src/icons/svg/zip.svg | 1 + src/icons/svgo.yml | 22 + src/layout/components/AppMain.vue | 57 + src/layout/components/Navbar.vue | 158 ++ src/layout/components/Settings/index.vue | 108 + src/layout/components/Sidebar/FixiOSBug.js | 26 + src/layout/components/Sidebar/Item.vue | 29 + src/layout/components/Sidebar/Link.vue | 36 + src/layout/components/Sidebar/Logo.vue | 80 + src/layout/components/Sidebar/SidebarItem.vue | 95 + src/layout/components/Sidebar/index.vue | 54 + src/layout/components/TagsView/ScrollPane.vue | 85 + src/layout/components/TagsView/index.vue | 289 +++ src/layout/components/index.js | 5 + src/layout/index.vue | 102 + src/layout/mixin/ResizeHandler.js | 45 + src/main.js | 51 + src/permission.js | 74 + src/router/index.js | 436 ++++ src/router/modules/charts.js | 37 + src/router/modules/components.js | 103 + src/router/modules/nested.js | 67 + src/router/modules/table.js | 42 + src/settings.js | 41 + src/store/getters.js | 15 + src/store/index.js | 25 + src/store/modules/app.js | 56 + src/store/modules/errorLog.js | 28 + src/store/modules/permission.js | 69 + src/store/modules/settings.js | 34 + src/store/modules/tagsView.js | 160 ++ src/store/modules/user.js | 136 ++ src/styles/btn.scss | 99 + src/styles/element-ui.scss | 84 + src/styles/element-variables.scss | 31 + src/styles/index.scss | 191 ++ src/styles/mixin.scss | 66 + src/styles/sidebar.scss | 209 ++ src/styles/transition.scss | 48 + src/styles/variables.scss | 35 + src/utils/auth.js | 15 + src/utils/clipboard.js | 32 + src/utils/error-log.js | 35 + src/utils/get-page-title.js | 10 + src/utils/index.js | 347 ++++ src/utils/open-window.js | 25 + src/utils/permission.js | 25 + src/utils/request.js | 85 + src/utils/scroll-to.js | 58 + src/utils/validate.js | 87 + src/vendor/Export2Excel.js | 220 ++ src/vendor/Export2Zip.js | 24 + src/views/charts/keyboard.vue | 23 + src/views/charts/line.vue | 23 + src/views/charts/mix-chart.vue | 23 + src/views/chatbot/index.vue | 58 + src/views/clipboard/index.vue | 49 + src/views/components-demo/avatar-upload.vue | 61 + src/views/components-demo/back-to-top.vue | 154 ++ src/views/components-demo/count-to.vue | 218 ++ src/views/components-demo/dnd-list.vue | 39 + src/views/components-demo/drag-dialog.vue | 61 + src/views/components-demo/drag-kanban.vue | 66 + src/views/components-demo/drag-select.vue | 43 + src/views/components-demo/dropzone.vue | 31 + src/views/components-demo/json-editor.vue | 36 + src/views/components-demo/markdown.vue | 101 + src/views/components-demo/mixin.vue | 169 ++ src/views/components-demo/split-pane.vue | 67 + src/views/components-demo/sticky.vue | 135 ++ src/views/components-demo/tinymce.vue | 36 + .../dashboard/admin/components/BarChart.vue | 102 + .../dashboard/admin/components/BoxCard.vue | 118 ++ .../dashboard/admin/components/LineChart.vue | 135 ++ .../dashboard/admin/components/PanelGroup.vue | 181 ++ .../dashboard/admin/components/PieChart.vue | 79 + .../admin/components/RaddarChart.vue | 116 ++ .../admin/components/TodoList/Todo.vue | 81 + .../admin/components/TodoList/index.scss | 320 +++ .../admin/components/TodoList/index.vue | 127 ++ .../admin/components/TransactionTable.vue | 55 + .../admin/components/mixins/resize.js | 55 + src/views/dashboard/admin/index.vue | 120 ++ src/views/dashboard/editor/index.vue | 72 + src/views/dashboard/index.vue | 31 + src/views/documentation/index.vue | 70 + src/views/error-log/components/ErrorTestA.vue | 13 + src/views/error-log/components/ErrorTestB.vue | 11 + src/views/error-log/index.vue | 32 + src/views/error-page/401.vue | 99 + src/views/error-page/404.vue | 228 +++ .../example/components/ArticleDetail.vue | 289 +++ .../example/components/Dropdown/Comment.vue | 41 + .../example/components/Dropdown/Platform.vue | 46 + .../example/components/Dropdown/SourceUrl.vue | 38 + .../example/components/Dropdown/index.js | 3 + src/views/example/components/Warning.vue | 13 + src/views/example/create.vue | 13 + src/views/example/edit.vue | 13 + src/views/example/list.vue | 112 ++ .../excel/components/AutoWidthOption.vue | 34 + src/views/excel/components/BookTypeOption.vue | 39 + src/views/excel/components/FilenameOption.vue | 27 + src/views/excel/export-excel.vue | 116 ++ src/views/excel/merge-header.vue | 101 + src/views/excel/select-excel.vue | 107 + src/views/excel/upload-excel.vue | 42 + src/views/guide/index.vue | 36 + src/views/guide/steps.js | 53 + src/views/icons/element-icons.js | 74 + src/views/icons/index.vue | 101 + src/views/icons/svg-icons.js | 10 + src/views/login/auth-redirect.vue | 15 + src/views/login/components/SocialSignin.vue | 72 + src/views/login/index.vue | 332 +++ src/views/nested/menu1/index.vue | 7 + src/views/nested/menu1/menu1-1/index.vue | 7 + src/views/nested/menu1/menu1-2/index.vue | 7 + .../nested/menu1/menu1-2/menu1-2-1/index.vue | 5 + .../nested/menu1/menu1-2/menu1-2-2/index.vue | 5 + src/views/nested/menu1/menu1-3/index.vue | 5 + src/views/nested/menu2/index.vue | 5 + src/views/pdf/content.js | 58 + src/views/pdf/download.vue | 201 ++ src/views/pdf/index.vue | 13 + .../permission/components/SwitchRoles.vue | 32 + src/views/permission/directive.vue | 111 + src/views/permission/page.vue | 19 + src/views/permission/role.vue | 270 +++ src/views/profile/components/Account.vue | 38 + src/views/profile/components/Activity.vue | 185 ++ src/views/profile/components/Timeline.vue | 48 + src/views/profile/components/UserCard.vue | 133 ++ src/views/profile/index.vue | 65 + src/views/qiniu/upload.vue | 41 + src/views/redirect/index.vue | 12 + src/views/tab/components/TabPane.vue | 103 + src/views/tab/index.vue | 57 + src/views/table/complex-table.vue | 389 ++++ src/views/table/drag-table.vue | 153 ++ .../dynamic-table/components/FixedThead.vue | 62 + .../dynamic-table/components/UnfixedThead.vue | 50 + src/views/table/dynamic-table/index.vue | 24 + src/views/table/inline-edit-table.vue | 149 ++ src/views/theme/index.vue | 120 ++ src/views/zip/index.vue | 77 + tests/unit/.eslintrc.js | 5 + tests/unit/components/Hamburger.spec.js | 18 + tests/unit/components/SvgIcon.spec.js | 22 + tests/unit/utils/formatTime.spec.js | 29 + tests/unit/utils/parseTime.spec.js | 27 + tests/unit/utils/validate.spec.js | 28 + vue.config.js | 139 ++ 297 files changed, 21298 insertions(+) create mode 100644 .editorconfig create mode 100644 .env.development create mode 100644 .env.production create mode 100644 .env.staging create mode 100644 .eslintignore create mode 100644 .eslintrc.js create mode 100644 .gitignore create mode 100644 README.md create mode 100644 babel.config.js create mode 100644 build/index.js create mode 100644 jest.config.js create mode 100644 jsconfig.json create mode 100644 mock/article.js create mode 100644 mock/index.js create mode 100644 mock/mock-server.js create mode 100644 mock/remote-search.js create mode 100644 mock/role/index.js create mode 100644 mock/role/routes.js create mode 100644 mock/user.js create mode 100644 package.json create mode 100644 plop-templates/component/index.hbs create mode 100644 plop-templates/component/prompt.js create mode 100644 plop-templates/utils.js create mode 100644 plop-templates/view/index.hbs create mode 100644 plop-templates/view/prompt.js create mode 100644 plopfile.js create mode 100644 postcss.config.js create mode 100644 public/favicon.ico create mode 100644 public/index.html create mode 100644 src/App.vue create mode 100644 src/api/article.js create mode 100644 src/api/qiniu.js create mode 100644 src/api/remote-search.js create mode 100644 src/api/role.js create mode 100644 src/api/user.js create mode 100644 src/assets/401_images/401.gif create mode 100644 src/assets/404_images/404.png create mode 100644 src/assets/404_images/404_cloud.png create mode 100644 src/assets/custom-theme/fonts/element-icons.ttf create mode 100644 src/assets/custom-theme/fonts/element-icons.woff create mode 100644 src/assets/custom-theme/index.css create mode 100644 src/assets/logo/join_logo.png create mode 100644 src/assets/logo/joinlogosquare.png create mode 100644 src/components/BackToTop/index.vue create mode 100644 src/components/Breadcrumb/index.vue create mode 100644 src/components/Charts/Keyboard.vue create mode 100644 src/components/Charts/LineMarker.vue create mode 100644 src/components/Charts/MixChart.vue create mode 100644 src/components/Charts/mixins/resize.js create mode 100644 src/components/DndList/index.vue create mode 100644 src/components/DragSelect/index.vue create mode 100644 src/components/Dropzone/index.vue create mode 100644 src/components/ErrorLog/index.vue create mode 100644 src/components/GithubCorner/index.vue create mode 100644 src/components/Hamburger/index.vue create mode 100644 src/components/HeaderSearch/index.vue create mode 100644 src/components/ImageCropper/index.vue create mode 100755 src/components/ImageCropper/utils/data2blob.js create mode 100755 src/components/ImageCropper/utils/effectRipple.js create mode 100755 src/components/ImageCropper/utils/language.js create mode 100755 src/components/ImageCropper/utils/mimes.js create mode 100644 src/components/JsonEditor/index.vue create mode 100644 src/components/Kanban/index.vue create mode 100644 src/components/MDinput/index.vue create mode 100644 src/components/MarkdownEditor/default-options.js create mode 100644 src/components/MarkdownEditor/index.vue create mode 100644 src/components/Pagination/index.vue create mode 100644 src/components/PanThumb/index.vue create mode 100644 src/components/RightPanel/index.vue create mode 100644 src/components/Screenfull/index.vue create mode 100644 src/components/Share/DropdownMenu.vue create mode 100644 src/components/SizeSelect/index.vue create mode 100644 src/components/Sticky/index.vue create mode 100644 src/components/SvgIcon/index.vue create mode 100644 src/components/TextHoverEffect/Mallki.vue create mode 100644 src/components/ThemePicker/index.vue create mode 100644 src/components/Tinymce/components/EditorImage.vue create mode 100644 src/components/Tinymce/dynamicLoadScript.js create mode 100644 src/components/Tinymce/index.vue create mode 100644 src/components/Tinymce/plugins.js create mode 100644 src/components/Tinymce/toolbar.js create mode 100644 src/components/Upload/SingleImage.vue create mode 100644 src/components/Upload/SingleImage2.vue create mode 100644 src/components/Upload/SingleImage3.vue create mode 100644 src/components/UploadExcel/index.vue create mode 100644 src/directive/clipboard/clipboard.js create mode 100644 src/directive/clipboard/index.js create mode 100644 src/directive/el-drag-dialog/drag.js create mode 100644 src/directive/el-drag-dialog/index.js create mode 100644 src/directive/el-table/adaptive.js create mode 100644 src/directive/el-table/index.js create mode 100644 src/directive/permission/index.js create mode 100644 src/directive/permission/permission.js create mode 100644 src/directive/sticky.js create mode 100644 src/directive/waves/index.js create mode 100644 src/directive/waves/waves.css create mode 100644 src/directive/waves/waves.js create mode 100644 src/filters/index.js create mode 100644 src/icons/index.js create mode 100644 src/icons/svg/404.svg create mode 100644 src/icons/svg/bug.svg create mode 100644 src/icons/svg/chart.svg create mode 100644 src/icons/svg/clipboard.svg create mode 100644 src/icons/svg/component.svg create mode 100644 src/icons/svg/dashboard.svg create mode 100644 src/icons/svg/documentation.svg create mode 100644 src/icons/svg/drag.svg create mode 100644 src/icons/svg/edit.svg create mode 100644 src/icons/svg/education.svg create mode 100644 src/icons/svg/email.svg create mode 100644 src/icons/svg/example.svg create mode 100644 src/icons/svg/excel.svg create mode 100644 src/icons/svg/exit-fullscreen.svg create mode 100644 src/icons/svg/eye-open.svg create mode 100644 src/icons/svg/eye.svg create mode 100644 src/icons/svg/form.svg create mode 100644 src/icons/svg/fullscreen.svg create mode 100644 src/icons/svg/guide.svg create mode 100644 src/icons/svg/icon.svg create mode 100644 src/icons/svg/international.svg create mode 100644 src/icons/svg/language.svg create mode 100644 src/icons/svg/link.svg create mode 100644 src/icons/svg/list.svg create mode 100644 src/icons/svg/lock.svg create mode 100644 src/icons/svg/message.svg create mode 100644 src/icons/svg/money.svg create mode 100644 src/icons/svg/nested.svg create mode 100644 src/icons/svg/password.svg create mode 100644 src/icons/svg/pdf.svg create mode 100644 src/icons/svg/people.svg create mode 100644 src/icons/svg/peoples.svg create mode 100644 src/icons/svg/qq.svg create mode 100644 src/icons/svg/search.svg create mode 100644 src/icons/svg/shopping.svg create mode 100644 src/icons/svg/size.svg create mode 100644 src/icons/svg/skill.svg create mode 100644 src/icons/svg/star.svg create mode 100644 src/icons/svg/tab.svg create mode 100644 src/icons/svg/table.svg create mode 100644 src/icons/svg/theme.svg create mode 100644 src/icons/svg/tree-table.svg create mode 100644 src/icons/svg/tree.svg create mode 100644 src/icons/svg/user.svg create mode 100644 src/icons/svg/wechat.svg create mode 100644 src/icons/svg/zip.svg create mode 100644 src/icons/svgo.yml create mode 100644 src/layout/components/AppMain.vue create mode 100644 src/layout/components/Navbar.vue create mode 100644 src/layout/components/Settings/index.vue create mode 100644 src/layout/components/Sidebar/FixiOSBug.js create mode 100644 src/layout/components/Sidebar/Item.vue create mode 100644 src/layout/components/Sidebar/Link.vue create mode 100644 src/layout/components/Sidebar/Logo.vue create mode 100644 src/layout/components/Sidebar/SidebarItem.vue create mode 100644 src/layout/components/Sidebar/index.vue create mode 100644 src/layout/components/TagsView/ScrollPane.vue create mode 100644 src/layout/components/TagsView/index.vue create mode 100644 src/layout/components/index.js create mode 100644 src/layout/index.vue create mode 100644 src/layout/mixin/ResizeHandler.js create mode 100644 src/main.js create mode 100644 src/permission.js create mode 100644 src/router/index.js create mode 100644 src/router/modules/charts.js create mode 100644 src/router/modules/components.js create mode 100644 src/router/modules/nested.js create mode 100644 src/router/modules/table.js create mode 100644 src/settings.js create mode 100644 src/store/getters.js create mode 100644 src/store/index.js create mode 100644 src/store/modules/app.js create mode 100644 src/store/modules/errorLog.js create mode 100644 src/store/modules/permission.js create mode 100644 src/store/modules/settings.js create mode 100644 src/store/modules/tagsView.js create mode 100644 src/store/modules/user.js create mode 100644 src/styles/btn.scss create mode 100644 src/styles/element-ui.scss create mode 100644 src/styles/element-variables.scss create mode 100644 src/styles/index.scss create mode 100644 src/styles/mixin.scss create mode 100644 src/styles/sidebar.scss create mode 100644 src/styles/transition.scss create mode 100644 src/styles/variables.scss create mode 100644 src/utils/auth.js create mode 100644 src/utils/clipboard.js create mode 100644 src/utils/error-log.js create mode 100644 src/utils/get-page-title.js create mode 100644 src/utils/index.js create mode 100644 src/utils/open-window.js create mode 100644 src/utils/permission.js create mode 100644 src/utils/request.js create mode 100644 src/utils/scroll-to.js create mode 100644 src/utils/validate.js create mode 100644 src/vendor/Export2Excel.js create mode 100644 src/vendor/Export2Zip.js create mode 100644 src/views/charts/keyboard.vue create mode 100644 src/views/charts/line.vue create mode 100644 src/views/charts/mix-chart.vue create mode 100644 src/views/chatbot/index.vue create mode 100644 src/views/clipboard/index.vue create mode 100644 src/views/components-demo/avatar-upload.vue create mode 100644 src/views/components-demo/back-to-top.vue create mode 100644 src/views/components-demo/count-to.vue create mode 100644 src/views/components-demo/dnd-list.vue create mode 100644 src/views/components-demo/drag-dialog.vue create mode 100644 src/views/components-demo/drag-kanban.vue create mode 100644 src/views/components-demo/drag-select.vue create mode 100644 src/views/components-demo/dropzone.vue create mode 100644 src/views/components-demo/json-editor.vue create mode 100644 src/views/components-demo/markdown.vue create mode 100644 src/views/components-demo/mixin.vue create mode 100644 src/views/components-demo/split-pane.vue create mode 100644 src/views/components-demo/sticky.vue create mode 100644 src/views/components-demo/tinymce.vue create mode 100644 src/views/dashboard/admin/components/BarChart.vue create mode 100644 src/views/dashboard/admin/components/BoxCard.vue create mode 100644 src/views/dashboard/admin/components/LineChart.vue create mode 100644 src/views/dashboard/admin/components/PanelGroup.vue create mode 100644 src/views/dashboard/admin/components/PieChart.vue create mode 100644 src/views/dashboard/admin/components/RaddarChart.vue create mode 100644 src/views/dashboard/admin/components/TodoList/Todo.vue create mode 100644 src/views/dashboard/admin/components/TodoList/index.scss create mode 100644 src/views/dashboard/admin/components/TodoList/index.vue create mode 100644 src/views/dashboard/admin/components/TransactionTable.vue create mode 100644 src/views/dashboard/admin/components/mixins/resize.js create mode 100644 src/views/dashboard/admin/index.vue create mode 100644 src/views/dashboard/editor/index.vue create mode 100644 src/views/dashboard/index.vue create mode 100644 src/views/documentation/index.vue create mode 100644 src/views/error-log/components/ErrorTestA.vue create mode 100644 src/views/error-log/components/ErrorTestB.vue create mode 100644 src/views/error-log/index.vue create mode 100644 src/views/error-page/401.vue create mode 100644 src/views/error-page/404.vue create mode 100644 src/views/example/components/ArticleDetail.vue create mode 100644 src/views/example/components/Dropdown/Comment.vue create mode 100644 src/views/example/components/Dropdown/Platform.vue create mode 100644 src/views/example/components/Dropdown/SourceUrl.vue create mode 100644 src/views/example/components/Dropdown/index.js create mode 100644 src/views/example/components/Warning.vue create mode 100644 src/views/example/create.vue create mode 100644 src/views/example/edit.vue create mode 100644 src/views/example/list.vue create mode 100644 src/views/excel/components/AutoWidthOption.vue create mode 100644 src/views/excel/components/BookTypeOption.vue create mode 100644 src/views/excel/components/FilenameOption.vue create mode 100644 src/views/excel/export-excel.vue create mode 100644 src/views/excel/merge-header.vue create mode 100644 src/views/excel/select-excel.vue create mode 100644 src/views/excel/upload-excel.vue create mode 100644 src/views/guide/index.vue create mode 100644 src/views/guide/steps.js create mode 100644 src/views/icons/element-icons.js create mode 100644 src/views/icons/index.vue create mode 100644 src/views/icons/svg-icons.js create mode 100644 src/views/login/auth-redirect.vue create mode 100644 src/views/login/components/SocialSignin.vue create mode 100644 src/views/login/index.vue create mode 100644 src/views/nested/menu1/index.vue create mode 100644 src/views/nested/menu1/menu1-1/index.vue create mode 100644 src/views/nested/menu1/menu1-2/index.vue create mode 100644 src/views/nested/menu1/menu1-2/menu1-2-1/index.vue create mode 100644 src/views/nested/menu1/menu1-2/menu1-2-2/index.vue create mode 100644 src/views/nested/menu1/menu1-3/index.vue create mode 100644 src/views/nested/menu2/index.vue create mode 100644 src/views/pdf/content.js create mode 100644 src/views/pdf/download.vue create mode 100644 src/views/pdf/index.vue create mode 100644 src/views/permission/components/SwitchRoles.vue create mode 100644 src/views/permission/directive.vue create mode 100644 src/views/permission/page.vue create mode 100644 src/views/permission/role.vue create mode 100644 src/views/profile/components/Account.vue create mode 100644 src/views/profile/components/Activity.vue create mode 100644 src/views/profile/components/Timeline.vue create mode 100644 src/views/profile/components/UserCard.vue create mode 100644 src/views/profile/index.vue create mode 100644 src/views/qiniu/upload.vue create mode 100644 src/views/redirect/index.vue create mode 100644 src/views/tab/components/TabPane.vue create mode 100644 src/views/tab/index.vue create mode 100644 src/views/table/complex-table.vue create mode 100644 src/views/table/drag-table.vue create mode 100644 src/views/table/dynamic-table/components/FixedThead.vue create mode 100644 src/views/table/dynamic-table/components/UnfixedThead.vue create mode 100644 src/views/table/dynamic-table/index.vue create mode 100644 src/views/table/inline-edit-table.vue create mode 100644 src/views/theme/index.vue create mode 100644 src/views/zip/index.vue create mode 100644 tests/unit/.eslintrc.js create mode 100644 tests/unit/components/Hamburger.spec.js create mode 100644 tests/unit/components/SvgIcon.spec.js create mode 100644 tests/unit/utils/formatTime.spec.js create mode 100644 tests/unit/utils/parseTime.spec.js create mode 100644 tests/unit/utils/validate.spec.js create mode 100644 vue.config.js diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3454886 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..8f5856d --- /dev/null +++ b/.env.development @@ -0,0 +1,14 @@ +# just a flag +ENV = 'development' + +# base api +VUE_APP_BASE_API = '/dev-api' + +# vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable, +# to control whether the babel-plugin-dynamic-import-node plugin is enabled. +# It only does one thing by converting all import() to require(). +# This configuration can significantly increase the speed of hot updates, +# when you have a large number of pages. +# Detail: https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js + +VUE_CLI_BABEL_TRANSPILE_MODULES = true diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..80c8103 --- /dev/null +++ b/.env.production @@ -0,0 +1,6 @@ +# just a flag +ENV = 'production' + +# base api +VUE_APP_BASE_API = '/prod-api' + diff --git a/.env.staging b/.env.staging new file mode 100644 index 0000000..a8793a0 --- /dev/null +++ b/.env.staging @@ -0,0 +1,8 @@ +NODE_ENV = production + +# just a flag +ENV = 'staging' + +# base api +VUE_APP_BASE_API = '/stage-api' + diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..e6529fc --- /dev/null +++ b/.eslintignore @@ -0,0 +1,4 @@ +build/*.js +src/assets +public +dist diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..c977505 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,198 @@ +module.exports = { + root: true, + parserOptions: { + parser: 'babel-eslint', + sourceType: 'module' + }, + env: { + browser: true, + node: true, + es6: true, + }, + extends: ['plugin:vue/recommended', 'eslint:recommended'], + + // add your custom rules here + //it is base on https://github.com/vuejs/eslint-config-vue + rules: { + "vue/max-attributes-per-line": [2, { + "singleline": 10, + "multiline": { + "max": 1, + "allowFirstLine": false + } + }], + "vue/singleline-html-element-content-newline": "off", + "vue/multiline-html-element-content-newline":"off", + "vue/name-property-casing": ["error", "PascalCase"], + "vue/no-v-html": "off", + 'accessor-pairs': 2, + 'arrow-spacing': [2, { + 'before': true, + 'after': true + }], + 'block-spacing': [2, 'always'], + 'brace-style': [2, '1tbs', { + 'allowSingleLine': true + }], + 'camelcase': [0, { + 'properties': 'always' + }], + 'comma-dangle': [2, 'never'], + 'comma-spacing': [2, { + 'before': false, + 'after': true + }], + 'comma-style': [2, 'last'], + 'constructor-super': 2, + 'curly': [2, 'multi-line'], + 'dot-location': [2, 'property'], + 'eol-last': 2, + 'eqeqeq': ["error", "always", {"null": "ignore"}], + 'generator-star-spacing': [2, { + 'before': true, + 'after': true + }], + 'handle-callback-err': [2, '^(err|error)$'], + 'indent': [2, 2, { + 'SwitchCase': 1 + }], + 'jsx-quotes': [2, 'prefer-single'], + 'key-spacing': [2, { + 'beforeColon': false, + 'afterColon': true + }], + 'keyword-spacing': [2, { + 'before': true, + 'after': true + }], + 'new-cap': [2, { + 'newIsCap': true, + 'capIsNew': false + }], + 'new-parens': 2, + 'no-array-constructor': 2, + 'no-caller': 2, + 'no-console': 'off', + 'no-class-assign': 2, + 'no-cond-assign': 2, + 'no-const-assign': 2, + 'no-control-regex': 0, + 'no-delete-var': 2, + 'no-dupe-args': 2, + 'no-dupe-class-members': 2, + 'no-dupe-keys': 2, + 'no-duplicate-case': 2, + 'no-empty-character-class': 2, + 'no-empty-pattern': 2, + 'no-eval': 2, + 'no-ex-assign': 2, + 'no-extend-native': 2, + 'no-extra-bind': 2, + 'no-extra-boolean-cast': 2, + 'no-extra-parens': [2, 'functions'], + 'no-fallthrough': 2, + 'no-floating-decimal': 2, + 'no-func-assign': 2, + 'no-implied-eval': 2, + 'no-inner-declarations': [2, 'functions'], + 'no-invalid-regexp': 2, + 'no-irregular-whitespace': 2, + 'no-iterator': 2, + 'no-label-var': 2, + 'no-labels': [2, { + 'allowLoop': false, + 'allowSwitch': false + }], + 'no-lone-blocks': 2, + 'no-mixed-spaces-and-tabs': 2, + 'no-multi-spaces': 2, + 'no-multi-str': 2, + 'no-multiple-empty-lines': [2, { + 'max': 1 + }], + 'no-native-reassign': 2, + 'no-negated-in-lhs': 2, + 'no-new-object': 2, + 'no-new-require': 2, + 'no-new-symbol': 2, + 'no-new-wrappers': 2, + 'no-obj-calls': 2, + 'no-octal': 2, + 'no-octal-escape': 2, + 'no-path-concat': 2, + 'no-proto': 2, + 'no-redeclare': 2, + 'no-regex-spaces': 2, + 'no-return-assign': [2, 'except-parens'], + 'no-self-assign': 2, + 'no-self-compare': 2, + 'no-sequences': 2, + 'no-shadow-restricted-names': 2, + 'no-spaced-func': 2, + 'no-sparse-arrays': 2, + 'no-this-before-super': 2, + 'no-throw-literal': 2, + 'no-trailing-spaces': 2, + 'no-undef': 2, + 'no-undef-init': 2, + 'no-unexpected-multiline': 2, + 'no-unmodified-loop-condition': 2, + 'no-unneeded-ternary': [2, { + 'defaultAssignment': false + }], + 'no-unreachable': 2, + 'no-unsafe-finally': 2, + 'no-unused-vars': [2, { + 'vars': 'all', + 'args': 'none' + }], + 'no-useless-call': 2, + 'no-useless-computed-key': 2, + 'no-useless-constructor': 2, + 'no-useless-escape': 0, + 'no-whitespace-before-property': 2, + 'no-with': 2, + 'one-var': [2, { + 'initialized': 'never' + }], + 'operator-linebreak': [2, 'after', { + 'overrides': { + '?': 'before', + ':': 'before' + } + }], + 'padded-blocks': [2, 'never'], + 'quotes': [2, 'single', { + 'avoidEscape': true, + 'allowTemplateLiterals': true + }], + 'semi': [2, 'never'], + 'semi-spacing': [2, { + 'before': false, + 'after': true + }], + 'space-before-blocks': [2, 'always'], + 'space-before-function-paren': [2, 'never'], + 'space-in-parens': [2, 'never'], + 'space-infix-ops': 2, + 'space-unary-ops': [2, { + 'words': true, + 'nonwords': false + }], + 'spaced-comment': [2, 'always', { + 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ','] + }], + 'template-curly-spacing': [2, 'never'], + 'use-isnan': 2, + 'valid-typeof': 2, + 'wrap-iife': [2, 'any'], + 'yield-star-spacing': [2, 'both'], + 'yoda': [2, 'never'], + 'prefer-const': 2, + 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, + 'object-curly-spacing': [2, 'always', { + objectsInObjects: false + }], + 'array-bracket-spacing': [2, 'never'] + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..78a752d --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +.DS_Store +node_modules/ +dist/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +**/*.log + +tests/**/coverage/ +tests/e2e/reports +selenium-debug.log + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.local + +package-lock.json +yarn.lock diff --git a/README.md b/README.md new file mode 100644 index 0000000..a6a1044 --- /dev/null +++ b/README.md @@ -0,0 +1,217 @@ +

+ +

+ +

+ + vue + + + element-ui + + + Build Status + + + license + + + GitHub release + + + gitter + + + donate + +

+ +English | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md) | [Spanish](./README.es.md) + +## Introduction + +[vue-element-admin](https://panjiachen.github.io/vue-element-admin) is a production-ready front-end solution for admin interfaces. It is based on [vue](https://github.com/vuejs/vue) and uses the UI Toolkit [element-ui](https://github.com/ElemeFE/element). + +[vue-element-admin](https://panjiachen.github.io/vue-element-admin) is based on the newest development stack of vue and it has a built-in i18n solution, typical templates for enterprise applications, and lots of awesome features. It helps you build large and complex Single-Page Applications. I believe whatever your needs are, this project will help you. + +- [Preview](https://panjiachen.github.io/vue-element-admin) + +- [Documentation](https://panjiachen.github.io/vue-element-admin-site/) + +- [Gitter](https://gitter.im/vue-element-admin/discuss) + +- [Donate](https://panjiachen.github.io/vue-element-admin-site/donate/) + +- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki) + +- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览 + +- Base template recommends using: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template) +- Desktop: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin) +- Typescript: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour)) +- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312) + +**After the `v4.1.0+` version, the default master branch will not support i18n. Please use [i18n Branch](https://github.com/PanJiaChen/vue-element-admin/tree/i18n), it will keep up with the master update** + +**The current version is `v4.0+` build on `vue-cli`. If you find a problem, please put [issue](https://github.com/PanJiaChen/vue-element-admin/issues/new). If you want to use the old version , you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0), it does not rely on `vue-cli`** + +**This project does not support low version browsers (e.g. IE). Please add polyfill by yourself.** + +## Preparation + +You need to install [node](https://nodejs.org/) and [git](https://git-scm.com/) locally. The project is based on [ES2015+](https://es6.ruanyifeng.com/), [vue](https://cn.vuejs.org/index.html), [vuex](https://vuex.vuejs.org/zh-cn/), [vue-router](https://router.vuejs.org/zh-cn/), [vue-cli](https://github.com/vuejs/vue-cli) , [axios](https://github.com/axios/axios) and [element-ui](https://github.com/ElemeFE/element), all request data is simulated using [Mock.js](https://github.com/nuysoft/Mock). +Understanding and learning this knowledge in advance will greatly help the use of this project. + +

+ +

+ +## Sponsors + +Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor]](https://www.patreon.com/panjiachen) + +

Admin Dashboard Templates made with Vue, React and Angular.

+ +## Features + +``` +- Login / Logout + +- Permission Authentication + - Page permission + - Directive permission + - Permission configuration page + - Two-step login + +- Multi-environment build + - dev sit stage prod + +- Global Features + - I18n + - Multiple dynamic themes + - Dynamic sidebar (supports multi-level routing) + - Dynamic breadcrumb + - Tags-view (Tab page Support right-click operation) + - Svg Sprite + - Mock data + - Screenfull + - Responsive Sidebar + +- Editor + - Rich Text Editor + - Markdown Editor + - JSON Editor + +- Excel + - Export Excel + - Upload Excel + - Visualization Excel + - Export zip + +- Table + - Dynamic Table + - Drag And Drop Table + - Inline Edit Table + +- Error Page + - 401 + - 404 + +- Components + - Avatar Upload + - Back To Top + - Drag Dialog + - Drag Select + - Drag Kanban + - Drag List + - SplitPane + - Dropzone + - Sticky + - CountTo + +- Advanced Example +- Error Log +- Dashboard +- Guide Page +- ECharts +- Clipboard +- Markdown to html +``` + +## Getting started + +```bash +# clone the project +git clone https://github.com/PanJiaChen/vue-element-admin.git + +# enter the project directory +cd vue-element-admin + +# install dependency +npm install + +# develop +npm run dev +``` + +This will automatically open http://localhost:9527 + +## Build + +```bash +# build for test environment +npm run build:stage + +# build for production environment +npm run build:prod +``` + +## Advanced + +```bash +# preview the release environment effect +npm run preview + +# preview the release environment effect + static resource analysis +npm run preview -- --report + +# code format check +npm run lint + +# code format check and auto fix +npm run lint -- --fix +``` + +Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) for more information + +## Changelog + +Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases). + +## Online Demo + +[Preview](https://panjiachen.github.io/vue-element-admin) + +## Donate + +If you find this project useful, you can buy author a glass of juice :tropical_drink: + +![donate](https://wpimg.wallstcn.com/bd273f0d-83a0-4ef2-92e1-9ac8ed3746b9.png) + +[Paypal Me](https://www.paypal.me/panfree23) + +[Buy me a coffee](https://www.buymeacoffee.com/Pan) + +## Browsers support + +Modern browsers and Internet Explorer 10+. + +| [IE / Edge](https://godban.github.io/browsers-support-badges/)
IE / Edge | [Firefox](https://godban.github.io/browsers-support-badges/)
Firefox | [Chrome](https://godban.github.io/browsers-support-badges/)
Chrome | [Safari](https://godban.github.io/browsers-support-badges/)
Safari | +| --------- | --------- | --------- | --------- | +| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions + +## License + +[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE) + +Copyright (c) 2017-present PanJiaChen diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..ba17966 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: [ + '@vue/app' + ] +} diff --git a/build/index.js b/build/index.js new file mode 100644 index 0000000..0c57de2 --- /dev/null +++ b/build/index.js @@ -0,0 +1,35 @@ +const { run } = require('runjs') +const chalk = require('chalk') +const config = require('../vue.config.js') +const rawArgv = process.argv.slice(2) +const args = rawArgv.join(' ') + +if (process.env.npm_config_preview || rawArgv.includes('--preview')) { + const report = rawArgv.includes('--report') + + run(`vue-cli-service build ${args}`) + + const port = 9526 + const publicPath = config.publicPath + + var connect = require('connect') + var serveStatic = require('serve-static') + const app = connect() + + app.use( + publicPath, + serveStatic('./dist', { + index: ['index.html', '/'] + }) + ) + + app.listen(port, function () { + console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`)) + if (report) { + console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`)) + } + + }) +} else { + run(`vue-cli-service build ${args}`) +} diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..143cdc8 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,24 @@ +module.exports = { + moduleFileExtensions: ['js', 'jsx', 'json', 'vue'], + transform: { + '^.+\\.vue$': 'vue-jest', + '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': + 'jest-transform-stub', + '^.+\\.jsx?$': 'babel-jest' + }, + moduleNameMapper: { + '^@/(.*)$': '/src/$1' + }, + snapshotSerializers: ['jest-serializer-vue'], + testMatch: [ + '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' + ], + collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'], + coverageDirectory: '/tests/unit/coverage', + // 'collectCoverage': true, + 'coverageReporters': [ + 'lcov', + 'text-summary' + ], + testURL: 'http://localhost/' +} diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..958df04 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "baseUrl": "./", + "paths": { + "@/*": ["src/*"] + } + }, + "exclude": ["node_modules", "dist"] +} \ No newline at end of file diff --git a/mock/article.js b/mock/article.js new file mode 100644 index 0000000..bc236eb --- /dev/null +++ b/mock/article.js @@ -0,0 +1,116 @@ +import Mock from 'mockjs' + +const List = [] +const count = 100 + +const baseContent = '

I am testing data, I am testing data.

' +const image_uri = 'https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3' + +for (let i = 0; i < count; i++) { + List.push(Mock.mock({ + id: '@increment', + timestamp: +Mock.Random.date('T'), + author: '@first', + reviewer: '@first', + title: '@title(5, 10)', + content_short: 'mock data', + content: baseContent, + forecast: '@float(0, 100, 2, 2)', + importance: '@integer(1, 3)', + 'type|1': ['CN', 'US', 'JP', 'EU'], + 'status|1': ['published', 'draft', 'deleted'], + display_time: '@datetime', + comment_disabled: true, + pageviews: '@integer(300, 5000)', + image_uri, + platforms: ['a-platform'] + })) +} + +export default [ + { + url: '/article/list', + type: 'get', + response: config => { + const { importance, type, title, page = 1, limit = 20, sort } = config.query + + let mockList = List.filter(item => { + if (importance && item.importance !== +importance) return false + if (type && item.type !== type) return false + if (title && item.title.indexOf(title) < 0) return false + return true + }) + + if (sort === '-id') { + mockList = mockList.reverse() + } + + const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1)) + + return { + code: 20000, + data: { + total: mockList.length, + items: pageList + } + } + } + }, + + { + url: '/article/detail', + type: 'get', + response: config => { + const { id } = config.query + for (const article of List) { + if (article.id === +id) { + return { + code: 20000, + data: article + } + } + } + } + }, + + { + url: '/article/pv', + type: 'get', + response: _ => { + return { + code: 20000, + data: { + pvData: [ + { key: 'PC', pv: 1024 }, + { key: 'mobile', pv: 1024 }, + { key: 'ios', pv: 1024 }, + { key: 'android', pv: 1024 } + ] + } + } + } + }, + + { + url: '/article/create', + type: 'post', + response: _ => { + return { + code: 20000, + data: 'success' + } + } + }, + + { + url: '/article/update', + type: 'post', + response: _ => { + return { + code: 20000, + data: 'success' + } + } + } +] + diff --git a/mock/index.js b/mock/index.js new file mode 100644 index 0000000..6907e86 --- /dev/null +++ b/mock/index.js @@ -0,0 +1,70 @@ +import Mock from 'mockjs' +import { param2Obj } from '../src/utils' + +import user from './user' +import role from './role' +import article from './article' +import search from './remote-search' + +const mocks = [ + ...user, + ...role, + ...article, + ...search +] + +// for front mock +// please use it cautiously, it will redefine XMLHttpRequest, +// which will cause many of your third-party libraries to be invalidated(like progress event). +export function mockXHR() { + // mock patch + // https://github.com/nuysoft/Mock/issues/300 + Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send + Mock.XHR.prototype.send = function() { + if (this.custom.xhr) { + this.custom.xhr.withCredentials = this.withCredentials || false + + if (this.responseType) { + this.custom.xhr.responseType = this.responseType + } + } + this.proxy_send(...arguments) + } + + function XHR2ExpressReqWrap(respond) { + return function(options) { + let result = null + if (respond instanceof Function) { + const { body, type, url } = options + // https://expressjs.com/en/4x/api.html#req + result = respond({ + method: type, + body: JSON.parse(body), + query: param2Obj(url) + }) + } else { + result = respond + } + return Mock.mock(result) + } + } + + for (const i of mocks) { + Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response)) + } +} + +// for mock server +const responseFake = (url, type, respond) => { + return { + url: new RegExp(`/mock${url}`), + type: type || 'get', + response(req, res) { + res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond)) + } + } +} + +export default mocks.map(route => { + return responseFake(route.url, route.type, route.response) +}) diff --git a/mock/mock-server.js b/mock/mock-server.js new file mode 100644 index 0000000..4c4cb2a --- /dev/null +++ b/mock/mock-server.js @@ -0,0 +1,68 @@ +const chokidar = require('chokidar') +const bodyParser = require('body-parser') +const chalk = require('chalk') +const path = require('path') + +const mockDir = path.join(process.cwd(), 'mock') + +function registerRoutes(app) { + let mockLastIndex + const { default: mocks } = require('./index.js') + for (const mock of mocks) { + app[mock.type](mock.url, mock.response) + mockLastIndex = app._router.stack.length + } + const mockRoutesLength = Object.keys(mocks).length + return { + mockRoutesLength: mockRoutesLength, + mockStartIndex: mockLastIndex - mockRoutesLength + } +} + +function unregisterRoutes() { + Object.keys(require.cache).forEach(i => { + if (i.includes(mockDir)) { + delete require.cache[require.resolve(i)] + } + }) +} + +module.exports = app => { + // es6 polyfill + require('@babel/register') + + // parse app.body + // https://expressjs.com/en/4x/api.html#req.body + app.use(bodyParser.json()) + app.use(bodyParser.urlencoded({ + extended: true + })) + + const mockRoutes = registerRoutes(app) + var mockRoutesLength = mockRoutes.mockRoutesLength + var mockStartIndex = mockRoutes.mockStartIndex + + // watch files, hot reload mock server + chokidar.watch(mockDir, { + ignored: /mock-server/, + ignoreInitial: true + }).on('all', (event, path) => { + if (event === 'change' || event === 'add') { + try { + // remove mock routes stack + app._router.stack.splice(mockStartIndex, mockRoutesLength) + + // clear routes cache + unregisterRoutes() + + const mockRoutes = registerRoutes(app) + mockRoutesLength = mockRoutes.mockRoutesLength + mockStartIndex = mockRoutes.mockStartIndex + + console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`)) + } catch (error) { + console.log(chalk.redBright(error)) + } + } + }) +} diff --git a/mock/remote-search.js b/mock/remote-search.js new file mode 100644 index 0000000..bb33c2f --- /dev/null +++ b/mock/remote-search.js @@ -0,0 +1,51 @@ +import Mock from 'mockjs' + +const NameList = [] +const count = 100 + +for (let i = 0; i < count; i++) { + NameList.push(Mock.mock({ + name: '@first' + })) +} +NameList.push({ name: 'mock-Pan' }) + +export default [ + // username search + { + url: '/search/user', + type: 'get', + response: config => { + const { name } = config.query + const mockNameList = NameList.filter(item => { + const lowerCaseName = item.name.toLowerCase() + return !(name && lowerCaseName.indexOf(name.toLowerCase()) < 0) + }) + return { + code: 20000, + data: { items: mockNameList } + } + } + }, + + // transaction list + { + url: '/transaction/list', + type: 'get', + response: _ => { + return { + code: 20000, + data: { + total: 20, + 'items|20': [{ + order_no: '@guid()', + timestamp: +Mock.Random.date('T'), + username: '@name()', + price: '@float(1000, 15000, 0, 2)', + 'status|1': ['success', 'pending'] + }] + } + } + } + } +] diff --git a/mock/role/index.js b/mock/role/index.js new file mode 100644 index 0000000..3914807 --- /dev/null +++ b/mock/role/index.js @@ -0,0 +1,98 @@ +import Mock from 'mockjs' +import { deepClone } from '../../src/utils/index.js' +import { asyncRoutes, constantRoutes } from './routes.js' + +const routes = deepClone([...constantRoutes, ...asyncRoutes]) + +const roles = [ + { + key: 'admin', + name: 'admin', + description: 'Super Administrator. Have access to view all pages.', + routes: routes + }, + { + key: 'editor', + name: 'editor', + description: 'Normal Editor. Can see all pages except permission page', + routes: routes.filter(i => i.path !== '/permission')// just a mock + }, + { + key: 'visitor', + name: 'visitor', + description: 'Just a visitor. Can only see the home page and the document page', + routes: [{ + path: '', + redirect: 'dashboard', + children: [ + { + path: 'dashboard', + name: 'Dashboard', + meta: { title: 'dashboard', icon: 'dashboard' } + } + ] + }] + } +] + +export default [ + // mock get all routes form server + { + url: '/routes', + type: 'get', + response: _ => { + return { + code: 20000, + data: routes + } + } + }, + + // mock get all roles form server + { + url: '/roles', + type: 'get', + response: _ => { + return { + code: 20000, + data: roles + } + } + }, + + // add role + { + url: '/role', + type: 'post', + response: { + code: 20000, + data: { + key: Mock.mock('@integer(300, 5000)') + } + } + }, + + // update role + { + url: '/role/[A-Za-z0-9]', + type: 'put', + response: { + code: 20000, + data: { + status: 'success' + } + } + }, + + // delete role + { + url: '/role/[A-Za-z0-9]', + type: 'delete', + response: { + code: 20000, + data: { + status: 'success' + } + } + } +] diff --git a/mock/role/routes.js b/mock/role/routes.js new file mode 100644 index 0000000..d718919 --- /dev/null +++ b/mock/role/routes.js @@ -0,0 +1,525 @@ +// Just a mock data + +export const constantRoutes = [ + { + path: '/redirect', + component: 'layout/Layout', + hidden: true, + children: [ + { + path: '/redirect/:path*', + component: 'views/redirect/index' + } + ] + }, + { + path: '/login', + component: 'views/login/index', + hidden: true + }, + { + path: '/auth-redirect', + component: 'views/login/auth-redirect', + hidden: true + }, + { + path: '/404', + component: 'views/error-page/404', + hidden: true + }, + { + path: '/401', + component: 'views/error-page/401', + hidden: true + }, + { + path: '', + component: 'layout/Layout', + redirect: 'dashboard', + children: [ + { + path: 'dashboard', + component: 'views/dashboard/index', + name: 'Dashboard', + meta: { title: 'Dashboard', icon: 'dashboard', affix: true } + } + ] + }, + { + path: '/documentation', + component: 'layout/Layout', + children: [ + { + path: 'index', + component: 'views/documentation/index', + name: 'Documentation', + meta: { title: 'Documentation', icon: 'documentation', affix: true } + } + ] + }, + { + path: '/guide', + component: 'layout/Layout', + redirect: '/guide/index', + children: [ + { + path: 'index', + component: 'views/guide/index', + name: 'Guide', + meta: { title: 'Guide', icon: 'guide', noCache: true } + } + ] + } +] + +export const asyncRoutes = [ + { + path: '/permission', + component: 'layout/Layout', + redirect: '/permission/index', + alwaysShow: true, + meta: { + title: 'Permission', + icon: 'lock', + roles: ['admin', 'editor'] + }, + children: [ + { + path: 'page', + component: 'views/permission/page', + name: 'PagePermission', + meta: { + title: 'Page Permission', + roles: ['admin'] + } + }, + { + path: 'directive', + component: 'views/permission/directive', + name: 'DirectivePermission', + meta: { + title: 'Directive Permission' + } + }, + { + path: 'role', + component: 'views/permission/role', + name: 'RolePermission', + meta: { + title: 'Role Permission', + roles: ['admin'] + } + } + ] + }, + + { + path: '/icon', + component: 'layout/Layout', + children: [ + { + path: 'index', + component: 'views/icons/index', + name: 'Icons', + meta: { title: 'Icons', icon: 'icon', noCache: true } + } + ] + }, + + { + path: '/components', + component: 'layout/Layout', + redirect: 'noRedirect', + name: 'ComponentDemo', + meta: { + title: 'Components', + icon: 'component' + }, + children: [ + { + path: 'tinymce', + component: 'views/components-demo/tinymce', + name: 'TinymceDemo', + meta: { title: 'Tinymce' } + }, + { + path: 'markdown', + component: 'views/components-demo/markdown', + name: 'MarkdownDemo', + meta: { title: 'Markdown' } + }, + { + path: 'json-editor', + component: 'views/components-demo/json-editor', + name: 'JsonEditorDemo', + meta: { title: 'Json Editor' } + }, + { + path: 'split-pane', + component: 'views/components-demo/split-pane', + name: 'SplitpaneDemo', + meta: { title: 'SplitPane' } + }, + { + path: 'avatar-upload', + component: 'views/components-demo/avatar-upload', + name: 'AvatarUploadDemo', + meta: { title: 'Avatar Upload' } + }, + { + path: 'dropzone', + component: 'views/components-demo/dropzone', + name: 'DropzoneDemo', + meta: { title: 'Dropzone' } + }, + { + path: 'sticky', + component: 'views/components-demo/sticky', + name: 'StickyDemo', + meta: { title: 'Sticky' } + }, + { + path: 'count-to', + component: 'views/components-demo/count-to', + name: 'CountToDemo', + meta: { title: 'Count To' } + }, + { + path: 'mixin', + component: 'views/components-demo/mixin', + name: 'ComponentMixinDemo', + meta: { title: 'componentMixin' } + }, + { + path: 'back-to-top', + component: 'views/components-demo/back-to-top', + name: 'BackToTopDemo', + meta: { title: 'Back To Top' } + }, + { + path: 'drag-dialog', + component: 'views/components-demo/drag-dialog', + name: 'DragDialogDemo', + meta: { title: 'Drag Dialog' } + }, + { + path: 'drag-select', + component: 'views/components-demo/drag-select', + name: 'DragSelectDemo', + meta: { title: 'Drag Select' } + }, + { + path: 'dnd-list', + component: 'views/components-demo/dnd-list', + name: 'DndListDemo', + meta: { title: 'Dnd List' } + }, + { + path: 'drag-kanban', + component: 'views/components-demo/drag-kanban', + name: 'DragKanbanDemo', + meta: { title: 'Drag Kanban' } + } + ] + }, + { + path: '/charts', + component: 'layout/Layout', + redirect: 'noRedirect', + name: 'Charts', + meta: { + title: 'Charts', + icon: 'chart' + }, + children: [ + { + path: 'keyboard', + component: 'views/charts/keyboard', + name: 'KeyboardChart', + meta: { title: 'Keyboard Chart', noCache: true } + }, + { + path: 'line', + component: 'views/charts/line', + name: 'LineChart', + meta: { title: 'Line Chart', noCache: true } + }, + { + path: 'mixchart', + component: 'views/charts/mixChart', + name: 'MixChart', + meta: { title: 'Mix Chart', noCache: true } + } + ] + }, + { + path: '/nested', + component: 'layout/Layout', + redirect: '/nested/menu1/menu1-1', + name: 'Nested', + meta: { + title: 'Nested', + icon: 'nested' + }, + children: [ + { + path: 'menu1', + component: 'views/nested/menu1/index', + name: 'Menu1', + meta: { title: 'Menu1' }, + redirect: '/nested/menu1/menu1-1', + children: [ + { + path: 'menu1-1', + component: 'views/nested/menu1/menu1-1', + name: 'Menu1-1', + meta: { title: 'Menu1-1' } + }, + { + path: 'menu1-2', + component: 'views/nested/menu1/menu1-2', + name: 'Menu1-2', + redirect: '/nested/menu1/menu1-2/menu1-2-1', + meta: { title: 'Menu1-2' }, + children: [ + { + path: 'menu1-2-1', + component: 'views/nested/menu1/menu1-2/menu1-2-1', + name: 'Menu1-2-1', + meta: { title: 'Menu1-2-1' } + }, + { + path: 'menu1-2-2', + component: 'views/nested/menu1/menu1-2/menu1-2-2', + name: 'Menu1-2-2', + meta: { title: 'Menu1-2-2' } + } + ] + }, + { + path: 'menu1-3', + component: 'views/nested/menu1/menu1-3', + name: 'Menu1-3', + meta: { title: 'Menu1-3' } + } + ] + }, + { + path: 'menu2', + name: 'Menu2', + component: 'views/nested/menu2/index', + meta: { title: 'Menu2' } + } + ] + }, + + { + path: '/example', + component: 'layout/Layout', + redirect: '/example/list', + name: 'Example', + meta: { + title: 'Example', + icon: 'example' + }, + children: [ + { + path: 'create', + component: 'views/example/create', + name: 'CreateArticle', + meta: { title: 'Create Article', icon: 'edit' } + }, + { + path: 'edit/:id(\\d+)', + component: 'views/example/edit', + name: 'EditArticle', + meta: { title: 'Edit Article', noCache: true }, + hidden: true + }, + { + path: 'list', + component: 'views/example/list', + name: 'ArticleList', + meta: { title: 'Article List', icon: 'list' } + } + ] + }, + + { + path: '/tab', + component: 'layout/Layout', + children: [ + { + path: 'index', + component: 'views/tab/index', + name: 'Tab', + meta: { title: 'Tab', icon: 'tab' } + } + ] + }, + + { + path: '/error', + component: 'layout/Layout', + redirect: 'noRedirect', + name: 'ErrorPages', + meta: { + title: 'Error Pages', + icon: '404' + }, + children: [ + { + path: '401', + component: 'views/error-page/401', + name: 'Page401', + meta: { title: 'Page 401', noCache: true } + }, + { + path: '404', + component: 'views/error-page/404', + name: 'Page404', + meta: { title: 'Page 404', noCache: true } + } + ] + }, + + { + path: '/error-log', + component: 'layout/Layout', + redirect: 'noRedirect', + children: [ + { + path: 'log', + component: 'views/error-log/index', + name: 'ErrorLog', + meta: { title: 'Error Log', icon: 'bug' } + } + ] + }, + + { + path: '/excel', + component: 'layout/Layout', + redirect: '/excel/export-excel', + name: 'Excel', + meta: { + title: 'Excel', + icon: 'excel' + }, + children: [ + { + path: 'export-excel', + component: 'views/excel/export-excel', + name: 'ExportExcel', + meta: { title: 'Export Excel' } + }, + { + path: 'export-selected-excel', + component: 'views/excel/select-excel', + name: 'SelectExcel', + meta: { title: 'Select Excel' } + }, + { + path: 'export-merge-header', + component: 'views/excel/merge-header', + name: 'MergeHeader', + meta: { title: 'Merge Header' } + }, + { + path: 'upload-excel', + component: 'views/excel/upload-excel', + name: 'UploadExcel', + meta: { title: 'Upload Excel' } + } + ] + }, + + { + path: '/zip', + component: 'layout/Layout', + redirect: '/zip/download', + alwaysShow: true, + meta: { title: 'Zip', icon: 'zip' }, + children: [ + { + path: 'download', + component: 'views/zip/index', + name: 'ExportZip', + meta: { title: 'Export Zip' } + } + ] + }, + + { + path: '/pdf', + component: 'layout/Layout', + redirect: '/pdf/index', + children: [ + { + path: 'index', + component: 'views/pdf/index', + name: 'PDF', + meta: { title: 'PDF', icon: 'pdf' } + } + ] + }, + { + path: '/pdf/download', + component: 'views/pdf/download', + hidden: true + }, + + { + path: '/theme', + component: 'layout/Layout', + redirect: 'noRedirect', + children: [ + { + path: 'index', + component: 'views/theme/index', + name: 'Theme', + meta: { title: 'Theme', icon: 'theme' } + } + ] + }, + + { + path: '/clipboard', + component: 'layout/Layout', + redirect: 'noRedirect', + children: [ + { + path: 'index', + component: 'views/clipboard/index', + name: 'ClipboardDemo', + meta: { title: 'Clipboard Demo', icon: 'clipboard' } + } + ] + }, + + { + path: '/i18n', + component: 'layout/Layout', + children: [ + { + path: 'index', + component: 'views/i18n-demo/index', + name: 'I18n', + meta: { title: 'I18n', icon: 'international' } + } + ] + }, + + { + path: 'external-link', + component: 'layout/Layout', + children: [ + { + path: 'https://github.com/PanJiaChen/vue-element-admin', + meta: { title: 'External Link', icon: 'link' } + } + ] + }, + + { path: '*', redirect: '/404', hidden: true } +] diff --git a/mock/user.js b/mock/user.js new file mode 100644 index 0000000..254fe4b --- /dev/null +++ b/mock/user.js @@ -0,0 +1,84 @@ + +const tokens = { + admin: { + token: 'admin-token' + }, + editor: { + token: 'editor-token' + } +} + +const users = { + 'admin-token': { + roles: ['admin'], + introduction: 'I am a super administrator', + avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', + name: 'Super Admin' + }, + 'editor-token': { + roles: ['editor'], + introduction: 'Backend Developer bei RedBull', + avatar: 'https://lbsfilm.at/media/pages/about/1056669128-1567191147/square-small.jpg', + name: 'Lukas Bachschwell' + } +} + +export default [ + // user login + { + url: '/user/login', + type: 'post', + response: config => { + const { username } = config.body + const token = tokens[username] + + // mock error + if (!token) { + return { + code: 60204, + message: 'Account and password are incorrect.' + } + } + + return { + code: 20000, + data: token + } + } + }, + + // get user info + { + url: '/user/info\.*', + type: 'get', + response: config => { + const { token } = config.query + const info = users[token] + + // mock error + if (!info) { + return { + code: 50008, + message: 'Login failed, unable to get user details.' + } + } + + return { + code: 20000, + data: info + } + } + }, + + // user logout + { + url: '/user/logout', + type: 'post', + response: _ => { + return { + code: 20000, + data: 'success' + } + } + } +] diff --git a/package.json b/package.json new file mode 100644 index 0000000..0b04bcd --- /dev/null +++ b/package.json @@ -0,0 +1,106 @@ +{ + "name": "join-project", + "version": "4.2.1", + "description": "Joinbot Vue Admin vased on vue-element-admin by Pan ", + "author": "Lukas Bachschwell ", + "license": "MIT", + "scripts": { + "dev": "vue-cli-service serve", + "build:prod": "vue-cli-service build", + "build:stage": "vue-cli-service build --mode staging", + "preview": "node build/index.js --preview", + "lint": "eslint --ext .js,.vue src", + "test:unit": "jest --clearCache && vue-cli-service test:unit", + "test:ci": "npm run lint && npm run test:unit", + "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml", + "new": "plop" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "src/**/*.{js,vue}": [ + "eslint --fix", + "git add" + ] + }, + "keywords": [ + "vue", + "admin", + "dashboard", + "element-ui", + "boilerplate", + "admin-template", + "management-system" + ], + "dependencies": { + "axios": "0.18.1", + "clipboard": "2.0.4", + "codemirror": "5.45.0", + "driver.js": "0.9.5", + "dropzone": "5.5.1", + "echarts": "4.2.1", + "element-ui": "2.7.0", + "file-saver": "2.0.1", + "fuse.js": "3.4.4", + "js-cookie": "2.2.0", + "jsonlint": "1.6.3", + "jszip": "3.2.1", + "normalize.css": "7.0.0", + "nprogress": "0.2.0", + "path-to-regexp": "2.4.0", + "screenfull": "4.2.0", + "showdown": "1.9.0", + "sortablejs": "1.8.4", + "tui-editor": "1.3.3", + "vue": "2.6.10", + "vue-count-to": "1.0.13", + "vue-router": "3.0.2", + "vue-splitpane": "1.0.4", + "vuedraggable": "2.20.0", + "vuex": "3.1.0", + "xlsx": "0.14.1" + }, + "devDependencies": { + "@babel/core": "7.0.0", + "@babel/register": "7.0.0", + "@vue/cli-plugin-babel": "3.5.3", + "@vue/cli-plugin-eslint": "^3.9.1", + "@vue/cli-plugin-unit-jest": "3.5.3", + "@vue/cli-service": "3.5.3", + "@vue/test-utils": "1.0.0-beta.29", + "autoprefixer": "^9.5.1", + "babel-core": "7.0.0-bridge.0", + "babel-eslint": "10.0.1", + "babel-jest": "23.6.0", + "chalk": "2.4.2", + "chokidar": "2.1.5", + "connect": "3.6.6", + "eslint": "5.15.3", + "eslint-plugin-vue": "5.2.2", + "html-webpack-plugin": "3.2.0", + "husky": "1.3.1", + "lint-staged": "8.1.5", + "mockjs": "1.0.1-beta3", + "node-sass": "^4.9.0", + "plop": "2.3.0", + "runjs": "^4.3.2", + "sass-loader": "^7.1.0", + "script-ext-html-webpack-plugin": "2.1.3", + "script-loader": "0.7.2", + "serve-static": "^1.13.2", + "svg-sprite-loader": "4.1.3", + "svgo": "1.2.0", + "vue-template-compiler": "2.6.10" + }, + "engines": { + "node": ">=8.9", + "npm": ">= 3.0.0" + }, + "browserslist": [ + "> 1%", + "last 2 versions" + ] +} diff --git a/plop-templates/component/index.hbs b/plop-templates/component/index.hbs new file mode 100644 index 0000000..7661055 --- /dev/null +++ b/plop-templates/component/index.hbs @@ -0,0 +1,26 @@ +{{#if template}} + +{{/if}} + +{{#if script}} + +{{/if}} + +{{#if style}} + +{{/if}} diff --git a/plop-templates/component/prompt.js b/plop-templates/component/prompt.js new file mode 100644 index 0000000..3723e8e --- /dev/null +++ b/plop-templates/component/prompt.js @@ -0,0 +1,55 @@ +const { notEmpty } = require('../utils.js') + +module.exports = { + description: 'generate vue component', + prompts: [{ + type: 'input', + name: 'name', + message: 'component name please', + validate: notEmpty('name') + }, + { + type: 'checkbox', + name: 'blocks', + message: 'Blocks:', + choices: [{ + name: '