jeecg-boot/ant-design-vue-jeecg/src/components/jeecg/JSuperQuery.vue

473 lines
15 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="j-super-query-box">
<div @click="visible=true">
<slot>
<a-tooltip v-if="superQueryFlag" :mouseLeaveDelay="0.2">
<template slot="title">
<span></span>
<a-divider type="vertical"/>
<a @click="handleReset"></a>
</template>
<a-button type="primary">
<a-icon type="appstore" theme="twoTone" :spin="true"></a-icon>
<span></span>
</a-button>
</a-tooltip>
<a-button v-else type="primary" icon="filter" @click="visible=true"></a-button>
</slot>
</div>
<a-modal
title="高级查询构造器"
:width="1000"
:visible="visible"
@cancel="handleCancel"
:mask="false"
class="j-super-query-modal"
style="top:5%;max-height: 95%;">
<template slot="footer">
<div style="float: left">
<a-button :loading="loading" @click="handleReset"></a-button>
<a-button :loading="loading" @click="handleSave"></a-button>
</div>
<a-button :loading="loading" @click="handleCancel"></a-button>
<a-button :loading="loading" type="primary" @click="handleOk"></a-button>
</template>
<a-spin :spinning="loading">
<a-row>
<a-col :sm="24" :md="24-5">
<a-empty v-if="queryParamsModel.length === 0">
<div slot="description">
<span></span>
<a-divider type="vertical"/>
<a @click="handleAdd"></a>
</div>
</a-empty>
<a-form v-else layout="inline">
<a-form-item label="过滤条件匹配" style="margin-bottom: 12px;">
<a-select v-model="selectValue" :getPopupContainer="node=>node.parentNode">
<a-select-option value="and">AND</a-select-option>
<a-select-option value="or">OR</a-select-option>
</a-select>
</a-form-item>
<a-row type="flex" style="margin-bottom:10px" :gutter="16" v-for="(item, index) in queryParamsModel" :key="index">
<a-col :span="8">
<a-tree-select
showSearch
v-model="item.field"
:treeData="fieldTreeData"
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="选择查询字段"
allowClear
treeDefaultExpandAll
:getPopupContainer="node=>node.parentNode"
style="width: 100%"
@select="(val,option)=>handleSelected(option,item)"
>
</a-tree-select>
</a-col>
<a-col :span="4">
<a-select placeholder="匹配规则" v-model="item.rule" :getPopupContainer="node=>node.parentNode">
<a-select-option value="eq"></a-select-option>
<a-select-option value="ne"></a-select-option>
<a-select-option value="gt"></a-select-option>
<a-select-option value="ge"></a-select-option>
<a-select-option value="lt"></a-select-option>
<a-select-option value="le"></a-select-option>
<a-select-option value="right_like">..</a-select-option>
<a-select-option value="left_like">..</a-select-option>
<a-select-option value="like"></a-select-option>
<a-select-option value="in">...</a-select-option>
</a-select>
</a-col>
<a-col :span="8">
<template v-if="item.dictCode">
<template v-if="item.type === 'table-dict'">
<j-popup
v-model="item.val"
:code="item.dictTable"
:field="item.dictCode"
:orgFields="item.dictCode"
:destFields="item.dictCode"
></j-popup>
</template>
<j-dict-select-tag v-else v-model="item.val" :dictCode="item.dictCode" placeholder="请选择"/>
</template>
<j-select-multi-user
v-else-if="item.type === 'select-user'"
v-model="item.val"
:buttons="false"
:multiple="false"
placeholder="请选择用户"
:returnKeys="['id', item.customReturnField || 'username']"
/>
<j-select-depart
v-else-if="item.type === 'select-depart'"
v-model="item.val"
:multi="false"
placeholder="请选择部门"
:customReturnField="item.customReturnField || 'id'"
/>
<a-select v-else-if="item.options instanceof Array" v-model="item.val" :options="item.options" allowClear placeholder="请选择"/>
<j-date v-else-if=" item.type=='date' " v-model="item.val" placeholder="请选择日期" style="width: 100%"></j-date>
<j-date v-else-if=" item.type=='datetime' " v-model="item.val" placeholder="请选择时间" :show-time="true" date-format="YYYY-MM-DD HH:mm:ss" style="width: 100%"></j-date>
<a-input-number v-else-if=" item.type=='int'||item.type=='number' " style="width: 100%" placeholder="请输入数值" v-model="item.val"/>
<a-input v-else v-model="item.val" placeholder="请输入值"/>
</a-col>
<a-col :span="4">
<a-button @click="handleAdd" icon="plus"></a-button>&nbsp;
<a-button @click="handleDel( index )" icon="minus"></a-button>
</a-col>
</a-row>
</a-form>
</a-col>
<a-col :sm="24" :md="5">
<!-- -->
<a-card class="j-super-query-history-card" :bordered="true">
<div slot="title">
</div>
<a-empty v-if="treeData.length === 0" class="j-super-query-history-empty" description="没有保存任何查询"/>
<a-tree
v-else
class="j-super-query-history-tree"
showIcon
:treeData="treeData"
@select="handleTreeSelect"
@rightClick="handleTreeRightClick"
>
</a-tree>
</a-card>
</a-col>
</a-row>
</a-spin>
<a-modal title="请输入保存的名称" :visible="prompt.visible" @cancel="prompt.visible=false" @ok="handlePromptOk">
<a-input v-model="prompt.value"></a-input>
</a-modal>
</a-modal>
</div>
</template>
<script>
import * as utils from '@/utils/util'
import JDate from '@/components/jeecg/JDate.vue'
import JSelectDepart from '@/components/jeecgbiz/JSelectDepart'
import JSelectMultiUser from '@/components/jeecgbiz/JSelectMultiUser'
export default {
name: 'JSuperQuery',
components: { JDate, JSelectDepart, JSelectMultiUser },
props: {
/*
fieldList: [{
value:'',
text:'',
type:'',
dictCode:'' // 只要 dictCode 有值,无论 type 是什么,都显示为字典下拉框
}]
type:date datetime int number string
* */
fieldList: {
type: Array,
required: true
},
/*
* 这个回调函数接收一个数组参数 即查询条件
* */
callback: {
type: String,
required: false,
default: 'handleSuperQuery'
},
// 当前是否在加载中
loading: {
type: Boolean,
default: false
},
// 保存查询条件的唯一 code通过该 code 区分
saveCode: {
type: String,
default: 'testSaveCode'
}
},
data() {
return {
fieldTreeData: [],
prompt: {
visible: false,
value: ''
},
visible: false,
queryParamsModel: [{}],
treeIcon: <a-icon type="file-text"/>,
treeData: [],
// 保存查询条件的前缀名
saveCodeBefore: 'JSuperQuerySaved_',
selectValue: 'and',
superQueryFlag: false
}
},
watch: {
// 当 saveCode 变化时,重新查询已保存的条件
saveCode: {
immediate: true,
handler(val) {
let list = this.$ls.get(this.saveCodeBefore + val)
if (list instanceof Array) {
this.treeData = list.map(item => {
item.icon = this.treeIcon
return item
})
}
}
},
fieldList: {
deep: true,
immediate: true,
handler(val) {
let mainData = [], subData = []
val.forEach(item => {
let data = { ...item }
data.label = data.label || data.text
let hasChildren = (data.children instanceof Array)
data.disabled = hasChildren
data.selectable = !hasChildren
if (hasChildren) {
data.children = data.children.map(item2 => {
let child = { ...item2 }
child.label = child.label || child.text
child.label = data.label + '-' + child.label
child.value = data.value + ',' + child.value
child.val = ''
return child
})
data.val = ''
subData.push(data)
} else {
mainData.push(data)
}
})
this.fieldTreeData = mainData.concat(subData)
}
}
},
methods: {
show() {
if (!this.queryParamsModel || this.queryParamsModel.length == 0) {
this.queryParamsModel = [{}]
}
this.visible = true
},
handleOk() {
if (!this.isNullArray(this.queryParamsModel)) {
let event = {
matchType: this.selectValue,
params: this.removeEmptyObject(utils.cloneObject(this.queryParamsModel))
}
console.log('------>', event)
this.emitCallback(event.params, event.matchType)
} else {
this.emitCallback()
}
},
emitCallback(params, matchType) {
this.superQueryFlag = !!params
this.$emit(this.callback, params, matchType)
},
handleCancel() {
this.close()
},
close() {
this.$emit('close')
this.visible = false
},
handleAdd() {
this.queryParamsModel.push({})
},
handleDel(index) {
this.queryParamsModel.splice(index, 1)
},
handleSelected(node, item) {
let { type, options, dictCode, dictTable, customReturnField } = node.dataRef
item['type'] = type
item['options'] = options
item['dictCode'] = dictCode
item['dictTable'] = dictTable
item['customReturnField'] = customReturnField
this.$set(item, 'val', undefined)
},
handleReset() {
this.superQueryFlag = false
this.queryParamsModel = [{}]
this.emitCallback()
},
handleSave() {
let queryParams = this.removeEmptyObject(utils.cloneObject(this.queryParamsModel))
if (this.isNullArray(queryParams)) {
this.$message.warning('')
} else {
this.prompt.value = ''
this.prompt.visible = true
}
},
handlePromptOk() {
let { value } = this.prompt
// 判断有没有重名
let filterList = this.treeData.filter(i => i.title === value)
if (filterList.length > 0) {
this.$confirm({
content: `${value} `,
onOk: () => {
this.prompt.visible = false
filterList[0].records = this.removeEmptyObject(utils.cloneObject(this.queryParamsModel))
this.saveToLocalStore()
this.$message.success('')
}
})
} else {
this.prompt.visible = false
this.treeData.push({
title: value,
icon: this.treeIcon,
records: this.removeEmptyObject(utils.cloneObject(this.queryParamsModel))
})
this.saveToLocalStore()
this.$message.success('')
}
},
handleTreeSelect(idx, event) {
if (event.selectedNodes[0]) {
this.queryParamsModel = utils.cloneObject(event.selectedNodes[0].data.props.records)
}
},
handleTreeRightClick(args) {
this.$confirm({
content: '',
onOk: () => {
let { node: { eventKey } } = args
this.treeData.splice(Number.parseInt(eventKey.substring(2)), 1)
this.saveToLocalStore()
this.$message.success('')
},
})
},
// 将查询保存到 LocalStore 里
saveToLocalStore() {
this.$ls.set(this.saveCodeBefore + this.saveCode, this.treeData.map(item => {
return { title: item.title, records: item.records }
}))
},
isNullArray(array) {
//判断是不是空数组对象
if (!array || array.length === 0) {
return true
}
if (array.length === 1) {
let obj = array[0]
if (!obj.field || (obj.val == null || obj.val === '') || !obj.rule) {
return true
}
}
return false
},
// 去掉数组中的空对象
removeEmptyObject(array) {
for (let i = 0; i < array.length; i++) {
let item = array[i]
if (item == null || Object.keys(item).length <= 0) {
array.splice(i--, 1)
} else {
// 去掉特殊属性
delete item.options
}
}
return array
}
}
}
</script>
<style lang="scss" scoped>
.j-super-query-box {
display: inline-block;
}
.j-super-query-modal {
.j-super-query-history-card /deep/ {
.ant-card-body,
.ant-card-head-title {
padding: 0;
}
.ant-card-head {
padding: 4px 8px;
min-height: initial;
}
}
.j-super-query-history-empty /deep/ {
.ant-empty-image {
height: 80px;
line-height: 80px;
margin-bottom: 0;
}
img {
width: 80px;
height: 65px;
}
.ant-empty-description {
color: #afafaf;
margin: 8px 0;
}
}
.j-super-query-history-tree /deep/ {
.ant-tree-switcher {
display: none;
}
.ant-tree-node-content-wrapper {
width: 100%;
}
}
}
</style>