ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Java+Vue煤矿信息管理系统实战:从数据库设计到部署全流程解析

Java+Vue煤矿信息管理系统实战:从数据库设计到部署全流程解析

煤矿行业的信息化工作,跟普通企业的管理系统有个特别大的区别——业务链条长、安全责任重、现场环境不可控。前年我完整做了一套基于Java后端加Vue前端的煤矿信息管理系统,配套MySQL数据库和全套开发文档,从需求调研、表结构设计到前后端联调、低配置服务器部署,踩了不少坑,也沉淀了一些实打实的经验。这篇就把这套系统的设计思路、技术选型逻辑和实操落地的细节完整写一写,给正在做类似毕业设计或者准备入门企业级管理系统开发的朋友做个参考。

很多同学拿到类似标题的第一反应是“这不就是个常规增删改查吗”,真上手才会发现,煤矿业务里的数据权限、安全闭环、班次统计、设备状态流转,每一块都比想象中复杂。这篇内容不打算只讲界面长什么样,重点放在“为什么这么设计”和“实际开发里哪些地方最容易翻车”上,尽量让看完的人能直接照着搭出一套可用的系统。

1. 先搞清楚这套管理系统到底在管什么

1.1 煤矿信息化的核心痛点:不只是把纸质台账搬到电脑上

做系统之前必须先想明白一件事:煤矿的管理需求,跟学校、电商、进销存完全不是一个套路。井下作业环境特殊、人员流动频繁、设备种类多且检修周期严格,安全监控数据又是高优先级,这些因素叠加起来,决定了系统不能只是“录数据、查列表”。

我当时去现场调研了一圈,发现矿上的日常管理主要靠三类东西:班前会记录、纸质巡检单、调度电话。数据分散在各个科室,安检科有一份隐患台账,机电科有一份设备检修记录,调度室有一份产量日报,彼此之间不打通,月底汇总全靠人工对着Excel捋。

所以这套系统的第一诉求,就是把“分散的记录”变成“关联的数据”。人员入井记录要和班组排班挂钩,安全检查出的隐患要能追溯到具体区域和设备,设备检修计划要能根据上次检修时间自动提醒,产量数据要按班次、按采区自动汇总。这些场景不是几个CRUD页面能覆盖的,它需要清晰的业务建模。

1.2 我从业务调研里提炼出的四个关键需求层次

跟矿上的调度主任、安检员、机电技术员分别聊过之后,我把需求拆成了四层,这个层次划分直接影响了后面的模块设计和数据库结构:

  • 基础档案层:矿区内组织架构、人员档案、设备台账、采区/工作面信息。这是整个系统的地基,后续所有业务数据都要挂在档案上。
  • 安全生产管理层:安全巡检任务、隐患登记与整改、入井人员登记、领导带班计划、应急演练记录。这一层是煤矿系统的灵魂,功能上要突出“闭环”和“可追溯”。
  • 生产经营层:产量日报、掘进进尺、调度记录、物资领用。跟安全层比,它的数据更新频率高,统计口径复杂。
  • 系统管理层:用户、角色、权限、操作日志、数据备份。这层看起来普通,但煤矿对权限隔离的要求极高,后面细说。

这四个层次不是拍脑袋定的,而是根据“谁在用、用什么频率用、数据往哪流动”推出来的。安检科主要写安全相关数据,调度室关注产量与人员出勤,矿领导要看汇总报表,不同角色的数据边界必须从第一天就划清楚。

1.3 系统边界划定:哪些功能必须做,哪些坚决不做

跟很多项目一样,需求调研阶段最容易犯的错是把系统做成“大而全”。当时也有人提能不能把视频监控、人员定位基站的数据直接接进来,我斟酌了一下没有答应。

原因是这套系统的定位是信息管理,底层物联网数据的接入会带来三倍以上的复杂度:通信协议解析、设备接入稳定性、实时数据存储选型,这些都需要专门的人员和设备环境。做毕业设计或者中小型矿区管理系统,步子别迈太大。我最后划的边界是:手工录入为主、文件导入为辅,物联网接口预留但不实现。这样系统两个月能稳定跑起来,后续要扩展也有接口位置。

划边界时我给自己定了一个原则:凡是需要专用硬件配合的功能,这一期一律不做,只做流程管理和报表分析。事实证明这个决定非常关键,它把开发周期控制在了可交付的范围内,同时又保证了核心业务闭环完整。

2. Java+Vue这套组合为什么适合煤矿场景

