简单实现后台管理功能
- 1.创建管理员登录界面
- ①编辑首页html文件,admin-login.html(应用bootstrap中的样式)
- ②增加学生界面 add-students.html
- ③ 编辑学生界面 edit-student.html
- 2.前端监控文件
- ①index.js
- 3.编辑后台文件
- ①中枢文件app.js
- ②路由文件router.js
- 编辑仿数据库文件
- ①admin.json 存储管理员数据
- ②jurisdiction.json
- ③students.json 存储学生数据
1.创建管理员登录界面
①编辑首页html文件,admin-login.html(应用bootstrap中的样式)
<!doctype html>
<html lang="EN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>Welcome administrator login</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="../public/css/public.css">
</head>
<body>
<header class="container-fluid">
<div class="container">
<div class="row">
<h1 class="col-md-12">Welcome administrator login</h1>
</div>
</div>
</header>
<div class="container" id="loginInput">
<div class="row">
<div class="col-xs-8 col-xs-offset-2 ">
{{if isNotLogin}}
<p class="text-danger">账号密码错误,请重新输入</p>
{{/if}}
<form class="form-horizontal" method="post" action="/admin-login">
<div class="form-group">
<label for="account" class="col-sm-2 control-label">Account</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="account" name="account" placeholder="Account">
<p id="p1" class="text-danger hidden">手机号格式错误</p>
<p id="p2" class="text-danger hidden">账号未注册</p>
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-2 control-label">Password</label>
<div class="col-sm-10">
<input type="password" class="form-control" id="password" name="password" placeholder="Password">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox" name="remember"> Remember me
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Sign in</button>
</div>
</div>
</form>
</div>
</div>
</div>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="../public/js/login.js"></script>
</body>
</html>
②增加学生界面 add-students.html
<!DOCTYPE html>
<html lang="EN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>Welcome administrator login</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="../public/css/public.css">
<style>
#center{height: 600px;background: #fff}
</style>
</head>
<body>
<header class="container-fluid">
<div class="container">
<div class="row">
<h1 class="col-md-12">欢迎尊贵的{{result.admin.isSuperAdmin?"超级":""}}管理员</h1>
</div>
</div>
</header>
<div class="container" id="center" >
<div class="row">
<div class="col-sm-2 bg-success" >
<ul>
{{each result.jurisdictionResult}}
<li><a href="{{$value.path}}">{{$value.name}}</a></li>
{{/each}}
</ul>
</div>
<div class="col-sm-10 bg-warning" >
<form action="/add-students" method="get">
姓名 <input type="text" name="name"><br>
性别 <input type="radio" name="gender" value="1" checked>男
<input type="radio" name="gender" value="0">女<br>
birth<input type="text" name="birth"><br>
手机号<input type="text" name="account"><br>
期望薪资<input type="text" name="salary"><br>
<button type="submit">提交</button>
</form>
</div>
</div>
</div>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="../public/js/login.js"></script>
</body>
</html>
③ 编辑学生界面 edit-student.html
<!DOCTYPE html>
<html lang="EN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>Welcome administrator login</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="../public/css/public.css">
<style>
#center{height: 600px;background: #fff}
</style>
</head>
<body>
<header class="container-fluid">
<div class="container">
<div class="row">
<h1 class="col-md-12">欢迎尊贵的{{result.admin.isSuperAdmin?"超级":""}}管理员</h1>
</div>
</div>
</header>
<div class="container" id="center" >
<div class="row">
<div class="col-sm-2 bg-success" >
<ul>
{{each result.jurisdictionResult}}
<li><a href="{{$value.path}}">{{$value.name}}</a> </li>
{{/each}}
</ul>
</div>
<div class="col-sm-10 bg-warning" >
<form action="/edit-student" method="get">
<input type="hidden" name="id" value="{{result.student.id}}">
姓名 <input type="text" name="name" value="{{result.student.name}}"><br>
性别 <input type="radio" {{result.student.gender==1?'checked':''}} name="gender" value="1" >男
<input type="radio" {{result.student.gender==0?'checked':''}} name="gender" value="0">女<br>
birth<input type="text" name="birth" value="{{result.student.birth}}"><br>
手机号<input type="text" name="account" value="{{result.student.account}}"><br>
期望薪资<input type="text" name="salary" value="{{result.student.salary}}"><br>
<button type="submit">提交</button>
</form>
</div>
</div>
</div>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="../node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
</body>
</html>
2.前端监控文件
①index.js
const isSubmit={
account: false
}
const test_account=()=>{
/*
if($('#account').val()是手机号){
去掉"手机号格式错误"提示
提交给后端,后端判断是否是已注册账号
if(是){
}else{
提示:手机号未注册
}
}else{
提示:手机号格式错误
}
*/
/*手机号:11位,数字1开头,13[0-9],14[]*/
// 正则表达式 13312341234
const reg_phone=/^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
$('#p2').addClass('hidden')
if(reg_phone.test($('#account').val())){
$('#p1').addClass('hidden')
//提交给后端验证是否登录
$.get('/test-account',{account:$('#account').val()},data=>{
if(data){
$('#p2').addClass('hidden')
isSubmit.account=true
}else{
$('#p2').removeClass('hidden')
isSubmit.account=false
}
})
}else{
isSubmit.account=false
$('#p1').removeClass('hidden')
}
}
$('#account').blur(test_account)
$('form').submit(()=> {
/* if(isSubmit.account&&isSubmit.password){
return true
}else{
return false
}*/
// test_account()
// return isSubmit.account&&isSubmit.password
if(isSubmit.account){
return true
}
test_account()
return isSubmit.account
})
3.编辑后台文件
①中枢文件app.js
const express=require('express')
const session=require('express-session')
const router=require('./router')
//引入路由router
const app=express()
app.engine('html',require('express-art-template'))
app.use(express.urlencoded({extended: false}))
app.use(express.json())
//开放公共资源
app.use('/public',express.static('./public'))
app.use('/node_modules',express.static('./node_modules'))
app.use(session({
secret:"dsafsafsf", //设置签名秘钥 内容可以任意填写
cookie:{maxAge:10*1000}, //设置cookie的过期时间,例:80s后session和相应的cookie失效过期
resave:true, //强制保存,如果session没有被修改也要重新保存
saveUninitialized:false, //如果原先没有session那么久设置,否则不设置
rolling:true
}))
//路由
app.use(router)//
app.listen(3000,()=>console.log('app is running...'))
②路由文件router.js
const express=require('express')
const fs=require('fs')
const router=express.Router()
//引入router
router.get('/admin-login.html',(req,res)=>{
res.render('admin-login.html')
})
router.get('/test-account',(req,res)=>{
fs.readFile('data/admins.json',(err,data)=>{
if(err){
console.log(err)
return
}
res.send(Boolean(JSON.parse(data).find(value=>value.account==req.query.account)))
})
})
router.get('/admin-show-students.html',(req,res)=>{
// 验证是否有session
if(req.session.admin){
//读学生文件,并且发送给前端
fs.readFile('data/students.json', (err, data) => {
if (err) throw err
const students = JSON.parse(data)
students.map(value => delete value.password)
const admin=req.session.admin,
jurisdictionResult=req.session.jurisdictionResult
const result = {admin,jurisdictionResult,students}
res.render('admin-show-students.html', {result})
})
}else{
res.render('admin-login.html' ,{isNotLogin: true})
}
})
//管理与添加学生界面
router.get('/add-students.html',(req,res)=>{
if(req.session.admin){
const result={
admin:req.session.admin,
jurisdictionResult:req.session.jurisdictionResult
}
res.render('add-students.html',{result})
}else{
res.render('admin-login.html')
}
})
//跳转编辑学生界面
router.get('/edit-student.html',(req,res)=>{
if(req.session.admin){
fs.readFile('data/students.json',(err,data)=>{
if(err) throw err
const student=JSON.parse(data)
.find(value=>value.id==req.query.id)
if(student){
delete student.password
const result={
student,
admin:req.session.admin,
jurisdictionResult:req.session.jurisdictionResult
}
res.render('edit-student.html',{result})
}
})
}else{
res.render('admin-login.html')
}
})
router.get('/edit-student',(req,res)=>{
//根据id
fs.readFile('data/students.json',(err,data)=>{
if(err) throw err
const students=JSON.parse(data)
const index=students.findIndex(value=>value.id==req.query.id)
if(index!=-1){
students[index].name=req.query.name
students[index].gender=req.query.gender
students[index].birth=req.query.birth
students[index].salary=req.query.salary
students[index].account=req.query.account
fs.writeFile(
'data/students.json',
JSON.stringify(students),
err=>{
if(err) throw err
res.send('修改成功,请返回查看')
}
)
}
else{
res.redirect('/admin-show-students.html')
}
})
})
//删除学生
router.get('/delete-student',(req,res)=>{
if(req.session.admin){
fs.readFile('data/students.json',(err,data)=>{
if(err) throw err
const students=JSON.parse(data)
const index=students.findIndex(value => value.id==req.query.id)
students.splice(index,1)
console.log(index,students)
fs.writeFile(
'data/students.json',
JSON.stringify(students),
err=>{
if(err) throw err
//res.send('删除成功,请返回查看');
res.redirect('/admin-show-students.html')
}
)
})
}else{
res.redirect('/admin-login.html')
}
})
//添加学生数据
router.get('/add-students',(req,res)=>{
if(req.session.admin) {
fs.readFile('data/students.json', (err, data) => {
if (err) throw err
const students = JSON.parse(data)
const newStudent = req.query
newStudent.id = students[students.length - 1].id + 1
newStudent.password = 123456
students.push(newStudent)
console.log(students)
fs.writeFile(
'data/students.json',
JSON.stringify(students),
err => {
if (err) throw err
res.redirect('/admin-show-students.html')
}
)
})
}
else{
res.redirect('admin-login.html')
}
})
router.post('/admin-login',(req,res)=>{
fs.readFile('data/admins.json',(err,data)=>{
if(err)throw err
const admins=JSON.parse(data)
const admin=admins.find(value=>value.account==req.body.account)
if(admin&&admin.password==req.body.password){
// 读取权限文件
fs.readFile('data/jurisdiction.json', (err, data) => {
if (err) throw err
const jurisdiction = JSON.parse(data)
// 读到之后,把普通管理员权限赋值给jurisdictionResult
const jurisdictionResult = jurisdiction.adminJurisdiction
// 如果此账户是超级管理员,则再给其额外添加超级管理员权限
if (admin.isSuperAdmin) {
// arrA.push(...arrB)
// ...是es6新语法,就是把数组B里的每个元素按序添加到数组A中
jurisdictionResult.push(...jurisdiction.superAdminJurisdiction)
}
// 删除读到的账户密码,以便于把其他信息发送给前端
delete admin.password
req.session.admin=admin
req.session.jurisdictionResult=jurisdictionResult
res.redirect('/admin-show-students.html')
})
//
}else{
res.redirect('/admin-show-students.html')
}
})
})
//查赵学生
router.get('/search-student',(req,res)=>{
if(req.session.admin){
fs.readFile('data/students.json',(err,data)=>{
if(err) throw err
const student=JSON.parse(data)
.find(value=>value.account==req.query.account)
if(student){
res.send(student)
return
}
res.send(false)
})
}else {
res.render('admin-login.html')
}
})
module.exports=router
编辑仿数据库文件
①admin.json 存储管理员数据
[
{
"id": 0,
"name": "王二小",
"gender": 1,
"account": 13963040187,
"password": "0",
"isSuperAdmin": true
},
{
"id": 1,
"name": "张三",
"gender": 1,
"account": 13210201067,
"password": "000000",
"isSuperAdmin": false
}
]
②jurisdiction.json
{
"adminJurisdiction": [
{
"id": 0,
"name": "查看学生",
"path": "/admin-show-students.html"
},
{
"id": 1,
"name": "添加学生",
"path": "/add-students.html"
}
],
"superAdminJurisdiction": [
{
"id": 2,
"name": "查看管理员",
"path": "/admin-show"
},
{
"id": 3,
"name": "添加管理员",
"path": "/bbb"
}
]
}
③students.json 存储学生数据
[
{
"id": 2,
"name": "阿龙",
"gender": "1",
"birth": "952431631000",
"account": "15500001234",
"password": 123456,
"salary": "5001"
},
{
"id": 3,
"name": "阿宁",
"gender": 0,
"birth": 952482622000,
"account": 15512340000,
"password": 123456,
"salary": 5500
},
{
"name": "咖啡",
"gender": "0",
"birth": "3000",
"account": "13312341234",
"salary": "12220",
"id": 4,
"password": 123456
},
{
"name": "蓝色-全民抗疫",
"gender": "1",
"birth": "123",
"account": "123456",
"salary": "500",
"id": 5,
"password": 123456
}
]