注册/登录/后台管理系统/子路由/babel/upload

这篇博客主要探讨了前端如何实现用户注册、登录功能,以及后台管理系统的构建,包括子路由的设置和使用Babel进行代码转换。此外,还涉及到文件上传的相关技术。
const express = require('express')                                //index.js后端
const app = express()
const port = 3000

const bodyParser = require('body-parser');
app.use(bodyParser.json())

const cors = require('cors');
app.use(cors())

const mysql = require('mysql');
var db = mysql.createPool({
    connectionLimit: 10,
    host: 'localhost',
    user: 'root',
    password: '123456',
    database: 'kw31'
});

// 引入bcryptjs加密模块,用于注册密码时加密
var bcrypt = require('bcryptjs');

// token
const mySecret = "Life is short, you need front-end";
const jwt = require('jsonwebtoken');

let responseData = {
    code: 0,
    message: ""
};

app.get('/', (req, res) => res.send('Hello World!'))

app.get('/home', (req, res) => {
    let mytoken = req.headers['authorization'];
    if (mytoken) {
        try {
            let result = jwt.verify(mytoken, mySecret);
            console.log(result);
            res.json(result)
            //{ user_id: 2, user_name: 'huhu', iat: 1602763041, exp: 1602849441 }
            // let { exp = 0 } = result, current = Math.floor(Date.now() / 1000);
            // //官网表示不需要判断,时间到期自动判断
            // if (current <= exp) {
            //     console.log('没过期');
            //     res.json(result)
            // } else {
            //     console.log('过期了');
            //     res.json({ code: '999', msg: 'token过期了,请登录' })
            // }
        } catch (error) {
            console.log(error);
            res.json({ code: '999', msg: '权限验证失败,你无权访问用户列表' })
        }
    } else {
        res.json({ code: '999', msg: 'token为空,请登录!' })
    }
})

// 获取链接列表接口
app.get('/get-article', (req, res) => {
    db.query('SELECT * FROM article_table' , (err,results) => {
        if (err) throw err;
        console.log(results);
        res.json(results)
    })
})

// 创建链接的接口
app.post('/create-link', (req, res) => {
    let {title, content} = req.body;
    db.query('INSERT INTO  article_table(title,content) VALUES(?,?)' , [title,content], (err,results) => {
        if (err) throw err;
        console.log(results);
        res.json({code:0,msg:'金主爸爸创建成功!'})
    })
})

// 删除链接的接口
app.post('/delete-link', (req, res) => {
    let {id} = req.body;
    db.query('DELETE FROM article_table WHERE id = ?' , [id], (err,results) => {
        if (err) throw err;
        console.log(results);
        res.json({code:0,msg:'金主爸爸删除成功!'})
    })
})


// 获取指定id路径接口
app.get('/get-link-show', (req, res) => {
    let {id} = req.query;
    console.log(id);
    db.query('SELECT * FROM article_table WHERE id = ?' , [id], (err,results) => {
        if (err) throw err;
        console.log(results)
        res.json(results)
    })
})


// 编辑链接的接口
app.post('/edit-link', (req, res) => {
    let {id,title,content} = req.body;
    db.query('UPDATE article_table SET title = ?, content = ? WHERE id = ?' , [title,content,id], (err,results) => {
        if (err) throw err;
        res.json({code:0,msg:'金主爸爸保存成功!'})
    })
})



// 获取接口
app.get('/getLink', (req, res) => {

    console.log(req.query); // { curr: '1', limit: '10' }

    let page = Number(req.query.curr) - 1   // 第几页
    let count = Number(req.query.limit)     // 每页多少条

    db.query(`SELECT * FROM article_table`, (err, result) => {
        if (err) throw err;
        let total = result.length;
        db.query(`SELECT * FROM article_table limit ${page * count},${count}`, (err, result) => {
            if (err) throw err;
            let responseData = {
                code: 0,
                count: total,
                listData: result
            }
            res.send(responseData)
        });
    });

})



