1.0 项目介绍
开发工具:IDEA、VScode
服务器:Tomcat, JDK 17
项目构建:maven
数据库:mysql 8.0
系统用户前台和管理后台两部分,项目采用前后端分离
前端技术:vue3 + elementUI
服务端技术:springboot + mybatis + redis + mysql
1.1 项目功能
后台功能:
1)登录、退出系统、首页
2)教室管理
(1) 教室管理:添加、修改、删除、查询等功能。
3)教师管理
(1) 教师管理:添加、修改、删除、查询等功能。
4)课程管理
(1) 课程管理:添加、修改、删除、查询等功能。
5)设施管理
(1) 设施管理:添加、修改、删除、查询等功能。
6)教室设施信息
(1) 教室设施信息:添加、修改、删除、查询等功能。
7)课程安排
(1) 课程安排:添加、修改、删除、查询等功能。
8)教室使用记录
(1)教室使用记录:添加、修改、删除、查询等功能。
9)系统管理
用户信息管理
(1)用户信息管理:添加、修改、删除、查询等功能。
角色管理
(2)角色信息管理:添加、修改、删除、查询等功能。
菜单管理
(3)菜单信息管理:添加、修改、删除、查询等功能。
日志管理
(4)日志信息管理:添加、修改、删除、查询等功能。
10)系统监控
查看在先用户、设置定时任务、数据监控、缓存监控、查看缓存列表等。
11)权限管理
(1) 角色信息管理:添加、修改、删除、分配权限等功能。
(2) 资源信息管理:添加、修改、删除等功能。
注意:不一定非要完全符合开发环境,有稍微的差别也是可以开发的。
若需要项目完整源码,可以在 优快云 私信给我,我每天都有查看消息的,感谢大家支持,希
望可以帮助到大家!
2.0 用户登录
用户根据正确的用户名、密码且通过正确的校验码进行登录。使用了高质量的背景图片,希
望你喜欢。
整体的主题颜色为:猛男粉
实现了登录校验,还有用户注册功能:
用到了 Spring Security 框架来实现登录、校验、验证等功能。
相关的部分源码:
@RestController
public class SysLoginController
{
@Autowired
private SysLoginService loginService;
@Autowired
private ISysMenuService menuService;
@Autowired
private SysPermissionService permissionService;
/**
* 登录方法
*
* @param loginBody 登录信息
* @return 结果
*/
@PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody)
{
AjaxResult ajax = AjaxResult.success();
// 生成令牌
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
loginBody.getUuid());
ajax.put(Constants.TOKEN, token);
return ajax;
}
/**
* 获取用户信息
*
* @return 用户信息
*/
@GetMapping("getInfo")
public AjaxResult getInfo()
{
SysUser user = SecurityUtils.getLoginUser().getUser();
// 角色集合
Set<String> roles = permissionService.getRolePermission(user);
// 权限集合
Set<String> permissions = permissionService.getMenuPermission(user);
AjaxResult ajax = AjaxResult.success();
ajax.put("user", user);
ajax.put("roles", roles);
ajax.put("permissions", permissions);
return ajax;
}
/**
* 获取路由信息
*
* @return 路由信息
*/
@GetMapping("getRouters")
public AjaxResult getRouters()
{
Long userId = SecurityUtils.getUserId();
List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
return AjaxResult.success(menuService.buildMenus(menus));
}
}
public String login(String username, String password, String code, String uuid)
{
// 验证码校验
validateCaptcha(username, code, uuid);
// 登录前置校验
loginPreCheck(username, password);
// 用户验证
Authentication authentication = null;
try
{
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
AuthenticationContextHolder.setContext(authenticationToken);
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager.authenticate(authenticationToken);
}
catch (Exception e)
{
if (e instanceof BadCredentialsException)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
else
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
throw new ServiceException(e.getMessage());
}
}
finally
{
AuthenticationContextHolder.clearContext();
}
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getUserId());
// 生成token
return tokenService.createToken(loginUser);
}
3.0 首页界面
使用了各种各样的统计图表来直观展示数据。
相关的前端源码:
<template>
<div class="dashboard-container">
<div class="chart-container">
<div class="chart-header">
<h2>教室使用情况统计</h2>
</div>
<div class="charts">
<div id="barChart" class="chart"></div>
<div id="pieChart" class="chart"></div>
<div id="lineChart" class="chart"></div>
<div id="gaugeChart" class="chart"></div>
</div>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts';
export default {
name: 'Dashboard',
mounted() {
this.initBarChart();
this.initPieChart();
this.initLineChart();
this.initGaugeChart();
},
methods: {
initBarChart() {
const barChart = echarts.init(document.getElementById('barChart'));
const option = {
title: {
text: '各教室使用次数',
left: 'center',
textStyle: {
color: '#fff'
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: {
type: 'category',
data: ['教室3B-413', '教室3B-414', '教室3B-415', '教室3B-416', '教室3B-417'],
axisLabel: {
color: '#fff'
}
},
yAxis: {
type: 'value',
axisLabel: {
color: '#fff'
}
},
series: [{
data: [120, 200, 150, 80, 70],
type: 'bar',
itemStyle: {
color: '#FF69B4'
}
}]
};
barChart.setOption(option);
},
initPieChart() {
const pieChart = echarts.init(document.getElementById('pieChart'));
const option = {
title: {
text: '教室使用比例',
left: 'center',
textStyle: {
color: '#fff'
}
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left',
textStyle: {
color: '#fff'
}
},
series: [
{
name: '教室',
type: 'pie',
radius: '50%',
data: [
{ value: 335, name: '教室3B-413' },
{ value: 310, name: '教室3B-414' },
{ value: 234, name: '教室3B-415' },
{ value: 135, name: '教室3B-416' },
{ value: 1548, name: '教室3B-417' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
itemStyle: {
color: function(params) {
const colorList = ['#FF69B4', '#FF1493', '#DB7093', '#C71585', '#DA70D6'];
return colorList[params.dataIndex];
}
}
}
]
};
pieChart.setOption(option);
},
initLineChart() {
const lineChart = echarts.init(document.getElementById('lineChart'));
const option = {
title: {
text: '教室使用时间趋势',
left: 'center',
textStyle: {
color: '#fff'
}
},
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
axisLabel: {
color: '#fff'
}
},
yAxis: {
type: 'value',
axisLabel: {
color: '#fff'
}
},
series: [{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'line',
itemStyle: {
color: '#FF69B4'
}
}]
};
lineChart.setOption(option);
},
initGaugeChart() {
const gaugeChart = echarts.init(document.getElementById('gaugeChart'));
const option = {
title: {
text: '总使用次数',
left: 'center',
textStyle: {
color: '#fff'
}
},
tooltip: {
formatter: '{a} <br/>{b} : {c}'
},
series: [
{
name: '使用次数',
type: 'gauge',
detail: {
formatter: '{value}',
color: '#fff'
},
data: [{ value: 2500, name: '总次数' }],
axisLabel: {
color: '#fff'
},
axisLine: {
lineStyle: {
color: [[0.2, '#FF69B4'], [0.8, '#FF1493'], [1, '#DB7093']],
width: 12
}
},
pointer: {
width: 5
},
axisTick: {
length: 10,
lineStyle: {
color: 'auto'
}
},
splitLine: {
length: 15,
lineStyle: {
color: 'auto'
}
}
}
]
};
gaugeChart.setOption(option);
}
}
};
</script>
<style lang="scss">
$theme_color: #FF69B4;
.dashboard-container {
min-height: 100vh;
width: 100%;
background-image: url('../../assets/images/6.jpg'); /* 使用占位图片,你可以替换为实际图片 */
background-size: cover;
background-position: center;
display: flex;
justify-content: center;
align-items: center;
.chart-container {
background-color: rgba(0, 0, 0, 0.7); /* 半透明背景 */
border-radius: 20px;
box-shadow: 0 0 40px rgba(0, 0, 0, 0.5);
width: 80%;
max-width: 1200px;
padding: 40px;
color: #fff;
.chart-header {
text-align: center;
margin-bottom: 30px;
h2 {
color: $theme_color;
font-weight: bold;
}
}
.charts {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.chart {
width: 48%;
height: 400px;
margin-bottom: 20px;
}
}
}
}
</style>
4.0 教室管理功能
上传图片使用了第三方接口:x-File-Storage 框架。
相关源码:
@RestController
@RequestMapping("/manage/Classrooms")
public class ClassroomsController extends BaseController
{
@Autowired
private IClassroomsService classroomsService;
/**
* 查询教室信息列表
*/
@PreAuthorize("@ss.hasPermi('manage:Classrooms:list')")
@GetMapping("/list")
public TableDataInfo list(Classrooms classrooms)
{
startPage();
List<Classrooms> list = classroomsService.selectClassroomsList(classrooms);
return getDataTable(list);
}
/**
* 导出教室信息列表
*/
@PreAuthorize("@ss.hasPermi('manage:Classrooms:export')")
@Log(title = "教室信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, Classrooms classrooms)
{
List<Classrooms> list = classroomsService.selectClassroomsList(classrooms);
ExcelUtil<Classrooms> util = new ExcelUtil<Classrooms>(Classrooms.class);
util.exportExcel(response, list, "教室信息数据");
}
/**
* 获取教室信息详细信息
*/
@PreAuthorize("@ss.hasPermi('manage:Classrooms:query')")
@GetMapping(value = "/{classroomId}")
public AjaxResult getInfo(@PathVariable("classroomId") Long classroomId)
{
return success(classroomsService.selectClassroomsByClassroomId(classroomId));
}
/**
* 新增教室信息
*/
@PreAuthorize("@ss.hasPermi('manage:Classrooms:add')")
@Log(title = "教室信息", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody Classrooms classrooms)
{
return toAjax(classroomsService.insertClassrooms(classrooms));
}
/**
* 修改教室信息
*/
@PreAuthorize("@ss.hasPermi('manage:Classrooms:edit')")
@Log(title = "教室信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody Classrooms classrooms)
{
return toAjax(classroomsService.updateClassrooms(classrooms));
}
/**
* 删除教室信息
*/
@PreAuthorize("@ss.hasPermi('manage:Classrooms:remove')")
@Log(title = "教室信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{classroomIds}")
public AjaxResult remove(@PathVariable Long[] classroomIds)
{
return toAjax(classroomsService.deleteClassroomsByClassroomIds(classroomIds));
}
}
5.0 教师管理功能
相关源码:
@RestController
@RequestMapping("/manage/Teachers")
public class TeachersController extends BaseController
{
@Autowired
private ITeachersService teachersService;
/**
* 查询教师信息列表
*/
@PreAuthorize("@ss.hasPermi('manage:Teachers:list')")
@GetMapping("/list")
public TableDataInfo list(Teachers teachers)
{
startPage();
List<Teachers> list = teachersService.selectTeachersList(teachers);
return getDataTable(list);
}
/**
* 导出教师信息列表
*/
@PreAuthorize("@ss.hasPermi('manage:Teachers:export')")
@Log(title = "教师信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, Teachers teachers)
{
List<Teachers> list = teachersService.selectTeachersList(teachers);
ExcelUtil<Teachers> util = new ExcelUtil<Teachers>(Teachers.class);
util.exportExcel(response, list, "教师信息数据");
}
/**
* 获取教师信息详细信息
*/
@PreAuthorize("@ss.hasPermi('manage:Teachers:query')")
@GetMapping(value = "/{teacherId}")
public AjaxResult getInfo(@PathVariable("teacherId") Long teacherId)
{
return success(teachersService.selectTeachersByTeacherId(teacherId));
}
/**
* 新增教师信息
*/
@PreAuthorize("@ss.hasPermi('manage:Teachers:add')")
@Log(title = "教师信息", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody Teachers teachers)
{
return toAjax(teachersService.insertTeachers(teachers));
}
/**
* 修改教师信息
*/
@PreAuthorize("@ss.hasPermi('manage:Teachers:edit')")
@Log(title = "教师信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody Teachers teachers)
{
return toAjax(teachersService.updateTeachers(teachers));
}
/**
* 删除教师信息
*/
@PreAuthorize("@ss.hasPermi('manage:Teachers:remove')")
@Log(title = "教师信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{teacherIds}")
public AjaxResult remove(@PathVariable Long[] teacherIds)
{
return toAjax(teachersService.deleteTeachersByTeacherIds(teacherIds));
}
}
6.0 课程管理功能
相关源码:
@RestController
@RequestMapping("/manage/Courses")
public class CoursesController extends BaseController
{
@Autowired
private ICoursesService coursesService;
/**
* 查询课程信息列表
*/
@PreAuthorize("@ss.hasPermi('manage:Courses:list')")
@GetMapping("/list")
public TableDataInfo list(Courses courses)
{
startPage();
List<Courses> list = coursesService.selectCoursesList(courses);
return getDataTable(list);
}
/**
* 导出课程信息列表
*/
@PreAuthorize("@ss.hasPermi('manage:Courses:export')")
@Log(title = "课程信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, Courses courses)
{
List<Courses> list = coursesService.selectCoursesList(courses);
ExcelUtil<Courses> util = new ExcelUtil<Courses>(Courses.class);
util.exportExcel(response, list, "课程信息数据");
}
/**
* 获取课程信息详细信息
*/
@PreAuthorize("@ss.hasPermi('manage:Courses:query')")
@GetMapping(value = "/{courseId}")
public AjaxResult getInfo(@PathVariable("courseId") Long courseId)
{
return success(coursesService.selectCoursesByCourseId(courseId));
}
/**
* 新增课程信息
*/
@PreAuthorize("@ss.hasPermi('manage:Courses:add')")
@Log(title = "课程信息", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody Courses courses)
{
return toAjax(coursesService.insertCourses(courses));
}
/**
* 修改课程信息
*/
@PreAuthorize("@ss.hasPermi('manage:Courses:edit')")
@Log(title = "课程信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody Courses courses)
{
return toAjax(coursesService.updateCourses(courses));
}
/**
* 删除课程信息
*/
@PreAuthorize("@ss.hasPermi('manage:Courses:remove')")
@Log(title = "课程信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{courseIds}")
public AjaxResult remove(@PathVariable Long[] courseIds)
{
return toAjax(coursesService.deleteCoursesByCourseIds(courseIds));
}
}
7.0 设施管理功能
相关源码:
@RestController
@RequestMapping("/manage/Facilities")
public class FacilitiesController extends BaseController
{
@Autowired
private IFacilitiesService facilitiesService;
/**
* 查询教室设施列表
*/
@PreAuthorize("@ss.hasPermi('manage:Facilities:list')")
@GetMapping("/list")
public TableDataInfo list(Facilities facilities)
{
startPage();
List<Facilities> list = facilitiesService.selectFacilitiesList(facilities);
return getDataTable(list);
}
/**
* 导出教室设施列表
*/
@PreAuthorize("@ss.hasPermi('manage:Facilities:export')")
@Log(title = "教室设施", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, Facilities facilities)
{
List<Facilities> list = facilitiesService.selectFacilitiesList(facilities);
ExcelUtil<Facilities> util = new ExcelUtil<Facilities>(Facilities.class);
util.exportExcel(response, list, "教室设施数据");
}
/**
* 获取教室设施详细信息
*/
@PreAuthorize("@ss.hasPermi('manage:Facilities:query')")
@GetMapping(value = "/{facilityId}")
public AjaxResult getInfo(@PathVariable("facilityId") Long facilityId)
{
return success(facilitiesService.selectFacilitiesByFacilityId(facilityId));
}
/**
* 新增教室设施
*/
@PreAuthorize("@ss.hasPermi('manage:Facilities:add')")
@Log(title = "教室设施", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody Facilities facilities)
{
return toAjax(facilitiesService.insertFacilities(facilities));
}
/**
* 修改教室设施
*/
@PreAuthorize("@ss.hasPermi('manage:Facilities:edit')")
@Log(title = "教室设施", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody Facilities facilities)
{
return toAjax(facilitiesService.updateFacilities(facilities));
}
/**
* 删除教室设施
*/
@PreAuthorize("@ss.hasPermi('manage:Facilities:remove')")
@Log(title = "教室设施", businessType = BusinessType.DELETE)
@DeleteMapping("/{facilityIds}")
public AjaxResult remove(@PathVariable Long[] facilityIds)
{
return toAjax(facilitiesService.deleteFacilitiesByFacilityIds(facilityIds));
}
}