Vue-element简易后台管理系统

采用vue2+element构建网页主体,node作为本地服务器,mysql作为数据库,echarts做了一丁点可视化.

项目路径
Vue-element简易后台管理系统_第1张图片


一:配置路由以及服务器

1.配置vue.config.js

取消lint以及配置代理服务器解决跨域问题

可以在服务器app.js引入cors模块解决跨域,就不用配置代理了.

const {defineConfig} = require('@vue/cli-service')
module.exports = defineConfig({
	transpileDependencies: true,
	lintOnSave: false,
	devServer: {
		proxy: {
			'/register': {
				target: 'http://localhost:5000/register',
				changeOrigin: true,
				pathRewrite: {'^/register': ''}

			},
			'/updatePass':{
				target: 'http://localhost:5000/updatePass',
				pathRewrite: {'^/updatePass':''}
			},
			'/deleteSpecie':{
				target: 'http://localhost:5000/deleteSpecies',
				changeOrigin: true,
				pathRewrite: {'^/deleteSpecie':''}
			},
			'/addSpecie':{
				target: 'http://localhost:5000/addSpecies',
				changeOrigin: true,
				pathRewrite: {'^/addSpecie':''}
			},
			'/selectSpecie':{
				target: 'http://localhost:5000/selectSpecies',
				changeOrigin: true,
				pathRewrite: {'^/selectSpecie':''}
			},
			'/updateSpecie':{
				target: 'http://localhost:5000/updateSpecies',
				changeOrigin: true,
				pathRewrite: {'^/updateSpecie':''}
			},
			'/setAvatar':{
				target: 'http://localhost:5000/setAvatar',
				changeOrigin: true,
				pathRewrite: {'^/setAvatar':''}
			}
		}
	}
})

2.配置本地服务器app.js

//1.引入express
const express = require('express')
const mysql = require("mysql");
const multer = require("multer")
const cors = require('cors')


const bodyParser = require("body-parser");
const fs = require("fs");
const dayjs = require("dayjs");


//2.创建应用对象
const app = express()
app.use(bodyParser.urlencoded({extended: false})); //parse application/x-www-form-urlencoded
app.use(bodyParser.json());
app.use(cors())

let objMulter = multer({dest: "./public/upload"});
//实例化multer,传递的参数对象,dest表示上传文件的存储路径
app.use(objMulter.any())//any表示任意类型的文件
// app.use(objMulter.image())//仅允许上传图片类型

//静态资源托管
app.use(express.static("./public/upload"));

//创建mysql连接对象
const connection = mysql.createConnection({
    host: 'localhost',
    port: 3306,
    user: 'root',
    password: '123456',
    database: 'bigevent',
    multipleStatements: true

})

connection.connect()

//修改头像
app.post('/setAvatar', (req, res) => {
    let oldName = req.files[0].filename;//获取名字
    let originalname = req.files[0].originalname;//originnalname其实就是你上传时候文件起的名字
    //给新名字加上原来的后缀
    let newName = req.files[0].originalname;
    fs.renameSync('public/upload/' + oldName, './public/upload/' + newName);//改图片的名字注意此处一定是一个路径,而不是只有文件名
    // res.send({
    // 	err: 0,
    // 	url:"http://localhost:5000/public/upload/" +
    // 		newName
    // });
    const url = "http://localhost:5000/" + newName
    console.log(url)
    console.log(typeof url)
    const username = req.body.name
    console.log(username)
    const sql = `update account set avatar = '${url}' where username = '${username}'`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }
        console.log(result)
    })
    res.send(url)
})


//检查登录信息
app.get('/accounts', (request, response) => {
    //设置响应头 允许跨域
    response.setHeader('Access-Control-Allow-Origin', "*")

    //get方式通过params传递的参数可以直接通过request.query获取到
    const name = request.query.username
    const password = request.query.password
    console.log(request.query.username)
    console.log(request.query.password)


    const sql = `select * from bigevent.account where username='${name}' and password='${password}'`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }
        console.log(result)

        response.send(JSON.stringify(result))

    })


    console.log('有人请求服务器了')

})

//检查注册用户的用户名是否合法 即在数据库中是否存在这个用户名
app.get('/checkName', (request, response) => {
    //设置响应头 允许跨域
    response.setHeader('Access-Control-Allow-Origin', "*")

    const name = request.query.username

    console.log(request.query.username)


    const sql = `select * from bigevent.account where username='${name}'`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }
        console.log(result)

        response.send(JSON.stringify(result))

    })


    console.log('有人请求服务器了')

})

//注册用户 往数据库插入用户信息
app.post('/register', (request, response) => {
    //设置响应头 允许跨域
    response.setHeader('Access-Control-Allow-Origin', "*")
    const username = request.body.username
    const password = request.body.password
    console.log(username)
    console.log(password)

    const sql = `insert into account(username,password) values('${username}','${password}')`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }

        console.log(result)
        response.send(result)

    })
    console.log('有人请求服务器了')

})
//修改用户信息
app.post('/updateInfo', (request, response) => {
    // console.log(1)
    // console.log(request.body.pass)
    const age = request.body.age
    const gender = request.body.gender
    const newName = request.body.newName
    const oldName = request.body.oldName
    const maritalStatus = request.body.maritalStatus
    console.log(age)
    console.log(gender)
    console.log(newName)
    console.log(oldName)
    const sql = `update account set gender = '${gender}',age=${age},username='${newName}',marital_status='${maritalStatus}' where username = '${oldName}'`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }

        console.log(result)
        response.send(result)
    })
})

//修改用户密码
app.post('/updatePass', (request, response) => {

    console.log(request.body.pass)
    const newPass = request.body.pass
    const username = request.body.username
    const sql = `update account set password = '${newPass}' where username = '${username}'`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }

        console.log(result)
        response.send(result)
    })
})

//获取文章分类
app.get('/getSpecies', (request, response) => {
    //设置响应头 允许跨域
    response.setHeader('Access-Control-Allow-Origin', "*")
    const sql = `select * from article_species`
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }
        console.log(result)
        response.send(JSON.stringify(result))
    })
    console.log('有人请求服务器了')
})

//删除文章分类
app.post('/deleteSpecies', (request, response) => {
    //设置响应头 允许跨域
    // response.setHeader('Access-Control-Allow-Origin', "*")

    const id = request.body.id

    console.log(id)
    const sql = `delete from article_species where id = ${id}`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }
        console.log(result)
        response.send(JSON.stringify(result))
    })
    console.log('有人请求服务器了')
})

