import { Connect } from "@cqsjjb/jjb-dva-runtime"; import { Button, Empty, Form, Input, message, Modal, Row, Col, Select, Space, Tree } from "antd"; import { useEffect, useMemo, useRef, useState } from "react"; import AddIcon from "zy-react-library/components/Icon/AddIcon"; import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout"; import Search from "zy-react-library/components/Search"; import Table from "zy-react-library/components/Table"; import useTable from "zy-react-library/hooks/useTable"; import { NS_ORG_DEPARTMENT, NS_ORG_POSITION, NS_STAFF_INFO } from "~/enumerate/namespace"; import { asId, sameId } from "~/api/enterpriseInfo/idUtil"; import { safeListRequest, safeRequest } from "~/utils"; function findDeptNode(nodes = [], id) { for (const node of nodes) { if (sameId(node.id, id)) { return node; } if (node.children?.length) { const found = findDeptNode(node.children, id); if (found) { return found; } } } return null; } function toSelectedDept(node) { if (!node) { return null; } return { id: asId(node.id), deptName: node.deptName || node.title, leaderAccount: node.leaderAccount, leaderName: node.leaderName, deptLevel: node.deptLevel, }; } function DepartmentPositionPage(props) { const [selectedDept, setSelectedDept] = useState(null); const [treeData, setTreeData] = useState([]); const [deptModalOpen, setDeptModalOpen] = useState(false); const [positionModalOpen, setPositionModalOpen] = useState(false); const [currentId, setCurrentId] = useState(""); const [filterKeyword, setFilterKeyword] = useState(""); const [staffOptions, setStaffOptions] = useState([]); const [positionForm] = Form.useForm(); const [modalForm] = Form.useForm(); useEffect(() => { (async () => { try { const res = await props.staffInfoList?.({ pageIndex: 1, pageSize: 500 }); setStaffOptions((res?.data || []).map((s) => ({ label: `${s.staffName}(${s.account})`, value: s.account, staffName: s.staffName, }))); } catch (err) { console.warn("[DepartmentPosition] load staff options failed:", err); } })(); }, []); const { tableProps: positionTableProps, getData: getPositionData } = useTable( safeListRequest(props.orgPositionList), { form: positionForm, transform: (formData) => ({ ...formData, eqDeptId: asId(selectedDept?.id), }), }, ); const loadTree = async () => { try { const res = await props.orgDepartmentTree(); const normalizeTree = (nodes = []) => nodes.map((node) => ({ ...node, title: node.title || node.deptName, deptName: node.deptName || node.title, children: node.children ? normalizeTree(node.children) : [], })); const tree = normalizeTree(res?.data || []); setTreeData(tree); if (!selectedDept && tree.length) { setSelectedDept(toSelectedDept(tree[0])); } } catch (err) { console.warn("[DepartmentPosition] loadTree failed:", err); setTreeData([]); } }; useEffect(() => { loadTree(); }, []); useEffect(() => { if (selectedDept?.id) { getPositionData(); } }, [selectedDept?.id]); const filteredTree = useMemo(() => { if (!filterKeyword) { return treeData; } const filterNodes = (nodes) => { return nodes .map((node) => { const children = node.children ? filterNodes(node.children) : []; const match = (node.deptName || node.title)?.includes(filterKeyword); if (match || children.length) { return { ...node, children }; } return null; }) .filter(Boolean); }; return filterNodes(treeData); }, [treeData, filterKeyword]); const onDeleteDept = (id) => { Modal.confirm({ title: "提示", content: "数据将会删除,您是否确认删除?", okText: "是", cancelText: "否", onOk: async () => { const res = await props.orgDepartmentRemove({ id }); if (res?.success !== false) { message.success("删除成功"); if (sameId(selectedDept?.id, id)) { setSelectedDept(null); } loadTree(); } }, }); }; const onDeletePosition = (id) => { Modal.confirm({ title: "提示", content: "数据将会删除,您是否确认删除?", okText: "是", cancelText: "否", onOk: async () => { const res = await props.orgPositionRemove({ id }); if (res?.success !== false) { message.success("删除成功"); getPositionData(); } }, }); }; const closeDeptModal = () => { modalForm.resetFields(); setCurrentId(""); setDeptModalOpen(false); }; const closePositionModal = () => { modalForm.resetFields(); setCurrentId(""); setPositionModalOpen(false); }; const openDeptModal = (record) => { setCurrentId(asId(record?.id) || ""); setDeptModalOpen(true); }; const openPositionModal = (record) => { if (!selectedDept?.id) { message.warning("请先选择部门"); return; } setCurrentId(asId(record?.id) || ""); modalForm.resetFields(); if (record) { modalForm.setFieldsValue({ ...record, deptId: asId(record.deptId || selectedDept.id), deptName: record.deptName || selectedDept.deptName, }); } else { modalForm.setFieldsValue({ deptId: asId(selectedDept.id), deptName: selectedDept.deptName }); } setPositionModalOpen(true); }; const submitPosition = async (values) => { const request = currentId ? props.orgPositionEdit : props.orgPositionAdd; const payload = { ...values }; if (currentId) { payload.id = currentId; } payload.deptId = asId(values.deptId || selectedDept?.id); const res = await request(payload); if (res?.success !== false) { message.success(currentId ? "编辑成功" : "添加成功"); closePositionModal(); getPositionData(); } else { message.error(res?.message || "操作失败"); } }; return (
setFilterKeyword(e.target.value)} /> { setSelectedDept(toSelectedDept(node)); }} />
{selectedDept?.id ? ( <>
当前部门: {selectedDept.deptName}
( )} columns={[ { title: "名称", dataIndex: "positionName" }, { title: "职责", dataIndex: "dutyDesc" }, { title: "备注", dataIndex: "remark" }, { title: "操作", width: 160, render: (_, record) => ( ), }, ]} {...positionTableProps} /> ) : ( )} {deptModalOpen && ( )} {positionModalOpen && (
)} ); } function resolveLeaderAccount(dept, options) { if (dept?.leaderAccount) { return dept.leaderAccount; } if (dept?.leaderName) { const matched = options.find((item) => item.staffName === dept.leaderName); return matched?.value; } return undefined; } function DeptFormModal({ open, currentId, staffOptions, treeData, requestAdd, requestEdit, requestDetails, onCancel, onSuccess, }) { const [form] = Form.useForm(); const [submitting, setSubmitting] = useState(false); const [detailLoading, setDetailLoading] = useState(false); const staffOptionsRef = useRef(staffOptions); const treeDataRef = useRef(treeData); const requestDetailsRef = useRef(requestDetails); staffOptionsRef.current = staffOptions; treeDataRef.current = treeData; requestDetailsRef.current = requestDetails; useEffect(() => { if (!open) { return; } form.resetFields(); if (!currentId) { return; } let cancelled = false; setDetailLoading(true); const loadDetail = async () => { let dept = null; const getDetails = requestDetailsRef.current; if (typeof getDetails === "function") { const res = await safeRequest(getDetails, { id: currentId }); dept = res?.data || null; } if (!dept) { dept = findDeptNode(treeDataRef.current, currentId); } if (!cancelled && dept) { form.setFieldsValue({ ...dept, leaderAccount: resolveLeaderAccount(dept, staffOptionsRef.current), leaderName: dept.leaderName, }); } }; loadDetail().finally(() => { if (!cancelled) { setDetailLoading(false); } }); return () => { cancelled = true; }; }, [open, currentId]); const onLeaderChange = (account) => { const staff = staffOptions.find((s) => s.value === account); form.setFieldValue("leaderName", staff?.staffName || ""); }; const handleSubmit = async (values) => { try { setSubmitting(true); const request = currentId ? requestEdit : requestAdd; const payload = { ...values }; if (currentId) { payload.id = currentId; } const res = await request(payload); if (res?.success !== false) { message.success(currentId ? "编辑成功" : "添加成功"); form.resetFields(); onCancel(); await onSuccess(); } else { message.error(res?.message || "操作失败"); } } finally { setSubmitting(false); } }; return (
); } export default Connect([NS_ORG_DEPARTMENT, NS_ORG_POSITION, NS_STAFF_INFO], true)(DepartmentPositionPage);