From cbad6b85b796084fe1af56fe78422b3030be959b Mon Sep 17 00:00:00 2001 From: ddmt Date: Fri, 27 Sep 2024 21:05:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 14 + .env.development | 5 + .env.production | 6 + .env.staging | 8 + .eslintignore | 1 + .eslintrc.js | 198 ++ .gitignore | 23 + .travis.yml | 5 + LICENSE | 21 + babel.config.js | 14 + build/index.js | 35 + jest.config.js | 24 + jsconfig.json | 9 + mock/article.js | 116 ++ mock/index.js | 60 + mock/mock-server.js | 81 + mock/remote-search.js | 51 + mock/role/index.js | 98 + mock/role/routes.js | 530 +++++ mock/user.js | 84 + mock/utils.js | 48 + package.json | 105 + plop-templates/component/index.hbs | 26 + plop-templates/component/prompt.js | 55 + plop-templates/store/index.hbs | 16 + plop-templates/store/prompt.js | 62 + plop-templates/utils.js | 2 + plop-templates/view/index.hbs | 26 + plop-templates/view/prompt.js | 55 + plopfile.js | 9 + postcss.config.js | 5 + public/favicon.ico | Bin 0 -> 6168 bytes public/index.html | 15 + src/App.vue | 35 + src/api/article.js | 41 + src/api/login.js | 26 + src/api/procurement/HaveBid.js | 10 + src/api/procurement/Mark.js | 5 + src/api/procurement/complaint.js | 9 + src/api/procurement/enterpriseInformation.js | 6 + src/api/procurement/list.js | 6 + src/api/qiniu.js | 8 + src/api/remote-search.js | 17 + src/api/role.js | 38 + src/api/system/dict/data.js | 52 + src/api/system/dict/type.js | 60 + src/api/system/user.js | 135 ++ src/api/yxLicense.js | 31 + src/assets/401_images/401.gif | Bin 0 -> 164227 bytes src/assets/404_images/404.png | Bin 0 -> 107022 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/images/Banner1.png | Bin 0 -> 485932 bytes src/assets/images/Banner2.png | Bin 0 -> 888387 bytes src/assets/images/Banner3.png | Bin 0 -> 745260 bytes src/assets/images/avatar.png | Bin 0 -> 41745 bytes src/assets/images/bg.jpg | Bin 0 -> 543899 bytes src/assets/images/bg1.png | Bin 0 -> 99688 bytes src/assets/images/icon_twitter.png | Bin 0 -> 2333 bytes src/assets/images/icon_wechat.png | Bin 0 -> 2700 bytes src/assets/images/icon_weibo.png | Bin 0 -> 3446 bytes src/assets/images/login-bg1.png | Bin 0 -> 79702 bytes src/assets/images/login.png | Bin 0 -> 1285621 bytes src/assets/images/logo.png | Bin 0 -> 200969 bytes src/assets/images/logo01.png | Bin 0 -> 1487 bytes src/assets/images/profile.jpg | Bin 0 -> 171076 bytes src/components/BackToTop/index.vue | 111 + src/components/Breadcrumb/index.vue | 86 + src/components/Charts/Keyboard.vue | 155 ++ src/components/Charts/LineMarker.vue | 227 +++ src/components/Charts/MixChart.vue | 271 +++ src/components/Charts/mixins/resize.js | 56 + src/components/DictData/index.js | 49 + src/components/DictTag/index.vue | 52 + src/components/DndList/index.vue | 166 ++ src/components/DragSelect/index.vue | 65 + 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 | 1779 +++++++++++++++++ .../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/ImageUpload/index.vue | 222 ++ src/components/JsonEditor/index.vue | 77 + src/components/Kanban/index.vue | 99 + src/components/LangSelect/index.vue | 41 + src/components/MDinput/index.vue | 360 ++++ src/components/Pagination/index.vue | 101 + src/components/PanThumb/index.vue | 142 ++ src/components/RightPanel/index.vue | 145 ++ src/components/RightToolbar/index.vue | 104 + src/components/Screenfull/index.vue | 60 + src/components/Share/DropdownMenu.vue | 103 + 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 | 254 +++ 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 | 31 + 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/lang/en.js | 175 ++ src/lang/es.js | 175 ++ src/lang/index.js | 56 + src/lang/ja.js | 175 ++ src/lang/zh.js | 175 ++ src/layout/components/AppMain.vue | 57 + src/layout/components/Navbar.vue | 150 ++ src/layout/components/Settings/index.vue | 145 ++ src/layout/components/Sidebar/FixiOSBug.js | 26 + src/layout/components/Sidebar/Item.vue | 41 + src/layout/components/Sidebar/Link.vue | 43 + src/layout/components/Sidebar/Logo.vue | 82 + src/layout/components/Sidebar/SidebarItem.vue | 98 + src/layout/components/Sidebar/index.vue | 54 + src/layout/components/TagsView/ScrollPane.vue | 94 + src/layout/components/TagsView/index.vue | 294 +++ src/layout/components/index.js | 5 + src/layout/index.vue | 102 + src/layout/mixin/ResizeHandler.js | 45 + src/layout/procurement/head/index.vue | 155 ++ src/layout/procurement/index.vue | 25 + src/layout/procurement/tail/index.vue | 74 + src/main.js | 92 + src/permission.js | 67 + src/plugins/download.js | 72 + src/plugins/index.js | 11 + src/plugins/tab.js | 71 + src/router/index.js | 74 + src/router/modules/charts.js | 36 + src/router/modules/nested.js | 66 + src/router/modules/table.js | 41 + src/settings.js | 42 + src/store/getters.js | 17 + src/store/index.js | 25 + src/store/modules/app.js | 65 + src/store/modules/dict.js | 50 + src/store/modules/errorLog.js | 28 + src/store/modules/permission.js | 33 + src/store/modules/settings.js | 36 + src/store/modules/tagsView.js | 160 ++ src/store/modules/user.js | 139 ++ src/styles/btn.scss | 99 + src/styles/element-ui.scss | 84 + src/styles/element-variables.scss | 31 + src/styles/index.scss | 196 ++ src/styles/mixin.scss | 66 + src/styles/sidebar.scss | 226 +++ src/styles/transition.scss | 48 + src/styles/variables.scss | 35 + src/utils/auth.js | 15 + src/utils/clipboard.js | 32 + src/utils/common.js | 234 +++ src/utils/dict/Dict.js | 82 + src/utils/dict/DictConverter.js | 17 + src/utils/dict/DictData.js | 13 + src/utils/dict/DictMeta.js | 38 + src/utils/dict/DictOptions.js | 51 + src/utils/dict/index.js | 33 + src/utils/error-log.js | 35 + src/utils/errorCode.js | 6 + src/utils/generator/config.js | 438 ++++ src/utils/generator/css.js | 18 + src/utils/generator/drawingDefault.js | 29 + src/utils/generator/html.js | 359 ++++ src/utils/generator/icon.json | 1 + src/utils/generator/js.js | 236 +++ src/utils/generator/render.js | 126 ++ src/utils/get-page-title.js | 13 + src/utils/i18n.js | 12 + src/utils/index.js | 417 ++++ src/utils/open-window.js | 25 + src/utils/permission.js | 21 + src/utils/request.js | 146 ++ src/utils/scroll-to.js | 58 + src/utils/validate.js | 92 + src/vendor/Export2Excel.js | 220 ++ src/vendor/Export2Zip.js | 24 + src/views/applylicense.vue | 264 +++ .../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 | 124 ++ src/views/dashboard/editor/index.vue | 74 + src/views/dashboard/index.vue | 16 + src/views/error-log/components/ErrorTestA.vue | 13 + src/views/error-log/components/ErrorTestB.vue | 0 src/views/error-log/index.vue | 33 + src/views/error-page/401.vue | 99 + src/views/error-page/404.vue | 228 +++ src/views/login/auth-redirect.vue | 15 + src/views/login/components/SocialSignin.vue | 72 + src/views/login/index.vue | 362 ++++ src/views/procurement/index.vue | 178 ++ src/views/procurement/user/index.vue | 55 + .../user/userInformation/index.vue | 45 + src/views/redirect/index.vue | 12 + 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/param2Obj.spec.js | 14 + tests/unit/utils/parseTime.spec.js | 37 + tests/unit/utils/validate.spec.js | 28 + vue.config.js | 133 ++ 286 files changed, 19991 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 .travis.yml create mode 100644 LICENSE 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 mock/utils.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/store/index.hbs create mode 100644 plop-templates/store/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/login.js create mode 100644 src/api/procurement/HaveBid.js create mode 100644 src/api/procurement/Mark.js create mode 100644 src/api/procurement/complaint.js create mode 100644 src/api/procurement/enterpriseInformation.js create mode 100644 src/api/procurement/list.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/system/dict/data.js create mode 100644 src/api/system/dict/type.js create mode 100644 src/api/system/user.js create mode 100644 src/api/yxLicense.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/images/Banner1.png create mode 100644 src/assets/images/Banner2.png create mode 100644 src/assets/images/Banner3.png create mode 100644 src/assets/images/avatar.png create mode 100644 src/assets/images/bg.jpg create mode 100644 src/assets/images/bg1.png create mode 100644 src/assets/images/icon_twitter.png create mode 100644 src/assets/images/icon_wechat.png create mode 100644 src/assets/images/icon_weibo.png create mode 100644 src/assets/images/login-bg1.png create mode 100644 src/assets/images/login.png create mode 100644 src/assets/images/logo.png create mode 100644 src/assets/images/logo01.png create mode 100644 src/assets/images/profile.jpg 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/DictData/index.js create mode 100644 src/components/DictTag/index.vue 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 100644 src/components/ImageCropper/utils/data2blob.js create mode 100644 src/components/ImageCropper/utils/effectRipple.js create mode 100644 src/components/ImageCropper/utils/language.js create mode 100644 src/components/ImageCropper/utils/mimes.js create mode 100644 src/components/ImageUpload/index.vue create mode 100644 src/components/JsonEditor/index.vue create mode 100644 src/components/Kanban/index.vue create mode 100644 src/components/LangSelect/index.vue create mode 100644 src/components/MDinput/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/RightToolbar/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/lang/en.js create mode 100644 src/lang/es.js create mode 100644 src/lang/index.js create mode 100644 src/lang/ja.js create mode 100644 src/lang/zh.js 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/layout/procurement/head/index.vue create mode 100644 src/layout/procurement/index.vue create mode 100644 src/layout/procurement/tail/index.vue create mode 100644 src/main.js create mode 100644 src/permission.js create mode 100644 src/plugins/download.js create mode 100644 src/plugins/index.js create mode 100644 src/plugins/tab.js create mode 100644 src/router/index.js create mode 100644 src/router/modules/charts.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/dict.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/common.js create mode 100644 src/utils/dict/Dict.js create mode 100644 src/utils/dict/DictConverter.js create mode 100644 src/utils/dict/DictData.js create mode 100644 src/utils/dict/DictMeta.js create mode 100644 src/utils/dict/DictOptions.js create mode 100644 src/utils/dict/index.js create mode 100644 src/utils/error-log.js create mode 100644 src/utils/errorCode.js create mode 100644 src/utils/generator/config.js create mode 100644 src/utils/generator/css.js create mode 100644 src/utils/generator/drawingDefault.js create mode 100644 src/utils/generator/html.js create mode 100644 src/utils/generator/icon.json create mode 100644 src/utils/generator/js.js create mode 100644 src/utils/generator/render.js create mode 100644 src/utils/get-page-title.js create mode 100644 src/utils/i18n.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/applylicense.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/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/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/procurement/index.vue create mode 100644 src/views/procurement/user/index.vue create mode 100644 src/views/procurement/user/userInformation/index.vue create mode 100644 src/views/redirect/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/param2Obj.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..de583d0 --- /dev/null +++ b/.env.development @@ -0,0 +1,5 @@ +# just a flag +ENV = 'development' + +# base api +VUE_APP_BASE_API = '/dev-api' diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..270ebea --- /dev/null +++ b/.env.production @@ -0,0 +1,6 @@ +# just a flag +ENV = 'production' + +# base api +VUE_APP_BASE_API = 'http://192.168.1.100:9090' + 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..72e8ffc --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +* 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/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f4be7a0 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: 10 +script: npm run test +notifications: + email: false diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6151575 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017-present PanJiaChen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..fb82b27 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,14 @@ +module.exports = { + presets: [ + // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app + '@vue/cli-plugin-babel/preset' + ], + 'env': { + 'development': { + // babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require(). + // This plugin can significantly increase the speed of hot updates, when you have a large number of pages. + // https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html + 'plugins': ['dynamic-import-node'] + } + } +} 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..23d8ba5 --- /dev/null +++ b/mock/article.js @@ -0,0 +1,116 @@ +const Mock = require('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'], + display_time: '@datetime', + comment_disabled: true, + pageviews: '@integer(300, 5000)', + image_uri, + platforms: ['a-platform'] + })) +} + +module.exports = [ + { + url: '/vue-element-admin/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: '/vue-element-admin/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: '/vue-element-admin/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: '/vue-element-admin/article/create', + type: 'post', + response: _ => { + return { + code: 20000, + data: 'success' + } + } + }, + + { + url: '/vue-element-admin/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..2eed65d --- /dev/null +++ b/mock/index.js @@ -0,0 +1,60 @@ +const Mock = require('mockjs') +const { param2Obj } = require('./utils') + +const user = require('./user') +const role = require('./role') +const article = require('./article') +const search = require('./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). +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)) + } +} + +module.exports = { + mocks, + mockXHR +} diff --git a/mock/mock-server.js b/mock/mock-server.js new file mode 100644 index 0000000..8941ec0 --- /dev/null +++ b/mock/mock-server.js @@ -0,0 +1,81 @@ +const chokidar = require('chokidar') +const bodyParser = require('body-parser') +const chalk = require('chalk') +const path = require('path') +const Mock = require('mockjs') + +const mockDir = path.join(process.cwd(), 'mock') + +function registerRoutes(app) { + let mockLastIndex + const { mocks } = require('./index.js') + const mocksForServer = mocks.map(route => { + return responseFake(route.url, route.type, route.response) + }) + for (const mock of mocksForServer) { + app[mock.type](mock.url, mock.response) + mockLastIndex = app._router.stack.length + } + const mockRoutesLength = Object.keys(mocksForServer).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)] + } + }) +} + +// for mock server +const responseFake = (url, type, respond) => { + return { + url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`), + type: type || 'get', + response(req, res) { + console.log('request invoke:' + req.path) + res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond)) + } + } +} + +module.exports = app => { + // 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..8fc4926 --- /dev/null +++ b/mock/remote-search.js @@ -0,0 +1,51 @@ +const Mock = require('mockjs') + +const NameList = [] +const count = 100 + +for (let i = 0; i < count; i++) { + NameList.push(Mock.mock({ + name: '@first' + })) +} +NameList.push({ name: 'mock-Pan' }) + +module.exports = [ + // username search + { + url: '/vue-element-admin/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: '/vue-element-admin/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..4643f00 --- /dev/null +++ b/mock/role/index.js @@ -0,0 +1,98 @@ +const Mock = require('mockjs') +const { deepClone } = require('../utils') +const { asyncRoutes, constantRoutes } = require('./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' } + } + ] + }] + } +] + +module.exports = [ + // mock get all routes form server + { + url: '/vue-element-admin/routes', + type: 'get', + response: _ => { + return { + code: 20000, + data: routes + } + } + }, + + // mock get all roles form server + { + url: '/vue-element-admin/roles', + type: 'get', + response: _ => { + return { + code: 20000, + data: roles + } + } + }, + + // add role + { + url: '/vue-element-admin/role', + type: 'post', + response: { + code: 20000, + data: { + key: Mock.mock('@integer(300, 5000)') + } + } + }, + + // update role + { + url: '/vue-element-admin/role/[A-Za-z0-9]', + type: 'put', + response: { + code: 20000, + data: { + status: 'success' + } + } + }, + + // delete role + { + url: '/vue-element-admin/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..757aa38 --- /dev/null +++ b/mock/role/routes.js @@ -0,0 +1,530 @@ +// Just a mock data + +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 } + } + ] + } +] + +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: 'pagePermission', + roles: ['admin'] + } + }, + { + path: 'directive', + component: 'views/permission/directive', + name: 'DirectivePermission', + meta: { + title: 'directivePermission' + } + }, + { + path: 'role', + component: 'views/permission/role', + name: 'RolePermission', + meta: { + title: 'rolePermission', + 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: 'jsonEditor' } + }, + { + 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: 'avatarUpload' } + }, + { + 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: 'countTo' } + }, + { + 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: 'backToTop' } + }, + { + path: 'drag-dialog', + component: 'views/components-demo/drag-dialog', + name: 'DragDialogDemo', + meta: { title: 'dragDialog' } + }, + { + path: 'drag-select', + component: 'views/components-demo/drag-select', + name: 'DragSelectDemo', + meta: { title: 'dragSelect' } + }, + { + path: 'dnd-list', + component: 'views/components-demo/dnd-list', + name: 'DndListDemo', + meta: { title: 'dndList' } + }, + { + path: 'drag-kanban', + component: 'views/components-demo/drag-kanban', + name: 'DragKanbanDemo', + meta: { title: 'dragKanban' } + } + ] + }, + { + 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: 'keyboardChart', noCache: true } + }, + { + path: 'line', + component: 'views/charts/line', + name: 'LineChart', + meta: { title: 'lineChart', noCache: true } + }, + { + path: 'mixchart', + component: 'views/charts/mixChart', + name: 'MixChart', + meta: { title: 'mixChart', 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: 'createArticle', icon: 'edit' } + }, + { + path: 'edit/:id(\\d+)', + component: 'views/example/edit', + name: 'EditArticle', + meta: { title: 'editArticle', noCache: true }, + hidden: true + }, + { + path: 'list', + component: 'views/example/list', + name: 'ArticleList', + meta: { title: 'articleList', 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: 'errorPages', + icon: '404' + }, + children: [ + { + path: '401', + component: 'views/error-page/401', + name: 'Page401', + meta: { title: 'page401', noCache: true } + }, + { + path: '404', + component: 'views/error-page/404', + name: 'Page404', + meta: { title: 'page404', noCache: true } + } + ] + }, + + { + path: '/error-log', + component: 'layout/Layout', + redirect: 'noRedirect', + children: [ + { + path: 'log', + component: 'views/error-log/index', + name: 'ErrorLog', + meta: { title: 'errorLog', 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: 'exportExcel' } + }, + { + path: 'export-selected-excel', + component: 'views/excel/select-excel', + name: 'SelectExcel', + meta: { title: 'selectExcel' } + }, + { + path: 'export-merge-header', + component: 'views/excel/merge-header', + name: 'MergeHeader', + meta: { title: 'mergeHeader' } + }, + { + path: 'upload-excel', + component: 'views/excel/upload-excel', + name: 'UploadExcel', + meta: { title: 'uploadExcel' } + } + ] + }, + + { + 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: 'exportZip' } + } + ] + }, + + { + 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: 'clipboardDemo', 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: 'externalLink', icon: 'link' } + } + ] + }, + + { path: '*', redirect: '/404', hidden: true } +] + +module.exports = { + constantRoutes, + asyncRoutes +} diff --git a/mock/user.js b/mock/user.js new file mode 100644 index 0000000..d82e079 --- /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: 'I am an editor', + avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', + name: 'Normal Editor' + } +} + +module.exports = [ + // user login + { + url: '/vue-element-admin/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: '/vue-element-admin/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: '/vue-element-admin/user/logout', + type: 'post', + response: _ => { + return { + code: 20000, + data: 'success' + } + } + } +] diff --git a/mock/utils.js b/mock/utils.js new file mode 100644 index 0000000..f909a29 --- /dev/null +++ b/mock/utils.js @@ -0,0 +1,48 @@ +/** + * @param {string} url + * @returns {Object} + */ +function param2Obj(url) { + const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') + if (!search) { + return {} + } + const obj = {} + const searchArr = search.split('&') + searchArr.forEach(v => { + const index = v.indexOf('=') + if (index !== -1) { + const name = v.substring(0, index) + const val = v.substring(index + 1, v.length) + obj[name] = val + } + }) + return obj +} + +/** + * This is just a simple version of deep copy + * Has a lot of edge cases bug + * If you want to use a perfect deep copy, use lodash's _.cloneDeep + * @param {Object} source + * @returns {Object} + */ +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 +} + +module.exports = { + param2Obj, + deepClone +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..10fadda --- /dev/null +++ b/package.json @@ -0,0 +1,105 @@ +{ + "name": "vue-element-admin", + "version": "4.4.0", + "description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features", + "author": "Pan ", + "scripts": { + "dev": "vue-cli-service serve", + "lint": "eslint --ext .js,.vue src", + "build:prod": "vue-cli-service build", + "build:stage": "vue-cli-service build --mode staging", + "preview": "node build/index.js --preview", + "new": "plop", + "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml", + "test:unit": "jest --clearCache && vue-cli-service test:unit", + "test:ci": "npm run lint && npm run test:unit" + }, + "dependencies": { + "@riophae/vue-treeselect": "^0.4.0", + "axios": "^0.26.0", + "clipboard": "2.0.6", + "codemirror": "5.45.0", + "core-js": "^3.8.1", + "driver.js": "0.9.5", + "dropzone": "5.5.1", + "echarts": "^5.4.2", + "element-ui": "^2.15.6", + "file-saver": "2.0.5", + "fuse.js": "3.4.4", + "highlight.js": "9.18.5", + "js-cookie": "3.0.1", + "jsencrypt": "3.0.0-rc.1", + "jsonlint": "1.6.3", + "jszip": "3.2.1", + "normalize.css": "7.0.0", + "nprogress": "0.2.0", + "path-to-regexp": "2.4.0", + "quill": "^1.3.7", + "screenfull": "5.0.2", + "script-loader": "0.7.2", + "sortablejs": "1.8.4", + "vue": "^2.6.14", + "vue-awesome-swiper": "^5.0.1", + "vue-count-to": "1.0.13", + "vue-i18n": "7.3.2", + "vue-router": "^3.5.1", + "vue-splitpane": "1.0.4", + "vuedraggable": "2.20.0", + "vuex": "^3.6.2", + "xlsx": "0.14.1" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "4.4.4", + "@vue/cli-plugin-eslint": "4.4.4", + "@vue/cli-plugin-unit-jest": "4.4.4", + "@vue/cli-service": "4.4.4", + "@vue/test-utils": "1.0.0-beta.29", + "autoprefixer": "9.5.1", + "babel-eslint": "10.1.0", + "babel-jest": "23.6.0", + "babel-plugin-dynamic-import-node": "2.3.3", + "chalk": "2.4.2", + "chokidar": "2.1.5", + "connect": "3.6.6", + "eslint": "6.7.2", + "eslint-plugin-vue": "6.2.2", + "html-webpack-plugin": "3.2.0", + "husky": "1.3.1", + "lint-staged": "8.1.5", + "mockjs": "1.0.1-beta3", + "plop": "2.3.0", + "runjs": "4.3.2", + "sass": "1.26.2", + "sass-loader": "8.0.2", + "script-ext-html-webpack-plugin": "2.1.3", + "serve-static": "1.13.2", + "svg-sprite-loader": "4.1.3", + "svgo": "1.2.0", + "vue-template-compiler": "2.6.10" + }, + "browserslist": [ + "> 1%", + "last 2 versions" + ], + "bugs": { + "url": "https://github.com/PanJiaChen/vue-element-admin/issues" + }, + "engines": { + "node": ">=8.9", + "npm": ">= 3.0.0" + }, + "keywords": [ + "vue", + "admin", + "dashboard", + "element-ui", + "boilerplate", + "admin-template", + "management-system" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/PanJiaChen/vue-element-admin.git" + } +} 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: '