react antd框架表格实现父级总价实时计算

展示效果

在这里插入图片描述

全部代码

import React, { useState } from 'react';
import { Button, InputNumber, Flex, Table, Typography } from 'antd';
import { Item } from 'rc-menu';
// 生成随机数
function generateRandomString(length: number) {
  let charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  let values = new Uint32Array(length);
  window.crypto.getRandomValues(values);
  let str = '';
  for (let i = 0; i < length; i++) {
    str += charset[values[i] % charset.length];
  }
  return str;
}
// 定义类型
interface Item {
  id?: string;
  pId?: string;
  unit?: number;
  num?: number;
  total?: number;
  children?: Item[];
}
// 创建于一个类表数据  -- 类似后端返回数据
const originData: Item[] = [];
for (let i = 0; i < 3; i++) {
  const a = generateRandomString(20)
  originData.push({
    id: a,
    unit: 0,
    num: 0,
    total: 0,
  });
  for (let j = 0; j < 3; j++) {
    originData.push({
      id: generateRandomString(20),
      pId: a,
      unit: 0,
      num: 0,
      total: 0,
    })
  }
}
// 定义一个空对象等会与数组数据联动 哈希对照表
const hash: Item = {}
// 新创建数组,只选择顶层数据使用
const newOriginData: Item[] = []
// 新创建类型格式对象
class hashObj {
  constructor(obj) {
    this.id = obj.id || generateRandomString(20);
    this.pId = obj.pId;
    this._unit = obj.unit || 0;
    this._num = obj.num || 0;
    this.total = obj.total || 0;
  }
  get unit() {
    return this._unit
  };
  set unit(value) {
    this._unit = value
    // 设置单价时调用 汇总函数
    this.huizong()
  };
  get num() {
    return this._num
  };
  set num(value) {
    this._num = value;
    // 设置数量时调用 汇总函数
    this.huizong()
  };
  huizong = function () {
    if (this.children && this.children.length) {
      // 存在子级,总价=一级子级的和
      this.total = this.children.reduce((a: number, b: Item) => a + b.total, 0)
    } else if (this.unit && this.num) {
      // 不存在子级,总价= 数量*单价
      this.total = this.unit * this.num
    } else {
      this.total = 0
    }
    if (this.pId) {
      // 存在父级调用父级的汇总函数
      hash[this.pId].huizong()
    }
  }
}
// 遍历数据将数据转化为ID为 key  内容为value
originData.forEach((item: Item) => {
  // 对象添加数据内容
  hash[item.id] = new hashObj(item)
  if (item.pId) {
    // 如果有父级给父级添加子级数组
    if (hash[item.pId].children) {
      hash[item.pId].children.push(hash[item.id])
    } else {
      hash[item.pId].children = [hash[item.id]]
    }
  } else {
    // 没有父级的顶层数据并且与hash对象利用浅拷贝关联
    newOriginData.push(hash[item.id])
  }
})
console.log(hash, 'hash')
console.log(originData, 'originData')
console.log(newOriginData, 'newOriginData')
const App: React.FC = () => {
  // 响应数据
  const [data, setData] = useState(newOriginData);
  // 添加子级时
  const add = (record: Item[]) => {
    // 生成新数据
    const obj = new hashObj({ pId: record.id })
    // 添加哈希对照表
    hash[obj.id] = obj
    if (record.children) {
      record.children.push(obj)
    } else {
      record.children = [obj]
    }
    // 调用汇总会触发父级汇总
    obj.huizong();
    // 更新数据
    setData([...data])
  }
  // 生成一级数据
  const addAll = () => {
    const obj = new hashObj({})
    hash[obj.id] = obj
    data.push(obj)
    // 更新数据
    setData([...data])
  }
  // 递归删除hash 对照表中数据
  const delHash = (record: Item[]) => {
    record.forEach(item => {
      if (item.children && item.children.length) {
        delHash(item.children)
      }
      hash[item.id] = undefined;
    })
  }
  // 删除数据
  const del = (record: Item[]) => {
    let arr = data;
    if (record.pId) {
      hash[record.pId].children = hash[record.pId].children.filter((item) => {
        return item.id !== record.id
      });
      hash[record.pId].huizong();
      hash[record.id] = undefined;
    } else {
      hash[record.id] = undefined;
      arr = data.filter((item) => item.id !== record.id);
    }
    // 如果有子级,删除hash表中数据
    if (record.children && record.children.length) {
      delHash(record.children)
    }
    // 更新数据
    setData([...arr])
  }

  const columns = [
    {
      title: 'id',
      dataIndex: 'id',
      width: '20%',
      editable: true,
    },
    {
      title: '单价',
      dataIndex: 'unit',
      width: '20%',
      editable: true,
      render: (_: any, record: Item) => {
        return (
          <InputNumber defaultValue={record.unit} style={{ width: '100%' }} onChange={(val: number) => {
            // 输入时跟新展示
            record.unit = val
            setData([...data])
          }} />
        );
      },
    },
    {
      title: '数量',
      dataIndex: 'num',
      width: '20%',
      editable: true,
      render: (_: any, record: Item) => {
        return (
          <InputNumber defaultValue={record.num} style={{ width: '100%' }} onChange={(val: number) => {
            // 输入时跟新展示
            record.num = val
            setData([...data])
          }} />
        );
      },
    },
    {
      title: '总价',
      dataIndex: 'total',
      width: '20%',
      editable: true,
    },
    {
      title: '操作',
      width: '20%',
      dataIndex: 'operation',
      render: (_: any, record: Item) => {
        return (
          <span>
            <Typography.Link onClick={() => add(record)} style={{ marginRight: 8 }}>
              新增
            </Typography.Link>
            <Typography.Link onClick={() => del(record)}>
              删除
            </Typography.Link>
          </span>
        );
      },
    },
  ];
  return (
    <div>
      <Flex gap="small" wrap="wrap">
        <Button onClick={addAll} type="primary">新增</Button>
      </Flex>
      <Table
        bordered
        dataSource={data}
        columns={columns}
        rowKey="id"
        pagination={false}
      />
    </div>
  );
};

export default App;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值