2.1 后端选型:稳定、生态成熟是第一位的

技术栈定的是Java,具体用的是Spring Boot框架,搭配MyBatis-Plus做持久层访问,权限认证用的是JWT加Spring Security,数据库用MySQL。这套组合放到今天看不算新,但在企业管理系统的场景里,它是最稳的选择之一。

选它的第一个原因是人才生态。煤矿信息系统的开发和维护周期长,可能交付之后还有两三个技术人员轮流接手,Java系的工程结构规整,社区资料多,后来者维护成本低,不至于说换个维护人就得把整个项目重新学一遍。

第二个原因是Spring Boot的自动配置和起步依赖做得太省心了。项目结构清晰,控制层、业务层、数据访问层的分层几乎是行业规范,配合MyBatis-Plus的代码生成器,基础的单表CRUD代码可以快速生成,我把精力集中在业务规则上,而不是反复写重复的增删改查。

2.2 前端选型:表单密集、权限复杂,Vue生态最顺手

前端用了Vue,配Element UI组件库,Axios做HTTP请求,ECharts画图表。管理信息系统的前端有个特点,就是表单多、列表多、统计图多,界面交互不追求花哨,但要求大量业务组件的组合效率高。

Vue在这类场景的优势在于组件化思维和响应式数据流。拿巡检任务页面举例,一个页面里包含任务信息卡片、隐患明细表格、审批记录时间线、整改状态标签,这些用Vue组件切分后,每个子组件只管自己的数据和事件,任务状态一更新,派生的标签、颜色、按钮状态全部自动联动,开发效率明显比之前的模板字符串拼接方式高。

Element UI的表格组件也很能打,自带排序、筛选、多选、分页,配合自定义插槽能做很多扩展,比如根据隐患等级在行内渲染不同颜色的高亮标签。ECharts用来做产量趋势图、安全分类统计饼图、人员出勤柱状图,前后端交互只需要提供标准化JSON数据,图表配置代码写到单独的工具模块里,一个图表的开发时间控制在半小时以内。

2.3 整体架构与模块划分

整个系统采用前后端分离架构,后端起在8100端口,前端起在9527端口,开发环境通过代理转发解决跨域,生产环境用反向代理统一入口。后端按业务模块分包,前端按视图目录组织路由。

模块划分上,后端分了system、safety、production、equip、report这几个主包,分别对应系统管理、安全管理、生产管理、设备管理、报表统计。前端路由和菜单配置一一对应,菜单本身支持动态加载,根据登录用户的权限渲染不同入口。这套架构跑下来很顺,模块之间耦合少,适合一个小组两三个人并行开发。

3. 核心模块的落地设计,处处都是状态流转

3.1 安全巡检闭环:从任务下发到隐患整改的状态流转

安全模块是整个系统里业务逻辑最重的一块,核心流程是“巡检任务下发→巡检结果填报→隐患登记→整改任务派发→整改结果复核→闭环归档”。

我把它设计成一条状态链。巡检任务初始状态是“待开始”,安检员填报完成后变“已完成”,如果填报时勾选了隐患,隐患记录会单独生成一条记录并进入“待整改”状态。整改责任人填报整改措施后状态变“待复核”,安检科复核通过后整个隐患记录状态变“已闭环”。

这里有一个细节值得展开:隐患记录不是简单挂在巡检任务下面的子表,而是作为独立主表存在。因为一个任务可能查出多条隐患,一条隐患又可能派发给多个整改责任人,如果做成子表,后面做隐患统计报表时会非常痛苦。拆成独立主表后,巡检任务表和隐患记录表之间是1对N关系,隐患表通过任务ID回联,互不干扰。

权限上也要做控制:安检员只能填报巡检结果,不能直接修改整改措施;整改责任人只能看到派发给自己的隐患,不能越权查看其他班组的数据。这个在功能设计时通过接口层校验实现,后端在service层判断当前登录用户的角色和隶属部门,不依赖前端隐藏按钮来保障安全。

3.2 入井人员管理:层级授权与数据隔离的实现思路

入井登记不是简单地记一下几点几分谁下去了,而是连着排班、工种、区域、出入井时间、考勤统计一整条链路。井口检身人员登记入井信息时要选择对应班组、工作区域和工种,出井时记录升井时间,考勤数据由此自动生成。

数据隔离这块,煤矿的管理层级是“矿—区队—班组”三级,某个区队的管理员只能看本区队的入井记录,矿调度室能看全矿数据。最初我想得很简单——在用户表上加一个部门ID字段,查询时等于当前用户部门ID就行,结果被现实教育了。

