import React, { useEffect, useState, useRef } from 'react'; import { useHistory } from 'react-router-dom'; import classnames from 'classnames'; import { Tabs, Input, message, Modal, Button, Anchor, Tooltip, notification } from 'antd'; import { PlusOutlined, EditOutlined, DeleteOutlined, ExclamationCircleOutlined, HighlightOutlined, UnorderedListOutlined, FilePdfOutlined, } from '@ant-design/icons'; import gsap, { TweenMax, TimelineMax, ScrollToPlugin } from 'gsap/all'; import FlowModal from './workFlowComponents/FlowModal'; import FlowGroupModal from './workFlowComponents/FlowGroupModal'; import Order from './workFlowComponents/Order'; import styles from './WorkflowHomePage.less'; import { WFGetAllFlow, GetFlowNode, DeleteFlow, CheckDoingFlowNodes, CloseDoingFlowNodes, } from '@/services/workflow/workflow'; import { DownLoadFiles } from '@/services/common/api'; import { UpdateFlowGroup } from '@/services/workflow/workflow'; const plugins = [ScrollToPlugin]; const { Search } = Input; const { Link } = Anchor; const { confirm } = Modal; const path = require('path'); const WorkflowHomePage = () => { const history = useHistory(); const [flowList, setFlowList] = useState([]); // 流程列表 const [currentList, setCurrentList] = useState([]); // 当前tab显示列表 const [modalType, setModalType] = useState(null); // 弹窗类型是编辑还是新增 const [editMsg, setEditMsg] = useState({}); // 弹窗编辑回显 const [editIndex, setEditIndex] = useState(); // 编辑流程组得索引 const [hoverIndex, setHoverIndex] = useState(); const [flowNames, setFlowNames] = useState([]); const [flowTableScroll, setFlowTableScroll] = useState(0); const [visible, setVisible] = useState({ FlowModal: false, FlowGroupModal: false, order: false, }); // 弹窗显示 const [flag, setFlag] = useState(0); const activeKey = useRef(null); const isClick = useRef(false); const scrollTimer = useRef(); useEffect(() => { gsap.registerPlugin(ScrollToPlugin); getFlowList(); let flowTable = document.querySelector(`.${styles.flowTable}`); flowTable.addEventListener('scroll', setScroll); return () => { flowTable.removeEventListener('scroll', setScroll); }; }, []); useEffect(() => { clearTimeout(scrollTimer.current); scrollTimer.current = setTimeout(() => { // todo something scroll end isClick.current = false; }, 50); console.log(isClick.current, 'isClick.current'); if (isClick.current) { return; } flowList.forEach(item => { let groupSrolltop = document.getElementById(`${item.name}`)?.offsetTop; if (groupSrolltop <= flowTableScroll) { activeKey.current = item.name; setFlag(flag + 1); } }); }, [flowTableScroll]); useEffect(() => { console.log(history.location.state, 'history.location.state'); if (modalType) { if (modalType === 'add') { console.log('addsaasddfas'); isClick.current = true; setTimeout(() => { TweenMax.to(`.${styles.flowTable}`, 0.5, { scrollTo: { y: `#${activeKey.current}` } }); }, 0); } setModalType(null); return; } if (history.location.state) { console.log(document.querySelector(`.${styles.flowTable}`)); activeKey.current = history.location.state.activeKey; isClick.current = true; setTimeout(() => { TweenMax.to(`.${styles.flowTable}`, 0.5, { scrollTo: { y: history.location.state.scrollTop }, }); // let flowTable = document.querySelector(`.${styles.flowTable}`); // document.querySelector(`.${styles.flowTable}`).scrollTop = history.location.state.scrollTop; }, 0); } }, [flowList]); const setScroll = () => { let flowTable = document.querySelector(`.${styles.flowTable}`); setFlowTableScroll(flowTable.scrollTop); }; // 获取所有数据 const getFlowList = () => { WFGetAllFlow().then(res => { if (res.code === 0) { let flowNameList = []; let list = res.data.map((item, index) => { item.children.forEach(ele => { flowNameList.push(ele.FlowName); ele.PreviewImage = getImgUrl(ele.PreviewImage); }); item.isOld = true; item.bgType = (index + 1) % 5; return item; }); setFlowList(list); console.log(activeKey.current, 'activeKey'); // if (activeKey.current) { // setCurrentList(list.filter(item => item.name === activeKey.current)); // } else { // setCurrentList(list); // } setCurrentList(list); console.log(flowNameList, 'flowNameList'); setFlowNames(flowNameList); } else { message.error(res.msg); } }); }; // 弹窗显示控制 const showModal = (key, value) => { setVisible({ ...visible, [key]: value }); }; // 查看所有 const chageAll = () => { // setActiveKey(null); activeKey.current = null; setCurrentList(flowList); }; // 搜索 const onSearch = val => { // let copyList = JSON.parse(JSON.stringify(flowList)); // let list = activeKey.current // ? copyList.filter(item => item.name === activeKey.current) // : copyList; let list = JSON.parse(JSON.stringify(flowList)); if (val) { list.forEach(item => { item.children = item.children.filter(ele => ele.FlowName.includes(val)); }); } isClick.current = true; activeKey.current = list[0].name; setCurrentList(list); setFlag(flag + 1); setTimeout(() => { document.querySelector(`.${styles.flowTable}`).scrollTop = 0; }, 0); }; // 切换tab const onChange = val => { isClick.current = true; console.log(val); let flowTable = document.querySelector(`.${styles.flowTable}`); console.log(flowTable.scrollTop, 'flowTable'); TweenMax.to(`.${styles.flowTable}`, 0.5, { scrollTo: { y: `#${val}` } }); let copyList = JSON.parse(JSON.stringify(flowList)); let list = copyList.filter(item => item.name === val); activeKey.current = val; setFlag(flag + 1); // setCurrentList(list); // setActiveKey(val); }; // 编辑流程 const editFlow = (val, e) => { e.stopPropagation(); showModal('FlowModal', true); setModalType('edit'); setEditMsg(val); }; // 新增流程 const addFlow = val => { showModal('FlowModal', true); setEditMsg(val); setModalType('add'); }; // 添加流程组 const addFlowGroup = () => { showModal('FlowGroupModal', true); setModalType('add'); }; // 编辑流程组 const eiditFlowGroup = (val, index) => { setEditIndex(index); showModal('FlowGroupModal', true); setModalType('edit'); setEditMsg(val); }; // 编辑组回调 const groupCallBack = val => { activeKey.current = val; showModal('FlowGroupModal', false); // 编辑老数据需要掉接口更新新数据手动修改数据,新增插入一条数据 if (modalType === 'edit' && editMsg.isOld) { getFlowList(); } else if (modalType === 'edit') { let newflowList = [...flowList]; // newflowList[editIndex].name = val; setFlowList(newflowList); setCurrentList(newflowList.filter(item => item.name === activeKey.current)); } else { setCurrentList([{ name: val, children: [] }]); setFlowList([...flowList, { name: val }]); } }; const chooseNode = val => { let scroll = document.querySelector(`.${styles.flowTable}`).scrollTop; GetFlowNode({ flowID: val.FlowID }).then(res => { if (res.code === 0) { res.data.Nodes.forEach(item => { item.nodeDetail = JSON.stringify(item); }); setModalType(null); history.push({ pathname: '/biz/workflow/flowBoard', state: { scrollTop: scroll, flowData: { ...res.data, flowName: val.FlowName }, flowID: val.FlowID, chartLoading: false, activeKey: activeKey.current, flowTree: flowList, }, }); } else { message.error(res.msg); } }); }; // 删除流程 const delFlow = async (val, e) => { e.stopPropagation(); let res1 = await CheckDoingFlowNodes({ flowID: val.FlowID }); if (res1.code === 0) { if (res1.data > 0) { confirm({ title: '确定要删除当前流程吗?', icon: <ExclamationCircleOutlined />, content: <div>当前流程有{res1.data}条在办工单,确定删除会自动归档在办工单。</div>, okText: '是', okType: 'danger', cancelText: '否', onOk() { CloseDoingFlowNodes({ flowID: val.FlowID }).then(res2 => { if (res2.code === 0) { DeleteFlow({ FlowId: val.FlowID }) .then(res3 => { if (res3.code === 0) { setModalType('del'); getFlowList(); message.success('删除成功'); } else { message.error({ content: ( <div style={{ whiteSpace: 'pre-line', textAlign: 'justify' }}> {res3.msg} </div> ), }); } }) .catch(() => { message.error('网络异常请稍后再试'); }); } else { message.error(res2.msg); } }); }, onCancel() {}, }); } else { confirm({ title: '确定要删除吗?', icon: <ExclamationCircleOutlined />, content: '', okText: '是', okType: 'danger', cancelText: '否', onOk() { DeleteFlow({ FlowId: val.FlowID }) .then(res2 => { if (res2.code === 0) { setModalType('del'); getFlowList(); message.success('删除成功'); } else { message.error({ content: ( <div style={{ whiteSpace: 'pre-line', textAlign: 'justify' }}>{res2.msg}</div> ), }); } }) .catch(() => { message.error('网络异常请稍后再试'); }); }, onCancel() {}, }); } } else { message.error(res1.msg); } }; const getImgUrl = img => { // return new Promise((resolve, reject) => { // DownLoadFiles({ module: '图库', filePath: img }).then(res => { // let reader = new FileReader(); // reader.readAsDataURL(res); // reader.onload = () => resolve(reader.result); // }); // });a return `/PandaOMS/OMS/FileCenter/DownLoadFiles?module=熊猫智慧水务平台\\WorkFlowImage&filePath=${img}`; }; // tab栏选项渲染 const tabRender = (val, index) => ( <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-around' }}> {val.name}({val.count}) {/* {val.name === activeKey.current ? ( <EditOutlined onClick={() => eiditFlowGroup(val, index)} style={{ marginLeft: '5px' }} /> ) : ( '' )} */} </div> ); const toFlowGroup = (e, val) => { e.preventDefault(); let flowTable = document.querySelector(`.${styles.flowTable}`); console.log(`.${styles.flowTable}`); TweenMax.to(`.${styles.flowTable}`, 1, { scrollTo: val.href }); }; const updateFlowGroup = (oldName, newName) => { if (oldName === newName) { return; } UpdateFlowGroup({ oldName, newName, }).then(res => { if (res.code === 0) { notification.success({ message: '提示', duration: 3, description: '编辑成功', }); getFlowList(); } else { notification.error({ message: '提示', duration: 3, description: res.msg, }); } }); }; return ( <div className={classnames(styles.pageContent, { [styles.pageOms]: sessionStorage.getItem('_omsticket') !== 'd438aaf9578f405299ae740c4eb75aae', [styles.pageEmbed]: sessionStorage.getItem('_omsticket') === 'd438aaf9578f405299ae740c4eb75aae', })} > <div className={styles.headerBox}> <div className={styles.left}> <div className={classnames(styles.allFlows, { [styles.allFlowsChoose]: true })} // onClick={chageAll} /> <div className={styles.flows}> {/* <Anchor affix={false} onClick={toFlowGroup}> {flowList.map((item, index) => ( <Link href={`#${item.name}`} title={item.name} key={item.name} /> ))} </Anchor> */} <div className={styles.tabBox}> {flowList.map((item, index) => ( <div className={classnames(styles.tab, { [styles.activeTab]: item.name === activeKey.current, })} onClick={() => onChange(item.name)} key={item.name} > {item.name}({item.count}) </div> ))} </div> {/* <Tabs activeKey={activeKey.current} type="card" onChange={onChange} animated={false}> {flowList.map((item, index) => ( <Tabs.TabPane tab={tabRender(item, index)} key={item.name} /> ))} </Tabs> */} </div> </div> <div className={styles.right} onClick={() => { showModal('order', true); }} > {/* <div className={styles.icon} /> */} <UnorderedListOutlined style={{ marginRight: '5px' }} /> <div>流程排序</div> </div> </div> <div className={styles.controlBox}> <div className={styles.left}> 总计: <span>{currentList.reduce((sum, p) => p.children.length + sum, 0)}</span> </div> <div className={styles.right}> <div className={styles.btn} onClick={() => addFlow(currentList[0])}> <PlusOutlined style={{ marginRight: '5px' }} /> 新增流程 </div> <Search placeholder="输入关键字搜索" allowClear onSearch={onSearch} style={{ width: 490, }} /> </div> <div className={styles.showPDF}> <Tooltip title="点击查看对接文档"> <a style={{ display: 'inline-block', marginTop: '5px', marginRight: '20px' }} target="_blank" href={path.join(__dirname, '/civmanage/熊猫第三方工单对接说明文档.pdf')} rel="noopener noreferer" > <FilePdfOutlined style={{ fontSize: '24px' }} /> </a> </Tooltip> </div> </div> <div className={styles.flowTable}> {currentList.map((item, index) => ( <div className={styles.flowGroup} key={item.name} id={item.name}> <div className={styles.header} style={{ display: item.children.length > 0 ? 'flex' : 'none' }} > <div className={styles.line} /> <div className={styles.name} contenteditable="true"> <Input style={{ width: item.name.length * 14 + 'px', fontSize: '14px', padding: '0', }} placeholder="请输入分组名称" onBlur={e => { updateFlowGroup(item.name, e.currentTarget.value); }} bordered={false} defaultValue={item.name} onInput={e => { e.currentTarget.style.width = e.currentTarget.value.length * 14 + 'px'; }} // onPressEnter={e => { // console.log(e, '触发咯'); // }} /> </div> <EditOutlined style={{ marginLeft: '5px' }} onClick={() => eiditFlowGroup(item, index)} /> </div> <div className={styles.groupBox}> {item.children.map((ele, num) => ( <div className={styles.flowBox} type={item.bgType} key={ele.Code} onMouseEnter={() => setHoverIndex(JSON.stringify([index, num]))} onMouseLeave={() => setHoverIndex(null)} > <div className={styles.header}> <div className={styles.title}>{ele.FlowName}</div> <div className={styles.editBtn} onClick={e => editFlow(ele, e)}> <EditOutlined /> 修改 </div> </div> <div className={styles.imgBox}> <div className={classnames(styles.mask, { [styles.maskHover]: JSON.stringify([index, num]) === hoverIndex, })} /> <div className={classnames(styles.buttonBox, { [styles.buttonHover]: JSON.stringify([index, num]) === hoverIndex, })} > <div className={styles.lookDetail}> <Button type="primary" onClick={() => chooseNode(ele)} style={{ background: '#3D78FF', color: '#fff', opacity: 1 }} > 设计 </Button> {/* <HighlightOutlined onClick={e => chooseNode(ele, e)} /> */} </div> <div className={styles.delete}> <Button style={{ background: '#fff', border: '1px solid #FF4D4F', color: '#FF4D4F', opacity: 1, }} type="primary" onClick={e => delFlow(ele, e)} > 删除 </Button> {/* <DeleteOutlined onClick={e => delFlow(ele, e)} /> */} </div> </div> {ele.PreviewImage ? ( // <img // src={`${ // window.location.origin // }/PandaOMS/OMS/FileCenter/DownLoadFiles?filePath=${ele.PreviewImage}`} // /> // <img src={`${window.location.origin}/${ele.PreviewImage}`} /> <img src={ele.PreviewImage} /> ) : ( <img className={styles.noDataImg} src={require('../../../../assets/images/common/noData.png')} /> )} </div> <div className={styles.bottom}> <div className={styles.left}>{ele.CreateUser || ''}</div> <div className={styles.right}>更新于{ele.UpdateTime || '--'}</div> </div> </div> ))} </div> </div> ))} </div> {/* 添加流程弹窗 */} <FlowModal visible={visible.FlowModal} msg={editMsg} modalType={modalType} handleCancel={() => showModal('FlowModal', false)} keep={flowNames} treeData={flowList} onSubumit={val => { activeKey.current = val; showModal('FlowModal', false); getFlowList(); }} /> {/* 创建分组弹窗 */} <FlowGroupModal visible={visible.FlowGroupModal} msg={editMsg} modalType={modalType} handleCancel={() => showModal('FlowGroupModal', false)} treeData={flowList} keep={flowNames} onSubumit={val => groupCallBack(val)} /> {/* 排序弹窗 */} <Order visible={visible.order} processData={flowList} handleCancel={() => showModal('order', false)} submitCallBack={() => { // activeKey.current = currentList[0]; showModal('order', false); getFlowList(); }} /> </div> ); }; export default WorkflowHomePage;