|
|
<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>
|