Form.list + Table实现可编辑表格,添加,删除,上移下移

import React from 'react';
import { MinusCircleOutlined, PlusOutlined, EllipsisOutlined } from '@ant-design/icons';
import { Button, Dropdown, Form, Input, InputNumber, Menu, Select, Space, Table } from 'antd';
import { uniqueId } from 'lodash'

const mockData = [
    {
        key: '1',
        name: '小红',
        value: 12,
        type: 'Input'
    },
    {
        key: '2',
        name: '小明',
        value: 36,
        type: 'Input'
    }
]
const App: React.FC = () => {
    const [form] = Form.useForm();

    const onFinish = (values: any) => {
        console.log('Received values of form:', values);
    };

    const getInput = (record: { type: string }) => {
        if (record?.type === 'InputNumber') {
            return (
                <InputNumber />
            )
        }
        if (record?.type === 'Select') {
            return (
                <Select allowClear>
                    <Select value={true}></Select>
                    <Select value={false}></Select>
                </Select>
            )
        }
        return (
            <Input placeholder='请输入' allowClear />
        )
    }

    const getColumns = (remove, move) => {
        return [
            {
                title: "名称",
                dataIndex: 'name',
                render(text, field, index) {
                    const record = form.getFieldValue('users')?.[index];
                    const isEdit = record?.isEdit || false;
                    return (
                        <Form.Item required name={[field?.name, 'name']} shouldUpdate={true}>
                            {
                                isEdit ? <Input allowClear placeholder='请输入' /> : record.name
                            }
                        </Form.Item>
                    )
                }
            },
            {
                title: "数值",
                dataIndex: 'value',
                render(text, field, index) {
                    const record = form.getFieldValue('users')?.[index];
                    const isEdit = record?.isEdit || false;
                    return (
                        <Form.Item required name={[field?.name, 'value']} shouldUpdate={true}>
                            {
                                isEdit ? getInput(record) : record?.value
                            }
                        </Form.Item>
                    )
                }
            },
            {
                title: "操作",
                render(text, field, index) {
                    const record = form.getFieldValue('users')?.[index];
                    const isEdit = record?.isEdit || false;
                    const recordList = form.getFieldValue('users')
                    return (
                        <Space>
                            <a onClick={() => remove(field.name)}>删除</a>
                            {
                                !isEdit &&
                                <a onClick={() => {
                                    const newList = recordList?.map((item) => {
                                        if (item?.key === record?.key) {
                                            return { ...item, isEdit: true }
                                        }
                                        return item
                                    })
                                    // const itemIndex = newList?.findIndex((item) => item?.key === record?.key)
                                    // newList[itemIndex] = { ...newList[itemIndex], isEdit: true }
                                    form.setFieldsValue({ ['users']: newList })
                                }}>
                                    编辑
                                </a>
                            }
                            {
                                isEdit &&
                                <a onClick={() => {
                                    const list = [...form.getFieldValue(['users'])];
                                    const itemIndex = list?.findIndex((item) => item?.key === record?.key)
                                    list[itemIndex] = { ...list[itemIndex], isEdit: false }
                                    form.setFieldsValue({ ['users']: list })
                                }}>
                                    保存
                                </a>
                            }
                            {
                                isEdit &&
                                <a onClick={() => {
                                    const list = [...form.getFieldValue(['users'])];
                                    const itemIndex = list?.findIndex((item) => item?.key === record?.key)
                                    list[itemIndex] = { ...list[itemIndex], isEdit: false }
                                    form.setFieldsValue({ ['users']: list })
                                }}>
                                    取消
                                </a>
                            }
                            {/* 上移下移 */}
                            <Dropdown
                                getPopupContainer={(triggerNode) => triggerNode.parentElement}
                                overlay={
                                    <Menu>
                                        <Menu.Item>
                                            <a onClick={() => { if (index > 0) { move(index, index - 1) } }}>上移</a>
                                        </Menu.Item>
                                        <Menu.Item>
                                            <a onClick={() => { move(index, index + 1) }}>下移</a>
                                        </Menu.Item>
                                    </Menu>
                                }
                                trigger={['click']}
                            >
                                <EllipsisOutlined />
                            </Dropdown>
                        </Space>
                    )
                }
            }
        ]
    }
    return (
        <Form
            form={form}
            initialValues={{ users: mockData }}
            onFinish={onFinish}
            style={{ maxWidth: 800 }}
        >
            <Form.List name="users">
                {(fields, { add, remove, move }, { errors }) => (
                    <>
                        <Table
                            dataSource={fields}
                            columns={getColumns(remove, move)}
                            rowKey='key'
                            pagination={false}
                        />

                        <Form.Item>
                            <Button
                                type="dashed"
                                style={{ width: '100%', marginTop: '8px' }}
                                icon={<PlusOutlined />}
                                onClick={() => {
                                    // add('The head item', 0); //加个0 会从顶部添加
                                    // const newKey = uniqueId('tableForm') //添加一个唯一的key
                                    // add({key:newKey,});
                                    add({ isEdit: true })
                                }}
                            >
                                添加一行
                            </Button>
                        </Form.Item>
                    </>
                )}
            </Form.List>
            <Form.Item>
                <Button type="primary" htmlType="submit">
                    提交
                </Button>
            </Form.Item>
        </Form>
    );
};

