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
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;
|
|
|