NEZ-698 perf: 过滤筛选框调整

This commit is contained in:
chenjinsong
2021-06-07 15:09:11 +08:00
parent b403837a81
commit 5f5f94bc0b
7 changed files with 243 additions and 96 deletions

View File

@@ -343,7 +343,7 @@ export default {
item.labels = JSON.parse(item.labels)
if (!this.isBuildIn(item.alertRule)) {
const paramStr = JSON.stringify(this.promQueryParamConvert(item))
axiosAll.push(axios.get('/prom/api/v1/query?query=' + paramStr.substring(1, paramStr.length - 1).replace(/\+/g, '%2B').replace(/ /g, '%20').replace(/\\/g, '')))
axiosAll.push(axios.get('/prom/api/v1/query?query=' + paramStr.substring(1, paramStr.length - 1)))
} else {
axiosAll.push('')
}

View File

@@ -1,25 +1,30 @@
<template>
<div :style="{'height': height + 'px'}" class="search-box__container">
<div v-loading="!titleSearchListCopy.ready" :style="{'height': height + 'px'}" class="search-box__container">
<div v-for="(data, type, index) in titleSearchListCopy" v-cloak v-if="data.show" :key="index" ref="searchContentBox" class="search-content-box">
<label class="search-title">{{data.label}}:</label>
<el-checkbox-group v-if="data.type === 'checkBox'" ref="searchContent" v-model="selectValueOut[data.key]">
<template v-for="(item, j) in data.children">
<el-checkbox v-if="!data.showMore || j < data.index" :key="j" :label="item.value">{{item.key || item.name || item.label}}</el-checkbox>
<el-checkbox v-show="j < data.index || data.showMore" :key="j" :label="item.value">{{item.key || item.name || item.label}}</el-checkbox>
</template>
</el-checkbox-group>
<template v-for="(item, j) in data.children" v-else-if="data.type === 'dropdownCheckBox'">
<dropdown
v-if="!data.showMore || j < data.index"
v-show="j < data.index || data.showMore"
:key="j"
:ref="`${type}_cascader`"
:ref="`${type}_${item.id}_cascader`"
:collapse-tags="true"
:item="item"
@blur="casFocus"
@change="casChange(type, data.key)"
@change="(value) => casChange(value, type, item, data.key)"
@focus="casFocus"
></dropdown>
</template>
<span v-show="contentWidth <= data.width" class="search-more" @click="changShowMore(type)">更多 <i :class="data.showMore?'el-icon-arrow-down':'el-icon-arrow-up'"/></span>
<span v-show="contentWidth < data.width"
:style="{top: `${moreBtnTop(data.type)}px`}"
class="search-more"
@click="changShowMore(type)">
More <i :class="data.showMore ? 'arrow-up' : ''" class="el-icon-arrow-down arrow-down"/>
</span>
</div>
</div>
</template>
@@ -63,6 +68,23 @@ export default {
}
},
computed: {
moreBtnTop () {
return function (type) {
let top
switch (type) {
case 'checkBox': {
top = 4
break
}
case 'dropdownCheckBox': {
top = 8
break
}
default: break
}
return top
}
},
height () {
const paddingHeight = 30
const checkBoxRowHeight = 31
@@ -84,11 +106,14 @@ export default {
immediate: true,
deep: true,
handler (n) {
if (n.ready) {
this.titleSearchListCopy = JSON.parse(JSON.stringify(n))
this.$nextTick(() => {
this.setEachCascWidth()
this.needMore()
})
}
}
},
selectValue: {
immediate: true,
@@ -109,16 +134,59 @@ export default {
return {
selectValueOut: {},
contentWidth: 0, // 搜索框内部区域的宽度
titleSearchListCopy: {}
titleSearchListCopy: {},
widthConstant: {
checkBox: {
boxMargin: 30,
checkBox: 14,
tagPadding: 10,
tagBlankTotal: 24 // 以上2个空白占位的总和
},
dropdownCheckBox: {
boxMargin: 21,
labelPadding: 6,
tagMaxWidth: 150, // 定义tag标签最大宽度
// 先分解cascader输入框的结构如下
tagMargin: 6,
tagPadding: 10,
tagBorder: 2,
tagRemoveIcon: 11,
tagBlank: 2,
tagBlankTotal: 31, // 以上五个空白占位的总和
textMaxWidth: 119, // 纯文本最大宽度通过tag最大宽度减去total得到
inputOriginalWidth: 60, // 输入框初始宽度
moreNumberWidth: 42, // 选中选项时右侧的+1、+2...数字提示内容的宽度
arrowDownWidth: 30 // 输入框右端箭头区域的宽度
}
}
}
},
mounted () {
window.addEventListener('resize', this.needMore)
},
methods: {
casChange (type, key) {
/* value: 选择器返回的值 */
casChange (value, type, item, key) {
this.$nextTick(() => {
const cascs = this.$refs[`${type}_cascader`]
// 计算change后新宽度
const oldInputWidth = item.inputWidth
this.setEachCascWidth(value, type, item)
/* 为实现动态宽度而改变输入框宽度因为cascader组件的宽度是由它决定的 */
if (item.inputWidth !== oldInputWidth) {
this.$refs[`${type}_${item.id}_cascader`][0].$el.querySelector('.el-input__inner').style.width = `${item.inputWidth}px`
this.$nextTick(() => {
this.needMore(type, item)
})
}
/* 组织参数 */
const cascs = []
this.titleSearchListCopy[type].children.forEach(c => {
cascs.push(this.$refs[`${type}_${c.id}_cascader`][0])
})
if (type === 'assetLabel') { // label特殊处理组织成{“id”:[“张三”,"lw"],"id":["李四"]}
const values = {}
cascs.forEach(c => {
@@ -145,55 +213,94 @@ export default {
this.selectValueOut.change++
})
},
computeCascWidth (textWidth, labelWidth) { // label + tag + margin
const tagWidth = textWidth > this.widthConstant.dropdownCheckBox.textMaxWidth ? this.widthConstant.dropdownCheckBox.textMaxWidth : textWidth + this.widthConstant.dropdownCheckBox.tagBlankTotal // 限制原始文字宽度不超过最大值得到实际tag宽度
const inputWidth = tagWidth + this.widthConstant.dropdownCheckBox.moreNumberWidth + this.widthConstant.dropdownCheckBox.arrowDownWidth
return { tagWidth, inputWidth, width: labelWidth + inputWidth + this.widthConstant.dropdownCheckBox.boxMargin }
},
setEachCascWidth (value, type, item) {
if (type) {
if (value.length === 0) { // 回到初始宽度
item.width = item.originalWidth
item.inputWidth = this.widthConstant.dropdownCheckBox.inputOriginalWidth
} else {
const showTag = item.children.find(c => c.id === value[0][0]) // 展示的tag
const { tagWidth, inputWidth, width } = this.computeCascWidth(this.computeDistance(showTag.name, 12), item.labelWidth)
item.width = width
item.inputWidth = inputWidth
}
} else { // 初始
Object.keys(this.titleSearchListCopy).forEach(type => {
if (type !== 'ready') {
this.titleSearchListCopy[type].children.forEach(c => {
if (this.titleSearchListCopy[type].type === 'dropdownCheckBox') {
const labelWidth = this.computeDistance(c.name + ':') + this.widthConstant.dropdownCheckBox.labelPadding // cascader-label总宽度
const width = labelWidth + this.widthConstant.dropdownCheckBox.inputOriginalWidth + this.widthConstant.dropdownCheckBox.boxMargin
this.$set(c, 'width', width) // 总宽
this.$set(c, 'originalWidth', width) // 初始总宽
this.$set(c, 'labelWidth', labelWidth) // label区域宽
this.$set(c, 'inputWidth', this.widthConstant.dropdownCheckBox.inputOriginalWidth) // 内容区域宽
} else if (this.titleSearchListCopy[type].type === 'checkBox') {
const width = this.computeDistance(c.name) + this.widthConstant.checkBox.tagBlankTotal + this.widthConstant.checkBox.boxMargin
this.$set(c, 'width', width) // 总宽
}
})
}
})
}
},
casFocus (item, isFocus, e) {
this.$set(item, 'isFocus', isFocus)
},
needMore (key) {
// setTimeout(() => {
this.$nextTick(() => {
this.contentWidth = this.$refs.searchContentBox[0].offsetWidth - 210
Object.keys(this.titleSearchListCopy).forEach(key => {
this.titleSearchListCopy[key].width = 0
this.titleSearchListCopy[key].showMore = false
let index = -1
this.titleSearchListCopy[key].children.forEach((item, i) => {
/* (基础宽度 + 文字宽度) 总和大于文本长时 显示更多 */
if (index === -1) {
this.titleSearchListCopy[key].width += this.getDomWidth(this.titleSearchListCopy[key], item, i)
if (this.titleSearchListCopy[key].width > this.contentWidth) {
this.titleSearchListCopy[key].showMore = true
this.titleSearchListCopy[key].index = i
index = i
needMore (type, item) {
const contentWidth = this.$refs.searchContentBox[0].offsetWidth - 210
// 窗口尺寸没改变则只重排当前type
if (type && contentWidth === this.contentWidth) {
this.titleSearchListCopy[type].width = 0
let showMore = false
this.titleSearchListCopy[type].children.forEach((item, i) => {
if (!showMore) {
this.titleSearchListCopy[type].width += item.width
if (this.titleSearchListCopy[type].width > this.contentWidth) {
showMore = true
this.titleSearchListCopy[type].index = i
}
}
})
if (!showMore) {
this.titleSearchListCopy[type].index = this.titleSearchListCopy[type].children.length - 1
}
} else { // 全体重排
this.contentWidth = contentWidth
Object.keys(this.titleSearchListCopy).forEach(type => {
if (type !== 'ready') {
this.titleSearchListCopy[type].width = 0
this.titleSearchListCopy[type].showMore = false
let showMore = false
this.titleSearchListCopy[type].children.forEach((item, i) => {
if (!showMore) {
this.titleSearchListCopy[type].width += item.width
if (this.titleSearchListCopy[type].width > this.contentWidth) {
showMore = true
this.titleSearchListCopy[type].index = i
}
}
})
if (!showMore) {
this.titleSearchListCopy[type].index = this.titleSearchListCopy[type].children.length - 1
}
}
})
}
},
computeDistance (str) {
computeDistance (str, fontSize) {
let width = 0
const html = document.querySelector('.temp-dom')
const c = fontSize ? '.temp-dom--' + fontSize : '.temp-dom'
const html = document.querySelector(c)
html.innerText = str
width = html.offsetWidth
return width
},
getDomWidth (parentData, item, index) {
let width
if (parentData.type === 'dropdownCheckBox') {
width = this.computeDistance(`${item.name}:`)
const marginRight = 22
width = width + 182 + marginRight// 182是label框的宽度除去name外的部分
} else {
width = this.computeDistance(item.name)
width = width > 150 ? 150 : width
const paddingLeft = 10
const checkBox = 14
const marginRight = 30
width = width + paddingLeft + checkBox + marginRight
}
return width
},
changShowMore (key) {
this.titleSearchListCopy[key].showMore = !this.titleSearchListCopy[key].showMore
}
@@ -204,7 +311,19 @@ export default {
}
</script>
<style lang="scss" scoped>
<style lang="scss">
.arrow-down {
transform: rotate(0);
transition: all linear .2s;
}
.arrow-down.arrow-up {
transform: rotate(180deg);
}
.nz-label-search {
.el-input__inner {
width: 60px;
}
}
.search-box__container {
display: flex;
flex-direction: column;
@@ -228,6 +347,10 @@ export default {
font-weight: 500;
overflow: hidden;
}
.search-content-box--copy {
position: fixed;
visibility: hidden;
}
.search-content-box {
display: flex;
align-items: center;
@@ -248,7 +371,6 @@ export default {
.search-more {
position: absolute;
right: 4px;
top: 4px;
height: 22px;
line-height: 22px;
padding: 0 8px;

View File

@@ -14,7 +14,7 @@
popper-class="click-search-dropdown"
size="mini"
@blur="$emit('blur', item, false, $event)"
@change="$emit('change')"
@change="change"
@focus="$emit('focus', item, true, $event)"
></el-cascader>
</div>
@@ -34,6 +34,9 @@ export default {
methods: {
casHover (item, isHover, e) {
return this.$set(item, 'isHover', isHover)
},
change (value) {
this.$emit('change', value)
}
},
computed: {
@@ -56,6 +59,6 @@ export default {
}
</script>
<style scoped>
<style lang="scss" scoped>
</style>

View File

@@ -11,6 +11,7 @@
<span class="el-popover table-tooltip"></span>
<!-- 临时文本dom用来计算文本长度 -->
<span class="temp-dom"></span>
<span class="temp-dom--12"></span>
</div>
</template>
@@ -62,4 +63,9 @@ export default {
font-size: 14px;
position: fixed;
}
.temp-dom--12 {
visibility: hidden;
font-size: 12px;
position: fixed;
}
</style>

View File

@@ -409,6 +409,7 @@ export default {
}
this.$set(this.searchLabel, 'pageNo', this.pageObj.pageNo)
this.$set(this.searchLabel, 'pageSize', this.pageObj.pageSize)
this.$set(this.searchLabel, 'state', this.state)
if (this.searchTime && this.searchTime.length > 1) {
this.$set(this.searchLabel, 'startAt', this.timezoneToUtcTimeStr(this.searchTime[0]))
this.$set(this.searchLabel, 'endAt', this.timezoneToUtcTimeStr(this.searchTime[1]))
@@ -421,7 +422,7 @@ export default {
delete this.searchLabel.startAt
delete this.searchLabel.endAt
}
this.$get(this.url + '?state=' + this.state, this.searchLabel).then(response => {
this.$get(this.url, this.searchLabel).then(response => {
this.tools.loading = false
if (response.code == 200) {
this.nowTime = this.utcTimeToTimezoneStr(response.time)

View File

@@ -208,6 +208,7 @@ export default {
snmpCredentialData: [],
fieldGroupData: [],
titleSearchList: {
ready: false,
dc: {
label: this.$t('overall.dc'),
key: 'dcIds',
@@ -216,7 +217,7 @@ export default {
show: true,
showMore: false,
width: 0,
index: 0
index: -1
},
type: {
label: this.$t('overall.type'),
@@ -226,7 +227,7 @@ export default {
show: true,
showMore: false,
width: 0,
index: 0
index: -1
},
ping: {
label: 'ping',
@@ -239,7 +240,7 @@ export default {
show: true,
showMore: false,
width: 0,
index: 0
index: -1
},
model: {
label: this.$t('asset.model'),
@@ -249,7 +250,7 @@ export default {
show: true,
showMore: false,
width: 0,
index: 0
index: -1
},
assetLabel: {
label: 'More',
@@ -259,7 +260,7 @@ export default {
show: true,
showMore: false,
width: 0,
index: 0
index: -1
}
},
selectValue: {
@@ -298,7 +299,8 @@ export default {
return new Promise(resolve => {
this.$get('asset/typeConf?pageSize=-1').then(response => {
if (response.code === 200) {
this.titleSearchList.type.children = response.data.list.map(d => { return { ...d, value: d.id } })
resolve(response.data.list.map(d => { return { ...d, value: d.id } }))
// this.titleSearchList.type.children = response.data.list.map(d => { return { ...d, value: d.id } })
}
resolve()
})
@@ -329,7 +331,8 @@ export default {
this.$get('dc', { pageSize: -1 }).then(response => {
if (response.code === 200) {
this.dcData = response.data.list
this.titleSearchList.dc.children = response.data.list.map(d => { return { ...d, value: d.id } })
resolve(response.data.list.map(d => { return { ...d, value: d.id } }))
// this.titleSearchList.dc.children = response.data.list.map(d => { return { ...d, value: d.id } })
}
resolve()
})
@@ -372,7 +375,8 @@ export default {
}
}
})
this.titleSearchList.assetLabel.children = data
// this.titleSearchList.assetLabel.children = data
resolve(data)
setTimeout(() => {
const title = this.tools.customTableTitle
const originalTitle = title.slice(0, this.$refs.dataTable.tableTitle.length) // 原title
@@ -404,7 +408,8 @@ export default {
titleSearchData[m.brand.name] = { ...m.brand, children: [m] }
}
})
this.titleSearchList.model.children = Object.keys(titleSearchData).map(b => titleSearchData[b])
resolve(Object.keys(titleSearchData).map(b => titleSearchData[b]))
// this.titleSearchList.model.children = Object.keys(titleSearchData).map(b => titleSearchData[b])
}
resolve()
})
@@ -440,12 +445,15 @@ export default {
},
mounted () {
// 初始化数据
this.getModelData()
Promise.all([this.getModelData(), this.getTypeData(), this.getDcData(), this.getSearchableMetaData()]).then(res => {
this.titleSearchList.model.children = res[0]
this.titleSearchList.type.children = res[1]
this.titleSearchList.dc.children = res[2]
this.titleSearchList.assetLabel.children = res[3]
this.titleSearchList.ready = true
})
this.getStateData()
this.getTypeTreeData()
this.getTypeData()
this.getDcData()
this.getSearchableMetaData()
this.getSnmpCredentialData()
this.getFieldGroupData()
},

View File

@@ -42,7 +42,7 @@
<!-- </button>-->
</template>
<template v-slot:search>
<clickSearch :titleSearchList="titleSearchList" :selectValue.sync="selectValue" @reload="reloadTable"/>
<click-search :select-value.sync="selectValue" :title-search-list="titleSearchList" @reload="reloadTable"></click-search>
</template>
<template v-slot:default="slotProps">
<endpoint-table
@@ -165,6 +165,7 @@ export default {
},
titleSearch: {},
titleSearchList: {
ready: false,
project: {
label: 'Project',
key: 'projectIds',
@@ -173,7 +174,7 @@ export default {
show: true,
showMore: false,
width: 0,
index: 0
index: -1
},
module: {
label: 'Module',
@@ -183,7 +184,7 @@ export default {
show: true,
showMore: false,
width: 0,
index: 0
index: -1
},
state: {
label: 'State',
@@ -193,7 +194,7 @@ export default {
show: true,
showMore: false,
width: 0,
index: 0
index: -1
}
},
selectValue: {
@@ -293,29 +294,34 @@ export default {
this.getTableData()
},
getTitleSearch () {
const titleRequest = new Promise(resolve => {
this.$get('monitor/project', { pageSize: -1 }).then(res => {
if (res.code === 200) {
res.data.list.forEach((item) => {
this.titleSearchList.project.children.push(
{ key: item.name, value: item.id, name: item.name }
)
})
resolve(res.data.list)
}
})
})
const moduleRequest = new Promise(resolve => {
this.$get('monitor/module', { pageSize: -1 }).then(res => {
if (res.code === 200) {
res.data.list.forEach((item) => {
this.titleSearchList.module.children.push(
{ key: item.name, value: item.id, name: item.name }
)
})
resolve(res.data.list)
}
})
})
Promise.all([titleRequest, moduleRequest]).then(res => {
this.titleSearchList.project.children = res[0].map(item => {
return { key: item.name, value: item.id, name: item.name }
})
this.titleSearchList.module.children = res[1].map(item => {
return { key: item.name, value: item.id, name: item.name }
})
this.titleSearchList.state.children = [
{ key: 'Down', value: 0, name: 'Down' },
{ key: 'Up', value: 1, name: 'Up' },
{ key: 'Suspended', value: 2, name: 'Suspended' }
]
this.titleSearchList.ready = true
})
},
batchModify () {
if (!this.batchDeleteObjs.length) {
@@ -330,7 +336,6 @@ export default {
if (localStorage.getItem('endpointProjectId')) {
this.searchLabel.projectIds = localStorage.getItem('endpointProjectId')
}
this.getTitleSearch()
},
mounted () {
if (localStorage.getItem('endpointProjectId')) {
@@ -344,6 +349,8 @@ export default {
})
this.$refs.dataList.$refs.searchInput.sreach_num = 1
}
this.getTitleSearch()
},
watch: {
$route: {