项目介绍 :
Spring Boot + SpringMVC + MyBatis+ Mysql + druid + Vue 开发的前后端分离的停车场管理系统
项目演示:
https://www.bilibili.com/video/BV16i421o7gm/?vd_source=11ac782881cbade0d1444685d3b0d4df
环境需要:
- 运行环境: 最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。
- IDE环境:Eclipse,Myeclipse,IDEA或者Spring Tool Suite都可以
- 数据库:MySql 5.7
- Maven:3.3以上
技术栈
前端
Vue、Axios、Element UI、Vue-Router、Vuex、ECharts
后端
Spring Boot、JWT、MyBatis-Plus、MySQL
功能结构
管理员角色:
- 首页
- 用户信息管理
- 车位信息管理
- 车位费用设置
- 停泊车辆查询
- 车辆进出管理
- 登录日志查询
用户角色
首页
个人中心
预定停车位
缴费信息
项目预览
登录页
系统展示
部分代码
package com.example.parking.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.parking.entity.dto.DateType;
import com.example.parking.entity.po.User;
import com.example.parking.entity.query.UserQuery;
import com.example.parking.entity.vo.UserInfoVo;
import com.example.parking.service.UserService;
import com.example.parking.common.R;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 用户相关 控制层
*
* @date: 2023-12-02
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/user")
public class UserController {
private final UserService userService;
/**
* 用户登录
*
* @param user 用户信息
* @return 用户
*/
@PostMapping("/login")
public R<UserInfoVo> login(@RequestBody User user) {
return R.success(userService.login(user));
}
/**
* 注册用户
*
* @param user 用户信息
* @return 注册结果
*/
@PostMapping("/register")
public R<Boolean> register(@RequestBody User user) {
return R.success(userService.register(user));
}
/**
* 检查用户名
*
* @param username 用户名
* @return 是否重复
*/
@GetMapping("/checkUsername")
public R<Boolean> checkUsername(String username) {
return R.success(userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getUsername, username)) == null);
}
/**
* 新增用户
*
* @param user 用户信息
* @return 结果
*/
@PostMapping("/add")
public R<Boolean> addUser(@RequestBody User user) {
return R.success(userService.add(user));
}
/**
* 根据用户ID删除用户信息
*
* @param uid 用户id
* @return 结果
*/
@GetMapping("/del")
public R<Boolean> delUser(Integer uid) {
return R.success(userService.delUser(uid));
}
/**
* 分页获取用户
*
* @param userQuery 条件信息
* @return 用户信息
*/
@PostMapping("/getUsers")
public R<IPage<User>> getUsersPage(@RequestBody UserQuery userQuery) {
return R.success(userService.getUsersPage(userQuery));
}
/**
* 更改用户信息
*
* @param user 用户信息
* @return 更新结果
*/
@PostMapping("/update")
public R<Boolean> update(@RequestBody User user) {
return R.success(userService.updateUser(user));
}
/**
* 用户更改个人信息
*
* @param user 用户信息
* @return 更新结果
*/
@PostMapping("/updateByUser")
public R<Boolean> updateByUser(@RequestBody User user) {
return R.success(userService.updateByUser(user));
}
/**
* 重置密码
*
* @param uid 用户id
* @return 结果
*/
@GetMapping("/resetPassword")
public R<Boolean> resetPassword(Integer uid) {
return R.success(userService.resetPassword(uid));
}
/**
* 通过用户id查询
*
* @param uid 用户id
* @return 用户
*/
@GetMapping("/getUserByUid")
public R<User> gerUserByUid(Integer uid) {
return R.success(userService.getById(uid));
}
/**
* 用户充值
*
* @param user 用户信息
* @return 结果
*/
@PostMapping("/userPay")
public R<Boolean> userPay(@RequestBody User user) {
return R.success(userService.userPay(user));
}
/**
* 获取用户停车类型记录
*
* @param person 用户
* @return 停车位类型
*/
@GetMapping("/getCarTypes")
public R<List<DateType>> getCarTypes(String person) {
return R.success(userService.getUserDataType(person));
}
/**
* 获取用户缴费记录
*
* @param person 用户
* @return 缴费记录
*/
@GetMapping("/dataMoney")
public R<List<DateType>> getUserMoney(String person) {
return R.success(userService.getUserDataMoney(person));
}
}
<!--
* 车位管理
-->
<template>
<div>
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item
><i
class="iconfont icon-stall-menu"
style="margin: 5px; font-size: 22px"
>
车位信息管理</i
></el-breadcrumb-item
>
</el-breadcrumb>
<!-- 卡片视图区域 -->
<el-card>
<el-row :gutter="20">
<el-col :span="4">
<el-input
v-model="queryInfo.carArea"
placeholder="请输入停车区域"
>
</el-input>
</el-col>
<el-col :span="4">
<el-select
v-model="queryInfo.carType"
placeholder="请选择车位类型"
>
<el-option
v-for="item in carTypes"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-col>
<el-col :span="4">
<el-select
v-model="queryInfo.carState"
placeholder="请选择车位状态"
>
<el-option
v-for="item in carStates"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-col>
<el-col :span="2">
<el-button
size="small"
type="success"
icon="iconfont icon-search-menu"
style="font-size: 18px"
@click="getList"
>
搜索</el-button
>
</el-col>
<el-col :span="2">
<el-button
size="small"
type="primary"
icon="iconfont icon-add-button"
style="font-size: 18px"
@click="addCar"
>
新增</el-button
>
</el-col>
</el-row>
<!-- 车位信息区域 -->
<el-table v-loading="loading" :data="cars" border stripe>
<el-table-column
width="50"
label="序号"
align="center"
type="index"
></el-table-column>
<el-table-column label="车位号" prop="stallNum" align="center">
</el-table-column>
<el-table-column
label="车位区域"
prop="stallArea"
align="center"
>
</el-table-column>
<el-table-column
label="车位类型"
prop="stallType"
align="center"
>
</el-table-column>
<el-table-column
label="车位状态"
prop="stallState"
align="center"
>
</el-table-column>
<el-table-column
label="车位收费"
prop="stallMoney"
align="center"
>
<template slot-scope="scope">
{{ scope.row.stallMoney }}元/时
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
width="200"
fixed="right"
>
<template slot-scope="scope">
<el-button
@click="toEdit(scope.row)"
type="primary"
circle
><i
class="iconfont icon-edit-button"
style="font-size: 22px"
></i
></el-button>
<el-button
@click="carDelete(scope.row.sid)"
type="danger"
circle
><i
class="iconfont icon-del-button"
style="font-size: 22px"
></i
></el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="queryInfo.pagenum"
:page-sizes="[5, 10, 15, 20]"
:page-size="queryInfo.pageSize"
layout="total, sizes, prev, pager, next"
:total="total"
>
</el-pagination>
</el-card>
<el-dialog
title="新增车位"
:visible.sync="addShow"
width="500px"
center
@close="addClose"
>
<!-- 内容主题区域 -->
<el-form
:model="registerCar"
status-icon
:rules="registerRules"
ref="registerRules"
label-width="100px"
class="demo-ruleForm"
>
<el-form-item
label="车位号"
prop="stallNum"
class="is-required"
>
<el-input
v-model="registerCar.stallNum"
placeholder="请输入车位号"
style="width: 300px"
></el-input>
</el-form-item>
<el-form-item
label="车位区域"
prop="stallArea"
class="is-required"
>
<el-input
v-model="registerCar.stallArea"
placeholder="请输入车位区域"
>
</el-input>
</el-form-item>
<el-form-item
label="车位类型"
prop="stallType"
class="is-required"
>
<el-select
v-model="registerCar.stallType"
placeholder="请选择车位类型"
>
<el-option
v-for="item in carTypes"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
</el-form>
<!-- 底部区域 -->
<span slot="footer" class="dialog-footer">
<el-button @click="addClose">取 消</el-button>
<el-button type="primary" @click="submitForm('registerRules')"
>确认添加</el-button
>
</span>
</el-dialog>
<el-dialog
title="修改车位"
:visible.sync="editShow"
width="500px"
center
@close="editClose"
>
<!-- 内容主题区域 -->
<el-form
:model="editCar"
status-icon
:rules="registerRules"
ref="registerRules"
label-width="100px"
class="demo-ruleForm"
>
<el-form-item
label="车位号"
prop="stallNum"
class="is-required"
>
<el-input
v-model="editCar.stallNum"
placeholder="请输入车位号"
style="width: 300px"
></el-input>
</el-form-item>
<el-form-item
label="车位区域"
prop="stallArea"
class="is-required"
>
<el-input
v-model="editCar.stallArea"
placeholder="请输入车位区域"
>
</el-input>
</el-form-item>
<el-form-item
label="车位类型"
prop="stallType"
class="is-required"
>
<el-select
v-model="editCar.stallType"
placeholder="请选择车位类型"
>
<el-option
v-for="item in carTypes"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
</el-form>
<!-- 底部区域 -->
<span slot="footer" class="dialog-footer">
<el-button @click="editClose">取 消</el-button>
<el-button
type="primary"
@click="editSend('registerRules')"
icon="iconfont icon-r-yes"
>
确认修改</el-button
>
</span>
</el-dialog>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
total: 0,
loading: true,
queryInfo: {
carArea: "",
carType: "",
carState: "",
pagenum: 1,
pageSize: 6,
},
cars: [],
registerCar: {},
editCar: {
sid: "",
stallNum: "",
stallArea: "",
stallType: "",
},
editShow: false,
uid: undefined,
addShow: false,
registerRules: {
stallNum: [
{
required: true,
message: "请输入车牌号",
trigger: "blur",
},
],
stallArea: [
{
required: true,
message: "请输入车位区域",
trigger: "blur",
},
],
stallType: [
{
required: true,
message: "请选择车位类型",
trigger: "blur",
},
],
},
carTypes: [
{
value: null,
label: "全部",
},
{
value: "临时车位",
label: "临时车位",
},
{
value: "固定车位",
label: "固定车位",
},
],
carStates: [
{
value: null,
label: "全部",
},
{
value: "已停车",
label: "已停车",
},
{
value: "空闲中",
label: "空闲中",
},
],
};
},
methods: {
getList() {
axios
.post("/api/stall/pageStall", this.queryInfo)
.then((res) => {
this.loading = false;
this.total = res.data.data.total;
this.cars = res.data.data.records;
});
},
handleSizeChange(newSize) {
this.queryInfo.pageSize = newSize;
this.getList();
},
handleCurrentChange(newPage) {
this.queryInfo.pagenum = newPage;
this.getList();
},
addCar() {
for (let item in this.registerCar) {
this.registerCar[item] = "";
}
if (this.carTypes[0].label == "全部") {
this.carTypes.shift();
}
this.addShow = true;
},
addClose() {
if (this.carTypes[0].label != "全部") {
this.carTypes.unshift({ value: null, label: "全部" });
}
this.addShow = false;
this.$nextTick(() => {
this.$refs.registerRules.resetFields();
});
},
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.loading = true;
axios
.post("/api/stall/add", this.registerCar)
.then((res) => {
this.loading = false;
if (res.data.data.flag) {
// /^[A-Za-z0-9]+$/
this.$message.success("添加成功!");
this.getList();
this.addShow = false;
} else {
this.$message.error(res.data.data.msg);
}
});
} else {
return false;
}
});
},
toEdit(car) {
if (this.carTypes[0].label == "全部") {
this.carTypes.shift();
}
this.editCar.sid = car.sid;
this.editCar.stallArea = car.stallArea;
this.editCar.stallNum = car.stallNum;
this.editCar.stallType = car.stallType;
this.editShow = true;
},
editClose() {
if (this.carTypes[0].label != "全部") {
this.carTypes.unshift({ value: null, label: "全部" });
}
this.editShow = false;
this.$nextTick(() => {
this.$refs.registerRules.resetFields();
});
},
editSend(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.loading = true;
axios
.post("/api/stall/update", this.editCar)
.then((res) => {
this.loading = false;
if (res.data.data.flag) {
this.$message.success("更新成功");
this.getList();
this.editShow = false;
} else {
this.$message.error(res.data.data.msg);
}
});
} else {
// console.log('error submit!!');
return false;
}
});
},
async useStall(sid) {
const re = await this.$confirm(
"此操作将预定该车位, 是否继续?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
).catch((err) => err);
// console.log(re)
if (re != "confirm") {
this.$message.info("已取消预定!");
} else {
axios
.get(
"/api/stall/orderStall?uid=" + this.uid + "&sid=" + sid
)
.then((res) => {
if (res.data.data) {
this.$message.success("预定成功!");
this.getList();
} else {
this.$message.error("预定失败!");
}
});
}
},
async carDelete(sid) {
const re = await this.$confirm(
"此操作将永久删除该车位, 是否继续?",
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
).catch((err) => err);
if (re != "confirm") {
this.$message.info("已取消删除!");
} else {
axios.get("/api/stall/del?sid=" + sid).then((res) => {
if (res.data.data) {
this.$message.success("删除成功!");
this.getList();
} else {
this.$message.error("删除失败,青虫性操作!");
}
});
}
},
},
mounted() {
this.getList();
},
};
</script>
创作不易,源码非无偿提供,需要获取源码的私信博主