一个自用的表头组件

// @ts-nocheck
import React, { useRef, useState } from 'react';
import PropTypes from 'prop-types';
import { Form } from 'antd';
import { DownOutlined, UpOutlined, QuestionCircleOutlined } from '@ant-design/icons';
import _isEmpty from 'lodash/isEmpty';
import * as Components from './components';
import styles from './index.less?modules';

/**
 * 通用表单
 */
const getRuleMsg = (valueType, label = '', placeholder = '') => {
  if (placeholder) return placeholder;
  if (['请选择', '请填写'].indexOf(label) > -1) {
    return label;
  }
  if (['input', 'textArea', 'inputNumber', 'list'].indexOf(valueType) > -1) {
    return `请填写${label}`;
  }
  if (['rangePicker'].indexOf(valueType) > -1) {
    return void 0;
  }
  return `请选择${label}`;
};

const XParamForm: React.FC = (props) => {
  const { onReady, schema, style, expand, onExpand, ...others } = props;
  const [form] = Form.useForm();
  onReady && onReady(form);

  // 收起展开
  const [isExpand, setIsExpand] = useState(false);
  const [renderExpand, setRenderExpand] = useState(false);
  const paramsContent = useRef();
  setTimeout(() => {
    const paramsContentHeight = paramsContent.current?.clientHeight;
    if (paramsContentHeight && paramsContentHeight > 48 && !renderExpand) {
      setRenderExpand(true);
      setIsExpand(false);
    }
    if (paramsContentHeight && paramsContentHeight <= 48 && renderExpand) {
      setRenderExpand(false);
      setIsExpand(false);
    }
  }, 500);
  // 事件处理
  const eventAction = {};

  // dom渲染
  const domRender = {
    // label
    renderLabel: (label, labelStyle = {}, tooltip) => {
      if (label) {
        return (
          <span className={styles['XParamForm-label']} style={labelStyle}>
            {label}:
          </span>
        );
      }
      return null;
    },
    // 初始化分组配置项
    renderGroupSchema: (item) => {
      const { valueType, label, labelStyle, schema: memberSchema = [], style: memberStyle = {}, ...formItemProps } = item;
      // 属性名称
      // const labelDom = domRender.renderLabel(label, labelStyle);
      return (
        <div
          style={{
            border: '1px solid rgba(121, 121, 121, 1)',
            height: 'auto',
            padding: '15px 30px',
            marginBottom: '24px',
            backgroundColor: 'rgb(253, 253, 253)',
            ...memberStyle,
          }}>
          {domRender.renderSchema(memberSchema)}
        </div>
      );
    },
    // 初始化普通成员配置项
    renderItemSchema: (item) => {
      const formItems = [];
      const { required, rules, valueType, name, label, style = {}, labelStyle, itemProps = {}, tooltip, ...formItemProps } = item;
      // 成员组件
      const NodeComponent = Components[valueType] || Components['input'];
      // 属性名称
      const labelDom = domRender.renderLabel(label, labelStyle, tooltip);
      const _itemProps = { placeholder: getRuleMsg(valueType, label, itemProps?.placeholder), ...itemProps };
      formItems.push(
        <Form.Item
          name={name}
          label={labelDom}
          style={style}
          colon={false}
          rules={_isEmpty(rules) ? [{ required: required, message: `请填写 ${label}!` }] : rules}
          {...formItemProps}>
          <NodeComponent {..._itemProps} />
        </Form.Item>,
      );
      return formItems;
    },
    // 表单项
    renderSchema: (schema) => {
      const formItems = [];
      schema.forEach((item) => {
        if (item.valueType == 'button') return;
        if (item.display && item.display == 'none') return;
        // 如果值类型是一个分组,则分组下的内容在一个面板内,但是数据是平铺的
        if (item.valueType == 'group') {
          formItems.push(domRender.renderGroupSchema(item));
        } else {
          formItems.push(domRender.renderItemSchema(item));
        }
      });
      return (
        <div style={{ display: 'flex', flexWrap: 'wrap', flexDirection: 'row' }} ref={paramsContent}>
          {formItems}
        </div>
      );
    },
    renderOperate: () => {
      console.log('renderOperate', schema);
      const btnItems = [];
      schema.forEach((item) => {
        if (item.valueType == 'button' && (!item.display || item.display !== 'none')) btnItems.push(domRender.renderItemSchema(item));
      });
      return btnItems;
    },
    renderExpand: () => {
      const style = { margin: '0 6px' };
      return (
        renderExpand && (
          <span
            className={styles['expand']}
            onClick={() => {
              setIsExpand(!isExpand);
              onExpand && onExpand(!isExpand);
            }}>
            {isExpand ? ' 收起' : ' 展开'}
            {isExpand ? <UpOutlined style={style} /> : <DownOutlined style={style} />}
          </span>
        )
      );
    },

    renderDropdown: () => {
      const props = {
        valueType: 'dropdown',
        label: '下载',
      };
      const NodeComponent = Components[props.valueType];
      return <NodeComponent />;
    },
  };

  return (
    <div className={styles['XParamForm']} style={style}>
      <Form form={form} {...others}>
        <div className={styles['formItems']} style={{ height: isExpand ? 'fit-content' : 48 }}>
          {domRender.renderSchema(schema)}
        </div>
        <span className={styles['btnItems']}>
          {domRender.renderExpand()}
          {domRender.renderOperate(schema)}
        </span>
      </Form>
    </div>
  );
};

/**
 * 常用的配置
 */
XParamForm.propTypes = {
  style: PropTypes.object,
};

/**
 * 默认的配置
 */
XParamForm.defaultProps = {
  style: {},
  layout: 'inline',
  scrollToFirstError: true, // 提交失败自动滚动到第一个错误字段
  schema: [],
};

export default XParamForm;

.XParamForm {
  width: 100%;
  padding: 0;
  background: #fff;

  &-label {
    font-size: 14px;
  }

  .formItems {
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  .btnItems {
    display: flex;
    flex: 0 0 auto;
    align-items: flex-start;
    justify-content: flex-end;
    // :global {
    //   .ant-form-item {
    //     padding-right: 0 !important;
    //   }
    // }
  }
  .expand {
    z-index: 1;
    flex: 0 0 54px;
    margin-top: 14px;
    cursor: pointer;
  }

  :global {
    .ant-form-inline {
      display: flex;
      flex-wrap: nowrap;
      align-items: flex-start;
      justify-content: space-between;
    }
    .ant-form-inline .ant-form-item {
      margin: 0;
      padding: 8px 24px 8px 0;
    }
    // .ant-btn {
    //   height: 28px !important;
    //   margin: 0 8px;
    //   padding: 0px 18px !important;
    //   font-size: 14px !important;
    // }
    // .ant-select.ant-select-in-form-item {
    //   height: 100%;
    // }
    // .ant-select-show-search.ant-select:not(.ant-select-customize-input) .ant-select-selector {
    //   height: 100%;
    //   overflow-y: auto;
    //   background-color: #fff;
    // }
    // .ant-select-show-search.ant-select:not(.ant-select-customize-input) .ant-select-selector,
    // .ant-select:not(.ant-select-disabled):hover .ant-select-selector,
    // .ant-input-affix-wrapper:not(.ant-input-affix-wrapper-disabled):hover,
    // .ant-input-affix-wrapper:focus,
    // .ant-input-affix-wrapper-focused,
    // .ant-picker-focused {
    //   border-color: #d4d9e5;
    // }
  }
}

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容