w

import React, { useState, useMemo } from 'react';
import { Table, Button } from 'antd';
import { DownOutlined, RightOutlined } from '@ant-design/icons';

// ---------- 唯一 key 生成器 ----------
let childSeq = 0;
const newKey = () => `child-${Date.now()}-${childSeq++}`;

// ---------- 重算合计 ----------
const recalcSummary = (person) => {
  const sum = (f) => (person.children || []).reduce((s, d) => s + (Number(d[f]) || 0), 0);
  return {
    ...person,
    jul: sum('jul'),
    aug: sum('aug'),
    sep: sum('sep'),
    total: sum('total'),
  };
};

// ---------- 初始数据 ----------
const initialData = [
  {
    key: 'person-1',
    name: '张三',
    isSummary: true,
    jul: 300, aug: 400, sep: 500, total: 1200,
    children: [
      { key: newKey(), dept: 'A部门', jul: 100, aug: 150, sep: 200, total: 450 },
      { key: newKey(), dept: 'B部门', jul: 200, aug: 250, sep: 300, total: 750 },
    ],
  },
  {
    key: 'person-2',
    name: '李四',
    isSummary: true,
    jul: 0, aug: 0, sep: 0, total: 0,
    children: [],
  },
];

export default function SummaryTable() {
  const [data, setData] = useState(initialData);
  const [expandedKeys, setExpandedKeys] = useState(initialData.map((p) => p.key));

  // ---------- 追加子行 ----------
  const addChild = (personKey) => {
    setData((prev) =>
      prev.map((p) => {
        if (p.key !== personKey) return p;
        const newRow = {
          key: newKey(),
          dept: `新部门${(p.children?.length || 0) + 1}`,
          jul: 0, aug: 0, sep: 0, total: 0,
        };
        return recalcSummary({ ...p, children: [...(p.children || []), newRow] });
      })
    );
    setExpandedKeys((keys) =>
      keys.includes(personKey) ? keys : [...keys, personKey]
    );
  };

  // ---------- 删除子行 ----------
  const removeChild = (childKey) => {
    setData((prev) =>
      prev.map((p) => {
        if (!p.isSummary) return p;
        const newChildren = (p.children || []).filter((c) => c.key !== childKey);
        if (newChildren.length === (p.children || []).length) return p;
        return recalcSummary({ ...p, children: newChildren });
      })
    );
  };

  // ---------- 切换展开 ----------
  const toggleExpand = (personKey) => {
    setExpandedKeys((keys) =>
      keys.includes(personKey)
        ? keys.filter((k) => k !== personKey)
        : [...keys, personKey]
    );
  };

  // ---------- 列定义 ----------
  const columns = useMemo(
    () => [
      {
        title: '姓名 / 部门',
        dataIndex: 'dept',
        width: 200,
        render: (_, record) =>
          record.isSummary ? <strong>{record.name}</strong> : record.dept,
      },
      {
        title: '7月',
        dataIndex: 'jul',
        width: 120,
        render: (_, record) =>
          record.isSummary ? <strong>{record.jul}</strong> : record.jul,
      },
      {
        title: '8月',
        dataIndex: 'aug',
        width: 120,
        render: (_, record) =>
          record.isSummary ? <strong>{record.aug}</strong> : record.aug,
      },
      {
        title: '9月',
        dataIndex: 'sep',
        width: 120,
        render: (_, record) =>
          record.isSummary ? <strong>{record.sep}</strong> : record.sep,
      },
      {
        title: '合计有无',
        dataIndex: 'total',
        width: 140,
        className: 'expand-trigger-cell',
        render: (value, record) => {
          if (!record.isSummary) return value;
          const expanded = expandedKeys.includes(record.key);
          return (
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>{expanded ? (
                <DownOutlined style={{ fontSize: 12, color: '#1677ff' }} />
              ) : (
                <RightOutlined style={{ fontSize: 12, color: '#1677ff' }} />
              )}<strong>{value}</strong></span>
          );
        },
      },
      {
        title: '操作',
        width: 160,
        render: (_, record) => {
          if (record.isSummary) {
            return (
              <Button type="primary" size="small" onClick={() => addChild(record.key)}>
                + 追加
              </Button>
            );
          }
          return (
            <Button danger size="small" onClick={() => removeChild(record.key)}>
              删除
            </Button>
          );
        },
      },
    ],
    [expandedKeys] // 注意:依赖 expandedKeys,箭头才会随展开状态更新
  );

  return (
    <Table
      columns={columns}
      dataSource={data}
      rowKey="key"
      pagination={false}
      expandable={{
        rowExpandable: (record) => record.isSummary,
        expandedRowKeys: expandedKeys,
        onExpandedRowsChange: setExpandedKeys,
        expandIconColumnIndex: -1,
        expandIcon: () => null,
      }}
      onRow={(record) => {
        if (!record.isSummary) return {};
        return {
          onClick: (e) => {
            const cell = e.target.closest('td.expand-trigger-cell');
            if (!cell) return;
            toggleExpand(record.key);
          },
        };
      }}
    />
  );
}
posted @ 2026-10-09 12:43  小兔子09  阅读(6)  评论(0)    收藏  举报