//添加文章分类
app.post('/addSpecies', (request, response) => {
    //设置响应头 允许跨域
    // response.setHeader('Access-Control-Allow-Origin', "*")

    const name = request.body.name
    const nickname = request.body.nickname


    const sql = `insert into article_species(name,nickname) values('${name}','${nickname}')`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }
        console.log(result)
        response.send(JSON.stringify(result))
    })
    console.log('有人请求服务器了')
})
//搜索文章分类
app.post('/selectSpecies', (request, response) => {
    //设置响应头 允许跨域
    // response.setHeader('Access-Control-Allow-Origin', "*")

    const name = request.body.name


    const sql = `select * from article_species where name = '${name}'`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }
        console.log(result)
        response.send(JSON.stringify(result))
    })
    console.log('有人请求服务器了')
})
//更新分类内容
app.post('/updateSpecies', (request, response) => {
    //设置响应头 允许跨域
    // response.setHeader('Access-Control-Allow-Origin', "*")

    const name = request.body.name
    const id = request.body.id
    const nickname = request.body.nickname
    console.log(id)
    console.log(name)
    console.log(nickname)


    const sql = `update article_species set name = '${name}', nickname='${nickname}' where id = ${id}`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }
        console.log(result)
        response.send(JSON.stringify(result))
    })
    console.log('有人请求服务器了')
})
//搜索文章
app.post('/selectArticles', (request, response) => {
    //设置响应头 允许跨域
    // response.setHeader('Access-Control-Allow-Origin', "*")

    const specie = request.body.specie


    const sql = `select * from articles where specie = '${specie}'`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }
        console.log(result)
        response.send(JSON.stringify(result))
    })
    console.log('有人请求服务器了')
})
//发布文章
app.post('/publishArticle', (request, response) => {
    //设置响应头 允许跨域
    response.setHeader('Access-Control-Allow-Origin', "*")
    const title = request.body.title
    const content = request.body.content
    const author = request.body.author
    const pubtime = dayjs().format('YYYY-MM-DD HH:mm:ss')
    const specie = request.body.specie
    const sql = `insert into articles(title,specie,pubtime,content,author) values('${title}','${specie}','${pubtime}','${content}','${author}')`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }
        console.log(result)
        response.send(JSON.stringify(result))
    })


    console.log('有人请求服务器了')
})
//删除文章
app.post('/deleteArticle', (request, response) => {
    //设置响应头 允许跨域
    // response.setHeader('Access-Control-Allow-Origin', "*")

    const id = request.body.id

    console.log(id)
    const sql = `delete from articles where id = ${id}`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }
        console.log(result)
        response.send(JSON.stringify(result))
    })
    console.log('有人请求服务器了')
})
//修改文章
app.post('/editArticle', (request, response) => {
    //设置响应头 允许跨域
    response.setHeader('Access-Control-Allow-Origin', "*")
    const title = request.body.title
    const content = request.body.content
    const id = request.body.id
    const pubtime = dayjs().format('YYYY-MM-DD HH:mm:ss')
    const specie = request.body.specie
    const sql = `update articles set title ='${title}', specie='${specie}',pubtime='${pubtime}',content='${content}' where id = ${id}`
    console.log(sql)
    connection.query(sql, (error, result) => {
        if (error) {
            console.error(error)
            return
        }
        console.log(result)
        response.send(JSON.stringify(result))
    })


    console.log('有人请求服务器了')
})

//根据条件查询用户数目并返回
app.get('/statistics', (request, response) => {
    //设置响应头 允许跨域
    response.setHeader('Access-Control-Allow-Origin', "*")
    // const sql = `select * from article_species where id = 1`
    // const sql1 = `select * from article_species where id = 2`
    connection.query(
        // 'select count(1) from article_species;' +
        'select count(1) from account where age <18;'+
        'select count(1) from account where age >=18 and age <=30;'+
        'select count(1) from account where age >=30 and age <=50;'+
        'select count(1) from account where age >=50 and age <=70;'+
        'select count(1) from account where age >=70;'
        , (error, result) => {
            if (error) {
                console.error(error)
                return
            }
            console.log(result)
            response.send(JSON.stringify(result))
        })

    console.log('有人请求服务器了')
})
//根据条件查询文章数目并返回
app.post('/articleStatistics', (request, response) => {
    //设置响应头 允许跨域
    response.setHeader('Access-Control-Allow-Origin', "*")
    const species = request.body.species;
    console.log(species)
    let sql=``
    for (const specie of species) {
        console.log(specie)
        sql +=`select count(1) from articles where specie = '${specie}';`
    }
    console.log(sql)
    connection.query(sql,
                     (error, result) => {
        if (error) {
            console.error(error)
            return
        }
        console.log(result)
        response.send(JSON.stringify(result))
    })

    console.log('有人请求服务器了')
})


//4.监听端口启动服务
app.listen(5000, () => {
    console.log('服务已经启动,监听端口号5000')
})

3.配置路由

import Vue from "vue";
import Router from "vue-router";
import Register from "@/pages/Register";
import Login from "@/pages/Login";
import BackAdmin from "@/pages/BackAdmin";
import ResetPassword from "@/pages/ResetPassword";
import ArticleSpecies from "@/pages/ArticleSpecies";
import setAvatar from "@/pages/setAvatar";
import Statistics from "@/pages/Statistics";
import updateInfo from "@/pages/updateInfo";
import articleList from "@/pages/articleList";
import publishArticle from "@/pages/publishArticle";
import articleDetail from "@/pages/articleDetail";
import editArticle from "@/pages/editArticle";

Vue.use(Router)
const router =  new Router({
    routes:[
        {
            path:'/',
            component:Login,
            meta:{
                title:'后台管理登录',
                isAuth:true
            }

        },
        {
            path:'/register',
            component:Register,
            meta:{
                title:'用户注册'
            }
        },
        {
            path:'/admin',
            component:BackAdmin,
            meta:{
                title:'后台管理主页',
                auth:true
            },
            //设置重定向到统计页面
            redirect:{
                name:'statistics'
            },
            children:[
                {
                    path:'resetPass',
                    name:'resetPass',
                    component:ResetPassword,
                    meta:{
                        title:'修改密码',
                        auth:true
                    }
                },
                {
                    path:'articleSpecies',
                    name:'species',
                    component:ArticleSpecies,
                    meta:{
                        title:'文章分类',
                        isAuth:true,
                        auth:true
                    }
                },
                {
                    path:'setAvatar',
                    name:'setAvatar',
                    component:setAvatar,
                    meta:{
                        title:'修改头像',
                        auth:true
                    }
                },
                {
                    path:'statistics',
                    name:'statistics',
                    component:Statistics,
                    meta:{
                        title:'统计',
                        auth:true
                    }
                },
                {
                    path:'updateInfo',
                    name:'updateInfo',
                    component:updateInfo,
                    meta:{
                        title:'修改个人信息',
                        auth:true
                    }
                },
                {
                    path:'articleList',
                    name:'articleList',
                    component:articleList,
                    meta:{
                        title:'文章列表',
                        auth:true
                    }
                },
                {
                    path:'publishArticle',
                    name:'publishArticle',
                    component:publishArticle,
                    meta:{
                        title:'发布文章',
                        auth:true
                    }
                },
                {
                    path:'articleDetail',
                    name:'articleDetail',
                    component:articleDetail,
                    meta:{
                        title:'文章详情',
                        auth:true
                    },

                },
                {
                    path:'editArticle',
                    name:'editArticle',
                    component:editArticle,
                    meta:{
                        title:'修改文章',
                        auth:true
                    },

                },
            ]
        }
    ]
})
router.beforeEach((to,from,next)=>{
    //未登录前往登录后页面跳转到登录页
    if(to.meta.auth &&!localStorage.getItem('username')){
        router.push('/')
        return
    }
    if(to.meta.title){
        document.title  = to.meta.title
    }

    next()
})

