import React, { useState, useRef, memo, createElement, useEffect } from "react"; import { ProForm, ProFormDependency, ProFormSelect, ProFormText, ProFormMoney, ProFormTextArea, ProFormDigit, ProFormDigitRange, ProFormDatePicker, ProFormDateTimePicker, ProFormDateRangePicker, ProFormDateTimeRangePicker, ProFormTimePicker, ProFormTreeSelect, ProFormCheckbox, ProFormRadio, ProFormCascader, ProFormSwitch, ProFormRate, ProFormSlider, ProFormUploadDragger, ProFormUploadButton, ProFormList, } from "@ant-design/pro-components"; import ImgCrop from "antd-img-crop"; import { doFetch } from "@/utils/doFetch"; import dayjs from "dayjs"; import * as Antd from "antd"; import { PlusOutlined, DownOutlined, CloseOutlined, RedoOutlined, } from "@ant-design/icons"; import EditTable from "./EditTable"; import EditorItem from "./EditorItem"; const { Image, Form, Upload, Col, Dropdown, Menu, Tabs } = Antd; function upperCase(str) { const newStr = str.slice(0, 1).toUpperCase() + str.slice(1); return newStr; } // tree遍历 function treeForeach(tree, func) { tree.forEach((data) => { func(data); data.children && treeForeach(data.children, func); // 遍历子树 }); } // colProps 默认删格 function Input({ item, colProps }) { let keys = item.key ?? item.dataIndex ?? ""; keys = keys ?? ""; const defaultrule = keys.indexOf("phone") != -1 ? { pattern: /^(((\d{3,4}-)?[0-9]{7,8})|(1(3|4|5|6|7|8|9)\d{9}))$/, message: item.title + "格式不正确", } : keys.indexOf("mail") != -1 ? { pattern: /^[a-z0-9A-Z]+[- | a-z0-9A-Z . _]+@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\.)+[a-z]{2,}$/, message: "邮箱格式不正确", } : {}; return ( <> ); } //pwd function Password({ item, colProps }) { return ( <> ); } //money function Money({ item, colProps }) { return ( <> ); } //textarea function Textarea({ item }) { return ( <> ); } //digit function Digit({ item, colProps }) { return ( <> ); } //digitrange function DigitRange({ item, colProps }) { return ( <> ); } //Date function Date({ item, colProps }) { return ( <> ); } function DateWeek({ item, colProps }) { const weekFormat = "YYYY-MM-DD"; const customWeekStartEndFormat = (value) => `${dayjs(value).startOf("week").format(weekFormat)} ~ ${dayjs(value) .endOf("week") .format(weekFormat)}`; return ( <> ); } //DateMonth function DateMonth({ item, colProps }) { return ( <> ); } //DateQuarter function DateQuarter({ item, colProps }) { const quarterFormat = "YYYY-MM-DD"; const customWeekStartEndFormat = (value) => `${dayjs(value).startOf("quarter").format(quarterFormat)} ~ ${dayjs(value) .endOf("quarter") .format(quarterFormat)}`; return ( <> ); } //DateYear function DateYear({ item, colProps }) { return ( <> ); } //dateTime function DateTime({ item, colProps }) { return ( <> ); } //DateRange function DateRange({ item, colProps }) { return ( <> ); } //dateTimeRange function DateTimeRange({ item, colProps }) { return ( <> ); } //Time function Time({ item, colProps }) { return ( <> ); } //TimeRange function TimeRange({ item, colProps }) { return ( <> ); } function LinkSelect({ item, colProps, formRef, name, curindex }) { let curoption = item.options ?? null, curlinkparams = curoption?.linkParams ?? {}; //获取linkParams下声明的key return ( <> {(params) => { const curkey = item.key ?? item.dataIndex; return ( { return item?.fieldProps?.mode == "multiple" ? !value ? [] : null : null; }} fieldProps={item?.fieldProps} formItemProps={item.formItemProps} name={curkey} colProps={item.colProps ?? colProps} label={item.title} placeholder={`请选择${item.title}`} params={params} mode={item?.mode} request={async (parse) => { let result = {}; for (let key in curlinkparams) { let reversekey = !curlinkparams[key] ? key : curlinkparams[key]; result[reversekey] = parse[key]; } let res = await doFetch({ url: curoption?.path, params: result, }); if (name) { let curvals = formRef?.current?.getFieldValue(name); curvals = curvals.map((it, i) => { if (i == curindex) { it[curkey] = null; } return it; }); formRef?.current?.setFieldsValue({ [name]: curvals }); } else { let curval = formRef?.current?.getFieldValue(curkey), ifclean; if (Array.isArray(curval)) { ifclean = res?.data?.dataList ?.map((it) => it.value) .filter?.((it) => { return curval?.includes(it); }); } else { ifclean = res?.data?.dataList.filter( (it) => it.value == curval )?.[0]?.value; } formRef?.current?.setFieldsValue({ [curkey]: ifclean }); } return res?.data?.dataList ?? []; }} showSearch /> ); }} ); } function NolinkSelect({ item, colProps }) { let options = { options: [], }, curoption = item.options ?? null; if (Array.isArray(curoption)) { options = { options: [...curoption], }; } else if (curoption) { options = { request: async () => { let list = await doFetch({ url: curoption?.path, params: curoption?.params, }); return list.data.dataList; }, }; } return ( <> ); } //Select 高阶组建 function Select(props) { let ifs = props?.item?.options?.linkParams; if (ifs) { return ; } else { return ; } } function LinkTreeSelect({ item, colProps, formRef, name, curindex }) { let prevparse = useRef(); let curoption = item.options ?? null, curlinkparams = curoption?.linkParams ?? {}; //获取linkParams下声明的key return ( <> {(params) => { const curkey = item.key ?? item.dataIndex; return ( { delete parse.keyWords; let result = {}; for (let key in curlinkparams) { let reversekey = !curlinkparams[key] ? key : curlinkparams[key]; result[reversekey] = parse[key]; } let res = await doFetch({ url: curoption?.path, params: result, }); if (prevparse.current !== JSON.stringify(parse)) { if (name) { let curvals = formRef?.current?.getFieldValue(name); curvals = curvals.map((it, i) => { if (i == curindex) { it[curkey] = null; } return it; }); formRef?.current?.setFieldsValue({ [name]: curvals }); } else { let curval = formRef?.current?.getFieldValue(curkey), ifclean; //树结构所有value提取到数组 let allvalue = []; treeForeach(res?.data?.dataList, (node) => { allvalue.push(node.key); }); //过滤存在的value if (Array.isArray(curval)) { ifclean = allvalue?.filter?.((it) => { return curval?.includes(it); }); } else { ifclean = allvalue?.filter?.((it) => it == curval)?.[0]; } formRef?.current?.setFieldsValue({ [curkey]: ifclean }); } } prevparse.current = JSON.stringify(parse); return res?.data?.dataList ?? []; }} /> ); }} ); } function NolinkTreeSelect({ item, colProps }) { let options = { options: [], }, curoption = item.options ?? null; if (Array.isArray(curoption)) { options = { options: [...curoption], }; } else if (curoption) { options = { request: async () => { let list = await doFetch({ url: curoption?.path, params: curoption?.params, }); return list.data.dataList; }, }; } return ( <> ); } //TreeSelect 高阶组建 function TreeSelect(props) { let ifs = props?.item?.options?.linkParams; if (ifs) { return ; } else { return ; } } function CheckboxItem({ item, colProps }) { return ( <> ); } function LinkCheckbox({ item, colProps, formRef, name, curindex }) { let curoption = item.options ?? null, curlinkparams = curoption?.linkParams ?? {}; //获取linkParams下声明的key return ( <> {(params) => { const curkey = item.key ?? item.dataIndex; return ( { let result = {}; for (let key in curlinkparams) { let reversekey = !curlinkparams[key] ? key : curlinkparams[key]; result[reversekey] = parse[key]; } let res = await doFetch({ url: curoption?.path, params: result, }); if (name) { let curvals = formRef?.current?.getFieldValue(name); curvals = curvals.map((it, i) => { if (i == curindex) { it[curkey] = null; } return it; }); formRef?.current?.setFieldsValue({ [name]: curvals }); } else { let curval = formRef?.current?.getFieldValue(curkey), ifclean; if (Array.isArray(curval)) { ifclean = res?.data?.dataList ?.map((it) => it.value) .filter?.((it) => { return curval?.includes(it); }); } else { ifclean = res?.data?.dataList.filter( (it) => it.value == curval )?.[0]?.value; } formRef?.current?.setFieldsValue({ [curkey]: ifclean }); } return res?.data?.dataList ?? []; }} /> ); }} ); } function NolinkCheckbox({ item, colProps }) { let options = { options: [], }, curoption = item.options ?? null; if (Array.isArray(curoption)) { options = { options: [...curoption], }; } else if (curoption) { options = { request: async () => { let list = await doFetch({ url: curoption?.path, params: curoption?.params, }); return list.data.dataList; }, }; } return ( <> ); } //Checkbox 高阶组建 function Checkbox(props) { let ifs = props?.item?.options?.linkParams; if (ifs) { return ; } else { return ; } } function RadioItem({ item, colProps }) { return ( <> ); } function LinkRadio({ item, colProps, formRef, name, curindex }) { let curoption = item.options ?? null, curlinkparams = curoption?.linkParams ?? {}; //获取linkParams下声明的key return ( <> {(params) => { const curkey = item.key ?? item.dataIndex; return ( { let result = {}; for (let key in curlinkparams) { let reversekey = !curlinkparams[key] ? key : curlinkparams[key]; result[reversekey] = parse[key]; } let res = await doFetch({ url: curoption?.path, params: result, }); if (name) { let curvals = formRef?.current?.getFieldValue(name); curvals = curvals.map((it, i) => { if (i == curindex) { it[curkey] = null; } return it; }); formRef?.current?.setFieldsValue({ [name]: curvals }); } else { let curval = formRef?.current?.getFieldValue(curkey), ifclean; if (Array.isArray(curval)) { ifclean = res?.data?.dataList ?.map((it) => it.value) .filter?.((it) => { return curval?.includes(it); }); } else { ifclean = res?.data?.dataList.filter( (it) => it.value == curval )?.[0]?.value; } formRef?.current?.setFieldsValue({ [curkey]: ifclean }); } return res?.data?.dataList ?? []; }} /> ); }} ); } function NolinkRadio({ item, colProps }) { let options = { options: [], }, curoption = item.options ?? null; if (Array.isArray(curoption)) { options = { options: [...curoption], }; } else if (curoption) { options = { request: async () => { let list = await doFetch({ url: curoption?.path, params: curoption?.params, }); return list.data.dataList; }, }; } return ( <> ); } //Radio 高阶组建 function Radio(props) { let ifs = props?.item?.options?.linkParams; if (ifs) { return ; } else { return ; } } function LinkCascader({ item, colProps, formRef, name, curindex }) { let prevparse = useRef(); let curoption = item.options ?? null, curlinkparams = curoption?.linkParams ?? {}; //获取linkParams下声明的key return ( <> {(params) => { const curkey = item.key ?? item.dataIndex; return ( { delete parse.keyWords; let result = {}; for (let key in curlinkparams) { let reversekey = !curlinkparams[key] ? key : curlinkparams[key]; result[reversekey] = parse[key]; } let res = await doFetch({ url: curoption?.path, params: result, }); if (prevparse.current !== JSON.stringify(parse)) { if (name) { let curvals = formRef?.current?.getFieldValue(name); curvals = curvals.map((it, i) => { if (i == curindex) { it[curkey] = null; } return it; }); formRef?.current?.setFieldsValue({ [name]: curvals }); } else { let curval = formRef?.current?.getFieldValue(curkey), ifclean; if (Array.isArray(curval)) { ifclean = res?.data?.dataList ?.map((it) => it.value) .filter?.((it) => { return curval?.includes(it); }); } else { ifclean = res?.data?.dataList.filter( (it) => it.value == curval )?.[0]?.value; } formRef?.current?.setFieldsValue({ [curkey]: ifclean }); } } prevparse.current = JSON.stringify(parse); return res?.data?.dataList ?? []; }} /> ); }} ); } function NolinkCascader({ item, colProps }) { let options = { options: [], }, curoption = item.options ?? null; if (Array.isArray(curoption)) { options = { options: [...curoption], }; } else if (curoption) { options = { request: async () => { let list = await doFetch({ url: curoption?.path, params: curoption?.params, }); return list.data.dataList; }, }; } return ( <> ); } //Cascader 高阶组建 function Cascader(props) { let ifs = props?.item?.options?.linkParams; if (ifs) { return ; } else { return ; } } //switch function Switch({ item, colProps }) { return ( <> ); } //Rate function Rate({ item, colProps }) { return ( <> ); } //Slider function Slider({ item, colProps }) { return ( <> ); } //uploadbtn function UploadBtn({ item, colProps }) { return ( <> { let url = ""; if (file.response) { url = file.response.data.dataList[0].url; } else if (file.url) { url = file.url; } else { url = file.thumbUrl; } window.open(url); }, }} transform={(value) => { const key = item.key ?? item.dataIndex; const transvalue = value?.map((it) => { if (it.response) { return it?.response?.data?.dataList[0]; } else { return it; } }); return { [key]: transvalue, }; }} formItemProps={item.formItemProps} name={item.key ?? item.dataIndex} colProps={item.colProps ?? colProps} label={item.title} title={`上传${item.title}`} /> ); } function UploadImg({ value, onChange, fieldProps }) { const [image, setImage] = useState({}); let token = localStorage.getItem("TOKENES"); function beforeUpload(file) { const isJpgOrPng = file.type === "image/jpg" || file.type === "image/jpeg" || file.type === "image/png"; if (!isJpgOrPng) { message.error("只能上传.jpg/.jpeg/.png图片!"); return; } return true; } // maxCount 最大数量 const defaultconfig = { name: "file", action: REACT_APP_URL + "/file/upload", accept: ".jpg,.png,.jpeg", listType: "picture-card", beforeUpload: beforeUpload, defaultFileList: value, headers: { token }, onChange(info) { let { file: { status }, fileList, } = info; if (status == "error") { message.error(`${info.file.name} 上传失败`); } else if (status === "done") { const transfile = fileList.map((it) => { return it?.response ? it?.response.data.dataList[0] : it; }); onChange(transfile); } }, onRemove(file) { let uid = file?.response?.data?.dataList[0]?.uid ?? file?.uid; let newvalue = value.filter((it) => it.uid != uid); onChange(newvalue); }, onPreview(file) { let url = ""; if (file.response) { url = file.response.data.dataList[0].url; } else if (file.url) { url = file.url; } else { url = file.thumbUrl; } setImage({ url, visible: true, }); }, }; const uploadButton = (
上传图片
); return ( <> { if (image?.visible) { setImage((s) => ({ ...s, visible: false, })); } }, }} /> {fieldProps?.crop ? ( {!value ? uploadButton : value?.length < fieldProps.limit ? uploadButton : null} ) : ( {!value ? uploadButton : value?.length < fieldProps.limit ? uploadButton : null} )} ); } //upload Image function UploadImage({ item, colProps }) { let col = item.colProps ?? colProps; return ( ); } // uploadDragger function UploadDragger({ item, colProps }) { return ( <> { let url = ""; if (file.response) { url = file.response.data.dataList[0].url; } else if (file.url) { url = file.url; } else { url = file.thumbUrl; } window.open(url); }, }} transform={(value) => { const key = item.key ?? item.dataIndex; const transvalue = value?.map((it) => { if (it.response) { return it?.response?.data?.dataList[0]; } else { return it; } }); return { [key]: transvalue, }; }} formItemProps={item.formItemProps} name={item.key ?? item.dataIndex} colProps={item.colProps ?? colProps} label={item.title} /> ); } // editor function Editor({ item, colProps, formRef }) { let col = item.colProps ?? colProps; let curkey = item.key ?? item.dataIndex; return ( { // return BraftEditor.createEditorState(value); // }} transform={(value) => { return { [curkey]: value.toHTML(), }; }} name={curkey} label={item.title} {...item.formItemProps} > ); } function FormList({ item, colProps, formRef }) { let col = item.colProps ?? colProps; let fields = item.columns; return ( { return {doms}; }} alwaysShowItemLabel={false} > {(f, index, action) => { return ( ); }} ); } function TableSelect({ item, value, onChange, params = {} }) { const rowKey = item?.rowKey ?? "id"; const [chooses, setchooses] = useState([]); //mark 标记 const [activetab, setactivetab] = useState(1); const actionRef = useRef(); const menu = (selectedRows) => ( 0 ? selectedRows.map((it) => ({ key: it[rowKey], label: (
{ e.stopPropagation(); let key = it[rowKey]; setchooses((s) => { let news = [...s]; if (s.includes(key)) { news = news.filter((it) => { return it != key; }); } else { news.push(key); } return news; }); }} > {it[item.rowName]} { e.stopPropagation(); let newvalue = value.filter( (its) => its[rowKey] != it[rowKey] ); onChange(newvalue); setchooses((s) => { let news = [...s]; news = news.filter((its) => { return its != it[rowKey]; }); return news; }); }} />
), })) : [ { key: -1, label: "请先选择", }, ] } /> ); useEffect(() => { onChange([]); actionRef?.current?.reload?.(); }, [params]); const Todo = ( { if (chooses.includes(record[rowKey])) { return "lightblue"; } else { return ""; } }} rowSelection={{ ...item.rowSelection, columnWidth: 44, preserveSelectedRowKeys: true, selectedRowKeys: value && value?.map((it) => it[rowKey]), onChange: (selectedKeys, selectedRows) => { const rowkeylist = value ? value?.map((it) => it[rowKey]) : []; const newValue = selectedRows?.map((its) => { if (rowkeylist.includes(its[rowKey])) { return value.filter((it) => it[rowKey] == its[rowKey])[0]; } else { return its; } }); onChange(newValue); }, }} editable={{ onValuesChange: (record) => { const newValue = value?.map((its) => { if (its[rowKey] == record[rowKey]) { return record; } else { return its; } }); onChange(newValue); }, }} /> ); const Done = ( { if (chooses.includes(record[rowKey])) { return "lightblue"; } else { return ""; } }} rowSelection={{ ...item.rowSelection, columnWidth: 44, preserveSelectedRowKeys: true, selectedRowKeys: value && value?.map((it) => it[rowKey]), onChange: (selectedKeys, selectedRows) => { const rowkeylist = value ? value?.map((it) => it[rowKey]) : []; const newValue = selectedRows?.map((its) => { if (rowkeylist.includes(its[rowKey])) { return value.filter((it) => it[rowKey] == its[rowKey])[0]; } else { return its; } }); onChange(newValue); }, }} editable={{ onValuesChange: (record) => { const newValue = value?.map((its) => { if (its[rowKey] == record[rowKey]) { return record; } else { return its; } }); onChange(newValue); }, }} /> ); return (
已选择{value?.length ?? 0}项
{ onChange([]); setchooses([]); }} > 清空
} onChange={setactivetab} items={[ { label: "数据选择", key: 1, children: activetab == 1 && Todo }, { label: `选择结果${value?.length ?? 0}项`, key: 2, children: activetab == 2 && Done, }, ]} /> ); } function LinkSelectList({ item, colProps }) { let col = item.colProps ?? colProps; let curlinkparams = item?.linkParams ?? {}; //获取linkParams下声明的key return ( {(params) => { const curkey = item.key ?? item.dataIndex; let result = {}; for (let key in curlinkparams) { let reversekey = !curlinkparams[key] ? key : curlinkparams[key]; result[reversekey] = params[key]; } return ( ); }} ); } function NolinkSelectList({ item, colProps }) { let col = item.colProps ?? colProps; let curkey = item.key ?? item.dataIndex; //获取key return ( ); } function FormSelectList(props) { let ifs = props?.item?.linkParams; if (ifs) { return ; } else { return ; } } const FormItems = { Input, Password, Money, Textarea, Digit, DigitRange, Date, Time, DateTime, DateWeek, DateMonth, DateQuarter, DateYear, DateRange, TimeRange, DateTimeRange, Select, TreeSelect, Checkbox, Radio, Switch, Cascader, Rate, Slider, UploadBtn, UploadImage, UploadDragger, Editor, FormList, FormSelectList, CheckboxItem, RadioItem, }; let FormRender = memo(({ fields = [], name, curindex, formRef }) => { return ( <> {fields .filter((it) => it.hideInForm !== true) .map((item) => { let key = item?.valueType ? upperCase(item?.valueType) : "Input"; let { hideInForm } = item; if (hideInForm && Object.keys(hideInForm)) { return ( {(params) => { let ifs = true; let res = Object.keys(hideInForm).map((its) => { if (Array.isArray(hideInForm[its])) { return !hideInForm[its].includes(params[its]); } else { let vals = hideInForm[its].reverse; //取反 即不存在当前数组中的 return vals.indexOf(params[its]) != -1; } }); ifs = res.includes(false); if (ifs) { return ( {curindex == 0 ? (

!{" "} 需满足条件才可以填写{item.title}

) : (

!{" "} 需满足条件才可以填写{item.title}

)} ); } else { return ( <> {createElement(FormItems[key], { item: item, colProps: item.colProps, key: item.dataIndex, name: name, formRef, curindex, })} ); } }}
); } else { return ( <> {createElement(FormItems[key], { item: item, colProps: item.colProps, key: item.dataIndex, name: name, formRef, curindex, })} ); } })} ); }); export default { Input, Password, Money, Textarea, Digit, DigitRange, Date, Time, DateTime, DateWeek, DateMonth, DateQuarter, DateYear, DateRange, TimeRange, DateTimeRange, Select, TreeSelect, Checkbox, Radio, Switch, Cascader, Rate, Slider, UploadBtn, UploadImage, UploadDragger, Editor, FormList, FormSelectList, CheckboxItem, RadioItem, };