1、在 components 中创建 HeaderTable 文件夹,在创建 ColumnItem.vue 和 index.vue。
如下:
2、index.vue 代码内容,如下:
<template>
<div>
<el-table
:data="dataTableData"
style="width: 100%"
max-height="700"
:cell-style="{
'border-right': '1px solid #C4C6CB',
'border-bottom': '1px solid #C4C6CB',
}"
:header-cell-style="{
'background-color': '#f8f8f9',
'border-right': '1px solid #C4C6CB',
'border-bottom': '1px solid #C4C6CB',
}"
>
<el-table-column
prop="date"
label="时间"
width="150"
align="center"
v-if="flag"
>
</el-table-column>
<!-- 递归组件 -->
<template v-if="flag">
<ColumnItem
v-for="(item,index) in dataHeaders"
:key="item.label"
:col="item"
:maxLength="maxLength"
>
</ColumnItem>
</template>
<el-table-column
prop=""
width="150"
align="center"
v-if="showAddBut && flag"
>
<template slot="header" slot-scope="scope">
<i class="el-icon-plus" @click="getAdd({})"/>
</template>
</el-table-column>
</el-table>
<el-drawer
:title="title"
:visible.sync="drawer"
:size="350"
direction="ltr"
:before-close="handleClose">
<el-form
:inline="true"
:model="column"
label-position="right"
label-width="auto"
ref="ruleFormRef"
:rules="rules"
class="demo-form-inline form-padding"
>
<el-form-item label="名称" prop="label">
<el-input v-model="column.label" placeholder="请输入名称" clearable />
</el-form-item>
<el-form-item label="宽度" prop="width">
<el-input
v-model="column.width"
type="number"
placeholder="请输入列宽度(不填为自适应)"
clearable
/>
</el-form-item>
<el-form-item label="对齐方式" prop="align">
<el-select
v-model="column.align"
placeholder="请选择对齐方式"
clearable
>
<el-option label="左对齐" value="left" />
<el-option label="居中对齐" value="center" />
<el-option label="右对齐" value="right" />
</el-select>
</el-form-item>
<el-form-item label="映射变量" prop="prop">
<el-cascader
v-model="column.prop"
:options="options"
:props="optionProps"
@change="handleChange">
</el-cascader>
</el-form-item>
</el-form>
<div class="drawer-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" :loading="loading" @click="handleSubmit">
{{ submitText }}
</el-button>
</div>
</el-drawer>
</div>
</template>
<script>
import { EventBus } from "../../utils/event-bus.js";
import ColumnItem from './ColumnItem.vue';
import { apiEditHeaderTable, apiGetList, apiGetTreeselect } from "@/api/headerTable/index.js";
export default {
name: 'CustomElTable',
components: {
ColumnItem
},
props: {
// 表头数据
headers: {
type: Array,
required: true
},
// 表格列表数据
tableData: {
type: Array,
required: true
},
// 区分哪个页面下的列表
tablekey: {
type: String,
required: true
},
// 限制新增最大列
maxLength: {
type: Number,
required: false
},
},
data() {
return {
dataHeaders: this.headers,
dataTableData: this.tableData,
dataNum: this.num,
flag: true, // 为了更新子组件的状态
drawer: false,
loading: false,
column: {
label: "",
width: "",
align: "center",
prop: "",
},
optionProps: {
expandTrigger: 'click',
value: "id",
label: "label",
children: "children",
},
copyCol: {},
rules: {
label: [{ required: true, message: "请输入名称", trigger: "blur" }],
align: [{ required: true, message: "请选择对齐方式", trigger: "blur" }],
},
title: '新增列',
submitText: '新增',
options: [],
}
},
computed: {
showAddBut() {
return this.$store.state.common.headerEditBut
}
},
watch: {
headers: {
handler(newValue,oldValue) {
this.dataHeaders = newValue;
}
},
},
methods: {
// 删除
getDelete(col) {
this.$confirm('是否删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(_ => {
let newHeaders = this.getRecursion(this.dataHeaders,col);
console.log("处理完数据的", newHeaders);
this.dataHeaders = newHeaders;
// 数据更新,更新子组件状态
this.flag = false;
this.$nextTick(() => {
this.flag = true;
})
EventBus.$emit("getHeaders",this.headers)
}).catch(() => {});
},
// 递归删除
getRecursion(arr,col) {
arr.map((item,index) => {
if(item.label === col.label && item.deep === col.deep) {
arr.splice(index,1);
return;
}
if(item.children && item.children.length > 0) {
this.getRecursion(item.children,col)
}
})
return arr;
},
// 新增
getAdd(col) {
this.drawer = true;
this.title = '新增列';
this.submitText = '新增';
this.column.label = '新增列';
this.copyCol = col;
},
// 编辑
getEdit(col) {
this.drawer = true;
this.title = '编辑列',
this.submitText = '保存',
this.column.label = col.label;
this.copyCol = col;
},
// 编辑,新增里的取消
handleClose() {
this.$confirm('内容未保存,确认关闭?','提示',{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(_ => {
this.drawer = false;
})
.catch(_ => {});
},
// 编辑,新增里的保存
handleSubmit() {
let col = this.copyCol
this.loading = true;
let item = {
label: this.column.label,
prop: "",
width: this.column.width,
align: this.column.align,
deep: 1,
selected: false,
children: []
}
if(this.title === '新增列') {
if(!Object.keys(col).length == 0){
item.deep = col.deep + 1;
col.children.push(item);
}else {
this.dataHeaders.push(item);
}
}else {
this.flag = false;
this.$nextTick(() => {
this.flag = true;
col.label = this.column.label;
col.width = this.column.width;
col.align = this.column.align;
col.prop = this.column.prop;
})
}
this.loading = false;
this.drawer = false;
console.log("dataHeaders", this.dataHeaders);
// this.handleApi();
},
// 请求接口,保存表头数据
handleApi() {
let data = {
tableKey: this.tablekey,
tableJson: JSON.stringify(this.dataHeaders)
}
apiEditHeaderTable(data).then(() => {
this.loading = false;
this.drawer = false;
this.$message({
message: '编辑成功',
type: 'success'
});
}).catch(() => {
this.loading = false;
this.drawer = false;
this.$message({
message: '编辑失败',
type: 'error'
});
})
},
handlePreserve() {
console.log("保存");
this.handleApi();
},
//
handleChange(val) {
let aa = val[val.length-1]
apiGetList({
deptId: aa
}).then(res => {
console.log(">>>>",res);
})
},
handleList() {
let data = {}
apiGetTreeselect(data).then((res) => {
this.options = res.data;
})
}
},
mounted() {
this.handleList();
console.log("tablekey",this.tablekey);
EventBus.$on("getDelete",(col) => {
this.getDelete(col)
});
EventBus.$on("getAdd",(col) => {
this.getAdd(col)
});
EventBus.$on("getEdit",(col) => {
this.getEdit(col)
});
EventBus.$on("handlePreserve",() => {
this.handlePreserve()
});
}
}
</script>
<style lang="scss" scoped>
.scope_p {
margin: 0;
}
.i_margin {
margin: 0 10px;
}
.content-main {
.table-title {
display: flex;
justify-content: space-around;
margin-bottom: 10px;
> p {
flex: 1;
font-weight: bold;
font-size: 18px;
}
}
.el-input {
width: 250px;
}
.el-select {
width: 280px;
}
}
.form-padding {
padding: 0 20px;
}
.drawer-footer {
display: flex;
align-items: center;
justify-content: center;
}
.header-btn {
display: flex;
align-items: center;
justify-content: center;
.el-icon-plus {
margin-left: 10px;
cursor: pointer;
}
.el-icon-edit {
margin-left: 10px;
cursor: pointer;
}
.el-icon-delete {
margin-left: 10px;
cursor: pointer;
}
}
.selected {
color: #409eff;
}
.header-scroll::v-deep {
.el-table__header-wrapper {
overflow-x: auto;
}
/* 修改滚动条样式 */
::-webkit-scrollbar {
height: 8px; /* 设置滚动条宽度 */
}
::-webkit-scrollbar-track {
background-color: #ffffff; /* 设置滚动条轨道背景色 */
}
::-webkit-scrollbar-thumb {
background-color: #ececec; /* 设置滚动条滑块颜色 */
border-radius: 4px; /* 设置滚动条滑块圆角 */
}
::-webkit-scrollbar-thumb:hover {
background-color: #e2e2e2; /* 设置滚动条滑块鼠标悬停时颜色 */
}
}
.error_label {
color: #f56c6c !important;
}
</style>
3、ColumnItem.vue 代码内容,如下:
<template>
<el-table-column
:prop="col.prop"
:width="col.width"
:align="col.align"
min-width="150"
>
<template slot="header" slot-scope="scope">
<p class="scope_p">{{col.label}}</p>
<div v-if="showAddBut">
<i class="el-icon-plus" v-if="col.deep < maxLength" @click="Add(col)"/>
<i class="el-icon-edit-outline i_margin" @click="Edit(col)"/>
<i class="el-icon-delete" @click="Delete(col)"/>
</div>
</template>
<!-- 遍历递归 -->
<template v-for="(item,index) in col.children">
<ColumnItem v-if="item.children" :col="item" :key="item.label" :maxLength="maxLength"/>
</template>
</el-table-column>
</template>
<script>
import { EventBus } from "../../utils/event-bus.js";
export default {
name: "ColumnItem",
props: {
col: {
type: Object,
required: true
},
maxLength: {
type: Number,
required: false
},
},
methods: {
Add(col) {
EventBus.$emit("getAdd",col)
},
Edit(col) {
EventBus.$emit("getEdit",col)
},
Delete(col) {
console.log(col);
EventBus.$emit("getDelete",col)
}
},
computed: {
showAddBut() {
return this.$store.state.common.headerEditBut
}
},
mounted() {
},
}
</script>
<style lang="scss" scoped>
.scope_p {
margin: 0;
}
i {
cursor: pointer;
}
.i_margin {
margin: 0 10px;
}
</style>
4、在 .vue 文件中使用和数据,如下:
<HeaderTable :headers="headers" :tableData="tableData" :tablekey="tablekey" :maxLength="4"/>
data() {
return {
headers: [
{
label: "1",
prop: "name",
width: "150",
align: "center",
deep: 1,
selected: false,
children: [
{
label: "1-1",
prop: "",
width: "",
align: "center",
deep: 2,
selected: false,
children: [
{
label: "1-1-1",
prop: "",
width: "",
align: "center",
deep: 3,
selected: false,
children: []
}
]
},
{
label: "1-2",
prop: "",
width: "",
align: "center",
deep: 2,
selected: false,
children: []
}
]
},
{
label: "2",
prop: "name",
width: "150",
align: "center",
deep: 1,
selected: false,
children: [
{
label: "2-1",
prop: "",
width: "",
align: "center",
deep: 2,
selected: false,
children: [
{
label: "2-1-1",
prop: "",
width: "",
align: "center",
deep: 3,
selected: false,
children: []
},
{
label: "2-1-2",
prop: "",
width: "",
align: "center",
deep: 3,
selected: false,
children: []
}
]
},
{
label: "2-2",
prop: "",
width: "",
align: "center",
deep: 2,
selected: false,
children: []
}
]
}
],
tableData: [
{
date: '2016-05-03',
}, {
date: '2016-05-02',
}, {
date: '2016-05-04',
}, {
date: '2016-05-01',
}, {
date: '2016-05-08',
}, {
date: '2016-05-06',
}, {
date: '2016-05-07',
}
],
}
}