//在登录页禁用后退按钮 指定后退页面为登录页
router.afterEach((to,from)=>{
    if(to.meta.isAuth){
        history.pushState(null, null, location.protocol + '//' + location.host + '/#' + to.path)

    }
})
export default router


二:功能组件实现

1.登录页面Login.vue实现

<template>
  <div>
    <el-container>
      <el-main>

        <el-row>
          <el-input placeholder="请输入用户名" v-model="username" prefix-icon="el-icon-user-solid">
    </el-input>
        </el-row>

        <el-row>
          <el-input placeholder="请输入密码" v-model="password" show-password prefix-icon="el-icon-lollipop" @keyup.enter="handleLogin"></el-input>
        </el-row>

        <el-row>
          <el-button type="primary" style="width: 100%" @click="handleLogin" >登录</el-button>
        </el-row>
        <el-row>
          <router-link to="/register">去注册</router-link>
        </el-row>

      </el-main>

    </el-container>
  </div>

</template>

<script>
import axios from "axios";

export default {
  name: "Login",
  data(){
    return{
      username:'',
      password:'',
      timer:null
    }
  },
  methods:{
    //添加按键节流
    handleLogin(){
      if(this.timer){
        return
      }
      this.timer = setTimeout(()=>{
        this.login()
        this.timer = null
      },1000)

    },
    login(){
      if((!this.username || !this.password)){
        this.$message.error('用户名或密码不能为空!');
      }else {
        axios.get('http://localhost:5000/accounts',{
          params:{
            username:this.username,
            password:this.password
          }
        }).then(
            response=>{
              console.log(response.data)
              if(!response.data.length){
                this.$message.error('用户名或密码不正确!');
                this.password=''
                this.username=''

              }else {
                localStorage.setItem('username',this.username)
                localStorage.setItem('password',this.password)
                console.log(response.data[0].avatar)
                localStorage.setItem('url',response.data[0].avatar)
                this.$message({
                  message: '登陆成功~',
                  type: 'success',

                })

                //将数据存入state不合理页面刷新数据消失
                // this.$store.dispatch('addName',this.username)
                // this.$store.dispatch('addPass',this.password)
                setTimeout(()=>{
                  this.$router.push('/admin')
                },2000)
              }
            },
            error=>{
              console.log(error.message)
            }
        )
      }
    }
  },
  mounted() {
  }
}
</script>

<style scoped lang="less">


.el-container {
  width: 350px;

  margin: 300px auto 0;
  //padding: 50px;
  background-color: rgba(255,255,255,.4);
  border-radius: 20px;
  .el-row{
    padding: 5px;
    position: relative;
    .el-input__inner{
      padding: 0 28px!important;
    }
    i{
      position: absolute;
      left: 5px;
      top: 50%;
      transform: translateY(-50%);
      z-index: 99;

    }
    a{
      float: right;
      color: #fff;
      text-decoration: none;
    }

  }
}
</style>

2.注册组件Register.vue实现

<template>
  <div>
  <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm"  class="demo-ruleForm">
    <el-form-item prop="name">
      <el-input type="text" v-model="ruleForm.name" autocomplete="off" prefix-icon="el-icon-user-solid" placeholder="请输入用户名"></el-input>
    </el-form-item>
    <el-form-item prop="pass">
      <el-input type="password" v-model="ruleForm.pass" autocomplete="off" placeholder="请输入密码" prefix-icon="el-icon-sugar"></el-input>
    </el-form-item>
    <el-form-item prop="checkPass">
      <el-input type="password" v-model="ruleForm.checkPass" placeholder="请确认密码" prefix-icon="el-icon-apple" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm('ruleForm')" style="width: 100%">注册</el-button>
<!--      <el-button @click="resetForm('ruleForm')">重置</el-button>-->
    </el-form-item>
    <router-link to="/">去登录</router-link>
  </el-form>
  </div>
</template>

<script>
import axios from "axios";

export default {
  name: "Register",
  data() {
    const validateName = (rule, value, callback) => {
      if (!value) {
        return callback(new Error('用户名不能为空'));
      }
      setTimeout(() => {
        axios.get('http://localhost:5000/checkName',{
          params:{
            username:this.ruleForm.name
          }
        }).then(
            response=>{
                //校验用户名是否合法
              console.log(response.data)
              if(response.data.length){
                callback(new Error('该用户已存在'));
              }else {
                callback();
              }
            },
            error=>{
              console.log(error.message)
            }
        )
      }, 1000);

    };
    const validatePass = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请输入密码'));
      }else if(value.length<6){
        callback(new Error('密码不能少于6位!'));
      }
      else {
        if (this.ruleForm.checkPass !== '') {
          this.$refs.ruleForm.validateField('checkPass');
        }
        callback();
      }
    };
    const validatePass2 = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请再次输入密码'));
      } else if (value !== this.ruleForm.pass) {
        callback(new Error('两次输入密码不一致!'));
      } else {
        callback();
      }
    };
    return {
      ruleForm: {
        pass: '',
        checkPass: '',
        name:''
      },
      rules: {
        name:[
          { validator: validateName, trigger: 'blur' }
        ],
        pass: [
          { validator: validatePass, trigger: 'blur' }
        ],
        checkPass: [
          { validator: validatePass2, trigger: 'blur' }
        ],
      }
    };
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {

        if (valid) {
          axios.post('http://localhost:8080/register',{

              username:this.ruleForm.name,
              password:this.ruleForm.pass
            }
          ).then(
              response=>{
                console.log(response.data)
                this.$message({
                  message: '恭喜你,注册成功',
                  type: 'success'
                })
                //将输入存入本地
                localStorage.setItem('username',this.ruleForm.name)
                localStorage.setItem('password',this.ruleForm.pass)
                localStorage.setItem('url','')
                setTimeout(()=>{
                  this.$router.push('/admin')
                },1000)
              },
              error=>{
                console.log(error.message)
              }
          )

        } else {
          console.log('error submit!!');
          return false;
        }
      });
    }
  }
}
</script>

