/*
|
* @Author: dminyi 1301963064@qq.com
|
* @Date: 2024-08-29 17:41:09
|
* @LastEditors: lwh
|
* @LastEditTime: 2025-06-21 11:56:05
|
* @FilePath: \gzDyh\gz-customerSystem\src\components\SelectObjModal\selectPerson.jsx
|
* @Description: 选择经办人
|
*/
|
import React, { useState, useEffect, useMemo } from 'react';
|
import PropTypes from 'prop-types';
|
import { Button, Space, Input, Tree } from 'antd';
|
import { CloseOutlined } from '@ant-design/icons';
|
import './index.less';
|
import * as $$ from '../../utils/utility';
|
import { Modal, Spin } from '@arco-design/web-react';
|
|
const { Search } = Input;
|
|
const txtMap = {
|
supUnit: '组织',
|
dept: '部门',
|
person: '人',
|
unit: '组织'
|
}
|
|
// 获取人员,组织,部门数据
|
function getDataApi(type, searchData, caseId) {
|
let url
|
switch (type) {
|
case 'dept':
|
// url = `ctUnit/unitChoose`
|
url = `ctUnit/unitTree`
|
break;
|
case 'person':
|
url = 'ctUser/userChoose'
|
break
|
case 'unit':
|
url = 'ctUser/unitList'
|
break
|
case 'supUnit':
|
url = `caseInfoUnfold/superviceUnitChoose?caseId=${caseId}`
|
break
|
default:
|
break;
|
}
|
return $$.ax.request({ url, type: 'get', data: searchData, service: type === 'supUnit' ? 'mediate' : 'cust' });
|
}
|
|
/**
|
* visible, // 传入参数控制modal显示
|
* checkKeys, // 选中,数据格式 [{value:'',label':''}]
|
* type, // 'person': 选择人员 'unit': 选择组织 'dept': 选择部门 'supUnit': 督办组织
|
* isCheckbox, // 是否多选
|
* searchData, // 搜索条件
|
* onClose, // 关闭
|
* onOk, // 点击确定的回调
|
*/
|
const SelectObjModal = ({ visible = false, nameStr, checkKeys = [], type = 'dept', isCheckbox = false, searchData = {}, onClose, onOk, caseId }) => {
|
// 默认调解员查询'22_00024-4'
|
const searchRole = type === 'person' ? { roleCode: '22_00024-4' } : {};
|
const [data, setData] = useState([]);
|
const [checkedKeys, setCheckedKeys] = useState({ keys: [], items: [] });
|
const [expandedKeys, setExpandedKeys] = useState([]);
|
const [searchValue, setSearchValue] = useState('');
|
const [autoExpandParent, setAutoExpandParent] = useState(true);
|
const [dataList, setDataList] = useState([]);
|
const [loading, setLoading] = useState(false);
|
// 新增状态:用于区分是否为搜索状态
|
const [isSearchMode, setIsSearchMode] = useState(false);
|
|
// 获取第一层级的key
|
const getFirstLevelKeys = (treeData) => {
|
return treeData.map(item => item.value);
|
};
|
|
// tree复选框选择
|
function handleCheck(checkedKeys, e) {
|
if (!isCheckbox && checkedKeys.length > 1) {
|
$$.info({ type: 'warning', content: '当前选择只可单选' });
|
return;
|
}
|
setCheckedKeys({ keys: checkedKeys, items: e.node });
|
}
|
|
// 删除选项
|
function handleDelete(t) {
|
checkedKeys.keys.splice(t, 1);
|
checkedKeys.items.splice(t, 1);
|
setCheckedKeys({ ...checkedKeys });
|
}
|
|
const getParentKey = (key, tree) => {
|
|
let parentKey;
|
for (let i = 0; i < tree.length; i++) {
|
const node = tree[i];
|
if (node.children) {
|
if (node.children.some((item) => item.value === key)) {
|
parentKey = node.value;
|
} else if (getParentKey(key, node.children)) {
|
parentKey = getParentKey(key, node.children);
|
}
|
}
|
}
|
return parentKey;
|
};
|
|
// 获取所有父节点
|
const getAllParentKeys = (key, tree, parents = []) => {
|
for (let i = 0; i < tree.length; i++) {
|
const node = tree[i];
|
if (node.children) {
|
if (node.children.some((item) => item.value === key)) {
|
parents.push(node.value);
|
getAllParentKeys(node.value, tree, parents);
|
} else {
|
getAllParentKeys(key, node.children, parents);
|
}
|
}
|
}
|
return parents;
|
};
|
|
// 检查节点或其子节点是否包含搜索值
|
const hasMatchingChild = (node, searchValue) => {
|
if (node.label.indexOf(searchValue) > -1) {
|
return true;
|
}
|
if (node.children) {
|
return node.children.some(child => hasMatchingChild(child, searchValue));
|
}
|
return false;
|
};
|
|
// 获取搜索时需要展开的所有节点key
|
const getExpandedKeysForSearch = (searchValue, treeData) => {
|
const expandedKeys = [];
|
|
const traverse = (nodes, parentKeys = []) => {
|
nodes.forEach(node => {
|
const currentPath = [...parentKeys, node.value];
|
|
// 如果当前节点匹配搜索值
|
if (node.label.indexOf(searchValue) > -1) {
|
// 添加所有父节点到展开列表
|
expandedKeys.push(...parentKeys);
|
// 添加当前节点到展开列表
|
expandedKeys.push(node.value);
|
}
|
|
// 如果当前节点有子节点,继续遍历
|
if (node.children && node.children.length > 0) {
|
traverse(node.children, currentPath);
|
}
|
});
|
};
|
|
traverse(treeData);
|
return Array.from(new Set(expandedKeys));
|
};
|
|
function handleSearch(value, dataList) {
|
if (!value.trim()) {
|
// 如果搜索值为空,恢复到初始状态
|
const firstLevelKeys = getFirstLevelKeys(data);
|
setExpandedKeys(firstLevelKeys);
|
setSearchValue('');
|
setAutoExpandParent(false);
|
setIsSearchMode(false);
|
return;
|
}
|
|
// 使用新的函数来精确计算需要展开的节点
|
const newExpandedKeys = getExpandedKeysForSearch(value, data);
|
|
setExpandedKeys(newExpandedKeys);
|
setSearchValue(value);
|
setAutoExpandParent(true);
|
// 设置为搜索模式
|
setIsSearchMode(true);
|
}
|
|
function handleSearch1(value, dataList) {
|
if (!value.trim()) {
|
// 如果搜索值为空,恢复到初始状态
|
const firstLevelKeys = getFirstLevelKeys(data);
|
setExpandedKeys(firstLevelKeys);
|
setSearchValue('');
|
setAutoExpandParent(false);
|
setIsSearchMode(false);
|
return;
|
}
|
|
// 使用新的函数来精确计算需要展开的节点
|
const newExpandedKeys = getExpandedKeysForSearch(value, data);
|
|
setExpandedKeys(newExpandedKeys);
|
setSearchValue(value);
|
setAutoExpandParent(true);
|
// 设置为搜索模式
|
setIsSearchMode(true);
|
}
|
|
useEffect(() => {
|
if (!visible) return;
|
// 获取数据
|
async function getData() {
|
setLoading(true)
|
const res = await getDataApi(type, { ...searchRole, ...searchData }, caseId);
|
setLoading(false)
|
if (res.type) {
|
setData(res.data || []);
|
}
|
}
|
if (checkKeys.length !== 0) {
|
setCheckedKeys({ keys: checkKeys, items: [] });
|
} else {
|
setCheckedKeys({ keys: [], items: [] });
|
}
|
// 重置搜索模式
|
setIsSearchMode(false);
|
getData();
|
}, [type, visible]);
|
|
console.log('checkedKeys', checkedKeys);
|
|
// 搜索
|
useEffect(() => {
|
if (!visible) return;
|
const arr = [];
|
const generateList = (data) => {
|
for (let i = 0; i < data.length; i++) {
|
const node = data[i];
|
const { value, label } = node;
|
arr.push({ value, label });
|
if (node.children) {
|
generateList(node.children);
|
}
|
}
|
};
|
generateList(data);
|
setDataList(arr);
|
|
// 初始化时只展开第一层级,不调用handleSearch
|
if (data.length > 0 && !isSearchMode) {
|
const firstLevelKeys = getFirstLevelKeys(data);
|
setExpandedKeys(firstLevelKeys);
|
setAutoExpandParent(false);
|
}
|
}, [data]);
|
|
const treeData = useMemo(() => {
|
const loop = (data) => {
|
const copiedData = JSON.parse(JSON.stringify(data));
|
return copiedData.map((item, idx) => {
|
const strTitle = item.label;
|
const index = strTitle.indexOf(searchValue);
|
|
// 如果有搜索值,只保留包含 searchValue 的项或有匹配子节点的项
|
if (searchValue && index <= -1 && !hasMatchingChild(item, searchValue)) {
|
return null; // 返回 null 表示不包含在最终结果中
|
}
|
|
const beforeStr = strTitle.substring(0, index);
|
const afterStr = strTitle.slice(index + searchValue.length);
|
const label =
|
index > -1 ? (
|
<span>
|
{beforeStr}
|
<span className="selectObjModal-searchValue">{searchValue}</span>
|
{afterStr}
|
</span>
|
) : (
|
<span>{strTitle}</span>
|
);
|
|
if (item.children) {
|
const filteredChildren = loop(item.children).filter(Boolean); // 递归处理子项并过滤掉 null
|
return {
|
label,
|
name: strTitle,
|
value: item.value,
|
disabled: item.checkable ? false : true,
|
checkable: item.checkable,
|
children: filteredChildren.length > 0 ? filteredChildren : undefined,
|
};
|
}
|
|
return {
|
label,
|
name: strTitle,
|
disabled: item.checkable ? false : true,
|
checkable: item.checkable,
|
value: item.value,
|
};
|
}).filter(Boolean); // 过滤掉 null
|
};
|
return loop(data);
|
}, [searchValue, data]);
|
|
return (
|
<Modal
|
visible={!!visible}
|
title={`选择${nameStr}`}
|
footer={null}
|
onCancel={onClose}
|
unmountOnExit={true}
|
maskClosable={false}
|
style={{ width: '560px' }}
|
>
|
<div className="selectObjModal-main">
|
<div style={{ width: "100%" }}>
|
<div className="selectObjModal-left-search" style={{ paddingRight: '0px' }}>
|
<Search
|
placeholder={`查询${nameStr}名称`}
|
value={searchValue}
|
onChange={(e) => {
|
const value = e.target.value;
|
if (!value.trim()) {
|
// 清空搜索时恢复到初始状态
|
const firstLevelKeys = getFirstLevelKeys(data);
|
setExpandedKeys(firstLevelKeys);
|
setSearchValue('');
|
setAutoExpandParent(false);
|
setIsSearchMode(false);
|
} else {
|
// 实时搜索,使用相同的展开逻辑
|
const newExpandedKeys = getExpandedKeysForSearch(value, data);
|
setExpandedKeys(newExpandedKeys);
|
setSearchValue(value);
|
setAutoExpandParent(true);
|
setIsSearchMode(true);
|
}
|
}}
|
onSearch={(e) => handleSearch1(e, dataList)}
|
/>
|
</div>
|
<div className="selectObjModal-left-main">
|
<Spin loading={loading} style={{ width: '100%', height: '100%' }}>
|
{data.length > 0 ? (
|
<Tree
|
checkStrictly
|
// defaultExpandAll
|
onExpand={(newExpandedKeys) => {
|
setExpandedKeys(newExpandedKeys);
|
setAutoExpandParent(false);
|
}}
|
expandedKeys={expandedKeys}
|
// autoExpandParent={autoExpandParent}
|
onSelect={(checkedKeys, e) => {
|
handleCheck(checkedKeys, e);
|
onOk && onOk(e.node)
|
}}
|
selectedKeys={checkedKeys.keys}
|
treeData={treeData}
|
fieldNames={{ title: 'label', key: 'value' }}
|
height={400}
|
/>
|
) : (
|
$$.MyEmpty()
|
)}
|
</Spin>
|
</div>
|
</div>
|
</div>
|
</Modal>
|
);
|
};
|
|
SelectObjModal.propTypes = {
|
visible: PropTypes.any,
|
checkKeys: PropTypes.array,
|
type: PropTypes.string,
|
isCheckbox: PropTypes.bool,
|
searchData: PropTypes.object,
|
onClose: PropTypes.func,
|
onOk: PropTypes.func,
|
};
|
|
export default SelectObjModal;
|