// 注册接口
app.post('/register', function (req, res) {
    // console.log(req.body); // 打印注册的数据
    if (req.body.regUsername.trim() == '') {
        responseData.code = 1;
        responseData.message = "用户名不能为空";
        res.json(responseData);
        return;
    }
    if (req.body.regPassword.trim() == '') {
        responseData.code = 2;
        responseData.message = "密码不能为空";
        res.json(responseData);
        return;
    }
    if (req.body.regPassword.trim() !== req.body.checkPassword.trim()) {
        responseData.code = 3;
        responseData.message = "两次密码不一致";
        res.json(responseData);
        return;
    }
    // 查询数据
    db.query(`SELECT username FROM user_table WHERE username='${req.body.regUsername}'`, function (error, results) {
        if (error) throw error;
        console.log(results);
        if (results.length != 0) {
            responseData.code = 4;
            responseData.message = "用户名已经存在";
            res.json(responseData);
            return;
        } else {
            // 使用bcrypt模块将密码加密,自动生成盐和哈希。使用的是同步方法,官网还有异步方法
            var hash = bcrypt.hashSync(req.body.regPassword, 8)
            //将哈希存储在数据库密码字段中。
            db.query(`INSERT INTO user_table(username,password) VALUES('${req.body.regUsername}', '${hash}')`, (error, result) => {
                if (error) throw error;
                // console.log(result); // 打印数据库插入数据的结果
                responseData.code = 0; // 这个0一定要写,否则会继承上一次注册不成功的code值
                responseData.message = "注册成功";
                res.json(responseData);
            })
        }
    });
})




// 登录
app.post('/login', function (req, res) {
    // console.log(req.body); // 打印登录数据
    let { logUsername, logPassword } = req.body;

    // 这里只是简单验证一下用户名和密码是否非空,建议做下更复杂的验证如长度,非数字等
    if (logUsername.trim() == "" || logPassword.trim() == "") {
        responseData.code = 1;
        responseData.message = "用户名和密码不能为空";
        res.json(responseData);
        return;
    }

    // 根据登录名从数据库中查询数据
    db.query(`SELECT id,username,password,pic FROM user_table WHERE username="${logUsername}"`, function (error, results) {
        if (error) throw error;
        // console.log(results); // 打印数据库查询的结果,是一个数组
        if (results.length == 0) {
            responseData.code = 2;
            responseData.message = "用户名不存在";
            res.json(responseData);
        } else {
            // 比较登录密码和数据库中的哈希密码。使用的是bcrypt模块的compareSync同步方法,官网还有异步方法
            let checkpass = bcrypt.compareSync(logPassword, results[0].password);
            if (checkpass) {
                responseData.code = 0;
                responseData.message = "登录成功";
                // 根据前端登录的用户名或id生成一个token
                let token = jwt.sign({ user_id: results[0].id, user_name: results[0].username ,avater: results[0].pic}, mySecret, { expiresIn: '4h' })
                responseData.token = token;
                res.json(responseData);

            } else {
                responseData.code = 3;
                responseData.message = "密码错误";
                res.json(responseData);
            }

        }
    });
})

//上传
const path = require('path');
const fs = require('fs');

const multer = require('multer');
// 在根目录生成一个文件夹,把我们的上传的文件放到这个文件夹里面
var upload = multer({ dest: 'uploads/' })
app.post('/up', upload.single('avatar'), function (req, res) {
    console.log(req.file);

    var new_file_path = req.file.path + path.parse(req.file.originalname).ext
    // var newname2 = req.file.path + path.extname(req.file.originalname)
    console.log(new_file_path);

    // 使用fs模块的rename重命名
    fs.rename(req.file.path, new_file_path, (err) => {
        if (err) {
            res.json({code:1,msg:'上传失败了'})
        } else {
            res.json({code:0,msg:'上传成功了'})
        }
    })
})

app.listen(port, () => console.log(`服务器开始工作啦`))

前端

<template>      //App.vue
    <div>
        <router-view />
    </div>
</template>
//main.js
import Vue from 'vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
import VueAwesomeSwiper from 'vue-awesome-swiper'




import router from './routers/index.js';

import http from './config/axios.js';
Vue.prototype.$axios = http;

Vue.use(ElementUI);

Vue.config.productionTip = false
import 'element-tiptap/lib/index.css';
import { ElementTiptapPlugin } from 'element-tiptap';
Vue.use(ElementTiptapPlugin, {
  lang: 'zh',//配置语言为中文
});

new Vue({
  router,
  render: h => h(App),
}).$mount('#app')
//babel.config.js
module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ]
}
//index.js(路由)
import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

import h from '@/views/Home.vue';
import main from '@/views/articles/main.vue';
import s from '@/views/articles/showLink.vue';
import c from '@/views/articles/createLink.vue';
import e from '@/views/articles/editLink.vue';
import o from '@/views/entro.vue';
import p from '@/views/plant-Leek.vue';
import m from '@/views/materia/index.vue'
import v from '@/views/materia/veg.vue'
import d from '@/views/materia/Operate-echarts.vue'

