You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
org-chart-frant/src/components/drawer/index.jsx

542 lines
16 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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>
);
}
}