# boot-erp **Repository Path**: MISSMYSEIF/boot-erp ## Basic Information - **Project Name**: boot-erp - **Description**: 前后端分离的企业资源计划管理系统,涵盖采购、销售、库存、财务等核心业务模块。 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-20 - **Last Updated**: 2026-07-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ERP 管理系统 前后端分离的企业资源计划管理系统,涵盖采购、销售、库存、财务等核心业务模块,基于 Spring Boot 3 + Vue 3 技术栈构建。 ## 技术栈 ### 前端 | 技术 | 版本 | 说明 | |------|------|------| | Vue 3 | 3.5+ | 核心框架,Composition API | | TypeScript | 6.x | 类型安全,增强代码可维护性 | | Vite | 8.x | 极速构建工具,热更新 | | Pinia | 3.x | Vue 官方状态管理库 | | Vue Router | 4.x | 路由管理,支持动态路由 | | Element Plus | 2.x | 企业级 UI 组件库 | | Axios | 1.x | HTTP 请求封装 | | ECharts | 6.x | 数据可视化图表 | | @vueuse/core | 14.x | 组合式函数工具集 | | SCSS | - | CSS 预处理器 | ### 后端 | 技术 | 版本 | 说明 | |------|------|------| | Java | 17+ | LTS 版本,性能稳定 | | Spring Boot | 3.2+ | 核心框架,自动配置 | | Sa-Token | 1.37+ | 权限认证(JWT + Redis) | | MyBatis-Plus | 3.5+ | ORM 框架,简化 CRUD | | MySQL | 8.x | 关系型数据库 | | Redis | 7.x | 缓存 + Session 存储 | | Hutool | 5.8+ | Java 工具类库 | | Lombok | 1.18+ | 减少样板代码 | ### 基础设施 | 技术 | 说明 | |------|------| | Docker Compose | 容器编排(MySQL + Redis) | | Nginx | 前端部署 + 反向代理 | ## 项目结构 ``` boot-erp/ ├── frontend/ # 前端项目 │ ├── src/ │ │ ├── api/ # 接口请求封装 │ │ ├── assets/ # 静态资源(样式、图片、图标) │ │ ├── composables/ # 组合式函数(权限指令等) │ │ ├── layouts/ # 主布局(侧边栏+顶栏+标签页) │ │ ├── router/ # 路由配置 + 动态路由 + 守卫 │ │ ├── stores/ # Pinia 状态管理(用户、应用) │ │ ├── types/ # TypeScript 类型定义 │ │ ├── utils/ # 工具函数(Axios 封装等) │ │ └── views/ # 页面视图 │ │ ├── login/ # 登录页 │ │ ├── dashboard/ # 首页仪表盘 │ │ ├── system/ # 系统管理(用户/角色/菜单/部门) │ │ ├── purchase/ # 采购管理(订单/供应商) │ │ ├── sales/ # 销售管理(订单/客户) │ │ ├── inventory/ # 库存管理(仓库/商品/库存) │ │ ├── finance/ # 财务管理(财务记录) │ │ └── profile/ # 个人中心 │ └── vite.config.ts # Vite 构建配置 │ ├── backend/ # 后端项目 │ ├── src/main/java/com/erp/ │ │ ├── common/ # 公共模块 │ │ │ ├── base/ # BaseEntity 基类(主键、时间、逻辑删除) │ │ │ ├── config/ # 配置类(CORS/Sa-Token/MyBatis/Jackson) │ │ │ ├── exception/ # BusinessException + 全局异常处理器 │ │ │ └── result/ # 统一响应 Result + PageResult │ │ ├── system/ # 系统管理模块 │ │ │ ├── controller/ # 控制器(Auth/User/Role/Menu/Dept) │ │ │ ├── service/ # 服务层(接口 + 实现) │ │ │ ├── mapper/ # 数据访问层(Mapper + XML) │ │ │ └── entity/ # 实体类 │ │ ├── purchase/ # 采购管理模块 │ │ ├── sales/ # 销售管理模块 │ │ ├── inventory/ # 库存管理模块 │ │ ├── finance/ # 财务管理模块 │ │ ├── dashboard/ # 数据统计模块 │ │ └── ErpApplication.java # Spring Boot 启动类 │ ├── src/main/resources/ │ │ ├── application.yml # 应用配置 │ │ ├── init.sql # 数据库初始化脚本 │ │ └── mapper/ # MyBatis XML 映射文件 │ └── pom.xml # Maven 依赖管理 │ ├── docker-compose.yml # Docker 编排配置 ├── nginx.conf # Nginx 部署配置 ├── README.md # 项目说明文档 └── README.en.md # 英文文档 ``` ## 功能模块 | 模块 | 功能 | 说明 | |------|------|------| | **系统管理** | 用户管理 | 用户 CRUD、角色分配、密码重置 | | | 角色管理 | 角色 CRUD、菜单权限分配 | | | 菜单管理 | 菜单树管理、权限配置 | | | 部门管理 | 部门树形结构管理 | | **采购管理** | 供应商管理 | 供应商 CRUD、状态管理 | | | 采购订单 | 订单创建、审核、入库 | | **销售管理** | 客户管理 | 客户 CRUD、状态管理 | | | 销售订单 | 订单创建、审核、出库 | | **库存管理** | 仓库管理 | 仓库 CRUD | | | 商品管理 | 商品 CRUD、分类管理 | | | 库存查询 | 实时库存、库存预警 | | **财务管理** | 财务记录 | 收支记录、账龄分析 | | **数据统计** | 仪表盘 | 销售趋势、库存预警、待办事项 | ## 核心特性 ### 权限管理 - **RBAC 权限模型** — 用户 → 角色 → 菜单/按钮,支持页面级 + 按钮级两级权限控制 - **动态路由** — 根据用户角色从后端获取菜单,动态生成路由,无权限页面不可访问 - **按钮权限** — 前端 `v-permission` 指令控制按钮显示/隐藏 ### 认证安全 - **JWT + Redis** — Sa-Token 无状态认证,支持分布式部署 - **BCrypt 加密** — 密码单向加密存储,抗彩虹表攻击 - **验证码** — 图片验证码防暴力破解 - **逻辑删除** — 数据不真正删除,保留历史,满足审计需求 ### 数据处理 - **统一响应格式** — 前后端约定 `{code, message, data}`,前端拦截器统一处理错误 - **全局异常处理** — 业务异常/参数校验/系统异常统一捕获,安全返回 - **雪花算法 ID** — 分布式唯一 ID,趋势递增,对 B+ 树索引友好 - **分页查询** — MyBatis-Plus 分页插件,自动生成 LIMIT 语句 - **乐观锁** — 并发更新时防止数据覆盖 ### 前端体验 - **多页签** — 标签页 + keep-alive,切换页面不丢失状态 - **代码分割** — Vue / ElementPlus / ECharts 分包,按需加载 - **图标组件映射** — 字符串图标名称自动映射到 Element Plus 图标组件 ## 快速开始 ### 环境要求 | 软件 | 版本 | 说明 | |------|------|------| | Node.js | 18+ | 前端构建环境 | | Java | 17+ | 后端运行环境 | | Maven | 3.8+ | 依赖管理工具 | | MySQL | 8.x | 主数据库 | | Redis | 7.x | 缓存和会话存储 | ### 1. 启动 MySQL 确保 MySQL 服务已启动,并创建数据库: ```sql CREATE DATABASE IF NOT EXISTS erp_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ``` 然后导入初始化脚本: ```bash mysql -u root -p erp_db < backend/src/main/resources/init.sql ``` ### 2. 启动 Redis Redis 用于验证码存储、登录状态管理(Sa-Token Session)和数据缓存,**必须启动**。 #### Windows 安装 Redis 1. 下载 Windows 版 Redis:https://github.com/tporadowski/redis/releases 2. 解压到任意目录(如 `D:\Redis`) 3. 打开命令行,进入 Redis 目录,启动服务: ```bash redis-server.exe redis.conf ``` #### 验证 Redis 是否启动成功 ```bash redis-cli ping ``` 返回 `PONG` 表示 Redis 运行正常。 #### 将 Redis 注册为 Windows 服务(推荐) 以管理员身份打开命令行: ```bash # 安装为 Windows 服务 redis-server --service-install redis.conf # 启动服务 redis-server --service-start # 停止服务(需要时) redis-server --service-stop ``` #### 使用 Docker 启动 Redis(替代方案) ```bash docker run -d --name redis -p 6379:6379 redis:7 ``` #### Redis 默认配置 | 配置项 | 默认值 | 说明 | |--------|--------|------| | host | localhost | Redis 地址 | | port | 6379 | Redis 端口 | | password | (空) | 密码,默认无密码 | | database | 0 | 数据库编号(0-15) | 如需修改,编辑 `backend/src/main/resources/application.yml` 中的 `spring.data.redis` 部分。 ### 3. 启动后端 ```bash cd backend mvn clean install mvn spring-boot:run ``` 后端运行在 http://localhost:8088 ### 4. 启动前端 ```bash cd frontend npm install npm run dev ``` 前端运行在 http://localhost:5173,自动打开浏览器。 ### 5. 访问系统 - 地址:http://localhost:5173 - 账号:`admin` - 密码:`admin23` > 测试账号由后端 `DataInitRunner` 在每次启动时强制重置,确保始终可用。**生产环境请删除该 Runner**。 ## 生产部署 ### 前端构建 ```bash cd frontend npm run build ``` 产物输出到 `dist/` 目录,部署到 Nginx。 ### 后端打包 ```bash cd backend mvn clean package -DskipTests java -jar target/erp-backend-1.0.0.jar ``` ### Nginx 配置 将 `dist/` 目录和 `nginx.conf` 部署到 Nginx,前端静态文件由 Nginx 直接提供,`/api` 请求反向代理到后端。 ### Docker Compose 部署(推荐) ```bash docker-compose up -d ``` ## 数据库设计 系统共 15 张表,通过 `backend/sql/init.sql` 自动初始化: ### 系统管理 | 表名 | 说明 | |------|------| | sys_user | 用户表 | | sys_role | 角色表 | | sys_menu | 菜单表 | | sys_dept | 部门表 | | sys_user_role | 用户角色关联表 | | sys_role_menu | 角色菜单关联表 | ### 采购管理 | 表名 | 说明 | |------|------| | purchase_supplier | 供应商表 | | purchase_order | 采购订单表 | | purchase_order_item | 采购订单明细表 | ### 销售管理 | 表名 | 说明 | |------|------| | sales_customer | 客户表 | | sales_order | 销售订单表 | | sales_order_item | 销售订单明细表 | ### 库存管理 | 表名 | 说明 | |------|------| | inventory_warehouse | 仓库表 | | inventory_product | 商品表 | | inventory_stock | 库存表 | ### 财务管理 | 表名 | 说明 | |------|------| | finance_record | 财务记录表 | ## 开发规范 ### 前端规范 - 路径别名:`@/` 映射到 `src/` - API 接口统一在 `src/api/` 目录管理 - 新增页面在 `src/views/` 下创建,后端菜单表配置 component 路径即可自动路由 - 按钮权限使用 `v-permission="'模块:资源:操作'"` 指令 - 状态管理使用 Pinia,按模块划分 store - 组合式函数放在 `src/composables/` 目录 ### 后端规范 - 统一返回 `Result` 格式 - 业务异常抛出 `BusinessException`,由全局异常处理器捕获 - Service 层方法使用 `@Transactional` 注解管理事务 - Mapper 层使用 MyBatis-Plus LambdaQueryWrapper 构建查询条件 - 实体类继承 `BaseEntity`,使用 `@TableName` 指定表名 - 数据库字段命名使用下划线分隔(snake_case) ### 接口规范 | HTTP 方法 | 用途 | 示例 | |-----------|------|------| | GET | 查询列表/详情 | `/system/user/list`、`/system/user/{id}` | | POST | 新增 | `/system/user/add` | | PUT | 修改 | `/system/user/update` | | DELETE | 删除 | `/system/user/delete?id=1` | ### 权限标识规范 格式:`{模块}:{资源}:{操作}` | 示例 | 说明 | |------|------| | system:user:add | 用户管理-新增 | | system:user:edit | 用户管理-编辑 | | system:user:delete | 用户管理-删除 | | purchase:order:add | 采购订单-新增 | | sales:order:delete | 销售订单-删除 | ## API 接口列表 ### 认证接口 | 接口 | 方法 | 说明 | 是否需要登录 | |------|------|------|-------------| | /auth/login | POST | 用户登录 | 否 | | /auth/logout | POST | 用户登出 | 是 | | /auth/captcha | GET | 获取验证码 | 否 | | /auth/info | GET | 获取当前用户信息 | 是 | | /auth/profile | PUT | 更新用户信息 | 是 | | /auth/password | PUT | 修改密码 | 是 | ### 用户管理接口 | 接口 | 方法 | 说明 | 是否需要登录 | |------|------|------|-------------| | /system/user/list | GET | 分页查询用户列表 | 是 | | /system/user/{id} | GET | 查询用户详情 | 是 | | /system/user/add | POST | 新增用户 | 是 | | /system/user/update | PUT | 修改用户 | 是 | | /system/user/delete | DELETE | 删除用户 | 是 | | /system/user/batch-delete | DELETE | 批量删除用户 | 是 | | /system/user/reset-password | PUT | 重置密码 | 是 | | /system/user/assign-roles | POST | 分配角色 | 是 | | /system/user/role-ids | GET | 查询用户角色ID | 是 | ### 角色管理接口 | 接口 | 方法 | 说明 | 是否需要登录 | |------|------|------|-------------| | /system/role/list | GET | 查询角色列表 | 是 | | /system/role/add | POST | 新增角色 | 是 | | /system/role/update | PUT | 修改角色 | 是 | | /system/role/delete | DELETE | 删除角色 | 是 | | /system/role/assign-menu | POST | 分配菜单权限 | 是 | ### 菜单管理接口 | 接口 | 方法 | 说明 | 是否需要登录 | |------|------|------|-------------| | /system/menu/tree | GET | 获取完整菜单树 | 是 | | /system/menu/user-menus | GET | 获取当前用户菜单 | 是 | | /system/menu/add | POST | 新增菜单 | 是 | | /system/menu/update | PUT | 修改菜单 | 是 | | /system/menu/delete | DELETE | 删除菜单 | 是 | ### 部门管理接口 | 接口 | 方法 | 说明 | 是否需要登录 | |------|------|------|-------------| | /system/dept/tree | GET | 获取部门树 | 是 | | /system/dept/add | POST | 新增部门 | 是 | | /system/dept/update | PUT | 修改部门 | 是 | | /system/dept/delete | DELETE | 删除部门 | 是 | ## 核心算法说明 ### 树形结构构建(菜单/部门) 采用递归算法将扁平列表转换为树形结构: ```java private List buildTree(List menus, Object parentId) { return menus.stream() .filter(menu -> parentId.equals(menu.getParentId())) .peek(menu -> menu.setChildren(buildTree(menus, menu.getId()))) .collect(Collectors.toList()); } ``` **时间复杂度**:O(n),每个节点只访问一次 **空间复杂度**:O(n),递归栈深度最多为树的高度 ### Long 类型序列化处理 JavaScript 的 Number 类型最大安全整数是 2^53 - 1(约 16 位),而雪花算法生成的 ID 是 18 位 Long 类型,直接传输会导致精度丢失。 **解决方案**:在 JacksonConfig 中将 Long 类型序列化为 String。 ### 批量查询优化(避免 N+1 查询) 查询用户列表时,先查询所有用户,再批量查询所有用户的角色,最后按用户 ID 分组填充: ```java // 1. 查询所有用户 Page page = this.page(new Page<>(pageNum, pageSize), wrapper); // 2. 批量查询所有用户的角色(1次SQL) List userIds = records.stream().map(SysUser::getId).collect(Collectors.toList()); List allRoles = roleMapper.selectRolesByUserIds(userIds); // 3. 按用户ID分组 Map> roleMap = allRoles.stream() .collect(Collectors.groupingBy(SysRole::getUserId)); ``` ## 常见问题 ### Q1: 登录页面显示 502 Bad Gateway **原因**:前端代理无法连接后端服务。 **解决**: 1. 确认后端服务已启动(运行在 http://localhost:8088) 2. 确认前端代理配置正确(vite.config.ts 中 proxy 配置 target 为 http://localhost:8088) ### Q2: 登录后 500 Internal Server Error **原因**:可能是 Redis 未启动或数据库连接失败。 **解决**: 1. 确认 Redis 服务已启动(运行在 localhost:6379) 2. 确认 MySQL 服务已启动,数据库 erp_db 已创建 3. 查看后端日志,定位具体错误 ### Q3: 菜单树不显示 **原因**:可能是角色菜单关联数据缺失。 **解决**: 1. 确认 admin 角色已关联所有菜单权限 2. 查看数据库 sys_role_menu 表是否有数据 ### Q4: 前端控制台报错 "No match found for location" **原因**:动态路由生成失败。 **解决**: 1. 检查后端菜单表中 component 字段是否正确 2. 检查前端路由配置是否正确 ## 贡献指南 1. Fork 本仓库 2. 创建功能分支:`git checkout -b feature/xxx` 3. 提交代码:`git commit -m "feat: xxx"` 4. 推送到远程:`git push origin feature/xxx` 5. 创建 Pull Request ## 许可证 MIT License