功能如图
功能需求
表格树形表格勾选数据,右边显示对应勾选的数据内容,选中客户,自动勾选所有的店铺(子级),选中其中一个店铺,自动勾选上客户(父级),同时会存在只有客户(下面没有子级的情况),该功能还涉及到全选(不细讲),搜索勾选,搜索其中一个店铺,或者搜索客户显示所有店铺在勾选(如上面动态图)
功能思路
第一步我们确认此时是勾选动作还是取消勾选动作
第二步我们确认此时勾选的数据是当前哪一个
第三步我们确认此时勾选类型的是客户还是店铺
第四步根据勾选动作和勾选类型去做不同的逻辑操作
1.此时是选中状态---此时是选中的是店铺,通过当前页的客户数据下的店铺数据循环跟我们当前选中的数据对比,找到当前选中的客户数据(leftParent),存在两种情况
- 此时店铺所挂载客户不存在右边,需将客户同时勾选上并往右边加上数据
- 此时店铺所挂载客户存在右边,只需将店铺数据往右边加
若是此时选中的是客户,存在两种情况
- 存在有店铺的情况, (勾选客户会自动勾选店铺 触发下面点击店铺的操作)
- 存在没有店铺 只有客户的情况 (重新写一种情况就是没有店铺,即当前点击的target.shopList没有值,或者为空数组)
2.此时是取消勾选状态--此时是选中的店铺,先通过当前页客户的数据下的店铺数据循环跟我们当前选中的数据对比,找到当前选中的客户数据(leftParent),并此时知道右边所有的数据循环跟当前选中的左边客户数据对比,找到此时右边跟左边的相同的数据(rightParent)
- 此时找到相同的数据rightParent下的shopList的长度大于0,找到当前店铺的下标,然后取消勾选
- 当rightParent的shopList的长度等于0时,说明此时的店铺数据全部取消勾选,此时要同时取消该客户的勾选
此时是取消勾选状态-此时选中的是客户,两种情况
- 点击的客户是没有店铺的情况(直接取消该客户)
- 点击的客户是存在店铺的情况(点击客户,触发点击事件把所有的店铺也取消勾选,走上面的店铺取消勾选事件)
数据结构
[
{
"custId": "460860740775766666",
"custCode": "ZT10009999",
"custName": "邵阳县永民雄新置业有限公司",
"labels": null,
"labelnames": "智屏传统(剔除福州),乐华代理商",
"shopCodes": null,
"shopList": [
{
"shopId": "460861654907518976",
"shopCode": "DP20230625366666",
"shopName": "智能家庭京东专卖店1号店",
"labels": null,
"labelnames": null
},
{
"shopId": "460864194063667200",
"shopCode": "DP202306258888888",
"shopName": "酷友天猫优品旗舰店1号店",
"labels": null,
"labelnames": null
},
{
"shopId": "460865727429906432",
"shopCode": "DP20230625188888",
"shopName": "酷友天猫优品旗舰店2号店",
"labels": null,
"labelnames": null
},
{
"shopId": "460888467817926656",
"shopCode": "DP20230625179999",
"shopName": "智能家庭京东专卖店2号店",
"labels": null,
"labelnames": null
}
]
},
{
"custId": "470195685059002368",
"custCode": "ZT10006888",
"custName": "邵阳县大山贸易有限公司",
"labels": null,
"labelnames": null,
"shopCodes": null,
"shopList": null
}
]
部分代码如下
<el-table
ref="filterCusTable"
v-loading="leftLoading"
:data="customerList"
:show-header="true"
tooltip-effect="dark"
:header-cell-class-name="cellClass"
default-expand-all
:tree-props="{ children: 'shopList' }"
row-key="custCode"
max-height="600"
min-height="400"
@select="selectChange"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="30"></el-table-column>
<el-table-column
label="客户名称"
prop="custName"
></el-table-column>
<el-table-column
label="客户编码"
prop="custCode"
></el-table-column>
<el-table-column
label="客户标签"
prop="labelnames"
></el-table-column>
</el-table>
/**
* 用于树形表格多选,单选的封装
* @param selection
* @param row
*/
selectChange(selection, row) {
console.log('selection', selection, row)
const isCust = Array.isArray(row.shopList)
//勾选的客户把以下的店铺全部带上勾选
if (isCust) {
const isAdd = !this.leftSelectedList.some(
(cust) => cust.custCode === row.custCode
)
console.log('isAdd', isAdd)
// 这里得 nextTick
this.$nextTick(() => {
row.shopList.forEach((shop) =>
this.$refs.filterCusTable.toggleRowSelection(shop, isAdd)
)
})
}
},
//左侧客户选择
handleSelectionChange(selections) {
console.log('selections2', selections)
if (this.initializing == true) return
//selections是当前页勾选的数据 包含了客户和店铺
//this.leftSelectedList 一开始进来页面此时左边已经勾选上的数据(切换分页的时候会跟着变化是当前页所勾选的数据)
// 判断是新增还是减少
let isAdd = false
//当前选中的数据
let target = null
//选中的方法
const toggleSelection = (row, selected) =>
this.$refs.filterCusTable.toggleRowSelection(row, selected)
console.log('selections2', selections)
console.log('this.leftSelectedList', this.leftSelectedList)
if (
//可能会存在重复的数据
selections.length > uniqBy(this.leftSelectedList, 'custCode').length
) {
isAdd = true
//创建一个具有唯一array值的数组,每个值不包含在其他给定的数组中
target = difference(selections, this.leftSelectedList)[0]
} else {
// 取消选择
target = difference(this.leftSelectedList, selections)[0]
}
this.leftSelectedList = selections
//知道当前target点击的值是什么,就能区分我们当前勾选的是店铺还是客户
//shopCode可能是null undefined和""
const isShop = !!target.shopCode //此时就能知道点击的是店铺
let parent = null
//如果点击了店铺 通过当前页的数据循环找到当前满足一项的数据
//就退出循环得到的数据就是父数据(客户)
if (isShop) {
parent = this.customerList.find((item) => {
return (item.shopList || []).some(
(shop) => shop.shopCode === target.shopCode
)
})
console.log('parent', parent)
}
//此时选中
if (isAdd) {
if (isShop) {
//选中的是店铺,需要同时也选中父级的客户行
toggleSelection(parent, true)
this.pushToRight(target)
} else {
// 当前选中父亲,
//1.存在有店铺的情况, (勾选客户会自动勾选店铺 触发下面点击店铺的操作)
//2.存在没有店铺 只有客户的情况 (重新写一种情况就是没有店铺,即当前点击的target.shopList没有值,或者为空数组)
toggleSelection(target, true)
this.pushToRight(target)
}
}
//取消选中
else {
if (isShop) {
//如果点击的是店铺 则取消店铺操作勾选 从右边的数据移除
this.removeRightShop(target)
} else {
//如果点击的是客户,还是两种情况
//1.存在有店铺的情况, (勾选客户会自动勾选店铺 触发下面点击店铺的操作)
//2.存在没有店铺 只有客户的情况 (重新写一种情况就是没有店铺,即当前点击的target.shopList没有值,或者为空数组)
//2取消选中客户 没有店铺的情况
this.removeRightShop(target)
//1有店铺的情况,判断它此时shopList有数据,取消勾选 自动触发方法
target.shopList &&
target.shopList.length > 0 &&
target.shopList.forEach((row) => toggleSelection(row, false))
}
}
},
//选中---把数据往右边List加
pushToRight(row) {
console.log('row', row)
const leftParent = this.customerList.find((item) => {
return (item.shopList || []).some(
(shop) => shop.shopCode === row.shopCode
)
})
//leftParent可能会存在undefined的情况
//判断右边的父级(客户)数据是否已经存在右边,并找到此时右边的父级(客户)数据
const rightParent =
leftParent &&
this.rightCustomerList.find(
(item) => item.custCode === leftParent.custCode
)
if (rightParent) {
// 如果右边已经存在该店铺的客户,
// 但找不到该店铺的存在则直接push进来
if (
!(rightParent.shopList || []).some(
(shop) => shop.shopCode === row.shopCode
)
) {
rightParent.shopList.push({ ...row })
}
} else {
//如果右边不存在该店铺的客户
if (leftParent) {
const parent = { ...leftParent } //浅拷贝 方便进行数据处理和操作
parent.shopList = [{ ...row }] //浅拷贝展开操作,生成一个新的对象,用新对象将parent.shopList数组对象替换
this.rightCustomerList.push(parent) //通过以上的操作 这样就不会影响左边的数据
// 刷新右边的数据
this.tableData = this.rightCustomerList.slice(
(this.pageTwo - 1) * this.pagesize,
this.pageTwo * this.pagesize
)
} else {
//客户没有店铺的情况,直接添加
//一定要记得深拷贝一份,否则会出现影响左边数据的存在(如取消勾选掉子的会splice干掉)
if (!row.shopList || row.shopList.length == 0) {
let pushRow = JSON.parse(JSON.stringify(row))
this.rightCustomerList.push(pushRow)
// 刷新右侧
this.tableData = this.rightCustomerList.slice(
(this.pageTwo - 1) * this.pagesize,
this.pageTwo * this.pagesize
)
}
}
}
},
//取消选中 --把数据从左边删除
removeRightShop(row) {
const leftParent = this.customerList.find((item) => {
return (item.shopList || []).some(
(shop) => shop.shopCode === row.shopCode
)
})
const rightParent =
leftParent &&
this.rightCustomerList.find(
(item) => item.custCode === leftParent.custCode
)
//此时知道右边的当前选中右边选中的数据,然后拿到当前选中的数据,
//通过当前拿到rightParent数据中的shopList来判断
//shopList长度大于0的是店铺--取消客户下的店铺
//shopList长度为0的时候 说明所有店铺都取消,同时要取消该客户
/* 1.此时找到相同的数据rightParent下的shopList的长度大于0,找到当前店铺的下标,然后取消勾选
2.当rightParent的shopList的长度等于0时,说明此时的店铺数据全部取消勾选,此时要同时取消该客户的勾选 */
if (rightParent) {
//客户有店铺的情况
console.log('执行了几次', rightParent)
const shopIndex = rightParent.shopList.findIndex(
(shop) => shop.shopCode === row.shopCode
)
//获取到当前删除店铺的下标 然后取消勾选
if (shopIndex > -1) {
rightParent.shopList.splice(shopIndex, 1)
}
if (rightParent.shopList.length === 0) {
const custIndex = this.rightCustomerList.findIndex(
(item) => item.custCode === rightParent.custCode
)
if (custIndex > -1) {
this.rightCustomerList.splice(custIndex, 1)
// 刷新右侧
this.tableData = this.rightCustomerList.slice(
(this.pageTwo - 1) * this.pagesize,
this.pageTwo * this.pagesize
)
// 左侧取消选中父级
this.$refs.filterCusTable.toggleRowSelection(leftParent, false)
}
}
} else {
//客户没有店铺的情况
console.log('row', row)
if (!row.shopList || row.shopList.length == 0) {
const custIndex = this.rightCustomerList.findIndex(
(item) => item.custCode === row.custCode
)
console.log('custIndex', custIndex)
if (custIndex > -1) {
this.rightCustomerList.splice(custIndex, 1)
// 刷新右侧
this.tableData = this.rightCustomerList.slice(
(this.pageTwo - 1) * this.pagesize,
this.pageTwo * this.pagesize
)
}
}
}
},