工厂里的工单流转,很多中小型制造企业到今天还停在纸单和Excel阶段。一份派工单从车间写到办公室,再转给维修班和质检组,中间经历签字、拍照、口头提醒,效率低不说,查个历史记录能翻半天柜子。所以当我准备做工厂作业工单管理系统时,技术选型几乎是定死的:后端SpringBoot、前端Vue、数据库MySQL。这套组合在Java技术栈里的生态太成熟了,文档多、轮子全、人才也好招,做成一个前后端分离的Web系统,既能覆盖工单创建、派单、执行、验收的完整闭环,又能给车间主任和管理层提供实时看板。标题里的编号“hx0680”,你可以理解为项目代号,这套系统做出来的实际效果,是让工单从生成到归档全程可追踪、可统计、可复盘。
这篇博文我打算照着实际项目的落地顺序来写:先讲清楚工单管理系统到底要管什么、模块怎么拆,再分别从后端、前端、部署三个层面把核心实现讲透,最后把我踩过的坑整理成排查速查表。适合正在做SpringBoot+Vue毕设的学生、准备进制造企业做信息化的初中级开发,以及想把自己工厂的纸质工单流程搬到系统里的实施人员参考。
1. 项目整体设计与功能拆解
1.1 工单管理的核心需求分析
做系统之前,先把车间里的真实场景走一遍。工厂里的工单类型很多,常见的有生产任务单、设备维修单、质量异常处理单、保养计划单,不同行业叫法不一样,但流程骨架是一致的:有人发起、有人派活、有人干活、有人验收,最后留下记录供以后查询和统计。
所以我把这个系统的用户拆成四个角色:
- 提交人:发起工单的人,通常是产线操作工或质检员,他看到设备异响或者发现不良品率偏高,填写工单并提交。
- 调度员:工单处理的核心角色,负责审核提交上来的工单,判断应该派给哪个班组,设置优先级和期望完成时间。
- 执行人:接到工单后去现场处理的作业人员,处理完成后填写处理结果、上传现场照片、标记工时和物料消耗。
- 管理员:负责系统基础数据的维护,比如用户账号、角色权限、班组信息、工单类型字典,同时能查看全流程的统计报表。
明确了角色,工单的状态流转自然就清晰了。一个工单从出生到归档,至少要经历这些状态:
待审核 -> 待派单 -> 待接单 -> 进行中 -> 待验收 -> 已归档 \-> 驳回 -> 待审核(重新提交)这个状态机是整个系统的核心。很多初学者在做这类系统时喜欢用状态字段直接硬编码,在接口里写一长串if/else,结果上线后需求一变动就容易改出Bug。我建议一开始就建一个工单状态枚举类,把每个状态的合法流转规则定义清楚,后面所有业务方法都围绕这个状态机来写,代码会干净得多。这部分后面细说。
1.2 技术选型为什么是SpringBoot + Vue
这个组合放到今天来看依然是最稳妥的选择之一。SpringBoot的核心价值在于“自动装配”,它把Spring家族里繁琐的XML配置全部变成了约定俗成的starter依赖,一个main方法就能启动整个Web服务,内置的Tomcat也免去了单独部署容器的麻烦。对于工厂内部系统这种以CRUD为主、业务规则相对清晰的场景,SpringBoot的模板化开发效率非常高。
前端选Vue则是因为它对中小型系统特别友好。Vue的响应式数据绑定和组件化开发,让工单列表、表单、看板这些复用度高的界面可以抽成独立组件,哪个页面需要就直接引用。配合Vue Router做页面路由、Pinia或Vuex做状态管理,再接入Element Plus之类的组件库,两三天就能把管理后台的骨架搭出来。
后端、前端之外,还有几个必选组件:
| 组件 | 作用 | 选型理由 |
|---|---|---|
| MySQL | 主数据库,存工单、用户、角色、操作日志等结构化数据 | 免费、稳定、维护成本低 |
| Redis | 缓存热点数据,存登录token、工单统计结果 | 读写快,支撑看板和会话管理 |
| ActiveMQ | 消息队列,处理工单状态变更后的通知发送 | 和SpringBoot集成简单,比引入Kafka轻量得多 |
| Nginx | 部署时做静态资源服务和API反向代理 | 解决前后端分离的跨域和访问入口问题 |
这套组合的好处是每一层都有大量现成案例可以查,遇到问题不用自己瞎猜。就算你之前没接触过消息队列或者Redis,花个半天看看官方入门文档,也能在项目里用起来。
1.3 工程结构与代码分层规划
我的建议是前后端分成两个独立工程,放在同一个父目录下,用Git分开管理。这样部署时各自构建互不影响,团队协作时职责也更清晰。
后端用标准的Maven多模块或单模块分层都可以,小型系统单模块分层就够,不必为了结构好看强行拆多模块。典型的包结构长这样:
com.factory.workorder ├── controller // 接口层,接收请求参数,返回统一响应体 ├── service // 业务层,处理具体业务逻辑 │ └── impl ├── mapper // 数据访问层,基于MyBatis-Plus或MyBatis ├── entity // 数据库实体 ├── dto // 数据传输对象,比如查询条件、表单提交对象 ├── vo // 视图对象,返回给前端展示的数据 ├── config // 配置类:Redis、跨域、拦截器、消息队列 ├── common // 公共类:统一返回结果、状态码、工具类 └── enums // 枚举:工单状态、工单类型、删除标志等前端用Vue CLI或者Vite创建工程后,在src下按模块分组:
src ├── api // 接口请求封装,按业务模块建文件,比如workOrder.js ├── assets // 静态资源:图片、样式 ├── components // 公共组件:上传、富文本、工单状态标签 ├── router // 前端路由配置,登录守卫在这里做 ├── store // 全局状态管理:用户信息、菜单权限 ├── views // 页面视图:登录、工单列表、看板、用户管理 └── utils // 工具函数:请求封装、日期格式化分层清晰之后,前后端联调才不会手忙脚乱。后端的接口路径、请求方式、参数含义在写代码之前先用Swagger或者接口文档定下来,前端照着文档调,后端照着文档实现,两边并行开发不阻塞。
2. 后端核心实现与关键细节
2.1 SpringBoot工程搭建与基础配置
创建工程很简单,用IDEA的Spring Initializr直接生成就行。这里要重点提醒一句:SpringBoot版本选择不要一味追新,工厂类项目求的是稳定。当前主流稳定版本是2.7.x,很多第三方starter对接文档也以2.x为主。折腾过3.x的朋友应该深有体会,从javax包名改成jakarta,很多老教程的例子直接跑不起来,报错定位起来相当头疼。等我踩过几次版本坑之后,结论就是:除非有必须用新特性的需求,否则2.7.x够你用的。
项目生成后,配置文件至少包含三块内容:数据源、Redis、文件上传相关配置。核心的application.yml配置样例:
server: port: 8080 servlet: context-path: /api spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/workorder?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: yourpassword redis: host: localhost port: 6379 database: 0 servlet: multipart: max-file-size: 10MB max-request-size: 50MB mybatis-plus: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl jwt: secret: y0ur-s3cr3t-k3y-xxxxxx expire-hours: 24这里解释几个配置的关键点。数据源URL里serverTimezone=Asia/Shanghai是必须的,MySQL 8.x驱动默认时区是UTC,不设置的话系统时间和数据库时间对不上,工单的创建时间会差8小时。map-underscore-to-camel-case这个配置用于将数据库的下划线字段自动映射到Java的驼峰属性,比如数据库字段create_time自动映射到createTime,省去一堆@TableField注解。文件上传大小限制也要提前设好,否则工单现场照片传到一半就报超出限制错。
2.2 数据库设计:工单主表、明细表与字典表
数据库设计直接决定后面写代码的难易。工单管理系统至少要有这几张核心表:用户表、角色表、工单主表、工单操作记录表、字典表。
工单主表的字段设计,我列一个常用版本:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | bigint | 主键,建议雪花算法ID,不用自增 |
| work_order_no | varchar(32) | 工单编号,格式如WO+年月日+流水号 |
| title | varchar(200) | 工单标题,简要描述问题 |
| type | int | 工单类型,关联字典表 |
| priority | int | 优先级:1普通 2加急 3紧急 |
| status | int | 当前状态,关联枚举类 |
| submitter_id | bigint | 提交人ID |
| handler_id | bigint | 执行人ID |
| dispatcher_id | bigint | 派单人ID |
| plan_start_time | datetime | 计划开始时间 |
| plan_end_time | datetime | 计划完成时间 |
| actual_end_time | datetime | 实际完成时间 |
| description | text | 问题描述 |
| result_desc | text | 处理结果描述 |
| reject_reason | varchar(500) | 驳回原因 |
| is_deleted | tinyint | 逻辑删除标记 |
工单操作记录表非常关键,它记录工单每一次状态变更:谁在什么时间把工单从待审核改成了待派单,备注了什么内容。这张表的价值在于事后审计,谁在哪个环节耽误了时间,一查记录就清楚。工单管理看起来是管工单,本质上是管流程和管事。
工单编号的生成我推荐用Redis的incr命令来做:每天一个key,比如workorder:no:20250329,当天每创建一个工单就自增1,编号格式WO20250329001。天然防并发重复,而且第二天自动从0开始。
2.3 权限认证与用户登录
工厂系统的权限做到角色级别基本够用,不需要很复杂的RBAC资源权限设计。我的方案是JWT来实现登录状态管理,配合Spring Boot拦截器做token校验。
登录流程是这样:用户提交用户名密码,后端校验通过后生成一个JWT token,里面带上用户ID和角色编码,再把token存一份到Redis里并设置过期时间。前端把token存到localStorage,每次请求在请求头里带Authorization: Bearer <token>。后端拦截器校验token的签名和有效期,再把用户信息放到ThreadLocal里,供后续业务方法随时取当前操作人。
不直接用纯粹的JWT而要多存一份Redis,是为了解决“注销登录”的问题。JWT在有效期内是天然无法撤销的,如果你只靠JWT本身的过期时间,用户点了退出登录,token还是有效的,遇到工单接口被拿出去扫就很被动。存到Redis后,退出登录或者管理员踢人时,直接删掉Redis里的key就行。
拦截器里除了校验token,还有一个容易被忽略的细节:在线用户管理。工厂里经常需要查看“现在都有谁登录在系统里”,特别是遇到安全事件要追踪时,一张在线用户表能把人找出来。
2.4 工单状态机的后端落地
前面提了状态机,这里说实现。我建议在枚举类里把工单状态和流转规则集中定义:
public enum WorkOrderStatus { PENDING_AUDIT(0, "待审核"), PENDING_DISPATCH(1, "待派单"), PENDING_ACCEPT(2, "待接单"), IN_PROGRESS(3, "进行中"), PENDING_ACCEPTANCE(4, "待验收"), REJECTED(5, "已驳回"), ARCHIVED(6, "已归档"); public final Integer code; public final String desc; WorkOrderStatus(Integer code, String desc) { this.code = code; this.desc = desc; } }然后在Service层写一个状态变更方法,所有状态修改都走这个方法,而不是在Controller里直接调update:
public void changeStatus(WorkOrder workOrder, WorkOrderStatus targetStatus, String operatorId, String note) { WorkOrderStatus current = WorkOrderStatus.of(workOrder.getStatus()); if (!isAllowed(current, targetStatus)) { throw new BusinessException("不允许从" + current.desc + "变更为" + targetStatus.desc); } workOrder.setStatus(targetStatus.getCode()); workOrderMapper.updateById(workOrder); workOrderLogMapper.insert(...); }这样做的直接好处是,非法状态流转在Service层就被拦截,前端就算绕过按钮直接调接口,后端也不会放行。工单系统最怕的就是状态乱了套:工单还没派单就跳到已完成,报表数据直接成浆糊。
派单是整个系统里值得多花心思写的一个点。最简单的方案是调度员手动选择执行人,但更好的做法是支持按技能匹配自动推荐。工单类型(比如电气维修、机械维修、焊接)匹配执行人的技能标签,再结合当前待处理工单数量算出负载,把负载最低且技能匹配的执行人排在候选列表最前面。这套推荐逻辑不用做得很重,一个SQL查询加排序就能实现。
2.5 缓存、消息队列与通知
Redis在我的系统里承担了几个具体任务:缓存工单看板的统计数据、存储JWT、生成每日工单编号。其中工单统计看板是查询最频繁的接口,车间大屏可能每5秒刷新一次,如果每次都去MySQL里做聚合查询,数据库压力会比较大。我的做法是每个整点算一次统计数据放Redis,看板接口直接读缓存,同时管理员手动刷新的时候强制更新一次,这样统计数字顶多慢一两分钟,车间管理完全能接受。
ActiveMQ的主要用途是解耦通知发送。产生工单状态变更后,系统需要发站内信通知相关负责人,传统做法是在工单Service里同步调用消息服务,一但消息服务出问题或者变慢,工单主流程也跟着卡住。引入ActiveMQ后,工单Service只负责把状态变更事件发布到队列,通知模块异步消费消息,各干各的,互不拖累。
小系统中不一定非要上消息队列,但如果未来要接企业微信通知、短信通知、邮件通知,队列的价值就会非常明显:改一个消费端的逻辑,发短信还是发邮件,都只影响通知模块自身。
3. 前端核心实现与页面落地
3.1 Vue项目创建与开发环境配置
前端我建议直接用Vite创建Vue3项目,比Vue CLI更快,生态也更好。创建命令很简单:
npm create vite@latest workorder-web -- --template vue cd workorder-web npm install npm install vue-router@4 pinia element-plus axios echarts dayjs开发环境必须要配置代理,否则前端请求后端接口的时候会碰到跨域问题。在vite.config.js里加上:
export default defineConfig({ server: { port: 3000, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } })这里解释一下为什么不用后端开启CORS来省事。开发阶段用代理,前端请求的地址和后端是同源的,浏览器没有跨域限制,接口调试更顺。生产阶段用Nginx反向代理统一入口,同样不依赖后端处理CORS。后端把CORS放开的话,安全配置又要额外小心,自己能控制的方案才是好方案。
npm安装依赖慢是国内开发者的常态,如果第一次npm install等了十分钟还没装完,把镜像切到国内源或者手动指定npmmirror registry,能省下不少时间。但注意lock文件里锁的是依赖版本,换镜像不会改变版本,这个可以放心。
3.2 路由与权限控制
前端路由的核心职责是维护页面跳转规则和页面访问控制。我这里用了两种方式结合:
第一种是登录守卫,在router.beforeEach里判断:访问除登录页外的任何页面之前,先检查本地有没有token,没有就重定向到登录页。这个判断放在前端,是体验层面的拦截;真正的安全校验还是后端拦截器在做,两层各自职责不同。
第二种是菜单权限。管理员登录显示用户管理、字典配置菜单;普通操作工登录只显示我的工单、待办中心。实现方式是在动态路由里按角色注册路由表,或者在渲染侧边菜单时用v-if判断v-permission自定义指令。对于工单管理系统,菜单级权限就够了,不用精细到按钮级,避免过度设计。
Vue Router还有一个踩坑点:使用createWebHistory模式时,生产部署刷新页面会出现404,因为Nginx只认到了静态文件路径,没有把请求转发给index.html。解决办法是Nginx里配try_files $uri $uri/ /index.html;,这个后面部署部分会再提。
3.3 工单列表、筛选与状态标签
工单列表是系统里最核心的页面。我的设计思路是一页包含四块:筛选区、操作按钮区、表格区、分页器。筛选区支持按工单类型、状态、优先级、创建时间段、负责人等条件组合查询,状态用下拉框默认选中“进行中”而不是所有状态,因为车间主管打开列表最关心的是正在处理中的事。
状态标签组件是我前端里抽得比较成功的一个公共组件。不同状态配不同颜色:待审核灰色、待派单橙色、进行中蓝色、待验收青色、已归档绿色、已驳回红色。状态枚举是核心的全局概念,后端返回给前端的是状态码,前端拿到状态码之后映射为标签颜色和文案。前后端的状态枚举如果各写一份,共用同一个后端接口来返回状态列表,就不会出现两边定义不一致的情况。
表格操作列的按钮,我也会根据当前行状态动态显示。比如待审核的工单显示“审核”和“驳回”,“派单”按钮则不出现。这样用户可以直观地感知到当前能做的操作,误点的概率也大大降低。
3.4 表单校验、文件上传与看板
工单表单是提交人和调度员都要用的页面,差别只是字段不同。提交人填的是问题描述、设备编号、紧急程度;调度员填的是派单结果、计划时间、备注。这里我拆成了两个组件,而不是一个页面里通过v-if切换一堆字段,避免代码越写越长。
表单校验用的Element Plus自带的规则机制,重点校验工单标题不能为空、描述至少10个字、计划完成时间不能早于当前时间。这些规则前端校验一遍,后端在接收DTO时再用注解校验一遍,两层都做才能防住前端被绕过的情况。
现场照片上传用的是Element Plus的Upload组件,后端提供一个通用的文件上传接口,文件存在服务器的本地目录。要特别注意生产级改造时,文件不能存在应用服务器的磁盘上,因为单机磁盘早晚会满,而且应用重新部署时文件容易丢。更好的方案是把文件存OSS或者MinIO对象存储,但这对于小型毕设和内部系统不是必须的,本地目录加路径存库也能用。
看板页用ECharts做了三个图:工单类型分布饼图、近7日处理趋势折线图、班组平均处理时长柱状图。这几个图表的数据在后端封装好,前端接到数据直接塞给ECharts的option配置。如果硬件条件允许还可以接一个大屏页面,把这三个图放大到电视上给车间循环播放,管理效果非常直观。
4. 系统部署与常见问题排查
4.1 前后端分离部署的核心步骤
开发阶段前后端分开跑,部署到生产环境时就需要放在一起了。我的推荐拓扑是:一台服务器上装Nginx和Java服务,前端构建后的dist目录扔到Nginx的html目录,后端jar包用systemd或Docker守护进程运行,Nginx把/api开头的请求反向代理到后端的8080端口。
前端构建:
npm run build # 产物在 dist 目录后端构建:
mvn clean package -DskipTests # 产物在 target/workorder-1.0.0.jarNginx关键配置:
server { listen 80; server_name your-domain-or-ip; root /opt/workorder/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }两个关键点:try_files解决Vue History路由刷新404的问题;proxy_pass末尾的斜杠表示把/api前缀透传给后端,后端接口路径本身是/api开头,所以这里不能去除前缀。
4.2 常见问题排查实录速查表
| 症状 | 可能原因 | 解决办法 |
|---|---|---|
| 前端登录成功后再次刷新又回到登录页 | localStorage里的token丢失,或路由守卫误判 | 检查登录后是否localStorage.setItem,刷新时先读token再初始化store |
| 接口请求404 | 后端context-path与Nginx代理路径不一致 | 统一约定:后端context-path=/api,Nginx里location /api/对应 |
| 前端请求接口跨域 | 开发环境没配vite代理,或生产环境直接请求了后端地址 | 开发配vite proxy,生产配Nginx反代,前端请求相对路径/api |
| npm install安装依赖极慢 | 默认使用官方源 | 配npm config registry为国内镜像后重试 |
| 上传图片后接口504 | 上传大小超过默认限制或带宽问题 | 后端设multipart大小,Nginx设client_max_body_size |
| 数据库中文乱码 | 连接串没加characterEncoding=utf8或表是latin1编码 | 连接串加useUnicode=true&characterEncoding=utf8,建库用utf8mb4 |
| 微服务时间差8小时 | 数据库连接没设置时区 | URL加serverTimezone=Asia/Shanghai |
4.3 安全与性能优化建议
这套系统上线前,我建议至少做四件安全上的事。
第一,密码不要明文存数据库,用BCrypt加密。SpringSecurity自带BCryptPasswordEncoder,不用自己研究哈希算法,直接集成就行。
第二,接口层做好参数校验,防止SQL注入和恶意构造数据。MyBatis-Plus默认的wrapper拼接条件可能带来注入风险,能用@Param注解传参就不要拼字符串。
第三,敏感接口做权限校验。工单归档、删除、状态强制修改这类高危操作,不仅要登录,还要检查操作人的角色是管理员或调度员,防止操作工顺手把工单删了。
第四,SpringBoot项目的heapdump泄露问题要上心。曾经有安全通报提到SpringBoot的Actuator在生产环境暴露了heapdump接口,攻击者可以下载堆内存快照,从中提取密码、token等敏感信息。解决办法是生产环境不要暴露Actuator端点,或者用management.endpoints.web.exposure.include限制只开放必要的端点。
性能上来说,工单管理系统的表数据量在百万级以内时,MySQL加上合适的索引就足够应付。工单列表按create_time排序查询,给create_time加个普通索引;状态筛选频繁,给status加索引。再大才需要考虑分库分表,但对工厂内部系统来说,那属于几年后的事情,现在不必预支复杂度。
5. 后端一些容易忽视的开发细节
很多人做SpringBoot项目,启动起来能跑就以为万事大吉,其实有几个细节会在联调阶段反复折腾人。我在这里把最典型的几个展开讲。
第一个是统一响应体。我的所有接口返回结构是固定的:code(状态码)、message(提示消息)、data(业务数据)。前端封装的axios会拦截所有响应,code为200才把data返回给调用方,否则弹出message提示。这个约定一定要在开工第一天定好,否则每个人写接口返回格式不一致,前端解析逻辑就要写一堆兼容分支。空数据返回空数组,不返回null;单个实体不存在返回code=404,不返回null,这些边界约定写清楚,联调效率直接翻倍。
第二个是MyBatis-Plus的字段自动填充。创建时间、更新时间这两个字段,每个表都有。如果每次insert、update都手动set,很容易漏掉,数据库默认值又不会自动回填到Java对象里。用MyBatis-Plus的MetaObjectHandler做一个公共处理器,实现insertFill和updateFill方法,自动往实体的createTime和updateTime里填当前时间,从此这两个字段不用再手动管。
第三个是全局异常处理。BaseException、业务异常、系统异常要分开处理。Controller里不要写try/catch,统一用一个@RestControllerAdvice全局异常处理器来兜底。业务异常返回业务提示,比如“工单当前状态不允许此操作”;参数校验异常返回字段级别的提示;系统异常记日志并返回模糊的统一提示,不要把堆栈暴露给前端看。
第四个是接口幂等设计。创建工单接口,如果前端因为网络抖动重复提交了两次,数据库里就会多出一条重复工单。解决思路是前端提交时生成一个requestId,后端在Redis里以requestId为key做setnx,重复请求直接拦截。对制造业场景来说,重复工单不只是多一条数据,还可能导致同一台设备被重复派修,生产计划被搞乱,所以创建类接口的防重很有必要。
6. 实际研发中的体验与踩坑记录
最后聊点做这套系统时的真实体会,想到哪儿写到哪儿。
版本依赖是最大的隐性时间杀手。新开项目时,IDEA里Spring Initializr默认推荐的SpringBoot版本往往会比较新,我顺手就选了最新的3.1.x,结果公司的内网私服上没有对应版本的starter依赖,拉包就拉了半天。后面还是退回到2.7.x一切太平。搜索引擎上能查到的教程、踩坑记录,大部分都基于老版本。做业务的程序员不是搞基础框架的,没有必要永远站在新版本的最前线。
Vue项目打包后布局异常这个热词,我当年也搜过。现象是开发环境一切正常,build完之后某些页面错位、字体图标显示不出来。原因几乎总是静态资源路径问题:Vite的base配置默认是/,如果你把前端部署在域名根路径下还好,一旦部署到类似http://ip:8080/workorder/这种子路径下,资源就全部404了。解决方法是构建时指定base: '/workorder/',或者干脆让Nginx把前端服务在根路径下,就不需要改base。
还有个前端问题,Vue路由参数传一个对象或数组时,直接放进router.push的参数里,刷新页面后就拿不到了,因为URL只能存在字符串。正确做法是用query参数序列化,或者配合Pinia把复杂对象存到store里。工单列表跳转到详情页,传一个工单ID就够了,不要传整个工单对象过去,保持URL简洁也方便分享。
从时间安排来看,如果把整套系统控制在两个月内做完,我建议把大部分精力放在工单核心流程上。很多初学者容易被新技术吸引,花两周时间研究集成OnlyOffice、接视频流m3u8播放、接地图API,这些都是锦上添花的功能,做得再多,工单流转的核心逻辑不过关,系统照样没法用。核心流程做得扎实,基础页面整洁,代码分层清晰,答辩和评审讲出来的价值感完全不一样。
最后再分享一个小技巧:工单看板这部分,可以在后端把统计数据接口设计成按维度查询的综合查询,让前端传groupBy参数,而不是前端分别调类型统计、趋势统计、人员统计三个接口。这样接口更少,数据库聚合一次完成,等数据量上来之后做缓存也更加集中。这个设计思路不仅仅适用于工单系统,任何带报表统计的后台都可以参考。