船舶维保系统实战:SpringBoot+Vue3前后端分离实现与部署

发布时间:2026/10/20 6:39:28
船舶维保系统实战:SpringBoot+Vue3前后端分离实现与部署 没想到这个项目标题能被这么多人搜到看来船舶维保系统的需求确实不小。我之前跟几个做船舶信息化项目的朋友聊过大家普遍的感受是行业里的老系统大多是 C/S 架构的单机版操作繁琐、数据孤岛严重而市面上能直接落地的 B/S 架构维保系统源码并不算多。正好借这个机会把我自己参与过的一个模拟项目“某船舶维保管理系统”的完整实现经验拆开揉碎了讲一讲。这篇文章没有废话直接上干货从需求拆解到数据库设计、后端接口、前端页面、权限控制再到部署避坑一条线捋下来。如果你正准备做船舶相关的毕设或者公司内部想搭一套设备运维管理平台又或者只是单纯想学 SpringBoot Vue3 前后端分离项目的完整落地套路这篇内容都适合你。我尽量用“做过的人”的口吻把那些文档里不写、但实际开发中一定会踩的坑和细节一次性讲清楚。1. 项目整体设计与技术选型思路1.1 船舶维保系统的核心业务场景先别急着写代码搞懂业务才是第一步。船舶维保管理系统听起来高大上但落到实际使用场景核心其实就四件事管船、管养、管修、管件。管船需要维护每艘船的基本档案包括船名、船舶类型散货船、集装箱船、油轮等、吨位、建造日期、主机型号、当前状态在航、检修、停航等。管养也就是计划性维护Planned Maintenance。船舶设备需要按照运行小时数或日历周期进行保养比如“主机每运行 2000 小时更换滑油滤器”、“救生设备每月检查一次”。系统要能自动生成保养计划并提醒。管修设备真正出故障了要发起维修工单记录故障现象、维修内容、更换配件、工时和费用形成完整的维修履历。管件备品备件管理。维修时需要消耗配件完了要扣减库存库存不够时要触发采购提醒采购入库后更新库存。围绕这四个场景系统可以拆分为几个核心模块船舶档案模块、保养计划模块、维修工单模块、备件库存模块、统计分析模块、系统管理模块用户、角色、菜单、字典。1.2 技术栈选型为什么是 SpringBoot Vue3 MyBatis这个组合在当下属于非常主流的“Java 全栈开发黄金组合”选择它不只是因为流行更是因为它恰好覆盖了这套系统的所有需求点。我先说后端 SpringBoot。SpringBoot 最大的价值在于“约定优于配置”它能让你以极快的速度搭建一个可运行的 Web 服务相比于传统的 SSM 组合省掉了大量繁琐的 XML 配置。在船舶维保这种业务逻辑不算极其复杂、但涉及模块较多的管理系统中SpringBoot 的自动装配特性和丰富的 Starters 生态系统能大幅缩短开发周期。而且 Java 生态稳定适合船舶这种要求可靠性较高的工业管理场景。再看看前端 Vue3。Vue3 的组合式 APIComposition API和 TypeScript 支持让组件逻辑复用变得非常优雅。维保系统的界面有大量表格、表单、弹窗、统计图表Vue3 的响应式系统配合 Element Plus 组件库可以快速构建出质感不错的业务界面。加上 Vite 构建速度极快开发体验很舒服。至于 MyBatis虽然 JPA 也很流行但 MyBatis 在复杂查询优化和 SQL 精细控制方面更有优势。维保系统的报表统计模块往往涉及多表联查、条件动态拼接用 MyBatis 的 XML 映射文件可以写得很直观方便后期 DBA 优化慢查询。而且国内企业项目对 MyBatis 的接受度极高你几乎不用为“招来的人会不会用”发愁。最后是前后端分离架构。维保系统这种项目天然适合前后端分离。前端部署在 Nginx后端打包成 Jar 独立部署两者通过 RESTful API 通信。这样开发时前后端可以并行推进我用的是前端 Mock 数据先行后端接口对接的模式后期维护和升级也更灵活。MySQL 作为数据库选型对于这种量级的管理系统完全足够配合 MySQL Workbench 或者 Navicat 管理数据都很方便。1.3 功能模块划分与权限模型设计一个合格的维保系统必须有清晰的功能权限和数据权限控制。功能权限用经典的 RBAC基于角色的访问控制模型用户 - 角色 - 菜单权限。比如“驾驶员”角色只能查看自己船的维保记录“机务主管”可以创建保养计划和维修工单“备件管理员”只能操作备件出入库“系统管理员”则拥有全部权限。数据权限船舶维保有个特点不同角色看到的船舶范围不同。比如一个机务主管可能只管某几条船超级管理员可以看全部。这里我采用了比较灵活的方式给系统管理模块增加了“数据范围”字段全部数据、本部门数据、自定义数据用 AOP 拦截 SQL 实现行级数据隔离。虽然实现起来稍显复杂但这是系统能真实落地到多部门协作场景的关键。核心权限数据表设计如下表名说明核心字段sys_user用户表user_id, username, password, dept_id, statussys_role角色表role_id, role_name, role_key, data_scopesys_menu菜单权限表menu_id, parent_id, menu_name, perms, path, componentsys_user_role用户角色关联表user_id, role_idsys_role_menu角色菜单关联表role_id, menu_idsys_dept部门表dept_id, parent_id, dept_name这个表结构是经典的 RBAC 通用设计处理维保系统的“用户管理 - 船舶档案 - 维保业务”三层权限关系非常顺手。2. 数据库设计与关键业务规则沉淀2.1 船舶维保业务的核心数据表结构这张表结构是整个系统的地基我先讲最核心的几张业务表。船舶档案表ship_infoCREATE TABLE ship_info ( ship_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 船舶ID, ship_name VARCHAR(64) NOT NULL COMMENT 船名, ship_type VARCHAR(32) COMMENT 船舶类型散货船/集装箱船/油轮/拖轮等, imo_number VARCHAR(32) COMMENT IMO编号, gross_tonnage DECIMAL(10,2) COMMENT 总吨位, main_engine_model VARCHAR(64) COMMENT 主机型号, build_date DATE COMMENT 建造日期, current_status VARCHAR(16) DEFAULT ACTIVE COMMENT 状态ACTIVE在航/MAINTENANCE检修/STOP停航, dept_id BIGINT COMMENT 所属部门管理该船的部门, create_time DATETIME, update_time DATETIME, del_flag TINYINT DEFAULT 0 ) ENGINEInnoDB COMMENT船舶档案表;保养计划表maintenance_planCREATE TABLE maintenance_plan ( plan_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 计划ID, ship_id BIGINT NOT NULL COMMENT 船舶ID, equipment_name VARCHAR(100) COMMENT 设备名称, plan_type VARCHAR(16) COMMENT 计划类型CALENDAR按日历周期/HOURS按运行小时, cycle_value INT COMMENT 周期数值如30、90、2000, cycle_unit VARCHAR(8) COMMENT 周期单位DAY天/HOUR小时, last_maintenance_date DATE COMMENT 上次保养日期, last_maintenance_hours DECIMAL(10,2) COMMENT 上次保养时运行小时数, next_maintenance_date DATE COMMENT 下次保养日期自动计算, assignee VARCHAR(32) COMMENT 负责人, status VARCHAR(16) DEFAULT PENDING COMMENT 状态PENDING待执行/COMPLETED已完成/OVERDUE已逾期, remark VARCHAR(500), create_time DATETIME, update_time DATETIME ) ENGINEInnoDB COMMENT保养计划表;维修工单表repair_orderCREATE TABLE repair_order ( order_id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 工单ID, order_no VARCHAR(32) NOT NULL COMMENT 工单编号如RO20250115001, ship_id BIGINT NOT NULL COMMENT 船舶ID, equipment_name VARCHAR(100) COMMENT 故障设备, fault_description TEXT COMMENT 故障描述, fault_level VARCHAR(8) DEFAULT GENERAL COMMENT 故障级别GENERAL/URGENT/CRITICAL, repair_content TEXT COMMENT 维修内容, repair_begin_time DATETIME, repair_end_time DATETIME, repair_cost DECIMAL(12,2) DEFAULT 0 COMMENT 维修费用, parts_cost DECIMAL(12,2) DEFAULT 0 COMMENT 备件费用, labor_hours INT DEFAULT 0 COMMENT 工时, status VARCHAR(16) DEFAULT PENDING COMMENT 状态PENDING待派工/REPAIRING维修中/COMPLETED已完成/VERIFIED已验收, handler VARCHAR(32) COMMENT 维修人员, create_time DATETIME, update_time DATETIME ) ENGINEInnoDB COMMENT维修工单表;备件库存表spare_part与出入库记录表spare_part_stockCREATE TABLE spare_part ( part_id BIGINT PRIMARY KEY AUTO_INCREMENT, part_code VARCHAR(32) NOT NULL COMMENT 备件编码, part_name VARCHAR(100) NOT NULL COMMENT 备件名称, specification VARCHAR(100) COMMENT 规格型号, unit VARCHAR(8) COMMENT 单位个/套/箱, safety_stock INT DEFAULT 0 COMMENT 安全库存, current_stock INT DEFAULT 0 COMMENT 当前库存, location VARCHAR(64) COMMENT 存放位置, update_time DATETIME ) ENGINEInnoDB COMMENT备件表; CREATE TABLE spare_part_stock ( stock_id BIGINT PRIMARY KEY AUTO_INCREMENT, part_id BIGINT NOT NULL, change_type VARCHAR(8) COMMENT IN入库/OUT出库, quantity INT NOT NULL COMMENT 数量, related_order_no VARCHAR(32) COMMENT 关联单据号工单号/采购单号, operator VARCHAR(32) COMMENT 操作人, create_time DATETIME ) ENGINEInnoDB COMMENT备件出入库记录表;这张表设计里有几个细节非常关键保养计划表中的“运行小时”逻辑船舶主机和发电机的保养周期往往不是按日历天算而是按运行小时算比如主机每运行 2000 小时需换机油。这块我不仅存了 last_maintenance_hours还单独在船舶表关联了当前累积运行小时数由系统自动比对。如果只做日历提醒在真实业务中是要被机务主管吐槽的。维修工单的金额拆分维修成本分为维修费和备件费背后关联备件出库记录的订单号这样财务结算时可以追溯每笔钱花在哪里。工单流转时状态必须严格按“待派工 - 维修中 - 已完成 - 已验收”的顺序每一步的操作人、操作时间都应该记录在日志表里。软删除字段所有业务表都加了 del_flag 字段做逻辑删除而不是物理删除。船舶维修记录是重要台账物理删除了未来审计要吃大亏。2.2 维保到期自动计算基于日历周期与运行小时双模式这是整个系统业务逻辑最核心的点。实现思路是定时任务每天凌晨跑一次遍历所有保养计划自动判断并更新状态。日历周期模式的计算公式很简单下次保养日期 上次保养日期 周期数值天运行小时模式的公式稍微复杂预计下次保养日期 上次保养日期 (周期数值 - (当前累积运行小时数 - 上次保养时运行小时数)) / 日均运行小时数这里日均运行小时数是一个经验值比如主机日均运行 18 小时如果没有接入实时轮机数据就用这个估算值算出“预计日期”在界面上显示“预计剩余 XX 天”。如果累计运行小时数已经达到周期数值就直接触发逾期提醒。定时任务我用的是 Spring 自带的 Scheduled 注解每分钟跑一次“检查并更新维护计划”的任务。判断逻辑大概是// 伪代码逻辑 public void checkMaintenancePlan() { ListMaintenancePlan plans maintenancePlanMapper.selectAllActivePlans(); Date today new Date(); for (MaintenancePlan plan : plans) { if (plan.getPlanType().equals(CALENDAR)) { // 日历周期判断 Date nextDate DateUtil.offsetDay(plan.getLastMaintenanceDate(), plan.getCycleValue()); if (today.after(nextDate) plan.getStatus().equals(PENDING)) { // 更新状态为逾期 OVERDUE同时给负责人发站内消息 plan.setStatus(OVERDUE); // 推送到消息中心 } } else { // 运行小时判断 BigDecimal shipHours shipMapper.selectRunHours(plan.getShipId()); BigDecimal totalNeed plan.getLastMaintenanceHours().add(plan.getCycleValue()); if (shipHours.compareTo(totalNeed) 0) { plan.setStatus(OVERDUE); } } } }在真实项目中定时任务不要只依赖 Scheduled如果系统做了集群部署多台机器同时跑会重复处理。我当时是加了一个基于数据库的分布式锁表或者引入 XXL-Job 这类分布式调度中间件保证同一时刻只有一个节点在干活。2.3 备用配件库存扣减与安全库存预警维修工单完成时系统要支持“关联备件出库”。这块很容易做成一锤子买卖工单填个备件费用就完了库存不扣。实战中我设计如下流程工单进入“已完成”状态前必须经过“引用备件”步骤。前端弹出备件选择框选择备件编号和数量。后端收到请求后先查询当前库存库存充足才能扣减当前库存减去出库数量。扣减后判断当前库存是否小于安全库存如果小于自动生成一条补货预警消息推送给备件管理员。同时向 spare_part_stock 表插入一条出库记录关联工单号。这里有个非常容易踩坑的点是并发扣减导致库存变负数。解决思路很标准扣减库存的 SQL 必须使用乐观锁或条件更新比如执行UPDATE spare_part SET current_stock current_stock - #{quantity}, update_time NOW() WHERE part_id #{partId} AND current_stock #{quantity}如果返回的影响行数为 0说明库存不足直接抛出业务异常提示“库存不足”。这种原子性更新比“先查询再判断再更新”安全得多虽然看起来只是多了一个 where 条件但这就是老手和新手写库存系统的差别。3. 后端核心接口实现与业务逻辑落地3.1 工程结构规划与通用返回体设计后端工程我按经典的分层架构组织Controller - Service - Mapper清晰可维护。com.ship.maintenance ├─ common # 通用类返回体、异常处理、常量、工具类 ├─ config # 配置类MyBatis、安全配置、跨域配置、定时任务 ├─ controller # 接口层 ├─ service # 业务逻辑层 ├─ mapper # 数据访问层 ├─ entity # 数据库实体类 ├─ dto # 数据传输对象VO、BO ├─ security # 认证授权相关 └─ task # 定时任务通用的返回体设计是整个系统前后端沟通的“协议”。我自定义了一个 Result 类统一返回格式为{ code: 200, message: 操作成功, data: {} }code 为 200 表示成功401 表示未登录403 表示无权限500 表示服务器异常。所有 Controller 的返回值都是 Result 成功时调用 Result.success(data)失败时抛出自定义业务异常 BusinessException由全局异常处理器统一捕获并包装成上述结构返回。这个设计避免了每个接口各写一套返回格式的尴尬也方便了前端 axios 响应拦截器统一处理错误码比如 401 时自动跳转登录页403 时弹出“无权限”提示。3.2 基于 JWT 的登录认证与接口拦截器船舶维保系统的登录认证我用的是 JWTJSON Web Token Spring Security 的组合方案。JWT 的好处是无状态、便于水平扩展适合前后端分离架构。登录成功后后端签发一个 token 返回给前端前端存储在 localStorage 中每次请求通过 Header 的 Authorization 字段携带。核心逻辑// 登录成功后生成token String token JwtUtil.createToken(userId, username); // Spring Security 配置核心过滤器链 http .csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers(/api/auth/login, /api/auth/captcha).permitAll() .anyRequest().authenticated() .and() .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);这里要注意几个实操细节密码存储使用 BCryptPasswordEncoder 加密数据库中不要存明文。BCrypt 自带盐值同样的密码每次加密结果不同安全性远高于 MD5。JWT 密钥管理密钥不要硬编码在代码中要放到 application.yml 配置里并使用环境变量注入防止泄露。Token 过期策略登录态一般设置 12 小时过期。如果用户长期在线前端需要在 401 时自动调用刷新接口重新签发 token不然做一半就被强制下线体验很糟糕。继承权限注解在 Controller 方法上用 PreAuthorize(hasAuthority(maintenance:plan:add)) 做接口粒度权限控制前端按钮通过 v-permission 指令控制显隐前后端双重校验。3.3 典型业务接口实现保养计划 CRUD 与工单状态机流转我挑两个最具代表性的接口展开讲。保养计划创建。前端传 shipId、设备名称、周期数值、周期单位。后端除了做常规的字段校验还要做业务校验该船舶同一设备是否已存在活跃的保养计划避免重复创建。维修工单状态流转是这套系统状态设计最复杂的部分直接用硬编码字符串去 if-else 是灾难。我采用状态机设计模式来管理public enum RepairOrderStatus { PENDING { Override public RepairOrderStatus next() { return REPAIRING; } }, REPAIRING { Override public RepairOrderStatus next() { return COMPLETED; } }, COMPLETED { Override public RepairOrderStatus next() { return VERIFIED; } }, VERIFIED { Override public RepairOrderStatus next() { return null; } }; public abstract RepairOrderStatus next(); }比如“待派工”状态只能流转到“维修中”不能直接跳到“已完成”非法流转抛异常提示。这个设计在代码层面保证了流程不可跳步比在 Service 层写一堆 if-else 要优雅得多也方便后续加“驳回”“挂起”等特殊流转。4. 前端工程搭建与页面核心交互4.1 Vue3 Element Plus 工程搭建与项目目录前端使用 Vite Vue3 TypeScript Element Plus配合 Pinia 做状态管理Axios 封装请求。src ├─ api # 接口请求函数 ├─ assets # 静态资源 ├─ components # 通用组件 ├─ router # 路由配置 ├─ stores # Pinia状态仓库用户信息、权限、菜单 ├─ views # 页面组件 │ ├─ login │ ├─ dashboard │ ├─ ship │ ├─ plan │ ├─ order │ ├─ spare │ └─ system ├─ directives # 自定义指令v-permission ├─ utils # 请求封装、token管理、工具函数 └─ types # TS类型定义脚手架直接用npm create vuelatest生成。项目初始化的时候有几个实用配置值得说一下vite.config.ts 配置代理开发环境下前端访问 /api 自动代理到 http://localhost:8080解决跨域问题。注意生产环境跨域问题要通过 Nginx 反向代理解决不能在前端用 CORS 解决。// vite.config.ts 核心配置 server: { port: 3000, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, rewrite: (path) path.replace(/^\/api/, ) } } }Axios 请求封装统一携带 token统一处理错误码。响应拦截器里当 code 为 401 时清除本地登录态并跳转 /login。service.interceptors.request.use((config) { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }) service.interceptors.response.use( (response) { const res response.data if (res.code ! 200) { ElMessage.error(res.message) return Promise.reject(new Error(res.message)) } return res }, (error) { if (error.response.status 401) { localStorage.removeItem(token) router.push(/login) } return Promise.reject(error) } )4.2 船舶维保大屏与工单操作台界面实现前端界面是用户直接感知的部分。维保系统主要的界面包括数据看板、船舶档案管理页、保养计划页、维修工单页、备件库存页和系统管理页。数据看板是整个系统的门面我用 ECharts 做了四个核心指标待执行保养计划数、逾期未处理工单数、当前库存不足备件数、本月维修总成本。下方拆成“近 12 个月维修成本趋势折线图”和“各船舶维修次数占比饼图”这类图表在真实项目中非常常见是管理层的核心关注点。维修工单操作台是高频交互页面设计原则是“能在一个页面完成的工作绝不跳页”。我采用左侧工单列表 右侧详情抽屉Drawer的结构点击左侧工单时右侧展示设备故障描述、时间线、备件引用记录和费用明细。工单状态变更通过顶部状态按钮操作操作完成后自动刷新列表不必来回跳转。保养计划页面则采用了日历视图和列表视图切换的设计。日历视图按月展示计划到期日用不同颜色标识待执行蓝色、已完成绿色、逾期红色很像我们平时看共享单车的可用车辆地图一眼扫过去就能发现哪些船需要重点关注。4.3 前端权限按钮级控制与动态路由加载动态路由是后台管理系统中比较有挑战的一部分不同角色登录应该看到不同的菜单。我的方案是用户登录成功后通过接口getUserInfo获取该用户角色和权限标识集合后端再返回该用户可访问的路由表由后端根据 getRouters 接口动态路由生成前端拿到路由表后用 router.addRoute 动态注册。这套方案保持了前后端的权限唯一的真实性。按钮级的权限控制通过自定义指令实现在按钮上加v-permissionplan:add在指令的 mounted 钩子中判断当前用户是否有该权限没有则移除该按钮 DOM 元素。只有按钮隐藏还不够后端的 PreAuthorize 注解才是真正的防线。还有一个容易遗漏的问题是侧边菜单刷新后高亮状态丢失。解决方案是通过读取当前路由的 meta.activeMenu 来指定高亮菜单并在 Pinia 中缓存菜单列表刷新页面时从 store 中恢复。5. 环境部署与常见问题排查实录5.1 从开发到生产Nginx Jar 包部署实践开发完成后部署方案直接决定了系统能不能被真实的业务部门用起来。这套系统的生产部署方案我分三层数据库层MySQL 单独部署在一台服务器配置好远程访问账号开启 binlog 保证数据可回溯。后端层使用mvn package打包成 Jar 文件然后用nohup java -jar ship-maintenance.jar --spring.profiles.activeprod后台运行。生产环境配置一定要单独放一个 application-prod.yml数据库连接信息、Redis 地址等都和本地环境区分开。前端层npm run build生成 dist 目录把静态文件上传到 Nginx 的 html 目录下。关键配置是 location /api 反代到后端服务server { listen 80; server_name your-domain.com; location / { root /usr/share/nginx/html; index index.html; 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; } }这里有一个 Vue 路由刷新后 404 的坑hsitory 模式路由直接刷新后 Nginx 找不到对应的静态文件所以必须配置try_files $uri $uri/ /index.html把所有前端路由都指向 index.html 由 Vue Router 接管。另外一个坑是 proxy_pass 最后面的斜杠没有斜杠和带斜杠的路径拼接规则完全不同忘了这个细节调试跨域会调试到怀疑人生。5.2 常见问题速查表与避坑指南开发这套系统的过程中我整理了一些高频问题直接做成速查表分享给你。问题现象可能原因解决方案前端请求 /api 接口 404Nginx 代理未配置 /api 或 Vite proxy 配置错误确认代理路径是否匹配检查 rewrite 规则是否误删路径登录后菜单不显示后端返回的路由表为空或前端 addRoute 失败排查 getRouters 接口返回数据确认角色已关联菜单权限本地可以登录部署到服务器后提示 401系统时间不准导致 JWT 验签失败用 NTP 同步服务器时间JWT 签发和校验时间一致性是基本前提库存扣减出现负数没有用条件更新改用原子 UPDATE SQLWHERE current_stock quantity定时任务重复执行集群部署下每台机器都执行 Scheduled引入分布式锁或使用 XXL-Job 统一调度导出 Excel 中文乱码未设置响应编码设置 response.setCharacterEncoding(utf-8)并添加 UTF-8 BOM 头页面刷新菜单高亮丢失Vuex/Pinia 中菜单状态未持久化使用持久化插件保存 store或刷新时重新拉取菜单数据5.3 定时任务与消息通知的业务联动维保系统非常依赖“主动提醒”的能力船在海上跑机务主管不可能天天盯着系统看。我的方案是独立的消息中心模块保养计划逾期时生成站内信通知负责人备件库存低于安全库存时通知备件管理员工单验收超时提醒上一级主管。定时任务只是负责写消息记录真正的触达涉及邮件和短信通道。短信在远洋场景下经常信号不稳所以我会优先做站内信 邮件结合的方式邮件可以通过卫星网络异步接收。考虑到实际场景的通信限制消息中心在设计上要允许批量已读、按船舶筛选、按级别筛选方便高频使用者快速处理积压提醒。这块业务如果做得好系统粘性会高很多——因为用户不是来找数据的而是来“收通知、办事”的。6. 实测总结与老开发的一些心里话如果让我总结这套系统的开发心得最核心的一句话是不要只做一个 CRUD 系统要做一个懂业务的维保工具。CRUD 谁都会写但“保养计划按运行小时自动计算”“库存扣减防超卖”“工单状态机防跳步”这类的细节才是系统真正能用于生产的关键。关于框架选型我个人的体会是 SpringBoot Vue3 MyBatis 这套组合在船舶相关信息管理系统这个细分领域属于非常稳妥的选项。市场上招人容易出了问题社区资料多后期扩展比如接入电子海图数据、船舶定位信息也不至于推倒重来。如果项目已经过了原型阶段建议优先考虑引入工作流引擎比如 Flowable来处理更复杂的审批流因为船舶维修的审批链条往往比普通设备运维更长。最后再分享一个小技巧做这类行业管理系统多跟实际业务人员聊聊会比看任何技术文档都有用。我第一次做船舶维保时以为保养计划就是“每三个月做一次保养”后来跟老轨轮机长聊过才知道船上设备有“主机、辅机、锅炉、舵机、压载系统”之分很多保养是按运行小时而非日历天计算而且不同的船级社对保养记录的要求也完全不同。系统做得对不对不是看你代码有多漂亮而是看你的数据模型能不能准确还原这些真实业务场景。希望这篇实战笔记能帮你把这个系统更快地落地。如果你正在做类似的后台管理系统不管是船舶维保还是别的设备运维把上面这些数据表、状态机、定时任务的思路拿去调整复用应该能省不少弯路。有问题欢迎在评论区给我留言一起交流。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询