/* * @Author: yangzonglong * @Date: 2021-09-14 09:37:10 * @version: v1.0.0 * @Descripttion: select * @LastEditors: yangzonglong * @LastEditTime: 2021-09-15 09:16:14 * @Auditor: */ import React, { useState, useCallback, memo, useEffect, useRef, useMemo } from 'react'; import { Select as AntdSelect } from 'antd'; import { SelectProps as AntdSelectProps, SelectValue } from 'antd/lib/select'; import { evalTempStr, setFormExtraValues } from './util'; import { waitServer } from '../../utils'; const Option = AntdSelect.Option, defFieldNames = { label: 'label', value: 'value' }, pages = { page: 1, pageSize: 10 }; export interface SelectProps extends Omit, 'onChange'> { url?: string; name?: string; // form item name,单独使用select不需要传 cacheKey?: string; // 存在,只会调用一次数据 fieldNames?: { label: string; value: string }; dataSource?: RecordType[]; query?: string | object; // 查询参数 extra?: string[] // 额外输出,会额外输出item的值到form values id?: string; // 被form管控,单独使用无需传入 isModalTable?: boolean; // 为true 为modalTable使用,处理特殊的逻辑 autoSelected?: boolean | SelectValue; // 为true时 onChange?(value: SelectValue, id?: string): void; waitQuery?(query: string | object): boolean; // 等待query参数完整,再去请求接口 } function Select(props: SelectProps) { const { url, fieldNames, onFocus, cacheKey, id, onChange, extra, query, dataSource: propDataSource, isModalTable, waitQuery, ...selectProps } = props; const searchTimeout = useRef(null); const lastQuery = useRef(null); const isGetData = useRef(false); // 标记是否请求过数据 const [dataSource, setDataSource] = useState([]); const [loading, setLoading] = useState(false); const _fieldNames = fieldNames || defFieldNames; useEffect(() => { if (propDataSource) setDataSource(propDataSource) }, [propDataSource]); const getData = useCallback((searchQuery?: object) => { if (!url) return; setLoading(true); waitServer(cacheKey, { url, data: searchQuery || query }, (result: any) => { setLoading(false); if (result.rows) setDataSource(result.rows); }) }, [url, cacheKey, query, props.showSearch]); useEffect(() => { // value存在并且未获取过数据,请求数据 if (props.value !== undefined && !isGetData.current) { getData(); isGetData.current = true } }, [props.value]); useEffect(() => { if (lastQuery.current && lastQuery.current !== query) { if (JSON.stringify(query) !== JSON.stringify(lastQuery.current)) { setDataSource([]); // query 有变化,需要清空已选中数据 if (id && onChange) onChange(props.mode === 'multiple' || props.mode === 'tags' ? [] : '', id); } } lastQuery.current = query; }, [query, onChange, id, props.mode]); function _onFocus(e: React.FocusEvent) { if (!isGetData.current && !props.showSearch) { getData(); onFocus?.(e); } } function onSearch(str: string) { if (searchTimeout.current) { clearTimeout(searchTimeout.current); searchTimeout.current = null; } if (!str) return setDataSource([]); searchTimeout.current = window.setTimeout(async () => { let fuzzyField = [fieldNames?.value]; const fuzzyFieldExtra = extra?.map(item => { if (!item.includes(':')) return item; return item.split(':')[0] }) if (fuzzyFieldExtra) fuzzyField = fuzzyField.concat(fuzzyFieldExtra); const searchQuery = { ...query as object, pages, fuzzyValue: str, fuzzyQuery: true, fuzzyField }; searchTimeout.current = null; getData(searchQuery) }, 500); } function _onChange(...args: any) { if (id) { // form const isArr = Array.isArray(args[0]); let curs = dataSource.filter(item => { if (isArr) return args[0].includes(item[_fieldNames.value]); return item[_fieldNames.value] === args[0] }); if (extra?.length) { let extraValues: Record = {}; extra.forEach(item => { let [alias, vk] = item.includes(':') ? item.split(':') : [item, item]; extraValues[alias] = isArr ? curs.map(item => item[vk]) : curs[0][vk]; }) extraValues['_' + id] = curs; setFormExtraValues(extraValues); } else { setFormExtraValues({ ['_' + id]: curs }) } (onChange as any)(args[0], id); } else { onChange?.(args[0], args[1]); } } const _dataSource = useMemo(() => { if (!props.showSearch || dataSource.length < 10) return dataSource; return dataSource.splice(0, 10); }, [dataSource, props.showSearch]); const options = { ...selectProps, onFocus: _onFocus, onChange: _onChange, loading, onSearch: props.showSearch ? onSearch : undefined } if (isModalTable && !props.showSearch) { options.open = false } return ( {_dataSource.map(item => ( ))} ) } export default memo(Select);