Ant-design: Não há como mostrar dados de estatísticas de agregação na tabela

Criado em 11 abr. 2017  ·  78Comentários  ·  Fonte: ant-design/ant-design

Versão

2.9.1

Meio Ambiente

navegador

Link de reprodução

http: // nenhum

Passos para reproduzir

Quero mostrar estatísticas de agregação no rodapé da tabela, estou tentando as seguintes maneiras:

  1. usando footer prop, adicione tr e td a ele
      <Table
        dataSource={dataSource}
        footer={() => {
          return (
            <tr className='ant-table-row  ant-table-row-level-0'>
              <td>总计</td>
              <td>总计</td>
            <td>总计</td>
            </tr>
          )
        }}
      />
  1. adicione dados extras em dataSource prop
dataSource.push({id: '总计', price: '3000'})

O que é esperado?

Uma imagem vale mais que mil palavras:

O que realmente está acontecendo?

  1. usando footer prop, mas o footer prop não cabe na mesa.

  2. adicione dados extras em dataSource prop, mas se o comprimento da fonte de dados estiver acima de pageSize , os dados extras serão ignorados.

Inactive IssueHuntFest ❓FAQ 💡 Feature Request

Comentários muito úteis

Talvez possamos fazer algo para fazer footer caber na mesa para todo o corpo?

Todos 78 comentários

Olá @TangMonk , parece que você está solicitando um recurso em vez de relatar um bug, infelizmente não temos um plano para implementar este recurso. Você pode desabilitar a paginação padrão da tabela e implementar a paginação você mesmo.

Talvez possamos fazer algo para fazer footer caber na mesa para todo o corpo?

@yesmeck , obrigado pela sua resposta, mas há muitos problemas sobre isso, acho que esse recurso é realmente útil e necessário.

problemas relacionados: # 3591, # 1483, # 4581

@ afc163 , obrigado!

Qual é a sua sugestão ou solução?

Não tenho certeza, acho que não pode limitar estritamente o tamanho dos dados da tabela usando pageSize , os dados devem ser processados ​​pelo lado do servidor em vez do lado do cliente, então podemos adicionar quaisquer dados extras à tabela

Oi,
Existe alguma atualização sobre esses recursos? Ou outra maneira de fazer isso?

@yesmeck A solução mais simples é fazer o rodapé renderizar um <tfoot> real dentro da tabela, em vez de adicionar um <div> extra fora da tabela.

As pessoas estão tentando espremer uma linha extra em dataSource simplesmente porque desejam que o layout da tabela alinhe as colunas para elas.

Sim, já temos um footer prop, não podemos descobrir um nome apropriado para <tfoot/> .

Estou sugerindo reimplementar o footer prop atual para torná-lo um <tfoot /> dentro da tabela, sem adicionar um novo tfoot prop. Não pense que vai quebrar nada.

@yesmeck Parece que esse recurso é solicitado com frequência. Também estou lutando para adicionar uma linha de resumo. Tenho uma solução alternativa, mas envolve manipulação de hacky dom, feliz em ver uma solução mais bonita.

Alguém da equipe já está cuidando disso? Se não, talvez eu pudesse investigar.

Você pode tentar PR.

@yesmeck Aqui está: https://github.com/react-component/table/pull/191
Veja o exemplo / renderFooterInTable para o efeito

Depois de pensar um pouco sobre a API tfoot , gostaria de adicioná-la à propriedade column :

const columns = [{
  title: 'Age',
  dataIndex: 'age',
  key: 'age',
  footer: (data) => {
    return <div>Summary: {data.reduce((sum, record) => sum + record.age, 0)}</div>
  },
}, {
  title: 'Name',
  dataIndex: 'name',
  key: 'name',
}, {
  title: 'Address',
  dataIndex: 'address',
  key: 'address',
}];

renderiza

screen shot 2018-02-27 at 15 03 33

É mais claro fazer a diferença entre os Table[footer] atuais.

