el-table合并行,控制全选框的可选状态
给相同的类合并行
<el-table
border
class="customer-no-border-table"
element-loading-text="数据正在加载中..."
:row-class-name="tableRowClassName"
:header-cell-style="{ background: '#E7F2FD', color: '#252525' }"
style="width: 100%; border-top: 1px solid #409eff"
:cell-style="{ borderColor: '#1890ff' }"
v-loading="leftLoading"
ref="leftTable"
:data="leftTable"
@row-click="getItem"
highlight-current-row
height="400"
:span-method="objectSpanMethod"
>
<el-table-column
prop="detailTypeGroupStr"
align="center"
width="100"
>
</el-table-column>
<el-table-column
label="升级对象"
prop="detailTypeStr"
align="center"
>
<template slot-scope="{ row, $index }">
<div
style="
display: flex;
justify-content: space-around;
align-items: center;
"
>
<div>{{ row.detailTypeStr }}</div>
<div>
<el-button
type="primary"
size="small"
style="margin-left: 20px"
v-if="
(row.flagIndex !== 0 && row.detailTypeGroup === 11) ||
(row.flagIndex !== 0 && row.detailTypeGroup === 12)
"
@click="oneClickSet(row)"
>一键同步</el-button
>
</div>
</div>
</template>
</el-table-column>
</el-table>
this.leftTable = res.data;
this.getSpanArr(res.data);
// 给要显示一键设置按钮的行,添加flagIndex标识
const newArray = this.leftTable.map((i, index) => {
const j = this.spanArr[index];
return {
...i,
flagIndex: j,
};
});
this.leftTable = newArray;
// 合并行
objectSpanMethod({ rowIndex, columnIndex }) {
if (columnIndex === 0) {
const _row = this.spanArr[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
// [0,0] 表示这一行不显示, [2,1]表示行的合并数
rowspan: _row,
colspan: _col,
};
}
},
getSpanArr(data) {
// data就是我们从后台拿到的数据
for (let i = 0; i < data.length; i++) {
//如果是第一条记录(索引为0),向数组中加入1,并设置索引位置
if (i === 0) {
this.spanArr.push(1);
this.pos = 0; //spanArr的索引
} else {
//如果不是第一条记录,则判断它与前一条记录是否相等
//根据相同 扣分类别名称 进行合并,根据需要可进行修改
if (data[i].detailTypeGroup === data[i - 1].detailTypeGroup) {
//如果相等,则向spanArr中添入元素0,并将前一位元素+1,表示合并行数+1
this.spanArr[this.pos] += 1;
this.spanArr.push(0);
} else {
this.spanArr.push(1);
this.pos = i;
}
}
}
},
禁止选中
<el-table
border
class="customer-no-border-table"
element-loading-text="数据正在加载中..."
:row-class-name="tableRowClassName"
:header-cell-style="{ background: '#E7F2FD', color: '#252525' }"
style="width: 100%; border-top: 1px solid #409eff"
v-loading="centerLoading"
ref="centerTable"
:data="centerTable"
highlight-current-row
height="400"
:row-key="rowKey"
@row-click="getItemCenter"
:header-cell-class-name="cellClass"
>
<el-table-column
align="center"
:resizable="false"
:render-header="renderHeader"
width="55"
>
<template #default="scope">
<el-checkbox
v-model="scope.row.checked"
@change="select(scope.row)"
:disabled="disabled()"
/>
</template>
</el-table-column>
<el-table-column
label="硬件类型"
prop="deviceDictCodeStr"
align="center"
></el-table-column>
<div slot="empty">
<img
alt="暂无数据"
src="@/assets/noReport.png"
style="margin-top: 80px"
/>
</div>
</el-table>
computed: {
cellClass() {
if (
(this.leftItem.detailTypeGroup == 11 && this.leftItem.flagIndex == 0) ||
(this.leftItem.detailTypeGroup == 12 && this.leftItem.flagIndex == 0)
) {
return "DisableSelection";
}
},
},
methods:{
// 控制选择硬件的多选框能否被点击
disabled() {
// 有一键设置的时候, 不能编辑下面的厂商;
if (
(this.leftItem.detailTypeGroup == 11 && this.leftItem.flagIndex == 0) ||
(this.leftItem.detailTypeGroup == 12 && this.leftItem.flagIndex == 0)
) {
return true;
} else {
return false;
}
}
}
完整代码:
<template>
<div>
<div class="bigBox">
<div class="leftBox">
<div class="title">
<div class="img">
<img src="@/assets/upgradeObject.png" alt="升级对象" />
</div>
<div class="text">升级对象</div>
</div>
<el-form :inline="true" class="searchBox">
<el-form-item>
<el-input
v-model.trim="upgradeObject"
placeholder="请输入升级对象"
clearable
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" class="searchBut" @click="searchLeftTable"
>搜 索</el-button
>
</el-form-item>
</el-form>
<div class="leftTable">
<el-table
border
class="customer-no-border-table"
element-loading-text="数据正在加载中..."
:row-class-name="tableRowClassName"
:header-cell-style="{ background: '#E7F2FD', color: '#252525' }"
style="width: 100%; border-top: 1px solid #409eff"
:cell-style="{ borderColor: '#1890ff' }"
v-loading="leftLoading"
ref="leftTable"
:data="leftTable"
@row-click="getItem"
highlight-current-row
height="400"
:span-method="objectSpanMethod"
>
<el-table-column
prop="detailTypeGroupStr"
align="center"
width="100"
>
</el-table-column>
<el-table-column
label="升级对象"
prop="detailTypeStr"
align="center"
>
<template slot-scope="{ row, $index }">
<div
style="
display: flex;
justify-content: space-around;
align-items: center;
"
>
<div>{{ row.detailTypeStr }}</div>
<div>
<el-button
type="primary"
size="small"
style="margin-left: 20px"
v-if="
(row.flagIndex !== 0 && row.detailTypeGroup === 11) ||
(row.flagIndex !== 0 && row.detailTypeGroup === 12)
"
@click="oneClickSet(row)"
>一键同步</el-button
>
</div>
</div>
</template>
</el-table-column>
<div slot="empty">
<img
alt="暂无数据"
src="@/assets/noReport.png"
style="margin-top: 80px"
/>
</div>
</el-table>
</div>
</div>
<div v-if="isShow" class="rightBox">
<div class="centerTable">
<div class="title">
<div class="img">
<img src="@/assets/hardwareType.png" alt="硬件类型" />
</div>
<div class="text">硬件类型</div>
</div>
<el-form :inline="true" class="searchBox">
<el-form-item>
<el-input
v-model.trim="hardwareType"
placeholder="请输入硬件类型"
clearable
></el-input>
</el-form-item>
<el-form-item>
<el-button
type="primary"
class="searchBut"
@click="searchCenterTable"
>搜 索</el-button
>
</el-form-item>
</el-form>
<el-table
border
class="customer-no-border-table"
element-loading-text="数据正在加载中..."
:row-class-name="tableRowClassName"
:header-cell-style="{ background: '#E7F2FD', color: '#252525' }"
style="width: 100%; border-top: 1px solid #409eff"
v-loading="centerLoading"
ref="centerTable"
:data="centerTable"
highlight-current-row
height="400"
:row-key="rowKey"
@row-click="getItemCenter"
:header-cell-class-name="cellClass"
>
<el-table-column
align="center"
:resizable="false"
:render-header="renderHeader"
width="55"
>
<template #default="scope">
<el-checkbox
v-model="scope.row.checked"
@change="select(scope.row)"
:disabled="disabled()"
/>
</template>
</el-table-column>
<el-table-column
label="硬件类型"
prop="deviceDictCodeStr"
align="center"
></el-table-column>
<div slot="empty">
<img
alt="暂无数据"
src="@/assets/noReport.png"
style="margin-top: 80px"
/>
</div>
</el-table>
</div>
<div class="rightTable" v-if="isShowRight">
<div class="title">
<div class="img">
<img src="@/assets/factoryName.png" alt="厂商名称" />
</div>
<div class="text">厂商名称</div>
</div>
<el-table
border
class="customer-no-border-table"
element-loading-text="数据正在加载中..."
:row-class-name="tableRowClassName"
:header-cell-style="{ background: '#E7F2FD', color: '#252525' }"
style="width: 100%; border-top: 1px solid #409eff"
v-loading="rightLoading"
ref="rightTable"
:data="rightTable"
height="400"
>
<el-table-column
label="厂商名称"
prop="factoryDictCodeStr"
align="center"
></el-table-column>
<div slot="empty">
<img
alt="暂无数据"
src="@/assets/noReport.png"
style="margin-top: 80px"
/>
</div>
</el-table>
</div>
<div v-else style="margin: auto">
<img
src="@/assets/selectUpgrdeObject.png"
alt="请选择硬件类型进行配置"
/>
<div style="text-align: center">请选择硬件类型进行配置</div>
</div>
</div>
<div v-else style="margin: auto">
<img
src="@/assets/selectUpgrdeObject.png"
alt="请选择升级对象进行配置"
/>
<div style="text-align: center">请选择升级对象进行配置</div>
</div>
</div>
<div style="position: fixed; right: 40px">
<el-button
type="primary"
@click="save"
style="height: 30px; width: 78px; padding: 0; line-height: 30px"
>保存</el-button
>
</div>
</div>
</template>
<script>
import {
getBasicDataDictList,
getDetailTypeList,
getModuleList,
getFactoryList,
saveDetailTypeModuleLink,
} from "_config/url.js";
export default {
props: ["power"],
data() {
return {
upgradeObject: "", //升级对象
hardwareType: "", //硬件类型
leftTable: [],
centerTable: [],
rightTable: [],
leftLoading: false,
centerLoading: false,
rightLoading: false,
isShow: false,
isShowRight: false,
leftItem: "", //左边表格的选中行
centerItem: "", //中间表格的选中行
powerType: "", //功率code
spanArr: [], //每行合并数
pos: 0, //角标索引
isCheckAll: false,
isIndeterminate: false,
centerTableNoCondition: [],
};
},
computed: {
cellClass() {
if (
(this.leftItem.detailTypeGroup == 11 && this.leftItem.flagIndex == 0) ||
(this.leftItem.detailTypeGroup == 12 && this.leftItem.flagIndex == 0)
) {
return "DisableSelection";
}
},
},
mounted() {
this.getOptions();
},
methods: {
// 控制选择硬件的多选框能否被点击
disabled() {
// 有一键设置的时候, 不能编辑下面的厂商;
if (
(this.leftItem.detailTypeGroup == 11 && this.leftItem.flagIndex == 0) ||
(this.leftItem.detailTypeGroup == 12 && this.leftItem.flagIndex == 0)
) {
return true;
} else {
return false;
}
},
// 一键同步
oneClickSet(row) {
let group = row.detailTypeGroup;
this.leftTable = this.leftTable.map((item, i) => {
if (item.detailTypeGroup === group) {
return {
...item,
deviceCodeList: row.deviceCodeList,
};
} else {
return item;
}
});
},
// 合并行
objectSpanMethod({ rowIndex, columnIndex }) {
if (columnIndex === 0) {
const _row = this.spanArr[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
// [0,0] 表示这一行不显示, [2,1]表示行的合并数
rowspan: _row,
colspan: _col,
};
}
},
getSpanArr(data) {
// data就是我们从后台拿到的数据
for (let i = 0; i < data.length; i++) {
//如果是第一条记录(索引为0),向数组中加入1,并设置索引位置
if (i === 0) {
this.spanArr.push(1);
this.pos = 0; //spanArr的索引
} else {
//如果不是第一条记录,则判断它与前一条记录是否相等
//根据相同 扣分类别名称 进行合并,根据需要可进行修改
if (data[i].detailTypeGroup === data[i - 1].detailTypeGroup) {
//如果相等,则向spanArr中添入元素0,并将前一位元素+1,表示合并行数+1
this.spanArr[this.pos] += 1;
this.spanArr.push(0);
} else {
this.spanArr.push(1);
this.pos = i;
}
}
}
},
//获取字典项
getOptions() {
this.$fetch(getBasicDataDictList)
.then((res) => {
if (res.code == 200) {
this.optionsPowerType = res.data.powerTypeDict; //功率类型
const foundItem = this.optionsPowerType.find(
(i) => i.name == this.power
);
this.powerType = foundItem ? foundItem.code : "";
this.searchLeftTable();
} else {
this.$message.error(res.message);
}
})
.catch((err) => {
this.errorMessage(err);
});
},
// 左边表格选中
getItem(val) {
// console.log("🚀 ~ getItem ~ val:", val);
this.leftItem = val;
this.searchCenterTable();
this.isShow = true;
this.isShowRight = false;
},
//中间表格选中
getItemCenter(val) {
console.log("🚀 ~ getItemCenter ~ val:", val);
this.centerItem = val;
this.searchRightTable();
this.isShowRight = true;
},
// 升级对象列表接口场景传参:
// 设备厂商管理:powerType,detailTypeName
// 获取左侧数据列表
async searchLeftTable() {
this.leftLoading = true;
this.isShow = false;
this.isShowRight = false;
this.spanArr = []; //每行合并数
this.pos = 0; //角标索引
if (!this.powerType) {
return this.$message.warning("此功率类型已被禁用");
}
try {
const res = await this.$postjson(getDetailTypeList, {
powerType: this.powerType, //功率类型编码
detailTypeName: this.upgradeObject, //升级对象
});
if (res.code == 200) {
this.leftTable = res.data;
this.getSpanArr(res.data);
// 给要显示一键设置按钮的行,添加flagIndex标识
const newArray = this.leftTable.map((i, index) => {
const j = this.spanArr[index];
return {
...i,
flagIndex: j,
};
});
this.leftTable = newArray;
} else {
this.$message.error(res.message);
}
this.leftLoading = false;
} catch (error) {
this.leftLoading = false;
// console.log("🚀 ~ searchLeftTable ~ error:", error);
this.$message.error("网络异常,稍后请重试");
}
},
renderHeader(h) {
return h("span", [
h("el-checkbox", {
on: {
change: this.selectBox,
},
props: {
value: this.isCheckAll,
indeterminate: this.isIndeterminate,
},
}),
]);
},
// 全选框事件
selectBox(val) {
// 控制多选状态
this.isCheckAll = val;
this.isIndeterminate = false;
this.centerTable.forEach((k) => {
k.checked = val;
});
// 控制数据存储
if (val) {
this.multipleSelection = this.centerTable;
} else {
this.multipleSelection = [];
}
this.handleSelectionChange(this.multipleSelection);
},
// 勾选行
select(row) {
// 控制行多选状态
const checked = row.checked;
console.log("🚀 ~ select ~ checked :", checked);
this.centerTable.forEach((t) => {
if (row.deviceDictCode === t.deviceDictCode) {
t.checked = checked;
}
});
// 控制全选框状态
this.changeAllChecked();
// 控制数据存储
this.pushIfNotExists(this.multipleSelection, row);
this.handleSelectionChange(this.multipleSelection);
console.log(this.leftItem.deviceCodeList, "this.leftItem.deviceCodeList");
},
pushIfNotExists(arr, newItem) {
// console.log("🚀 ~ pushIfNotExists ~ arr, newItem:", arr, newItem);
// 检查数组中是否存在与 newItem 相同 deviceDictCode 的项
const existingItem = arr.find(
(item) => item.deviceDictCode === newItem.deviceDictCode
);
// 如果数组中有相同的项,进行删除
if (existingItem) {
const index = arr.indexOf(existingItem);
if (index !== -1) {
arr.splice(index, 1);
}
} else {
// 如果数组中不存在相同的项,则直接添加新项
arr.push(newItem);
}
return arr;
},
// 控制全选框状态
changeAllChecked() {
let array = this.centerTable.reduce((acc, i) => {
acc.push(i.checked);
return acc;
}, []);
this.isCheckAll = array.length > 0 && array.every((element) => element);
this.isIndeterminate =
!this.isCheckAll && array.some((element) => element);
},
async getCenterTableNoCondition() {
const res = await this.$postjson(getModuleList, {
detailType: this.leftItem.detailType, //升级对象编码
powerType: this.powerType, //功率类型编码
deviceName: "", // 设备名称
source: 1,
});
if (res.code == 200) {
this.centerTableNoCondition = res.data;
}
},
// 获取中间数据列表
async searchCenterTable() {
if (this.$refs.centerTable) {
this.$refs.centerTable.setCurrentRow();
}
this.isShowRight = false;
this.centerLoading = true;
try {
const res = await this.$postjson(getModuleList, {
detailType: this.leftItem.detailType, //升级对象编码
powerType: this.powerType, //功率类型编码
deviceName: this.hardwareType, // 设备名称
source: 1,
});
if (res.code == 200) {
this.centerTable = res.data.map((i) => {
return {
...i,
checked: false,
};
});
this.multipleSelection = [];
if (this.leftItem.deviceCodeList) {
//前端操作过,回显this.leftItem.deviceCodeList中存储的
if (this.hardwareType) {
// 有硬件类型搜索条件;
await this.getCenterTableNoCondition();
this.multipleSelection = this.centerTableNoCondition.filter((i) =>
this.leftItem.deviceCodeList.some((j) => i.deviceDictCode === j)
);
} else {
// 无硬件类型搜索条件
this.multipleSelection = this.centerTable.filter((i) =>
this.leftItem.deviceCodeList.some((j) => i.deviceDictCode === j)
);
}
} else {
if (this.hardwareType) {
// 有硬件类型搜索条件;
await this.getCenterTableNoCondition();
this.multipleSelection = this.centerTableNoCondition.filter(
(i) => i.isSelected === 1
);
} else {
// 无硬件类型搜索条件
this.multipleSelection = this.centerTable.filter(
(i) => i.isSelected === 1
);
}
}
console.log(
"🚀 ~ searchCenterTable ~ this.multipleSelection :",
this.multipleSelection
);
// 多选框状态回显
this.centerTable.forEach((i) => {
this.multipleSelection.forEach((j) => {
if (i.deviceDictCode == j.deviceDictCode) {
i.checked = true;
}
});
});
console.log(
"🚀 ~ this.centerTable.forEach ~ this.centerTable:",
this.centerTable
);
// 全选框状态回显
this.changeAllChecked();
} else {
this.$message.error(res.message);
}
this.centerLoading = false;
} catch (error) {
console.log("🚀 ~ searchCenterTable ~ error:", error);
this.centerLoading = false;
this.$message.error("网络异常,稍后请重试");
}
},
// 获取右侧数据列表
async searchRightTable() {
this.rightLoading = true;
try {
const res = await this.$postjson(getFactoryList, {
detailType: this.leftItem.detailType, //升级对象编码
powerType: this.powerType, //功率类型编码
deviceCode: this.centerItem.deviceDictCode, // 硬件类型编码
});
if (res.code == 200) {
this.rightTable = res.data;
} else {
this.$message.error(res.message);
}
this.rightLoading = false;
} catch (error) {
// console.log("🚀 ~ searchRightTable ~ error:", error);
this.rightLoading = false;
this.$message.error("网络异常,稍后请重试");
}
},
rowKey(row) {
return row.deviceDictCode;
},
// 中间表格多选
handleSelectionChange(val) {
// console.log("🚀 ~ handleSelectionChange ~ val:", val);
this.multipleSelection = val;
// 1.勾选了就存,在leftItem中存硬件类型的list,
let array = this.multipleSelection.map((i) => {
return i.deviceDictCode;
});
// console.log("🚀 ~ array ~ array:", array);
this.leftTable.forEach((i) => {
if (this.leftItem.detailTypeStr == i.detailTypeStr) {
i.deviceCodeList = array;
}
});
console.log(this.leftItem.deviceCodeList, "this.leftItem.deviceCodeList");
},
async save() {
let paramsArray = this.leftTable.map((i) => {
return {
detailType: i.detailType, //升级对象编码
powerType: this.powerType, //功率类型编码
deviceCodeList: i.deviceCodeList, // 硬件类型编码
operator: JSON.parse(localStorage.getItem("user")).staffAccount, // 操作人,
};
});
paramsArray = paramsArray.filter((i) => i.deviceCodeList);
console.log("🚀 ~ save ~ paramsArray :", paramsArray);
try {
const res = await this.$postjson(saveDetailTypeModuleLink, paramsArray);
if (res.code == 200) {
this.$message.success(res.message);
} else {
this.$message.error(res.message);
}
} catch (error) {
// console.log("🚀 ~ save ~ error:", error);
this.$message.error("网络异常,稍后请重试");
}
},
tableRowClassName({ rowIndex }) {
if (rowIndex % 2 === 1) {
return "success-row";
}
return "";
},
},
};
</script>
<style lang="less" scoped>
.leftTable /deep/ .el-table__body tr.current-row td {
border-top: 3px solid #4091f7;
border-bottom: 3px solid #4091f7;
}
.leftTable /deep/.el-table__body tr.current-row td:first-child {
border-left: 3px solid #4091f7;
}
.leftTable /deep/.el-table__body tr.current-row td:last-child {
border-right: 3px solid #4091f7;
}
.leftTable
/deep/.el-table--striped
.el-table__body
tr.el-table__row--striped.current-row
td:last-child {
border-right: 3px solid #4091f7;
}
/deep/ .el-table .DisableSelection .cell .el-checkbox__inner {
visibility: hidden;
}
/deep/.el-table__empty-text {
width: 100%;
}
/deep/ .el-form-item {
margin-bottom: 0px !important;
}
.title {
display: flex;
align-items: center;
margin-bottom: 10px;
.img {
height: 21px;
width: 21px;
margin-right: 10px;
}
.text {
font-size: 18px;
color: #1890ff;
}
}
.bigBox {
display: flex;
overflow-y: scroll;
.leftBox {
width: 30%;
padding-right: 20px;
border-right: 1px solid #d9d9d9;
}
.rightBox {
display: flex;
width: 70%;
.centerTable {
width: 50%;
padding: 0 20px;
border-right: 1px solid #d9d9d9;
}
.rightTable {
width: 50%;
margin-left: 20px;
}
}
}
</style>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】