<template> <view class="u-wrap"> <view class="serch txt-16"> <uni-search-bar class="flex1" placeholder="请输入菜单名称" @confirm="search" @input="input" cancelButton="none" @clear="clearfilterlist"> </uni-search-bar> <button class="mini-btn" type="primary" size="mini" style="margin-right:15rpx; font-size: 16px;" @click="search">搜索</button> </view> <view class="item-container" style="align-items: center; width: 100%;"> <view class="thumb-box" v-for="(item1, index1) in filterList" :key="index1" @click="openCheck(item1)" style="text-align: center; "> <view class="" style="position: relative; "> <image class="item-menu-image" :src="'/static/menus/'+item1.componentName" mode=""> </image> <view class=""> <text class="item-menu-name">{{item1.name}}</text> </view> </view> </view> <view v-if="serchval.length >0 && nomore == true" class="nomore" style=" width: 100%; justify-content: center; margin: 20rpx;"> <text style="font-size: 35rpx;">暂无数据</text> </view> </view> <view class="u-menu-wrap"> <scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop" :scroll-into-view="itemId"> <view v-for="(item,index) in tabbar" :key="index" class="u-tab-item" :class="[current == index ? 'u-tab-item-active' : '']" @tap.stop="swichMenu(index)"> <text class="u-line-1">{{item.name}}</text> </view> </scroll-view> <scroll-view :scroll-top="scrollRightTop" scroll-y scroll-with-animation class="right-box" @scroll="rightScroll"> <view class="page-view" style="padding-bottom: 100rpx;"> <view class="class-item" :id="'item' + index" v-for="(item , index) in tabbar" :key="index"> <view class="item-title"> <text>{{item.name}}</text> </view> <view class="item-container"> <view class="thumb-box" v-for="(item1, index1) in item.children" :key="index1" @click="openCheck(item1)"> <view class="" style="position: relative; "> <!-- <u-badge class="item-menu-badge" v-if="item1.count>0" type="error" :count="item1.count" :offset="position" :showZero="false"></u-badge> --> <text class="item-menu-badge" v-if="item1.count>0">{{item1.count>9?'9+':item1.count}}</text> <image v-if='item1.componentName==""' class="item-menu-image" src="/static/menus/default.svg" mode=""> </image> <image v-else class="item-menu-image" :src="'/static/menus/'+item1.componentName" mode=""> </image> <view class=""> <text class="item-menu-name">{{item1.name}}</text> </view> </view> </view> </view> </view> </view> </scroll-view> </view> <comMessage ref="comMessage"></comMessage> </view> </template> <script> import { getDictionaryItem, getPackageUnitList, getMainMessage, getSwitchByCode, getBusinessType } from '@/api/request2.js'; import { overPagePrint, overPageTemplate } from '@/common/config.js'; export default { components: {}, data() { return { title: 'WMS仓库管理系统', scrollTop: 0, //tab标题的滚动条位置 oldScrollTop: 0, current: 0, // 预设当前项的值 menuHeight: 0, // 左边菜单的高度 menuItemHeight: 0, // 左边菜单item的高度 itemId: '', // 栏目右边scroll-view用于滚动的id tabbar: [], menuItemPos: [], arr: [], scrollRightTop: 0, // 右边栏目scroll-view的滚动条高度 timer: null, // 定时器 timerHome: null, // 定时器 forcedLogin: false, count: 1, position: [-10, -10], menusCount: {}, filterList: [], serchval: "" } }, onLoad() { if (uni.getStorageSync("hasLogin")) { uni.showLoading({ title: "正在获取菜单...", mask: true }) this.$store.dispatch('getPermissionInfo').then(res => { uni.hideLoading() if (res.menus.length > 0) { var menus = res.menus.filter(item => item.name == "PDA菜单管理") if (menus != undefined && menus.length > 0) { var tab = menus[0].children.filter(res => res.visible == true) tab.forEach(res => { for (var i = 0; i < res.children.length; i++) { if (res.children[i].visible == false) { res.children.splice(i, 1) } } }) this.tabbar = tab; var i = 0; this.tabbar.forEach(res => { res.children.forEach(res => { i++ }) }) this.getDictory() this.timerRefresh(); } else { this.showMessage("获取菜单失败") } } }).catch(error => { uni.hideLoading() this.showMessage(error) }); } }, onReady() { if (uni.getStorageSync("hasLogin")) { this.getMenuItemTop() } }, onHide() { this.stopRefresh(); }, onShow() { if (uni.getStorageSync("hasLogin") == null || uni.getStorageSync("hasLogin") == false) { uni.showModal({ title: '未登录', content: '您未登录 , 需要登录后才能继续', //如果需要强制登录,不显示取消按钮 showCancel: !this.forcedLogin, success: (res) => { if (res.confirm) { //如果需要强制登录,使用reLanch方式 if (this.forcedLogin) { uni.reLaunch({ url: '../login/index' }) } else { uni.navigateTo({ url: '../login/index' }) } } } }) } else { this.timerRefresh(); } }, onUnload() { this.stopRefresh(); }, mounted() {}, methods: { timerRefresh() { this.getMainMessage(); this.stopRefresh(); var that = this; this.timer = setInterval(function() { that.getMainMessage(); console.log('刷新菜单'); }, 1000 * 60) }, stopRefresh() { if (this.timer) { clearInterval(this.timer); this.timer = null; } }, getMainMessage() { getMainMessage().then(res => { this.menusCount = res.data; this.tabbar.forEach(item => { item.children.forEach(rightItem => { var count = 0 if(Array.isArray(this.menusCount[rightItem.component.split('-')[0]])&&this.menusCount[rightItem.component.split('-')[0]].length>0){ if(rightItem.component=='productionreturn'){ this.menusCount[rightItem.component].forEach((item)=>{ count += item.count }) }else{ if(rightItem.component=='inventorymove-HoldToScrap'){ } this.menusCount[rightItem.component.split('-')[0]].forEach((item)=>{ if(item.businessType ==rightItem.component.split('-')[1] ){ count = item.count } }) } }else{ count =this.menusCount[rightItem.component] } if (count != undefined) { rightItem.count = count; } }) }) this.$forceUpdate() }).catch(res => { console.log("获取消息失败", res) }); }, findList(tab) { let res = null for (let i = 0; i < tab.length; i++) { if (tab[i].visible === true) { res = tab[i] return tab[i] } else if (tab[i].children && tab[i].children.length > 0) { res = findList(tab[i].children) } if (res) break } return res }, // 点击左边的栏目切换 async swichMenu(index) { if (this.arr.length == 0) { await this.getMenuItemTop(); } if (index == this.current) return; this.scrollRightTop = this.oldScrollTop; this.$nextTick(function() { this.scrollRightTop = this.arr[index]; this.current = index; this.leftMenuStatus(index); }) }, // 获取一个目标元素的高度 getElRect(elClass, dataVal) { new Promise((resolve, reject) => { const query = uni.createSelectorQuery().in(this); query.select('.' + elClass).fields({ size: true }, res => { // 如果节点尚未生成,res值为null,循环调用执行 if (!res) { setTimeout(() => { this.getElRect(elClass); }, 10); return; } this[dataVal] = res.height; resolve(); }).exec(); }) }, // 观测元素相交状态 async observer() { this.tabbar.map((val, index) => { let observer = uni.createIntersectionObserver(this); // 检测右边scroll-view的id为itemxx的元素与right-box的相交状态 // 如果跟.right-box底部相交,就动态设置左边栏目的活动状态 observer.relativeTo('.right-box', { top: 0 }).observe('#item' + index, res => { if (res.intersectionRatio > 0) { let id = res.id.substring(4); this.leftMenuStatus(id); } }) }) }, // 设置左边菜单的滚动状态 async leftMenuStatus(index) { this.current = index; // 如果为0,意味着尚未初始化 if (this.menuHeight == 0 || this.menuItemHeight == 0) { await this.getElRect('menu-scroll-view', 'menuHeight'); await this.getElRect('u-tab-item', 'menuItemHeight'); } // 将菜单活动item垂直居中 this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2; }, // 获取右边菜单每个item到顶部的距离 getMenuItemTop() { new Promise(resolve => { let selectorQuery = uni.createSelectorQuery(); selectorQuery.selectAll('.class-item').boundingClientRect((rects) => { // 如果节点尚未生成,rects值为[](因为用selectAll,所以返回的是数组),循环调用执行 if (!rects.length) { setTimeout(() => { this.getMenuItemTop(); }, 10); return; } rects.forEach((rect) => { // 这里减去rects[0].top,是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况) this.arr.push(rect.top - rects[0].top); resolve(); }) }).exec() }) }, // 右边菜单滚动 async rightScroll(e) { this.oldScrollTop = e.detail.scrollTop; if (this.arr.length == 0) { await this.getMenuItemTop(); } if (this.timerHome) return; if (!this.menuHeight) { await this.getElRect('menu-scroll-view', 'menuHeight'); } setTimeout(() => { // 节流 this.timerHome = null; // scrollHeight为右边菜单垂直中点位置 let scrollHeight = e.detail.scrollTop + this.menuHeight / 5; for (let i = 0; i < this.arr.length; i++) { let height1 = this.arr[i]; let height2 = this.arr[i + 1]; // 如果不存在height2,意味着数据循环已经到了最后一个,设置左边菜单为最后一项即可 if (!height2 || scrollHeight >= height1 && scrollHeight < height2) { this.leftMenuStatus(i); return; } } }, 10) }, getDictory() { var params = { types: ["job_status", "location_type", "item_status", "item_type", "uom", "inventory_status", "container_type", "pack_unit", "unplanned_receipt_reason", "unplanned_issue_reason", "scrap_reason", "inspect_failed_reason", "request_status", "inspect_type", "next_action", "sample_method", "transfer_mode", "count_stage", "inspect_result", "area_type","count_scope_type","priority","receive_status", ] } getDictionaryItem(params).then(res => { if (res.data.length > 0) { uni.setStorageSync("dictionary", res.data) } }).catch(res => { console.log("获取字典失败", res) }) var unitparams = { filters: [], pageNo: 1, pageSize: 1000, } getPackageUnitList(unitparams).then(unitres => { if (unitres.data.list.length > 0) { uni.setStorageSync("packunit", unitres.data.list) } }).catch(res => { console.log("包装规格获取失败", res) }) var switchCode="FgPutawayLocationCodeValidate,SemiPutawayLocationCodeValidate,PurchasePutawayToLocationCodeValidate,IssueToLocationCodeValidate,fgProductReceipCommitValidate,semiProductReceipCommitValidate,purchasereceiptPrintPDA,purchaseReceiptLocationCodeValidate,CreateProductputawayRequestAfterProductreceiptRecordCreated,EnableQms,ShowPackingNumber"; getSwitchByCode(switchCode).then(res=>{ uni.setStorageSync("switch", res.data) }).catch(error=>{ }) // 获取业务类型 getBusinessType().then(res=>{ uni.setStorageSync("businessType", res.data.list) }).catch(error=>{ }) }, openCheck(item) { let name = item.name.split('\\n').join('') if(item.path.indexOf('?')>-1){ uni.navigateTo({ url: `/${item.path}&title=${name}` }); }else{ uni.navigateTo({ url: `/${item.path}?title=${name}` }); } this.filterList = [] }, showMessage(message) { this.$refs.comMessage.showMessage(message, res => { if (res) { } }); }, search() { let that = this that.filterList = [] that.nomore = false if (that.serchval.length !== 0) { this.tabbar.forEach((v) => { v.children.forEach((i) => { if (i.name.indexOf(that.serchval) !== -1) { // console.log("dddd", i) that.filterList.push(i) } }) }) if (that.filterList == 0) { that.nomore = true } } }, clearfilterlist() { let that = this; that.filterList = []; }, input(v) { this.serchval = v this.nomore = false if (this.serchval == "") { this.clearfilterlist() } }, } } </script> <style lang="scss" scoped> .u-wrap { height: calc(100vh); /* #ifdef H5 */ height: calc(100vh - var(--window-top)); /* #endif */ display: flex; flex-direction: column; } .u-search-box { padding: 18rpx 30rpx; } .u-menu-wrap { flex: 1; display: flex; overflow: hidden; } .u-search-inner { background-color: rgb(234, 234, 234); border-radius: 100rpx; display: flex; align-items: center; padding: 10rpx 16rpx; } .u-search-text { font-size: 26rpx; color: $u-tips-color; margin-left: 10rpx; } .u-tab-view { width: 180rpx; height: 100%; } .u-tab-item { height: 110rpx; background: #f6f6f6; box-sizing: border-box; display: flex; align-items: center; justify-content: center; font-size: 30rpx; color: #444; font-weight: 400; line-height: 1; } .u-tab-item-active { position: relative; color: #000; font-size: 30rpx; font-weight: 600; background: #fff; } .u-tab-item-active::before { content: ""; position: absolute; border-left: 4px solid $u-type-primary; height: 32rpx; left: 0; top: 39rpx; } .u-tab-view { height: 100%; } .right-box { background-color: rgb(250, 250, 250); } .page-view { padding: 16rpx; } .class-item { margin-bottom: 30rpx; background-color: #fff; padding: 16rpx; border-radius: 8rpx; } .class-item:last-child { min-height: 100vh; } .item-title { font-size: 32rpx; color: $u-main-color; font-weight: bold; } .item-menu-name { font-weight: normal; font-size: 28rpx; color: $u-main-color; width: 120rpx; // word-wrap: break-word; // word-break: break-all; // white-space: pre-wrap; } .item-container { display: flex; flex-wrap: wrap; } .thumb-box { width: 33.333333%; display: flex; align-items: center; // justify-content: center; flex-direction: column; margin-top: 20rpx; text-align: center; } .item-menu-image { width: 32px; height: 32px; } .item-menu-badge { width: 36rpx; height: 36rpx; align-items: center; // top: -5px; // right: -5px; font-size: 0.6rem; background-color: #fa3534; position: absolute; right: 0; color: #fff; text-align: center; line-height: 36rpx; border-radius: 50%; } .serch { width: 100%; display: flex; /* height: 130upx; */ align-items: center; } .flex1 { flex: 1; font-size: 18px; } .menu { width: 100%; } .nomore { font-size: 30rpx; color: #666; text-align: center; align-items: center; } </style>