tableGroup

import React, { useState,useEffect,ReactNode} from ‘react‘
import { Icon } from ‘antd‘
import $ from ‘./styleTableGroup.scss‘

export interface Column {
  key: string
  title: ReactNode
  thClassName?: string
  tdClassName?: string
  width?: number | string
  alignment?: string
  render?: (value: any, record: any) => ReactNode
  sorter?: ‘asc‘|"desc"| boolean
  children?: any[]
}
interface Props {
  columns: Column[]
  dataSource: any[]
  rowKey: string
  tableWidth?: number | string
  maxHeight?: number | string
  className?: string
  stickyTop?: boolean
  stickyLeft?: boolean
  onChange?:(flag: ‘asc‘| "desc", col: any) => void
}

enum textAlign {
  ‘left‘ = ‘left‘,
  ‘right‘ = ‘right‘,
}
export default function({
  columns,
  dataSource,
  rowKey,
  className,
  tableWidth = ‘‘,
  maxHeight,
  stickyTop = false,
  stickyLeft = true,
  onChange=()=>{}
}: Props) {
  const [currentSortCol,setCurrentSortCol] =useState<Column>()
  const sortChange = (col: Column, flag:‘asc‘|"desc") => {
    setCurrentSortCol({...col,sorter:flag})
    onChange(flag, col)
  }
  useEffect(()=>{
  let realCols:Column[] = []
   columns.forEach(col=>{
     if(col.children?.length){
      realCols = realCols.concat(col.children)
     }else{
      realCols = realCols.concat(col)
     }
   })
   const sortsColumns = realCols.filter(col=>col.sorter)
   setCurrentSortCol({...sortsColumns[0],sorter:"desc"})
   /* eslint-disable-next-line */
  },[])

  const sorter = (col: Column) => {
    return (
      <span className={$.sorter}>
        <Icon
          type="caret-up"
          // onClick={() => sortChange(col, "asc")}
          style={{ color: col.key=== currentSortCol?.key&&currentSortCol?.sorter === "asc" ? ‘#1989FA‘:‘#C0C4CC‘ }}
        />
        <Icon
          type="caret-down"
          // onClick={() => sortChange(col, "desc")}
          style={{ color:col.key=== currentSortCol?.key&&currentSortCol?.sorter === "desc" ? ‘#1989FA‘:‘#C0C4CC‘ }}
        />
      </span>
    )
  }
  const isSticky = (index: number, left: boolean, top: boolean): object => {
    if (top && !left) {
      return { position: ‘sticky‘, top: 0 }
    } else if (top && left) {
      if (index === 0) {
        return { position: ‘sticky‘, left: 0, top: 0, zIndex: 4 }
      } else {
        return { position: ‘sticky‘, top: 0 }
      }
    } else if (left && index === 0) {
      return { position: ‘sticky‘, left: 0, zIndex: 3 }
    }
    return {}
  }
  const head = (cols: Column[]) => {
    return (
      <thead>
        <tr>
          {cols.map((col, i) => (
            <th
              key={col.key}
              className={stickyLeft && i === 0 ? `${col.thClassName} group_${i} ${$.shadow}` : `group_${i} ${col.thClassName}`}
              style={{
                ...isSticky(i, stickyLeft, stickyTop),
                textAlign: (col.alignment as textAlign) || ‘left‘,
              }}
              colSpan={col.children?.length}
            >
              <div
                style={{
                  width: col.width,
                }}
              >
                <span>{col.title}</span>
              </div>
            </th>
          ))}
        </tr>
        <tr>
          {cols.map((colG, i) => (
            colG.children?.map((col,idx)=>(
              <th
                key={col.key}
                className={stickyLeft && i === 0 ? `${col.thClassName} group_${i}_col_${idx} ${$.shadow}` : `group_${i}_col_${idx} ${col.thClassName}`}
                style={{
                ...isSticky(i, stickyLeft, stickyTop),
                textAlign: (col.alignment as textAlign) || ‘left‘,
              }}
                onClick={col.sorter?() => sortChange(col, currentSortCol?.sorter === "desc"?"asc":"desc"):()=>{}}
              >
                <div
                  style={{
                  width: col.width,
                  display: ‘flex‘,
                  justifyContent: col.alignment === ‘right‘ ? ‘flex-end‘ : ‘flex-start‘,
                  alignItems: ‘center‘,
                }}
                >
                  <span>{col.title}</span>
                  {col.sorter && sorter(col)}
                </div>
              </th>
            ))
            
          ))
          }
        </tr>
      </thead>
    )
  }

  const body = (bodyData: any[], cols: Column[]) => {
    return (
      <tbody>
        {bodyData.map((record, index) => (
          <tr key={record[rowKey]}>
            {
              cols.map((colsG,i)=>(
                colsG.children?.map(({ key, alignment, render, width, tdClassName }, idx) => (

                  <td
                    key={key}
                    className={stickyLeft && i === 0 ? `${tdClassName} group_${i}_col_${idx} ${$.shadow}` : `group_${i}_col_${idx} ${tdClassName}`}
                    style={{
                      ...isSticky(i, stickyLeft, false),
                      textAlign: (alignment as textAlign) || ‘left‘,
                    }}
                  >
                    <div style={{ width: width || ‘‘ }}>
                      {render ? render(record[key], { index, ...record }) : record[key]}
                    </div>
                  </td>
                ))
              ))
            }
          </tr>
        ))}
      </tbody>
    )
  }

  return (
    <div
      className={`${$.table_wrap} ${className}`}
      style={{width: tableWidth && tableWidth, maxHeight }}
    >
      <table>
        <colgroup>
          {columns.map(item => {
            return <col key={item.key} className={`colgroup_${item.children?.length}`} span={item.children?.length} />
          })}
        </colgroup>
        {head(columns)}
        {body(dataSource, columns)}
      </table>
    </div>
  )
}


//./styleTableGroup.scss
.table_wrap {
  position: relative;
  overflow-x: auto;
  overflow-y: hidden;
  transition: opacity 0.3s;
  height: 100%;
  &::-webkit-scrollbar {
    display: none !important;
  }
  table {
    min-width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    table-layout: fixed;
    height: 100%;
  }
  :global {
    .colgroup_1 {
      background-color: #fff;
      z-index: 2;
    }
    .colgroup_2,
    .colgroup_3,
    .colgroup_4,
    .colgroup_5 {
      background-image: linear-gradient(90deg, #f8f8f8 0%, #ffffff 100%);
    }
    .group_0,
    .group_0_col_0 {
      background-color: #fff;
    }
  }
  thead {
    tr {
      &:first-child {
        th {
          border-bottom: unset;
          background-color: #fff;
          padding: 8px 0;
        }
      }
    }
  }
  td,
  th {
    text-align: left;
    padding: 8px;
    border-bottom: 1px solid #ebeef5;
    &:last-child {
      text-align: right;
    }
  }
  th {
    font-family: PingFangSC-Medium;
    font-size: 13px;
    color: #909399;
    letter-spacing: 0;
    z-index: 2;
  }
  .shadow {
    position: relative;
    // &::after {
    //   content: ‘‘;
    //   position: absolute;
    //   display: inline-block;
    //   top: 0;
    //   right: -8px;
    //   bottom: -2px;
    //   width: 8px;
    //   background-image: linear-gradient(90deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0) 100%);
    // }
  }
  .sorter {
    display: inline-flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    margin: 0 4px;
    i{
      font-size: 16px;
      color: rgb(192, 196, 204);
      margin: -4px 0px;
    }
  }
}

  

tableGroup

上一篇:分段锁


下一篇:个人系统研发记录