import Login from '@/views/Login.vue';
import Register from '@/views/Register.vue';

const router = new VueRouter({
    mode: 'history',
    routes: [
        { path: '/', redirect:'/home' },//一级路由
        { path: '/home', component:h,children:[
            { path: '', component:main },
            { path: '/show-link', component:s },
            { path: '/create-link', component:c },
            { path: '/edit-link/:id', component:e},
            { path: '/entrepreneurship', component:o},
            { path: '/plant', component:p},
            { path: '/material', component:m},
            { path: '/vegaterbal', component:v},
            { path: '/datacount', component:d},

        ]},//二级路由
        { path: '/login', name:'LoginPage', component: Login },
        { path: '/register', component: Register }
    ]
});

export default router;
//Home.vue
<template>
<el-container style="height: 100vh">
    <el-header>
        <el-row>
            <el-col :span="6">
                <span class="font1">稂莠</span>
            </el-col>
            <el-col :span="12" class="frind"> 金主爸爸的韭菜之旅 </el-col>
            <el-col :span="5" class="text-right frinds">
                <el-dropdown>
                    <span class="el-dropdown-link">
                        <el-avatar class="icon" :src="avater" size="small"></el-avatar>
                        <span style="color: white; margin-right: 10px">{{
                loginName
              }}</span>
                        <i class="el-icon-arrow-down" style="margin-right: 15px"></i>
                    </span>

                    <el-dropdown-menu slot="dropdown">
                        <el-dropdown-item><span @click="logout">退出</span></el-dropdown-item>
                    </el-dropdown-menu>
                </el-dropdown>
            </el-col>
        </el-row>
    </el-header>

    <el-container style="height: 500px; border: 1px solid #999">
        <el-aside width="230px" style="background-color: rgb(238, 241, 246)">
            <el-menu :default-openeds="['1']" unique-opened router active-text-color="#008c8c" :default-active="$route.path">
                <el-menu-item index="/home">
                    <i class="el-icon-setting"></i>
                    <span slot="title">首页 </span>
                </el-menu-item>
                <el-submenu index="1">
                    <template slot="title"><i class="el-icon-tickets"></i>金主</template>
                    <el-menu-item index="/show-link">金主信息</el-menu-item>
                    <el-menu-item index="/create-link">创建金主</el-menu-item>
                </el-submenu>
                <el-submenu index="2">
                    <template slot="title"><i class="el-icon-menu"></i>兴趣</template>
                    <el-menu-item-group>
                        <template slot="title">韭菜</template>
                        <el-menu-item index="/entrepreneurship">割韭菜</el-menu-item>
                        <el-menu-item index="/plant">种韭菜</el-menu-item>
                    </el-menu-item-group>
                </el-submenu>
                <el-menu-item index="/entrepreneurship">
                    <i class="el-icon-setting"></i>
                    <span slot="title">种菜实例 </span>
                </el-menu-item>
                <el-menu-item index="/material">
                    <i class="el-icon-document-add"></i>
                    <span slot="title">韭菜种类管理 </span>
                </el-menu-item>
                <el-menu-item index="/vegaterbal">
                    <i class="el-icon-potato-strips"></i>
                    <span slot="title">养菜日记 </span>
                </el-menu-item>
                <el-menu-item index="/datacount">
                    <i class="el-icon-s-promotion"></i>
                    <span slot="title">种菜活动统计 </span>
                </el-menu-item>
            </el-menu>
        </el-aside>

        <el-container>
            <el-main>
                <router-view />
            </el-main>
        </el-container>
    </el-container>
    <el-footer style="background-color: #eee; color: gray" class="copyright">版权所有 &copy; 金主爸爸科技有限公司</el-footer>
</el-container>
</template>

