helper.js
import moreIcon from '@/assets/org/icon_more.png'
import personIcon from '@/assets/org/icon_person.png'
import orgIcon from '@/assets/org/icon_org.png'
//创建echarts 配置
export function createTreeOption(params) {
const option = {
tooltip: {
trigger: 'item',
triggerOn: 'none',//不触发
height: '350px',
enterable: true,//鼠标是否可进入提示框浮层中
confine: true//是否将tooltip框限制在图表的区域内
},
series: {
name: '树图',
type: 'tree',
orient: 'vertical', // vertical horizontal
borderColor: 'black',
edgeShape: 'polyline',//折线
top: '10%',
bottom: '10%',
left: '0px',
right: '0px',
expandAndCollapse: false,//点击展开折叠
itemStyle: {
color: '#fff' // 节点背景色
},
label: {
show: true,
backgroundColor: '#fff',
borderColor: '#333',
borderWidth: 1,
borderRadius: 5,
distance: 100,
color: '#000',
fontSize: 14,
rich: {//自定义label节点内容样式
titleBg: {
// 标题背景
backgroundColor: '#16bc83',
height: 30,
align: 'right',
borderRadius: [5, 5, 0, 0],
width: '100%'
},
titleStyle: {
// 标题
align: 'left',
color: '#eee',
padding: [0, 4, 0, 4]
},
titleIcon: {
// 标题图标
height: 25,
align: 'right',
backgroundColor: {
image: orgIcon
}
},
staffIcon: {
// 员工图标
height: 25,
align: 'right',
verticalAlign: 'center',
backgroundColor: {
image: personIcon
}
},
manageStaffName: {
// 负责人样式
align: 'center',
color: '#16bc83',
verticalAlign: 'center',
padding: 10
},
centerBg: {
height: 50,
align: 'right',
padding: [0, 20, 0, 0], // 上右下左
width: '100%'
},
moreIcon: {
// 更多图标
height: 25,
align: 'left',
verticalAlign: 'center',
backgroundColor: {
image: moreIcon
}
},
compileTitleStyle: {
// 编制样式
align: 'left',
color: '#333',
padding: [10, 0, 3, 3]
},
compileStyle: {
// 编制样式
align: 'left',
color: '#333',
padding: [10, 3, 3, 1]
},
unequal: {
color: '#f00',
align: 'left',
padding: [10, 3, 3, 1]
}
}
}
}
}
option.series.data = [createNode(params)]
return option
}
//创建树图label内容节点
export function createNode({
orgId,
orgName,
manageStaffName,
compileNum,
onJobNum,
children
}) {
const node = {
value: orgId,
name: orgName,
label: {
formatter: function() {//自定义布局
var arr = []
arr.push(`{titleIcon|}{titleStyle|${orgName}}{titleBg|}`)
arr.push(
` {staffIcon|}{manageStaffName|${
manageStaffName || ''
}}{moreIcon|}{centerBg|}`
)
arr.push(
`{compileTitleStyle|编制:}{${
onJobNum !== compileNum ? 'unequal' : 'compileStyle'
}| ${onJobNum}/${compileNum}}`
)
return arr.join('\n')
}
}
}
if (children) {
node.children = []
children.forEach(item => {
node.children.push(createNode(item))
})
}
return node
}
vue文件
<template>
<div class="page">
<div class="page-title">组织架构图</div>
<div class="btn-box">
<el-button
size="mini"
type="primary"
@click="print"
>打印</el-button>
</div>
<el-divider />
<div class="canvas">
<div
id="infoTable"
style="width: 0px;height: 0px;"
>
<div class="table-title">
{{ nodeOrgName }}
</div>
<el-table
ref="refTable"
v-loading="loadingCompile"
border
style="maxWidth:600px;"
max-height="300px"
:data="tableData"
:cell-style="cellStyle"
header-row-class-name="table-list-header"
row-key="orgId"
>
<el-table-column
min-width="180"
align="center"
prop="postName"
label="职位"
/>
<el-table-column
min-width="120"
align="center"
prop="compileNum"
label="编制数"
/>
<el-table-column
min-width="120"
align="center"
prop="onJobNum"
label="在职数"
/>
<el-table-column
min-width="120"
align="center"
:formatter="computdiff"
label="差异"
/>
</el-table>
</div>
<div id="diagram" /><!-- 内容画布 -->
</div>
</div>
</template>
<script>
import * as echarts from 'echarts/core'
import { TreeChart } from 'echarts/charts'
import { createTreeOption } from './helper'
import { TooltipComponent } from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'
import { getOrgTreeById } from '@/api/org/info'
import { getByOrgId } from '@/api/org/compile'
import { printDom } from '@/utils/index'
export default {
name: 'OrgArchitecture',
data() {
return {
nodeOrgName: '',
orgId: '',
currentId: '',
tableData: [],
currentOrgTree: [],
rotateNum: 0,
myChart: null
}
},
created() {
this.orgId = this.$route.query.orgId
echarts.use([
TreeChart,
TooltipComponent,
CanvasRenderer
])
this.createDiagram()
},
beforeDestroy() {
if (this.myChart) {
this.myChart.dispose()
}
this.myChart = null
},
methods: {
computdiff(row) {
return (row && (row.onJobNum !== row.compileNum)) ? String(row.onJobNum - row.compileNum) : ''
},
cellStyle({ row, columnIndex }) {
var overflow = row && row.onJobNum > row.compileNum
if (columnIndex > 1 && overflow) {
return 'color:#f00'
}
return ''
},
createDiagram() {
getOrgTreeById(this.orgId)
.then(res => {
var doc = document.getElementById('diagram')
var myChart = echarts.init(doc)//初始化
this.myChart = myChart
this.currentOrgTree = []
this.currentOrgTree.push(res.data)
var op = createTreeOption(this.currentOrgTree[0])//创建配置参数
const that = this
op.tooltip.formatter = this.showCompile//tooltip显示内容
myChart.on('click', (params) => {//点击事件处理
that.getCompileDetial(params, myChart)
})
myChart.setOption(op)//设置配置
var allNode = 0
var nodes = myChart._chartsViews[0]._data._graphicEls
for (var i = 0, count = nodes.length; i < count; i++) {
var node = nodes[i]
if (node === undefined) { continue }
allNode++
}
var width = window.innerWidth
var currentWidth = 120 * allNode
var newWidth = Math.max(currentWidth, width)
myChart.resize({//重置画布尺寸
width: newWidth
})
})
},
closeTip() {
if (this.myChart) {
// 手动隐藏tooltip
this.myChart.dispatchAction({
type: 'hideTip'
})
}
},
showCompile() {
return `<div class="table-box">${document.getElementById('infoTable').innerHTML}</div>`
},
getCompileDetial(params, myChart) {
this.tableData = []
if (params && params.data && params.data.value) {
this.nodeOrgName = params.name
getByOrgId(params.data.value)
.then(res => {
if (res && res.data) {
this.tableData = res.data
if (myChart) {
setTimeout(() => {//手动显示tooltip
myChart.dispatchAction({
type: 'showTip',
position: [params.event.event.zrX, params.event.event.zrY],
seriesIndex: params.seriesIndex,
name: params.name
})
}, 100)
}
} else {
this.$message.error(res && res.msg ? res.msg : '查询编制失败')
}
})
}
},
print() {
this.closeTip()
var canvas = echarts.getInstanceByDom(document.getElementsByTagName('canvas')[0].parentNode.parentNode)
var dataUrl = canvas.getDataURL()//获取画布内容
var parentDom = document.createElement('div')
var translateDom = document.createElement('div')
var newImg = document.createElement('img')
newImg.src = dataUrl
newImg.height = 800
newImg.width = canvas.getWidth() / canvas.getHeight() * 800
newImg.setAttribute(
'style',
'transform-origin:0% 0%;transform:rotate(90deg);'
)
translateDom.setAttribute(
'style',
`transform:translateX(100%);`
)
translateDom.append(newImg)
parentDom.append(translateDom)
printDom({
parentDom,
title: '组织架构图',
zoom: 1
})
}
}
}
</script>
<style lang="scss" scoped>
.page {
display: flex;
flex-direction: column;
}
.page-title {
font-size: 14px;
color: #333;
font-weight: bold;
}
/deep/.el-divider--horizontal {
margin-top: 12px;
}
.btn-box {
display: flex;
margin-right: 10px;
align-items: center;
justify-content: flex-end;
}
.canvas {
flex: 1;
#diagram {
width: 100%;
height: calc(100% - 10px);
background: white;
overflow: auto;
}
.table-box {
border: #999 solid 1px;
border-radius: 4px;
background: #fff;
z-index: 100;
}
.table-title {
padding: 12px;
color: #333;
font-size: 12px;
font-weight: bold;
width: calc(100% - 24px);
display: flex;
justify-content: space-between;
}
}
</style>