Boa ideia. Eu concordo que este seria um lugar melhor para inserir uma nova API.

@hackape Você poderia propor um novo PR?

coisa certa

https://codesandbox.io/s/m45r6o4nj8
Alcançado, mas há um problema com a ligação da barra de rolagem, é mais conveniente ver

@yesmeck qual é o estado do componente

Vi fundido 👍 @yesmeck

No entanto, recebi uma solicitação de recurso adicional. Eu gostaria de propor permitir que o chamado "rodapé" apareça no topo da tabela, logo abaixo do cabeçalho da tabela.

Exemplo:
image

O recurso real solicitado sendo discutido o tempo todo é um meio de espremer uma linha extra para exibir informações estatísticas - em outras palavras, uma "linha de resumo", sem adulterar o conteúdo de dataSource , não um "rodapé" em o sentido posicional.

@hackape Você pode usar o agrupamento de colunas, consulte https://codesandbox.io/s/pmorq2x2lq

Sim, se fosse apenas para fins de posicionamento, este seria um meio viável. Mas no sentido da lógica de negócios, é muito melhor permitir que o usuário faça isso por meio de minha API proposta.

Pense que podemos renomear a API column.footer para column.summary .

const columns = [{
  title: 'Age',
  dataIndex: 'age',
  key: 'age',
  summary: {
    render: (data) => {
      return <div>Summary: {data.reduce((sum, record) => sum + record.age, 0)}</div>
    },
    position: 'bottom',  // default to 'bottom', could be 'top'
  }
}]

Eu proponho apresentar dois novos profissionais chamados pinnedTopData e pinnedBottomData .

const columns = [
  { title: 'Price', dataIndex: 'price' },
  { name: 'Name', dataIndex: 'name' },
];

const data = [
  { price: 3, Name: 'Foo' },
  { price: 5, Name: 'Bar' },
];

const pinnedData = [
  { price: <span style={{ fontWeight: 'bold' }}>Total: 8</span> }
];

<Table
  columns={columns}
  dataSource={data}
  pinnedTopData={pinnedData}
  pinnedBottomData={pinnedData}
/>

Renderiza:

| Preço | Nome
| ---------- | ------ |
| Total: 8 | |
| 3 | Foo |
| 5 | Bar |
| Total: 8 | |

É melhor resolver o # 6896 e este problema com a mesma API.

Existe um novo progresso?

@Nokecy vê sua solução de duas maneiras. Ele não a adicionou ao atributo temporariamente. Acho que sua reorganização tem esse atributo. A premissa é que o número da versão seja atualizado para a mais recente, mas antd package.json deve ser modificado. Também Dois métodos,
1. Se não houver muitas colunas e nenhuma barra de rolagem for exibida, é fácil de resolver.Tenho um exemplo acima.
2. Você pode usar várias barras de título para exibir, não parece tão bonito.

Estou ansioso para que eles melhorem esta função e continuem prestando atenção, mas nosso antd é 2. Mesmo que seja atualizado, não sei se a versão

Alguma atualização para este problema ??

antes que eles possam enviar uma API oficial, por enquanto, sugiro fornecer um componente personalizado table.props.components.body.wrapper e adulterar o props.children ele recebeu.

https://codesandbox.io/s/xpvwpx0npw
Eu manipulei diretamente o elemento dom e encapsulei um total. Você pode adicionar muitos rodapés de acordo com este método, mas o oficial não recomenda operar diretamente o elemento dom. Se você precisar urgentemente, pode consultar isto

@ LDD123 o scroll x está apenas no rodapé em seu exemplo. o corpo também deve rolar com rodapé

image

@jagratiTomar o corpo irá rolar quando o rodapé estiver rolando, eu

@ LDD123 você pode compartilhar um exemplo onde há um scroll-y também no corpo, porque nesse caso apenas o corpo deve rolar e não o rodapé

