import { MyBetaModalFormProps, MyButtons, renderTextHelper } from '@/common'; import { MyModal } from '@/components/MyModal'; import { Apis } from '@/gen/Apis'; import { HouseBillsTypeEnum, HouseChargeStandardsCalculationModeEnum, HouseChargeStandardsCalculationPeriodEnum, } from '@/gen/Enums'; import { ProCard } from '@ant-design/pro-components'; import { Alert, Button, Checkbox, message, Space, Tree, Typography, } from 'antd'; import { CheckboxChangeEvent } from 'antd/es/checkbox'; import type { DataNode } from 'antd/es/tree'; import { useEffect, useRef, useState } from 'react'; const { Title } = Typography; interface TreeNodeType extends DataNode { id: number; key: string; title: string; isLeaf?: boolean; children?: TreeNodeType[]; asset_buildings_id?: number; asset_units_id?: number; } // 扩展 MyBetaModalFormProps 接口,添加 onCancel 属性 interface ChargeStandardHasHouseProps extends MyBetaModalFormProps { onCancel?: () => void; } export default function ChargeStandardHasHouse( props: ChargeStandardHasHouseProps, ) { const [treeData, setTreeData] = useState([]); const [expandedKeys, setExpandedKeys] = useState([]); const [checkedKeys, setCheckedKeys] = useState([]); const [selectedKeys, setSelectedKeys] = useState([]); const [autoExpandParent, setAutoExpandParent] = useState(true); const [loading, setLoading] = useState(false); const [selectAll, setSelectAll] = useState(false); const [selectedHouses, setSelectedHouses] = useState< { id: number; name: string }[] >([]); const modalRef: any = useRef(null); // 加载楼栋数据 const loadBuildings = async () => { setLoading(true); try { const res = await Apis.Asset.AssetBuildings.List({ asset_projects_id: props?.item?.asset_projects_id, }); if (res?.data) { const buildings = res.data.map((building: any) => ({ id: building.id, key: `building-${building.id}`, title: building.name, children: [], isLeaf: false, })); setTreeData(buildings); } } catch (error) { console.error('加载楼栋失败:', error); } finally { setLoading(false); } }; // 加载单元数据 const loadUnits = async (buildingId: number, buildingKey: string) => { setLoading(true); try { const res = await Apis.Asset.AssetUnits.List({ asset_projects_id: props?.item?.asset_projects_id, asset_buildings_id: buildingId, }); if (res?.data) { const units = res.data.map((unit: any) => ({ id: unit.id, key: `unit-${unit.id}`, title: unit.name, children: [], isLeaf: false, asset_buildings_id: buildingId, })); // 更新树形数据 const newTreeData = [...treeData]; const buildingNode = newTreeData.find( (node) => node.key === buildingKey, ); if (buildingNode) { buildingNode.children = units; } setTreeData(newTreeData); } } catch (error) { console.error('加载单元失败:', error); } finally { setLoading(false); } }; // 加载房屋数据 const loadHouses = async ( buildingId: number, unitId: number, unitKey: string, ) => { setLoading(true); try { const res = await Apis.Asset.AssetHouses.List({ asset_projects_id: props?.item?.asset_projects_id, asset_buildings_id: buildingId, asset_units_id: unitId, }); if (res?.data) { const houses = res.data.map((house: any) => ({ id: house.id, key: `house-${house.id}`, title: `${house.name} (${house.floor}层)`, isLeaf: true, asset_buildings_id: buildingId, asset_units_id: unitId, })); // 更新树形数据 const newTreeData = [...treeData]; const buildingNode = newTreeData.find( (node) => node.asset_buildings_id === undefined && node.id === buildingId, ); if (buildingNode && buildingNode.children) { const unitNode = buildingNode.children.find( (node) => node.key === unitKey, ); if (unitNode) { unitNode.children = houses; } } setTreeData(newTreeData); } } catch (error) { console.error('加载房屋失败:', error); } finally { setLoading(false); } }; // 初始化加载数据 useEffect(() => { if (props?.item?.asset_projects_id) { loadBuildings(); } else { console.warn('缺少 asset_projects_id 参数'); } }, [props?.item?.id]); // 处理节点展开 const onExpand = (expandedKeysValue: React.Key[]) => { setExpandedKeys(expandedKeysValue); setAutoExpandParent(false); }; // 处理节点选中 const onCheck = async ( checkedKeysValue: | React.Key[] | { checked: React.Key[]; halfChecked: React.Key[] }, ) => { // 处理不同格式的返回值 const keys = Array.isArray(checkedKeysValue) ? checkedKeysValue : checkedKeysValue.checked; // 获取之前的选中状态,用于比较变化 const prevKeys = new Set(checkedKeys); const newKeys = new Set(keys); // 找出新选中的节点 const newlyCheckedKeys = [...newKeys].filter((key) => !prevKeys.has(key)); // 找出新取消选中的节点 const uncheckedKeys = [...prevKeys].filter((key) => !newKeys.has(key)); // 处理新选中的节点 for (const key of newlyCheckedKeys) { const keyStr = key.toString(); // 如果选中的是楼栋 if (keyStr.startsWith('building-')) { const buildingNode = treeData.find((node) => node.key === key); if (buildingNode) { // 调用接口获取该楼栋下所有房屋 await loadBuildingHouses(buildingNode.id); } } // 如果选中的是单元 else if (keyStr.startsWith('unit-')) { // 查找该单元所属的楼栋和单元ID for (const building of treeData) { const unitNode = building.children?.find((unit) => unit.key === key); if (unitNode) { // 调用接口获取该单元下所有房屋 await loadUnitHouses(building.id, unitNode.id); break; } } } } // 如果有节点被取消选中,同步取消其所有子节点 if (uncheckedKeys.length > 0) { const keysToRemove = new Set(); const findChildKeys = (nodes: TreeNodeType[], parentKey: React.Key) => { nodes.forEach((node) => { if (node.key === parentKey) { // 将当前节点及其所有子节点的key加入待移除集合 const collectKeys = (n: TreeNodeType) => { keysToRemove.add(n.key); if (n.children) { n.children.forEach(collectKeys); } }; collectKeys(node); } else if (node.children) { findChildKeys(node.children, parentKey); } }); }; uncheckedKeys.forEach((key) => { findChildKeys(treeData, key); }); // 从选中keys中移除所有需要取消的节点 const finalKeys = keys.filter((key) => !keysToRemove.has(key)); setCheckedKeys(finalKeys); // 更新selectedHouses,移除被取消选中的房屋 const houseKeysToRemove = new Set(); keysToRemove.forEach((key) => { if (key.toString().startsWith('house-')) { houseKeysToRemove.add(key.toString().replace('house-', '')); } }); const updatedHouses = selectedHouses.filter( (house) => !houseKeysToRemove.has(house.id.toString()), ); setSelectedHouses(updatedHouses); } else { setCheckedKeys(keys); } // 收集所有选中的房屋 const selectedHousesList: { id: number; name: string; buildingName?: string; unitName?: string; }[] = [...selectedHouses]; // 遍历树形数据,收集选中节点下的所有房屋 const collectHouses = (nodes: TreeNodeType[], checkedKeys: React.Key[]) => { nodes.forEach((node) => { if (checkedKeys.includes(node.key)) { if (node.isLeaf) { // 如果是房屋节点,检查是否已经存在 const houseId = node.id; const exists = selectedHousesList.some( (house) => house.id === houseId, ); if (!exists) { // 查找楼栋和单元信息 let buildingName = ''; let unitName = ''; // 查找楼栋和单元 for (const building of treeData) { if (building.id === node.asset_buildings_id) { buildingName = building.title as string; // 查找单元 const unit = building.children?.find( (u) => u.id === node.asset_units_id, ); if (unit) { unitName = unit.title as string; } break; } } // 添加到选中列表 selectedHousesList.push({ id: houseId, name: `${buildingName} ${unitName} ${node.title}(${houseId})`, buildingName, unitName, }); } } else { // 如果是楼栋或单元节点,递归收集其下的所有房屋 if (node.children) { collectHouses(node.children, checkedKeys); } } } }); }; collectHouses(treeData, keys); setSelectedHouses(selectedHousesList); setSelectAll( selectedHousesList.length > 0 && selectedHousesList.length === treeData.reduce( (total, building) => total + (building.children?.reduce( (unitTotal, unit) => unitTotal + (unit.children?.length || 0), 0, ) || 0), 0, ), ); }; // 处理节点选择 const onSelect = (selectedKeysValue: React.Key[]) => { setSelectedKeys(selectedKeysValue); }; // 处理动态加载数据 const onLoadData = async (node: TreeNodeType) => { if (node.isLeaf) { return Promise.resolve(); } // 加载楼栋下的单元 if (node.key.toString().startsWith('building-')) { console.log('node.key', node.key); // 从key中提取buildingId,格式为'building-{id}' const buildingId = parseInt( node.key.toString().replace('building-', ''), 10, ); await loadUnits(buildingId, node.key as string); // 如果楼栋被选中,加载并选中其下所有单元和房屋 if (checkedKeys.includes(node.key)) { // 直接调用loadBuildingHouses加载该楼栋下所有房屋 await loadBuildingHouses(buildingId); } return Promise.resolve(); } // 加载单元下的房屋 if (node.key.toString().startsWith('unit-')) { // 从key中提取unitId,格式为'unit-{id}' const unitId = parseInt(node.key.toString().replace('unit-', ''), 10); const buildingId = node.asset_buildings_id as number; await loadHouses(buildingId, unitId, node.key as string); // 如果单元被选中,选中其下所有房屋 if (checkedKeys.includes(node.key)) { // 直接调用loadUnitHouses加载该单元下所有房屋 await loadUnitHouses(buildingId, unitId); } return Promise.resolve(); } return Promise.resolve(); }; // 加载所有房屋数据 const loadAllHouses = async () => { setLoading(true); try { const res = await Apis.Asset.AssetHouses.List({ asset_projects_id: props?.item?.asset_projects_id, }); if (res?.data) { const allHouseKeys: React.Key[] = []; const allHouses: { id: number; name: string; buildingName: string; unitName: string; }[] = []; // 创建映射以快速查找楼栋和单元名称 const buildingMap = new Map(); const unitMap = new Map(); // 填充楼栋映射 treeData.forEach((building) => { buildingMap.set(building.id, building.title); building.children?.forEach((unit) => { unitMap.set(unit.id, unit.title); }); }); res.data.forEach((house: any) => { const houseKey = `house-${house.id}`; allHouseKeys.push(houseKey); const buildingName = buildingMap.get(house.asset_buildings_id) || ''; const unitName = unitMap.get(house.asset_units_id) || ''; allHouses.push({ id: house.id, name: `${buildingName} ${unitName} ${house.name}(${house.id})`, buildingName: buildingName as string, unitName: unitName as string, }); }); setCheckedKeys(allHouseKeys); setSelectedHouses(allHouses); } } catch (error) { console.error('加载所有房屋失败:', error); message.error('加载所有房屋失败'); } finally { setLoading(false); } }; // 加载楼栋下所有房屋 const loadBuildingHouses = async (buildingId: number) => { setLoading(true); try { const res = await Apis.Asset.AssetHouses.List({ asset_projects_id: props?.item?.asset_projects_id, asset_buildings_id: buildingId, }); if (res?.data) { const buildingHouseKeys: React.Key[] = []; const buildingHouses: { id: number; name: string; buildingName: string; unitName: string; }[] = []; // 获取楼栋名称 const building = treeData.find((b) => b.id === buildingId); const buildingName = building?.title || ''; // 创建单元映射 const unitMap = new Map(); building?.children?.forEach((unit) => { unitMap.set(unit.id, unit.title); }); res.data.forEach((house: any) => { const houseKey = `house-${house.id}`; buildingHouseKeys.push(houseKey); const unitName = unitMap.get(house.asset_units_id) || ''; buildingHouses.push({ id: house.id, name: `${buildingName} ${unitName} ${house.name}(${house.id})`, buildingName: buildingName as string, unitName: unitName as string, }); }); // 合并当前选中的keys和新的keys const newCheckedKeys = Array.from( new Set([...checkedKeys, ...buildingHouseKeys]), ); setCheckedKeys(newCheckedKeys); // 合并当前选中的房屋和新的房屋 const existingIds = new Set(selectedHouses.map((h) => h.id)); const newHouses = buildingHouses.filter((h) => !existingIds.has(h.id)); setSelectedHouses([...selectedHouses, ...newHouses]); } } catch (error) { console.error('加载楼栋房屋失败:', error); message.error('加载楼栋房屋失败'); } finally { setLoading(false); } }; // 加载单元下所有房屋 const loadUnitHouses = async (buildingId: number, unitId: number) => { setLoading(true); try { const res = await Apis.Asset.AssetHouses.List({ asset_projects_id: props?.item?.asset_projects_id, asset_buildings_id: buildingId, asset_units_id: unitId, }); if (res?.data) { const unitHouseKeys: React.Key[] = []; const unitHouses: { id: number; name: string; buildingName: string; unitName: string; }[] = []; // 获取楼栋和单元名称 const building = treeData.find((b) => b.id === buildingId); const buildingName = building?.title || ''; const unit = building?.children?.find((u) => u.id === unitId); const unitName = unit?.title || ''; res.data.forEach((house: any) => { const houseKey = `house-${house.id}`; unitHouseKeys.push(houseKey); unitHouses.push({ id: house.id, name: `${buildingName} ${unitName} ${house.name}(${house.id})`, buildingName: buildingName as string, unitName: unitName as string, }); }); // 合并当前选中的keys和新的keys const newCheckedKeys = Array.from( new Set([...checkedKeys, ...unitHouseKeys]), ); setCheckedKeys(newCheckedKeys); // 合并当前选中的房屋和新的房屋 const existingIds = new Set(selectedHouses.map((h) => h.id)); const newHouses = unitHouses.filter((h) => !existingIds.has(h.id)); setSelectedHouses([...selectedHouses, ...newHouses]); } } catch (error) { console.error('加载单元房屋失败:', error); message.error('加载单元房屋失败'); } finally { setLoading(false); } }; // 处理全选 const handleSelectAll = async (e: CheckboxChangeEvent) => { setSelectAll(e.target.checked); if (e.target.checked) { // 调用接口获取所有房屋 await loadAllHouses(); } else { // 取消全选 setCheckedKeys([]); setSelectedHouses([]); } }; // 提交选中的房屋 const handleSubmit = async () => { if (selectedHouses.length === 0) { message.warning('请至少选择一个房屋'); return; } try { setLoading(true); // 将 number[] 转换为 string[] const houses_ids = selectedHouses.map((house) => house.id.toString()); await Apis.HouseCharage.HouseChargeHasHouses.Store({ house_charge_standards_id: props?.item?.id, houses_ids, }); message.success('绑定房屋成功'); props?.reload?.(); props?.onCancel?.(); } catch (error) { console.error('绑定房屋失败:', error); message.error('绑定房屋失败'); } finally { setLoading(false); } }; return ( } node={ <div> <div>收费标准名称:{props?.item?.name || '标准名称'}</div> <Space> <renderTextHelper.Tag Enums={HouseBillsTypeEnum} value={props?.item?.charge_type} key="type" /> <renderTextHelper.Tag Enums={HouseChargeStandardsCalculationModeEnum} value={props?.item?.calculation_mode} key="type" /> <renderTextHelper.Tag Enums={HouseChargeStandardsCalculationPeriodEnum} value={props?.item?.calculation_period} key="type" /> </Space> </div> } >
全选
{loading &&
加载中...
}
已选房屋 ({selectedHouses.length})
{selectedHouses.length > 0 ? (
    {selectedHouses.map((house) => (
  • {house.name}
  • ))}
) : (
暂无选中房屋{' '}
)}
} /> ); }