拓冰建站拓冰建站
首页 / 资讯中心 / 正文

基于JVS物联网平台的可视化门户千人千面改造实践

去年年中的时候我接了一个智慧园区项目底座选了JVS物联网平台。项目本身不算复杂真正让我头疼的是一个看似“无理”的需求业主方说不想让每个领导登录后台看到的东西都一样。这句话翻译过来就是可视化门户要做到“千人千面”。当时我还没太当回事觉得多套几套模板不就行了结果后面被现实狠狠教育了一轮运营人员只想看设备告警和工单部门主管关心能耗曲线园区总经理要的是当天经营总览巡检员得第一时间看到自己负责区域的异常。如果所有人登录JVS物联网后台看到的都是同一套可视化门户那信息要么冗余到没人看要么关键指标被淹没。这篇文章我打算把整个改造过程完整拆开从权限模型到动态页面渲染再到数据权限隔离一步一步讲清楚给正在做物联网平台二次开发、或者准备用JVS搭后台门户的同学做个参考。1. 为什么可视化门户一定要做千人千面1.1 一个“统一门户”版本把我坑惨了的项目最早赶工期我图省事做了一个“标准版门户”。所有用户登录后看到的菜单、首页卡片、大屏入口完全一样。当时想的是反正功能都在大家自己找呗。结果交付后三个月问题啪啪打脸。园区运营主管直接跟我说“我每天只要看设备告警和工单你给我整这么多能耗曲线干什么”另一边财务总监想看电费分项统计翻了三层菜单才找到入口打电话吐槽系统难用。更严重的一次巡检员登录大屏展示页因为统一门户把管理端删除按钮也暴露了出来鼠标一抖差点把生产设备给误删了。这种“一人一套全功能”的做法还有一个很隐蔽的坑看起来功能都在实际上没人愿意用。大屏沦为装饰后台变成无人问津的数据仓库。我做复盘的时候总结了三个根本问题一是信息过载角色和页面之间没有匹配关系每个用户都被迫看大量和自己无关的内容二是权限风险菜单按钮全量展示低权限用户也能看到高权限入口误操作和越权访问只隔了一个点击三是维护成本业务方每次提“加一个卡片”的需求我都得去改模板、发版本累得半死。归根到底问题不在功能不够而在于门户的“供给”和用户的“需求”完全错位了。1.2 千人千面的本质把页面当数据管痛定思痛我开始琢磨“千人千面”到底应该怎么做。传统思路是给每个角色复制一套页面模板管理员一套、运营一套、访客一套。这个做法一开始看起来简单但做深了就发现维护成本高得离谱加一个卡片要改三套模板加一个菜单要同步配置四次改到最后连我自己都分不清哪套模板是新的。后来我换了一个思路把页面本身当成“数据”来管。具体来说菜单、首页布局、卡片组件、主题颜色、大屏入口这些原本写死在代码里的东西全部改成配置项存到数据库。用户登录后后端先拉取这个人的“门户配置”包括他有权限的菜单树、他的首页布局JSON、他的主题偏好然后前端通过一个渲染引擎把配置变成实际界面。这样千人千面的本质就变了一份权限数据加一份布局配置渲染出一个专属门户。你可以把这件事理解成手机桌面同一个人可以自定义壁纸、图标排列、小组件换了账号就是另一套桌面。JVS物联网平台本身就有角色权限、菜单管理、大屏设计这些模块我们要做的不是推翻重来而是把这些能力串成一条链路让页面从“写死的前端路由”变成“动态组装的数据产物”。1.3 别把千人千面和“多套模板”混为一谈这里要特别强调一下千人千面不等于做多套模板。模板再多也是有限的、静态的而且每套模板之间还需要同步维护。千人千面是配置驱动的用户可以在权限范围内自己调整布局管理员可以随时修改某个角色的默认门户后端配置一变前端立即生效不需要发版。我在项目里做完这套机制之后业务方再提“给运营加一个今日能耗卡片”我只需要在配置中心拖一个组件进去绑定数据源保存五分钟搞定。这在以前简直不敢想。所以如果你准备做类似改造一定要先确立“配置化”这个核心思路而不是一头扎进去写模板页面。2. 思路拆解JVS物联网里实现千人千面的架构路径2.1 权限模型是地基RBAC 不够还要加数据维度JVS物联网使用的是经典的RBAC权限模型也就是用户-角色-权限这套体系。用户属于一个或多个角色角色绑定菜单权限、按钮权限这套模型是所有门户功能的地基。刚开始我以为只要把菜单权限配好就万事大吉后来发现远远不够。举个例子运营主管和部门经理都能看到“设备管理”这个菜单但运营主管只能看A车间的设备部门经理却能看全园区的设备。这种差异在菜单权限层面根本区分不出来。所以我在权限模型里又加了一层“数据权限”包含两个维度机构维度和设备分组维度。角色配置里可以设置数据范围比如本人、本部门、全部再结合设备分组表做过滤。这样一来菜单权限解决的是“入口能不能看见”数据权限解决的是“入口进去了能看多少数据”两者必须配合使用。2.2 页面即配置从静态路由到动态可配置JVS的前端默认是用路由表静态定义菜单的菜单长什么样是写死在代码里的。我要做的第一个核心改动就是把这部分数据化。系统管理里维护一份“资源目录”资源可以是菜单、页面、卡片、大屏然后再把资源目录和角色绑定。前端启动时不再直接加载全量路由而是先请求一个门户配置接口后端根据当前登录用户的角色返回有权限的菜单树前端再通过动态路由机制把页面组件挂载上去。首页也是同样的思路。我把首页的布局存成一份JSON配置里面包含每个区域放哪个组件、组件的参数是什么、数据源是哪个接口。用户保存布局后前端根据JSON去渲染。这样做有个直接好处不同角色登录看到的首页结构可以完全不同。巡检员的首页可能是告警列表加地图领导的首页可能是综合态势大屏入口加核心指标卡而这一切都是配置出来的不是代码写死的。2.3 数据联动看到的东西和能看到的数据必须一致只做菜单和布局还不够如果用户能看到“能耗分析”这个卡片但卡片里的数据是全园区的那就等于把数据权限绕过了。所以我在设计配置结构时给每个卡片组件都加了一个“数据域”字段。组件加载数据时必须带上这个数据域后端接口根据数据域解析出对应设备分组再拼接权限过滤条件。举个例子同一个能耗统计接口A用户传的是deviceGroupId1001B用户传的是deviceGroupId1002后端拼出来的SQL不同返回的数据自然不同。这一步是整个改造里最容易漏的但恰恰是“千人千面加数据安全”的核心闭环。如果漏掉就会出现低权限用户改一下前端请求参数就能看到全园区数据的严重漏洞。2.4 这套方案的适用范围与边界也不是所有项目都需要做成千人千面。我后来总结了一下如果你的系统只有两三种固定角色页面总共不超过十个用户群体统一那做一套模板完全够用做成千人千面反而是过度设计。但如果系统面向的角色多、数据敏感度高、业务方又经常调整展示内容那就值得投入做配置化门户。另外纯对外展示的可视化大屏比如园区展厅那种固定循环播放的也不适合做千人千面因为观看者不是登录用户没有个性化需求。判断标准就一条用户需不需要在登录后按自己的身份和偏好看到不同的东西需要就做不需要别给自己加戏。3. 实操过程一步步把 JVS 门户改成千人千面3.1 基础准备先把用户体系和资源目录建好在动手写代码之前我先花了两天时间把系统里的用户、角色、组织架构彻底梳理了一遍。这个环节看起来不产生代码但实际上决定了后续所有配置的合理性。我把真实业务角色分成了五类平台管理员、园区运营、部门主管、设备巡检、访客。然后按角色去划分资源目录。资源目录我建议这样组织一级资源是功能模块比如工作台、可视化大屏、设备管理、告警中心、能耗分析、系统设置二级资源是模块下的具体页面比如大屏下面的综合态势、能耗大屏、安防大屏三级资源是页面上的操作按钮比如新增、删除、导出。这些资源最终都会绑定到角色上。JVS系统管理里本身就有角色权限配置功能直接勾选菜单目录和按钮权限就行不需要改一行代码。这里我踩了一个坑一开始我把大屏页面和后台页面混在一个菜单里结果访客角色也能看到系统设置。后来我把资源目录分成了PC门户资源和大屏展示资源两个独立分组权限才真正好配。3.2 配置角色权限把菜单和按钮先收口角色权限配置我强烈推荐“最小授权”原则。操作路径很简单系统管理、角色管理、找到对应角色、分配权限。但一定不要图省事直接全选而是先全部取消再一项一项按需添加。我给巡检员角色只勾选了工作台、告警中心、设备管理下的设备列表以及告警查看按钮设备编辑、导出Excel这些权限一律不给。这样做的直接收益有两个一是页面干净了巡检员登录后第一眼看到的就是自己负责区域的告警卡片二是误操作入口被彻底堵死想删设备都没有按钮。配置完成后一定要记得清缓存。JVS的权限缓存默认是登录态内存缓存改了角色权限不清理就会出现“权限改了但用户还是能访问”的假象。我在项目里踩过这个坑当时以为代码逻辑有问题排查了半天最后发现是缓存没刷新差点把自己整崩溃。3.3 设计首页布局拖拽卡片与布局JSONJVS可视化门户的首页是支持自定义布局的在门户设置里可以拖拽卡片、调整大小和区域。我用这个功能把默认首页改造成了几套典型的角色布局运营管理首页是顶部告警摘要、中间设备在线率、底部今日工单领导视察首页是全屏大屏入口加园区综合指标访客首页则是园区介绍、开放区域地图和欢迎页。拖拽完成后页面会生成一个布局JSON这个JSON我建议一定要保存到数据库而不是留在浏览器本地。因为不同用户登录时后端要根据角色下发不同的布局。在JVS中用户保存的布局会存在用户偏好表里这里要特别注意一个优先级逻辑默认布局和用户自定义布局是两套数据如果用户没有自定义过就走角色默认布局如果用户自己调整过就优先取用户自己的配置。这个优先级关系千万不要搞反否则会出现“管理员改了默认布局但所有用户都不变”的诡异现象。3.4 绑定数据源与设备分组让卡片“各回各家”布局只是骨架真正让门户千人千面的是卡片背后绑定的数据。每个首页卡片比如设备在线率、告警数量、能耗趋势在JVS大屏设计器里都对应一个可视化组件组件绑定数据接口。我在创建设计器组件时会把数据源参数设为带设备分组的接口类似 /iot-data/dashboard/overview?deviceGroupIdxxx。后端的逻辑是先通过当前登录人的数据权限解析出允许访问的设备分组ID集合再和请求参数里的ID求交集。如果交集为空直接返回空数据而不是报错。这样即使有人手动去改URL参数也拿不到越权数据。我在这个环节专门做了测试用低权限账号试着访问高权限分组ID结果返回的都是空心里才踏实。3.5 主题皮肤与偏好设置最后的印象分千人千面如果只做到菜单和数据用户还是会觉得“换汤不换药”。JVS系统设置里有主题配置深色、浅色、品牌色都有。我把它拆成了用户级偏好用户在门户右上角可以直接切换主题切换时选择记住偏好之后每次登录都按用户偏好渲染。另外我还把默认展示的大屏也做成了用户级配置巡检员登录默认跳转设备告警大屏领导登录默认跳转综合态势大屏。这两个小细节一加不同角色的第一屏体验立刻不一样领导们的印象分一下子拉高了。实现上很简单登录接口返回的UserInfo里加一个portalPreference字段前端拿到后优先应用如果用户没设置过就使用后台的角色默认值。这一步没有技术难度但产品体验的提升非常明显属于典型的高性价比改造。4. 核心代码与配置细节这里最干4.1 后端动态菜单接口一次登录把门户配置拉齐我在JVS的登录成功处理器里加了一个门户聚合接口把菜单、首页布局、主题偏好一次性返回给前端避免前端发四五次请求去拼页面。接口大致长这样GetMapping(/portal/config) public RPortalConfigVO getPortalConfig() { LoginUser user SecurityUtils.getLoginUser(); PortalConfigVO vo new PortalConfigVO(); // 1. 拉取菜单树按角色过滤 vo.setMenus(menuService.listMenuByUserId(user.getUserId())); // 2. 拉取角色默认首页布局用户自定义优先 LayoutConfig layout layoutService.getUserLayout(user.getUserId()); if (layout null) { layout layoutService.getRoleLayout(user.getRoleIds()); } vo.setLayout(layout); // 3. 主题偏好 vo.setTheme(userService.getThemePreference(user.getUserId())); // 4. 数据权限范围供前端做按钮级控制 vo.setDataScope(permissionService.getDataScope(user.getUserId())); return R.ok(vo); }前端拿到这份配置后先注册菜单路由再渲染首页布局再应用主题一次把门户完整拼出来。这个接口最大的好处是在登录后的第一秒就能决定用户看到什么不会出现长时间的白屏闪烁。4.2 布局 JSON 的结构设计别把所有东西塞一个数组首页布局到底怎么存我经历了三次迭代最终确定用“栅格加卡片”的结构。栅格负责位置和大小的描述卡片负责具体内容和数据源。一个典型的布局JSON长这样{ rowNum: 12, gutter: 16, widgets: [ { id: widget-alarm-sum, type: alarmSummary, title: 今日告警, x: 0, y: 0, w: 6, h: 2, dataSource: { api: /iot-data/dashboard/alarm-summary, deviceGroupId: 1001, refreshInterval: 30 }, visibleRoleIds: [role_operator, role_manager] }, { id: widget-energy-trend, type: lineChart, title: 能耗趋势, x: 6, y: 0, w: 6, h: 2, dataSource: { api: /iot-data/dashboard/energy-trend, deviceGroupId: 1002, refreshInterval: 60 } } ] }关键点有两个。第一每个widget都有独立的dataSource包括接口地址、设备分组、刷新间隔这样卡片级的数据权限才能落地。第二widget里带有visibleRoleIds前端渲染布局时会再筛一遍把没有权限的卡片直接隐藏。后端保存布局时我也会校验权限防止低权限角色把高权限的卡片加到自己的布局里再保存。4.3 前端动态渲染Vue 路由 动态组件JVS前端用的是Vue技术栈动态路由我参考了常见的路由守卫方案。每次路由跳转前检查当前监听的路由表是否已经注册了该用户的路由如果没有就用门户接口返回的菜单数据生成路由追加进去。核心逻辑大概是这样router.beforeEach((to, from, next) { const portalConfig store.getters.portalConfig; if (!portalConfig) { // 尚未拉取门户配置先请求并写入store return dispatch(loadPortalConfig).then(() { next({ ...to, replace: true }); }); } next(); });动态组件渲染首页卡片时不要预先引入所有图表组件而是用Vue的异步组件加映射表按需加载。比如type为lineChart时加载components/dashboard/LineChart.vuetype为alarmSummary时加载AlarmSummary.vue。这样做的好处是首屏不会把所有大屏组件打包进来页面加载速度能明显提升尤其是组件库比较重的时候这个优化效果非常可观。4.4 数据权限的 SQL 拦截一个注解搞定数据权限我是在MyBatis层做的拦截给查询接口加了一个自定义注解DataScope拦截器解析当前用户的数据权限范围然后自动拼接SQL条件。核心思路是Aspect Component public class DataScopeAspect { Before(annotation(dataScope)) public void doBefore(JoinPoint point, DataScope dataScope) { // 解析当前用户的设备分组ID集合 ListLong groupIds permissionService.getDeviceGroupIds(); // 放入ThreadLocal供SQL拦截器使用 DataScopeContext.setGroupIds(groupIds); } }配合MyBatis拦截器在SQL解析阶段发现表名匹配设备关联表就自动追加where条件。这样就算开发人员写SQL时忘了加过滤条件数据权限依然生效。这个做法在交付后的安全测试里帮了大忙测试人员拿着低权限账号试了一下午也没越权查出任何一条数据。5. 常见问题与排查技巧实录做这套东西过程中踩过的坑不少我把最典型的几个问题和排查思路整理成了速查表方便你直接对着查现象排查顺序常见根因权限改了但用户还是老界面清缓存、退登录、重新登录权限缓存、会话未刷新刷新页面后白屏看动态路由初始化、看菜单权限路由表重建逻辑缺失卡片能渲染但数据为空看接口、看参数、看数据权限数据权限与分组冲突门户首屏加载慢看接口次数、组件体积、SQL慢日志配置查询多、没有按需加载5.1 权限配置改了用户登录还是老界面这个问题几乎每个项目都会遇到。JVS的权限是登录时就加载到会话里的后端改了角色权限已经在线的用户不会自动刷新必须退出重新登录或者等会话过期才能看到变化。我在项目里加了一个“强制刷新权限”的接口调用后清除该用户的登录态缓存再配合前端重新拉取portalConfig就能让配置立即生效。另外如果系统里用了Redis做缓存还要把角色权限对应的缓存键一起清理否则后端判断按钮权限时还是会命中旧数据。5.2 动态路由导致刷新白屏动态路由一个最常见的坑是用户直接刷新浏览器页面时地址栏里的路由还在但动态注册的路由表在内存里还没初始化前端匹配不到组件于是白屏。解决方法是全局路由守卫里加一个判断如果当前路由的name在权限菜单里找不到就重新从后端拉取portalConfig并重新注册动态路由再重定向到目标路由。这个判断必须做“找得到就不管找不到才重新拉取”否则会陷入无限重定向循环页面直接卡死。5.3 卡片显示了但数据全是空的布局里的卡片能正常渲染但数据一直为空这个问题的排查顺序一般是先看数据源接口是否报错再看设备分组ID参数是否传对最后看数据权限是否把该分组过滤掉了。我遇到最多的是第三种情况巡检员角色配置的数据权限只包含本部门但卡片绑定的设备分组属于另一个部门后端计算交集为空自然返回空数据。这种问题不是开发Bug而是配置冲突。解决办法是在角色数据权限配置页把对应设备分组加上或者把卡片改成绑定到该用户有权限的设备分组上二选一。5.4 门户页面加载慢首屏要等好几秒门户加载变慢大概率是三个原因叠加门户配置接口查询了太多表、前端一次性注册了几十个大屏路由、卡片接口并发请求太多。我优化时做了三件事门户配置接口增加Redis缓存五分钟过期前端路由改成按需注册打开哪个大屏再注册哪个卡片接口统一改成批量接口一个接口返回一整屏所需的数据减少HTTP连接数。优化完之后首屏从四秒多降到了1.5秒以内领导打开大屏再也没吐槽转圈了。我自己做完这个改造最深的体会是千人千面不是炫技功能它本质上是权限模型、配置数据和前端渲染三者协同的结果。如果你只把精力放在拖拽组件和页面样式上忽略了数据权限和动态菜单这两层地基那做出来的门户一定会在真实业务里出各种幺蛾子。JVS物联网平台给了很好的底座菜单、角色、大屏、可视化组件都是现成的关键是把它们串起来的这条链路设计清楚。最后分享一个小技巧做门户配置前先把每个角色的“第一屏”用纸质原型画出来让业务方签字确认再回填到配置中心。这样能少走很多返工的弯路毕竟业务眼里的“改一下”和开发眼里的“改一下”往往不是同一个工作量。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门