|
|
import React from 'react';
|
|
|
import {
|
|
|
Drawer,
|
|
|
Space,
|
|
|
Button,
|
|
|
Dropdown,
|
|
|
Menu,
|
|
|
Table,
|
|
|
Spin,
|
|
|
Checkbox,
|
|
|
Row,
|
|
|
Col,
|
|
|
} from 'antd';
|
|
|
import { OrgChartComponent } from '@/components/orgChart';
|
|
|
import * as d3 from 'd3';
|
|
|
import qs from 'qs';
|
|
|
import { message } from 'antd';
|
|
|
import jsPDF from 'jspdf';
|
|
|
import ExportJsonExcel from 'js-export-excel';
|
|
|
import './index.less';
|
|
|
import { CodepenCircleOutlined } from '@ant-design/icons';
|
|
|
|
|
|
let addNodeChildFunc = null;
|
|
|
let orgChart = null;
|
|
|
let active = 'top';
|
|
|
export default class DrawerComponents extends React.Component {
|
|
|
constructor(props) {
|
|
|
super(props);
|
|
|
this.state = {
|
|
|
open: false,
|
|
|
data: [],
|
|
|
detailType: 'chart',
|
|
|
params: {},
|
|
|
dataSource: [],
|
|
|
columns: [],
|
|
|
spinning: true,
|
|
|
showJob: false,
|
|
|
nbOptions: [],
|
|
|
defaultNbValue: [],
|
|
|
wbOptions: [],
|
|
|
defaultWbValue: [],
|
|
|
};
|
|
|
}
|
|
|
|
|
|
componentDidMount() {}
|
|
|
|
|
|
componentDidUpdate(prevProps, prevState, snapshotValue) {
|
|
|
// 组件更新后的操作
|
|
|
// if (orgChart != null) {
|
|
|
// orgChart.getChartState().svgHeight = 3000;
|
|
|
// }
|
|
|
}
|
|
|
|
|
|
// 点击节点
|
|
|
onNodeClick(node) {
|
|
|
if (node.ftype == '4') {
|
|
|
window.open(node.pcUrl, '_blank');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
onButtonClick(event, d) {
|
|
|
if (d.children) {
|
|
|
let idsList = [];
|
|
|
d.children.forEach((item) => {
|
|
|
if (item.data.hasChildren && !item._children) {
|
|
|
idsList.push(item.data.id);
|
|
|
}
|
|
|
});
|
|
|
if (idsList.length == 0) {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 获取部门图片
|
|
|
getDepartmentImage(fisvitual) {
|
|
|
return fisvitual == '0'
|
|
|
? `./img/user-card/user-card.png`
|
|
|
: `./img/user-card/user-card-blue.png`;
|
|
|
}
|
|
|
|
|
|
//查询条件
|
|
|
getDeatilCondition() {
|
|
|
return new Promise((resolve) => {
|
|
|
d3.json('/api/bs/hrmorganization/orgchart/getDeptDetailCondition?').then(
|
|
|
(data) => {
|
|
|
this.setState({
|
|
|
nbOptions: data.nbCondition,
|
|
|
wbOptions: data.wbCondition,
|
|
|
defaultNbValue: data.nbValue,
|
|
|
defaultWbValue: data.wbValue,
|
|
|
});
|
|
|
resolve();
|
|
|
},
|
|
|
);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
//获取数据
|
|
|
getDeatilDatas(params, type = 'chart', showJob = '0') {
|
|
|
this.setState({ spinning: true, data: [] });
|
|
|
d3.json(
|
|
|
'/api/bs/hrmorganization/orgchart/getDepartmentDetail?' +
|
|
|
qs.stringify({ detailType: type, ...params, showJob }),
|
|
|
).then((data) => {
|
|
|
//
|
|
|
if (type == 'chart') {
|
|
|
this.setState({ data: data.data, spinning: false });
|
|
|
} else {
|
|
|
this.setState({
|
|
|
dataSource: data.dataSource,
|
|
|
columns: data.columns,
|
|
|
spinning: false,
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// ButtonContent渲染
|
|
|
buttonContentRender = ({ node, state }) => {
|
|
|
return `
|
|
|
<div style="margin-left: 16px; margin-top: 10px;">
|
|
|
<img src="./img/button_content.png" />
|
|
|
</div>
|
|
|
`;
|
|
|
};
|
|
|
|
|
|
// 节点宽度渲染
|
|
|
nodeWidthRender = (d) => {
|
|
|
return 280;
|
|
|
};
|
|
|
|
|
|
nodeHeightRender = (d) => {
|
|
|
return 160;
|
|
|
};
|
|
|
|
|
|
// tool bar start
|
|
|
handleTopLayoutClick = (progressBtn) => {
|
|
|
progressBtn.current.style.top = 50 + 'px';
|
|
|
orgChart &&
|
|
|
orgChart
|
|
|
.setCentered(orgChart.getChartState().root.id)
|
|
|
.layout('top')
|
|
|
.render();
|
|
|
active = 'top';
|
|
|
};
|
|
|
|
|
|
handleLeftLayoutClick = (progressBtn) => {
|
|
|
progressBtn.current.style.top = 50 + 'px';
|
|
|
orgChart &&
|
|
|
orgChart
|
|
|
.layout('left')
|
|
|
.setCentered(orgChart.getChartState().root.id)
|
|
|
.render();
|
|
|
active = 'left';
|
|
|
};
|
|
|
|
|
|
handleZoomIn = (progressBtn) => {
|
|
|
if (progressBtn) {
|
|
|
let top = parseInt(progressBtn.current.style.top) - 10;
|
|
|
if (top >= 0) {
|
|
|
progressBtn.current.style.top = top + 'px';
|
|
|
} else {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
orgChart && orgChart.zoomIn();
|
|
|
};
|
|
|
|
|
|
handleZoomOut = (progressBtn) => {
|
|
|
if (progressBtn) {
|
|
|
let top = parseInt(progressBtn.current.style.top) + 10;
|
|
|
if (top <= 100) {
|
|
|
progressBtn.current.style.top = top + 'px';
|
|
|
} else {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
orgChart && orgChart.zoomOut();
|
|
|
};
|
|
|
|
|
|
downloadPdf = (chart) => {
|
|
|
chart.exportImg({
|
|
|
save: false,
|
|
|
full: true,
|
|
|
onLoad: (base64) => {
|
|
|
var pdf = new jsPDF();
|
|
|
var img = new Image();
|
|
|
img.src = base64;
|
|
|
img.onload = function () {
|
|
|
pdf.addImage(
|
|
|
img,
|
|
|
'JPEG',
|
|
|
5,
|
|
|
5,
|
|
|
595 / 3,
|
|
|
((img.height / img.width) * 595) / 3,
|
|
|
);
|
|
|
pdf.save('chart.pdf');
|
|
|
};
|
|
|
},
|
|
|
});
|
|
|
};
|
|
|
|
|
|
handleExport = (e) => {
|
|
|
let type = e.key == '1' ? 'png' : e.key == '1' ? 'pdf' : 'excel';
|
|
|
if (type == 'png') {
|
|
|
orgChart && orgChart.exportImg({ full: true });
|
|
|
} else if (type == 'pdf') {
|
|
|
orgChart && this.downloadPdf(orgChart);
|
|
|
} else {
|
|
|
let { dataSource } = this.state;
|
|
|
var option = {};
|
|
|
let dataTable = [];
|
|
|
if (dataSource) {
|
|
|
for (let i in dataSource) {
|
|
|
if (dataSource) {
|
|
|
let obj = {
|
|
|
序号: dataSource[i].id,
|
|
|
工号: dataSource[i].workCode,
|
|
|
姓名: dataSource[i].lastName,
|
|
|
性别: dataSource[i].sex,
|
|
|
部门: dataSource[i].departmentName,
|
|
|
分部: dataSource[i].subcompanyName,
|
|
|
岗位: dataSource[i].jobTitle,
|
|
|
手机号: dataSource[i].mobile,
|
|
|
};
|
|
|
dataTable.push(obj);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
option.fileName = '组织信息';
|
|
|
option.datas = [
|
|
|
{
|
|
|
sheetData: dataTable,
|
|
|
sheetName: 'sheet',
|
|
|
sheetFilter: [
|
|
|
'序号',
|
|
|
'工号',
|
|
|
'姓名',
|
|
|
'性别',
|
|
|
'部门',
|
|
|
'分部',
|
|
|
'岗位',
|
|
|
'手机号',
|
|
|
],
|
|
|
sheetHeader: [
|
|
|
'序号',
|
|
|
'工号',
|
|
|
'姓名',
|
|
|
'性别',
|
|
|
'部门',
|
|
|
'分部',
|
|
|
'岗位',
|
|
|
'手机号',
|
|
|
],
|
|
|
},
|
|
|
];
|
|
|
var toExcel = new ExportJsonExcel(option);
|
|
|
toExcel.saveExcel();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* 节点渲染
|
|
|
*/
|
|
|
nodeContentRender = (d, i, arr, state) => {
|
|
|
let name = d.data.deptType == 0 ? '所属部门' : '所属科室';
|
|
|
if (d.data.fisvitual != 0) {
|
|
|
name = '所属部门';
|
|
|
}
|
|
|
|
|
|
if (d.data.ftype == 2) {
|
|
|
return `<div style="position: relative;">
|
|
|
<div style=" height: 152px;background-size: 100% 100%;box-sizing: border-box;padding-top: 30px;position:relative;z-index:2">
|
|
|
<div style='position:absolute;z-index:-1;top:0'>
|
|
|
<img style='width: 295px;height: 163px;' src="${this.getDepartmentImage(
|
|
|
d.data.fisvitual,
|
|
|
)}">
|
|
|
</div>
|
|
|
<div style="display: inline-block; background-size: 100% 100%; width: 35%; height: 90px; text-align:center; vertical-align: top; margin-left: 11px;box-sizing: border;">
|
|
|
<img src='./img/user-card/avatar-outer.png' style='position:absolute;width:90px;height:90px;left:11px'/>
|
|
|
<img src="${
|
|
|
d.data.fleaderimg
|
|
|
? d.data.fleaderimg
|
|
|
: './img/department.png'
|
|
|
}" style="width: 58px; height: 58px;position:absolute;left:29px; border-radius: 50%; margin-top: 16px;position:absolute;left:29px;z-index:999"/>
|
|
|
</div>
|
|
|
<div style="display: inline-block; margin-left: 6px;width: 55%">
|
|
|
<div class="dept-box" style="font-size: 15px;font-family: Microsoft YaHei-Regular, Microsoft YaHei;font-weight: 900;color: #333333;height: 25px;line-height: 25px;width:110px,white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">
|
|
|
${d.data.fname}
|
|
|
</div>
|
|
|
<div style="font-size: 13px;font-family: Microsoft YaHei-Bold, Microsoft YaHei;color: #333333;height: 25px;line-height: 25px;">
|
|
|
负责人:${d.data.fleader}
|
|
|
</div>
|
|
|
<div style="display:flex" >
|
|
|
<div style="height: 25px; line-height: 25px; min-width: 80px;">
|
|
|
在岗: ${d.data.fonjob} 人
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
</div>`;
|
|
|
} else if (d.data.ftype == 3) {
|
|
|
return `<div style="position: relative;">
|
|
|
<div style=" height: 152px;background-size: 100% 100%;box-sizing: border-box;padding-top: 40px;">
|
|
|
<div style='position:absolute;z-index:-1;top:0'>
|
|
|
<img style='width: 295px;height: 163px;' src='./img/user-card/user-card-orange.png'>
|
|
|
</div>
|
|
|
<img src="./img/user-card/jobicon-orange.png" style="margin-left: 20px; vertical-align: top;"/>
|
|
|
<div style="display: inline-block; margin-left: 15px;">
|
|
|
<div style="font-size: 15px;height: 25px;line-height: 25px;font-family: Microsoft YaHei-Bold, Microsoft YaHei;font-weight: bold;color: #333333;">${d.data.fname}</div>
|
|
|
<div style="font-size: 13px;font-family: Microsoft YaHei-Regular, Microsoft YaHei;font-weight: 400;color: #333333;display: flex;height: 25px;line-height: 25px;">
|
|
|
<span>在岗: ${d.data.fonjob} 人</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>`;
|
|
|
} else if (d.data.ftype == 4) {
|
|
|
return `<div style="position: relative;" >
|
|
|
<div style="height: 152px;background-size: 100% 100%;box-sizing: border-box;padding-top: 30px;">
|
|
|
<div style='position:absolute;z-index:-1;top:0px'>
|
|
|
<img style='width: 295px;height: 163px;' src='./img/user-card/user-card-green.png'>
|
|
|
</div>
|
|
|
<div style="display: inline-block; background-size: 100% 100%; width: 35%; height: 90px; text-align:center; vertical-align: top; margin-left: 11px;box-sizing: border;">
|
|
|
<img src='./img/user-card/avatar-outer-green.png' style='position:absolute;width:90px;height:90px;left:11px;z-index:-1'/>
|
|
|
<img src="${
|
|
|
d.data.fleaderimg
|
|
|
? d.data.fleaderimg
|
|
|
: './img/default_avator.png'
|
|
|
}" style="width: 58px; height: 58px; border-radius: 50%; margin-top: 16px;margin-left: -6px;z-index:999" />
|
|
|
</div>
|
|
|
<div style="display: inline-block; margin-left: 6px;width: 55%;height:100%;margin-top: -12px;">
|
|
|
<div style='display:flex;align-items:center;height: 25px;line-height: 25px;margin-top:15px'>
|
|
|
<div style="font-weight: bold;font-size: 15px;ont-family: Microsoft YaHei-Bold, Microsoft YaHei;color: #333333;">${
|
|
|
d.data.fname
|
|
|
}</div>
|
|
|
</div>
|
|
|
<div style="font-size: 13px;font-family: Microsoft YaHei-Regular, Microsoft YaHei;font-weight: 400;color: #333333;height: 25px;line-height: 25px;">
|
|
|
<span>${name}: ${d.data.localDeptName} </span>
|
|
|
<div>岗位名称: ${d.data.jobTitle}</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>`;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
showDrawer = async (params) => {
|
|
|
this.setState({ open: true, params: params });
|
|
|
await this.getDeatilCondition();
|
|
|
const { defaultNbValue, defaultWbValue } = this.state;
|
|
|
params = {
|
|
|
...params,
|
|
|
nbValue: defaultNbValue.join(','),
|
|
|
wbValue: defaultWbValue.join(','),
|
|
|
};
|
|
|
this.getDeatilDatas(params, 'chart', '0');
|
|
|
};
|
|
|
|
|
|
onClose = () => {
|
|
|
this.setState({
|
|
|
open: false,
|
|
|
detailType: 'chart',
|
|
|
showJob: false,
|
|
|
data: [],
|
|
|
dataSource: [],
|
|
|
defaultNbValue: [],
|
|
|
defaultWbValue: [],
|
|
|
});
|
|
|
};
|
|
|
|
|
|
changeDetail = () => {
|
|
|
const {
|
|
|
defaultNbValue,
|
|
|
defaultWbValue,
|
|
|
detailType,
|
|
|
params,
|
|
|
data,
|
|
|
dataSource,
|
|
|
} = this.state;
|
|
|
let type = detailType == 'chart' ? 'table' : 'chart';
|
|
|
this.setState({
|
|
|
detailType: type,
|
|
|
});
|
|
|
const nParam = {
|
|
|
...params,
|
|
|
nbValue: defaultNbValue.join(','),
|
|
|
wbValue: defaultWbValue.join(','),
|
|
|
};
|
|
|
this.getDeatilDatas(nParam, type, '0');
|
|
|
};
|
|
|
|
|
|
onNbChange = (checkedValues) => {
|
|
|
this.setState({
|
|
|
defaultNbValue: checkedValues,
|
|
|
});
|
|
|
const { defaultWbValue, params, detailType } = this.state;
|
|
|
const nParam = {
|
|
|
...params,
|
|
|
nbValue: checkedValues.join(','),
|
|
|
wbValue: defaultWbValue.join(','),
|
|
|
};
|
|
|
this.getDeatilDatas(nParam, detailType, '0');
|
|
|
};
|
|
|
|
|
|
onWbChange = (checkedValues) => {
|
|
|
this.setState({
|
|
|
defaultWbValue: checkedValues,
|
|
|
});
|
|
|
const { defaultNbValue, params, detailType } = this.state;
|
|
|
const nParam = {
|
|
|
...params,
|
|
|
nbValue: defaultNbValue.join(','),
|
|
|
wbValue: checkedValues.join(','),
|
|
|
};
|
|
|
this.getDeatilDatas(nParam, detailType, '0');
|
|
|
};
|
|
|
|
|
|
render() {
|
|
|
const {
|
|
|
params,
|
|
|
open,
|
|
|
data,
|
|
|
detailType,
|
|
|
dataSource,
|
|
|
columns,
|
|
|
spinning,
|
|
|
showJob,
|
|
|
nbOptions,
|
|
|
defaultNbValue,
|
|
|
wbOptions,
|
|
|
defaultWbValue,
|
|
|
} = this.state;
|
|
|
let arr = [];
|
|
|
|
|
|
if (detailType == 'chart') {
|
|
|
arr.push({ label: '导出图片', key: '1' });
|
|
|
//arr.push({ label: '导出PDF', key: '2' });
|
|
|
} else {
|
|
|
arr.push({ label: '导出表格', key: '3' });
|
|
|
}
|
|
|
|
|
|
const menu = <Menu onClick={this.handleExport.bind(this)} items={arr} />;
|
|
|
|
|
|
return (
|
|
|
<Drawer
|
|
|
title={
|
|
|
<>
|
|
|
<CodepenCircleOutlined
|
|
|
style={{ color: '#0086ff', fontSize: '16px' }}
|
|
|
/>
|
|
|
<span style={{ marginLeft: '5px', color: '#0086ff' }}>
|
|
|
部门详情
|
|
|
</span>
|
|
|
</>
|
|
|
}
|
|
|
width={1200}
|
|
|
onClose={this.onClose}
|
|
|
open={open}
|
|
|
extra={
|
|
|
<Space>
|
|
|
<Dropdown overlay={menu}>
|
|
|
<Button type="primary">导出</Button>
|
|
|
</Dropdown>
|
|
|
<Button type="primary" onClick={this.changeDetail}>
|
|
|
切换
|
|
|
</Button>
|
|
|
</Space>
|
|
|
}
|
|
|
>
|
|
|
<>
|
|
|
<Row style={{ margin: '20px 20px' }}>
|
|
|
<Col span={2}>内部职工:</Col>{' '}
|
|
|
<Col span={22}>
|
|
|
{' '}
|
|
|
<Checkbox.Group
|
|
|
options={nbOptions}
|
|
|
value={defaultNbValue}
|
|
|
onChange={this.onNbChange}
|
|
|
/>
|
|
|
</Col>
|
|
|
</Row>
|
|
|
<Row style={{ margin: '0px 20px' }}>
|
|
|
<Col span={2}>外部人员:</Col>
|
|
|
<Col span={22}>
|
|
|
{' '}
|
|
|
<Checkbox.Group
|
|
|
options={wbOptions}
|
|
|
value={defaultWbValue}
|
|
|
onChange={this.onWbChange}
|
|
|
/>
|
|
|
</Col>
|
|
|
</Row>
|
|
|
{detailType == 'chart' ? (
|
|
|
<div className="svg-container">
|
|
|
<Spin
|
|
|
size="large"
|
|
|
spinning={spinning}
|
|
|
tip="正在读取数据...."
|
|
|
className="loading-center"
|
|
|
/>
|
|
|
{data.length > 0 && (
|
|
|
<OrgChartComponent
|
|
|
setChart={(chart) => (orgChart = chart)}
|
|
|
setClick={(click) => (addNodeChildFunc = click)}
|
|
|
onNodeClick={this.onNodeClick}
|
|
|
onButtonClick={this.onButtonClick}
|
|
|
data={data}
|
|
|
buttonContent={this.buttonContentRender}
|
|
|
nodeWidth={this.nodeWidthRender}
|
|
|
nodeHeight={this.nodeHeightRender}
|
|
|
nodeContent={this.nodeContentRender}
|
|
|
/>
|
|
|
)}
|
|
|
</div>
|
|
|
) : (
|
|
|
<div style={{ padding: '0 20px' }}>
|
|
|
<Table
|
|
|
dataSource={dataSource}
|
|
|
columns={columns}
|
|
|
scroll={{ y: 500 }}
|
|
|
loading={spinning}
|
|
|
pagination={{
|
|
|
locale: {
|
|
|
// 翻页文本替换
|
|
|
items_per_page: '条/页',
|
|
|
jump_to: '跳至',
|
|
|
page: '页',
|
|
|
},
|
|
|
showTotal: (total) => `共 ${dataSource.length} 条`,
|
|
|
}}
|
|
|
/>
|
|
|
</div>
|
|
|
)}
|
|
|
</>
|
|
|
</Drawer>
|
|
|
);
|
|
|
}
|
|
|
}
|