Commit 3a5e2d08 authored by limeimei's avatar limeimei

1

parent ab34a00f
Pipeline #2388 failed with stages
{
"presets": [
["es2015", { "modules": false }],
"stage-2"
],
"plugins": ["transform-runtime"],
"comments": false,
"env": {
"test": {
"plugins": [ "istanbul" ]
}
}
}
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
node_modules
# vue-login-manage
# manage-system #
基于Vue.js 2.x系列 + Element UI + Node.js + Mysql的后台管理系统解决方案。
## 准备工作 ##
需在本地安装 Node.js
## 功能 ##
- [x] Element UI
- [x] 登录/注销
- [x] 个人中心
- [x] 修改用户信息
- [x] 修改密码
- [x] mysql
- [x] 图形验证码
## 目录结构介绍 ##
|-- build // webpack配置文件
|-- config // 项目打包路径
|-- src // 源码目录
├─service // 服务端
│ │-- app.js // express 入口文件
│ |-- api // 接口
│ │-- userApi.js // 接口映射文件
│ |-- db // 数据库
│ |-- db.js // 连接数据库
│ |-- sqlMap.js // 数据库映射文件
| |-- components // 组件
| |-- common // 公共组件
| |-- Header.vue // 公共头部
| |-- Home.vue // 公共路由入口
| |-- Sidebar.vue // 公共左边栏
| |-- page // 主要路由页面
| |-- Identify.vue // 图形验证码
| |-- Login.vue // 登录
| |-- ModifyPassword.vue // 修改密码
| |-- ModifyUser.vue // 修改用户
| |-- Readme.vue // 简介
| |-- Register.vue // 注册组件
| |-- UserCenter.vue // 用户中心
| |-- Success.vue // 修改成功
| |-- App.vue // 页面入口文件
| |-- main.js // 程序入口文件,加载各种公共组件
|-- .babelrc // ES6语法编译配置
|-- .editorconfig // 代码编写规格
|-- .gitignore // 忽略的文件
|-- index.html // 入口html文件
|-- package.json // 项目及工具的依赖配置文件
|-- README.md // 说明
## 安装步骤 ##
https://github.com/sakila1012/vue-login-manage-system.git // 把项目下载到本地
cd manage-system // 进入项目目录
npm install // 安装项目依赖,等待安装完成之后
## 本地开发 ##
// 开启前端服务器,浏览器访问 http://localhost:8083,在根目录下执行下面命令
npm run dev
## 服务端开发 ##
// 开启后端服务器
cd service
node app
## 构建生产 ##
// 执行构建命令,生成的dist文件夹放在服务器下即可访问
npm run build
// https://github.com/shelljs/shelljs
require('./check-versions')()
process.env.NODE_ENV = 'production'
var ora = require('ora')
var path = require('path')
var chalk = require('chalk')
var shell = require('shelljs')
var webpack = require('webpack')
var config = require('../config')
var webpackConfig = require('./webpack.prod.conf')
var spinner = ora('building for production...')
spinner.start()
var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory)
shell.rm('-rf', assetsPath)
shell.mkdir('-p', assetsPath)
shell.config.silent = true
shell.cp('-R', 'static/*', assetsPath)
shell.config.silent = false
webpack(webpackConfig, function (err, stats) {
spinner.stop()
if (err) throw err
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n')
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'
))
})
var chalk = require('chalk')
var semver = require('semver')
var packageConfig = require('../package.json')
function exec (cmd) {
return require('child_process').execSync(cmd).toString().trim()
}
var versionRequirements = [
{
name: 'node',
currentVersion: semver.clean(process.version),
versionRequirement: packageConfig.engines.node
},
{
name: 'npm',
currentVersion: exec('npm --version'),
versionRequirement: packageConfig.engines.npm
}
]
module.exports = function () {
var warnings = []
for (var i = 0; i < versionRequirements.length; i++) {
var 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 (var i = 0; i < warnings.length; i++) {
var warning = warnings[i]
console.log(' ' + warning)
}
console.log()
process.exit(1)
}
}
/* eslint-disable */
require('eventsource-polyfill')
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
hotClient.subscribe(function (event) {
if (event.action === 'reload') {
window.location.reload()
}
})
require('./check-versions')()
var config = require('../config')
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
}
var opn = require('opn')
var path = require('path')
var express = require('express')
var webpack = require('webpack')
var proxyMiddleware = require('http-proxy-middleware')
var webpackConfig = require('./webpack.dev.conf')
// default port where dev server listens for incoming traffic
var port = process.env.PORT || config.dev.port
// automatically open browser, if not set will be false
var autoOpenBrowser = !!config.dev.autoOpenBrowser
// Define HTTP proxies to your custom API backend
// https://github.com/chimurai/http-proxy-middleware
var proxyTable = config.dev.proxyTable
var app = express()
var compiler = webpack(webpackConfig)
var rouuter = express.Router();
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
quiet: true
})
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
log: () => {}
})
// force page reload when html-webpack-plugin template changes
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
hotMiddleware.publish({ action: 'reload' })
cb()
})
})
// proxy api requests
Object.keys(proxyTable).forEach(function (context) {
var options = proxyTable[context]
if (typeof options === 'string') {
options = { target: options }
}
app.use(proxyMiddleware(options.filter || context, options))
})
// handle fallback for HTML5 history API
app.use(require('connect-history-api-fallback')())
// serve webpack bundle output
app.use(devMiddleware)
// enable hot-reload and state-preserving
// compilation error display
app.use(hotMiddleware)
// serve pure static assets
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
app.use(staticPath, express.static('./static'))
var uri = 'http://localhost:' + port
devMiddleware.waitUntilValid(function () {
console.log('> Listening at ' + uri + '\n')
})
module.exports = app.listen(port, function (err) {
if (err) {
console.log(err)
return
}
// when env is testing, don't need open it
if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
opn(uri)
}
})
var path = require('path')
var config = require('../config')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
exports.assetsPath = function (_path) {
var assetsSubDirectory = process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory
: config.dev.assetsSubDirectory
return path.posix.join(assetsSubDirectory, _path)
}
exports.cssLoaders = function (options) {
options = options || {}
// generate loader string to be used with extract text plugin
function generateLoaders (loaders) {
var sourceLoader = loaders.map(function (loader) {
var extraParamChar
if (/\?/.test(loader)) {
loader = loader.replace(/\?/, '-loader?')
extraParamChar = '&'
} else {
loader = loader + '-loader'
extraParamChar = '?'
}
return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '')
}).join('!')
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: sourceLoader,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader', sourceLoader].join('!')
}
}
// http://vuejs.github.io/vue-loader/en/configurations/extract-css.html
return {
css: generateLoaders(['css']),
postcss: generateLoaders(['css']),
less: generateLoaders(['css', 'less']),
sass: generateLoaders(['css', 'sass?indentedSyntax']),
scss: generateLoaders(['css', 'sass']),
stylus: generateLoaders(['css', 'stylus']),
styl: generateLoaders(['css', 'stylus'])
}
}
// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
var output = []
var loaders = exports.cssLoaders(options)
for (var extension in loaders) {
var loader = loaders[extension]
output.push({
test: new RegExp('\\.' + extension + '$'),
loader: loader
})
}
return output
}
This diff is collapsed.
var utils = require('./utils')
var config = require('../config')
var isProduction = process.env.NODE_ENV === 'production'
module.exports = {
loaders: utils.cssLoaders({
sourceMap: isProduction
? config.build.productionSourceMap
: config.dev.cssSourceMap,
extract: isProduction
}),
postcss: [
require('autoprefixer')({
browsers: ['last 2 versions']
})
]
}
var path = require('path')
var utils = require('./utils')
var webpack = require('webpack')
var config = require('../config')
var vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
entry: {
app: ['babel-polyfill','./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'],
modules: [
resolve('src'),
resolve('node_modules')
],
alias: {
'vue$': 'vue/dist/vue.common.js',
'@': resolve('src'),
'assets': resolve('src/assets'),
'components': resolve('src/components')
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
query: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
query: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
// plugins: [
// new webpack.DllReferencePlugin({
// context: path.resolve(__dirname, '..'),
// manifest: require('./vendor-manifest.json')
// })
// ]
}
var utils = require('./utils')
var webpack = require('webpack')
var config = require('../config')
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
// add hot-reload related code to entry chunks
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})
module.exports = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
},
// cheap-module-eval-source-map is faster for development
devtool: '#cheap-module-eval-source-map',
plugins: [
new webpack.DefinePlugin({
'process.env': config.dev.env
}),
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
new FriendlyErrorsPlugin()
]
})
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
vendor: ['vue/dist/vue.common.js','vue-router', 'babel-polyfill','axios']
},
output: {
path: path.join(__dirname, '../static/js'),
filename: '[name].dll.js',
library: '[name]_library'
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, '.', '[name]-manifest.json'),
name: '[name]_library'
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
})
]
};
\ No newline at end of file
var path = require('path')
var utils = require('./utils')
var webpack = require('webpack')
var config = require('../config')
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var env = config.build.env
var webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true
})
},
devtool: config.build.productionSourceMap ? '#source-map' : 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 webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
}),
// extract css into its own file
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css')
}),
// 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'
}),
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module, count) {
// 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',
chunks: ['vendor']
})
]
})
if (config.build.productionGzip) {
var 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) {
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig
var merge = require('webpack-merge')
var prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"'
})
// see http://vuejs-templates.github.io/webpack for documentation.
var path = require('path')
module.exports = {
build: {
env: require('./prod.env'),
index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: './',
productionSourceMap: false,
// 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
},
dev: {
env: require('./dev.env'),
port: 8086,
autoOpenBrowser: true,
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {
'/api':{
// target:'http://jsonplaceholder.typicode.com',
target: 'http://127.0.0.1:3000/api/',
changeOrigin:true,
pathRewrite:{
'^/api':''
}
},
// '/ms':{
// target: 'https://www.easy-mock.com/mock/592501a391470c0ac1fab128',
// changeOrigin: true
// }
},
// CSS Sourcemaps off by default because relative paths are "buggy"
// with this option, according to the CSS-Loader README
// (https://github.com/webpack/css-loader#sourcemaps)
// In our experience, they generally work as expected,
// just be aware of this issue when enabling this option.
cssSourceMap: false
},
}
module.exports = {
NODE_ENV: '"production"'
}
.header{
background-color: #242f42;
}
.login-wrap{
background: #324157;
}
.plugins-tips{
background: #eef1f6;
}
.plugins-tips a{
color: #20a0ff;
}
.el-upload--text em {
color: #20a0ff;
}
.pure-button{
background: #20a0ff;
}
\ No newline at end of file
.vue-datasource *{
box-sizing: border-box;
font-size: 14px;
}
.vue-datasource .panel {
margin-bottom: 22px;
background-color: #fff;
border: 1px solid transparent;
border-radius: 4px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
}
.vue-datasource .panel-default {
border-color: #d3e0e9;
}
.vue-datasource .panel-heading {
padding: 10px 15px;
border-bottom: 1px solid transparent;
border-top-right-radius: 3px;
border-top-left-radius: 3px;
}
.vue-datasource .panel-default > .panel-heading {
height:56px;
color: #333333;
background-color: #fff;
border-color: #d3e0e9;
}
.vue-datasource .pull-left {
float: left !important;
}
.vue-datasource .pull-right {
float: right !important;
}
.vue-datasource .form-group {
margin-bottom: 15px;
}
.vue-datasource label {
display: inline-block;
max-width: 100%;
margin-bottom: 5px;
font-weight: bold;
}
.vue-datasource .form-control {
display: block;
width: 100%;
height: 36px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.6;
color: #555555;
background-color: #fff;
background-image: none;
border: 1px solid #ccd0d2;
border-radius: 4px;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
}
.vue-datasource .btn {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
padding: 6px 12px;
font-size: 14px;
line-height: 1.6;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.vue-datasource .btn-primary {
color: #fff;
background-color: #3097D1;
border-color: #2a88bd;
}
.vue-datasource .table {
width: 100%;
max-width: 100%;
margin-bottom: 22px;
border-collapse: collapse;
border-spacing: 0;
text-align: center;
}
.vue-datasource .table > thead > tr > th {
vertical-align: bottom;
border-bottom: 2px solid #ddd;
}
.vue-datasource .table th ,.vue-datasource .table td {
padding: 8px;
line-height: 1.6;
vertical-align: top;
border-top: 1px solid #ddd;
}
.vue-datasource .table-striped > tbody > tr:nth-of-type(odd) {
background-color: #f9f9f9;
}
.vue-datasource .success th ,.vue-datasource .success td{
background-color: #dff0d8;
}
.vue-datasource .pagination {
display: inline-block;
padding-left: 0;
margin: 22px 0;
border-radius: 4px;
}
.vue-datasource .pagination > li {
display: inline;
}
.pagination > li > a,.pagination > li > span {
position: relative;
float: left;
padding: 6px 12px;
line-height: 1.6;
text-decoration: none;
color: #3097D1;
background-color: #fff;
border: 1px solid #ddd;
margin-left: -1px;
}
.pagination > .disabled > span, .pagination > .disabled > span:hover, .pagination > .disabled > span:focus, .pagination > .disabled > a, .pagination > .disabled > a:hover, .pagination > .disabled > a:focus {
color: #777777;
background-color: #fff;
border-color: #ddd;
cursor: not-allowed;
}
.pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus, .pagination > .active > span, .pagination > .active > span:hover, .pagination > .active > span:focus {
z-index: 3;
color: #fff;
background-color: #3097D1;
border-color: #3097D1;
cursor: default;
}
.vue-datasource .pagination > li:first-child > a, .vue-datasource .pagination > li:first-child > span {
margin-left: 0;
border-bottom-left-radius: 4px;
border-top-left-radius: 4px;
}
.vue-datasource .text-center {
text-align: center;
}
@media (min-width: 768px){
.form-inline .form-group {
display: inline-block;
margin-bottom: 0;
vertical-align: middle;
}
.form-inline .control-label {
margin-bottom: 0;
vertical-align: middle;
}
.form-inline .form-control {
display: inline-block;
width: auto;
vertical-align: middle;
}
}
*{margin:0;padding:0;}
html,body,#app,.wrapper{
width:100%;
height:100%;
overflow: hidden;
}
body{
font-family:"Helvetica Neue",Helvetica, "microsoft yahei", arial, STHeiTi, sans-serif;
}
a{text-decoration: none}
.content{
background: none repeat scroll 0 0 #fff;
position: absolute;
left: 250px;
right: 0;
top: 70px;
bottom:0;
width: auto;
padding:40px;
box-sizing: border-box;
overflow-y: scroll;
}
.crumbs{
margin-bottom: 20px;
}
.pagination{
margin: 20px 0;
text-align: right;
}
.plugins-tips{
padding:20px 10px;
margin-bottom: 20px;
}
.el-button+.el-tooltip {
margin-left: 10px;
}
.el-table tr:hover{
background: #f6faff;
}
.mgb20{
margin-bottom: 20px;
}
.move-enter-active,.move-leave-active{
transition: opacity .5s;
}
.move-enter,.move-leave{
opacity: 0;
}
/*BaseForm*/
.form-box{
width:600px;
}
.form-box .line{
text-align: center;
}
.el-time-panel__content::after, .el-time-panel__content::before {
margin-top: -7px;
}
/*Readme*/
.ms-doc .el-checkbox__input.is-disabled+.el-checkbox__label{
color: #333;
cursor: pointer;
}
/*Upload*/
.pure-button{
width:150px;
height:40px;
line-height: 40px;
text-align: center;
color: #fff;
border-radius: 3px;
}
.g-core-image-corp-container .info-aside{
height:45px;
}
.el-upload--text {
background-color: #fff;
border: 1px dashed #d9d9d9;
border-radius: 6px;
box-sizing: border-box;
width: 360px;
height: 180px;
text-align: center;
cursor: pointer;
position: relative;
overflow: hidden;
}
.el-upload--text .el-icon-upload {
font-size: 67px;
color: #97a8be;
margin: 40px 0 16px;
line-height: 50px;
}
.el-upload--text {
color: #97a8be;
font-size: 14px;
text-align: center;
}
.el-upload--text em {
font-style: normal;
}
/*VueEditor*/
.ql-container{
min-height: 400px;
}
.ql-snow .ql-tooltip{
transform: translateX(117.5px) translateY(10px) !important;
}
.editor-btn{
margin-top: 20px;
}
\ No newline at end of file
.header{
background-color: #00d1b2;
}
.login-wrap{
background: rgba(56, 157, 170, 0.82);;
}
.plugins-tips{
background: #f2f2f2;
}
.plugins-tips a{
color: #00d1b2;
}
.el-upload--text em {
color: #00d1b2;
}
.pure-button{
background: #00d1b2;
}
.vue-datasource .btn-primary {
color: #fff;
background-color: #00d1b2 !important;
border-color: #00d1b2 !important;
}
.pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus, .pagination > .active > span, .pagination > .active > span:hover, .pagination > .active > span:focus {
background-color: #00d1b2 !important;
border-color: #00d1b2 !important;
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"pagination": {
"total": 15,
"per_page": 15,
"current_page": 1,
"last_page": 1,
"from": 1,
"to": 15
},
"data": [
{
"id": 1,
"name": "Jaylen Schmidt",
"email": "aheaney@example.org",
"city": "Conroyburgh",
"company": "Kunde, Gerhold and Runte",
"job": "Soil Scientist",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 2,
"name": "Ms. Desiree Franecki III",
"email": "pweissnat@example.net",
"city": "New Mathew",
"company": "Davis Ltd",
"job": "Customer Service Representative",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 3,
"name": "Clyde Corwin",
"email": "rolfson.lexus@example.com",
"city": "East Ron",
"company": "Zieme and Sons",
"job": "Claims Taker",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 4,
"name": "Mr. Tyrese Kuphal",
"email": "libby.heaney@example.com",
"city": "Cristianland",
"company": "Abernathy LLC",
"job": "Occupational Health Safety Technician",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 5,
"name": "Ms. Amya West PhD",
"email": "uheller@example.org",
"city": "Treutelmouth",
"company": "Mraz-Effertz",
"job": "Hazardous Materials Removal Worker",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 6,
"name": "Murphy Stamm IV",
"email": "ckautzer@example.com",
"city": "Myleneshire",
"company": "Sporer-Wolf",
"job": "Pipelaying Fitter",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 7,
"name": "Elsa Jast",
"email": "kaitlyn.lang@example.net",
"city": "Mariahstad",
"company": "Hackett LLC",
"job": "Record Clerk",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 8,
"name": "Hardy Mosciski DVM",
"email": "soledad44@example.net",
"city": "Jasminborough",
"company": "Haley Ltd",
"job": "Kindergarten Teacher",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 9,
"name": "Demarcus Littel",
"email": "americo84@example.com",
"city": "New Lilaton",
"company": "Satterfield Group",
"job": "Plant Scientist",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 10,
"name": "Dr. Shad Gleichner",
"email": "eleanora23@example.com",
"city": "Lake Whitneyberg",
"company": "Fay Group",
"job": "Rotary Drill Operator",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 11,
"name": "Milford Mann",
"email": "shartmann@example.net",
"city": "Lake Austinport",
"company": "Sporer-Langosh",
"job": "Social and Human Service Assistant",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 12,
"name": "Prof. Mustafa Lindgren Sr.",
"email": "lizeth.morissette@example.net",
"city": "Roweborough",
"company": "Mitchell-Ratke",
"job": "Shoe Machine Operators",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 13,
"name": "Mrs. Brittany Bode Sr.",
"email": "wiegand.mozelle@example.org",
"city": "South Maxwellville",
"company": "Reilly Inc",
"job": "Bridge Tender OR Lock Tender",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 14,
"name": "Dariana Bauch",
"email": "dessie.schamberger@example.net",
"city": "East Linnie",
"company": "Wuckert PLC",
"job": "Elementary and Secondary School Administrators",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
},
{
"id": 15,
"name": "Jalon Renner",
"email": "lulu45@example.net",
"city": "New Rashad",
"company": "Muller-Kuhn",
"job": "Manufactured Building Installer",
"created_at": "2017-01-13 19:17:16",
"updated_at": "2017-01-13 19:17:16"
}
]
}
\ No newline at end of file
{
"data": [{
"id": 1,
"name": "段娜",
"email": "g.rgiuory@kctbut.mw",
"ip": "68.28.4.232"
},
{
"id": 2,
"name": "蔡洋",
"email": "y.mwjjoje@lpkshev.tg",
"ip": "22.126.12.189"
},
{
"id": 3,
"name": "陈敏",
"email": "e.voaiiuo@mvng.sn",
"ip": "227.89.13.37"
},
{
"id": 4,
"name": "朱平",
"email": "e.lduuf@nkfypn.az",
"ip": "9.39.240.243"
},
{
"id": 5,
"name": "侯平",
"email": "t.czqjyndts@jmwenklns.md",
"ip": "178.162.29.113"
},
{
"id": 6,
"name": "常超",
"email": "d.dhysgem@uxpcutmlk.tt",
"ip": "192.50.103.170"
},
{
"id": 7,
"name": "许平",
"email": "g.fiqdonvbc@wanepptw.tv",
"ip": "73.20.99.60"
},
{
"id": 8,
"name": "毛超",
"email": "w.unyyejh@qus.gt",
"ip": "10.88.135.123"
},
{
"id": 9,
"name": "周磊",
"email": "e.qbejguqqg@ejpxhltoak.gw",
"ip": "244.221.237.210"
},
{
"id": 10,
"name": "胡秀英",
"email": "s.dszo@uxaojtj.sy",
"ip": "86.199.17.210"
}
],
"pagination": {
"total": 15,
"per_page": 15,
"current_page": 1,
"last_page": 1,
"from": 1,
"to": 15
}
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"list": [{
"date": "1997-11-11",
"name": "林丽",
"address": "吉林省 辽源市 龙山区"
}, {
"date": "1987-09-24",
"name": "文敏",
"address": "江西省 萍乡市 芦溪县"
}, {
"date": "1996-08-08",
"name": "杨秀兰",
"address": "黑龙江省 黑河市 五大连池市"
}, {
"date": "1978-06-18",
"name": "魏强",
"address": "广东省 韶关市 始兴县"
}, {
"date": "1977-07-09",
"name": "石秀兰",
"address": "江苏省 宿迁市 宿豫区"
}, {
"date": "1994-09-20",
"name": "朱洋",
"address": "海外 海外 -"
}, {
"date": "1980-01-22",
"name": "傅敏",
"address": "海外 海外 -"
}, {
"date": "1985-10-10",
"name": "毛明",
"address": "内蒙古自治区 包头市 九原区"
}, {
"date": "1975-09-08",
"name": "何静",
"address": "西藏自治区 阿里地区 普兰县"
}, {
"date": "1970-06-07",
"name": "郭秀英",
"address": "四川省 巴中市 恩阳区"
}]
}
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vue-manage-system | 基于Vue 的后台管理系统</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
<meta name="keywords" content="vue.js, wms, vue2, 后台模板, 管理系统, element" />
<meta name="description" content="基于Vue2 + Element UI 的后台管理系统解决方案" />
</head>
<body>
<div id="app"></div>
<!--<script src="./static/js/vendor.dll.js"></script>-->
<!-- <script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?1c343a080809502ac823823ae4c9ffe3";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script> -->
</body>
</html>
This diff is collapsed.
{
"name": "manage-system",
"version": "2.1.0",
"description": "基于Vue.js 2.x系列 + element-ui 内容管理系统解决方案",
"author": "lin-xin <2981207131@qq.com>",
"private": true,
"scripts": {
"dev": "node build/dev-server.js",
"build": "node build/build.js",
"build:dll": "webpack --config build/webpack.dll.conf.js"
},
"dependencies": {
"axios": "^0.15.3",
"babel-polyfill": "^6.23.0",
"body-parser": "^1.18.2",
"element-ui": "1.3.1",
"js-cookie": "^2.2.0",
"mysql": "^2.15.0",
"normalize.css": "^8.0.0",
"nprogress": "^0.2.0",
"vue": "^2.3.2",
"vue-core-image-upload": "2.1.11",
"vue-datasource": "1.0.9",
"vue-quill-editor": "2.1.6",
"vue-router": "^2.3.1",
"vue-schart": "^0.1.2",
"vue-simplemde": "0.3.8",
"vuex": "^3.0.1"
},
"devDependencies": {
"autoprefixer": "^6.7.2",
"babel-core": "^6.22.1",
"babel-loader": "^6.2.10",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-preset-es2015": "^6.22.0",
"babel-preset-stage-2": "^6.22.0",
"babel-register": "^6.22.0",
"chalk": "^1.1.3",
"connect-history-api-fallback": "^1.3.0",
"css-loader": "^0.28.0",
"eventsource-polyfill": "^0.9.6",
"express": "^4.14.1",
"extract-text-webpack-plugin": "^2.0.0",
"file-loader": "^0.11.1",
"friendly-errors-webpack-plugin": "^1.1.3",
"function-bind": "^1.1.0",
"html-webpack-plugin": "^2.28.0",
"http-proxy-middleware": "^0.17.3",
"opn": "^4.0.2",
"ora": "^1.2.0",
"semver": "^5.3.0",
"shelljs": "^0.7.6",
"url-loader": "^0.5.8",
"vue-loader": "^11.3.4",
"vue-style-loader": "^2.0.5",
"vue-template-compiler": "^2.2.6",
"webpack": "^2.3.3",
"webpack-bundle-analyzer": "^2.2.1",
"webpack-dev-middleware": "^1.10.0",
"webpack-hot-middleware": "^2.18.0",
"webpack-merge": "^4.1.0"
},
"engines": {
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
var models = require('../db/db');
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
var $sql = require('../db/sqlMap');
var conn = mysql.createConnection(models.mysql);
conn.connect();
var jsonWrite = function(res, ret) {
if(typeof ret === 'undefined') {
res.send('err');
} else {
console.log(ret);
res.send(ret);
}
}
var dateStr = function(str) {
return new Date(str.slice(0,7));
}
// 增加用户接口
router.post('/addUser', (req, res) => {
var sql = $sql.user.add;
var params = req.body;
console.log(params);
console.log(params.birth);
conn.query(sql, [params.name, params.account, params.pass, params.checkPass,
params.email, params.phone, params.card, dateStr(params.birth), params.sex], function(err, result) {
if (err) {
console.log(err);
}
if (result) {
jsonWrite(res, result);
}
})
});
//查找用户接口
router.post('/login', (req, res) => {
var sql_name = $sql.user.select_name;
// var sql_password = $sql.user.select_password;
var params = req.body;
var keywords = JSON.parse(Object.keys(params)[0]);
if (keywords.name) {
sql_name += " where username ='"+ keywords.name +"'";
}
console.log(sql_name);
conn.query(sql_name, params.name, function(err, result) {
if (err) {
console.log(err);
}
result=JSON.parse(JSON.stringify(result))
if (result[0] === undefined) {
res.send('-1') //查询不出username,data 返回-1
} else {
var resultArray = result[0];
// console.log(keywords);
let data= {code:200,data:{...resultArray}}
if(resultArray.password === keywords.password) {
jsonWrite(res,data);
} else {
res.send('0') //username
}
}
})
});
//获取用户信息
router.post('/getUser', (req, res) => {
var sql_name = $sql.user.select_menu;
var sql_name2 = $sql.user.select_name;
// var sql_password = $sql.user.select_password;
var params = req.body;
// if (params.name) {
// sql_name += " where username ='"+ params.name +"'";
// }
var sql_name3 = $sql.user.select_role;
conn.query(sql_name2, params.name, function(err, result) {
if (err) {
console.log(err);
}
result=JSON.parse(JSON.stringify(result))
console.log(result);
// if (result[0] === undefined) {
// res.send('-1') //查询不出username,data 返回-1
// } else {
// jsonWrite(res, data);
// }
let arr;
conn.query(sql_name3, params.name, function(err, result3) {
if (err) {
console.log(err);
}
result3=JSON.parse(JSON.stringify(result3))
arr=result3.map((item)=>{return item.rolename})
})
conn.query(sql_name, params.name, function(err, result1) {
if (err) {
console.log(err);
}
let data={code:200,data:{icon:result[0].icon,username:result[0].username,menu:result1,roles:arr}}
// let data={data:{menu:result1}}
console.log(data);
if (result1[0] === undefined) {
res.send('-1') //查询不出username,data 返回-1
} else {
jsonWrite(res, data);
}
})
})
});
//更新用户信息
router.post('/updateUser', (req, res) => {
var sql_update = $sql.user.update_user;
var params = req.body;
console.log(params);
if (params.id) {
sql_update += " email = '" + params.email +
"',phone = '" + params.phone +
"',card = '" + params.card +
"',birth = '" + params.birth +
"',sex = '" + params.sex +
"' where id ='"+ params.id + "'";
}
conn.query(sql_update, params.id, function(err, result) {
if (err) {
console.log(err);
}
console.log(result);
if (result.affectedRows === undefined) {
res.send('更新失败,请联系管理员') //查询不出username,data 返回-1
} else {
res.send('ok');
}
})
});
//更改密码
router.post('/modifyPassword', (req, res) => {
var sql_modify = $sql.user.update_user;
var params = req.body;
console.log(params);
if (params.id) {
sql_modify += " password = '" + params.pass +
"',repeatPass = '" + params.checkPass +
"' where id ='"+ params.id + "'";
}
conn.query(sql_modify, params.id, function(err, result) {
if (err) {
console.log(err);
}
// console.log(result);
if (result.affectedRows === undefined) {
res.send('修改密码失败,请联系管理员') //查询不出username,data 返回-1
} else {
res.send('ok');
}
})
});
module.exports = router;
const userApi = require('./api/userApi');
const fs = require('fs');
const path = require('path');
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded())
app.use('/api/user', userApi);
app.listen(3000);
console.log('success listen at port: 3000')
\ No newline at end of file
module.exports = {
mysql: {
host: 'localhost',
user: 'root',
password: '123456',
port: '3306',
database: 'login'
}
}
var sqlMap = {
user: {
add: 'insert into user (username, account, password, repeatPass, email, phone, card, birth, sex) values (?,?,?,?,?,?,?,?,?)',
select_name: 'select a.username,a.password,a.token,a.icon,a.tokenHead from user as a',
update_user: 'update user set',
select_menu:'select a.username ,b.* from user a,menu b where a.u_id=b.m_no',
select_role: 'select rolename from role ',
},
menu: {
add: 'insert into user (username, account, password, repeatPass, email, phone, card, birth, sex) values (?,?,?,?,?,?,?,?,?)',
select_name: 'select a.username ,b.* from user as a,menu as b where a.m_no=b.m_no',
update_user: 'update user set'
}
}
module.exports = sqlMap;
\ No newline at end of file
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<style>
@import "../static/css/main.css";
@import "../static/css/color-dark.css"; /*深色主题*/
/*@import "../static/css/theme-green/color-green.css"; 浅绿色主题*/
</style>
\ No newline at end of file
This diff is collapsed.
<template>
<div class="header">
<div class="logo">登录管理系统</div>
<div class="user-info">
<el-dropdown trigger="click" @command="handleCommand">
<span class="el-dropdown-link">
<img class="user-logo" src="../../../static/img/img.jpg">
{{username}}
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="userCenter">个人中心</el-dropdown-item>
<el-dropdown-item command="loginout">退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
<script>
export default {
data() {
return {
name: 'linxin'
}
},
computed:{
username(){
let username = sessionStorage.getItem('ms_username');
return username ? username : this.name;
}
},
methods:{
handleCommand(command) {
if(command == 'loginout'){
sessionStorage.removeItem('ms_username')
sessionStorage.removeItem('ms_userId')
this.$router.push('/login');
} else if (command == 'userCenter') {
this.$router.push('/userCenter');
}
}
}
}
</script>
<style scoped>
.header {
position: relative;
box-sizing: border-box;
width: 100%;
height: 70px;
font-size: 22px;
line-height: 70px;
color: #fff;
}
.header .logo{
float: left;
width:250px;
text-align: center;
}
.user-info {
float: right;
padding-right: 50px;
font-size: 16px;
color: #fff;
}
.user-info .el-dropdown-link{
position: relative;
display: inline-block;
padding-left: 50px;
color: #fff;
cursor: pointer;
vertical-align: middle;
}
.user-info .user-logo{
position: absolute;
left:0;
top:15px;
width:40px;
height:40px;
border-radius: 50%;
}
.el-dropdown-menu__item{
text-align: center;
}
</style>
<template>
<div class="wrapper">
<v-head></v-head>
<v-sidebar></v-sidebar>
<div class="content">
<transition name="move" mode="out-in"><router-view></router-view></transition>
</div>
</div>
</template>
<script>
import vHead from './Header.vue';
import vSidebar from './Sidebar.vue';
export default {
components:{
vHead, vSidebar
}
}
</script>
<template>
<div class="sidebar">
<el-menu :default-active="$route.path" class="el-menu-vertical-demo" theme="dark" unique-opened router>
<template v-for="item in routes">
<template v-if="item.children">
<el-submenu :index="item.path">
<template slot="title"><i :class="item.icon"></i>{{ item.title }}</template>
<el-menu-item v-for="(subItem,i) in item.children" :key="i" :index="subItem.path">{{ subItem.title }}
</el-menu-item>
</el-submenu>
</template>
<template v-else>
<router-link :to="item.path">
<el-menu-item :index="item.path">
<i :class="item.icon"></i>{{ item.title }}11
</el-menu-item>
</router-link>
</template>
</template>
</el-menu>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
data() {
return {
items: [
{
icon: 'el-icon-setting',
index: 'readme',
title: '简介'
},
{
icon: 'el-icon-setting',
index: 'device',
title: '设备管理',
subs: [
{
index: 'device',
title: '详情'
},
{
index: 'detail',
title: '列表'
},
]
}, {
icon: 'el-icon-setting',
index: 'model',
title: '机型列表'
}, {
icon: 'el-icon-setting',
index: 'engraving',
title: '雕刻机'
},
{
icon: 'el-icon-setting',
index: 'userCenter',
title: '设置',
subs: [
{
index: 'upload',
title: '文件上传'
},
{
index: 'modifyUser',
title: '修改用户'
},
{
index: 'modifyPassword',
title: '修改密码'
}
]
}
]
}
},
// computed:{
// onRoutes(){
// return this.$route.path.replace('/','');
// }
// },
computed: {
...mapGetters([
'sidebar',
'routers'
]),
routes() {
console.log(this.routers)
// return this.$router.options.routes
return this.routers
},
// isCollapse() {
// return !this.sidebar.opened
// }
},
created() {
console.log(this.routers)
},
}
</script>
<style scoped>
.sidebar{
display: block;
position: absolute;
width: 250px;
left: 0;
top: 70px;
bottom:0;
background: #2E363F;
}
.sidebar > ul {
height:100%;
}
</style>
<template>
<div class="s-canvas">
<canvas id="s-canvas" :width="contentWidth" :height="contentHeight"></canvas>
</div>
</template>
<script>
export default{
name: 'SIdentify',
props: {
identifyCode: {
type: String,
default: '1234'
},
fontSizeMin: {
type: Number,
default: 16
},
fontSizeMax: {
type: Number,
default: 40
},
backgroundColorMin: {
type: Number,
default: 180
},
backgroundColorMax: {
type: Number,
default: 240
},
colorMin: {
type: Number,
default: 50
},
colorMax: {
type: Number,
default: 160
},
lineColorMin: {
type: Number,
default: 40
},
lineColorMax: {
type: Number,
default: 180
},
dotColorMin: {
type: Number,
default: 0
},
dotColorMax: {
type: Number,
default: 255
},
contentWidth: {
type: Number,
default: 112
},
contentHeight: {
type: Number,
default: 38
}
},
methods: {
// 生成一个随机数
randomNum (min, max) {
return Math.floor(Math.random() * (max - min) + min)
},
// 生成一个随机的颜色
randomColor (min, max) {
let r = this.randomNum(min, max)
let g = this.randomNum(min, max)
let b = this.randomNum(min, max)
return 'rgb(' + r + ',' + g + ',' + b + ')'
},
drawPic () {
let canvas = document.getElementById('s-canvas')
let ctx = canvas.getContext('2d')
ctx.textBaseline = 'bottom'
// 绘制背景
ctx.fillStyle = this.randomColor(this.backgroundColorMin, this.backgroundColorMax)
ctx.fillRect(0, 0, this.contentWidth, this.contentHeight)
// 绘制文字
for (let i = 0; i < this.identifyCode.length; i++) {
this.drawText(ctx, this.identifyCode[i], i)
}
this.drawLine(ctx)
this.drawDot(ctx)
},
drawText (ctx, txt, i) {
ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax)
ctx.font = this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei'
let x = (i + 1) * (this.contentWidth / (this.identifyCode.length + 1))
let y = this.randomNum(this.fontSizeMax, this.contentHeight - 5)
var deg = this.randomNum(-45, 45)
// 修改坐标原点和旋转角度
ctx.translate(x, y)
ctx.rotate(deg * Math.PI / 180)
ctx.fillText(txt, 0, 0)
// 恢复坐标原点和旋转角度
ctx.rotate(-deg * Math.PI / 180)
ctx.translate(-x, -y)
},
drawLine (ctx) {
// 绘制干扰线
for (let i = 0; i < 8; i++) {
ctx.strokeStyle = this.randomColor(this.lineColorMin, this.lineColorMax)
ctx.beginPath()
ctx.moveTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
ctx.lineTo(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight))
ctx.stroke()
}
},
drawDot (ctx) {
// 绘制干扰点
for (let i = 0; i < 100; i++) {
ctx.fillStyle = this.randomColor(0, 255)
ctx.beginPath()
ctx.arc(this.randomNum(0, this.contentWidth), this.randomNum(0, this.contentHeight), 1, 0, 2 * Math.PI)
ctx.fill()
}
}
},
watch: {
identifyCode () {
this.drawPic()
}
},
mounted () {
this.drawPic()
}
}
</script>
\ No newline at end of file
<template>
<div class="login-wrap">
<div class="ms-title">登录管理系统</div>
<div class="ms-login">
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="0px" class="demo-ruleForm">
<div v-if="errorInfo">
<span>{{errInfo}}</span>
</div>
<el-form-item prop="name">
<el-input v-model="ruleForm.name" placeholder="账号" ></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input type="password" placeholder="密码" v-model="ruleForm.password" @keyup.enter.native="submitForm('ruleForm')"></el-input>
</el-form-item>
<el-form-item prop="validate">
<el-input v-model="ruleForm.validate" class="validate-code" placeholder="验证码" ></el-input>
<div class="code" @click="refreshCode">
<s-identify :identifyCode="identifyCode"></s-identify>
</div>
</el-form-item>
<div class="login-btn">
<el-button type="primary" @click="submitForm('ruleForm')">登录</el-button>
</div>
<p class="register" @click="handleCommand()">注册</p>
</el-form>
</div>
</div>
</template>
<script>
import { setSupport, getSupport, setCookie, getCookie } from "../../utils/support.js";
export default {
name: 'login',
data() {
return {
loading: false,
identifyCodes: "1234567890",
identifyCode: "",
errorInfo : false,
ruleForm: {
name: '',
password: '',
validate: ''
},
rules: {
name: [
{ required: true, message: '请输入用户名', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' }
],
validate: [
{ required: true, message: '请输入验证码', trigger: 'blur' }
]
}
}
},
mounted() {
this.identifyCode = "";
this.makeCode(this.identifyCodes, 4);
},
methods: {
submitForm(formName) {
// debounceAjax(formName)
const self = this;
self.$refs[formName].validate((valid) => {
if (valid) {
// self.$http.post('/api/user/login',JSON.stringify(self.ruleForm))
this.$store.dispatch("Login", self.ruleForm)
.then((response) => {
self.$router.push('/readme');
}).then((error) => {
console.log(error);
})
} else {
console.log('error submit!!');
return false;
}
});
},
handleCommand() {
this.$router.push('/register');
},
randomNum(min, max) {
return Math.floor(Math.random() * (max - min) + min);
},
refreshCode() {
this.identifyCode = "";
this.makeCode(this.identifyCodes, 4);
},
makeCode(o, l) {
for (let i = 0; i < l; i++) {
this.identifyCode += this.identifyCodes[
this.randomNum(0, this.identifyCodes.length)
];
}
console.log(this.identifyCode);
},
debounce(func, delay) {
return function(args) {
var _this = this
var _args = args
clearTimeout(func.id)
func.id = setTimeout(function() {
func.call(_this, _args)
}, delay)
}
},
submitDebounce(formName) {
const self = this;
self.$refs[formName].validate((valid) => {
if (valid) {
localStorage.setItem('ms_username',self.ruleForm.name);
localStorage.setItem('ms_user',JSON.stringify(self.ruleForm));
console.log(JSON.stringify(self.ruleForm));
self.$http.post('/api/user/login',JSON.stringify(self.ruleForm))
.then((response) => {
console.log(response);
if (response.data == -1) {
self.errorInfo = true;
self.errInfo = '该用户不存在';
console.log('该用户不存在')
} else if (response.data == 0) {
console.log('密码错误')
self.errorInfo = true;
self.errInfo = '密码错误';
} else if (response.status == 200) {
self.$router.push('/readme');
}
}).then((error) => {
console.log(error);
})
} else {
console.log('error submit!!');
return false;
}
});
},
debounceAjax () {
debounce(submitDebounce,1000);
}
}
}
</script>
<style scoped>
.login-wrap{
position: relative;
width:100%;
height:100%;
}
.ms-title{
position: absolute;
top:50%;
width:100%;
margin-top: -230px;
text-align: center;
font-size:30px;
color: #fff;
}
.ms-login{
position: absolute;
left:50%;
top:50%;
width:300px;
height:240px;
margin:-150px 0 0 -190px;
padding:40px;
border-radius: 5px;
background: #fff;
}
.ms-login span {
color: red;
}
.login-btn{
text-align: center;
}
.login-btn button{
width:100%;
height:36px;
}
.code {
width: 112px;
height: 35px;
border: 1px solid #ccc;
float: right;
border-radius: 2px;
}
.validate-code {
width: 136px;
float: left;
}
.register {
font-size:14px;
line-height:30px;
color:#999;
cursor: pointer;
float:right;
}
</style>
\ No newline at end of file
<template>
<div>
<div class="crumbs">
<el-breadcrumb separator="/">
<el-breadcrumb-item><i class="el-icon-edit"></i> 个人中心</el-breadcrumb-item>
<el-breadcrumb-item>修改密码</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="userContent">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item prop="pass" label="密码">
<el-input v-model="form.pass" type="password" placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item prop="checkPass" label="确认密码">
<el-input v-model="form.checkPass" type="password" placeholder="请再次输入密码"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit('form')">确定</el-button>
<el-button @click="onCancle()">取消</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
data() {
var validatePass = (rule, value, callback) => {
if(value === '') {
callback(new Error('请输入密码'));
} else {
if(this.form.checkPass !== '') {
this.$refs.form.validateField('checkPass');
}
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if(value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.form.pass) {
callback(new Error('两次输入的密码不一致'));
} else {
callback();
}
};
return {
form: {
pass: '',
checkPass: ''
},
rules: {
pass: [
{ validator: validatePass, trigger: 'blur'}
],
checkPass: [
{ validator: validatePass2, trigger: 'blur' }
]
}
}
},
methods:{
onSubmit(formName) {
const self = this;
let formData = {
id: parseInt(sessionStorage.getItem('ms_userId')),
pass: self.form.pass,
checkPass: self.form.checkPass
};
self.$refs[formName].validate((valid) => {
if (valid) {
self.$http.post('/api/user/modifyPassword',formData).then(function(response) {
console.log(response);
self.$router.push('/login');
}).then(function(error) {
console.log(error);
})
} else {
console.log('error submit!!');
return false;
}
});
},
onCancle() {
this.$router.push('/userCenter');
}
}
}
</script>
<style>
.userContent {
width: 400px;
margin: 0 auto;
}
</style>
\ No newline at end of file
<template>
<div>
<div class="crumbs">
<el-breadcrumb separator="/">
<el-breadcrumb-item><i class="el-icon-edit"></i> 个人中心</el-breadcrumb-item>
<el-breadcrumb-item>修改用户</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="userContent">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item prop="name" label="用户名称">
<el-input v-model="form.name" disabled></el-input>
</el-form-item>
<el-form-item prop="account" label="账号名称">
<el-input v-model="form.account" disabled></el-input>
</el-form-item>
<el-form-item prop="email" label="邮箱">
<el-input v-model="form.email" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item prop="phone" label="手机">
<el-input v-model="form.phone" placeholder="请输入手机号"></el-input>
</el-form-item>
<el-form-item prop="card" label="身份证">
<el-input v-model="form.card" placeholder="请输入身份证"></el-input>
</el-form-item>
<el-form-item prop="birth" label="出生日期">
<el-col :span="24">
<el-date-picker type="date" placeholder="选择日期" v-model="form.birth" value-format="yyyy-MM-dd" style="width: 100%;"></el-date-picker>
</el-col>
</el-form-item>
<el-form-item prop="sex" label="性别">
<el-select class="select-sex" v-model="form.sex" placeholder="请选择性别">
<el-option label="男" value="man"></el-option>
<el-option label="女" value="woman"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="updateUserData('form')">确定</el-button>
<el-button @click="onCancle()">取消</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import Util from '../../utils/utils';
export default {
data() {
var validateEmail = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入邮箱'));
} else if (!Util.emailReg.test(this.form.email)){
callback(new Error('请输入正确的邮箱'));
} else {
callback();
}
};
var validatePhone = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入手机号'));
} else if (!Util.phoneReg.test(this.form.phone)){
callback(new Error('请输入正确的手机号'));
} else {
callback();
}
};
var validateCard = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入身份证号'));
} else if (!Util.idCardReg.test(this.form.card)){
callback(new Error('请输入正确的身份证号'));
} else {
callback();
}
};
return {
form: {
name: '',
account: '',
email: '',
phone: '',
card: '',
birth: '',
sex: ''
},
rules: {
name: [
{ required: true, message: '请输入用户名', trigger: 'blur' }
],
account: [
{ required: true, message: '请输入账号', trigger: 'blur' }
],
email: [
{ validator: validateEmail, trigger: 'blur' }
],
phone: [
{ validator: validatePhone, trigger: 'blur' }
],
card: [
{ validator: validateCard, trigger: 'blur' }
],
birth: [
{ required: true, message: '请输入出生日期',type: 'date', trigger: 'blur' }
],
sex: [
{ required: true, message: '请输入性别', trigger: 'blur' }
]
}
}
},
methods:{
getUserData() {
const self = this;
let username = sessionStorage.getItem('ms_user').name;
self.$http.get('/api/user/getUser',{name: username}).then(function(response) {
console.log(response);
let result = response.data[0];
self.form.name = result.username;
self.form.account = result.account;
self.form.email = result.email;
self.form.phone = result.phone;
self.form.card = result.card;
self.form.birth = new Date(result.birth);
self.form.sex = result.sex;
sessionStorage.setItem('ms_userId', result.id);
}).then(function(error) {
console.log(error);
})
},
updateUserData(formName) {
const self = this;
let formData = {
id: parseInt(sessionStorage.getItem('ms_userId')),
email: self.form.email,
phone: self.form.phone,
card: self.form.card,
birth: self.form.birth,
sex: self.form.sex
};
self.$refs[formName].validate((valid) => {
if (valid) {
self.$http.post('/api/user/updateUser',formData).then(function(response) {
console.log(response);
self.$router.push('/success');
}).then(function(error) {
console.log(error);
})
} else {
console.log('error submit!!');
return false;
}
});
},
onCancle() {
this.$router.push('/userCenter');
}
},
//初始化
mounted() {
this.getUserData();
}
}
</script>
<style>
.userContent {
width: 400px;
margin: 0 auto;
}
.select-sex {
width: 320px;
}
</style>
\ No newline at end of file
<template>
<div>
<div class="crumbs">
<el-breadcrumb separator="/">
<el-breadcrumb-item><i class="el-icon-setting"></i> 简介</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="ms-doc">
<h3>README.md</h3>
<article>
<h1>manage-system</h1>
<p>基于Vue.js 2.x系列 + Element UI + Node.js + MySQL的登录管理系统</p>
<h2>前言</h2>
<p>用了Vue + Element组件库做了个登录管理系统,包括注册,登录,个人中心3个功能模块。</p>
<p>该方案作为一套多功能的后台框架模板,适用于绝大部分的后台管理系统(Web Management System)开发。基于vue.js,使用vue-cli脚手架快速生成项目目录,引用Element UI组件库,方便开发快速简洁好看的组件。分离颜色样式,支持手动切换主题色,而且很方便使用自定义主题色。</p>
<h2>功能</h2>
<el-checkbox disabled checked>Element UI</el-checkbox>
<br>
<el-checkbox disabled checked>登录/注销</el-checkbox>
<br>
<el-checkbox disabled checked>图片拖拽/裁剪上传</el-checkbox>
<br>
<el-checkbox disabled checked>修改密码</el-checkbox>
<br>
<el-checkbox disabled checked>修改用户信息</el-checkbox>
<br>
<h2>安装步骤</h2>
<p>cd vue-manage-system //进入项目目录</p>
<p>npm install //安装项目依赖,等待安装完成</p>
<h2>本地开发</h2>
<p>//开启前端服务,浏览器访问 http://localhost:8082</p>
<p>npm run dev</p>
<p>//开启后端服务</p>
<p>cd service</p>
<p>node app</p>
<h2>设置代理与跨域</h2>
<p>vue-cli的config文件中有一个proxyTable参数,用来设置地址映射表,可以添加到开发时配置(dev)中</p>
<p>dev: {
// ...
proxyTable: {
'/api': {
target: 'http://127.0.0.1:3000/api/',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
},
// ...
}</p>
<p>即请求/api时就代表http://127.0.0.1:3000/api/(这里要写ip,不要写localhost),changeOrigin参数接收一个布尔值,如果为true,这样就不会有跨域问题了。</p>
<h2>最终项目的目录结构</h2>
<div>
<img src="../../../static/img/tree.png" alt="">
</div>
</article>
</div>
</div>
</template>
<script>
export default {
data: function(){
return {}
},
created() {
// this.submitForm(1)
},
methods: {
submitForm(formName) {
// debounceAjax(formName)
const self = this;
self.$http.post('/api/user/getUser',{name:'181549306'})
.then((response) => {
console.log(response);
}).then((error) => {
console.log(error);
})
},
}
}
</script>
<style scoped>
.ms-doc{
width:100%;
max-width: 980px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}
.ms-doc h3{
padding: 9px 10px 10px;
margin: 0;
font-size: 14px;
line-height: 17px;
background-color: #f5f5f5;
border: 1px solid #d8d8d8;
border-bottom: 0;
border-radius: 3px 3px 0 0;
}
.ms-doc article{
padding: 45px;
word-wrap: break-word;
background-color: #fff;
border: 1px solid #ddd;
border-bottom-right-radius: 3px;
border-bottom-left-radius: 3px;
}
.ms-doc article h1{
font-size:32px;
padding-bottom: 10px;
margin-bottom: 15px;
border-bottom: 1px solid #ddd;
}
.ms-doc article h2 {
margin: 24px 0 16px;
font-weight: 600;
line-height: 1.25;
padding-bottom: 7px;
font-size: 24px;
border-bottom: 1px solid #eee;
}
.ms-doc article p{
margin-bottom: 15px;
line-height: 1.5;
}
.ms-doc article .el-checkbox{
margin-bottom: 5px;
}
</style>
\ No newline at end of file
<template>
<div>
<div class="crumbs crumbs-register">
<el-breadcrumb separator="/" class="register-title">
<el-breadcrumb-item><i class="el-icon-setting"></i>注册</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="userContent">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item prop="name" label="用户名称">
<el-input v-model="form.name" placeholder="请输入用户名称"></el-input>
</el-form-item>
<el-form-item prop="account" label="账号名称">
<el-input v-model="form.account" placeholder="请输入账号"></el-input>
</el-form-item>
<el-form-item prop="pass" label="密码">
<el-input v-model="form.pass" type="password" placeholder="请输入密码"></el-input>
</el-form-item>
<el-form-item prop="checkPass" label="确认密码">
<el-input v-model="form.checkPass" type="password" placeholder="请再次输入密码"></el-input>
</el-form-item>
<el-form-item prop="email" label="邮箱">
<el-input v-model="form.email" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item prop="phone" label="手机">
<el-input v-model="form.phone" placeholder="请输入手机号"></el-input>
</el-form-item>
<el-form-item prop="card" label="身份证">
<el-input v-model="form.card" placeholder="请输入身份证号"></el-input>
</el-form-item>
<el-form-item prop="birth" label="出生日期">
<el-col :span="24">
<el-date-picker type="date" placeholder="选择日期" v-model="form.birth" value-format="yyyy-MM-dd" style="width: 100%;"></el-date-picker>
</el-col>
</el-form-item>
<el-form-item prop="sex" label="性别">
<el-select class="select-sex" v-model="form.sex" placeholder="请选择性别">
<el-option label="男" value="man"></el-option>
<el-option label="女" value="woman"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit('form')">确定</el-button>
<el-button @click="onCancle()">取消</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import Util from '../../utils/utils';
export default {
data() {
var validatePass = (rule, value, callback) => {
if(value === '') {
callback(new Error('请输入密码'));
} else {
if(this.form.checkPass !== '') {
this.$refs.form.validateField('checkPass');
}
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if(value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.form.pass) {
callback(new Error('两次输入的密码不一致'));
} else {
callback();
}
};
var validateEmail = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入邮箱'));
} else if (!Util.emailReg.test(this.form.email)){
callback(new Error('请输入正确的邮箱'));
} else {
callback();
}
};
var validatePhone = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入手机号'));
} else if (!Util.phoneReg.test(this.form.phone)){
callback(new Error('请输入正确的手机号'));
} else {
callback();
}
};
var validateCard = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入身份证号'));
} else if (!Util.idCardReg.test(this.form.card)){
callback(new Error('请输入正确的身份证号'));
} else {
callback();
}
};
return {
form: {
name: '',
account: '',
pass: '',
checkPass: '',
email: '',
phone: '',
card: '',
birth: '',
sex: ''
},
rules: {
name: [
{ required: true, message: '请输入用户名', trigger: 'blur' }
],
account: [
{ required: true, message: '请输入账号', trigger: 'blur' }
],
pass: [
{ validator: validatePass, trigger: 'blur' }
],
checkPass: [
{ validator: validatePass2, trigger: 'blur' }
],
email: [
{ validator: validateEmail, trigger: 'blur' }
],
phone: [
{ validator: validatePhone, trigger: 'blur' }
],
card: [
{ validator: validateCard, trigger: 'blur' }
],
birth: [
{ required: true, message: '请输入出生日期',type: 'date', trigger: 'blur' }
],
sex: [
{ required: true, message: '请输入性别', trigger: 'blur' }
]
}
}
},
methods:{
onSubmit(formName) {
const self = this;
self.$refs[formName].validate((valid) => {
if (valid) {
self.$http.post('/api/user/addUser',self.form).then(function(response) {
console.log(response);
self.$router.push('/register-success');
}).then(function(error) {
console.log(error);
})
} else {
console.log('error submit!!');
return false;
}
});
},
onCancle() {
this.$router.push('/login');
},
getDateTimes(str) {
var str = new Date(str);
return str;
}
}
}
</script>
<style>
.crumbs-register {
background-color: #324157;
height: 50px;
line-height: 50px;
}
.register-title {
line-height: 50px;
margin: 0 auto;
width: 50px;
font-size: 16px;
}
.userContent {
width: 400px;
margin: 0 auto;
}
.select-sex {
width: 320px;
}
</style>
\ No newline at end of file
<template>
<div>
<div class="crumbs crumbs-register">
<el-breadcrumb separator="/" class="register-title">
<el-breadcrumb-item><i class="el-icon-setting"></i>注册成功</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="userContent">
<div class="eidt-success">
<div class="show-success">
<i class="el-icon-check"></i>&nbsp;&nbsp;<span>恭喜您,注册成功</span>
</div>
<div class="click-login">
<a href="#" @click="handleCommand()">跳转登录</a>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
form: {
}
}
},
methods: {
handleCommand() {
this.$router.push('/login');
}
}
}
</script>
<style>
.crumbs {
margin-bottom: 0;
}
.crumbs-register {
background-color: #324157;
height: 50px;
line-height: 50px;
}
.register-title {
line-height: 50px;
margin: 0 auto;
width: 100px;
font-size: 16px;
}
.userContent {
width: 100%;
margin: 0 auto;
background-image: url('../../../static/img/success.jpg');
background-size: cover;
height: 500px;
}
.select-sex {
width: 320px;
}
.eidt-success {
width: 400px;
margin: 0 auto;
position: relative;
}
.eidt-success .show-success {
position: absolute;
margin-left: -190px;
left: 50%;
}
.click-login {
position: absolute;
margin-left: -40px;
left: 50%;
top: 61px;
}
.eidt-success i {
color: #67C23A;
}
.eidt-success i,.eidt-success span {
font-size: 40px;
font-family: Microsoft YaHei;
}
</style>
\ No newline at end of file
<template>
<div class="main-content">
<div class="crumbs">
<el-breadcrumb separator="/">
<el-breadcrumb-item><i class="el-icon-menu"></i>&nbsp;&nbsp;修改成功</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="eidt-success">
<div>
<i class="el-icon-check"></i>&nbsp;&nbsp;<span>恭喜您,修改成功</span>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
form: {
}
}
}
}
</script>
<style>
.main-content{
background-image: url('../../../static/img/success.jpg');
background-size: cover;
height: 100%;
}
.eidt-success {
width: 400px;
margin: 0 auto;
position: relative;
}
.eidt-success div {
position: absolute;
margin-left: -190px;
left: 50%;
}
.eidt-success i {
color: #67C23A;
}
.eidt-success i,.eidt-success span {
font-size: 40px;
font-family: Microsoft YaHei;
}
</style>
\ No newline at end of file
<template>
<div>
<div class="crumbs">
<el-breadcrumb separator="/">
<el-breadcrumb-item><i class="el-icon-date"></i> 个人中心</el-breadcrumb-item>
<el-breadcrumb-item>图片上传</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="content-title">支持拖拽</div>
<div class="plugins-tips">
Element UI自带上传组件。
访问地址:<a href="http://element.eleme.io/#/zh-CN/component/upload" target="_blank">Element UI Upload</a>
</div>
<el-upload
class="upload-demo"
drag
action="/api/posts/"
multiple>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
<div class="content-title">支持裁剪</div>
<div class="plugins-tips">
Vue-Core-Image-Upload:一款轻量级的vue上传插件,支持裁剪。
访问地址:<a href="https://github.com/Vanthink-UED/vue-core-image-upload" target="_blank">Vue-Core-Image-Upload</a>
</div>
<img class="pre-img" :src="src" alt="">
<vue-core-image-upload :class="['pure-button','pure-button-primary','js-btn-crop']"
:crop="true"
text="上传图片"
url="/api/posts/"
extensions="png,gif,jpeg,jpg"
@:imageuploaded="imageuploaded"
@:errorhandle="handleError"></vue-core-image-upload>
</div>
</template>
<script>
import VueCoreImageUpload from 'vue-core-image-upload';
export default {
data: function(){
return {
src: './static/img/img.jpg',
fileList: []
}
},
components: {
VueCoreImageUpload
},
methods:{
imageuploaded(res) {
console.log(res)
},
handleError(){
this.$notify.error({
title: '上传失败',
message: '图片上传接口上传失败,可更改为自己的服务器接口'
});
}
}
}
</script>
<style scoped>
.content-title{
font-weight: 400;
line-height: 50px;
margin: 10px 0;
font-size: 22px;
color: #1f2f3d;
}
.pre-img{
width:250px;
height: 250px;
margin-bottom: 20px;
}
</style>
\ No newline at end of file
<template>
<div>
<div class="crumbs">
<el-breadcrumb separator="/">
<el-breadcrumb-item><i class="el-icon-setting"></i>个人中心</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="userContent">
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="用户名称">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="账号名称">
<el-input v-model="form.account"></el-input>
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="form.email"></el-input>
</el-form-item>
<el-form-item label="手机">
<el-input v-model="form.phone"></el-input>
</el-form-item>
<el-form-item label="身份证">
<el-input v-model="form.card"></el-input>
</el-form-item>
<el-form-item label="出生日期">
<el-col :span="24">
<el-date-picker type="date" placeholder="选择日期" v-model="form.birth" style="width: 100%;"></el-date-picker>
</el-col>
</el-form-item>
<el-form-item label="性别">
<el-select class="select-sex" v-model="form.sex" placeholder="请选择性别">
<el-option label="男" value="man"></el-option>
<el-option label="女" value="woman"></el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
data() {
return {
form: {
}
}
},
methods:{
getUserData() {
const self = this;
let username = localStorage.getItem('ms_user').name;
self.$http.get('/api/user/getUser',{name: username}).then(function(response) {
console.log(response);
let result = response.data[0];
self.form.name = result.username;
self.form.account = result.account;
self.form.email = result.email;
self.form.phone = result.phone;
self.form.card = result.card;
self.form.birth = result.birth;
self.form.sex = result.sex;
}).then(function(error) {
console.log(error);
})
}
},
mounted() {
this.getUserData();
}
}
</script>
<style>
.userContent {
width: 400px;
margin: 0 auto;
}
.select-sex {
width: 320px;
}
</style>
\ No newline at end of file
import Vue from 'vue';
import App from './App';
import router from './router';
import axios from 'axios';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-default/index.css'; // 默认主题
// import '../static/css/theme-green/index.css'; // 浅绿色主题
import SIdentify from './components/page/Identify'; //自定义组件
import "babel-polyfill";
// import '@/permission' // permission control
import store from './store'
Vue.component("SIdentify",SIdentify);
Vue.use(ElementUI);
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'
Vue.prototype.$http = window.axios
// Vue.use(axios);
const vue =new Vue({
router,
store,
render: h => h(App)
}).$mount('#app');
window.Vue = vue
export default vue
import router from './router'
import store from './store'
import NProgress from 'nprogress' // Progress 进度条
import 'nprogress/nprogress.css'// Progress 进度条样式
import { Message } from 'element-ui'
import { getToken } from '@/utils/auth' // 验权
const whiteList = ['/login'] // 不重定向白名单
router.beforeEach((to, from, next) => {
NProgress.start()
if (getToken()) {
// console.log(to.path)
// return
if (to.path === '/login') {
next()
NProgress.done() // if current page is dashboard will not trigger afterEach hook, so manually handle it
} else {
if (store.getters.roles.length === 0) {
console.log(2222)
// console.log(window)
store.dispatch('GetInfo').then(res => { // 拉取用户信息
console.log(res)
let menus=res.data.data.menu;
let username=res.data.data.username;
store.dispatch('GenerateRoutes', { menus,username }).then(() => { // 生成可访问的路由表
console.log(store.getters.addRouters)
router.addRoutes(store.getters.addRouters); // 动态添加可访问路由表
next({ ...to, replace: true })
})
}).catch((err) => {
console.log(err)
return
store.dispatch('FedLogOut').then(() => {
Message.error(err || 'Verification failed, please login again')
next({ path: '/' })
})
})
} else {
next()
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
next('/login')
NProgress.done()
}
}
})
router.afterEach(() => {
NProgress.done() // 结束Progress
})
import Vue from 'vue';
import Router from 'vue-router';
import Layout from '../components/common/Home.vue'
Vue.use(Router);
// export default new Router({
// routes: [
// {
// path: '/',
// redirect: '/login'
// },
// {
// path: '/readme',
// component: resolve => require(['../components/common/Home.vue'], resolve),
// children:[
// {
// path: '/',
// component: resolve => require(['../components/page/Readme.vue'], resolve)
// },
// {
// path: '/upload',
// component: resolve => require(['../components/page/Upload.vue'], resolve) // Vue-Core-Image-Upload组件
// },
// {
// path: '/userCenter',
// component: resolve => require(['../components/page/UserCenter.vue'], resolve) // 拖拽列表组件
// },
// {
// path: '/modifyUser',
// component: resolve => require(['../components/page/ModifyUser.vue'], resolve)
// },
// {
// path: '/modifyPassword',
// component: resolve => require(['../components/page/ModifyPassword.vue'], resolve)
// },
// {
// path: '/success',
// component: resolve => require(['../components/page/Success.vue'], resolve)
// }
// ]
// },
// {
// path: '/register',
// component: resolve => require(['../components/page/Register.vue'], resolve)
// },
// {
// path: '/register-success',
// component: resolve => require(['../components/page/RegisterSuccess.vue'], resolve)
// },
// {
// path: '/login',
// component: resolve => require(['../components/page/Login.vue'], resolve)
// },
// ]
// })
export const constantRouterMap = [
{ path: '/login', component: () => import('../components/page/Login.vue'), hidden: true },
{ path: '/404', component: () => import('@/views/404'), hidden: true },
{
path: '',
component: Layout,
redirect: '/readme',
children: [{
path: '/',
name: 'readme',
component: () => import('../components/page/Readme.vue'),
meta: { title: '首页', icon: 'home' }
},
{
path: '/upload',
component: resolve => require(['../components/page/Upload.vue'], resolve) // Vue-Core-Image-Upload组件
},
{
path: '/userCenter',
component: resolve => require(['../components/page/UserCenter.vue'], resolve) // 拖拽列表组件
},
{
path: '/modifyUser',
component: resolve => require(['../components/page/ModifyUser.vue'], resolve)
},
{
path: '/modifyPassword',
component: resolve => require(['../components/page/ModifyPassword.vue'], resolve)
},
{
path: '/success',
component: resolve => require(['../components/page/Success.vue'], resolve)
}
]
},
// {
// path: '/readme',
// name:'readme',
// component: resolve => require(['../components/common/Home.vue'], resolve),
// children:[
// {
// path: '/',
// name: "readme",
// component: resolve => require(['../components/page/Readme.vue'], resolve)
// },
// {
// path: '/upload',
// component: resolve => require(['../components/page/Upload.vue'], resolve) // Vue-Core-Image-Upload组件
// },
// {
// path: '/userCenter',
// component: resolve => require(['../components/page/UserCenter.vue'], resolve) // 拖拽列表组件
// },
// {
// path: '/modifyUser',
// component: resolve => require(['../components/page/ModifyUser.vue'], resolve)
// },
// {
// path: '/modifyPassword',
// component: resolve => require(['../components/page/ModifyPassword.vue'], resolve)
// },
// {
// path: '/success',
// component: resolve => require(['../components/page/Success.vue'], resolve)
// }
// ]
// },
]
export const asyncRouterMap = [
{
path: "/device",
name: "device",
redirect: "/device/deviceList",
meta: { title: "设备管理", icon: "order" },
component: Layout,
children: [
{
path: "deviceList",
name: "deviceList",
component: () => import("@/views/device/index"),
meta: { title: "设备列表", icon: "order" }
},
{
path: "detail",
name: "detail",
component: () => import("@/views/device/detail"),
meta: { title: "设备详情", icon: "order" },
hidden: true
},
]
},
{
path: "/model",
name: "model",
component: Layout,
redirect: "/model/modelList",
meta: { title: "机型管理", icon: "order" },
children: [
{
path: "modelList",
name: "modelList",
component: () => import("@/views/model/index"),
meta: { title: "机型列表", icon: "order" }
},
]
},
{
path: "/engraving",
name: "engraving",
component: Layout,
redirect: "/engraving/engravingUpload",
meta: { title: "雕刻机", icon: "order" },
children: [
{
path: "engravingUpload",
name: "engravingUpload",
component: () => import("@/views/engraving/index"),
meta: { title: "雕刻机", icon: "order" }
},
]
},
// {
// path: '/ums',
// component: Layout,
// redirect: '/ums/admin',
// name: 'ums',
// meta: { title: '权限', icon: 'ums' },
// children: [
// {
// path: 'admin',
// name: 'admin',
// component: () => import('@/views/ums/admin/index'),
// meta: { title: '用户列表', icon: 'ums-admin' }
// },
// {
// path: 'role',
// name: 'role',
// component: () => import('@/views/ums/role/index'),
// meta: { title: '角色列表', icon: 'ums-role' }
// },
// {
// path: 'allocMenu',
// name: 'allocMenu',
// component: () => import('@/views/ums/role/allocMenu'),
// meta: { title: '分配菜单' },
// hidden: true
// },
// {
// path: 'allocResource',
// name: 'allocResource',
// component: () => import('@/views/ums/role/allocResource'),
// meta: { title: '分配资源' },
// hidden: true
// },
// {
// path: 'menu',
// name: 'menu',
// component: () => import('@/views/ums/menu/index'),
// meta: { title: '菜单列表', icon: 'ums-menu' }
// },
// {
// path: 'addMenu',
// name: 'addMenu',
// component: () => import('@/views/ums/menu/add'),
// meta: { title: '添加菜单' },
// hidden: true
// },
// {
// path: 'updateMenu',
// name: 'updateMenu',
// component: () => import('@/views/ums/menu/update'),
// meta: { title: '修改菜单' },
// hidden: true
// },
// {
// path: 'resource',
// name: 'resource',
// component: () => import('@/views/ums/resource/index'),
// meta: { title: '资源列表', icon: 'ums-resource' }
// },
// {
// path: 'resourceCategory',
// name: 'resourceCategory',
// component: () => import('@/views/ums/resource/categoryList'),
// meta: { title: '资源分类' },
// hidden: true
// }
// ]
// },
{ path: '*', redirect: '/404', hidden: true }
]
export default new Router({
// mode: 'history', //后端支持可开
// scrollBehavior: () => ({ y: 0 }),
routes: constantRouterMap
})
\ No newline at end of file
const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
roles: state => state.user.roles,
addRouters: state => state.permission.addRouters,
routers: state => state.permission.routers
}
export default getters
import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
import user from './modules/user'
import permission from './modules/permission'
import getters from './getters'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
app,
user,
permission
},
getters
})
export default store
import Cookies from 'js-cookie'
const app = {
state: {
sidebar: {
opened: !+Cookies.get('sidebarStatus'),
withoutAnimation: false
},
device: 'desktop'
},
mutations: {
TOGGLE_SIDEBAR: state => {
if (state.sidebar.opened) {
Cookies.set('sidebarStatus', 1)
} else {
Cookies.set('sidebarStatus', 0)
}
state.sidebar.opened = !state.sidebar.opened
},
CLOSE_SIDEBAR: (state, withoutAnimation) => {
Cookies.set('sidebarStatus', 1)
state.sidebar.opened = false
state.sidebar.withoutAnimation = withoutAnimation
},
TOGGLE_DEVICE: (state, device) => {
state.device = device
}
},
actions: {
ToggleSideBar: ({ commit }) => {
commit('TOGGLE_SIDEBAR')
},
CloseSideBar({ commit }, { withoutAnimation }) {
commit('CLOSE_SIDEBAR', withoutAnimation)
},
ToggleDevice({ commit }, device) {
commit('TOGGLE_DEVICE', device)
}
}
}
export default app
import { asyncRouterMap, constantRouterMap } from '@/router/index';
//判断是否有权限访问该菜单
function hasPermission(menu, route) {
if (route.name) {
let currMenu = getMenu(route.name, menu);
if (currMenu!=null) {
//设置菜单的标题、图标和可见性
if (currMenu.title != null && currMenu.title !== '') {
route.meta.title = currMenu.title;
}
if (currMenu.icon != null && currMenu.title !== '') {
route.meta.icon = currMenu.icon;
}
if(currMenu.hidden!=null){
route.hidden = currMenu.hidden !== 0;
}
if (currMenu.sort != null && currMenu.sort !== '') {
route.sort = currMenu.sort;
}
return true;
} else {
route.sort = 0;
if (route.hidden !== undefined && route.hidden === true) {
route.sort=-1;
return true;
} else {
return false;
}
}
} else {
return true
}
}
//根据路由名称获取菜单
function getMenu(name, menu1) {
for (let i = 0; i < menu1.length; i++) {
let menu = menu1[i];
if (name===menu.name) {
return menu;
}
}
return null;
}
//对菜单进行排序
function sortRouters(accessedRouters) {
for (let i = 0; i < accessedRouters.length; i++) {
let router = accessedRouters[i];
if(router.children && router.children.length > 0){
router.children.sort(compare("sort"));
}
}
accessedRouters.sort(compare("sort"));
}
//降序比较函数
function compare(p){
return function(m,n){
let a = m[p];
let b = n[p];
return b - a;
}
}
const permission = {
state: {
routers: constantRouterMap,
addRouters: []
},
mutations: {
SET_ROUTERS: (state, routers) => {
state.addRouters = routers;
state.routers = constantRouterMap.concat(routers);
}
},
actions: {
GenerateRoutes({ commit }, data) {
return new Promise(resolve => {
const { menus } = data;
const { username } = data;
const accessedRouters = asyncRouterMap.filter(v => {
//admin帐号直接返回所有菜单
// if(username==='admin') return true;
if (hasPermission(menus, v)) {
if (v.children && v.children.length > 0) {
v.children = v.children.filter(child => {
if (hasPermission(menus, child)) {
return child
}
return false;
});
return v
} else {
return v
}
}
return false;
});
//对菜单进行排序
sortRouters(accessedRouters);
commit('SET_ROUTERS', accessedRouters);
resolve();
})
}
}
};
export default permission;
// import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'
const user = {
state: {
token: getToken(),
name: '',
avatar: '',
roles: []
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_NAME: (state, name) => {
state.name = name
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_ROLES: (state, roles) => {
state.roles = roles
}
},
actions: {
// 登录
Login({ commit }, userInfo) {
let self=window.Vue
// // return
// const username = userInfo.username.trim()
return new Promise((resolve, reject) => {
// login(username, userInfo.password).then(response => {
// const data = response.data
// const tokenStr = data.tokenHead+data.token
// setToken(tokenStr)
// commit('SET_TOKEN', tokenStr)
// resolve()
// }).catch(error => {
// reject(error)
// })
self.$http.post('/api/user/login',JSON.stringify(userInfo))
.then((response) => {
if (response.data == -1) {
self.errorInfo = true;
self.errInfo = '该用户不存在';
console.log('该用户不存在')
} else if (response.data == 0) {
console.log('密码错误')
self.errorInfo = true;
self.errInfo = '密码错误';
} else if (response.status == 200) {
const data = response.data.data
const tokenStr = data.tokenHead+data.token
setToken(tokenStr)
commit('SET_TOKEN', tokenStr)
resolve()
// sessionStorage.setItem('ms_username',self.ruleForm.name);
// sessionStorage.setItem('ms_user',JSON.stringify(self.ruleForm));
// console.log(JSON.stringify(self.ruleForm));
}
}).then((error) => {
console.log(error);
})
})
},
// 获取用户信息
GetInfo({ commit, state }) {
let self=window.Vue
return new Promise((resolve, reject) => {
self.$http.post('/api/user/getUser',{name:'181549306'}).then(response => {
const data = response.data.data
if (data.roles && data.roles.length > 0) { // 验证返回的roles是否是一个非空数组
commit('SET_ROLES', data.roles)
} else {
reject('getInfo: roles must be a non-null array !')
}
commit('SET_NAME', data.username)
commit('SET_AVATAR', data.icon)
resolve(response)
}).catch(error => {
reject(error)
})
})
},
// 登出
LogOut({ commit, state }) {
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
resolve()
}).catch(error => {
reject(error)
})
})
},
// 前端 登出
FedLogOut({ commit }) {
return new Promise(resolve => {
commit('SET_TOKEN', '')
removeToken()
resolve()
})
}
}
}
export default user
import Cookies from 'js-cookie'
const TokenKey = 'loginToken'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
import Cookies from "js-cookie";
const SupportKey='supportKey';
export function getSupport() {
return Cookies.get(SupportKey)
}
export function setSupport(isSupport) {
return Cookies.set(SupportKey, isSupport,{ expires: 3 })
}
export function setCookie(key,value,expires) {
return Cookies.set(key, value,{ expires: expires})
}
export function getCookie(key) {
return Cookies.get(key)
}
var utils = {
emailReg : /^[a-z0-9A-Z]+([-|_|\.]+[a-z0-9A-Z]+)*@([a-z0-9A-Z]+[-|\.])+[a-zA-Z]{2,5}$/,
idCardReg : /^(([1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4})|([1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|(X|x))))$/,
phoneReg : /^1[34578]\d{9}$/,
}
export default utils
\ No newline at end of file
<template>
<div>
<div class="app-container">
<el-col :span="12">
<img :src="img_404" alt="404" class="img-style">
</el-col>
<el-col :span="12">
<div style="margin-left: 100px;margin-top: 60px">
<h1 class="color-main">OOPS!</h1>
<h2 style="color: #606266">很抱歉,页面它不小心迷路了!</h2>
<div style="color:#909399;font-size: 14px">请检查您输入的网址是否正确,请点击以下按钮返回主页或者发送错误报告</div>
<el-button style="margin-top: 20px" type="primary" round @click="handleGoMain">返回首页</el-button>
</div>
</el-col>
</div>
</div>
</template>
<script>
import img_404 from '@/assets/images/gif_404.gif';
export default {
name: 'wrongPage',
data() {
return {
img_404
}
},
methods: {
handleGoMain() {
this.$router.push({path: '/'})
}
},
}
</script>
<style scoped>
.app-container {
width: 80%;
margin: 120px auto;
}
.img-style {
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
}
</style>
<template>
<div class="detail-container">
设备列表详情
</div>
</template>
<script>
</script>
<style scoped>
.detail-container {
position: absolute;
left: 0;
right: 0;
width: 1080px;
padding: 35px 35px 15px 35px;
margin: 20px auto;
}
.standard-margin {
margin-top: 15px;
}
.form-border {
border-right: 1px solid #dcdfe6;
border-bottom: 1px solid #dcdfe6;
padding: 10px;
}
.form-container-border {
border-left: 1px solid #dcdfe6;
border-top: 1px solid #dcdfe6;
margin-top: 15px;
}
.form-left-bg {
background: #f2f6fc;
}
</style>
<template>
<div class="app-container">
设备列表
</div>
</template>
<script>
</script>
<style>
.el-upload {
height: 100%;
}
.dialog-footer {
display: flex;
align-items: center;
justify-content: flex-end;
}
</style>
<template>
<div class="detail-container">
雕刻机列表详情
</div>
</template>
<script>
</script>
<style scoped>
.detail-container {
position: absolute;
left: 0;
right: 0;
width: 1080px;
padding: 35px 35px 15px 35px;
margin: 20px auto;
}
.standard-margin {
margin-top: 15px;
}
.form-border {
border-right: 1px solid #dcdfe6;
border-bottom: 1px solid #dcdfe6;
padding: 10px;
}
.form-container-border {
border-left: 1px solid #dcdfe6;
border-top: 1px solid #dcdfe6;
margin-top: 15px;
}
.form-left-bg {
background: #f2f6fc;
}
</style>
<template>
<div class="detail-container">
机型列表详情
</div>
</template>
<script>
</script>
<style scoped>
.detail-container {
position: absolute;
left: 0;
right: 0;
width: 1080px;
padding: 35px 35px 15px 35px;
margin: 20px auto;
}
.standard-margin {
margin-top: 15px;
}
.form-border {
border-right: 1px solid #dcdfe6;
border-bottom: 1px solid #dcdfe6;
padding: 10px;
}
.form-container-border {
border-left: 1px solid #dcdfe6;
border-top: 1px solid #dcdfe6;
margin-top: 15px;
}
.form-left-bg {
background: #f2f6fc;
}
</style>
<template>
<div class="detail-container">
售后列表详情
</div>
</template>
<script>
</script>
<style scoped>
.detail-container {
position: absolute;
left: 0;
right: 0;
width: 1080px;
padding: 35px 35px 15px 35px;
margin: 20px auto;
}
.standard-margin {
margin-top: 15px;
}
.form-border {
border-right: 1px solid #dcdfe6;
border-bottom: 1px solid #dcdfe6;
padding: 10px;
}
.form-container-border {
border-left: 1px solid #dcdfe6;
border-top: 1px solid #dcdfe6;
margin-top: 15px;
}
.form-left-bg {
background: #f2f6fc;
}
</style>
<template>
<div class="detail-container">
售后详情
</div>
</template>
<script>
</script>
<style scoped>
.detail-container {
position: absolute;
left: 0;
right: 0;
width: 1080px;
padding: 35px 35px 15px 35px;
margin: 20px auto;
}
.standard-margin {
margin-top: 15px;
}
.form-border {
border-right: 1px solid #dcdfe6;
border-bottom: 1px solid #dcdfe6;
padding: 10px;
}
.form-container-border {
border-left: 1px solid #dcdfe6;
border-top: 1px solid #dcdfe6;
margin-top: 15px;
}
.form-left-bg {
background: #f2f6fc;
}
</style>
<template>
<div class="detail-container">
售后列表
</div>
</template>
<script>
</script>
<style scoped>
.detail-container {
position: absolute;
left: 0;
right: 0;
width: 1080px;
padding: 35px 35px 15px 35px;
margin: 20px auto;
}
.standard-margin {
margin-top: 15px;
}
.form-border {
border-right: 1px solid #dcdfe6;
border-bottom: 1px solid #dcdfe6;
padding: 10px;
}
.form-container-border {
border-left: 1px solid #dcdfe6;
border-top: 1px solid #dcdfe6;
margin-top: 15px;
}
.form-left-bg {
background: #f2f6fc;
}
</style>
This diff is collapsed.
<template> 
<menu-detail :is-edit='false'></menu-detail>
</template>
<script>
import MenuDetail from './components/MenuDetail'
export default {
name: 'addMenu',
components: { MenuDetail }
}
</script>
<style>
</style>
<template>
<el-card class="form-container" shadow="never">
<el-form :model="menu"
:rules="rules"
ref="menuFrom"
label-width="150px">
<el-form-item label="菜单名称:" prop="title">
<el-input v-model="menu.title"></el-input>
</el-form-item>
<el-form-item label="上级菜单:">
<el-select v-model="menu.parentId"
placeholder="请选择菜单">
<el-option
v-for="item in selectMenuList"
:key="item.id"
:label="item.title"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="前端名称:" prop="name">
<el-input v-model="menu.name"></el-input>
</el-form-item>
<el-form-item label="前端图标:" prop="icon">
<el-input v-model="menu.icon" style="width: 80%"></el-input>
<svg-icon style="margin-left: 8px" :icon-class="menu.icon"></svg-icon>
</el-form-item>
<el-form-item label="是否显示:">
<el-radio-group v-model="menu.hidden">
<el-radio :label="0"></el-radio>
<el-radio :label="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="排序:">
<el-input v-model="menu.sort"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit('menuFrom')">提交</el-button>
<el-button v-if="!isEdit" @click="resetForm('menuFrom')">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</template>
<script>
import {fetchList, createMenu, updateMenu, getMenu} from '@/api/menu';
const defaultMenu = {
title: '',
parentId: 0,
name: '',
icon: '',
hidden: 0,
sort: 0
};
export default {
name: "MenuDetail",
props: {
isEdit: {
type: Boolean,
default: false
}
},
data() {
return {
menu: Object.assign({}, defaultMenu),
selectMenuList: [],
rules: {
title: [
{required: true, message: '请输入菜单名称', trigger: 'blur'},
{min: 2, max: 140, message: '长度在 2 到 140 个字符', trigger: 'blur'}
],
name: [
{required: true, message: '请输入前端名称', trigger: 'blur'},
{min: 2, max: 140, message: '长度在 2 到 140 个字符', trigger: 'blur'}
],
icon: [
{required: true, message: '请输入前端图标', trigger: 'blur'},
{min: 2, max: 140, message: '长度在 2 到 140 个字符', trigger: 'blur'}
]
}
}
},
created() {
if (this.isEdit) {
getMenu(this.$route.query.id).then(response => {
this.menu = response.data;
});
} else {
this.menu = Object.assign({}, defaultMenu);
}
this.getSelectMenuList();
},
methods: {
getSelectMenuList() {
fetchList(0, {pageSize: 100, pageNum: 1}).then(response => {
this.selectMenuList = response.data.list;
this.selectMenuList.unshift({id: 0, title: '无上级菜单'});
});
},
onSubmit(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.$confirm('是否提交数据', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (this.isEdit) {
updateMenu(this.$route.query.id, this.menu).then(response => {
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
this.$router.back();
});
} else {
createMenu(this.menu).then(response => {
this.$refs[formName].resetFields();
this.resetForm(formName);
this.$message({
message: '提交成功',
type: 'success',
duration: 1000
});
this.$router.back();
});
}
});
} else {
this.$message({
message: '验证失败',
type: 'error',
duration: 1000
});
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
this.menu = Object.assign({}, defaultMenu);
this.getSelectMenuList();
},
}
}
</script>
<style scoped>
</style>
<template>
<div class="app-container">
<el-card class="operate-container" shadow="never">
<i class="el-icon-tickets" style="margin-top: 5px"></i>
<span style="margin-top: 5px">数据列表</span>
<el-button
class="btn-add"
@click="handleAddMenu()"
size="mini">
添加
</el-button>
</el-card>
<div class="table-container">
<el-table ref="menuTable"
style="width: 100%"
:data="list"
v-loading="listLoading" border>
<el-table-column label="编号" width="100" align="center">
<template slot-scope="scope">{{scope.row.id}}</template>
</el-table-column>
<el-table-column label="菜单名称" align="center">
<template slot-scope="scope">{{scope.row.title}}</template>
</el-table-column>
<el-table-column label="菜单级数" width="100" align="center">
<template slot-scope="scope">{{scope.row.level | levelFilter}}</template>
</el-table-column>
<el-table-column label="前端名称" align="center">
<template slot-scope="scope">{{scope.row.name}}</template>
</el-table-column>
<el-table-column label="前端图标" width="100" align="center">
<template slot-scope="scope"><svg-icon :icon-class="scope.row.icon"></svg-icon></template>
</el-table-column>
<el-table-column label="是否显示" width="100" align="center">
<template slot-scope="scope">
<el-switch
@change="handleHiddenChange(scope.$index, scope.row)"
:active-value="0"
:inactive-value="1"
v-model="scope.row.hidden">
</el-switch>
</template>
</el-table-column>
<el-table-column label="排序" width="100" align="center">
<template slot-scope="scope">{{scope.row.sort }}</template>
</el-table-column>
<el-table-column label="设置" width="120" align="center">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
:disabled="scope.row.level | disableNextLevel"
@click="handleShowNextLevel(scope.$index, scope.row)">查看下级
</el-button>
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
@click="handleUpdate(scope.$index, scope.row)">编辑
</el-button>
<el-button
size="mini"
type="text"
@click="handleDelete(scope.$index, scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination-container">
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
layout="total, sizes,prev, pager, next,jumper"
:page-size="listQuery.pageSize"
:page-sizes="[10,15,20]"
:current-page.sync="listQuery.pageNum"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script>
import {fetchList,deleteMenu,updateMenu,updateHidden} from '@/api/menu'
export default {
name: "menuList",
data() {
return {
list: null,
total: null,
listLoading: true,
listQuery: {
pageNum: 1,
pageSize: 5
},
parentId: 0
}
},
created() {
this.resetParentId();
this.getList();
},
watch: {
$route(route) {
this.resetParentId();
this.getList();
}
},
methods: {
resetParentId(){
this.listQuery.pageNum = 1;
if (this.$route.query.parentId != null) {
this.parentId = this.$route.query.parentId;
} else {
this.parentId = 0;
}
},
handleAddMenu() {
this.$router.push('/ums/addMenu');
},
getList() {
this.listLoading = true;
fetchList(this.parentId, this.listQuery).then(response => {
this.listLoading = false;
this.list = response.data.list;
this.total = response.data.total;
});
},
handleSizeChange(val) {
this.listQuery.pageNum = 1;
this.listQuery.pageSize = val;
this.getList();
},
handleCurrentChange(val) {
this.listQuery.pageNum = val;
this.getList();
},
handleHiddenChange(index, row) {
updateHidden(row.id,{hidden:row.hidden}).then(response=>{
this.$message({
message: '修改成功',
type: 'success',
duration: 1000
});
});
},
handleShowNextLevel(index, row) {
this.$router.push({path: '/ums/menu', query: {parentId: row.id}})
},
handleUpdate(index, row) {
this.$router.push({path:'/ums/updateMenu',query:{id:row.id}});
},
handleDelete(index, row) {
this.$confirm('是否要删除该菜单', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteMenu(row.id).then(response => {
this.$message({
message: '删除成功',
type: 'success',
duration: 1000
});
this.getList();
});
});
}
},
filters: {
levelFilter(value) {
if (value === 0) {
return '一级';
} else if (value === 1) {
return '二级';
}
},
disableNextLevel(value) {
if (value === 0) {
return false;
} else {
return true;
}
}
}
}
</script>
<style scoped>
</style>
<template> 
<menu-detail :is-edit='true'></menu-detail>
</template>
<script>
import MenuDetail from './components/MenuDetail'
export default {
name: 'updateMenu',
components: { MenuDetail }
}
</script>
<style>
</style>
.header{
background-color: #242f42;
}
.login-wrap{
background: #324157;
}
.plugins-tips{
background: #eef1f6;
}
.plugins-tips a{
color: #20a0ff;
}
.el-upload--text em {
color: #20a0ff;
}
.pure-button{
background: #20a0ff;
}
\ No newline at end of file
.vue-datasource *{
box-sizing: border-box;
font-size: 14px;
}
.vue-datasource .panel {
margin-bottom: 22px;
background-color: #fff;
border: 1px solid transparent;
border-radius: 4px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
}
.vue-datasource .panel-default {
border-color: #d3e0e9;
}
.vue-datasource .panel-heading {
padding: 10px 15px;
border-bottom: 1px solid transparent;
border-top-right-radius: 3px;
border-top-left-radius: 3px;
}
.vue-datasource .panel-default > .panel-heading {
height:56px;
color: #333333;
background-color: #fff;
border-color: #d3e0e9;
}
.vue-datasource .pull-left {
float: left !important;
}
.vue-datasource .pull-right {
float: right !important;
}
.vue-datasource .form-group {
margin-bottom: 15px;
}
.vue-datasource label {
display: inline-block;
max-width: 100%;
margin-bottom: 5px;
font-weight: bold;
}
.vue-datasource .form-control {
display: block;
width: 100%;
height: 36px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.6;
color: #555555;
background-color: #fff;
background-image: none;
border: 1px solid #ccd0d2;
border-radius: 4px;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
}
.vue-datasource .btn {
display: inline-block;
margin-bottom: 0;
font-weight: normal;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
border: 1px solid transparent;
white-space: nowrap;
padding: 6px 12px;
font-size: 14px;
line-height: 1.6;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.vue-datasource .btn-primary {
color: #fff;
background-color: #3097D1;
border-color: #2a88bd;
}
.vue-datasource .table {
width: 100%;
max-width: 100%;
margin-bottom: 22px;
border-collapse: collapse;
border-spacing: 0;
text-align: center;
}
.vue-datasource .table > thead > tr > th {
vertical-align: bottom;
border-bottom: 2px solid #ddd;
}
.vue-datasource .table th ,.vue-datasource .table td {
padding: 8px;
line-height: 1.6;
vertical-align: top;
border-top: 1px solid #ddd;
}
.vue-datasource .table-striped > tbody > tr:nth-of-type(odd) {
background-color: #f9f9f9;
}
.vue-datasource .success th ,.vue-datasource .success td{
background-color: #dff0d8;
}
.vue-datasource .pagination {
display: inline-block;
padding-left: 0;
margin: 22px 0;
border-radius: 4px;
}
.vue-datasource .pagination > li {
display: inline;
}
.pagination > li > a,.pagination > li > span {
position: relative;
float: left;
padding: 6px 12px;
line-height: 1.6;
text-decoration: none;
color: #3097D1;
background-color: #fff;
border: 1px solid #ddd;
margin-left: -1px;
}
.pagination > .disabled > span, .pagination > .disabled > span:hover, .pagination > .disabled > span:focus, .pagination > .disabled > a, .pagination > .disabled > a:hover, .pagination > .disabled > a:focus {
color: #777777;
background-color: #fff;
border-color: #ddd;
cursor: not-allowed;
}
.pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus, .pagination > .active > span, .pagination > .active > span:hover, .pagination > .active > span:focus {
z-index: 3;
color: #fff;
background-color: #3097D1;
border-color: #3097D1;
cursor: default;
}
.vue-datasource .pagination > li:first-child > a, .vue-datasource .pagination > li:first-child > span {
margin-left: 0;
border-bottom-left-radius: 4px;
border-top-left-radius: 4px;
}
.vue-datasource .text-center {
text-align: center;
}
@media (min-width: 768px){
.form-inline .form-group {
display: inline-block;
margin-bottom: 0;
vertical-align: middle;
}
.form-inline .control-label {
margin-bottom: 0;
vertical-align: middle;
}
.form-inline .form-control {
display: inline-block;
width: auto;
vertical-align: middle;
}
}
This diff is collapsed.
.header{
background-color: #00d1b2;
}
.login-wrap{
background: rgba(56, 157, 170, 0.82);;
}
.plugins-tips{
background: #f2f2f2;
}
.plugins-tips a{
color: #00d1b2;
}
.el-upload--text em {
color: #00d1b2;
}
.pure-button{
background: #00d1b2;
}
.vue-datasource .btn-primary {
color: #fff;
background-color: #00d1b2 !important;
border-color: #00d1b2 !important;
}
.pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus, .pagination > .active > span, .pagination > .active > span:hover, .pagination > .active > span:focus {
background-color: #00d1b2 !important;
border-color: #00d1b2 !important;
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment