前端应用界面的展示与优化(记录)
情景:由于项目要分期上线,并且数据库中删除是改变删除标识而id不发生改变,分期上线时会先展示部分功能,后期再加上新菜单时与本地环境的数据库id不同将导致列表展示有误,故选择将根据id展示改成根据菜单标识名来匹配。由于不同模块的子应用展示时会有不同的判定条件,为了减少逻辑上的判断和加快逻辑将由遍历本地静态路由和请求返回的动态路由完成比对后显示的方式改为将返回的树结构中的标识名称取出,再将本地的树形路由改为平面数组的形式,完成比对后将数组转成树形结构,只能说比一个个去遍历和判断方便的多。。。
这个界面主要分三个部分,设备、航班是可以直接根据系统中的路由来显示的,任务管理中的功能是要根据用户权限现实的,学习园地,设备档案,智慧运营这三个是在跟设备,航班同级的应用模块下的子功能,这就导致了整个页面要实现动态展现要进行三种判断。
先放上第一种,直接看数据库根据数据库中的id来判断,由于pc端删除菜单时是不会去删库数据而是改标识id,所以直接根据id来判定是可行的。(后期才发现问题多多。。。)
前端部分由于要配合左侧的模块实现点击模块名右侧功能实现自动定位所以整体的结构与后端返回的路由并不能一一对应。
后端返回形式
前端实际的形式
如上文所说,应用部分与返回部分不是同级,任务部分并不根据实际返回的路由显示而是进行二次判断。
方法一:根据id判断,优:操作简单 缺:如果上线过程中创建菜单过程不一样也就是菜单部分建库时不带数据将导致菜单混乱。逻辑判断冗杂
静态路由写死,遍历返回的菜单根据id去判断
静态:
applicationList: [{"title": this.$t('DeviceManagement'),"id": "DeviceManagement","menu": 2,"showModel": false,"menuName": "设备","list": [{"showItem": false,"menu": 23,"title": this.$t('AllDevice'),"title_initial": "B","name": "Repair","icon": this.$mAssetsPath.allEqp,"group": "device","url": "/pages/application/Device/index?navIndex=0&statusCurrent=1&menu=23"},{"showItem": false,"menu": 23,"title": this.$t('AlarmDevice'),"title_initial": "B","name": "Repair","icon": this.$mAssetsPath.alarmEqp,"group": "device","url": "/pages/application/Device/index?navIndex=0&statusCurrent=0&menu=23"},{"menu": 24,"title": this.$t('HistoryQuery'),"title_initial": "B","name": "Repair","icon": this.$mAssetsPath.getHistory,"group": "device","url": "/pages/application/Device/index?navIndex=1&menu=24"},{"menu": 25,"title": this.$t("DeviceSet"),"title_initial": "B","name": "Repair","icon": this.$mAssetsPath.eqpSetting,"group": "approve","url": "/pages/application/Device/index?navIndex=2&menu=25"},{"menu": 26,"title": this.$t('FaultReport'),"title_initial": "B","name": "Repair","icon": this.$mAssetsPath.faultReporting,"group": "device","url": "/pages/application/Device/index?navIndex=3&menu=26"}]}, {"title": this.$t("Flight"),"id": "Flight","menu": 3,"showModel": false,"menuName": "航班","list": [{"menu": 21,"title": this.$t('FlightInfo'),"title_initial": "C","name": "flightInfo","icon": this.$mAssetsPath.flightInfo,"group": "flight","url": "/pages/application/Flight/" + mConstDataConfig.airportSignage +"/Flight?radio=0"},{"menu": 22,"title": this.$t('FlightFocused'),"title_initial": "C","name": "favFlight","icon": this.$mAssetsPath.favFlight,"group": "flight","url": "/pages/application/Flight/" + mConstDataConfig.airportSignage +"/Flight?radio=1"},{"menu": 404,"title": "写入nfc",// "title_initial": "C","name": "Car","icon": this.$mAssetsPath.writeNFC,"group": "flight","url": "/pages/application/Flight/" + mConstDataConfig.airportSignage +"/addNFC/addNFC"}]}, {"menu": 4,"showModel": false,"title": this.$t("TaskManagement"),"id": "TaskManagement","menuName": "任务","list": [{"title": this.$t("RepairTask"),"title_initial": "J","name": "Rewards","icon": this.$mAssetsPath.maintenance,"group": "task","url": "/pages/application/works/" + mConstDataConfig.airportSignage +"/index?navIndex=3"}, {"title": this.$t("SafeguardTask"),"title_initial": "S","name": "Insurance","icon": this.$mAssetsPath.guarantee,"group": "task","url": "/pages/application/works/" + mConstDataConfig.airportSignage +"/index?navIndex=1"}, {"title": this.$t('MaintainTask'),"title_initial": "Y","name": "Employees","icon": this.$mAssetsPath.repair,"group": "task","url": "/pages/application/works/" + mConstDataConfig.airportSignage +"/index?navIndex=5"}]}, {"showModel": false,"title": "学习园地","id": "learn","menuName": "应用","menuNameItem": "学习","menu": 5,"meauI": 10,"list": [{"menu": 29,"showItem": false,"title": "案例维修","icon": this.$mAssetsPath.knowledgeBase,"name": "News","group": "learn","menuName": "案例维修","url": "/pages/center/learn/repairCase/repairCase"}, {"menu": 30,"showItem": false,"title": "考试","icon": this.$mAssetsPath.exam,"name": "News","group": "learn","menuName": "考试","url": "/pages/center/learn/exam/exam"}, {"menu": 31,"showItem": false,"title": "问卷调查","icon": this.$mAssetsPath.questionnaire,"name": "News","group": "learn","menuName": "问卷","url": "/pages/center/learn/questionnaire/questionnaire"}]},{"showModel": false,"title": "设备档案","id": "archives","menuName": "应用","menuNameItem": "档案","menu": 5,"meauI": 11,"list": [{"menu": 32,"showItem": false,"title": "维修指引","icon": this.$mAssetsPath.guide,"name": "News","menuName": "维修指引","url": "/pages/center/archives/repair/repair"}, {"menu": 33,"showItem": false,"title": "保养标准","icon": this.$mAssetsPath.stader,"name": "News","group": "learn","menuName": "保养标准","url": "/pages/center/archives/standard/standard1"}, ]},{"showModel": false,"title": "智慧运维","id": "archives","menuName": "应用","menuNameItem": "智慧运维","menu": 5,"meauI": 34,"list": [{"menu": 35,"showItem": false,"title": "专项检查","menuName": "专项检查","icon": this.$mAssetsPath.specialInspect,"name": "News","group": "learn","url": "/pages/center/operation/specialInspection/specialInspection"}, {"menu": 36,"showItem": false,"title": "其他工作","icon": this.$mAssetsPath.otherWork,"name": "News","group": "learn","menuName": "其他工作","url": "/pages/center/operation/otherWork/otherWork"}, {"menu": 37,"showItem": false,"title": "交接班记录","icon": this.$mAssetsPath.changeShifts,"name": "News","group": "learn","menuName": "交接班记录","url": "/pages/center/operation/changeShifts/changeShifts"}]}],
处理部分:
//获取当前用户对应的菜单 --------开始--------------//内部操作是根据完整的菜单列表getRouters().then(res => {if (res.ok()) {console.log(res)//声明当前菜单列表let meau = []//遍历返回的菜单列表获得id列表let l = res.data.lengthfor (let i = 0; i < l; i++) {meau.push(res.data[i].id)}console.log("后端返回的用户菜单:" + meau)//遍历本地静态列表确定是否显示let l1 = this.applicationList.lengthfor (let i = 0; i < l1; i++) {//判断当前模块是否要显示// console.log(this.applicationList[i].menu)if (meau.indexOf(this.applicationList[i].menu) != -1) {//现阶段任务是特殊的,先分开判断if (this.applicationList[i].menu != 4 && this.applicationList[i].menu != 5) {this.applicationList[i].showModel = true//如果显示当前模块,获取当前模块要显示的id列表let itemList = []let itemLen = res.data[meau.indexOf(this.applicationList[i].menu)].children.length//获取二级列表for (let p = 0; p < itemLen; p++) {itemList.push(res.data[meau.indexOf(this.applicationList[i].menu)].children[p].id)}//遍历对应的静态列表判断当前页面是否显示let itemLen2 = this.applicationList[i].list.lengthfor (let q = 0; q < itemLen2; q++) {if (itemList.indexOf(this.applicationList[i].list[q].menu) != -1) {this.applicationList[i].list[q].showItem = true}}} else if (this.applicationList[i].menu == 5) {//应用模块也是特殊化处理//先遍历children看有没有现实的,并作为左侧题目,再遍历children的children显示内部的二级页面//后端返回的应用模块子模块数console.log("进入应用列表")let centerChildrenLength = res.data[meau.indexOf(this.applicationList[i].menu)].children.lengthconsole.log("子模块列表长度" + centerChildrenLength)//遍历子模块,如果有就显示for (let a = 0; a < centerChildrenLength; a++) {console.log(res.data[meau.indexOf(this.applicationList[i].menu)].children[a].id)if (res.data[meau.indexOf(this.applicationList[i].menu)].children[a].id == this.applicationList[i].meauI) {this.applicationList[i].showModel = true//再遍历应用子模块中的子列表判断具体功能是否显示let smallLength = (res.data[meau.indexOf(this.applicationList[i].menu)].children[a].children || []).lengthconsole.log(smallLength + "=========")if (smallLength > 0) {//把对应的id存进去let centerMeau = []for (let b = 0; b < smallLength; b++) {centerMeau.push(res.data[meau.indexOf(this.applicationList[i].menu)].children[a].children[b].id)}//看本地的有没有符合的,符合就显示let itemLen3 = this.applicationList[i].list.lengthconsole.log(itemLen3)for (let f = 0; f < itemLen3; f++) {console.log(centerMeau)// console.log(centerMeau.indexOf(this.applicationList[i].list[f].menu)if (centerMeau.indexOf(this.applicationList[i].list[f].menu) != -1) {console.log("有啦")this.applicationList[i].list[f].showItem = true}}} else {}}}} else { //TODO 任务先根据角色显示getInfo().then(res1 => {let roles = res1.data.rolesconsole.log(roles)//判断是否显示if (roles.indexOf('super_admin') != -1) {this.applicationList[i].showModel = truelet itemLen2 = this.applicationList[i].list.lengthfor (let q = 0; q < itemLen2; q++) {this.applicationList[i].list[q].showItem = true}} else {if (roles.indexOf('MAINT_OPERATOR') != -1) {console.log(roles.indexOf('MAINT_OPERATOR'))this.applicationList[i].showModel = truethis.applicationList[i].list[0].showItem = true}if (roles.indexOf('OPERATOR_PBB') != -1) {console.log("不是操作员")// console.log(roles.indexOf('OPERATOR_PBB'))this.applicationList[i].showModel = truethis.applicationList[i].list[1].showItem = true}if (roles.indexOf('OPERATOR_APU') != -1) {// console.log(roles.indexOf('OPERATOR_APU'))console.log("不是操作员")this.applicationList[i].showModel = truethis.applicationList[i].list[1].showItem = true}if (roles.indexOf('MAINT_OPERATOR') != -1) {console.log(roles.indexOf('MAINT_OPERATOR'))this.applicationList[i].showModel = truethis.applicationList[i].list[2].showItem = true}}/*** 判断跳转参数1 遍历this.applicationList[i]2 不是操作员,保障不显示,不用改*/if (roles.indexOf('OPERATOR_APU') == -1 && roles.indexOf('OPERATOR_PBB') == -1) {//判断是不是维修人员//是维修人员 维修变成0,保养变成2if (roles.indexOf('MAINT_OPERATOR') != -1) {this.taskIndex1 = 0this.applicationList[i].list[0].url ="/pages/application/works/index?navIndex=0"this.applicationList[i].list[2].url ="/pages/application/works/index?navIndex=2"} else { //不是维修人员,按理说不显示}} else { //只要是操作员,必有保障,只要跳0即可 原本就是0不用变//判断还是不是维修人员//是的话也是按顺序往上加,不用变,不是的话也不用变QAQif (roles.indexOf('MAINT_OPERATOR') != -1) {} else {}}})}}}}})获取当前用户对应的菜单 --------结束--------------
方法2 :根据路由中的汉字名称判断 优:不用担心id不同菜单紊乱的问题 缺:跟id一样,判断逻辑不复杂但是冗长
处理代码:
getRouters().then(res => {if (res.ok()) {//声明返回的菜单名列表let nameMeau = []let allMeau = res.data//遍历返回的菜单列表获得id列表let l = (res.data || []).lengthfor (let i = 0; i < l; i++) {nameMeau.push(res.data[i].menuName)}//遍历本地静态列表确定是否显示let staticMeauLength = this.applicationList.lengthfor (let i in this.applicationList) {//判断当前模块是否要显示if (nameMeau.indexOf(this.applicationList[i].menuName) != -1) {let modeName = this.applicationList[i].menuNameconsole.log(modeName)//任务,应用要特殊化if(modeName == "任务"){this.applicationList[i].menuName}else if(modeName == "应用"){let index = nameMeau.indexOf(this.applicationList[i].menuName) //判断应用有没有二级列表if(allMeau[index].children != null){//声明返回二级菜单名称列表let titleList = []// console.log(allMeau[index].children)for(let p in allMeau[index].children){titleList.push(allMeau[index].children[p].menuName)if(titleList.includes(this.applicationList[i].menuNameItem)){//将应用二级标题展示this.applicationList[i].showModel = truelet titleIndex = titleList.indexOf(this.applicationList[i].menuNameItem)//获取要展示的功能的列表的长度let itemLength = (allMeau[index].children[titleIndex].children||[]).lengthif(itemLength > 0){//声明要展示的功能的名称列表let itemNameList = []for(let q in allMeau[index].children[titleIndex].children){itemNameList.push(allMeau[index].children[titleIndex].children[q].menuName)}// 遍历叶子节点将功能显示for(let m in this.applicationList[i].list){if(itemNameList.includes(this.applicationList[i].list[m].menuName)){console.log(allMeau[index].children[titleIndex].children) this.applicationList[i].list[m].showItem = true}}}}}//判断// console.log(itemList)// for(let q in this.applicationList[i].list){// console.log(itemList)// console.log(itemList.indexOf("问卷"))// if(itemList.indexOf(this.applicationList[i].list[q].menuName) != -1){// console.log("显示"+this.applicationList[i].list[q].menuName)// this.applicationList[i].list[q].showItem = true// }// }}console.log(allMeau[index])// res.data[meau.indexOf(this.applicationList[i].menu)].children[a]// .id}else{}}}}})
方法三:将静态路由由树状改为平面数组,数组内对象添加父id,整体还是通过名称来判断,同伙静态路由的父id来实现应用模块的特殊化需求,遍历路由后将数组重新组成树结构
//遍历菜单树dfsMeauTree(meauList) {let that = thisif(meauList.visible == 1){that.nameList.push(meauList.menuName)}if (meauList.children) {meauList.children.forEach(child => this.dfsMeauTree(child));}},buildTree(arr, parentId = null) {let result = [];let temp = arr.filter(item => item.parentId === parentId);temp.forEach(item => {//对于每个节点,递归调用buildTree函数来构建其子树,并将结果赋值给item.children。let children = this.buildTree(arr, item.id);if (children.length) {item.children = children;}result.push(item);});//将当前节点添加到结果数组中。最终,返回结果数组作为树的根节点。return result;},detailMeau() {console.log("处理菜单")let that = thislet aasd = []//获取要展示的功能名称列表getRouters().then(res => {let currentName = []for (let i in res.data) {that.dfsMeauTree(res.data[i])}console.log(that.nameList)for (let i in that.nameList) {currentName.push(that.nameList[i])}//遍历本地静态数组for (let i in this.applicationList) {if (currentName.includes(this.applicationList[i].menuName)) {console.log(this.applicationList[i].menuName)this.applicationList[i].showItem = truethis.applicationList[i].showModel = true}//对任务模块的进行特殊处理getInfo().then(res1 => {let roles = res1.data.rolesif (this.applicationList[i].parentId == "TaskManagement") {for (let p in this.applicationList[i].role) {// console.log("遍历任务选项中角色的循环======"+p)if (roles.indexOf(this.applicationList[i].role[p]) != -1 || roles.indexOf('super_admin') != -1) {this.applicationList[i].showItem = true// break;}else{this.applicationList[i].showItem = false}}}})}//将数组转换成树形结构let meauTree = that.buildTree(this.applicationList)this.meauTree = meauTree})}}
静态路由设计:
applicationList: [{id: "DeviceManagement",title: this.$t('DeviceManagement'),menu: 2,showModel: false,showItem: false,menuName: "设备",url: null,parentId: null,},{id: "AllDevice",id1: "",menu: 22,title: this.$t('AllDevice'),showModel: false,showItem: false,menuName: "状态",url: ,parentId: "DeviceManagement",icon: this.$mAssetsPath.allEqp},{id: "SafeguardTask",menu: null,title: this.$t("SafeguardTask"),showModel: false,showItem: false,menuName: "任务",url: ,parentId: "TaskManagement",role: ['OPERATOR_PBB', 'OPERATOR_APU'],icon: this.$mAssetsPath.guarantee}]
仅记录优化的过程和部分代码。。。