基于elementplus 实现多级表格 最后一级展示图片

news2025/1/12 22:49:42

想要实现的效果
在这里插入图片描述
总共四级 前三级是表格 第四级使用图片展示; 看了一下官网 计划使用官网的树形结构, 但是发现并不能满足最后一个是图片形式的展示

最后利用了表格的expand;
在过程中主要需要解决的问题有:vue3 递归使用组件;递归处理数据;展开全部级。

  • 递归处理数据

首先需要处理一下数据,把他们弄成字段一致的,如果后端处理过,前端也会需要处理一下,用于前端自己新增使用的字段 ,我这边 新增了三个字段
disableExpand: 用于我的展开表格 单行能不能展开
id: 后端没有给id字段 用于唯一标识
level: 判断当前数据是第几级数据

const getOverviewList = async () => {
  if (!searchParams.value.train_type_id) {
    return;
  }
  const resp = await Pepper.get('/api/match/detail', {
    params: searchParams.value
  });
  overviewTotal.value = resp.data.list.length;
  overviewList.value = handleOverviewList(resp.data.list);
};

const handleOverviewList = (data: OverviewListModel[], listLevel = 1) => {
  const result: OverviewListModel[] = data.map((item, index) => {
    return {
      ...item,
      // 新增字段
      disableExpand: !!item.sub_number,
      level: listLevel,
      id: listLevel + '-' + index,
      // 处理list
      list: item.list && item.list.length ? handleOverviewList(item.list as OverviewListModel[], listLevel + 1) : []
    };
  });
  return result;
};
  • 递归调用组件
    因为字段一致所以我使用的是同一个组件,需要说明的是 vue3使用自己组件的时候直接使用即可
    在外层:传入所有的data
	<overview-table
      ref="overviewTableRef"
      :total="overviewTotal"
      :data="overviewList"
    />

在OverviewTable组件中 直接使用OverviewTable就可;下面这个包括展开所有级的代码
展开所有级 利用@expand=“handleExpand” 修改expandKeys即可

<template>
  <div>
    <expand-table
      ref="tableRef"
      :data="data"
      :total="total"
      :pageParams="pageParams"
      v-model:expandRowKeys="expandKeys"
      v-bind="$attrs"
      @oneClick="rowClick"
      @expand="handleExpand"
    >
      <template #expand="{ row }">
        <overview-table
          :ref="el => setOverviewDetailRef(el, row.id)"
          v-if="row.level !== 3"
          :data="row.list"
          :total="row.list.length"
          :show-header="false"
          :height="2000"
          :table-level="row.level + 1"
        />
        <overview-table-detail
          v-else
          :data="row.list"
          @openDialog="openDialog"
        />
      </template>
      <el-table-column
        prop="name"
        min-width="10%"
        label="数据类型"
      />
      ....
      <el-table-column
        prop="sub_number"
        min-width="10%"
        label="包含下级数"
      >
        <template #default="{ row }">
          <span :class="!row.sub_number ? 'no-sub' : ''">{{ row.sub_number }}</span>
        </template>
      </el-table-column>
      <operation-column
        min-width="10%"
        :operationOptions="operationOptions"
      />
    </expand-table>
    <image-detail-dialog
      :showDeleteBtn="false"
      ref="imageDetailDialogRef"
    />
  </div>
</template>

<script setup lang="ts">
import { computed, ref, inject, nextTick } from 'vue';
import ExpandTable from '@/components/table/ExpandTable.vue';
import OverviewTableDetail from './OverviewTableDetail.vue';
import ImageDetailDialog from '../../original/stop/ImageDetailDialog.vue';
import OperationColumn, { OperationOptionModel } from '@/components/table/OperationColumn.vue';
import { PageAware } from '@/model';
import { ConfigModel } from 'public/config';
import { OverviewListModel } from '@/model/registration';
import { PhotoListModel } from '@/model/original';

