Ant-Design-Pro-Components: EditableProTable、ProTable组件数据联动。

一、组件属性分析:

  1. 使用name绑定到表单上, 虽然提供了value以及onChange但操作数据及表单联动比较麻烦。
  2. 可以使用formItemProps配置该录入组件Form.Item的属性,比如getValueProps,getValueFromEvent等,
    参照antd的Form.Item属性。
  3. 使用fieldProps配置表单内录入组件属性,比如onChange,onBlur等,具体录入组件可用属性参考antd官方文档

在这里插入图片描述

二、案例展示:

1.案例一:

import { EditableProTable } from '@ant-design/pro-components';
import { Button, Form } from 'antd';
import React, { useEffect } from 'react';

export default function index() {
  const [form] = Form.useForm();

  const columns = [
    // 数据展示
    // readonly: true 的render处理级别为 renderFormItem > renderText 不会显示render
    {
      title: '活动名称',
      dataIndex: 'title',
      readonly: true,
      // renderFormItem: () => 'renderFormItem', // 优先处理
      // renderText: () => 'renderText',
      // render: () => 'render', // 不会显示
    },
    // 对象数组类型的数据无法使用readonly: true展示
    // 数据无法转化会抛出异常
    // Error : Objects are not valid as a React child (found: object with keys {name}). If you meant to render a collection of children, use an array instead.
    // 此时可以使用 editable: false,
    {
      title: '活动步骤',
      dataIndex: 'steps',
      editable: false,
      render: (dom, config) => {
        console.log(dom); // 对象数组
        return config.steps?.map((step, i) => <p key={i}>{step.name}</p>);
      },
    },
    // 数据录入
    // input
    {
      title: '活动名称',
      dataIndex: 'title',
      // 必填校验
      formItemProps: {
        rules: [{ required: true, message: '请输入!' }],
      },
    },
    // select
    {
      title: '活动类型',
      dataIndex: 'type',
      valueType: 'select',
      // 选项推荐写法 数据录入组件有options属性的都可以用
      fieldProps: {
        options: [
          { value: 1, label: '类型1' },
          { value: 2, label: '类型2' },
        ],
      },
      // 官网实例写法(不是很推荐 写法复杂且限制字符串数据类型):
      // valueEnum: {
      //   one: { text: '类型1', status: '1' },
      //   two: { text: '类型2', status: '2' },
      //   three: { text: '类型3', status: '3' },
      // },
    },
    // switch
    {
      title: '状态',
      dataIndex: 'state',
      initialValue: 'up',
      valueType: 'switch',
      fieldProps: {
        checkedChildren: '上架',
        unCheckedChildren: '下架',
      },
      // switch绑定boolean值只有true/false 可以使用getValueProps和getValueFromEvent再加工
      // 其他录入组件都同理
      formItemProps: {
        getValueProps: (value) => ({ value: value == 'up' }),
        getValueFromEvent: (value) => (value ? 'up' : 'down'),
      },
    },
    // 联动
    {
      title: '活动描述模板',
      dataIndex: 'descTemp',
      // valueType: 'select',
      fieldProps: (form, config) => ({
        // options: [
        //   { value: 1, label: '模板1' },
        //   { value: 2, label: '模板2' },
        // ],
        onChange: (changeValue) => {
          console.log('switch onchange changeValue =', changeValue);
          // {type, isEditable, rowKey, rowIndex, entity}
          console.log(config);
          // 可以直接拿到数据
          const descTemp = form.getFieldValue(['editableData', config.rowIndex, 'descTemp']);
          // 联动数据
          form.setFieldValue(['editableData', config.rowIndex, 'decs'], '描述模板' + descTemp);
        },
      }),
    },
    {
      title: '描述',
      dataIndex: 'decs',
      readonly: true,
    },
    // 不展示列
    {
      title: '描述',
      hideInTable: true,
      dataIndex: 'decs',
      readonly: true,
    },
    // valueType: 'option'
    // 这里配置非编辑状态的操作
    // 编辑状态的操作 在表格editable属性的actionRender属性配置
    {
      title: '操作',
      key: 'action',
      valueType: 'option',
      align: 'center',
      render: (_, record, index, action) => {
        return [
          <a
            key="eidit"
            onClick={() => {
              action?.startEditable(record.key);
            }}
          >
            编辑
          </a>,
        ];
      },
    },
  ];
  return (
    <Form form={form}>
      <EditableProTable
        recordCreatorProps={{
          record: () => {
            return {
              key: `0${Date.now()}`,
            };
          },
        }}
        name="editableData" // 绑定到表单上方便管理
        columns={columns}
        rowKey="key"
      />
    </Form>
  );
}

