326 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Vue
		
	
	
	
			
		
		
	
	
			326 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Vue
		
	
	
	
<template>
 | 
						|
	<view class="table pr" :style="'zoom:'+size+';'">
 | 
						|
		<view class="v-tr" style="display: flex;">
 | 
						|
			<view class="v-td" :class="{
 | 
						|
					colspan: Array.isArray(treeData.children) ? treeData.children.length * 2 : 1,
 | 
						|
					parentLevel: Array.isArray(treeData.children) && treeData.children.length,
 | 
						|
					extend: Array.isArray(treeData.children) && treeData.children.length && treeData.extend
 | 
						|
				}">
 | 
						|
				<view :class="{ node: true }">
 | 
						|
					<view class="person" :class="Array.isArray(treeData.class) ? treeData.class : []">
 | 
						|
						<image @click.stop="clickNode(treeData)" class="person-ava" :src="treeData.avatarUrl" mode=""></image>
 | 
						|
					</view>
 | 
						|
				</view>
 | 
						|
			</view>
 | 
						|
		</view>
 | 
						|
		<view class="v-tr" v-if="Array.isArray(treeData.children) && treeData.children.length && treeData.extend">
 | 
						|
			<view v-for="(children, index) in treeData.children" :key="index" colspan="2" class="childLevel v-td">
 | 
						|
				<TreeChart :json="children" :left="0" :top="0" @click-node="clickNode" />
 | 
						|
			</view>
 | 
						|
		</view>
 | 
						|
	</view>
 | 
						|
</template>
 | 
						|
 | 
						|