<style scoped>
.el-form{
  width: 350px;
  margin: 250px auto 0;
  padding: 50px;
  background-color: rgba(255,255,255,.5);
  border-radius: 20px;
}
a{
  float: right;
  color: #fff;
  text-decoration: none;
}

</style>

采用element表单组件设置自定义校验规则,十分方便

3.后台主页backAdmin.vue实现

<template>
  <div>
    <el-container style="height: 630px; border: 1px solid #eee;overflow: hidden">
      <!--          左侧导航栏开始-->
      <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
        <el-row style="height: 60px">

          <h1>后台管理系统</h1>
        </el-row>
<!--        <el-menu :default-openeds="['1']"> 设置默认打开选项栏 通过唯一标识index指定-->
        <el-menu>

          <el-submenu index="1">
            <template slot="title"><i class="el-icon-message"></i>首页</template>
            <el-menu-item-group>

              <el-menu-item >
                <router-link :to="{name:'statistics'}" slot="title">
                  统计
                </router-link>
              </el-menu-item>
            </el-menu-item-group>

          </el-submenu>
          <el-submenu index="2">
            <template slot="title"><i class="el-icon-menu"></i>文章管理</template>
            <el-menu-item-group>

              <el-menu-item :route="{
                  name:'species'}"
              >
                <router-link :to="{
                  name:'species'
                }">文章分类</router-link>
                </el-menu-item>
              <el-menu-item>

                <router-link :to="{
                  name:'articleList'
                }">文章列表</router-link>
              </el-menu-item>
              <el-menu-item>

                <router-link :to="{
                  name:'publishArticle'
                }">发布文章</router-link>
              </el-menu-item>
            </el-menu-item-group>

          </el-submenu>
          <el-submenu index="3">
            <template slot="title"><i class="el-icon-user-solid"></i>个人信息</template>
            <el-menu-item>

              <router-link :to="{
                  name:'updateInfo'
            }">修改详细信息
              </router-link>
            </el-menu-item>
            <el-menu-item>

              <router-link :to="{
                  name:'resetPass'
            }">修改密码
              </router-link>
            </el-menu-item>
            <el-menu-item>

              <router-link :to="{
                  name:'setAvatar'
            }">修改头像
              </router-link>
            </el-menu-item>

          </el-submenu>
        </el-menu>
      </el-aside>

<!--      下拉列表选项卡-->
      <el-container>
        <el-header style="text-align: right; font-size: 12px">
          <el-dropdown>
            <i class="el-icon-setting" style="margin-right: 15px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>
                <router-link :to="{name:'updateInfo'}">修改信息</router-link>
              </el-dropdown-item>
              <el-dropdown-item>
                <router-link :to="{name:'resetPass'}">修改密码</router-link>
              </el-dropdown-item>
              <el-dropdown-item>
                <router-link replace to="/">退出</router-link>
              </el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>

<!--          头像与姓名-->
          <el-avatar :src="this.url" style="height: 60px;width: 60px;display: inline-block;margin: 0 10px"></el-avatar>
          <span style="display: inline-block;height: 60px;float: right;font-weight: 700;font-size: 14px">{{name}}</span>
        </el-header>

<!--        切换路由显示组件位置-->

        <el-main style="background-color: rgba(255,255,255,.5);">
            <router-view></router-view>
        </el-main>
      </el-container>
    </el-container>
    <el-footer style="height: 65px">&copy;Designed by Pegnet &target;2022</el-footer>
  </div>
</template>

<script>
export default {
  name: "BackAdmin",
  data() {

    return {
      name:localStorage.getItem('username'),
      url:localStorage.getItem('url')
    }
  },
  mounted() {
    this.$bus.$on('getUrl',()=>{
      this.name = localStorage.getItem('username')
      this.url = localStorage.getItem('url')
    })

  },
  beforeDestroy() {
    localStorage.removeItem('username')
    // localStorage.removeItem('id')
    localStorage.removeItem('password')
    localStorage.removeItem('url')
  }
}
</script>

将用户的输入存入本地以便通过路由守卫鉴权,未登录状态通过url访问网址重定向到登录页

4.统计页面Statistics.vue实现

<template>
  <div>
    <el-container>
      <el-card class="box-card" style="">
        <h1>
          用户总数
        </h1>
        <span>{{ userSum }}</span>
      </el-card>
      <el-card class="box-card">
        <h1>
          文章总数
        </h1>
        <span>{{ articleSum }}</span>
      </el-card>
    </el-container>
    <div>
      <div id="age" style="width: 50%;height: 500px;display: inline-block;margin-top: 20px;float: left"></div>
      <div id="species" style="width: 50%;height: 500px;display: inline-block;float:right"></div>
    </div>
  </div>
</template>

<script>
import * as echarts from 'echarts';
import axios from "axios";