const props = withDefaults(
  defineProps<{
    data: OverviewListModel[];
    total: number;
    tableLevel?: number;
  }>(),
  {
    data: () => [],
    tableLevel: 1
  }
);

const pageParams = ref<PageAware>({
  page_no: 1,
  page_size: (inject('global') as ConfigModel).registration.registrationLimit
});

const tableRef = ref<InstanceType<typeof ExpandTable>>();
const overviewDetailRefs = ref<any>({});
const imageDetailDialogRef = ref<InstanceType<typeof ImageDetailDialog>>();
const expandKeys = ref<string[]>([]);

const operationOptions = computed<OperationOptionModel[]>(() => {
  return [
    {
      icon: 'icon-upload',
      title: '上传',
      hidden: props.tableLevel !== 1,
      onClick: () => {}
    },
    {
      icon: 'icon-compute',
      title: '计算',
      hidden: props.tableLevel !== 2,
      disabled: (row: OverviewListModel) => {
        return row.state !== '待计算';
      },
      onClick: () => {}
    }
  ];
});

// 动态ref
const setOverviewDetailRef = (el: any, id: number) => {
  if (el) {
    overviewDetailRefs.value[id] = el;
  }
};

// 打开弹窗
const openDialog = (index: any, data: PhotoListModel[]) => {
  imageDetailDialogRef.value?.open(index, data);
};

// 单击展开/关闭
const rowClick = (row: OverviewListModel) => {
  if (expandKeys.value.includes(row.id)) {
    tableRef.value?.closeRowExpansion(row);
  } else {
    expandKeys.value.push(row.id);
  }
};

// 展开全部
const handleExpand = (ids: number[] | string[]) => {
  // 情况1:一级全部展开 点击其他的时候 只展开下一级
  // const handleExpand = (ids: number[] | string[], autoExpand) => {
  // autoExpand.value = autoExpandEd ? autoExpandEd : props.tableLevel === 1;
  // if (!autoExpand.value) {
  //   return;
  // }
  //  情况3:点击一级 只展开到三级
  // if (props.tableLevel !== 1) {
  //   return;
  // }
  ids.forEach(async id => {
    await nextTick();
    const stopOverviewDetailRef = overviewDetailRefs.value[id];
    if (stopOverviewDetailRef) {
      await stopOverviewDetailRef?.openRowExpansion();
    }
  });
};

const openRowExpansion = () => {
  //情况1:一级全部展开 点击其他的时候 只展开下一级
  // const ids = (props.data as OverviewListModel[]).map(i => i.id);
  // handleExpand(ids, true);

  // 情况2:点击任何一级 他下面的都展开
  props.data.map(item => {
    if (!item.disableExpand) {
      return;
    }
    if (!expandKeys.value.includes(item.id)) {
      expandKeys.value.push(item.id);
    }
  });
};

const reset = () => {
  // 重新搜索的时候 关闭展开的
  tableRef.value?.closeAllExpand();
  expandKeys.value = [];
};

defineExpose({
  reset,
  expandKeys,
  openRowExpansion
});
</script>

