基于 Vue 3 + TypeScript + Leaflet + HiFleet SDK 的海运大屏示例,面向"航线轨迹展示 + 航线总览 + 主题/语言切换 + 实时船位增量刷新"的场景。
当前工程的核心思路不是把所有能力都压到单一地图 SDK 上,而是采用:
HiFleet SDK负责海图底座、底图模式、地图语言。Leaflet负责轨迹、点位、船舶标记、tooltip 等业务覆盖层。Vue 3负责大屏 UI、主题、国际化、交互状态与数据编排。
这样做的目的是把"底图能力"和"业务可定制层"分开,降低后续接真实数据或替换底图方案的成本。
当前实际技术栈
Vue 3 + <script setup>: 页面结构、状态编排、组件通信。TypeScript: 统一定义航次、轨迹点、实时消息等模型。HiFleet SDK: 底图实例、地图语言、底图模式切换。Leaflet: 轨迹、船舶标记、线段、点位、tooltip 覆盖层。 当前主要通过 HiFleet SDK 暴露的window.L能力接入,并在src/types/hifleet-map.ts中维护项目内的最小类型抽象。vue-i18n: 中英文切换。v-scale-screen: 1920x1080 大屏缩放适配。Vitest + Vue Test Utils + jsdom: service、composable、组件级单测。
当前目录结构
text
src/
App.vue
main.ts
style.css
components/
layout/
ScreenAdapter.vue
map/
MapStage.vue
MapToolbar.vue
MapStage.test.ts
panels/
RouteListPanel.vue
composables/
useDashboardPreferences.ts
useDashboardPreferences.test.ts
useHifleetMap.ts
useMockVoyageStream.ts
useVoyageDashboard.ts
useVoyageSocket.ts
data/
mockVoyages.ts
i18n/
index.ts
locales/
dashboard.ts
services/
hifleet-loader.ts
mock-voyage-stream.ts
mock-voyage-stream.test.ts
trajectory-optimizer.ts
trajectory-optimizer.test.ts
voyage-realtime.ts
voyage-realtime.test.ts
types/
hifleet-map.ts
realtime.ts
voyage.ts
vite-env.d.ts
说明:
- 当前仓库没有
ShipDetailPanel.vue,右侧详情面板仍是后续可扩展项。 - 当前仓库没有
worker渲染链路,海量点优化主要依赖视野过滤、抽稀和单航次增量刷新。
类型分层
当前项目把类型定义按职责拆在 src/types 下,便于业务层、服务层和地图层分别演进:
voyage.ts- 定义航次主模型,包括航次摘要、指标、挂靠计划、轨迹点和地图模式。
realtime.ts- 定义 WebSocket 实时事件、连接状态、实时快照与增量轨迹点。
hifleet-map.ts- 定义项目内使用到的
Leaflet / Map / Layer最小能力接口,用于隔离第三方 SDK 实现细节。
- 定义项目内使用到的
架构分层
App.vue- 负责拼装页面壳层,连接地图舞台、左侧航线面板和主题/语言偏好。
useVoyageDashboard.ts- 维护航线列表、当前选中航次、左侧统计摘要。
MapStage.vue- 负责地图舞台头部、主题/语言按钮、底图模式工具栏。
useHifleetMap.ts- 负责 SDK 加载、地图实例初始化、覆盖层渲染、实时点位刷新。
RouteListPanel.vue- 左侧航线总览列表和汇总卡片。
useVoyageSocket.ts- 真实 WebSocket 事件接入、断线重连与心跳保活。
useMockVoyageStream.ts- 未配置真实 WS 地址时的 mock 实时流兜底。
hifleet-loader.ts- 负责显式注入 HiFleet SDK 的 CSS 和 JS 资源。
当前 Demo 能力
- 左侧展示航线总览、状态、装载率、ETA、延误摘要。
- 中央地图展示多条航线轨迹,并高亮当前选中航次。
- 支持底图模式切换:
标准 / 海图 / 卫星。 - 支持中英文切换。
- 支持大屏主题切换,并对地图本体做可见的深浅色处理。
- 点击左侧航线卡片或地图轨迹,可切换当前选中航次。
- 未配置
VITE_VOYAGE_WS_URL时,默认启用 mock 实时事件流。 - 配置
VITE_VOYAGE_WS_URL后,可切换到真实 WebSocket 船位事件流。 - 轨迹绘制支持按地图视野过滤、按 zoom 抽稀和单航次增量刷新。
- 页面默认按
1920x1080设计稿做缩放适配。
HiFleet SDK 深度定制能力边界
这一节是本项目最重要的落地结论。
当前项目实际使用了什么
当前代码里,HiFleet SDK 主要承担以下职责:
- 创建地图实例。
- 暴露底层
Leaflet Map对象。 - 切换底图模式:
global / nauticalmap / satellite。 - 切换地图语言:
cn / en。
也就是说,本项目对 HiFleet 的使用更接近"可切换底图的海图底座",而不是"全业务渲染引擎"。
HiFleet SDK 适合做什么
基于公开文档和当前接入方式,HiFleet 更适合以下场景:
- 使用官方海图、标准图、卫星图作为底座。
- 使用官方支持的地图语言切换。
- 使用官方开放的天气、洋流、风场、港口等标准能力。
- 快速搭建航运领域的底图和海事图层能力。
HiFleet SDK 不适合做什么
如果目标是"深度定制化地图引擎",HiFleet 不是一个理想边界内的方案。当前能明确看到的限制包括:
-
底图换肤能力有限- 公开 API 能确认的是底图模式切换,不是完整的品牌级换肤系统。
- 目前没有可靠公开能力可以像 Mapbox Style 那样对道路、海洋、陆地、文字、边界做逐层样式编排。
-
地图渲染管线不可控- SDK 内部实现和 pane 结构由其自身接管。
- 业务方可以在外部加
Leaflet覆盖层,但不能真正接管底图渲染规则。
-
地图 UI 深改空间有限- 顶部按钮、浮层、主题按钮这类强业务 UI,仍然建议由外层 Vue 自己实现。
- 不建议把复杂业务交互强行塞到 SDK 内建 UI 上。
-
品牌化主题能力有限- 目前项目里做的"地图深浅主题",本质上是对底图区域做 CSS 滤镜和背景处理。
- 这是工程上可用的增强,不等同于底图源本身支持完整皮肤系统。
-
更深层控制需要自建方案- 如果你要做矢量瓦片样式编辑、动态图层规则、品牌底图、地图控件体系统一,HiFleet 不适合作为唯一核心层。
本项目对 HiFleet 的取舍策略
本项目采用的是一个很现实的折中方案:
HiFleet提供航运地图底座。Leaflet提供业务覆盖层和交互。CSS 主题类提供地图区域的深浅视觉增强。
这个策略的优点:
- 上手快,行业能力现成。
- 业务层仍然可控。
- 后续替换底图成本可控。
这个策略的缺点:
- 地图主题是"增强层",不是底图原生换肤。
- 超深度样式统一仍然受制于 SDK 本身。
当前地图主题方案说明
当前项目里的"地图主题切换"分成两层:
大屏 UI 主题- 通过
data-theme和 CSS 变量切换整体界面视觉。
- 通过
地图本体主题- 通过
MapStage上的主题类和.leaflet-tile-pane滤镜,对底图做深浅色增强。
- 通过
这意味着:
- 你可以获得肉眼可见的深浅变化。
- 但这不代表 HiFleet 官方提供了完整地图皮肤 API。
- 如果未来要品牌级地图风格统一,仍需要更换底图方案或自建样式系统。
平替方案
这里的"平替"不是单纯替换一个 SDK,而是根据定制深度选方案。
方案一:保留 HiFleet,继续采用"底图 + 覆盖层"模式
适合:
- 仍然需要海图、航运领域底图能力。
- 主要定制点在业务轨迹、船舶标记、主题壳层、面板交互。
做法:
- 继续使用 HiFleet 做底图。
- 业务图层全部放在
Leaflet覆盖层。 - 主题仍然走 CSS 滤镜增强。
优点:
- 接入成本最低。
- 行业能力保留最多。
缺点:
- 深度换肤和品牌化地图风格仍然受限。
方案二:纯 Leaflet + 自有瓦片服务
适合:
- 需要稳定二维地图能力。
- 需要深浅主题、品牌底图、底图替换自由度。
- 不强依赖 HiFleet 官方航运图层。
做法:
- 直接使用
Leaflet。 - 底图改为自有瓦片、第三方瓦片或深浅色双套 tile 源。
- 业务轨迹仍沿用当前覆盖层思路。
优点:
- 成本适中。
- 底图可控性明显提升。
- 与当前项目代码结构最兼容。
缺点:
- 需要自己解决海图来源和行业数据接入。
方案三:MapLibre GL JS + 矢量瓦片样式
适合:
- 需要真正的地图换肤、品牌色、图层规则、文字样式统一。
- 需要高度可编排的地图主题系统。
做法:
- 用
MapLibre GL JS替代 HiFleet 底图层。 - 使用矢量瓦片和 style JSON 做地图样式控制。
- 航运业务图层按 GL 图层或自定义 overlay 重建。
优点:
- 真正支持深度样式定制。
- 地图视觉体系最完整。
缺点:
- 迁移成本最高。
- 航运专项图层需要自己补。
方案四:Cesium 或三维引擎
适合:
- 目标已经从二维运营大屏升级到三维全球态势、航线回放、时空演化。
优点:
- 三维表现力强。
缺点:
- 工程复杂度高。
- 对当前二维业务场景通常属于过度设计。
选型建议
如果你的目标是:
快速上线航运地图大屏- 继续用
HiFleet + Leaflet。
- 继续用
做深浅主题、品牌化 UI,但接受底图不是完全原生换肤- 继续用当前方案。
做真正的地图换肤系统、品牌地图、可编排样式体系- 优先评估
Leaflet + 自有底图或MapLibre GL JS。
- 优先评估
做三维态势或全球地球场景- 再考虑
Cesium。
- 再考虑
实时通信设计
WebSocket 事件类型
voyage.snapshot: 航次快照,更新进度、ETA、装载率、速度、告警等。voyage.point: 增量轨迹点,适合船位流式刷新。voyage.alert: 告警事件,直接推送异常标签。heartbeat: 心跳包,用于保活和链路可观测。
通信建议
- 接口层统一做协议归一化
- 前后端字段不要直接散落到组件层,统一在
voyage-realtime.ts处理。
- 前后端字段不要直接散落到组件层,统一在
- 增量更新代替全量覆盖
voyage.point只追加单点,并限制单航次最大轨迹长度。
- 断线自动重连
- 当前 demo 已带指数退避重连和心跳保活。
- mock 流兜底
- 无真实 WS 地址时,自动切换到 mock 事件流,方便演示与联调。
环境变量
当前项目实际读取以下 Vite 环境变量:
VITE_VOYAGE_WS_URL- 真实 WebSocket 地址;未配置时自动回退到 mock 实时流。
VITE_HIFLEET_SDK_KEY- HiFleet SDK key;配置后会按官方 key 地址拼接 SDK 脚本。
VITE_HIFLEET_SDK_SRC- 自定义 SDK JS 地址;适合内网代理、私有镜像或固定版本接入。
VITE_HIFLEET_SDK_CSS- 自定义 SDK CSS 地址;用于覆盖默认样式资源地址。
示例:
bash
VITE_VOYAGE_WS_URL=wss://example.com/voyage/ws
VITE_HIFLEET_SDK_KEY=your-sdk-key
VITE_HIFLEET_SDK_SRC=https://sdk.hifleet.com/sdk/get?key=your-sdk-key
VITE_HIFLEET_SDK_CSS=https://sdk.hifleet.com/sdk/theme.css
地图性能策略
当前已落地
按视野过滤- 仅更新与当前地图 bounds 相交的航次图层。
按 zoom 抽稀- zoom 越低,折线和点位抽稀越强,降低低层级渲染压力。
单航次增量刷新- 实时事件只更新对应航次图层,不再整图重绘。
覆盖层与底图分离- 底图交给 SDK,业务图层交给
Leaflet,减少耦合。
- 底图交给 SDK,业务图层交给
后续生产建议
- 按视野过滤
- 仅渲染当前 bounds 内的重点航次。
- 图层分级
- 航线线、船位、告警、港口分层管理,按需开关。
- 更大规模优化
- 万级以上节点建议评估
Leaflet.Canvas、PixiOverlay或 WebGL 方案。
- 万级以上节点建议评估
- 更强主题能力
- 如果地图主题需求继续升级,优先换底图技术栈,而不是继续堆 CSS 滤镜。
大屏响应式方案
- 已集成
v-scale-screen,由ScreenAdapter.vue做统一封装。 - 当前按
1920x1080设计稿做等比缩放,并启用bodyOverflowHidden。
自动化测试
当前项目包含以下高价值测试:
voyage-realtime.test.ts- 校验 WebSocket 消息归一化和增量数据合并。
trajectory-optimizer.test.ts- 校验长轨迹抽稀、视野过滤和 zoom 级别策略。
mock-voyage-stream.test.ts- 校验 mock 事件流生成逻辑。
useDashboardPreferences.test.ts- 校验主题/语言初始化、切换和持久化。
MapStage.test.ts- 校验地图主题类、头部交互事件和主题同步逻辑。
测试命令:
bash
npm run test
npm run test:run
注意:
- 当前个别 Windows 环境如果本机
localhost解析异常,Vitest启动可能被环境阻断。 - 这类问题通常属于本机网络/hosts 配置,不是测试断言本身失败。
接真实数据时的建议
- 航线基础信息接口
- 返回船名、MMSI、状态、ETA、装载率、预警信息。
- 航迹接口
- 返回轨迹点数组,字段建议包含
lat、lon、timestamp、speed、label。
- 返回轨迹点数组,字段建议包含
- WebSocket 增量推送
- 仅更新单航次最新点位和状态,不必整页重绘。
- 历史轨迹查询接口
- 首屏加载历史轨迹,实时流只补增量点。
- 图层权限分级
- 如果生产环境涉及天气、风场、港口等能力,建议把 SDK 图层权限和业务开关拆开管理。
运行方式
首次运行请先安装依赖:
bash
npm install
npm run dev
npm run test:run
如果内网无法直接访问 npm registry,建议:
- 配置公司私有镜像源。
- 或直接把当前源码合入你现有的大屏工程中。
HiFleet 接入说明
HiFleet 文档给出的异步地址本质上会注入一份 CSS 和一份 JS。为了避免 document.write 在异步场景覆盖页面,本 demo 在 hifleet-loader.ts 中改为显式注入这两个资源地址。
当前加载策略支持三种来源:
- 优先使用
VITE_HIFLEET_SDK_SRC和VITE_HIFLEET_SDK_CSS指定的自定义资源地址。 - 如果只提供
VITE_HIFLEET_SDK_KEY,则按 key 拼接官方 SDK 地址。 - 如果以上都未提供,则回退到仓库里保留的历史公开 CSS/JS 地址。
需要注意的是,当前代码并没有实现 SDK 加载失败后自动降级到本地纯 Leaflet 底图。如果 SDK 脚本不可达,页面会进入地图初始化失败状态,并显示相应错误提示。因此在生产环境中,建议优先通过环境变量固定 SDK 资源来源,避免运行时依赖不稳定的公共地址。
后续可扩展项
- 接入真实船位刷新与轨迹回放。
- 增加天气、风场、洋流图层切换。
- 增加区域筛选、船公司筛选、异常告警联动。
- 增加右侧详情面板或点击船舶浮层详情。
- 如果地图主题要求继续上升,评估
Leaflet + 自有瓦片或MapLibre GL JS迁移方案。