mh_jy_safe_web/src/feui/search/AdvanceSearch.js

374 lines
15 KiB
JavaScript
Raw Normal View History

2025-08-25 10:08:30 +08:00
// 核心库
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
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
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)