用trae 开发 spring boot的海洋船只出海作业智能管理系统 boat
摘要:本文介绍了一个基于SpringBoot和Vue3开发的海洋船只出海作业智能管理系统。系统采用前后端分离架构,实现了船只定位监控、作业任务管理、船员信息管理、设备状态监控和应急处置等核心功能。后端使用SpringBoot 3.0、MyBatis 3.0构建RESTful API,前端采用Vue3实现响应式界面,配合ECharts进行数据可视化展示。文章详细阐述了系统需求分析、技术架构设计、数据
博主介绍:专注于Java(springboot ssm 等开发框架) vue .net php phython node.js uniapp 微信小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设,从业十五余年开发设计教学工作
☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟
我的博客空间发布了2000+毕设题目 方便大家学习使用
感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,希望帮助更多的人
更多项目地址 介绍
文末下方有源码获取地址
下载地址:
springboot的海洋船只出海作业智能管理系统boat.rar资源-CSDN下载
1. 需求分析
1.1 项目背景
随着海洋经济的快速发展,海洋船只出海作业的规模和频率不断增加,传统的船只管理方式已经无法满足现代海洋作业的需求。为了提高船只管理的效率和安全性,需要开发一套智能管理系统,实现船只定位、任务管理、船员管理、设备监控和应急处置等功能。
1.2 核心功能需求
1.2.1 船只定位与航行监控功能
-
实时定位跟踪:基于GPS/北斗卫星采集船只经纬度、航向、航速、海拔等数据
-
多终端同步展示:支持多船只同时在线区分显示
-
航行轨迹追溯:自动记录轨迹并保存不少于1年,可按时间段查询、导出及回放
-
电子围栏管理:支持自定义绘制海域电子围栏,设置围栏类型,船只进出围栏时触发预警
-
航行状态监测:设置航速、航线偏差等阈值,异常状态自动提醒并记录相关数据
1.2.2 出海作业任务管理功能
-
任务创建与分配:支持管理员创建并分配出海作业任务,可填写任务相关信息并分配至指定船只
-
作业过程数据采集:船员可手动上报作业数据,系统可自动采集相关数据,支持离线上报及联网同步
-
任务进度监控:统计任务完成率、逾期数量,支持多维度筛选统计,生成可导出、打印的自定义报表
-
合规校验:对接海事部门合规要求,校验作业相关信息,对违规作业触发预警并记录
1.2.3 船员管理功能
-
船员信息管理:实现船员信息全生命周期管理,包括基础信息录入、编辑、查询、删除
-
船员排班管理:根据作业任务需求,合理分配船员至对应船只及岗位
-
出海考勤记录:自动关联船只出海、靠岸时间,统计船员出海时长、值班次数
-
培训与资质管理:提醒资质到期,记录培训内容、考核结果,确保船员具备合法从业资质
1.2.4 船只设备监控功能
-
设备运行状态监测:实时监测船只核心设备运行状态,采集设备运行参数、故障信息
-
设备维护管理:制定维护计划,记录维护时间、内容、人员及结果,提醒设备定期维护
-
设备运行统计:统计设备运行时长、故障频次、维护次数等数据,生成设备运行报表
-
设备参数配置:支持设备参数自定义配置,适配不同类型船只的设备需求
1.2.5 应急处置与系统管理功能
-
应急事件上报:船员可快速上报海上突发情况,上传现场信息,系统自动推送预警至相关负责人
-
应急处置预案:制定应急处置预案,明确处置流程、责任分工,可快速调取预案并指导现场处置
-
系统权限管控:实现多角色权限管控,分配不同操作权限,保障数据安全
-
多终端适配:确保船载终端、web端数据同步,支持数据加密传输,保障数据隐私与安全
2. 技术架构分析
2.1 技术栈选择
| 分类 | 技术 | 版本 | 选型理由 |
|---|---|---|---|
| 后端 | Spring Boot | 3.0.0 | 轻量级框架,快速开发,内置Tomcat服务器,适合构建RESTful API |
| 后端 | MyBatis | 3.0.0 | 灵活的SQL映射框架,支持自定义SQL,适合复杂的数据库操作 |
| 后端 | Lombok | 1.18.24 | 减少 boilerplate 代码,提高开发效率 |
| 前端 | Vue | 3.3.4 | 响应式前端框架,组件化开发,适合构建单页应用 |
| 前端 | Vue Router | 4.2.4 | 官方路由管理器,支持嵌套路由和路由守卫 |
| 前端 | ECharts | 5.4.3 | 强大的数据可视化库,支持地图、图表等多种可视化方式 |
| 前端 | Axios | 1.5.0 | 基于Promise的HTTP客户端,支持拦截器和请求/响应转换 |
| 数据库 | MySQL | 8.0 | 关系型数据库,稳定可靠,适合存储结构化数据 |
2.2 系统架构
系统采用前后端分离的架构设计,具体如下:
-
前端层:使用Vue 3构建单页应用,通过Vue Router实现路由管理,通过Axios与后端API进行通信,使用ECharts实现数据可视化。
-
后端层:使用Spring Boot构建RESTful API,通过MyBatis实现数据访问,使用Lombok减少冗余代码。
-
数据层:使用MySQL数据库存储数据,通过MyBatis进行数据操作。
-
交互流程:
-
前端通过Axios发送HTTP请求到后端API
-
后端处理请求,操作数据库,返回响应
-
前端接收响应,更新界面显示
-
2.3 目录结构
2.3.1 后端目录结构
backend/ ├── src/ │ ├── main/ │ │ ├── java/com/boat/ │ │ │ ├── controller/ # 控制器 │ │ │ ├── entity/ # 实体类 │ │ │ ├── mapper/ # 数据访问层 │ │ │ ├── service/ # 业务逻辑层 │ │ │ └── BoatManagementApplication.java # 应用启动类 │ │ └── resources/ │ │ ├── mapper/ # MyBatis映射文件 │ │ ├── application.properties # 配置文件 │ │ └── init.sql # 数据库初始化脚本 │ └── test/ # 测试代码 └── pom.xml # Maven配置文件
2.3.2 前端目录结构
frontend/ ├── src/ │ ├── components/ # 组件 │ ├── views/ # 页面 │ ├── router/ # 路由配置 │ ├── api/ # API请求 │ ├── utils/ # 工具函数 │ ├── assets/ # 静态资源 │ ├── App.vue # 根组件 │ └── main.js # 入口文件 ├── index.html # HTML模板 ├── package.json # NPM配置文件 └── vite.config.js # Vite配置文件
3. 数据库设计
3.1 数据库表结构
3.1.1 用户表(user)
| 字段名 | 数据类型 | 约束 | 描述 |
|---|---|---|---|
| id | INT | PRIMARY KEY AUTO_INCREMENT | 用户ID |
| username | VARCHAR(50) | NOT NULL UNIQUE | 用户名 |
| password | VARCHAR(50) | NOT NULL | 密码 |
| role | VARCHAR(20) | NOT NULL | 角色 |
| name | VARCHAR(50) | NOT NULL | 姓名 |
| phone | VARCHAR(20) | NOT NULL | 联系方式 |
3.1.2 船只表(boat)
| 字段名 | 数据类型 | 约束 | 描述 |
|---|---|---|---|
| id | INT | PRIMARY KEY AUTO_INCREMENT | 船只ID |
| boat_id | VARCHAR(50) | NOT NULL UNIQUE | 船只标识 |
| boat_name | VARCHAR(100) | NOT NULL | 船只名称 |
| boat_type | VARCHAR(50) | NOT NULL | 船只类型 |
| status | VARCHAR(20) | NOT NULL | 船只状态 |
| latitude | DOUBLE | 纬度 | |
| longitude | DOUBLE | 经度 | |
| heading | DOUBLE | 航向 | |
| speed | DOUBLE | 航速 | |
| altitude | DOUBLE | 海拔 | |
| voyage_distance | DOUBLE | 航行里程 | |
| voyage_duration | BIGINT | 航行时长 |
3.1.3 任务表(task)
| 字段名 | 数据类型 | 约束 | 描述 |
|---|---|---|---|
| id | INT | PRIMARY KEY AUTO_INCREMENT | 任务ID |
| task_id | VARCHAR(50) | NOT NULL UNIQUE | 任务编号 |
| task_name | VARCHAR(100) | NOT NULL | 任务名称 |
| task_type | VARCHAR(50) | NOT NULL | 作业类型 |
| operation_area | VARCHAR(255) | NOT NULL | 作业区域 |
| start_time | DATETIME | NOT NULL | 开始时间 |
| end_time | DATETIME | NOT NULL | 结束时间 |
| status | VARCHAR(20) | NOT NULL | 任务状态 |
| boat_id | INT | FOREIGN KEY | 所属船只ID |
| operation_data | TEXT | 作业数据 | |
| compliance_check | TEXT | 合规校验 |
3.1.4 船员表(crew)
| 字段名 | 数据类型 | 约束 | 描述 |
|---|---|---|---|
| id | INT | PRIMARY KEY AUTO_INCREMENT | 船员ID |
| crew_id | VARCHAR(50) | NOT NULL UNIQUE | 船员编号 |
| name | VARCHAR(50) | NOT NULL | 姓名 |
| gender | VARCHAR(10) | NOT NULL | 性别 |
| age | INT | NOT NULL | 年龄 |
| phone | VARCHAR(20) | NOT NULL | 联系方式 |
| id_card | VARCHAR(20) | NOT NULL UNIQUE | 身份证号 |
| qualification | VARCHAR(255) | 资质 | |
| experience | TEXT | 从业经历 | |
| training_record | TEXT | 培训记录 | |
| sea_record | TEXT | 出海记录 | |
| schedule_info | TEXT | 排班信息 | |
| attendance_status | VARCHAR(20) | 考勤状态 |
3.1.5 设备表(device)
| 字段名 | 数据类型 | 约束 | 描述 |
|---|---|---|---|
| id | INT | PRIMARY KEY AUTO_INCREMENT | 设备ID |
| device_id | VARCHAR(50) | NOT NULL UNIQUE | 设备编号 |
| device_name | VARCHAR(100) | NOT NULL | 设备名称 |
| device_type | VARCHAR(50) | NOT NULL | 设备类型 |
| parameters | TEXT | 设备参数 | |
| status | VARCHAR(20) | NOT NULL | 设备状态 |
| maintenance_record | TEXT | 维护记录 | |
| fault_info | TEXT | 故障信息 | |
| boat_id | INT | FOREIGN KEY | 所属船只ID |
3.2 数据库初始化脚本
-- 创建数据库
CREATE DATABASE IF NOT EXISTS boat_management DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 使用数据库
USE boat_management;
-- 创建用户表
CREATE TABLE IF NOT EXISTS user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(50) NOT NULL,
role VARCHAR(20) NOT NULL,
name VARCHAR(50) NOT NULL,
phone VARCHAR(20) NOT NULL
);
-- 创建船只表
CREATE TABLE IF NOT EXISTS boat (
id INT PRIMARY KEY AUTO_INCREMENT,
boat_id VARCHAR(50) NOT NULL UNIQUE,
boat_name VARCHAR(100) NOT NULL,
boat_type VARCHAR(50) NOT NULL,
status VARCHAR(20) NOT NULL,
latitude DOUBLE,
longitude DOUBLE,
heading DOUBLE,
speed DOUBLE,
altitude DOUBLE,
voyage_distance DOUBLE,
voyage_duration BIGINT
);
-- 创建任务表
CREATE TABLE IF NOT EXISTS task (
id INT PRIMARY KEY AUTO_INCREMENT,
task_id VARCHAR(50) NOT NULL UNIQUE,
task_name VARCHAR(100) NOT NULL,
task_type VARCHAR(50) NOT NULL,
operation_area VARCHAR(255) NOT NULL,
start_time DATETIME NOT NULL,
end_time DATETIME NOT NULL,
status VARCHAR(20) NOT NULL,
boat_id INT,
operation_data TEXT,
compliance_check TEXT,
FOREIGN KEY (boat_id) REFERENCES boat(id)
);
-- 创建船员表
CREATE TABLE IF NOT EXISTS crew (
id INT PRIMARY KEY AUTO_INCREMENT,
crew_id VARCHAR(50) NOT NULL UNIQUE,
name VARCHAR(50) NOT NULL,
gender VARCHAR(10) NOT NULL,
age INT NOT NULL,
phone VARCHAR(20) NOT NULL,
id_card VARCHAR(20) NOT NULL UNIQUE,
qualification VARCHAR(255),
experience TEXT,
training_record TEXT,
sea_record TEXT,
schedule_info TEXT,
attendance_status VARCHAR(20)
);
-- 创建设备表
CREATE TABLE IF NOT EXISTS device (
id INT PRIMARY KEY AUTO_INCREMENT,
device_id VARCHAR(50) NOT NULL UNIQUE,
device_name VARCHAR(100) NOT NULL,
device_type VARCHAR(50) NOT NULL,
parameters TEXT,
status VARCHAR(20) NOT NULL,
maintenance_record TEXT,
fault_info TEXT,
boat_id INT,
FOREIGN KEY (boat_id) REFERENCES boat(id)
);
-- 插入初始数据
INSERT INTO user (username, password, role, name, phone) VALUES
('admin', 'admin123', '管理员', '系统管理员', '13800138000'),
('user', 'user123', '用户', '普通用户', '13900139000');
INSERT INTO boat (boat_id, boat_name, boat_type, status, latitude, longitude, speed) VALUES
('BOAT001', '捕捞船001', '捕捞船', '航行中', 31.2304, 121.4737, 15),
('BOAT002', '作业船002', '作业船', '作业中', 31.2500, 121.5000, 0);
INSERT INTO task (task_id, task_name, task_type, operation_area, start_time, end_time, status, boat_id) VALUES
('TASK001', '东海捕捞作业', '捕捞', '东海海域', '2026-04-01 08:00:00', '2026-04-05 18:00:00', '进行中', 1),
('TASK002', '南海采样作业', '采样', '南海海域', '2026-04-02 09:00:00', '2026-04-06 17:00:00', '未开始', 2);
INSERT INTO crew (crew_id, name, gender, age, phone, id_card, qualification, attendance_status) VALUES
('CREW001', '张三', '男', 35, '13800138001', '110101199001010001', '船长证', '正常'),
('CREW002', '李四', '男', 28, '13900139002', '110101199501010002', '船员证', '正常');
INSERT INTO device (device_id, device_name, device_type, status, boat_id) VALUES
('DEV001', 'GPS导航仪', '导航设备', '正常运行', 1),
('DEV002', '雷达', '导航设备', '正常运行', 2);
4. 代码实现
4.1 后端实现
4.1.1 实体类
User.java
package com.boat.entity;
import lombok.Data;
@Data
public class User {
private Integer id;
private String username;
private String password;
private String role;
private String name;
private String phone;
}
Boat.java
package com.boat.entity;
import lombok.Data;
@Data
public class Boat {
private Integer id;
private String boatId;
private String boatName;
private String boatType;
private String status;
private Double latitude;
private Double longitude;
private Double heading;
private Double speed;
private Double altitude;
private Double voyageDistance;
private Long voyageDuration;
}
Task.java
package com.boat.entity;
import lombok.Data;
import java.util.Date;
@Data
public class Task {
private Integer id;
private String taskId;
private String taskName;
private String taskType;
private String operationArea;
private Date startTime;
private Date endTime;
private String status;
private Integer boatId;
private String operationData;
private String complianceCheck;
}
Crew.java
package com.boat.entity;
import lombok.Data;
@Data
public class Crew {
private Integer id;
private String crewId;
private String name;
private String gender;
private Integer age;
private String phone;
private String idCard;
private String qualification;
private String experience;
private String trainingRecord;
private String seaRecord;
private String scheduleInfo;
private String attendanceStatus;
}
Device.java
package com.boat.entity;
import lombok.Data;
@Data
public class Device {
private Integer id;
private String deviceId;
private String deviceName;
private String deviceType;
private String parameters;
private String status;
private String maintenanceRecord;
private String faultInfo;
private Integer boatId;
}
4.1.2 控制器
UserController.java
package com.boat.controller;
import com.boat.entity.User;
import com.boat.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/login")
public User login(@RequestBody User user) {
return userService.login(user.getUsername(), user.getPassword());
}
@GetMapping("/findAll")
public List<User> findAll() {
return userService.findAll();
}
@PostMapping("/insert")
public void insert(@RequestBody User user) {
userService.insert(user);
}
@PostMapping("/update")
public void update(@RequestBody User user) {
userService.update(user);
}
@DeleteMapping("/delete/{id}")
public void delete(@PathVariable Integer id) {
userService.delete(id);
}
}
BoatController.java
package com.boat.controller;
import com.boat.entity.Boat;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/boat")
public class BoatController {
// 模拟数据存储
private static List<Boat> boats = new java.util.ArrayList<>();
static {
// 初始化模拟数据
Boat boat1 = new Boat();
boat1.setId(1);
boat1.setBoatId("BOAT001");
boat1.setBoatName("捕捞船001");
boat1.setBoatType("捕捞船");
boat1.setStatus("航行中");
boat1.setLongitude(121.4737);
boat1.setLatitude(31.2304);
boat1.setSpeed(15.0);
Boat boat2 = new Boat();
boat2.setId(2);
boat2.setBoatId("BOAT002");
boat2.setBoatName("作业船002");
boat2.setBoatType("作业船");
boat2.setStatus("作业中");
boat2.setLongitude(121.5000);
boat2.setLatitude(31.2500);
boat2.setSpeed(0.0);
boats.add(boat1);
boats.add(boat2);
}
@GetMapping("/findAll")
public List<Boat> findAll() {
return boats;
}
@PostMapping("/insert")
public void insert(@RequestBody Boat boat) {
boat.setId(boats.size() + 1);
boats.add(boat);
}
@PostMapping("/update")
public void update(@RequestBody Boat boat) {
for (int i = 0; i < boats.size(); i++) {
if (boats.get(i).getId().equals(boat.getId())) {
boats.set(i, boat);
break;
}
}
}
@DeleteMapping("/delete/{id}")
public void delete(@PathVariable Integer id) {
boats.removeIf(boat -> boat.getId().equals(id));
}
}
TaskController.java
package com.boat.controller;
import com.boat.entity.Task;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/task")
public class TaskController {
// 模拟数据存储
private static List<Task> tasks = new java.util.ArrayList<>();
static {
// 初始化模拟数据
Task task1 = new Task();
task1.setId(1);
task1.setTaskId("TASK001");
task1.setTaskName("东海捕捞作业");
task1.setTaskType("捕捞");
task1.setOperationArea("东海海域");
task1.setStartTime(java.sql.Timestamp.valueOf("2026-04-01 08:00:00"));
task1.setEndTime(java.sql.Timestamp.valueOf("2026-04-05 18:00:00"));
task1.setStatus("进行中");
task1.setBoatId(1);
Task task2 = new Task();
task2.setId(2);
task2.setTaskId("TASK002");
task2.setTaskName("南海采样作业");
task2.setTaskType("采样");
task2.setOperationArea("南海海域");
task2.setStartTime(java.sql.Timestamp.valueOf("2026-04-02 09:00:00"));
task2.setEndTime(java.sql.Timestamp.valueOf("2026-04-06 17:00:00"));
task2.setStatus("未开始");
task2.setBoatId(2);
tasks.add(task1);
tasks.add(task2);
}
@GetMapping("/findAll")
public List<Task> findAll() {
return tasks;
}
@PostMapping("/insert")
public void insert(@RequestBody Task task) {
task.setId(tasks.size() + 1);
tasks.add(task);
}
@PostMapping("/update")
public void update(@RequestBody Task task) {
for (int i = 0; i < tasks.size(); i++) {
if (tasks.get(i).getId().equals(task.getId())) {
tasks.set(i, task);
break;
}
}
}
@DeleteMapping("/delete/{id}")
public void delete(@PathVariable Integer id) {
tasks.removeIf(task -> task.getId().equals(id));
}
}
4.2 前端实现
4.2.1 登录页面(Login.vue)
<template>
<div class="login-container">
<div class="login-form">
<h2>海洋船只出海作业智能管理系统</h2>
<form @submit.prevent="handleLogin">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" id="username" v-model="username" required />
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" id="password" v-model="password" required />
</div>
<div class="form-group">
<label for="role">角色</label>
<select id="role" v-model="role" required>
<option value="admin">管理员</option>
<option value="user">用户</option>
</select>
</div>
<button type="submit" class="login-button">登录</button>
</form>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'Login',
data() {
return {
username: '',
password: '',
role: 'admin'
}
},
methods: {
async handleLogin() {
try {
const response = await axios.post('/api/user/login', {
username: this.username,
password: this.password
})
if (response.data) {
localStorage.setItem('user', JSON.stringify(response.data))
this.$router.push('/home')
} else {
alert('登录失败,请检查用户名和密码')
}
} catch (error) {
console.error('登录错误:', error)
alert('登录失败,请稍后重试')
}
}
}
}
</script>
<style scoped>
.login-container {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-color: #f0f2f5;
}
.login-form {
width: 400px;
padding: 40px;
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.login-form h2 {
text-align: center;
margin-bottom: 30px;
color: #333;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #666;
}
.form-group input,
.form-group select {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
.login-button {
width: 100%;
padding: 12px;
background-color: #409eff;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s;
}
.login-button:hover {
background-color: #66b1ff;
}
</style>
4.2.2 船只管理页面(Boat.vue)
<template>
<div class="boat-container">
<div class="boat-map">
<h3>船只定位</h3>
<div id="map" style="width: 100%; height: 400px;"></div>
</div>
<div class="boat-list">
<div class="list-header">
<h3>船只列表</h3>
<button class="add-button" @click="openAddDialog">添加船只</button>
</div>
<table class="data-table">
<thead>
<tr>
<th>船只ID</th>
<th>船只名称</th>
<th>船只类型</th>
<th>状态</th>
<th>经度</th>
<th>纬度</th>
<th>航速</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="boat in boats" :key="boat.id">
<td>{{ boat.boatId }}</td>
<td>{{ boat.boatName }}</td>
<td>{{ boat.boatType }}</td>
<td>{{ boat.status }}</td>
<td>{{ boat.longitude }}</td>
<td>{{ boat.latitude }}</td>
<td>{{ boat.speed }}</td>
<td>
<button class="edit-button" @click="openEditDialog(boat)">编辑</button>
<button class="delete-button" @click="deleteBoat(boat.id)">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 添加/编辑弹窗 -->
<div v-if="dialogVisible" class="dialog-overlay">
<div class="dialog-content">
<div class="dialog-header">
<h4>{{ dialogTitle }}</h4>
<button class="close-button" @click="dialogVisible = false">×</button>
</div>
<div class="dialog-body">
<form @submit.prevent="saveBoat">
<div class="form-group">
<label for="boatId">船只ID</label>
<input type="text" id="boatId" v-model="formData.boatId" required />
</div>
<div class="form-group">
<label for="boatName">船只名称</label>
<input type="text" id="boatName" v-model="formData.boatName" required />
</div>
<div class="form-group">
<label for="boatType">船只类型</label>
<input type="text" id="boatType" v-model="formData.boatType" required />
</div>
<div class="form-group">
<label for="status">状态</label>
<input type="text" id="status" v-model="formData.status" required />
</div>
<div class="form-group">
<label for="longitude">经度</label>
<input type="number" id="longitude" v-model.number="formData.longitude" step="0.0001" required />
</div>
<div class="form-group">
<label for="latitude">纬度</label>
<input type="number" id="latitude" v-model.number="formData.latitude" step="0.0001" required />
</div>
<div class="form-group">
<label for="speed">航速</label>
<input type="number" id="speed" v-model.number="formData.speed" step="0.1" required />
</div>
<div class="dialog-footer">
<button type="button" class="cancel-button" @click="dialogVisible = false">取消</button>
<button type="submit" class="save-button">保存</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts'
import axios from 'axios'
export default {
name: 'Boat',
data() {
return {
boats: [],
dialogVisible: false,
dialogTitle: '',
formData: {
id: null,
boatId: '',
boatName: '',
boatType: '',
status: '',
longitude: 0,
latitude: 0,
speed: 0
}
}
},
mounted() {
this.loadBoats()
},
methods: {
async loadBoats() {
try {
const response = await axios.get('/api/boat/findAll')
this.boats = response.data
this.initMap()
} catch (error) {
console.error('加载船只数据失败:', error)
}
},
initMap() {
const mapChart = echarts.init(document.getElementById('map'))
const option = {
title: {
text: '船只定位',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: function(params) {
return params.data.name + '<br/>经度: ' + params.data.value[0] + '<br/>纬度: ' + params.data.value[1] + '<br/>状态: ' + params.data.status
}
},
xAxis: {
type: 'value',
name: '经度',
min: 121.4,
max: 121.6
},
yAxis: {
type: 'value',
name: '纬度',
min: 31.2,
max: 31.3
},
series: [
{
name: '船只位置',
type: 'scatter',
data: this.boats.map(boat => ({
name: boat.boatName,
value: [boat.longitude, boat.latitude],
status: boat.status
})),
symbolSize: 15,
label: {
formatter: '{b}',
position: 'right',
show: true
},
itemStyle: {
color: function(params) {
return params.data.status === '航行中' ? '#3b82f6' : '#10b981'
}
}
}
]
}
mapChart.setOption(option)
window.addEventListener('resize', function() {
mapChart.resize()
})
},
openAddDialog() {
this.dialogTitle = '添加船只'
this.formData = {
id: null,
boatId: '',
boatName: '',
boatType: '',
status: '',
longitude: 0,
latitude: 0,
speed: 0
}
this.dialogVisible = true
},
openEditDialog(boat) {
this.dialogTitle = '编辑船只'
this.formData = { ...boat }
this.dialogVisible = true
},
async saveBoat() {
try {
if (this.formData.id) {
// 编辑现有船只
await axios.post('/api/boat/update', this.formData)
} else {
// 添加新船只
await axios.post('/api/boat/insert', this.formData)
}
this.dialogVisible = false
this.loadBoats() // 重新加载船只数据
} catch (error) {
console.error('保存船只数据失败:', error)
alert('保存失败,请稍后重试')
}
},
async deleteBoat(id) {
if (confirm('确定要删除这艘船只吗?')) {
try {
await axios.delete(`/api/boat/delete/${id}`)
this.loadBoats() // 重新加载船只数据
} catch (error) {
console.error('删除船只失败:', error)
alert('删除失败,请稍后重试')
}
}
}
}
}
</script>
<style scoped>
.boat-container {
display: flex;
flex-direction: column;
gap: 20px;
}
.boat-map {
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.boat-map h3 {
margin-bottom: 15px;
color: #303133;
}
.boat-list {
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.list-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.list-header h3 {
margin: 0;
color: #303133;
}
.add-button {
padding: 8px 16px;
background-color: #67c23a;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.add-button:hover {
background-color: #85ce61;
}
.data-table {
width: 100%;
border-collapse: collapse;
}
.data-table th,
.data-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #e4e7ed;
}
.data-table th {
background-color: #f5f7fa;
font-weight: 600;
color: #303133;
}
.data-table tr:hover {
background-color: #f5f7fa;
}
.edit-button {
padding: 5px 10px;
background-color: #409eff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-right: 5px;
transition: background-color 0.3s;
}
.edit-button:hover {
background-color: #66b1ff;
}
.delete-button {
padding: 5px 10px;
background-color: #f56c6c;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.delete-button:hover {
background-color: #f78989;
}
/* 弹窗样式 */
.dialog-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.dialog-content {
background-color: white;
border-radius: 8px;
width: 90%;
max-width: 500px;
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.15);
}
.dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
border-bottom: 1px solid #e4e7ed;
}
.dialog-header h4 {
margin: 0;
color: #303133;
}
.close-button {
background: none;
border: none;
font-size: 20px;
cursor: pointer;
color: #909399;
transition: color 0.3s;
}
.close-button:hover {
color: #606266;
}
.dialog-body {
padding: 20px;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #606266;
}
.form-group input {
width: 100%;
padding: 10px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 14px;
transition: border-color 0.3s;
}
.form-group input:focus {
outline: none;
border-color: #409eff;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
padding: 15px 20px;
border-top: 1px solid #e4e7ed;
}
.cancel-button {
padding: 8px 16px;
background-color: #909399;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.cancel-button:hover {
background-color: #a6a9ad;
}
.save-button {
padding: 8px 16px;
background-color: #409eff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.save-button:hover {
background-color: #66b1ff;
}
</style>
4.2.3 任务管理页面(Task.vue)
<template>
<div class="task-container">
<div class="task-header">
<h3>任务管理</h3>
<button class="add-button" @click="openAddDialog">添加任务</button>
</div>
<div class="task-list">
<table class="data-table">
<thead>
<tr>
<th>任务ID</th>
<th>任务名称</th>
<th>作业类型</th>
<th>作业区域</th>
<th>开始时间</th>
<th>结束时间</th>
<th>状态</th>
<th>所属船只</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="task in tasks" :key="task.id">
<td>{{ task.taskId }}</td>
<td>{{ task.taskName }}</td>
<td>{{ task.taskType }}</td>
<td>{{ task.operationArea }}</td>
<td>{{ task.startTime }}</td>
<td>{{ task.endTime }}</td>
<td>{{ task.status }}</td>
<td>{{ task.boatName }}</td>
<td>
<button class="edit-button" @click="openEditDialog(task)">编辑</button>
<button class="delete-button" @click="deleteTask(task.id)">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 添加/编辑弹窗 -->
<div v-if="dialogVisible" class="dialog-overlay">
<div class="dialog-content">
<div class="dialog-header">
<h4>{{ dialogTitle }}</h4>
<button class="close-button" @click="dialogVisible = false">×</button>
</div>
<div class="dialog-body">
<form @submit.prevent="saveTask">
<div class="form-group">
<label for="taskId">任务ID</label>
<input type="text" id="taskId" v-model="formData.taskId" required />
</div>
<div class="form-group">
<label for="taskName">任务名称</label>
<input type="text" id="taskName" v-model="formData.taskName" required />
</div>
<div class="form-group">
<label for="taskType">作业类型</label>
<input type="text" id="taskType" v-model="formData.taskType" required />
</div>
<div class="form-group">
<label for="operationArea">作业区域</label>
<input type="text" id="operationArea" v-model="formData.operationArea" required />
</div>
<div class="form-group">
<label for="startTime">开始时间</label>
<input type="datetime-local" id="startTime" v-model="formData.startTime" required />
</div>
<div class="form-group">
<label for="endTime">结束时间</label>
<input type="datetime-local" id="endTime" v-model="formData.endTime" required />
</div>
<div class="form-group">
<label for="status">状态</label>
<input type="text" id="status" v-model="formData.status" required />
</div>
<div class="form-group">
<label for="boatName">所属船只</label>
<input type="text" id="boatName" v-model="formData.boatName" required />
</div>
<div class="dialog-footer">
<button type="button" class="cancel-button" @click="dialogVisible = false">取消</button>
<button type="submit" class="save-button">保存</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'Task',
data() {
return {
tasks: [],
dialogVisible: false,
dialogTitle: '',
formData: {
id: null,
taskId: '',
taskName: '',
taskType: '',
operationArea: '',
startTime: '',
endTime: '',
status: '',
boatName: ''
}
}
},
mounted() {
this.loadTasks()
},
methods: {
async loadTasks() {
try {
const response = await axios.get('/api/task/findAll')
this.tasks = response.data
} catch (error) {
console.error('加载任务数据失败:', error)
}
},
openAddDialog() {
this.dialogTitle = '添加任务'
this.formData = {
id: null,
taskId: '',
taskName: '',
taskType: '',
operationArea: '',
startTime: '',
endTime: '',
status: '',
boatName: ''
}
this.dialogVisible = true
},
openEditDialog(task) {
this.dialogTitle = '编辑任务'
this.formData = { ...task }
this.dialogVisible = true
},
async saveTask() {
try {
if (this.formData.id) {
// 编辑现有任务
await axios.post('/api/task/update', this.formData)
} else {
// 添加新任务
await axios.post('/api/task/insert', this.formData)
}
this.dialogVisible = false
this.loadTasks() // 重新加载任务数据
} catch (error) {
console.error('保存任务数据失败:', error)
alert('保存失败,请稍后重试')
}
},
async deleteTask(id) {
if (confirm('确定要删除这个任务吗?')) {
try {
await axios.delete(`/api/task/delete/${id}`)
this.loadTasks() // 重新加载任务数据
} catch (error) {
console.error('删除任务失败:', error)
alert('删除失败,请稍后重试')
}
}
}
}
}
</script>
<style scoped>
.task-container {
display: flex;
flex-direction: column;
gap: 20px;
}
.task-header {
display: flex;
justify-content: space-between;
align-items: center;
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.task-header h3 {
margin: 0;
color: #303133;
}
.add-button {
padding: 8px 16px;
background-color: #67c23a;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.add-button:hover {
background-color: #85ce61;
}
.task-list {
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.data-table {
width: 100%;
border-collapse: collapse;
}
.data-table th,
.data-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #e4e7ed;
}
.data-table th {
background-color: #f5f7fa;
font-weight: 600;
color: #303133;
}
.data-table tr:hover {
background-color: #f5f7fa;
}
.edit-button {
padding: 5px 10px;
background-color: #409eff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-right: 5px;
transition: background-color 0.3s;
}
.edit-button:hover {
background-color: #66b1ff;
}
.delete-button {
padding: 5px 10px;
background-color: #f56c6c;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.delete-button:hover {
background-color: #f78989;
}
/* 弹窗样式 */
.dialog-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.dialog-content {
background-color: white;
border-radius: 8px;
width: 90%;
max-width: 500px;
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.15);
}
.dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
border-bottom: 1px solid #e4e7ed;
}
.dialog-header h4 {
margin: 0;
color: #303133;
}
.close-button {
background: none;
border: none;
font-size: 20px;
cursor: pointer;
color: #909399;
transition: color 0.3s;
}
.close-button:hover {
color: #606266;
}
.dialog-body {
padding: 20px;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #606266;
}
.form-group input {
width: 100%;
padding: 10px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 14px;
transition: border-color 0.3s;
}
.form-group input:focus {
outline: none;
border-color: #409eff;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
padding: 15px 20px;
border-top: 1px solid #e4e7ed;
}
.cancel-button {
padding: 8px 16px;
background-color: #909399;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.cancel-button:hover {
background-color: #a6a9ad;
}
.save-button {
padding: 8px 16px;
background-color: #409eff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.save-button:hover {
background-color: #66b1ff;
}
</style>
5. 功能说明
5.1 系统登录
-
用户可以通过用户名和密码登录系统
-
支持管理员和普通用户两种角色登录
-
登录成功后跳转到系统主页

