阅行客电子档案
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

462 lines
15 KiB

<template>
<el-dialog
:visible.sync="visible"
title="高级检索"
width="1000px"
:close-on-click-modal="false"
:modal-append-to-body="false"
append-to-body
:before-close="handleClose"
>
<div class="advanced-search-modal">
<el-form ref="form" inline :model="form" :rules="rules" size="small" label-width="70px">
<el-form-item label="字段名" prop="field">
<el-select v-model="form.field" value-key="id" style="width: 200px;">
<el-option v-for="item in fieldOptions" :key="item.id" :label="item.label" :value="item" />
</el-select>
</el-form-item>
<el-form-item label="运算符" prop="symbol">
<el-select v-model="form.symbol" value-key="value" placeholder="请选择" style="width: 200px;">
<el-option
v-for="item in symbolOptions"
:key="item.value"
:label="item.label"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item label="检索值" prop="keyWord" :rules="getKeywordRules">
<el-input v-model="form.keyWord" :type="inputType" style="width: 200px;" />
</el-form-item>
</el-form>
<div class="advanced-btn">
<el-button size="mini" @click="addConditionData"><i class="iconfont icon-xinzeng" />新增</el-button>
<el-button class="filter-refresh" size="mini" icon="el-icon-refresh-left" @click="resetQuery">重置</el-button>
</div>
<div class="search-condition">
<h4> 检索条件</h4>
<div class="condition-main">
<div class="condition-left">
<el-button size="mini" :disabled="currentIndex===null" @click="deltCurrent(currentIndex)"><i class="iconfont icon-shanchu" />删除</el-button>
<el-button size="mini" icon="el-icon-top" :disabled="currentIndex === 0" @click="moveUp(currentIndex)">上移</el-button>
<el-button size="mini" icon="el-icon-bottom" :disabled="currentIndex === conditionData.length - 1" @click="moveDown(currentIndex)">下移</el-button>
</div>
<ul id="condition-container-modal" class="condition-content">
<li v-for="(item, index) in conditionData" :id="'modal-element-id-' + index" :key="index" :class="currentIndex===index ? 'active': ''" @click="selectCurrent(index)">
<span style="color:#0348F3">{{ item.field }}</span>
<span style="color:#ED4A41; margin:0 4px">{{ item.symbol }}</span>
<span v-if="item.symbol && (item.symbol === '包含'|| item.symbol === '不包含')" class="keyword-style"><i>'%</i>{{ item.keyWord }}<i>%'</i></span>
<span v-else-if="item.keyWord && isNaN(parseInt(item.keyWord))" class="keyword-style"><i>'</i>{{ item.keyWord }}<i>'</i></span>
<span v-else class="keyword-style">{{ item.keyWord }}</span>
<span>{{ item.connector }}</span>
<span>{{ item.bracket }}</span>
</li>
</ul>
<div class="condition-right">
<el-button v-for="(item,index) in connectorList" :key="index" type="primary" size="mini" @click="addConnector(item)">{{ item }}</el-button>
</div>
</div>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="handleSearch">检索</el-button>
</div>
</el-dialog>
</template>
<script>
import { FetchInitCategoryInputFieldByPid } from '@/api/system/category/category'
export default {
name: 'AdvancedSearchModal',
props: {
visible: {
type: Boolean,
default: false
},
selectedCategory: {
type: Object,
default: () => ({})
},
collectLevel: {
type: Number,
default: 0
},
initialConditions: {
type: Array,
default: () => []
}
},
data() {
return {
form: {
field: null,
symbol: null,
keyWord: null
},
fieldOptions: [],
symbolOptions: [
{
label: '包含',
value: 'like'
},
{
label: '不包含',
value: 'not like'
},
{
label: '等于',
value: '='
},
{
label: '不等于',
value: '!='
},
{
label: '为空',
value: 'is null'
},
{
label: '不为空',
value: 'is not null'
},
{
label: '大于',
value: '>'
},
{
label: '大于等于',
value: '>='
},
{
label: '小于',
value: '<'
},
{
label: '小于等于',
value: '<='
}
],
rules: {
field: [
{ required: true, message: '请选择字段名', trigger: 'change' }
],
symbol: [
{ required: true, message: '请选择运算符', trigger: 'change' }
]
},
conditionData: [],
currentIndex: null,
connectorList: ['并且', '或者', '(', ')']
}
},
computed: {
getKeywordRules() {
if ((this.form.symbol && this.form.symbol.label === '为空') || (this.form.symbol && this.form.symbol.label === '不为空')) {
return []
} else {
return [{ required: true, message: '请输入检索值', trigger: 'blur' }]
}
},
inputType() {
if (
this.form.symbol &&
(this.form.symbol.label === '大于' ||
this.form.symbol.label === '大于等于' ||
this.form.symbol.label === '小于' ||
this.form.symbol.label === '小于等于')
) {
return 'number'
} else {
return 'text'
}
}
},
watch: {
visible(newVal) {
if (!newVal) {
this.resetQuery()
this.conditionData = []
this.currentIndex = null
} else if (this.initialConditions && this.initialConditions.length > 0) {
this.conditionData = JSON.parse(JSON.stringify(this.initialConditions))
}
}
},
mounted() {
this.getFieldCommon()
},
methods: {
resetQuery() {
if (this.$refs.form) {
this.$refs.form.resetFields()
}
},
addConditionData() {
this.$refs.form.validate((valid) => {
if (valid) {
const newConditionData = {}
newConditionData.field = this.form.field.label
newConditionData.fieldName = this.form.field.value
newConditionData.symbol = this.form.symbol.label
newConditionData.symbolCode = this.form.symbol.value
newConditionData.keyWord = this.form.keyWord
this.conditionData.push(newConditionData)
this.$nextTick(() => {
const container = document.getElementById('condition-container-modal')
container.scrollTop = container.scrollHeight
})
}
})
},
moveUp(index) {
if (index > 0) {
const temp = this.conditionData[index]
this.conditionData[index] = this.conditionData[index - 1]
this.conditionData[index - 1] = temp
this.currentIndex = index - 1
}
const targetElement = document.getElementById('modal-element-id-' + this.currentIndex)
if (targetElement) {
targetElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
}
},
moveDown(index) {
if (index < this.conditionData.length - 1) {
const temp = this.conditionData[index]
this.conditionData[index] = this.conditionData[index + 1]
this.conditionData[index + 1] = temp
this.currentIndex = index + 1
}
const targetElement = document.getElementById('modal-element-id-' + this.currentIndex)
if (targetElement) {
targetElement.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
}
},
deltCurrent(index) {
this.conditionData.splice(index, 1)
this.currentIndex = null
},
selectCurrent(index) {
if (this.currentIndex === index) {
this.currentIndex = null
} else {
this.currentIndex = index
}
},
addConnector(item) {
const newConditionData = {}
if (item === '并且' || item === '或者') {
newConditionData.connector = item
} else {
newConditionData.bracket = item
}
this.conditionData.push(newConditionData)
this.$nextTick(() => {
const container = document.getElementById('condition-container-modal')
container.scrollTop = container.scrollHeight
})
},
getFieldCommon() {
const params = {
'categoryId': this.selectedCategory.id,
'categoryLevel': this.collectLevel
}
// console.log('params', params)
FetchInitCategoryInputFieldByPid(params).then((data) => {
if (data && data.length > 0) {
this.fieldOptions = data
.filter(item => item.fieldName !== 'fonds_no' && item.fieldName !== 'fonds_name')
.map(item => {
return {
id: item.id,
label: item.fieldCnName,
value: item.fieldName
}
})
}
})
},
checkConditions(conditionData) {
let brackets = 0
let fields = 0
let connectors = 0
let previousTokenType = null
let hasValidConditionBetweenBrackets = false
for (var i = 0; i < conditionData.length; i++) {
const condition = conditionData[i]
let currentTokenType = ''
if (condition.hasOwnProperty('bracket')) {
currentTokenType = 'bracket'
brackets++
} else if (condition.hasOwnProperty('field')) {
currentTokenType = 'field'
fields++
if (brackets > 0) {
hasValidConditionBetweenBrackets = true
}
} else if (condition.hasOwnProperty('connector')) {
currentTokenType = 'connector'
connectors++
}
if (previousTokenType && currentTokenType) {
if ((previousTokenType === 'field' && currentTokenType === 'field') ||
(previousTokenType === 'connector' && currentTokenType === 'connector')) {
this.$message({ message: '条件之间缺少或且连接符', type: 'error', offset: 8 })
return null
}
}
previousTokenType = currentTokenType
}
if (brackets > 0 && !hasValidConditionBetweenBrackets) {
this.$message({ message: '请输入有效条件', type: 'error', offset: 8 })
return null
} else if (brackets > 0 && brackets % 2 !== 0) {
this.$message({ message: '括号不对称', type: 'error', offset: 8 })
return null
} else if (fields === 0) {
this.$message({ message: '请输入有效条件', type: 'error', offset: 8 })
return null
} else if (fields === 1 || connectors === fields - 1) {
const wheresql = this.conditionData.map(obj => {
if (obj.field) {
if (obj.symbol === '包含' || obj.symbol === '不包含') {
return obj.fieldName + ' ' + obj.symbolCode + " '%" + obj.keyWord + "%'"
} else if (obj.keyWord && isNaN(parseInt(obj.keyWord))) {
return obj.fieldName + ' ' + obj.symbolCode + " '" + obj.keyWord + "'"
} else {
return obj.fieldName + ' ' + obj.symbolCode + ' ' + obj.keyWord
}
} else if (obj.connector === '并且') {
return 'and'
} else if (obj.connector === '或者') {
return 'or'
} else {
return obj.bracket
}
}).join(' ')
return wheresql
} else {
this.$message({ message: '条件之间缺少或且连接符', type: 'error', offset: 8 })
return null
}
},
handleSearch() {
const wheresql = this.checkConditions(this.conditionData)
// console.log('wheresql', wheresql)
if (wheresql) {
const conditions = JSON.parse(JSON.stringify(this.conditionData))
// 保存到 localStorage
localStorage.setItem('advancedSearchConditions', JSON.stringify(conditions))
localStorage.setItem('advancedSearchSql', wheresql)
// 发送 SQL 条件和原始条件数据(用于显示文案)
this.$emit('search', {
sql: wheresql,
conditions: conditions
})
}
},
handleClose() {
this.$emit('update:visible', false)
}
}
}
</script>
<style lang='scss' scoped>
.advanced-search-modal {
.el-form--inline .el-form-item {
margin-right: 20px !important;
}
.advanced-btn {
display: flex;
justify-content: center;
margin-top: 15px;
.el-button {
margin-right: 10px;
}
}
.search-condition {
padding: 18px;
margin-top: 20px;
background: #F6F9FF;
border-radius: 3px;
border: 1px dashed #DCDFE6;
h4 {
margin: 0 0 17px 0;
padding-left: 25px;
color: #0C0E1E;
font-size: 14px;
font-weight: bold;
}
}
.condition-main {
display: flex;
justify-content: center;
flex-wrap: nowrap;
.condition-left {
display: flex;
flex-direction: column;
justify-content: center;
.el-button {
width: 76px;
margin: 5px 0;
::v-deep i.el-icon-top,
::v-deep i.el-icon-bottom {
font-size: 16px;
font-weight: bold;
}
}
}
.condition-content {
width: 500px;
height: 160px;
margin: 0 10px;
padding: 0;
background: #E6E8ED;
overflow: hidden;
overflow-y: scroll;
li {
display: flex;
justify-content: center;
flex-wrap: nowrap;
height: 32px;
line-height: 32px;
font-size: 14px;
text-align: center;
background-color: #fff;
border-bottom: 1px solid #E6E8ED;
cursor: default;
&:hover,
&:focus,
&.active {
background-color: #E8F2FF;
}
.keyword-style {
color: #2ECAAC;
i {
font-style: normal;
color: #545B65;
}
}
}
}
.condition-right {
display: flex;
flex-direction: column;
justify-content: center;
.el-button {
width: 64px;
margin: 5px 0;
background-color: #0348F3;
color: #fff;
}
}
}
}
</style>