export default App;

在这里插入图片描述

import React, { useState, useEffect } from 'react'; import { Form, Input, Button } from 'antd'; import { CHI_AZ_NUM_COMMON } from 'common/constants'; import FormFooter from 'common/form-footer'; import { errorModal } from 'common/helper'; import ProtocolCode from './ProtocolCode'; import GoodsList from './GoodsList'; import { createCodeApi, updateCodeApi, agreementDetailApi } from '../service'; const Item = Form.Item; const formItemLayout = { labelCol: { xs: { span: 24 }, sm: { span: 3 } }, wrapperCol: { xs: { span: 24 }, sm: { span: 10 } }, }; const ProtocolAdd = props => { const { history, form, match } = props; const { getFieldDecorator, validateFieldsAndScroll } = form || {}; const { params = {} } = match; const [deleteList, setDeleteList] = useState([]); const [state, setState] = useState({ name: '', code: '', list: [], }); const [test, setCount] = useState(0); const [tableData, setTableData] = useState([]); const { name, code, list } = state; useEffect(() => { (async () => { if (params.id) { const res = await agreementDetailApi({ agreementId: params.id }); const { name, agreementCode, skuDetailList = [] } = res || {}; setState({ name, code: agreementCode, list: skuDetailList.map(i => ({ ...i, name: i.itemName, id: i.skuId, saleStatus: i.status })), }); } })(); }, []); const validatorList = (_, value, callback) => { if (!value || !value?.length) { callback('至少选择一个商品的SKU'); } else { callback(); } }; const handleDelete = ids => { setDeleteList([...new Set([...deleteList, ...ids])]); }; const handleSubmit = () => { validateFieldsAndScroll(async (err, value) => { if (!err) { const { skuIds = [], ...other } = value || {}; if (skuIds.length > 400) { errorModal('最多可添加400个商品SKU'); return; } const id = params.id; const payload = { ...other, skuIds: skuIds?.reduce((result, item) => { result[item.id] = item.saleStatus; return result; }, {}), }; if (id) { payload.id = id; payload.deleteSkuIds = deleteList.reduce((result, item) => { result[item.id] = item.saleStatus; return result; }, {}); } const res = await (id ? updateCodeApi(payload) : createCodeApi(payload)); if (res) { history.push('/protocol/list'); } } }); }; // 上移行 const handleMoveUp = index => { if (index <= 0) return; const newData = [...tableData]; [newData[index], newData[index - 1]] = [newData[index - 1], newData[index]]; setTableData([...newData]); // 修改:返回一个全新数组 }; // 下移行 const handleMoveDown = index => { if (index >= tableData.length - 1) return; const newData = [...tableData]; [newData[index], newData[index + 1]] = [newData[index + 1], newData[index]]; setTableData([...newData]); // 修改:返回一个全新数组 }; // 删除行 const handleDeleteRow = index => { const newData = tableData.filter((_, i) => i !== index); setTableData([...newData]); // 修改:返回一个全新数组 }; // 新增行 const handleAddRow = () => { setCount(test + 1); const newEntry = { id: test, name: '', code: '' }; setTableData([...tableData, newEntry]); }; // 更新表格数据 const handleInputChange = (index, field, value) => { const updatedTableData = [...tableData]; updatedTableData[index][field] = value; setTableData(updatedTableData); // 修复:直接传入更新后的数组 }; // 新增 handleProtocolCodeChange 方法 const handleProtocolCodeChange = (index, value) => { const updatedTableData = [...tableData]; updatedTableData[index].code = value; setTableData(updatedTableData); // 修复:直接传入更新后的数组 }; return ( <Form {...formItemLayout} autoComplete="off"> <h2 className="box-title">配置信息</h2> <Item label="配置名称"> {getFieldDecorator('mock1', { initialValue: name, rules: [ { required: true, message: '请输入数字、汉字、英文、特殊字符,不超过20个字符' }, { pattern: CHI_AZ_NUM_COMMON, message: '请输入数字、汉字、英文、特殊字符,不超过20个字符' }, ], })(<Input placeholder="请输入配置名称" maxLength={20} />)} </Item> <h2 className="box-title">协议信息</h2> <Item label="协议名称"> {getFieldDecorator('name', { initialValue: name, rules: [ { required: true, message: '请输入数字、汉字、英文、特殊字符,不超过20个字符' }, { pattern: CHI_AZ_NUM_COMMON, message: '请输入数字、汉字、英文、特殊字符,不超过20个字符' }, ], })(<Input placeholder="请输入协议名称" maxLength={20} />)} </Item> <Item label="协议code"> {getFieldDecorator('agreementCode', { initialValue: code, rules: [{ required: true, message: '请选择协议code' }], })(<ProtocolCode />)} </Item> <h2 className="box-title">协议信息1</h2> <pre>{JSON.stringify(tableData, null, 2)}</pre> <div className="xieyi" key={`table-${tableData.length}-${Date.now()}`}> <table style={{ width: '100%', borderCollapse: 'collapse' }}> <thead> <tr> <th style={{ border: '1px solid #ddd', padding: '8px' }}>协议名称</th> <th style={{ border: '1px solid #ddd', padding: '8px' }}>协议code</th> <th style={{ border: '1px solid #ddd', padding: '8px' }}>操作栏</th> </tr> </thead> <tbody> {tableData?.map((row, index) => ( <tr key={index}> <td style={{ border: '1px solid #ddd', padding: '8px' }}> {getFieldDecorator(`tableData[${index}].name`, { initialValue: row.name, rules: [ { required: true, message: '请输入数字、汉字、英文、特殊字符,不超过20个字符' }, { pattern: CHI_AZ_NUM_COMMON, message: '请输入数字、汉字、英文、特殊字符,不超过20个字符' }, ], })( <Input placeholder="请输入协议名称" onChange={e => handleInputChange(index, 'name', e.target.value)} maxLength={20} /> )} </td> <td style={{ border: '1px solid #ddd', padding: '8px' }}> {getFieldDecorator(`tableData[${index}].code`, { initialValue: row.code, rules: [{ required: true, message: '请选择协议code' }], })(<ProtocolCode onChange={value => handleProtocolCodeChange(index, value)} />)} </td> <td style={{ border: '1px solid #ddd', padding: '8px' }}> <Button type="primary" onClick={() => handleDeleteRow(index)} style={{ display: index === 0 ? 'none' : 'inline-block' }} > 删除 </Button> <Button type="primary" onClick={() => handleMoveUp(index)} disabled={index === 0} style={{ display: index === 0 ? 'none' : 'inline-block' }} > 上移 </Button> <Button type="primary" onClick={() => handleMoveDown(index)} style={{ display: index === tableData.length - 1 ? 'none' : 'inline-block' }} disabled={index === tableData.length - 1} > 下移 </Button> </td> </tr> ))} </tbody> </table> <Button type="primary" onClick={handleAddRow} style={{ display: tableData.length >= 5 ? 'none' : 'inline-block' }} > 添加 </Button> </div> <h2 className="box-title">商品信息</h2> <Item wrapperCol={{ xs: { span: 24 }, sm: { span: 24 } }}> {getFieldDecorator('skuIds', { initialValue: list, rules: [{ validator: validatorList }], })( <GoodsList tips="最多可添加400个商品SKU" rowKey="id" onDelete={handleDelete} agreementId={params.id} deleteList={deleteList} /> )} </Item> <FormFooter handleCancel={history.goBack} handleSubmit={handleSubmit} autoSubmit={false} /> </Form> ); }; export default Form.create()(ProtocolAdd); 帮我分析一下,当前代码,为什么,对 tabledata表格进行,删除上移下移等操作,数据变了,但是试图没有变化
09-18
import { Form, Select, message, Button, Row, Col, Tooltip } from 'antd'; import { useEffect, useState } from 'react'; import { PlusOutlined, MinusCircleOutlined, ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons'; import DNBModal from '@components/DNBModal'; import { udopMetaTable } from 'api/systemConfig'; import { orderOptions } from '@lib/constants'; import st from './index.module.scss'; export default function EditOrderOptionModal({ visible, setVisible, dataSource, detailInfo, setDetailInfo }) { const { tableId, tableType } = detailInfo; const [form] = Form.useForm(); const [loading, setLoading] = useState(false); useEffect(() => { const orderOption = JSON.parse(detailInfo?.orderOption || '[]'); form.setFieldsValue({ orderOption }); }, [detailInfo?.orderOption]); const handleCancel = () => setVisible(false); const handleSumbit = async () => { try { const values = await form.validateFields(); const orderOption = JSON.stringify(values.orderOption); setLoading(true); await udopMetaTable({ tableId: tableId, tableType, orderOption }); setLoading(false); setVisible(false); setDetailInfo({ ...detailInfo, orderOption }); message.success('保存成功'); } catch (error) { setLoading(false); message.error(error.msg || error.message || '操作失败'); } }; const fieldNameValidator = (value) => { if (!value) return Promise.resolve(); const allValues = form.getFieldValue('orderOption') || []; const duplicateCount = allValues.filter((item) => item && item.fieldName === value).length; if (duplicateCount > 1) { return Promise.reject(new Error('排序字段不能重复')); } return Promise.resolve(); }; const options = dataSource?.filter((item) => item.isSortable); return ( <DNBModal title='修改排序字段' open={visible} maskClosable={false} onCancel={handleCancel} onOk={handleSumbit} confirmLoading={loading} width='50rem' > <Form form={form}> <Form.List name='orderOption'> {(fields, { add, remove, move }) => ( <> {fields.map(({ key, name, ...restField }) => ( <div key={key} className={st.row} align='baseline'> <div className={st.col}> <Form.Item {...restField} name={[name, 'fieldName']} label='排序字段' rules={[ { required: true, message: '请选择排序字段' }, { validator: (_, value) => fieldNameValidator(value), }, ]} > <Select placeholder='请选择排序字段' options={options} fieldNames={{ label: 'fieldNameCamel', value: 'fieldNameCamel' }} allowClear showSearch filterOption={(input, option) => (option?.fieldNameCamel ?? '').toLowerCase().includes(input.toLowerCase()) } style={{ width: '100%' }} /> </Form.Item> </div> <div className={st.col}> <Form.Item {...restField} name={[name, 'orderType']} label='排序方式' rules={[{ required: true, message: '请选择排序方式' }]} > <Select placeholder='请选择排序方式' options={orderOptions} allowClear style={{ width: '100%' }} /> </Form.Item> </div> <div className={st.iconBtns}> <Tooltip title='上移'> <ArrowUpOutlined onClick={() => move(name, name - 1)} className={name === 0 && st.disabled} /> </Tooltip> <Tooltip title='下移'> <ArrowDownOutlined onClick={() => move(name, name + 1)} className={name === fields.length - 1 && st.disabled} /> </Tooltip> <Tooltip title='删除'> <MinusCircleOutlined onClick={() => remove(name)} /> </Tooltip> </div> </div> ))} <Form.Item> <Button type='dashed' onClick={() => add()} block icon={<PlusOutlined />}> 新增 </Button> </Form.Item> </> )} </Form.List> </Form> </DNBModal> ); }你需要把里面的中文都提取出来(注释内的不需要),每一个都作为object的key,对应的value是一个数组,数组第一个元素和key相同,第二个元素是key翻译出来的英文,直接给结果 ,再给这个文件加上import { useTranslation } from 'react-i18next'; const { t, i18n: { language }, } = useTranslation();,每个中文要用t('')包裹起来,直接给结果
最新发布
11-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值