基于Vue的智慧水务系统开发:从大屏可视到前后端分离实战
2026/9/15 18:12:09 网站建设 项目流程

简介:这是一个基于 Vue 技术栈开发的智慧水务系统完整项目资源,作为已获导师认可的高分项目,适合计算机相关专业(如人工智能、物联网、自动化等)在校学生用于毕业设计、课程设计或项目演示,也适合开发者学习企业级前端工程的组织方式。压缩包共 230 个文件,约 2MB,文件类型涵盖 45 个 Vue 组件、78 个 CSS 样式、31 个 JavaScript 脚本,以及图片、图标字体、配置文件、说明文档等,基本覆盖系统页面搭建、交互逻辑、界面样式、图标资源与工程配置等主要环节。已有 138 人浏览学习。项目源码经过运行测试,功能可用,且附带较完整的设计说明与文档,便于理解整体结构;读者既可将其作为完整参考实施,也能在现有基础上扩展修改。项目定位偏向智慧水务场景的可视化管理,适合不同阶段的学习者深入阅读与二次开发。

1. 基于 Vue 的智慧水务系统:拿“全部资料+高分项目”当目标时,先想清楚交付什么

水务系统的业务边界比普通管理系统宽:既有大屏上不断跳动的流量、压力、水质指标,又有厂区视频监控、设备状态点位和地图上的管网标注。只用 Vue 写一套增删改查后台显然不够;但直接把几十个页面堆在一起、数据全部写死在代码里,又会在答辩和源码审查阶段被一眼看穿。一个能打包成“全部资料+高分项目+详细文档”的 Vue 智慧水务项目,本质上是一套可复现、可讲解、可演进的工程样板:它必须有清晰的分层目录、能远程联调的接口封装、可配置的地图与图表组件,以及一本把设计思路讲完整的说明文档。适合正在接智慧水务、智慧园区项目的团队,也适合拿同一个课题做课程设计和毕业设计的人。你不需要把所有传感器都接进系统,但必须让每个功能点在数据流上说得通。

2. Vue 项目目录与开发环境配置:先把工程骨架搭成能展开讲的样子

2.1 一个能被一眼看懂的水务系统前端目录长什么样

很多同学在 vue 安装依赖后直接开始写页面,最后src/views下面三四十个 vue 文件,找不到任何一个可复用的零件。一个要作为“全部资料”交付的项目,如果给下一个人阅读、给评委审查,我一般会至少保持这样的目录:

src ├── api │ ├── water.js │ ├── alarm.js │ └── device.js ├── assets │ ├── icons │ └── styles ├── components │ ├── chart │ │ ├── BaseChart.vue │ │ └── LiquidLevel.vue │ └── map │ └── WaterMap.vue ├── layout ├── router │ └── index.js ├── store │ ├── modules │ │ └── monitoring.js ├── utils │ ├── request.js │ └── websocket.js └── views ├── dashboard ├── monitor ├── device └── alarm

api/water.js只放水务业务接口,utils/request.js只暴露封装好的 axios 实例,两者分开,后期切换到 Spring Boot 或若依后端时只改一处。components/chart里的BaseChart.vue统一初始化 ECharts、处理 resize 和销毁,每个页面不再出现散装的echarts.initviews/monitor负责大屏布局,views/device负责台账和点位,整个目录本身就是一篇极简架构文档,答辩时不需要翻着代码逐张解释。

2.2 依赖安装选型:从 package.json 开始固定版本

智慧水务前端不是越新越好。数据可视化、地图和视频流依赖,我建议直接在package.json里锁版本:

{ "name": "smart-water-vue", "version": "1.0.0", "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build" }, "dependencies": { "vue": "^2.6.14", "vue-router": "^3.5.3", "vuex": "^3.6.2", "axios": "^0.27.2", "echarts": "^5.3.3", "element-ui": "^2.15.10", "leaflet": "^1.8.0", "hls.js": "^1.2.4" }, "devDependencies": { "@vue/cli-service": "~5.0.0", "sass": "^1.32.0", "sass-loader": "^10.0.0" } }