@jagratiTomar agora, eu oculto scroll-x não rolar, vai ficar tudo bem

@ LDD123 então você está dizendo que quando há scroll-y este exemplo funcionaria certo?

sim

Olá @yesmeck @ afc163 ,

Nossos designers colocam o rodapé (ele tem os valores agregados) no topo do corpo e logo abaixo do cabeçalho para fins de experiência do usuário. As setas para a classificação no cabeçalho e rodapé possuem apenas valores agregados. Com o ColumnGroup, as setas para classificação são anexadas à parte inferior. Do ponto de vista do estilo, é muito mais fácil estilizar o rodapé e colocá-lo no topo, pois o contêiner do rodapé tem uma cor diferente e apenas algumas células têm separador.

Eu apenas faria:

.my-table tfoot > tr {
 background-color: gray;
}

O componente da tabela pode ter algo assim:

<Table appendColumnFooterTop={true}>
   <Column
      footer={(data) => <div>Summary: {data.reduce((sum, record) => sum + record.age, 0)}</div>}
   />
</Table>

Projeto:
screen shot 2018-05-30 at 17 07 38

Não se preocupe com o texto desalinhado nas células, é de uma página feita anteriormente, eles têm que se alinhar na nova que estamos codificando.

Eu poderia oferecer minha ajuda se soubesse que poderia ser liberado em 2 ou 3 semanas (rodapé da coluna e seu alinhamento). Caso contrário, serei forçado a encontrar outras soluções.

Ah, e não consegui entender se # 6896 é sobre rodapé de coluna, então escrevi aqui.

Obrigado.

@kaanozcan Eu enviei um PR implementando a mesma ideia (veja aqui ) em março, a equipe principal o fundiu e depois foi revertido. Parece que eles têm outra ideia de como o problema deve ser enfrentado. Dada a situação, sugiro que você siga o caminho "encontre outras soluções".

@kaanozcan Aqui está um exemplo que atinge seu objetivo por componentes personalizados https://codesandbox.io/s/xjpkx9rzzw

@yesmeck Isso funciona perfeitamente. Obrigado.

O fechamento devido à solicitação original pode ser realizado por componentes personalizados.

@yesmeck Podemos fornecer uma demonstração sobre esse caso de uso?

https://codesandbox.io/s/xjpkx9rzzw
Este exemplo não tem significado prático. Porque se os dados mudarem .. A última soma não usa os dados mais recentes. É o resultado da última atualização. Deve ser onde há dados sujos.

@yesmeck O exemplo que você deu não pode ser usado ... porque os dados não podem ser alterados.
const data = [ { key: "1", name: "John Brown", age: 30, address: "New York No. 1 Lake Park", }, { key: "2", name: "Jim Green", age: 20, address: "London No. 1 Lake Park", }, { key: "3", name: "Joe Black", age: Math.random() * 20, address: "Sidney No. 1 Lake Park", }, ]; como esta modificação ... na verdade, a soma final está incorreta.

@yesmeck https://codesandbox.io/s/xjpkx9rzzw Este demo tem problema, quando você define à esquerda do fixo, você pode ver que o estilo está uma bagunça。

Consegui fazer isso usando o invólucro do componente, mas é meio estranho. Código se parece com este

export default class extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      localData: props.data,
    };

    this.tableRef = React.createRef();
  }

  handleTableUpdate = () => {
    this.setState({ localData: this.tableRef.current.getLocalData() });
  }

  render() {
    return (
      <Table
        ref={this.tableRef}
        columns={this.props.columns}
        dataSource={this.props.data}
        onChange={this.handleTableUpdate}
        components={{
          body: {
            wrapper: (props) => (
              <BodyWithSummary
                columns={this.props.columns}
                data={this.state.localData}
                {...props}
              />
            ),
          },
        }}
      />
    );
  }
}

