Skip to content

11.3 笔记

项目整理

场景1 table展开行使用

描述

INFO

现在有一种需求,希望table呈现出Tree的效果,并且可以支持搜索高亮功能

思路

  1. 主要就是利用expandable这个属性

在里面主要就是维护expandRowKeysonExpand这两个属性

1. `expandRowKeys`:展开行,控制属性,但是不要和`**defaultExpandedRowKeys**`**一起使用**
2. `onExpand`:展开图标时触发
  1. 在数据一上来,我就希望可以默认将所有数据全部展开,这样的好处是,可以方便后续高亮展示

默认展示,我们会使用**defaultExpandedRowKeys**这个属性,但是这个属性不可以和**expandRowKeys**一起使用,可能两个属性会“打架”

那么我们就只能自己去维护**expandRowKeys**,也就是我们在拿到**TreeData**的时候,就去收集所有的**id**,这样**Table**就会自动展开

  1. 如何做到满足搜索条件的高亮展示?

使用的rowClassName这个属性,但是最主要的是怎么判断当前满足条件呢?

1. 当我们没有加上任何查询条件,也就是希望搜索所有的时候,我们默认不需要高亮
2. 在所有的`tableData`中寻找是否有数据满足`form`表单里面的数据,收集`id`(**递归:因为有children**)
3. 后续我们只需要判断:当前row的id是否在`匹配到的ids`里面
  1. 查看下级

我们点击查看下级的时候,需要实时的维护expandRowKeys

代码

  1. 因为这里面涉及,查看下级,并且查看下级会导致dataSource直接发生改变,所以这边并没有使用request,而是我们自己来维护dataSource
  2. onSubmit:就是自己调用ProTable上提交表单时触发
  3. onReset:重置表单时触发
typescript
      <ProTable
        // some useless codes
        dataSource={dataSource}
        rowKey={"id"}
        pagination={false}
        expandable={{
          expandedRowKeys,
          onExpand,
        }}
        // 提交表单时候触发
        onSubmit={(params) => {
          getTableData(params);
        }}
        // 重置表单时触发
        onReset={() => {
          getTableData({});
        }}
        // 匹配到的行高亮
        rowClassName={(record) => {
          return isMatchData(record) ? "light-row" : "";
        }}
      />

因为希望页面一上来就全部展开,所以在每次请求数据时候:不仅获取到treeData而且将TreeData里面的ids也收集起来

typescript
export async function getDepartmentList(params) {
  const { simLevel, ...left } = params;
  const res = await request("/v2/web_api/company_depart/new/company_depart_list", {
    method: "post",
    data: {
      ...left,
      simLeave: Number(simLevel),
    },
  });
  // 获取ids
  const expandKeys = collectParentId(JSON.parse(JSON.stringify([res.model])));
  const data = formatTreeData(res.model);
  // 匹配参数,找到对应的部门
  return {
    data: [data],
    success: res.success,
    expandKeys,
  };
}

收集所有ids的时候,不要只是收集部门的id,虽然确实是只有部门才会展开,人员没有下级。

但是如果你现在没有收集,那么后续,高亮进行匹配的时候就会出现问题

typescript
export const collectParentId = (data: any) => {
  const arr: string[] = [];
  const render = (treeDatas: any) => {
    treeDatas.forEach((item: any) => {
      arr.push(item.id);
      if (item.childDeparentList) {
        render(item.childDeparentList);
      }
      if (item.childUserList) {
        render(item.childUserList);
      }
    });
  };
  render(data);
  return arr;
};

因为页面展示的时候,每一行的row的类型其实是不同的,包含人员和部门,这时候我们就需要调整一下格式

  1. children:人员在上面,部门在下面
  2. childDeparentList:可能会存在下级,所以需要递归,但是人员下面一定不存在下级,没必要递归
typescript
export const formatTreeData = (data: TreeData): any => {
  const { childDeparentList, childUserList, ...rest } = data;
  const children = (childDeparentList || []).map((item) => {
    return formatTreeData(item);
  });
  const users = (childUserList || []).map((item) => {
    return item;
  });
  // 将users 放到children中
  const newChildren = [...users, ...children];
  if (!newChildren.length) {
    return { ...rest, children: undefined };
  }
  return { ...rest, children: newChildren };
};

我们这里的判断条件只需要满足其中一个,那么就可以高亮了

因为加了搜索条件的TreeData其实本身就已经满足了搜索条件,所以我们要做的就是对这个数据直接高亮就可以了

typescript
export const findIdByForm = (data: tableData[], form: any) => {
  const id: string[] = [];
  const render = (treeDatas: tableData[]) => {
    treeDatas.forEach((item) => {
      if (item.id === form.departId || item.id === form.userId || Number(item.simLevel) === Number(form.simLevel)) {
        id.push(item.id);
      }
      if (item.children) {
        render(item.children as tableData[]);
      }
    });
  };
  render(data);
  return id;
};

每次获取TreeData的时候:

  1. 收集TreeData数据
  2. 收集TreeData里面所有的ids,用于展开
  3. 收集和当前搜索条件匹配到ids,用于后续高亮
typescript
  async function getTableData(params: any) {
    const res = await getDepartmentList(params);
    if (res.success) {
      const { data, expandKeys } = res;
      setDataSource(data as never[]);
      setExpandedRowKeys(expandKeys);
      const ids = findIdByForm(data, formRef.current?.getFieldsValue());
      setLastKeys(ids);
    }
  }

用户点击获取下级的时候

  1. 直接获取到下级应该有的数据,在获取到就对数据进行format,使他满足展示的格式
  2. dataSource里面匹配id(当前点击的id),将获取到的数据替换到children上面
typescript
  const checkMore = (id: string) => {
    // 设置展开行的rowKeys
    setExpandedRowKeys([...expandedRowKeys, id]);
    getDepartmentChildList(id).then((res) => {
      if (res.success) {
        const { data } = res;
        const cloneData = lodash.cloneDeep(dataSource)[0];
        const datas = findTreeData({
          data: cloneData,
          id,
          newChidren: data[0].children,
        });
        setDataSource([datas] as never[]);

      };
    });
  };

查询下级的数据,同样的,也需要对数据进行一个format

typescript
export async function getDepartmentChildList(params, fn) {
  const res = await request("/v2/web_api/company_depart/company_depart_info", {
    method: "post",
    data: {
      id: params,
    }
  });
  const data = formatTreeData(res.model);
  return {
    data: [data],
    success: res.success,
  };
}

我们需要在datasource里面去匹配到当前点击的id,然后将他的children替换为newChildren

typescript
interface tableData {
  simLevel: number;
  areaCode: string;
  caId: string;
  caName: string;
  id: string;
  isArea: number;
  name: string;
  parentId: string;
  children: tableData[] | User[];
}

interface IFindTreeData {
  data: tableData;
  id: string;
  newChidren: tableData[] | User[];
}

export const findTreeData = (params: IFindTreeData): tableData => {
  const { data, id, newChidren } = params;
  if (data.id === id) {
    return { ...data, children: newChidren };
  }
  // 在datasource里面去寻找数据
  if (data.children) {
    return {
      ...data,
      children: data.children.map((item) => {
        return findTreeData({ data: item as tableData, id, newChidren });
      }),
    };
  }
  return data;
};