function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
var _excluded = ["dragger", "rowKey", "name", "columns", "dataSource", "form", "placeholder", "onSort", "footer"];
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
/**
 * 可编辑table
 * @author 施阳 2021-6-26
 * @description
 * 1、可编辑table通常业务场景中可编辑项需要做必填校验，故结合form实现此功能；
 * 2、组件对外暴露新增、移除、拖拽排序、设置编辑态等方法，满足定制化业务场景；
 * 3、内置拖拽排序table的原因是我们必须调用Form.List暴露的move方法，而不是在上层操作dataSource；
 */
import React, { useState, useEffect, forwardRef, useImperativeHandle, isValidElement, useRef, useContext } from 'react';
import { Input, InputNumber, Form, Table } from 'antd';
import { useConfig } from "../_util/hooks";
import { ConfigContext } from "../config-provider/context";
import DragTable from "../drag-table";
import "./index.less";

// 列表操作项

var FIELD_NAME = 'dataSource'; // form表单域名称
var PREFIX = '$$dynamic_id_'; // 动态生成的id前缀

// 获取需要验证的表单字段
function getRowNamePath(columns, index, prefix) {
  var fieldArr = columns.filter(function (item) {
      var _item$formItemProps;
      return !!((_item$formItemProps = item.formItemProps) !== null && _item$formItemProps !== void 0 && _item$formItemProps.rules);
    }).map(function (item) {
      return item.dataIndex;
    }),
    namePath = [];
  fieldArr.forEach(function (key) {
    return namePath.push([prefix, index, key]);
  });
  return namePath;
}
var EditTable = /*#__PURE__*/forwardRef(function (props, ref) {
  var componentContext = useContext(ConfigContext);
  var uiLocale = componentContext.uiLocale;
  var dragger = props.dragger,
    _props$rowKey = props.rowKey,
    rowKey = _props$rowKey === void 0 ? 'id' : _props$rowKey,
    _props$name = props.name,
    name = _props$name === void 0 ? FIELD_NAME : _props$name,
    columns = props.columns,
    dataSource = props.dataSource,
    outerForm = props.form,
    _props$placeholder = props.placeholder,
    placeholder = _props$placeholder === void 0 ? '-' : _props$placeholder,
    onSort = props.onSort,
    footer = props.footer,
    rest = _objectWithoutProperties(props, _excluded);
  var _Form$useForm = Form.useForm(outerForm),
    _Form$useForm2 = _slicedToArray(_Form$useForm, 1),
    form = _Form$useForm2[0];
  var _useState = useState({}),
    _useState2 = _slicedToArray(_useState, 2),
    editMap = _useState2[0],
    setEditMap = _useState2[1]; // 设置编辑态
  var _useState3 = useState(),
    _useState4 = _slicedToArray(_useState3, 2),
    activeIndex = _useState4[0],
    setActiveIndex = _useState4[1]; // 记录当前操作项索引
  var operateRef = useRef(); // 存储FormList的新增、删除、移动的方法
  var _useState5 = useState(),
    _useState6 = _slicedToArray(_useState5, 2),
    operation = _useState6[0],
    setOperation = _useState6[1]; // 存储FormList的新增、删除、移动的方法
  var cacheRecord = useRef({}); // 缓存编辑前数据

  // 获取列表数据(当前table与form结合，故获取列表数据需要调用form方法拿到最新值)
  var getDataSource = function getDataSource() {
    return form.getFieldsValue()[name] || [];
  };

  // 监听数据源
  useEffect(function () {
    dataSource !== undefined && form.setFieldsValue(_defineProperty({}, name, dataSource));
  }, [dataSource, form, name]);

  // 同步操作方法
  useEffect(function () {
    setOperation(operateRef.current);
  }, []);

  // 设置编辑态
  var setMode = function setMode(key, bool) {
    setEditMap(_objectSpread(_objectSpread({}, editMap), {}, _defineProperty({}, key, bool)));
  };

  // 设置当前操作项索引
  var setIndex = function setIndex(key) {
    var _getDataSource;
    setActiveIndex((_getDataSource = getDataSource()) === null || _getDataSource === void 0 ? void 0 : _getDataSource.findIndex(function (item) {
      var _item$rowKey;
      return ((_item$rowKey = item[rowKey]) !== null && _item$rowKey !== void 0 ? _item$rowKey : item[PREFIX]) === key;
    }));
  };

  // 确认
  var _onConfirm = function _onConfirm(key, index, fn) {
    var _getDataSource2, _getDataSource2$filte;
    setIndex(key);
    var currRecord = ((_getDataSource2 = getDataSource()) === null || _getDataSource2 === void 0 ? void 0 : (_getDataSource2$filte = _getDataSource2.filter(function (item) {
      var _item$rowKey2;
      return ((_item$rowKey2 = item[rowKey]) !== null && _item$rowKey2 !== void 0 ? _item$rowKey2 : item[PREFIX]) === key;
    })) === null || _getDataSource2$filte === void 0 ? void 0 : _getDataSource2$filte[0]) || {}; // 当前操作项单条数据

    // 只校验当前操作项
    form.validateFields(getRowNamePath(columns, index, name)).then(function () {
      if (fn) {
        // 当前操作项为手动添加，则保存时需要去掉临时生成的动态ID
        if (currRecord !== null && currRecord !== void 0 && currRecord[PREFIX]) {
          delete currRecord[PREFIX];
        }
        var res = fn(currRecord, index) || {};

        // 若onConfirm为Promise函数，则resolved状态下需要取消编辑态
        if (res.then) {
          res.then(function () {
            setMode(key, false);
          });
          return;
        }
      }
      setMode(key, false);
    });
  };

  // 取消
  var _onCancel = function _onCancel(key, index) {
    setIndex(key);
    // 临时添加的数据取消时删除
    if (key.toString().includes(PREFIX)) {
      operation === null || operation === void 0 ? void 0 : operation.remove(index);
    } else {
      var currDataSource = getDataSource(); // 当前列表全量数据
      currDataSource.splice(index, 1, cacheRecord.current[key]); // 复原编辑前数据
      form.setFieldsValue(_defineProperty({}, name, currDataSource));
    }
    delete cacheRecord.current[key]; // 删除缓存
    setMode(key, false);
  };

  // 编辑
  var _onEdit = function _onEdit(key, record) {
    setIndex(key);
    cacheRecord.current[key] = record; // 缓存编辑前数据，取消编辑时恢复这里缓存的数据
    setMode(key, true);
  };

  // 删除
  var _onDelete = function _onDelete(key, index) {
    setIndex(key);
    operation === null || operation === void 0 ? void 0 : operation.remove(index);
    setMode(key, false);
  };

  // 添加
  var _onAdd = function _onAdd(value, index) {
    var dynamicId = "".concat(PREFIX).concat(Date.now()); // 动态生成唯一索引
    operation === null || operation === void 0 ? void 0 : operation.add(value || _defineProperty({}, PREFIX, dynamicId), index);
    setIndex(dynamicId);
    setMode(dynamicId, true);
  };

  // 排序
  var _onSort = function _onSort(from, to, move) {
    var allData = getDataSource();
    var _allData$splice = allData.splice(from, 1),
      _allData$splice2 = _slicedToArray(_allData$splice, 1),
      item = _allData$splice2[0]; // 截取移动项
    allData.splice(to, 0, item); // 将移动项插入到新位置
    move(from, to);
    onSort && onSort(allData);
  };

  // 渲染节点
  var renderColumns = function renderColumns(column) {
    return function (text, record, index) {
      var _relRecord$rowKey;
      var fieldType = column.fieldType,
        fieldProps = column.fieldProps,
        dataIndex = column.dataIndex,
        _column$formItemProps = column.formItemProps,
        formItemProps = _column$formItemProps === void 0 ? {} : _column$formItemProps,
        editable = column.editable,
        render = column.render;
      var relRecord = form.getFieldValue([name, index]) || {},
        // 获取单条数据
        relText = relRecord[dataIndex]; // 当前字段值

      var onlyKey = (_relRecord$rowKey = relRecord[rowKey]) !== null && _relRecord$rowKey !== void 0 ? _relRecord$rowKey : relRecord[PREFIX]; // 唯一值(手动添加数据取动态生成的ID)
      var isEdit = editable ? typeof editable === 'boolean' ? editable : editable(relText, relRecord, index) : !!editMap[onlyKey]; // 是否为编辑态

      if (fieldType && render) {
        console.warn('fieldType 与 render属性结合使用时，fieldType属性无效!');
      }

      // 存在render方法，则直接调用(第四个参数将内部参数暴露到上层组件，方便自定义操作按钮)
      if (render) {
        var renderDom = render(relText, relRecord, index, {
          activeIndex: activeIndex,
          editable: isEdit,
          onConfirm: function onConfirm(fn) {
            return _onConfirm(onlyKey, index, fn);
          },
          onCancel: function onCancel() {
            return _onCancel(onlyKey, index);
          },
          onEdit: function onEdit() {
            return _onEdit(onlyKey, relRecord);
          },
          onDelete: function onDelete() {
            return _onDelete(onlyKey, index);
          }
        });
        return /*#__PURE__*/isValidElement(renderDom) ? /*#__PURE__*/React.createElement(Form.Item, _extends({}, formItemProps, {
          className: "in-cell-field",
          name: [index, dataIndex]
        }), renderDom) : renderDom;
      }

      // 编辑态（渲染内置表单组件）
      if (isEdit) {
        var formDom = relText !== null && relText !== void 0 ? relText : placeholder;
        fieldType === 'input' && (formDom = /*#__PURE__*/React.createElement(Input, _extends({
          placeholder: uiLocale.global.inputPlaceholder
        }, fieldProps)));
        fieldType === 'textarea' && (formDom = /*#__PURE__*/React.createElement(Input.TextArea, _extends({
          placeholder: uiLocale.global.inputPlaceholder
        }, fieldProps)));
        fieldType === 'inputNumber' && (formDom = /*#__PURE__*/React.createElement(InputNumber, _extends({
          placeholder: uiLocale.global.inputPlaceholder
        }, fieldProps)));
        return /*#__PURE__*/React.createElement(Form.Item, _extends({}, formItemProps, {
          className: "in-cell-field",
          name: [index, dataIndex]
        }), formDom);
      }
      return relText !== null && relText !== void 0 ? relText : placeholder;
    };
  };

  // 暴露组件内部方法
  var options = _objectSpread(_objectSpread({}, operation), {}, {
    add: _onAdd
  });
  useImperativeHandle(ref, function () {
    return options;
  });

  // table属性
  var tableProps = _objectSpread(_objectSpread({}, rest), {}, {
    columns: columns.map(function (item) {
      return _objectSpread(_objectSpread({}, item), {}, {
        render: renderColumns(item)
      });
    }),
    footer: footer ? function (data) {
      return footer(data, options);
    } : undefined
  });
  var content = /*#__PURE__*/React.createElement(Form.List, {
    name: name
  }, function (fields, _ref2) {
    var add = _ref2.add,
      remove = _ref2.remove,
      move = _ref2.move;
    !operateRef.current && (operateRef.current = {
      add: add,
      remove: remove,
      move: move
    });

    /**
     * 1、调用add、remove、move方法时，实际改变的是fields，故这里的dataSource只能为fields，且rowKey只能为key；
     * 2、内置拖拽排序table是因为这里不能直接操作dataSource而是要调用move方法来控制fields；
     */
    return dragger ? /*#__PURE__*/React.createElement(DragTable, _extends({}, tableProps, {
      rowKey: "key",
      dataSource: fields,
      onSort: function onSort(from, to) {
        return _onSort(from, to, move);
      }
    })) : /*#__PURE__*/React.createElement(Table, _extends({}, tableProps, {
      rowKey: "key",
      dataSource: fields
    }));
  });
  return useConfig( /*#__PURE__*/React.createElement("div", {
    className: "u-editable-table"
  }, outerForm ? content : /*#__PURE__*/React.createElement(Form, {
    form: form,
    autoComplete: "off"
  }, content)));
});
export default EditTable;