实际业务里,矿级领导需要跨部门看汇总,区队长要看自己分管范围内的数据,而且可能一个区队下面的班组分布在多个采区。纯靠一个部门ID做过滤根本不够用。我最终用的是“数据权限范围”的概念:每个用户配置一个数据权限级别,参数化查询时动态拼接过滤条件。矿级用户不带过滤条件,区队级用户带区队ID过滤,班组级用户带班组ID过滤。这个设计在真实场景里才算真正能落地。

3.3 设备台账与检修计划:状态机设计很关键

设备模块容易让人轻敌,以为就是登记一下型号、厂家、购置日期。但矿上设备的检修逻辑比普通企业复杂得多:有日检、周检、月检、年检,不同设备类型检修周期不同,检修完成要关联下次检修计划,设备故障可能要停机停产。

我在设备表上设计了一个综合状态字段:正常、待检修、检修中、故障停机、报废。每次创建检修计划时,系统自动判断设备当前状态,检修完成后把状态更新回“正常”,同时按照设备设定的周期计算下一次计划日期,自动插入一条“待执行”的检修计划。

这个自动生成计划的功能,是用设备类型表里的“检修周期天数”字段配合数据库日期运算实现的。例如一台主通风机设定120天检修周期,当前计划完成日期是2026年3月1日,完成后系统自动算出下次计划日期为6月29日,生成新的计划记录,状态待执行。这套机制上线后,机电科的人就不用再手动去翻台账盯检修时间了。

3.4 产量与调度数据:报表统计的两个隐藏坑

产量数据来自采区填报,调度室会做汇总审核。这块业务功能本身不复杂,就是录入产量、核对、确认、汇总,但我在做统计报表时踩了两个大坑,非常值得写出来。

第一个坑是班次跨天。煤矿有早班、中班、夜班三个班次,夜班时间是从前一天晚上到第二天凌晨,如果按自然日分组统计,夜班的产量会算到第二天头上,和历史手写台账对不上账。解决方案是在产量表里同时保存“产量日期”和“班次”两个字段,统计时按这两个字段做date_add和日期格式化处理,手机端录入时默认选择当前实际班次,而不是想当然地取系统当前日期。

第二个坑是取数口径。一张日产量报表要同时体现“采区上报产量”和“调度室核定产量”,这两个数经常不一样,报表面临取哪个数的问题。我当时设计了两套口径:默认展示调度室核定产量,录入明细页面可以看到上报产量与核定产量的差额,便于逐条核对。报表接口的参数里专门加了“取数类型”枚举,避免后续需求变化时要大规模改动SQL。

4. 数据库设计里的几个关键决策

4.1 表结构设计:哪些表必须拆,哪些字段必须冗余

数据库总共设计了三十多张表,核心表的命名都遵循模块前缀加业务名的方式,例如安全模块的表用safe_前缀,设备模块用equip_前缀,生产模块用prod_前缀。这个命名习惯看起来小,但在后面写SQL、排查问题时省了大量时间,文件列表一拉就知道哪张表属于哪个模块。

有两个拆分决策想重点讲。第一个是巡检任务表和隐患记录表拆开,前面已经说过,这是为了支持隐患的独立流转和统计。第二个是产量表和调度表拆开,虽然调度记录和产量数据在页面上是同一个表单提交的,但它们的生命周期不同——产量是原始数据,调度是审核动作,一旦合并,后续要追溯“这个产量是谁审核的”就变得很别扭。拆开后,调度表通过产量ID回联,既保留了完整链路,又降低了表之间的耦合。

冗余字段方面,我刻意在明细表里冗余了“编码、名称”这类字段,而不是通过联合查询去关联档案表取名称。比如隐患记录表里直接存隐患所在区域名称和责任人姓名,而不是只存区域ID和用户ID。这样做的原因是煤矿现场操作人员经常在弱网环境用手机填报,减少一次关联查询就能明显提升页面的响应速度。数据一致性靠录入时的校验来保障,因为名称字段只作为展示冗余,修改基础档案的显示名称后,历史记录里的名称保持不变,这正好符合“历史快照”的业务语义。

4.2 数据权限怎么做:部门隔离不是简单加个字段

数据权限这块前面提到了基本思路,这里把数据库层面的实现也说清楚。我在用户表里增加了data_scope字段,值分别是1全局、2区队、3班组,然后在关键业务表上统一预留dept_id和team_id两个隔离字段。写查询接口时,通过MyBatis的自定义拦截器自动拼装权限条件。

