375 lines
15 KiB
JavaScript
375 lines
15 KiB
JavaScript
// 核心库
|
||
import React, { Component } from 'react'
|
||
import { connect } from 'dva'
|
||
// 组件库
|
||
import { Form, Button } from 'antd'
|
||
import IFComponent from '../common/IFComponent'
|
||
import UserCustomSearchEditModel from './UserCustomSearchEditModel'
|
||
// 工具库
|
||
import { isEqual } from 'lodash'
|
||
import {
|
||
getDataFieldValue,
|
||
setDataFieldValue
|
||
} from '../utils/common'
|
||
import storage from '../utils/storage'
|
||
import getControl from '../utils/getControl'
|
||
import { getFieldConfigs, getRuleByFieldConfigs } from '../utils/getFieldConfigs'
|
||
|
||
class AdvanceSearch extends Component {
|
||
constructor (props) {
|
||
super(props)
|
||
this.state = {
|
||
data: {},
|
||
fieldConfigs: [],
|
||
isShowContent: false // 展开收起
|
||
}
|
||
// 搜索条件共享与记忆
|
||
const { filterItem = {}, filterList = [], maxShowContentNum = 4 } = props
|
||
const { ID, SHARE_KEY, IS_REMEMBER } = filterItem
|
||
this.insRef = ID // 当前 Search 组件的唯一标识
|
||
this.insRefs = filterList.map(item => item.ID) // 同 filterList 组里面所有的 AdvanceSearch 组件标识
|
||
this.shareKey = SHARE_KEY // 共享数据标识
|
||
this.isRemember = IS_REMEMBER // 是否记忆搜索条件
|
||
// 展开收起阈值
|
||
this.maxShowContentNum = maxShowContentNum
|
||
}
|
||
|
||
componentDidMount () {
|
||
const { preventDefaultSearch, onRef, fields, presetValue } = this.props
|
||
// 只在初次加载时,提取本地存储的共享查询条件作为预设值
|
||
this.setFieldConfigs({ fields, presetValue: this.checkPresetValue(presetValue) }, () => {
|
||
!preventDefaultSearch && this.handleSearch()
|
||
})
|
||
onRef instanceof Function && onRef(this)
|
||
}
|
||
|
||
UNSAFE_componentWillReceiveProps (nextProps) {
|
||
if (!isEqual(nextProps.fields, this.props.fields) || !isEqual(nextProps.presetValue, this.props.presetValue)) {
|
||
const { fields, presetValue } = nextProps
|
||
this.setFieldConfigs({ fields, presetValue }, this.handleSearch)
|
||
}
|
||
}
|
||
|
||
componentWillUnmount () {
|
||
// 组件销毁时清空当前共享实例
|
||
if (this.shareKey) {
|
||
this.props.dispatch({
|
||
type: 'search/cleanShareIns',
|
||
payload: {
|
||
key: this.shareKey,
|
||
insRef: this.insRef
|
||
}
|
||
})
|
||
}
|
||
// 如果不记住查询条件,则组件销毁时,清空共享数据
|
||
if (this.shareKey && !this.isRemember) {
|
||
this.props.dispatch({
|
||
type: 'search/setShareData',
|
||
payload: {
|
||
key: this.shareKey,
|
||
data: []
|
||
}
|
||
})
|
||
storage('session').removeItem(this.shareKey)
|
||
}
|
||
}
|
||
|
||
// 相同 formCode 的搜索组件共享搜索条件
|
||
setShareIns = (self = true) => {
|
||
const { search, dispatch } = this.props
|
||
let stopSelfChangeSearch = false
|
||
let stopSelfExtraSearch = false
|
||
console.log('共享搜索条件', this.shareKey)
|
||
if (this.shareKey) {
|
||
const instances = search.shareIns[this.shareKey] || []
|
||
// 同一 filterList 组里面的 Search 组件不共享搜索条件
|
||
const targetIns = instances.filter(ins => ins.insRef !== this.insRef && this.insRefs.indexOf(ins.insRef) === -1)
|
||
if (targetIns.length) {
|
||
// 设置自身状态
|
||
if (self) {
|
||
// 配置的查询条件
|
||
const { instance } = targetIns[0]
|
||
const { fieldConfigs: insFieldConfigs = [], data: insData = {} } = instance.state || {}
|
||
const { fieldConfigs: thisFieldConfigs = [], data: thisData = {} } = this.state
|
||
thisFieldConfigs.forEach(item => {
|
||
// 拥有相同的编码 code 或者 field 字段,就表示查询项需要共享查询条件
|
||
const find = insFieldConfigs.find(ifc => (item.code && ifc.code === item.code) || ifc.field === item.field)
|
||
// 默认显示的查询条件才允许共享查询
|
||
if (find && item.isDefaultQuery) {
|
||
const setValue = getDataFieldValue(insData, find.id)
|
||
if (Object.keys(insData).length) {
|
||
item.value !== setValue && (stopSelfChangeSearch = true)
|
||
item.value = setValue
|
||
thisData[item.id] = setValue
|
||
}
|
||
}
|
||
})
|
||
// 自定义添加的额外查询条件
|
||
const { getExtraData: insGetExtraData } = instance.props || {}
|
||
const { setExtraData: thisSetExtraData, getExtraData: thisGetExtraData } = this.props
|
||
if (insGetExtraData instanceof Function && thisSetExtraData instanceof Function && thisGetExtraData instanceof Function) {
|
||
const insExtraData = insGetExtraData()
|
||
const thisExtraData = thisGetExtraData()
|
||
stopSelfExtraSearch = !isEqual(insExtraData, thisExtraData)
|
||
}
|
||
// 先判断额外搜索条件,额外搜索成立,则调用thisSetExtraData,并在回调中继续调用搜索
|
||
if (stopSelfExtraSearch) {
|
||
thisSetExtraData(insGetExtraData(), this.handleSearch)
|
||
} else if (stopSelfChangeSearch) {
|
||
// fieldConfigs 搜索成立,则调用 setState(因为之前在配置的查询条件中是直接更改 state 的),回调中继续调用搜索
|
||
this.setState({ ...this.state }, this.handleSearch)
|
||
}
|
||
} else {
|
||
// 设置其他关联的Search组件状态
|
||
let stopChangeSearch = false
|
||
let stopExtraSearch = false
|
||
targetIns.forEach(({ instance }) => {
|
||
// 配置的查询条件
|
||
const { fieldConfigs: insFieldConfigs = [], data: insData = {} } = instance.state || {}
|
||
const { fieldConfigs: thisFieldConfigs = [], data: thisData = {} } = this.state
|
||
insFieldConfigs.forEach(item => {
|
||
// 拥有相同的编码 code 或者 field 字段,就表示查询项需要共享查询条件
|
||
const find = thisFieldConfigs.find(tfc => (item.code && tfc.code === item.code) || tfc.field === item.field)
|
||
// 默认显示的查询条件才允许共享查询
|
||
if (find && item.isDefaultQuery) {
|
||
const setValue = getDataFieldValue(thisData, find.id)
|
||
if (Object.keys(thisData).length) {
|
||
item.value !== setValue && (stopChangeSearch = true)
|
||
item.value = setValue
|
||
insData[item.id] = setValue
|
||
}
|
||
}
|
||
})
|
||
// 自定义添加的额外查询条件
|
||
const { setExtraData: insSetExtraData, getExtraData: insGetExtraData } = instance.props || {}
|
||
const { getExtraData: thisGetExtraData } = this.props
|
||
if (thisGetExtraData instanceof Function && insSetExtraData instanceof Function && insGetExtraData instanceof Function) {
|
||
const thisExtraData = thisGetExtraData()
|
||
const insExtraData = insGetExtraData()
|
||
stopExtraSearch = !isEqual(thisExtraData, insExtraData)
|
||
}
|
||
// 先判断额外搜索条件,额外搜索成立,则调用thisSetExtraData,并在回调中继续调用搜索
|
||
if (stopExtraSearch) {
|
||
insSetExtraData(thisGetExtraData(), instance.handleSearch)
|
||
} else if (stopChangeSearch) {
|
||
// fieldConfigs 搜索成立,则调用 setState(因为之前在配置的查询条件中是直接更改 state 的),回调中继续调用搜索
|
||
instance.setState({ ...instance.state }, instance.handleSearch)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// 存储当前 Search 组件实例
|
||
dispatch({
|
||
type: 'search/setShareIns',
|
||
payload: {
|
||
key: this.shareKey,
|
||
insRef: this.insRef,
|
||
instance: this
|
||
}
|
||
})
|
||
// 存储当前 shareKey 的查询数据
|
||
dispatch({
|
||
type: 'search/setShareData',
|
||
payload: {
|
||
key: this.shareKey,
|
||
data: this.state.fieldConfigs
|
||
}
|
||
})
|
||
storage('session').setItem(this.shareKey, this.state.fieldConfigs)
|
||
}
|
||
return stopSelfChangeSearch || stopSelfExtraSearch
|
||
}
|
||
|
||
// 提取本地存储的共享查询条件作为预设值
|
||
checkPresetValue = (presetValue) => {
|
||
const { search } = this.props
|
||
const presetFieldConfigs = search.shareData[this.shareKey] || storage('session').getItem(this.shareKey).val
|
||
const localPreset = {}
|
||
if (Array.isArray(presetFieldConfigs)) {
|
||
presetFieldConfigs.forEach(({ code, field, value }) => {
|
||
// 编码 code 作为查询项共享查询条件的附加标识,因为有些查询项的 field 不一样,但又需要共享查询条件,所以额外配置 code 编码,
|
||
// 当多个查询项拥有相同的编码 code 时,视为这些查询项需要共享查询条件
|
||
code && (localPreset[code] = value)
|
||
field && (localPreset[field] = value)
|
||
})
|
||
}
|
||
return Object.assign(localPreset, presetValue)
|
||
}
|
||
|
||
// 处理父组件传下来的 fields
|
||
setFieldConfigs = ({ fields, presetValue }, callback) => {
|
||
const fieldConfigs = []
|
||
if (fields && fields.length) {
|
||
fields.sort((x, y) => x.NUM - y.NUM)
|
||
fields.forEach(item => {
|
||
if (!item.USER_C_C_QUERY_GROUP_ID) {
|
||
const config = getFieldConfigs({
|
||
field: item,
|
||
onLoadData: this.onLoadData,
|
||
onPressEnter: this.onPressEnter,
|
||
onSelect: this.onDropDownPaginationSelect,
|
||
onChange: this.onChange,
|
||
onSearchRef: this.handleSearch
|
||
})
|
||
fieldConfigs.push(config)
|
||
}
|
||
})
|
||
}
|
||
// 赋值 data { field: value }
|
||
const data = {}
|
||
fieldConfigs.forEach(item => {
|
||
if (presetValue !== undefined && typeof presetValue === 'object' && Object.keys(presetValue).length) {
|
||
// 拥有相同编码 code 的查询项共享查询条件
|
||
if (Object.prototype.hasOwnProperty.call(presetValue, item.code)) {
|
||
data[item.id] = presetValue[item.code]
|
||
return
|
||
}
|
||
if (Object.prototype.hasOwnProperty.call(presetValue, item.field)) {
|
||
data[item.id] = presetValue[item.field]
|
||
return
|
||
}
|
||
}
|
||
if (item.defaultValue !== undefined) {
|
||
data[item.id] = item.defaultValue
|
||
}
|
||
})
|
||
|
||
this.saveFieldConfigs(fieldConfigs)
|
||
this.setState({
|
||
data,
|
||
fieldConfigs
|
||
}, callback)
|
||
}
|
||
|
||
// field change 时候赋值给 data
|
||
onChange = (params) => {
|
||
const { value, colConfig } = params
|
||
const data = { ...this.state.data }
|
||
setDataFieldValue(data, colConfig.id, value)
|
||
this.setState({ data })
|
||
}
|
||
|
||
// 提供给分页下拉 下拉树选择 级联组件调用(详见 getControl.js),以获取上述组件的树数据,用于导出 table 时,获取到查询数据,并生成导出标题
|
||
onLoadData = (id, data) => {
|
||
const targetFieldConfig = this.state.fieldConfigs.find(item => item.id === id)
|
||
if (targetFieldConfig) {
|
||
targetFieldConfig.dataSource = data
|
||
this.saveFieldConfigs(this.state.fieldConfigs)
|
||
}
|
||
}
|
||
|
||
// 将对应 formCode 的 fieldConfigs 存到 store 中,用于导出 table 时获取到查询数据,并生成导出标题
|
||
saveFieldConfigs = (fieldConfigs) => {
|
||
const { formCode, dispatch } = this.props
|
||
if (formCode) {
|
||
dispatch({
|
||
type: 'search/setFieldConfigs',
|
||
payload: {
|
||
key: formCode,
|
||
data: fieldConfigs
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// 回车搜索
|
||
onPressEnter = ({ e: evt }) => {
|
||
evt.stopPropagation()
|
||
this.handleSearch(false)
|
||
}
|
||
|
||
// 提供给分页下拉的回调
|
||
onDropDownPaginationSelect = (params) => {
|
||
const { record, complete, colConfig } = params || {}
|
||
const data = { ...this.state.data }
|
||
setDataFieldValue(data, colConfig.id, record ? record.ID : null)
|
||
setDataFieldValue(data, `selectedRecord.${colConfig.id}`, record)
|
||
|
||
this.setState({ data }, () => complete instanceof Function && complete())
|
||
}
|
||
|
||
/**
|
||
* 执行搜索,搜索流程为:
|
||
* 调用 Search 组件 onSearch 方法,
|
||
* 然后 Search 分别通过 ref 分别调用 AdvanceSearch 和 SearchGroupField 的 getSearchParams 方法获取到搜索参数,
|
||
* 最后再由 Search 组件完成搜索操作,这样搜索就统一在 Search 中做了
|
||
* @param {*} self 设置自身状态还是设置共享状态
|
||
*/
|
||
handleSearch = (self = true) => {
|
||
if (this.setShareIns(self)) return
|
||
console.log('调用查询开始', 1)
|
||
const { onSearch } = this.props
|
||
onSearch instanceof Function && onSearch()
|
||
}
|
||
|
||
// 获取搜索参数 提供给 ref 调用
|
||
getSearchParams = (rules = [], groups = []) => {
|
||
return getRuleByFieldConfigs(this.state.data, this.state.fieldConfigs, rules, groups,this.props.user)
|
||
}
|
||
|
||
render () {
|
||
const { fieldConfigs = [], data, isShowContent } = this.state
|
||
const { formCode, formId, code, iconEle, extraInsertPlace, extraSearch = [], onEditModalClose, onAddGroupConfig } = this.props
|
||
let extraFieldConfigs = extraInsertPlace === 'after' ? fieldConfigs.concat(extraSearch.map(extra => ({ extraSearch: true, extra }))) : extraSearch.map(extra => ({ extraSearch: true, extra })).concat(fieldConfigs)
|
||
extraFieldConfigs = extraFieldConfigs.filter(item => item.isDefaultQuery || item.extraSearch)
|
||
let showFieldConfigs = extraFieldConfigs
|
||
if (showFieldConfigs.length > this.maxShowContentNum - 1) {
|
||
showFieldConfigs = isShowContent ? extraFieldConfigs : extraFieldConfigs.slice(0, this.maxShowContentNum - 1)
|
||
}
|
||
return (
|
||
<Form hideRequiredMark className='opt-search__form'>
|
||
{
|
||
showFieldConfigs.map(item => {
|
||
if (item.extraSearch) return item.extra
|
||
item.value = getDataFieldValue(data, item.id)
|
||
return (
|
||
<Form.Item
|
||
key={item.id}
|
||
label={<>{item.isRequire ? <span style={{ color: 'red' }}>*</span> : null}{item.label}</>}
|
||
>
|
||
{getControl(item, null, this)}
|
||
</Form.Item>
|
||
)
|
||
})
|
||
}
|
||
<div className='opt-search__btns-zone'>
|
||
<IFComponent IF={showFieldConfigs.length}>
|
||
<Button type='primary' onClick={() => this.handleSearch(false)}>查询</Button>
|
||
</IFComponent>
|
||
<div className='opt-search__tool-wrap'>
|
||
<div className='opt-search__children'>{iconEle}</div>
|
||
<Button.Group>
|
||
<UserCustomSearchEditModel
|
||
formCode={formCode}
|
||
formId={formId}
|
||
code={code}
|
||
close={onEditModalClose}
|
||
>
|
||
<Button icon='edit' title='添加自定义查询' size='small' />
|
||
</UserCustomSearchEditModel>
|
||
<Button icon='reload' size='small' title='刷新' onClick={() => this.handleSearch(false)} />
|
||
<Button
|
||
size='small'
|
||
title='新增分组'
|
||
icon='plus'
|
||
onClick={onAddGroupConfig}
|
||
/>
|
||
<IFComponent IF={extraFieldConfigs.length >= this.maxShowContentNum}>
|
||
<Button
|
||
size='small'
|
||
title='展开收起'
|
||
icon={isShowContent ? 'up' : 'down'}
|
||
onClick={() => this.setState({ isShowContent: !isShowContent })}
|
||
/>
|
||
</IFComponent>
|
||
</Button.Group>
|
||
</div>
|
||
</div>
|
||
</Form>
|
||
)
|
||
}
|
||
}
|
||
|
||
export default connect(({ search }) => ({ search }))(AdvanceSearch)
|