commit
14c8cfc54d
41 changed files with 30839 additions and 0 deletions
-
12.babelrc
-
9.editorconfig
-
13.env.development
-
9.env.production
-
4.eslintignore
-
23.eslintrc.js
-
14.gitignore
-
10.postcssrc.js
-
21README.md
-
41build/build.js
-
54build/check-versions.js
-
BINbuild/logo.png
-
101build/utils.js
-
22build/vue-loader.conf.js
-
92build/webpack.base.conf.js
-
95build/webpack.dev.conf.js
-
145build/webpack.prod.conf.js
-
7config/dev.env.js
-
76config/index.js
-
4config/prod.env.js
-
12index.html
-
29244package-lock.json
-
77package.json
-
12src/App.vue
-
13src/api/login.js
-
BINsrc/assets/images/background.jpg
-
0src/components/Hello.vue
-
42src/main.js
-
19src/router/index.js
-
26src/router/routers.js
-
19src/settings.js
-
4src/store/getters.js
-
3src/store/index.js
-
25src/utils/auth.js
-
30src/utils/permission.js
-
121src/utils/request.js
-
32src/utils/rsaEncrypt.js
-
13src/view/Main.vue
-
239src/view/login.vue
-
0static/.gitkeep
-
156vue.config.js
@ -0,0 +1,12 @@ |
|||
{ |
|||
"presets": [ |
|||
["env", { |
|||
"modules": false, |
|||
"targets": { |
|||
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"] |
|||
} |
|||
}], |
|||
"stage-2" |
|||
], |
|||
"plugins": ["transform-vue-jsx", "transform-runtime"] |
|||
} |
@ -0,0 +1,9 @@ |
|||
root = true |
|||
|
|||
[*] |
|||
charset = utf-8 |
|||
indent_style = space |
|||
indent_size = 2 |
|||
end_of_line = lf |
|||
insert_final_newline = true |
|||
trim_trailing_whitespace = true |
@ -0,0 +1,13 @@ |
|||
#全局开发环境配置文件 |
|||
ENV = 'development' |
|||
|
|||
# 本地接口地址 测试使用 |
|||
VUE_APP_BASE_API = 'http://localhost:8000' |
|||
VUE_APP_WS_API = 'ws://localhost:8000' |
|||
|
|||
# 外网接口地址 |
|||
#VUE_APP_BASE_API = 'https://yxkadmin.aiyxlib.com' |
|||
#VUE_APP_WS_API = 'wss://yxkadmin.aiyxlib.com' |
|||
|
|||
# 是否启用 babel-plugin-dynamic-import-node插件 |
|||
VUE_CLI_BABEL_TRANSPILE_MODULES = true |
@ -0,0 +1,9 @@ |
|||
#全局生产环境配置文件 |
|||
|
|||
ENV = 'production' |
|||
|
|||
# 如果使用 Nginx 代理后端接口,那么此处需要改为 '/' |
|||
# 接口地址,注意协议,如果你没有配置 ssl,需要将 https 改为 http |
|||
VUE_APP_BASE_API = 'https://yxkadmin.aiyxlib.com' |
|||
# 如果接口是 http 形式, wss 需要改为 ws |
|||
VUE_APP_WS_API = 'wss://yxkadmin.aiyxlib.com' |
@ -0,0 +1,4 @@ |
|||
/build/ |
|||
/config/ |
|||
/dist/ |
|||
/*.js |
@ -0,0 +1,23 @@ |
|||
// https://eslint.org/docs/user-guide/configuring
|
|||
|
|||
module.exports = { |
|||
root: true, |
|||
parserOptions: { |
|||
parser: 'babel-eslint' |
|||
}, |
|||
env: { |
|||
browser: true, |
|||
}, |
|||
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
|
|||
// consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
|
|||
extends: ['plugin:vue/essential'], |
|||
// required to lint *.vue files
|
|||
plugins: [ |
|||
'vue' |
|||
], |
|||
// add your custom rules here
|
|||
rules: { |
|||
// allow debugger during development
|
|||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' |
|||
} |
|||
} |
@ -0,0 +1,14 @@ |
|||
.DS_Store |
|||
node_modules/ |
|||
/dist/ |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
|
|||
# Editor directories and files |
|||
.idea |
|||
.vscode |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
@ -0,0 +1,10 @@ |
|||
// https://github.com/michael-ciniawsky/postcss-load-config
|
|||
|
|||
module.exports = { |
|||
"plugins": { |
|||
"postcss-import": {}, |
|||
"postcss-url": {}, |
|||
// to edit target browsers: use "browserslist" field in package.json
|
|||
"autoprefixer": {} |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
# yxkadmin-el |
|||
|
|||
> A Vue.js project |
|||
|
|||
## Build Setup |
|||
|
|||
``` bash |
|||
# install dependencies |
|||
npm install |
|||
|
|||
# serve with hot reload at localhost:8080 |
|||
npm run dev |
|||
|
|||
# build for production with minification |
|||
npm run build |
|||
|
|||
# build for production and view the bundle analyzer report |
|||
npm run build --report |
|||
``` |
|||
|
|||
For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). |
@ -0,0 +1,41 @@ |
|||
'use strict' |
|||
require('./check-versions')() |
|||
|
|||
process.env.NODE_ENV = 'production' |
|||
|
|||
const ora = require('ora') |
|||
const rm = require('rimraf') |
|||
const path = require('path') |
|||
const chalk = require('chalk') |
|||
const webpack = require('webpack') |
|||
const config = require('../config') |
|||
const webpackConfig = require('./webpack.prod.conf') |
|||
|
|||
const spinner = ora('building for production...') |
|||
spinner.start() |
|||
|
|||
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { |
|||
if (err) throw err |
|||
webpack(webpackConfig, (err, stats) => { |
|||
spinner.stop() |
|||
if (err) throw err |
|||
process.stdout.write(stats.toString({ |
|||
colors: true, |
|||
modules: false, |
|||
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
|
|||
chunks: false, |
|||
chunkModules: false |
|||
}) + '\n\n') |
|||
|
|||
if (stats.hasErrors()) { |
|||
console.log(chalk.red(' Build failed with errors.\n')) |
|||
process.exit(1) |
|||
} |
|||
|
|||
console.log(chalk.cyan(' Build complete.\n')) |
|||
console.log(chalk.yellow( |
|||
' Tip: built files are meant to be served over an HTTP server.\n' + |
|||
' Opening index.html over file:// won\'t work.\n' |
|||
)) |
|||
}) |
|||
}) |
@ -0,0 +1,54 @@ |
|||
'use strict' |
|||
const chalk = require('chalk') |
|||
const semver = require('semver') |
|||
const packageConfig = require('../package.json') |
|||
const shell = require('shelljs') |
|||
|
|||
function exec (cmd) { |
|||
return require('child_process').execSync(cmd).toString().trim() |
|||
} |
|||
|
|||
const versionRequirements = [ |
|||
{ |
|||
name: 'node', |
|||
currentVersion: semver.clean(process.version), |
|||
versionRequirement: packageConfig.engines.node |
|||
} |
|||
] |
|||
|
|||
if (shell.which('npm')) { |
|||
versionRequirements.push({ |
|||
name: 'npm', |
|||
currentVersion: exec('npm --version'), |
|||
versionRequirement: packageConfig.engines.npm |
|||
}) |
|||
} |
|||
|
|||
module.exports = function () { |
|||
const warnings = [] |
|||
|
|||
for (let i = 0; i < versionRequirements.length; i++) { |
|||
const mod = versionRequirements[i] |
|||
|
|||
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { |
|||
warnings.push(mod.name + ': ' + |
|||
chalk.red(mod.currentVersion) + ' should be ' + |
|||
chalk.green(mod.versionRequirement) |
|||
) |
|||
} |
|||
} |
|||
|
|||
if (warnings.length) { |
|||
console.log('') |
|||
console.log(chalk.yellow('To use this template, you must update following to modules:')) |
|||
console.log() |
|||
|
|||
for (let i = 0; i < warnings.length; i++) { |
|||
const warning = warnings[i] |
|||
console.log(' ' + warning) |
|||
} |
|||
|
|||
console.log() |
|||
process.exit(1) |
|||
} |
|||
} |
After Width: 200 | Height: 200 | Size: 6.7 KiB |
@ -0,0 +1,101 @@ |
|||
'use strict' |
|||
const path = require('path') |
|||
const config = require('../config') |
|||
const ExtractTextPlugin = require('extract-text-webpack-plugin') |
|||
const packageConfig = require('../package.json') |
|||
|
|||
exports.assetsPath = function (_path) { |
|||
const assetsSubDirectory = process.env.NODE_ENV === 'production' |
|||
? config.build.assetsSubDirectory |
|||
: config.dev.assetsSubDirectory |
|||
|
|||
return path.posix.join(assetsSubDirectory, _path) |
|||
} |
|||
|
|||
exports.cssLoaders = function (options) { |
|||
options = options || {} |
|||
|
|||
const cssLoader = { |
|||
loader: 'css-loader', |
|||
options: { |
|||
sourceMap: options.sourceMap |
|||
} |
|||
} |
|||
|
|||
const postcssLoader = { |
|||
loader: 'postcss-loader', |
|||
options: { |
|||
sourceMap: options.sourceMap |
|||
} |
|||
} |
|||
|
|||
// generate loader string to be used with extract text plugin
|
|||
function generateLoaders (loader, loaderOptions) { |
|||
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] |
|||
|
|||
if (loader) { |
|||
loaders.push({ |
|||
loader: loader + '-loader', |
|||
options: Object.assign({}, loaderOptions, { |
|||
sourceMap: options.sourceMap |
|||
}) |
|||
}) |
|||
} |
|||
|
|||
// Extract CSS when that option is specified
|
|||
// (which is the case during production build)
|
|||
if (options.extract) { |
|||
return ExtractTextPlugin.extract({ |
|||
use: loaders, |
|||
fallback: 'vue-style-loader' |
|||
}) |
|||
} else { |
|||
return ['vue-style-loader'].concat(loaders) |
|||
} |
|||
} |
|||
|
|||
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
|
|||
return { |
|||
css: generateLoaders(), |
|||
postcss: generateLoaders(), |
|||
less: generateLoaders('less'), |
|||
sass: generateLoaders('sass', { indentedSyntax: true }), |
|||
scss: generateLoaders('sass'), |
|||
stylus: generateLoaders('stylus'), |
|||
styl: generateLoaders('stylus') |
|||
} |
|||
} |
|||
|
|||
// Generate loaders for standalone style files (outside of .vue)
|
|||
exports.styleLoaders = function (options) { |
|||
const output = [] |
|||
const loaders = exports.cssLoaders(options) |
|||
|
|||
for (const extension in loaders) { |
|||
const loader = loaders[extension] |
|||
output.push({ |
|||
test: new RegExp('\\.' + extension + '$'), |
|||
use: loader |
|||
}) |
|||
} |
|||
|
|||
return output |
|||
} |
|||
|
|||
exports.createNotifierCallback = () => { |
|||
const notifier = require('node-notifier') |
|||
|
|||
return (severity, errors) => { |
|||
if (severity !== 'error') return |
|||
|
|||
const error = errors[0] |
|||
const filename = error.file && error.file.split('!').pop() |
|||
|
|||
notifier.notify({ |
|||
title: packageConfig.name, |
|||
message: severity + ': ' + error.name, |
|||
subtitle: filename || '', |
|||
icon: path.join(__dirname, 'logo.png') |
|||
}) |
|||
} |
|||
} |
@ -0,0 +1,22 @@ |
|||
'use strict' |
|||
const utils = require('./utils') |
|||
const config = require('../config') |
|||
const isProduction = process.env.NODE_ENV === 'production' |
|||
const sourceMapEnabled = isProduction |
|||
? config.build.productionSourceMap |
|||
: config.dev.cssSourceMap |
|||
|
|||
module.exports = { |
|||
loaders: utils.cssLoaders({ |
|||
sourceMap: sourceMapEnabled, |
|||
extract: isProduction |
|||
}), |
|||
cssSourceMap: sourceMapEnabled, |
|||
cacheBusting: config.dev.cacheBusting, |
|||
transformToRequire: { |
|||
video: ['src', 'poster'], |
|||
source: 'src', |
|||
img: 'src', |
|||
image: 'xlink:href' |
|||
} |
|||
} |
@ -0,0 +1,92 @@ |
|||
'use strict' |
|||
const path = require('path') |
|||
const utils = require('./utils') |
|||
const config = require('../config') |
|||
const vueLoaderConfig = require('./vue-loader.conf') |
|||
|
|||
function resolve (dir) { |
|||
return path.join(__dirname, '..', dir) |
|||
} |
|||
|
|||
const createLintingRule = () => ({ |
|||
test: /\.(js|vue)$/, |
|||
loader: 'eslint-loader', |
|||
enforce: 'pre', |
|||
include: [resolve('src'), resolve('test')], |
|||
options: { |
|||
formatter: require('eslint-friendly-formatter'), |
|||
emitWarning: !config.dev.showEslintErrorsInOverlay |
|||
} |
|||
}) |
|||
|
|||
module.exports = { |
|||
context: path.resolve(__dirname, '../'), |
|||
entry: { |
|||
app: './src/main.js' |
|||
}, |
|||
output: { |
|||
path: config.build.assetsRoot, |
|||
filename: '[name].js', |
|||
publicPath: process.env.NODE_ENV === 'production' |
|||
? config.build.assetsPublicPath |
|||
: config.dev.assetsPublicPath |
|||
}, |
|||
resolve: { |
|||
extensions: ['.js', '.vue', '.json'], |
|||
alias: { |
|||
'vue$': 'vue/dist/vue.esm.js', |
|||
'@': resolve('src'), |
|||
} |
|||
}, |
|||
module: { |
|||
rules: [ |
|||
...(config.dev.useEslint ? [createLintingRule()] : []), |
|||
{ |
|||
test: /\.vue$/, |
|||
loader: 'vue-loader', |
|||
options: vueLoaderConfig |
|||
}, |
|||
{ |
|||
test: /\.js$/, |
|||
loader: 'babel-loader', |
|||
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] |
|||
}, |
|||
{ |
|||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, |
|||
loader: 'url-loader', |
|||
options: { |
|||
limit: 10000, |
|||
name: utils.assetsPath('img/[name].[hash:7].[ext]') |
|||
} |
|||
}, |
|||
{ |
|||
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, |
|||
loader: 'url-loader', |
|||
options: { |
|||
limit: 10000, |
|||
name: utils.assetsPath('media/[name].[hash:7].[ext]') |
|||
} |
|||
}, |
|||
{ |
|||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, |
|||
loader: 'url-loader', |
|||
options: { |
|||
limit: 10000, |
|||
name: utils.assetsPath('fonts/[name].[hash:7].[ext]') |
|||
} |
|||
} |
|||
] |
|||
}, |
|||
node: { |
|||
// prevent webpack from injecting useless setImmediate polyfill because Vue
|
|||
// source contains it (although only uses it if it's native).
|
|||
setImmediate: false, |
|||
// prevent webpack from injecting mocks to Node native modules
|
|||
// that does not make sense for the client
|
|||
dgram: 'empty', |
|||
fs: 'empty', |
|||
net: 'empty', |
|||
tls: 'empty', |
|||
child_process: 'empty' |
|||
} |
|||
} |
@ -0,0 +1,95 @@ |
|||
'use strict' |
|||
const utils = require('./utils') |
|||
const webpack = require('webpack') |
|||
const config = require('../config') |
|||
const merge = require('webpack-merge') |
|||
const path = require('path') |
|||
const baseWebpackConfig = require('./webpack.base.conf') |
|||
const CopyWebpackPlugin = require('copy-webpack-plugin') |
|||
const HtmlWebpackPlugin = require('html-webpack-plugin') |
|||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') |
|||
const portfinder = require('portfinder') |
|||
|
|||
const HOST = process.env.HOST |
|||
const PORT = process.env.PORT && Number(process.env.PORT) |
|||
|
|||
const devWebpackConfig = merge(baseWebpackConfig, { |
|||
module: { |
|||
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) |
|||
}, |
|||
// cheap-module-eval-source-map is faster for development
|
|||
devtool: config.dev.devtool, |
|||
|
|||
// these devServer options should be customized in /config/index.js
|
|||
devServer: { |
|||
clientLogLevel: 'warning', |
|||
historyApiFallback: { |
|||
rewrites: [ |
|||
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }, |
|||
], |
|||
}, |
|||
hot: true, |
|||
contentBase: false, // since we use CopyWebpackPlugin.
|
|||
compress: true, |
|||
host: HOST || config.dev.host, |
|||
port: PORT || config.dev.port, |
|||
open: config.dev.autoOpenBrowser, |
|||
overlay: config.dev.errorOverlay |
|||
? { warnings: false, errors: true } |
|||
: false, |
|||
publicPath: config.dev.assetsPublicPath, |
|||
proxy: config.dev.proxyTable, |
|||
quiet: true, // necessary for FriendlyErrorsPlugin
|
|||
watchOptions: { |
|||
poll: config.dev.poll, |
|||
} |
|||
}, |
|||
plugins: [ |
|||
new webpack.DefinePlugin({ |
|||
'process.env': require('../config/dev.env') |
|||
}), |
|||
new webpack.HotModuleReplacementPlugin(), |
|||
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
|
|||
new webpack.NoEmitOnErrorsPlugin(), |
|||
// https://github.com/ampedandwired/html-webpack-plugin
|
|||
new HtmlWebpackPlugin({ |
|||
filename: 'index.html', |
|||
template: 'index.html', |
|||
inject: true |
|||
}), |
|||
// copy custom static assets
|
|||
new CopyWebpackPlugin([ |
|||
{ |
|||
from: path.resolve(__dirname, '../static'), |
|||
to: config.dev.assetsSubDirectory, |
|||
ignore: ['.*'] |
|||
} |
|||
]) |
|||
] |
|||
}) |
|||
|
|||
module.exports = new Promise((resolve, reject) => { |
|||
portfinder.basePort = process.env.PORT || config.dev.port |
|||
portfinder.getPort((err, port) => { |
|||
if (err) { |
|||
reject(err) |
|||
} else { |
|||
// publish the new Port, necessary for e2e tests
|
|||
process.env.PORT = port |
|||
// add port to devServer config
|
|||
devWebpackConfig.devServer.port = port |
|||
|
|||
// Add FriendlyErrorsPlugin
|
|||
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ |
|||
compilationSuccessInfo: { |
|||
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], |
|||
}, |
|||
onErrors: config.dev.notifyOnErrors |
|||
? utils.createNotifierCallback() |
|||
: undefined |
|||
})) |
|||
|
|||
resolve(devWebpackConfig) |
|||
} |
|||
}) |
|||
}) |
@ -0,0 +1,145 @@ |
|||
'use strict' |
|||
const path = require('path') |
|||
const utils = require('./utils') |
|||
const webpack = require('webpack') |
|||
const config = require('../config') |
|||
const merge = require('webpack-merge') |
|||
const baseWebpackConfig = require('./webpack.base.conf') |
|||
const CopyWebpackPlugin = require('copy-webpack-plugin') |
|||
const HtmlWebpackPlugin = require('html-webpack-plugin') |
|||
const ExtractTextPlugin = require('extract-text-webpack-plugin') |
|||
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') |
|||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin') |
|||
|
|||
const env = require('../config/prod.env') |
|||
|
|||
const webpackConfig = merge(baseWebpackConfig, { |
|||
module: { |
|||
rules: utils.styleLoaders({ |
|||
sourceMap: config.build.productionSourceMap, |
|||
extract: true, |
|||
usePostCSS: true |
|||
}) |
|||
}, |
|||
devtool: config.build.productionSourceMap ? config.build.devtool : false, |
|||
output: { |
|||
path: config.build.assetsRoot, |
|||
filename: utils.assetsPath('js/[name].[chunkhash].js'), |
|||
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') |
|||
}, |
|||
plugins: [ |
|||
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
|||
new webpack.DefinePlugin({ |
|||
'process.env': env |
|||
}), |
|||
new UglifyJsPlugin({ |
|||
uglifyOptions: { |
|||
compress: { |
|||
warnings: false |
|||
} |
|||
}, |
|||
sourceMap: config.build.productionSourceMap, |
|||
parallel: true |
|||
}), |
|||
// extract css into its own file
|
|||
new ExtractTextPlugin({ |
|||
filename: utils.assetsPath('css/[name].[contenthash].css'), |
|||
// Setting the following option to `false` will not extract CSS from codesplit chunks.
|
|||
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
|
|||
// It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
|
|||
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
|
|||
allChunks: true, |
|||
}), |
|||
// Compress extracted CSS. We are using this plugin so that possible
|
|||
// duplicated CSS from different components can be deduped.
|
|||
new OptimizeCSSPlugin({ |
|||
cssProcessorOptions: config.build.productionSourceMap |
|||
? { safe: true, map: { inline: false } } |
|||
: { safe: true } |
|||
}), |
|||
// generate dist index.html with correct asset hash for caching.
|
|||
// you can customize output by editing /index.html
|
|||
// see https://github.com/ampedandwired/html-webpack-plugin
|
|||
new HtmlWebpackPlugin({ |
|||
filename: config.build.index, |
|||
template: 'index.html', |
|||
inject: true, |
|||
minify: { |
|||
removeComments: true, |
|||
collapseWhitespace: true, |
|||
removeAttributeQuotes: true |
|||
// more options:
|
|||
// https://github.com/kangax/html-minifier#options-quick-reference
|
|||
}, |
|||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
|||
chunksSortMode: 'dependency' |
|||
}), |
|||
// keep module.id stable when vendor modules does not change
|
|||
new webpack.HashedModuleIdsPlugin(), |
|||
// enable scope hoisting
|
|||
new webpack.optimize.ModuleConcatenationPlugin(), |
|||
// split vendor js into its own file
|
|||
new webpack.optimize.CommonsChunkPlugin({ |
|||
name: 'vendor', |
|||
minChunks (module) { |
|||
// any required modules inside node_modules are extracted to vendor
|
|||
return ( |
|||
module.resource && |
|||
/\.js$/.test(module.resource) && |
|||
module.resource.indexOf( |
|||
path.join(__dirname, '../node_modules') |
|||
) === 0 |
|||
) |
|||
} |
|||
}), |
|||
// extract webpack runtime and module manifest to its own file in order to
|
|||
// prevent vendor hash from being updated whenever app bundle is updated
|
|||
new webpack.optimize.CommonsChunkPlugin({ |
|||
name: 'manifest', |
|||
minChunks: Infinity |
|||
}), |
|||
// This instance extracts shared chunks from code splitted chunks and bundles them
|
|||
// in a separate chunk, similar to the vendor chunk
|
|||
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
|
|||
new webpack.optimize.CommonsChunkPlugin({ |
|||
name: 'app', |
|||
async: 'vendor-async', |
|||
children: true, |
|||
minChunks: 3 |
|||
}), |
|||
|
|||
// copy custom static assets
|
|||
new CopyWebpackPlugin([ |
|||
{ |
|||
from: path.resolve(__dirname, '../static'), |
|||
to: config.build.assetsSubDirectory, |
|||
ignore: ['.*'] |
|||
} |
|||
]) |
|||
] |
|||
}) |
|||
|
|||
if (config.build.productionGzip) { |
|||
const CompressionWebpackPlugin = require('compression-webpack-plugin') |
|||
|
|||
webpackConfig.plugins.push( |
|||
new CompressionWebpackPlugin({ |
|||
asset: '[path].gz[query]', |
|||
algorithm: 'gzip', |
|||
test: new RegExp( |
|||
'\\.(' + |
|||
config.build.productionGzipExtensions.join('|') + |
|||
')$' |
|||
), |
|||
threshold: 10240, |
|||
minRatio: 0.8 |
|||
}) |
|||
) |
|||
} |
|||
|
|||
if (config.build.bundleAnalyzerReport) { |
|||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin |
|||
webpackConfig.plugins.push(new BundleAnalyzerPlugin()) |
|||
} |
|||
|
|||
module.exports = webpackConfig |
@ -0,0 +1,7 @@ |
|||
'use strict' |
|||
const merge = require('webpack-merge') |
|||
const prodEnv = require('./prod.env') |
|||
|
|||
module.exports = merge(prodEnv, { |
|||
NODE_ENV: '"development"' |
|||
}) |
@ -0,0 +1,76 @@ |
|||
'use strict' |
|||
// Template version: 1.3.1
|
|||
// see http://vuejs-templates.github.io/webpack for documentation.
|
|||
|
|||
const path = require('path') |
|||
|
|||
module.exports = { |
|||
dev: { |
|||
|
|||
// Paths
|
|||
assetsSubDirectory: 'static', |
|||
assetsPublicPath: '/', |
|||
proxyTable: {}, |
|||
|
|||
// Various Dev Server settings
|
|||
host: 'localhost', // can be overwritten by process.env.HOST
|
|||
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
|
|||
autoOpenBrowser: false, |
|||
errorOverlay: true, |
|||
notifyOnErrors: true, |
|||
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
|
|||
|
|||
// Use Eslint Loader?
|
|||
// If true, your code will be linted during bundling and
|
|||
// linting errors and warnings will be shown in the console.
|
|||
useEslint: true, |
|||
// If true, eslint errors and warnings will also be shown in the error overlay
|
|||
// in the browser.
|
|||
showEslintErrorsInOverlay: false, |
|||
|
|||
/** |
|||
* Source Maps |
|||
*/ |
|||
|
|||
// https://webpack.js.org/configuration/devtool/#development
|
|||
devtool: 'cheap-module-eval-source-map', |
|||
|
|||
// If you have problems debugging vue-files in devtools,
|
|||
// set this to false - it *may* help
|
|||
// https://vue-loader.vuejs.org/en/options.html#cachebusting
|
|||
cacheBusting: true, |
|||
|
|||
cssSourceMap: true |
|||
}, |
|||
|
|||
build: { |
|||
// Template for index.html
|
|||
index: path.resolve(__dirname, '../dist/index.html'), |
|||
|
|||
// Paths
|
|||
assetsRoot: path.resolve(__dirname, '../dist'), |
|||
assetsSubDirectory: 'static', |
|||
assetsPublicPath: '/', |
|||
|
|||
/** |
|||
* Source Maps |
|||
*/ |
|||
|
|||
productionSourceMap: true, |
|||
// https://webpack.js.org/configuration/devtool/#production
|
|||
devtool: '#source-map', |
|||
|
|||
// Gzip off by default as many popular static hosts such as
|
|||
// Surge or Netlify already gzip all static assets for you.
|
|||
// Before setting to `true`, make sure to:
|
|||
// npm install --save-dev compression-webpack-plugin
|
|||
productionGzip: false, |
|||
productionGzipExtensions: ['js', 'css'], |
|||
|
|||
// Run the build command with an extra argument to
|
|||
// View the bundle analyzer report after build finishes:
|
|||
// `npm run build --report`
|
|||
// Set to `true` or `false` to always turn it on or off
|
|||
bundleAnalyzerReport: process.env.npm_config_report |
|||
} |
|||
} |
@ -0,0 +1,4 @@ |
|||
'use strict' |
|||
module.exports = { |
|||
NODE_ENV: '"production"' |
|||
} |
@ -0,0 +1,12 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta name="viewport" content="width=device-width,initial-scale=1.0"> |
|||
<title>yxkadmin-el</title> |
|||
</head> |
|||
<body> |
|||
<div id="app"></div> |
|||
<!-- built files will be auto injected --> |
|||
</body> |
|||
</html> |
29244
package-lock.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,77 @@ |
|||
{ |
|||
"name": "yxkadmin-el", |
|||
"version": "1.0.0", |
|||
"description": "yxkadmin", |
|||
"author": "刘力 <soldierliuli@hotmail.com>", |
|||
"private": true, |
|||
"scripts": { |
|||
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", |
|||
"start": "npm run dev", |
|||
"lint": "eslint --ext .js,.vue src", |
|||
"build": "node build/build.js" |
|||
}, |
|||
"dependencies": { |
|||
"axios": "^0.21.4", |
|||
"element-ui": "^2.15.6", |
|||
"js-cookie": "^3.0.1", |
|||
"jsencrypt": "^3.2.1", |
|||
"vue": "^2.5.2", |
|||
"vue-highlightjs": "^1.3.3", |
|||
"vue-router": "^3.0.1", |
|||
"vuex": "^3.6.2" |
|||
}, |
|||
"devDependencies": { |
|||
"autoprefixer": "^7.1.2", |
|||
"babel-core": "^6.22.1", |
|||
"babel-eslint": "^8.2.1", |
|||
"babel-helper-vue-jsx-merge-props": "^2.0.3", |
|||
"babel-loader": "^7.1.1", |
|||
"babel-plugin-syntax-jsx": "^6.18.0", |
|||
"babel-plugin-transform-runtime": "^6.22.0", |
|||
"babel-plugin-transform-vue-jsx": "^3.5.0", |
|||
"babel-preset-env": "^1.3.2", |
|||
"babel-preset-stage-2": "^6.22.0", |
|||
"chalk": "^2.0.1", |
|||
"copy-webpack-plugin": "^4.0.1", |
|||
"css-loader": "^0.28.0", |
|||
"eslint": "^4.15.0", |
|||
"eslint-friendly-formatter": "^3.0.0", |
|||
"eslint-loader": "^1.7.1", |
|||
"eslint-plugin-vue": "^4.0.0", |
|||
"extract-text-webpack-plugin": "^3.0.0", |
|||
"file-loader": "^1.1.4", |
|||
"friendly-errors-webpack-plugin": "^1.6.1", |
|||
"html-webpack-plugin": "^2.30.1", |
|||
"js-cookie": "^3.0.1", |
|||
"node-notifier": "^5.1.2", |
|||
"node-sass": "^6.0.1", |
|||
"optimize-css-assets-webpack-plugin": "^3.2.0", |
|||
"ora": "^1.2.0", |
|||
"portfinder": "^1.0.13", |
|||
"postcss-import": "^11.0.0", |
|||
"postcss-loader": "^2.0.8", |
|||
"postcss-url": "^7.2.1", |
|||
"rimraf": "^2.6.0", |
|||
"sass-loader": "^12.1.0", |
|||
"semver": "^5.3.0", |
|||
"shelljs": "^0.7.6", |
|||
"uglifyjs-webpack-plugin": "^1.1.1", |
|||
"url-loader": "^0.5.8", |
|||
"vue-loader": "^13.3.0", |
|||
"vue-style-loader": "^3.0.1", |
|||
"vue-template-compiler": "^2.5.2", |
|||
"webpack": "^3.6.0", |
|||
"webpack-bundle-analyzer": "^2.9.0", |
|||
"webpack-dev-server": "^2.9.1", |
|||
"webpack-merge": "^4.1.0" |
|||
}, |
|||
"engines": { |
|||
"node": ">= 6.0.0", |
|||
"npm": ">= 3.0.0" |
|||
}, |
|||
"browserslist": [ |
|||
"> 1%", |
|||
"last 2 versions", |
|||
"not ie <= 8" |
|||
] |
|||
} |
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div id="app"> |
|||
<router-link to="login">login</router-link> |
|||
<router-view/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'App' |
|||
} |
|||
</script> |
@ -0,0 +1,13 @@ |
|||
|
|||
import request from '@/utils/request' |
|||
|
|||
|
|||
|
|||
|
|||
//获取验证码
|
|||
export function getCodeImg(){ |
|||
return request({ |
|||
url:'auth/code', |
|||
method:'get' |
|||
}) |
|||
} |
After Width: 1920 | Height: 1080 | Size: 162 KiB |
@ -0,0 +1,42 @@ |
|||
import Vue from 'vue' |
|||
import App from './App' |
|||
import router from './router' |
|||
// import store from './store'
|
|||
import Cookies from 'js-cookie' |
|||
|
|||
// 引入elementui组件
|
|||
import ElementUI from 'element-ui' |
|||
import 'element-ui/lib/theme-chalk/index.css' |
|||
|
|||
// 代码高亮
|
|||
import VueHighlightJS from 'vue-highlightjs' |
|||
import 'highlight.js/styles/atom-one-dark.css' |
|||
// 加载路由
|
|||
import './router/index' |
|||
|
|||
//加载权限指令
|
|||
//import checkPer from '@./utils/permission'
|
|||
//import permission from './components/Permission'
|
|||
|
|||
|
|||
|
|||
//加载路由
|
|||
Vue.use(router) |
|||
// 加载代码高亮
|
|||
Vue.use(VueHighlightJS) |
|||
// 加载elementui
|
|||
Vue.use(ElementUI,{ |
|||
// 设置element-ui默认大小
|
|||
size:Cookies.get('size') || 'small' |
|||
}) |
|||
//加载权限指令
|
|||
Vue.use(checkPer) |
|||
|
|||
Vue.config.productionTip = false |
|||
|
|||
new Vue({ |
|||
el: '#app', |
|||
router, |
|||
// store,
|
|||
render:h=>h(App) |
|||
}) |
@ -0,0 +1,19 @@ |
|||
import Vue from 'vue' |
|||
import Router from 'vue-router' |
|||
import Main from '../view/Main' |
|||
import Login from '../view/Login' |
|||
|
|||
|
|||
Vue.use(Router) |
|||
|
|||
export default new Router({ |
|||
routes: [ |
|||
{ |
|||
path: '/main', |
|||
component: Main |
|||
},{ |
|||
path:'/login', |
|||
component: Login |
|||
} |
|||
] |
|||
}) |
@ -0,0 +1,26 @@ |
|||
import Vue from 'vue' |
|||
import Router from 'vue-router' |
|||
|
|||
|
|||
//加载路由
|
|||
Vue.use(Router) |
|||
|
|||
|
|||
//路由映射
|
|||
export const constantRouterMap=[ |
|||
{ |
|||
//路径
|
|||
path:'/login', |
|||
//路由过渡信息,此处使用面包屑功能或判断用户是否登录
|
|||
meta:{title:'登录',noCache:true}, |
|||
//加载组件
|
|||
component:(resolve)=>require(['@/views/login'], resolve), |
|||
//是否展示该理由
|
|||
hidden:true |
|||
} |
|||
|
|||
] |
|||
|
|||
export default new Router({ |
|||
|
|||
}) |
@ -0,0 +1,19 @@ |
|||
// 全局设置
|
|||
module.exports = { |
|||
|
|||
//网站标题
|
|||
title: '阅行资源库后台管理系统', |
|||
|
|||
//记住密码状态下的token在Cookie中存储的天数,默认1天
|
|||
tokenCookieExpires: 1, |
|||
|
|||
//记住密码状态下的密码在Cookie中存储的天数,默认1天s
|
|||
passCookieExpires: 1, |
|||
|
|||
//token key
|
|||
TokenKey: 'YXK-ADMIN-TOKEN', |
|||
|
|||
//请求超时时间,毫秒(默认2分钟)
|
|||
timeout: 1200000, |
|||
|
|||
} |
@ -0,0 +1,4 @@ |
|||
const getters={ |
|||
|
|||
} |
|||
export default getters |
@ -0,0 +1,3 @@ |
|||
import Vue from "vue" |
|||
import Vuex from 'vuex' |
|||
import getters from './getters' |
@ -0,0 +1,25 @@ |
|||
import Cookies from 'js-cookie'; |
|||
import Config from '@/settings' |
|||
|
|||
|
|||
const TokenKey = Config.TokenKey |
|||
|
|||
|
|||
//获取Token
|
|||
export function getToken() { |
|||
return Cookies.get(TokenKey) |
|||
} |
|||
|
|||
//写入Token
|
|||
export function setToken(token, rememberMe) { |
|||
if (rememberMe) { |
|||
return Cookies.set(TokenKey, token, { |
|||
expires: Config.tokenCookieExpires |
|||
}) |
|||
} else return Cookies.set(TokenKey, token) |
|||
} |
|||
|
|||
//移除Token
|
|||
export function removeToken() { |
|||
return Cookies.remove(TokenKey) |
|||
} |
@ -0,0 +1,30 @@ |
|||
import store from '@/store' //引入状态管理组件
|
|||
|
|||
export default { |
|||
install(Vue) { |
|||
// 添加属性
|
|||
Vue.prototype.checkPer=(value)=>{ |
|||
// 判断是否为数组对象且长度小于0
|
|||
if(value && value instanceof Array && value.length > 0){ |
|||
const roles=store.getters && store.getters.roles |
|||
const permissionRoles=value |
|||
|
|||
const hasPermission=roles.some(role=>{ |
|||
//检测role值并返回
|
|||
return permissionRoles.includes(role) |
|||
}) |
|||
|
|||
//判断hasPermission
|
|||
if(!hasPermission){ |
|||
return false |
|||
} |
|||
return true |
|||
// 否则返回错误
|
|||
}else { |
|||
//需要角色拥有admin editor 权限
|
|||
console.error(`need roles! Like v-permission="['admin','editor']"`) |
|||
return false |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,121 @@ |
|||
import axios from "axios" |
|||
import router from '@/router/routers' |
|||
import { Notification } from 'element-ui' //elementUI 提示框组件
|
|||
import store from '../store' |
|||
import { getToken } from '@./utils/auth' |
|||
import Config from '@/settings' |
|||
import Cookies from "js-cookie" |
|||
|
|||
|
|||
//创建axios 实例
|
|||
const service = axios.create({ |
|||
//api 的 base_url在.env.development有配置
|
|||
baseURL: process.env.NODE_ENV === 'production' ? process.env.VUE_APP_BASE_API : '/', |
|||
//请求超时时间
|
|||
timeout: Config.timeout |
|||
}) |
|||
|
|||
|
|||
//添加请求拦截器
|
|||
service.interceptors.request.use( |
|||
// 在发送请求之前做些什么
|
|||
config => { |
|||
//如果获取token
|
|||
if (getToken()) { |
|||
//每次请求都附带上header的Authorization
|
|||
config.headers['Authorization'] = getToken() |
|||
} |
|||
//请求格式
|
|||
config.headers['Content-Type'] = 'application/json' |
|||
return config |
|||
}, |
|||
error => { |
|||
//对请求错误的处理
|
|||
Promise.reject(error) |
|||
} |
|||
) |
|||
|
|||
//添加响应拦截器
|
|||
service.interceptors.response.use( |
|||
//响应后要做的事情
|
|||
response => { |
|||
//返回响应数据
|
|||
return response.data |
|||
}, |
|||
//响应错误处理
|
|||
error => { |
|||
//兼容blob下载出错json提示
|
|||
if (error.response.data instanceof Blob && error.response.data.type.toLowerCase().indexOf('json') !== -1) { |
|||
//创建文件读取对象
|
|||
const reader = new FileReader() |
|||
//读取指定的Blob中错误信息内容
|
|||
reader.readAsText(error.response.data, 'utf-8') |
|||
//读取文件完成后触发onload事件
|
|||
reader.onload = function (e) { |
|||
//转换错误信息
|
|||
const errorMsg = JSON.parse(reader.result).message |
|||
//通知提醒框返回错误信息
|
|||
Notification.error({ |
|||
title: errorMsg, |
|||
duration: 5000 |
|||
}) |
|||
} |
|||
} else { |
|||
let code = 0 |
|||
//捕获错误信息
|
|||
try { |
|||
//获取响应错误状态码
|
|||
code = error.response.data.status |
|||
} catch (e) { |
|||
//做请求超时判断
|
|||
if (error.toString().indexOf('Error:timeout') !== -1) { |
|||
Notification.error({ |
|||
title: '网络请求超时', |
|||
duration: 5000 |
|||
}) |
|||
//拿到回调信息并返回
|
|||
return Promise.reject(error) |
|||
} |
|||
} |
|||
console.log(code) |
|||
//错误代码判断
|
|||
if (code) { |
|||
if (code === 401) { |
|||
//跳转401并写入Cookies
|
|||
store.dispatch('LogOut').then(() => { |
|||
// 用户登录界面提示
|
|||
Cookies.set('point', 401) |
|||
//重新加载
|
|||
location.reload() |
|||
}) |
|||
} else if (code === 403) { |
|||
//如果是403直接返回401页面路径
|
|||
router.push({ |
|||
path: '/401' |
|||
}) |
|||
} else { |
|||
//获取错误信息
|
|||
const errorMsg = error.response.data.message |
|||
if (errorMsg !== undefined) { |
|||
//告知提示框错误信息
|
|||
Notification.error({ |
|||
title: errorMsg, |
|||
duration: 5000 |
|||
}) |
|||
} |
|||
} |
|||
} else { |
|||
//否则把请求接口失败告知提示框
|
|||
Notification.error({ |
|||
title: '接口请求失败', |
|||
duration: 5000 |
|||
}) |
|||
} |
|||
} |
|||
|
|||
//返回错误
|
|||
return Promise.reject(error) |
|||
} |
|||
) |
|||
|
|||
export default service |
@ -0,0 +1,32 @@ |
|||
import JSEncrypt from 'jsencrypt/bin/jsencrypt.min' |
|||
|
|||
|
|||
//密钥对生成:http://web.chacuo.net/netrsakeypair
|
|||
//设置公钥
|
|||
const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMEOuFWzyferOY27HOOKkeNCexTXunvK\n' + |
|||
'Bk62mavgNn6G6r9PB4gT71YdXkk/3JmnrUue3L/MPOIpAD5ZadAXdBcCAwEAAQ==' |
|||
|
|||
|
|||
//设置私钥
|
|||
const privateKey = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAwQ64VbPJ96s5jbsc\n' + |
|||
'44qR40J7FNe6e8oGTraZq+A2fobqv08HiBPvVh1eST/cmaetS57cv8w84ikAPllp\n' + |
|||
'0Bd0FwIDAQABAkBf3tB5dsPoIvZ8xJuu/2Q9KAl5KzwnNwb01cbwTHKjV7yORPaL\n' + |
|||
'Y6rlCmIae8GCkvJMtaJRiLbViM14U2jIKEgxAiEA9jIJm34V4nGlqg3M3EZjnn/B\n' + |
|||
'nDUrIp/FRsG4yEbDMukCIQDIvvDrMM9Ay3mbQjUOayjFguA5qlA8o8oj58WJnocO\n' + |
|||
'/wIgetNL579nu6lnNQfdhKe5W4HxXbVI5+U9zqcnQQPMrsECIQDDMte0+jstOC3B\n' + |
|||
'SLmqkYyNsdsyd2eZ73IpQ7+TN/EAJQIgWmJh6+b5sw4Q/Emb9ypPAE3peP09QmhP\n' + |
|||
'ZnAyYEuUiNY=' |
|||
|
|||
//输入加密
|
|||
export function encrypt(txt) { |
|||
const encryptor = new JSEncrypt() |
|||
encryptor.setPublicKey(publicKey) // 设置公钥
|
|||
return encryptor.encrypt(txt) // 对需要加密的数据进行加密
|
|||
} |
|||
|
|||
//输入解密
|
|||
export function decrypt(txt) { |
|||
const encryptor = new JSEncrypt() |
|||
encryptor.setPrivateKey(privateKey) |
|||
return encryptor.decrypt(txt) |
|||
} |
@ -0,0 +1,13 @@ |
|||
<template> |
|||
<h1>首页</h1> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name:"Main" |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
|
|||
</style> |
@ -0,0 +1,239 @@ |
|||
<template> |
|||
<div class="login" :style="'background-image:url('+ Background +');'"> |
|||
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" label-position="left" label-width="0px" class="login-form"> |
|||
<h3 class="title"> |
|||
阅行客后台管理系统 |
|||
</h3> |
|||
<el-form-item prop="username"> |
|||
<el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号"> |
|||
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" /> |
|||
</el-input> |
|||
</el-form-item> |
|||
<el-form-item prop="password"> |
|||
<el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码" @keyup.enter.native="handleLogin"> |
|||
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" /> |
|||
</el-input> |
|||
</el-form-item> |
|||
<el-form-item prop="code"> |
|||
<el-input v-model="loginForm.code" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter.native="handleLogin"> |
|||
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" /> |
|||
</el-input> |
|||
<div class="login-code"> |
|||
<img :src="codeUrl" @click="getCode"> |
|||
</div> |
|||
</el-form-item> |
|||
<el-checkbox v-model="loginForm.rememberMe" style="margin:0 0 25px 0;"> |
|||
记住我 |
|||
</el-checkbox> |
|||
<el-form-item style="width:100%;"> |
|||
<el-button :loading="loading" size="medium" type="primary" style="width:100%;" @click.native.prevent="handleLogin"> |
|||
<span v-if="!loading">登 录</span> |
|||
<span v-else>登 录 中...</span> |
|||
</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
<!-- 底部 --> |
|||
<div v-if="$store.state.settings.showFooter" id="el-login-footer"> |
|||
<span v-html="$store.state.settings.footerTxt" /> |
|||
<span> ⋅ </span> |
|||
<a href="https://beian.miit.gov.cn/#/Integrated/index" target="_blank">{{ $store.state.settings.caseNumber }}</a> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { encrypt } from "@/utils/rsaEncrypt"; |
|||
import Config from "@/settings"; |
|||
import Cookies from "js-cookie"; |
|||
import Background from "@/assets/images/background.jpg"; |
|||
|
|||
export default { |
|||
//输出模块名称 |
|||
name: "Login", |
|||
data() { |
|||
return { |
|||
//背景图 |
|||
Background: Background, |
|||
//登录验证码 |
|||
codeUrl: "", |
|||
//通行证 |
|||
cookiePass: "", |
|||
//默认登录信息--测试用 |
|||
loginForm: { |
|||
username: "admin", |
|||
password: "123456", |
|||
rememberMe: false, |
|||
code: "", |
|||
uuid: "", |
|||
}, |
|||
//登录规则 |
|||
loginRules: { |
|||
username: [ |
|||
{ required: true, trigger: "blur", message: "用户名不能为空" }, |
|||
], |
|||
password: [ |
|||
{ required: true, trigger: "blur", message: "密码不能为空" }, |
|||
], |
|||
code: [ |
|||
{ required: true, trigger: "change", message: "验证码不能为空" }, |
|||
], |
|||
}, |
|||
//加载状态是否显示 |
|||
loading: false, |
|||
//跳转定向 |
|||
redirect: undefined, |
|||
}; |
|||
}, |
|||
watch: { |
|||
//监听路由变化 |
|||
$route: { |
|||
handler: function (route) { |
|||
this.redirect = route.query && route.query.redirect; |
|||
}, |
|||
//立即执行handler |
|||
immediate: true, |
|||
}, |
|||
}, |
|||
// 使用钩子初始化获取信息 |
|||
created() { |
|||
//获取验证码 |
|||
this.getCode(); |
|||
//获取用户名密码等 Cookie |
|||
this.getCookie(); |
|||
// token过期提示 |
|||
this.point(); |
|||
}, |
|||
methods: { |
|||
//获取验证码方法 |
|||
getCode() { |
|||
getCodeImg().then((res) => { |
|||
this.codeUrl = res.img; |
|||
this.loginForm.uuid = res.uuid; |
|||
}); |
|||
}, |
|||
//获取Cookie |
|||
getCookie() { |
|||
const username = Cookies.get("username"); |
|||
let password = Cookies.get("password"); |
|||
const rememberMe = Cookies.get("rememberMe"); |
|||
// 保存cookie里面的加密后的密码 |
|||
this.cookiePass = password === undefined ? "" : password; |
|||
password = password === undefined ? this.loginForm.password : password; |
|||
this.loginForm = { |
|||
username: username === undefined ? this.loginForm.username : username, |
|||
password: password, |
|||
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe), |
|||
code: "", |
|||
}; |
|||
}, |
|||
handleLogin() { |
|||
this.$refs.loginForm.validate((valid) => { |
|||
// 获取登录信息 |
|||
const user = { |
|||
username: this.loginForm.username, |
|||
password: this.loginForm.password, |
|||
rememberMe: this.loginForm.rememberMe, |
|||
code: this.loginForm.code, |
|||
uuid: this.loginForm.uuid, |
|||
}; |
|||
//如果cookie通行证不匹配 |
|||
if (user.password !== this.cookiePass) { |
|||
//把密码进行加密处理 |
|||
user.password = encrypt(user.password); |
|||
} |
|||
if (valid) { |
|||
this.loading = true; |
|||
if (user.rememberMe) { |
|||
Cookies.set("username", user.username, { |
|||
expires: Config.passCookieExpires, |
|||
}); |
|||
Cookies.set("password", user.password, { |
|||
expires: Config.passCookieExpires, |
|||
}); |
|||
Cookies.set("rememberMe", user.rememberMe, { |
|||
expires: Config.passCookieExpires, |
|||
}); |
|||
} else { |
|||
Cookies.remove("username"); |
|||
Cookies.remove("password"); |
|||
Cookies.remove("rememberMe"); |
|||
} |
|||
this.$store |
|||
.dispatch("Login", user) |
|||
.then(() => { |
|||
this.loading = false; |
|||
this.$router.push({ path: this.redirect || "/" }); |
|||
}) |
|||
.catch(() => { |
|||
this.loading = false; |
|||
this.getCode(); |
|||
}); |
|||
} else { |
|||
console.log("提交错误!!"); |
|||
return false; |
|||
} |
|||
}); |
|||
}, |
|||
point() { |
|||
const point = Cookies.get("point") !== undefined; |
|||
if (point) { |
|||
this.$notify({ |
|||
title: "提示", |
|||
message: "当前登录状态已过期,请重新登录!", |
|||
type: "warning", |
|||
duration: 5000, |
|||
}); |
|||
Cookies.remove("point"); |
|||
} |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style rel="stylesheet/scss" lang="scss"> |
|||
.login { |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
height: 100%; |
|||
background-size: cover; |
|||
} |
|||
.title { |
|||
margin: 0 auto 30px auto; |
|||
text-align: center; |
|||
color: #707070; |
|||
} |
|||
|
|||
.login-form { |
|||
border-radius: 6px; |
|||
background: #ffffff; |
|||
width: 385px; |
|||
padding: 25px 25px 5px 25px; |
|||
.el-input { |
|||
height: 38px; |
|||
input { |
|||
height: 38px; |
|||
} |
|||
} |
|||
.input-icon { |
|||
height: 39px; |
|||
width: 14px; |
|||
margin-left: 2px; |
|||
} |
|||
} |
|||
.login-tip { |
|||
font-size: 13px; |
|||
text-align: center; |
|||
color: #bfbfbf; |
|||
} |
|||
.login-code { |
|||
width: 33%; |
|||
display: inline-block; |
|||
height: 38px; |
|||
float: right; |
|||
img { |
|||
cursor: pointer; |
|||
vertical-align: middle; |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,156 @@ |
|||
'use strict' |
|||
|
|||
//基本项目配置
|
|||
const path = require('path') |
|||
const defaultSettings = require('./src/settings.js') |
|||
|
|||
//项目路径
|
|||
function resolve(dir) { |
|||
return path.join(__dirname, dir) |
|||
} |
|||
|
|||
// 网址标题
|
|||
const name = defaultSettings.title |
|||
// 端口配置
|
|||
const port = 8013 |
|||
|
|||
//代理配置
|
|||
module.exports = { |
|||
|
|||
// hash 模式下可使用
|
|||
// publicPath: process.env.NODE_ENV === 'development' ? '/' : './',
|
|||
//部署应用包时的基本 URL
|
|||
publicPath: '/', |
|||
//当运行 vue-cli-service build 时生成的生产环境构建文件的目录
|
|||
outputDir: 'dist', |
|||
//放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录
|
|||
assetsDir: 'static', |
|||
//是否在开发环境下通过 eslint-loader 在每次保存时 lint 代码
|
|||
lintOnSave: process.env.NODE_ENV === 'development', |
|||
//不需要生产环境构建source map,方便输出的错误信息
|
|||
productionSourceMap: false, |
|||
|
|||
devServer: { |
|||
//配置服务器端口设置
|
|||
port: port, |
|||
//告诉 dev-server 在服务器已经启动后打开浏览器。设置其为 true 以打开你的默认浏览器。
|
|||
open: true, |
|||
//当出现编译错误或警告时,在浏览器中显示全屏覆盖。
|
|||
overlay: { |
|||
warnings: false, |
|||
errors: true |
|||
}, |
|||
//开发代理服务设置
|
|||
proxy: { |
|||
'/api': { |
|||
//代理目标路径
|
|||
target: process.env.VUE_APP_BASE_API, |
|||
//保留主机头的来源
|
|||
changeOrigin: true, |
|||
//路径规则
|
|||
pathRewrite: { |
|||
'^/api': 'api' |
|||
} |
|||
}, |
|||
'/auth': { |
|||
target: process.env.VUE_APP_BASE_API, |
|||
changeOrigin: true, |
|||
pathRewrite: { |
|||
'^/auth': 'auth' |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
// configureWebpack: {
|
|||
// // 覆盖webpack默认配置的都在这里
|
|||
// name: name,
|
|||
// resolve: {
|
|||
// alias: {
|
|||
// '@': resolve('src'),
|
|||
// '@crud': resolve('src/components/Crud')
|
|||
// },
|
|||
|
|||
// chainWebpack(config) {
|
|||
// config.plugins.delete('preload')
|
|||
// config.plugins.delete('prefetch')
|
|||
|
|||
// // set svg-sprite-loader
|
|||
// config.module
|
|||
// .rule('svg')
|
|||
// .exclude.add(resolve('src/assets/icons'))
|
|||
// .end()
|
|||
// config.module
|
|||
// .rule('icons')
|
|||
// .test(/\.svg$/)
|
|||
// .include.add(resolve('src/assets/icons'))
|
|||
// .end()
|
|||
// .use('svg-sprite-loader')
|
|||
// .loader('svg-sprite-loader')
|
|||
// .options({
|
|||
// symbolId: 'icon-[name]'
|
|||
// })
|
|||
// .end()
|
|||
|
|||
// // set preserveWhitespace
|
|||
// config.module
|
|||
// .rule('vue')
|
|||
// .use('vue-loader')
|
|||
// .loader('vue-loader')
|
|||
// .tap(options => {
|
|||
// options.compilerOptions.preserveWhitespace = true
|
|||
// return options
|
|||
// })
|
|||
// .end()
|
|||
|
|||
// config
|
|||
|
|||
// .when(process.env.NODE_ENV === 'development',
|
|||
// config => config.devtool('cheap-source-map')
|
|||
// )
|
|||
|
|||
// config
|
|||
// .when(process.env.NODE_ENV !== 'development',
|
|||
// config => {
|
|||
// config
|
|||
// .plugin('ScriptExtHtmlWebpackPlugin')
|
|||
// .after('html')
|
|||
// .use('script-ext-html-webpack-plugin', [{
|
|||
|
|||
// inline: /runtime\..*\.js$/
|
|||
// }])
|
|||
// .end()
|
|||
// config
|
|||
// .optimization.splitChunks({
|
|||
// chunks: 'all',
|
|||
// cacheGroups: {
|
|||
// libs: {
|
|||
// name: 'chunk-libs',
|
|||
// test: /[\\/]node_modules[\\/]/,
|
|||
// priority: 10,
|
|||
// chunks: 'initial'
|
|||
// },
|
|||
// elementUI: {
|
|||
// name: 'chunk-elementUI',
|
|||
// priority: 20,
|
|||
// test: /[\\/]node_modules[\\/]_?element-ui(.*)/
|
|||
// },
|
|||
// commons: {
|
|||
// name: 'chunk-commons',
|
|||
// test: resolve('src/components'),
|
|||
// minChunks: 3,
|
|||
// priority: 5,
|
|||
// reuseExistingChunk: true
|
|||
// }
|
|||
// }
|
|||
// })
|
|||
// config.optimization.runtimeChunk('single')
|
|||
// }
|
|||
// )
|
|||
// },
|
|||
// transpileDependencies: [
|
|||
// 'vue-echarts',
|
|||
// 'resize-detector'
|
|||
// ]
|
|||
// }
|
|||
// }
|
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue