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.
193 lines
5.4 KiB
TypeScript
193 lines
5.4 KiB
TypeScript
/*
|
|
* Author: 黎永顺
|
|
* name: 薪资项目-拓扑图
|
|
* Description:
|
|
* Date: 2023/10/19
|
|
*/
|
|
import React, { FunctionComponent, useEffect, useMemo, useState } from "react";
|
|
import { DecompositionTreeGraph, NodeConfig } from "@ant-design/graphs";
|
|
import { notification } from "antd";
|
|
import { exceptStr } from "@/utils/common";
|
|
import API from "@/api";
|
|
// @ts-ignore
|
|
import uuidV4 from "uuid/v4";
|
|
|
|
interface OwnProps {
|
|
}
|
|
|
|
type Props = OwnProps;
|
|
const index: FunctionComponent<Props> = (props) => {
|
|
const [dataSource, setDataSource] = useState<any>({});
|
|
const [i18n, setI18n] = useState<any>({});
|
|
useEffect(() => {
|
|
window.parent.postMessage({ type: "initDiagram" }, "*");
|
|
window.addEventListener("message", receiveMessageFromIndex, false);
|
|
return () => {
|
|
window.removeEventListener("message", receiveMessageFromIndex, false);
|
|
};
|
|
}, []);
|
|
const receiveMessageFromIndex = (event: any) => {
|
|
const data: any = exceptStr(event.data);
|
|
if (!_.isEmpty(data)) {
|
|
const { i18n, acctEmpId, salaryItemId, salarySobId } = data;
|
|
setI18n(i18n);
|
|
init({ acctEmpId, salaryItemId, salarySobId });
|
|
}
|
|
};
|
|
const init = (paylaod: any) => {
|
|
API.CalculateService.getSalarysobItemTopology(paylaod).then(({ data }) => {
|
|
const { status, data: result } = data;
|
|
if (status) {
|
|
const dataSource = {
|
|
id: result.salaryItemId.toString(),
|
|
value: { title: result.salaryItemName, formula: result.formula, items: [{ text: result.result }] },
|
|
children: !_.isEmpty(result.children) ? traverse(result.children) : []
|
|
};
|
|
setDataSource(dataSource);
|
|
}
|
|
});
|
|
};
|
|
const getChildren = async (nodeCfg: NodeConfig) => {
|
|
return findChildren(extractTree(dataSource.children), nodeCfg.id);
|
|
};
|
|
const openNotification = (data: any) => {
|
|
const { value: { formula } } = data;
|
|
notification.destroy();
|
|
if (_.isEmpty(formula)) return;
|
|
const { formula: description } = formula;
|
|
notification.open({
|
|
message: i18n["公式"],
|
|
duration: 5,
|
|
description,
|
|
style: { maxWidth: 600 }
|
|
});
|
|
};
|
|
const component: any = useMemo(() => {
|
|
const config = {
|
|
data: {
|
|
...dataSource,
|
|
children: dataSource.children ? _.map(dataSource.children, o => ({ ...o, children: null })) : null
|
|
},
|
|
autoFit: false, animate: true,
|
|
nodeCfg: {
|
|
getChildren,
|
|
autoWidth: true,
|
|
title: {
|
|
style: { fill: "#333" },
|
|
containerStyle: () => {
|
|
return {
|
|
fill: "#f7fbfe",
|
|
stroke: "#e5e5e5"
|
|
};
|
|
}
|
|
},
|
|
nodeStateStyles: {
|
|
hover: {
|
|
stroke: '#e5e5e5',
|
|
lineWidth: 1,
|
|
},
|
|
},
|
|
items: {
|
|
style: (cfg: any, group: any, type: string) => {
|
|
const styles = {
|
|
value: { fill: "#333" }
|
|
};
|
|
return styles[type];
|
|
}
|
|
},
|
|
style: {
|
|
stroke: "#e5e5e5"
|
|
}
|
|
},
|
|
markerCfg: (cfg: any) => {
|
|
const { g_level, id } = cfg;
|
|
return {
|
|
show: (g_level === 0 && !_.isEmpty(dataSource.children)) || getStorageIds(dataSource.children).includes(id)
|
|
};
|
|
},
|
|
onReady: (graph: any) => {
|
|
graph.on("node:click", (evt: any) => {
|
|
if (_.isEmpty(evt.target.attrs) || JSON.stringify(evt.target.attrs).indexOf("cursor") !== -1) return;
|
|
openNotification(evt.item._cfg.model);
|
|
});
|
|
setTimeout(() => {
|
|
graph.zoom(1);
|
|
});
|
|
},
|
|
behaviors: ["drag-canvas", "zoom-canvas"]
|
|
};
|
|
// @ts-ignore
|
|
return !_.isEmpty(dataSource) ? <DecompositionTreeGraph {...config} /> : null;
|
|
}, [dataSource]);
|
|
return component;
|
|
};
|
|
|
|
export default index;
|
|
|
|
const traverse: any = (arr: any[]) => {
|
|
return _.map(arr, item => {
|
|
if (!_.isEmpty(item.children)) {
|
|
const uuid = uuidV4();
|
|
return {
|
|
id: uuid,
|
|
value: { title: item.salaryItemName, formula: item.formula, items: [{ text: item.result }] },
|
|
children: traverse(item.children)
|
|
};
|
|
} else {
|
|
const uuid = uuidV4();
|
|
return {
|
|
id: uuid, value: { title: item.salaryItemName, formula: item.formula, items: [{ text: item.result }] }
|
|
};
|
|
}
|
|
});
|
|
};
|
|
const findChildren: any = (arr: any[], id: string) => {
|
|
const dataSource = _.find(arr, o => o.id === id).children;
|
|
return _.map(dataSource, o => ({ ...o, children: [] }));
|
|
};
|
|
/*
|
|
* Author: 黎永顺
|
|
* Description:数组扁平换
|
|
* Params:
|
|
* Date: 2023/10/26
|
|
*/
|
|
export const extractTree = (data: any[]) => {
|
|
if (!data.length) return [];
|
|
const list: any[] = [];
|
|
const getObj = (arr: any[]) => {
|
|
arr.forEach((row: any) => {
|
|
let obj = {};
|
|
obj = JSON.parse(JSON.stringify(row));
|
|
list.push(obj);
|
|
if (row.children) {
|
|
getObj(row.children);
|
|
}
|
|
});
|
|
return list;
|
|
};
|
|
return getObj(data);
|
|
};
|
|
/*
|
|
* Author: 黎永顺
|
|
* Description: 有children子集的id集合
|
|
* Params:
|
|
* Date: 2023/10/26
|
|
*/
|
|
const getStorageIds = (array: any[]) => {
|
|
let ids: any = [];
|
|
const getIds = (array: any, ids: any) => {
|
|
array.forEach((item: any) => {
|
|
if (item.children) ids.push(item.id);
|
|
if (item.children) ids = getIds(item.children, ids);
|
|
});
|
|
return ids;
|
|
};
|
|
if (Array.isArray(array)) {
|
|
if (array.length === 0) return [];
|
|
} else {
|
|
return [];
|
|
}
|
|
ids = getIds(array, ids);
|
|
return ids;
|
|
};
|