diff --git a/.umirc.ts b/.umirc.ts index b736ce4..bda2586 100644 --- a/.umirc.ts +++ b/.umirc.ts @@ -13,14 +13,15 @@ export default defineConfig({ { path: '/user', component: '@/pages/user' }, { path: '/company', component: '@/pages/company' }, { path: '/dragtree', component: '@/pages/dragTree' }, + { path: '/statistics', component: '@/pages/statisticsTable' }, ], fastRefresh: {}, antd: {}, proxy: { '/api': { // 标识需要进行转换的请求的url - //target: 'http://127.0.0.1:8686/api', // 服务端域名 / http://localhost:8686 - target: 'http://221.226.25.34:11080/api', + target: 'http://127.0.0.1:8686/api', // 服务端域名 + //target: 'http://221.226.25.34:11080/api', changeOrigin: true, // 允许域名进行转换 pathRewrite: { '^/api': '' }, // 将请求url里的ci去掉 }, diff --git a/dist.zip b/dist.zip deleted file mode 100644 index a35ae0b..0000000 Binary files a/dist.zip and /dev/null differ diff --git a/public/img/back/background.png b/public/img/back/background.png new file mode 100644 index 0000000..e1175ef Binary files /dev/null and b/public/img/back/background.png differ diff --git a/public/img/back/inset.png b/public/img/back/inset.png new file mode 100644 index 0000000..b1c1e6a Binary files /dev/null and b/public/img/back/inset.png differ diff --git a/src/components/dialog/copyDialog.jsx b/src/components/dialog/copyDialog.jsx index 3e3d296..ac89253 100644 --- a/src/components/dialog/copyDialog.jsx +++ b/src/components/dialog/copyDialog.jsx @@ -1,25 +1,39 @@ -import { Form, Input, Modal, TreeSelect, message } from 'antd'; -import React, { useState, useEffect } from 'react'; +import { Form, Input, Modal, TreeSelect, message, Checkbox } from 'antd'; +import React, { + useState, + useEffect, + useRef, + forwardRef, + useImperativeHandle, +} from 'react'; import * as d3 from 'd3'; import './index.less'; +import { HomeOutlined } from '@ant-design/icons'; +import './index.less'; const layout = { - labelCol: { span: 6 }, + labelCol: { span: 8 }, wrapperCol: { span: 14 }, }; -const CopyDialog = ({ open, onCreate, onCancel }) => { +const CopyDialog = forwardRef(({ open, onCreate, onCancel }, ref) => { + const [treeData, setData] = useState([]); const [form] = Form.useForm(); + const formRef = useRef(null); - const [treeData, setData] = useState([]); - console.log(treeData); - useEffect(() => { - d3.json('/api/bs/hrmorganization/orgchart/getSubCompanyTree').then( - (data) => { - setData(data.companyTree); - }, - ); - }, [true]); + useImperativeHandle(ref, () => ({ + getTreeData() { + form.resetFields(); + d3.json('/api/bs/hrmorganization/orgchart/getSubCompanyTree').then( + (data) => { + data.companyTree.map((item, index) => { + item.icon = ; + }); + setData(data.companyTree); + }, + ); + }, + })); /** * 根节点树异步加载 @@ -33,7 +47,9 @@ const CopyDialog = ({ open, onCreate, onCancel }) => { d3.json( `/api/bs/hrmorganization/orgchart/getSubCompanyTree?subcompany=${id}`, ).then((data) => { - debugger; + data.companyTree.map((item, index) => { + item.icon = ; + }); let arr = [...treeData, ...data.companyTree]; setData(arr); }); @@ -59,41 +75,38 @@ const CopyDialog = ({ open, onCreate, onCancel }) => { }); }} > -
+ - +
); -}; +}); export default CopyDialog; diff --git a/src/components/dialog/index.less b/src/components/dialog/index.less index b286550..1e3cc83 100644 --- a/src/components/dialog/index.less +++ b/src/components/dialog/index.less @@ -1,3 +1,5 @@ -.ant-tree .ant-tree-treenode-disabled .ant-tree-node-content-wrapper { - color: #222526; +.ant-select-tree + .ant-select-tree-treenode-disabled + .ant-select-tree-node-content-wrapper { + color: rgba(0, 0, 0, 0.85); } diff --git a/src/components/dialog/mergeDialog.jsx b/src/components/dialog/mergeDialog.jsx index 7c9cb59..1cb38e3 100644 --- a/src/components/dialog/mergeDialog.jsx +++ b/src/components/dialog/mergeDialog.jsx @@ -8,6 +8,8 @@ import React, { } from 'react'; import * as d3 from 'd3'; import './index.less'; +import { HomeOutlined, FolderOutlined } from '@ant-design/icons'; +import './index.less'; const layout = { labelCol: { span: 6 }, @@ -19,11 +21,16 @@ const MergeDialog = forwardRef(({ open, onCreate, onCancel }, ref) => { const [form] = Form.useForm(); const formRef = useRef(null); + const [treeLine, setTreeLine] = useState(true); + useImperativeHandle(ref, () => ({ getTreeData() { form.resetFields(); d3.json('/api/bs/hrmorganization/orgchart/getDepartmentTree').then( (data) => { + data.departmentTree.map((item, index) => { + item.icon = ; + }); setData(data.departmentTree); }, ); @@ -42,6 +49,13 @@ const MergeDialog = forwardRef(({ open, onCreate, onCancel }, ref) => { d3.json( `/api/bs/hrmorganization/orgchart/getDepartmentTree?subcompany=${id}`, ).then((data) => { + data.departmentTree.map((item, index) => { + if (item.key.indexOf('d') > -1) { + item.icon = ; + } else { + item.icon = ; + } + }); let arr = [...treeData, ...data.departmentTree]; setData(arr); }); @@ -79,12 +93,14 @@ const MergeDialog = forwardRef(({ open, onCreate, onCancel }, ref) => { ]} > diff --git a/src/components/drawer/index.jsx b/src/components/drawer/index.jsx index 789c545..e102ee1 100644 --- a/src/components/drawer/index.jsx +++ b/src/components/drawer/index.jsx @@ -181,8 +181,8 @@ export default class DrawerComponents extends React.Component { 工号: dataSource[i].workCode, 姓名: dataSource[i].lastName, 性别: dataSource[i].sex, - 部门: dataSource[i].departmentId, - 分部: dataSource[i].subcompanyid1, + 部门: dataSource[i].departmentName, + 分部: dataSource[i].subcompanyName, 岗位: dataSource[i].jobTitle, 手机号: dataSource[i].mobile, }; diff --git a/src/components/timeline/img/leftTree-hide.png b/src/components/timeline/img/leftTree-hide.png new file mode 100644 index 0000000..0a1cadf Binary files /dev/null and b/src/components/timeline/img/leftTree-hide.png differ diff --git a/src/components/timeline/img/leftTree-show-hover.png b/src/components/timeline/img/leftTree-show-hover.png new file mode 100644 index 0000000..96967b5 Binary files /dev/null and b/src/components/timeline/img/leftTree-show-hover.png differ diff --git a/src/components/timeline/img/leftTree-show.png b/src/components/timeline/img/leftTree-show.png new file mode 100644 index 0000000..cc791aa Binary files /dev/null and b/src/components/timeline/img/leftTree-show.png differ diff --git a/src/components/timeline/index.jsx b/src/components/timeline/index.jsx index 49f34e8..a961adf 100644 --- a/src/components/timeline/index.jsx +++ b/src/components/timeline/index.jsx @@ -2,19 +2,22 @@ * @Author: Chengliang 1546584672@qq.com * @Date: 2023-06-25 16:33:21 * @LastEditors: Chengliang 1546584672@qq.com - * @LastEditTime: 2023-06-29 14:24:04 + * @LastEditTime: 2023-09-14 17:48:39 * @FilePath: /org-chart-frant/src/components/timeline/index.jsx * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ import React from 'react'; -import { Timeline } from 'antd'; +import { Timeline, Drawer } from 'antd'; import styles from './index.less'; +import leftTreeShow from './img/leftTree-show.png'; +import leftHide from './img/leftTree-hide.png'; export default class TimeLine extends React.Component { constructor(props) { super(props); this.state = { timelineList: [], + open: true, }; } @@ -46,26 +49,61 @@ export default class TimeLine extends React.Component { }); } + setOpen = () => { + this.setState({ + open: !this.state.open, + }); + }; + render() { + let showStyle = {}; + let positionStyle = {}; + if (this.state.open) { + showStyle = { + display: 'block', + }; + positionStyle = { + left: '219px', + background: `url(${leftTreeShow}) no-repeat -2px 0`, + }; + } else { + showStyle = { + display: 'none', + }; + positionStyle = { + left: '0', + background: `url(${leftHide}) no-repeat -2px 0`, + }; + } + return ( -
- - {this.state.timelineList.map((item) => { - return ( - -
{item.title}
-
{item.time}
-
- ); - })} -
-
+ <> +
+
+ + {this.state.timelineList.map((item) => { + return ( + +
{item.title}
+
{item.time}
+
+ ); + })} +
+
+ ); } } diff --git a/src/components/timeline/index.less b/src/components/timeline/index.less index 55d216d..3d5571b 100644 --- a/src/components/timeline/index.less +++ b/src/components/timeline/index.less @@ -24,6 +24,21 @@ } } +.leftRightLayoutBtn { + width: 18px; + height: 60px; + position: absolute; + top: 50%; + margin-top: -30px; + z-index: 101; + cursor: pointer; +} + +.leftRightLayoutBtn :hover { + background-image: url(./img/leftTree-show-hover.png) no-repeat -2px 0 !important; + background-color: #1890ff; +} + .lineWrapper::-webkit-scrollbar { /*滚动条整体样式*/ width: 10px; diff --git a/src/components/topBar/index.jsx b/src/components/topBar/index.jsx index 3ee4c2e..06b3f73 100644 --- a/src/components/topBar/index.jsx +++ b/src/components/topBar/index.jsx @@ -35,6 +35,7 @@ export class TopBar extends React.Component { root: undefined, level: '2', fisvitual: '0', + hidedept: '0', }, open: false, confirmLoading: false, @@ -201,6 +202,7 @@ export class TopBar extends React.Component { root: undefined, level: '2', fisvitual: '0', + hidedept: '0', }; this.handleFormChange(requestData); this.getNodeTreeNode( @@ -234,22 +236,22 @@ export class TopBar extends React.Component { this.handleFormChange({ - fisvitual: e.target.checked ? '1' : '0', + hidedept: e.target.checked ? '1' : '0', }) } > - 显示虚拟组织 + 隐藏部门 @@ -269,7 +271,29 @@ export class TopBar extends React.Component { - + + + this.handleFormChange({ + fisvitual: e.target.checked ? '1' : '0', + }) + } + > + 显示虚拟组织 + + + + + + + + diff --git a/src/department/index.js b/src/department/index.js deleted file mode 100644 index b04fce2..0000000 --- a/src/department/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import React from 'react' - -export default () => { - return
Hello
-} \ No newline at end of file diff --git a/src/pages/company.jsx b/src/pages/company.jsx index 4700f79..eafb603 100644 --- a/src/pages/company.jsx +++ b/src/pages/company.jsx @@ -10,7 +10,8 @@ import OperateDialog from '../components/dialog'; import jsPDF from 'jspdf'; import moment from 'moment'; import qs from 'qs'; -import { message, Spin } from 'antd'; +import { message, Spin, notification } from 'antd'; +import { SmileOutlined } from '@ant-design/icons'; let active = 'top'; let drawerCom = null; @@ -31,6 +32,14 @@ export default function companyPage() { const [timelineId, setTimelineId] = useState(0); const infoRef = useRef(); + useEffect(() => { + notification.open({ + message: '提示', + description: + '组织架构图中编制数和在编数显示初始化需参考文档配置定时任务并执行!!!(编制数默认取本年度最新编制信息,人数统计展示仅限于行政维度)', + icon: , + }); + }, []); useEffect(() => { infoRef.current = timelineId; }, [timelineId]); @@ -100,7 +109,7 @@ export default function companyPage() { // 获取数据 useEffect(() => { d3.json( - '/api/bs/hrmorganization/orgchart/companyData?fclass=0&fisvitual=0&root=0&level=2&id=0', + '/api/bs/hrmorganization/orgchart/companyData?fclass=0&fisvitual=0&hidedept=0&root=0&level=2&id=0', ).then((data) => { setData(data.data); setHasRight(data?.hasRight); @@ -140,6 +149,8 @@ export default function companyPage() { }; const nodeContentRender = (d, i, arr, state) => { + let fclass = topbar.state.requestData.fclass; + let statisticsStyle = fclass == 0 ? 'block' : 'none'; if (d.data.ftype == 0) { return `
@@ -166,7 +177,13 @@ export default function companyPage() { d.data.fname } style="width: 110px;margin: 0 auto;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;-o-text-overflow:ellipsis; line-height: 18px;word-break: break-all;">${d.data.fname}
-
`; +
+ ${d.data.staffNum} / + ${d.data.onJobNum} +
+ + + `; } else if (d.data.ftype == 2) { return `
@@ -179,6 +196,10 @@ export default function companyPage() { font-family: Microsoft YaHei-Regular, Microsoft YaHei;color: #333333;text-align: center;">
${d.data.fname}
+
+ ${d.data.staffNum} / + ${d.data.onJobNum} +
`; @@ -326,7 +347,12 @@ export default function companyPage() { const timeLineSearch = (timeline) => { setTimelineId(timeline.id); const fclass = topbar.state.requestData.fclass; - const resetParams = { root: undefined, level: '2', fisvitual: '0' }; + const resetParams = { + root: undefined, + level: '2', + fisvitual: '0', + hidedept: '0', + }; topbar.handleFormChange({ ...resetParams }); topbar.getNodeTreeNode( `/api/bs/hrmorganization/orgchart/getSubCompanyTree?fclass=${fclass}&id=${timeline.id}`, diff --git a/src/pages/dragTree.jsx b/src/pages/dragTree.jsx index 37acab6..ba718fb 100644 --- a/src/pages/dragTree.jsx +++ b/src/pages/dragTree.jsx @@ -1,25 +1,31 @@ -import { Tree, message, Modal, Popconfirm, Spin } from 'antd'; +import { Tree, message, Modal, Popconfirm, Spin, Layout, Drawer } from 'antd'; import React, { useEffect, useState, useRef } from 'react'; import * as d3 from 'd3'; import qs from 'qs'; import MergeDialog from '../components/dialog/mergeDialog'; import CopyDialog from '../components/dialog/copyDialog'; +import inset from '../../public/img/back/inset.png'; import { HomeOutlined, FolderOutlined, ClusterOutlined, ApartmentOutlined, + QuestionCircleOutlined, } from '@ant-design/icons'; +const { Header, Footer, Sider, Content } = Layout; import './index.less'; const DragTree = () => { const [gData, setGData] = useState([]); const [expandedKeys, setExpandedKeys] = useState([undefined]); const childRef = useRef(null); - const [tip, setTip] = useState('正在加载...'); + const copyChildRef = useRef(null); + const [tip, setTip] = useState('正在加载,请稍候...'); const [loading, setLoading] = useState(false); const [showCanceled, setShowCanceled] = useState(0); + const [drawerOpen, setDrawerOpen] = useState(false); + const [iframe, setIframe] = useState(''); const [open, setOpen] = useState(false); const [mergeId, setMergeId] = useState(null); @@ -30,10 +36,10 @@ const DragTree = () => { getMoveTree(0); }, [true]); - const getMoveTree = (showCanceled) => { + const getMoveTree = (showCanceled, expandedKeys = '') => { setLoading(true); d3.json( - `/api/bs/hrmorganization/orgchart/getMovingTree?showCanceled=${showCanceled}`, + `/api/bs/hrmorganization/orgchart/getMovingTree?showCanceled=${showCanceled}&expandedKeys=${expandedKeys}`, ).then((data) => { setGData(data.movingTree); setExpandedKeys(data.expandedKeys); @@ -59,79 +65,95 @@ const DragTree = () => { }; const onDrop = (info) => { - setLoading(true); - setTip('正在转移,请稍候...'); const dropKey = info.node.key; const dragKey = info.dragNode.key; const dropPos = info.node.pos.split('-'); const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]); - fetch('/api/bs/hrmorganization/dept/dragDepartment', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - sourcekey: dragKey, - targetkey: dropKey, - dropPosition: dropPosition, - }), - }) - .then((response) => response.json()) - .then((res) => { - if (res.code == 200) { - const data = [...gData]; - // Find dragObject - let dragObj; - loop(data, dragKey, (item, index, arr) => { - arr.splice(index, 1); - dragObj = item; - }); - if (!info.dropToGap) { - // Drop on the content - loop(data, dropKey, (item) => { - item.children = item.children || []; - // where to insert 示例添加到头部,可以是随意位置 - item.children.unshift(dragObj); - }); - } else if ( - (info.node.props.children || []).length > 0 && - // Has children - info.node.props.expanded && - // Is expanded - dropPosition === 1 // On the bottom gap - ) { - loop(data, dropKey, (item) => { - item.children = item.children || []; - // where to insert 示例添加到头部,可以是随意位置 - item.children.unshift(dragObj); - // in previous version, we use item.children.push(dragObj) to insert the - // item to the tail of the children - }); - } else { - let ar = []; - let i; - loop(data, dropKey, (_item, index, arr) => { - ar = arr; - i = index; - }); - if (dropPosition === -1) { - ar.splice(i, 0, dragObj); + + if (dropPosition == -1) { + return message.error('不支持该操作!!!', 2); + } + let pos = dropPosition == 0 ? '内部' : '下方'; + + let title = `确定将【${info.dragNode.title}】移到 【${info.node.title}】${pos}`; + Modal.confirm({ + title: '转移操作', + content: title, + okText: '确认', + cancelText: '取消', + onOk() { + setLoading(true); + setTip('正在转移,请稍候...'); + + fetch('/api/bs/hrmorganization/dept/dragDepartment', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + sourcekey: dragKey, + targetkey: dropKey, + dropPosition: dropPosition, + }), + }) + .then((response) => response.json()) + .then((res) => { + if (res.code == 200) { + const data = [...gData]; + // Find dragObject + let dragObj; + loop(data, dragKey, (item, index, arr) => { + arr.splice(index, 1); + dragObj = item; + }); + if (!info.dropToGap) { + // Drop on the content + loop(data, dropKey, (item) => { + item.children = item.children || []; + // where to insert 示例添加到头部,可以是随意位置 + item.children.unshift(dragObj); + }); + } else if ( + (info.node.props.children || []).length > 0 && + // Has children + info.node.props.expanded && + // Is expanded + dropPosition === 1 // On the bottom gap + ) { + loop(data, dropKey, (item) => { + item.children = item.children || []; + // where to insert 示例添加到头部,可以是随意位置 + item.children.unshift(dragObj); + // in previous version, we use item.children.push(dragObj) to insert the + // item to the tail of the children + }); + } else { + let ar = []; + let i; + loop(data, dropKey, (_item, index, arr) => { + ar = arr; + i = index; + }); + if (dropPosition === -1) { + ar.splice(i, 0, dragObj); + } else { + ar.splice(i + 1, 0, dragObj); + } + } + setGData(data); + message.success('转移成功', 2); } else { - ar.splice(i + 1, 0, dragObj); + message.warning(res.msg, 2); } - } - setGData(data); - } else { - message.warning(res.msg, 2); - } - setLoading(false); - }) - .catch((error) => { - message.error('接口异常,请联系管理员'); - }); - - setTimeout(function () {}, 1000); + setLoading(false); + }) + .catch((error) => { + message.error('接口异常,请联系管理员'); + }); + }, + onCancel() {}, + }); }; /** @@ -145,7 +167,7 @@ const DragTree = () => { headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify({ ids: nodeData.id }), + body: JSON.stringify({ ids: nodeData.id.substring(1) }), }) .then((response) => response.json()) .then((res) => { @@ -172,6 +194,7 @@ const DragTree = () => { * @param {*} nodeData */ const onCancel = (nodeData) => { + setShowCanceled(0); const extend = nodeData.type == '1' ? 'comp' : 'dept'; fetch(`/api/bs/hrmorganization/${extend}/updateForbiddenTagById`, { method: 'POST', @@ -179,7 +202,7 @@ const DragTree = () => { 'Content-Type': 'application/json', }, body: JSON.stringify({ - id: nodeData.id, + id: nodeData.id.substring(1), canceled: nodeData.canceled != '0', }), }) @@ -187,11 +210,18 @@ const DragTree = () => { .then((res) => { if (res.code == 200) { const data = [...gData]; - loop(data, nodeData.key, (item, index, arr) => { - arr.splice(index, 1); - }); + if (nodeData.canceled != '0') { + message.success('恢复成功', 2); + loop(data, nodeData.key, (item, index, arr) => { + arr[index].canceled = '0'; + }); + } else { + loop(data, nodeData.key, (item, index, arr) => { + arr.splice(index, 1); + }); + message.success('封存成功', 2); + } setGData(data); - message.success('封存成功', 2); } else { message.warning(res.msg, 2); } @@ -229,6 +259,7 @@ const DragTree = () => { .then((response) => response.json()) .then((res) => { if (res.code == 200) { + getMoveTree(0, values.department); message.success('合并成功', 2); } else { message.warning(res.msg, 2); @@ -245,22 +276,31 @@ const DragTree = () => { * @param {*} nodeData */ const onCopy = (nodeData) => { + if (copyChildRef.current) { + copyChildRef.current.getTreeData(); + } setCopyOpen(true); setCopyId(nodeData.id); }; const onCopyCreate = (values) => { + let params = { + company: values.company, + copySubDept: values.copySubDept ? '1' : '0', + ids: copyId.substring(1), + }; fetch(`/api/bs/hrmorganization/dept/copyDepartment`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify({ ...values, ids: copyId }), + body: JSON.stringify(params), }) .then((response) => response.json()) .then((res) => { if (res.code == 200) { setCopyOpen(false); + getMoveTree(0, values.company); message.success('复制成功', 2); } else { message.warning(res.msg, 2); @@ -282,7 +322,6 @@ const DragTree = () => { <> {nodeData.type == 0 ? ( - {' '} {nodeData.title} @@ -290,22 +329,33 @@ const DragTree = () => { <> {icon} - {nodeData.title} + + {nodeData.title} + {nodeData.canceled == '1' ? ( + + (已封存) + + ) : ( + '' + )} +
- window.open( - `/spa/organization/static/index.html#/main/organization/${extend}/${nodeData.id}`, - '_blank', - ) - } + onClick={() => { + setDrawerOpen(true); + setIframe( + `/spa/organization/static/index.html#/main/organization/${extend}/${nodeData.id.substring( + 1, + )}`, + ); + }} > 查看 onDelete(nodeData)} okText="确认" cancelText="取消" @@ -343,43 +393,87 @@ const DragTree = () => { ); }; + const onExpand = (info) => { + setExpandedKeys(info); + }; + return ( - <> - { - const value = showCanceled == 0 ? 1 : 0; - setShowCanceled(value); - getMoveTree(value); +
+ +
+
+ +
组织快速调整
+
+
+ { + const value = showCanceled == 0 ? 1 : 0; + setTip('正在加载,请稍候...'); + setShowCanceled(value); + getMoveTree(value); + }} + /> + +
+ setDrawerOpen(false)} + open={drawerOpen} + > +