├── .gitignore ├── README.md ├── client ├── .editorconfig ├── .env.development ├── .env.production ├── .env.staging ├── .eslintignore ├── .eslintrc.js ├── .github │ ├── FUNDING.yml │ └── ISSUE_TEMPLATE │ │ ├── bug_report.md │ │ ├── feature_request.md │ │ └── question.md ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.es.md ├── README.ja.md ├── README.md ├── README.zh-CN.md ├── babel.config.js ├── build │ └── index.js ├── dist │ ├── favicon.ico │ ├── index.html │ └── static │ │ ├── css │ │ ├── app.e44a11ae.css │ │ ├── chunk-30ca8599.b1dd7a76.css │ │ ├── chunk-5324a645.a18cfec9.css │ │ ├── chunk-5390c43f.13a7e89e.css │ │ ├── chunk-5a85ac74.9539a687.css │ │ ├── chunk-6bf375a1.a07666d2.css │ │ ├── chunk-6d33572c.c5654950.css │ │ ├── chunk-930b7de2.863f08f8.css │ │ ├── chunk-a57bb2ee.13c55322.css │ │ └── chunk-libs.3dfb7769.css │ │ ├── fonts │ │ ├── element-icons.535877f5.woff │ │ └── element-icons.732389de.ttf │ │ ├── img │ │ ├── 401.089007e7.gif │ │ ├── 404.a57b6f31.png │ │ └── 404_cloud.0f4bc32b.png │ │ └── js │ │ ├── app.c94fe7cc.js │ │ ├── chunk-17ac072a.6154fd53.js │ │ ├── chunk-2d0cfe36.4eddf515.js │ │ ├── chunk-2d21b85a.be1c6752.js │ │ ├── chunk-2d230fe7.042d38d1.js │ │ ├── chunk-30ca8599.3706bd61.js │ │ ├── chunk-40c651d8.d813f012.js │ │ ├── chunk-5324a645.35d81635.js │ │ ├── chunk-5390c43f.d32c89e9.js │ │ ├── chunk-5a85ac74.75720cf9.js │ │ ├── chunk-6bf375a1.abb41963.js │ │ ├── chunk-6d33572c.b127fb04.js │ │ ├── chunk-71276642.05ca38cb.js │ │ ├── chunk-930b7de2.e53a153f.js │ │ ├── chunk-a57bb2ee.dd9a58b9.js │ │ ├── chunk-elementUI.5044cc0b.js │ │ └── chunk-libs.de10ae78.js ├── jest.config.js ├── jsconfig.json ├── mock │ ├── article.js │ ├── index.js │ ├── mock-server.js │ ├── remote-search.js │ ├── role │ │ ├── index.js │ │ └── routes.js │ ├── user.js │ └── utils.js ├── package-lock.json ├── package.json ├── plop-templates │ ├── component │ │ ├── index.hbs │ │ └── prompt.js │ ├── store │ │ ├── index.hbs │ │ └── prompt.js │ ├── utils.js │ └── view │ │ ├── index.hbs │ │ └── prompt.js ├── plopfile.js ├── postcss.config.js ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── api │ │ ├── article.js │ │ ├── operate-log.js │ │ ├── qiniu.js │ │ ├── remote-search.js │ │ ├── role.js │ │ ├── service-manage.js │ │ ├── spider.js │ │ └── user.js │ ├── assets │ │ ├── 401_images │ │ │ └── 401.gif │ │ ├── 404_images │ │ │ ├── 404.png │ │ │ └── 404_cloud.png │ │ └── custom-theme │ │ │ ├── fonts │ │ │ ├── element-icons.ttf │ │ │ └── element-icons.woff │ │ │ └── index.css │ ├── components │ │ ├── BackToTop │ │ │ └── index.vue │ │ ├── Breadcrumb │ │ │ └── index.vue │ │ ├── Charts │ │ │ ├── Keyboard.vue │ │ │ ├── LineMarker.vue │ │ │ ├── MixChart.vue │ │ │ └── mixins │ │ │ │ └── resize.js │ │ ├── DndList │ │ │ └── index.vue │ │ ├── DragSelect │ │ │ └── index.vue │ │ ├── Dropzone │ │ │ └── index.vue │ │ ├── ErrorLog │ │ │ └── index.vue │ │ ├── GithubCorner │ │ │ └── index.vue │ │ ├── Hamburger │ │ │ └── index.vue │ │ ├── HeaderSearch │ │ │ └── index.vue │ │ ├── ImageCropper │ │ │ ├── index.vue │ │ │ └── utils │ │ │ │ ├── data2blob.js │ │ │ │ ├── effectRipple.js │ │ │ │ ├── language.js │ │ │ │ └── mimes.js │ │ ├── JsonEditor │ │ │ └── index.vue │ │ ├── Kanban │ │ │ └── index.vue │ │ ├── MDinput │ │ │ └── index.vue │ │ ├── MarkdownEditor │ │ │ ├── default-options.js │ │ │ └── index.vue │ │ ├── Pagination │ │ │ └── index.vue │ │ ├── PanThumb │ │ │ └── index.vue │ │ ├── RightPanel │ │ │ └── index.vue │ │ ├── Screenfull │ │ │ └── index.vue │ │ ├── Share │ │ │ └── DropdownMenu.vue │ │ ├── SizeSelect │ │ │ └── index.vue │ │ ├── Sticky │ │ │ └── index.vue │ │ ├── SvgIcon │ │ │ └── index.vue │ │ ├── TextHoverEffect │ │ │ └── Mallki.vue │ │ ├── ThemePicker │ │ │ └── index.vue │ │ ├── Tinymce │ │ │ ├── components │ │ │ │ └── EditorImage.vue │ │ │ ├── dynamicLoadScript.js │ │ │ ├── index.vue │ │ │ ├── plugins.js │ │ │ └── toolbar.js │ │ ├── Upload │ │ │ ├── SingleImage.vue │ │ │ ├── SingleImage2.vue │ │ │ └── SingleImage3.vue │ │ └── UploadExcel │ │ │ └── index.vue │ ├── directive │ │ ├── clipboard │ │ │ ├── clipboard.js │ │ │ └── index.js │ │ ├── el-drag-dialog │ │ │ ├── drag.js │ │ │ └── index.js │ │ ├── el-table │ │ │ ├── adaptive.js │ │ │ └── index.js │ │ ├── permission │ │ │ ├── index.js │ │ │ └── permission.js │ │ ├── sticky.js │ │ └── waves │ │ │ ├── index.js │ │ │ ├── waves.css │ │ │ └── waves.js │ ├── filters │ │ └── index.js │ ├── icons │ │ ├── index.js │ │ ├── svg │ │ │ ├── 404.svg │ │ │ ├── bug.svg │ │ │ ├── chart.svg │ │ │ ├── clipboard.svg │ │ │ ├── component.svg │ │ │ ├── dashboard.svg │ │ │ ├── documentation.svg │ │ │ ├── drag.svg │ │ │ ├── edit.svg │ │ │ ├── education.svg │ │ │ ├── email.svg │ │ │ ├── example.svg │ │ │ ├── excel.svg │ │ │ ├── exit-fullscreen.svg │ │ │ ├── eye-open.svg │ │ │ ├── eye.svg │ │ │ ├── form.svg │ │ │ ├── fullscreen.svg │ │ │ ├── guide.svg │ │ │ ├── icon.svg │ │ │ ├── international.svg │ │ │ ├── language.svg │ │ │ ├── link.svg │ │ │ ├── list.svg │ │ │ ├── lock.svg │ │ │ ├── message.svg │ │ │ ├── money.svg │ │ │ ├── nested.svg │ │ │ ├── password.svg │ │ │ ├── pdf.svg │ │ │ ├── people.svg │ │ │ ├── peoples.svg │ │ │ ├── qq.svg │ │ │ ├── search.svg │ │ │ ├── shopping.svg │ │ │ ├── size.svg │ │ │ ├── skill.svg │ │ │ ├── star.svg │ │ │ ├── tab.svg │ │ │ ├── table.svg │ │ │ ├── theme.svg │ │ │ ├── tree-table.svg │ │ │ ├── tree.svg │ │ │ ├── user.svg │ │ │ ├── wechat.svg │ │ │ └── zip.svg │ │ └── svgo.yml │ ├── layout │ │ ├── components │ │ │ ├── AppMain.vue │ │ │ ├── Navbar.vue │ │ │ ├── Settings │ │ │ │ └── index.vue │ │ │ ├── Sidebar │ │ │ │ ├── FixiOSBug.js │ │ │ │ ├── Item.vue │ │ │ │ ├── Link.vue │ │ │ │ ├── Logo.vue │ │ │ │ ├── SidebarItem.vue │ │ │ │ └── index.vue │ │ │ ├── TagsView │ │ │ │ ├── ScrollPane.vue │ │ │ │ └── index.vue │ │ │ └── index.js │ │ ├── index.vue │ │ └── mixin │ │ │ └── ResizeHandler.js │ ├── main.js │ ├── permission.js │ ├── router │ │ ├── index.js │ │ └── modules │ │ │ ├── charts.js │ │ │ ├── components.js │ │ │ ├── nested.js │ │ │ ├── spider.js │ │ │ └── table.js │ ├── settings.js │ ├── store │ │ ├── getters.js │ │ ├── index.js │ │ └── modules │ │ │ ├── app.js │ │ │ ├── errorLog.js │ │ │ ├── permission.js │ │ │ ├── settings.js │ │ │ ├── tagsView.js │ │ │ └── user.js │ ├── styles │ │ ├── btn.scss │ │ ├── element-ui.scss │ │ ├── element-variables.scss │ │ ├── index.scss │ │ ├── mixin.scss │ │ ├── sidebar.scss │ │ ├── transition.scss │ │ └── variables.scss │ ├── utils │ │ ├── auth.js │ │ ├── clipboard.js │ │ ├── error-log.js │ │ ├── get-page-title.js │ │ ├── index.js │ │ ├── open-window.js │ │ ├── permission.js │ │ ├── request.js │ │ ├── scroll-to.js │ │ └── validate.js │ ├── vendor │ │ ├── Export2Excel.js │ │ └── Export2Zip.js │ └── views │ │ ├── charts │ │ ├── keyboard.vue │ │ ├── line.vue │ │ └── mix-chart.vue │ │ ├── clipboard │ │ └── index.vue │ │ ├── components-demo │ │ ├── avatar-upload.vue │ │ ├── back-to-top.vue │ │ ├── count-to.vue │ │ ├── dnd-list.vue │ │ ├── drag-dialog.vue │ │ ├── drag-kanban.vue │ │ ├── drag-select.vue │ │ ├── dropzone.vue │ │ ├── json-editor.vue │ │ ├── markdown.vue │ │ ├── mixin.vue │ │ ├── split-pane.vue │ │ ├── sticky.vue │ │ └── tinymce.vue │ │ ├── dashboard │ │ ├── admin │ │ │ ├── components │ │ │ │ ├── BarChart.vue │ │ │ │ ├── BoxCard.vue │ │ │ │ ├── LineChart.vue │ │ │ │ ├── PanelGroup.vue │ │ │ │ ├── PieChart.vue │ │ │ │ ├── RaddarChart.vue │ │ │ │ ├── TodoList │ │ │ │ │ ├── Todo.vue │ │ │ │ │ ├── index.scss │ │ │ │ │ └── index.vue │ │ │ │ ├── TransactionTable.vue │ │ │ │ └── mixins │ │ │ │ │ └── resize.js │ │ │ └── index.vue │ │ ├── editor │ │ │ └── index.vue │ │ └── index.vue │ │ ├── documentation │ │ └── index.vue │ │ ├── error-log │ │ ├── components │ │ │ ├── ErrorTestA.vue │ │ │ └── ErrorTestB.vue │ │ └── index.vue │ │ ├── error-page │ │ ├── 401.vue │ │ └── 404.vue │ │ ├── example │ │ ├── components │ │ │ ├── ArticleDetail.vue │ │ │ ├── Dropdown │ │ │ │ ├── Comment.vue │ │ │ │ ├── Platform.vue │ │ │ │ ├── SourceUrl.vue │ │ │ │ └── index.js │ │ │ └── Warning.vue │ │ ├── create.vue │ │ ├── edit.vue │ │ └── list.vue │ │ ├── excel │ │ ├── components │ │ │ ├── AutoWidthOption.vue │ │ │ ├── BookTypeOption.vue │ │ │ └── FilenameOption.vue │ │ ├── export-excel.vue │ │ ├── merge-header.vue │ │ ├── select-excel.vue │ │ └── upload-excel.vue │ │ ├── guide │ │ ├── index.vue │ │ └── steps.js │ │ ├── icons │ │ ├── element-icons.js │ │ ├── index.vue │ │ └── svg-icons.js │ │ ├── login │ │ └── index.vue │ │ ├── nested │ │ ├── menu1 │ │ │ ├── index.vue │ │ │ ├── menu1-1 │ │ │ │ └── index.vue │ │ │ ├── menu1-2 │ │ │ │ ├── index.vue │ │ │ │ ├── menu1-2-1 │ │ │ │ │ └── index.vue │ │ │ │ └── menu1-2-2 │ │ │ │ │ └── index.vue │ │ │ └── menu1-3 │ │ │ │ └── index.vue │ │ └── menu2 │ │ │ └── index.vue │ │ ├── operate-log │ │ └── index.vue │ │ ├── pdf │ │ ├── content.js │ │ ├── download.vue │ │ └── index.vue │ │ ├── permission │ │ ├── components │ │ │ └── SwitchRoles.vue │ │ ├── directive.vue │ │ ├── page.vue │ │ └── role.vue │ │ ├── profile │ │ ├── components │ │ │ ├── Account.vue │ │ │ ├── Activity.vue │ │ │ ├── Timeline.vue │ │ │ └── UserCard.vue │ │ └── index.vue │ │ ├── qiniu │ │ └── upload.vue │ │ ├── redirect │ │ └── index.vue │ │ ├── service-manager │ │ ├── config-center │ │ │ └── index.vue │ │ └── service-manage │ │ │ └── list.vue │ │ ├── spider │ │ ├── index.vue │ │ └── tieba │ │ │ ├── detail │ │ │ └── index.vue │ │ │ ├── form │ │ │ └── index.vue │ │ │ ├── index.vue │ │ │ └── list │ │ │ └── index.vue │ │ ├── tab │ │ ├── components │ │ │ └── TabPane.vue │ │ └── index.vue │ │ ├── table │ │ ├── complex-table.vue │ │ ├── drag-table.vue │ │ ├── dynamic-table │ │ │ ├── components │ │ │ │ ├── FixedThead.vue │ │ │ │ └── UnfixedThead.vue │ │ │ └── index.vue │ │ └── inline-edit-table.vue │ │ ├── theme │ │ └── index.vue │ │ └── zip │ │ └── index.vue ├── tests │ └── unit │ │ ├── .eslintrc.js │ │ ├── components │ │ ├── Hamburger.spec.js │ │ └── SvgIcon.spec.js │ │ └── utils │ │ ├── formatTime.spec.js │ │ ├── param2Obj.spec.js │ │ ├── parseTime.spec.js │ │ └── validate.spec.js └── vue.config.js └── server ├── README.md ├── app ├── __init__.py ├── app_config.py ├── base │ ├── __init__.py │ ├── baseenum.py │ ├── basemodel.py │ ├── baseview.py │ ├── enum_code.py │ └── status_code.py ├── controllers │ ├── __init__.py │ ├── operate_log.py │ ├── ping.py │ ├── spider.py │ ├── tieba.py │ └── user.py ├── models │ ├── __init__.py │ ├── operate_log.py │ ├── ping.py │ ├── spider.py │ ├── tieba.py │ └── user.py ├── tasks │ ├── __init__.py │ ├── operate_info.py │ └── spider_tasks.py ├── urls.py ├── utils │ ├── Singleton.py │ ├── __init__.py │ ├── logger.py │ ├── service_manager.py │ ├── spider_utils │ │ ├── __init__.py │ │ └── crawl_tieba.py │ └── token.py └── views │ ├── __init__.py │ ├── operate_log.py │ ├── ping.py │ ├── service_manage.py │ ├── spider.py │ ├── tieba.py │ └── user.py ├── config.py ├── manage.py └── requirements.txt /client/.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | insert_final_newline = false 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /client/.env.development: -------------------------------------------------------------------------------- 1 | # just a flag 2 | ENV = 'development' 3 | 4 | # base api 5 | VUE_APP_BASE_API = '/api' 6 | -------------------------------------------------------------------------------- /client/.env.production: -------------------------------------------------------------------------------- 1 | # just a flag 2 | ENV = 'production' 3 | 4 | # base api 5 | VUE_APP_BASE_API = '/api' 6 | 7 | -------------------------------------------------------------------------------- /client/.env.staging: -------------------------------------------------------------------------------- 1 | NODE_ENV = production 2 | 3 | # just a flag 4 | ENV = 'staging' 5 | 6 | # base api 7 | VUE_APP_BASE_API = '/stage-api' 8 | 9 | -------------------------------------------------------------------------------- /client/.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | src/assets 3 | public 4 | dist 5 | -------------------------------------------------------------------------------- /client/.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: panjiachen 4 | custom: https://panjiachen.github.io/vue-element-admin-site/donate 5 | -------------------------------------------------------------------------------- /client/.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report(报告问题) 3 | about: Create a report to help us improve 4 | --- 5 | 10 | 11 | 12 | ## Bug report(问题描述) 13 | 14 | #### Steps to reproduce(问题复现步骤) 15 | 20 | 21 | #### Screenshot or Gif(截图或动态图) 22 | 23 | 24 | #### Link to minimal reproduction(最小可在线还原demo) 25 | 26 | 29 | 30 | #### Other relevant information(格外信息) 31 | - Your OS: 32 | - Node.js version: 33 | - vue-element-admin version: 34 | -------------------------------------------------------------------------------- /client/.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request(新功能建议) 3 | about: Suggest an idea for this project 4 | --- 5 | 6 | ## Feature request(新功能建议) 7 | 8 | -------------------------------------------------------------------------------- /client/.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question(提问) 3 | about: Asking questions about use 4 | --- 5 | 6 | ## Question(提问) 7 | 8 | 15 | 16 | #### Steps to reproduce(问题复现步骤) 17 | 22 | 23 | #### Screenshot or Gif(截图或动态图) 24 | 25 | 26 | #### Link to minimal reproduction(最小可在线还原demo) 27 | 28 | 31 | 32 | #### Other relevant information(格外信息) 33 | - Your OS: 34 | - Node.js version: 35 | - vue-element-admin version: 36 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | #dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | **/*.log 8 | 9 | tests/**/coverage/ 10 | tests/e2e/reports 11 | selenium-debug.log 12 | 13 | # Editor directories and files 14 | .idea 15 | .vscode 16 | *.suo 17 | *.ntvs* 18 | *.njsproj 19 | *.sln 20 | *.local 21 | 22 | package-lock.json 23 | yarn.lock 24 | -------------------------------------------------------------------------------- /client/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 10 3 | script: npm run test 4 | notifications: 5 | email: false 6 | -------------------------------------------------------------------------------- /client/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-present PanJiaChen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /client/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app 4 | '@vue/cli-plugin-babel/preset' 5 | ], 6 | 'env': { 7 | 'development': { 8 | // babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require(). 9 | // This plugin can significantly increase the speed of hot updates, when you have a large number of pages. 10 | // https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html 11 | 'plugins': ['dynamic-import-node'] 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /client/build/index.js: -------------------------------------------------------------------------------- 1 | const { run } = require('runjs') 2 | const chalk = require('chalk') 3 | const config = require('../vue.config.js') 4 | const rawArgv = process.argv.slice(2) 5 | const args = rawArgv.join(' ') 6 | 7 | if (process.env.npm_config_preview || rawArgv.includes('--preview')) { 8 | const report = rawArgv.includes('--report') 9 | 10 | run(`vue-cli-service build ${args}`) 11 | 12 | const port = 9526 13 | const publicPath = config.publicPath 14 | 15 | var connect = require('connect') 16 | var serveStatic = require('serve-static') 17 | const app = connect() 18 | 19 | app.use( 20 | publicPath, 21 | serveStatic('./dist', { 22 | index: ['index.html', '/'] 23 | }) 24 | ) 25 | 26 | app.listen(port, function () { 27 | console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`)) 28 | if (report) { 29 | console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`)) 30 | } 31 | 32 | }) 33 | } else { 34 | run(`vue-cli-service build ${args}`) 35 | } 36 | -------------------------------------------------------------------------------- /client/dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junpengxu/Apollo/b34f183a18f8e14944d72b64d9c160b4e6d360c8/client/dist/favicon.ico -------------------------------------------------------------------------------- /client/dist/static/css/chunk-30ca8599.b1dd7a76.css: -------------------------------------------------------------------------------- 1 | .errPage-container[data-v-35ca77fc]{width:800px;max-width:100%;margin:100px auto}.errPage-container .pan-back-btn[data-v-35ca77fc]{background:#008489;color:#fff;border:none!important}.errPage-container .pan-gif[data-v-35ca77fc]{margin:0 auto;display:block}.errPage-container .pan-img[data-v-35ca77fc]{display:block;margin:0 auto;width:100%}.errPage-container .text-jumbo[data-v-35ca77fc]{font-size:60px;font-weight:700;color:#484848}.errPage-container .list-unstyled[data-v-35ca77fc]{font-size:14px}.errPage-container .list-unstyled li[data-v-35ca77fc]{padding-bottom:5px}.errPage-container .list-unstyled a[data-v-35ca77fc]{color:#008489;text-decoration:none}.errPage-container .list-unstyled a[data-v-35ca77fc]:hover{text-decoration:underline} -------------------------------------------------------------------------------- /client/dist/static/css/chunk-6bf375a1.a07666d2.css: -------------------------------------------------------------------------------- 1 | @supports(-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-444282ed]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-444282ed]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-444282ed]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-444282ed]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-444282ed]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-444282ed]{position:relative}.login-container .title-container .title[data-v-444282ed]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-444282ed]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-444282ed]{position:absolute;right:0;bottom:6px}@media only screen and (max-width:470px){.login-container .thirdparty-button[data-v-444282ed]{display:none}} -------------------------------------------------------------------------------- /client/dist/static/css/chunk-6d33572c.c5654950.css: -------------------------------------------------------------------------------- 1 | .form[data-v-d9e92356]{width:60%;margin:50px} -------------------------------------------------------------------------------- /client/dist/static/css/chunk-930b7de2.863f08f8.css: -------------------------------------------------------------------------------- 1 | .input-content[data-v-4362e218]{width:500px}.search-button[data-v-4362e218]{margin-left:100px} -------------------------------------------------------------------------------- /client/dist/static/css/chunk-a57bb2ee.13c55322.css: -------------------------------------------------------------------------------- 1 | .input-content[data-v-3dadd6b4]{width:500px}.search-button[data-v-3dadd6b4]{margin-left:100px} -------------------------------------------------------------------------------- /client/dist/static/fonts/element-icons.535877f5.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junpengxu/Apollo/b34f183a18f8e14944d72b64d9c160b4e6d360c8/client/dist/static/fonts/element-icons.535877f5.woff -------------------------------------------------------------------------------- /client/dist/static/fonts/element-icons.732389de.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junpengxu/Apollo/b34f183a18f8e14944d72b64d9c160b4e6d360c8/client/dist/static/fonts/element-icons.732389de.ttf -------------------------------------------------------------------------------- /client/dist/static/img/401.089007e7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junpengxu/Apollo/b34f183a18f8e14944d72b64d9c160b4e6d360c8/client/dist/static/img/401.089007e7.gif -------------------------------------------------------------------------------- /client/dist/static/img/404.a57b6f31.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junpengxu/Apollo/b34f183a18f8e14944d72b64d9c160b4e6d360c8/client/dist/static/img/404.a57b6f31.png -------------------------------------------------------------------------------- /client/dist/static/img/404_cloud.0f4bc32b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junpengxu/Apollo/b34f183a18f8e14944d72b64d9c160b4e6d360c8/client/dist/static/img/404_cloud.0f4bc32b.png -------------------------------------------------------------------------------- /client/dist/static/js/chunk-2d0cfe36.4eddf515.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d0cfe36"],{6644:function(e,n,t){"use strict";t.r(n);var c=function(){var e=this,n=e.$createElement,t=e._self._c||n;return t("div",[e._v("待开发")])},a=[],u={name:"Index"},r=u,s=t("2877"),d=Object(s["a"])(r,c,a,!1,null,"28fd32a5",null);n["default"]=d.exports}}]); -------------------------------------------------------------------------------- /client/dist/static/js/chunk-2d21b85a.be1c6752.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d21b85a"],{bfaa:function(e,n,t){"use strict";t.r(n);var a=function(){var e=this,n=e.$createElement,t=e._self._c||n;return t("div",{staticStyle:{padding:"30px"}},[t("router-view")],1)},u=[],c=t("2877"),i={},l=Object(c["a"])(i,a,u,!1,null,null,null);n["default"]=l.exports}}]); -------------------------------------------------------------------------------- /client/dist/static/js/chunk-2d230fe7.042d38d1.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d230fe7"],{ef3c:function(e,r,n){"use strict";n.r(r);n("ac1f"),n("5319");var t,u,a={created:function(){var e=this.$route,r=e.params,n=e.query,t=r.path;this.$router.replace({path:"/"+t,query:n})},render:function(e){return e()}},c=a,o=n("2877"),p=Object(o["a"])(c,t,u,!1,null,null,null);r["default"]=p.exports}}]); -------------------------------------------------------------------------------- /client/dist/static/js/chunk-30ca8599.3706bd61.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-30ca8599"],{"1a27":function(t,a,i){"use strict";var e=i("a5e5"),s=i.n(e);s.a},"24e2":function(t,a,i){"use strict";i.r(a);var e=function(){var t=this,a=t.$createElement,i=t._self._c||a;return i("div",{staticClass:"errPage-container"},[i("el-button",{staticClass:"pan-back-btn",attrs:{icon:"el-icon-arrow-left"},on:{click:t.back}},[t._v(" 返回 ")]),i("el-row",[i("el-col",{attrs:{span:12}},[i("h1",{staticClass:"text-jumbo text-ginormous"},[t._v(" Oops! ")]),t._v(" gif来源"),i("a",{attrs:{href:"https://zh.airbnb.com/",target:"_blank"}},[t._v("airbnb")]),t._v(" 页面 "),i("h2",[t._v("你没有权限去该页面")]),i("h6",[t._v("如有不满请联系你领导")]),i("ul",{staticClass:"list-unstyled"},[i("li",[t._v("或者你可以去:")]),i("li",{staticClass:"link-type"},[i("router-link",{attrs:{to:"/dashboard"}},[t._v(" 回首页 ")])],1),i("li",{staticClass:"link-type"},[i("a",{attrs:{href:"https://www.taobao.com/"}},[t._v("随便看看")])]),i("li",[i("a",{attrs:{href:"#"},on:{click:function(a){a.preventDefault(),t.dialogVisible=!0}}},[t._v("点我看图")])])])]),i("el-col",{attrs:{span:12}},[i("img",{attrs:{src:t.errGif,width:"313",height:"428",alt:"Girl has dropped her ice cream."}})])],1),i("el-dialog",{attrs:{visible:t.dialogVisible,title:"随便看"},on:{"update:visible":function(a){t.dialogVisible=a}}},[i("img",{staticClass:"pan-img",attrs:{src:t.ewizardClap}})])],1)},s=[],r=i("cc6c"),n=i.n(r),c={name:"Page401",data:function(){return{errGif:n.a+"?"+ +new Date,ewizardClap:"https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646",dialogVisible:!1}},methods:{back:function(){this.$route.query.noGoBack?this.$router.push({path:"/dashboard"}):this.$router.go(-1)}}},l=c,o=(i("1a27"),i("2877")),u=Object(o["a"])(l,e,s,!1,null,"35ca77fc",null);a["default"]=u.exports},a5e5:function(t,a,i){},cc6c:function(t,a,i){t.exports=i.p+"static/img/401.089007e7.gif"}}]); -------------------------------------------------------------------------------- /client/dist/static/js/chunk-5390c43f.d32c89e9.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-5390c43f"],{"122a":function(t,s,a){},"1db4":function(t,s,a){"use strict";a.r(s);var e=function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"wscn-http404-container"},[a("div",{staticClass:"wscn-http404"},[t._m(0),a("div",{staticClass:"bullshit"},[a("div",{staticClass:"bullshit__oops"},[t._v("OOPS!")]),t._m(1),a("div",{staticClass:"bullshit__headline"},[t._v(t._s(t.message))]),a("div",{staticClass:"bullshit__info"},[t._v("Please check that the URL you entered is correct, or click the button below to return to the homepage.")]),a("a",{staticClass:"bullshit__return-home",attrs:{href:""}},[t._v("Back to home")])])])])},c=[function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("div",{staticClass:"pic-404"},[e("img",{staticClass:"pic-404__parent",attrs:{src:a("a36b"),alt:"404"}}),e("img",{staticClass:"pic-404__child left",attrs:{src:a("26fc"),alt:"404"}}),e("img",{staticClass:"pic-404__child mid",attrs:{src:a("26fc"),alt:"404"}}),e("img",{staticClass:"pic-404__child right",attrs:{src:a("26fc"),alt:"404"}})])},function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"bullshit__info"},[t._v("All rights reserved "),a("a",{staticStyle:{color:"#20a0ff"},attrs:{href:"https://wallstreetcn.com",target:"_blank"}},[t._v("wallstreetcn")])])}],i={name:"Page404",computed:{message:function(){return"The webmaster said that you can not enter this page..."}}},l=i,n=(a("35e7"),a("2877")),r=Object(n["a"])(l,e,c,!1,null,"26fcd89f",null);s["default"]=r.exports},"26fc":function(t,s,a){t.exports=a.p+"static/img/404_cloud.0f4bc32b.png"},"35e7":function(t,s,a){"use strict";var e=a("122a"),c=a.n(e);c.a},a36b:function(t,s,a){t.exports=a.p+"static/img/404.a57b6f31.png"}}]); -------------------------------------------------------------------------------- /client/dist/static/js/chunk-a57bb2ee.dd9a58b9.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-a57bb2ee"],{"5fd4":function(t,e,a){"use strict";a.r(e);var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("div",[a("div",{staticClass:"app-container"},[a("el-table",{attrs:{data:t.tableData}},[a("el-table-column",{attrs:{prop:"node_name",label:"节点名称"}}),a("el-table-column",{attrs:{prop:"node_host",label:"节点ip"}}),a("el-table-column",{attrs:{prop:"node_port",label:"节点端口"}}),a("el-table-column",{attrs:{prop:"node_register_time",label:"注册时间"}})],1),a("div",{staticClass:"block",staticStyle:{float:"right"}},[a("el-pagination",{attrs:{"current-page":this.page,"page-sizes":[10,50,100,200],"page-size":this.offset,layout:"total, sizes, prev, pager, next, jumper",total:this.totalNum},on:{"size-change":t.handleSizeChange,"current-change":t.handleCurrentChange}})],1)],1)])},l=[],i=(a("4de4"),a("b775"));function o(t){return Object(i["a"])({url:"/service_manage/get_all_service",method:"post",data:t})}var s={data:function(){return{page:1,offset:10,totalNum:1e3,tableData:[],input:""}},created:function(){this.filter()},methods:{filter:function(){var t=this,e={page:this.page,offset:this.offset,content:this.input};o(e).then((function(e){var a=t.$createElement;t.tableData=e.data.data,t.totalNum=e.data["total_nums"],t.$notify({title:"搜索成功",message:a("i",{style:"color: teal"},"搜索成功"),duration:1e3})})).catch((function(t){console.log(t)}))},handleSizeChange:function(t){this.offset=t},handleCurrentChange:function(t){this.page=t,this.filter()},onSubmit:function(){this.tableData=[],this.filter()}}},r=s,c=(a("dd5b"),a("2877")),u=Object(c["a"])(r,n,l,!1,null,"3dadd6b4",null);e["default"]=u.exports},a461:function(t,e,a){},dd5b:function(t,e,a){"use strict";var n=a("a461"),l=a.n(n);l.a}}]); -------------------------------------------------------------------------------- /client/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: ['js', 'jsx', 'json', 'vue'], 3 | transform: { 4 | '^.+\\.vue$': 'vue-jest', 5 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 6 | 'jest-transform-stub', 7 | '^.+\\.jsx?$': 'babel-jest' 8 | }, 9 | moduleNameMapper: { 10 | '^@/(.*)$': '/src/$1' 11 | }, 12 | snapshotSerializers: ['jest-serializer-vue'], 13 | testMatch: [ 14 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' 15 | ], 16 | collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'], 17 | coverageDirectory: '/tests/unit/coverage', 18 | // 'collectCoverage': true, 19 | 'coverageReporters': [ 20 | 'lcov', 21 | 'text-summary' 22 | ], 23 | testURL: 'http://localhost/' 24 | } 25 | -------------------------------------------------------------------------------- /client/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "paths": { 5 | "@/*": ["src/*"] 6 | } 7 | }, 8 | "exclude": ["node_modules", "dist"] 9 | } -------------------------------------------------------------------------------- /client/mock/index.js: -------------------------------------------------------------------------------- 1 | const Mock = require('mockjs') 2 | const { param2Obj } = require('./utils') 3 | 4 | const user = require('./user') 5 | const role = require('./role') 6 | const article = require('./article') 7 | const search = require('./remote-search') 8 | 9 | const mocks = [ 10 | ...user, 11 | ...role, 12 | ...article, 13 | ...search 14 | ] 15 | 16 | // for front mock 17 | // please use it cautiously, it will redefine XMLHttpRequest, 18 | // which will cause many of your third-party libraries to be invalidated(like progress event). 19 | function mockXHR() { 20 | // mock patch 21 | // https://github.com/nuysoft/Mock/issues/300 22 | Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send 23 | Mock.XHR.prototype.send = function() { 24 | if (this.custom.xhr) { 25 | this.custom.xhr.withCredentials = this.withCredentials || false 26 | 27 | if (this.responseType) { 28 | this.custom.xhr.responseType = this.responseType 29 | } 30 | } 31 | this.proxy_send(...arguments) 32 | } 33 | 34 | function XHR2ExpressReqWrap(respond) { 35 | return function(options) { 36 | let result = null 37 | if (respond instanceof Function) { 38 | const { body, type, url } = options 39 | // https://expressjs.com/en/4x/api.html#req 40 | result = respond({ 41 | method: type, 42 | body: JSON.parse(body), 43 | query: param2Obj(url) 44 | }) 45 | } else { 46 | result = respond 47 | } 48 | return Mock.mock(result) 49 | } 50 | } 51 | 52 | for (const i of mocks) { 53 | Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response)) 54 | } 55 | } 56 | 57 | module.exports = { 58 | mocks, 59 | mockXHR 60 | } 61 | -------------------------------------------------------------------------------- /client/mock/remote-search.js: -------------------------------------------------------------------------------- 1 | const Mock = require('mockjs') 2 | 3 | const NameList = [] 4 | const count = 100 5 | 6 | for (let i = 0; i < count; i++) { 7 | NameList.push(Mock.mock({ 8 | name: '@first' 9 | })) 10 | } 11 | NameList.push({ name: 'mock-Pan' }) 12 | 13 | module.exports = [ 14 | // username search 15 | { 16 | url: '/vue-element-admin/search/user', 17 | type: 'get', 18 | response: config => { 19 | const { name } = config.query 20 | const mockNameList = NameList.filter(item => { 21 | const lowerCaseName = item.name.toLowerCase() 22 | return !(name && lowerCaseName.indexOf(name.toLowerCase()) < 0) 23 | }) 24 | return { 25 | code: 20000, 26 | data: { items: mockNameList } 27 | } 28 | } 29 | }, 30 | 31 | // transaction list 32 | { 33 | url: '/vue-element-admin/transaction/list', 34 | type: 'get', 35 | response: _ => { 36 | return { 37 | code: 20000, 38 | data: { 39 | total: 20, 40 | 'items|20': [{ 41 | order_no: '@guid()', 42 | timestamp: +Mock.Random.date('T'), 43 | username: '@name()', 44 | price: '@float(1000, 15000, 0, 2)', 45 | 'status|1': ['success', 'pending'] 46 | }] 47 | } 48 | } 49 | } 50 | } 51 | ] 52 | -------------------------------------------------------------------------------- /client/mock/user.js: -------------------------------------------------------------------------------- 1 | 2 | const tokens = { 3 | admin: { 4 | token: 'admin-token' 5 | }, 6 | editor: { 7 | token: 'editor-token' 8 | } 9 | } 10 | 11 | const users = { 12 | 'admin-token': { 13 | roles: ['admin'], 14 | introduction: 'I am a super administrator', 15 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', 16 | name: 'Super Admin' 17 | }, 18 | 'editor-token': { 19 | roles: ['editor'], 20 | introduction: 'I am an editor', 21 | avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', 22 | name: 'Normal Editor' 23 | } 24 | } 25 | 26 | module.exports = [ 27 | // user login 28 | { 29 | url: '/vue-element-admin/user/login', 30 | type: 'post', 31 | response: config => { 32 | const { username } = config.body 33 | const token = tokens[username] 34 | 35 | // mock error 36 | if (!token) { 37 | return { 38 | code: 60204, 39 | message: 'Account and password are incorrect.' 40 | } 41 | } 42 | 43 | return { 44 | code: 20000, 45 | data: token 46 | } 47 | } 48 | }, 49 | 50 | // get user info 51 | { 52 | url: '/vue-element-admin/user/info\.*', 53 | type: 'get', 54 | response: config => { 55 | const { token } = config.query 56 | const info = users[token] 57 | 58 | // mock error 59 | if (!info) { 60 | return { 61 | code: 50008, 62 | message: 'Login failed, unable to get user details.' 63 | } 64 | } 65 | 66 | return { 67 | code: 20000, 68 | data: info 69 | } 70 | } 71 | }, 72 | 73 | // user logout 74 | { 75 | url: '/vue-element-admin/user/logout', 76 | type: 'post', 77 | response: _ => { 78 | return { 79 | code: 20000, 80 | data: 'success' 81 | } 82 | } 83 | } 84 | ] 85 | -------------------------------------------------------------------------------- /client/mock/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} url 3 | * @returns {Object} 4 | */ 5 | function param2Obj(url) { 6 | const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') 7 | if (!search) { 8 | return {} 9 | } 10 | const obj = {} 11 | const searchArr = search.split('&') 12 | searchArr.forEach(v => { 13 | const index = v.indexOf('=') 14 | if (index !== -1) { 15 | const name = v.substring(0, index) 16 | const val = v.substring(index + 1, v.length) 17 | obj[name] = val 18 | } 19 | }) 20 | return obj 21 | } 22 | 23 | /** 24 | * This is just a simple version of deep copy 25 | * Has a lot of edge cases bug 26 | * If you want to use a perfect deep copy, use lodash's _.cloneDeep 27 | * @param {Object} source 28 | * @returns {Object} 29 | */ 30 | function deepClone(source) { 31 | if (!source && typeof source !== 'object') { 32 | throw new Error('error arguments', 'deepClone') 33 | } 34 | const targetObj = source.constructor === Array ? [] : {} 35 | Object.keys(source).forEach(keys => { 36 | if (source[keys] && typeof source[keys] === 'object') { 37 | targetObj[keys] = deepClone(source[keys]) 38 | } else { 39 | targetObj[keys] = source[keys] 40 | } 41 | }) 42 | return targetObj 43 | } 44 | 45 | module.exports = { 46 | param2Obj, 47 | deepClone 48 | } 49 | -------------------------------------------------------------------------------- /client/plop-templates/component/index.hbs: -------------------------------------------------------------------------------- 1 | {{#if template}} 2 | 5 | {{/if}} 6 | 7 | {{#if script}} 8 | 20 | {{/if}} 21 | 22 | {{#if style}} 23 | 26 | {{/if}} 27 | -------------------------------------------------------------------------------- /client/plop-templates/component/prompt.js: -------------------------------------------------------------------------------- 1 | const { notEmpty } = require('../utils.js') 2 | 3 | module.exports = { 4 | description: 'generate vue component', 5 | prompts: [{ 6 | type: 'input', 7 | name: 'name', 8 | message: 'component name please', 9 | validate: notEmpty('name') 10 | }, 11 | { 12 | type: 'checkbox', 13 | name: 'blocks', 14 | message: 'Blocks:', 15 | choices: [{ 16 | name: '