👨🏻‍💻👩🏻‍💻 Use Ant Design like a Pro!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

268 lines
7.2 KiB

import { PlusOutlined } from '@ant-design/icons';
import { Button, Divider, Input, message, Popconfirm, Table } from 'antd';
import type { FC } from 'react';
import React, { useState } from 'react';
import useStyles from '../style.style';
type TableFormDateType = {
key: string;
workId?: string;
name?: string;
department?: string;
isNew?: boolean;
editable?: boolean;
};
type TableFormProps = {
value?: TableFormDateType[];
onChange?: (value: TableFormDateType[]) => void;
};
const TableForm: FC<TableFormProps> = ({ value, onChange }) => {
const { styles } = useStyles();
const [clickedCancel, setClickedCancel] = useState(false);
const [loading, setLoading] = useState(false);
const [index, setIndex] = useState(0);
const [cacheOriginData, setCacheOriginData] = useState<Record<string, any>>(
{},
);
const [data, setData] = useState(value);
const getRowByKey = (key: string, newData?: TableFormDateType[]) =>
(newData || data)?.filter((item) => item.key === key)[0];
const toggleEditable = (
e: React.MouseEvent | React.KeyboardEvent,
key: string,
) => {
e.preventDefault();
const newData = data?.map((item) => ({
...item,
}));
const target = getRowByKey(key, newData);
if (target) {
// 进入编辑状态时保存原始数据
if (!target.editable) {
cacheOriginData[key] = {
...target,
};
setCacheOriginData(cacheOriginData);
}
target.editable = !target.editable;
setData(newData);
}
};
const newMember = () => {
const newData =
data?.map((item) => ({
...item,
})) || [];
newData.push({
key: `NEW_TEMP_ID_${index}`,
workId: '',
name: '',
department: '',
editable: true,
isNew: true,
});
setIndex(index + 1);
setData(newData);
};
const remove = (key: string) => {
const newData = data?.filter(
(item) => item.key !== key,
) as TableFormDateType[];
setData(newData);
if (onChange) {
onChange(newData);
}
};
const handleFieldChange = (
e: React.ChangeEvent<HTMLInputElement>,
fieldName: keyof TableFormDateType,
key: string,
) => {
const newData = [...(data as TableFormDateType[])];
const target = getRowByKey(key, newData);
if (target?.[fieldName]) {
target[fieldName as 'key'] = e.target.value;
setData(newData);
}
};
const saveRow = (e: React.MouseEvent | React.KeyboardEvent, key: string) => {
e.persist();
setLoading(true);
setTimeout(() => {
if (clickedCancel) {
setClickedCancel(false);
return;
}
const target = getRowByKey(key) || ({} as any);
if (!target.workId || !target.name || !target.department) {
message.error('请填写完整成员信息。');
(e.target as HTMLInputElement).focus();
setLoading(false);
return;
}
delete target.isNew;
toggleEditable(e, key);
if (onChange) {
onChange(data as TableFormDateType[]);
}
setLoading(false);
}, 500);
};
const handleKeyPress = (e: React.KeyboardEvent, key: string) => {
if (e.key === 'Enter') {
saveRow(e, key);
}
};
const cancel = (e: React.MouseEvent, key: string) => {
setClickedCancel(true);
e.preventDefault();
const newData = [...(data as TableFormDateType[])];
// 编辑前的原始数据
let cacheData = [];
cacheData = newData.map((item) => {
if (item.key === key) {
if (cacheOriginData[key]) {
const originItem = {
...item,
...cacheOriginData[key],
editable: false,
};
delete cacheOriginData[key];
setCacheOriginData(cacheOriginData);
return originItem;
}
}
return item;
});
setData(cacheData);
setClickedCancel(false);
};
const columns = [
{
title: '成员姓名',
dataIndex: 'name',
key: 'name',
width: '20%',
render: (text: string, record: TableFormDateType) => {
if (record.editable) {
return (
<Input
value={text}
autoFocus
onChange={(e) => handleFieldChange(e, 'name', record.key)}
onKeyPress={(e) => handleKeyPress(e, record.key)}
placeholder="成员姓名"
/>
);
}
return text;
},
},
{
title: '工号',
dataIndex: 'workId',
key: 'workId',
width: '20%',
render: (text: string, record: TableFormDateType) => {
if (record.editable) {
return (
<Input
value={text}
onChange={(e) => handleFieldChange(e, 'workId', record.key)}
onKeyPress={(e) => handleKeyPress(e, record.key)}
placeholder="工号"
/>
);
}
return text;
},
},
{
title: '所属部门',
dataIndex: 'department',
key: 'department',
width: '40%',
render: (text: string, record: TableFormDateType) => {
if (record.editable) {
return (
<Input
value={text}
onChange={(e) => handleFieldChange(e, 'department', record.key)}
onKeyPress={(e) => handleKeyPress(e, record.key)}
placeholder="所属部门"
/>
);
}
return text;
},
},
{
title: '操作',
key: 'action',
render: (_text: string, record: TableFormDateType) => {
if (!!record.editable && loading) {
return null;
}
if (record.editable) {
if (record.isNew) {
return (
<span>
<a onClick={(e) => saveRow(e, record.key)}></a>
<Divider type="vertical" />
<Popconfirm
title="是否要删除此行?"
onConfirm={() => remove(record.key)}
>
<a></a>
</Popconfirm>
</span>
);
}
return (
<span>
<a onClick={(e) => saveRow(e, record.key)}></a>
<Divider type="vertical" />
<a onClick={(e) => cancel(e, record.key)}></a>
</span>
);
}
return (
<span>
<a onClick={(e) => toggleEditable(e, record.key)}></a>
<Divider type="vertical" />
<Popconfirm
title="是否要删除此行?"
onConfirm={() => remove(record.key)}
>
<a></a>
</Popconfirm>
</span>
);
},
},
];
return (
<>
<Table<TableFormDateType>
loading={loading}
columns={columns}
dataSource={data}
pagination={false}
rowClassName={(record) => (record.editable ? styles.editable : '')}
/>
<Button
style={{
width: '100%',
marginTop: 16,
marginBottom: 8,
}}
type="dashed"
onClick={newMember}
>
<PlusOutlined />
</Button>
</>
);
};
export default TableForm;