<template>
<div style="display: flex">
<!-- 左树 -->
<div class="left-card" >
<a-col :span="25">
<a-tree
:treeData="treeData"
@select="handleSelect"
>
<template slot="custom" slot-scope="item">
<span
>{{ item.name }}
<span>({{ item.userCount }})</span>
</span>
</template>
</a-tree>
</a-col>
</div>
<!-- 右表 -->
<div class="right-card" style="width: 100%" >
<a-table
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
:columns="columns"
:data-source="data"
size="default"
ref="table"
rowKey="userId"
@change="onChange"
>
<template slot="operation" slot-scope="record">
<a-tooltip title="详情" >
<a-icon type="eye" style="color: #0080ff;margin:0 4px" @click="onDetail(record)" />
</a-tooltip>
<a-tooltip title="编辑" >
<a-icon style="color: #0080ff;margin:0 4px" type="form" @click="onEdit(record)" />
</a-tooltip>
<!-- 运行 -->
<a-tooltip title="运行">
<a-icon type="play-circle" style="color: #0080ff;margin:0 4px" @click="onRun(record)"/>
</a-tooltip>
<a-tooltip title="删除" >
<a-popconfirm
title="Are you sure delete this case?"
ok-text="Yes"
cancel-text="No"
@confirm="confirm"
@cancel="cancel"
>
<a-icon style="color: #0080ff;margin:0 4px" type="delete" @click="onDelete(record)"/>
</a-popconfirm>
</a-tooltip>
</template>
</a-table>
</div>
</div>
</template>
<script>
import {get_case_list} from "@/services/build_history";
const treeData = [
{
title: 'parent 0',
key: '0-0',
children: [
{
title: 'leaf 0-0',
key: '0-0-0',
isLeaf: true,
},
{
title: 'leaf 0-1',
key: '0-0-1',
isLeaf: true,
},
],
},
{
title: 'parent 1',
key: '0-1',
children: [
{
title: 'leaf 1-0',
key: '0-1-0',
isLeaf: true,
},
{
title: 'leaf 1-1',
key: '0-1-1',
isLeaf: true,
},
],
},
];
const columns = [
{
title : '用例名称',
dataIndex: 'case_name',
resizable: true, //设置 resizable 开启拖动列
width: 20,
},
{
title : '优先级',
dataIndex: 'priority',
resizable: true,
width: 20,
},
{
title: '用例状态',
dataIndex: 'status',
resizable: true,
width: 20,
},
{
title: '创建人',
dataIndex: 'creator',
resizable: true,
width: 20,
},
{
title: '更新时间',
dataIndex: 'update_time',
resizable: true,
width: 50,
//通过指定列的 sorter 函数即可启动排序按钮。sorter: function(rowA, rowB) { ... }, rowA、rowB 为比较的两个行数据
sorter: (a, b) => Date.parse(a.update_time) - Date.parse(b.update_time),
defaultSortOrder: 'descend',
sortDirections: ['ascend', 'descend'], //sortDirections: ['ascend' | 'descend']改变每列可用的排序方式
},
{
title: '操作',
dataIndex: 'operation',
resizable: true,
scopedSlots: { customRender: 'operation' }, //值跟dataIndex对应,支持操作列插槽
width: 100,
},
];
export default {
data () {
return {
treeData,
data:[],
columns,
selectedRowKeys:[],
case_list:"http://localhost:7777/auth/case_list",
}
},
methods: {
handleSelect(selectedKeys, info) {
//把列表接口里的参数改为从树选中事件的参数打印后拿到的值,然后刷新列表
console.log(selectedKeys, info, 'tree 选择')
this.queryParam = selectedKeys[0],
console.log(this.$refs.table,'refresh')
this.reload() //刷新table
// this.$refs.table.refresh(true)
},
onSelectChange(selectedRowKeys){
this.selectedRowKeys = selectedRowKeys;
if (this.selectedRowKeys.length > 0) {
this.hasSelected = true
}
},
onChange(pagination, filters, sorter) {
console.log('params', pagination, filters, sorter);
},
reload () {
const case_dir_name = this.queryParam;
console.log(case_dir_name);
get_case_list(this.case_list, { case_dir_name })
.then((result) => {
this.loading = false;
this.data = result.data.data; //跟后端接口response对齐
})
.catch((err) => {
this.data = err;
});
},
confirm() {},
cancel() {},
},
}
</script>
其中reload()用于刷新,handleSelect()用于传递选中目录的case_dir
<template>
<div>
<a-card class="container">
<div class="tree-container">
<div class="left">
<div class="left-input">
<a-input-search v-model="searchValue" style="margin-bottom: 8px" placeholder="Search" />
<a-button @click="newlyAdded" style="margin-bottom: 4px" class="add">新增</a-button>
</div>
<!-- 树形组织架构树 -->
<a-tree
class="draggable-tree"
draggable
block-node
:defaultExpandAll="false"
:expanded-keys="expandedKeys"
:auto-expand-parent="autoExpandParent"
:tree-data="treeData"
@dragenter="onDragEnter"
@drop="onDrop"
@expand="onExpand"
@select="handleSelect"
>
<template #title="{ title }">
<span v-if="title.indexOf(searchValue) > -1">
{{ title.substr(0, title.indexOf(searchValue)) }}
<span style="color: #f50">{{ searchValue }}</span>
{{ title.substr(title.indexOf(searchValue) + searchValue.length) }}
</span>
<span v-else>{{ title }}</span>
</template>
<template slot="custom" slot-scope="item">
<div>
<!-- 名称 -->
<span class="node-title">{{ item.title }} </span>
<span style="margin-left: 20px">
<!-- 新增 -->
<span style="margin-right: 10px;">
<a-icon type="plus-circle" style="color: #0080ff;margin:0 4px" @click="subordinateItem(item)"/>
</span>
<!-- 编辑 -->
<span style="margin-right: 10px;">
<a-icon type="edit" style="color: #0080ff;margin:0 4px" @click="modifyItem(item)"/>
</span>
<!-- 删除 -->
<span style="margin-right: 10px;">
<a-popconfirm title="是否要删除此行?" @confirm="deleteItem(item)">
<a-icon type="delete" style="color: #0080ff;margin:0 4px" />
</a-popconfirm>
</span>
</span>
</div>
</template>
</a-tree>
</div>
<!-- 分割线 -->
<a-divider type="vertical" style="height: 600px; border-color: #7cb305" />
<div class="right">
<a-form
:model="formState"
name="horizontal_login"
layout="inline"
autocomplete="off"
@finish="onFinish"
@finishFailed="onFinishFailed"
>
<a-form-item
label="用例名称"
name="case_name"
:rules="[{ required: true, message: 'Please input your case_name!' }]"
>
<a-input v-model="formState.casename" />
</a-form-item>
<a-form-item
label="创建人"
name="creator"
:rules="[{ required: true, message: 'Please input your creator!' }]"
>
<a-select v-model="UserType" style="width:150px" allowClear>
<a-select-option :value="item.id" v-for="(item, i) in UserArr" :key="i">
{{ item.name }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item>
<a-button type="primary" html-type="submit" @click="onSelectData" >查询</a-button>
<a-button :style="{ marginLeft: '8px' }" @click="reset">重置</a-button>
</a-form-item>
</a-form>
<div>
<a-button type="primary" @click="showModal">+用例</a-button>
<a-tooltip title="勾选case后才可新建Task" >
<a-button type="primary" :disabled="!hasSelected" :loading="loading" @click="showModal">+Task</a-button>
</a-tooltip>
<a-popconfirm
title="确定要批量删除case吗?"
ok-text="删除"
cancel-text="取消"
@confirm="confirm"
@cancel="cancel"
>
<a-button type="primary" :disabled="!hasSelected" :loading="loading" @click="start">批量删除</a-button>
</a-popconfirm>
<a-button type="primary" :disabled="!hasSelected" :loading="loading" @click="start">批量移动用例</a-button>
<span >
<template v-if="hasSelected">
{{ `Selected ${selectedRowKeys.length} items` }}
</template>
</span>
<a-upload
v-model="fileList"
name="file"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
@change="handleChange"
>
<a-button style="margin-bottom: 8px" >Xmind导入</a-button>
<a-button style="margin-bottom: 8px" >Cooper导出</a-button>
</a-upload>
<a-modal v-model="visible" width="500px" title="添加用例" @ok="handleOk">
<a-form-item label="目录名称" v-bind="project_name">
<a-input v-model="project_name" />
</a-form-item>
</a-modal>
</div>
<!-- 表格开始 -->
<a-table
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
:columns="columns"
:data-source="data"
:rowKey='record=>record.id'
@change="onChange" >
<template slot="operation" slot-scope="record">
<a-drawer :title="myTitle" :visible="isEnable" :mask=false @close="onClose" width="520" :bodyStyle="{ marginBottom: '30px' }">
<a-form :model="contents" :rules="rules" layout="vertical">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="case名称" name="case_name">
<a-input v-model="contents.case_name" style="width: 100%" :disabled="disabled" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="优先级" name="priority">
<a-input v-model="contents.priority" style="width: 100%" :disabled="disabled" />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="状态" name="status">
<a-input v-model="contents.status" style="width: 100%" :disabled="disabled" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="创建人" name="creator">
<a-input v-model="contents.creator" style="width: 100%" :disabled="disabled" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="更新时间" name="update_time">
<a-input v-model="contents.update_time" style="width: 100%" :disabled="disabled" />
</a-form-item>
</a-col>
</a-row>
</a-form>
<template #extra>
<a-button style="margin-right: 8px" @click="onClose">Cancel</a-button>
<a-button type="primary" @click="onClose">Submit</a-button>
</template>
</a-drawer>
<a-tooltip title="详情" >
<a-icon type="eye" style="color: #0080ff;margin:0 4px" @click="onDetail(record)" />
</a-tooltip>
<a-tooltip title="编辑" >
<a-icon style="color: #0080ff;margin:0 4px" type="form" @click="onEdit(record)" />
</a-tooltip>
<!-- 运行 -->
<a-tooltip title="运行">
<a-icon type="play-circle" style="color: #0080ff;margin:0 4px" @click="onRun(record)"/>
<a-modal v-model="isshow" title="执行case:" @ok="handleOk">
<a-form
:model="env"
name="basic"
autocomplete="off"
@finish="onFinish"
@finishFailed="onFinishFailed"
>
<a-form-item
label="执行环境"
name="env"
:rules="[{ required: true, message: 'Please input env!' }]"
>
<a-input v-model="env" />
</a-form-item>
</a-form>
</a-modal>
</a-tooltip>
<a-tooltip title="删除" >
<a-popconfirm
title="确定要删除此case吗?"
ok-text="删除"
cancel-text="取消"
@confirm="confirm"
@cancel="cancel"
>
<a-icon style="color: #0080ff;margin:0 4px" type="delete" @click="onDelete(record)"/>
</a-popconfirm>
</a-tooltip>
</template>
</a-table>
<!-- 表格结束 -->
</div>
</div>
</a-card>
<!-- 弹窗开始 -->
<tree-lower-modules ref="treeLowerModules" @ok="onOk"/>
</div>
</template>
<script>
import {get_case_list, get_case_detail} from "@/services/build_history";
import {message} from "ant-design-vue";
import {getDirList, getUserList} from "@/services/postman";
import treeLowerModules from '../../components/treeModules'
const x = 3;
const y = 2;
const z = 1;
const genData = [];
const generateData = (_level, _preKey, _tns) => {
const preKey = _preKey || '0';
const tns = _tns || genData;
const children = [];
for (let i = 0; i < x; i++) {
const key = `${preKey}-${i}`;
tns.push({ title: key, key });
if (i < y) {
children.push(key);
}
}
if (_level < 0) {
return tns;
}
const level = _level - 1;
children.forEach((key, index) => {
tns[index].children = [];
return generateData(level, key, tns[index].children);
});
};
generateData(z);
const dataList = [];
const generateList = (data) => {
for (let i = 0; i < data.length; i++) {
const node = data[i];
const key = node.key;
dataList.push({ key, title: key });
if (node.children) {
generateList(node.children);
}
}
};
generateList(genData);
const getParentKey = (key,tree ) => {
let parentKey;
for (let i = 0; i < tree.length; i++) {
const node = tree[i];
if (node.children) {
if (node.children.some(item => item.key === key)) {
parentKey = node.key;
} else if (getParentKey(key, node.children)) {
parentKey = getParentKey(key, node.children);
}
}
}
return parentKey;
};
const columns = [
{
title : '用例名称',
dataIndex: 'case_name',
resizable: true, //设置 resizable 开启拖动列
width: 20,
},
{
title : '优先级',
dataIndex: 'priority',
resizable: true,
width: 20,
},
{
title: '用例状态',
dataIndex: 'status',
resizable: true,
width: 20,
},
{
title: '创建人',
dataIndex: 'creator',
resizable: true,
width: 20,
},
{
title: '更新时间',
dataIndex: 'update_time',
resizable: true,
width: 50,
//通过指定列的 sorter 函数即可启动排序按钮。sorter: function(rowA, rowB) { ... }, rowA、rowB 为比较的两个行数据
sorter: (a, b) => Date.parse(a.update_time) - Date.parse(b.update_time),
defaultSortOrder: 'descend',
sortDirections: ['ascend', 'descend'], //sortDirections: ['ascend' | 'descend']改变每列可用的排序方式
},
{
title: '操作',
dataIndex: 'operation',
resizable: true,
scopedSlots: { customRender: 'operation' }, //值跟dataIndex对应,支持操作列插槽
width: 100,
},
];
const rules = {
case_name: [{ required: true, message: 'Please enter case_name' }],
priority: [{ required: true, message: 'please enter priority' }],
status: [{ required: true, message: 'Please choose the status' }],
creator: [{ required: true, message: 'Please choose the creator', type: 'object' }],
update_time: [{ required: true, message: 'Please enter update_time' }],
};
export default {
name: 'OrganizateTree',
components: { treeLowerModules },
data () {
return {
case_list:"http://localhost:7777/auth/case_list",
case_detail:"http://localhost:7777/auth/case_detail",
// 组织树数据
treeData: [],
selectKeys: [],
// 表格数据
data:[],
// 表格行
columns: columns,
//form
formState: {
creator: '',
case_name: '',
},
UserArr:[],
UserType:'',
fileList:[],
form: this.$form.createForm(this, {name: 'case'}),
//table
hasSelected:false,
loading: false,
visible: false,
selectedRowKeys:[],
project_name:"",
searchValue:"",
expandedKeys:[],
autoExpandParent:true,
myTitle:'',
isEnable:false,
rules:rules,
contents:"",
disabled:false,
isshow:false,
env:'dev',
}
},
methods: {
onSelectData() {
this.loading = true;
const case_name = this.formState.case_name
const creator = this.UserType
console.log(case_name,creator);
get_case_list(this.case_list, {case_name, creator})
.then((result) => {
this.loading = false;
this.data = result.data.data; //跟后端接口response对齐
})
.catch((err) => {
this.data = err;
});
},
reset() {
this.UserType = '' //清空casename
this.formState = [] //清空创建人
this.data = [] //清空搜索结果
this.hasSelected = false //清空选择条数
},
showModal(){ //点击添加用例后展示弹窗
this.visible = true;
},
handleOk(e){
console.log(e);
this.visible = false;
},
onSelectChange(selectedRowKeys){
this.selectedRowKeys = selectedRowKeys;
if (this.selectedRowKeys.length > 0) {
this.hasSelected = true
}
},
onChange(pagination, filters, sorter) {
console.log('params', pagination, filters, sorter);
},
start(){
this.loading = true;
// ajax request after empty completing
setTimeout(() => {
this.loading = false;
this.selectedRowKeys = [];
}, 1000);
},
handleChange(info) {
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (info.file.status === 'done') {
message.success(`${info.file.name} file uploaded successfully`);
} else if (info.file.status === 'error') {
message.error(`${info.file.name} file upload failed.`);
}
},
onFinish(val) {
console.log('endValue', val);
},
onFinishFailed(val) {
console.log('endValue', val);
},
confirm() {},
cancel() {},
// 递归每一项都加 scopedSlots: { title: 'custom' }
handleData (tree) {
for (const item of tree) {
item['scopedSlots'] = { title: 'custom' }
if (item.children && item.children.length) {
this.handleData(item.children)
}
}
},
/**
* 组织树新增按钮
*/
newlyAdded () {
const item = { key: this.treeData[0].key, operation: 1 }
this.$refs.treeLowerModules.add(item)
},
/**
* 添加下級
* @param item
*/
subordinateItem (item) {
item.operation = 2
this.$refs.treeLowerModules.add(item)
},
/**
* 修改
* @param item
*/
modifyItem (item) {
this.$refs.treeLowerModules.edit(item)
},
/**
* 確定按鈕
* @param val
*/
onOk (val) {
// 1:一级新增, 3:编辑, 2:二级新增
if (val.operation === 1) {
this.selectKeys = [val.key]
this.dataDriveAddSame(val.title)
} else if (val.operation === 2) {
this.selectKeys = [val.key]
this.dataDriveAddSub(val.title)
} else if (val.operation === 3) {
this.selectKeys = [val.key]
this.dataDriveModify(val.title)
}
},
/**
* 公共父级修改方法
* @param childs: 组织树数据
* @param findKey 目标key
*/
getTreeDataByKey (childs = [], findKey) {
let finditem = null
for (let i = 0, len = childs.length; i < len; i++) {
const item = childs[i]
if (item.key !== findKey && item.children && item.children.length > 0) {
finditem = this.getTreeDataByKey(item.children, findKey)
}
if (item.key === findKey) {
finditem = item
}
if (finditem != null) {
break
}
}
return finditem
},
/**
* 公共父级方法
* @param childs: 组织树数据
* @param findKey 目标key
*/
getTreeParentChilds (childs = [], findKey) {
let parentChilds = []
for (let i = 0, len = childs.length; i < len; i++) {
const item = childs[i]
if (item.key !== findKey && item.children && item.children.length > 0) {
parentChilds = this.getTreeParentChilds(item.children, findKey)
}
if (item.key === findKey) {
parentChilds = childs
}
if (parentChilds.length > 0) {
break
}
}
return parentChilds
},
/**
* 添加同级
* @param title
*/
dataDriveAddSame (title) {
const parentChilds = this.getTreeParentChilds(
this.treeData,
this.selectKeys[0]
)
// 校验 相同的不能不可以添加
const existence = parentChilds.find(item => { return item.key === title })
if (!existence) {
parentChilds.push({
title: title,
key: new Date().getTime(),
scopedSlots: { title: 'custom' }
})
} else {
this.$message.success('此数据已存在')
return false
}
},
/**
* 添加下级
* @param title
*/
dataDriveAddSub (title) {
const selectItem = this.getTreeDataByKey(this.treeData, this.selectKeys[0])
if (!selectItem.children) {
this.$set(selectItem, 'children', [])
}
// 校验 相同的不能不可以添加
const existence = selectItem.children.find(item => { return item.title === title })
if (!existence) {
selectItem.children.push({
title: title,
key: new Date().getTime(),
scopedSlots: { title: 'custom' }
})
} else {
this.$message.success('此数据已存在')
return false
}
this.$forceUpdate()
},
/**
* 一级修改
* @param title
*/
dataDriveModify (title) {
const selectItem = this.getTreeDataByKey(this.treeData, this.selectKeys[0])
selectItem.title = title
},
/**
* 刪除
* @param item
*/
deleteItem (item) {
this.selectKeys = [item.key]
this.dataDriveDelete()
},
/**
* 删除方法
*/
dataDriveDelete () {
const parentChilds = this.getTreeParentChilds(
this.treeData,
this.selectKeys[0]
)
// 对删除的数据若下面有子级就给与提示不允许删除
parentChilds.map(item => {
console.log(item.children, '000')
return item.children
})
// console.log(noeDel, 'shanchu')
const delIndex = parentChilds.findIndex(
(item) => item.key === this.selectKeys[0]
)
parentChilds.splice(delIndex, 1)
},
/**
* 拖拽
* @param info
*/
onDragEnter (info) {
console.log(info, '12222')
// expandedKeys 需要受控时设置
// this.expandedKeys = info.expandedKeys
},
/**
* 拖拽
* @param info
*/
onDrop (info) {
console.log(info)
const dropKey = info.node.eventKey
const dragKey = info.dragNode.eventKey
const dropPos = info.node.pos.split('-')
const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1])
const loop = (data, key, callback) => {
data.forEach((item, index, arr) => {
if (item.key === key) {
return callback(item, index, arr)
}
if (item.children) {
return loop(item.children, key, callback)
}
})
}
const data = [...this.treeData]
// Find dragObject
let dragObj
loop(data, dragKey, (item, index, arr) => {
arr.splice(index, 1)
dragObj = item
})
if (!info.dropToGap) {
// Drop on the content
loop(data, dropKey, item => {
item.children = item.children || []
// where to insert 示例添加到尾部,可以是随意位置
item.children.push(dragObj)
})
} else if (
(info.node.children || []).length > 0 && // Has children
info.node.expanded && // Is expanded
dropPosition === 1 // On the bottom gap
) {
loop(data, dropKey, item => {
item.children = item.children || []
// where to insert 示例添加到尾部,可以是随意位置
item.children.unshift(dragObj)
})
} else {
let ar
let i
loop(data, dropKey, (item, index, arr) => {
ar = arr
i = index
})
if (dropPosition === -1) {
ar.splice(i, 0, dragObj)
} else {
ar.splice(i + 1, 0, dragObj)
}
}
this.treeData = data
},
onExpand(keys) {
this.expandedKeys = keys;
this.autoExpandParent = false;
},
handleSelect(selectedKeys, info) {
//把列表接口里的参数改为从树选中事件的参数打印后拿到的值,然后刷新列表
console.log(selectedKeys, info, 'tree 选择')
this.queryParam = selectedKeys[0],
this.reload() //刷新table
// this.$refs.table.refresh(true)
},
reload () {
const case_dir_name = this.queryParam;
console.log('case dir:', case_dir_name);
get_case_list(this.case_list, { case_dir_name })
.then((result) => {
this.loading = false;
this.data = result.data.data; //跟后端接口response对齐
})
.catch((err) => {
this.data = err;
});
},
onEdit(record) {
this.isEnable = true //控制展示 Drawer抽屉
this.disabled = false
this.flag = true //控制编辑页 展示Transfer 穿梭框
this.myTitle = "更新Task"
console.log('case edit:', this.flag);
get_case_detail(this.case_detail, {record})
.then((result) => {
this.loading = false;
this.contents = result.data.data; //跟后端接口response对齐
console.log('onedit ', this.contents);
})
.catch((err) => {
this.contents = err;
});
},
onDelete(e) {
console.log(e);
},
onRun(record) {
this.isEnable = false //控制不展示 Drawer抽屉
this.isshow= true
this.myTitle = "case运行"
console.log('case run:', record); //TODO 调用后端运行接口
},
onDetail(record) {
this.isEnable = true //控制展示 Drawer抽屉
this.disabled = true //控制详情页输入框 不可编辑
this.myTitle = "Case详情页"
console.log('task detail:', this.flag);
get_case_detail(this.case_detail, {record})
.then((result) => {
this.loading = false;
this.contents = result.data.data; //跟后端接口response对齐
console.log('case ondetail ', this.contents);
})
.catch((err) => {
this.contents = err;
});
},
onClose () {
this.isEnable = false;
},
},
mounted() {
const dir_id = 1 //TODO 应该传入左侧的dir_id
getUserList().then(res => {
this.UserArr = res.data.data //跟后端接口response对齐
console.log('搜索条件',this.UserArr);
}),
getDirList({dir_id}).then(res => {
this.loading = false;
this.treeData = res.data.data //跟后端接口response对齐
if(this.treeData !==undefined && this.treeData != null && this.treeData.length > 0) {
console.log('getDirList: ', this.treeData);
// 每一项都加 scopedSlots: { title: 'custom' }
this.handleData(this.treeData)
}
})
},
watch: {
// 监听 searchValue 属性的数据变化,只要 searchValue 的值发生变化,这个方法就会被调用
searchValue(value) {
const expanded = dataList
.map((item) => {
if (item.title.indexOf(value) > -1) {
return getParentKey(item.key, this.treeData);
}
return null;
})
.filter((item, i, self) => item && self.indexOf(item) === i);
this.expandedKeys = expanded;
this.searchValue = value;
this.autoExpandParent = true;
}
},
}
</script>
<style scoped lang="less">
.node-title {
padding-right: 15px;
}
.add {
background: #1890ff;
color: #FFFFFF;
}
.tree-container {
display: flex;
flex-direction: row;
.left-input{
display: flex;
flex-direction: row;
margin-bottom: 2px;
}
.right{
margin-left: 0px;
width: 100%;
&-btn{
float: right;
margin-bottom: 10px;
}
}
}
</style>