function BodyWithSummary(props) {
  const { data, columns, ...otherProps } = props;
  return (
    <tbody {...otherProps}>
      <React.Fragment>
        {data && data.length > 0 && (
          <tr>
            {props.columns.map((col) => renderColumn(col, data))}
          </tr>
        )}
        {props.children}
      </React.Fragment>
    </tbody>
  );
}

O chato é que preciso chamar getLocalData se quiser que os dados agregados sejam calculados nas linhas filtradas.
Seria muito melhor se o body wrapper recebesse a tabela ref como um suporte ou tivesse uma maneira mais fácil de acessar os dados que serão renderizados (props.children é uma lista de nós de reação, não muito útil para calcular os agregados)

Podemos usar footer prop, mas renderizar na tabela em vez de div adicional?

Manipulado temporariamente assim:

20180927 0905

      .ant-table-footer {
        padding: 0;
      }
                                    footer={(currentPageData)=>{
                                        return (
                                            <Row style={{marginRight:17}}>
                                                <Col span={4} className="brd">
                                                    <Card bordered={false} className="bgfb" bodyStyle={{padding:'10px 15px'}}>合计</Card>
                                                </Col>
                                                <Col span={4} className="brd">
                                                    <Card bordered={false} className="bgfb" bodyStyle={{padding:'10px 15px'}}>123456789</Card>
                                                </Col>
                                                <Col span={4} className="brd">
                                                    <Card bordered={false} className="bgfb" bodyStyle={{padding:'10px 15px'}}>123456789</Card>
                                                </Col>
                                                <Col span={4} className="brd">
                                                    <Card bordered={false} className="bgfb" bodyStyle={{padding:'10px 15px'}}>123456789</Card>
                                                </Col>
                                                <Col span={4} className="brd">
                                                    <Card bordered={false} className="bgfb" bodyStyle={{padding:'10px 15px'}}>123456789</Card>
                                                </Col>
                                                <Col span={4}>
                                                    <Card bordered={false} className="bgfb" bodyStyle={{padding:'10px 15px'}}>123456789</Card>
                                                </Col>
                                            </Row>
                                        );
                                    }}

Não é perfeito.

Ansioso para ver a base das colunas saindo em breve O (∩_∩) O

@ybning Você tem problemas com colunas fixas? Muitas dessas colunas fixas terão problemas. .

@yesmeck Seu exemplo quebra a contagem interna da tabela: https://codesandbox.io/s/rrpo02qwkq
Navegue para a página 2 e volte para a página 1, pois os dados são duplicados em cada navegação.

Alguma atualização para este problema?

@linrf não, espero que alguém consiga resolver esse problema

Podemos adicionar uma proposta total às estatísticas de agregação de negócios?
total é diferente com footer ,
só aceita uma função para lidar com os dados da coluna, o padrão é reduce

v7a kvx 5cig rjeo 696g
Eu finalmente coloquei o total na coluna

A renderização do conteúdo do rodapé da tabela do antd não é realmente fácil de usar, especialmente quando a própria tabela tem colunas fixas.

Você pode alterar a forma de implementá-lo com duas tabelas, uma para renderizar a tabela original e a outra para renderizar o elemento do rodapé inferior. Com cobertura de estilo, oculte a ponta do rodapé da tabela e a barra de rolagem da área de rolagem da tabela original. Por fim, adicione o código JS para alinhar as posições de rolagem horizontal das duas tabelas. É quase o mesmo.

Componentes:

import React, { PureComponent } from 'react';
import { Table } from 'antd';
import styles from './index.less';