2. 案例二:

![在这里插入图片描述](https://img-blog.csdnimg.cn/7cdb9842f3584f758731b4acc8fecbc2.png

点击 EditableProTable的编辑按钮,输入讲师编码失去焦点调取接口填充当前行讲师姓名,如若先输入讲师姓名失去焦点调取接口弹出讲师列表:
在这里插入图片描述

点击某一个列表前单选按钮,点击确定使用该讲师,按钮弹窗关闭,讲师编码赋值成功,点击 EditableProTable组件 保存 按钮即可。
在这里插入图片描述

代码如下:

import React, { useRef, useState, Fragment, useEffect } from 'react';
import { Modal, Button, Table, Form, Collapse, Spin, message, Tooltip } from 'antd';
import { EditableProTable, ProForm, ProTable } from '@ant-design/pro-components';
import { CaretRightOutlined, ExportOutlined } from '@ant-design/icons';
import BasicInfo from '../basicInfo';
import {
  getCourseListByClassCode,
  getTeacherInfoByStaffCode,
  updateClassSchedule,
  courseTeacherExportExcel,
} from '@/services/train/train';
const { Panel } = Collapse;

export default function Teacher({
  current,
  setCurrent,
  handleModalVisible,
  currentRow,
  yesOrNo,
  orgList,
  idtypeArray,
  sexArray,
  teacherTypeArray,
  yesOrNoObj,
}) {
  const [form] = Form.useForm(); // 创建表单
  const [saveLoading, setSaveLoading] = useState(false); // 保存讲师按钮
  const [teacherListVisible, handleTeacherListVisible] = useState(false); // 讲师姓名列表 的弹窗
  const [teacherList, setTeacherList] = useState([]); // 讲师列表
  const [curConfigAndForm, setCurConfigAndForm] = useState({}); // 讲师姓名失去焦点时当前行信息
  const [curTeacherInfo, setTeacherInfo] = useState({}); // 讲师弹窗列表点击确定时讲师个人信息
  const [spinLoading, setSpinLoading] = useState(false); // loading
  const [courseData, setCourseData] = useState([]); // 课表讲师列表数据
  const [editableKeys, setEditableRowKeys] = useState([]); // 课程讲师信息列表编辑
  const [downloadParams, setDownloadParams] = useState(''); //导出参数

  useEffect(() => {
    setSpinLoading(true);
    if (currentRow && currentRow.classCode) {
      setDownloadParams(currentRow.classCode);
      getCourseList(currentRow.classCode);
    } else {
      setSpinLoading(false);
    }
  }, []);

  const getCourseList = (classCode) => {
    getCourseListByClassCode(classCode).then((res) => {
      if (res && res.success && res.data) {
        const { data } = res;
        form.setFieldsValue({
          teacherDetails: data,
        });
        setSpinLoading(false);
      }
    });
    setSpinLoading(false);
  };

  // 导出讲师信息
  const genExtra = () => (
    <Tooltip placement="topLeft" title="点击导出讲师课表信息">
      <Button
        type="default"
        key="export"
        loading={spinLoading}
        onClick={() => {
          courseTeacherExportExcel({
            downloadParams,
            setSpinLoading,
            yesOrNoObj,
          });
        }}
      >
        <ExportOutlined /> 导出数据
      </Button>
    </Tooltip>
  );
  // 保存课表讲师信息
  const handleSubmit = (value) => {
    const { teacherDetails } = value;
    setSaveLoading(true);
    let flag = teacherDetails.every((item, index) => {
      if (!item.staffCode) {
        message.error(`${index + 1}行,	讲师编码或者讲师姓名不能为空!`);
        return false;
      }
      return item.staffCode != null || item.staffCode != '';
    });
    if (flag) {
      updateClassSchedule(teacherDetails).then((res) => {
        if (res && res.success && res?.data?.code == '200') {
          setSaveLoading(false);
          message.success('保存讲师信息成功!');
        } else {
          message.error(res?.data?.message);
        }
        setSaveLoading(false);
      });
    } else {
      setSaveLoading(false);
    }
  };

  // 讲师列表点击选择讲师信息
  const rowSelectOnChange = (selectedRowKeys, selectedRows) => {
    if (selectedRows && selectedRows.length > 0) {
      console.log('selectedRows', selectedRows);
      console.log('curConfigAndForm', curConfigAndForm);
      setTeacherInfo(selectedRows[0]);
    }
  };

  //确定使用该讲师
  const confirmCurTeacher = () => {
    // 联动数据赋值助教姓名
    curConfigAndForm.form.setFieldValue(
      ['teacherDetails', curConfigAndForm.config.rowIndex, 'staffCode'],
      curTeacherInfo.staffCode,
    );
    handleTeacherListVisible(false);
  };

  // 课程列表
  const columns2 = [
    {
      title: '课程名称',
      dataIndex: 'courseName',
      editable: false,
    },
    {
      title: '授课日期',
      dataIndex: 'lectureDate',
      valueType: 'date',
      editable: false,
    },
    {
      title: '课时',
      dataIndex: 'courseHours',
      editable: false,
    },
    {
      title: '开始时间',
      dataIndex: 'beginTime',

      editable: false,
    },
    {
      title: '结束时间',
      dataIndex: 'endTime',
      editable: false,
    },
    {
      title: '是否计入讲师课时',
      dataIndex: 'isTakeIntoHours',
      editable: false,
      valueType: 'select',
      fieldProps: {
        options: yesOrNo,
        fieldNames: {
          // 树属性重命名
          label: 'codeName',
          value: 'code',
        },
      },
    },
    {
      title: '是否支付课时津贴',
      dataIndex: 'isPayAllowance',
      editable: false,
      valueType: 'select',
      fieldProps: {
        options: yesOrNo,
        fieldNames: {
          // 树属性重命名
          label: 'codeName',
          value: 'code',
        },
      },
    },
    {
      title: '讲师编码',
      dataIndex: 'staffCode',
      formItemProps: {
        rules: [
          {
            required: true,
            message: '此项为必填项',
          },
        ],
      },
      fieldProps: (form, config) => ({
        onBlur: (changeValue) => {
          // 可以直接拿到当前行数据
          const staffCode = form.getFieldValue(['teacherDetails', config.rowIndex, 'staffCode']);
          if (staffCode) {
            getTeacherInfoByStaffCode({ staffCode: staffCode }).then((res) => {
              if (res && res.success && res?.data?.code == '200') {
                // 联动数据赋值姓名
                form.setFieldValue(
                  ['teacherDetails', config.rowIndex, 'teacherName'],
                  res?.data?.data[0].name,
                );
              }
            });
          } else {
            form.setFieldValue(['teacherDetails', config.rowIndex, 'teacherName'], '');
          }
        },
      }),
    },
    {
      title: '讲师姓名',
      dataIndex: 'teacherName',
      formItemProps: {
        rules: [
          {
            required: false,
            message: '此项为必填项',
          },
        ],
      },
      fieldProps: (form, config) => ({
        onBlur: (changeValue) => {
          // 可以直接拿到当前行数据
          const teacherName = form.getFieldValue([
            'teacherDetails',
            config.rowIndex,
            'teacherName',
          ]);
          if (teacherName) {
            getTeacherInfoByStaffCode({ name: teacherName }).then((res) => {
              if (res && res.success && res?.data?.code == '200') {
                if (res?.data?.data.length > 0) {
                  res?.data?.data.map((item, index) => {
                    item.listKey = index + 1;
                  });
                }
                setCurConfigAndForm({
                  form,
                  config,
                });
                setTeacherList(res?.data?.data);
                // 联动数据赋值助教姓名
                // form.setFieldValue(
                //   ['teacherDetails', config.rowIndex, 'staffCode'],
                //   res?.data?.data?.name,
                // );
              }
            });
            handleTeacherListVisible(true);
          } else {
            form.setFieldValue(['teacherDetails', config.rowIndex, 'staffCode'], '');
          }
        },
      }),
    },
    {
      title: '操作',
      key: 'action',
      valueType: 'option',
      render: (_, record, index, action) => {
        return [
          <a
            key="editable"
            onClick={() => {
              action?.startEditable(record.seriesNo);
            }}
          >
            编辑
          </a>,
        ];
      },
    },
  ];
  // 讲师列表
  const columns3 = [
    {
      title: '管理机构',
      dataIndex: 'manageCom',
      width: 180,
      valueType: 'select',
      fieldProps: {
        options: orgList,
        fieldNames: {
          label: 'name',
          value: 'comCode',
        },
      },
    },
    {
      title: '营销员编码(工号)',
      dataIndex: 'staffCode',
      width: 150,
    },
    {
      title: '姓名',
      dataIndex: 'name',
      width: 180,
    },
    {
      title: '性别',
      dataIndex: 'sex',
      width: 150,
      valueType: 'select',
      fieldProps: {
        options: sexArray,
        fieldNames: {
          // 树属性重命名
          label: 'codeName',
          value: 'code',
        },
      },
    },
    {
      title: '证件类型',
      dataIndex: 'idNoType',
      width: 150,
      valueType: 'select',
      fieldProps: {
        options: idtypeArray,
        fieldNames: {
          // 树属性重命名
          label: 'codeName',
          value: 'code',
        },
      },
    },
    {
      title: '证件号码',
      dataIndex: 'idNo',
      width: 180,
    },
    {
      title: '讲师类型',
      dataIndex: 'teacherType',
      width: 150,
      valueType: 'select',
      fieldProps: {
        options: teacherTypeArray,
        fieldNames: {
          // 树属性重命名
          label: 'codeName',
          value: 'code',
        },
      },
    },
  ];

  return (
    <Spin spinning={spinLoading}>
      <BasicInfo basicInfo={currentRow} />
      <Collapse
        defaultActiveKey={['12']}
        bordered={false}
        ghost
        collapsible="header"
        expandIcon={({ isActive }) => <CaretRightOutlined rotate={isActive ? 90 : 0} />}
      >
        <Panel
          header="课程讲师信息"
          key="12"
          style={{ fontWeight: 700, width: '90%' }}
          extra={genExtra()}
        >
          <ProForm
            // layout="horizontal"
            form={form}
            style={{ fontWeight: 500 }}
            submitter={{
              // 完全自定义整个区域
              render: (props, doms) => {
                return [
                  <Button
                    type="primary"
                    key="save"
                    loading={saveLoading}
                    onClick={() => {
                      // props.form?.resetFields();
                      props.form?.submit?.();
                    }}
                  >
                    保存讲师信息
                  </Button>,
                ];
              },
            }}
            // initialValues={{ teacherDetails: tableData }}
            onFinish={handleSubmit}
          >
            <ProForm.Item>
              <EditableProTable
                name="teacherDetails"
                columns={columns2}
                recordCreatorProps={{
                  style: {
                    display: 'none',
                  }, // 隐藏添加一行
                }}
                rowKey="seriesNo"
                editable={{
                  type: 'single',
                  actionRender: (row, config, defaultDom) => [defaultDom?.save],
                  editableKeys,
                  onChange: setEditableRowKeys,
                }}
              />
              {/* <EditableProTable
                recordCreatorProps={{
                  record: () => {
                    return {
                      key: `0${Date.now()}`,
                    };
                  },
                }}
                columns={columns2}
                rowKey="seriesNo"
              /> */}
            </ProForm.Item>
          </ProForm>
        </Panel>
      </Collapse>
      <div style={{ position: 'fixed', bottom: '30px' }}>
        <Button
          type="primary"
          key="back2"
          onClick={() => {
            // handleModalVisible(false);
            setCurrent(current - 1);
          }}
          style={{ marginRight: 10 }}
        >
          上一步
        </Button>
        <Button
          type="primary"
          key="next2"
          onClick={() => {
            setCurrent(current + 1);
          }}
        >
          下一步
        </Button>
      </div>

      {teacherListVisible ? (
        <Modal
          title="讲师列表"
          visible={teacherListVisible}
          destroyOnClose
          width="60%"
          onCancel={() => handleTeacherListVisible(false)}
          footer={[
            <Button key="confirm" type="primary" onClick={() => confirmCurTeacher()}>
              确定使用该讲师
            </Button>,
            <Button key="close" onClick={() => handleTeacherListVisible(false)}>
              关闭
            </Button>,
          ]}
          maskClosable={false}
        >
          <ProTable
            style={{ marginLeft: '-20px' }}
            headerTitle=""
            rowKey="listKey"
            options={false}
            search={false}
            pagination={false}
            dataSource={teacherList}
            revalidateOnFocus={false}
            columns={columns3}
            rowSelection={{
              selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT],
              defaultSelectedRowKeys: [],
              type: 'radio',
              onChange: rowSelectOnChange,
            }}
            tableAlertOptionRender={false}
            tableAlertRender={false}
          />
        </Modal>
      ) : null}
    </Spin>
  );
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值