初始化项目
Showing
42 changed files
with
1488 additions
and
0 deletions
.editorconfig
0 → 100644
.env.development
0 → 100644
.env.production
0 → 100644
.env.staging
0 → 100644
.eslintignore
0 → 100644
.eslintrc.js
0 → 100644
| 1 | module.exports = { | ||
| 2 | root: true, | ||
| 3 | parserOptions: { | ||
| 4 | parser: 'babel-eslint', | ||
| 5 | sourceType: 'module' | ||
| 6 | }, | ||
| 7 | env: { | ||
| 8 | browser: true, | ||
| 9 | node: true, | ||
| 10 | es6: true | ||
| 11 | }, | ||
| 12 | extends: ['plugin:vue/recommended', 'eslint:recommended'], | ||
| 13 | |||
| 14 | // add your custom rules here | ||
| 15 | //it is base on https://github.com/vuejs/eslint-config-vue | ||
| 16 | rules: { | ||
| 17 | 'vue/max-attributes-per-line': [ | ||
| 18 | 2, | ||
| 19 | { | ||
| 20 | singleline: 10, | ||
| 21 | multiline: { | ||
| 22 | max: 1, | ||
| 23 | allowFirstLine: false | ||
| 24 | } | ||
| 25 | } | ||
| 26 | ], | ||
| 27 | 'vue/singleline-html-element-content-newline': 'off', | ||
| 28 | 'vue/multiline-html-element-content-newline': 'off', | ||
| 29 | 'vue/name-property-casing': ['error', 'PascalCase'], | ||
| 30 | 'vue/no-v-html': 'off', | ||
| 31 | 'accessor-pairs': 2, | ||
| 32 | 'arrow-spacing': [ | ||
| 33 | 2, | ||
| 34 | { | ||
| 35 | before: true, | ||
| 36 | after: true | ||
| 37 | } | ||
| 38 | ], | ||
| 39 | 'block-spacing': [2, 'always'], | ||
| 40 | 'brace-style': [ | ||
| 41 | 2, | ||
| 42 | '1tbs', | ||
| 43 | { | ||
| 44 | allowSingleLine: true | ||
| 45 | } | ||
| 46 | ], | ||
| 47 | camelcase: [ | ||
| 48 | 0, | ||
| 49 | { | ||
| 50 | properties: 'always' | ||
| 51 | } | ||
| 52 | ], | ||
| 53 | 'comma-dangle': [2, 'never'], | ||
| 54 | 'comma-spacing': [ | ||
| 55 | 2, | ||
| 56 | { | ||
| 57 | before: false, | ||
| 58 | after: true | ||
| 59 | } | ||
| 60 | ], | ||
| 61 | 'comma-style': [2, 'last'], | ||
| 62 | 'constructor-super': 2, | ||
| 63 | curly: [2, 'multi-line'], | ||
| 64 | 'dot-location': [2, 'property'], | ||
| 65 | 'eol-last': 2, | ||
| 66 | eqeqeq: ['error', 'always', { null: 'ignore' }], | ||
| 67 | 'generator-star-spacing': [ | ||
| 68 | 2, | ||
| 69 | { | ||
| 70 | before: true, | ||
| 71 | after: true | ||
| 72 | } | ||
| 73 | ], | ||
| 74 | 'handle-callback-err': [2, '^(err|error)$'], | ||
| 75 | 'indent': ['off', 2], | ||
| 76 | 'jsx-quotes': [2, 'prefer-single'], | ||
| 77 | 'key-spacing': [ | ||
| 78 | 2, | ||
| 79 | { | ||
| 80 | beforeColon: false, | ||
| 81 | afterColon: true | ||
| 82 | } | ||
| 83 | ], | ||
| 84 | 'keyword-spacing': [ | ||
| 85 | 2, | ||
| 86 | { | ||
| 87 | before: true, | ||
| 88 | after: true | ||
| 89 | } | ||
| 90 | ], | ||
| 91 | 'new-cap': [ | ||
| 92 | 2, | ||
| 93 | { | ||
| 94 | newIsCap: true, | ||
| 95 | capIsNew: false | ||
| 96 | } | ||
| 97 | ], | ||
| 98 | 'new-parens': 2, | ||
| 99 | 'no-array-constructor': 2, | ||
| 100 | 'no-caller': 2, | ||
| 101 | 'no-console': 'off', | ||
| 102 | 'no-class-assign': 2, | ||
| 103 | 'no-cond-assign': 2, | ||
| 104 | 'no-const-assign': 2, | ||
| 105 | 'no-control-regex': 0, | ||
| 106 | 'no-delete-var': 2, | ||
| 107 | 'no-dupe-args': 2, | ||
| 108 | 'no-dupe-class-members': 2, | ||
| 109 | 'no-dupe-keys': 2, | ||
| 110 | 'no-duplicate-case': 2, | ||
| 111 | 'no-empty-character-class': 2, | ||
| 112 | 'no-empty-pattern': 2, | ||
| 113 | 'no-eval': 2, | ||
| 114 | 'no-ex-assign': 2, | ||
| 115 | 'no-extend-native': 2, | ||
| 116 | 'no-extra-bind': 2, | ||
| 117 | 'no-extra-boolean-cast': 2, | ||
| 118 | 'no-extra-parens': [2, 'functions'], | ||
| 119 | 'no-fallthrough': 2, | ||
| 120 | 'no-floating-decimal': 2, | ||
| 121 | 'no-func-assign': 2, | ||
| 122 | 'no-implied-eval': 2, | ||
| 123 | 'no-inner-declarations': [2, 'functions'], | ||
| 124 | 'no-invalid-regexp': 2, | ||
| 125 | 'no-irregular-whitespace': 2, | ||
| 126 | 'no-iterator': 2, | ||
| 127 | 'no-label-var': 2, | ||
| 128 | 'no-labels': [ | ||
| 129 | 2, | ||
| 130 | { | ||
| 131 | allowLoop: false, | ||
| 132 | allowSwitch: false | ||
| 133 | } | ||
| 134 | ], | ||
| 135 | 'no-lone-blocks': 2, | ||
| 136 | 'no-mixed-spaces-and-tabs': 2, | ||
| 137 | 'no-multi-spaces': 2, | ||
| 138 | 'no-multi-str': 2, | ||
| 139 | 'no-multiple-empty-lines': [ | ||
| 140 | 2, | ||
| 141 | { | ||
| 142 | max: 1 | ||
| 143 | } | ||
| 144 | ], | ||
| 145 | 'no-native-reassign': 2, | ||
| 146 | 'no-negated-in-lhs': 2, | ||
| 147 | 'no-new-object': 2, | ||
| 148 | 'no-new-require': 2, | ||
| 149 | 'no-new-symbol': 2, | ||
| 150 | 'no-new-wrappers': 2, | ||
| 151 | 'no-obj-calls': 2, | ||
| 152 | 'no-octal': 2, | ||
| 153 | 'no-octal-escape': 2, | ||
| 154 | 'no-path-concat': 2, | ||
| 155 | 'no-proto': 2, | ||
| 156 | 'no-redeclare': 2, | ||
| 157 | 'no-regex-spaces': 2, | ||
| 158 | 'no-return-assign': [2, 'except-parens'], | ||
| 159 | 'no-self-assign': 2, | ||
| 160 | 'no-self-compare': 2, | ||
| 161 | 'no-sequences': 2, | ||
| 162 | 'no-shadow-restricted-names': 2, | ||
| 163 | 'no-spaced-func': 2, | ||
| 164 | 'no-sparse-arrays': 2, | ||
| 165 | 'no-this-before-super': 2, | ||
| 166 | 'no-throw-literal': 2, | ||
| 167 | 'no-trailing-spaces': 2, | ||
| 168 | 'no-undef': 2, | ||
| 169 | 'no-undef-init': 2, | ||
| 170 | 'no-unexpected-multiline': 2, | ||
| 171 | 'no-unmodified-loop-condition': 2, | ||
| 172 | 'no-unneeded-ternary': [ | ||
| 173 | 2, | ||
| 174 | { | ||
| 175 | defaultAssignment: false | ||
| 176 | } | ||
| 177 | ], | ||
| 178 | 'no-unreachable': 2, | ||
| 179 | 'no-unsafe-finally': 2, | ||
| 180 | 'no-unused-vars': [ | ||
| 181 | 2, | ||
| 182 | { | ||
| 183 | vars: 'all', | ||
| 184 | args: 'none' | ||
| 185 | } | ||
| 186 | ], | ||
| 187 | 'no-useless-call': 2, | ||
| 188 | 'no-useless-computed-key': 2, | ||
| 189 | 'no-useless-constructor': 2, | ||
| 190 | 'no-useless-escape': 0, | ||
| 191 | 'no-whitespace-before-property': 2, | ||
| 192 | 'no-with': 2, | ||
| 193 | 'one-var': [ | ||
| 194 | 2, | ||
| 195 | { | ||
| 196 | initialized: 'never' | ||
| 197 | } | ||
| 198 | ], | ||
| 199 | 'operator-linebreak': [ | ||
| 200 | 2, | ||
| 201 | 'after', | ||
| 202 | { | ||
| 203 | overrides: { | ||
| 204 | '?': 'before', | ||
| 205 | ':': 'before' | ||
| 206 | } | ||
| 207 | } | ||
| 208 | ], | ||
| 209 | 'padded-blocks': [2, 'never'], | ||
| 210 | quotes: [ | ||
| 211 | 2, | ||
| 212 | 'single', | ||
| 213 | { | ||
| 214 | avoidEscape: true, | ||
| 215 | allowTemplateLiterals: true | ||
| 216 | } | ||
| 217 | ], | ||
| 218 | semi: [2, 'never'], | ||
| 219 | 'semi-spacing': [ | ||
| 220 | 2, | ||
| 221 | { | ||
| 222 | before: false, | ||
| 223 | after: true | ||
| 224 | } | ||
| 225 | ], | ||
| 226 | 'space-before-blocks': [2, 'always'], | ||
| 227 | 'space-before-function-paren': [2, 'never'], | ||
| 228 | 'space-in-parens': [2, 'never'], | ||
| 229 | 'space-infix-ops': 2, | ||
| 230 | 'space-unary-ops': [ | ||
| 231 | 2, | ||
| 232 | { | ||
| 233 | words: true, | ||
| 234 | nonwords: false | ||
| 235 | } | ||
| 236 | ], | ||
| 237 | 'spaced-comment': [ | ||
| 238 | 2, | ||
| 239 | 'always', | ||
| 240 | { | ||
| 241 | markers: [ | ||
| 242 | 'global', | ||
| 243 | 'globals', | ||
| 244 | 'eslint', | ||
| 245 | 'eslint-disable', | ||
| 246 | '*package', | ||
| 247 | '!', | ||
| 248 | ',' | ||
| 249 | ] | ||
| 250 | } | ||
| 251 | ], | ||
| 252 | 'template-curly-spacing': [2, 'never'], | ||
| 253 | 'use-isnan': 2, | ||
| 254 | 'valid-typeof': 2, | ||
| 255 | 'wrap-iife': [2, 'any'], | ||
| 256 | 'yield-star-spacing': [2, 'both'], | ||
| 257 | yoda: [2, 'never'], | ||
| 258 | 'prefer-const': 2, | ||
| 259 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, | ||
| 260 | 'object-curly-spacing': [ | ||
| 261 | 2, | ||
| 262 | 'always', | ||
| 263 | { | ||
| 264 | objectsInObjects: false | ||
| 265 | } | ||
| 266 | ], | ||
| 267 | 'array-bracket-spacing': [2, 'never'], | ||
| 268 | 'vue/html-self-closing': ["error",{ | ||
| 269 | "html": { | ||
| 270 | "void": "never", | ||
| 271 | "normal": "any", | ||
| 272 | "component": "any" | ||
| 273 | }, | ||
| 274 | "svg": "always", | ||
| 275 | "math": "always" | ||
| 276 | }] | ||
| 277 | } | ||
| 278 | } |
.gitignore
0 → 100644
.postcssrc.js
0 → 100644
.travis.yml
0 → 100644
LICENSE
0 → 100644
| 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. |
babel.config.js
0 → 100644
build/index.js
0 → 100644
| 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 = 9018 | ||
| 13 | const 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 | } |
jest.config.js
0 → 100644
| 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 | '^@/(.*)$': '<rootDir>/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: '<rootDir>/tests/unit/coverage', | ||
| 18 | // 'collectCoverage': true, | ||
| 19 | 'coverageReporters': [ | ||
| 20 | 'lcov', | ||
| 21 | 'text-summary' | ||
| 22 | ], | ||
| 23 | testURL: 'http://localhost/' | ||
| 24 | } |
package.json
0 → 100644
| 1 | { | ||
| 2 | "name": "vue-admin-template", | ||
| 3 | "version": "4.1.0", | ||
| 4 | "description": "A vue admin template with Element UI & axios & iconfont & permission control & lint", | ||
| 5 | "author": "Pan <panfree23@gmail.com>", | ||
| 6 | "license": "MIT", | ||
| 7 | "scripts": { | ||
| 8 | "dev": "vue-cli-service serve", | ||
| 9 | "build:prod": "vue-cli-service build", | ||
| 10 | "build:stage": "vue-cli-service build --mode staging", | ||
| 11 | "preview": "node build/index.js --preview", | ||
| 12 | "lint": "eslint --ext .js,.vue src", | ||
| 13 | "test:unit": "jest --clearCache && vue-cli-service test:unit", | ||
| 14 | "test:ci": "npm run lint && npm run test:unit", | ||
| 15 | "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml" | ||
| 16 | }, | ||
| 17 | "dependencies": { | ||
| 18 | "axios": "0.18.0", | ||
| 19 | "lib-flexible": "^0.3.2", | ||
| 20 | "normalize.css": "7.0.0", | ||
| 21 | "vant": "^1.6.19", | ||
| 22 | "vue": "2.6.10", | ||
| 23 | "vue-router": "3.0.6", | ||
| 24 | "vuex": "3.1.0" | ||
| 25 | }, | ||
| 26 | "devDependencies": { | ||
| 27 | "@babel/core": "7.0.0", | ||
| 28 | "@babel/register": "7.0.0", | ||
| 29 | "@vue/cli-plugin-babel": "3.6.0", | ||
| 30 | "@vue/cli-plugin-eslint": "3.6.0", | ||
| 31 | "@vue/cli-plugin-unit-jest": "3.6.3", | ||
| 32 | "@vue/cli-service": "3.6.0", | ||
| 33 | "@vue/test-utils": "1.0.0-beta.29", | ||
| 34 | "babel-core": "7.0.0-bridge.0", | ||
| 35 | "babel-eslint": "10.0.1", | ||
| 36 | "babel-jest": "23.6.0", | ||
| 37 | "babel-plugin-import": "^1.11.2", | ||
| 38 | "chalk": "2.4.2", | ||
| 39 | "connect": "3.6.6", | ||
| 40 | "eslint": "5.15.3", | ||
| 41 | "eslint-plugin-vue": "5.2.2", | ||
| 42 | "html-webpack-plugin": "3.2.0", | ||
| 43 | "node-sass": "^4.9.0", | ||
| 44 | "postcss-pxtorem": "^4.0.1", | ||
| 45 | "runjs": "^4.3.2", | ||
| 46 | "sass-loader": "^7.1.0", | ||
| 47 | "script-ext-html-webpack-plugin": "2.1.3", | ||
| 48 | "script-loader": "0.7.2", | ||
| 49 | "serve-static": "^1.13.2", | ||
| 50 | "svgo": "1.2.2", | ||
| 51 | "vue-template-compiler": "2.6.10" | ||
| 52 | }, | ||
| 53 | "engines": { | ||
| 54 | "node": ">=8.9", | ||
| 55 | "npm": ">= 3.0.0" | ||
| 56 | }, | ||
| 57 | "browserslist": [ | ||
| 58 | "> 1%", | ||
| 59 | "last 2 versions", | ||
| 60 | "not ie <= 8" | ||
| 61 | ] | ||
| 62 | } |
public/favicon.ico
0 → 100644
No preview for this file type
public/index.html
0 → 100644
| 1 | <!DOCTYPE html> | ||
| 2 | <html> | ||
| 3 | <head> | ||
| 4 | <meta charset="utf-8"> | ||
| 5 | <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | ||
| 6 | <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> | ||
| 7 | |||
| 8 | <link rel="icon" href="<%= BASE_URL %>favicon.ico"> | ||
| 9 | <title><%= webpackConfig.name %></title> | ||
| 10 | </head> | ||
| 11 | <body> | ||
| 12 | <noscript> | ||
| 13 | <strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> | ||
| 14 | </noscript> | ||
| 15 | <div id="app"></div> | ||
| 16 | <!-- built files will be auto injected --> | ||
| 17 | </body> | ||
| 18 | </html> |
src/App.vue
0 → 100644
src/api/user.js
0 → 100644
src/assets/404_images/404.png
0 → 100644
95.8 KB
src/assets/404_images/404_cloud.png
0 → 100644
4.65 KB
src/assets/css/element-ui.scss
0 → 100644
| 1 | // cover some element-ui styles | ||
| 2 | |||
| 3 | .el-breadcrumb__inner, | ||
| 4 | .el-breadcrumb__inner a { | ||
| 5 | font-weight: 400 !important; | ||
| 6 | } | ||
| 7 | |||
| 8 | .el-upload { | ||
| 9 | input[type="file"] { | ||
| 10 | display: none !important; | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | .el-upload__input { | ||
| 15 | display: none; | ||
| 16 | } | ||
| 17 | |||
| 18 | |||
| 19 | // to fixed https://github.com/ElemeFE/element/issues/2461 | ||
| 20 | .el-dialog { | ||
| 21 | transform: none; | ||
| 22 | left: 0; | ||
| 23 | position: relative; | ||
| 24 | margin: 0 auto; | ||
| 25 | } | ||
| 26 | |||
| 27 | // refine element ui upload | ||
| 28 | .upload-container { | ||
| 29 | .el-upload { | ||
| 30 | width: 100%; | ||
| 31 | |||
| 32 | .el-upload-dragger { | ||
| 33 | width: 100%; | ||
| 34 | height: 200px; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | ||
| 38 | |||
| 39 | // dropdown | ||
| 40 | .el-dropdown-menu { | ||
| 41 | a { | ||
| 42 | display: block | ||
| 43 | } | ||
| 44 | } |
src/assets/css/index.scss
0 → 100644
| 1 | @import './variables.scss'; | ||
| 2 | @import './mixin.scss'; | ||
| 3 | @import './transition.scss'; | ||
| 4 | @import './element-ui.scss'; | ||
| 5 | @import './sidebar.scss'; | ||
| 6 | |||
| 7 | body { | ||
| 8 | height: 100%; | ||
| 9 | -moz-osx-font-smoothing: grayscale; | ||
| 10 | -webkit-font-smoothing: antialiased; | ||
| 11 | text-rendering: optimizeLegibility; | ||
| 12 | font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; | ||
| 13 | } | ||
| 14 | |||
| 15 | label { | ||
| 16 | font-weight: 700; | ||
| 17 | } | ||
| 18 | |||
| 19 | html { | ||
| 20 | height: 100%; | ||
| 21 | box-sizing: border-box; | ||
| 22 | } | ||
| 23 | |||
| 24 | #app { | ||
| 25 | height: 100%; | ||
| 26 | } | ||
| 27 | |||
| 28 | *, | ||
| 29 | *:before, | ||
| 30 | *:after { | ||
| 31 | box-sizing: inherit; | ||
| 32 | } | ||
| 33 | |||
| 34 | a:focus, | ||
| 35 | a:active { | ||
| 36 | outline: none; | ||
| 37 | } | ||
| 38 | |||
| 39 | a, | ||
| 40 | a:focus, | ||
| 41 | a:hover { | ||
| 42 | cursor: pointer; | ||
| 43 | color: inherit; | ||
| 44 | text-decoration: none; | ||
| 45 | } | ||
| 46 | |||
| 47 | div:focus { | ||
| 48 | outline: none; | ||
| 49 | } | ||
| 50 | |||
| 51 | .clearfix { | ||
| 52 | &:after { | ||
| 53 | visibility: hidden; | ||
| 54 | display: block; | ||
| 55 | font-size: 0; | ||
| 56 | content: " "; | ||
| 57 | clear: both; | ||
| 58 | height: 0; | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | // main-container global css | ||
| 63 | .app-container { | ||
| 64 | padding: 20px; | ||
| 65 | } |
src/assets/css/mixin.scss
0 → 100644
| 1 | @mixin clearfix { | ||
| 2 | &:after { | ||
| 3 | content: ""; | ||
| 4 | display: table; | ||
| 5 | clear: both; | ||
| 6 | } | ||
| 7 | } | ||
| 8 | |||
| 9 | @mixin scrollBar { | ||
| 10 | &::-webkit-scrollbar-track-piece { | ||
| 11 | background: #d3dce6; | ||
| 12 | } | ||
| 13 | |||
| 14 | &::-webkit-scrollbar { | ||
| 15 | width: 6px; | ||
| 16 | } | ||
| 17 | |||
| 18 | &::-webkit-scrollbar-thumb { | ||
| 19 | background: #99a9bf; | ||
| 20 | border-radius: 20px; | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | @mixin relative { | ||
| 25 | position: relative; | ||
| 26 | width: 100%; | ||
| 27 | height: 100%; | ||
| 28 | } |
src/assets/css/sidebar.scss
0 → 100644
| 1 | #app { | ||
| 2 | |||
| 3 | .main-container { | ||
| 4 | min-height: 100%; | ||
| 5 | transition: margin-left .28s; | ||
| 6 | margin-left: $sideBarWidth; | ||
| 7 | position: relative; | ||
| 8 | } | ||
| 9 | |||
| 10 | .sidebar-container { | ||
| 11 | transition: width 0.28s; | ||
| 12 | width: $sideBarWidth !important; | ||
| 13 | background-color: $menuBg; | ||
| 14 | height: 100%; | ||
| 15 | position: fixed; | ||
| 16 | font-size: 0px; | ||
| 17 | top: 0; | ||
| 18 | bottom: 0; | ||
| 19 | left: 0; | ||
| 20 | z-index: 1001; | ||
| 21 | overflow: hidden; | ||
| 22 | |||
| 23 | // reset element-ui css | ||
| 24 | .horizontal-collapse-transition { | ||
| 25 | transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; | ||
| 26 | } | ||
| 27 | |||
| 28 | .scrollbar-wrapper { | ||
| 29 | overflow-x: hidden !important; | ||
| 30 | } | ||
| 31 | |||
| 32 | .el-scrollbar__bar.is-vertical { | ||
| 33 | right: 0px; | ||
| 34 | } | ||
| 35 | |||
| 36 | .el-scrollbar { | ||
| 37 | height: 100%; | ||
| 38 | } | ||
| 39 | |||
| 40 | &.has-logo { | ||
| 41 | .el-scrollbar { | ||
| 42 | height: calc(100% - 50px); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | .is-horizontal { | ||
| 47 | display: none; | ||
| 48 | } | ||
| 49 | |||
| 50 | a { | ||
| 51 | display: inline-block; | ||
| 52 | width: 100%; | ||
| 53 | overflow: hidden; | ||
| 54 | } | ||
| 55 | |||
| 56 | .svg-icon { | ||
| 57 | margin-right: 16px; | ||
| 58 | } | ||
| 59 | |||
| 60 | .el-menu { | ||
| 61 | border: none; | ||
| 62 | height: 100%; | ||
| 63 | width: 100% !important; | ||
| 64 | } | ||
| 65 | |||
| 66 | // menu hover | ||
| 67 | .submenu-title-noDropdown, | ||
| 68 | .el-submenu__title { | ||
| 69 | &:hover { | ||
| 70 | background-color: $menuHover !important; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | .is-active>.el-submenu__title { | ||
| 75 | color: $subMenuActiveText !important; | ||
| 76 | } | ||
| 77 | |||
| 78 | & .nest-menu .el-submenu>.el-submenu__title, | ||
| 79 | & .el-submenu .el-menu-item { | ||
| 80 | min-width: $sideBarWidth !important; | ||
| 81 | background-color: $subMenuBg !important; | ||
| 82 | |||
| 83 | &:hover { | ||
| 84 | background-color: $subMenuHover !important; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | .hideSidebar { | ||
| 90 | .sidebar-container { | ||
| 91 | width: 54px !important; | ||
| 92 | } | ||
| 93 | |||
| 94 | .main-container { | ||
| 95 | margin-left: 54px; | ||
| 96 | } | ||
| 97 | |||
| 98 | .submenu-title-noDropdown { | ||
| 99 | padding: 0 !important; | ||
| 100 | position: relative; | ||
| 101 | |||
| 102 | .el-tooltip { | ||
| 103 | padding: 0 !important; | ||
| 104 | |||
| 105 | .svg-icon { | ||
| 106 | margin-left: 20px; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | .el-submenu { | ||
| 112 | overflow: hidden; | ||
| 113 | |||
| 114 | &>.el-submenu__title { | ||
| 115 | padding: 0 !important; | ||
| 116 | |||
| 117 | .svg-icon { | ||
| 118 | margin-left: 20px; | ||
| 119 | } | ||
| 120 | |||
| 121 | .el-submenu__icon-arrow { | ||
| 122 | display: none; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | .el-menu--collapse { | ||
| 128 | .el-submenu { | ||
| 129 | &>.el-submenu__title { | ||
| 130 | &>span { | ||
| 131 | height: 0; | ||
| 132 | width: 0; | ||
| 133 | overflow: hidden; | ||
| 134 | visibility: hidden; | ||
| 135 | display: inline-block; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | } | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | .el-menu--collapse .el-menu .el-submenu { | ||
| 143 | min-width: $sideBarWidth !important; | ||
| 144 | } | ||
| 145 | |||
| 146 | // mobile responsive | ||
| 147 | .mobile { | ||
| 148 | .main-container { | ||
| 149 | margin-left: 0px; | ||
| 150 | } | ||
| 151 | |||
| 152 | .sidebar-container { | ||
| 153 | transition: transform .28s; | ||
| 154 | width: $sideBarWidth !important; | ||
| 155 | } | ||
| 156 | |||
| 157 | &.hideSidebar { | ||
| 158 | .sidebar-container { | ||
| 159 | pointer-events: none; | ||
| 160 | transition-duration: 0.3s; | ||
| 161 | transform: translate3d(-$sideBarWidth, 0, 0); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | .withoutAnimation { | ||
| 167 | |||
| 168 | .main-container, | ||
| 169 | .sidebar-container { | ||
| 170 | transition: none; | ||
| 171 | } | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | // when menu collapsed | ||
| 176 | .el-menu--vertical { | ||
| 177 | &>.el-menu { | ||
| 178 | .svg-icon { | ||
| 179 | margin-right: 16px; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | .nest-menu .el-submenu>.el-submenu__title, | ||
| 184 | .el-menu-item { | ||
| 185 | &:hover { | ||
| 186 | // you can use $subMenuHover | ||
| 187 | background-color: $menuHover !important; | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | // the scroll bar appears when the subMenu is too long | ||
| 192 | >.el-menu--popup { | ||
| 193 | max-height: 100vh; | ||
| 194 | overflow-y: auto; | ||
| 195 | |||
| 196 | &::-webkit-scrollbar-track-piece { | ||
| 197 | background: #d3dce6; | ||
| 198 | } | ||
| 199 | |||
| 200 | &::-webkit-scrollbar { | ||
| 201 | width: 6px; | ||
| 202 | } | ||
| 203 | |||
| 204 | &::-webkit-scrollbar-thumb { | ||
| 205 | background: #99a9bf; | ||
| 206 | border-radius: 20px; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | } |
src/assets/css/transition.scss
0 → 100644
| 1 | // global transition css | ||
| 2 | |||
| 3 | /* fade */ | ||
| 4 | .fade-enter-active, | ||
| 5 | .fade-leave-active { | ||
| 6 | transition: opacity 0.28s; | ||
| 7 | } | ||
| 8 | |||
| 9 | .fade-enter, | ||
| 10 | .fade-leave-active { | ||
| 11 | opacity: 0; | ||
| 12 | } | ||
| 13 | |||
| 14 | /* fade-transform */ | ||
| 15 | .fade-transform-leave-active, | ||
| 16 | .fade-transform-enter-active { | ||
| 17 | transition: all .5s; | ||
| 18 | } | ||
| 19 | |||
| 20 | .fade-transform-enter { | ||
| 21 | opacity: 0; | ||
| 22 | transform: translateX(-30px); | ||
| 23 | } | ||
| 24 | |||
| 25 | .fade-transform-leave-to { | ||
| 26 | opacity: 0; | ||
| 27 | transform: translateX(30px); | ||
| 28 | } | ||
| 29 | |||
| 30 | /* breadcrumb transition */ | ||
| 31 | .breadcrumb-enter-active, | ||
| 32 | .breadcrumb-leave-active { | ||
| 33 | transition: all .5s; | ||
| 34 | } | ||
| 35 | |||
| 36 | .breadcrumb-enter, | ||
| 37 | .breadcrumb-leave-active { | ||
| 38 | opacity: 0; | ||
| 39 | transform: translateX(20px); | ||
| 40 | } | ||
| 41 | |||
| 42 | .breadcrumb-move { | ||
| 43 | transition: all .5s; | ||
| 44 | } | ||
| 45 | |||
| 46 | .breadcrumb-leave-active { | ||
| 47 | position: absolute; | ||
| 48 | } |
src/assets/css/variables.scss
0 → 100644
| 1 | // sidebar | ||
| 2 | $menuText:#bfcbd9; | ||
| 3 | $menuActiveText:#409EFF; | ||
| 4 | $subMenuActiveText:#f4f4f5; //https://github.com/ElemeFE/element/issues/12951 | ||
| 5 | |||
| 6 | $menuBg:#304156; | ||
| 7 | $menuHover:#263445; | ||
| 8 | |||
| 9 | $subMenuBg:#1f2d3d; | ||
| 10 | $subMenuHover:#001528; | ||
| 11 | |||
| 12 | $sideBarWidth: 210px; | ||
| 13 | |||
| 14 | // the :export directive is the magic sauce for webpack | ||
| 15 | // https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass | ||
| 16 | :export { | ||
| 17 | menuText: $menuText; | ||
| 18 | menuActiveText: $menuActiveText; | ||
| 19 | subMenuActiveText: $subMenuActiveText; | ||
| 20 | menuBg: $menuBg; | ||
| 21 | menuHover: $menuHover; | ||
| 22 | subMenuBg: $subMenuBg; | ||
| 23 | subMenuHover: $subMenuHover; | ||
| 24 | sideBarWidth: $sideBarWidth; | ||
| 25 | } |
src/config/env.development.js
0 → 100644
src/config/env.production.js
0 → 100644
src/config/env.staging.js
0 → 100644
src/config/index.js
0 → 100644
src/main.js
0 → 100644
| 1 | import Vue from 'vue' | ||
| 2 | |||
| 3 | import 'normalize.css/normalize.css' // A modern alternative to CSS resets | ||
| 4 | import '@/assets/css/index.scss' // global css | ||
| 5 | //移动端适配 | ||
| 6 | import "lib-flexible/flexible.js" | ||
| 7 | import App from './App' | ||
| 8 | import store from './store' | ||
| 9 | import router from './router' | ||
| 10 | Vue.config.productionTip = false | ||
| 11 | |||
| 12 | new Vue({ | ||
| 13 | el: '#app', | ||
| 14 | router, | ||
| 15 | store, | ||
| 16 | render: h => h(App) | ||
| 17 | }) |
src/router/index.js
0 → 100644
| 1 | import Vue from 'vue' | ||
| 2 | import Router from 'vue-router' | ||
| 3 | |||
| 4 | Vue.use(Router) | ||
| 5 | export const constantRoutes = [ | ||
| 6 | { | ||
| 7 | path: '/', | ||
| 8 | component: () => import('@/views/home/index'), | ||
| 9 | meta: { | ||
| 10 | keepAlive: false | ||
| 11 | } | ||
| 12 | } | ||
| 13 | ] | ||
| 14 | |||
| 15 | const createRouter = () => | ||
| 16 | new Router({ | ||
| 17 | // mode: 'history', // require service support | ||
| 18 | scrollBehavior: () => ({ y: 0 }), | ||
| 19 | routes: constantRoutes | ||
| 20 | }) | ||
| 21 | |||
| 22 | export default createRouter() |
src/store/getters.js
0 → 100644
src/store/index.js
0 → 100644
src/store/modules/app.js
0 → 100644
src/utils/index.js
0 → 100644
| 1 | /** | ||
| 2 | * Created by PanJiaChen on 16/11/18. | ||
| 3 | */ | ||
| 4 | |||
| 5 | /** | ||
| 6 | * Parse the time to string | ||
| 7 | * @param {(Object|string|number)} time | ||
| 8 | * @param {string} cFormat | ||
| 9 | * @returns {string} | ||
| 10 | */ | ||
| 11 | export function parseTime(time, cFormat) { | ||
| 12 | if (arguments.length === 0) { | ||
| 13 | return null | ||
| 14 | } | ||
| 15 | const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}' | ||
| 16 | let date | ||
| 17 | if (typeof time === 'object') { | ||
| 18 | date = time | ||
| 19 | } else { | ||
| 20 | if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { | ||
| 21 | time = parseInt(time) | ||
| 22 | } | ||
| 23 | if ((typeof time === 'number') && (time.toString().length === 10)) { | ||
| 24 | time = time * 1000 | ||
| 25 | } | ||
| 26 | date = new Date(time) | ||
| 27 | } | ||
| 28 | const formatObj = { | ||
| 29 | y: date.getFullYear(), | ||
| 30 | m: date.getMonth() + 1, | ||
| 31 | d: date.getDate(), | ||
| 32 | h: date.getHours(), | ||
| 33 | i: date.getMinutes(), | ||
| 34 | s: date.getSeconds(), | ||
| 35 | a: date.getDay() | ||
| 36 | } | ||
| 37 | const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { | ||
| 38 | let value = formatObj[key] | ||
| 39 | // Note: getDay() returns 0 on Sunday | ||
| 40 | if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] } | ||
| 41 | if (result.length > 0 && value < 10) { | ||
| 42 | value = '0' + value | ||
| 43 | } | ||
| 44 | return value || 0 | ||
| 45 | }) | ||
| 46 | return time_str | ||
| 47 | } | ||
| 48 | |||
| 49 | /** | ||
| 50 | * @param {number} time | ||
| 51 | * @param {string} option | ||
| 52 | * @returns {string} | ||
| 53 | */ | ||
| 54 | export function formatTime(time, option) { | ||
| 55 | if (('' + time).length === 10) { | ||
| 56 | time = parseInt(time) * 1000 | ||
| 57 | } else { | ||
| 58 | time = +time | ||
| 59 | } | ||
| 60 | const d = new Date(time) | ||
| 61 | const now = Date.now() | ||
| 62 | |||
| 63 | const diff = (now - d) / 1000 | ||
| 64 | |||
| 65 | if (diff < 30) { | ||
| 66 | return '刚刚' | ||
| 67 | } else if (diff < 3600) { | ||
| 68 | // less 1 hour | ||
| 69 | return Math.ceil(diff / 60) + '分钟前' | ||
| 70 | } else if (diff < 3600 * 24) { | ||
| 71 | return Math.ceil(diff / 3600) + '小时前' | ||
| 72 | } else if (diff < 3600 * 24 * 2) { | ||
| 73 | return '1天前' | ||
| 74 | } | ||
| 75 | if (option) { | ||
| 76 | return parseTime(time, option) | ||
| 77 | } else { | ||
| 78 | return ( | ||
| 79 | d.getMonth() + | ||
| 80 | 1 + | ||
| 81 | '月' + | ||
| 82 | d.getDate() + | ||
| 83 | '日' + | ||
| 84 | d.getHours() + | ||
| 85 | '时' + | ||
| 86 | d.getMinutes() + | ||
| 87 | '分' | ||
| 88 | ) | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | /** | ||
| 93 | * @param {string} url | ||
| 94 | * @returns {Object} | ||
| 95 | */ | ||
| 96 | export function param2Obj(url) { | ||
| 97 | const search = url.split('?')[1] | ||
| 98 | if (!search) { | ||
| 99 | return {} | ||
| 100 | } | ||
| 101 | return JSON.parse( | ||
| 102 | '{"' + | ||
| 103 | decodeURIComponent(search) | ||
| 104 | .replace(/"/g, '\\"') | ||
| 105 | .replace(/&/g, '","') | ||
| 106 | .replace(/=/g, '":"') | ||
| 107 | .replace(/\+/g, ' ') + | ||
| 108 | '"}' | ||
| 109 | ) | ||
| 110 | } |
src/utils/request.1.js
0 → 100644
| 1 | import axios from 'axios' | ||
| 2 | import store from '@/store' | ||
| 3 | |||
| 4 | // create an axios instance | ||
| 5 | const service = axios.create({ | ||
| 6 | baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url | ||
| 7 | withCredentials: true, // send cookies when cross-domain requests | ||
| 8 | timeout: 5000 // request timeout | ||
| 9 | }) | ||
| 10 | |||
| 11 | // request interceptor | ||
| 12 | service.interceptors.request.use( | ||
| 13 | config => { | ||
| 14 | // do something before request is sent | ||
| 15 | if (store.getters.token) { | ||
| 16 | // let each request carry token | ||
| 17 | // ['X-Token'] is a custom headers key | ||
| 18 | // please modify it according to the actual situation | ||
| 19 | config.headers['X-Token'] = '' | ||
| 20 | } | ||
| 21 | return config | ||
| 22 | }, | ||
| 23 | error => { | ||
| 24 | // do something with request error | ||
| 25 | console.log(error) // for debug | ||
| 26 | return Promise.reject(error) | ||
| 27 | } | ||
| 28 | ) | ||
| 29 | |||
| 30 | // response interceptor | ||
| 31 | service.interceptors.response.use( | ||
| 32 | response => { | ||
| 33 | const res = response.data | ||
| 34 | |||
| 35 | // if the custom code is not 20000, it is judged as an error. | ||
| 36 | if (res.code !== 20000) { | ||
| 37 | Message({ | ||
| 38 | message: res.message || 'error', | ||
| 39 | type: 'error', | ||
| 40 | duration: 5 * 1000 | ||
| 41 | }) | ||
| 42 | |||
| 43 | // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; | ||
| 44 | if (res.code === 50008 || res.code === 50012 || res.code === 50014) { | ||
| 45 | // to re-login | ||
| 46 | MessageBox.confirm( | ||
| 47 | 'You have been logged out, you can cancel to stay on this page, or log in again', | ||
| 48 | 'Confirm logout', | ||
| 49 | { | ||
| 50 | confirmButtonText: 'Re-Login', | ||
| 51 | cancelButtonText: 'Cancel', | ||
| 52 | type: 'warning' | ||
| 53 | } | ||
| 54 | ).then(() => { | ||
| 55 | store.dispatch('user/resetToken').then(() => { | ||
| 56 | location.reload() | ||
| 57 | }) | ||
| 58 | }) | ||
| 59 | } | ||
| 60 | return Promise.reject(res.message || 'error') | ||
| 61 | } else { | ||
| 62 | return res | ||
| 63 | } | ||
| 64 | }, | ||
| 65 | error => { | ||
| 66 | console.log('err' + error) // for debug | ||
| 67 | Message({ | ||
| 68 | message: error.message, | ||
| 69 | type: 'error', | ||
| 70 | duration: 5 * 1000 | ||
| 71 | }) | ||
| 72 | return Promise.reject(error) | ||
| 73 | } | ||
| 74 | ) | ||
| 75 | |||
| 76 | export default service |
src/utils/request.js
0 → 100644
| 1 | import axios from 'axios' | ||
| 2 | import store from '@/store' | ||
| 3 | import { Toast } from 'vant' | ||
| 4 | // create an axios instance | ||
| 5 | const service = axios.create({ | ||
| 6 | baseURL: process.env.BASE_URL, // url = base url + request url | ||
| 7 | withCredentials: true, // send cookies when cross-domain requests | ||
| 8 | timeout: 5000 // request timeout | ||
| 9 | }) | ||
| 10 | |||
| 11 | // request拦截器 request interceptor | ||
| 12 | service.interceptors.request.use( | ||
| 13 | config => { | ||
| 14 | // 不传递默认开启loading | ||
| 15 | if (!config.hideloading) { | ||
| 16 | // loading | ||
| 17 | Toast.loading({ | ||
| 18 | forbidClick: true | ||
| 19 | }) | ||
| 20 | } | ||
| 21 | if (store.getters.token) { | ||
| 22 | config.headers['X-Token'] = '' | ||
| 23 | } | ||
| 24 | return config | ||
| 25 | }, | ||
| 26 | error => { | ||
| 27 | // do something with request error | ||
| 28 | console.log(error) // for debug | ||
| 29 | return Promise.reject(error) | ||
| 30 | } | ||
| 31 | ) | ||
| 32 | // respone拦截器 | ||
| 33 | service.interceptors.response.use( | ||
| 34 | response => { | ||
| 35 | Toast.clear() | ||
| 36 | // 如果是数据流 | ||
| 37 | if (response.config.responseType === 'arraybuffer') { | ||
| 38 | return response.data | ||
| 39 | } else { | ||
| 40 | const res = response.data | ||
| 41 | if (res.status !== 200) { | ||
| 42 | // 登录超时,重新登录 | ||
| 43 | if (res.status === 401) { | ||
| 44 | store.dispatch('FedLogOut').then(() => { | ||
| 45 | location.reload() | ||
| 46 | }) | ||
| 47 | } | ||
| 48 | return Promise.reject(res || 'error') | ||
| 49 | } else { | ||
| 50 | return Promise.resolve(res) | ||
| 51 | } | ||
| 52 | } | ||
| 53 | }, | ||
| 54 | error => { | ||
| 55 | Toast.clear() | ||
| 56 | console.log('err' + error) // for debug | ||
| 57 | return Promise.reject(error) | ||
| 58 | } | ||
| 59 | ) | ||
| 60 | |||
| 61 | export default service |
src/utils/signature.js
0 → 100644
File mode changed
src/utils/validate.js
0 → 100644
| 1 | /** | ||
| 2 | * Created by PanJiaChen on 16/11/18. | ||
| 3 | */ | ||
| 4 | |||
| 5 | /** | ||
| 6 | * @param {string} path | ||
| 7 | * @returns {Boolean} | ||
| 8 | */ | ||
| 9 | export function isExternal(path) { | ||
| 10 | return /^(https?:|mailto:|tel:)/.test(path) | ||
| 11 | } | ||
| 12 | |||
| 13 | /** | ||
| 14 | * @param {string} str | ||
| 15 | * @returns {Boolean} | ||
| 16 | */ | ||
| 17 | export function validUsername(str) { | ||
| 18 | const valid_map = ['admin', 'editor'] | ||
| 19 | return valid_map.indexOf(str.trim()) >= 0 | ||
| 20 | } |
src/views/home/index.vue
0 → 100644
| 1 | <!-- home --> | ||
| 2 | <template> | ||
| 3 | <div> | ||
| 4 | <h1>home</h1> | ||
| 5 | <van-button type="primary">主要按钮</van-button> | ||
| 6 | </div> | ||
| 7 | </template> | ||
| 8 | |||
| 9 | <script> | ||
| 10 | import { | ||
| 11 | Button | ||
| 12 | } from 'vant' | ||
| 13 | export default { | ||
| 14 | data() { | ||
| 15 | return {}; | ||
| 16 | }, | ||
| 17 | |||
| 18 | components: { | ||
| 19 | 'van-button': Button | ||
| 20 | }, | ||
| 21 | |||
| 22 | computed: {}, | ||
| 23 | |||
| 24 | mounted() {}, | ||
| 25 | |||
| 26 | methods: {} | ||
| 27 | } | ||
| 28 | |||
| 29 | </script> | ||
| 30 | <style lang='scss' scoped> | ||
| 31 | h1 { | ||
| 32 | background: red; | ||
| 33 | width: 375px; | ||
| 34 | } | ||
| 35 | |||
| 36 | </style> |
vue.config.js
0 → 100644
| 1 | 'use strict' | ||
| 2 | const path = require('path') | ||
| 3 | const defaultSettings = require('./src/config/index.js') | ||
| 4 | function resolve(dir) { | ||
| 5 | return path.join(__dirname, dir) | ||
| 6 | } | ||
| 7 | |||
| 8 | const name = defaultSettings.title || 'vue mobile template' // page title | ||
| 9 | const port = 9018 // dev port | ||
| 10 | module.exports = { | ||
| 11 | publicPath: '/', | ||
| 12 | outputDir: 'dist', | ||
| 13 | assetsDir: 'static', | ||
| 14 | lintOnSave: process.env.NODE_ENV === 'development', | ||
| 15 | productionSourceMap: false, | ||
| 16 | devServer: { | ||
| 17 | port: port, | ||
| 18 | open: true, | ||
| 19 | overlay: { | ||
| 20 | warnings: false, | ||
| 21 | errors: true | ||
| 22 | } | ||
| 23 | }, | ||
| 24 | // css: { | ||
| 25 | // loaderOptions: { | ||
| 26 | // postcss: { | ||
| 27 | // plugins: [ | ||
| 28 | // require('postcss-plugin-px2rem')({ | ||
| 29 | // rootValue: 75, // 换算基数, 默认100 ,这样的话把根标签的字体规定为1rem为50px,这样就可以从设计稿上量出多少个px直接在代码中写多上px了。 | ||
| 30 | // // unitPrecision: 5, //允许REM单位增长到的十进制数字。 | ||
| 31 | // // propWhiteList: [], //默认值是一个空数组,这意味着禁用白名单并启用所有属性。 | ||
| 32 | // // propBlackList: [], //黑名单 | ||
| 33 | // exclude: /(node_module)/, // 默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)\/如果想把前端UI框架内的px也转换成rem,请把此属性设为默认值 | ||
| 34 | // // selectorBlackList: [], //要忽略并保留为px的选择器 | ||
| 35 | // // ignoreIdentifier: false, //(boolean/string)忽略单个属性的方法,启用ignoreidentifier后,replace将自动设置为true。 | ||
| 36 | // // replace: true, // (布尔值)替换包含REM的规则,而不是添加回退。 | ||
| 37 | // mediaQuery: false, // (布尔值)允许在媒体查询中转换px。 | ||
| 38 | // minPixelValue: 3 // 设置要替换的最小像素值(3px会被转rem)。 默认 0 | ||
| 39 | // }) | ||
| 40 | // ] | ||
| 41 | // } | ||
| 42 | // } | ||
| 43 | // }, | ||
| 44 | configureWebpack: { | ||
| 45 | name: name, | ||
| 46 | resolve: { | ||
| 47 | alias: { | ||
| 48 | '@': resolve('src') | ||
| 49 | } | ||
| 50 | } | ||
| 51 | }, | ||
| 52 | chainWebpack(config) { | ||
| 53 | config.plugins.delete('preload') // TODO: need test | ||
| 54 | config.plugins.delete('prefetch') // TODO: need test | ||
| 55 | // set preserveWhitespace | ||
| 56 | config.module | ||
| 57 | .rule('vue') | ||
| 58 | .use('vue-loader') | ||
| 59 | .loader('vue-loader') | ||
| 60 | .tap(options => { | ||
| 61 | options.compilerOptions.preserveWhitespace = true | ||
| 62 | return options | ||
| 63 | }) | ||
| 64 | .end() | ||
| 65 | |||
| 66 | config | ||
| 67 | // https://webpack.js.org/configuration/devtool/#development | ||
| 68 | .when(process.env.NODE_ENV === 'development', config => | ||
| 69 | config.devtool('cheap-source-map') | ||
| 70 | ) | ||
| 71 | |||
| 72 | config.when(process.env.NODE_ENV !== 'development', config => { | ||
| 73 | console.log(config) | ||
| 74 | config | ||
| 75 | .plugin('ScriptExtHtmlWebpackPlugin') | ||
| 76 | .after('html') | ||
| 77 | .use('script-ext-html-webpack-plugin', [ | ||
| 78 | { | ||
| 79 | // `runtime` must same as runtimeChunk name. default is `runtime` | ||
| 80 | inline: /runtime\..*\.js$/ | ||
| 81 | } | ||
| 82 | ]) | ||
| 83 | .end() | ||
| 84 | config.optimization.splitChunks({ | ||
| 85 | chunks: 'all', | ||
| 86 | cacheGroups: { | ||
| 87 | libs: { | ||
| 88 | name: 'chunk-libs', | ||
| 89 | test: /[\\/]node_modules[\\/]/, | ||
| 90 | priority: 10, | ||
| 91 | chunks: 'initial' // only package third parties that are initially dependent | ||
| 92 | }, | ||
| 93 | // elementUI: { | ||
| 94 | // name: 'chunk-elementUI', // split elementUI into a single package | ||
| 95 | // priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app | ||
| 96 | // test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm | ||
| 97 | // }, | ||
| 98 | commons: { | ||
| 99 | name: 'chunk-commons', | ||
| 100 | test: resolve('src/components'), // can customize your rules | ||
| 101 | minChunks: 3, // minimum common number | ||
| 102 | priority: 5, | ||
| 103 | reuseExistingChunk: true | ||
| 104 | } | ||
| 105 | } | ||
| 106 | }) | ||
| 107 | config.optimization.runtimeChunk('single') | ||
| 108 | }) | ||
| 109 | } | ||
| 110 | } |
-
Please register or sign in to post a comment