export default {
  name: "Statistics",
  data() {
    return {
      ageData: [
        {value: 0, name: '18岁以下'},
        {value: 0, name: '18岁以上30岁以下'},
        {value: 0, name: '30岁以上50岁以下'},
        {value: 0, name: '50岁以上70岁以下'},
        {value: 0, name: '70岁以上'},
      ],
      species: [],
      speciesData: [],
      userSum: 0,
      articleSum: 0
    }
  },
  mounted() {
    //获取年龄统计数据
    const age = echarts.init(document.getElementById('age'));


    const ageOption = {

      textStyle:{

        fontSize: 14,
        fontWeight: 700,
      },
      title: {
        text: '用户年龄分布',
        subtext: '来自数据库',
        left: 'center'
      },
      tooltip: {
        trigger: 'item'
      },
      legend: {
        orient: 'vertical',
        left: 'left'
      },
      series: [
        {
          name: '用户年龄',
          type: 'pie',
          radius: '50%',
          data: this.ageData,
          emphasis: {
            itemStyle: {
              shadowBlur: 10,
              shadowOffsetX: 0,
              shadowColor: 'rgba(0, 0, 0, 0.5)'
            }
          }
        }
      ]
    }
    axios.get('http://localhost:5000/statistics').then(
        response => {
          console.log(response.data)
          response.data.forEach((item, index) => {
            this.ageData[index].value = item[0]['count(1)']
            this.userSum += this.ageData[index].value
            // console.log(this.data[index].value)
          })
          age.setOption(ageOption);
        }
    )

    //获取文章分类统计数据
    const species = echarts.init(document.getElementById('species'));
    const specieOption = {
      textStyle:{

        fontSize: 14,
        fontWeight: 700,
        color:'black'
      },
      title: {
        text: '文章分类数量',
        subtext: '来自数据库',
        left: 'center'
      },
      xAxis: {
        type: 'category',
        data: this.species
      },
      yAxis: {
        type: 'value'
      },
      series: [
        {
          data: this.speciesData,
          type: 'bar',
          showBackground: true,
          backgroundStyle: {
            color: 'rgba(180, 180, 180, 0.2)'
          }
        }
      ]
    };
    //获取文章分类
    axios.get('http://localhost:5000/getSpecies').then(
        response => {
          // console.log(response.data)
          response.data.forEach((item) => {
            // console.log(item)
            this.species.push(item.name)

          })
          //获取文章分类文章数量
          axios.post('http://localhost:5000/articleStatistics', {
            species: this.species
          }).then(
              response => {
                // console.log(response.data)
                response.data.forEach((item, index) => {
                  this.speciesData[index] = item[0]['count(1)']
                  // console.log(this.data[index].value)
                  this.articleSum += this.speciesData[index]
                  console.log(this.speciesData)
                  species.setOption(specieOption);
                })
              },
              error => {
                console.log(error.message)
              }
          )
          species.setOption(specieOption);
          // console.log(this.species)
          // this.specieData = response.data
        },
        error => {
          console.log(error.message)
        }
    )
  }
}
</script>

5.文章分类ArticleSpecies.vue实现

<template>
  <div>
    <el-row style="float: right;margin-bottom: 10px">
      <!--      <el-button type="primary">添加分类</el-button>-->
      <!--      添加分类弹出层-->
      <el-popover
          placement="left"
          width="400"
          trigger="click">
        <!--        提交表单-->
        <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
          <el-form-item label="分类名" prop="name">
            <el-input type="text" v-model="ruleForm.name" autocomplete="off"></el-input>
          </el-form-item>
          <el-form-item label="分类别名" prop="nickname">
            <el-input type="text" v-model="ruleForm.nickname" autocomplete="off"></el-input>
          </el-form-item>

          <el-form-item>
            <el-button type="primary" @click="submitForm('ruleForm')">添加</el-button>
            <el-button @click="resetForm('ruleForm')">重置</el-button>
          </el-form-item>
        </el-form>
        <!--        <el-button type="primary" plain style="width: 100%" @click="addSpecie">确认添加</el-button>-->
        <el-button slot="reference" type="primary">添加分类</el-button>
      </el-popover>
    </el-row>
    <!--    显示分类表格主体-->
    <transition-group
        appear
        name="animate__animated animate__bounce"
        enter-active-class="animate__bounce"
        leave-active-class="animate__bounce"

    >
      <el-table
          :data="tableData"
          style="width: 100%"
          key="1"
      >
        <el-table-column
            label="序号"
            width="180"
            key="2"
        >
          <template slot-scope="scope">
            <span style="margin-left: 10px">{{ scope.row.id }}</span>
          </template>
        </el-table-column>
        <el-table-column
            label="分类名称"
            width="280">
          <template slot-scope="scope">
            <span style="margin-left: 10px">{{ scope.row.name }}</span>
          </template>
        </el-table-column>
        <el-table-column
            label="分类别名"
            width="280">
          <template slot-scope="scope">

            <div slot="reference" class="name-wrapper">
              <el-tag size="medium">{{ scope.row.nickname }}</el-tag>
            </div>

          </template>
        </el-table-column>
        <!--        表格操作列-->
        <el-table-column label="操作">
          <!--          编辑弹出层-->
          <template slot-scope="scope">
            <el-popover
                placement="left"
                width="400"
                trigger="click"
            >
              <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px"
                       class="demo-ruleForm">
                <el-form-item label="分类名" prop="name">
                  <!--                  <input type="text" :value="scope.row.name">-->
                  <el-input type="text" v-model="ruleForm.name" :placeholder="scope.row.name"
                            autocomplete="off"></el-input>
                </el-form-item>
                <el-form-item label="分类别名" prop="nickname">
                  <el-input type="text" v-model="ruleForm.nickname" :placeholder="scope.row.nickname"
                            autocomplete="off"></el-input>
                </el-form-item>

                <el-form-item>
                  <el-button type="primary" @click="submitForm('ruleForm',scope.$index, scope.row)">修改</el-button>
                  <el-button @click="resetForm('ruleForm')">重置</el-button>
                </el-form-item>
              </el-form>
              <el-button
                  slot="reference"
                  size="mini"
                  type="warning"
                  style="margin-right: 10px"
              >编辑
              </el-button>
            </el-popover>
            <el-popconfirm
                title="确定删除这个分类吗?"
                icon="el-icon-info"
                icon-color="red"
                @confirm="handleDelete(scope.$index, scope.row)">

            <el-button
                size="mini"
                slot="reference"
                type="danger">删除
            </el-button>
            </el-popconfirm>
          </template>
        </el-table-column>
      </el-table>
    </transition-group>

    <!--    <el-empty description="暂无数据" v-show="isShow"></el-empty>-->
  </div>
</template>

<script>
import axios from "axios";
import 'animate.css'

