效果如图
鼠标滑动效果
关联性效果
<template ><div class="main" ref="predecessor"><div class="search"><div class="search-item"><div class="search-item-label">部门</div><Treeselect v-model="dept":options="deptOptions"show-countplaceholder="请选择部门"@change="changeDept()"/><!-- <el-cascader v-model="dept" clearable placeholder="请选择部门" ><el-option v-for="item in deptOptions" :key="item.id" :label="item.label" :value="item.id"></el-option></el-cascader> --></div><div class="search-item"><div class="search-item-label">周期</div><el-cascader v-model="TypeSelectValue" :options="cycleTypeSelect" :props="{checkStrictly: true,expandTrigger: 'hover'}" @change="handleChange" /></div></div><div class="main-predecessor"><div v-for="(item, index) in predecessorList" :key="'father' + index" class="father-predecessor"><div v-for="(itm, idx) in item" :key="itm.id"><div v-if="itm.status === 0 && itm.display === true" :id="itm.id" class="children-predecessor-big"@mouseenter="enter(index, idx)" @mouseleave="leave()":style="changeCardList.indexOf(itm.id) === -1 ? '' : 'background:rgba(206, 210, 232, 0.87)'"@click="clickDownsize(index, idx)"><div class="caption">{{ itm.okrUserOrDept }}</div><Vptip :content="itm.okrOContent" :width="'100%'" style="max-width: 500px;margin-bottom: 10px;"><span class="O-list" :style="changeOList.indexOf(itm.id) === -1 ? '' : 'color:#8198fe;font-weight: 700;'">O:{{`${itm.okrOContent}` }}</span></Vptip><div v-for="(im, indx) in itm.okrKrConfigList"><Vptip :content="im.okrKrContent" :width="'100%'" style="max-width: 500px;"><span class="kr-list":style="changeKrList.indexOf(im.id) === -1 ? '' : 'color:#8198fe;font-weight: 700;'">KR{{ indx + 1 }}: {{ `${im.okrKrContent}` }}</span></Vptip></div><div class="button"><el-button type="text" class="open" v-if="itm.isHeader && !itm.buttonDisplay" :disabled="timeout !== 0"@click.stop="commencementAll(index, itm.id, idx)" icon="el-icon-caret-bottom" /><el-button type="text" class="open" v-if="itm.isHeader && itm.buttonDisplay" :disabled="timeout !== 0"@click.stop="implicitAll(index, itm.id, idx)" icon="el-icon-caret-top" /></div></div><div v-if="itm.status === 1 && itm.display === true" :id="itm.id" class="children-predecessor-middle"@mouseenter="enter(index, idx)" @mouseleave="leave()":style="changeCardList.indexOf(itm.id) === -1 ? '' : 'background:rgba(206, 210, 232, 0.87)'"@click="clickDownsize(index, idx)"><div class="caption">{{ itm.okrUserOrDept }}</div><Vptip :content="itm.okrOContent" :width="'100%'" style="max-width: 500px;"><span class="O-list" :style="changeOList.indexOf(itm.id) === -1 ? '' : 'color:#8198fe;font-weight: 700;'">O:{{`${itm.okrOContent}` }}</span></Vptip><div class="button"><el-button type="text" class="open" v-if="itm.isHeader && !itm.buttonDisplay" :disabled="timeout !== 0"@click.stop="commencementAll(index, itm.id, idx)" icon="el-icon-caret-bottom" /><el-button type="text" class="open" v-if="itm.isHeader && itm.buttonDisplay" :disabled="timeout !== 0"@click.stop="implicitAll(index, itm.id, idx)" icon="el-icon-caret-top" /></div></div><div v-if="itm.status === 2 && itm.display === true" :id="itm.id" class="children-predecessor-small"@mouseenter="enter(index, idx)" @mouseleave="leave()":style="changeCardList.indexOf(itm.id) === -1 ? '' : 'background:rgba(206, 210, 232, 0.87)'"@click="clickDownsize(index, idx)"><div class="caption">{{ itm.okrUserOrDept }}</div><div class="button"><el-button type="text" class="open" v-if="itm.isHeader && !itm.buttonDisplay" :disabled="timeout !== 0"@click.stop="commencementAll(index, itm.id, idx)" icon="el-icon-caret-bottom" /><el-button type="text" class="open" v-if="itm.isHeader && itm.buttonDisplay" :disabled="timeout !== 0"@click.stop="implicitAll(index, itm.id, idx)" icon="el-icon-caret-top" /></div></div></div></div></div></div>
</template><script >
import { deptTreeSelect } from '@/api/system/user'
import okrConstant from '@/utils/okr/okrConstant'
import { getOkrPredecessor } from '@/api/okr/okrPredecessor'
import LeaderLine from 'leader-line'
import Vptip from "@/components/vptip" // 自定义Tooltip 文字提示
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
export default {name: 'okrPredecessor',components: {Vptip,Treeselect},data() {return {// 级联选择器下拉框selectOKrForm: {// 年份搜索值okrCycleYear: okrConstant.yearDecade()[0].value,// 季度搜索值okrCycleQuarter: okrConstant.currentMonthIsQuarter(),// 月份搜索值okrCycleMonth: '',},TypeSelectValue: okrConstant.currentMonthIsQuarter(),cycleTypeSelect: okrConstant.yearDecade(),// 部门列表deptOptions: [],// 部门数据dept: undefined,// 控制按钮的倒计时timeout: 0,// 线条的数组lineList: {},// 接口返回的循环数据predecessorListAll: [],// 继承的渲染数据predecessorList: [// [// {// id: 0,// // 展开还是缩小状态// status: 0,// // 能否展开或者缩小下一级// isHeader: true,// // 目前在显示还是隐藏// display: true,// // 当前按钮是展开还是隐藏// buttonDisplay: true,// // 父级相关的id合集// fatherUserId: []// }// ]],// 所有的线条allLineList: [],// 应该画出来的线drawLineList: [],// 隐藏的数组listdisplayList: [],// 变色的卡片IDchangeCardList: [],// 变色的KRIDchangeKrList: [],// 变色的OIDchangeOList: [],// 变色的线段changeDrawLineList: []}},watch:{dept(){this.search()}},// 注册监听mounted() {// 获取部门列表this.getDept()window.addEventListener('resize', this.getScroll)// 监听div滚动事件let scrollView = this.$refs.predecessorscrollView.addEventListener("scroll", this.positionLine);document.body.style.overflow = 'hidden'this.search()},// 销毁前beforeDestroy() {document.body.style.overflow = ''// 销毁线条this.removeLines()},// 销毁监听,防止内存泄露destroyed() {window.removeEventListener('resize', this.getScroll)},methods: {// 获取部门列表getDept() {deptTreeSelect().then(response => {this.deptOptions = response.data[0].children})},// 鼠标移出事件(将O和KR两个数组归0)leave() {// 变色的KRIDthis.changeKrList = []// 变色的OIDthis.changeOList = []// 变色的卡片IDthis.changeCardList = []// 线段颜色恢复this.resumption()// 特殊线段归0this.changeDrawLineList = []},// 鼠标移入事件enter(index, idx) {// 变色的KRIDthis.changeKrList = []// 变色的OIDthis.changeOList = []// 变色的卡片IDthis.changeCardList = []// 获取到第一层DIV之后首先对上下紧挨的关系层进行循环// 寻找相关的父级this.findFatherList(index, idx)// 寻找相关的子集this.findChildrenList(index, idx)// 先将他本身的数据push进去if (this.predecessorList[index][idx].okrKrConfigList) {for (let i = 0; i < this.predecessorList[index][idx].okrKrConfigList.length; i++) {this.changeKrList.push(this.predecessorList[index][idx].okrKrConfigList[i].id)}}this.changeOList.push(this.predecessorList[index][idx].id)this.changeCardList.push(this.predecessorList[index][idx].id)// 获取线段变化线段this.getChangeLine()// 更改相关线段this.changeLineColor()},// 获取相关需要更改线段getChangeLine() {this.changeDrawLineList = []// 判断开头结尾都在变色的卡片之中for (let j = 0; j < this.drawLineList.length; j++) {if (this.changeCardList.indexOf(Number(this.drawLineList[j].start)) !== -1 && this.changeCardList.indexOf(Number(this.drawLineList[j].end)) !== -1) {this.changeDrawLineList.push(this.drawLineList[j])}}},// 恢复相关线段颜色resumption() {for (let i = 0; i < this.changeDrawLineList.length; i++) {this.twiceGetLine(this.changeDrawLineList[i].start, this.changeDrawLineList[i].end, i)}},// 更改相关线段颜色changeLineColor() {for (let i = 0; i < this.changeDrawLineList.length; i++) {this.changeGetLine(this.changeDrawLineList[i].start, this.changeDrawLineList[i].end, i)}},// 寻找相关的子集findChildrenList(index, idx) {// 对所有的线段进行遍历(因为只有O能够继承,所以子集直接往下找,只要有就是要变色)for (let i = 0; i < this.drawLineList.length; i++) {// 寻找到以此为开头的数据if (this.drawLineList[i].start === String(this.predecessorList[index][idx].id)) {// 对页面数据进行遍历寻找出此ID的位置,为后续获取KR做准备for (let x = 0; x < this.predecessorList.length; x++) {if (this.predecessorList[x]) {for (let y = 0; y < this.predecessorList[x].length; y++) {// 寻找到线段结束点位的内容if (String(this.predecessorList[x][y].id) === this.drawLineList[i].end) {// 变色的OIDthis.changeOList.push(this.predecessorList[x][y].id)// 变色的卡片IDthis.changeCardList.push(this.predecessorList[x][y].id)// 对KRLIST进行遍历,渲染KRLISTfor (let z = 0; z < this.predecessorList[x][y].okrKrConfigList.length; z++) {// 将所有相关kr进行pushthis.changeKrList.push(this.predecessorList[x][y].okrKrConfigList[z].id)}// 删除递归根节点功能// this.findChildrenList(x, y)}}}}}}},// 寻找相关的父级findFatherList(index, idx) {let fatherList = this.predecessorList[index][idx].extendsKrs// 对FATHERlIST进行遍历for (let i = 0; i < fatherList.length; i++) {// 只要是存在的Oid卡片就跟随变色(需要两点之间还存在连线关系)for (let j = 0; j < this.drawLineList.length; j++) {if (this.drawLineList[j].start === String(fatherList[i].okrId) && this.drawLineList[j].end === String(this.predecessorList[index][idx].id)) {this.changeCardList.push(fatherList[i].okrId)// 如果继承的是KR(O不变色,但是KR需要变色)if (fatherList[i].krId !== null) {this.changeKrList.push(fatherList[i].krId)} else {// 如果继承的是O,那么OKR全部变色,并且继续寻找上一层的OKR// 将变色Opush进入O的数组this.changeOList.push(fatherList[i].okrId)// 将变色O所对应的KR全部push进入数组(遍历寻找对应O)for (let x = 0; x < this.predecessorList.length; x++) {if (this.predecessorList[x]) {for (let y = 0; y < this.predecessorList[x].length; y++) {// 找出对应的IDif (fatherList[i].okrId === this.predecessorList[x][y].id) {// 对ID中的OKR进行循环pushfor (let z = 0; z < this.predecessorList[x][y].okrKrConfigList.length; z++) {// 将所有相关kr进行pushthis.changeKrList.push(this.predecessorList[x][y].okrKrConfigList[z].id)}// 寻找完O之后,将后生成的O继续进行上层寻找循环// 删除递归根节点功能// this.findFatherList(x, y)}}}}}}}}},// 级联改变方法handleChange(value) {this.selectOKrForm.okrCycleYear = ''this.selectOKrForm.okrCycleQuarter = ''this.selectOKrForm.okrCycleMonth = ''value.forEach((element, index) => {switch (index) {case 0: this.selectOKrForm.okrCycleYear = element; breakcase 1: this.selectOKrForm.okrCycleQuarter = element; breakcase 2: this.selectOKrForm.okrCycleMonth = element; break}})this.search()},// 搜索search() {let params = {okrUserDept: this.dept,okrCycleYear: this.selectOKrForm.okrCycleYear,okrCycleQuarter: this.selectOKrForm.okrCycleQuarter,okrCycleMonth: this.selectOKrForm.okrCycleMonth}// 跑接口之前销毁所有线条this.removeLines()// 获取继承关系详细数据getOkrPredecessor(params).then(res => {// 所有的线条this.allLineList = []// 应该画出来的线this.drawLineList = []// 页面渲染数据this.predecessorList = []this.predecessorListAll = res.data// 递归逻辑for (let i = 0; i < this.predecessorListAll.length; i++) {for (let j = 0; j < this.predecessorListAll[i].inheritedToOkrId.length; j++) {let level = this.predecessorListAll[i].levellet fatherUserId = []// 获取fatherListfor (let x = 0; x < this.predecessorListAll[i].inheritedToOkrId[j].extendsKrs.length; x++) {if (fatherUserId.indexOf(this.predecessorListAll[i].inheritedToOkrId[j].extendsKrs[x].okrId) === -1) {fatherUserId.push(this.predecessorListAll[i].inheritedToOkrId[j].extendsKrs[x].okrId)}}// 如果此层级还不存在先重置层级if (!this.predecessorList[level]) {this.predecessorList[level] = []}this.predecessorList[level].push(this.predecessorListAll[i].inheritedToOkrId[j])this.predecessorList[level][this.predecessorList[level].length - 1].fatherUserId = fatherUserIdthis.predecessorList[level][this.predecessorList[level].length - 1].status = 2this.predecessorList[level][this.predecessorList[level].length - 1].isHeader = falsethis.predecessorList[level][this.predecessorList[level].length - 1].display = truethis.predecessorList[level][this.predecessorList[level].length - 1].buttonDisplay = true}}// 寻找父子关系的连线this.findLineList()// 更改header属性判断是否可以当标头this.whetherIsHeader()// 刷新数组变化导致的数据更改this.$forceUpdate()// 画线(页面加载有一个动画,需要等动画完毕再开始加载线条保证线条的稳定性)setTimeout(() => { this.drawLine() }, 500)})},// 判断是否可以当标头,是否含有展开收起属性whetherIsHeader() {// 对二维数组进行遍历for (let x = 0; x < this.predecessorList.length; x++) {// 判断此层级中是否有内容if (this.predecessorList[x]) {for (let y = 0; y < this.predecessorList[x].length; y++) {// 对当前所有连线进行遍历for (let i = 0; i < this.allLineList.length; i++) {// 如果存在以此ID为开头的线段,证明为header,isHeader属性为trueif (String(this.predecessorList[x][y].id) === this.allLineList[i].start) {this.predecessorList[x][y].isHeader = true}}}}}},// 寻找父子关系的连线findLineList() {// 对二维数组进行循环for (let i = 0; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {// 对父级进行循环if (this.predecessorList[i][j].fatherUserId) {for (let x = 0; x < this.predecessorList[i][j].fatherUserId.length; x++) {if (this.existent(this.predecessorList[i][j].fatherUserId[x], this.predecessorList[i][j].id)) {this.allLineList.push({start: String(this.predecessorList[i][j].fatherUserId[x]),end: String(this.predecessorList[i][j].id)})}}}}}}// 将数据同步到渲染的线段中,默认全部显示this.drawLineList = JSON.parse(JSON.stringify(this.allLineList))},// 验证是否存在该条数据existent(start, end) {// 对二维数组进行遍历for (let i = 0; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {if (this.predecessorList[i][j].id === start) {// 如果开始符合,看结束是否存在for (let x = 0; x < this.predecessorList.length; x++) {if (this.predecessorList[x]) {for (let y = 0; y < this.predecessorList[x].length; y++) {if (this.predecessorList[x][y].id === end) {return true}}}}}}}}return false},// 点击展开// 准备开始展开递归将所有关联的数据进行处理commencementAll(index, id, idx) {this.timeout = 1// 防抖setTimeout(() => {this.timeout = 0}, 500)// 更改按钮let changeIndexfor (let i = 0; i < this.predecessorList[index].length; i++) {if (this.predecessorList[index][i].id === id) {changeIndex = i}}// 更改按钮状态this.predecessorList[index][changeIndex].buttonDisplay = true// 目前已经确认隐藏的id标题// 把跟原标题有关的数据全都找出来再进行删除let oldIdList = this.displayList// 所有可以改回状态的IDlet deleteIdList = [id]// 新的ID集合let newIdList = []// 进行遍历寻找不需要删除的数组for (let i = index; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {if (this.arbitrarily(deleteIdList, this.predecessorList[i][j].fatherUserId)) {deleteIdList.push(this.predecessorList[i][j].id)}}}}// 生成新数组for (let i = 0; i < oldIdList.length; i++) {let haveId = truefor (let j = 0; j < deleteIdList.length; j++) {if (deleteIdList[j] === oldIdList[i]) {haveId = false}}if (haveId) {newIdList.push(oldIdList[i])}}// 当前禁止当头的数据 this.displayListthis.displayList = [...newIdList]// 更改页面this.commencement(index, id)// 更改页面显示this.enter(index, idx)},// 点击收起implicitAll(index, id, idx) {this.timeout = 1// 防抖setTimeout(() => {this.timeout = 0}, 1000)// 更改按钮let changeIndexfor (let i = 0; i < this.predecessorList[index].length; i++) {if (this.predecessorList[index][i].id === id) {changeIndex = i}}// 更改按钮状态this.predecessorList[index][changeIndex].buttonDisplay = false// 寻找子集this.findImplicit(index, id)// 更改页面this.implicit(index, id)// 更改页面显示this.enter(index, idx)},// 展开隐藏后续内容commencement(index, id) {// 操作线条// 销毁线条this.removeLines()// 线条数组清零let newDrawLineList = []// 对目前所有线条进行循环for (let i = 0; i < this.allLineList.length; i++) {let remain = falsefor (let j = 0; j < this.displayList.length; j++) {if (this.allLineList[i].start === String(this.displayList[j])) {remain = true}}if (remain === false) {newDrawLineList.push(this.allLineList[i])}}// 操作卡片// 寻找各个子集,并且观察子集是不是只有这一个fatherUserIdfor (let i = index; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {// 如果先前的隐藏那么展开后按钮状态为打开if (this.predecessorList[i][j].display === false) {this.predecessorList[i][j].buttonDisplay = true}// 只有从无到有的才进行回显this.predecessorList[i][j].display = trueif (this.including(this.displayList, this.predecessorList[i][j].fatherUserId)) {this.predecessorList[i][j].display = false}}}}// 验证画线数据结尾是否实际存在let trueLineList = []for (let i = 0; i < newDrawLineList.length; i++) {if (this.trueDiv(newDrawLineList[i].end)) {trueLineList.push(newDrawLineList[i])}}// 新的画线数据this.drawLineList = trueLineList// 重新画线setTimeout(() => { this.drawLine() }, 50)},// 隐藏后续内容implicit(index, id) {// 操作线条// 销毁线条this.removeLines()// 线条数组清零let newDrawLineList = []// 对目前所有线条进行循环for (let i = 0; i < this.allLineList.length; i++) {let remain = falsefor (let j = 0; j < this.displayList.length; j++) {if (this.allLineList[i].start === String(this.displayList[j])) {remain = true}}if (remain === false) {newDrawLineList.push(this.allLineList[i])}}// 操作卡片// 寻找各个子集,并且观察子集是不是只有这一个fatherUserIdfor (let i = index; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {if (this.including(this.displayList, this.predecessorList[i][j].fatherUserId)) {this.predecessorList[i][j].display = false}}}}// 验证画线数据结尾是否实际存在let trueLineList = []for (let i = 0; i < newDrawLineList.length; i++) {if (this.trueDiv(newDrawLineList[i].end)) {trueLineList.push(newDrawLineList[i])}}// 新的画线数据this.drawLineList = trueLineList// 重新画线setTimeout(() => { this.drawLine() }, 50)},// div节点是否是实际存在的trueDiv(id) {for (let i = 0; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {if (String(this.predecessorList[i][j].id) === id && this.predecessorList[i][j].display === true) {return true}}}}return false},// 寻找子集findImplicit(index, id) {// 目前已经确认隐藏的id标题this.displayList.push(id)// 进行遍历寻找for (let i = index; i < this.predecessorList.length; i++) {if (this.predecessorList[i]) {for (let j = 0; j < this.predecessorList[i].length; j++) {if (this.including(this.displayList, this.predecessorList[i][j].fatherUserId)) {this.displayList.push(this.predecessorList[i][j].id)}}}}let newArr = [];for (let i = 0; i < this.displayList.length; i++) {if (!newArr.includes(this.displayList[i])) {newArr.push(this.displayList[i])}}// 隐藏的数组数据: this.displayListthis.displayList = [...newArr]},// 判断子数组中是否存在任意包含关系,不需要全等,只要有一个就行arbitrarily(list, fatherUserId) {let x = 0for (let i = 0; i < list.length; i++) {for (let j = 0; j < fatherUserId.length; j++) {if (list[i] === fatherUserId[j]) {x++}}}if (x !== 0) {return true}return false},// 判断子数组中是否存在包含关系including(list, fatherUserId) {let x = 0for (let i = 0; i < list.length; i++) {for (let j = 0; j < fatherUserId.length; j++) {if (list[i] === fatherUserId[j]) {x++}}}if (x === fatherUserId.length && fatherUserId.length !== 0) {return true}return false},// 重新定位各线positionLine() {for (let i = 0; i < this.drawLineList.length; i++) {let nameLine = this.drawLineList[i].start + '' + this.drawLineList[i].end// 判断线段是否真实存在if (this.lineList[nameLine] !== undefined) {this.lineList[nameLine].position()}}},// 开始画线drawLine() {for (let i = 0; i < this.drawLineList.length; i++) {this.getLine(this.drawLineList[i].start, this.drawLineList[i].end, i)}},// 点击展开缩小重新定位线条hideLines() {for (let i = 0; i < this.drawLineList.length; i++) {let nameLine = this.drawLineList[i].start + '' + this.drawLineList[i].endthis.lineList[nameLine].position()}},// 隐藏线条hideLine(start, end) {let nameLine = start + endthis.lineList[nameLine].hide()},// 销毁线条removeLines() {for (let i = 0; i < this.drawLineList.length; i++) {let nameLine = this.drawLineList[i].start + '' + this.drawLineList[i].endthis.lineList[nameLine].remove()}},// 点击展开clickDownsize(index, idx) {// 卡片三种状态互相切换if (this.predecessorList[index][idx].status === 0) {this.predecessorList[index][idx].status = 1} else if (this.predecessorList[index][idx].status === 1) {this.predecessorList[index][idx].status = 2} else {this.predecessorList[index][idx].status = 0}let predecessor = JSON.parse(JSON.stringify(this.predecessorList))this.predecessorList = []this.predecessorList = JSON.parse(JSON.stringify(predecessor))setTimeout(() => { this.positionLine() }, 50)},// 画线changeGetLine(start, end, i) {let lineStart = document.getElementById(start)let lineEnd = document.getElementById(end)let styleOption = {color: 'red', // 指引线颜色endPlug: '', // 指引线结束点的样式 hand,discsize: 2, // 线条尺寸startSocket: 'bottom', //在指引线开始的地方从元素左侧开始endSocket: 'top', //在指引线开始的地方从元素右侧结束// hide: true, // 绘制时隐藏,默认为false,在初始化时可能会出现闪烁的线条// startPlugColor: '#ff3792', // 渐变色开始色// endPlugColor: '#fff386', // 渐变色结束色gradient: false, // 使用渐变色outLineColor: 'blue',path: 'fluid', // straight,arc,fluid,magnet,grid// dash: {// // 虚线样式// animation: true // 让线条滚动起来// },hide: true,}let nameLine = start + endthis.lineList[nameLine].setOptions(styleOption)/** 显示效果* draw 绘制线条* fade 淡入* none 无效果,即直接显示*/// let showEffectName = 'draw'// // 动画参数// let animOptions = {// // duration: 1000, //持续时长// // timing: 'ease-in' // 动画函数// }// this.lineList[nameLine].show()// this.lineList[nameLine].position()},// 恢复线段twiceGetLine(start, end, i) {let lineStart = document.getElementById(start)let lineEnd = document.getElementById(end)let styleOption = {color: '#6a6a6a', // 指引线颜色endPlug: '', // 指引线结束点的样式 hand,discsize: 2, // 线条尺寸startSocket: 'bottom', //在指引线开始的地方从元素左侧开始endSocket: 'top', //在指引线开始的地方从元素右侧结束// hide: true, // 绘制时隐藏,默认为false,在初始化时可能会出现闪烁的线条// startPlugColor: '#ff3792', // 渐变色开始色// endPlugColor: '#fff386', // 渐变色结束色gradient: false, // 使用渐变色outLineColor: '#6a6a6a',path: 'fluid', // straight,arc,fluid,magnet,grid// dash: {// // 虚线样式// animation: true // 让线条滚动起来// },hide: true,}let nameLine = start + endthis.lineList[nameLine].setOptions(styleOption)},// 画线getLine(start, end, i) {let lineStart = document.getElementById(start)let lineEnd = document.getElementById(end)let styleOption = {color: '#6a6a6a', // 指引线颜色endPlug: '', // 指引线结束点的样式 hand,discsize: 2, // 线条尺寸startSocket: 'bottom', //在指引线开始的地方从元素左侧开始endSocket: 'top', //在指引线开始的地方从元素右侧结束// hide: true, // 绘制时隐藏,默认为false,在初始化时可能会出现闪烁的线条// startPlugColor: '#ff3792', // 渐变色开始色// endPlugColor: '#fff386', // 渐变色结束色gradient: false, // 使用渐变色outLineColor: '#6a6a6a',path: 'fluid', // straight,arc,fluid,magnet,grid// dash: {// // 虚线样式// animation: true // 让线条滚动起来// },hide: true,}let nameLine = start + endthis.$set(this.lineList, `${nameLine}`, null)this.lineList[nameLine] = new LeaderLine(lineStart, lineEnd, styleOption)/** 显示效果* draw 绘制线条* fade 淡入* none 无效果,即直接显示*/// let showEffectName = 'draw'// // 动画参数// let animOptions = {// // duration: 1000, //持续时长// // timing: 'ease-in' // 动画函数// }this.lineList[nameLine].show()this.lineList[nameLine].position()},}
}
</script>
<style>
.leader-line {z-index: -1
}
</style>
<style lang="scss" scoped >
.search-item-label {width: 30%;font-size: 14px;color: #333;font-weight: 600;
}.search-item {width: 40%;display: flex;align-items: center;margin-right: 5%;
}
.vue-treeselect{width: 80%;
}
.search {margin-left: 20px;margin-top: 20px;width: 500px;display: flex;justify-content: space-between;.el-button+.el-button {margin-left: 0px;}
}.main {height: calc(100vh - 84px);overflow-x: scroll;overflow-y: scroll;
}.main-predecessor {min-width: 1100px;width: fit-content;min-height: calc(100vh - 94px);}.father-predecessor {display: flex;justify-content: space-around;align-items: flex-start;
}.children-predecessor-big {width: 250px;height: 200px;border: 1px solid #f8f8f8;margin: 60px 10px;border-radius: 6px;box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;background-color: rgba(255, 255, 255, 0.95);position: relative;}.children-predecessor-middle {width: 200px;height: 80px;border: 1px solid #f8f8f8;margin: 60px 10px;border-radius: 6px;box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;background-color: rgba(255, 255, 255, 0.95);position: relative;
}.children-predecessor-small {width: 130px;height: 50px;border: 1px solid #f8f8f8;margin: 60px 10px;border-radius: 6px;box-shadow: rgba(136, 165, 191, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;background-color: rgba(255, 255, 255, 0.95);position: relative;
}.button {position: absolute;text-align: center;bottom: -10px;left: 0;width: 100%;height: 20px;}.caption {text-align: center;line-height: 30px;
}.icon {cursor: pointer;float: right;font-size: 20px;line-height: 30px;color: #158BBB;margin-right: 10px;
}::v-deep .open {padding: 0 !important;border: 1px solid #b4b4b4;box-shadow: rgba(135, 138, 141, 0.48) 6px 2px 16px 0px, rgba(255, 255, 255, 0.8) -6px -2px 16px 0px;background-color: rgba(255, 255, 255, 0.95);border-radius: 50%;
}.O-list {margin-left: 10px;font-size: 18px;
}.kr-list {margin-left: 10px;font-size: 16px;
}::v-deep .small-select {.el-input__inner {width: 120px;}
}
</style>