报销管理系统)
大家好我是Java1234_小锋老师分享一套锋哥原创的SpringBoot4Vue3差旅(出差)报销管理系统。项目介绍随着企业经营规模的不断扩大和异地业务的日益频繁员工出差已成为企业日常经营活动中的常态。传统的差旅报销主要依赖纸质单据和人工审核存在单据易丢失、填报不规范、审批流程冗长、统计汇总困难、财务对账效率低等突出问题难以满足现代企业精细化、信息化管理的需求。因此设计并实现一套高效、规范、易用的差旅(出差)报销管理系统具有重要的现实意义。本系统采用前后端分离的架构思想进行设计与开发。后端基于 SpringBoot 框架搭建利用其自动配置和起步依赖特性快速构建 RESTful 接口持久层采用 MyBatis-Plus 框架通过其内置的通用 Mapper、条件构造器和分页插件大幅简化数据库访问代码数据库选用 MySQL 进行数据的持久化存储。前端采用 Vue3 框架并结合 Element Plus 组件库进行页面构建通过 Axios 与后端进行数据交互借助 Vue Router 和 Pinia 完成路由管理与状态管理实现了组件化、响应式的用户界面。系统按照角色划分为普通员工、审批人和系统管理员三类用户主要实现了用户登录、个人中心、出差申请管理、报销单填报、报销审批、费用类型与部门等基础数据管理以及系统公告等功能模块。论文按照软件工程的思想依次完成了系统的需求分析、概念结构设计(E-R 图)、功能结构设计、业务流程设计(时序图)、数据库设计以及各功能模块的编码实现并对系统进行了功能测试。测试结果表明本系统功能完整、运行稳定、操作便捷能够有效规范企业差旅报销流程提高报销审批效率降低人工成本具有较好的实用价值和推广意义。源码下载链接: https://pan.baidu.com/s/1wOVtO2kPVJBtoJHYBTkc4Q?pwd1234提取码: 1234系统展示核心代码package com.java1234.controller; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.java1234.common.BusinessException; import com.java1234.common.Result; import com.java1234.config.ClaimsHolder; import com.java1234.entity.ExpenseType; import com.java1234.service.ExpenseTypeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; /** * 费用类型管理控制器 */ RestController RequestMapping(/api/expense-type) public class ExpenseTypeController { Autowired private ExpenseTypeService expenseTypeService; /** * 分页查询费用类型列表 */ GetMapping(/page) public ResultIPageExpenseType page( RequestParam(defaultValue 1) int pageNum, RequestParam(defaultValue 10) int pageSize, RequestParam(required false) String typeName) { checkAdmin(); LambdaQueryWrapperExpenseType wrapper new LambdaQueryWrapper(); if (StrUtil.isNotBlank(typeName)) { wrapper.like(ExpenseType::getTypeName, typeName); } wrapper.orderByDesc(ExpenseType::getCreateTime); return Result.success(expenseTypeService.page(new Page(pageNum, pageSize), wrapper)); } /** * 获取所有启用的费用类型 */ GetMapping(/list) public ResultListExpenseType list() { return Result.success(expenseTypeService.list( new LambdaQueryWrapperExpenseType().eq(ExpenseType::getStatus, 1))); } /** * 新增费用类型 */ PostMapping public ResultVoid add(RequestBody ExpenseType expenseType) { checkAdmin(); expenseTypeService.save(expenseType); return Result.success(); } /** * 修改费用类型 */ PutMapping public ResultVoid update(RequestBody ExpenseType expenseType) { checkAdmin(); expenseTypeService.updateById(expenseType); return Result.success(); } /** * 删除费用类型 */ DeleteMapping(/{id}) public ResultVoid delete(PathVariable Long id) { checkAdmin(); expenseTypeService.removeById(id); return Result.success(); } /** * 校验管理员权限 */ private void checkAdmin() { if (!ClaimsHolder.isAdmin()) { throw new BusinessException(403, 无权操作); } } }template el-container classlayout-container el-aside :widthisCollapse ? 64px : 220px classsidebar div classlogo el-icon :size24Suitcase //el-icon span v-show!isCollapse差旅报销系统/span /div el-menu :default-activeroute.path :collapseisCollapse router background-colortransparent text-color#bfcbd9 active-text-color#409eff el-menu-item index/home el-iconHomeFilled //el-icon span首页/span /el-menu-item el-menu-item index/reimbursement el-iconDocument //el-icon span报销单管理/span /el-menu-item el-menu-item v-ifuserStore.isAdmin index/audit el-iconChecked //el-icon span审批管理/span /el-menu-item el-sub-menu v-ifuserStore.isAdmin indexsystem template #title el-iconSetting //el-icon span系统管理/span /template el-menu-item index/user用户管理/el-menu-item el-menu-item index/dept部门管理/el-menu-item el-menu-item index/expense-type费用类型/el-menu-item /el-sub-menu el-menu-item index/profile el-iconUser //el-icon span个人中心/span /el-menu-item /el-menu /el-aside el-container el-header classheader div classheader-left el-icon classcollapse-btn clickisCollapse !isCollapse Fold v-if!isCollapse /Expand v-else / /el-icon el-breadcrumb separator/ el-breadcrumb-item{{ route.meta.title || 首页 }}/el-breadcrumb-item /el-breadcrumb /div div classheader-right el-dropdown commandhandleCommand span classuser-info el-avatar :size32 stylebackground:#409eff{{ userStore.user?.realName?.charAt(0) }}/el-avatar span classusername{{ userStore.user?.realName }}/span el-iconArrowDown //el-icon /span template #dropdown el-dropdown-menu el-dropdown-item commandprofile个人中心/el-dropdown-item el-dropdown-item commandlogout divided退出登录/el-dropdown-item /el-dropdown-menu /template /el-dropdown /div /el-header el-main classmain-content router-view / /el-main /el-container /el-container /template script setup import { ref } from vue import { useRoute, useRouter } from vue-router import { useUserStore } from /stores/user const route useRoute() const router useRouter() const userStore useUserStore() const isCollapse ref(false) function handleCommand(cmd) { if (cmd logout) { userStore.logout() router.push(/login) } else if (cmd profile) { router.push(/profile) } } /script style scoped .layout-container { height: 100vh; } .sidebar { background: linear-gradient(180deg, #1a1f3a 0%, #2d3561 100%); transition: width 0.3s; overflow: hidden; } .logo { height: 60px; display: flex; align-items: center; justify-content: center; gap: 8px; color: #fff; font-size: 16px; font-weight: bold; border-bottom: 1px solid rgba(255,255,255,0.1); } .sidebar :deep(.el-menu) { border-right: none; } .sidebar :deep(.el-menu-item.is-active) { background: rgba(64, 158, 255, 0.15) !important; border-right: 3px solid #409eff; } .header { display: flex; align-items: center; justify-content: space-between; background: #fff; box-shadow: 0 1px 4px rgba(0,0,0,0.08); padding: 0 20px; } .header-left { display: flex; align-items: center; gap: 16px; } .collapse-btn { font-size: 20px; cursor: pointer; color: #606266; } .user-info { display: flex; align-items: center; gap: 8px; cursor: pointer; } .username { color: #303133; font-size: 14px; } .main-content { background: #f0f2f5; padding: 0; overflow-y: auto; } /style