export default {

  name: "ArticleSpecies",

  data() {
    //定义检验规则
    const validateName = (rule, value, callback) => {
      // console.log(value)
      if (value === '') {
        callback(new Error('请输入分类名'));
      } else {
        this.tableData.forEach((val) => {
          if (value === val.name) {
            callback(new Error('分类名已存在!'));
          }
          // console.log(val)
          // console.log(val.name)
        })
        callback();
      }
    };
    const validateNickname = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请输入分类别名'));
      } else {
        callback();
      }
    };
    return {
      tableData: [],
      isShow: false,
      timer: null,
      ruleForm: {
        name: '',
        nickname: '',


      },
      rules: {
        name: [
          {validator: validateName, trigger: 'blur'}
        ],
        nickname: [
          {validator: validateNickname, trigger: 'blur'}
        ],
      }

    }
  },
  watch: {
    tableData: {
      // deep:true,
      handler(newValue, oldValue) {
        if (!newValue) {
          this.isShow = true
        } else {
          this.isShow = true
        }

      }
    }
  },
  methods: {
    handleEdit(index, row) {
      console.log(index, row);
    },
    //删除分类,形参与实参列表必须一一对应
    handleDelete(index, row) {
      //实现节流以及鉴权
      if (this.timer) {
        return
      } else {
        if ([1, 2, 3].includes(row.id) && localStorage.getItem('username') !== 'admin') {
          this.timer = setTimeout(() => {
            this.$message.error('非管理员不可删除这个分类!');
            this.timer = null
          }, 1000)

        }else {
          axios.post('http://localhost:8080/deleteSpecie', {

            id: row.id


          }).then(
              response => {
                console.log(response.data)
                //获取当前行的id直接从数据中删除
                this.tableData.splice(index, 1)
              },
              error => {
                console.log(error.message)
              }
          )
        }
      }
    },
    //添加分类
    addSpecie() {
      axios.post('http://localhost:8080/addSpecie', {
        name: this.ruleForm.name,
        nickname: this.ruleForm.nickname
      }).then(
          response => {
            console.log(response.data)
          },
          error => {
            console.log(error.message)
          }
      )
    },
    //查询分类
    selectSpecie(status, index) {
      axios.post('http://localhost:8080/selectSpecie', {
        name: this.ruleForm.name,
      }).then(
          response => {
            if (status === 'add') {
              this.tableData.push(response.data[0])
            } else {
              this.tableData.splice(index, 1, response.data[0])
            }
            // console.log(response.data)
          },
          error => {
            console.log(error.message)
          }
      )
    },
    //更新分类
    updateSpecie(id, name, nickname) {
      axios.post('http://localhost:8080/updateSpecie', {
        id,
        name,
        nickname
      }).then(
          response => {
            console.log(response.data)
          },
          error => {
            console.log(error.message)
          }
      )
    },
    //提交添加分类
    submitForm(formName, index = '', row = '') {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          if (!index && !row) {
            this.addSpecie()
            this.selectSpecie('add')
            this.ruleForm.nickname = ''
            this.ruleForm.name = ''
            this.$message({
              message: '添加成功~',
              type: 'success'
            })
          } else {
            // console.log(e.target)
            console.log(index)
            console.log(row)
            if ([1, 2, 3].includes(row.id) && localStorage.getItem('username') !== 'admin'){
              this.$message.error('非管理员不可修改这个分类!');
              this.ruleForm.nickname = ''
              this.ruleForm.name = ''
            }else{
              this.updateSpecie(row.id, this.ruleForm.name, this.ruleForm.nickname)
              this.selectSpecie('edit', index)
              this.ruleForm.nickname = ''
              this.ruleForm.name = ''
              this.$message({
                message: '修改成功~',
                type: 'success'
              })
            }
          }
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },
    //重置表单
    resetForm(formName) {
      this.$refs[formName].resetFields();
    }
  },
  //当dom元素挂载完毕执行
  mounted() {
    axios.get('http://localhost:5000/getSpecies').then(
        response => {
          console.log(response.data)
          this.tableData = response.data
        },
        error => {
          console.log(error.message)
        }
    )
  }
}
</script>

6.文章列表ArticleList.vue实现

<template>
  <el-container>
    <el-card class="box-card" style="width: 100%">
      <div slot="header" class="clearfix">
        <span style="font-weight: 700">文章列表</span>

      </div>
      <el-row>
        <el-select v-model="value" filterable placeholder="请选择">
          <el-option
              v-for="item in options"
              :key="item.id"
              :label="item.name"
              :value="item.name">
          </el-option>
        </el-select>
        <el-button type="primary" @click="searchArticle" style="margin-left: 10px">搜索</el-button>
        <el-button type="success" plain style="float: right" @click="publishArticle">发表文章</el-button>
      </el-row>
      <el-main>
      <el-table
          :data="tableData"
          border
          style="width: 100%">
        <el-table-column
            prop="title"
            align="center"
            label="文章标题"
            class="name-wrapper"
            width="250">
        </el-table-column>
        <el-table-column
            prop="specie"
            align="center"
            label="文章分类"
            width="160">
        </el-table-column>
        <el-table-column

            prop="pubtime"
            align="center"

            :formatter="dateFormatter"
            label="发布时间"
            width="320">
        </el-table-column>
        <el-table-column
            prop="author"
            align="center"
            label="作者"
            width="160">
        </el-table-column>

        <el-table-column
            label="操作"
            align="center"
            width="305">
          <template slot-scope="scope">
<!--            <el-popover-->
<!--                placement="left"-->
<!--                width="800"-->
<!--                trigger="click">-->
<!--              <p ref="content"></p>-->
<!--            <el-button type="primary" slot="reference" size="small" @click="showContent(scope.$index, scope.row)">查看</el-button>-->
<!--            </el-popover>-->
            <el-button type="primary" slot="reference" size="small" @click="showContent(scope.$index, scope.row)">查看</el-button>

<!--            只有文章的作者才有权限编辑和删除文章-->
            <el-button type="warning" size="small" v-show="scope.row.author === username" @click="editArticle(scope.row)">编辑</el-button>
            <el-popconfirm
                title="确定删除这个文章吗?"
                icon="el-icon-info"
                icon-color="red"
                @confirm="deleteArticle(scope.$index,scope.row.id)"
            >
              <el-button type="danger" slot="reference" size="small" style="margin-left: 7px"  v-show="scope.row.author === username">删除</el-button>

            </el-popconfirm>
          </template>

        </el-table-column>

      </el-table>
      </el-main>
    </el-card>

  </el-container>

</template>

<script>
import axios from "axios";
import dayjs from "dayjs";

export default {
  name: "articleList",
  data() {
    return {
      options: [],
      value: '',
      tableData: [],
      timer: null,
      status:null,
      username:window.localStorage.getItem('username'),
      cacheSpecie:localStorage.getItem('cacheSpecie')
    }
  },
  //dom加载完成从数据库获取所有文章分类并渲染页面
  mounted() {
    axios.get('http://localhost:5000/getSpecies').then(
        response => {
          this.options = response.data
        },
        error => {
          console.log(error.message)
        }
    )
    //如果有搜索历史优先展示缓存中搜索的结果
    if(this.cacheSpecie){
      axios.post('http://localhost:5000/selectArticles', {
        specie: this.cacheSpecie
      }).then(
          response => {
            this.tableData = response.data
            this.value = this.cacheSpecie
            this.timer = null
          },
          error => {
            console.log(error.message)
          }
      )
    }

  },
  methods: {
    //根据分类搜索文章列表
    searchArticle() {
      if (this.timer) {
        return
      }
      this.timer = setTimeout(() => {
        axios.post('http://localhost:5000/selectArticles', {
          specie: this.value
        }).then(
            response => {
              console.log(response.data)
              localStorage.setItem('cacheSpecie',this.value)
              this.tableData = response.data
              this.timer = null
            },
            error => {
              console.log(error.message)
            }
        )
      }, 500)

    },
    //定义格式化函数
    dateFormatter(cellvalue) {
      // console.log('@',cellvalue)
      // cellvalue为当前行对象
      return dayjs(cellvalue.pubtime).format('YYYY-MM-DD HH:mm:ss')
    },
    //前往发布文章页面
    publishArticle(){
      this.$router.push({
        name:'publishArticle'
      })
    },
    //查看文章
    showContent(index,row){
      // console.log(index)
      // console.log(row.content)
      this.$router.push({
        name:'articleDetail',
        params:{
          article:row
        }
      })
      // this.$refs.content.innerHTML = row.content
    },
    //修改文章
    editArticle(row){
      // console.log(index)
      // console.log(row.content)
      this.$router.push({
        name:'editArticle',
        params:{
          article:row
        }
      })
      // this.$refs.content.innerHTML = row.content
    },
    //删除文章
    deleteArticle(index,id){
      console.log(id)
      axios.post('http://localhost:5000/deleteArticle', {
        id: id
      }).then(
          response => {
            console.log(response.data)
            this.tableData.splice(index, 1)

          },
          error => {
            console.log(error.message)
          }
      )
    }
  },


}
</script>

