/* * @Author: code4eat awesomedema@gmail.com * @Date: 2023-03-03 11:30:33 * @LastEditors: code4eat awesomedema@gmail.com * @LastEditTime: 2025-12-15 11:18:35 * @FilePath: /KC-MiddlePlatform/src/pages/platform/setting/pubDicTypeMana/index.tsx * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ import React, { useEffect, useRef, useState } from 'react'; import { Input, message, Card, Button, Modal, Tabs, Radio, Popconfirm, Dropdown, Menu, Checkbox, } from 'antd'; import { ActionType, ProColumns } from '@ant-design/pro-table'; import KCIMPagecontainer from '@/components/KCIMPageContainer'; import { KCIMTable } from '@/components/KCIMTable'; import { ModalForm, ProFormText, ProFormTextArea, ProFormSelect, } from '@ant-design/pro-form'; import { PlusOutlined, SearchOutlined, MoreOutlined } from '@ant-design/icons'; import { createFromIconfontCN } from '@ant-design/icons'; import './style.less'; import { getChackGroupData, addData, editData, delData, getCheckGroupEmployees, addCheckGroupEmployee, delCheckGroupEmployee, getAvailableEmployees, setGroupManager, getCheckGroupCheckpoints, getGroupPendingCheckpoints, addCheckGroupCheckpoints, delCheckGroupCheckpoints, } from './service'; const IconFont = createFromIconfontCN({ scriptUrl: '', }); // 添加查核要点弹窗组件 const AddCheckpointModal: React.FC<{ selectedGroup: any; onSuccess: () => void; }> = ({ selectedGroup, onSuccess }) => { const [modalVisible, setModalVisible] = useState(false); const [selectedCheckpointIds, setSelectedCheckpointIds] = useState< React.Key[] >([]); const [searchKeyword, setSearchKeyword] = useState(''); const [allCheckpointSelectData, setAllCheckpointSelectData] = useState( [], ); const checkpointSelectTableRef = useRef(); // 获取可添加的查核要点列表 const getCheckpointSelectData = async (params: any) => { if (!selectedGroup?.id) { return { data: [], success: true, total: 0, }; } try { const { current = 1, pageSize = 10 } = params; const res = await getGroupPendingCheckpoints( selectedGroup.id, searchKeyword, current, pageSize, ); // 保存所有数据,用于后续选择时获取完整信息 if (current === 1) { setAllCheckpointSelectData(res.list || []); } else { setAllCheckpointSelectData((prev) => [...prev, ...(res.list || [])]); } return { data: res.list || [], success: res.success, total: res.total || 0, }; } catch (error) { return { data: [], success: false, total: 0, }; } }; // 打开弹窗时重置状态 const handleOpenModal = () => { setModalVisible(true); setSelectedCheckpointIds([]); setSearchKeyword(''); setAllCheckpointSelectData([]); // 延迟触发表格重新加载 setTimeout(() => { checkpointSelectTableRef.current?.reload(); }, 100); }; // 提交添加 const handleSubmit = async () => { if (selectedCheckpointIds.length === 0) { message.warning('请至少选择一个查核要点'); return; } try { // 直接按“要点ID”提交(与接口分页口径一致) const selectedIds = Array.from( new Set( selectedCheckpointIds .map((k) => Number(k)) .filter((n) => !Number.isNaN(n)), ), ) as number[]; const result = await addCheckGroupCheckpoints( selectedGroup.id, selectedIds, ); // 检查返回值,如果是false说明业务失败 if (result === false) { return; // 错误消息已在响应拦截器中显示,直接返回 } message.success(`已添加 ${selectedIds.length} 个查核要点`); setModalVisible(false); onSuccess(); // 调用成功回调 } catch (error) { message.error('添加失败'); } }; // 定义表格列 const checkpointSelectColumns: ProColumns[] = [ { title: '要点名称', dataIndex: 'name', width: 260, align: 'left' as 'left', }, { title: '查核项数', dataIndex: 'checkItemList', width: 100, align: 'center' as 'center', render: (_: any, record: any) => Array.isArray(record?.checkItemList) ? record.checkItemList.length : 0, }, ]; return ( <> setModalVisible(false)} width={700} footer={[ , , ]} className="checkpoint-select-modal" >
{ setSearchKeyword(e.target.value); if (e.target.value === '') { // 清空搜索时自动刷新 checkpointSelectTableRef.current?.reload(); } }} onPressEnter={() => checkpointSelectTableRef.current?.reload()} suffix={ checkpointSelectTableRef.current?.reload()} style={{ cursor: 'pointer', color: '#99A6BF' }} /> } style={{ width: '100%' }} />
null, }} rowSelection={{ selectedRowKeys: selectedCheckpointIds, onChange: (selectedRowKeys) => { setSelectedCheckpointIds(selectedRowKeys); }, preserveSelectedRowKeys: true, }} tableAlertRender={false} scroll={{ y: 360 }} expandable={{ expandedRowRender: (record: any) => (
{Array.isArray(record?.checkItemList) && record.checkItemList.length > 0 ? (
    {record.checkItemList.map((ci: any) => (
  • {ci.name}
  • ))}
) : ( 无明细 )}
), }} />
); }; // 添加人员弹窗组件 const AddEmployeeModal: React.FC<{ selectedGroup: any; onSuccess: () => void; }> = ({ selectedGroup, onSuccess }) => { const [modalVisible, setModalVisible] = useState(false); const [selectedEmployeeIds, setSelectedEmployeeIds] = useState( [], ); const [selectedEmployeeData, setSelectedEmployeeData] = useState([]); const [searchKeyword, setSearchKeyword] = useState(''); const [allEmployeeData, setAllEmployeeData] = useState([]); const employeeTableRef = useRef(); // 获取可添加的人员列表 const getEmployeeSelectData = async (params: any) => { if (!selectedGroup?.id) { return { data: [], success: true, total: 0, }; } try { const { current = 1, pageSize = 10 } = params; const res = await getAvailableEmployees( selectedGroup.id, searchKeyword, current, pageSize, ); // 保存所有数据,用于后续选择时获取完整信息 if (current === 1) { setAllEmployeeData(res.list || []); } else { setAllEmployeeData((prev) => [...prev, ...(res.list || [])]); } return { data: res.list || [], success: res.success, total: res.total || 0, }; } catch (error) { return { data: [], success: false, total: 0, }; } }; // 打开弹窗时重置状态 const handleOpenModal = () => { setModalVisible(true); setSelectedEmployeeIds([]); setSelectedEmployeeData([]); setSearchKeyword(''); setAllEmployeeData([]); // 延迟触发表格重新加载 setTimeout(() => { employeeTableRef.current?.reload(); }, 100); }; // 提交添加 const handleSubmit = async () => { if (selectedEmployeeIds.length === 0) { message.warning('请至少选择一个人员'); return; } try { // 根据选中的ID获取完整的人员信息 const selectedEmployees = allEmployeeData.filter((emp) => selectedEmployeeIds.includes(emp.id), ); const result = await addCheckGroupEmployee( selectedGroup.id, selectedEmployees, ); // 检查返回值,如果是false说明业务失败 if (result === false) { return; // 错误消息已在响应拦截器中显示,直接返回 } message.success(`已添加 ${selectedEmployeeIds.length} 个人员`); setModalVisible(false); onSuccess(); // 调用成功回调 } catch (error) { message.error('添加失败'); } }; // 定义表格列 const employeeSelectColumns: ProColumns[] = [ { title: '工号', dataIndex: 'code', width: 120, }, { title: '姓名', dataIndex: 'name', width: 120, }, ]; return ( <> setModalVisible(false)} width={352} footer={[ , , ]} className="employee-select-modal" >
{ setSearchKeyword(e.target.value); if (e.target.value === '') { // 清空搜索时自动刷新 employeeTableRef.current?.reload(); } }} onPressEnter={() => employeeTableRef.current?.reload()} suffix={ employeeTableRef.current?.reload()} style={{ cursor: 'pointer', color: '#99A6BF' }} /> } style={{ width: '100%' }} />
null, }} rowSelection={{ selectedRowKeys: selectedEmployeeIds, onChange: (selectedRowKeys) => { setSelectedEmployeeIds(selectedRowKeys); }, }} tableAlertRender={false} scroll={{ y: 360 }} />
); }; // 主页面组件 const CheckGroupMana: React.FC = () => { // 左侧查核组数据 const [groupData, setGroupData] = useState([]); const [filteredGroupData, setFilteredGroupData] = useState([]); const [selectedGroup, setSelectedGroup] = useState(null); const [groupSearchKeywords, setGroupSearchKeywords] = useState(''); const [hoveredNode, setHoveredNode] = useState(null); const [openDropdownNode, setOpenDropdownNode] = useState(null); // 分页加载相关状态 const [currentPage, setCurrentPage] = useState(1); const [totalCount, setTotalCount] = useState(0); const [loading, setLoading] = useState(false); const [hasMore, setHasMore] = useState(true); // 右侧人员表格相关 const [employeeSearchKeywords, setEmployeeSearchKeywords] = useState(''); const [selectedEmployeeKeys, setSelectedEmployeeKeys] = useState( [], ); const [allEmployeeList, setAllEmployeeList] = useState([]); // 存储原始组员数据 const [filteredEmployeeList, setFilteredEmployeeList] = useState([]); // 存储过滤后的组员数据 const employeeTableRef = useRef(); // 查核要点相关状态 const [checkpointSearchKeywords, setCheckpointSearchKeywords] = useState(''); const [selectedCheckpointKeys, setSelectedCheckpointKeys] = useState< string[] >([]); const [allCheckpointList, setAllCheckpointList] = useState([]); // 存储原始查核要点数据 const [filteredCheckpointList, setFilteredCheckpointList] = useState( [], ); // 存储过滤后的查核要点数据 const checkpointTableRef = useRef(); // 右侧内容区ref和操作栏定位状态 const deptContentRef = useRef(null); const [actionBarStyle, setActionBarStyle] = useState<{ left: number; width: number; }>({ left: 0, width: 0 }); // 更新操作栏定位,支持ResizeObserver const updateActionBarPosition = () => { if (deptContentRef.current) { const rect = deptContentRef.current.getBoundingClientRect(); setActionBarStyle({ left: rect.left, width: rect.width }); } }; useEffect(() => { updateActionBarPosition(); window.addEventListener('resize', updateActionBarPosition); window.addEventListener('scroll', updateActionBarPosition, true); let resizeObserver: ResizeObserver | null = null; if (deptContentRef.current && typeof ResizeObserver !== 'undefined') { resizeObserver = new ResizeObserver(() => { updateActionBarPosition(); }); resizeObserver.observe(deptContentRef.current); } return () => { window.removeEventListener('resize', updateActionBarPosition); window.removeEventListener('scroll', updateActionBarPosition, true); if (resizeObserver && deptContentRef.current) { resizeObserver.unobserve(deptContentRef.current); resizeObserver.disconnect(); } }; }, []); // 获取左侧查核组数据 useEffect(() => { fetchGroupData(); }, []); const fetchGroupData = async ( page: number = 1, isLoadMore: boolean = false, keyword?: string, ) => { try { setLoading(true); // 如果传入了keyword参数,使用它;否则使用状态中的groupSearchKeywords const searchKeyword = keyword !== undefined ? keyword : groupSearchKeywords; const res = await getChackGroupData({ current: page, pageSize: 100, groupName: searchKeyword, }); if (res) { // 转换数据格式,符合树形组件需要的格式,同时保留原始数据 const transformedData = res.list.map((item: any) => ({ title: item.name, key: item.id, type: 'checkGroup', // 标记为查核组 // 保留原始数据 id: item.id, name: item.name, groupManagerName: item.groupManagerName, remark: item.remark, createUserName: item.createUserName, })); if (isLoadMore) { // 加载更多时,追加到现有数据 setGroupData((prev) => [...prev, ...transformedData]); setFilteredGroupData((prev) => [...prev, ...transformedData]); } else { // 首次加载或搜索时,替换数据 setGroupData(transformedData); setFilteredGroupData(transformedData); // 默认选中第一个 if (transformedData.length > 0) { setSelectedGroup(transformedData[0]); } } // 更新分页信息 setTotalCount(res.totalCount); setCurrentPage(page); setHasMore(res.list.length === 100 && page * 100 < res.totalCount); } } catch (error) { message.error('获取查核组数据失败'); } finally { setLoading(false); } }; // 本地过滤组员数据 const filterEmployeeData = (data: any[], keyword: string) => { if (!keyword.trim()) { return data; } return data.filter( (emp) => emp.employeeId?.toString().includes(keyword) || emp.employeeName?.includes(keyword), ); }; // 监听搜索关键词变化,进行本地过滤 useEffect(() => { const filtered = filterEmployeeData( allEmployeeList, employeeSearchKeywords, ); setFilteredEmployeeList(filtered); }, [allEmployeeList, employeeSearchKeywords]); // 监听选中项变化,加载组员数据和查核要点数据 useEffect(() => { if (selectedGroup?.key) { loadEmployeeData(); loadCheckpointData(); } else { setAllEmployeeList([]); setFilteredEmployeeList([]); setAllCheckpointList([]); setFilteredCheckpointList([]); } }, [selectedGroup?.key]); // 加载组员数据 const loadEmployeeData = async () => { if (!selectedGroup?.id) return; try { const result = await getCheckGroupEmployees({ groupId: selectedGroup.id, }); if (result.success) { setAllEmployeeList(result.data || []); } } catch (error) { console.error('加载组员数据失败:', error); setAllEmployeeList([]); } }; // 本地过滤查核要点数据 const filterCheckpointData = (data: any[], keyword: string) => { if (!keyword.trim()) { return data; } return data.filter( (item) => item.pointName?.includes(keyword) || item.checkItemName?.includes(keyword), ); }; // 监听查核要点搜索关键词变化,进行本地过滤 useEffect(() => { const filtered = filterCheckpointData( allCheckpointList, checkpointSearchKeywords, ); setFilteredCheckpointList(filtered); }, [allCheckpointList, checkpointSearchKeywords]); // 加载查核要点数据 const loadCheckpointData = async () => { if (!selectedGroup?.id) return; try { const result = await getCheckGroupCheckpoints({ groupId: selectedGroup.id, }); if (result.success) { setAllCheckpointList(result.data || []); } } catch (error) { console.error('加载查核要点数据失败:', error); setAllCheckpointList([]); } }; // 处理查核组搜索 - 点击搜索图标或回车时触发 const handleGroupSearch = () => { setCurrentPage(1); setHasMore(true); fetchGroupData(1, false); }; // 处理搜索输入框的变化 const handleSearchInputChange = (value: string) => { setGroupSearchKeywords(value); // 如果清空搜索,立即重新加载数据,传入空字符串确保清空搜索 if (!value.trim()) { setCurrentPage(1); setHasMore(true); // 直接传入空字符串,而不是依赖状态更新 fetchGroupData(1, false, ''); } }; // 加载更多数据 const loadMoreData = () => { if (!loading && hasMore) { const nextPage = currentPage + 1; fetchGroupData(nextPage, true); } }; // 滚动事件处理 const handleScroll = (e: React.UIEvent) => { const { scrollTop, scrollHeight, clientHeight } = e.currentTarget; // 当滚动到底部附近时加载更多数据 if (scrollHeight - scrollTop <= clientHeight + 10) { loadMoreData(); } }; // 新增查核组弹窗组件 const AddCheckGroupModal = () => { return ( } className="add-button" />} onFinish={async (val: any) => { try { await addData(val); message.success('新增成功!'); fetchGroupData(1, false); // 重新获取数据 return true; } catch (error) { message.error('新增失败'); return false; } }} modalProps={{ destroyOnClose: true, maskClosable: false, }} > ); }; // 更多操作菜单 const getMoreMenu = (node: any) => ( 编辑} onFinish={async (val: any) => { try { await editData({ id: node.id, name: val.name, }); message.success('编辑成功!'); fetchGroupData(1, false); return true; } catch (error) { message.error('编辑失败'); return false; } }} modalProps={{ destroyOnClose: true }} > { // 删除确认 Modal.confirm({ title: '确认删除', content: `确定要删除查核组"${node.name}"吗?`, okText: '确定', cancelText: '取消', onOk: async () => { try { await delData(node.id); message.success('删除成功!'); fetchGroupData(1, false); // 如果删除的是当前选中的组,清空选中状态 if (selectedGroup?.id === node.id) { setSelectedGroup(null); } } catch (error) { message.error('删除失败'); } }, }); }} > 删除 ); // 左侧查核组树形组件渲染 const renderGroupTree = () => { return (
} className="search-input" value={groupSearchKeywords} onChange={(e) => handleSearchInputChange(e.target.value)} onPressEnter={handleGroupSearch} allowClear />
{filteredGroupData.map((item) => (
{ setSelectedGroup(item); }} onMouseEnter={() => setHoveredNode(item.key)} onMouseLeave={() => setHoveredNode(null)} > {item.title} {(selectedGroup?.key === item.key || hoveredNode === item.key || openDropdownNode === item.key) && ( { if (visible) { setOpenDropdownNode(item.key); } else { setOpenDropdownNode(null); } }} >
))} {/* 加载更多提示 */} {loading && (
加载中...
)} {!hasMore && filteredGroupData.length > 0 && (
已加载全部数据(共{totalCount}条)
)}
); }; // 设置组长 const handleSetManager = async (employeeId: number) => { if (!selectedGroup?.id) return; try { const result = await setGroupManager(selectedGroup.id, employeeId); // 检查返回值,如果是false说明业务失败 if (result === false) { return; // 错误消息已在响应拦截器中显示,直接返回 } message.success('设置组长成功!'); // 只需要刷新组员表格数据 loadEmployeeData(); } catch (error) { message.error('设置组长失败'); } }; // 处理删除查核要点 const handleDeleteCheckpoint = async (record: any) => { try { const result = await delCheckGroupCheckpoints([record.originalPointId]); // 检查返回值,如果是false说明业务失败 if (result === false) { return; // 错误消息已在响应拦截器中显示,直接返回 } message.success('删除要点成功'); loadCheckpointData(); } catch (error) { message.error('删除要点失败'); } }; // 计算全选状态 const getAllSelectableKeys = () => { return filteredCheckpointList .filter((item) => item.rowSpan > 0) // 只获取合并行的ID .map((item) => item.id); }; const allSelectableKeys = getAllSelectableKeys(); const isAllSelected = allSelectableKeys.length > 0 && allSelectableKeys.every((key) => selectedCheckpointKeys.includes(key)); const isIndeterminate = selectedCheckpointKeys.length > 0 && selectedCheckpointKeys.length < allSelectableKeys.length; // 处理全选/取消全选 const handleSelectAll = (checked: boolean) => { if (checked) { setSelectedCheckpointKeys(allSelectableKeys); } else { setSelectedCheckpointKeys([]); } }; // 查核要点表格列定义 const checkpointColumns: ProColumns[] = [ { title: (
handleSelectAll(e.target.checked)} /> 要点名称
), dataIndex: 'pointName', width: 200, align: 'left' as 'left', render: (dom: React.ReactNode, record: any) => { if (record.rowSpan > 0) { return { children: (
{ if (selectedCheckpointKeys.includes(record.id)) { setSelectedCheckpointKeys( selectedCheckpointKeys.filter((k) => k !== record.id), ); } else { setSelectedCheckpointKeys([ ...selectedCheckpointKeys, record.id, ]); } }} /> {dom}
), props: { rowSpan: record.rowSpan }, }; } return { children: null, props: { rowSpan: 0 } }; }, }, { title: '查核项名称', dataIndex: 'checkItemName', align: 'left' as 'left', }, { title: '操作', dataIndex: 'option', width: 80, align: 'center' as 'center', render: (_: any, record: any) => { if (record.rowSpan > 0) { return { children: ( handleDeleteCheckpoint(record)} > 删除 ), props: { rowSpan: record.rowSpan }, }; } return { children: null, props: { rowSpan: 0 } }; }, }, ]; // 人员表格列定义 const employeeColumns: ProColumns[] = [ { title: '工号', dataIndex: 'employeeCode', width: 120, }, { title: '姓名', dataIndex: 'employeeName', width: 120, }, { title: '组长', dataIndex: 'isManager', width: 100, render: (text: any, record: any) => ( handleSetManager(record.employeeId)} /> ), }, { title: '操作', key: 'option', width: 100, valueType: 'option', render: (_: any, record: any) => [ { Modal.confirm({ title: '确认移除该人员吗?', onOk: async () => { try { const result = await delCheckGroupEmployee([record.id]); // 检查返回值,如果是false说明业务失败 if (result === false) { return; // 错误消息已在响应拦截器中显示,直接返回 } message.success('移除成功!'); loadEmployeeData(); } catch (error) { message.error('移除失败'); } }, okText: '确定', cancelText: '取消', }); }} > 删除 , ], }, ]; return (
{/* 左侧查核组树 */} {renderGroupTree()} {/* 右侧内容区 */}
{selectedGroup && (
检索: } style={{ width: 250 }} value={employeeSearchKeywords} onChange={(e) => { setEmployeeSearchKeywords(e.target.value); }} />
loadEmployeeData()} />
setSelectedEmployeeKeys(keys as string[]), }} tableAlertRender={false} />
检索: } style={{ width: 250 }} value={checkpointSearchKeywords} onChange={(e) => { setCheckpointSearchKeywords(e.target.value); }} />
loadCheckpointData()} />
)} {!selectedGroup && (
请选择左侧查核组查看详情
)}
{/* 批量操作栏 - 固定在页面底部,宽度跟dept-content一致 */} {(selectedEmployeeKeys.length > 0 || selectedCheckpointKeys.length > 0) && (
已选 {selectedEmployeeKeys.length + selectedCheckpointKeys.length}{' '} 项
{selectedEmployeeKeys.length > 0 && ( { try { const result = await delCheckGroupEmployee( selectedEmployeeKeys, ); // 检查返回值,如果是false说明业务失败 if (result === false) { return; // 错误消息已在响应拦截器中显示,直接返回 } message.success('批量移除成功'); setSelectedEmployeeKeys([]); loadEmployeeData(); } catch (e) { message.error('批量移除失败'); } }} > )} {selectedCheckpointKeys.length > 0 && ( { try { // 从选中的ID中提取原始要点ID(去重) const originalIds = Array.from( new Set( selectedCheckpointKeys .map((id) => { const record = filteredCheckpointList.find( (item: any) => item.id === id, ); return record?.originalPointId; }) .filter((id) => id !== undefined), ), ); const result = await delCheckGroupCheckpoints(originalIds); // 检查返回值,如果是false说明业务失败 if (result === false) { return; // 错误消息已在响应拦截器中显示,直接返回 } message.success('批量删除成功'); setSelectedCheckpointKeys([]); loadCheckpointData(); } catch (e) { message.error('批量删除失败'); } }} > )}
)}
); }; export default CheckGroupMana;