这里有三个重点。第一,Vue 2.6 配合 Element UI 2.15 是水务后台比较稳妥的组合,很多现成地图控件和视频插件还停留在 Vue2 写法;第二,ECharts 选 5.x,大屏性能和组织结构比 4 强一个档次;第三,sass-loader 不要装到 11 以上,否则在 Vue2 下会报this.getOptions is not a function,这是 vue 安装依赖阶段最常见的翻车点。如果你打算用 Vue3,可以换成 Ant Design Vue 或 Naive UI,同时把vue-router升到 4。

一个容易被忽略的动作是安装后先跑一次npm run build,而不仅是npm run serve。开发模式不报错不代表构建产物没问题,能看到 dist 目录正常生成,才开始写业务代码。如果团队换电脑,要把这条写进 README 第一行,节省大量环境排查时间。

2.3 开发代理与 publicPath:这里藏着 vue 打包后布局异常

vue.config.js里配置 devServer 代理,解决前端调用 Spring Boot 接口的跨域问题:

const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ publicPath: process.env.NODE_ENV === 'production' ? '/water/' : '/', devServer: { port: 8080, proxy: { '/api': { target: 'http://localhost:8081', changeOrigin: true, pathRewrite: { '^/api': '' } } } } })

publicPath直接决定 vue 打包后布局异常是否出现。部署在子路径下必须写成/water/,否则index.html里引用的 js/css 全部 404,页面白屏,背景图也会错位。devServer.proxy/api转发到本地 8081 的后端服务,changeOrigin让后端看到的是代理请求而不是跨域 Origin。pathRewrite是否去掉前缀,要看后端@RequestMapping有没有统一前缀。

环境变量建议分成.env.development.env.production

VUE_APP_BASE_URL=/api VUE_APP_WS_URL=ws://localhost:8081/ws/water

前端所有跨域和 WebSocket 地址都走环境变量,不需要改代码。源码里硬编码ws://地址,往往是答辩时被追问得比较尴尬的一点;用环境变量之后,本地和服务器两端只维护两个变量。

3. 地图、大屏与实时数据:Vue 组件里的智慧水务核心功能怎么写

3.1 大屏图表不能只有静态数据:轮询、WebSocket 和销毁

智慧水务最典型的是总览大屏:左边水厂出水流量,中间污水管网 GIS,右边压力曲线。这类页面的核心不是图表本身,而是数据持续更新。放一个最简单的轮询写法:

<template> <div ref="chart" class="chart"></div> </template> <script> import * as echarts from 'echarts' export default { name: 'PollutionTrend', data() { return { chart: null, timer: null } }, mounted() { this.chart = echarts.init(this.$refs.chart) this.loadData() this.timer = setInterval(this.loadData, 5000) }, beforeDestroy() { clearInterval(this.timer) this.chart.dispose() }, methods: { async loadData() { const data = await this.$http.get('/monitor/pollution/trend') this.chart.setOption({ xAxis: { data: data.times }, series: [{ data: data.values }] }) } } } </script>

setInterval每 5 秒拉一次数据,beforeDestroy里必须clearIntervaldispose图表。很多大屏项目切路由后内存飙升,就是漏了这一步。对压力、流量这类秒级指标,轮询够用;对设备启停记录这种事件型数据,要用 WebSocket。建议把utils/websocket.js封装成单例,统一处理断线重连:

let socket = null export function connectWS(url, onMessage) { if (socket && socket.readyState === WebSocket.OPEN) return socket = new WebSocket(url) socket.onmessage = (e) => { const data = JSON.parse(e.data) onMessage(data) } socket.onclose = () => setTimeout(() => connectWS(url, onMessage), 3000) }

