需求: 后台返回数组对像,前端组合成数组,根据name组合成一个个数组并把后台返回的值当成一个children推入数组,在数组中自定义属性备份数据防止搜索的时候改变原数组使得数组无法回退
这里是用的vuex存储,因为多个页面使用同一个接口;所以没必要重复请请求 src\store\module\metadata.js
import { Loading, Message } from 'element-ui'
import { apiManager } from '@/plugins/ajax'
let loadingInstance
const state = {
allList: [],
navList: [],
name: {}
}
const mutations = {
SET_NAVLIST: (state, list) => {
state.navList = list.map(item => {
if (item.children) {
item.backList = JSON.stringify(item.children)
}
})
},
SET_ALLLIST: (state, list) => {
state.allList = list
},
SET_NAME: (state, obj) => {
Object.assign(state.name, obj)
}
}
const actions = {
requestMetadata({ commit, state }, { name, navList }) {
return new Promise(resolve => {
const nameKey = Object.keys(state.name)
if (nameKey.indexOf(name) !== -1) {
resolve(state.name[name])
} else {
loadingInstance = Loading.service()
state.name[name] = name
apiManager
.post('/metadata/tableInfo/query')
.then(res => {
commit('SET_ALLLIST', res.data)
for (const i in res.data) {
const item = navList.find(v => v.name === i)
if (item) {
item.children = res.data[i]
item.navSearch = ''
item.backList = []
}
}
commit('SET_NAVLIST', navList)
commit('SET_NAME', { [name]: navList })
resolve(navList)
loadingInstance.close()
})
.catch(err => {
resolve([])
loadingInstance.close()
Message.error(err)
})
}
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
页面父组件使用子组件 src\views\console\dataAccessManage\dataResourceTable\FileXs.vue
<transition name="component-fade" mode="out-in">
<floating-menu v-show="isCollapse" :newList='navList' @getDatails='getDatails' />
</transition>
data() {
return {
navList: [
{
imgSrc: require('./../../../../../public/images/m6.png'),
name: 'ftp',
typeName: 'FTP服务器',
children: [],
total: 0
},
{
imgSrc: require('./../../../../../public/images/m5.png'),
name: 'txt',
typeName: '文件服务器',
children: [],
total: 0
}
],
},
async mounted() {
const param = {
name: 'fileXs',
navList: this.navList
}
this.navlist = await this.$store.dispatch('metadata/requestMetadata', param)
},
子组件 src\views\console\dataAccessManage\components\floatingMenu.vue
<template>
<div class="data-sheet-main__nav" v-if="sjktcList.length || newList.length">
<div>
<div class="nav__item" v-for="(item,index) in sjktcList" :key="'info2-' + index">
<div class="item_name sjk_name" :class="{ sjk_active: sjkActive == index }" @click="sjktcShow(item.type,index)">{{item.typeName}}</div>
</div>
</div>
<el-collapse class="nav__item" v-model="activeNames">
<el-collapse-item class="item_name" :title="item.typeName" :name="item.typeName" v-for="(item,index) in newList" :key="index">
<ul class="nav__item__list">
<li class="list__li">
<el-input v-input-val-bg v-model="item.navSearch" @input="handleNavSearch(item)" prefix-icon="el-icon-search" size="mini" placeholder="请输入关键字" clearable></el-input>
</li>
<li v-for="(key,i) in item.children" :key="i" :class="{ 'list__li--active': key.id == dbId }" class="list__li" @click="getDatails(key,item)">
<span :title="key.name" class="list--title">{{key.name}}</span>
<span class="list--count">{{key.total || 0}}</span>
</li>
<li class="no-data" v-if="!item.children.length">暂无数据</li>
</ul>
</el-collapse-item>
</el-collapse>
</div>
</template>
<script>
import { debounce } from '@/utils'
export default {
name: 'floatingMenu',
props: {
sjktcList: {
type: Array,
default: () => []
},
newList: {
type: Array,
default: () => []
}
},
components: {},
data() {
return {
sjkActive: 0,
navSearch: '',
navChildData: [],
dbId: '',
activeNames: []
}
},
mounted() {
},
methods: {
getDatails(args, db) {
this.dbId = args.id
this.$emit('getDatails', { args, db })
},
handleNavSearch: debounce(function (obj) {
this.$forceUpdate()
const currlist = JSON.parse(obj.backList)
if (obj.navSearch == '') {
obj.children = currlist
} else {
obj.children = currlist.filter(item => {
return item.name.toLowerCase().indexOf(obj.navSearch.toLowerCase()) != -1
})
}
}, 100),
sjktcShow(type, i) {
this.sjkActive = i
this.$emit('sjktcShow', [type])
}
},
watch: {
newList: {
deep: true,
handler(list) {
if (list) {
for (let i = 0; i < list.length; i++) {
const item = list[i]
if (!this.dbId && item.children.length) {
this.activeNames = item.typeName
this.getDatails(item.children[0], item)
}
}
}
}
}
}
}
</script>
<style lang='scss' scoped>
.data-sheet-main__nav {
width: 180px;
position: absolute;
top: 0px;
left: -190px;
z-index: 100;
background: #fff;
border: 1px solid #6579fe;
padding-top: 10px;
.sjk_active {
color: $theme !important;
}
.nav__item {
position: relative;
margin-bottom: 15px;
.item_name {
width: 100%;
display: inline-block;
padding-left: 17px;
font-size: 14px;
line-height: 24px;
color: rgba(0, 0, 0, 0.85);
/deep/.el-collapse-item__header {
font-weight: bold;
border-bottom: none;
position: relative;
padding-left: 15px;
.el-collapse-item__arrow {
position: absolute;
left: 0;
transform: rotate(270deg);
}
.el-collapse-item__arrow.is-active {
transform: rotate(90deg);
}
}
&:hover {
cursor: pointer;
}
}
.no-data {
text-align: center;
color: #999;
padding: 10px 0;
width: 100%;
}
img {
width: 100%;
height: 50px;
}
.nav__item--total {
position: absolute;
display: block;
width: 30px;
height: 30px;
background: #fff;
border: 1px solid #ccc;
border-radius: 50%;
line-height: 30px;
border: 1px solid #71b1ec;
box-shadow: 0 3px 6px #156d90;
text-align: center;
color: #fd0b0b;
font-size: 16px;
top: 0;
right: 0;
transform: translate(25%, -20%);
}
.nav__item__list {
display: flex;
max-height: 246px;
overflow-y: auto;
flex-wrap: wrap;
.list__li {
width: 100%;
margin-top: 5px;
line-height: 30px;
padding: 0 6px 0 17px;
position: relative;
cursor: pointer;
color: #333;
&:hover {
color: $blue;
}
.list--title {
width: 90px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
float: left;
&:hover {
color: #409eff;
}
}
.list--count {
color: #46a0fc;
float: right;
}
}
.list__li--active {
color: $blue;
}
}
}
/deep/.el-collapse {
border-top: none;
}
}
.data-sheet-main__list {
flex: 1;
margin-left: 20px;
.list-header {
flex-direction: column;
.order {
text-align: right;
a {
background: #6579fe;
font-family: PingFangSC-Regular;
font-size: 12px;
line-height: 22px;
color: #ffffff;
padding: 6px;
border-radius: 4px;
}
}
}
.handler--fixed-right {
padding: 25px 10px;
}
.nodata {
text-align: center;
font-size: 16px;
}
}
</style>
|