温故而知新,最近项目中频繁使用树形结构展示效果,因为不熟悉,备受折磨。
代码贴出来,再复习一次。
代码太长了,想看分析的可以搜我下一篇文章,下一篇会详细的写如何在项目中使用
效果:左侧是树,右侧是表格。点击任何一行都会展示对应的表格
**完整代码如下:**模板区
<el-card >
<div style="display: flex; justify-content: start">
<div class="leftBox">
<div
v-for="(item, index) in buttonList"
:key="index"
@click="num = index"
style="float: left"
>
<el-button class="buttonList" size="medium" @click="treeDataList('parent_id')">{{
item.label
}}</el-button>
</div>
<div class="treeclass">
<!-- :default-expanded-keys(默认展开项)
通过render-content方法定义树节点内容(js代码)
node-key:设置选中节点对应的值
default-expand-all:是否默认展开所有节点
:default-checked-keys 设置默认选中项的数组
ref:设置引用
:load="loadChildData" (load 加载子树数据的方法,仅仅当lazy属性为true时生效) -->
<el-input
placeholder="输入关键字进行过滤"
v-model="filterText"
></el-input>
<el-tree
class="treeitems"
:data="treeData"
node-key="id"
:props="defaultProps"
accordion
default-expand-all
:filter-node-method="filterNode"
@node-click="handleNodeClick"
ref="tree"
>
<span
class="custom-tree-node"
slot-scope="{ node, data }"
@mouseenter="mouseenter(data)"
@mouseleave="mouseleave(data)"
>
<span>
<span v-if="!node.isLeaf">
<i class="folder-open" v-if="node.expanded"></i>
<i class="folder-close" v-else></i>
</span>
<i v-else class="el-icon-document"></i>
{{ node.label }}</span>
<span class="span_icon">
<span v-show="data.show" style="float: right">
<img
src="@/assets/images/png"
alt=""
@click.stop="() => append(node, data)"
/>
<img
src="@/assets/images/png"
alt=""
@click.stop="() => appendChild(node, data)"
/>
<img
src="@/assets/images/png"
alt=""
@click.stop="() => editNode(node, data)"
/>
<img
src="@/assets/images/png"
alt=""
@click.stop="() => deleteNode(node, data)"
/>
</span>
</span>
</span>
</el-tree>
</div>
</div>
<div class="rightBox">
<el-table :data="tableData">
<!-- <el-table-column type="index" label="序号" align="center"> </el-table-column> -->
<el-table-column type="index" label="序号" align="center" width="70">
</el-table-column>
<el-table-column prop="" label="" align="center">
</el-table-column>
<el-table-column prop="" label="" align="center">
</el-table-column>
<el-table-column prop="cost_target" label="目标成本" align="center">
</el-table-column>
<el-table-column
prop="cost_construction"
label="建筑单方造价"
align="center"
>
</el-table-column>
<el-table-column
prop="cost_sellable"
label="可售单方造价"
align="center"
>
</el-table-column>
<!-- <el-table-column prop="mark" label="备注" align="center">
</el-table-column> -->
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<!-- 表格查看 -->
<img
src="~/@/assets/images/"
class="icon icon-deal"
alt=""
style="margin-right: 20px; color: #409eff"
@click="reviewworkFile(scope.row)"
/>
<!-- 表格编辑 -->
<img
src="~/@/assets/images/icon-update.png"
alt=""
class="icon icon-deal"
style="margin-right: 20px; color: #409eff"
@click="editworkFile(scope.row)"
/>
<!-- 表格删除-->
<img
src="~/@/assets/images/png"
alt=""
class="icon icon-deal"
style="color: #fe775c"
@click="removeworkFile(scope.row.id)"
/>
</template>
</el-table-column>
</el-table>
</div>
</div>
<!-- 添加树节点 -->
<el-dialog
:title="addNodeForm.id ? '修改xx分类' : '添加xx分类'"
center
:visible.sync="nodeDialogVisible"
width="30%"
:before-close="nodeClose"
>
<span>
<el-form
:model="addNodeForm"
:rules="addNodeFormRules"
ref="addNodeRef"
label-width="130px"
>
<el-form-item label="关联项目:" prop="project_id">
<el-select
clearable
v-model="addNodeForm.project_id"
placeholder="请选择项目"
>
<el-option
v-for="item in projects"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label=":" prop="">
<el-input v-model=""></el-input>
</el-form-item>
<el-form-item label="" prop="">
<el-input v-model.number="t"></el-input>
</el-form-item>
<el-form-item label="" prop="">
<el-input
type="textarea"
v-model=""
rows="3"
></el-input>
</el-form-item>
</el-form>
</span>
<span slot="footer" class="dialog-footer">
<el-button @click="nodeClose">取 消</el-button>
<el-button type="primary" @click="submitNode">确 定</el-button>
</span>
</el-dialog>
<!-- 添加表格 -->
<el-dialog
:title="dialogTitle"
center
:visible.sync="tableDialogVisible"
width="30%"
:before-close="tableClose"
>
<span>
<el-form
:model="addTableForm"
:rules="addTableFormRules"
ref="addTableRef"
label-width="130px"
>
<el-form-item label="关联项目:">
<el-select
clearable
v-model="addTableForm.project_id"
:disabled="inputFlag"
placeholder="请选择项目"
>
<el-option
v-for="item in projects"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="项目分类:">
<!-- label="title" v-model="addTableForm.category_id" -->
<treeselect
:options="treeData"
:value='value'
:normalizer="normalizer"
placeholder="请选择项目类型"
/>
</el-form-item>
<el-form-item label="科目类型" prop="type">
<el-select
v-model="addTableForm.type_text"
placeholder="请选择"
>
<el-option
v-for="item in typeSelect"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="" prop="">
<el-input v-model.number="" :disabled="inputFlag">
<template slot="append">万元</template>
</el-input>
</el-form-item>
<el-form-item label="">
<el-input v-model="" :disabled="inputFlag">
<template slot="append">万元</template>
</el-input>
</el-form-item>
<el-form-item label="">
<el-input v-model.number="" :disabled="inputFlag">
<template slot="append">万元</template>
</el-input>
</el-form-item>
<el-form-item label="备注">
<el-input
type="textarea"
v-model=""
:disabled="inputFlag"
rows="3"
></el-input>
</el-form-item>
</el-form>
</span>
<span slot="footer" class="dialog-footer" v-if="!inputFlag">
<el-button @click="tableClose">取 消</el-button>
<el-button type="primary" @click="submitTable">确 定</el-button>
</span>
</el-dialog>
</el-card>
script
<script>
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import {
burgetAdd,
burgetRemove,
burgetUpdate,
burgetFindProject,
amountList,
amountAdd,
amountRemove,
amountUpdate,
amountFindProject,
burgetSubject,
burgetTree,
} from "@/api/burget";
import { list } from "@/api/user";
export default {
name: "",
components: { pages, Treeselect },
props: {},
data() {
return {
value:null,
dialogTitle: "", //表格弹窗文本
inputFlag: false, //查看表格的变量,隐藏取消和确认按钮,禁用弹窗
nodeDialogVisible: false, //添加树弹窗
tableDialogVisible: false, //添加表格弹窗
filterText: "", //树过滤
num: 0,
projects: [], //多项目option绑的值
cateprojects: [], //项目分类option绑的值
typeSelect: [], //科目类型option绑的值
activeName: "1",
tableData: [], //表格数据源
treeData: [], //权限树数据
//添加节点表单
addNodeForm: {
parent_id: "",
},
// 添加表格表单
addTableForm: {},
//添加节点表单验证
addNodeFormRules: {
project_id: [
{ required: true, message: "请选择项目", trigger: "blur" },
],
title: [{ required: true, message: "请输入标题", trigger: "blur" }],
},
// 添加表格验证
addTableFormRules: {
type: [
{ required: true, message: "请输入物资名称", trigger: "blur" },
],
cost_target: [
{ required: true, message: "请输入整数", trigger: "blur" },
{ type: "number", message: "必须为数字值", trigger: "blur" },
],
},
//查询项目
projectQuery: {
project_id: "",
category_id: "",
page: 1,
size: 10,
},
//多项目数据
projectForm: {
page: 1,
size: 10000,
tltle: "",
},
query: {
page: "",
size: "",
project_id: "",
parent_id: "",
},
buttonList: [
{ value: 1, label: "xx" },
{ value: 2, label: "xx" },
{ value: 3, label: "xx" },
{ value: 4, label: "xx" },
],
// addform: {},
defaultProps: {
//树形控件的属性绑定对象
children: "children", //设置通过children属性展示子节点信息
label: "title", //通过label设置树形节点文本展示
isLeaf: "leaf",
},
};
},
computed: {},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
},
},
created() {
this.treeDataList();
this.moreProject();
this.addProject();
},
mounted() {},
methods: {
//获取项目列表
async moreProject() {
try {
const data = await list(this.projectForm);
// console.log("列表", data);
this.projectForm = data.data;
this.projects = data.data.items.map((item) => {
return {
label: item.title,
value: item.project_id,
};
});
// window.localStorage.setItem('duoproject',JSON.stringify(this.projects))
} catch (err) {
console.log(err);
}
},
// 添加数据弹窗里的科目类型
async addProject() {
const data = await burgetSubject(this.addTableForm);
let obj = data.data;
for (const key in obj) {
this.typeSelect.push({
value: key,
label: obj[key],
});
}
// console.log(this.typeSelect);
},
normalizer(node){
return{
id:node.id,
label:node.title,
children:node.children,
}
},
handleCurrentChange() {},
//获取左侧树
async treeDataList(id) {
try {
const data = await burgetTree();
this.treeData = data.data;
// console.log("树数据", data.data);
} catch (error) {
console.log(error);
}
},
//树过滤
filterNode(value, data) {
if (!value) return true;
return data.title.indexOf(value) !== -1;
},
//树节点点击
handleNodeClick(data, node) {
// console.log("点击节点", data, node);
this.projectQuery.category_id = node.key;
this.getTableData();
},
// 树节点鼠标移入移出
mouseenter(data) {
this.$set(data, "show", true);
},
mouseleave(data) {
this.$set(data, "show", false);
},
//添加同级节点
append(node) {
// console.log("1111111", node, data);
this.nodeDialogVisible = true;
this.addNodeForm.parent_id = node.parent.key;
},
// 添加子级节点
appendChild(node) {
this.nodeDialogVisible = true;
this.treeDataList();
this.addNodeForm.parent_id = node.key;
},
// 编辑节点
async editNode(node) {
const data = await burgetFindProject({ id: node.key });
// console.log('树节点详情', data);
if (data.code == 200) {
this.addNodeForm = data.data;
this.nodeDialogVisible = true;
}
},
// 删除节点
deleteNode(node) {
this.$confirm("是否删除当前节点?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
burgetRemove({ id: node.key }).then((res) => {
if (res.code == 200) {
this.$message.success("删除成功");
this.treeDataList();
}
});
})
.catch((err) => err);
},
//添加、修改节点提交
submitNode() {
this.$refs.addNodeRef.validate(async (valid) => {
if (!valid) return;
try {
if (this.addNodeForm.id) {
var data = await burgetUpdate(this.addNodeForm);
} else {
var data = await burgetAdd(this.addNodeForm);
}
// console.log('添加树', data);
if (data.code == 200) {
this.$message.success("操作成功");
this.nodeDialogVisible = false;
this.treeDataList();
this.addNodeForm = { parent_id: "" };
}
} catch (error) {
console.log(error);
}
});
},
//添加节点弹窗关闭
nodeClose() {
this.addNodeForm = { parent_id: "" };
this.nodeDialogVisible = false;
},
//实现局部刷新,在点击弹窗处调用的
partialRefreshpartialRefresh(node) {
//设置loaded为false;模拟一次节点展开事件,加载重命名后的新数据;
node.loaded = false;
node.expand();
//新建子节点是刷新一次本节点的展开请求,而重命名和删除则需要刷新父级节点的的展开事件,
//可以设置node.parent.loaded = false;node.parent.expand();
},
//获取表格数据
async getTableData() {
try {
// console.log('查询入参', this.projectQuery);
const data = await amountList(this.projectQuery);
// console.log("表", data);
if (data.code == 200) {
this.tableData = data.data.items;
}
} catch (error) {
console.log(error);
}
},
// 查看表格
reviewworkFile(row) {
this.dialogTitle = "查看xx";
this.tableDialogVisible = true;
this.addTableForm = row;
this.inputFlag = true;
},
// 编辑表格
editworkFile(row) {
this.inputFlag = false;
this.dialogTitle = "编辑xx";
this.tableDialogVisible = true;
this.addTableForm = JSON.parse(JSON.stringify(row)); //row当前行数据,把当前行的数据赋值给表单
},
// 添加表格
addworkFile() {
this.inputFlag = false;
this.dialogTitle = "新增xx";
this.tableDialogVisible = true;
},
// 删除表格
async removeworkFile(id) {
//弹出确定取消框,是否删除用户
const confirmResult = await this.$confirm(
"是否要永久删除该条数据",
"删除提示",
{
confirmButtonText: "确认删除",
cancelButtonText: "取消",
type: "warning",
}
).catch((err) => err);
//如果用户点击确认,则confirmResult 为'confirm'
//如果用户点击取消, 则confirmResult获取的就是catch的错误消息'cancel'
if (confirmResult != "confirm") {
return this.$message.info("已经取消删除");
}
// console.log(id);
const data = await amountRemove({ id });
// console.log(data);
if (data.code == 200) {
this.$message.success("删除成功");
this.treeDataList();
this.getTableData();
}
},
//添加表格弹窗关闭
tableClose() {
this.resetForm();
this.tableDialogVisible = false;
},
// 添加修改弹窗确认事件
async submitTable() {
this.$refs.addTableRef.validate(async (valid) => {
if (!valid) return;
try {
if (this.addTableForm.id) {
var data = await amountUpdate(this.addTableForm);
// console.log("xiugai", data);
} else {
var data = await amountAdd(this.addTableForm);
// console.log("add", data);
}
// console.log('data出参',data);
if (data.code == 200) {
this.$message.success("操作成功");
this.resetForm();
this.tableDialogVisible = false;
this.getTableData();
}
} catch (error) {
console.log(error);
}
});
},
resetForm() {
this.addTableForm = {
type: "",
cost_target: "",
mark: "",
};
},
},
};
</script>
样式的代码不贴了,写的有点乱,这个自己调试都可以调出来的