一、項目演示
項目演示地址: 視頻地址
二、項目介紹
項目描述:這是一個基于SpringBoot+Vue框架開發(fā)的高校圖書館管理系統(tǒng)。首先,這是一個前后端分離的項目,代碼簡潔規(guī)范,注釋說明詳細,易于理解和學習。其次,這項目功能豐富,具有一個高校圖書館管理系統(tǒng)該有的所有功能。
項目功能:此項目分為兩個角色:學生和管理員。學生有登錄注冊、管理個人信息、瀏覽座位信息、預(yù)約選座、瀏覽圖書信息、借閱圖書、瀏覽借閱信息、管理預(yù)約信息等等功能。管理員有管理所有用戶新息、管理所有座位信息、管理所有時刻信息、管理所有信譽積分信息、管理所有圖書信息、管理所有預(yù)約選座、借閱信息等等功能。
應(yīng)用技術(shù):SpringBoot + Vue + MySQL + MyBatis + Redis + ElementUI
運行環(huán)境:IntelliJ IDEA2019.3.5 + MySQL5.7(項目壓縮包中自帶) + Redis5.0.5(項目壓縮包中自帶) + JDK1.8 + Gradle5.6.4(項目壓縮包中自帶)+ Node14.16.1(項目壓縮包中自帶)
三、項目運行截圖
項目運行截圖:
四、主要代碼
1.前端預(yù)約選座頁面代碼:
<template>
<div>
<!-- 面包屑導航 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home/dash-board' }">首頁</el-breadcrumb-item>
<el-breadcrumb-item>選座頁面</el-breadcrumb-item>
</el-breadcrumb>
<!-- 搜索篩選 -->
<el-form :inline="true" :model="searchParams" class="user-search">
<el-form-item label="搜索:">
<el-date-picker
value-format="yyyy-MM-dd"
format="yyyy-MM-dd"
size="small"
v-model="searchParams.openTime"
type="date"
:picker-options="pickerOptions"
:clearable="false"
:editable="false">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-select v-model="searchParams.scheduleId" size="small" placeholder="請選擇時刻">
<el-option v-for="(item, index) in scheduleList" :key="index" :label="item.name + '(' + item.rangeTime + ')'" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" icon="el-icon-search" @click="searchByTime">搜索</el-button>
<el-button size="small" v-if="loginUser.roleId === 1" type="primary" icon="el-icon-date" @click="pickOrderSeat">預(yù)約</el-button>
</el-form-item>
</el-form>
<el-table :key="index" v-if="seat.row !== 0 && seat.col !== 0" size="small" :data="tableData" v-loading="loading" border element-loading-text="拼命加載中" style="width: 100%;">
<el-table-column width="55">
<template slot-scope="scope">
<span style="color: #909399; font-weight: bold;">第{{scope.$index + 1}}行</span>
</template>
</el-table-column>
<el-table-column :width="seat.col > 9 ? 150 : ''" v-for="n in seat.col" :key="n" align="center" :label="'第' + n + '列'" >
<template slot-scope="scope">
<el-badge v-if="scope.row.picked[n-1] === 0" type="danger" value="占座" style="margin-top: 10px">
<img style="width: 30px; height: 30px; margin-top: 10px"
src="../../assets/img/sold_seat.jpg" />
<div>第{{scope.$index + 1}}行第{{n}}列</div>
</el-badge>
<el-badge v-else-if="scope.row.picked[n-1] === 1" type="primary" value="可選" style="margin-top: 10px">
<div @click="pickSeat(scope.$index, n-1)">
<img style="width: 30px; height: 30px; margin-top: 10px"
src="../../assets/img/selectable_seat.jpg" />
<div>第{{scope.$index + 1}}行第{{n}}列</div>
</div>
</el-badge>
<el-badge v-else-if="scope.row.picked[n-1] === 2" type="success" value="選中" style="margin-top: 10px">
<div @click="cancelSeat(scope.$index + 1, n)">
<img style="width: 30px; height: 30px; margin-top: 10px"
src="../../assets/img/selected_seat.jpg" />
<div>第{{scope.$index + 1}}行第{{n}}列</div>
</div>
</el-badge>
</template>
</el-table-column>
</el-table>
<el-empty v-else :image-size="200"></el-empty>
</div>
</template>
<script>
export default {
name: 'PickList',
data() {
return {
pickerOptions: {
disabledDate: (time) => {
return time.getTime() < Date.now() - 8.64e7
}
},
searchParams: {
openTime: '',
scheduleId: ''
},
seat: {
row: 0,
col: 0
},
scheduleList: [],
loading: false,
tableData: [],
pickSeatList: [],
seatItemList: [],
index: 0,
loginUser: {}
}
},
created() {
this.searchParams.openTime = this.getNowDay();
this.getLoginUser();
this.getAllScheduleList();
},
methods: {
getNowDay() {
let date = new Date();
let y = date.getFullYear();
let m = date.getMonth() + 1;
m = m < 10 ? ('0' + m) : m;
let d = date.getDate();
d = d < 10 ? ('0' + d) : d;
return y + '-' + m + '-' + d;
},
getLoginUser() {
this.$ajax.post("/user/getLoginUser", {token: Tool.getLoginUser()}).then((response)=>{
let resp = response.data;
if(resp.code === 0){
if(resp.data) {
this.loginUser = resp.data;
} else {
this.$message.error(resp.msg);
this.$router.push("/login");
}
}
});
},
pickSeat(row, col) {
if(this.pickSeatList.length >= 1) {
this.$message.warning("一次最多只能選1個座位!");
return false;
}
this.tableData[row].picked[col] = 2;
// 動態(tài)刷新表格
this.index = this.index + 1;
this.pickSeatList.push({row: row + 1, col: col + 1});
},
cancelSeat(row, col) {
this.tableData[row-1].picked[col-1] = 1;
// 動態(tài)刷新表格
this.index = this.index + 1;
let nowSeatList = [];
this.pickSeatList.forEach(item => {
if(item.col !== col || item.row !== row) {
nowSeatList.push(item);
}
});
this.pickSeatList = nowSeatList;
},
getSeatBySearch() {
this.loading = true;
this.$ajax.post("/seat/getByTime", this.searchParams).then((response)=>{
let resp = response.data;
if(resp.code === 0){
if(resp.data) {
this.seat = resp.data;
this.getSeatItem();
} else {
this.seat = {row: 0, col: 0};
}
}
});
},
initSeatDetailList() {
this.tableData = [];
for(let i=1; i<=this.seat.row; i++) {
let item = {picked: []};
for(let j=1; j<=this.seat.col; j++) {
item.picked.push(this.isPicked(i, j));
}
this.tableData.push(item);
}
this.loading = false;
},
isPicked(row, col) {
let result = 1;
this.seatItemList.forEach(item => {
if(item.row === row && item.col === col) {
result = 0; // 已被占座
}
});
return result; // 未被占座
},
getSeatItem() {
this.$ajax.post("/seat/getItemBySeatId", {id: this.seat.id}).then((response)=>{
let resp = response.data;
if(resp.code === 0){
this.seatItemList = resp.data;
this.initSeatDetailList();
} else {
this.$message.error(resp.msg);
}
});
},
pickOrderSeat() {
if(this.pickSeatList.length === 0) {
this.$message.warning("請至少選擇一個座位!");
return false;
}
let seat = this.pickSeatList[0];
this.$confirm('確定要預(yù)約第'+ seat.row +'行第'+ seat.col +'列的座位?', '提示', {
confirmButtonText: '確定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$ajax.post("/seat/pick", {...seat, seatId: this.seat.id, userId: this.loginUser.id}).then((response)=>{
let resp = response.data;
if(resp.code === 0){
this.$message.success(resp.msg);
this.getSeatBySearch();
this.pickSeatList = [];
} else {
this.$message.error(resp.msg);
}
});
});
},
searchByTime() {
this.$confirm('搜索將導致當前選中的記錄丟失,確認繼續(xù)此操作?', '提示', {
confirmButtonText: '確定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.pickSeatList = [];
this.getSeatBySearch();
});
},
getAllScheduleList() {
this.$ajax.post("/schedule/all").then((response)=>{
let resp = response.data;
if(resp.code === 0){
this.scheduleList = resp.data;
this.searchParams.scheduleId = this.scheduleList[0] ? this.scheduleList[0].id : '';
this.getSeatBySearch();
}
});
}
}
}
</script>
<style scoped>
.user-search {
margin-top: 20px;
}
/deep/ .el-table tbody tr:hover>td {
background-color:unset !important
}
</style>
2.借閱圖書業(yè)務(wù)邏輯代碼:文章來源:http://www.zghlxwxcb.cn/news/detail-425895.html
/**
* 借閱圖書操作
* @param rentalItemDTO
* @return
*/
@Override
public ResponseDTO<Boolean> rentalBook(RentalItemDTO rentalItemDTO) {
// 進行統(tǒng)一表單驗證
CodeMsg validate = ValidateEntityUtil.validate(rentalItemDTO);
if(!validate.getCode().equals(CodeMsg.SUCCESS.getCode())){
return ResponseDTO.errorByMsg(validate);
}
User user = userMapper.selectByPrimaryKey(rentalItemDTO.getUserId());
if(user == null) {
return ResponseDTO.errorByMsg(CodeMsg.USER_NOT_EXIST);
}
if (user.getCreditRate() < 80) {
return ResponseDTO.errorByMsg(CodeMsg.CREDIT_RENTAL_ERROR);
}
Book book = bookMapper.selectByPrimaryKey(rentalItemDTO.getBookId());
if(book == null) {
return ResponseDTO.errorByMsg(CodeMsg.BOOK_NOT_EXIST);
}
if(CommonUtil.differentDaysByMillisecond(new Date(), rentalItemDTO.getPredictTime()) > 180) {
return ResponseDTO.errorByMsg(CodeMsg.BOOK_RENTAL_TIME_OVER);
}
// 修改圖書狀態(tài) 樂觀鎖控制
BookExample bookExample = new BookExample();
bookExample.createCriteria().andIdEqualTo(book.getId()).andVersionEqualTo(book.getVersion());
book.setState(BookStateEnum.RENTAL.getCode());
book.setVersion(book.getVersion() + 1);
if(bookMapper.updateByExampleSelective(book, bookExample) == 0) {
return ResponseDTO.errorByMsg(CodeMsg.BOOK_EDIT_ERROR);
}
// 寫入借閱詳情信息
RentalItem rentalItem = CopyUtil.copy(rentalItemDTO, RentalItem.class);
rentalItem.setId(UuidUtil.getShortUuid());
rentalItem.setCreateTime(new Date());
rentalItem.setBookName(book.getName());
rentalItem.setBookPhoto(book.getPhoto());
rentalItem.setState(RentalItemStateEnum.RENTAL.getCode());
if(rentalItemMapper.insertSelective(rentalItem) == 0) {
throw new RuntimeException(CodeMsg.BOOK_RENTAL_ERROR.getMsg());
}
return ResponseDTO.successByMsg(true, "借閱成功!");
}
3.用戶登錄業(yè)務(wù)邏輯代碼:文章來源地址http://www.zghlxwxcb.cn/news/detail-425895.html
/**
* 用戶登錄操作
* @param userDTO
* @return
*/
@Override
public ResponseDTO<UserDTO> login(UserDTO userDTO) {
// 進行是否為空判斷
if(CommonUtil.isEmpty(userDTO.getUsername())){
return ResponseDTO.errorByMsg(CodeMsg.USERNAME_EMPTY);
}
if(CommonUtil.isEmpty(userDTO.getPassword())){
return ResponseDTO.errorByMsg(CodeMsg.PASSWORD_EMPTY);
}
if(CommonUtil.isEmpty(userDTO.getCaptcha())){
return ResponseDTO.errorByMsg(CodeMsg.CAPTCHA_EMPTY);
}
if(CommonUtil.isEmpty(userDTO.getCorrectCaptcha())){
return ResponseDTO.errorByMsg(CodeMsg.CAPTCHA_EXPIRED);
}
// 比對驗證碼是否正確
String value = stringRedisTemplate.opsForValue().get((userDTO.getCorrectCaptcha()));
if(CommonUtil.isEmpty(value)){
return ResponseDTO.errorByMsg(CodeMsg.CAPTCHA_EXPIRED);
}
if(!value.toLowerCase().equals(userDTO.getCaptcha().toLowerCase())){
return ResponseDTO.errorByMsg(CodeMsg.CAPTCHA_ERROR);
}
// 對比昵稱和密碼是否正確
UserExample userExample = new UserExample();
// select * from user where username = ? and password = ?
userExample.createCriteria().andUsernameEqualTo(userDTO.getUsername()).andPasswordEqualTo(userDTO.getPassword());
List<User> userList = userMapper.selectByExample(userExample);
if(userList == null || userList.size() != 1){
return ResponseDTO.errorByMsg(CodeMsg.USERNAME_PASSWORD_ERROR);
}
// 生成登錄token并存入Redis中
UserDTO selectedUserDto = CopyUtil.copy(userList.get(0), UserDTO.class);
String token = UuidUtil.getShortUuid();
selectedUserDto.setToken(token);
//把token存入redis中 有效期1小時
stringRedisTemplate.opsForValue().set("USER_" + token, JSON.toJSONString(selectedUserDto), 3600, TimeUnit.SECONDS);
return ResponseDTO.successByMsg(selectedUserDto, "登錄成功!");
}
到了這里,關(guān)于SpringBoot+Vue實現(xiàn)的高校圖書館管理系統(tǒng) 附帶詳細運行指導視頻的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!