<script>
 | 
						|
	export default {
 | 
						|
		name: 'TreeChart',
 | 
						|
		props: ['json', 'size'],
 | 
						|
		data() {
 | 
						|
			return {
 | 
						|
				treeData: {}
 | 
						|
			};
 | 
						|
		},
 | 
						|
		watch: {
 | 
						|
			json: {
 | 
						|
				handler: function(Props) {
 | 
						|
					let extendKey = function(jsonData) {
 | 
						|
						jsonData.extend = jsonData.extend === void 0 ? true : !!jsonData.extend;
 | 
						|
						if (Array.isArray(jsonData.children)) {
 | 
						|
							jsonData.children.forEach(c => {
 | 
						|
								extendKey(c);
 | 
						|
							});
 | 
						|
						}
 | 
						|
						return jsonData;
 | 
						|
					};
 | 
						|
					if (Props) {
 | 
						|
						this.treeData = extendKey(Props);
 | 
						|
					}
 | 
						|
				},
 | 
						|
				immediate: true
 | 
						|
			}
 | 
						|
		},
 | 
						|
		methods: {
 | 
						|
			toggleExtend: function(treeData) {
 | 
						|
				treeData.extend = !treeData.extend;
 | 
						|
				this.$forceUpdate();
 | 
						|
			},
 | 
						|
			clickNode(e){
 | 
						|
				this.$emit('click-node',e)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	};
 | 
						|
</script>
 | 
						|
 | 
						|
<style scoped>
 | 
						|
	.f18 {
 | 
						|
		font-size: 18rpx;
 | 
						|
	}
 | 
						|
 | 
						|
	.pv-btn {
 | 
						|
		width: 200rpx;
 | 
						|
		height: 50rpx;
 | 
						|
		background-color: #b2821e;
 | 
						|
		color: #fff;
 | 
						|
		font-size: 20rpx;
 | 
						|
		line-height: 50rpx;
 | 
						|
		display: flex;
 | 
						|
		align-items: center;
 | 
						|
		margin: auto;
 | 
						|
		margin-top: 12rpx;
 | 
						|
		margin-bottom: 12rpx;
 | 
						|
	}
 | 
						|
 | 
						|
	.next-btn {
 | 
						|
		border-radius: 50%;
 | 
						|
		background: none;
 | 
						|
		width: 40rpx;
 | 
						|
		height: 40rpx;
 | 
						|
		margin: auto;
 | 
						|
		padding: 0;
 | 
						|
		display: flex;
 | 
						|
		justify-content: center;
 | 
						|
		align-items: center;
 | 
						|
	}
 | 
						|
 | 
						|
	.table {
 | 
						|
		border-collapse: separate !important;
 | 
						|
		border-spacing: 0 !important;
 | 
						|
		width: 100%;
 | 
						|
	}
 | 
						|
 | 
						|
	.v-tr {
 | 
						|
		
 | 
						|
		 display: inline-flex;
 | 
						|
		  justify-content: center;
 | 
						|
		  align-items: flex-start;
 | 
						|
		  /* width: 100%; */
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	.v-td {
 | 
						|
		position: relative;
 | 
						|
		vertical-align: top;
 | 
						|
		padding: 0 0 100rpx 0;
 | 
						|
		text-align: center;
 | 
						|
	}
 | 
						|
 | 
						|
	.extend_handle {
 | 
						|
		position: absolute;
 | 
						|
		left: 50%;
 | 
						|
		bottom: 30rpx;
 | 
						|
		width: 10rpx;
 | 
						|
		height: 10rpx;
 | 
						|
		padding: 10rpx;
 | 
						|
		transform: translate3d(-30rpx, 0, 0);
 | 
						|
		cursor: pointer;
 | 
						|
	}
 | 
						|
 | 
						|
	.extend_handle:before {
 | 
						|
		content: '';
 | 
						|
		display: block;
 | 
						|
		width: 100%;
 | 
						|
		height: 100%;
 | 
						|
		box-sizing: border-box;
 | 
						|
		border: 4rpx solid;
 | 
						|
		border-color: #f2f2f2 #f2f2f2 transparent transparent;
 | 
						|
		transform: rotateZ(135deg);
 | 
						|
		transform-origin: 50% 50% 0;
 | 
						|
		transition: transform ease 300ms;
 | 
						|
	}
 | 
						|
 | 
						|
	.extend_handle:hover:before {
 | 
						|
		border-color: #f2f2f2 #f2f2f2 transparent transparent;
 | 
						|
	}
 | 
						|
 | 
						|
	.extend .extend_handle:before {
 | 
						|
		transform: rotateZ(-45deg);
 | 
						|
	}
 | 
						|
 | 
						|
	.extend::after {
 | 
						|
		content: '';
 | 
						|
		position: absolute;
 | 
						|
		left: 50%;
 | 
						|
		bottom: 84rpx;
 | 
						|
		height: 84rpx;
 | 
						|
		border-left: 4rpx solid #f2f2f2;
 | 
						|
		transform: translate3d(-2rpx, 0, 0);
 | 
						|
	}
 | 
						|
 | 
						|
	.childLevel::before {
 | 
						|
		content: '';
 | 
						|
		position: absolute;
 | 
						|
		left: 50%;
 | 
						|
		bottom: 100%;
 | 
						|
		height: 84rpx;
 | 
						|
		border-left: 4rpx solid #f2f2f2;
 | 
						|
		transform: translate3d(-2rpx, 0, 0);
 | 
						|
	}
 | 
						|
 | 
						|
	.childLevel::after {
 | 
						|
		content: '';
 | 
						|
		position: absolute;
 | 
						|
		left: 0;
 | 
						|
		right: 0;
 | 
						|
		top: -88rpx;
 | 
						|
		border-top: 4rpx solid #f2f2f2;
 | 
						|
	}
 | 
						|
 | 
						|
	.childLevel:first-child:before,
 | 
						|
	.childLevel:last-child:before {
 | 
						|
		display: none;
 | 
						|
	}
 | 
						|
 | 
						|
	.childLevel:first-child:after {
 | 
						|
		left: 50%;
 | 
						|
		height: 84rpx;
 | 
						|
		border: 4rpx solid;
 | 
						|
		border-color: #f2f2f2 transparent transparent #f2f2f2;
 | 
						|
		border-radius: 6rpx 0 0 0;
 | 
						|
		transform: translate3d(2rpx, 0, 0);
 | 
						|
	}
 | 
						|
 | 
						|
	.childLevel:last-child:after {
 | 
						|
		right: 50%;
 | 
						|
		height: 84rpx;
 | 
						|
		border: 4rpx solid;
 | 
						|
		border-color: #f2f2f2 #f2f2f2 transparent transparent;
 | 
						|
		border-radius: 0 6rpx 0 0;
 | 
						|
		transform: translate3d(-2rpx, 0, 0);
 | 
						|
	}
 | 
						|
 | 
						|
	.childLevel:first-child.childLevel:last-child::after {
 | 
						|
		left: auto;
 | 
						|
		border-radius: 0;
 | 
						|
		border-color: transparent #f2f2f2 transparent transparent;
 | 
						|
		transform: translate3d(2rpx, 0, 0);
 | 
						|
	}
 | 
						|
 | 
						|
	.node {
 | 
						|
		position: relative;
 | 
						|
		display: inline-block;
 | 
						|
		margin: 0 10rpx;
 | 
						|
		box-sizing: border-box;
 | 
						|
		text-align: center;
 | 
						|
	}
 | 
						|
 | 
						|
	.node .person {
 | 
						|
		position: relative;
 | 
						|
		display: inline-block;
 | 
						|
		z-index: 2;
 | 
						|
		width: 104rpx;
 | 
						|
		height: 104rpx;
 | 
						|
	}
 | 
						|
 | 
						|
	.node .person .person-ava {
 | 
						|
		width: 104rpx;
 | 
						|
		height: 104rpx;
 | 
						|
	}
 | 
						|
 | 
						|
	.node .person .avat {
 | 
						|
		display: block;
 | 
						|
		width: 4em;
 | 
						|
		height: 4em;
 | 
						|
		margin: auto;
 | 
						|
		overflow: hidden;
 | 
						|
		background: #fff;
 | 
						|
		border: 4px solid #f2f2f2;
 | 
						|
		box-sizing: border-box;
 | 
						|
		border-radius: 0.5em;
 | 
						|
	}
 | 
						|
 | 
						|
	.node .person .avat img {
 | 
						|
		width: 100%;
 | 
						|
		height: 100%;
 | 
						|
	}
 | 
						|
 | 
						|
	.node .person .name {
 | 
						|
		display: block;
 | 
						|
		margin: auto;
 | 
						|
		overflow: hidden;
 | 
						|
		box-sizing: border-box;
 | 
						|
		overflow: hidden;
 | 
						|
		font-size: 20rpx;
 | 
						|
		line-height: 1.5;
 | 
						|
		padding-top: 24rpx;
 | 
						|
	}
 | 
						|
 | 
						|
	.node .person .name-bottom {
 | 
						|
		display: block;
 | 
						|
		margin: auto;
 | 
						|
		overflow: hidden;
 | 
						|
		border-top: none;
 | 
						|
		box-sizing: border-box;
 | 
						|
		overflow: hidden;
 | 
						|
	}
 | 
						|
 | 
						|
	.node .person .operation {}
 | 
						|
 | 
						|
	.node.hasMate::after {
 | 
						|
		content: '';
 | 
						|
		position: absolute;
 | 
						|
		left: 2em;
 | 
						|
		right: 2em;
 | 
						|
		top: 2em;
 | 
						|
		border-top: 4px solid #f2f2f2;
 | 
						|
		z-index: 1;
 | 
						|
	}
 | 
						|
 | 
						|
	/* 横板 */
 | 
						|
	.landscape {
 | 
						|
		transform: translate(-100%, 0) rotate(-90deg);
 | 
						|
		transform-origin: 100% 0;
 | 
						|
	}
 | 
						|
 | 
						|
	.landscape .node {
 | 
						|
		text-align: left;
 | 
						|
		height: 8em;
 | 
						|
		width: 8em;
 | 
						|
	}
 | 
						|
 | 
						|
	.landscape .person {
 | 
						|
		position: relative;
 | 
						|
		transform: rotate(90deg);
 | 
						|
		padding-left: 4.5em;
 | 
						|
		height: 4em;
 | 
						|
		top: 4em;
 | 
						|
		left: -1em;
 | 
						|
	}
 | 
						|
 | 
						|
	.landscape .person .avat {
 | 
						|
		position: absolute;
 | 
						|
		left: 0;
 | 
						|
	}
 | 
						|
 | 
						|
	.landscape .person .name {
 | 
						|
		height: 4em;
 | 
						|
		line-height: 4em;
 | 
						|
	}
 | 
						|
 | 
						|
	.landscape .hasMate {
 | 
						|
		position: relative;
 | 
						|
	}
 | 
						|
 | 
						|
	.landscape .hasMate .person {
 | 
						|
		position: absolute;
 | 
						|
	}
 | 
						|
 | 
						|
	.landscape .hasMate .person:first-child {
 | 
						|
		left: auto;
 | 
						|
		right: -4em;
 | 
						|
	}
 | 
						|
 | 
						|
	.landscape .hasMate .person:last-child {
 | 
						|
		left: -4em;
 | 
						|
		margin-left: 0;
 | 
						|
	}
 | 
						|
</style> |