export default class ChartTable extends PureComponent {
  constructor(props) {
    super(props);

    this.refBox = React.createRef();
  }
  componentDidMount() {
    const tableList = Array.from(this.refBox.current.querySelectorAll('.ant-table-body'));
    this.tableList = tableList;
    tableList.forEach((table) => {
      table.addEventListener('scroll', this.handleTableScroll);
    });
  }
  componentWillUnmount() {
    this.tableList.forEach((table) => {
      table.removeEventListener('scroll', this.handleTableScroll);
    });
  }
  handleTableScroll = (e) => {
    const current = e.currentTarget;
    this.tableList.forEach((table) => {
      if (table !== current && table.scrollLeft !== current.scrollLeft) {
        table.scrollLeft = current.scrollLeft;
      }
    });
  }
  renderFooterTable = () => {
    const { columns, dataSource } = this.props;
    const dataList = [{
      department: '合计',
    }];
    return (
      <Table
        className={styles.footerTable}
        pagination={false}
        scroll={{ x: 'max-content' }}
        size="small"
        columns={columns}
        dataSource={dataList}
      />
    );
  }
  render() {
    return (
      <div ref={this.refBox}>
        <Table
          className={styles.mainTable}
          pagination={false}
          scroll={{ x: 'max-content', y: 350 }}
          size="small"
          columns={this.props.columns}
          dataSource={this.props.dataSource}
        />
        {this.renderFooterTable()}
      </div>
    );
  }
}

Arquivo de cobertura de estilo:

mainTable {
  :global {
    .ant-table-body::-webkit-scrollbar {
      display: none;
    }
  }  
}
.footerTable {
  border-top: 1px solid #e8e8e8;

  :global {
    thead {
      display: none;
    }
  }
}

+1 Adoraria ter uma maneira de mostrar agregações de colunas no rodapé.

Isso pode ser implementado usando componentes prop.

const __Table = (totalsRow = initTotals(), key='tableKey') => ({
    className,
    style,
    children
}) => (
    <table className={className} style={style} key={key}>
        {children}
        <tfoot>
            <tr>
                // add tfoot td here
            </tr>
        </tfoot>
    </table>
);

const TableWithTFoot = ({allData, columns}) =>
    <Table
        dataSource={allData.data}
        columns={columns}
        pagination={false}
        components={{ table: __Table(allData.totals) }}
    />

@rororofff financiou $ 5,00 para esta edição.


@piuccio De acordo com o seu pensamento, escrevo à máquina.

https://github.com/Arweil/antd-ext/blob/master/src/TableExt/TableExt.tsx

https://github.com/ant-design/ant-design/issues/5710#issuecomment -450855438

this.refBox = React.createRef();

Eu uso este pacote de versão, execute este código falhou.
"antd": "2.13.14", "react": "15.4.0", "react-dom": "15.4.0"

mensagem de erro
Uncaught TypeError: _react2.default.createRef is not a function at new EstimationReport (psReport.js?18c1:47) at eval (ReactCompositeComponent.js?063f:295) at measureLifeCyclePerf (ReactCompositeComponent.js?063f:75) at

@carvendy Provavelmente é sua configuração de resolução de módulo ao importar react . Tente mudar

import from 'react';

nisso:

import * as react from 'react'

Eu fiz um componente,
Use o modelo de colunas para renderizar o rodapé
No entanto, as barras de rolagem não são suportadas atualmente.

import React from 'react';

class TableFooter extends React.Component {
  render() {
    const { dataSource, columns } = this.props;
    return (
      <table className="ant-table">
        <colgroup>
          {columns.map((colModel, index) => {
            return <col style={{
              width: colModel.width,
              minWidth: colModel.width
            }} key={index} />
          })}
        </colgroup>
        <tfoot >
          <tr >
            {columns.map((colum, idxCol) => {
              return <td style={{ padding: "0px 8px" }} className={colum.className} key={idxCol}>
                <strong>
                  {colum.footerContent ? colum.footerContent : (colum.footerSum ? dataSource.reduce((sum, record) => sum + parseFloat(record[colum.key]), 0) : "")}
                </strong>
              </td>
            })}
          </tr>
        </tfoot>
      </table>
    )
  }
}
export default TableFooter;

Chamada de página

