笔记
用户上传头像的功能
上传图片的接口
// 上传上传用户头像图片的业务逻辑
let UploadImg = (req, res) => {
// 1.实例化一个表单对象
const form = new formidable.IncomingForm();
// 2.配置文件上传路径 E:\好谷前端\03作业\myServer/public/uploads
//path.join("a","b","c") a\\b\\c
form.uploadDir = path.join(__dirname, "../", "public", "uploads");
// 3.解析上传的文件
form.parse(req, (err, fields, files) => {
// 4.重命名图片 (老路径,新路径)
let oldPath = files.file.filepath;
let newPath = path.join(__dirname, "../", "public", "uploads") + "/hg_" + Date.now() + files.file.originalFilename;
fs.renameSync(oldPath, newPath); //同步的重命名
// 返回jason
res.json({
status: 200,
imgPath: "uploads" + newPath.split('uploads')[1]
})
/*
// fields 文本数据 files:文件数据
//现在文件的路径(老路径) 'E:\\好谷前端\\03作业\\myServer\\public\\uploads\\319bb20f85a8084183dc81c00'
console.log(files.file.filepath);
//原文件名:'HbuilderX.png'
console.log(files.file.originalFilename);
*/
});
}
上传头像组件
//结构
<el-upload
class="avatar-uploader"
action="http://localhost:3000/api/upload"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img
v-if="imageUrl"
:src="'http://localhost:3000/' + imageUrl"
class="avatar"
/>
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
//方法:
// methods中上传头像的方法
handleAvatarSuccess(res, file) {
console.log(res); //返回的是接口返回的数据
console.log(file);
// 让imageUrl上传图像的数据等于后台响应回来的值
this.imageUrl = res.imgPath;
},
beforeAvatarUpload(file) {
const isJPG =
file.type === "image/jpeg" ||
file.type === "image/gif" ||
file.type === "image/png";
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error("上传头像图片只能是 JPG 格式!");
}
if (!isLt2M) {
this.$message.error("上传头像图片大小不能超过 2MB!");
}
return isJPG && isLt2M;
},
自定义表单验证规则
//结构
<!-- 表单 -->
<el-form
:model="useraddDatas"
status-icon
:rules="rules"
label-width="80px"
ref="ruleForm"
>
<el-form-item label="用户名" prop="username">
<el-input
v-model="useraddDatas.username"
placeholder="邮箱/手机号"
></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input
v-model="useraddDatas.password"
placeholder="密码"
show-password
></el-input>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input
v-model.number="useraddDatas.age"
placeholder="年龄"
></el-input>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input
v-model="useraddDatas.phone"
placeholder="手机号"
></el-input>
</el-form-item>
<el-form-item label="是否可用">
<el-switch
v-model="useraddDatas.is_show"
active-color="#13ce66"
inactive-color="#ff4949"
active-text="开"
inactive-text="关"
active-value="1"
inactive-value="0"
>
</el-switch>
</el-form-item>
<el-form-item label="用户等级">
<el-radio-group v-model="useraddDatas.level">
<el-radio :label="0">超级</el-radio>
<el-radio :label="1">管理员</el-radio>
<el-radio :label="2">老师</el-radio>
<el-radio :label="3">学生</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="用户头像">
<el-upload
class="avatar-uploader"
action="http://localhost:3000/api/upload"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img
v-if="imageUrl"
:src="'http://localhost:3000/' + imageUrl"
class="avatar"
/>
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')"
>添加</el-button
>
</el-form-item>
</el-form>
data:
data() {
//这里存放数据
// 自定义校验规则--用户名
var checkUsername = (rule, value, callback) => {
if (value === "") {
callback(new Error("请输入用户名"));
} else {
// 进行正则验证
if (!(tools.regPhone.test(value) || tools.regEmail.test(value))) {
callback(new Error("用户名格式不正确"));
}
callback();
}
};
// 自定义校验规则--手机号
var checkPhone = (rule, value, callback) => {
if (value === "") {
callback(new Error("请输入手机号"));
} else {
// 进行正则验证
if (!tools.regPhone.test(value)) {
callback(new Error("手机号格式不正确"));
}
callback();
}
};
// 自定义校验规则--年龄
var checkAge = (rule, value, callback) => {
if (!value) {
return callback(new Error("年龄不能为空"));
}
setTimeout(() => {
if (!Number.isInteger(value)) {
callback(new Error("请输入数字值"));
} else {
if (value < 18) {
callback(new Error("必须年满18岁"));
} else {
callback();
}
}
}, 1000);
};
return {
// 表单的数据
useraddDatas: {
username: "",
password: "",
age: "",
phone: "",
is_show: "1",
},
// 上传头像的数据
imageUrl: "",
// 自定义校验规则
rules: {
username: [{ validator: checkUsername, trigger: "blur" }],
age: [{ validator: checkAge, trigger: "blur" }],
phone: [{ validator: checkPhone, trigger: "blur" }],
},
};
},
对应的正则
utils--tools
// 正则表达式--手机号和邮箱
let tools = {
regPhone: /^1[358][0-9]{9}$/,
regEmail: /^[0-9a-zA-Z]{6,20}@[0-9a-zA-Z]+\.[a-zA-Z]{2,6}$/
}
export default tools;
useradd接口的业务
// /useradd添加用户的逻辑
let UserAdd = async (req, res) => {
// console.log(req.body);
let { username, phone, age, email, address, is_show, imgsrc, level } = req.body;
//在插入前需要先判断数据库有没有该数据,有的话给一个提醒,,没有的话插入
let isexistSql = `select * from hg_users where username="${username} "`
let is_exist = await request(isexistSql); //得到的是一个数组
if (is_exist.length > 0) {
res.json({
status: 4002,
msg: "用户已存在,请去登录"
})
} else {
let password = md5(req.body.password); //密码加密
let create_time = moment().format("YYYY-MM-DD hh:mm:ss"); //格式化添加时间
// 插入的sql语句
let add_sql = `insert into hg_users
set username="${username}",
password="${password}",
phone="${phone}" ,
age="${age}",
email="${email}",
address="${address}",
is_show="${is_show}",
create_time="${create_time}",
imgsrc="${imgsrc}",
level="${level}"`
// 调用request方法将数据插入到mysql数据库
let result = await request(add_sql);
console.log(result);
if (result.affectedRows == 1) {
res.json({
status: 200,
msg: "插入成功",
})
} else {
res.json({
status: 4001,
msg: "插入失败",
})
}
}
};
点击添加按钮事件里调用useraddApi
// 点击添加的表单验证的方法
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
// 点击添加进行异步请求修改数据库
this.$set(this.useraddDatas, "imgsrc", this.imageUrl); //修改表单对象,添加img路径
userAddApi(this.useraddDatas).then((result) => {
console.log(result);
if (result.data.status == 200) {
this.$router.push("/layout/userlist");
}
});
} else {
console.log("error submit!!");
return false;
}
});
},
将表格的用户等级从数据转换成对应的级别
store–user.js
// 引入异步请求的userlist的api
import { userlistApi } from "@/api/user.js";
// 定义模块化的users
let users = {
state: {
num: 100,
userlistDatas: {}
},
mutations: {
changeUserlistDatas(state, data) {
state.userlistDatas = data;
}
},
actions: {
async actChangeUserlistDatas(context, params) {
let result = await userlistApi(params);
console.log(result.data.data);
// 在此过滤表格中的用户等级从数字到对应的文字
result.data.data.map(item => {
switch (item.level) {
case "0":
item.level = "超级管理员"
break;
case "1":
item.level = "管理员"
break;
case "2":
item.level = "老师"
break;
case "3":
item.level = "学生"
break;
default:
break;
}
})
context.commit("changeUserlistDatas", result.data);
}
},
getters: {},
modules: {}
}
// 暴露出users到store的modules下
export default users;
给表格添加Tab页
结构
<!-- Tab标签页 -->
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane
v-for="tabsData in tabs"
:key="tabsData.id"
:label="tabsData.title"
:name="tabsData.level"
></el-tab-pane>
</el-tabs>
methods:
// Tab标签页的方法
handleClick(tab, event) {
console.log(tab.name, event);
// 让分页的数据level等于当前的标签页的name
this.level = tab.name;
// 再次提交至状态管理store进行axios的请求
// 提交派遣分页数据给store的user.js
this.$store.dispatch("actChangeUserlistDatas", {
page: this.page,
size: this.size,
level: this.level,
});
},
改造登录页面
登录页面
<!-- -->
<template>
<div class="user_login">
<div class="container">
<div class="left">
<!-- 左边轮播图 -->
<el-carousel height="400px">
<el-carousel-item>
<img src="@/assets/images/vae01.jpg" alt="" />
</el-carousel-item>
<el-carousel-item>
<img src="@/assets/images/vae02.jpg" alt="" />
</el-carousel-item>
<el-carousel-item>
<img src="@/assets/images/vae03.jpg" alt="" />
</el-carousel-item>
</el-carousel>
</div>
<div class="right">
<div class="title"><h2>好谷大咖管理系统</h2></div>
<el-form
:model="loginData"
:rules="loginRules"
ref="ruleForm"
status-icon
>
<el-form-item prop="username">
<el-input
v-model="loginData.username"
placeholder="用户名"
></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginData.password"
show-password
placeholder="密码"
></el-input>
</el-form-item>
<el-form-item label="">
<el-radio-group v-model="loginData.level">
<el-radio :label="1">管理员</el-radio>
<el-radio :label="2">老师</el-radio>
<el-radio :label="3">学生</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="verifycode">
<div class="verify">
<el-input
v-model="loginData.verifycode"
placeholder=" 验证码"
style="width: 60%"
></el-input>
<img
src="http://localhost:3000/api/captcha"
alt=""
ref="img"
@click="changeCaptcha"
/>
</div>
</el-form-item>
<el-form-item>
<el-button
type="primary"
style="width: 100%"
@click="submitForm('ruleForm')"
>登录</el-button
>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
import { loginApi } from "@/api/user.js"; //引入验证登录的异步
import { setCookie } from "@/utils/auth.js";
export default {
//import引入的组件需要注入到对象中才能使用
components: {},
data() {
//这里存放数据
return {
loginData: {
username: "",
password: "",
verifycode: "",
level: "",
},
loginRules: {
username: [
{ required: true, message: "请输入用户名", trigger: "blur" },
{
min: 2,
max: 10,
message: "长度在2到10个字符",
trigger: "blur",
},
],
password: [
{ required: true, message: "请输入密码", trigger: "blur" },
{
min: 5,
max: 12,
message: "长度在 5 到 12 个字符",
trigger: "blur",
},
],
verifycode: [
{ required: true, message: "请输入验证码", trigger: "blur" },
],
},
};
},
//计算属性 类似于data概念
computed: {},
//监控data中的数据变化
watch: {},
//方法集合
methods: {
// 表单验证的代码方法
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
// 异步请求判断用户名是否一致
loginApi(this.loginData).then((result) => {
console.log(result);
if (result.data.status == 200) {
// 设置cookie
setCookie("token", result.data.token);
setCookie("level", result.data.level);
// 跳转到layout/userlist
this.$router.push("/layout/userlist");
} else {
alert(result.data.msg);
}
});
} else {
console.log("error submit!!");
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
},
// 点击刷新验证码
changeCaptcha() {
// 保证每次请求的接口不一样
this.$refs.img.src = "http://localhost:3000/api/captcha?t=" + Date.now();
},
},
beforeCreate() {}, //生命周期 - 创建之前
//生命周期 - 创建完成(可以访问当前this实例)
created() {},
beforeMount() {}, //生命周期 - 挂载之前
//生命周期 - 挂载完成(可以访问DOM元素)
mounted() {},
beforeUpdate() {}, //生命周期 - 更新之前
updated() {}, //生命周期 - 更新之后
beforeDestroy() {}, //生命周期 - 销毁之前
destroyed() {}, //生命周期 - 销毁完成
activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
<style lang="scss">
.user_login {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url("../../assets/images/bg.jpg");
background-size: 100% 100%;
.container {
width: 800px;
height: 400px;
position: absolute;
top: 50%;
left: 50%;
margin-left: -400px;
margin-top: -200px;
border-radius: 10px;
overflow: hidden;
background-color: #fff;
display: flex;
.left {
width: 400px;
height: 400px;
.el-carousel__item {
img {
width: 100%;
height: 100%;
}
}
}
.right {
width: 323px;
height: 400px;
margin: 0px 50px;
.title {
margin: 20px 0px;
text-align: center;
}
.verify {
display: flex;
justify-content: space-between;
img {
width: 100px;
height: 40px;
}
}
}
}
}
</style>
//登录接口的业务
//登录验证用户名密码的接口业务逻辑
let LoginFn = async (req, res) => {
let captcha = req.body.verifycode;
if (captcha.toLowerCase() != tempCaptcha) {
res.json({
status: 1004,
msg: "验证码输入有误"
})
}
// 这里假设已经接收到表单传递过来的参数
let username = req.body.username;
let password = md5(req.body.password);
let level = req.body.level || 0;
// 根据username向数据库发送请求先判断有没有该用户并且等级匹配
let usernameSql = `SELECT * from hg_users where username="${username}" and level="${level}"`;
let result = await request(usernameSql);
if (result.length > 0) {
//说明验证用户名成功,则再次判断用户名和密码还有等级是否一致
let pwdSql = `SELECT * from hg_users where username="${username}" and password="${password}" and level="${level}"`
let result2 = await request(pwdSql);
if (result2.length > 0) {
// 登录成功,设置一条token
let token = createToken({ username: username, isLogin: true });
console.log(token);
// 将数据响应成json
res.json({
status: 200,
msg: "登录成功",
token: token,
level: level
})
} else {
res.json({
status: 1004,
msg: "用户名密码不匹配,请重新输入!"
})
}
} else {
res.json({
//说明验证用户名失败
status: "4004",
msg: "用户名不存在,点击这里注册"
})
}
}
用户列表页面的mounted中:
mounted() {
//获取coolie的level并且替换掉数据level
this.level = getCookie("level");
//可以获取到模块化后的vuex状态管理
console.log(this.$store.state.users);
// 提交派遣分页数据给store的user.js
this.$store.dispatch("actChangeUserlistDatas", {
page: this.page,
size: this.size,
level: this.level,
});
},