一、前端处理
1.概述
在之前已经将系统后端逻辑业务代码编写了部分,在此,需要实现前端页面的展示,使用到html、css、js的技术,借助vue等进阶技术展示更优化的界面。
2.前端分析
前端业务代码应当分为两部分,一部分为用户与界面的交互,另一部分为前台与后端的业务处理 。
3.运用技术
采用vue、jquery和element等技术,需要调用各自的js文件库。创建目录路径如下,部分css、js文件需要网上下载导入。
二、前端实现
1.各功能的界面
(1)用户管理user.html
需求分析
顶部:分级关系;
主体:搜索栏、数据列表、分页
源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta HTTP-EQUIV="pragma" CONTENT="no-cache">
<meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<meta HTTP-EQUIV="expires" CONTENT="0">
<title>用户管理</title>
<link rel="stylesheet" href="../../css/element.css">
<link rel="stylesheet" href="../../css/base.css">
</head>
<body>
<!--整个界面-->
<div id="wrapper" v-cloak>
<!-- 顶部 -->
<div style="padding-bottom: 10px">
<!-- separator-class指定每两个item之前用图标相隔 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<!-- “首页”绑定点击事件,触发返回首页 -->
<el-breadcrumb-item @click.native="parent.changeIndex('index')">首页</el-breadcrumb-item>
<el-breadcrumb-item>用户管理</el-breadcrumb-item>
</el-breadcrumb>
</div>
<!-- 分割线 -->
<div style="height: 1px; margin: 10px 0; background-color: white"></div>
<!-- 搜索框 -->
<div style="margin: 10px 0">
<!-- suffix-icon在输入框尾部插入,查询图标 -->
<el-input v-model="search" style="width: 20%;" suffix-icon="el-icon-search"
placeholder="请输入关键字搜索"></el-input>
<el-button @click="loadTable" type="primary" style="margin: 10px 0">查询</el-button>
<el-button @click="add" type="primary" style="margin: 10px 0">新增</el-button>
</div>
<!-- 展示列表的表头,通过data注入数据,prop取数据并填充,label定义列名 -->
<el-table :data="tableData" border style="width: 100%">
<!-- sortable指定列具备排序功能,主键 -->
<el-table-column prop="id" label="ID" width="70" sortable></el-table-column>
<!-- 基础属性 -->
<el-table-column prop="username" label="用户名"></el-table-column>
<el-table-column prop="nickName" label="昵称"></el-table-column>
<el-table-column prop="email" label="邮箱"></el-table-column>
<el-table-column prop="phone" label="电话"></el-table-column>
<el-table-column prop="age" label="年龄"></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<!-- 设置用户的权限角色,使得在此单元格内可以随意更改权限角色的权限 -->
<el-table-column label="角色">
<!-- 定义模板将权限角色读取,设置复选框供选择 -->
<template slot-scope="scope">
<el-select v-model="scope.row.role" value-key="id" multiple placeholder="请选择"
@change="changeRole(scope.row)">
<el-option v-for="item in options" :key="item.id"
:label="item.name" :value="item.id"></el-option>
</el-select>
</template>
</el-table-column>
<!-- 操作:对每条数据进行编辑及删除 -->
<el-table-column fixed="right" label="操作" width="150">
<!-- 定义模板进行操作 -->
<template slot-scope="scope">
<!-- 第一按钮,编辑 -->
<el-button type="primary" @click="edit(scope.row)" icon="el-icon-edit" circle></el-button>
<!-- 第二个按钮,删除,设置type为danger,设置二次删除确认 -->
<el-popconfirm @onConfirm="del(scope.row.id)" title="确定删除?">
<el-button type="danger" icon="el-icon-delete" circle slot="reference"></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div style="background-color: white; padding: 10px 0">
<!-- layout:组件布局,子组件名用逗号隔开;prev(上一页按钮)、page(页码)、nex(下一页按钮)、jumper(跳转)、->(空格)、total(总条目数)-->
<!-- 当前页数current-page,每页展示条目数page-size,可选每页展示条目数page-sizes-->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[5, 10, 20, 40]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
<!-- 新增用户提示框,有关闭按钮 -->
<!-- 父子组件双向绑定,实现子组件向父组件通信 -->
<el-dialog title="用户信息" :visible.sync="dialogFormVisible" width="40%"
:close-on-click-modal="false">
<el-form :model="entity">
<!-- 用户各项信息填写 -->
<el-form-item label="用户名" label-width="100px">
<el-input v-model="entity.username" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="昵称" label-width="100px">
<el-input v-model="entity.nickName" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="邮箱" label-width="100px">
<el-input v-model="entity.email" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="电话" label-width="100px">
<el-input v-model="entity.phone" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="年龄" label-width="100px">
<el-input v-model="entity.age" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="地址" label-width="100px">
<el-input v-model="entity.address" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<!-- 用户密码可不在此设置,后台判断未设定密码,将自动赋值为“123456” -->
</el-form>
<!-- 自定义按钮,1.取消;2.确定 -->
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible=false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
</div>
<script src="../../js/jquery.min.js"></script>
<script src="../../js/vue.min.js"></script>
<script src="../../js/element.js"></script>
<script src="../../js/tinymce/tinymce.min.js"></script>
<script>
// 设置路径
let urlBase = "/api/user/";
// vue接管
new Vue({
el: "#wrapper",
// 部分数据初始化
data: {
user: {},
tableData: [],
pageNum: 1,
pageSize: 10,
total: 0,
dialogFormVisible: false,
entity: {},
isCollapse: false,
search: '',
options: [],
props: [
{"label": "用户名", "prop": "username"},
{"label": "邮箱", "prop": "email"},
{"label": "电话", "prop": "phone"}
]
},
// 生命周期钩子函数
created() {
this.user = sessionStorage.getItem("user") ? JSON.parse(sessionStorage.getItem("user")) : {};
this.loadTable();
},
// 函数定义
methods: {
// 用户的权限角色改变
changeRole(row) {
this.entity = JSON.parse(JSON.stringify(row));
this.save();
},
// 请求退出接口
logout() {
$.get("/api/user/logout");
localStorage.removeItem("user");
location.href = "/page/end/login.html";
},
// 加载列表数据
loadTable() {
$.get(urlBase + "page?pageNum=" + this.pageNum + "&pageSize=" + this.pageSize + "&name=" + this.search).then(res => {
this.tableData = res.data.records;
this.total = res.data.total;
})
$.get("/api/role").then(res => {
this.options = res.data;
})
},
// 改变每页展示条目数
handleSizeChange(pageSize) {
this.pageSize = pageSize;
this.loadTable();
},
// 改变当前战术页
handleCurrentChange(pageNum) {
this.pageNum = pageNum;
this.loadTable();
},
// 添加用户
add() {
this.entity = {};
this.dialogFormVisible = true;
},
// 新增用户
save() {
// 需要用户名
if (!this.entity.username) {
this.$message({
message: "请填写用户名",
type: "warning"
})
return
}
// ajax来处理保存
let type = this.entity.id ? "PUT" : "POST";
$.ajax({
url: urlBase,
type: type,
contentType: "application/json",
data: JSON.stringify(this.entity)
}).then(res => {
if (res.code === '0') {
this.$message({
message: "保存成功",
type: "success"
});
this.loadTable();
} else {
this.$message({
message: res.msg,
type: "error"
})
}
// 保存后退出子组件
this.dialogFormVisible = false;
})
},
// 编辑,进入子组件,展示用户信息,提供编辑
edit(obj) {
this.entity = JSON.parse(JSON.stringify(obj));
this.dialogFormVisible = true;
},
// 删除用户
del(id) {
$.ajax({
url: urlBase + id,
type: "delete"
}).then(res => {
if (res.code === '0') {
this.$message({
message: "删除成功",
type: "success"
})
this.loadTable();
} else {
this.$message({
message: res.msg,
type: "error"
})
}
})
}
}
})
</script>
</body>
</html>
(2)权限角色管理Role.html
在前端需求上,用户管理、权限角色管理、功能许可管理,三者是相似的,因此直接前端代码也是近似。
源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta HTTP-EQUIV="pragma" CONTENT="no-cache">
<meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<meta HTTP-EQUIV="expires" CONTENT="0">
<title>权限角色管理</title>
<link rel="stylesheet" href="../../css/element.css">
<link rel="stylesheet" href="../../css/base.css">
</head>
<body>
<!-- 整体区域 -->
<div id="wrapper" v-cloak>
<!-- 顶部 -->
<div style="padding-bottom: 10px">
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item @click.native="parent.changeIndex('index')">首页</el-breadcrumb-item>
<el-breadcrumb-item>角色管理</el-breadcrumb-item>
</el-breadcrumb>
</div>
<!-- 分割线 -->
<div style="height: 1px; margin: 10px 0; background-color: white"></div>
<!-- 搜索栏 -->
<div style="margin: 10px 0">
<el-input v-model="search" style="width: 20%;" suffix-icon="el-icon-search" placeholder="请输入名称搜索"></el-input>
<el-button @click="loadTable" type="primary" style="margin: 10px 0">查询</el-button>
<el-button @click="add" type="primary" style="margin: 10px 0">新增</el-button>
</div>
<!-- 数据列表 -->
<el-table :data="tableData" border style="width: 100%">
<!-- 基础属性 -->
<el-table-column prop="id" label="ID" width="50"></el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="description" label="描述"></el-table-column>
<!-- 权限角色具备的许可的更改 -->
<el-table-column label="权限" width="600">
<template slot-scope="scope">
<el-button type="text" @click="setPer(scope.row)">权限设置</el-button>
</template>
</el-table-column>
<!-- 每行数据的操作,编辑、删除 -->
<el-table-column fixed="right" label="操作" width="150">
<template slot-scope="scope">
<el-button type="primary" @click="edit(scope.row)" icon="el-icon-edit" circle ></el-button>
<el-popconfirm @onConfirm="del(scope.row.id)" title="确定删除?">
<el-button type="danger" icon="el-icon-delete" circle slot="reference" ></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div style="background-color: white">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[5, 10, 20, 40]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
<!-- 新增权限角色 -->
<el-dialog title="角色信息" :visible.sync="dialogFormVisible" width="40%" :close-on-click-modal="false" >
<el-form :model="entity">
<el-form-item label="名称" label-width="120px">
<el-input v-model="entity.name" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="描述" label-width="120px">
<el-input v-model="entity.description" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
<!-- 编辑权限角色的功能许可 -->
<el-dialog title="权限菜单" :visible.sync="vis" width="40%" :close-on-click-modal="false" >
<el-form :model="entity" style="width: 80%; margin: 0 auto; line-height: 40px">
<el-checkbox-group v-model="entity.permission" >
<el-checkbox :label="item.id" v-for="item in options" :key="item.id">{{ item.name }}</el-checkbox>
</el-checkbox-group>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="vis = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
</div>
<script src="../../js/jquery.min.js"></script>
<script src="../../js/vue.min.js"></script>
<script src="../../js/element.js"></script>
<script src="../../js/tinymce/tinymce.min.js"></script>
<script>
let urlBase = "/api/role/";
new Vue({
el: "#wrapper",
data: {
user: {},
tableData: [],
pageNum: 1,
pageSize: 10,
total: 0,
dialogFormVisible: false,
entity: {},
isCollapse: false,
search: '',
options: [],
vis: false
},
created() {
this.user = sessionStorage.getItem("user") ? JSON.parse(sessionStorage.getItem("user")) : {};
this.loadTable();
},
methods: {
// 设置权限
setPer(obj) {
this.entity = JSON.parse(JSON.stringify(obj))
this.vis = true;
},
// 退出
logout() {
$.get("/api/user/logout");
sessionStorage.removeItem("user");
location.href = "/page/end/login.html";
},
// 加载数据
loadTable() {
$.get(urlBase + "page?pageNum=" + this.pageNum + "&pageSize=" + this.pageSize + "&name=" + this.search).then(res => {
this.tableData = res.data.records;
this.total = res.data.total;
});
$.get("/api/permission").then(res => {
this.options = res.data;
})
},
// 页面大小更改
handleSizeChange(pageSize) {
this.pageSize = pageSize;
this.loadTable();
},
// 当前页更改
handleCurrentChange(pageNum) {
this.pageNum = pageNum;
this.loadTable();
},
// 添加权限用户
add() {
this.entity = {};
this.dialogFormVisible = true;
},
// 保存
save() {
let type = this.entity.id ? "PUT" : "POST";
$.ajax({
url: urlBase,
type: type,
contentType: "application/json",
data: JSON.stringify(this.entity)
}).then(res => {
if (res.code === '0') {
this.$message({
message: "保存成功",
type: "success"
});
this.loadTable();
} else {
this.$message({
message: res.msg,
type: "error"
})
}
// 退出子组件
this.dialogFormVisible = false;
this.vis = false;
// 重新请求用户基础数据
$.get("/api/user/detail/" + this.user.username).then(res => {
this.user = res.data;
sessionStorage.setItem("user", JSON.stringify(this.user));
parent.call()
})
})
},
// 编辑
edit(obj) {
this.entity = JSON.parse(JSON.stringify(obj));
this.dialogFormVisible = true;
},
// 删除
del(id) {
$.ajax({
url: urlBase + id,
type: "delete"
}).then(res => {
if (res.code === '0') {
this.$message({
message: "删除成功",
type: "success"
})
this.loadTable();
} else {
this.$message({
message: res.msg,
type: "error"
})
}
})
},
}
})
</script>
</body>
</html>
(3)权限许可管理Permission.html
源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta HTTP-EQUIV="pragma" CONTENT="no-cache">
<meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<meta HTTP-EQUIV="expires" CONTENT="0">
<title>权限许可管理</title>
<link rel="stylesheet" href="../../css/element.css">
<link rel="stylesheet" href="../../css/base.css">
</head>
<body>
<!-- 整体区域 -->
<div id="wrapper" v-cloak>
<!-- 顶部 -->
<div style="padding-bottom: 10px">
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item @click.native="parent.changeIndex('index')">首页</el-breadcrumb-item>
<el-breadcrumb-item>权限管理</el-breadcrumb-item>
</el-breadcrumb>
</div>
<!-- 分割线 -->
<div style="height: 1px; margin: 10px 0; background-color: white"></div>
<!-- 数据列表 -->
<el-input v-model="search" style="width: 20%;" suffix-icon="el-icon-search" placeholder="请输入名称按回车搜索" @keyup.enter.native="loadTable"></el-input>
<el-button @click="add" type="primary" style="margin: 10px 0">新增</el-button>
<el-table :data="tableData" border style="width: 100%">
<!-- 表头 -->
<el-table-column prop="id" label="ID" width="50"></el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="description" label="描述"></el-table-column>
<el-table-column prop="path" label="菜单路径"></el-table-column>
<el-table-column prop="icon" label="图标"></el-table-column>
<!--操作,编辑、删除-->
<el-table-column fixed="right" label="操作" width="150">
<template slot-scope="scope">
<el-button type="primary" @click="edit(scope.row)" icon="el-icon-edit" circle ></el-button>
<el-popconfirm @onConfirm="del(scope.row.id)" title="确定删除?">
<el-button type="danger" icon="el-icon-delete" circle slot="reference" ></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div style="background-color: white">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[5, 10, 20, 40]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
<!-- 添加 -->
<el-dialog title="权限信息" :visible.sync="dialogFormVisible" width="40%" :close-on-click-modal="false" >
<!-- 基础属性 -->
<el-form :model="entity">
<el-form-item label="名称" label-width="120px">
<el-input v-model="entity.name" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="描述" label-width="120px">
<el-input v-model="entity.description" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="菜单路径" label-width="120px">
<el-input v-model="entity.path" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="图标" label-width="120px">
<el-input v-model="entity.icon" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
</el-form>
<!-- 与否按钮 -->
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
</div>
<script src="../../js/jquery.min.js"></script>
<script src="../../js/vue.min.js"></script>
<script src="../../js/element.js"></script>
<script src="../../js/tinymce/tinymce.min.js"></script>
<script>
let urlBase = "/api/permission/";
new Vue({
el: "#wrapper",
data: {
user: {},
tableData: [],
pageNum: 1,
pageSize: 10,
total: 0,
dialogFormVisible: false,
entity: {},
isCollapse: false,
search: '',
},
created() {
this.user = sessionStorage.getItem("user") ? JSON.parse(sessionStorage.getItem("user")) : {};
this.loadTable();
},
methods: {
// 退出
logout() {
$.get("/api/user/logout");
sessionStorage.removeItem("user");
location.href = "/page/end/login.html";
},
// 加载数据
loadTable() {
$.get(urlBase + "page?pageNum=" + this.pageNum + "&pageSize=" + this.pageSize + "&name=" + this.search).then(res => {
this.tableData = res.data.records;
this.total = res.data.total;
})
},
handleSizeChange(pageSize) {
this.pageSize = pageSize;
this.loadTable();
},
handleCurrentChange(pageNum) {
this.pageNum = pageNum;
this.loadTable();
},
add() {
this.entity = {};
this.dialogFormVisible = true;
},
save() {
let type = this.entity.id ? "PUT" : "POST";
$.ajax({
url: urlBase,
type: type,
contentType: "application/json",
data: JSON.stringify(this.entity)
}).then(res => {
if (res.code === '0') {
this.$message({
message: "保存成功",
type: "success"
});
this.loadTable();
} else {
this.$message({
message: res.msg,
type: "error"
})
}
this.dialogFormVisible = false;
// 重新请求用户基础数据
$.get("/api/user/detail/" + this.user.username).then(res => {
this.user = res.data;
sessionStorage.setItem("user", JSON.stringify(this.user));
parent.call()
})
})
},
edit(obj) {
this.entity = JSON.parse(JSON.stringify(obj));
this.dialogFormVisible = true;
},
del(id) {
$.ajax({
url: urlBase + id,
type: "delete"
}).then(res => {
if (res.code === '0') {
this.$message({
message: "删除成功",
type: "success"
});
// 重新请求用户基础数据
$.get("/api/user/detail/" + this.user.username).then(res => {
this.user = res.data;
console.log(this.user)
sessionStorage.setItem("user", JSON.stringify(this.user));
})
} else {
this.$message({
message: res.msg,
type: "error"
})
}
this.loadTable();
// 重新请求用户基础数据
$.get("/api/user/detail/" + this.user.username).then(res => {
this.user = res.data;
sessionStorage.setItem("user", JSON.stringify(this.user));
parent.call()
})
})
}
}
})
</script>
</body>
</html>
2.登录及注册界面
(1)登录界面login.html
需求分析
一个系统登录界面,简单点就是验证用户输入的信息与库中数据的对比,在用户量较少的情况下,登录输入框就可以简单地设置为——用户名、密码。同时应该提供给用户注册账号的功能。
源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta HTTP-EQUIV="pragma" CONTENT="no-cache">
<meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<meta HTTP-EQUIV="expires" CONTENT="0">
<title>登录</title>
<link rel="stylesheet" href="../../css/base.css">
<link rel="stylesheet" href="../../css/element.css">
</head>
<body style="background:url('../../images/bg.jpg') no-repeat; background-size: cover;">
<!-- 整体区域 -->
<div id="wrapper">
<!-- 登录框区域 -->
<div style="width: 400px; margin: 120px auto; background-color:rgba(100,149,237,0.5); border-radius: 10px">
<!-- 头 -->
<div style="width: 100%; height: 100px; font-size: 30px;line-height: 100px; text-align: center; color: #eee">欢迎登录</div>
<!-- 输入框 -->
<div style="margin-top: 25px; width: 100%; height: 320px;">
<div style="width: 60%; margin: 0 auto">
<!-- 用户名 -->
<input v-model="user.username" type="text"
style="border: 1px solid #ccc; height: 40px;
padding: 10px; width: 100%" placeholder="请输入账号" @keyup.enter="login">
<!-- 密码 -->
<input v-model="user.password" type="password"
style="border: 1px solid #ccc; height: 40px; padding: 10px; width: 100%; margin-top: 25px"
placeholder="请输入密码" @keyup.enter="login">
<!-- 登录按钮 -->
<button @click="login" style="height: 40px; padding: 10px; width: 100%; margin-top: 25px;
background-color: mediumseagreen; color: white">登录</button>
<!-- 注册按钮 -->
<a style="width: 100%; text-align: right; display: inline-block; margin-top: 25px;
color: #eee" href="register.html">还没账号?去注册</a>
</div>
</div>
</div>
</div>
<script src="../../js/jquery.min.js"></script>
<script src="../../js/vue.min.js"></script>
<script src="../../js/element.js"></script>
<script src="../../js/gVerify.js"></script>
<script>
new Vue({
el: "#wrapper",
data: {
user: {}
},
methods: {
// 登录
login() {
// 名字不为空
if (!this.user.username) {
this.$message({
message: "请输入用户名",
type: "error"
});
return;
}
// 密码不为空
if (!this.user.password) {
this.$message({
message: "请输入密码",
type: "error"
});
return;
}
// ajax判断登录账号密码的正确
$.ajax({
url: "/api/user/login",
type: "POST",
contentType: "application/json",
data: JSON.stringify(this.user)
}).then(res => {
if (res.code === '0') {
this.$message({
message: "登录成功",
type: "success"
});
sessionStorage.setItem("user", JSON.stringify(res.data));
setTimeout(() => {
location.href = "/page/end/frame.html"
}, 1000)
} else {
this.$message({
message: res.msg,
type: "error"
})
}
})
}
}
})
</script>
</body>
</html>
(2)注册界面register.html
需求分析
注册界面面向用户就是让用户注册一个登录系统的账号,而对于系统来说就是创建一个新的user表的数据,因此,用户不仅需要输入想要的用户名、密码,还需要为系统提供应有的信息:邮箱email、电话phone。
源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta HTTP-EQUIV="pragma" CONTENT="no-cache">
<meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<meta HTTP-EQUIV="expires" CONTENT="0">
<title>注册</title>
<link rel="stylesheet" href="../../css/base.css">
<link rel="stylesheet" href="../../css/element.css">
</head>
<body style="background:url('../../images/bg.jpg') no-repeat; background-size: cover;">
<!-- 整体区域 -->
<div id="wrapper">
<div style="width: 400px; margin: 120px auto;background-color:rgba(100,149,237,0.5); border-radius: 10px">
<!-- 头部 -->
<div style="width: 100%; height: 100px; color: #eee; font-size: 30px;line-height: 100px; text-align: center">
欢迎注册
</div>
<div style="margin-top: 25px; width: 100%; height: 350px; text-align: center">
<!-- 各信息输入框 -->
<input v-model="user.username" type="text"
style="border: 1px solid #ccc; height: 40px; padding: 10px; width: 60%"
placeholder="请输入账号"
>
<input v-model="user.password" type="password"
style="border: 1px solid #ccc; height: 40px; padding: 10px; width: 60%; margin-top: 20px"
placeholder="请输入密码"
>
<input v-model="user.email" type="text"
style="border: 1px solid #ccc; height: 40px; padding: 10px; width: 60%; margin-top: 20px"
placeholder="请输入邮箱"
>
<input v-model="user.phone" type="text"
style="border: 1px solid #ccc; height: 40px; padding: 10px; width: 60%; margin-top: 20px"
placeholder="请输入电话"
@keyup.enter="register"
>
<!-- 注册按钮 -->
<button @click="register"
style="height: 40px; padding: 10px; width: 60%; margin-top: 25px; background-color: steelblue; color: white"
>注册
</button>
<!-- 跳转登录 -->
<div style="margin-top: 25px">
<a style="width: 60%; text-align: right; display: inline-block; color: #eee"
href="login.html">已有账号,去登录</a>
</div>
</div>
</div>
</div>
<script src="../../js/jquery.min.js"></script>
<script src="../../js/vue.min.js"></script>
<script src="../../js/element.js"></script>
<script>
new Vue({
el: "#wrapper",
data: {
user: {}
},
methods: {
// 注册
register() {
// 用户名和密码不能为空
if (!this.user.username) {
this.$message({
message: "请输入用户名",
type: "error"
});
return;
}
if (!this.user.password) {
this.$message({
message: "请输入密码",
type: "error"
});
return;
}
$.ajax({
url: "/api/user/register",
type: "POST",
contentType: "application/json",
data: JSON.stringify(this.user)
}).then(res => {
if (res.code === '0') {
this.$message({
message: "注册成功",
type: "success"
});
sessionStorage.setItem("user", JSON.stringify(res.data));
setTimeout(() => {
location.href = "/page/end/login.html"
}, 1000)
} else {
this.$message({
message: res.msg,
type: "error"
})
}
})
}
}
})
</script>
</body>
</html>
3.系统主界面及首页
(1)需求分析
对于一个系统,应当将整个界面进行划分以便安排展示界面;在系统顶部,在左侧提供一个图标标识系统,同时能够方便用户快速返回首页,而在右侧,则是展示用户的个人部分信息,同时提供用户去往个人信息或是退出的功能。
(2)整体界面frame.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta HTTP-EQUIV="pragma" CONTENT="no-cache">
<meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<meta HTTP-EQUIV="expires" CONTENT="0">
<title>后台管理</title>
<link rel="stylesheet" href="../../css/element.css">
<link rel="stylesheet" href="../../css/base.css">
</head>
<body>
<!-- 整体区域 -->
<div id="wrapper" v-cloak>
<el-container>
<el-aside :width="isCollapse ? '64px' : '200px'"
style="background-color: black; transition:width .5s; min-height: 100vh">
<!-- 左上角标志,绑定点击事件为回到首页 -->
<div style="background-color: black; height: 60px; line-height: 60px; text-align: center;color: white; font-size: 20px;">
<transition name="el-fade-in-linear">
<span id="fade" v-show="!isCollapse"><a href="/page/end/frame.html">Megumi</a></span>
</transition>
</div>
<!-- 侧边栏菜单 -->
<el-menu style="border: none;" background-color="black" text-color="#fff" active-text-color="#ffd04b"
:default-active="src" @select="handleSelect" :collapse="isCollapse">
<!-- 首页 -->
<el-menu-item index="index">
<i class="el-icon-data-line"></i>
<span slot="title">首页</span>
</el-menu-item>
<!-- 根据用户的权限角色所持有的功能许可在侧边展示功能 -->
<el-menu-item :index="item.path" v-for="item in user.permission">
<!-- 图标 -->
<i :class=`el-icon-${item.icon}`></i>
<!-- 名称 -->
<span slot="title">{{item.name}}</span>
</el-menu-item>
</el-menu>
</el-aside>
<el-container>
<el-header style="background-color: black; line-height: 60px; color: white;">
<el-row>
<!-- 侧边栏缩放,图标按钮 -->
<el-col :span="1">
<i style="font-size: 22px; cursor: pointer" :class="[isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold']" @click="handleCollapse"></i>
</el-col>
<!-- 右上角当前登录系统的用户的个人信息 -->
<el-col :span="23" style="text-align: right">
<el-dropdown placement="bottom-end" @command="handleDropdownCommand">
<!-- 用户昵称及头像 -->
<div style="cursor:pointer;display:flex;flex-direction: row;margin-right: 20px;align-items: center;">
<span style="color: white; margin-right: 8px;font-size: 1.05rem;">{{user.nickName}}</span>
<img :src=`/files/${user.avatar}` style="width: 40px; height: 40px; border-radius: 50%">
</div>
<!-- 在鼠标聚焦用户昵称及头像时,出现下列选项,选择个人具体信息或用户退出系统 -->
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click="handleSelect('person')" command="person">个人信息</el-dropdown-item>
<el-dropdown-item @click="logout" command="logout">退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-col>
</el-row>
</el-header>
<!-- 主体区域 -->
<el-main>
<iframe id="myIframe" :src="src + '.html?new=' + Math.random()" frameborder="0" scrolling="no" style="width: 100%"></iframe>
</el-main>
</el-container>
</el-container>
</div>
<script src="../../js/jquery.min.js"></script>
<script src="../../js/vue.min.js"></script>
<script src="../../js/element.js"></script>
<script>
// 请求用户信息
function call() {
vm.user = JSON.parse(sessionStorage.getItem("user"))
}
// 回到首页
function changeIndex(index) {
vm.src = index
location.search = "target=" + index
window.setInterval("reinitIframe()", 50);
}
// 实现 iframe 高度自适应
function reinitIframe() {
const iframe = document.getElementById("myIframe");
try {
const bHeight = iframe.contentWindow.document.body.scrollHeight;
const dHeight = iframe.contentWindow.document.documentElement.scrollHeight;
iframe.height = Math.max(bHeight, dHeight, (window.innerHeight - 105));
} catch (ex) {
}
}
window.setInterval("reinitIframe()", 50);
let vm = new Vue({
el: "#wrapper",
data: {
src: 'index',
active: 0,
user: {},
isCollapse: false,
},
created() {
this.user = sessionStorage.getItem("user") ? JSON.parse(sessionStorage.getItem("user")) : {};
if (location.search) {
this.src = getUrlParamValue('target')
}
},
methods: {
handleSelect(key) {
this.src = key
location.search = "target=" + this.src
window.setInterval("reinitIframe()", 50);
},
handleDropdownCommand(command) {
if (command === "person") {
this.handleSelect('person')
}
if (command === "logout") {
this.logout()
}
},
handleCollapse() {
this.isCollapse = !this.isCollapse;
},
logout() {
$.get("/api/user/logout");
sessionStorage.removeItem("user");
location.href = "/page/end/login.html";
}
}
})
/**
* 获取url参数
* @param name
* @returns {string|null}
*/
function getUrlParamValue(name) {
if (name == null || name === 'undefined') {
return '';
}
let searchStr = decodeURI(location.search);
let infoIndex = searchStr.indexOf(name + "=");
if (infoIndex === -1) {
return null;
}
let searchInfo = searchStr.substring(infoIndex + name.length + 1);
let tagIndex = searchInfo.indexOf("&");
if (tagIndex !== -1) {
searchInfo = searchInfo.substring(0, tagIndex);
}
return searchInfo;
}
</script>
</body>
</html>
(3)首页index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta HTTP-EQUIV="pragma" CONTENT="no-cache">
<meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<meta HTTP-EQUIV="expires" CONTENT="0">
<title>首页</title>
<link rel="stylesheet" href="../../css/element.css">
<link rel="stylesheet" href="../../css/base.css">
</head>
<body>
<!-- 整体区域 -->
<div id="wrapper" v-cloak>
<!-- 左上角,系统公告 -->
<el-row :gutter="10">
<el-col :span="12">
<el-card>
<!-- 标题 -->
<div slot="header" class="clearfix">
<h3>系统公告</h3>
</div>
<!-- -->
<el-collapse accordion v-model="active">
<el-collapse-item :name="index" v-for="(item ,index) in notices">
<!-- 公告标题、发布时间、公告内容 -->
<template slot="title">
<b>{{ item.title }}</b>
<span style="margin-left: 50px; color: #888">{{ item.time }}</span>
</template>
<div style="padding: 0 20px">{{ item.content }}</div>
</el-collapse-item>
</el-collapse>
</el-card>
</el-col>
<!-- 设计饼状图统计用户地区比例 -->
<el-col :span="12">
<el-card>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 100%;height:400px; margin: 0 auto"></div>
</el-card>
</el-col>
</el-row>
</div>
<script src="../../js/echarts.min.js"></script>
<script src="../../js/china.js"></script>
<script src="../../js/jquery.min.js"></script>
<script src="../../js/vue.min.js"></script>
<script src="../../js/element.js"></script>
<script>
// 设计饼状图的属性
const pieOption = {
title: {text: '用户地区比例统计'},
tooltip: {trigger: 'item'},
legend: {top: '0', left: 'right'},
series: [
{
name: '访问来源',
type: 'pie',
radius: ['40%', '70%'],
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
data: []
}
]
};
new Vue({
el: "#wrapper",
data: {
active: 0,
users: [],
roles: [],
permissions: [],
notices: [],
user: {},
tableData: [],
pageNum: 1,
pageSize: 10,
total: 0,
dialogFormVisible: false,
entity: {},
isCollapse: false
},
// 当前用户获取及加载
mounted() {
this.user = sessionStorage.getItem("user") ? JSON.parse(sessionStorage.getItem("user")) : {};
this.load();
},
methods: {
load() {
// 加载系统公告
$.get("/api/notice/").then((res) => {
this.notices = res.data;
})
// 基于准备好的dom,初始化echarts实例
let myChart = echarts.init(document.getElementById('main'));
$.ajax({
url: "/api/user",
success(res) {
let address = Array.from(new Set(res.data.map(v => v.address)))
address.forEach(item => {
let count = res.data.filter(v => v.address === item).length
pieOption.series[0].data.push({name: item, value: count})
})
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(pieOption);
}
})
},
handleCollapse() {
this.isCollapse = !this.isCollapse;
},
// 退出
logout() {
$.get("/api/user/logout");
sessionStorage.removeItem("user");
location.href = "/page/end/login.html";
}
}
})
</script>
</body>
</html>
3.其余界面
(1)个人信息person.html
需求分析
在首页顶部右侧提供了用户查看并编辑个人信息的功能。
源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta HTTP-EQUIV="pragma" CONTENT="no-cache">
<meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<meta HTTP-EQUIV="expires" CONTENT="0">
<title>个人信息</title>
<link rel="stylesheet" href="../../css/element.css">
<link rel="stylesheet" href="../../css/base.css">
<!-- 设置部分标签样式 -->
<style>
.avatar-uploader {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
}
.avatar {
width: 100px;
height: 100px;
display: block;
}
</style>
</head>
<body style="background-color: #ddd">
<!-- 整体区域 -->
<div id="wrapper" v-cloak>
<el-card style="width: 40%;">
<!-- 顶部 -->
<div slot="header" class="clearfix" style="display: flex">
<!-- 标题 -->
<div style="font-size: 24px; flex: 1">个人信息</div>
<div style="flex: 1; text-align: right">
<el-button size="small" type="primary" @click="edit">编辑</el-button>
</div>
</div>
<div>
<!-- 用户头像及头像上传 -->
<div style="padding: 10px 0; text-align: center">
<el-upload
class="avatar-uploader"
action="/files/upload"
:show-file-list="false"
:on-success="handleAvatarSuccess">
<img v-if="user.avatar" :src="['/files/' + user.avatar]" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</div>
<!-- 用户个人信息打印 -->
<div style="width: 300px; margin: 0 auto">
<el-form>
<el-form-item label="用户名:" label-width="120px" style="margin: 0">
<div>{{ user.username }}</div>
</el-form-item>
<el-form-item label="昵称:" label-width="120px" style="margin: 0">
<div>{{ user.nickName }}</div>
</el-form-item>
<el-form-item label="邮箱:" label-width="120px" style="margin: 0">
<div>{{ user.email }}</div>
</el-form-item>
<el-form-item label="电话:" label-width="120px" style="margin: 0">
<div>{{ user.phone }}</div>
</el-form-item>
<el-form-item label="年龄:" label-width="120px" style="margin: 0">
<div>{{ user.age }}</div>
</el-form-item>
<el-form-item label="地址:" label-width="120px" style="margin: 0">
<div>{{ user.address }}</div>
</el-form-item>
</el-form>
</div>
</div>
</el-card>
<!-- 编辑子组件 -->
<el-dialog title="用户信息" :visible.sync="dialogFormVisible" width="40%" close-on-click-modal="false" close-on-press-escape="false" show-close="false">
<!-- 用户各信息展示并提供修改 -->
<el-form :model="user">
<el-form-item label="用户名" label-width="100px">
<el-input v-model="entity.username" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="昵称" label-width="100px">
<el-input v-model="entity.nickName" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="邮箱" label-width="100px">
<el-input v-model="entity.email" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="电话" label-width="100px">
<el-input v-model="entity.phone" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="年龄" label-width="100px">
<el-input v-model="entity.age" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="地址" label-width="100px">
<el-input v-model="entity.address" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="密码" label-width="100px">
<el-input show-password v-model="user.password" autocomplete="off" style="width: 80%"></el-input>
</el-form-item>
</el-form>
<!-- 与否按钮 -->
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
</div>
<script src="../../js/jquery.min.js"></script>
<script src="../../js/vue.min.js"></script>
<script src="../../js/element.js"></script>
<script>
new Vue({
el: "#wrapper",
data: {
user: {},
isCollapse: false,
entity: {},
dialogFormVisible: false
},
// 获取当前用户及加载
created() {
this.user = sessionStorage.getItem("user") ? JSON.parse(sessionStorage.getItem("user")) : {};
this.load();
},
methods: {
// 退出
logout() {
$.get("/api/user/logout");
sessionStorage.removeItem("user");
location.href = "/page/end/login.html";
},
handleCollapse() {
this.isCollapse = !this.isCollapse;
},
// 编辑
edit() {
this.entity = JSON.parse(JSON.stringify(this.user))
this.dialogFormVisible = true;
},
// 根据用户名加载用户数据
load() {
$.get("/api/user/detail/" + this.user.username).then(res => {
this.user = res.data;
})
},
// 保存用户信息
save() {
$.ajax({
url: "/api/user",
type: "PUT",
contentType: "application/json",
data: JSON.stringify(this.entity)
}).then(res => {
if (res.code === '0') {
this.$message({
message: "保存成功",
type: "success"
});
this.load();
} else {
this.$message({
message: res.msg,
type: "error"
})
}
// 退出子组件
this.dialogFormVisible = false;
})
},
}
})
</script>
</body>
</html>
(2)权限设置authority.html
需求分析
在前面的需求分析中,了解到,用户访问系统功能需要具备功能许可,因此在前端界面展示也因有根据权限展示的功能
源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta HTTP-EQUIV="pragma" CONTENT="no-cache">
<meta HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<meta HTTP-EQUIV="expires" CONTENT="0">
<title>权限限制</title>
<link rel="stylesheet" href="../../css/element.css">
<link rel="stylesheet" href="../../css/base.css">
</head>
<body>
<!-- 整体区域 -->
<div id="wrapper" v-cloak>
<el-container>
<el-aside :width="isCollapse ? '64px' : '200px'" style="background-color: black; transition:width .5s; min-height: 100vh">
<!-- 左上角系统标识,绑定事件回到首页 -->
<div style="background-color: black; height: 60px; line-height: 60px; text-align: center;color: white; font-size: 20px;">
<transition name="el-fade-in-linear">
<span id="fade" v-show="!isCollapse"><a href="/page/end/frame.html">Megumi</a></span>
</transition>
</div>
<!-- 侧边栏菜单 -->
<el-menu :default-openeds="['1']" style="border: none;" background-color="black" text-color="#fff"
active-text-color="#ffd04b"
default-active="home"
class="el-menu-vertical-demo" :collapse="isCollapse">
<!-- 首页 -->
<a href="/page/end/frame.html">
<el-menu-item index="home">
<i class="el-icon-data-line"></i>
<span slot="title">首页</span>
</el-menu-item>
</a>
<!-- 其余有许可功能 -->
<a :href=`${item.path}` v-for="item in user.permission" :key="item.id">
<el-menu-item :index="item.flag">
<i class="el-icon-s-data"></i>
<span slot="title">{{item.name}}</span>
</el-menu-item>
</a>
</el-menu>
</el-aside>
<el-container>
<el-header style="background-color: black; line-height: 60px; color: white;">
<el-row>
<!-- 侧边栏缩放 -->
<el-col :span="1">
<i style="font-size: 22px; cursor: pointer"
:class="[isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold']" @click="handleCollapse"></i>
</el-col>
<el-col :span="2" :offset="21" style="text-align: right">
<!-- 用户昵称、头像,绑定事件鼠标聚焦展示下拉选项,提供个人信息、退出功能 -->
<span style="color: white; margin-right: 10px">{{user.username}}</span>
<el-dropdown>
<img :src=`/files/${user.avatar}`
style="width: 40px; height: 40px; margin-right: 10px; border-radius: 50%">
<el-dropdown-menu slot="dropdown">
<a href="/page/end/person.html"
style="display:inline-block; padding: 5px 0; width: 100px; text-align: center; color: black">个人信息</a>
<a @click="logout" href="#"
style="display:block; width: 100px; text-align: center; color: black">退出</a>
</el-dropdown-menu>
</el-dropdown>
</el-col>
</el-row>
</el-header>
<!-- 主体区域 -->
<el-main>
<div style="padding: 10px; font-size: 30px; color: red">
good!
</div>
</el-main>
</el-container>
</el-container>
</div>
<script src="../../js/echarts.min.js"></script>
<script src="../../js/china.js"></script>
<script src="../../js/jquery.min.js"></script>
<script src="../../js/vue.min.js"></script>
<script src="../../js/element.js"></script>
<script>
new Vue({
el: "#wrapper",
data: {
user: {},
isCollapse: false
},
// 获取当前用户及加载
created() {
this.user = sessionStorage.getItem("user") ? JSON.parse(sessionStorage.getItem("user")) : {};
},
methods: {
handleCollapse() {
this.isCollapse = !this.isCollapse;
},
// 退出
logout() {
$.get("/api/user/logout");
sessionStorage.removeItem("user");
location.href = "/page/end/login.html";
}
}
});
</script>
</body>
</html>
(3)base.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul,li{
list-style: none;
}
a {
text-decoration: none;
color: cornflowerblue;
}
body {
font-size:14px;
color:#333;
background-color: #eeeeee;
}
img {
border: none;
vertical-align: middle;
}
input, textarea {
outline: none;
border: none;
}
textarea {
resize: none;
overflow: auto;
}
button {
border: none;
outline: none;
cursor: pointer;
}
.frame-body {
background-color: Ivory;
}
.tip {
position: relative;
margin: 10px auto;
height: 50px;
line-height: 50px;
color: white;
text-align: center;
border-radius: 10px;
font-family: sans-serif;
}
.tip:after {
content: '';
position: absolute;
width: 0;
height: 0;
border: 8px solid;
}
.right {
background-color: deepskyblue;
}
.left {
background-color: forestgreen;
}
.left:after {
border-right-color: forestgreen;
top: 50%;
right: 100%;
margin-top: -9px;
}
.right:after {
border-left-color: deepskyblue;
left: 100%;
top: 50%;
margin-top: -7px;
}
/*elementUI样式调整*/
[v-cloak] {
display: none;
}
.el-header {
padding-left: 0;
}
.el-aside {
min-height: 100vh;
}
.el-aside,.el-menu {
overflow-x: hidden;
}
.horizontal-collapse-transition {
transition: 0s;
}
.el-menu a {
color: white;
}
.el-menu .is-active a {
color: #ffd04b;
}
.el-breadcrumb__inner {
cursor: pointer;
}