前端学习了这么久了,node.js 也有了一定的了解,知道使用node也可以来开发后端,今天给大家分享 使用node 来做后端,vue来写前端,做一个简单的图书管理系统。我们在刚开始学习编程的时候,需要自己写大量的项目来练习自己的编程技能,在开发中你会遇到各种各样的编程问题,这个时候 就可以根据自己学习到的编程知识来解决开发中遇到的问题,这样我们就会慢慢的掌握一门编程语言。
今天分享的就是我最近写的一个图书管理系统。
使用技术:
Node.js:后端使用Node.js平台,版本要求16.20以上,基于其高性能和跨平台特性,能够轻松支持大规模的API请求。
Express框架:简洁高效的后端框架,帮助快速搭建API服务。
MySQL 5.7:作为关系型数据库管理系统,MySQL用于存储用户和图书信息,并支持CRUD操作。
Vue2:前端使用Vue2框架,配合Element UI组件库,提供响应式页面和现代化用户界面。
Element UI:帮助实现简洁且功能丰富的UI设计,极大提高了前端开发效率。
系统功能:
用户管理:可以新增、编辑、删除用户信息。
图书管理:添加、修改、删除图书,并能够查看图书列表。
借阅管理:记录图书借阅、归还情况。
数据展示:通过前端页面展示系统中的图书、用户信息,提供了简洁、易用的界面。
部分页面效果展示:
目录结构:
部分前端代码:
<template>
<div class="app-container">
<!-- 搜索和操作栏 -->
<div class="filter-container">
<el-input
v-model="listQuery.name"
placeholder="请输入图书名称"
style="width: 200px; margin-right: 10px"
class="filter-item"
@keyup.enter.native="handleFilter"
/>
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">搜索</el-button>
<el-button type="primary" @click="handleCreate" style="margin-left: 10px">新增图书</el-button>
</div>
<!-- 数据表格 -->
<el-table
v-loading="listLoading"
:data="list"
element-loading-text="加载中..."
border
fit
highlight-current-row
style="margin-top: 20px;"
>
<el-table-column label="图书编号" prop="book_no" align="center" />
<el-table-column label="图书名称" prop="name" align="center" />
<el-table-column label="分类" prop="category_name" align="center" />
<el-table-column label="作者" prop="author" align="center" />
<el-table-column label="使用状态" align="center">
<template slot-scope="{row}">
<el-tag :type="row.use_status === 0 ? 'info' : row.use_status === 1 ? 'success' : 'warning'">
{{ row.use_status === 0 ? '在书架' : row.use_status === 1 ? '已买' : '已借出' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="是否二手" align="center">
<template slot-scope="{row}">
<el-tag :type="row.is_second_hand === 1 ? 'warning' : 'info'">
{{ row.is_second_hand === 1 ? '是' : '否' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="状态" align="center">
<template slot-scope="{row}">
<el-tag :type="row.status === 1 ? 'success' : 'danger'" style="cursor: pointer">
{{ row.status === 1 ? '正常' : '维护' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="备注" prop="remark" align="center" show-overflow-tooltip />
<el-table-column label="创建时间" prop="created_at" align="center" />
<el-table-column label="操作" align="center" width="160" fixed="right">
<template slot-scope="{row}">
<el-button type="primary" size="mini" @click="handleUpdate(row)">编辑</el-button>
<el-button type="danger" size="mini" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 新增/编辑对话框 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="600px">
<el-form
ref="dataForm"
:model="temp"
:rules="rules"
label-position="left"
label-width="100px"
style="margin-left: 50px; margin-right: 50px"
>
<el-form-item label="图书编号" prop="book_no">
<el-input v-model="temp.book_no" placeholder="请输入图书编号" />
</el-form-item>
<el-form-item label="图书名称" prop="name">
<el-input v-model="temp.name" placeholder="请输入图书名称" />
</el-form-item>
<el-form-item label="图书分类" prop="category_id">
<el-select v-model="temp.category_id" placeholder="请选择图书分类" style="width: 100%">
<el-option
v-for="item in categories"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="作者" prop="author">
<el-input v-model="temp.author" placeholder="请输入作者" />
</el-form-item>
<el-form-item label="出版日期" prop="publish_date">
<el-date-picker
v-model="temp.publish_date"
type="datetime"
placeholder="请选择出版日期"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="定价" prop="price">
<el-input-number
v-model="temp.price"
:precision="2"
:step="0.1"
:min="0"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="temp.status" placeholder="请选择状态" style="width: 100%">
<el-option label="正常" :value="1" />
<el-option label="维护" :value="0" />
</el-select>
</el-form-item>
<el-form-item label="使用状态" prop="use_status">
<el-select v-model="temp.use_status" placeholder="请选择使用状态" style="width: 100%">
<el-option label="在书架" :value="0" />
<el-option label="已买" :value="1" />
<el-option label="已借出" :value="2" />
</el-select>
</el-form-item>
<el-form-item label="是否二手" prop="is_second_hand">
<el-select v-model="temp.is_second_hand" placeholder="请选择是否二手" style="width: 100%">
<el-option label="否" :value="0" />
<el-option label="是" :value="1" />
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="temp.remark"
type="textarea"
placeholder="请输入备注信息"
:rows="3"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
getBookList,
createBook,
updateBook,
deleteBook,
updateBookStatus
} from '@/api/book'
import { getCategoryList } from '@/api/category'
export default {
name: 'BookList',
data() {
return {
list: [], // 图书列表数据
categories: [], // 分类列表数据
listLoading: false, // 列表加载状态
listQuery: { // 查询参数
name: '' // 图书名称搜索关键词
},
dialogVisible: false, // 对话框显示状态
dialogTitle: '', // 对话框标题
temp: { // 临时数据对象
id: undefined,
book_no: '',
name: '',
category_id: undefined,
author: '',
publish_date: undefined,
price: 0,
status: 1,
remark: '',
use_status: 0,
is_second_hand: 0
},
rules: { // 表单验证规则
book_no: [{ required: true, message: '请输入图书编号', trigger: 'blur' }],
name: [{ required: true, message: '请输入图书名称', trigger: 'blur' }],
category_id: [{ required: true, message: '请选择图书分类', trigger: 'change' }],
author: [{ required: true, message: '请输入作者', trigger: 'blur' }],
publish_date: [{ required: true, message: '请选择出版日期', trigger: 'change' }],
price: [{ required: true, message: '请输入定价', trigger: 'blur' }]
}
}
},
created() {
this.getList()
this.getCategories()
},
methods: {
// 获取图书列表
async getList() {
try {
this.listLoading = true
const { data } = await getBookList(this.listQuery)
this.list = data
} catch (error) {
console.error('获取图书列表失败:', error)
} finally {
this.listLoading = false
}
},
// 处理搜索
handleFilter() {
this.getList()
},
// 获取分类列表
async getCategories() {
try {
const { data } = await getCategoryList()
this.categories = data
} catch (error) {
console.error('获取分类列表失败:', error)
}
},
// 重置表单
resetTemp() {
this.temp = {
id: undefined,
book_no: '',
name: '',
category_id: undefined,
author: '',
publish_date: undefined,
price: 0,
status: 1,
remark: '',
use_status: 0,
is_second_hand: 0
}
},
// 打开新增对话框
handleCreate() {
this.resetTemp()
this.dialogTitle = '新增图书'
this.dialogVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
// 打开编辑对话框
handleUpdate(row) {
this.temp = Object.assign({}, row)
this.dialogTitle = '编辑图书'
this.dialogVisible = true
this.$nextTick(() => {
this.$refs['dataForm'].clearValidate()
})
},
// 提交表单
submitForm() {
this.$refs['dataForm'].validate(async (valid) => {
if (valid) {
try {
if (this.temp.id) {
// 更新
await updateBook(this.temp.id, this.temp)
this.$message.success('更新成功')
} else {
// 新增
await createBook(this.temp)
this.$message.success('创建成功')
}
this.dialogVisible = false
this.getList()
} catch (error) {
console.error('保存图书失败:', error)
}
}
})
},
// 删除图书
handleDelete(row) {
this.$confirm('确认删除该图书吗?', '提示', {
type: 'warning'
}).then(async () => {
try {
await deleteBook(row.id)
this.$message.success('删除成功')
this.getList()
} catch (error) {
console.error('删除图书失败:', error)
}
}).catch(() => {})
},
// 更新状态
async handleStatusChange(row) {
try {
await updateBookStatus(row.id, row.status)
this.$message.success('状态更新成功')
} catch (error) {
console.error('更新状态失败:', error)
// 恢复原状态
row.status = row.status === 1 ? 0 : 1
}
}
}
}
</script>
<style lang="scss" scoped>
.filter-container {
padding-bottom: 10px;
.filter-item {
margin-right: 10px;
}
}
</style>
部分后端代码:
const BookModel = require('../models/book.model')
const Response = require('../utils/response')
const asyncHandler = require('../utils/asyncHandler')
class BookController {
/**
* 获取图书列表
*/
getList = asyncHandler(async (req, res) => {
const { name } = req.query
const books = await BookModel.getAll({ name })
res.json(Response.success(books))
})
/**
* 获取图书详情
*/
getDetail = asyncHandler(async (req, res) => {
const { id } = req.params
const book = await BookModel.findById(id)
if (!book) {
return res.json(Response.error('图书不存在'))
}
res.json(Response.success(book))
})
/**
* 创建图书
*/
create = asyncHandler(async (req, res) => {
const { book_no, name, category_id, author, publish_date, price, status, remark, use_status, is_second_hand } = req.body
// 验证必填字段
if (!book_no) {
return res.json(Response.error('图书编号不能为空'))
}
if (!name) {
return res.json(Response.error('图书名称不能为空'))
}
if (!category_id) {
return res.json(Response.error('图书分类不能为空'))
}
if (!author) {
return res.json(Response.error('作者不能为空'))
}
if (!publish_date) {
return res.json(Response.error('出版日期不能为空'))
}
if (!price) {
return res.json(Response.error('定价不能为空'))
}
const id = await BookModel.create({
book_no,
name,
category_id,
author,
publish_date,
price,
status,
remark,
use_status,
is_second_hand
})
const book = await BookModel.findById(id)
res.json(Response.success(book, '创建成功'))
})
/**
* 更新图书
*/
update = asyncHandler(async (req, res) => {
const { id } = req.params
const { book_no, name, category_id, author, publish_date, price, status, remark, use_status, is_second_hand } = req.body
const book = await BookModel.update(id, {
book_no,
name,
category_id,
author,
publish_date,
price,
status,
remark,
use_status,
is_second_hand
})
res.json(Response.success(book, '更新成功'))
})
/**
* 删除图书
*/
delete = asyncHandler(async (req, res) => {
const { id } = req.params
await BookModel.delete(id)
res.json(Response.success(null, '删除成功'))
})
/**
* 更新图书状态
*/
updateStatus = asyncHandler(async (req, res) => {
const { id } = req.params
const { status } = req.body
if (status === undefined) {
return res.json(Response.error('状态不能为空'))
}
const book = await BookModel.updateStatus(id, status)
res.json(Response.success(book, '状态更新成功'))
})
}
module.exports = new BookController()
代码量还是很多的,毕竟是一个管理系统,由于文章字数,这里就不一一复制粘贴代码了,如果你需要完整的项目源码,可以去下方网站了解。
https://wwwoop.com/home/Index/projectInfo?goodsId=97&typeParam=1&subKey=0