
装修行业做管理系统的痛点我太有体会了。之前帮一个做整装的朋友看过他们的项目流转合同、设计、施工、材料、验收全是Excel和微信群来回倒项目一多必然乱套。后来我们一起梳理了一套基于SpringBootVue的在线装修管理系统从设计到落地跑通全流程这里把完整的技术方案和实践经验整理出来。这套系统用SpringBoot搭建后端服务Vue负责前端页面交互MyBatis做数据持久层MySQL存业务数据前后端分离代码结构清晰特别适合中小型装修公司做项目管理和想拿真实项目练手的Java全栈开发者。无论是做毕业设计、个人项目沉淀还是企业级二次开发这套系统都有很强的参考价值。1. 在线装修管理系统的整体业务拆解1.1 为什么装修公司需要一套管理系统装修行业的业务链条特别长从获客、量房、出方案、报价、签合同到开工交底、材料进场、施工巡查、节点验收、竣工交付中间还穿插着增项变更和售后维保。传统的人工管理方式问题往往出在“信息断层”上设计师不知道工地实际进度项目经理不知道材料到没到货老板想统计某个项目的毛利得翻半天Excel。这些问题的本质是业务流程没有形成闭环每个环节的信息都是割裂的。系统要做的事情就是把这几个核心角色——客户、设计师、项目经理、材料商、财务——统一拉到一个平台上。在线装修管理系统源码的核心价值不在“在线”两个字而在于把装修业务的每一个节点变成一条条可查询、可跟踪、可统计的数据。客户能看进度施工队能报节点管理层能掌握全局这才是系统真正解决的需求。1.2 核心业务模块划分围绕装修公司的日常工作系统按角色和业务线大致拆成下面几个模块客户管理记录业主基本信息、房屋地址、户型面积、装修预算、意向状态支持销售跟进记录。设计管理上传设计方案、效果图、施工图记录设计费报价与方案版本。合同管理管理装修合同、补充协议、增项变更单关联客户和设计方案。施工管理拆分为开工、水电、泥瓦、木工、油漆、安装、竣工等节点项目经理按节点上报进度和现场照片。材料管理材料清单、采购单、出入库记录材料与施工节点关联。财务管理收款计划、实际收款、退款、发票记录形成简单的项目收支台账。系统管理用户、角色、权限、菜单管理这是每个后台系统的基本盘。1.3 关键业务流程与状态流转业务模块之间不是孤立的而是靠状态流转串起来的。我把最核心的一条主链路梳理一下客户状态从“意向客户”变为“已签合同”在系统中同步生成设计任务和施工项目施工项目启动后项目经理按节点上报进度每个节点状态有“未开始、进行中、待验收、已完成”材料采购单会根据施工节点自动触发提醒财务收款计划关联合同付款方式。这条链路里状态机设计是系统能不能真正“好用”的关键。如果状态直接扔一个字符串字段硬写后面统计和权限控制都会非常别扭。建议每个实体都设计独立的status字段并在Service层封装统一的状态流转方法不要散落在各个Controller里。2. 技术选型SpringBootVueMyBatisMySQL的组合逻辑2.1 后端为什么选SpringBoot现在Java后端做业务系统SpringBoot基本是默认选项几乎没有第二个值得纠结的框架。它的核心价值在于“约定大于配置”以前SSH时代写一堆XML配置才能跑起来的工程现在一个启动类加几个注解就搞定了。对内嵌Tomcat的支持也省掉了单独部署Web服务器的麻烦本地开发一个main方法直接启动非常符合快速迭代的需求。但是要注意SpringBoot版本迭代太快很多老项目升级的时候踩坑不断。如果你是新建项目我建议直接用稳定版本不要追求最新。用Spring Initializr生成项目时Java版本、Maven仓库、依赖版本最好和团队保持一致否则不同人拉下来跑不起来纯属浪费工时。网上那些“SpringBoot版本太高”导致启动报错的帖子几乎都是依赖版本和JDK版本不匹配造成的。2.2 前端为什么选VueVue在国内前端圈子的普及率非常高核心原因是学习曲线平缓模板语法直观组件化开发效率高。对于装修管理系统这种典型的后台管理项目页面大多以表格、表单、弹窗、统计卡片为主Vue加Element UI或者Element Plus几乎可以“所见即所得”地搭建界面。Vue 3是目前的主流版本配合Composition API写业务逻辑比Options API更清晰。不过如果你要维护老项目Vue 2的项目存量依然很大网上搜到的大部分装修管理系统源码也都是Vue 2写的接手的时候看清楚package.json里的版本别混着学。2.3 MyBatis与MySQL为什么是经典搭配MyBatis相比JPA和Hibernate最大的优势是SQL由开发者完全掌控。装修管理系统的查询场景特别复杂比如按客户状态筛选、按日期范围统计收款、按材料分类汇总库存这些SQL写起来不难但用JPA的Criteria API写就非常痛苦。MyBatis直接用XML写动态SQLif判断、foreach遍历、choose分支都是很自然的写法。MySQL这边没什么好说的开源、轻量、稳定中小型项目首选。值得注意的是字符集和排序规则建库的时候必须用utf8mb4别用utf8否则客户名字里带个生僻字前端传过来存进去直接变问号这种问题排查起来特别隐蔽。2.4 整体项目结构规划我采用标准的Maven多模块单工程结构注意不是多模块Maven项目而是单工程内部分层这样结构简单、适合中小型团队。后端包结构如下com.decoration ├── controller # 接口层 ├── service # 业务层 │ └── impl ├── mapper # MyBatis Mapper接口 ├── entity # 数据库实体 ├── dto # 数据传输对象 ├── vo # 视图对象 ├── config # 配置类 ├── common # 通用工具、统一返回、异常处理 └── security # 登录认证与权限前端用Vue CLI或Vite创建工程src目录下同样按模块组织views、components、router、store、api。这套结构最大的好处是前端页面能很方便地对应到后端的Controller一个装修项目模块从前到后一条线拉通新人接手也容易上手。3. 数据库设计装修业务领域的建模思路3.1 核心表结构设计数据库设计是整个系统最重要的地基我见过太多项目最终死在一张表上两百个字段、关联关系乱成一团。装修管理系统的表设计我按业务域拆成几大块客户域customer客户表、customer_follow跟进记录表合同域contract合同主表、contract_item合同明细表、contract_change增项变更表设计域design_scheme设计方案表、design_file设计文件表施工域project施工项目表、project_node施工节点表、node_progress节点进度上报表材料域material材料表、purchase_order采购单表、purchase_item采购明细表、stock_record出入库记录表财务域payment_plan收款计划表、payment_record收款记录表系统域sys_user、sys_role、sys_menu、sys_user_role、sys_role_menu核心的客户表和施工项目表可以单独拿出来说。customer表除了姓名、电话、地址这些基础字段一定要留几个扩展字段比如来源渠道、意向程度、房屋面积、预算区间这些字段后续做运营统计的时候非常有用。3.2 施工节点表与进度上报设计施工项目的状态流转是装修业务区别于其他管理系统的核心特征。我设计了project_node表来存储每个施工节点的定义比如“水电改造”“泥瓦工程”“木工制作”每个节点有排序号、计划开始时间、计划结束时间、实际开始时间、实际结束时间、状态、负责人。项目启动时系统根据项目类型自动初始化一批节点项目经理每日或每周上报节点进度填写完成百分比上传现场照片。这里有个经验不要把百分比当成一个纯展示字段一定要参与计算。项目整体进度可以取所有节点百分比的平均值也可以按节点权重加权平均我建议在project表里加一个progress字段每次节点上报后由后端统一重新计算而不是每次查询时现算否则数据量大了以后报表接口会越写越慢。3.3 关键字段与索引设计规范字段类型和索引是数据库设计里容易被忽略但影响极大的细节。几个关键点金额字段用decimal(10,2)别用float或double不然对账差一分钱能把人逼疯。时间字段统一用datetime不用timestamp避免2038年问题。状态字段用tinyint不要用varchar存中文状态码加注释Java里用枚举对应。所有表都要有id主键、create_time、update_time、deleted逻辑删除标记。逻辑删除字段虽然麻烦但装修行业的数据纠纷比较多物理删除用户数据风险很大建议保留。索引方面customer表对phone建普通索引因为客户查询大多按手机号或姓名模糊搜索project表对customer_id和status建联合索引因为列表页最常用的筛选条件就是“某个客户的项目”和“某状态的多个项目”payment_record表对project_id建索引统计收款的时候能明显感觉到差异。4. 后端核心功能落地从工程骨架到业务接口4.1 SpringBoot工程初始化与配置我建议直接用Spring Initializr生成基础工程选择Java 8或Java 11、Spring Boot 2.7.x这是目前兼容性最稳的组合。Spring Boot 3.x也出来几年了但强制要求JDK 17如果团队里有人还在用JDK 8开发老项目混合维护会很痛苦所以稳定压倒一切。生成工程后核心依赖文件pom.xml需要添加MyBatis Starter、MySQL驱动、Lombok、Spring Security如果做权限等。配置文件application.yml里几个容易踩坑的地方单独列出来spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/decoration?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: root password: 123456 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.decoration.entity configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl这段配置里最值得说两句的一个是serverTimezone必须设置MySQL 8的驱动默认要求时区不设直接报错另一个是map-underscore-to-camel-case必须开这样数据库字段user_name和Java属性userName才能自动映射否则每个实体都要写一堆ResultMap相当痛苦。4.2 登录认证与权限控制装修管理系统里有客户、设计师、项目经理、财务、管理员等多种角色权限控制必须做。我先说结论如果不想引入太重的框架用Spring Security加JWT最合适如果项目比较急直接用拦截器加Redis会话控制也够用。我自己的项目用的是Spring Security加JWT一套配置下来思路如下用户登录成功后后端生成JWT令牌包含用户ID、用户名、角色编码设置过期时间。前端每次请求在Header里带上Authorization: Bearer token。后端写一个JWT过滤器校验令牌合法性把用户信息存入SecurityContext。接口上用PreAuthorize(hasAuthority(admin))控制角色权限。一定要好好处理异常JWT过期、签名错误、无权限访问都必须返回统一的JSON格式不要堆栈信息直接抛给前端。可以写一个全局异常处理器把认证异常、业务异常、参数校验异常统一转换为Result对象返回这是工程规范里特别重要的一环。4.3 MyBatis核心用法与动态SQL实战MyBatis最强大的地方是动态SQL装修管理系统的复杂查询基本都靠它。我做了一个项目列表动态查询的例子非常典型select idselectProjectList resultTypecom.decoration.vo.ProjectVO SELECT p.*, c.name AS customer_name, c.phone AS customer_phone FROM project p LEFT JOIN customer c ON p.customer_id c.id where if teststatus ! null AND p.status #{status} /if if testcustomerName ! null and customerName ! AND c.name LIKE CONCAT(%, #{customerName}, %) /if if teststartDate ! null AND p.create_time gt; #{startDate} /if if testendDate ! null AND p.create_time lt; #{endDate} /if /where ORDER BY p.create_time DESC /select注意几个细节like查询用CONCAT拼接而不是直接写%#{name}%避免参数绑定问题时间比较用大于等于和小于等于而不是between因为between的边界有时候不是想要的where标签自动处理第一个and关键字比手动写where 11优雅得多。4.4 批量插入与更新操作项目管理里有一个高频场景创建项目时初始化一批施工节点。如果一条一条insert十几条数据就要访问数据库十几次性能很差。MyBatis的批量插入用foreach标签insert idbatchInsertNodes INSERT INTO project_node (project_id, node_name, sort_order, plan_start, plan_end, status) VALUES foreach collectionlist itemnode separator, (#{node.projectId}, #{node.nodeName}, #{node.sortOrder}, #{node.planStart}, #{node.planEnd}, #{node.status}) /foreach /insert注意MySQL默认的max_allowed_packet限制一次别插太多条我通常控制在200条以内。批量更新的话MyBatis原生支持比较繁琐如果用了MyBatis-Plus直接调saveBatch和updateBatchById底层已经帮你拼好批量SQL简单很多。不过原生MyBatis理解了这个foreach原理换成MP也只是换个方法名的事。4.5 常见业务接口示例项目进度上报进度上报是装修系统里最有业务特色的接口。前端传过来的是节点ID、完成百分比、现场照片URL列表、备注文字后端要做的事情不止是update一行数据Transactional(rollbackFor Exception.class) public void reportProgress(ProgressReportDTO dto) { // 1. 校验节点是否存在且属于当前项目经理 ProjectNode node nodeMapper.selectById(dto.getNodeId()); if (node null) { throw new BusinessException(节点不存在); } // 2. 更新节点状态和百分比 node.setProgress(dto.getProgress()); node.setStatus(dto.getProgress() 100 ? 3 : 2); node.setActualEnd(dto.getProgress() 100 ? new Date() : null); nodeMapper.updateById(node); // 3. 写入进度上报记录 NodeProgress progress new NodeProgress(); progress.setNodeId(node.getId()); progress.setProgress(dto.getProgress()); progress.setRemark(dto.getRemark()); progress.setPhotos(String.join(,, dto.getPhotoUrls())); progress.setReportTime(new Date()); nodeProgressMapper.insert(progress); // 4. 重新计算项目整体进度 recalcProjectProgress(node.getProjectId()); }这个接口用Transactional控制事务任何一步失败都回滚。进度上报记录单独建表方便后续追溯“这个节点什么时候报到百分之多少”比只更新一个字段靠谱得多。5. 前端核心功能落地Vue项目管理后台实战5.1 项目初始化与依赖安装前端工程我建议直接用Vite创建相比WebpackVite的开发服务器启动速度快得不是一点半点。npm create vitelatest decoration-web -- --template vue cd decoration-web npm install vue-router4 pinia element-plus axiosElement Plus的按需引入用unplugin-auto-import和unplugin-vue-components这两个插件能省掉很多手动import的代码但第一次配置容易踩坑如果觉得麻烦可以先全量引入。注意Vite和Node版本有对应关系Node版本太旧跑不起来报错的时候先查这个。5.2 路由配置与登录守卫Vue Router做后台路由配置要点是路由懒加载和登录守卫。装修系统根据角色去显示不同菜单路由表里通过meta字段标记角色const routes [ { path: /login, component: () import(/views/Login.vue) }, { path: /, component: () import(/layout/Index.vue), redirect: /dashboard, children: [ { path: project/list, name: ProjectList, component: () import(/views/project/List.vue), meta: { title: 项目管理, roles: [admin, manager] } } ] } ]路由守卫在跳转前检查token没有token一律踢回登录页有token的话再根据roles判断当前用户有没有权限访问这个页面。登录状态存Pinia里顺便持久化到localStorage刷新页面后重新拉取用户信息。5.3 Axios封装与接口对接Axios封装是前端工程化的基本功。我在项目里做了一个统一封装的request模块处理baseURL、token注入、响应拦截、错误统一提示几个事import axios from axios import { ElMessage } from element-plus const request axios.create({ baseURL: /api, timeout: 10000 }) request.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }) request.interceptors.response.use( response { const res response.data if (res.code ! 200) { ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message)) } return res.data }, error { if (error.response?.status 401) { localStorage.removeItem(token) window.location.href /login } else { ElMessage.error(error.message || 网络异常) } return Promise.reject(error) } ) export default request关键点是响应拦截器直接返回res.data这样业务代码里拿到的就是后端返回的实际数据对象不用每处都写res.data.data清爽很多。5.4 核心页面实现思路项目详情与进度时间线项目管理页面是这个系统里最能用上Vue组件化能力的页面。列表页用Element Plus的el-table展示项目列表支持状态筛选、客户姓名搜索、分页。点击详情进入项目详情页上半部分是项目基本信息卡片中间是用el-steps展示的施工节点总览底部是每个节点上报记录的el-timeline时间线。时间线组件在这里非常合适因为装修施工的进度天然就是一条时间线每个节点上报就是时间线上的一个点。客户端小程序或H5如果也接入这套后端前后端共用同一套接口前端页面只要把接口数据适配成组件需要的格式就行。5.5 Vue3组合式API的实践感受做这套系统前我一直用Vue 2的Options API这次全程用Vue 3的Composition API最大的感受是业务逻辑的聚合度高了很多。以前一个进度上报页面data、methods、computed分散在代码里同一个业务的数据和逻辑可能隔了几百行用setup函数后进度上报相关的ref、函数、computed都写在同一个区域后续维护定位问题快很多。如果有人接手建议先看store里的状态管理再看页面里的逻辑组织方式通常一套下来就能搞清楚系统的脉络。6. 环境准备、部署上线与常见问题排查6.1 从零搭建开发环境拿到源码第一步是搭开发环境。需要的工具清单如下JDK 8或11配置JAVA_HOME环境变量。Maven 3.6以上配置阿里云镜像加速依赖下载。MySQL 8.0安装完设置root密码运行项目提供的sql脚本建库建表。Node.js 16以上npm或yarn安装前端依赖。IDE推荐IDEA后端导入Maven工程前端用VSCode或IDEA打开都行。MySQL是新手最容易卡住的环节我建议用命令行安装加Workbench图形化工具的组合。命令行安装省心Workbench负责建表和查数据。装完MySQL记得检查服务有没有启动Windows上服务列表里找不到就打开管理工具里的服务手动启动一下。6.2 常见问题速查表开发调试过程中遇到的问题我整理成一张速查表都是高频踩坑点现象原因解决方案SpringBoot启动报DataSource相关错误MySQL未启动或配置的账号密码不对先确认能命令行连上MySQL再检查application.ymlMyBatis mapper接口绑定报错mapper.xml的namespace写错或方法id不匹配对照Mapper接口方法名和XML里的id前端请求接口404后端接口路径和前端api路径不一致或未配置代理Vite配置server.proxy把/api代理到后端端口数据插入成功但没写入数据库可能是事务没提交或使用了逻辑删除字段导致查询被过滤检查是否有Transactional且没抛异常查VO里deleted字段默认值中文乱码数据库字符集不是utf8mb4或连接串没加characterEncoding建库时指定utf8mb4连接串加characterEncodingutf8前端白屏路由懒加载失败或JS报错打开F12控制台看具体报错先解决首个异常登录成功后权限接口403Spring Security放行了登录接口但未放行其他接口或角色编码不匹配检查SecurityConfig的放行规则和角色编码本地后端启动端口被占用8080端口被其他进程占用application.yml改server.port或用命令查占用进程6.3 SpringBoot版本过高和MyBatis兼容问题前面提到SpringBoot版本选择要保守这里展开说说。Spring Boot 3.x相比2.x改动很大底层从javax包迁移到了jakarta包MyBatis官方适配也分了两条线mybatis-spring-boot-starter 2.x对应Spring Boot 2.x3.x对应Spring Boot 3.x。如果你新建项目时Spring Initializr默认选了3.x然后又去网上找了一个2.x的starter依赖启动时报ClassNotFoundException是一定的。我建议最省事的做法是Spring Boot 2.7.x mybatis-spring-boot-starter 2.3.x MySQL 8 JDK 8这套组合我实测下来最稳。如果你想用Spring Boot 3.x就要对应JDK 17和mybatis-spring-boot-starter 3.x同时注意代码里javax.sql改成jakarta.sql相关包改起来不复杂但新手容易被这个坑劝退。6.4 部署上线与后续扩展方向本地开发跑通后部署上线有两种主流方式传统云服务器部署和Docker部署。传统方式简单直接后端打包成jar前端npm run build生成dist目录用Nginx托管前端静态文件并反向代理后端接口。Docker方式适合维护多环境用Dockerfile分别构建前端和后端镜像再用docker-compose编排MySQL、后端、前端三个容器。这套系统的扩展空间也很大如果后面想接工地监控和进度可视化管理前端可以用vue-video-player去播放视频流后端只要预留视频地址字段就行。另外如果想把设计图、合同附件等文件统一管理可以引入对象存储服务或MinIO私有化部署代码层面只需要封装一个文件上传下载的接口。最后分享一点个人体会系统做完了我最大的感受是技术框架本身并不难难的是把装修行业的业务规则理解透再用代码表达出来。比如“增项变更”这个场景合同金额、收款计划、施工范围都可能发生变化如果不做版本记录后续对账时就是一笔糊涂账。我带着这些业务思考去做数据库设计和接口设计项目的品质感明显不一样。如果你只是在网上找一个源码跑通然后写论文那这套SpringBootVue的装修管理系统能帮你快速理解前后端分离模式下业务系统的常规写法但如果你真的想做一个能用的产品建议多到施工现场和项目经理聊一聊你会发现很多系统设计时根本没想到的真实需求。技术会过时但对业务的理解深度才是这类系统真正值钱的地方。