有个容易忽略的点是:数据权限不能只写在查询接口里,更新删除接口同样要加到条件里,否则就可能出现A班组的整改责任人把B班组的隐患记录直接改了的情况。我在service层封装了一个数据权限工具类,所有业务模块在做update、delete之前都必须调用这个工具类的条件构造方法,确保操作范围不越级。这个习惯从开发第一天就坚持,上线后权限相关的问题几乎为零。

4.3 历史数据归档与性能预留

煤矿系统的数据量跟互联网应用没法比,但有个特殊特点:安全隐患、检修记录、入井记录都是需要长期留存的,而且业务上“近几年同期对比”是刚需,不能随便清理历史数据。产期运行下来,业务大表的数据量增长其实很快,巡检明细表甚至可能每年几十万行起步。

我的方案是做了月份分区表加归档机制。业务表按月份做分区,三个月前的数据自动迁移到历史库,业务上查询近三个月的数据走主表,跨月统计的时候走归档视图,通过Union查询把两部分合并。这个机制通过一个定时任务实现,每天晚上跑一次,使用时完全透明,不用改业务代码。做完这个之后,页面加载速度基本保持稳定,不会因为时间推移越来越卡。

5. 源码和数据库脚本拿到之后,按什么顺序看

5.1 跑起来的完整步骤:从导入数据库到浏览器打开登录页

如果读者拿到的是一套带源码的压缩包,我建议按下面的顺序操作,能省去很多排查问题的时间。

  1. 准备环境:安装JDK8,注意配置JAVA_HOME环境变量;安装Maven,配置阿里云镜像加速依赖下载;安装Node.js,Vue版本如果是2.x,建议用Node14系列,如果是3.x用Node18以上;数据库用MySQL5.7或者8.0都行,建议8.0,字符集选utf8mb4。
  2. 导数据库:用Navicat或者命令行工具,执行源码压缩包里的xxx.sql脚本,脚本一般包含建库、建表、初始数据。导入后检查一下库名、用户名密码和配置文件里的是否一致,这是新手最常踩的坑,一会儿专门说。
  3. 启动后端:打开后端工程目录,用IDE(比如IDEA)加载pom.xml,等依赖下载完成后,运行启动类。看到控制台打印“Started application”表示成功。注意配置文件里的数据库连接地址改成自己的IP和端口。
  4. 启动前端:在frontend目录下执行npm install安装依赖,然后npm run dev启动开发服务器。开发服务器的默认端口一般配置在vue.config.js里面,页面上会提示访问地址。
  5. 访问系统:浏览器打开前端地址,默认账号和密码在数据库脚本的sys_user表里能看到,通常是admin/123456这种,登录后就能看到完整的菜单和页面。

5.2 数据库脚本里的初始数据有什么用

很多人以为数据库脚本里只有建表语句,其实系统能不能跑起来、菜单权限能不能正确显示,全靠脚本里的初始数据。sys_menu表里填了所有菜单项和路由地址,sys_role_menu里配置了角色和菜单的关联关系,sys_user里还预置了不同类型的登录账号,比如矿领导、安检员、区队长、调度员。

这些初始数据的作用是让整个系统交付后“开箱即用”。菜单结构和权限分配已经配好,不需要手工去后台一个一个补。我建议读者拿到手先别急着改密码,先用预置账号登录一遍,把每个角色能看到什么、不能看到什么体验一遍,再去理解权限表之间的关联关系,这对后续二次开发帮助很大。

5.3 完整文档应该重点看哪几部分

文档一般包含需求分析、数据库设计说明、接口文档、部署文档四大部分,内容多的可能还有操作手册。很多读者习惯从头到尾翻一遍,其实效率很低,我建议按角色跳着看。

先看需求分析里的“系统功能结构图”和“角色权限说明”这两节,快速建立全局概念。再看数据库设计说明里的核心表ER图和字段注释,重点理解业务表之间的外键关系和状态字段的取值字典。然后看接口文档里登录、巡检任务、隐患处理这三个模块的接口示例,理解前后端数据交互的标准格式。最后部署文档里的环境准备和常见问题章节,把部署过程中容易踩的坑提前避开。

6. 联调和部署阶段的坑,我一个个踩过来的

6.1 前后端联调的跨域与Token过期问题

