commit 6e668c9d89ae211d4f8806aff2d39bc699de6a89
Author: MustangDeng <670124965@qq.com>
Date: Tue Jul 12 17:10:03 2022 +0800
组织结构图v1.0
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..7e3649a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,16 @@
+# http://editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
+
+[Makefile]
+indent_style = tab
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bee1cf6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,20 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/npm-debug.log*
+/yarn-error.log
+/yarn.lock
+/package-lock.json
+
+# production
+/dist
+
+# misc
+.DS_Store
+
+# umi
+/src/.umi
+/src/.umi-production
+/src/.umi-test
+/.env.local
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..0d4222f
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,8 @@
+**/*.md
+**/*.svg
+**/*.ejs
+**/*.html
+package.json
+.umi
+.umi-production
+.umi-test
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..94beb14
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,11 @@
+{
+ "singleQuote": true,
+ "trailingComma": "all",
+ "printWidth": 80,
+ "overrides": [
+ {
+ "files": ".prettierrc",
+ "options": { "parser": "json" }
+ }
+ ]
+}
diff --git a/.umirc.ts b/.umirc.ts
new file mode 100644
index 0000000..e54955f
--- /dev/null
+++ b/.umirc.ts
@@ -0,0 +1,25 @@
+import { defineConfig } from 'umi';
+
+export default defineConfig({
+ hash: true,
+ history: { type: 'hash'},
+ base: "/spa/orgChart/",
+ // exportStatic: {},
+ publicPath: './',
+ nodeModulesTransform: {
+ type: 'none',
+ },
+ routes: [
+ { path: '/user', component: '@/pages/user' },
+ { path: '/company', component: '@/pages/company' }
+ ],
+ fastRefresh: {},
+ antd: {},
+ proxy: {
+ "/api": { // 标识需要进行转换的请求的url
+ "target": "http://localhost:18089/api", // 服务端域名
+ "changeOrigin": true, // 允许域名进行转换
+ "pathRewrite": { "^/api": ''} // 将请求url里的ci去掉
+ }
+ }
+});
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..07afeb7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
+# umi project
+
+## Getting Started
+
+Install dependencies,
+
+```bash
+$ yarn
+```
+
+Start the dev server,
+
+```bash
+$ yarn start
+```
diff --git a/mock/api.ts b/mock/api.ts
new file mode 100644
index 0000000..f845c0d
--- /dev/null
+++ b/mock/api.ts
@@ -0,0 +1,158 @@
+export default {
+ 'GET /company/data': [
+ {
+ "id": 1,
+ "fname": "集团公司",
+ "ftype": 0,
+ "parentId": null
+ },
+ {
+ "id": 2,
+ "fname": "HRSSC共享服务中心",
+ "ftype": 1,
+ "parentId": 1
+ },
+ {
+ "id": 3,
+ "fname": "事业部A",
+ "ftype": 1,
+ "parentId": 1
+ },
+ {
+ "id": 4,
+ "fname": "苏州分公司",
+ "ftype": 1,
+ "parentId": 1
+ },
+ {
+ "id": 5,
+ "fname": "人力资源部经理",
+ "ftype": 2,
+ "parentId": 2
+ },
+ {
+ "id": 6,
+ "fname": "招聘组",
+ "ftype": 2,
+ "parentId": 3
+ },
+ {
+ "id": 7,
+ "fname": "薪酬核算组",
+ "ftype": 2,
+ "parentId": 4
+ },
+ {
+ "id": 8,
+ "fname": "人事服务组",
+ "ftype": 2,
+ "parentId": 2
+ },
+ {
+ "id": 9,
+ "fname": "培训组",
+ "ftype": 2,
+ "parentId": 2
+ },
+ {
+ "id": 10,
+ "fname": "员工关系组",
+ "ftype": 2,
+ "parentId": 2
+ },
+ {
+ "id": 11,
+ "fname": "服务管理组",
+ "ftype": 2,
+ "parentId": 2
+ },
+ {
+ "id": 12,
+ "fname": "信息与数据组",
+ "ftype": 2,
+ "parentId": 2
+ }
+ ],
+ 'GET /user/data': [
+ {
+ "id": 1,
+ "parentId": null,
+ "ftype": 0,
+ "fname": "维森集团",
+ "fleadername": "杨文元",
+ "fleaderimg": "./img/avator.png",
+ "fleaderjob": "董事长",
+ "fplan": 1000,
+ "fonjob": 987
+ },
+ {
+ "id": 2,
+ "parentId": 1,
+ "ftype": 1,
+ "fname": "南京分公司",
+ "fleadername": "杨文元",
+ "fleaderimg": "./img/avator.png",
+ "fleaderjob": "总经理",
+ "fplan": 300,
+ "fonjob": 287
+ },
+ {
+ "id": 3,
+ "parentId": 1,
+ "ftype": 1,
+ "fname": "南京分公司",
+ "fleadername": "杨文元",
+ "fleaderimg": "./img/avator.png",
+ "fleaderjob": "总经理",
+ "fplan": 300,
+ "fonjob": 287
+ },
+ {
+ "id": 4,
+ "parentId": 1,
+ "ftype": 1,
+ "fname": "南京分公司",
+ "fleadername": "杨文元",
+ "fleaderimg": "./img/avator.png",
+ "fleaderjob": "总经理",
+ "fplan": 300,
+ "fonjob": 287
+ },
+ {
+ "id": 5,
+ "parentId": 2,
+ "ftype": 2,
+ "fname": "销售部",
+ "fleadername": "杨文元",
+ "fleaderimg": "./img/avator.png",
+ "fleaderjob": "部长",
+ "fplan": 200,
+ "fonjob": 200
+ },
+ {
+ "id": 6,
+ "parentId": 5,
+ "ftype": 3,
+ "fname": "销售",
+ "fleadername": null,
+ "fleaderimg": null,
+ "fleaderjob": null,
+ "fplan": 200,
+ "fonjob": 200
+ },
+ {
+ "id": 7,
+ "parentId": 6,
+ "ftype": 4,
+ "fname": "杨文元",
+ "fleadername": "杨文元",
+ "department": "销售部",
+ "fleaderimg": "./img/avator.png",
+ "fleaderjob": "销售",
+ "mobile": "13989058743",
+ "address": "秦淮区新街口12-201",
+ "fplan": 200,
+ "fonjob": 200
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..7f0d301
--- /dev/null
+++ b/package.json
@@ -0,0 +1,44 @@
+{
+ "private": true,
+ "scripts": {
+ "start": "umi dev",
+ "build": "umi build",
+ "postinstall": "umi generate tmp",
+ "prettier": "prettier --write '**/*.{js,jsx,tsx,ts,less,md,json}'",
+ "test": "umi-test",
+ "test:coverage": "umi-test --coverage"
+ },
+ "gitHooks": {
+ "pre-commit": "lint-staged"
+ },
+ "lint-staged": {
+ "*.{js,jsx,less,md,json}": [
+ "prettier --write"
+ ],
+ "*.ts?(x)": [
+ "prettier --parser=typescript --write"
+ ]
+ },
+ "dependencies": {
+ "@ant-design/pro-layout": "^6.5.0",
+ "@types/d3": "^7.4.0",
+ "d3": "7.4.4",
+ "d3-org-chart": "2.6.0",
+ "jspdf": "^2.5.1",
+ "moment": "^2.29.3",
+ "qs": "^6.11.0",
+ "react": "17.x",
+ "react-dom": "17.x",
+ "umi": "^3.5.26"
+ },
+ "devDependencies": {
+ "@types/react": "^17.0.0",
+ "@types/react-dom": "^17.0.0",
+ "@umijs/preset-react": "1.x",
+ "@umijs/test": "^3.5.26",
+ "lint-staged": "^10.0.7",
+ "prettier": "^2.2.0",
+ "typescript": "^4.1.2",
+ "yorkie": "^2.0.0"
+ }
+}
diff --git a/public/img/avator.png b/public/img/avator.png
new file mode 100644
index 0000000..ea4f2d0
Binary files /dev/null and b/public/img/avator.png differ
diff --git a/public/img/button_content.png b/public/img/button_content.png
new file mode 100644
index 0000000..458a4f0
Binary files /dev/null and b/public/img/button_content.png differ
diff --git a/public/img/company.png b/public/img/company.png
new file mode 100644
index 0000000..3288b0e
Binary files /dev/null and b/public/img/company.png differ
diff --git a/public/img/company_job_label.png b/public/img/company_job_label.png
new file mode 100644
index 0000000..109a4eb
Binary files /dev/null and b/public/img/company_job_label.png differ
diff --git a/public/img/default_avator.png b/public/img/default_avator.png
new file mode 100644
index 0000000..84572e3
Binary files /dev/null and b/public/img/default_avator.png differ
diff --git a/public/img/department/1.png b/public/img/department/1.png
new file mode 100644
index 0000000..34cec80
Binary files /dev/null and b/public/img/department/1.png differ
diff --git a/public/img/department/2.png b/public/img/department/2.png
new file mode 100644
index 0000000..f21e553
Binary files /dev/null and b/public/img/department/2.png differ
diff --git a/public/img/department/3.png b/public/img/department/3.png
new file mode 100644
index 0000000..f9296ad
Binary files /dev/null and b/public/img/department/3.png differ
diff --git a/public/img/department/4.png b/public/img/department/4.png
new file mode 100644
index 0000000..36c4979
Binary files /dev/null and b/public/img/department/4.png differ
diff --git a/public/img/department/5.png b/public/img/department/5.png
new file mode 100644
index 0000000..47981a3
Binary files /dev/null and b/public/img/department/5.png differ
diff --git a/public/img/department/6.png b/public/img/department/6.png
new file mode 100644
index 0000000..3441b82
Binary files /dev/null and b/public/img/department/6.png differ
diff --git a/public/img/department/7.png b/public/img/department/7.png
new file mode 100644
index 0000000..c685368
Binary files /dev/null and b/public/img/department/7.png differ
diff --git a/public/img/department/8.png b/public/img/department/8.png
new file mode 100644
index 0000000..1d3a147
Binary files /dev/null and b/public/img/department/8.png differ
diff --git a/public/img/manager.png b/public/img/manager.png
new file mode 100644
index 0000000..34cec80
Binary files /dev/null and b/public/img/manager.png differ
diff --git a/public/img/subcompany/1.png b/public/img/subcompany/1.png
new file mode 100644
index 0000000..bb91a88
Binary files /dev/null and b/public/img/subcompany/1.png differ
diff --git a/public/img/subcompany/2.png b/public/img/subcompany/2.png
new file mode 100644
index 0000000..3a93936
Binary files /dev/null and b/public/img/subcompany/2.png differ
diff --git a/public/img/subcompany/3.png b/public/img/subcompany/3.png
new file mode 100644
index 0000000..88ffaa1
Binary files /dev/null and b/public/img/subcompany/3.png differ
diff --git a/public/img/subcompany1.png b/public/img/subcompany1.png
new file mode 100644
index 0000000..bb91a88
Binary files /dev/null and b/public/img/subcompany1.png differ
diff --git a/public/img/user-card/avatar-outer.png b/public/img/user-card/avatar-outer.png
new file mode 100644
index 0000000..8570ea4
Binary files /dev/null and b/public/img/user-card/avatar-outer.png differ
diff --git a/public/img/user-card/card-label-start.png b/public/img/user-card/card-label-start.png
new file mode 100644
index 0000000..88b48b4
Binary files /dev/null and b/public/img/user-card/card-label-start.png differ
diff --git a/public/img/user-card/jobicon.png b/public/img/user-card/jobicon.png
new file mode 100644
index 0000000..5c25edd
Binary files /dev/null and b/public/img/user-card/jobicon.png differ
diff --git a/public/img/user-card/line1.png b/public/img/user-card/line1.png
new file mode 100644
index 0000000..341964f
Binary files /dev/null and b/public/img/user-card/line1.png differ
diff --git a/public/img/user-card/line2.png b/public/img/user-card/line2.png
new file mode 100644
index 0000000..aa3045e
Binary files /dev/null and b/public/img/user-card/line2.png differ
diff --git a/public/img/user-card/user-card.png b/public/img/user-card/user-card.png
new file mode 100644
index 0000000..92e0995
Binary files /dev/null and b/public/img/user-card/user-card.png differ
diff --git a/src/components/orgChart/index.jsx b/src/components/orgChart/index.jsx
new file mode 100644
index 0000000..a010448
--- /dev/null
+++ b/src/components/orgChart/index.jsx
@@ -0,0 +1,58 @@
+import React, { useLayoutEffect, useRef, useEffect } from 'react';
+import { OrgChart } from 'd3-org-chart';
+import * as d3 from 'd3';
+
+export const OrgChartComponent = (props, ref) => {
+ const d3Container = useRef(null);
+ let chart = null;
+
+ function addNode(node) {
+ chart.addNode(node);
+ }
+
+ props.setClick(addNode);
+
+
+ // We need to manipulate DOM
+ useLayoutEffect(() => {
+ if (props.data && d3Container.current) {
+ if (!chart) {
+ chart = new OrgChart();
+ }
+ props.setChart(chart)
+ try {
+ chart
+ .container(d3Container.current)
+ .data(props.data)
+ .nodeWidth(props.nodeWidth)
+ .nodeHeight(props.nodeHeight)
+ .layout("left")
+
+ .linkUpdate(function(d, i, arr) {
+ d3.select(this)
+ .attr("stroke", "#66BAF5")
+ .attr("stroke-width", 1)
+ .style("stroke-dasharray", ("3, 3"))
+ })
+ .onNodeClick((d, i, arr) => {
+ console.log(d, 'Id of clicked node ');
+ props.onNodeClick(d);
+ })
+ .buttonContent(props.buttonContent)
+ .nodeContent(props.nodeContent)
+ .render();
+
+ chart.expandAll()
+ } catch(err) {
+ console.log(err);
+ }
+ }
+ }, [props.data, d3Container.current]);
+
+
+ return (
+
+ );
+};
diff --git a/src/components/toolBar/img/add.png b/src/components/toolBar/img/add.png
new file mode 100644
index 0000000..f300dcc
Binary files /dev/null and b/src/components/toolBar/img/add.png differ
diff --git a/src/components/toolBar/img/decrease.png b/src/components/toolBar/img/decrease.png
new file mode 100644
index 0000000..3f70bc2
Binary files /dev/null and b/src/components/toolBar/img/decrease.png differ
diff --git a/src/components/toolBar/img/left.png b/src/components/toolBar/img/left.png
new file mode 100644
index 0000000..ae542f9
Binary files /dev/null and b/src/components/toolBar/img/left.png differ
diff --git a/src/components/toolBar/img/left_active.png b/src/components/toolBar/img/left_active.png
new file mode 100644
index 0000000..9986912
Binary files /dev/null and b/src/components/toolBar/img/left_active.png differ
diff --git a/src/components/toolBar/img/top.png b/src/components/toolBar/img/top.png
new file mode 100644
index 0000000..935c0b0
Binary files /dev/null and b/src/components/toolBar/img/top.png differ
diff --git a/src/components/toolBar/img/top_active.png b/src/components/toolBar/img/top_active.png
new file mode 100644
index 0000000..379a699
Binary files /dev/null and b/src/components/toolBar/img/top_active.png differ
diff --git a/src/components/toolBar/index.jsx b/src/components/toolBar/index.jsx
new file mode 100644
index 0000000..5de765c
--- /dev/null
+++ b/src/components/toolBar/index.jsx
@@ -0,0 +1,78 @@
+import React from 'react'
+import add from './img/add.png'
+import decrease from './img/decrease.png'
+import styles from './index.less';
+import top from './img/top.png';
+import left from './img/left.png';
+import topActive from './img/top_active.png'
+import leftActive from './img/left_active.png'
+
+export default class ToolBar extends React.Component {
+ progressBtn = React.createRef()
+ start = false;
+ clientY = 0
+ originalY = 0
+ top = 50
+ constructor(props) {
+ super(props);
+ this.state = {
+ toolActive: "left"
+ }
+ }
+
+ handleMouseDown(e) {
+ this.clientY = e.clientY
+ this.originalY = e.clientY
+ this.top = parseInt(this.progressBtn.current.style.top)
+ this.start = true;
+ }
+
+ handleMouseMove(e) {
+ if(this.start && e.clientY - this.clientY > 10) {
+ this.props.onZoomOut()
+ this.clientY = e.clientY
+ } else if(this.start && e.clientY - this.clientY < - 10) {
+ this.props.onZoomIn()
+ this.clientY = e.clientY
+ }
+ if(this.start) {
+ let offset = e.clientY - this.originalY
+ console.log("offset:", offset);
+ if((this.top + offset) < 0) {
+ offset = 0 - this.top
+ }
+ if((this.top + offset) > 100) {
+ offset = 100 - this.top
+ }
+ console.log("(this.top + offset):", (this.top + offset))
+ this.progressBtn.current.style.top = (this.top + offset) + "px";
+ }
+ }
+
+ handleMouseUp(e) {
+ this.start = false;
+ console.log("this.start:", this.start)
+
+ }
+
+ render() {
+ return (
+
+

{this.props.onZoomIn(this.progressBtn)}}/>
+
+
{this.handleMouseDown(e)}}
+ onMouseMove={(e) => {this.handleMouseMove(e)}}
+ onMouseUp={(e) => {this.handleMouseUp(e)}}
+ onMouseLeave={(e) => {this.handleMouseUp(e)}}
+ >
+
+
+

{this.props.onZoomOut(this.progressBtn)}}/>
+
+

{this.setState({toolActive: "top"}); this.props.onTopLayoutClick(this.progressBtn)}}/>
+

{this.setState({toolActive: "left"}); this.props.onLeftLayoutClick(this.progressBtn)}}/>
+
+ )
+ }
+}
\ No newline at end of file
diff --git a/src/components/toolBar/index.less b/src/components/toolBar/index.less
new file mode 100644
index 0000000..ffe10d8
--- /dev/null
+++ b/src/components/toolBar/index.less
@@ -0,0 +1,38 @@
+.toolbarWrapper {
+ width: 68px;
+ position: fixed;
+ right: 10px;
+ z-index: 100;
+ background: #fff;
+ border-radius: 20px;
+ padding-top: 20px;
+ padding-bottom: 20px;
+ text-align: center;
+ .progressWrapper {
+ position: relative;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ margin-left: 20px;
+ .progressLine {
+ height: 100px;
+ width: 0px;
+ border-left: 2px solid #C9C9C9;
+ margin-left: 12px;
+ }
+ .progressBtn {
+ width: 16px;
+ height: 9px;
+ background-color: #C9C9C9;
+ position: absolute;
+ left: 5px;
+ top: 0px;
+ }
+ }
+ .toolBarItem {
+ display: block;
+ margin-top: 20px;
+ margin-bottom: 20px;
+ margin-left: 20px;
+ cursor: pointer;
+ }
+}
\ No newline at end of file
diff --git a/src/components/topBar/index.jsx b/src/components/topBar/index.jsx
new file mode 100644
index 0000000..c0a888a
--- /dev/null
+++ b/src/components/topBar/index.jsx
@@ -0,0 +1,123 @@
+import React from 'react'
+import style from './index.less'
+import { DatePicker, Select, Button, Checkbox, Row, Col, Dropdown, Menu, } from 'antd'
+const { Option } = Select;
+import moment from 'moment';
+
+
+export class TopBar extends React.Component {
+
+ constructor(props) {
+ super(props)
+ this.state = {
+ fclasslist: [],
+ companylist: [],
+ requestData: {
+ date: moment(new Date()).format("YYYY-MM-DD"),
+ fclass: "0",
+ root: "0",
+ level: "3",
+ fisvitual: "0"
+ }
+ }
+ }
+
+ handleFormChange(payload) {
+ let requestData = {...this.state.requestData, ...payload}
+ this.setState({requestData})
+ }
+
+ handleExportMenuClick(e) {
+ this.props.onExport(e.key == '1' ? "png" : "pdf")
+ }
+
+ handleExportButtonClick() {
+ this.props.onExport("png")
+ }
+
+ componentDidMount() {
+ fetch(this.props.url).then(res => res.json()).then(data => {
+ this.setState({
+ fclasslist: data.fclasslist,
+ companylist: data.companylist
+ })
+ })
+ }
+
+ menu = (
+
+ );
+
+ render() {
+ return (
+
+
+
+
+ 数据日期: this.handleFormChange({date: value && value != "" ? value.format("YYYY-MM-DD") : ""})} />
+
+
+
+
+ 维度:
+
+
+
+ 根节点:
+
+
+
+ 显示层级:
+
+
+
+ this.handleFormChange({fisvitual: e.target.checked ? "1": "0"})}>显示虚拟组织
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+}
\ No newline at end of file
diff --git a/src/components/topBar/index.less b/src/components/topBar/index.less
new file mode 100644
index 0000000..e3e9c4d
--- /dev/null
+++ b/src/components/topBar/index.less
@@ -0,0 +1,9 @@
+.topbarWrapper {
+ margin: 20px;
+ background: #FFFFFF;
+ // background: red;
+ padding: 20px 26px 20px 26px;
+ box-shadow: 0px 5px 5px #e2e2e2;
+ border-radius: 0px 0px 0px 0px;
+ vertical-align: middle;
+}
\ No newline at end of file
diff --git a/src/department/index.js b/src/department/index.js
new file mode 100644
index 0000000..b04fce2
--- /dev/null
+++ b/src/department/index.js
@@ -0,0 +1,5 @@
+import React from 'react'
+
+export default () => {
+ return Hello
+}
\ No newline at end of file
diff --git a/src/pages/company.jsx b/src/pages/company.jsx
new file mode 100644
index 0000000..0a6fd8c
--- /dev/null
+++ b/src/pages/company.jsx
@@ -0,0 +1,252 @@
+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 jsPDF from 'jspdf'
+import moment from 'moment';
+import qs from 'qs';
+
+
+export default function companyPage() {
+ const [data, setData] = useState(null);
+ const [sliderProgress, setSliderProgress] = useState(50);
+ let addNodeChildFunc = null;
+ let orgChart = null;
+
+ // 点击节点
+ function onNodeClick(nodeId) {
+ // alert('clicked ' + nodeId);
+ }
+
+ // 获取部门图片
+ function getDepartmentImage() {
+ let index = Math.floor(Math.random() * 8) + 1
+ return `./img/department/${index}.png`
+ }
+
+ // 获取部门图片
+ function getSubcompanyImage() {
+ let index = Math.floor(Math.random() * 3) + 1
+ return `./img/subcompany/${index}.png`
+ }
+
+ // 获取数据
+ useEffect(() => {
+ d3.json(
+ // "/company/data"
+ "/api/bs/hrmorganization/orgchart/companyData?fclass=0&root=0&date=" + moment(new Date()).format("YYYY-MM-DD")
+ ).then(data => {
+ setData(data.data);
+ });
+ }, [true]);
+
+ // ButtonContent渲染
+ const buttonContentRender = ({ node, state }) => {
+ if(node.children) {
+ return ``;
+ } else {
+ return ``
+ }
+ }
+
+ // 节点宽度渲染
+ const nodeWidthRender = d =>
+ {
+ if(d.data.ftype == 0) {
+ return 220;
+ } 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 160;
+ }else if(d.data.ftype == 2) {
+ return 56;
+ }
+ return 120;
+ }
+
+
+
+ const nodeContentRender = (d, i, arr, state) => {
+ if(d.data.ftype == 0) {
+ return `
+
+

+
+
+
${d.data.fname}
+
COMPANY_GROUP
+
+
`
+ } else if(d.data.ftype == 1) {
+ return `
+
+
})
+
+
+ ${d.data.fname}
+
+
`
+ } else if(d.data.ftype == 2) {
+ return `
+
+
+
})
+
${d.data.fname}
+
+
+ `
+ }
+ return `${d.data.fname}
`
+ }
+
+
+ // tool bar start
+ const handleTopLayoutClick = (progressBtn) => {
+ progressBtn.current.style.top= 50 + "px";
+ orgChart && orgChart.layout('top').render().fit();
+ }
+
+ const handleLeftLayoutClick = (progressBtn) => {
+ progressBtn.current.style.top= 50 + "px";
+ orgChart && orgChart.layout('left').render().fit();
+ }
+
+ const handleZoomIn = (progressBtn) => {
+ if(progressBtn) {
+ let top = (parseInt(progressBtn.current.style.top) - 10)
+ if(top <= 0) {
+ top = 30;
+ }
+ progressBtn.current.style.top = top + "px";
+ }
+ orgChart && orgChart.zoomIn();
+ }
+
+ const handleZoomOut = (progressBtn) => {
+ if(progressBtn) {
+ let top = (parseInt(progressBtn.current.style.top) + 10)
+ if(top >= 100) {
+ top = 70;
+ }
+ progressBtn.current.style.top = top + "px";
+ }
+
+ orgChart && orgChart.zoomOut();
+ }
+
+ const handleZoomBehavior = (value) => {
+ orgChart && orgChart.zoomBehavior(value - 50);
+ }
+
+ // tool bar end
+
+ // top bar start
+
+ function downloadPdf(chart) {
+ chart.exportImg({
+ save: false,
+ 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');
+ };
+ },
+ });
+ }
+
+ const handleExport = (type) => {
+ if(type == "png") {
+ orgChart && orgChart.exportImg({full:true});
+ } else {
+ orgChart && downloadPdf(orgChart)
+ }
+ }
+
+ const handleSearch = (requestData) => {
+ let api = "/api/bs/hrmorganization/orgchartt/companyData" + qs.stringify(requestData, {addQueryPrefix: true})
+ fetch(api).then(res => res.json()).then(data => {
+ setData(data.data);
+ })
+ }
+
+ // top bar end
+
+
+ return (
+
+ {handleExport(type)}}
+ onSearch={(requestData) => {handleSearch(requestData)}}
+ url="/bs/hrmorganization/orgchart/jcl/orgchart/getCondition?type=company"
+ />
+ handleTopLayoutClick(progressBtn)}
+ onLeftLayoutClick={(progressBtn) => handleLeftLayoutClick(progressBtn)}
+ onZoomOut={(progressBtn) => handleZoomOut(progressBtn)}
+ onZoomIn={(progressBtn) => handleZoomIn(progressBtn)}
+ onZoomBehavior={(value) => handleZoomBehavior(value)}
+ />
+ orgChart = chart}
+ setClick={click => (addNodeChildFunc = click)}
+ onNodeClick={onNodeClick}
+ data={data}
+ buttonContent={
+ buttonContentRender
+ }
+ nodeWidth={nodeWidthRender}
+ nodeHeight={nodeHeightRender}
+ nodeContent={nodeContentRender}
+ />
+
+ );
+}
diff --git a/src/pages/index.less b/src/pages/index.less
new file mode 100644
index 0000000..0186693
--- /dev/null
+++ b/src/pages/index.less
@@ -0,0 +1,11 @@
+.title {
+ background: rgb(121, 242, 157);
+}
+
+.wrapper {
+ background: #F7F9FD;
+}
+
+.contentWrapper {
+ background-color: #F7F9FD;
+}
\ No newline at end of file
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
new file mode 100644
index 0000000..b725177
--- /dev/null
+++ b/src/pages/index.tsx
@@ -0,0 +1,9 @@
+import styles from './index.less';
+
+export default function IndexPage() {
+ return (
+
+
Page index
+
+ );
+}
diff --git a/src/pages/user.jsx b/src/pages/user.jsx
new file mode 100644
index 0000000..0dea0da
--- /dev/null
+++ b/src/pages/user.jsx
@@ -0,0 +1,304 @@
+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 moment from "moment";
+import qs from 'qs';
+
+
+export default function userPage() {
+ const [data, setData] = useState(null);
+ const [progressTop, setProgressTop] = useState(50);
+ let addNodeChildFunc = null;
+ let orgChart = null;
+ let progressBtnRef = null;
+
+ // 点击节点
+ function onNodeClick(nodeId) {
+ // alert('clicked ' + nodeId);
+ }
+
+ // 获取部门图片
+ function getDepartmentImage() {
+ let index = Math.floor(Math.random() * 8) + 1
+ return `./img/department/${index}.png`
+ }
+
+ // 获取部门图片
+ function getSubcompanyImage() {
+ let index = Math.floor(Math.random() * 3) + 1
+ return `./img/subcompany/${index}.png`
+ }
+
+ // 获取数据
+ useEffect(() => {
+ d3.json(
+ // "/user/data"
+ "/api/bs/hrmorganization/orgchart/userData?fclass=0&root=0&date=" + moment(new Date()).format("YYYY-MM-DD")
+ ).then(data => {
+ setData(data.data);
+ });
+ }, [true]);
+
+ // ButtonContent渲染
+ const buttonContentRender = ({ node, state }) => {
+ return `
+
+

+
+ `
+ }
+
+ // 节点宽度渲染
+ const nodeWidthRender = d =>
+ {
+ return 280;
+ }
+
+ const nodeHeightRender = d => {
+ return 160;
+ }
+
+ // tool bar start
+ const handleTopLayoutClick = (progressBtn) => {
+ progressBtn.current.style.top= 50 + "px";
+ orgChart && orgChart.layout('top').render().fit();
+ }
+
+ const handleLeftLayoutClick = (progressBtn) => {
+ progressBtn.current.style.top= 50 + "px";
+ orgChart && orgChart.layout('left').render().fit();
+ }
+
+ const handleZoomIn = (progressBtn) => {
+ if(progressBtn) {
+ let top = (parseInt(progressBtn.current.style.top) - 10)
+ if(top <= 0) {
+ top = 30;
+ }
+ progressBtn.current.style.top = top + "px";
+ }
+ orgChart && orgChart.zoomIn();
+ }
+
+ const handleZoomOut = (progressBtn) => {
+ if(progressBtn) {
+ let top = (parseInt(progressBtn.current.style.top) + 10)
+ if(top >= 100) {
+ top = 70;
+ }
+ progressBtn.current.style.top = top + "px";
+ }
+ orgChart && orgChart.zoomOut();
+ }
+
+ // tool bar end
+
+
+ // top bar start
+
+ function downloadPdf(chart) {
+ chart.exportImg({
+ save: false,
+ 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');
+ };
+ },
+ });
+ }
+
+ const handleExport = (type) => {
+ if(type == "png") {
+ orgChart && orgChart.exportImg({full:true});
+ } else {
+ orgChart && downloadPdf(orgChart)
+ }
+ }
+
+ const handleSearch = (requestData) => {
+ let api = "/api/bs/hrmorganization/orgchart/jcl/orgchart/userData" + qs.stringify(requestData, {addQueryPrefix: true})
+ fetch(api).then(res => res.json()).then(data => {
+ setData(data.data)
+ })
+ }
+
+ // top bar end
+
+ const nodeContentRender = (d, i, arr, state) => {
+ if(d.data.ftype == 0 || d.data.ftype == 1 || d.data.ftype == 2) {
+ return `
+
+

+
${d.data.fname}
+
+
+
+
+
+
+

+
+
+
${d.data.fleadername}
+
${d.data.fname} / ${d.data.fleaderjob}
+
+
编制: ${d.data.fplan}
+
在岗: ${d.data.fonjob}
+
+
+
+
+
`
+ } else if(d.data.ftype == 3) {
+ return `
+
+

+
${d.data.fname}
+
+
+
+
+
+

+
+
${d.data.fname}
+
+ 编制:${d.data.fplan}
+ 在岗:${d.data.fonjob}
+
+
+
+
+
`
+ } else if(d.data.ftype == 4) {
+ return `
+
+

+
+
+
+
+
+
+

+
+
+
${d.data.fname}
+
${d.data.department} / ${d.data.fleaderjob}
+
${d.data.mobile}
+
地址:${d.data.address}
+
+
+
+
`
+ }
+ }
+
+ return (
+
+ {handleExport()}}
+ onSearch={(requestData) => {handleSearch(requestData)}}
+ url="/api/bs/hrmorganization/orgchart/getCondition?type=user"
+ />
+ handleTopLayoutClick(progressBtn)}
+ onLeftLayoutClick={(progressBtn) => handleLeftLayoutClick(progressBtn)}
+ onZoomOut={(progressBtn) => handleZoomOut(progressBtn)}
+ onZoomIn={(progressBtn) => handleZoomIn(progressBtn)}
+ />
+ orgChart = chart}
+ setClick={click => (addNodeChildFunc = click)}
+ onNodeClick={onNodeClick}
+ data={data}
+ buttonContent={
+ buttonContentRender
+ }
+ nodeWidth={nodeWidthRender}
+ nodeHeight={nodeHeightRender}
+ nodeContent={nodeContentRender}
+ />
+
+ );
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..6d42f8c
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,37 @@
+{
+ "compilerOptions": {
+ "target": "esnext",
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "importHelpers": true,
+ "jsx": "react-jsx",
+ "esModuleInterop": true,
+ "sourceMap": true,
+ "baseUrl": "./",
+ "strict": true,
+ "paths": {
+ "@/*": ["src/*"],
+ "@@/*": ["src/.umi/*"]
+ },
+ "allowSyntheticDefaultImports": true
+ },
+ "include": [
+ "mock/**/*",
+ "src/**/*",
+ "config/**/*",
+ ".umirc.ts",
+ "typings.d.ts"
+ ],
+ "exclude": [
+ "node_modules",
+ "lib",
+ "es",
+ "dist",
+ "typings",
+ "**/__test__",
+ "test",
+ "docs",
+ "tests"
+ ]
+}
diff --git a/typings.d.ts b/typings.d.ts
new file mode 100644
index 0000000..06c8a5b
--- /dev/null
+++ b/typings.d.ts
@@ -0,0 +1,10 @@
+declare module '*.css';
+declare module '*.less';
+declare module '*.png';
+declare module '*.svg' {
+ export function ReactComponent(
+ props: React.SVGProps,
+ ): React.ReactElement;
+ const url: string;
+ export default url;
+}