资讯动态

基于SpringBoot+Vue的工作量统计系统设计与前后端分离部署实践

发布时间:2026/10/14 23:41:18 来源:尧图企业网站定制
前阵子接了个内部需求某部门要做一套工作量统计系统用来代替月底手工汇总Excel表格的方式。这个系统说大不大说小也不小——多人填报、多角色查看、按项目按月出报表还要能导出存档。我直接用前后端分离的方案来落地后端SpringBootMyBatisMySQL前端Vue两边独立开发独立部署。整套做完再回看工作量统计这类系统非常适合作为全栈练手项目也适合直接改一改塞进公司内部工具里。这篇文章我把完整的设计思路、核心代码、部署过程、以及测试阶段踩过的坑都整理出来想自己动手做一个类似系统的话照着走基本能复现。先说下这套系统能干什么。登录后普通成员可以填报每天的工作内容和工作时长部门负责人可以审核、查看团队维度的日报月报管理员负责维护成员账号和项目信息。数据全程线上流转月末再也不用找每个人要Excel了。统计报表按人、按项目、按月份三个维度展开工作量自动汇总一键导出。文章适合刚接触前后端分离开发的同学也适合想快速搭一套内部管理系统的开发者后端用Java前端用Vue数据库用MySQL技术栈都是国内团队最常用的那一套。1. 系统到底做什么需求拆解与功能设计开发之前先把需求问清楚尤其是“工作量统计”这四个字背后的真实场景。一开始只说是“统计每个人干了多少活”真去聊才发现要细分成很多情况有人一天要做多个任务一个任务跨好几天月底要按人汇总、按项目汇总还要分“已审核”和“未审核”的状态。这些不提前梳理清楚后面改起来非常痛。1.1 工作量统计在真实场景中的痛点没上系统之前多数团队用共享Excel表格统计工作量。月初建一张表每人一行每天往里填几小时、做了什么月底负责人手工汇总。人员一多问题马上出来格式不统一。有的人填“3小时”有的人填“半天”还有人写“上午”汇总时根本没法直接加总。填写不及时。月底补填是常态补填出来的数据基本靠回忆准确性没法保证。权限没法控制。一张表大家都能看有些项目的工时信息本不该全量公开。汇总工作量巨大。负责人要把几十行的碎片记录按人按项目归类还不能只靠Excel函数硬算。历史数据查询困难。翻上几个月前的记录得一个一个打开历史文件。这套系统要解决的就是上面这些事。核心原则是录入标准化统一工作时长单位、流程线上化谁提交谁审核有记录、统计自动化汇总交给SQL和图表不靠人肉。1.2 功能模块怎么拆角色、流程、数据闭环拆功能模块的时候我按“角色-流程-数据”三个维度来思考。系统角色分成三类普通成员自己的工作量填报、查看个人历史记录。部门负责人查看所辖成员的工作量对填报内容做审核查看团队统计报表。系统管理员维护用户账号、角色权限、项目信息。流程上闭环是成员提交工作量 - 负责人审核 - 审核通过后计入统计报表。如果某个填报数据不真实可以驳回并填写理由成员重新修改后再提交。这个审核环节可以保证月度汇总的数据是经过确认的而不只是大家随手填的数字。数据方面工作量填报是最核心的记录表围绕它衍生出项目表、用户表、角色表。报表统计则是从记录表聚合出来的结果。整个系统的数据流并不复杂但每一步都要有明确的状态标记比如记录是“草稿”“待审核”还是“已通过”方便后续统计时过滤。1.3 为什么选前后端分离而不是单页一体项目立项时有人问我这个规模也不大直接用个服务端模板渲染不就行了何必前后端分离。我的判断是这套系统大概率不是一次性交付后续还会扩展移动端、追加统计图表、甚至接入第三方登录前后端分离可以让后续扩展省很多事。前端只通过接口拿数据后端只提供JSON接口边界清楚出问题好定位。另外一个现实好处是开发可以并行。前端负责页面交互后端负责接口和业务逻辑两个人同时开工互不阻塞。我这次前端用Vue框架加开源的组件库搭建后端直接启一个SpringBoot项目写接口数据库表结构定下来后两端的联调效率非常高。做前后端分离最难的反而不是技术是接口约定的管理。接口路径、参数、返回结构必须一开始就统一。我的做法是后端定义一个统一返回结构包含code、message、data三个字段前端封装请求方法统一处理。后面所有接口都走这个结构联调阶段几乎没出现过“解析不到数据”的情况。2. 后端设计与核心接口实现后端基于SpringBoot构建持久层用MyBatis数据存储用MySQL。工作量的月度汇总、项目维度统计这些核心能力本质上都是SQL的聚合查询选MyBatis主要是看中SQL的可控性复杂的统计SQL可以直接写清楚性能也可以针对索引来做优化。2.1 建表要点工作量统计的库表怎么设计数据库表设计决定了后面无论是功能开发还是统计报表都会顺畅很多。这里给出核心表的结构和设计思路。第一张表是用户表字段包含用户ID、用户名、密码BCrypt加密存储、姓名、部门、状态。用户表和角色表是多对多关系中间表存userId和roleId。密码一定不能明文存这是底线。第二张表是工作记录表这是全系统的核心业务表。字段如下字段名类型说明idbigint主键user_idbigint填报人IDproject_idbigint所属项目IDwork_datedate工作日期f_monthvarchar(7)冗余的工作月份格式如2025-01work_hoursdecimal(4,1)工作时长单位小时work_contentvarchar(500)工作内容说明statustinyint0草稿1待审核2已通过3已驳回create_timedatetime创建时间update_timedatetime更新时间这里account特别注意f_month这个冗余字段。work_date本身是日期类型完全可以用DATE_FORMAT函数从work_date里取月份来查询。但实际测试发现一旦数据量上来对work_date加函数运算会让索引失效查询变慢。所以录入数据的时候直接把月份冗余存一份同时在f_month和user_id上建联合索引月度统计查询的速度非常快。这就是典型的“空间换时间”的取舍。第三张表是项目管理表字段包含项目ID、项目名称、项目编号、负责人ID、项目状态、开始结束时间。工作量填报需要选择所属项目这张表就是项目数据源。第四张表是审核记录表记录谁在什么时间审核了哪条工作量记录、审核结果是什么、备注是什么。这个表非常适合追溯万一某条数据统计口径有争议直接查审核记录。2.2 月度工作量统计SQL核心查询怎么写工作量统计系统最关键的查询是按月统计每个人的总工时。这个SQL看起来不难但有几个细节值得注意。基础版SQL如下SELECT u.id AS user_id, u.real_name AS user_name, IFNULL(SUM(w.work_hours), 0) AS total_hours FROM sys_user u LEFT JOIN t_work_log w ON w.user_id u.id AND w.f_month 2025-01 WHERE w.status 2 GROUP BY u.id, u.real_name ORDER BY total_hours DESC这里两个容易踩的坑第一LEFT JOIN的过滤条件不能放在WHERE子句里否则左连接会退化成内连接导致没有填报记录的成员查不出来。所以月份条件放到了JOIN的ON子句里。第二统计口径上只统计status为2已通过的记录草稿和未审核状态的数据不算数否则月底负责人看到的数字和上报的数字对不上。按项目维度的统计类似把它提成一个通用SQL模板SELECT p.id AS project_id, p.project_name, SUM(w.work_hours) AS total_hours, COUNT(*) AS record_count FROM t_work_log w LEFT JOIN t_project p ON w.project_id p.id WHERE w.f_month 2025-01 AND w.status 2 GROUP BY p.id, p.project_name ORDER BY total_hours DESC这段SQL配合前端报表接口使用返回结果直接就是项目维度的汇总数据。2.3 JWT登录鉴权前后端分离时认证怎么做前后端分离的项目不能依赖Session因为前端页面和后端接口可能不在同一个域名下而且移动端以后也要接同一套接口。这里我采用JWT做登录鉴权。流程不复杂用户输入用户名密码后端校验通过后生成JWT令牌返回前端。前端把JWT存在本地存储中每次请求在请求头上带Authorization: Bearer token。后端定义一个拦截器从请求头解析JWT并校验签名和有效期。校验通过后把用户ID和角色信息放进请求上下文供后续业务使用。JWT的密钥要放到配置文件中不要硬编码在代码里。过期时间我设置的是24小时太短影响体验太长有安全风险。对于内部管理类系统24小时合理。拦截器是核心。要放行登录接口其他接口都要校验同时处理token过期时的返回信息。我这边把校验逻辑写成一个HandlerInterceptor在preHandle方法里做解析和校验失败时直接返回401状态码加统一JSON结构。这里有一个要注意的细节预检请求OPTIONS必须直接放行否则前端跨域访问时会被拦截器挡住联调时很容易怀疑人生。2.4 接口清单与参数约束后端做完接口清单大概是这样的接口路径方法说明/api/auth/loginPOST登录返回JWT/api/worklogPOST新增工作量记录/api/worklogPUT修改工作量记录/api/worklog/myGET查询我的填报记录/api/worklog/pageGET分页查询记录负责人/api/worklog/auditPOST审核通过或驳回/api/worklog/exportGET导出Excel/api/stats/monthlyGET月度人员统计/api/stats/projectGET项目维度统计参数约束方面work_hours必须大于0且不超过24work_date不能晚于当前日期。项目经验是后端接口越早做参数校验越好。一开始偷懒没校验测试的时候前端把小数写成了字符串到统计阶段数据直接乱了。后来统一用注解方式做参数校验不合规的请求在进入业务逻辑之前就被挡掉了。3. 前端页面与交互实现前端用的是Vue框架配合组件库后台管理类的页面本身对交互要求不算高关键是表单录入的体验和统计图表的展示。工程结构按页面维度拆分搭配路由和状态管理。3.1 前端工程结构和登录态处理前端工程的结构我按下面这种方式组织页面目录login登录页、layout布局页、dashboard工作台、worklog填报页、worklogList记录列表、statistics统计报表页、project项目管理、user用户管理。请求封装目录统一处理axios实例的创建、请求头注入、响应拦截。路由配置配置页面路径和权限meta信息。状态管理存储用户信息、权限标识、当前选中项目。登录态处理上前端在路由切换前加一个全局前置守卫。如果没有本地存储的token就跳转到登录页如果有token但刷新页面时用户信息为空就调接口重新获取。刷新页面不掉登录态这个细节要处理好否则用户体验很割裂。axios响应拦截器里做统一的错误处理。token过期时返回401拦截器内清除本地存储并跳转登录页。后端返回业务错误时前端弹提示框显示message字段。这些统一的处理逻辑放在拦截器里页面代码就不需要关心错误处理了。3.2 工作量填报页核心交互设计工作量填报页是整个系统前端最核心的部分。设计原则是让成员尽量减少操作成本否则大家都会排斥用系统。我做了三件事来优化填报体验。第一日期默认是今天用户不用每次选。第二项目字段做下拉搜索项目多的时输入关键字直接过滤。第三“保存”和“提交”分开。保存是把记录存成草稿可以继续修改提交则把数据推给负责人审核提交后自己就不能再改了。这个交互设计对应后端status字段的0和1状态。表单校验也要做。工作内容不能少于几个字、时长必填、日期必填这些在前端做一遍快速提示后端再严校验一遍。有同学问为什么前后端都要校验省一端不行吗答案是前端校验是为了用户体验后端校验才是真正的安全防线。绕过前端直接调接口是可以做到的后端不校验等于裸奔。填报记录列表和分页查询也在这个模块里。列表要显示每条记录的状态待审核的显示“待审核”标签已通过的显示“已通过”被驳回的要显示驳回原因和修改按钮。这样成员能及时知道自己的填报是否被确认形成闭环反馈。3.3 统计报表与图表展示统计报表这块前端用柱状图加表格组合的方式展示。柱状图展示每个人月度总工时的对比表格展示明细数据按项目可切换维度。图表本身用开源图表库就能满足不复杂难在数据接入。报表接口返回结构化数据后前端要做一次数据映射把后端字段映射成图表需要的格式。这个映射逻辑抽出来放成一个独立工具函数方便多个页面复用。另一个细节是月份选择器默认当月可以往前翻历史月份。每次切换月份重新请求数据数据加载时加Loading状态体验就不会显得卡顿。导出功能是一个隐藏的刚需。“工作量统计系统”做到后面负责人最关心的就是月底能不能把报表导出发给上级。导出接口由后端生成Excel文件返回二进制流前端通过Blob方式下载。这个功能看似简单但要注意请求时带token如果用普通链接直接访问下载接口请求头里没有Authorization会被拦截器挡在门外。前端必须用axios以blob类型请求再从响应头取文件名。4. 部署上线全流程开发完代码只是第一步真正让系统跑起来还需要部署。前后端分离项目的部署核心思想是前端构建出静态文件交给Nginx托管后端打包成可执行的jar包通过Java命令直接运行。整个过程我按“本地检查 - 环境准备 - 后端部署 - 前端部署 - 上线验证”五步走。4.1 本地打包前要检查什么打包这件事最怕的是本地能跑服务器上起不来。我一般会在打包前检查三个东西第一检查数据库连接配置。本地连接地址往往是localhost打包前要改成服务器对应配置或者直接把配置外置到application-prod配置文件中部署时通过参数指定这样源码包和运行环境彻底分离。第二检查前后端接口地址。前端代码里请求的接口地址如果是localhost打包出来肯定是废的。正确做法是把接口地址写成相对路径如/api由Nginx反向代理转发到后端服务。这样前端构建包不管部署到哪个域名下面都不用改代码。第三检查第三方依赖的版本兼容。强烈建议固定版本号不要用latest。SpringBoot的版本、前端组件库的版本锁定后部署环境才稳定。实际遇到过几次开发时能用重新拉依赖后版本更新导致各种怪异问题排查起来非常耗时间。4.2 服务器基础环境准备部署这套系统需要的环境有JDK运行时、MySQL数据库、Nginx。服务器操作系统我用的Linux发行版这是最主流的部署环境。JDK安装注意版本要和项目一致。SpringBoot版本对JDK版本有要求装错了Jar包直接跑不起来。装完以后在终端里执行java -version看一下当前版本确认无误再继续。MySQL安装后要创建对应的数据库和账号。部署环境里的数据库建议单独创建一个业务账号只授予当前数据库的权限不要直接用root账号跑业务安全考量多一些。创建数据库时指定字符集为utf8mb4这个字符集才能完整支持中文和特殊符号否则导入数据时中文可能变成乱码。Nginx安装完成后默认配置在/etc/nginx/目录下主要改动的是站点配置文件。如果对Nginx配置不熟操作前先把默认配置备份一份改坏了能快速还原。4.3 后端部署jar包运行与进程守护后端项目在本地执行打包命令构建出可执行的jar包上传到服务器指定目录。我用/opt/app作为部署目录jar包直接放里面。第一次启动用下面的命令测试java -jar work-statistics-1.0.0.jar --spring.profiles.activeprod这一步先在前台运行观察启动日志。日志里出现“Started Application”说明启动成功。如果出现报错多半是环境问题比如端口被占用、数据库连不上。这些都解决后再进入下一步。长期运行不能只靠前台启动。我这边用systemd来做进程守护创建服务配置文件[Unit] DescriptionWork Statistics Service Afternetwork.target [Service] Typesimple Userdeploy WorkingDirectory/opt/app ExecStart/usr/local/java/bin/java -jar /opt/app/work-statistics-1.0.0.jar --spring.profiles.activeprod Restarton-failure RestartSec10 [Install] WantedBymulti-user.target配置好之后使用systemctl daemon-reload重载配置然后systemctl start work-statistics启动服务。有了systemd管理即使进程意外退出也会自动拉起重启机器后服务也会自动启动。这一步非常关键线上服务绝对不能裸跑。4.4 前端部署nginx托管与接口反向代理前端构建命令执行后dist目录里就是静态文件。把dist目录里的全部内容上传到服务器放在Nginx配置的站点根目录下。Nginx站点配置的核心是两块静态文件托管和接口反向代理。配置如下server { listen 80; server_name your-domain.com; root /opt/www/work-ui; index index.html; location /api/ { proxy_pass http://127.0.0.1:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location / { try_files $uri $uri/ /index.html; } }第二段location里那行try_files $uri $uri/ /index.html非常关键。Vue是单页应用路由切换是用前端路由实现的如果用户在页面上按F5刷新Nginx会去找对应的真实文件找不到就会404。加上这行配置后所有找不到的路径统一回退到index.html前端路由接手渲染对应的页面。接口代理这段把/api/开头的请求转发到后端8080端口的服务上。这样前端页面和接口就处于同一个域名下不跨域省掉很多跨域配置的麻烦。4.5 数据库初始化与上线检查数据库初始化用的是项目里的SQL脚本。执行完脚本后可以先插入管理员账号然后登录后台创建部门、项目、测试账号走通一遍核心业务流程。上线检查清单我一般固定看这几项登录页能不能正常访问能不能登录成功。刷新一个带路由的页面比如/dashboard会不会404。填报一条工作量记录看能不能提交。负责人账号登录看能不能看到待审核记录正常审核通过。切到统计报表页看图表数据是否与数据库查询结果一致。导出Excel确认下载的文件能正常打开。这六项全部走通系统基本上就稳定可用了。我还会顺手测一下非法路径访问会不会弹到登录页、连续输错密码会不会被拦住这些体验细节对内部系统的口碑影响很大。5. 常见问题与排查实录测试和试运行阶段我其实遇到了不少问题。多数问题集中在环境配置和发布遗漏上代码本身的Bug反而比较少。挑几个最典型的问题记录一下给大家排雷。5.1 前端请求接口404 / 502现象是页面能打开但列表数据为空浏览器的开发者工具里看到请求接口返回404或502。404一般是接口路径不对检查一下请求路径和后端Controller的RequestMapping路径是否完全一致。502则基本是后端服务没起来或者Nginx代理地址写错了。排查的时候先去服务器上看后端日志日志是最诚实的。还有一种非常容易踩的情况本地开发时前端走Vite的代理路径是对的部署时忘了把接口返回路径改成相对路径代码里硬编码了localhost那在服务器上必然白屏。所以前端请求统一走相对路径加Nginx代理不要硬编码。5.2 打包后前端页面刷新404这是单页应用部署最常见的坑。部署完后访问首页正常点进某个子页面再按F5页面直接404。原因就是Nginx没有配置单页回退静态文件服务器去找不存在的物理路径。解决方案就是上面写的try_files $uri $uri/ /index.html。这个配置加上后问题立即消失。5.3 数据库连接失败与时区报错后端启动时经常遇到两类数据库报错。一类是连接被拒绝检查数据库服务是否真的启动了、端口是否开放、用户名密码是否正确。另一类是时区报错MySQL连接串需要加上时区参数。我当时遇到的报错信息类似“连接数据库时区无法识别”解决方法是连接串里显式指定serverTimezoneAsia/Shanghai。或者直接在MySQL配置里设置默认时区。这个报错本质是Java连接器版本较新时要求明确指定时区。5.4 用户反馈提交不进去、数据不见了试运行期间有成员反馈提交不进去后端日志看到创建记录的接口返回了参数校验失败。查下来是前端传的work_hours字段类型是字符串后端用注解校验数值范围时直接报类型不匹配。这个在联调阶段就应该发现的后端校验注解里明确标注了类型但我一开始图省事只做了范围校验没做类型校验。后面在全局异常处理器里增加了类型转换失败的处理并返回明确的中文提示问题才算闭环。“数据不见了”则多半出在审核未通过和统计口径上。成员以为填了就算数负责人这边还没审核月度报表自然不包含这些数据。这不算是Bug是没跟使用方讲清楚流程。后来在统计报表页面增加了状态说明文字类似“报表仅统计已审核通过的工作记录”用户再没问过这类问题。5.5 一套可以直接抄的避坑清单最后整理一份避坑清单都是实际项目里用教训换来的数据库连接串一定要带时区参数连接池大小要设置合理值。后端全局异常处理器必须覆盖参数校验异常和HTTP状态码异常否则前端拿到的提示信息全是英文技术术语使用方看了也不知道什么意思。部署上传jar包前用jps或ps -ef看一下旧进程是否还占用端口。JWT密钥和数据库密码不要硬编码在代码里放到配置文件中并在部署时替换。定时备份数据库内部系统也要备份。我是用系统自带的crontab每天凌晨备份一次保留最近7天的备份文件数据量不大成本非常低。上线前把所有需要手动执行的SQL脚本整理成一个文件按版本号命名。后面加字段、加表都按这个规范来方便追溯也方便新环境初始化。这套系统从开发到上线核心的时间其实花在需求梳理和细节校验上前后端分离本身并不复杂。我个人在实际操作中最满意的部分是报表统计和审核流程的闭环有这两个模块系统才真正解决了手工汇总Excel的痛点。测试阶段收到的最有价值的反馈是“导出Excel能不能加个文件名带月份”这个改动很小但使用方满意度直接提升一个档次。这类内部系统做完之后额外扩展的空间还有不少。比如在填报基础上加日报周报汇总、把工作量数据接入月度绩效计算、增加按季度维度的趋势图。底层的表结构和统计逻辑是稳的往上加功能只是时间问题。最后再提醒一点项目里所有环境相关的配置能外置就外置这是后续运维体验好不好的分水岭。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