3.2 地图叠加:Leaflet、腾讯地图和离线瓦片的取舍

厂区、泵站、管网这些点需要落到地图上。做项目时不用把地图写死成某一家 API,申请 token 和配额可能在评审前过期。常见做法是 Leaflet 配天地图底图,或者用腾讯地图服务。下表是我在项目里的选择依据:

地图方案适合场景注意点
Leaflet + 天地图纯点位展示、管网覆盖、线上演示需要申请 tk,加载速度受外网影响
vue-baidu-map带车辆或人员轨迹回放的页面部分组件与 Vue3 兼容性差
腾讯地图关注并发和小程序复用配额按次计费,演示前要测试
离线瓦片内网部署或演练场地需要准备切片文件,占用存储

地图组件里不要直接操作全局变量,点位应定义成 props:

export default { props: { points: { type: Array, required: true } }, watch: { points: { deep: true, handler(list) { this.layer.clearLayers() list.forEach(p => L.marker([p.lat, p.lng]).addTo(this.layer)) } } } }

父组件从接口拿到points后,地图图层与图表组件一起响应式更新。如果做的是“web vue 开发 配电工艺图”这类需要精确到设备轮廓的场景,地图并不适用,应改用 SVG 工艺图纸加坐标映射。

3.3 实时视频:Vue 播放 m3u8 的落地方式

水务厂区通常有多个摄像头点位,网页端最常见的监控流格式是 m3u8,也就是 HLS 流。Vue 直接播放 m3u8 不能只依赖<video src="...">,需要做兼容处理,否则 iPhone 上能播、电脑 Chrome 黑屏:

import Hls from 'hls.js' export function playM3u8(videoElement, url) { if (Hls.isSupported()) { const hls = new Hls({ maxBufferLength: 30 }) hls.loadSource(url) hls.attachMedia(videoElement) } else if (videoElement.canPlayType('application/vnd.apple.mpegurl')) { videoElement.src = url } else { videoElement.innerHTML = '当前浏览器不支持 HLS 播放' } }

maxBufferLength控制缓存时长,太大浪费网络资源,太小播放容易卡顿。在智慧水务场景,视频组件应该独立成弹窗,点击才创建实例,关闭时调用hls.destroy()。还有一个隐蔽问题:本地播放器能跑,放到服务器上取不到流,通常是监控平台的流地址本身需要鉴权或 referer 校验,需要后端生成带签名时间的 URL。

4. 前后端分离的接口约定与 vue 路由权限设计

4.1 axios 拦截器:统一 code、token 和 401 跳转

springboot vue前后端分离项目,最容易乱的是响应结构。后端一个方法返回Map,另一个返回String,前端每种都要单独解析。我一般会和后端约定统一响应体:

{ "code": 0, "msg": "success", "data": {} }

然后在utils/request.js里用 axios 拦截器统一处理:

import axios from 'axios' import router from '@/router' const service = axios.create({ baseURL: process.env.VUE_APP_BASE_URL, timeout: 15000 }) service.interceptors.request.use(config => { const token = localStorage.getItem('water_token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) service.interceptors.response.use( response => { const res = response.data if (res.code !== 0) { return Promise.reject(new Error(res.msg || '请求失败')) } return res.data }, error => { if (error.response && error.response.status === 401) { localStorage.removeItem('water_token') router.replace('/login') } return Promise.reject(error) } )

这个封装有两个值得说明的参数。timeout: 15000配合大屏长时间轮询,建议大于 10 秒,否则后端做报表聚合时容易被误判超时。Authorization使用Bearer前缀是为对接 Spring Security 或若依框架准备,不要自己发明 token 头。拦截器返回res.data后,调用方拿到的就是data字段,组件里const data = await this.$http.get('/monitor/...')会非常干净。

4.2 路由守卫处理登录态和重定向

Vue 路由参数经常会带一个redirect,作用是在登录后回到被拦截的页面。路由守卫需要处理三种情况:已登录、未登录但访问白名单、未登录访问受保护页面。

const whiteList = ['/login', '/404'] router.beforeEach((to, from, next) => { const token = localStorage.getItem('water_token') if (token) { if (to.path === '/login') { next('/') } else { next() } } else if (whiteList.includes(to.path)) { next() } else { next(`/login?redirect=${encodeURIComponent(to.fullPath)}`) } })

encodeURIComponent是必须的,因为原始路径里可能带查询参数,比如/device/1?active=1,不编码会把 redirect 截断。登录成功后要读取this.$route.query.redirect再跳转。水务项目里一个账号往往绑定多个水厂区域,登录后还要拉取用户菜单,这部分建议放在store/modules,不要在router/index.js里动态改路由表。

4.3 与 Spring Boot 端联调:从本地到服务器的一路姿势

前后端联调时的常见配置参照如下:

环节前端位置后端位置常见错误
本地开发vue.config.jsproxySpring Boot 8081前端 8080 直接跨域
测试环境.env.staging网关或 8082BASE_URL没切换
生产环境.env.productionNginx 反代静态资源 404

使用若依 Vue 开源项目做底座的团队,经常遇到前端vite或 webpack 端口与 IDEA 里 Spring Boot 端口不一致的问题。若依前端默认走/dev-api/prod-api,后端application.yml可能只开了 8080。拿到这类项目时,第一件事就是把.env.development里的VUE_APP_BASE_URL改成/api,在vue.config.js代理到http://localhost:8080。生产环境如果放在/water/子路径,Nginx 需要同时处理前端路由回退和接口转发,否则刷新页面 vue 路由会 404。这部分和部署检查一起说。

5. 部署到内网服务器前,按这份清单把 Vue 项目打成高分交付件

5.1 用 Nginx 发布 Vue 构建产物的最小配置

后端是 Spring Boot 时,常见做法是前端npm run build后把 dist 上传到服务器,由 Nginx 托管静态文件并反代接口:

server { listen 80; server_name water.example.com; root /data/water-web/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8081/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

try_files把不存在的路径交给index.html,解决 vue 路由刷新时找不到文件。proxy_pass末尾带/,等于把/api/前缀替换成后端根路径,和开发环境pathRewrite的行为保持一致;如果这里不带/,前端本地正常、服务器上接口却全部 404。

5.2 高分项目验收:文档、演示和源码干净度

提交前建议直接拿下面的表逐项检查,去掉任何一步都可能成为现场演示的断点:

检查项验收标准常见翻车点
README有环境要求、启动步骤、默认账号缺少npm install前置说明
数据库脚本SQL 可执行且有初始数据时间字段全是0000-00-00
接口文档包含地址、入参、出参参数类型写错
大屏图表5 秒内能看到数据变化演示时后端没开,全部白屏
视频监控至少一个 m3u8 地址可播放用内网 IP,评委外网访问不了
路由权限未登录跳登录页,登录后回跳路由守卫没处理 redirect

实际操作时,我会把npm run build产物和源码分开打两个包,一个叫water-web-dist.zip,一个叫“全部资料+高分项目+详细文档.zip”。文档里除了 README,还要有数据库结构说明和功能演示视频,视频用 vue 播放 m3u8 的方式挂到页面里,评审自己点开就能看。

5.3 手机端布局与调试:最后一道 vue 样式卡口

public/index.html里加 viewport 设置:

<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />

验证方法不是看 console 有没有报错,而是在浏览器开发者工具里打开设备模拟器,从 375px 宽度拖到 768px,观察图表容器是否出现横向滚动。如果出现滚动,先检查 body、html 是否设了overflow-x: hidden,再看 echarts 容器是否被某个固定宽度撑破。配合postcss-px-to-viewport做移动端适配,大屏组件和移动端卡片就能共用同一套源码,这一项往往比多写两个页面更能拉开评分差距。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询