基于Vue的智慧水务系统开发:从大屏可视到前后端分离实战
简介这是一个基于 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 └── alarmapi/water.js只放水务业务接口utils/request.js只暴露封装好的 axios 实例两者分开后期切换到 Spring Boot 或若依后端时只改一处。components/chart里的BaseChart.vue统一初始化 ECharts、处理 resize 和销毁每个页面不再出现散装的echarts.init。views/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.productionVUE_APP_BASE_URL/api VUE_APP_WS_URLws://localhost:8081/ws/water前端所有跨域和 WebSocket 地址都走环境变量不需要改代码。源码里硬编码ws://地址往往是答辩时被追问得比较尴尬的一点用环境变量之后本地和服务器两端只维护两个变量。3. 地图、大屏与实时数据Vue 组件里的智慧水务核心功能怎么写3.1 大屏图表不能只有静态数据轮询、WebSocket 和销毁智慧水务最典型的是总览大屏左边水厂出水流量中间污水管网 GIS右边压力曲线。这类页面的核心不是图表本身而是数据持续更新。放一个最简单的轮询写法template div refchart classchart/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 }] }) } } } /scriptsetInterval每 5 秒拉一次数据beforeDestroy里必须clearInterval和dispose图表。很多大屏项目切路由后内存飙升就是漏了这一步。对压力、流量这类秒级指标轮询够用对设备启停记录这种事件型数据要用 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 兼容性差腾讯地图关注并发和小程序复用配额按次计费演示前要测试离线瓦片内网部署或演练场地需要准备切片文件占用存储地图组件里不要直接操作全局变量点位应定义成 propsexport 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?active1不编码会把 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 nameviewport contentwidthdevice-width, initial-scale1.0, viewport-fitcover /验证方法不是看 console 有没有报错而是在浏览器开发者工具里打开设备模拟器从 375px 宽度拖到 768px观察图表容器是否出现横向滚动。如果出现滚动先检查 body、html 是否设了overflow-x: hidden再看 echarts 容器是否被某个固定宽度撑破。配合postcss-px-to-viewport做移动端适配大屏组件和移动端卡片就能共用同一套源码这一项往往比多写两个页面更能拉开评分差距。本文还有配套的精品资源点击获取