vue手写多对多关联图,连线用leader-line

效果如图

 鼠标滑动效果

关联性效果

 

 

<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>

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/32456.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

10种常见网站安全攻击手段及防御方法

随着互联网技术的发展&#xff0c;网站所遭受的网络攻击频率也在不断上升。某种程度上&#xff0c;我们可以说互联网上的每个网站都容易遭受安全攻击。因为网络攻击者最主要的动机是求财。无论你运营的是电子商务项目还是简单的小型商业网站&#xff0c;潜在攻击的风险就在那里…

数据结构顺序表

今天主要讲解顺序表&#xff0c;实现顺序表的尾插&#xff0c;头插&#xff0c;头删&#xff0c;还有尾删等操作&#xff0c;和我们之前写的通讯录的增删查改有类似的功能。接下来让我们开始我们的学习吧。 1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特…

04-1_Qt 5.9 C++开发指南_常用界面设计组件_字符串QString

本章主要介绍Qt中的常用界面设计组件&#xff0c;因为更多的是涉及如何使用&#xff0c;因此会强调使用&#xff0c;也就是更多针对实例&#xff0c;而对于一些细节问题&#xff0c;需要参考《Qt5.9 c开发指南》进行学习。 文章目录 1. 字符串与普通转换、进制转换1.1 可视化U…

【Tomcat】Tomcat部署及优化

Tomcat 它是一个免费、开源的web应用服务器&#xff1b;基于java代码开发的软件&#xff1b;处理动态请求和基于Java代码的页面开发&#xff1b; 可以在html当中写入Java代码&#xff0c;Tomcat可以解析html页面当中的Java代码&#xff0c;执行动态请求以及动态页面 缺点&#…

springboot文件上传和下载接口的简单思路

springboot文件上传和下载的简单思路 文件上传文件下载 文件上传 在springboot中&#xff0c;上传文件只需要在接口中通过 MultipartFile 对象来获取前端传递的数据&#xff0c;然后将数据存储&#xff0c;并且返回一个对外访问路径即可。一般对于上传文件的文件名&#xff0c…

多用户微商城多端智慧生态电商系统搭建

多用户微商城多端智慧生态电商系统的搭建步骤如下&#xff1a; 系统规划&#xff1a;在搭建多用户微商城多端智慧生态电商系统之前&#xff0c;需要进行系统规划。包括确定系统的目标、功能、架构、技术选型、开发流程等方面。市场调研&#xff1a;进行市场调研&#xff0c;了…

unity 修改默认脚本

using System.Collections; using System.Collections.Generic; using UnityEngine; //***************************************** //创建人&#xff1a; xxxx //功能说明&#xff1a; //***************************************** #ROOTNAMESPACEBEGIN# public class #SCRI…

C# PDF加盖电子章