前后端分离架构里,跨域是最经典的问题。开发环境我用vue.config.js里的proxy配置解决,把前端的/api接口请求代理到后端的8100端口,后端不单独配置跨域,开发体验很干净。

生产环境又不一样。前端打包成dist目录后由nginx托管,nginx把以/api开头的请求反代到后端服务。如果后端还在用开发时的跨域配置,就会出现权限认证过滤器和跨域过滤器顺序不对导致的“请求被拦截”或者“OPTIONS预检失败”。我的经验是生产环境在后端关闭跨域配置,统一交给nginx处理,同时把jwt过滤器的顺序放在跨域处理之后,否则预检请求会被当成未认证请求拦截。

Token过期的问题也容易忽略。前端Axios封装里有一个响应拦截器,当后端返回401状态码时,统一做退出登录处理,清掉本地缓存的Token并跳回登录页。还有一个细节是JWT生成时要设置合理的过期时间,我设的是2小时,并让前端在每次请求前检查Token剩余有效期,如果低于20分钟且本地有记住密码标记,就自动调用刷新接口换取新Token。这套机制一开始没做,员工用着用着突然要重新登录,用户反馈意见很大,后来加上自动刷新才好。

6.2 日期格式与煤矿“三个班次”的数据边界

日期格式化是个看起来小、实际很折磨人的问题。前端传过来的日期时间格式和后端默认解析的格式不一致,就会报400错误或者存进去的时间少了8小时。解决办法是统一全局日期格式:前端提交的JSON字符串统一用yyyy-MM-dd HH:mm:ss格式,后端在配置文件里设置全局的Jackson序列化格式,数据库连接串加上serverTimezone=Asia/Shanghai,三层格式全部对齐。

班次的业务边界前面提了一嘴,这里展开说下具体实现。班次表里存了early、middle、night三个编码,分别对应早班、中班、夜班。录入产量时,前端根据当前时间自动判断默认班次,判断逻辑是:6点到14点算早班,14点到22点算中班,22点到次日6点算夜班。后端在接收数据时不能只取“当前时间”作为产量日期,因为夜班的产量日期应该是当天日期减一天,这个判断在前后端都要做一遍,前端是为了默认值友好,后端是为了数据安全,防止手工构造请求时绕过规则。产量统计报表里,按班次分组排序时也是用固定的班次顺序枚举排序,而不是按字符串排序。

6.3 低配置服务器上的部署优化

煤矿信息管理系统很多时候部署在矿区内部的低配置服务器上,2核4G的机器非常常见,怎么在有限资源下跑得顺是个现实问题。我从三个方面做了优化。

第一,JVM参数调优。启动命令里设置初始堆和最大堆大小为512MB到1GB之间,避免在内存不足的环境里频繁触发Full GC。同时开启类共享功能,减少冷启动时间。第三,MySQL的缓冲池调整成适合4G内存的默认大小,关闭无关的日志功能,减少磁盘占用。

第二,前端资源压缩。构建时开启gzip压缩,nginx同样开启gzip,图片资源能压则压,静态文件全部上CDN或本地缓存,减少重复请求。打包后的首屏体积从4MB压到了1.2MB,慢速网络下打开登录页也不再是白屏半天。

第三,偶尔任务调度的时机。报表统计、历史归档这类定时任务统一安排在凌晨2点到4点之间执行,避免白天业务高峰时段抢占数据库资源。任务执行时间通过Spring的定时任务注解配置,如果某次执行失败,会保留错误日志并触发下一轮重试,不会因为一次失败就遗漏整个周期。

7. 最后说点个人体会

做完这套煤矿信息管理系统,我的一个感受是:企业管理系统的复杂度从来不在于技术本身,而在于对业务规则的理解有多深。同样是Java加Vue的框架,换一个行业就要重新理解它的安全流程、数据口径和权限边界,这就是为什么源码和文档看起来都能跑,但真正维护起来水平差距会很大。

如果学员或者初级开发者拿这套源码练手,我建议别急着改业务逻辑,先用预置账号把每一个模块从录入到审批走一遍,再把数据库的E-R关系梳理一遍,最后尝试自己加一个“安全教育培训记录”这类新模块,走通全链路。把这个过程做完,比单纯看十遍文档都管用。

系统跑起来之后还可以往两个方向扩展:一是接入井下物联网设备的实时数据,把手工填报逐步替代掉;二是增加移动端应用,让安检员在现场直接拍照取证、语音录入隐患,减少二次转抄的工作量。这些都是后话,先把基础打扎实再说。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进