第一步:首先明确需要编写的文件:
vue前端的登录页面:login.vue
vue前端的注册页面:sign.vue
vue前端的路由页面,负责vue框架内页面的跳转:index.js
node后端连接数据,建立请求文件 :app.js
node后端连接数据库文件:mysql.js
一定要确保对应文件的连接位置。
代码架构:
javascript
主目录
src目录
view目录
login.vue
sign.vue
router目录
index.js
api目录
app.js
mysql.js
第二步书写对应的文件
login.vue
html
<template>
<div class="login-container">
<div class="layer">
<div class="some-space">
<div class="form">
<h2>大数据可视化平台</h2>
<div class="item">
<i class="iconfont icon-user"></i>
<label for="username">登录</label>
<input autocomplete="off"
type="text"
class="input"
v-model="form.username"
placeholder="请输入用户名" />
</div>
<div class="item">
<i class="iconfont icon-password"></i>
<label for="password">密码</label>
<input autocomplete="off"
type="password"
class="input"
v-model="form.password"
maxlength="20"
@keyup.enter="login"
placeholder="请输入密码" />
</div>
<!-- 添加验证码相关的输入框和显示区域 -->
<div class="item">
<i class="iconfont icon-password"></i>
<label for="verificationCode">验证码</label>
<input autocomplete="off"
type="text"
class="input"
v-model="form.verificationCode"
placeholder="请输入验证码" />
<span class="verification-code-img" @click="refreshVerificationCode">
{
{ verificationCodeText }}
</span>
</div>
<button class="loginBtn"
:disabled="isLoginAble"
@click.stop="login">
立即登录
</button>
<button class="registerBtn" @click="goToRegister">
注册用户
</button>
<div class="tip">
默认用户名:admin ,默认密码:123456
</div>
</div>
</div>
</div>
<vue-particles color="#6495ED"
:particleOpacity="0.7"
:particlesNumber="80"
shapeType="circle"
:particleSize="4"
linesColor="#6495ED"
:linesWidth="1"
:lineLinked="true"
:lineOpacity="0.6"
:linesDistance="150"
:moveSpeed="3"
:hoverEffect="true"
hoverMode="grab"
:clickEffect="true"
clickMode="push">
</vue-particles>
<bgAnimation />
</div>
</template>
<script>
import { userLogin } from '../api/user';
import router from '../router';
export default {
name: 'Home',
data() {
return {
form: {
username: '',
password: '',
verificationCode: '' // 添加验证码字段
},
verificationCodeText: '1234' // 模拟验证码文本,实际应用中应从后端获取并更新
};
},
methods: {
login() {
// 简单验证验证码是否正确(这里只是简单示例,实际要对接后端验证逻辑)
if (this.form.verificationCode === this.verificationCodeText) {
userLogin(this.form)
.then((res) => {
alert(res.data.msg);
router.push({
path: '/traffic'
});
})
.catch((err) => {
alert(err.response.data.msg);
});
} else {
alert('验证码错误,请重新输入');
}
},
goToRegister() {
console.log('准备跳转');
router.push({
path: '/about'
});
console.log('已执行跳转操作');
},
refreshVerificationCode() {
// 模拟刷新验证码,这里简单修改文本,实际应从后端获取新的验证码
this.verificationCodeText = Math.floor(Math.random() * 10000).toString().padStart(4, '0');
}
}
};
</script>
<style lang="scss" scoped>
.login-container {
.layer {
position: absolute;
height: 100%;
width: 100%;
background-image: url('../assets/bg-4.jpg');
background-size: cover;
background-repeat: no-repeat;
}
#particles-js {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
}
.some-space {
color: white;
font-weight: 100;
letter-spacing: 2px;
position: absolute;
top: 50%;
left: 50%;
z-index: 1001;
-webkit-transform: translate3d(-50%, -50%, 0);
transform: translate3d(-50%, -50%, 0);
-ms-animation: cloud 2s 3s ease-in infinite alternate;
-moz-animation: cloud 2s 3s ease-in infinite alternate;
-webkit-animation: cloud 2s 3s ease-in infinite alternate;
-o-animation: cloud 2s 3s ease-in infinite alternate;
animation: cloud 2s 3s ease-in infinite alternate;
.form {
width: 460px;
height: auto;
background: rgba(36, 36, 85, 0.5);
margin: 0 auto;
padding: 35px 30px 25px;
box-shadow: 0 0 25px rgba(255, 255, 255, 0.5);
border-radius: 10px;
.item {
display: flex;
align-items: center;
margin-bottom: 25px;
border-bottom: 1px solid #d3d7f7;
i {
color: #d3d7f7;
margin-right: 10px;
}
}
h2 {
text-align: center;
font-weight: normal;
font-size: 26px;
color: #d3d7f7;
padding-bottom: 35px;
}
.input {
font-size: 16px;
line-height: 30px;
width: 100%;
color: #d3d7f7;
outline: none;
border: none;
background-color: rgba(0, 0, 0, 0);
padding: 10px 0;
}
.loginBtn {
width: 100%;
padding: 12px 0;
border: 1px solid #d3d7f7;
font-size: 16px;
color: #d3d7f7;
cursor: pointer;
background: transparent;
border-radius: 4px;
margin-top: 10px;
&:hover {
color: #fff;
background: #0090ff;
border-color: #0090ff;
}
}
.registerBtn {
width: 100%;
padding: 12px 0;
border: 1px solid #d3d7f7;
font-size: 16px;
color: #d3d7f7;
cursor: pointer;
background: transparent;
border-radius: 4px;
margin-top: 10px;
&:hover {
color: #fff;
background: #0090ff;
border-color: #0090ff;
}
}
.tip {
font-size: 12px;
padding-top: 20px;
}
// 验证码显示区域样式
.verification-code-img {
margin-left: 10px;
cursor: pointer;
color: #d3d7f7;
}
}
}
}
input::-webkit-input-placeholder {
color: #d3d7f7;
}
input::-moz-placeholder {
/* Mozilla Firefox 19+ */
color: #d3d7f7;
}
input:-moz-placeholder {
/* Mozilla Firefox 4 to 18 */
color: #d3d7f7;
}
input:-ms-input-placeholder {
/* Internet Explorer 10-11 */
color: #d3d7f7;
}
@-ms-keyframes cloud {
0% {
-ms-transform: translate(-50%, -50%);
}
40% {
opacity: 1;
}
60% {
opacity: 1;
}
100% {
-ms-transform: translate(-50%, -40%);
}
}
@-moz-keyframes cloud {
0% {
-moz-transform: translate(-50%, -50%);
}
40% {
opacity: 1;
}
60% {
opacity: 1;
}
100% {
-moz-transform: translate(-50%, -40%);
}
}
@-o-keyframes cloud {
0% {
-o-transform: translate(-50%, -50%);
}
40% {
opacity: 1;
}
60% {
opacity: 1;
}
100% {
-o-transform: translate(-50%, -40%);
}
}
@-webkit-keyframes cloud {
0% {
-webkit-transform: translate(-50%, -50%);
}
40% {
opacity: 1;
}
60% {
opacity: 1;
}
100% {
-webkit-transform: translate(-50%, -40%);
}
}
@keyframes cloud {
0% {
transform: translate(-50%, -50%);
}
40% {
opacity: 1;
}
60% {
opacity: 1;
}
100% {
transform: translate(-50%, -40%);
}
}
</style>
sign.vue
html
<template>
<div class="login-container">
<div class="layer"></div>
<div id="particles-js"></div>
<div class="some-space">
<div class="form">
<h2>用户登录/注册</h2>
<div class="item">
<i class="icon-user"></i>
<input type="text" v-model="form.username" placeholder="请输入用户名" class="input" />
</div>
<div class="item">
<i class="icon-lock"></i>
<input type="password" v-model="form.password" placeholder="请输入密码" class="input" />
</div>
<div class="item">
<i class="icon-lock"></i>
<input type="password" v-model="form.confirmPassword" placeholder="请再次输入密码" class="input" />
</div>
<button @click="register" class="loginBtn">注册</button>
<button @click="getUser" class="loginBtn">登录</button>
<div class="tip">温馨提示:请按照要求填写信息哦~</div>
</div>
</div>
</div>
</template>
<script>
import { getUserInfo, register } from '../api/user';
export default {
data() {
return {
form: {
username: '',
password: '',
confirmPassword: ''
},
userInfo: {}
};
},
methods: {
getUser() {
getUserInfo(this.form.username).then(res => {
this.userInfo = res.data.data[0];
}).catch((err) => {
console.log(err);
});
},
register() {
if (
this.form.username === '' ||
this.form.password === '' ||
this.form.confirmPassword === ''
) {
alert('数据不能为空');
return;
}
// 验证两次输入的密码是否一致
if (this.form.password!== this.form.confirmPassword) {
alert('两次输入的密码不一致,请重新输入');
return;
}
register({
username: this.form.username,
password: this.form.password
})
.then((res) => {
alert(res.data.msg);
this.$router.push('/');
})
.catch((err) => {
alert(err.response.data.msg);
});
}
}
};
</script>
<style lang="scss" scoped>
.login-container {
.layer {
position: absolute;
height: 100%;
width: 100%;
background-image: url('../assets/bg-4.jpg');
background-size: cover;
background-repeat: no-repeat;
}
#particles-js {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
}
.some-space {
color: white;
font-weight: 100;
letter-spacing: 2px;
position: absolute;
top: 50%;
left: 50%;
z-index: 1001;
-webkit-transform: translate3d(-50%, -50%, 0);
transform: translate3d(-50%, -50%, 0);
-ms-animation: cloud 2s 3s ease-in infinite alternate;
-moz-animation: cloud 2s 3s ease-in infinite alternate;
-webkit-animation: cloud 2s 3s ease-in infinite alternate;
-o-animation: cloud 2s 3s ease-in infinite alternate;
animation: cloud 2s 3s ease-in infinite alternate;
.form {
width: 460px;
height: auto;
background: rgba(36, 36, 85, 0.5);
margin: 0 auto;
padding: 35px 30px 25px;
box-shadow: 0 0 25px rgba(255, 255, 255, 0.5);
border-radius: 10px;
.item {
display: flex;
align-items: center;
margin-bottom: 25px;
border-bottom: 1px solid #d3d7f7;
i {
color: #d3d7f7;
margin-right: 10px;
}
}
h2 {
text-align: center;
font-weight: normal;
font-size: 26px;
color: #d3d7f7;
padding-bottom: 35px;
}
.input {
font-size: 16px;
line-height: 30px;
width: 100%;
color: #d3d7f7;
outline: none;
border: none;
background-color: rgba(0, 0, 0, 0);
padding: 10px 0;
}
.loginBtn {
width: 100%;
padding: 12px 0;
border: 1px solid #d3d7f7;
font-size: 16px;
color: #d3d7f7;
cursor: pointer;
background: transparent;
border-radius: 4px;
margin-top: 10px;
&:hover {
color: #fff;
background: #0090ff;
border-color: #0090ff;
}
}
// 注册按钮样式,与登录按钮样式保持一致
.registerBtn {
width: 100%;
padding: 12px 0;
border: 1px solid #d3d7f7;
font-size: 16px;
color: #d3d7f7;
cursor: pointer;
background: transparent;
border-radius: 4px;
margin-top: 10px;
&:hover {
color: #fff;
background: #0090ff;
border-color: #0090ff;
}
}
.tip {
font-size: 12px;
padding-top: 20px;
}
}
}
}
input::-webkit-input-placeholder {
color: #d3d7f7;
}
input::-moz-placeholder {
/* Mozilla Firefox 19+ */
color: #d3d7f7;
}
input:-moz-placeholder {
/* Mozilla Firefox 4 to 18 */
color: #d3d7f7;
}
input:-ms-input-placeholder {
/* Internet Explorer 10-11 */
color: #d3d7f7;
}
@-ms-keyframes cloud {
0% {
-ms-transform: translate(-50%, -50%);
}
40% {
opacity: 1;
}
60% {
opacity: 1;
}
100% {
-ms-transform: translate(-50%, -40%);
}
}
@-moz-keyframes cloud {
0% {
-moz-transform: translate(-50%, -50%);
}
40% {
opacity: 1;
}
60% {
opacity: 1;
}
100% {
-moz-transform: translate(-50%, -40%);
}
}
@-o-keyframes cloud {
0% {
-o-transform: translate(-50%, -50%);
}
40% {
opacity: 1;
}
60% {
opacity: 1;
}
100% {
-o-transform: translate(-50%, -40%);
}
}
@-webkit-keyframes cloud {
0% {
-webkit-transform: translate(-50%, -50%);
}
40% {
opacity: 1;
}
60% {
opacity: 1;
}
100% {
-webkit-transform: translate(-50%, -40%);
}
}
@keyframes cloud {
0% {
transform: translate(-50%, -50%);
}
40% {
opacity: 1;
}
60% {
opacity: 1;
}
100% {
transform: translate(-50%, -40%);
}
}
</style>
index.js
javascript
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter);
const routes = [
{
path: '/',
name: 'Home',
component: () => import('@/views/Home.vue'),
meta: {
title: '登录界面'
}
},
{
path: '/login',
redirect: '/'
},
{
path: '/about',
name: 'About',
component: () => import('@/views/About.vue'),
}
];
const router = new VueRouter({
routes,
});
export default router;
app.js
javascript
const express = require('express');
const bodyParser = require('body-parser');
const multiparty = require('connect-multiparty');
const fs = require('fs');
let { conMysql } = require('./mysql');
// 创建统一的返回报文对象
class Response {
constructor(isSucceed, msg, code, data) {
this.isSucceed = isSucceed;
this.msg = msg;
this.code = code;
this.data = data;
}
}
// 创建
const app = express();
// 处理 x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }));
// 处理 application/json
app.use(bodyParser.json());
// 处理 multipart/form-data
app.use(multiparty());
// 设置跨域访问
const cors = require('cors');
app.use(cors());
// 测试接口能否正常调用
app.get('/info', (req, res) => {
res.send('Hello shaoyahu!');
});
// 测试数据库连接是否正常
app.get('/getUser', (req, res) => {
let sql = 'select * from userinfo';
conMysql(sql).then(result => {
res.send(result);
});
});
// 登录
app.post('/login', (req, res) => {
let sql = `select * from userinfo where username = '${req.body.username}'`;
conMysql(sql).then(result => {
if (result[0]?.password === req.body.password) {
let response = new Response(true, '登录成功', 200, result);
res.send(response);
} else {
let response = new Response(false, '用户名或密码错误', 400);
res.status(400).send(response);
}
}).catch(err => {
res.status(500).send('数据库连接出错!');
});
});
// 修改密码
app.post('/updatePassword', (req, res) => {
let sql = `update userinfo set password = '${req.body.newPassword}' where username = '${req.body.username}'`;
conMysql(sql).then(result => {
if (result.affectedRows == 1) {
let response = new Response(true, '修改成功', 200, result);
res.send(response);
} else {
let response = new Response(false, '修改失败,请稍后重试', 400);
res.status(400).send(response);
}
}).catch(err => {
res.status(500).send('数据库连接出错!');
});
});
// 用户注册接口
app.post('/register', (req, res) => {
const { username, password } = req.body;
// 简单的合法性校验,用户名和密码都不能为空
if (!username ||!password) {
let response = new Response(false, '用户名和密码不能为空', 400);
res.status(400).send(response);
return;
}
// 检查用户名是否已存在
let checkSql = `select * from userinfo where username = '${username}'`;
conMysql(checkSql).then(existResult => {
if (existResult.length > 0) {
let response = new Response(false, '用户名已存在,请更换用户名', 400);
res.status(400).send(response);
return;
}
// 插入新用户信息到数据库
let insertSql = `insert into userinfo (username, password) values ('${username}', '${password}')`;
conMysql(insertSql).then(insertResult => {
if (insertResult.affectedRows === 1) {
let response = new Response(true, '注册成功', 200, insertResult);
res.send(response);
} else {
let response = new Response(false, '注册失败,请稍后重试', 400);
res.status(400).send(response);
}
}).catch(err => {
res.status(500).send('数据库连接出错!');
});
}).catch(err => {
res.status(500).send('数据库连接出错!');
});
});
// 获取当前用户信息
app.get('/getUserInfo', (req, res) => {
let sql = `select * from userinfo where username = '${req.query.username}'`;
conMysql(sql).then(result => {
let response = new Response(true, '获取成功', 200, result);
res.send(response);
}).catch(err => {
res.status(500).send('数据库连接出错!');
});
});
// 生成文件的接口
app.get('/generateFile', async (req, res) => {
try {
let sql = 'select * from userinfo';
const result = await conMysql(sql);
const dataString = JSON.stringify(result, null, 2);
fs.writeFileSync('userinfo.json', dataString);
let response = new Response(true, '文件生成成功', 200, null);
res.send(response);
} catch (err) {
res.status(500).send('数据库连接出错或文件生成失败!');
}
});
// 启动
app.listen(3000, () => {
console.log('express server running at http://127.0.0.1:' + 3000);
});
mysql.js
javascript
let mysql = require('mysql')
const db_config = {
host: 'localhost',
user: 'root',
password: 'mysql',
port: '3306',
database: 'db1'
}
function conMysql(sql) {
let connect = mysql.createConnection(db_config)
// 开始连接数据库
connect.connect(function (err) {
if (err) {
console.log(`mysql连接失败: ${err}!`)
} else {
console.log('mysql连接成功!')
}
})
return new Promise((resolve, reject) => {
connect.query(sql, (err, result) => {
if (err) {
reject(err)
} else {
let res = JSON.parse(JSON.stringify(result))
closeMysql(connect)
resolve(res)
}
})
})
}
// 查询成功后关闭mysql
function closeMysql(connect) {
connect.end((err) => {
if (err) {
console.log(`mysql关闭失败:${err}!`)
} else {
console.log('mysql关闭成功!')
}
})
}
exports.conMysql = conMysql
要注意对应版本和环境
记得添加对应下载环境包
javascript
{
"name": "express",
"version": "1.0.0",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.20.0",
"connect-multiparty": "^2.2.0",
"cors": "^2.8.5",
"express": "^4.18.1",
"mysql": "^2.18.1"
},
"devDependencies": {
"babel-preset-env": "^1.7.0"
},
"description": ""
}
第三部进pnpm命令安装和运行------效果展示






