拓冰建站拓冰建站
首页 / 资讯中心 / 正文

船舶维保管理系统开发实战:Spring Boot+Vue全栈实现设备全生命周期管理

1. 项目背景与需求解析做船舶维保管理系统这类毕业设计或实际项目最忌讳的就是一上来就写代码。我见过太多同学把需求文档丢到一边直接建个表就开始CRUD结果做到一半发现业务流程根本对不上返工成本高得离谱。船舶维保这个场景尤其特殊——它不是普通的进销存也不是简单的事务管理系统它背后是一套完整的设备全生命周期管理逻辑。1.1 这个系统到底在解决什么问题船舶维保管理系统核心要解决的是三件事设备台账数字化、保养计划自动化、维修流程闭环化。先说设备台账数字化。一条船上少说有几十上百台设备主机、辅机、发电机、压载水处理系统、导航设备、消防设备每台设备都有自己的型号、出厂编号、安装位置、上次保养时间、下次保养时间。传统做法是excel表格加纸质档案一旦设备多了查询某个设备的历史维保记录要翻半天更别提统计整条船的维保成本了。系统要做的第一件事就是把这张“设备卡片”搬到线上。再说保养计划自动化。船舶设备的保养不是想起来再做而是有严格的周期要求——有的按运行小时有的按日历天数比如主机滑油每运行500小时要取样化验消防设备每季度要检查一次救生艇释放装置每半年要测试。人工记这些周期非常容易漏漏一次可能就是安全事故。系统需要做到的是根据每台设备的保养周期自动生成到期的保养任务提前提醒机务人员。最后是维修流程闭环化。设备出故障了谁报修、谁审批、谁派工、维修结果怎么验收、换了什么备件、花了多少钱这些环节如果在线下流转大概率会出现单据丢失、责任不清、成本汇总困难的问题。系统要把整条链路串起来让每一步都有记录、可追溯。1.2 目标用户与典型使用场景这套系统主要面向两类用户船上的轮机员/机务人员和岸基管理人员。船上的机务人员是主要操作者他们每天要填写设备运行状态、登记故障情况、接收保养任务、记录维修结果。他们需要的界面要足够简单操作路径要短最好三步之内就能完成一次维保记录的填写。我见过有些系统把表单做得极其复杂一个保养记录二十多个必填字段结果船员根本没耐心填系统就沦为摆设。岸基管理人员更关注宏观层面的事情机队维保成本分析、设备故障率统计、各船维保计划执行率、备件库存周转情况。他们需要的是报表和可视化看板能快速定位哪些船、哪些设备的维保工作滞后了。还有一个容易被忽略的使用场景是审批流转。船舶在海上是移动的网络环境不稳定所以系统在设计时要考虑报修单能否在离线状态下暂存恢复网络后再提交审批节点能否支持移动端操作方便不在船上的轮机长随时处理。这也是为什么现在这种系统普遍采用前后端分离架构后端提供接口前端可以同时适配PC浏览器和移动端。1.3 为什么选择Web系统而不是C/S架构很多早年的船舶管理系统用的是C/S架构客户端要安装exe程序数据库直连。这种模式在局域网环境里挺好用但船队管理通常是岸基与多艘船之间通信跨越的地理范围很大C/S的部署成本和网络穿透问题都很头疼。B/S架构的好处是零安装浏览器即开即用船上的电脑配置普遍不高只要有个浏览器就能访问。另外B/S架构天然适合前后端分离的微服务演进。初期可以做成单体应用快速上线后面需要对接船联网、卫星通信数据、第三方接口时再逐步拆分服务灵活性高得多。对于毕业设计而言选择Spring Boot Vue这套主流组合也是在“技术先进性”和“开发效率”之间取了平衡点。2. 核心技术栈与架构设计技术选型这件事踩过的坑多了就会明白不是越新越好也不是越多越好而是要匹配项目规模和团队能力。船舶维保管理系统业务复杂度中等偏上并发量不高一个船队同时在线的人撑死几百个但对数据准确性、流程严谨性要求很高。基于这个判断我选择了下面这套已经被无数同类项目验证过的组合。2.1 后端框架选型Spring Boot MyBatis PlusJava后端这块Spring Boot已经成为事实标准版本选的是2.7.x稳定而且资料多遇到问题在网上基本都能搜到答案。选Spring Boot而不是SSH或者裸Servlet理由很简单自动配置能省掉大量XML配置工作内置Tomcat让部署变成“打jar包上传服务器运行”对开发效率和部署友好度都是质的提升。持久层我用的MyBatis Plus而不是Spring Data JPA。原因有两条。第一这个项目的查询多数是条件组合查询比如“查询某艘船、某个时间段内、某种状态的所有维修工单”MyBatis Plus的LambdaQueryWrapper写起来非常顺手条件动态拼接逻辑清晰。第二MyBatis Plus提供了逻辑删除、自动填充、分页插件这些现成能力少写很多样板代码。不过要提醒一句MyBatis Plus只是简化了CRUD复杂报表查询还是得手写SQL不要迷信框架。2.2 前端方案Vue 3 Element Plus前端选的Vue 3 Element Plus是当下后台管理系统的主流搭配。Vue 3的Composition API让逻辑复用变得容易比如设备信息的表单校验、工单列表的分页状态、保养计划的倒计时显示这些都能抽成独立的hook函数。Element Plus这套组件库覆盖了表格、表单、弹窗、树形控件、日期选择这些后台系统的常规需求不需要自己造轮子。有一点经验之谈项目管理、工单流转这类页面看起来功能简单但表格的列非常多建议从一开始就封装一个通用的Table组件把分页、刷新、列显隐、排序这些逻辑收敛在一起后面开发效率能提升不少。2.3 数据库设计与选型MySQL 8.0数据库用的MySQL 8.0InnoDB引擎字符集utf8mb4。船舶维保系统的数据量级跑个几年也就在百万条记录以内MySQL完全够用没必要上PostgreSQL或者Oracle。8.0相比5.7有几个正向改进窗口函数做统计报表很方便、JSON类型存设备扩展属性很灵活、通用表表达式递归查询设备父子层级。设计数据库时有几点容易踩坑的地方需要特别注意。第一设备表要有独立的设备编码字段不要用自增主键直接当业务编码。因为船舶设备的编号往往有行业习惯和业务含义比如主机编码是ME-01、辅机是AE-01这种编码规则要单独维护。第二保养计划表里要同时存“计划名称”和“执行周期类型”。周期类型有运行小时如500小时和日历天数如90天两种计算下次保养时间时逻辑截然不同运行小时类型的需要结合设备运行记录表来累加。第三所有业务表都要有create_time、update_time、logic_delete这三个公共字段。逻辑删除尤其重要设备或者工单记录一旦物理删除了后面的审计和追溯就断了船东检查时拿不出完整的维保历史是要出问题的。2.4 系统整体架构与模块划分系统的整体架构分三层表现层Vue页面、业务层Spring Boot接口、数据层MySQL。没有引入Redis做缓存也没有搞消息队列原因是这个系统的数据实时性要求没那么高查设备列表、查维保记录这些高频操作直接查MySQL也够用。引入中间件反而增加部署复杂度对毕业设计和中小型项目运维都是负担。但架构上有一件事一定要做好——接口的返回结构要统一。我用的规范是状态码200成功、400参数错误、401未认证、500服务异常、消息描述、数据体三个字段。前端所有请求都封装一个axios实例统一处理token注入、错误码提示这样联调时能省一半扯皮时间。模块划分上系统拆成了六大业务模块模块名称核心功能关键数据表设备台账管理设备档案新增、编辑、退役、查询device_info保养计划管理保养周期配置、任务生成、到期提醒maintain_plan, maintain_task维修工单管理报修、审批、派工、完工验收、评价repair_order, repair_log备件库存管理备件出入库、库存预警、备件与工单关联spare_part, stock_record系统用户管理用户认证、角色权限分配sys_user, sys_role统计报表管理维保成本统计、设备故障率、计划执行率基于以上业务表聚合查询这六个模块不是拍脑袋拆的而是从业务链路自然梳理出来的设备是维保对象保养计划是主动维护维修工单是故障处理备件是资源支撑用户和权限是系统底座报表是管理层视角。模块划分清楚之后后面团队协作并行开发时互相之间的代码冲突就会少很多。3. 数据库表设计与核心功能模块拆解数据库设计的好坏直接决定后面写代码是顺畅还是痛苦。我带着好几个项目总结下来的教训是建表之前先在白纸上把业务对象和对象之间的关系画出来表结构设计至少要花整个项目四分之一的时间。3.1 核心数据表结构与字段解析船舶维保系统的数据库核心表有七张左右这里把最关键的几张掰开揉碎讲。设备信息表device_info是基础表字段设计要注意区分“设备本体属性”和“管理属性”。本体属性包括设备名称、型号、出厂编号、制造商、安装位置管理属性包括所属船舶编号、设备状态运行中/停机/维修中/已退役、责任人。本体属性是客观的管理属性是跟随业务状态变化的。两张属性混在一起没问题但新增设备时表单要引导用户把两类信息分开填避免填到一半不知道哪个字段是必填。保养计划表maintain_plan要重点讲。建议的字段结构是计划编号、设备编号、保养项目名称、保养内容描述、周期类型1-运行小时2-日历天数、周期值、提醒提前天数、下次执行时间、状态启用/停用。这里有个关键的业务规则运行小时型周期要通过设备运行记录表device_running_log累计运行小时数达到周期值时触发任务日历天型周期直接按日期加减计算下次执行时间。两种类型混在一起容易乱建议单独用字段标识计算逻辑分开关联。维修工单表repair_order是整个系统流转最复杂的表状态机要理清楚。工单状态从待审批到审批通过、待派工、维修中、待验收、已关闭、已驳回。每张工单要有报修人、报修时间、故障描述、紧急程度、审批意见、维修人、维修方案、更换备件记录、验收人、验收结果这些字段。状态字段用tinyint存数值配合状态枚举类管理不要让状态散落在各处if判断里。备件库存表spare_part需要说的是备件信息最好支持“适用设备型号多对多关联”因为一种备件可能适配多种设备。这种关系在MySQL里怎么处理单独建一张关联表即可。备件出库时要同时写库存变动记录保证以后能追溯每一次出入库流水这既是为了成本核算也是为了防止操作人员误改库存数据。3.2 设备全生命周期管理模块设备全生命周期这个说法听起来高大上落到实处其实就是从设备登记入库到日常运行到保养、维修再到最终退役每一个环节都有记录、有责任人、有时间戳。在代码层面这个模块最核心的是设备详情页如何聚合展示。我采用的方式是设备列表用表格展示摘要字段点击“详情”跳转到设备详情页详情页顶部是设备基本信息卡片下方用Tabs组件分开展示“维保记录”“维修记录”“备件更换记录”“关联工单”。这样做的好处是一个页面对应一个设备的完整历史查问题时不用在不同菜单之间来回跳。设备退役这块容易被忽略。退役不是简单把状态改成“已退役”而是要校验该设备是否存在未完成的维保任务或未关闭的维修工单如果有系统要给出提示不允许退役操作。这个校验逻辑放在后端Service层处理前端只负责展示提示信息。我在实际项目里遇到过设备被误退役后工单还在流转的情况加了这个校验以后就再没犯过这种错。3.3 保养计划自动生成与提醒机制保养计划自动生成是这个系统里最“智能”的部分也是让船东觉得“这套系统值钱”的关键功能。实现思路是这样的系统每天定时跑一个任务我用的是Spring Schedule每天凌晨执行一次扫描所有状态为“启用”的保养计划判断每种计划下一次执行时间或运行小时是否已到期到期则生成一条保养任务记录并推送到对应责任人的待办列表里。为了防止重复生成要在任务表里做唯一约束比如同一天同一计划只允许生成一条任务。这里有一个细节提醒机制不能只在系统内提示最好还要支持站内消息后期还可以接入企业微信或者钉钉通知。但毕业设计做到站内消息就够了用户登录后待办角标有数字提醒点进去在待办列表里看到。提醒的“提前天数”要有比如保养计划还有7天到期系统就要开始展示黄色预警到期当天变红色。预警阈值的计算逻辑放在前端展示层做后端只保证“下次执行时间”字段是准确的。生成保养任务之后任务本身要有状态流转待执行、执行中、已完成、已逾期。已逾期这个状态特别重要哪个计划逾期了一目了然这一项在船舶安全检查中是重点被查的内容。我见过不少系统不做逾期状态任务到期后没完成就直接消失这是管理上的大忌。3.4 维修工单全流程状态流转维修工单的状态流转用我前面提到的状态机图可以先画出状态转换关系再写对应的接口。这里按操作角色划分清楚每个环节该谁操作报修船员在“报修”页面提交工单填设备、故障描述、紧急程度系统自动带上报修人和时间。审批轮机长或设备主管审批可以同意进入待派工或驳回退回报修人要填驳回原因。派工调度人员指定维修负责人和期望完成时间。维修执行维修人填写实际维修方案、更换备件清单、工时、实际完成时间。验收轮机长验收可以选择通过工单关闭或不通过退回维修中填验收意见。评价选做功能可以对维修质量打分数据纳入维修人员绩效考核。至少做到前三步流转系统就具备基本的工作流价值了。我在开发时踩过一个坑初期把“审批”和“派工”合并成一个状态结果实际操作中审批人和派工人往往不是同一个人流程走不通。后面拆开之后才顺畅。所以设计状态机时宁可多拆几步也不要试图用“备注字段”去弥补状态缺失。3.5 备件库存管理与工单联动备件库存管理一旦和维修工单联动数据一致性的问题就出现了。典型场景维修工单里填了“更换主机滤芯1个”备件库存表就要自动扣减1个。这个扣减动作不能写在工单保存接口里因为工单保存时维修人可能还没最终确认用了哪些备件。更合理的做法是维修执行环节单独设计一个“备件出库”的操作维修人在备件列表里选择出库出库成功后系统自动写入库存变动流水工单里同步展示关联的出库记录。库存在临界点的时候要预警。每年设定一个库存预警阈值比如滤芯少于10个就提示采购系统在备件列表页用不同颜色标记正常、偏低、不足三种状态。预警逻辑放在查询接口里做返回每条备件的库存状态字段前端直接着色就行不需要额外定时任务。还有一个建议备件的主数据字段名称、规格、单位、适配设备型号在建表时就要注意数据规范名称和规格不能混在一个字段里。原因很简单后续统计“某型号设备的备件消耗情况”时如果名称和规格混在一起SQL写起来会非常痛苦而且要随时面临数据清洗问题。4. 核心功能模块的代码级实现细节这一节从代码层面拆几个核心功能的实现思路。我默认看这篇博客的读者已经有了基础所以只把关键逻辑和容易写错的地方拎出来说代码片段选取核心部分给出。4.1 保养计划到期的判断与任务生成保养任务生成的核心是到期判断逻辑。这里要注意区分“按运行小时”和“按日历天数”两种计算方式。按日历天数的方式很简单用下一条计划执行日期和当前日期比较即可。但按运行小时的方式要麻烦一点需要从设备运行记录表里累加从上一次保养结束到现在的运行小时数当累计小时数达到周期值时触发。实现时可以在设备运行记录表里存放每次的运行起始和结束时间计算时用SUM聚合函数累加。下面这段是任务生成的核心代码简单做了一层抽象用工厂模式区分两种周期类型的计算器。public interface DueDateCalculator { LocalDateTime calculateNextDue(DeviceDevice device, MaintainPlan plan); } Component public class CalendarDueDateCalculator implements DueDateCalculator { Override public LocalDateTime calculateNextDue(Device device, MaintainPlan plan) { // 日历天类型下次到期 上次执行时间 周期天数 LocalDateTime lastExecTime plan.getLastExecTime() null ? LocalDateTime.now() : plan.getLastExecTime(); return lastExecTime.plusDays(plan.getCycleValue()); } } Component public class RuntimeHoursDueDateCalculator implements DueDateCalculator { Override public LocalDateTime calculateNextDue(Device device, MaintainPlan plan) { // 运行小时类型下次到期 上次执行时间 需要累计的运行小时数转换成天数 // 这里简化了把小时按每天平均运行8小时折算成天数 long remainingHours plan.getCycleValue() - getAccumulatedHours(device, plan); long daysToAdd (long) Math.ceil(remainingHours / 8.0); return LocalDateTime.now().plusDays(daysToAdd); } private long getAccumulatedHours(Device device, MaintainPlan plan) { // 这里实际应该查 device_running_log 表SUM(start_time, end_time) return 0L; } }计费这种用工厂模式的好处是将来如果有新周期类型比如按航次数量、按操作次数只要新增一个实现的类不用改动调用方逻辑。这是设计模式在真实业务里的一个典型落地场景——不是为了用模式而用模式而是因为周期计算逻辑确实存在多分支的扩展需求。调度的定时任务我用的Spring Schedule的Scheduled(cron 0 0 2 * * ?)凌晨两点跑一次避免影响白天的正常业务。任务逻辑是遍历所有启用的保养计划调用对应的计算器算出到期时间到期则新增保养任务并推送到待办。查询时只要简单处理“今天之前含今天的到期任务为空”这些边界条件就够了。4.2 工单状态机的数据库与接口实现工单状态流转我强烈建议用状态 操作事件两张表来维护而不是每一处都硬编码改状态。思路是这样的主表repair_order里存当前状态子表repair_order_log存每一次状态变更的日志谁、什么时候、从什么状态改成什么状态、审批意见是什么。这样既能看到工单的实时状态又能回溯完整的历史轨迹审计和排障都好用。接口层定义了一个changeOrderStatus方法核心逻辑是校验当前状态是否允许执行目标操作。比如只有状态为“待审批”时才能审批通过进入“待派工”只有“维修中”才能提交验收。这个校验放在Service层统一拦截避免前端绕过按钮直接调用接口把状态改乱了。Transactional public void approveOrder(Long orderId, Long approverId, String comment) { RepairOrder order repairOrderMapper.selectById(orderId); if (order null) { throw new ServiceException(工单不存在); } if (!OrderStatus.PENDING_APPROVAL.getCode().equals(order.getStatus())) { throw new ServiceException(当前状态不允许审批只能审批待审批状态的工单); } order.setStatus(OrderStatus.PENDING_DISPATCH.getCode()); repairOrderMapper.updateById(order); repairOrderLogMapper.insert(RepairOrderLog.builder() .orderId(orderId) .operatorId(approverId) .beforeStatus(OrderStatus.PENDING_APPROVAL.getCode()) .afterStatus(OrderStatus.PENDING_DISPATCH.getCode()) .operationType(APPROVE) .comment(comment) .build()); }工单状态用常量类或枚举类统一管理不让状态魔法值散落在各个业务代码里这个是维护阶段能救命的习惯。4.3 报表统计模块的SQL实践经验统计报表是留给自己最有用的功能之一也是最容易写烂SQL的地方。以“设备故障率统计”为例常见的需求是按月统计某条船或整个船队的故障工单数量、平均维修时长、故障设备类型分布。这里强烈推荐MySQL 8.0的窗口函数。先写一张基础明细子查询再用窗口函数做聚合逻辑清楚得多。演示一个按月统计故障数的示例SELECT DATE_FORMAT(o.create_time, %Y-%m) AS month, d.device_type, COUNT(*) AS fault_count, ROUND(AVG(TIMESTAMPDIFF(HOUR, o.create_time, o.finish_time)), 1) AS avg_hours FROM repair_order o LEFT JOIN device_info d ON o.device_id d.device_id WHERE o.create_time 2024-01-01 AND o.create_time 2025-01-01 GROUP BY month, d.device_type ORDER BY month, fault_count DESC;这种SQL在数据量不大的时候执行性能完全能接受。如果后面数据量上去了记得给create_time、device_id、status这些查询条件常见的字段加联合索引。有一次我把设备类型筛选条件放在了WHERE子句中导致统计结果不对——因为某些工单关联的设备已经退役被逻辑删除了LEFT JOIN后device_type为NULL被WHERE条件过滤掉了。解决办法是统计结果永远基于业务时间范围create_time过滤不基于设备现状过滤统计口径才不会漂移。4.4 用户权限管理的经典实现用户权限用RBAC模型三张表用户表、角色表、用户角色关联表。再加菜单表或者权限点表然后用户角色关联权限。船舶维保系统的角色一般有系统管理员、机务主管、轮机员、普通船员、岸基管理。每个角色能访问的菜单和操作的按钮不一样。实现方式可以用Spring Security JWT也可以用拦截器手写。这里我给一个建议如果赶时间或代码熟练度一般用拦截器实现基于注解的权限校验足够了比引入Spring Security全家桶要简单可控得多。Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface RequirePermission { String value(); }然后在接口方法上加注解RequirePermission(maintain:plan:update) PostMapping(/plan) public Result? updatePlan(RequestBody MaintainPlan plan) { ... }拦截器里拿到当前登录用户的角色查角色对应的权限点列表判断是否包含注解要求的权限点不包含就返回403。这套方案麻雀虽小五脏俱全而且权限点字符串可以精确到某个按钮级别的操作业务扩展性够用。4.5 数据统计与图表展示的落地报表模块我用的是ECharts。前端拿到后端统计接口返回的数据结构直接用option配置渲染折线图、柱状图、饼图。不要在这个模块上花费太多精力做复杂的图表交互一个月度的维保计划完成率趋势图、一个设备故障类型分布饼图、一个备件库存预警表基本就覆盖了管理者的核心诉求。图表数据接口要注意的细节是统计的粒度参数按月、按季度、按年、维度参数按船舶、按设备类型、按故障类型两种维度要支持自由组合。前端用异步请求参数控制后端SQL用动态拼接实现。前端loading状态和空数据展示一定要处理好空图表直接显示一个“暂无数据”的插画比显示空白页面专业得多。5. 开发与调试实战经验总结最后这部分写写我在开发和部署过程中踩过的坑这些“亏”能帮后面的人省下大把时间。5.1 数据库时间字段的坑这是我第一次做船舶系统时踩得很惨的一次。船上设备的运行数据有的是UTC时间有的是北京时间一旦混了按小时统计就会差8个小时轻则报表数据偏差重则保养计划提前或错后一天触发。解决办法是统一规范数据库中所有时间字段一律存UTC时间展示层通过前端时区转换。但如果开发环境都在国内图省事也可以统一存北京时间关键是要全链路统一不能有的表存UTC有的表存本地时间。我的建议是毕业设计直接用本地时间加上时区字段做标识不搞全球跨时区部署就够用。5.2 备件库存超卖与并发问题最早设计备件出库接口时我只写了简单的逻辑查库存判断库存充足扣减库存。但如果在多用户同时操作时直接修改库存条数会出现超卖——两个出库请求同时读到库存是3件各自都判断“够扣”结果都扣了库存变成负的。正确做法是用数据库行锁或乐观锁。我用的是乐观锁版本号方案表里加一个version字段UPDATE语句带WHERE id ? AND version ?更新成功version自增更新影响行数为0说明有并发冲突提示用户刷新重试。这个方案实现成本低对毕业设计足够用了。UPDATE spare_part SET stock stock - #{count}, version version 1 WHERE id #{sparePartId} AND version #{version} AND stock #{count}5.3 权限组件在维护工单场景的兼容处理我遇到过一种常见情况某个船员被换岗到另一条船了但之前关联的工单还没完全流转完。如果权限校验是严格按“当前用户所属船舶”来判断那换岗后看到的工单列表就全都是过期的无法继续处理。解决方案是在工单上冗余一个“当前处理人所属船舶”字段。工单创建时快照该值业务查询时就按照快照值过滤而不是实时关联用户表里的船舶信息。这个“快照”思维在工单、审批、订单这类有时效性的业务中经常用到核心目的是保持业务发生时的上下文一致。5.4 启动阶段容易踩的配置坑第一是数据库驱动版本号。Spring Boot 2.7.x默认依赖的MySQL驱动是8.0系列如果你本地的MySQL版本是5.7注意驱动兼容性否则会出现乱码或者连接不稳定。第二是时区配置数据库连接串后要加serverTimezoneAsia/Shanghai。第三是MyBatis Plus的驼峰自动映射如果没开启查询结果里的device_name字段无法自动映射到deviceName属性。这些配置问题通常看一眼启动日志就能定位但在新手期会卡很久。5.5 如何把项目从“能跑”做到“出彩”如果要让这套系统在答辩或实际交付中更有竞争力我有几条锦上添花的建议。第一加一个消息通知模块能把保养任务到期、工单审批提醒、备件库存预警这三类消息发送到用户的站内收件箱。技术上就是一张消息表和收件箱接口逻辑不难但能极大提升系统完成度。第二做一个“船队总览”的驾驶舱页面整条船队的设备总数、今日到期保养、待处理工单、本月维保成本四个核心指标放一张卡片页展示下面叠加近期趋势图。这个页面就是给管理者看的数据接口可以复用报表模块的统计接口前端只需把布局搭好看一点。第三加一个维保记录导入/导出Excel功能船员在实际使用中很喜欢这个功能——他们可以用Excel批量导入初始设备台账也可以用Excel导出月度维保报告去汇报存档。用EasyExcel库能快速搞定重点是表头模板要和系统字段严格对应导入前做好格式校验。6. 写在最后的几点心得这套系统前前后后我改了三版才觉得像个能用的产品。第一版只做了基础的设备增删改查被一句“这跟Excel有什么区别”问住了第二版补上了保养计划和工单流转业务逻辑通了但界面糙得不好意思演示第三版才开始注重用户体验和报表展示。所以如果你正在做类似项目别指望一版到位需求总是在代码写完之后才真正清晰起来的。如果你做这个项目是为了毕业设计我的建议是在数据库设计和状态机设计上多花时间答辩老师最喜欢问这两块展示时优先讲“保养计划如何自动化生成”“工单状态如何流转”“报表数据怎么聚合”这三个点思路清晰远比界面华丽重要。如果是为了真实部署我再多说一句船舶现场的硬件环境参差不齐有的船电脑还在用Windows 7浏览器是IE内核的老版本前端框架如果用Vue 3的话打包时注意浏览器兼容目标必要时降级到Vue 2或者加polyfill。这个细节对于实际落地很重要但在演示环境里常常被忽略。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门