...
render() {
  const columns = [
      {
        key: 'productName'
        footerContent: 'SUM:',
      },
      {
        key: 'quantity',
        footerSum: true,
      }
    }
];
return (
  <Table
    columns={columns}
    dataSource={dataSource}
    footer={()=> {
        return (
           <TableFooter dataSource={dataSource} columns={columns} />
        )
       }
    }
  />
)
....

var data = this.getLocalData ();
var current;
var pageSize;
var state = this.state; // Se não houver paginação, todos são exibidos por padrão

  if (!this.hasPagination()) {
    pageSize = Number.MAX_VALUE;
    current = 1;
  } else {
    pageSize = state.pagination.pageSize;
    current = this.getMaxCurrent(state.pagination.total || data.length);
  } // 分页
  // ---
  // 当数据量少于等于每页数量时,直接设置数据
  // 否则进行读取分页数据


  if (data.length > pageSize || pageSize === Number.MAX_VALUE) {
    data = data.filter(function (_, i) {
      return i >= (current - 1) * pageSize && i < current * pageSize;
    });
  }

  return data;
}

É se o código-fonte dos dados de processamento da tabela pode adicionar uma função aqui para calcular a soma dos valores da lista, adicionar o número total de dados na saída e subtrair os dados recém-adicionados da página e do tamanho da página

após 2 anos, esse problema ainda persiste.

após 2 anos, esse problema ainda existe.

Eu usei originalmente o método de modificar a renderização de reescrever col e anexar dados na tabela não paginada:

image

Mas no caso de paginação, se vários dados forem carregados, eles serão eliminados. Https://github.com/ant-design/ant-design/blob/fee5e291632cce131611dd1a9e2ab89e02ee43a3/components/table/Table.tsx#L407

Quero fazer RP, mas receio que meu design de API não atenda aos requisitos de meu chefe @ afc163 ...

após 2 anos, esse problema ainda existe.

a nova mesa a caminho. Esperando pela nova mesa

https://github.com/ant-design/ant-design/issues/16911#issuecomment -523423460

@ alexchen1875 Isso não mencionou nada relacionado a isso.

@ alexchen1875 Isso não mencionou nada relacionado a isso.

Leia as instruções na seção da mesa cuidadosamente.

@ alexchen1875 incrível!

Desejo enviar um PR e adicionar temporariamente um adereços "Permitir que os dados não cortem os dados" para apoiar o salto https://github.com/ant-design/ant-design/blob/61e319b66826530a1882c20a41862a15d57b120a/components/table/Table.tsx A lógica do filtro de https://github.com/ant-design/ant-design/issues/5710#issuecomment -524164125 disponível também no caso de paginação, não sei se a equipe aceitará ...

Eu modifiquei esta demonstração ,
adicionado suporte para colunas fixas , agrupamento de cabeçalho , mesclagem de células e rolagem ,
Eu usei \

e a paginação não será afetada.Usado temporariamente em meu projeto

👉 novo endereço de demonstração

uso:

const calcRow = [
    {
        colspan: 2,
        render: () => 'total'
    },
    {
        render: sum => sum('age')
    },
    {
        render: sum => sum('score')
    }
]

image

antd v4 suportou a tabela summary : # 21656

image

https://ant.design/components/table/#components -table-demo-summary

antd4 suporta resumo, mas sinto que este resumo ainda precisa ser iterado. Embora a forma atual de usá-lo seja gratuita, mas ao mesmo tempo o impacto é que o código é muito complicado e não se encaixa na intenção original de antd4 de se tornar mais simples

Um cenário simples comum é resumir os dados da página atual. A experiência amigável deve ser configurar diretamente o resumo: verdadeiro na cloumn, para que o código seja organizado e unificado. Muitos cenários complexos podem usar a barra de resumo atual.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

tangsj picture tangsj  ·  3Comentários

longhuasishen picture longhuasishen  ·  3Comentários

drcmda picture drcmda  ·  3Comentários

PeteAndersen picture PeteAndersen  ·  3Comentários

mineralres picture mineralres  ·  3Comentários