winform界面 1.选择加签pdf按钮代码实现 private void button1_Click(object sender, EventArgs e){OpenFileDialog op new OpenFileDialog();op.Filter "PDF文件(*.pdf)|*.pdf";bool flag op.ShowDialog() DialogResult.OK;if (flag){string pdfPath Path.Get…

栈和队列详解(2)

目录 一、什么是队列&#xff1f; 二、创建一个我们自己的队列 1.前置准备 1.1需要的三个文件 1.2结构体的创建和头文件的引用 2.接口的实现 2.1初始化队列 2.2入队 2.3队列元素个数和判空 2.4取队头元素和队尾元素 2.5出队 2.6摧毁队列 2.7测试接口 三、所有代码 1.…

系列七、RocketMQ如何保证顺序消费消息

一、概述 所谓顺序消费指的是可以按照消息的发送顺序来进行消费。例如一笔订单产生了3条消息&#xff0c;即下订单》减库存》增加订单&#xff0c;消费时要按照顺序消费才有意义&#xff0c;要不然就乱套了&#xff08;PS&#xff1a;你总不能订单还没下&#xff0c;就开始减库…

既然jmeter也能做接口自动化,为什么还需要pytest自己搭框架?

今天这篇文章呢&#xff0c;我会从以下几个方面来介绍&#xff1a; 1、首先介绍一下pytest框架 2、带大家安装Pytest框架 3、使用pytest框架时需要注意的点 4、pytest的运行方式 5、pytest框架中常用的插件 一、pytest框架介绍 pytest 是 python 的第三方单元测试框架&a…

springBoot整合RabbitMq实现手动确认消息

如何保证消息的可靠性投递&#xff1f; 1.保证生产者向broke可靠性投递&#xff0c;开启ack投递成功确认&#xff0c;如果失败的话进行消息补偿 /*** author yueF_L* date 2023-08-10 01:32* ConfirmCallback&#xff1a;消息只要被 RabbitMQ broker 接收到就会触发confirm方…

整理mongodb文档:collation

文章连接 整理mongodb文档:collation 看前提示 对于mongodb的collation。个人主要用的范围是在createcollection&#xff0c;以及find的时候用&#xff0c;所以本片介绍的时候也是这两个地方入手&#xff0c;对新手个人觉得理解概念就好。不要求强制性掌握&#xff0c;但是要…

07 Ubuntu中使用poetry工具管理python环境——巨详细!!!

由于conda和ros2的环境实在太容易冲突了。我真的不敢再使用conda&#xff0c;着实是有些搞不明白这解释器之间的关系。 conda的卸载和ros2的安装暂不赘述&#xff0c;下面着重来说如何在Ubuntu中使用poetry进行包管理及遇到的问题。 1 安装poetry 由于在有写入权限的限制&am…

01:STM32点灯大师和蜂鸣器

目录 一:点亮1个LED 1:连接图 2:函数介绍 3:点灯代码 二:LED闪烁 1:函数介绍 2:闪烁代码 三:LED流水灯 1:连接图 2:函数介绍 3:流水灯代码 四:蜂鸣器 1:连接图 2:蜂鸣器代码 一:点亮1个LED 1:连接图 因为IO口与LED负极相连所以IO口输出低电频,点亮LED (采用的是低…

【LeetCode】122. 买卖股票的最佳时机 II - 贪婪算法

目录 2023-8-10 10:29:32 122. 买卖股票的最佳时机 II 2023-8-10 10:29:32 没错&#xff0c;还是用双指针思想来套出来的。 感觉步骤很复杂&#xff0c;还调试了半天。 class Solution {public int maxProfit(int[] prices) {int pre 0;int last 1;int maxProfit 0;int c…

vCenter Server Appliance(VCSA )7.0 部署指南

vCenter Server Appliance&#xff08;VCSA &#xff09;7.0 部署指南 vmware 服务器 网络 vCenter Server Appliance&#xff08;VCSA &#xff09;7.0 部署指南 部署准备 1、下载VMware-VCSA-all-7.0.0-xxxx.iso文件&#xff0c;用虚拟光驱挂载或者解压运行&#xff0c;本…

Ansible的安装和配置

安装和配置 Ansible 安装所需的软件包 创建名为 /home/greg/ansible/inventory 的静态清单文件&#xff0c;以满足以下要求&#xff1a; 172.25.250.9 是 dev 主机组的成员 172.25.250.10 是 test 主机组的成员 172.25.250.11 和 172.25.250.12 是 prod 主机组的成员 172.2…

Linux系统编程之信号(上)

一、信号概念 信号就是软件中断。每当程序收到一个信号&#xff0c;都需要按指定的方法去处理。以下是UNIX系统的信号表。 其中core表示产生一个复制了该进程内存映像的core文件&#xff0c;它保存了程序现场&#xff0c;可以使用gdb来调试。 二、signal() signal()函数用于改…

nginx负载均衡的几种配置方式介绍

一.负载均衡含义简介 二.nginx负载均衡配置方式 准备三台设备&#xff1a; 2.190均衡服务器&#xff0c;2.191web服务器1&#xff0c;2.160web服务器2&#xff0c;三台设备均安装nginx&#xff0c;两台web服务器均有网页内容 1.一般轮询负载均衡 &#xff08;1&#xff09…