React 18 + NestJS 全栈课设:实验室设备管理系统,TypeScript 前后端一条龙

发布时间:2026/11/6 2:02:28
React 18 + NestJS 全栈课设:实验室设备管理系统,TypeScript 前后端一条龙 如果你的课设想走前端方向但只做一个纯前端的后台管理系统模板改改字分数不会太高——因为没有后端就没有真实数据没有真实数据就写不出像样的文档。实验室设备管理系统正好解决这个问题它有明确的业务实体设备、预约、审批、维保有清晰的角色边界教师 / 学生 / 管理员还有真实的管理需求。而且它天生适合TypeScript 全栈——前后端共享一套类型定义这一点在文档里是很好的技术亮点。一、技术选型为什么不用 ExpressExpress 自由度太高课设阶段反而容易写成一坨 route。NestJS 的 Module / Controller / Service 三层结构逼着你想清楚分层技术文档里的系统架构章节直接就有了。二、数据模型Prisma SchemaPrisma 的好处是 schema 即文档直接贴进技术文档的数据库设计章节也没问题model Device { id String id default(cuid()) code String unique // DEV-2024-001 name String model String // 型号规格 labId String status DeviceStatus default(IN_USE) purchaseAt DateTime keeperId String? // 保管人 createdAt DateTime default(now()) lab Lab relation(fields: [labId], references: [id]) bookings Booking[] } enum DeviceStatus { IN_USE // 在用 BOOKED // 预约中 REPAIRING // 维修中 CHECKING // 待检定 SCRAPPED // 已报废 } model Booking { id String id default(cuid()) deviceId String userId String startTime DateTime endTime DateTime purpose String? // 用途审批时必看 status BookingStatus default(PENDING) reviewerId String? reviewNote String? device Device relation(fields: [deviceId], references: [id]) index([deviceId, startTime]) } enum BookingStatus { PENDING APPROVED REJECTED FINISHED CANCELLED }两个设计点值得写进文档status用枚举而不是 intPrisma 会生成 TS 的联合类型前端渲染标签时类型安全不会出现status 传了个 6 结果前端白屏index([deviceId, startTime])预约冲突检测的查询全部走这个联合索引一条索引解决 80% 的性能问题三、核心难点 1时间冲突检测这是最关键的一段逻辑设备预约的本质是时间区间不能重叠。很多人写法是这样的// ❌ 错误写法只判断是否被完全包含 const conflict await prisma.booking.findFirst({ where: { deviceId, startTime: { gte: start }, endTime: { lte: end } } })这种写法漏掉了三种重叠情况新区间包含旧区间、左重叠、右重叠。正确的判据是两个区间重叠 ⟺ 新开始 旧结束 且 新结束 旧开始async function checkConflict(deviceId: string, start: Date, end: Date) { if (start end) throw new BadRequestException(结束时间必须晚于开始时间) const conflict await prisma.booking.findFirst({ where: { deviceId, status: { in: [PENDING, APPROVED] }, startTime: { lt: end }, // 旧开始 新结束 endTime: { gt: start }, // 旧结束 新开始 }, }) if (conflict) { throw new ConflictException( 该时段已被占用${format(conflict.startTime)} ~ ${format(conflict.endTime)} ) } }这段代码建议在文档里配一张时间轴示意图说明四种重叠情况比纯文字清楚十倍也是很好的图示能力体现。四、核心难点 2RBAC 权限控制菜单 按钮级课设里常见的权限就是登录一下谁都能看所有页面。真正的 RBAC 至少要做到两层第一层接口级后端守卫Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(ctx: ExecutionContext): boolean { const roles this.reflector.getRole[](roles, ctx.getHandler()) if (!roles) return true // 未声明则放行 const { user } ctx.switchToHttp().getRequest() return roles.includes(user.role) } } // 使用 Roles(ADMIN, TEACHER) Post(:id/approve) approve(Param(id) id: string, Body() dto: ApproveDto) { return this.bookingService.approve(id, dto) }第二层前端按钮级用access字段控制菜单和按钮可见性Ant Design Pro 自带这套机制Access accessible{currentUser?.role ADMIN} Button danger onClick{handleDelete}删除设备/Button /Access关键提醒前端隐藏按钮只是体验优化真正的权限判断必须在后端。文档里明确写这句话是安全意识的体现答辩很容易被问到。五、核心难点 3审批事务与并发管理员点通过时要做三件事更新预约状态、扣减设备可用性、写操作日志。这三步必须在同一个事务里async approve(id: string, dto: ApproveDto) { return this.prisma.$transaction(async (tx) { const booking await tx.booking.findUnique({ where: { id } }) if (!booking) throw new NotFoundException(预约不存在) if (booking.status ! PENDING) throw new BadRequestException(该申请已处理) // 二次校验冲突从提交到审批之间可能已有人被批准 await this.checkConflictInTx(tx, booking.deviceId, booking.startTime, booking.endTime, id) const updated await tx.booking.update({ where: { id }, data: { status: APPROVED, reviewerId: dto.reviewerId, reviewNote: dto.note }, }) await tx.device.update({ where: { id: booking.deviceId }, data: { status: BOOKED } }) await tx.auditLog.create({ data: { action: APPROVE_BOOKING, targetId: id, operatorId: dto.reviewerId } }) return updated }) }二次校验冲突这一步是很多人的实现里没有的但它是真实业务必须的A 和 B 同时申请同一台设备同一时段管理员先批了 A再批 B 就必须报冲突。审阅老师看到这一段会认为你想过并发场景。六、页面效果设备台账页是这类系统的主界面重点在表格的信息密度和状态标签的视觉区分设备状态用四色标签区分在用 / 预约中 / 维修中 / 待检定一眼就能看出哪台设备有问题。Ant Design 的TableTag组合基本改改样式就能实现不用自己造轮子。审批看板用左侧使用频次条形图 右侧待审批列表的组合条形图不用引入 ECharts纯 CSS 宽度百分比就够了——课设阶段少一个依赖少一个坑效果上完全看不出来。七、三周排期二维码这个功能建议加上每台设备生成一个二维码贴在机器上扫码直接跳到该设备的预约页。实现只要几行qrcode库但演示效果非常好答辩时拿手机扫一下老师印象会深很多。八、可以写的技术亮点文档里单独列一节前后端共享 TypeScript 类型packages/shared/types接口字段改动编译期就能发现Prisma 迁移脚本纳入版本管理团队协作不冲突Swagger Postman 双份接口文档测试同学可直接导入统一响应拦截器与异常过滤器前端只处理code ! 0一种错误形态这几条不写进代码也不影响运行但写进文档就是工程规范是拉开分数的地方。最后这个题目的优势是技术栈现代、工程规范性强适合想往 Web 全栈方向走的同学。缺点是纯管理系统在创新性上稍弱所以一定要靠业务细节取胜——冲突检测、RBAC、审批事务这三个点认真实现就足以撑起一篇有分量的技术文档。下一篇写点更新的用 Spring AI 给课程资料做一个 RAG 智能问答助手涉及向量检索和大模型调用是目前最热的方向。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询