react select 远程搜索

import React, { useState, useMemo, useRef, useEffect } from 'react';
import { Select, Spin } from 'antd';
import debounce from 'lodash/debounce';

const { Option } = Select;

const PersonSelect = () => {
  const [DSPCodeList, setDSPCodeList] = useState<any[]>([]);
  const [loading, setLoading] = useState(false);
  const fetchIdRef = useRef(0);

  // 权限参数:组件初始化时解析一次localStorage
  const authParams = useMemo(() => {
    const globeMap = JSON.parse(localStorage.getItem('globeMap') || '{}');
    return {
      filiales: globeMap.gRoleFiliales || [],
      pdepts: globeMap.gRoleDeptCodes || []
    };
  }, []);

  // 防抖搜索函数:缓存实例避免失效
  const debounceSearch = useMemo(() => {
    const fetchPersons = async (keyword: string) => {
      if (!keyword.trim()) {
        setDSPCodeList([]);
        setLoading(false);
        return;
      }
      fetchIdRef.current += 1;
      const currentFetchId = fetchIdRef.current;
      setDSPCodeList([]);
      setLoading(true);
      try {
        const _Result = await getPersonByAbbr({
          abbr: keyword.toUpperCase(),
          ...authParams
        });
        if (currentFetchId === fetchIdRef.current) {
          setDSPCodeList(_Result?.result || []);
        }
      } catch (error) {
        console.error('人员搜索失败:', error);
        if (currentFetchId === fetchIdRef.current) setDSPCodeList([]);
      } finally {
        if (currentFetchId === fetchIdRef.current) setLoading(false);
      }
    };
    return debounce(fetchPersons, 300);
  }, [authParams]);

  // 组件卸载时取消防抖,防止内存泄漏
  useEffect(() => {
    return () => debounceSearch.cancel();
  }, [debounceSearch]);

  return (
    <Select
      placeholder="请输入拼音/工号/姓名搜索"
      showSearch
      style={{ width: '100%' }}
      allowClear
      filterOption={false}
      onSearch={debounceSearch}
      onClear={() => {
        fetchIdRef.current += 1;
        setDSPCodeList([]);
        setLoading(false);
      }}
      loading={loading}
      notFoundContent={loading ? <Spin size="small" /> : '无匹配数据'}
      defaultActiveFirstOption
      // ✅ 核心:指定用Option的label属性作为输入框回显文本
      optionLabelProp="label"
    >
      {DSPCodeList?.map((item: any) => (
        <Option
          key={item.workerNo}
          value={item.workerNo} // 提交的值:工号(不改变原有逻辑)
          label={item.CName} // 输入框回显:姓名(关键配置)
          cname={item.CName}
          pyAbbr={item.pyAbbr}
          workerNo={item.workerNo}
        >
          {/* ✅ 下拉列表显示:姓名(工号)(你要的效果) */}
          {item.CName}({item.workerNo})
        </Option>
      ))}
    </Select>
  );
};

// 接口函数(保持原有逻辑)
const getPersonByAbbr = async (params: any) => {
  return fetch('/api/person/search', {
    method: 'POST',
    body: JSON.stringify(params)
  }).then(res => res.json());
};

export default PersonSelect;

 

posted @ 2026-05-26 15:48  小蘑菇123  阅读(5)  评论(0)    收藏  举报