mh_jy_safe_web/src/feui/search/AdvanceSearch.js

375 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 核心库
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)