<style lang="scss" scoped>
:deep(.el-table__expanded-cell[class*='cell']) {
  padding: 0;
}
:deep(.el-button + .el-button) {
  margin-left: 0;
}
.no-sub {
  color: #b9bdc9;
}
// 防止弹框样式有问题
:deep(.el-table .el-table__row) {
  position: relative;
  z-index: 0;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/468343.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript题解2652.倍数求和|容斥原理

解题思路 在JavaScript中计算7/3*3&#xff0c;结果是7&#xff0c;而不是6。这是因为JavaScript中除法运算符&#xff08;/&#xff09;得到的结果是一个浮点数&#xff0c;而不是一个整数。 具体来说&#xff0c;7/3得到的结果是2.3333…&#xff0c;然后再乘以3得到7.0000…

辞了外包,上岸字节我落泪了,400多个日夜没人知道我付出了多少....

前言&#xff1a; 没有绝对的天才&#xff0c;只有持续不断的付出。对于我们每一个平凡人来说&#xff0c;改变命运只能依靠努力幸运&#xff0c;但如果你不够幸运&#xff0c;那就只能拉高努力的占比。 2023年3月&#xff0c;我有幸成为了字节跳动的一名自动化测试工程师&am…

nacos搭建

1、查询对应的nacos版本 在pom.xml文件中&#xff0c;按住ctrl单击 spring-cloud-alibaba-dependencies 跳转到对应的页面&#xff0c;搜索nacos 2、下载软件nacos 官网&#xff1a;https://nacos.io/zh-cn/ 地址 https://github.com/alibaba/nacos/releases 这里我们根据我…

【架构】如何在微服务下保证事务的一致性

文章目录 背景一、事务的介绍1.1 事务1.1.1 事务的产生1.1.2 事务的概念1.1.3 事务的特性1.1.4 Mysql隔离级别1.1.5 启动事务 1.2 本地事务1.2.1 本地事务定义1.2.2 本地事务的缺点 二、分布式事务定义三、分布式事务-强一致性解决方案3.1 二阶段提交协议3.2 三阶段提交协议 四…

centos7 nbd 挂在qcow2或qcow,raw,虚机镜像,virsh,virt,使用qemu-nbd挂载qcow2镜像文件

[rootlocalhost linux-3.10.63]# cat ../../../readme https://blog.51cto.com/mshxuyi/5857760 https://blog.csdn.net/weixin_42097108/article/details/111414501 错误解决 &#xff11;、nbd 模块未安装 登录后复制 [rootlocalhost ~]# modprobe nbd modprobe: FATAL…

ElasticJob-Lite 3.x 集成springBoot 实战 (一次性作业、定时作业)

文章目录 前言ElasticJob-Lite 3.x 集成springBoot 实战 (一次性作业、定时作业)1. ElasticJob简介2. ElasticJob-Lite 是什么3. 功能列表4. 所需依赖包5. 定时作业配置5.1. 作业:5.2. yml配置:5.3. 测试 6. 一次性任务配置、并手动触发6.1. 作业:6.2. yml配置:6.3. 测试 7. 其…

洞见数字时代的创新原力,数云原力大会暨2023TECH第五届数字中国技术年会开幕

4月25日&#xff0c;神州控股、神州信息、神州数码集团共同主办的数云原力大会暨2023TECH第五届数字中国技术年会开幕。开幕式上&#xff0c;数百位投身并关注数字技术、数字产业发展的学者、技术专家、从业者、行业用户齐聚一堂&#xff0c;围绕云原生、数字原生、大数据、金融…

2.龙芯2k1000 linux3.10内核编译过程

龙芯2k1000 linux3.10内核编译过程 文章目录 龙芯2k1000 linux3.10内核编译过程&#xff08;一&#xff09;、在Ubuntu环境下载并配置交叉编译链&#xff08;二&#xff09;、下载linux3.10内核源码&#xff08;三&#xff09;、使用menuconfig配置内核&#xff08;四&#xff…

【react从入门到精通】深入理解react生命周期这一篇就够了

文章目录 前言React的生命周期是什么React v16.0前的生命周期组件初始化(initialization)阶段组件挂载(Mounting)阶段组件更新(update)阶段组件销毁阶段 React v16.4 的生命周期总结写在最后 前言 在上一篇文章《react入门这一篇就够了》中我们已经掌握了React的基本知识。通过…

XXE原理利用防御

XXE原理利用防御 一、XML定义 1、定义 XML用于标记电子文件使其具有结构性的标记语言&#xff0c;可以用来标记数据、定义数据类型&#xff0c;是一种允许用户对自己的标记语言进行定义的源语言。 2、原因 应用程序解析XML时&#xff0c;没有过滤外部实体的加载&#xff0…

多用户商城平台开发需要注意哪些问题?

电子商务的快速发展&#xff0c;越来越多的企业选择借助第三方商城软件开设自己的多用户商城平台&#xff0c;以此来帮助他们增加销售额和提高品牌知名度&#xff0c;如目前市面上常见的shop、shopnc等第三方商城软件。但是&#xff0c;多用户商城平台的开发并不是一件容易的事…

QFIELD-GIS工具版如何编辑数据

一、 简介 在现场进行GIS数据对比、采集、编辑是移动GIS App的一项非常实用的功能。能够使用户更加及时准确的收集到第一手资料&#xff0c;并在现场第一时间进行编辑和完善。同时配合遥感、GPS或移动设备自带各类传感器&#xff0c;再辅助以其它矢量参考数据可以对已有成果…

如何利用社交媒体来做Etsy店铺推广?

利用社交媒体是 Etsy 店铺推广的重要一环。通过创作优秀的社交媒体内容、定期发布内容、与关注者互动和利用广告&#xff0c;你可以吸引更多的潜在客户&#xff0c;增加你的店铺销售量和品牌影响力。以下是详细说明如何利用社交媒体来做店铺推广&#xff1a; 选择适合的社交媒体…

FinClip 现已支持云开发

在开发一个小程序时&#xff0c;除了考虑界面功能逻辑外&#xff0c;还需要后端的数据支持&#xff0c;开发者需要提前考虑服务器、存储和数据库等相关需求的支持能力&#xff0c;此外还可能需要花费时间精力在部署应用、和依赖服务的建设上。 因此&#xff0c;腾讯小程序为了实…

NetMQ | 实现TCP的发布订阅模式

NetMQ | 实现TCP的发布订阅模式 文章目录 NetMQ | 实现TCP的发布订阅模式前言什么是发布订阅模式&#xff1f;实现步骤步骤1&#xff1a;创建Publisher和Subscriber步骤2&#xff1a;绑定和连接步骤3&#xff1a;添加订阅步骤4&#xff1a;发布消息步骤5&#xff1a;接收消息 示…

构建一体化数字营销平台,助力医药企业实现销售转化能级大幅跃迁 | 案例研究

今日分享的案例企业成立于1994年&#xff0c;主要从事心血管、消化领域的药品生产、加工、分装和销售&#xff0c;其中心血管相关药品广泛畅销至世界很多个国家。目前&#xff0c;该医药公司销售网络遍及全国80余个城市&#xff0c;以专业人员组成的营业队伍&#xff0c;致力于…

【Linux系统安装Python3 --- 思路清晰的五大步】

水善利万物而不争&#xff0c;处众人之所恶&#xff0c;故几于道&#x1f4a6; 目录 一、检查Python版本 二、下载源码包 三、解压编译源码 四、安装Python 五、调整系统默认Python指向 一、检查Python版本 1.直接进入python命令行查看python版本 python 2.列出系统上所…

[Android 模块化配置实践] Java + Gradle7配置模块化实践记录

文章目录 1.项目配置及环境2.项目工程结构3.Project下的系列设置自定义config.gradlesetting.gradlebuild.gradle(:project) 添加modulemodule_common下的build.gradle配置遇到的报错一遇到的报错二 applicationId问题 module_xxx下的build.gradle示例 由于目前刚开始学习模块化…

【vxe-table】自定义表头列是否可以排序

vxe-table真是让人又爱又恨&#xff0c;官网示例还有文档都很详细&#xff0c;但是可能是用的人少&#xff0c;每次遇到问题&#xff0c;都百度不到啥解决方法&#xff0c;不像el-table,全是方法 今天给我提了个bug&#xff0c;vxe-table要支持指定列排序&#xff0c;意思就是…

如何用3D人脸扫描设备制作虚拟数字人?

在海心沙元宇宙音乐会上&#xff0c;虚拟数字人“杜杜”与真人主持杜雨轩老师同台主持&#xff0c;带领现场观众感受虚实融合的音乐世界。 其实虚拟数字人“杜杜”是使用了数字人复刻技术&#xff0c;以真人主持杜雨轩老师1&#xff1a;1复刻的。在模型制作上不同于往常的美型数…