资讯动态

工作量统计系统开发实战:SpringBoot+Vue3前后端分离架构

发布时间:2026/10/15 9:06:19 来源:尧图企业网站定制
1. 工作量统计系统的核心定位它到底解决什么问题先聊一个很现实的问题为什么需要一套独立的工作量统计系统很多团队一开始都用共享表格、聊天记录接龙来统计大家干了多少活一开始十几个人还能凑合等团队上了几十人、任务拆到子任务级别、还要按周或者按月汇总绩效数据的时候表格方案直接崩盘——数据对不上、漏报瞒报没人知道、领导要报表的时候你得熬一整夜手工整理。这套系统解决的就是这些痛点。它的核心定位是把“谁、在什么时间、做了哪个任务、花了多少工时、产出是什么”这些信息从一个靠自觉填报的分散状态收拢成一个有权限管控、有审批流程、有量化报表的集中管理平台。简单说就是从“口说无凭”变成“系统留痕”。具体到技术实现上项目采用 Java SpringBoot 作为后端服务框架Vue3 作为前端界面框架MyBatis 作为数据持久层框架搭配 MySQL 存储业务数据整体采用前后端分离架构。这套组合在国内的企业级管理系统里非常成熟招聘市场上人才储备也充足后续找人维护不用发愁。从使用场景来看它适用于以下几类情况项目型团队按项目拆任务统计每个成员在项目上的投入工时。部门日常管理记录日常事务性工作的完成情况和工作量。跨部门协作 A 部门提需求B 部门承接实施系统里留痕结算时有据可查。绩效考核辅助为绩效评定提供量化数据支撑减少主观争议。如果你正好需要开发类似系统或者你想学习一套完整的、可以直接落地的前后端分离项目源码这篇内容会从业务设计、数据库建模、后端接口、前端页面到问题排查完整走一遍。2. 需求梳理与业务边界开工前必须定清楚的几件事2.1 工作量统计的核心指标怎么定义工作量这个词听着简单真落到系统设计里要先回答几个问题按什么单位统计是按“小时”还是按“任务个数”一个任务可以拆分给多个人吗任务是先派发再确认还是先填报再审批统计周期怎么算按自然周、自然月还是按项目周期我在做类似系统的时候通常是这么设计的工作量 有效任务工时。每个任务由负责人创建可以指派给多个执行人每个执行人填报自己在该任务上的实际工时然后由负责人或管理员审批。审批通过后的工时才进入统计报表未审批的和被驳回的不计入。这套流程比单纯让员工自己填一个总数要严谨得多也方便后续追溯。还有一种做法是“派工单模式”管理员直接给成员派活成员只能确认不能自己填工时。这种模式适合任务分配非常明确的团队但灵活性差一些。当前这个项目采用的更偏向填报加审批的模式兼顾了灵活性和管控。2.2 角色权限的划分工作量系统涉及的数据比较敏感权限设计不能马虎。一般的角色划分如下角色核心权限系统管理员用户管理、角色配置、数据字典、系统参数、查看全部报表项目负责人创建项目、创建任务、审批工时、查看本项目报表普通成员填报工时、查看个人报表、查看项目公开信息这套权限模型用 SpringBoot 的拦截器加注解就能实现配合前端路由守卫做双保险。后端是真正的权限控制点前端隐藏按钮只是提升体验千万不能把权限安全寄托在前端。2.3 功能模块拆分整个系统按我的习惯会拆成五个核心模块用户认证模块登录、退出、密码加密存储、Token 鉴权。项目管理模块项目增删改查、项目成员维护、项目状态管理。任务与工时模块任务创建、任务指派、工时填报、工时审批。统计报表模块个人维度、项目维度、时间维度的多条件统计。系统管理模块用户管理、角色分配、操作日志、数据字典。这五个模块边界清晰每个模块都能独立开发测试前后端对接起来也方便。从源码结构上看后端包结构按模块划分前端页面按视图划分这一套组织方式对后续扩展非常友好。3. 数据库设计工作量统计系统的地基怎么打3.1 核心表结构规划数据库设计决定了这个系统能走多远。我建议核心表不要少于八张包括用户表、角色表、用户角色关联表、项目表、项目成员表、任务表、任务执行人表、工时记录表加上操作日志表。拿任务表举例关键字段大致如下CREATE TABLE task ( id BIGINT PRIMARY KEY AUTO_INCREMENT, project_id BIGINT NOT NULL COMMENT 所属项目ID, task_name VARCHAR(200) NOT NULL COMMENT 任务名称, task_desc TEXT COMMENT 任务描述, priority TINYINT DEFAULT 1 COMMENT 优先级 1低 2中 3高, status TINYINT DEFAULT 0 COMMENT 状态 0待开始 1进行中 2已完成 3已取消, creator_id BIGINT NOT NULL COMMENT 创建人ID, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_project_id (project_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT任务表;工时记录表是整个系统的核心需要特别注意每个字段的含义CREATE TABLE work_log ( id BIGINT PRIMARY KEY AUTO_INCREMENT, task_id BIGINT NOT NULL COMMENT 任务ID, user_id BIGINT NOT NULL COMMENT 填报人ID, work_date DATE NOT NULL COMMENT 工作日期, work_hours DECIMAL(4,1) NOT NULL COMMENT 工时支持0.5小时粒度, work_content VARCHAR(500) COMMENT 工作内容描述, status TINYINT DEFAULT 0 COMMENT 0待审批 1已通过 2已驳回, approver_id BIGINT COMMENT 审批人ID, approve_time DATETIME COMMENT 审批时间, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_task_id (task_id), KEY idx_user_id (user_id), KEY idx_work_date (work_date), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT工时记录表;3.2 设计时容易忽略的三个细节第一工时字段建议用 DECIMAL 而不是 INT因为实际填报时经常出现 3.5 小时、0.5 天这种粒度用整数会逼着用户四舍五入数据失真。第二所有业务表都要带 create_time 和 update_time排查问题的时候能少掉很多头发。第三逻辑删除优于物理删除尤其是工时和任务这种数据后来发现某个数据被直接物理删除找不回来那种心情真的很难受。建议表中加一个 deleted 字段查询时默认过滤。索引设计上不要盲目加索引要根据查询条件来。工时记录表最常见的查询是按 userId workDate 查个人某段时间的工时按 projectId taskId 查项目维度的工作量所以索引要优先覆盖这两个方向。4. 后端核心实现SpringBoot MyBatis 的关键细节4.1 分层架构与包结构后端如果用单一 Controller 写到底前期是爽后面想死的心都有。建议按经典四层结构来组织Controller 层接收请求参数校验返回统一响应体。Service 层业务逻辑事务控制审批规则校验。Mapper 层MyBatis 数据访问SQL 写在 XML 里避免注解 SQL 混在 Java 代码中难维护。DTO/VO 层前端交互的数据载体不要直接暴露数据库实体。统一响应体我一般这样设计public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(操作成功); result.setData(data); return result; } public static T ResultT error(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }这样前后端对接时只需要约定 code 和 message 的语义不需要每个接口单独讨论返回格式能省很多沟通成本。4.2 登录认证与 Token 机制工作量系统肯定不能裸奔登录认证是标配。常用的方案是 Spring Security JWT但对于这个体量的系统可以不用 Spring Security 那么重直接用拦截器 JWT 也能实现代码更少也好理解。核心逻辑如下用户登录成功后后端生成 TokenToken 里携带 userId 和角色信息。前端把 Token 存在本地每次请求放在请求头 Authorization 里。后端写一个拦截器从请求头解析 Token解析失败直接返回 401。需要做权限控制的方法上用自定义注解标记角色拦截器里校验。密码存储必须用 BCrypt 加密绝对不能明文存数据库。我见过有项目把密码明文放在数据库里一旦数据库泄露所有账号都完蛋这是非常严重的低级错误。4.3 工时填报与审批的业务逻辑实现工时填报是最容易出现并发问题的环节。举个例子用户提交一个任务工时时系统需要校验该任务是否已结束、当天工时是否超出限制、该用户是否有权限操作这个任务。这些校验必须放在 Service 层的事务里不能只靠前端表单校验。审批环节要注意状态冲突。审批过程中同一份工时记录不能被两个人同时审批否则会出现重复计数。我处理的办法是加一个乐观锁版本号更新时带上版本条件更新影响行数为 0 就说明数据已被别人改过Update(UPDATE work_log SET status #{status}, approver_id #{approverId}, approve_time NOW() WHERE id #{id} AND status 0) int approveWorkLog(Long id, Integer status, Long approverId);这里最关键的就是 WHERE 条件里加上了 status 0意思是只有待审批状态才能更新成功。如果两个人同时点了审批第二个人的语句会因为状态已经变了而更新 0 行Service 层就能感知到冲突并提示“该记录已被审批”。4.4 MyBatis 动态 SQL 处理复杂统计查询统计报表功能是工作量系统里 SQL 最复杂的地方因为它涉及多表关联、条件筛选、分组和聚合。MyBatis 的动态 SQL 在这里优势非常明显。比如统计某个时间段内每个成员的累计工时可以这样写select idstatUserWorkHours resultTypemap SELECT u.id AS userId, u.real_name AS realName, IFNULL(SUM(wl.work_hours), 0) AS totalHours, COUNT(DISTINCT wl.task_id) AS taskCount FROM sys_user u LEFT JOIN work_log wl ON wl.user_id u.id AND wl.status 1 AND wl.work_date BETWEEN #{startDate} AND #{endDate} where if testprojectId ! null AND wl.task_id IN (SELECT id FROM task WHERE project_id #{projectId}) /if if testdeptId ! null AND u.dept_id #{deptId} /if /where GROUP BY u.id, u.real_name ORDER BY totalHours DESC /select这段 SQL 用 LEFT JOIN 保证没有填报工时的成员也出现在统计结果里totalHours 为 0而不是被直接过滤掉。这是统计报表里非常容易踩的坑——用 INNER JOIN 会把没干活的人漏掉汇报的时候领导会问“为什么张三不见了”。5. 前端工程Vue3 组合式 API 的项目实践5.1 前端目录结构与工程化搭建前端用 Vite 构建 Vue3 项目目录结构我建议这样组织src/ api/ # 接口请求封装 assets/ # 静态资源 components/ # 公共组件 layout/ # 布局组件 router/ # 路由配置 stores/ # 状态管理Pinia views/ # 页面视图 login/ dashboard/ project/ task/ worklog/ report/ system/ utils/ # 工具函数API 请求封装上推荐用 Axios 实例统一配置 baseURL、请求拦截器和响应拦截器。请求拦截器里带上 Token响应拦截器里统一处理业务错误码和 401 跳转。这样可以避免每个页面都写一遍错误处理也让代码很干净。5.2 核心页面工时填报的交互设计工时填报页面是用户每天都可能用的页面交互设计上一定要快。我的做法是采用“日历 列表”双视图模式。日历视图让用户直观看到每天是否已填报点击某一天弹出填报表单表单里可以选择任务、填写工时数和工作内容。列表视图则是按时间倒序展示当前用户的填报记录每条记录都能查看审批状态。表单校验需要注意工时数必须大于 0且不能超过 24。一个用户同一天不能针对同一个任务重复填报。工作内容不能为空。这些校验前端要做一遍后端必须再做一遍。前端的校验是提升用户体验后端的校验才是真正的数据安全防线。5.3 报表展示的图表方案统计报表页面需要展示趋势图和排名表。图表推荐使用 ECharts配合 Vue3 的封装组件使用。工作量趋势图用折线图展示横轴是日期纵轴是总工时人员排名用横向柱状图项目投入分布用饼图。ECharts 的配置项在 Vue3 里需要放在 onMounted 后初始化并记得在组件卸载时销毁实例避免内存泄漏。这里有个实践经验报表页面的数据不应该每次进入都重新请求全量数据而是提供一个筛选区域让用户选择时间范围和维度后再加载。全部数据一次性渲染几千条不仅在查询上压力大前端渲染也会卡顿。6. 前后端分离部署与联调的那些坑6.1 开发环境跨域问题前后端分离开发时前端跑在 5173 端口后端跑在 8080 端口跨域是第一个要解决的问题。开发环境最简单的做法是 Vite 配置代理// vite.config.js export default defineConfig({ server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } });这样前端请求 /api/login 会被代理到后端服务的 /api/login不需要后端开启跨域。生产环境则通过 Nginx 反向代理统一入口前后端用一个域名更安全也更便于维护。6.2 后端接口联调时的状态规范联调过程中最常见的问题就是接口返回格式不一致。我强烈建议前后端在项目启动前就把接口规范文档定下来不要边写边改。规范至少包含这些请求方法、路径、参数类型。返回统一 Result 结构。分页参数用 pageNum 和 pageSize返回数据里包含 total。时间字段统一用字符串格式 yyyy-MM-dd HH:mm:ss。枚举值的取值范围在数据字典里统一维护。这些看似琐碎的约定能节省大量联调时间。我见过团队因为没有约定时间格式前端把时间戳当成字符串传后端解析失败两个人排查了整整一个下午最后发现就是格式问题。7. 典型问题排查实录与优化建议7.1 统计结果和人工核算不一致这是工作量系统最容易被质疑的问题。排查时按这三个方向走是否把未审批的工时记录计入统计口径必须统一报表里要明确过滤 status 1。是否有跨用户的重复填报比如一个任务指派给三个人三个人都填报了 8 小时但任务本身只需要 8 小时。这种情况不是系统 bug是业务逻辑的问题需要任务负责人把任务拆分成更小的子任务。是否有跨时区或日期边界问题服务器时区和数据库时区不一致会导致按日统计偏差。我处理这类问题的习惯是在报表数据之外给每条统计数加一个“数据来源明细”的跳转链接让统计结果可以一层层下钻到原始工时记录。这样用户有疑问时可以直接核对明细省了很多解释成本。7.2 MyBatis XML 里 SQL 语句报错开启动态 SQL 加 log 输出是排查 SQL 问题的第一步。在 application.yml 里配置mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl这样控制台会打印完整 SQL 语句带参数值的那种方便直接复制到数据库工具里执行验证。最常见的问题就是if标签里的条件写错拼接出来的 SQL 语法错误或者 where 条件恒真把整个表的数据都查出来了。建议每次写完复杂 SQL先打印语句看一眼再基于真实数据验证一遍。7.3 响应慢性能优化三板斧系统用久了数据量上来报表查询会变慢。优化顺序是先看 SQL 执行计划确认是否命中索引。该加索引的地方别省。再确认查询是否真的需要实时聚合如果不是考虑建立统计汇总表每天定时任务刷新。最后考虑缓存报表数据用 Redis 缓存一段时间不用每次查询都跑全量聚合。对于企业内部的业务系统第一板斧就能解决 80% 的问题。7.4 源码二次开发时需要关注什么拿到这套源码后要做二次开发我建议先别急着改功能先做三件事把数据库脚本跑通确认基础数据能初始化成功。把前后端项目分别启动走一遍登录到报表的完整链路确认自己能跑通。读懂核心模块的代码流转用户登录后 Token 怎么传递任务创建后状态怎么流转工时审批后数据怎么进报表。这三件事做完你对整个系统的理解会超过 80% 的人。然后再去改需求比如把工时粒度从 0.5 小时改成 15 分钟或者增加一个“加班时长单独统计”字段都会顺手很多。8. 落桌分享我实际开发这类系统时的一些心里话这套系统我在实际项目里做过不止一次每次做都会发现新的问题。印象最深的一次是统计报表上线后有同事质疑“为什么我上个月明明干了很多活统计出来却这么少”。后来一查他发现是因为没有点提交审批所有工时记录都停在待审批状态。这件事让我意识到系统设计得再严谨用户不按流程走就会出数据偏差。于是后来我在前端加了未提交工时的提醒角标后端也提供了一个“本月未审批记录”的汇总接口让问题前置暴露。还有一次是把工时字段设计成 INT 整数结果用户反馈“我做了两个小时零十分钟怎么填”最后逼着改成 DECIMAL 并支持 0.5 粒度还加了自定义备注。所以后来我再设计这种系统第一件事永远是把度量单位定好前端表单、后端校验、数据库字段、统计口径全链路统一。如果你打算拿这套源码学习或者做二次开发我建议你把重点放在理解业务和代码的对应关系上。比如“审批通过后工时进入统计”这个规则在数据库层面是 status 字段的变化在后端是 update 语句的条件控制在统计 SQL 里是对 status 的过滤。把这条线理清楚整个系统你就吃透了大半。最后分享一个小技巧这类统计系统上线之后最好先并行运行两周让团队既用系统填报也保留原有的手工统计两边数据对照一下。没有异常后再停掉手工流程。这个过渡策略看起来保守但对团队接受度和数据可靠性来说是值得的。

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

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

免费获取报价 →
↑