只有文章的作者才能修改或删除文章,其余用户只能查看

7.发布文章PublishArticle.vue实现

<template>
  <el-container>
    <el-header>
      <el-input
          v-model="title"
          placeholder="请输入标题"
          style="width: 300px;margin-right: 20px"
          maxlength="10"
          show-word-limit
      ></el-input>
      <el-select v-model="specie" filterable placeholder="请选择">
        <el-option
            v-for="item in options"
            :key="item.id"
            :label="item.name"
            :value="item.name">
        </el-option>
      </el-select>
      <el-button type="primary" style="margin-left: 20px" @click="publishArticle">发布文章</el-button>
    </el-header>
    <div style="border: 1px solid #ccc;height: 400px">
      <Toolbar
          style="border-bottom: 1px solid #ccc"
          :editor="editor"
          :defaultConfig="toolbarConfig"
          :mode="mode"
      />
      <Editor
          style="height: 500px; overflow-y: hidden;"
          v-model="content"
          :defaultConfig="editorConfig"
          :mode="mode"
          @onCreated="onCreated"
      />
    </div>
  </el-container>

</template>

<script>
import {Editor, Toolbar} from '@wangeditor/editor-for-vue'
import axios from "axios";

export default {
  name: "publishArticle",
  components: {Editor, Toolbar},
  data() {
    return {
      editor: null,
      content: '',
      toolbarConfig: {},
      editorConfig: {placeholder: '请输入内容...'},
      mode: 'default', // or 'simple'
      options: [],
      specie: '',
      title:'',
      timer:null
    }
  },
  methods: {
    onCreated(editor) {
      this.editor = Object.seal(editor) // 一定要用 Object.seal() ,否则会报错
    },
    //发布文章
    publishArticle(){
      if(this.timer){
        return;
      }
      this.timer = setTimeout(()=>{
        if(!this.title){
          this.$message({
            showClose: true,
            message: '请输入标题',
            type: 'warning'
          });
          return this.timer=null
        }
        if(!this.specie){
          this.$message({
            showClose: true,
            message: '请选择分类',
            type: 'warning'
          });
          return this.timer=null
        }
        if(!this.content){
          this.$message({
            showClose: true,
            message: '请输入文章内容',
            type: 'warning'
          });
          return this.timer=null
        }
        console.log(this.title)
        console.log(this.content)
        console.log(this.specie)
        axios.post('http://localhost:5000/publishArticle',{
          title:this.title,
          content:this.content,
          specie:this.specie,
          author:localStorage.getItem('username'),

        }).then(
            response=>{
              console.log(response.data)
              this.$notify({
                title: '成功',
                message: '发布成功~',
                type: 'success'
              });
              this.timer=null
              this.title=''
              this.content=''
              this.specie=''
            },
            error=>{
              this.$notify({
                title: '失败',
                message: '发布失败!',
                type: 'warning'
              });
              console.log(error.message)
            }
        )
      },1000)

    }
  },
  mounted() {
    // // 模拟 ajax 请求,异步渲染编辑器
    // setTimeout(() => {
    //   this.content = '请输入内容'
    // }, 1500)
    axios.get('http://localhost:5000/getSpecies').then(
        response => {
          this.options = response.data

        },
        error => {
          console.log(error.message)
        }
    )
  },
  beforeDestroy() {
    const editor = this.editor
    if (editor == null) return
    editor.destroy() // 组件销毁时,及时销毁编辑器
  }
}

</script>

<style scoped>
@import "@wangeditor/editor/dist/css/style.css";
</style>

8.修改文章内容EditArticle.vue实现

<template>
  <el-container>
    <el-header>
      <el-button type="primary" plain icon="el-icon-arrow-left" style="float: left" @click="toList">返回</el-button>
      <el-input
          v-model="title"
          placeholder="请输入标题"
          style="width: 300px;margin-right: 20px"
          maxlength="10"
          show-word-limit
      ></el-input>
      <el-select v-model="specie" filterable placeholder="请选择">
        <el-option
            v-for="item in options"
            :key="item.id"
            :label="item.name"
            :value="item.name">
        </el-option>
      </el-select>
      <el-button type="success" plain style="margin-left: 20px" @click="publishArticle">确认修改</el-button>
    </el-header>
    <div style="border: 1px solid #ccc;height: 400px">
      <Toolbar
          style="border-bottom: 1px solid #ccc"
          :editor="editor"
          :defaultConfig="toolbarConfig"
          :mode="mode"
      />
      <Editor
          style="height: 500px; overflow-y: hidden;"
          v-model="content"
          :defaultConfig="editorConfig"
          :mode="mode"
          @onCreated="onCreated"
      />
    </div>
  </el-container>

</template>

<script>
import {Editor, Toolbar} from '@wangeditor/editor-for-vue'
import axios from "axios";

