import React, { useEffect, useState } from 'react'; import { notification, Tooltip, Modal, Spin, Empty } from 'antd'; import Tree from '@/components/ExpendableTree'; import { FileAddTwoTone, FolderAddTwoTone, FolderFilled, FileOutlined, DeleteTwoTone, } from '@ant-design/icons'; import classnames from 'classnames'; import styles from './webMenu.less'; import AddForm from './AddForm'; import EditForm from './editForm'; import CheckList from './checkBox'; import { addWebMenu, // 增 deleteWebMenu, // 删 editWebMenu, // 改 getWebMenuInfo, // 查 dragMenu, // 菜单拖拽 getProductList, getWebModuleTree, pEditWebMenu, } from '@/services/webConfig/api'; const MiniMenu = props => { const { menu, configFiles, subSystemValue, updateMenuTree, userMode, webid, } = props; const [flag, setFlag] = useState(1); // 刷新标志 const [loading, setLoading] = useState(false); // 加载 const [menuID, setMenuID] = useState(''); // 选中的树ID const [nodeType, setNodeType] = useState(''); // 选中的节点类型 const [info, setInfo] = useState({}); const [addVisible, setAddVisible] = useState(false); // 新增弹窗 const [addTwoVisible, setAddTwoVisible] = useState(false); // 编辑弹窗 const [delVisible, setDelVisible] = useState(false); // 删除弹窗 const [nodeObj, setNodeObj] = useState({}); const [addType, setAddType] = useState(''); // 添加下级类型 const [modalTitle, setModalTitle] = useState(''); const [roleList, setRoleList] = useState([]); // 复选框选中的值 const [modalLoading, setModalLoading] = useState(false); const [submitLoading, setSubmitLoading] = useState(false); const [newTreeList, setNewTreeList] = useState([]); const [productList, setProductList] = useState([]); // 选中的产品类型 const [menuList, setMenuList] = useState([]); // 菜单树 /* ***************************************************** */ const [curMenuType, setCurMenuType] = useState(''); // 获取菜单信息 useEffect(() => { getInfo(); }, [menuID, webid]); useEffect(() => { getProductList().then(res => { const { code } = res; if (code === 0) { const { data: { UserProducts }, } = res; if (UserProducts && UserProducts.length > 0) { setProductList(UserProducts); } // setProductList(data); } }); }, []); useEffect(() => { setLoading(true); getWebModuleTree(userMode || 'super') .then(res => { setLoading(false); const { code, data } = res; if (code === 0) { let arr = data .filter(item => item.id === 'Web4SingleStation') .map(r => r.children.filter(i => i.id === webid)) .flat(2); let arr2 = arr[0].children.find(item => item.text === '菜单管理').children || []; setMenuList(arr2 || []); } }) .catch(err => { setLoading(false); }); return () => { setLoading(false); }; }, [flag, webid]); useEffect(() => { setNewTreeList(menuList || []); }, [menuList]); // 处理数据 const mapTree = val => { const obj = { ...val }; const hasChild = obj.children.length > 0; return { title: ( <div className={styles.title}> <div>{obj.text}</div> <div className={styles.tip}> {obj.menuType === 'Web4MenuGroup' && ( <Tooltip title="新增菜单组" className={styles.fs}> <FolderAddTwoTone onClick={e => addMenuGroupTip(obj, e)} /> </Tooltip> )} {obj.menuType === 'Web4MenuGroup' && ( <Tooltip title="新增功能菜单" className={styles.fs}> <FileAddTwoTone onClick={e => addMenuTip(obj, e)} /> </Tooltip> )} <Tooltip title="删除菜单" className={styles.fs}> <DeleteTwoTone onClick={e => deleteMenuTip(obj, e)} /> </Tooltip> </div> </div> ), key: obj.menuID, icon: obj.menuType === 'Web4MenuGroup' ? <FolderFilled /> : <FileOutlined />, menuType: obj.menuType, children: hasChild ? obj.children.map(i => mapTree(i)) : [], }; }; // 树的点击事件 const handleSelect = (prop, treeNode) => { if (treeNode) { const { node: { menuType }, } = treeNode; setCurMenuType(menuType); switch (menuType) { case 'Web4MenuGroup': setNodeType(2); setAddType(2); break; default: setNodeType(1); setAddType(1); break; } } if (prop[0]) { setMenuID(prop[0]); } }; const getInfo = id => { if (!menuID) { return; } setLoading(true); getWebMenuInfo({ menuID, _dc: Date.now(), }) .then(res => { setLoading(false); if (res.success) { setInfo({ ...res }); } else { notification.error({ message: '提示', duration: 10, description: res.message || '获取失败', }); } }) .catch(err => { setLoading(false); console.error(err); }); }; // 删除的回调 const deleteMenuTip = (val, e) => { e.stopPropagation(); setModalTitle(val.text); setNodeObj(val); setDelVisible(true); }; const delMenu = () => { setModalLoading(true); deleteWebMenu({ menuID: nodeObj.menuID, _dc: Date.now(), }) .then(res => { setModalLoading(false); if (res.success) { setDelVisible(false); setFlag(flag + 1); setNodeType(''); setNodeObj(''); // updateMenuTree('delete', nodeObj); notification.success({ message: '提示', duration: 3, description: '删除成功', }); } else { notification.error({ message: '提示', duration: 10, description: res.message || '删除失败', }); } }) .catch(err => { setModalLoading(false); console.error(err); }); }; // 新增菜单组 const addMenuGroupTip = (val, e) => { e.stopPropagation(); setModalTitle(`在${val.text}下新增菜单组`); setNodeObj(val); setAddType(2); setAddVisible(true); }; const rootAddGroup = () => { setNodeObj(''); setModalTitle('新增最上级菜单组'); setAddType(2); setAddVisible(true); }; // 新增功能菜单 const addMenuTip = (val, e) => { e.stopPropagation(); setNodeObj(val); setModalTitle(`在${val.text}下新增功能菜单`); setAddType(1); setAddTwoVisible(true); }; const rootAdd = () => { setModalTitle('新增最上级功能菜单'); setNodeObj(''); setAddType(1); setAddTwoVisible(true); }; const handleGeturl = val => { let url; const isSite = val.includes('CityTemp'); if (isSite) { url = val; } else { url = localStorage.getItem('pd2-baseUrl') ? localStorage.getItem('pd2-baseUrl') + val : val; } return url; }; // 新增提交的回调 const submitCallback = (prop, item) => { setSubmitLoading(true); let baseUrl = handleGeturl(prop.imageUrl); let obj = { ...prop, baseUrl }; const parentID = item.menuID ? item.menuID : -1; addWebMenu({ _dc: Date.now(), parentID, subSystemValue, ...obj, }) .then(res => { setSubmitLoading(false); if (res.success) { setAddVisible(false); setAddTwoVisible(false); setFlag(flag + 1); // updateMenuTree('add', item); notification.success({ message: '提示', description: '新增成功', duration: 3, }); } else { notification.error({ message: '提示', description: res.message || '新增失败', duration: 10, }); } }) .catch(err => { setSubmitLoading(false); console.error(err); }); }; // 编辑的回调 const editSubmitCallback = prop => { setLoading(true); let baseUrl = handleGeturl(prop.imageUrl); let obj = { ...prop, baseUrl }; if (nodeType === 1) { obj.relatedRoleList = String(roleList) || ''; editWebMenu({ _dc: Date.now(), menuID, // subSystemValue, ...obj, }) .then(res => { setLoading(false); if (res.success) { setFlag(flag + 1); // updateMenuTree('edit'); notification.success({ message: '提示', duration: 3, description: '编辑成功', }); } else { notification.error({ message: '提示', duration: 3, description: res.message || '编辑失败', }); } }) .catch(err => { // eslint-disable-next-line no-console console.error(err); setLoading(false); }); } else { pEditWebMenu({ _dc: Date.now(), menuID, // subSystemValue, ...obj, }) .then(res => { setLoading(false); if (res.success) { setFlag(flag + 1); // updateMenuTree('edit'); notification.success({ message: '提示', duration: 3, description: '编辑成功', }); } else { notification.error({ message: '提示', duration: 3, description: res.message || '编辑失败', }); } }) .catch(err => { // eslint-disable-next-line no-console console.error(err); setLoading(false); }); } }; const valueCallback = val => { let arr = [...val]; let arr2 = []; arr.map(item => { if (item.related) { arr2.push(item.relatedRoleCode); } }); setRoleList(arr2); }; // 树的拖动 const handleDrop = infos => { const { pos } = infos.node.props; const dragKey = infos.dragNode.props.eventKey; const dragPos = infos.dragNode.props.pos.split('-'); // 拖动的节点 const dropKey = infos.node.props.eventKey; const dropPos = infos.node.props.pos.split('-'); // 拖动结束的节点 const endIndex = Number(dropPos[dropPos.length - 1]); const dropPosition = infos.dropPosition - Number(dropPos[dropPos.length - 1]); // let obj = findNum(newTreeList, dragKey, getArrList); let obj; findNum(newTreeList, dragKey, (arr, id, parentId, index) => { obj = { arr, id, parentId, index }; return { arr, id, parentId, index }; }); let arrList = []; if ( dragPos.length !== dropPos.length || dragPos[dragPos.length - 2] !== dropPos[dropPos.length - 2] ) { notification.warning({ message: '提示', duration: 3, description: '操作失败', }); return null; } let idIndex; obj.arr.map((item, index) => { if (item.menuID === obj.id) { idIndex = index; return; } arrList.push(item.menuID); }); if (idIndex > endIndex) { if (dropPosition === -1) { arrList.splice(endIndex, 0, obj.id); } else if (dropPosition === 1) { arrList.splice(endIndex + 1, 0, obj.id); } } else if (idIndex < endIndex) { if (dropPosition === -1) { arrList.splice(endIndex - 1, 0, obj.id); } else if (dropPosition === 1) { arrList.splice(endIndex, 0, obj.id); } } dragMenu({ menuID: obj.id, newParentID: obj.parentId || -1, menuList: String(arrList) || '', _version: 9999, _dc: Date.now(), }).then(res => { if (res.success) { // updateMenuTree(); setFlag(flag + 1); } else { notification.error({ message: '提示', duration: 3, description: res.message || '操作失败', }); } }); }; const findNum = (array, id, callback, parentId = '') => { let ptId = parentId; let arrFlag = true; array.map((item, index) => { if (item.menuID === id) { callback(array, id, parentId, index); arrFlag = false; return; } if (arrFlag && item.children && item.children.length > 0) { ptId = item.menuID; findNum(item.children, id, callback, ptId); } }); }; return ( <Spin spinning={loading} tip="loading..."> <div className={classnames({ [styles.box]: true, })} > <div className={classnames({ [styles.left]: true, })} > <div className={classnames({ [styles.leftTop]: true, })} > 菜单列表 <div className={classnames(styles.tRight)}> <Tooltip title="新增最上级菜单组"> <FolderAddTwoTone className={`${styles.icon1} ${styles.icon}`} onClick={() => rootAddGroup()} /> </Tooltip> <Tooltip title="新增最上级功能菜单"> <FileAddTwoTone onClick={() => rootAdd()} className={`${styles.icon2} ${styles.icon}`} /> </Tooltip> </div> </div> {menuList.length > 0 && ( <Tree showIcon onSelect={handleSelect} treeData={menuList.map(item => mapTree(item))} blockNode draggable autoExpandParent selectedKeys={[menuID]} onDrop={handleDrop} // expandedKeys={[menuID]} /> )} </div> <Modal visible={addVisible} title={modalTitle} bodyStyle={{ width: '100%', minHeight: '100px' }} style={{ top: 80 }} width="600px" destroyOnClose footer={null} cancelText="取消" okText="确认" maskClosable={false} onCancel={() => setAddVisible(false)} onConfirm={() => { submitCallback(); }} > <AddForm nodeObj={nodeObj} addType={addType} configFiles={configFiles} submitCallback={submitCallback} submitLoading={submitLoading} productList={productList} /> </Modal> <Modal visible={addTwoVisible} title={modalTitle} bodyStyle={{ width: '100%', minHeight: '100px' }} style={{ top: 80 }} width="600px" destroyOnClose footer={null} maskClosable={false} cancelText="取消" okText="确认" onCancel={() => setAddTwoVisible(false)} > <AddForm submitLoading={submitLoading} nodeObj={nodeObj} configFiles={configFiles} addType={addType} productList={productList} submitCallback={submitCallback} /> </Modal> <Modal visible={delVisible} title="请确认" bodyStyle={{ width: '100%', minHeight: '100px' }} style={{ top: 80 }} width="400px" destroyOnClose cancelText="取消" okText="确认" maskClosable={false} onCancel={() => setDelVisible(false)} onOk={() => delMenu()} confirmLoading={modalLoading} > 是否删除<span style={{ color: 'red' }}>{modalTitle}</span>? </Modal> <div className={classnames({ [styles.middle]: true, })} > 菜单配置 {nodeType ? ( <EditForm nodeType={nodeType} info={info} configFiles={configFiles} productList={productList} submitCallback={editSubmitCallback} valueCallback={valueCallback} /> ) : ( <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="当前未选中菜单" /> )} </div> {/* <div className={classnames({ [styles.rightBox]: true, })} > 关联角色 <CheckList info={info} nodeType={nodeType} valueCallback={valueCallback} /> </div> */} </div> </Spin> ); }; export default MiniMenu;