一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
本篇其实没啥内容,主要就是对前面一文的完整代码展示,避免前文章内容主次不清
完整代码如下:
ps: 可以直接将代码复制粘贴,安装好依赖即可运行看效果哦~
组件代码
import type { ReactElement, ReactNode } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { CloseOutlined, PlusCircleOutlined } from '@ant-design/icons';
import type { DrawerFormProps, ModalFormProps } from '@ant-design/pro-form';
import { DrawerForm, ModalForm } from '@ant-design/pro-form';
import type { ProTableProps } from '@ant-design/pro-table';
import ProTable from '@ant-design/pro-table';
import { Button, Space } from 'antd';
import { isArray } from 'lodash';
type showTypeEnum = 'button' | 'input';
interface handleValueType<T, S> {
(selectedVal: T): S;
}
/**
* T 表示数据行类型
* S 表示数据行转换成value的类型
*/
export type FormListSelectProps<T = unknown, S = unknown | T> = {
// handleValue?:handleValueType<T,S>
valueDispose?: {
tag: keyof S | string[]; // 显示值的字段
key: keyof S | string[]; // 显示值的key
handleValue: handleValueType<T, S>;
};
title?: string;
multiple?: boolean;
showType?: showTypeEnum;
triggerType?: 'modal' | 'drawer';
triggerForm?: ModalFormProps & DrawerFormProps;
tableProps?: ProTableProps<T, Record<string, unknown>>;
isTableSearch?: boolean;
onChange?: (v: S | S[]) => void;
children?: ReactNode;
value?: S[];
defaultValue?: S[];
};
function FormListSelect<T = Record<string, unknown>, S = T>(props: FormListSelectProps<T, S>) {
const [selectValArray, setSelectValArray] = useState<S[]>([]);
const {
tableProps,
title,
multiple,
isTableSearch,
showType,
onChange,
triggerType,
triggerForm,
valueDispose,
defaultValue,
} = props;
const triggerTypeElementMap = {
modal: ModalForm,
drawer: DrawerForm,
};
const RenderTrigger = triggerTypeElementMap[props.triggerType || 'modal'];
const selectKeyArray = useMemo<(string | number)[]>(() => {
if (!selectValArray) {
return [];
}
const result = selectValArray.map((item: S | T) => {
if (valueDispose) {
if (isArray(valueDispose.key)) {
let res = item;
valueDispose.key.forEach((its) => {
console.log(its, item[its]);
res = res[its];
});
return res;
} else {
return item[valueDispose.key as string];
}
} else {
return item;
}
});
return result;
}, [selectValArray]);
useEffect(() => {
if (props.value) {
setSelectValArray(Array.isArray(props.value) ? props.value : [props.value]);
}
}, [props.value]);
useEffect(() => {
if (defaultValue) {
setSelectValArray(Array.isArray(defaultValue) ? defaultValue : [defaultValue]);
}
}, [defaultValue]);
const fromTiggerRender = (value: (S | T)[], type: showTypeEnum = 'button', tagfiled: keyof S | string[]) => {
if (type === 'button') {
return (
<div>
<Space style={{ display: value.length !== 0 ? 'inline-flex' : 'none' }}>
{value.map((item) => {
const timeStr = new Date().getTime();
if (typeof item !== 'object') {
return (
<Button key={timeStr} size="small" type="dashed">
<Space>
{item}
<CloseOutlined />
</Space>
</Button>
);
} else {
let showTag = item;
if (isArray(tagfiled)) {
tagfiled.forEach((tagf) => {
showTag = showTag[tagf];
});
} else {
showTag = showTag[tagfiled as string];
}
return (
<Button size="small" type="dashed" key={timeStr}>
<Space>
{showTag}
<CloseOutlined />
</Space>
</Button>
);
}
})}
</Space>
<Space style={{ display: value.length == 0 ? 'inline-flex' : 'none' }}>
<Button>
<Space>
{title}
<PlusCircleOutlined />
</Space>
</Button>
</Space>
</div>
);
} else {
return <></>;
}
};
let TiggerProps = {};
if (triggerType === 'modal') {
TiggerProps = Object.assign(triggerForm ? triggerForm : {}, {
modalProps: {
bodyStyle: {
maxHeight: '65vh',
overflow: 'auto',
},
...triggerForm?.modalProps,
},
});
} else {
TiggerProps = triggerForm ? triggerForm : {};
}
const CustomNode = props.children;
return RenderTrigger ? (
<RenderTrigger
title={title}
{...TiggerProps}
onFinish={async () => {
console.log(selectValArray, '触发提交');
if (onChange) onChange(multiple ? selectValArray : selectValArray?.[0]);
return true;
}}
trigger={fromTiggerRender(selectValArray, showType, valueDispose?.tag || [])}
>
{!CustomNode ? (
<ProTable
toolBarRender={false}
{...tableProps}
rowSelection={
multiple
? {
type: 'checkbox',
onSelect(_, __, selectedRows) {
const res = selectedRows.map((item) => {
if (valueDispose) return valueDispose.handleValue(item);
return item as unknown as S;
});
setSelectValArray(() => {
return res;
});
},
selectedRowKeys: selectKeyArray,
}
: {
type: 'radio',
onSelect(_, __, selectedRows) {
const res = selectedRows.map((item) => {
if (valueDispose) return valueDispose.handleValue(item);
return item as unknown as S;
});
setSelectValArray(() => {
return res;
});
},
selectedRowKeys: selectKeyArray,
}
}
pagination={{
defaultCurrent: 1,
defaultPageSize: 10,
showQuickJumper: true,
}}
search={
isTableSearch
? {
collapseRender: false,
collapsed: false,
labelWidth: 'auto',
...tableProps?.search,
}
: false
}
/>
) : (
React.cloneElement(CustomNode as ReactElement, {
onChange(value: T) {
console.log(value, 'afasdfa');
let valueRes: S | S[];
if (valueDispose) {
valueRes = isArray(value)
? value.map((vs: T) => {
return valueDispose.handleValue(vs);
})
: valueDispose.handleValue(value);
} else {
valueRes = value as unknown as S | S[];
}
setSelectValArray(() => {
return isArray(valueRes) ? valueRes : [valueRes];
});
},
value: selectValArray,
})
)}
</RenderTrigger>
) : (
<></>
);
}
FormListSelect.defaultProps = {
title: '标题',
triggerType: 'modal',
showType: 'button',
multiple: false,
isTableSearch: false,
tagLabelField: 'name',
handleValue: (p: unknown) => p,
};
export default FormListSelect;
后记
欢迎大家指出问题并改进