小白入門請多關(guān)照.如有問題,還望指點!
如果覺得不錯請支持一下!
image.png
核心代碼
更新樹狀節(jié)點
注意修改tableRefName
updateTableTree(pid, nodes) {
//更新節(jié)點數(shù)據(jù)
//pid為父級id,nodes為修改后的子集內(nèi)容
//以下面數(shù)據(jù)結(jié)構(gòu)舉例
//pid=3 子集為id等于3的children數(shù)據(jù)
this.$set(this.$refs.tableRefName.store.states.lazyTreeNodeMap,pid, nodes );
},
refTable() {
/**
*作用:更新樹狀節(jié)點
* 因樹狀原因需更新外層
*所以遞歸更新所有節(jié)點
*/
let _this = this;
function dg(data) {
for (let i in data) {
if (data[i].children) {
_this.updateTableTree(data[i].id, data[i].children);
dg(data[i].children);
}
}
}
dg(this.tableData);
}
數(shù)據(jù)結(jié)構(gòu)
sourceData: [{
id: 3,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀區(qū)金沙江路 1519 弄',
pid: null,
children: [{
id: 31,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀區(qū)金沙江路 1520 弄',
pid: 3
}, {
id: 32,
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀區(qū)金沙江路 1521 弄',
pid: 3
}]
}, {
id: 4,
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀區(qū)金沙江路 1516 弄'
}],
全部源碼
增刪改查的地方已修改為相應(yīng)的注釋
<template>
<div style="width:100%;height:100%">
<div class="cd-tool">
<el-input size="mini" style="width:220px" v-model="searchValue" placeholder="請輸入地址關(guān)鍵字"></el-input>
<el-button type size="mini" @click="search">搜索</el-button>
<el-button type size="mini" @click="enableSel=!enableSel">{{enableSel?'關(guān)閉':'啟用'}}選擇</el-button>
<el-button type size="mini" @click="relDict">關(guān)聯(lián)字典</el-button>
<el-button type size="mini" @click="addTool">新增</el-button>
<el-button type size="mini" @click="batchEdit">批量編輯</el-button>
<el-button type size="mini" @click="batchDel">批量刪除</el-button>
<el-button type size="mini" @click="saveTbale">保存</el-button>
</div>
<el-table
:data="tableData"
style="width: 100%"
row-key="id"
border
stripe
size="mini"
class="data-table"
ref="cimsDictTable"
tooltip-effect="dark"
:height="tableMaxHeight"
@selection-change="handleSelectionChange"
@select="select"
@select-all="selectAll"
header-row-class-name="data-table-header"
lazy
:show-overflow-tooltip="true"
:load="load"
:tree-props="{children:'children'}"
>
<el-table-column v-if="enableSel" type="selection" width="55"></el-table-column>
<el-table-column label="日期">
<template slot-scope="scope">
<el-input v-model="scope.row.date" placeholder="請輸入字典名稱" v-if="scope.row.edit"></el-input>
<span v-else>{{scope.row.date}}</span>
</template>
</el-table-column>
<el-table-column label="姓名">
<template slot-scope="scope">
<el-input v-model="scope.row.name" placeholder="請輸入字典名稱" v-if="scope.row.edit"></el-input>
<span v-else>{{scope.row.name}}</span>
</template>
</el-table-column>
<el-table-column label="地址">
<template slot-scope="scope">
<el-input v-model="scope.row.address" placeholder="請?zhí)顚憘渥? v-if="scope.row.edit"></el-input>
<span v-else>{{scope.row.address}}</span>
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="editRow(scope.row,scope.$index)">編輯</el-button>
<el-button type="text" size="mini" @click="delRow(scope.row,scope.$index)">刪除</el-button>
<el-button type="text" size="mini" @click="addRow(scope.row,scope.$index)">新增</el-button>
<!-- <el-button type="text" size="mini" @click="upRow(scope,scope.row,scope.$index)">上移</el-button>
<el-button type="text" size="mini" @click="downRow(scope.row,scope.$index)">下移</el-button>-->
</template>
</el-table-column>
</el-table>
<el-dialog title="菜單選擇" :visible.sync="dialogVisibleMenu" width="30%" :before-close="Menuclose">
<el-tree
class="filter-tree"
:data="menuSource"
node-key="id"
:props="defaultProps"
:default-expand-all="false"
:expand-on-click-node="false"
ref="tree"
@node-click="onMenuSl"
>
<span class="custom-tree-node" slot-scope="{ node}">
<span>{{ node.label }}</span>
</span>
</el-tree>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisibleMenu = false">取 消</el-button>
<el-button type="primary" @click="cnfAsMenu">確 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
function filterNodes(nodes, query, filterName) {
// 條件就是節(jié)點的filterName過濾關(guān)鍵字
let predicate = function (node) {
if (node[filterName].indexOf(query) > -1) {
return true;
} else {
return false;
}
};
if (!(nodes && nodes.length)) {
return [];
}
let newChildren = [];
for (let node of nodes) {
let subs = filterNodes(node.children, query, filterName);
if (predicate(node)) {
newChildren.push(node);
} else if (subs && subs.length) {
node.children = subs;
newChildren.push(node);
}
}
return newChildren.length ? newChildren : [];
}
export default {
name: "tree-table",
data() {
return {
dialogVisibleMenu: false,
ref: "cimsDictTable",
tableMaxHeight: 400,
enableSel: false,
tableData: [],
cimsDictTable: [],
searchSource: [],
searchValue: "",
menuSource: [],
defaultProps: {
children: "children",
label: "name",
}, //菜單節(jié)點
sourceData: [
{
id: 1,
date: "2016-05-02",
name: "王小虎",
address: "上海市普陀區(qū)金沙江路 1518 弄",
pid: null,
},
{
id: 2,
date: "2016-05-04",
name: "王小虎",
address: "上海市普陀區(qū)金沙江路 1517 弄",
pid: null,
},
{
id: 3,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀區(qū)金沙江路 1519 弄",
pid: null,
children: [
{
id: 31,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀區(qū)金沙江路 1520 弄",
pid: 3,
},
{
id: 32,
date: "2016-05-01",
name: "王小虎",
address: "上海市普陀區(qū)金沙江路 1521 弄",
pid: 3,
},
],
},
{
id: 4,
date: "2016-05-03",
name: "王小虎",
address: "上海市普陀區(qū)金沙江路 1516 弄",
},
],
};
},
methods: {
addTool() {
let addrow = this.setRowData();
this.tableData.push(addrow);
},
onMenuSl(obj, node, data) {
this.id = obj.id;
},
cnfAsMenu() {
if (this.id == null) {
this.$message({
message: "請先選擇關(guān)聯(lián)菜單! ",
type: "warning",
});
} else {
let arr = this.getSelectedList();
let p = arr.map((m) => m.id);
//關(guān)聯(lián)字典接口
this.$message({
message: "關(guān)聯(lián)成功! ",
type: "success",
});
this.dialogVisibleMenu = false;
this.initData();
this.id = null;
}
},
Menuclose() {
this.dialogVisibleMenu = false;
},
search() {
this.tableData = filterNodes(
this.searchSource,
this.searchValue,
"address"
);
this.refTable();
},
setRowData(pid) {
return {
id: new Date().valueOf(),
name: "",
pid: pid ? pid : null,
address: "",
edit: true,
add: true,
};
},
relDict() {
//關(guān)聯(lián)字典
if (!this.checkSelected(this.cimsDictTable, "至少選擇一項")) {
return;
}
//模仿數(shù)據(jù)請求接口
let res = this.sourceData;
this.menuSource = JSON.parse(JSON.stringify(res));
this.dialogVisibleMenu = true;
},
tableRules(list) {
/**
* 驗證規(guī)則
* name不為空
*/
for (let i in list) {
if (list[i].name) {
return false;
}
}
return true;
},
saveTbale() {
//保存
let saveList = [];
let saveTableData = JSON.parse(JSON.stringify(this.tableData));
function dg(saveTableData) {
for (let i in saveTableData) {
if (saveTableData[i].edit) {
//設(shè)置序號
saveTableData[i].cdOrderNum = parseInt(i) + 1;
//2.重置新增數(shù)據(jù)的id為null
if (saveTableData[i].add) {
saveTableData[i].id = null;
}
//3.保存編輯的數(shù)據(jù)
saveList.push(saveTableData[i]);
}
if (saveTableData[i].children) {
dg(saveTableData[i].children);
}
}
}
dg(saveTableData);
if (!this.checkSelected(saveList, "至少編輯一項")) {
return;
}
if (this.tableRules(saveList)) {
this.$message.error("編輯項中存在空數(shù)據(jù),請?zhí)顚懟蛘邉h除");
return;
}
this.$confirm(`操作確認,是否繼續(xù)?`, "提示", {
confirmButtonText: "確定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
//批量保存與更新接口
this.$message({
message: "操作成功! ",
type: "success",
});
this.initData();
})
.catch(() => {});
},
//表格選擇操作方法
// 手動勾選數(shù)據(jù)行
select(selection, row) {
// 判斷當(dāng)前行是否選中
// 不需要判斷 id, 因為引用地址相同
const selected = selection.some((item) => item === row);
// 處理所有子級
this.selectChildren(row, selected);
},
selectAll(selection) {
/*
* 這里引用別人的代碼:
* selectAll 只有兩種狀態(tài): 全選和全不選
* 所以我們只需要判斷一種狀態(tài)即可
* 而且也不需要判斷 id, 因為 selection 和 this.data 中對象引用地址是相同的
*/
// tableData 第一層只要有在 selection 里面就是全選
const isSelect = this.tableData.some((item) => selection.includes(item));
if (isSelect) {
selection.forEach((item) => {
this.selectChildren(item, isSelect);
});
} else {
this.tableData.forEach((item) => {
this.selectChildren(item, isSelect);
});
}
},
selectChildren(row, selected) {
if (row["children"] && Array.isArray(row["children"])) {
row["children"].forEach((item) => {
this.toggleSelection(item, selected);
this.selectChildren(item, selected);
});
}
},
selectionChange(selection) {
this.debounce(this.tableSelectChange, 100, selection);
},
toggleSelection(row, select) {
row &&
this.$nextTick(() => {
this.$refs[this.ref] &&
this.$refs[this.ref].toggleRowSelection(row, select);
});
},
cancelAll() {
this.$refs[this.ref] && this.$refs[this.ref].clearSelection();
},
// 防抖
debounce(fun, wait, params) {
clearTimeout(this.timeout);
this.timeout = setTimeout(fun, wait, params);
},
getSelectedList() {
//獲取選中數(shù)據(jù)源
let list = JSON.parse(JSON.stringify(this.cimsDictTable));
list.forEach((e) => (e.children = null));
return list;
},
checkSelected(data, mange) {
//批量操作檢查
let v = data.length > 0;
if (!v) {
this.$message({
type: "warning",
message: mange,
});
}
return v;
},
batchEdit() {
//批量編輯
if (!this.checkSelected(this.cimsDictTable, "至少選擇一項")) {
return;
}
for (let i in this.cimsDictTable) {
this.$set(this.cimsDictTable[i], "edit", true);
}
},
batchDel() {
//批量刪除
if (!this.checkSelected(this.cimsDictTable, "至少選擇一項")) {
return;
}
let arr = this.getSelectedList();
this.$confirm(`刪除選中的${arr.length}項目數(shù)據(jù)?`, "提示", {
confirmButtonText: "確定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
let p = [];
arr.forEach((d) => {
if (!d.add) {
p.push(d.id);
}
});
//刪除接口
//todo:需判斷2種狀態(tài)提示 前端刪除 和 需要傳回后端
this.initData();
})
.catch(() => {});
},
addRow(row, index) {
if (!row.add) {
//新增行數(shù)據(jù)
let addrow = this.setRowData(row.id);
//新增
if (row.children) {
row.children.push(addrow);
} else {
//添加數(shù)據(jù)
this.$set(row, "children", [addrow]);
}
//展開行
this.$nextTick(() => {
//更新后打開節(jié)點
this.$refs.cimsDictTable.toggleRowExpansion(row, true);
//刷新樹
this.refTable();
});
} else {
this.$message({
message: "請保存后再繼續(xù)添加子節(jié)點!",
type: "warning",
});
}
},
updateTableTree(pid, nodes) {
//更新需要先更新上級節(jié)點
this.$set(
this.$refs.cimsDictTable.store.states.lazyTreeNodeMap,
pid,
nodes
);
},
refTable() {
let _this = this;
function dg(data) {
for (let i in data) {
if (data[i].children) {
_this.updateTableTree(data[i].id, data[i].children);
dg(data[i].children);
}
}
}
dg(this.tableData);
},
editRow(row, index) {
//編輯
this.$set(row, "edit", true);
},
delRow(row, index) {
//刪除行
let delArr = [];
function dg(data) {
for (let i in data) {
//過濾當(dāng)前新增的數(shù)據(jù)
if (!data[i].add) {
delArr.push(data[i].id);
}
if (data[i].children) {
dg(data[i].children);
}
}
}
dg([row]);
//刪除
this.$confirm(
`刪除選中的 ${row.name} 數(shù)據(jù)項?如果有子項,也會一并刪除!`,
"提示",
{
confirmButtonText: "確定",
cancelButtonText: "取消",
type: "warning",
}
)
.then(() => {
if (p.length > 0) {
//刪除接口
this.$message({
message: "刪除成功! ",
type: "success",
});
this.initData();
} else {
this.$message({
message: "刪除成功! ",
type: "success",
});
this.initData();
}
})
.catch(() => {});
},
upRow(scope, row, index) {
console.info(scope, row, index);
//上移
},
downRow(row, index) {
//下移
},
proTableData(data) {
let _this = this;
//處理數(shù)據(jù)
function dg(data) {
for (let i in data) {
_this.$set(data[i], "edit", false);
if (data[i].children) {
//重要:樹狀節(jié)點數(shù)據(jù)刷新
_this.updateTableTree(data[i].id, data[i].children);
dg(data[i].children);
}
}
}
dg(data);
},
initData() {
//數(shù)據(jù)加載 模仿數(shù)據(jù)請求
let res = JSON.parse(JSON.stringify(this.sourceData));
//數(shù)據(jù)處理 添加編輯標識
this.proTableData(res);
this.searchSource = JSON.parse(JSON.stringify(res));
this.tableData = res;
},
load(tree, treeNode, resolve) {
//節(jié)點加載
setTimeout(() => {
resolve(tree.children);
}, 1000);
},
handleSelectionChange(val) {
//全選
this.cimsDictTable = val;
},
},
mounted() {
this.initData();
},
beforeMount() {
this.tableMaxHeight = document.body.clientHeight;
},
};
</script>
<style scoped lang="scss">
.cd-tool {
display: flex;
flex-direction: row;
}
.data-table {
/deep/ .cell {
display: flex;
align-items: center;
}
}
</style>