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/pages/company.jsx

398 lines
11 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 styles from './index.less';
import React, { useEffect, useState } from 'react';
import { OrgChartComponent } from '@/components/orgChart';
import * as d3 from 'd3';
import { TopBar } from '../components/topBar';
import ToolBar from '../components/toolBar';
import TimeLine from '../components/timeline';
import jsPDF from 'jspdf';
import moment from 'moment';
import qs from 'qs';
import { message } from 'antd';
let active = 'top';
export default function companyPage() {
const [data, setData] = useState(null);
const [sliderProgress, setSliderProgress] = useState(50);
let addNodeChildFunc = null;
let orgChart = null;
let topBarSearchRequest = null;
const [hasRight, setHasRight] = useState('');
const [disabled, setDisabled] = useState(false);
// 点击节点
function onNodeClick(nodeId) {
// alert('clicked ' + nodeId);
}
// 扩展按钮点击
function 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;
}
let idsStr = idsList.join(',');
let api = '';
if (topBarSearchRequest) {
let request = { ...topBarSearchRequest, ids: idsStr };
api =
'/api/bs/hrmorganization/orgchart/asyncCompanyData' +
qs.stringify(request, { addQueryPrefix: true });
} else {
api =
'/api/bs/hrmorganization/orgchart/asyncCompanyData?fclass=0&root=0&date=' +
moment(new Date()).format('YYYY-MM-DD') +
'&ids=' +
idsStr;
}
fetch(api)
.then((res) => res.json())
.then((data) => {
if (data.data) {
data.data.forEach((item) => {
window.chart.addNode(item);
});
}
});
}
}
// 获取部门图片
function getDepartmentImage() {
let index = Math.floor(Math.random() * 8) + 1;
return `./img/back/level4.png`;
}
// 获取分部图片
function getSubcompanyImage() {
let index = Math.floor(Math.random() * 3) + 1;
return `./img/subcompany/2.png`;
}
// 获取数据
useEffect(() => {
d3.json(
// "/company/data"
'/api/bs/hrmorganization/orgchart/companyData?fclass=0&isvitual=0&root=0&date=' +
moment(new Date()).format('YYYY-MM-DD'),
).then((data) => {
setData(data.data);
setHasRight(data?.hasRight);
});
}, [true]);
// ButtonContent渲染
const buttonContentRender = ({ node, state }) => {
if (node.children) {
return `<div style="border-radius:3px;padding:3px;font-size:10px;margin:auto auto;background-color:#66BAF5"> <div style="margin-top:0px;line-height:1.35;height:11px;font-size:25px; color: #fff;">ˆ</div> </div>`;
} else {
return `<div style="border-radius:3px;padding:3px;font-size:10px;margin:auto auto;background-color:#66BAF5"> <div style="margin-top:0px;line-height:1.35;height:11px;font-size:25px; color: #fff;transform:rotate(180deg)">ˆ</div> </div>`;
}
};
// 节点宽度渲染
const nodeWidthRender = (d) => {
if (d.data.ftype == 0) {
return 1000;
} else if (d.data.ftype == 1) {
return 160;
} else if (d.data.ftype == 2) {
return 144;
}
return 200;
};
const nodeHeightRender = (d) => {
if (d.data.ftype == 0) {
return 100;
} else if (d.data.ftype == 1) {
return 80;
} else if (d.data.ftype == 2) {
return 106;
}
return 120;
};
const nodeContentRender = (d, i, arr, state) => {
// 集团地址
let companyUrl =
'/spa/organization/static/index.html#/main/organization/group';
// 分部地址
let subcompanyUrl = `/spa/organization/static/index.html#/main/organization/companyExtend/${d.data.fobjid}`;
// 部门地址
let departmentUrl = `/spa/organization/static/index.html#/main/organization/departmentExtend/${d.data.fobjid}`;
if (d.data.ftype == 0) {
return `<div onclick="if(${d.data.fisvitual}==1) return;window.open('${companyUrl}', '_blank')" style="text-align:center">
<div style="display: inline-block; vertical-align: top;">
<img src="./img/company.png" />
</div>
<div style="display: inline-block; text-align: center; margin-left: 5px;">
<div style="
font-size: 24px;
font-family: Microsoft YaHei-Bold, Microsoft YaHei;
font-weight: bold;
color: #000000;
line-height: 28px;
letter-spacing: 1px;
margin-top: 10px;
">${d.data.fname}</div>
</div>
</div>`;
} else if (d.data.ftype == 1) {
return `<div onclick="if(${d.data.fisvitual}==1) return;window.open('${subcompanyUrl}', '_blank')">
<div style="width: 144px; border: 1px solid #66BAF5; margin: 10px auto 0px; border-radius: 10px; text-align: center;
font-size: 14px;
font-family: Microsoft YaHei-Regular, Microsoft YaHei;
font-weight: 400;
color: #333333;
height: 56px;
padding: 15px 10px;
">
${d.data.fname}
</div>
</div>`;
} else if (d.data.ftype == 2) {
return `
<div style="width: 100%; height: 100%; background-size: 100% 100%;" onclick="if(${
d.data.fisvitual
}==1) return;window.open('${departmentUrl}')">
<div style='position:absolute;height:100%'>
<img style='width:144px;height:106px' src="${getDepartmentImage()}"/>
</div>
<div style="width: 144px;height: 80px;top: 35px;position: relative;font-weight: 400;font-size: 14px;
font-family: Microsoft YaHei-Regular, Microsoft YaHei;color: #333333;text-align: center;">
<div title=${
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>
`;
}
return `<div>${d.data.fname}</div>`;
};
// tool bar start
const handleTopLayoutClick = (progressBtn) => {
progressBtn.current.style.top = 50 + 'px';
orgChart &&
orgChart
.layout('top')
.setCentered(orgChart.getChartState().root.id)
.render();
active = 'top';
};
const handleLeftLayoutClick = (progressBtn) => {
progressBtn.current.style.top = 50 + 'px';
orgChart &&
orgChart
.layout('left')
.setCentered(orgChart.getChartState().root.id)
.render();
active = 'left';
};
const 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();
};
const 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();
};
const handleZoomBehavior = (value) => {
orgChart && orgChart.zoomBehavior(value - 50);
};
// tool bar end
// top bar start
function 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');
};
},
});
}
/**
* 导出
* @param {*} type
*/
const handleExport = (type) => {
if (type == 'png') {
orgChart && orgChart.exportImg({ full: true });
} else {
orgChart && downloadPdf(orgChart);
}
};
/**
* 时间轴点击
* @param {*} timeline
*/
const timeLineSearch = (timeline) => {};
/**
* 查询
* @param {*} requestData
*/
const handleSearch = (requestData) => {
topBarSearchRequest = requestData;
let api =
'/api/bs/hrmorganization/orgchart/companyData' +
qs.stringify(requestData, { addQueryPrefix: true });
fetch(api)
.then((res) => res.json())
.then((data) => {
if (data.data) {
if (!data.data.length) {
setData([{}]);
message.warning('暂无数据');
} else {
setData(data?.data);
}
}
});
};
/**
* 同步数据
* @param {*} requestData
*/
const handleSynchronous = (requestData) => {
setDisabled(true);
let api = '/api/bs/hrmorganization/orgchart/synchronousData';
fetch(api)
.then((res) => res.json())
.then((data) => {
if (data.code == 200) {
message.success('同步成功,请重新查询');
} else {
message.error('数据同步失败');
}
setDisabled(false);
//this.handleSearch(requestData);
});
};
useEffect(() => {
if (active == 'left') {
orgChart &&
orgChart
.setCentered(orgChart.getChartState().root?.id)
.layout('left')
.render();
} else {
orgChart &&
orgChart
.setCentered(orgChart.getChartState().root?.id)
.layout('top')
.render();
}
}, [data]);
if (hasRight === false) {
return (
<div style={{ width: '100%', top: '40%', position: 'absolute' }}>
<img
style={{ display: 'block', margin: '0 auto' }}
src="./img/permission.png"
/>
<p style={{ textAlign: 'center' }}>对不起您暂时没有权限!</p>
</div>
);
}
return (
hasRight && (
<div className={styles.contentWrapper}>
<TopBar
onExport={(type) => {
handleExport(type);
}}
onSearch={(requestData) => {
handleSearch(requestData);
}}
onSynchronous={(requestData) => {
handleSynchronous(requestData);
}}
disabled={disabled}
type="company"
url="/api/bs/hrmorganization/orgchart/getCondition?type=company"
/>
<ToolBar
onTopLayoutClick={(progressBtn) => handleTopLayoutClick(progressBtn)}
onLeftLayoutClick={(progressBtn) =>
handleLeftLayoutClick(progressBtn)
}
onZoomOut={(progressBtn) => handleZoomOut(progressBtn)}
onZoomIn={(progressBtn) => handleZoomIn(progressBtn)}
onZoomBehavior={(value) => handleZoomBehavior(value)}
/>
<TimeLine
onClick={(timeline) => {
timeLineSearch(timeline);
}}
url="/api/bs/hrmorganization/orgchart/timelines?type=company"
/>
<OrgChartComponent
setChart={(chart) => (orgChart = chart)}
setClick={(click) => (addNodeChildFunc = click)}
onNodeClick={onNodeClick}
data={data}
onButtonClick={onButtonClick}
buttonContent={buttonContentRender}
nodeWidth={nodeWidthRender}
nodeHeight={nodeHeightRender}
nodeContent={nodeContentRender}
/>
</div>
)
);
}