dataFilters.vue
<template>
<div class="filter">
<div class="groupAdd" @click="addCondition">
<a-icon type="plus-circle" theme="twoTone" two-tone-color="#52c41a" />
<span>数据过滤</span>
</div>
<div class="list" :style="{ maxHeight: height + 'px' }">
<data-filter-group
:key="filter.key"
:filter="filter"
:deep="1"
:columns="columns"
@modifyed="filter.key = new Date().getTime()"
/>
</div>
</div>
</template>
<script>
import DataFilterGroup from './DataFilterGroup'
export default {
name: 'dataFilters',
components: {
DataFilterGroup,
},
props: {
//下拉框中的数据
columns: {
type: Array | Object,
default: () => {},
required: false,
},
height: {
type: Number,
default: 200,
},
filter: {
type: Object | Array,
default: () => {
return {
label: '且',
operate: 'and',
conditions: [],
key: "key1",
}
},
required: false,
},
},
data() {
return {
defaultFilter: { column: null, operate: null, value: null, function: null, key: null },
}
},
watch: {
filter(val) {
if (typeof val === 'undefined' || Object.keys(val).length == 0) {
this.filter={
label: '且',
operate: 'and',
conditions: [],
key: 1,
}
}else{
this.filter=val
}
},
},
computed: {},
mounted() {},
methods: {
addCondition() {
let obj = JSON.parse(JSON.stringify(this.defaultFilter))
obj.key = new Date().getTime()
this.filter.conditions.push(obj)
this.filter.key = new Date().getTime()
},
},
}
</script>
<style lang='less' scoped>
.groupAdd {
line-height: 20px;
padding: 10px;
cursor: pointer;
display: inline-block;
& i {
font-size: 20px;
vertical-align: middle;
}
& span {
padding: 0px 10px;
user-select: none;
}
}
.list {
overflow-y: auto;
&::-webkit-scrollbar {
8px;
height: 8px;
background-color: #f5f5f5 !important;
}
&::-webkit-scrollbar-track {
background: #f6f6f6 !important;
border-radius: 2px;
}
&::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background-color: #6f6f6f !important;
/*background: #cd4426;*/
/*border-radius:2px;*/
}
&::-webkit-scrollbar-thumb:hover {
background: #747474;
}
&::-webkit-scrollbar-corner {
background: #f6f6f6;
}
}
</style>
DataFilterGroup.vue
<template>
<div class="filter-group">
<div v-for="(item, index) in filter.conditions" :key="index">
<data-filter-group
v-if="item.conditions instanceof Array"
:filter="item"
:columns="columns"
:deep="2"
@upSub="upSubFilter"
@modifyed="$emit('modifyed', filter)"
></data-filter-group>
<a-row class="filter-component" :gutter="15" v-else>
<a-col :span="7" v-if="columns instanceof Array">
<a-select v-model="item.column">
<a-select-option v-for="(option, index) in columns" :key="index" :value="option.id"
>{{ option.columnCode }} / {{ option.columnName }}</a-select-option
>
</a-select>
</a-col>
<a-col :span="7" v-else>
<a-tree-select
tree-node-filter-prop="title"
v-model="item.column"
show-search
style=" 100%"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择"
allow-clear
tree-default-expand-all
>
<a-tree-select-node
v-for="(value, key) in columns"
:key="key"
:selectable="false"
:value="key"
:title="key"
>
<a-tree-select-node
v-for="(option, index) in value"
:key="index"
:value="key.split('(')[1].replace(')', '') + '.' + option.id"
:title="option.columnCode + '/' + option.columnName"
/>
</a-tree-select-node>
</a-tree-select>
</a-col>
<a-col :span="7">
<a-select v-model="item.operate" placeholder="请选择过滤条件">
<a-select-option v-for="(item, index) in filterTypes" :key="index" :value="item.value">{{
item.text
}}</a-select-option>
</a-select>
</a-col>
<a-col :span="7">
<a-input v-model="item.value" placeholder="请输入值" />
</a-col>
<a-col :span="3" class="filter-buttons">
<a-space>
<a-icon class="filter-option delete" type="minus-circle-o" @click="removeCondition(item, index)" />
<a-icon class="filter-option add" type="plus-circle" @click="addCondition(item, index)" />
</a-space>
</a-col>
</a-row>
</div>
<div
class="relation line"
v-if="filter.conditions && filter.conditions instanceof Array && filter.conditions.length > 1"
></div>
<span
class="relation button"
@click="switchClick(filter)"
v-if="filter.conditions && filter.conditions instanceof Array && filter.conditions.length > 1"
>{{ filter.label }}</span
>
</div>
</template>
<script>
import { initDictOptions, filterDictText } from '@/components/dict/JDictSelectUtil'
export default {
name: 'DataFilterGroup',
components: {},
props: {
columns: {
type: Array | Object,
default: () => [],
required: true,
},
deep: {
type: Number,
require: true,
default: 1,
},
filter: {
require: true,
type: Array | Object,
},
},
data () {
return {
filterGroup: {
label: '且',
key: null,
operate: 'and',
conditions: [{ column: null, operate: null, value: null, function: null, key: null }],
},
filterTypes: [],
subFilter: { column: null, operate: null, value: null, function: null, key: null },
}
},
computed: {},
mounted () {
this.initDictConfig()
},
methods: {
generateKey () {
return new Date().getTime()
},
addCondition (item, index) {
// 一级的增加按钮,点击后将当前降级成子级,并添加一条新过滤条件
if (this.deep == 1) {
let group = Object.assign({ key: this.generateKey() }, this.filterGroup)
group.conditions.splice(0, 0, JSON.parse(JSON.stringify(item)))
this.filter.conditions[index] = group
} else {
let subfilter = JSON.parse(JSON.stringify(this.subFilter))
subfilter.key = this.generateKey()
this.filter.conditions.push(subfilter)
this.filter.key = this.generateKey()
}
this.$emit('modifyed', this.filter)
},
removeCondition (item, index) {
console.log('removeCondition', this.deep, this.filter)
// 第一级时,直接减
if (this.deep == 1) {
this.filter.conditions.splice(index, 1)
} else {
// 第二级时,判断减完后是不是只剩一个,只剩一个时,将子级提升到一级,
this.filter.conditions.splice(index, 1)
if (this.filter.conditions.length == 1) {
//由于组件自我递归调用,子级无法修改当前对象,需向上冒泡给父级,进行调整。
this.$emit('upSub', this.filter, index)
}
}
this.$emit('modifyed', this.filter)
},
//接收子级冒泡,将孙级变为子级
upSubFilter (subFilter, index) {
for (let i = 0; i < this.filter.conditions.length; i++) {
if (this.filter.conditions[i].key == subFilter.key) {
let obj = JSON.parse(JSON.stringify(subFilter.conditions[0]))
this.filter.conditions[i] = obj
}
}
console.log('upSubFilter', this.deep, this.filter)
},
switchClick (val) {
if (val.label === '或') {
val.label = '且'
val.operate = 'and'
} else {
val.label = '或'
val.operate = 'or'
}
this.$emit('modifyed', this.filter)
},
},
}
</script>
<style lang='less' scoped>
.filter-component {
90%;
}
.filter-group {
96%;
position: relative;
padding-left: 30px;
margin-bottom: 20px;
& .filter-option {
font-size: 20px;
cursor: pointer;
display: inline-block;
&.add {
color: #1890ff;
}
&.delete {
color: rgb(226, 189, 119);
transition: all 0.3s;
&:hover {
color: rgb(243, 12, 12);
}
}
}
& .relation {
position: absolute;
left: 15px;
user-select: none;
&.button {
cursor: pointer;
top: 50%;
top: 50%;
margin-top: -13px;
margin-left: -13px;
position: absolute;
background: #ddefff;
27px;
height: 27px;
border-radius: 50%;
font-size: 12px;
color: #2491f7;
text-align: center;
line-height: 26px;
}
&.line {
top: 0px;
height: 100%;
2px;
background: #ddefff;
}
}
}
</style>