Merge pull request 'feature/cl' (#7) from feature/cl into master
Reviewed-on: http://221.226.25.34:3000/liang.cheng/org-chart-frant/pulls/7
This commit is contained in:
commit
32e1b51632
|
|
@ -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去掉
|
||||
},
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 485 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
|
|
@ -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 [form] = Form.useForm();
|
||||
|
||||
const CopyDialog = forwardRef(({ open, onCreate, onCancel }, ref) => {
|
||||
const [treeData, setData] = useState([]);
|
||||
console.log(treeData);
|
||||
useEffect(() => {
|
||||
d3.json('/api/bs/hrmorganization/orgchart/getSubCompanyTree').then(
|
||||
(data) => {
|
||||
setData(data.companyTree);
|
||||
},
|
||||
);
|
||||
}, [true]);
|
||||
const [form] = Form.useForm();
|
||||
const formRef = useRef(null);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
getTreeData() {
|
||||
form.resetFields();
|
||||
d3.json('/api/bs/hrmorganization/orgchart/getSubCompanyTree').then(
|
||||
(data) => {
|
||||
data.companyTree.map((item, index) => {
|
||||
item.icon = <HomeOutlined />;
|
||||
});
|
||||
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 = <HomeOutlined />;
|
||||
});
|
||||
let arr = [...treeData, ...data.companyTree];
|
||||
setData(arr);
|
||||
});
|
||||
|
|
@ -59,41 +75,38 @@ const CopyDialog = ({ open, onCreate, onCancel }) => {
|
|||
});
|
||||
}}
|
||||
>
|
||||
<Form {...layout} form={form} name="form_in_modal">
|
||||
<Form ref={formRef} {...layout} form={form} name="form_in_modal">
|
||||
<Form.Item
|
||||
name="department"
|
||||
label="合并到部门"
|
||||
name="company"
|
||||
label="复制到分部"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '【合并到部门】为必填项!',
|
||||
message: '【复制到分部】为必填项!',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<TreeSelect
|
||||
className="custom-tree-select"
|
||||
treeDataSimpleMode
|
||||
allowClear
|
||||
style={{ width: '100%' }}
|
||||
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
|
||||
loadData={onRootLoadData}
|
||||
treeData={treeData}
|
||||
treeIcon
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="mergeName"
|
||||
label="合并后名称"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: '【合并后的名称】为必填项!',
|
||||
},
|
||||
]}
|
||||
name="copySubDept"
|
||||
valuePropName="checked"
|
||||
label="是否复制子部门信息"
|
||||
>
|
||||
<Input />
|
||||
<Checkbox />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
});
|
||||
export default CopyDialog;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = <HomeOutlined />;
|
||||
});
|
||||
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 = <FolderOutlined />;
|
||||
} else {
|
||||
item.icon = <HomeOutlined />;
|
||||
}
|
||||
});
|
||||
let arr = [...treeData, ...data.departmentTree];
|
||||
setData(arr);
|
||||
});
|
||||
|
|
@ -79,12 +93,14 @@ const MergeDialog = forwardRef(({ open, onCreate, onCancel }, ref) => {
|
|||
]}
|
||||
>
|
||||
<TreeSelect
|
||||
className="custom-tree-select"
|
||||
treeDataSimpleMode
|
||||
allowClear
|
||||
style={{ width: '100%' }}
|
||||
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
|
||||
loadData={onRootLoadData}
|
||||
treeData={treeData}
|
||||
treeIcon
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
|
|
@ -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 (
|
||||
<div className={styles.lineWrapper}>
|
||||
<Timeline>
|
||||
{this.state.timelineList.map((item) => {
|
||||
return (
|
||||
<Timeline.Item
|
||||
key={item.key}
|
||||
onClick={this.handleLineClick.bind(this, item)}
|
||||
className={styles.timeline}
|
||||
color={item.color}
|
||||
style={{ color: item.color == 'blue' ? '#1890ff' : 'dimgray' }}
|
||||
>
|
||||
<div>{item.title}</div>
|
||||
<div className={styles.time}>{item.time}</div>
|
||||
</Timeline.Item>
|
||||
);
|
||||
})}
|
||||
</Timeline>
|
||||
</div>
|
||||
<>
|
||||
<div
|
||||
className={styles.leftRightLayoutBtn}
|
||||
style={positionStyle}
|
||||
onClick={this.setOpen}
|
||||
></div>
|
||||
<div className={styles.lineWrapper} style={showStyle}>
|
||||
<Timeline>
|
||||
{this.state.timelineList.map((item) => {
|
||||
return (
|
||||
<Timeline.Item
|
||||
key={item.key}
|
||||
onClick={this.handleLineClick.bind(this, item)}
|
||||
className={styles.timeline}
|
||||
color={item.color}
|
||||
style={{
|
||||
color: item.color == 'blue' ? '#1890ff' : 'dimgray',
|
||||
}}
|
||||
>
|
||||
<div>{item.title}</div>
|
||||
<div className={styles.time}>{item.time}</div>
|
||||
</Timeline.Item>
|
||||
);
|
||||
})}
|
||||
</Timeline>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
|||
<Col span={6}>
|
||||
<Checkbox
|
||||
style={{ marginTop: '5px', marginLeft: 100 }}
|
||||
checked={this.state.requestData.fisvitual == '1'}
|
||||
checked={this.state.requestData.hidedept == '1'}
|
||||
onChange={(e) =>
|
||||
this.handleFormChange({
|
||||
fisvitual: e.target.checked ? '1' : '0',
|
||||
hidedept: e.target.checked ? '1' : '0',
|
||||
})
|
||||
}
|
||||
>
|
||||
显示虚拟组织
|
||||
隐藏部门
|
||||
</Checkbox>
|
||||
<Tooltip
|
||||
title="提示:若启用虚拟组织,需要在分部自定义表增加字段(名称 fblx) 字段类型 下拉框(0实体 1虚拟) 部门自定义表同上(字段名称 bmlx)。"
|
||||
color="#FF7F00"
|
||||
title="提示:开启后将只显示分部组织架构!!!"
|
||||
color="#0082fb"
|
||||
placement="rightTop"
|
||||
>
|
||||
<QuestionCircleOutlined
|
||||
style={{ color: '#FF7F00', cursor: 'pointer', fontSize: 16 }}
|
||||
style={{ color: '#0082fb', cursor: 'pointer', fontSize: 16 }}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Col>
|
||||
|
|
@ -269,7 +271,29 @@ export class TopBar extends React.Component {
|
|||
</Col>
|
||||
</Row>
|
||||
<Row style={{ marginTop: '15px' }}>
|
||||
<Col span={8}>
|
||||
<Col span={6}>
|
||||
<Checkbox
|
||||
style={{ marginTop: '5px' }}
|
||||
checked={this.state.requestData.fisvitual == '1'}
|
||||
onChange={(e) =>
|
||||
this.handleFormChange({
|
||||
fisvitual: e.target.checked ? '1' : '0',
|
||||
})
|
||||
}
|
||||
>
|
||||
显示虚拟组织
|
||||
</Checkbox>
|
||||
<Tooltip
|
||||
title="提示:若启用虚拟组织,需要在分部自定义表增加字段(名称 fblx) 字段类型 下拉框(0实体 1虚拟) 部门自定义表同上(字段名称 bmlx)。"
|
||||
color="#0082fb"
|
||||
placement="rightTop"
|
||||
>
|
||||
<QuestionCircleOutlined
|
||||
style={{ color: '#0082fb', cursor: 'pointer', fontSize: 16 }}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Col>
|
||||
<Col span={16}>
|
||||
<Button
|
||||
type="primary"
|
||||
style={{ marginRight: '10px' }}
|
||||
|
|
@ -290,6 +314,24 @@ export class TopBar extends React.Component {
|
|||
>
|
||||
查询
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
style={{ marginRight: '10px' }}
|
||||
onClick={() => {
|
||||
window.open('#/dragtree', 'blank');
|
||||
}}
|
||||
>
|
||||
组织调整
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
style={{ marginRight: '10px' }}
|
||||
onClick={() => {
|
||||
window.open('#/statistics', 'blank');
|
||||
}}
|
||||
>
|
||||
人数统计
|
||||
</Button>
|
||||
<Dropdown overlay={this.menu}>
|
||||
<Button type="primary">导出</Button>
|
||||
</Dropdown>
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
import React from 'react'
|
||||
|
||||
export default () => {
|
||||
return <div>Hello</div>
|
||||
}
|
||||
|
|
@ -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: <SmileOutlined style={{ color: '#108ee9' }} />,
|
||||
});
|
||||
}, []);
|
||||
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 `<div>
|
||||
<div style="display: inline-block; text-align: center; margin-left: 5px;">
|
||||
|
|
@ -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}</div>
|
||||
</div>`;
|
||||
<div style="display: ${statisticsStyle}">
|
||||
<span style="color:red">${d.data.staffNum}</span> /
|
||||
<span style="color:green">${d.data.onJobNum}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
} else if (d.data.ftype == 2) {
|
||||
return `
|
||||
<div style="width: 100%; height: 100%; background-size: 100% 100%;">
|
||||
|
|
@ -179,6 +196,10 @@ export default function companyPage() {
|
|||
font-family: Microsoft YaHei-Regular, Microsoft YaHei;color: #333333;text-align: center;">
|
||||
<div style="width: 110px;margin: 0 auto;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;
|
||||
line-height: 18px;word-break: break-all;">${d.data.fname}</div>
|
||||
<div style="display: ${statisticsStyle}">
|
||||
<span style="color:red">${d.data.staffNum}</span> /
|
||||
<span style="color:green">${d.data.onJobNum}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
@ -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}`,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
} else {
|
||||
ar.splice(i + 1, 0, dragObj);
|
||||
}
|
||||
}
|
||||
setGData(data);
|
||||
} else {
|
||||
message.warning(res.msg, 2);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
message.error('接口异常,请联系管理员');
|
||||
});
|
||||
|
||||
setTimeout(function () {}, 1000);
|
||||
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 {
|
||||
message.warning(res.msg, 2);
|
||||
}
|
||||
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 ? (
|
||||
<span>
|
||||
{' '}
|
||||
<ClusterOutlined />
|
||||
<span style={{ marginLeft: '5px' }}>{nodeData.title}</span>
|
||||
</span>
|
||||
|
|
@ -290,22 +329,33 @@ const DragTree = () => {
|
|||
<>
|
||||
<span>
|
||||
{icon}
|
||||
<span style={{ marginLeft: '5px' }}>{nodeData.title}</span>
|
||||
<span style={{ marginLeft: '5px' }}>
|
||||
{nodeData.title}
|
||||
{nodeData.canceled == '1' ? (
|
||||
<span style={{ color: 'red', marginLeft: '5px' }}>
|
||||
(已封存)
|
||||
</span>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
<div id="drag-button-ops">
|
||||
<span
|
||||
className="drag-button"
|
||||
onClick={() =>
|
||||
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,
|
||||
)}`,
|
||||
);
|
||||
}}
|
||||
>
|
||||
查看
|
||||
</span>
|
||||
<Popconfirm
|
||||
title={`确认要删除 [${nodeData.title}] 吗?`}
|
||||
title={`确认要删除[${nodeData.title}] 吗?`}
|
||||
onConfirm={() => onDelete(nodeData)}
|
||||
okText="确认"
|
||||
cancelText="取消"
|
||||
|
|
@ -343,43 +393,87 @@ const DragTree = () => {
|
|||
);
|
||||
};
|
||||
|
||||
const onExpand = (info) => {
|
||||
setExpandedKeys(info);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ApartmentOutlined
|
||||
style={{ color: showCanceled == 0 ? '#1890ff' : '#eb2f96' }}
|
||||
onClick={() => {
|
||||
const value = showCanceled == 0 ? 1 : 0;
|
||||
setShowCanceled(value);
|
||||
getMoveTree(value);
|
||||
<div className="drag-wrapper">
|
||||
<Spin tip={tip} spinning={loading}>
|
||||
<div className="drag-layout">
|
||||
<div className="drag-header">
|
||||
<img src={inset} />
|
||||
<div>组织快速调整</div>
|
||||
</div>
|
||||
<div className="drag-content">
|
||||
<ApartmentOutlined
|
||||
className="drag-showcanceled"
|
||||
style={{ color: showCanceled == 0 ? '#000' : '#1890ff' }}
|
||||
onClick={() => {
|
||||
const value = showCanceled == 0 ? 1 : 0;
|
||||
setTip('正在加载,请稍候...');
|
||||
setShowCanceled(value);
|
||||
getMoveTree(value);
|
||||
}}
|
||||
/>
|
||||
<Tree
|
||||
className="draggable-tree"
|
||||
//defaultExpandedKeys={expandedKeys}
|
||||
expandedKeys={expandedKeys}
|
||||
onExpand={onExpand}
|
||||
draggable
|
||||
icon={false}
|
||||
blockNode
|
||||
onDragEnter={onDragEnter}
|
||||
onDrop={onDrop}
|
||||
treeData={gData}
|
||||
titleRender={onTitleRender}
|
||||
/>
|
||||
</div>
|
||||
<Drawer
|
||||
width="60%"
|
||||
placement="right"
|
||||
closable={false}
|
||||
onClose={() => setDrawerOpen(false)}
|
||||
open={drawerOpen}
|
||||
>
|
||||
<iframe src={iframe} width="100%" height="100%" />
|
||||
</Drawer>
|
||||
|
||||
<div className="drag-footer">
|
||||
<p>
|
||||
<QuestionCircleOutlined />
|
||||
小提示
|
||||
</p>
|
||||
<div className="tips">
|
||||
<div>1.鼠标拖拽Tree节点到任一分部部门下可快速完成组织转移;</div>
|
||||
<div>2.点击【查看】侧滑打开组织详细信息,可快速编辑;</div>
|
||||
<div>
|
||||
3.鼠标悬停树节点 一键开启【删除】【封存】【合并】【复制】等功能;
|
||||
</div>
|
||||
<div>4.顶部小图标点击可显示已封存的组织架构。</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
|
||||
<MergeDialog
|
||||
ref={childRef}
|
||||
open={open}
|
||||
onCreate={onMergeCreate}
|
||||
onCancel={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
<Spin tip={tip} spinning={loading}>
|
||||
<Tree
|
||||
className="draggable-tree"
|
||||
defaultExpandedKeys={expandedKeys}
|
||||
draggable
|
||||
icon={false}
|
||||
blockNode
|
||||
onDragEnter={onDragEnter}
|
||||
onDrop={onDrop}
|
||||
treeData={gData}
|
||||
titleRender={onTitleRender}
|
||||
/>
|
||||
<MergeDialog
|
||||
ref={childRef}
|
||||
open={open}
|
||||
onCreate={onMergeCreate}
|
||||
onCancel={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
{/* <CopyDialog open={copyopen}
|
||||
<CopyDialog
|
||||
ref={copyChildRef}
|
||||
open={copyopen}
|
||||
onCreate={onCopyCreate}
|
||||
onCancel={() => {
|
||||
setCopyOpen(false);
|
||||
}}/> */}
|
||||
</Spin>
|
||||
</>
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default DragTree;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
#root {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.title {
|
||||
background: rgb(121, 242, 157);
|
||||
}
|
||||
|
|
@ -24,11 +28,11 @@
|
|||
|
||||
#drag-button-ops {
|
||||
display: none;
|
||||
width: 500px;
|
||||
height: 16px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
margin-left: 100px;
|
||||
|
||||
.drag-button {
|
||||
display: inline-block;
|
||||
padding: 0 10px;
|
||||
|
|
@ -40,3 +44,76 @@
|
|||
color: #22c8fb;
|
||||
}
|
||||
}
|
||||
|
||||
.drag-wrapper {
|
||||
min-height: inherit;
|
||||
background-image: url('../../public/img/back/background.png') !important;
|
||||
}
|
||||
|
||||
.drag-layout {
|
||||
min-height: inherit;
|
||||
padding: 25px;
|
||||
|
||||
.drag-header {
|
||||
text-align: center;
|
||||
|
||||
div {
|
||||
display: inline-block;
|
||||
font-size: 25px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.drag-content {
|
||||
width: auto;
|
||||
background: #f8fafc;
|
||||
border: 1px solid rgba(218, 237, 255, 1);
|
||||
border-radius: 8px;
|
||||
margin-top: 20px;
|
||||
|
||||
.drag-showcanceled {
|
||||
font-size: 18px;
|
||||
line-height: 30px;
|
||||
margin-left: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.drag-footer {
|
||||
margin-top: 15px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid rgba(218, 237, 255, 1);
|
||||
border-radius: 8px;
|
||||
padding: 22px;
|
||||
|
||||
p {
|
||||
span {
|
||||
color: #178eff;
|
||||
margin-right: 5px;
|
||||
}
|
||||
font-family: PingFangSC-Medium;
|
||||
font-size: 14px;
|
||||
color: #596378;
|
||||
line-height: 24px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.tips {
|
||||
font-family: PingFangSC-Regular;
|
||||
font-size: 14px;
|
||||
color: #596378;
|
||||
line-height: 21px;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-tree {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.ant-drawer-body {
|
||||
padding: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* @Author: Chengliang 1546584672@qq.com
|
||||
* @Date: 2023-09-11 15:33:27
|
||||
* @LastEditors: Chengliang 1546584672@qq.com
|
||||
* @LastEditTime: 2023-09-13 17:49:16
|
||||
* @FilePath: /org-chart-frant/src/pages/statisticsTable.jsx
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
*/
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import * as d3 from 'd3';
|
||||
import qs from 'qs';
|
||||
import { Table } from 'antd';
|
||||
|
||||
const StatisticsTable = () => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [dataSource, setDataSource] = useState([]);
|
||||
const [columns, setColumns] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'key',
|
||||
key: 'key',
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'dataIdName',
|
||||
key: 'dataIdName',
|
||||
},
|
||||
{
|
||||
title: '上级',
|
||||
dataIndex: 'superIdName',
|
||||
key: 'superIdName',
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
render(value, row, index) {
|
||||
if (value == 1) {
|
||||
return '分部';
|
||||
} else {
|
||||
return '部门';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '在编数',
|
||||
dataIndex: 'onJobNum',
|
||||
key: 'onJobNum',
|
||||
},
|
||||
{
|
||||
title: '编制数',
|
||||
dataIndex: 'staffNum',
|
||||
key: 'staffNum',
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
dataIndex: 'creator',
|
||||
key: 'creator',
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
dataIndex: 'updateTime',
|
||||
key: 'updateTime',
|
||||
},
|
||||
];
|
||||
setColumns(columns);
|
||||
d3.json(`/api/bs/hrmorganization/orgchart/selectStatistics`).then((res) => {
|
||||
setDataSource(res.data.result);
|
||||
setLoading(false);
|
||||
});
|
||||
}, [true]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ padding: '50px' }}>
|
||||
<Table dataSource={dataSource} columns={columns} loading={loading} />;
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default StatisticsTable;
|
||||
|
|
@ -99,9 +99,8 @@ export default function userPage() {
|
|||
// 获取数据
|
||||
useEffect(() => {
|
||||
document.cookie =
|
||||
'ecology_JSessionid=aaaUMPsdM5DKIgXzYrwMy; JSESSIONID=aaaUMPsdM5DKIgXzYrwMy; __randcode__=f5b6cc86-28ff-416b-bc87-569246714d54; loginidweaver=1; languageidweaver=7; loginuuids=1';
|
||||
'ecology_JSessionid=aaaQRFwOgYRXPc88EZiQy; JSESSIONID=aaaQRFwOgYRXPc88EZiQy; Systemlanguid=7; languageidweaver=7; loginuuids=1; loginidweaver=sysadmin; __randcode__=0418808b-1045-4624-bea6-5b308360da7b';
|
||||
d3.json(
|
||||
// "/user/data"
|
||||
'/api/bs/hrmorganization/orgchart/userData?fclass=0&fisvitual=0&root=0&level=3&id=0',
|
||||
).then((data) => {
|
||||
setData(data.data);
|
||||
|
|
|
|||
Loading…
Reference in New Issue