<script>
export default {
    watch: {
        '$route.path': function () {
            // this.$message.success('系好安全带,发车啦')
            this.$message({
                showClose: true,
                message: '系好安全带,发车啦',
                duration: 1000,
                type: 'success'
            });
        }
    },
    data() {
        return {
            loginName: "",
            avater: ''
        };
    },
    created() {
        if (!localStorage.getItem("mytoken")) {
            //方法一1)没有token则去登录
            this.$router.push("/login");
        }
        this.$axios.get("/home").then((res) => {
            if (res.data.code == "999") {
                //方法二2)后端验证:请求/home,没有\错误则返回999,去登录
                this.$router.push("/login"); //避免DOM加载
            } else {
                //否则有token返回其解码数据
                this.loginName = res.data.user_name; //如果有,姓名放于data内
                this.avater = res.data.avater
            }
        });
    },
    methods: {
        logout() {
            localStorage.clear();
            this.$message.success("再见,爸爸!");
            this.$router.push({
                name: "LoginPage"
            });
        },
        debounce(fn, delay) { //防抖函数
            let timeout;
            return function () {
                clearTimeout(timeout)
                timeout = setTimeout(() => {
                    fn.apply(this, arguments)
                }, delay)
            }
        },
        jieliu(fn, delay) {
            let timeout;
            return function () {
                if (timeout) {
                    return
                }
                timeout = setTimeout(() => {
                    fn.apply(this, arguments) //函数本身再走一遍
                    timeout = null
                })
            }
        }
    },
    mounted() {
        document.body.style.backgroundColor = "#fff";
    },
};
</script>

<style>
body {
    margin: 0;
    padding: 0;
}

.icon {
    position: relative;
    top: 7px;
    right: 10px;
}

.frinds {
    font-size: 20px;
    margin-left: 30px !important;
    text-align: right !important;
}

.frind {
    font-size: 20px;
    text-align: center;
}

.el-header {
    background-color: #008c8c;
    color: white;
    line-height: 60px;
}

.copyright {
    display: flex;
    justify-content: center;
    padding-top: 17px;
}

.el-aside {
    color: #333;
}

.el-menu-item.is-active {
    color: #333;
}

.font1 {
    font-family: font1;
    color: white;
    font-size: 40px !important;
}