export default {
  name: "editArticle",
  components: {Editor, Toolbar},
  data() {
    return {
      editor: null,
      content: this.$route.params.article.content,
      toolbarConfig: {},
      editorConfig: {placeholder: '请输入内容...'},
      mode: 'default', // or 'simple'
      options: [],
      specie: this.$route.params.article.specie,
      title:this.$route.params.article.title,
      timer:null
    }
  },
  methods: {
    onCreated(editor) {
      this.editor = Object.seal(editor) // 一定要用 Object.seal() ,否则会报错
    },
    //发布文章
    publishArticle(){
      if(this.timer){
        return;
      }
      this.timer = setTimeout(()=>{
        if(!this.title){
          this.$message({
            showClose: true,
            message: '请输入标题',
            type: 'warning'
          });
          return this.timer=null
        }
        if(!this.specie){
          this.$message({
            showClose: true,
            message: '请选择分类',
            type: 'warning'
          });
          return this.timer=null
        }
        if(!this.content){
          this.$message({
            showClose: true,
            message: '请输入文章内容',
            type: 'warning'
          });
          return this.timer=null
        }
        console.log(this.title)
        console.log(this.content)
        console.log(this.specie)
        axios.post('http://localhost:5000/editArticle',{
          title:this.title,
          content:this.content,
          specie:this.specie,
          // author:localStorage.getItem('username'),
          id:this.$route.params.article.id,

        }).then(
            response=>{
              console.log(response.data)
              this.$notify({
                title: '成功',
                message: '修改成功~',
                type: 'success'
              });
              this.timer=null
              this.title=''
              this.content=''
              this.specie=''
            },
            error=>{
              console.log(error.message)
            }
        )
      },1000)

    },
    toList(){
      this.$router.back()
    }
  },
  mounted() {
    // // 模拟 ajax 请求,异步渲染编辑器
    // setTimeout(() => {
    //   this.content = '请输入内容'
    // }, 1500)
    axios.get('http://localhost:5000/getSpecies').then(
        response => {
          this.options = response.data

        },
        error => {
          console.log(error.message)
        }
    )
  },
  beforeDestroy() {
    const editor = this.editor
    if (editor == null) return
    editor.destroy() // 组件销毁时,及时销毁编辑器
  }
}

</script>

<style scoped>
@import "@wangeditor/editor/dist/css/style.css";
</style>

与发布组件一致,只需要简单赋值修改即可

9.修改个人信息UpdateInfo.vue(只是为了可视化数据,可以自定义)

<template>
  <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
    <el-form-item label="用户名" prop="username">
      <el-input type="text" v-model="ruleForm.username" autocomplete="off"></el-input>
    </el-form-item>
    <el-form-item label="性别" style="text-align: left;font-weight: 700">
      <el-select v-model="ruleForm.gender" placeholder="请选择性别" value="">
        <el-option label="男" value="male"></el-option>
        <el-option label="女" value="female"></el-option>
        <el-option label="其他" value="other"></el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="婚况" style="text-align: left">
      <el-select v-model="ruleForm.maritalStatus" placeholder="请选择婚况" value="">
        <el-option label="已婚" value="unmarried"></el-option>
        <el-option label="未婚" value="married"></el-option>
        <el-option label="丧偶" value="widow"></el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="年龄" prop="age">
      <el-input v-model.number="ruleForm.age"></el-input>
    </el-form-item>
    <el-form-item style="text-align: left">
      <el-button type="primary" @click="submitForm('ruleForm')">确认修改</el-button>
      <el-button @click="resetForm('ruleForm')">重置</el-button>
    </el-form-item>
  </el-form>
</template>

<script>
import axios from "axios";

export default {
  name: "updateInfo",
  data() {
    //检验年龄是否合法
    const checkAge = (rule, value, callback) => {
      if (!value) {
        return callback(new Error('年龄不能为空'));
      }
      setTimeout(() => {
        if (!Number.isInteger(value)) {
          callback(new Error('请输入数字值'));
        } else {
          if (value < 10) {
            callback(new Error('必须年满10岁'));
          } else {
            callback();
          }
        }
      }, 1000);
    };
    //检验用户名是否合法
    const validateName = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请输入用户名'));
      } else {
        setTimeout(() => {
          axios.get('http://localhost:5000/checkName',{
            params:{
              username:this.ruleForm.username
            }
          }).then(
              response=>{
                console.log(response.data)
                if(response.data.length){
                  callback(new Error('该用户已存在'));
                }else {
                  callback();
                }
              },
              error=>{
                console.log(error.message)
              }
          )
        }, 1000);
        // callback();
      }
    };

    return {
      ruleForm: {
        username: '',
        age: '',
        gender:'',
        maritalStatus:'',
        oldName :localStorage.getItem('username')
      },
      rules: {
        username: [
          { required:true,validator: validateName, trigger: 'blur' }
        ],
        gender: [
          { message: '请选择性别', trigger: 'change' }
        ],
        age: [
          { required:true,validator: checkAge, trigger: 'blur' }
        ]
      }
    };
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
         axios.post('http://localhost:5000/updateInfo',{
           newName:this.ruleForm.username,
           oldName:this.ruleForm.oldName,
           age:this.ruleForm.age,
           maritalStatus:this.ruleForm.maritalStatus,
           gender:this.ruleForm.gender,
         }).then(
             response=>{
               console.log(response.data)

               localStorage.setItem('username',this.ruleForm.username)
               this.ruleForm.oldName = this.ruleForm.username
               this.$bus.$emit('getUrl')
               this.$message({
                 message: '修改成功~',
                 type: 'success',

               })
               this.ruleForm.username = ''
               this.ruleForm.age = ''
               this.ruleForm.gender = ''
               this.ruleForm.maritalStatus = ''
             },
             error=>{
               console.log(error.message)
             }
         )
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    }
  }
}
</script>

10.上传头像SetAvatar.vue实现

<template>
  <div>
    <el-upload
        class="avatar-uploader"
        action="http://localhost:5000/setAvatar"
        :data="{name:this.username}"
        :show-file-list="false"
        :on-success="handleAvatarSuccess"
        :before-upload="beforeAvatarUpload">
      <img v-if="imageUrl" :src="imageUrl" class="avatar" alt="丢失">
      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
      <div style="color: #3a3b3d">点击上传头像</div>
    </el-upload>
<!--    <img :src="this.url" alt="">-->
  </div>
</template>

<script>
export default {
  name: "setAvatar",
  data() {
    return {
      imageUrl: '',
      username:localStorage.getItem('username'),
      url:localStorage.getItem('url'),
    };
  },

  methods: {
    handleAvatarSuccess(res, file) {
      console.log(this.username)

      this.imageUrl = URL.createObjectURL(file.raw);
      console.log(res)
      localStorage.setItem('url',res)
      this.$bus.$emit('getUrl')
      console.log(this.imageUrl)
    },
    beforeAvatarUpload(file) {
      const isJPG = file.type === 'image/jpeg';
      const isLt2M = file.size / 1024 / 1024 < 2;

      if (!isJPG) {
        this.$message.error('上传头像图片只能是 JPG 格式!');
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!');
      }
      return isJPG && isLt2M;
    }
  }
}
</script>

采用element头像组件上传到服务器本地以及数据库
全部代码https://gitee.com/pegnet/bigevent.git

你可能感兴趣的:(vue.js,javascript,前端)