import React, { useLayoutEffect, useRef, useState } from 'react'; import { isVoidField, Field } from '@formily/core'; import { useField, observer } from '@formily/react'; import { Popover } from 'antd'; import { EditOutlined, CloseOutlined, MessageOutlined } from '@ant-design/icons'; import { BaseItem, IFormItemProps } from '@formily/antd/lib/form-item'; import { PopoverProps } from 'antd/lib/popover'; import { useClickAway, usePrefixCls } from '@formily/antd/lib/__builtins__'; import cls from 'classnames'; import { get } from 'lodash'; import { Ellipsis } from '@/components'; /** * 默认Inline展示 */ type IPopoverProps = PopoverProps; type ComposedEditable = React.FC> & { Popover?: React.FC>; }; const useParentPattern = () => { const field = useField(); return field?.parent?.pattern || field?.form?.pattern; }; const useEditable = (): [boolean, (payload: boolean) => void] => { const pattern = useParentPattern(); const field = useField(); useLayoutEffect(() => { if (pattern === 'editable') { return field.setPattern('readPretty'); } }, [pattern]); return [ field.pattern === 'editable', (payload: boolean) => { if (pattern !== 'editable') return; field.setPattern(payload ? 'editable' : 'readPretty'); }, ]; }; const useFormItemProps = (): IFormItemProps => { const field = useField(); if (isVoidField(field)) return {}; if (!field) return {}; const takeMessage = () => { if (field.selfErrors.length) return field.selfErrors; if (field.selfWarnings.length) return field.selfWarnings; if (field.selfSuccesses.length) return field.selfSuccesses; }; return { feedbackStatus: field.validateStatus === 'validating' ? 'pending' : field.validateStatus, feedbackText: takeMessage(), extra: field.description, }; }; export const Editable: ComposedEditable = observer((props) => { const [editable, setEditable] = useEditable(); const pattern = useParentPattern(); const itemProps = useFormItemProps(); const field = useField(); const basePrefixCls = usePrefixCls(); const prefixCls = usePrefixCls('formily-editable'); const ref = useRef(); const innerRef = useRef(); const recover = () => { if (ref.current && !field?.errors?.length) { setEditable(false); } }; const renderEditHelper = () => { if (editable) return; return ( {pattern === 'editable' && } {pattern !== 'editable' && } ); }; const renderCloseHelper = () => { if (!editable) return; return ( ); }; useClickAway((e) => { const target = e.target as HTMLElement; if (target?.closest(`.${basePrefixCls}-select-dropdown`)) return; if (target?.closest(`.${basePrefixCls}-picker-dropdown`)) return; if (target?.closest(`.${basePrefixCls}-cascader-menus`)) return; recover(); }, innerRef); const onClick = (e: React.MouseEvent) => { const target = e.target as HTMLElement; const close = innerRef.current?.querySelector(`.${prefixCls}-close-btn`); if (target?.contains(close) || close?.contains(target)) { recover(); } else if (!ref.current) { setTimeout(() => { setEditable(true); setTimeout(() => { innerRef.current?.querySelector('input')?.focus(); }); }); } }; ref.current = editable; return (
{props.children} {renderEditHelper()} {renderCloseHelper()}
); }); Editable.Popover = observer((props) => { const field = useField(); // console.log(field.path.segments) // console.log(field.form.query(field.path).pattern.segments) const pattern = useParentPattern(); let title = props.title || field.title; const [visible, setVisible] = useState(false); const prefixCls = usePrefixCls('formily-editable'); const closePopover = async () => { try { await field.form.validate(`${field.address}.*`); } finally { const errors = field.form.queryFeedbacks({ type: 'error', address: `${field.address}.*`, }); if (errors?.length) return; setVisible(false); } }; const openPopover = () => { setVisible(true); }; if ((field.title === '配置参数' || field.title === '指标数据') && !props.title) { const filterKeys = ['config', 'edit']; const path = field.path.segments.filter((key: any) => !filterKeys.includes(key)); // console.log('EditTable', path, field.form.values); const value = get(field.form.values, path)?.name; title = value || '配置参数'; } const headTitle = () => { return (
{ setVisible(false); }} />
); }; return ( { if (param) { openPopover(); } else { closePopover(); } }} >
{title} {pattern === 'editable' && } {pattern !== 'editable' && }
); }); export default Editable;