@font-face {
    font-family: "font1";
    font-display: swap;
    src: url("//at.alicdn.com/t/webfont_4pyteix3g3l.eot");
    /* IE9*/
    src: url("//at.alicdn.com/t/webfont_4pyteix3g3l.eot?#iefix") format("embedded-opentype"),
        /* IE6-IE8 */
        url("//at.alicdn.com/t/webfont_4pyteix3g3l.woff2") format("woff2"),
        url("//at.alicdn.com/t/webfont_4pyteix3g3l.woff") format("woff"),
        /* chrome、firefox */
        url("//at.alicdn.com/t/webfont_4pyteix3g3l.ttf") format("truetype"),
        /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/
        url("//at.alicdn.com/t/webfont_4pyteix3g3l.svg#站酷高端黑") format("svg");
    /* iOS 4.1- */
}
</style>
//lLogin.vue
<template>
  <div>
    <h1 class="mylogo">
      <router-link to="/"
        ><span class="font1 font-28">稂莠family</span></router-link
      >
    </h1>
    <div class="box">
      <h2>
        <router-link to="/login" class="text-secondary">登录</router-link>
        <span class="text-dark">·</span>
        <router-link to="/register" class="text-secondary">注册</router-link>
      </h2>

      <el-form
        :model="formData"
        :rules="rules"
        ref="loginForm"
        label-width="0px"
      >
        <el-form-item prop="logUsername">
          <el-input v-model="formData.logUsername" placeholder="用户名">
            <i slot="prefix" class="el-input__icon el-icon-user-solid"></i>
          </el-input>
        </el-form-item>
        <el-form-item prop="logPassword">
          <el-input
            type="password"
            v-model="formData.logPassword"
            placeholder="密码"
          >
            <i slot="prefix" class="el-input__icon el-icon-lock"></i>
          </el-input>
        </el-form-item>
        <el-form-item>
          <el-button
            type="primary"
            @click="onSubmitForm('loginForm')"
            class="myw"
            :loading="isLoading">立即登录</el-button
          >
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      formData: {
        logUsername: "",
        logPassword: "",
      },
      isLoading:false,
      rules: {
        // rules里的username和el-form-item的prop值必须一致,而prop值必须和formdata里的username一致
        logUsername: [
          { required: true, message: "请输入用户名", trigger: "blur" },
        ],
        logPassword: [
          { required: true, message: "请输入密码", trigger: "blur" },
        ],
      },
    };
  },
  methods: {
    onSubmitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          this.isLoading=true
          console.log("submit!");
          this.$axios
            .post("/login", this.formData)
            .then((res) => {
              console.log(res.data);
              if (res.data.code == 1) {
                this.$message({
                  // showClose: true,
                  message: res.data.message,
                  type: "warning",
                });
                return;
              }
              if (res.data.code == 2) {
                this.$message({
                  // showClose: true,
                  message: res.data.message,
                  type: "warning",
                });
                return;
              }
              if (res.data.code == 3) {
                this.$message({
                  // showClose: true,
                  message: res.data.message,
                  type: "warning",
                });
                return;
              }

              if (res.data.code == 0) {
                // 存储token
                localStorage.setItem("mytoken", res.data.token);
                // elementui消息提示
                this.$message({
                  message: res.data.message,
                  type: "success",
                });
                this.isLoading=true
                this.$router.push("/home");
              }
            })
            .catch((err) => {
              console.log("有错误2:");
              console.error(err);
            });
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
  },
  mounted() {
    document.body.style.backgroundColor = "#eee";
  },
};
</script>
//Register.vue
<template>
  <div>
    <h1 class="mylogo">
      <router-link to="/home"><span class="font1 ">稂莠family</span></router-link>
    </h1>
    <div class="box">
      <h2>
        <router-link to="/login" class="text-secondary">登录</router-link>
        <span class="text-dark">·</span>
        <router-link to="/register" class="text-secondary">注册</router-link>
      </h2>

      
      <el-form :model="formData" :rules="rules" ref="regForm" label-width="0px">
        <el-form-item prop="regUsername">
          <el-input v-model="formData.regUsername" placeholder="用户名">
            <i slot="prefix" class="el-input__icon el-icon-user-solid"></i>
          </el-input>
        </el-form-item>
        <el-form-item label prop="regPassword">
          <el-input
            type="password"
            v-model="formData.regPassword"
            autocomplete="off"
            placeholder="密码"
          >
            <i slot="prefix" class="el-input__icon el-icon-lock"></i>
          </el-input>
        </el-form-item>
        <el-form-item label prop="checkPassword">
          <el-input
            type="password"
            v-model="formData.checkPassword"
            autocomplete="off"
            placeholder="确认密码"
          >
            <i slot="prefix" class="el-input__icon el-icon-lock"></i>
          </el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="onRegForm('regForm')" class="myw"
            >立即注册</el-button
          >
        </el-form-item>
      </el-form>
      <p class="text-center text-primary">
        点击 “注册” 即表示您同意并愿意遵守协议
      </p>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    var validateUserName = (rule, value, callback) => {
      var reg = /^\w{3,15}$/;
      if (!reg.test(value)) {
        callback(new Error("字母、数字、下划线组成"));
      } else {
        callback();
      }
    };
    var validatePass2 = (rule, value, callback) => {
      if (value === "") {
        callback(new Error("请再次输入密码"));
      } else if (value !== this.formData.regPassword) {
        callback(new Error("两次输入密码不一致!"));
      } else {
        callback();
      }
    };
    return {
      formData: {
        regUsername: "",
        regPassword: "",
        checkPassword: "",
      },
      rules: {
        // rules里的username和el-form-item的prop值必须一致,而prop值必须和formdata里的username一致
        regUsername: [
          { required: true, message: "请输入用户名", trigger: "blur" },
          { min: 3, max: 15, message: "长度3-16位之间", trigger: "blur" },
          { validator: validateUserName, trigger: "blur" },
        ],
        regPassword: [
          { required: true, message: "请输入密码", trigger: "blur" },
          { min: 6, max: 15, message: "长度6-15位之间", trigger: "blur" },
        ],
        checkPassword: [
          { min: 6, max: 15, message: "长度6-15位之间", trigger: "blur" },
          { validator: validatePass2, trigger: "blur" },
        ],
      },
    };
  },
  methods: {
    onRegForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          console.log("submit!");
          this.$axios
            .post("/register", this.formData)
            .then((res) => {
              console.log(res.data);

              if (res.data.code == 4) {
                this.$message({
                  showClose: true,
                  //默认的 Message 是不可以被人工关闭的,如果需要可手动关闭的 Message,可以使用showClose字段
                  message: res.data.message,
                  type: "warning",
                });
                return;
              }

              if (res.data.code == 0) {
                // elementui消息提示
                this.$message({
                  message: "恭喜您,注册成功",
                  type: "success",
                });

                // 编程式导航,跳转到login页
                this.$router.push("/login");
              }
            })
            .catch((err) => {
              console.error(err);
            });
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
  },
  mounted() {
    document.body.style.backgroundColor = "#eee";
  },
};
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值