import { doFetch } from "@/utils/doFetch"; import { ArrowDownOutlined, ArrowRightOutlined } from "@ant-design/icons"; import AddIcon from "@mui/icons-material/Add"; import BorderColorIcon from "@mui/icons-material/BorderColor"; import HorizontalRuleIcon from "@mui/icons-material/HorizontalRule"; import { Box, colors, IconButton, Typography } from "@mui/material"; import { useRequest } from "ahooks"; import { Input, message, Modal, Popconfirm, Tooltip, Tree } from "antd"; import { useEffect, useMemo, useState } from "react"; import "./index.less"; { /* <TreeRender url="/ngic-workmanship/pmMaterieType/queryTreeList" deleteurl="/ngic-workmanship/pmMaterieType/deleteById" saveurl="/ngic-workmanship/pmMaterieType/save" onselected={(vals) => { setmaterieTypeId(vals[0] ?? ""); }} /> */ } let { Search } = Input; 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) => { return item.key === key; }) ) { parentKey = node.key; } else if (getParentKey(key, node.children)) { parentKey = getParentKey(key, node.children); } } } return parentKey; }; function TreeRender({ url, deleteurl, saveurl, onselected, params, noaction, maxWidth, style, submitKey, courseId, }) { const [search, setsearch] = useState(""); const [savetitle, setsavetitle] = useState(null); const [modal, setModal] = useState({ visible: false, }), [drawer, setDrawer] = useState({ item: null, open: false, }); const [expandall, setexpandall] = useState(false); const [expandedKeys, onExpand] = useState(); const { data, refresh, loading } = useRequest(() => { return doFetch({ url, params: params ?? {} }); }); const [autoExpandParent, setAutoExpandParent] = useState(true); const allkeys = useMemo(() => { let res = []; const fn = (source) => { source?.map((el) => { res.push(el); el.children && el.children.length > 0 ? fn(el.children) : ""; // 子级递归 }); }; fn(data?.data?.dataList ?? []); return res.filter((it) => it.children).map((it) => it.key); }, [data]); const alldata = useMemo(() => { let res = []; const fn = (source) => { source?.map((el) => { res.push(el); el.children && el.children.length > 0 ? fn(el.children) : ""; // 子级递归 }); }; fn(data?.data?.dataList ?? []); return res; }, [data]); const treeData = useMemo(() => { let res = data?.data?.dataList ?? []; return [ ...res, // { // title: "查看实验", // key: "cksy", // }, // { // title: "常见问题", // key: "cjwt", // }, ]; }, [data]); const onChange = (e) => { const { value } = e.target; const dataLists = getAllList(); const newExpandedKeys = dataLists .map((item) => { if (item.title.indexOf(value) > -1) { return getParentKey(item.key, treeData); } return null; }) .filter((item, i, self) => item && self.indexOf(item) === i); setsearch(value); if (newExpandedKeys.length > 0) { setexpandall(true); setAutoExpandParent(true); } else { setexpandall(false); setAutoExpandParent(false); } onExpand(newExpandedKeys); }; const loop = (data) => data.map((item) => { const index = item.title.indexOf(search); const beforeStr = item.title.substr(0, index); const afterStr = item.title.substr(index + search.length); let title = index > -1 ? ( <Tooltip title={item.title} placement="topRight"> <span style={{ display: "block", maxWidth: maxWidth ?? 88, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", marginRight: 6, }} > {beforeStr} <span style={{ color: "#f50" }}>{search}</span> {afterStr} </span> </Tooltip> ) : ( <Tooltip title={item.title} placement="topRight"> <span style={{ display: "block", maxWidth: maxWidth ?? 100, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", marginRight: 6, }} > {item.title} </span> </Tooltip> ); const actiontitle = ( <div className="tree-item" style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "4px 6px", }} > <span style={{ marginRight: 6 }}>{title}</span> <div className="center" style={{ gap: 8 }}> {item.key && item.key != "00000000" && ( <Tooltip title="编辑" onClick={(e) => { e.stopPropagation(); setsavetitle(null); if (true) { setModal({ visible: true, closable: true, title: "修改节点名称", okText: "修改", cancelText: "取消", placeholder: item.title, key: item.key, }); } }} > <div className="bgs"> <BorderColorIcon style={{ color: "#1890ff", fontSize: 14 }} /> </div> </Tooltip> )} {item.key && item.key != "00000000" && item.children && ( <Tooltip title="新增"> <div className="bgs"> <AddIcon disabled={false} onClick={(e) => { e.stopPropagation(); setsavetitle(null); if (true) { setModal({ visible: true, closable: true, title: "新增子结构", okText: "新增", cancelText: "取消", placeholder: item.title, key: item.key, }); } }} style={{ color: `${true ? "green" : ""}`, fontSize: 20, }} /> </div> </Tooltip> )} {item.key != "0" && ( <Popconfirm placement="top" title="是否删除该节点?" okText="删除" cancelText="取消" onConfirm={() => { doFetch({ url: deleteurl, params: { id: item.key } }).then( (res) => { if (res.code == "0000") { message.success("操作成功"); refresh(); } } ); }} > <Tooltip title="删除" placement="bottom"> <div className="bgs"> <HorizontalRuleIcon style={{ color: "red", fontSize: 16 }} /> </div> </Tooltip> </Popconfirm> )} {/* { item.key === "00000000" && <Divider type='vertical' style={{ margin: "0 6px" }}></Divider> } */} {/* { item.key === "00000000" && <Tooltip title={expandall ? "收起" : "展开"} onClick={(e) => { e.stopPropagation(); setexpandall(!expandall) onExpand(expandall ? [] : allkeys) }}> {expandall ? <ArrowDownOutlined /> : <ArrowRightOutlined />} </Tooltip> } */} </div> </div> ); if (item.key === "00000000") { title = ( <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", flex: 1, }} > {title} <Tooltip title={expandall ? "收起" : "展开"} onClick={(e) => { e.stopPropagation(); setexpandall(!expandall); onExpand(expandall ? [] : allkeys); setAutoExpandParent(!expandall); }} > {expandall ? <ArrowDownOutlined /> : <ArrowRightOutlined />} </Tooltip> </div> ); } if (item.children) { return { title: noaction ? title : actiontitle, key: item.key, children: loop(item.children), level: item.level, type: item.type, }; } return { title: noaction ? title : actiontitle, key: item.key, level: item.level, type: item.type, icon: item.icon ?? null, }; }); useEffect(() => { setexpandall(true); onExpand(allkeys); }, [allkeys]); function getAllList() { const dataLists = []; const generateLists = (data) => { for (let i = 0; i < data.length; i++) { const node = data[i]; const key = node.key; dataLists.push({ key, title: node.title, level: node.level }); if (node.children) { generateLists(node.children, node.key); } } }; generateLists(treeData); return dataLists; } return ( <> <Box flexDirection={"row"} display={"flex"} justifyContent={"space-between"} alignItems={"center"} mt={0} > <Typography variant="h6">课程目录</Typography> <IconButton onClick={() => { setDrawer({ open: true }); }} > <AddIcon style={{ fontSize: 20, color: colors.blue[600] }}></AddIcon> </IconButton> <Modal {...drawer} closable={false} maskClosable={true} title="新增章标题" okText="新增" cancelText="取消" onCancel={() => { setDrawer(() => ({ item: null, open: false, })); }} okButtonProps={{ loading, }} onOk={() => { return new Promise((resolve, reject) => { if (drawer?.item) { doFetch({ url: "/sysCourseTrain/saveOrUpdateCatalogue", params: { courseId, catalogue: drawer.item, }, }).then((res) => { if (res.code == "0000") { message.success("操作成功"); refresh(); setDrawer({ item: null, open: false, }); } }); refresh(); resolve(); } else { message.warning("请输入修改的名称"); reject(); } }); }} > <div> <Input placeholder="请输入章标题" allowClear value={drawer?.item} onChange={(e) => { setDrawer((v) => ({ ...v, item: e.target.value, })); }} ></Input> </div> </Modal> </Box> <div style={{ ...style }}> <Modal {...modal} onCancel={() => { setModal((s) => ({ ...s, visible: false, })); }} okButtonProps={{ loading, }} onOk={() => { if (modal.okText == "修改") { return new Promise((resolve, reject) => { if (savetitle) { doFetch({ url: saveurl, params: { [submitKey]: savetitle, id: modal.key, courseId, }, }).then((res) => { if (res.code == "0000") { message.success("操作成功"); refresh(); setModal({ visible: false, }); } }); resolve(); } else { message.warning("请输入修改的名称"); reject(); } }); } else { return new Promise((resolve, reject) => { if (savetitle) { doFetch({ url: saveurl, params: { [submitKey]: savetitle, parentId: modal.key, courseId, }, }).then((res) => { if (res.code == "0000") { message.success("操作成功"); refresh(); setModal({ visible: false, }); } }); resolve(); } else { message.warning("请输入修改的名称"); reject(); } }); } }} > {modal.okText == "修改" ? ( <div> <Input placeholder={modal.placeholder} allowClear value={savetitle} onChange={(e) => { setsavetitle(e.target.value); }} ></Input> </div> ) : ( <div> <div style={{ marginBottom: 15, color: "#f50", fontSize: 16 }}> 当前结构:{modal.placeholder} </div> <Input placeholder="子结构" allowClear onChange={(e) => { setsavetitle(e.target.value); }} ></Input> </div> )} </Modal> <Search value={search} style={{ margin: "16px 0 8px 0" }} placeholder="搜索" onChange={onChange} /> <Tree showIcon showLine onSelect={(selectedKeys, e) => { // //console.log(selectedKeys); onselected?.(selectedKeys, e, alldata); }} autoExpandParent={autoExpandParent} defaultExpandAll={true} expandedKeys={expandedKeys} onExpand={(expandedKeys, { expanded: bool, node }) => { onExpand(expandedKeys); setAutoExpandParent(false); if (!bool && node.key == "00000000") { setexpandall(false); } else { setexpandall(true); } }} treeData={loop(treeData ?? [])} > {/* {loop(treeData ? treeData : [])} */} </Tree> </div> </> ); } export default TreeRender;