ChangeCheckTable

ChangeCheckTable

//@ts-nocheck index.tsx import React, {FC, useState, useMemo, useEffect, useRef} from "react" ; import {Button, Table, Form, Input, InputNumber, Space, Modal} from "antd" ; import {ColumnType} from "antd/es/table" ; import {CalculatorOutlined} from "@ant-design/icons" ; import {SplitModal} from "./SplitModal" ; import {changeTypes, mock} from "./mocks" ; const {Item, List} = Form; export interface IRecord { key?: string; //The key is important, it identifies the uniqueness and distinguishes the data type of each row (header row, row that can be split, row that has been split, distinguished by _) gudName?: string; children?: IRecord[]; gudType?: string; gufType?: string; changeItem?: string; perPrice?: number; } export const ChangeCheckTable: FC = () => { const [form] = Form.useForm(); const dataRef = useRef( JSON .parse( JSON .stringify(mock))); const [mockData, setMockData] = useState(mock ); const [totalPerPrice, setTotalPerPrice] = useState( 0 ); const [expandedRowKeys, setExpandedRowKeys] = useState<string[]>([]); const [btnLoading, setBtnLoading] = useState( false ); const [modalConfig, setModalConfig] = useState<ISplitModal>({ visible : false , }); //When the form data changes useEffect( () => { //Reset the form value const obj = mockData.reduce( ( preV, currV ) => ({ ...preV, [currV.key]: currV.children} ), {} ); form.setFieldsValue(obj); //Recalculate the summary value const sumPerPrice = mockData.reduce( ( preV, currV ) => { return preV + currV.children.reduce( ( pre, cur ) => pre + cur.perPrice, 0 ); }, 0 ); setTotalPerPrice(sumPerPrice); }, [mockData]); //Column configuration const columns: ColumnType<IRecord>[] = [ { title : "key" , dataIndex : "key" , fixed : "left" , render : ( value, record, index ) => { //Title line special processing if (changeTypes.find( ( item ) => item?. changeType === record?.key)) { return value; } //Render cell const [type, idx] = record?.key?.split( "_" ); return ( <> < span > {value} </span >     < Item name = {[type , + index , " key "]} hidden noStyle > < Input/> </Item > </> ); }, }, { title : "Shareholder name" , dataIndex : "gudName" , fixed : "left" , render : ( value, record, index ) => { //Special treatment for the title line if (changeTypes.find( ( item ) => item? .changeType === record?.key)) { return value; } //Render cell const [type, idx] = record.key.split( "_" ); return ( < Item name = {[type, + index , " gudName "]}> < Input/> </Item > ); }, }, { title : "Shareholder Type" , dataIndex : "gudType" , render : ( value, record, index ) => { if (changeTypes.find( ( item ) => item?.changeType === record?.key)) { return null ; } const [type, idx] = record.key.split( "_" ); return ( < Item name = {[type, + index , " gudType "]}> < Input/> </Item > ); }, }, { title : "Share Type" , dataIndex : "gufType" , render : ( value, record, index ) => { if (changeTypes.find( ( item ) => item?.changeType === record?.key)) { return null ; } const [type, idx] = record.key.split( "_" ); return ( < Item name = {[type, + index , " gufType "]}> < Input/> </Item > ); }, }, { title : "Change Item" , dataIndex : "changeItem" , render : ( value, record, index ) => { if (changeTypes.find( ( item ) => item?.changeType === record?.key)) { return null ; } const [type, idx] = record.key.split( "_" ); return ( < Item name = {[type, + index , " changeItem "]} rules = {[{ required: true , whitespace: true }] } > < Input/> </Item > ); }, }, { title : "Price per share" , dataIndex : "perPrice" , render : ( value, record, index ) => { if (changeTypes.find( ( item ) => item?.changeType === record?.key)) { return null ; } const [type, idx] = record.key.split( "_" ); return ( < Item name = {[type, + index , " perPrice "]} rules = {[{ required: true }]}> < InputNumber/> </Item > ); }, }, { title : "Operation" , render : ( value, record, index ) => { if (changeTypes.find( ( item ) => item?.changeType === record?.key)) { return null ; } const [type, idx, splitSeq] = record.key.split( "_" ); //Description is a subline that has been split if (splitSeq !== undefined ) { return ( < Item > < Space > < Button onClick = {() => { const d = form.getFieldValue(type); console.log("kkk", d); setModalConfig((preV) => ({ ...preV, visible: true, type: "edit", data: d.filter((item) => item.key.startsWith(`${type}_${idx}`) ), })); }} > modify </Button > < Button onClick = {() => { const d = form.getFieldValue(type); const posi = d.findIndex((item) => item.key.startsWith(`${type}_${idx}`) ); const num = d.filter((item) => item.key.startsWith(`${type}_${idx}`) ).length; const obj = dataRef.current .find((item) => item.key === type) .children.find((item) => item.key.startsWith(`${type}_${idx}`) ); d.splice(posi, num, obj); setMockData((preV) => { const o = preV.find((item) => item.key === type); o.children = d; return [...preV]; }); }} > reduction </Button > </Space > </Item > ); } //Description is a line that has not been split if (splitSeq === undefined ) { return ( < Item > < Button onClick = (() => { const d = form.getFieldValue([type, index]); setModalConfig((preV) => ({ ...preV, visible: true, type: "add", data: [d], })); }} > Split </Button > </Item > ); } }, }, ]; return ( <> < Form name = "form" form = {form} onValuesChange = {(changedValues, allValues ) => { console.log("Changed form values---", changedValues); }} onFieldsChange={(changedFields, allFields) => { console.log("Changed form fields---", changedFields); //Recalculate the summary value const [type, idx, prop] = changedFields[0]?.name || []; if (prop === "perPrice") { const expandedData = form.getFieldsValue(); const sumPerPrice = mockData.reduce((preV, currV) => { if (!expandedRowKeys.includes(currV.key)) { return ( preV + currV.children.reduce((pre, cur) => pre + cur.perPrice, 0) ); } else { return ( preV + expandedData[currV.key].reduce( (pre, cur) => pre + cur.perPrice, 0 ) ); } }, 0); setTotalPerPrice(sumPerPrice); } }} > < Table columns = {columns} dataSource = {mockData} expandable = {{ expandedRowKeys , onExpand: async ( expanded , record ) => { if (expanded) { //when expanding setExpandedRowKeys((preV) => [...preV, record?.key]); } else { //when put away //Verify the current expanded row form const values = await form.validateFields(); console.log("When put away, verify the value of the form ---", values); if (!values) { console.log("The current expanded line form validation failed..."); return; } //Modify the expansion keys setExpandedRowKeys((preV) => preV.filter((item) => item !== record?.key) ); //Update data setMockData((preV) => { preV.find((item) => item?.key === record?.key).children = values[record?.key]; return [...preV]; }); } }, }} pagination={false} scroll={{ x: 600 }} sticky rowKey="key" summary={(pageData) => { //Show summary value return ( < Table.Summary.Row > < Table.Summary.Cell index = {0} > Total </Table.Summary.Cell > {[1, 2, 3, 4].map((item) => ( < Table.Summary.Cell key = {item}/> ))} < Table.Summary.Cell index = {5} > {totalPerPrice} </Table.Summary.Cell > < Table.Summary.Cell/> </Table.Summary.Row > ); }} /> < Button type = "primary" loading = {btnLoading} onClick = {async () => { //Validation form const values = await form.validateFields(); if (!values) { console.log("Verification failed"); return; } //Take the form data of the current expanded row, which is values console.log(values); //Combine, generate the latest data to submit the request mockData.forEach((item) => { if (expandedRowKeys.includes(item?.key)) { item.children = values[item?.key]; } }); console.log("The latest form value fetched---", mockData); }} > Value </Button > </Form > < SplitModal { ...modalConfig } onClose = {() => { setModalConfig({ visible: false, }); }} onRefresh={async (key, num, datas) => { console.log("Data information of split processing---", key, num, datas); const [type, idx, splitSeq] = key.split("_"); const newData = JSON.parse(JSON.stringify(mockData)); const curr = newData.find((item) => item?.key === type); const index = curr?.children?.findIndex((item) => item.key.startsWith(`${type}_${idx}`) ); curr?.children?.splice(index, num, ...datas); console.log("New data after successful split---", newData); setMockData(newData); }} /> </> ); }; Copy code
//@ts-nocheck import React, {FC, useState, useMemo, useEffect} from "react" ; import {Button, Table, Form, Input, InputNumber, Space, Modal} from "antd" ; import {ColumnType} from " antd/es/table" ; import {CalculatorOutlined} from "@ant-design/icons" ; const {Item, List} = Form; //Define Modal export interface ISplitModal { visible : boolean; type?: "add" | "edit" ; data?: IRecord[]; onClose?: () => void ; onRefresh?: ( key: string, num: number, datas: IRecord[] ) => void ; } export const SplitModal: FC<ISplitModal> = ( { visible, type, data, onRefresh, onClose, } ) => { const [splitForm] = Form.useForm(); useEffect( () => { let d; if (type === "add" ) { d = [ 0 , 1 ].map( ( item ) => { return { ...data[ 0 ], key : ` ${data[ 0 ].key} _ ${item} ` , }; }); } else { d = data; } splitForm.setFieldsValue({ splitData : d }); }, [data, type]); return ( < Modal title = "Split" width = {1200} visible = {visible} onOk = {async () => { const values = await splitForm.validateFields(); if (values) { onClose && onClose(); onRefresh(data[0].key, data?.length, values?.splitData); } }} onCancel={() => { onClose && onClose(); }} > < Form name = "split" form = {splitForm} > < List name = "splitData" > {(fields, {add, remove, move }) => { const columns: ColumnType < IRecord > [] = [ { title: "key", dataIndex: "key", render: (value, record, index) => { return ( < Item name = {[index, " key "]}> < Input/> </Item > ); }, }, { title: "Shareholder Name", dataIndex: "gudName", render: (value, record, index) => { return ( < Item name = {[index, " gudName "]}> < Input/> </Item > ); }, }, { title: "Shareholder Type", dataIndex: "gudType", render: (value, record, index) => { return ( < Item name = {[index, " gudType "]}> < Input/> </Item > ); }, }, { title: "Share Type", dataIndex: "gufType", render: (value, record, index) => { return ( < Item name = {[index, " gufType "]}> < Input/> </Item > ); }, }, { title: "Change Project", dataIndex: "changeItem", render: (value, record, index) => { return ( < Item name = {[index, " changeItem "]} rules = {[{ required: true }]} > < Input/> </Item > ); }, }, { title: "Price per Share", dataIndex: "perPrice", render: (value, record, index) => { return ( < Item name = {[index, " perPrice "]} rules = {[{ required: true }]} > < InputNumber/> </Item > ); }, }, { title: "Operation", render: (value, record, index) => { return ( < Item > < Button onClick = {() => { remove(index); }} disabled={fields.length <3} > delete </Button > </Item > ); }, }, ]; return ( <> < Table dataSource = {fields} columns = {columns} pagination = {false} rowKey = "key" /> < Button icon = { < CalculatorOutlined/> } onClick={() => { const [type, idx] = data[0].key.split("_"); const splitSeq = +splitForm .getFieldValue("splitData") [fields.length-1].key.split("_")[2] + 1; add({ key: `${type}_${idx}_${splitSeq}`, }); }} > Add to </Button > </> ); }} </List > </Form > </Modal > ); }; Copy code
//mock export const changeTypes = [ { changeType : "addGud" , changeTypeDesc : "add shareholder" }, { changeType : "exitGud" , changeTypeDesc : "exit shareholders" }, { changeType : "changedGud" , changeTypeDesc : "change shareholder" }, { changeType : "unChangedGud" , changeTypeDesc : " Unchanged shareholders" }, ]; export const mock = changeTypes.map( ( parent, i ) => { return { key : parent.changeType, gudName : parent.changeTypeDesc, children : new Array ( 5 ).fill( "" ).map( ( child, j ) => { return { key : ` ${parent.changeType} _ ${j} ` , gudName : `Shareholder ${i} ${j} ` , gudType:`Shareholder type ${i} ${j} ` , gufType : `Share type ${i} ${j} ` , changeItem : `New director` , perPrice : Math .ceil( Math .random() * 30 ), }; }), }; }); Copy code