刘力
3 years ago
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