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 { width: 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="width: 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 { width: 90%; } .filter-group { width: 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; width: 27px; height: 27px; border-radius: 50%; font-size: 12px; color: #2491f7; text-align: center; line-height: 26px; } &.line { top: 0px; height: 100%; width: 2px; background: #ddefff; } } } </style>