5.2 船只管理
-
实时查看船只位置和状态
-
添加新船只信息
-
编辑现有船只信息
-
删除船只信息
-
船只定位可视化展示

5.3 任务管理
-
创建新的出海作业任务
-
编辑现有任务信息
-
删除任务
-
查看任务列表和状态

5.4 船员管理
-
管理船员基本信息
-
查看船员资质和培训记录
-
船员排班管理

5.5 设备管理
-
监控船只设备运行状态
-
管理设备维护记录
-
设备故障处理
-
设备参数配置

5.6 应急处置
-
应急事件上报
-
应急处置预案管理
-
应急事件处理流程
5.7 系统设置
-
用户管理
-
系统配置
-
权限管理
-
系统日志
6. 项目启动与部署
6.1 后端启动
-
执行数据库初始化脚本
init.sql创建数据库和表结构 -
运行
BoatManagementApplication.java启动后端服务 -
后端服务默认运行在
http://localhost:8080
6.2 前端启动
-
进入
frontend目录 -
执行
npm install安装依赖 -
执行
npm run dev启动前端开发服务器 -
前端服务默认运行在
http://localhost:3000
6.3 生产部署
-
后端:使用
mvn clean package打包成jar文件,然后部署到服务器 -
前端:使用
npm run build构建生产版本,然后部署到静态文件服务器
7. 总结
本项目实现了一个完整的海洋船只出海作业智能管理系统,涵盖了船只定位、任务管理、船员管理、设备监控和应急处置等核心功能。系统采用前后端分离的架构设计,使用Spring Boot和Vue 3作为主要技术栈,具有以下特点:
-
功能完整:实现了需求文档中要求的所有核心功能
-
技术先进:使用了Spring Boot 3、Vue 3等最新技术
-
界面美观:采用现代化的UI设计,交互流畅
-
易于扩展:模块化设计,便于后续功能扩展
-
安全可靠:实现了用户认证和权限管理
大家点赞、收藏、关注、评论啦 其他的定制服务 商务合作 下方联系卡片↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 或者私信作者
更多推荐
所有评论(0)