UNPKG

cw-form-render-mobile

Version:

通过 JSON Schema 生成标准 Form,常用于自定义搭建配置界面生成

593 lines (592 loc) 25.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _form = _interopRequireDefault(require("antd-mobile/es/components/form")); var _tslib = require("tslib"); var _react = require("react"); var _lodashEs = require("lodash-es"); var _formCoreUtils = require("cw-form-render/es/models/formCoreUtils"); var _bindValues = require("cw-form-render/es/models/bindValues"); var _flattenSchema = require("cw-form-render/es/models/flattenSchema"); var _filterValuesUndefined = _interopRequireDefault(require("cw-form-render/es/models/filterValuesUndefined")); var _filterValuesHidden = _interopRequireDefault(require("cw-form-render/es/models/filterValuesHidden")); var _utils = require("../utils"); var _constants = require("../constants"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _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(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } var updateSchemaByPath = function updateSchemaByPath(_path, _newSchema, formSchema) { var path = (0, _formCoreUtils.getSchemaFullPath)(_path, formSchema); var currSchema = (0, _utils._get)(formSchema, path, {}); var newSchema = (0, _utils.isFunction)(_newSchema) ? _newSchema(currSchema) : _newSchema; var result = Object.assign(Object.assign({}, currSchema), newSchema); if (newSchema.props) { result.props = Object.assign(Object.assign({}, currSchema === null || currSchema === void 0 ? void 0 : currSchema.props), newSchema.props); } (0, _utils._set)(formSchema, path, result); }; var getFieldName = function getFieldName(_path) { if (!_path) { return undefined; } if (typeof _path === 'boolean') { return _path; } var result = []; if ((0, _utils.isArray)(_path)) { result = _path.map(function (item) { return item.split('.').map(function (ite) { if (!isNaN(Number(ite))) { return ite * 1; } return ite; }); }); } result = _path.split('.').map(function (item) { if (!isNaN(Number(item))) { return item * 1; } return item; }); result = result.map(function (item) { if (typeof item === 'string' && (item === null || item === void 0 ? void 0 : item.indexOf('[')) === 0 && (item === null || item === void 0 ? void 0 : item.indexOf(']')) === (item === null || item === void 0 ? void 0 : item.length) - 1) { return Number(item.substring(1, item.length - 1)); } return item; }); return result; }; var useForm = function useForm() { var _Form$useForm = _form.default.useForm(), _Form$useForm2 = _slicedToArray(_Form$useForm, 1), form = _Form$useForm2[0]; var flattenSchemaRef = (0, _react.useRef)({}); var storeRef = (0, _react.useRef)(null); var schemaRef = (0, _react.useRef)({}); var fieldRefs = (0, _react.useRef)({}); var getFieldError = form.getFieldError, getFieldsError = form.getFieldsError, setFields = form.setFields, isFieldsTouched = form.isFieldsTouched, isFieldTouched = form.isFieldTouched, isFieldValidating = form.isFieldValidating, resetFields = form.resetFields, validateFields = form.validateFields, otherForm = (0, _tslib.__rest)(form, ["getFieldError", "getFieldsError", "setFields", "isFieldsTouched", "isFieldTouched", "isFieldValidating", "resetFields", "validateFields"]); var xform = otherForm; var setStoreData = function setStoreData(data) { var setState = storeRef.current.setState; if (!setState) { setTimeout(function () { setState({ schema: schemaRef.current, flattenSchema: flattenSchemaRef.current }); }, 0); } setState(data); }; var handleSchemaUpdate = function handleSchemaUpdate(newSchema) { // form.__schema = Object.freeze(newSchema); flattenSchemaRef.current = (0, _flattenSchema.flattenSchema)(newSchema) || {}; schemaRef.current = newSchema; setStoreData({ schema: newSchema, flattenSchema: flattenSchemaRef.current }); }; xform.setSchema = function (obj) { var cover = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; if (!(0, _utils.isObject)(obj)) { return; } if (cover) { handleSchemaUpdate(obj); return; } var schema = (0, _lodashEs.cloneDeep)(schemaRef.current); Object.keys(obj || {}).forEach(function (path) { updateSchemaByPath(path, obj[path], schema); }); handleSchemaUpdate(schema); }; // 设置某个字段的协议 xform.setSchemaByPath = function (_path, _newSchema) { // diff 判断是否需要更新,存在函数跳过 if (!(0, _utils.hasFuncProperty)(_newSchema) && (0, _lodashEs.isMatch)(_newSchema, xform.getSchemaByPath(_path))) { return; } var schema = (0, _lodashEs.cloneDeep)(schemaRef.current); updateSchemaByPath(_path, _newSchema, schema); handleSchemaUpdate(schema); }; // 通过字段名设置 schema(从 flattenSchema 中查找对应路径) xform.setSchemaByName = function (name, _newSchema) { var _a; if (typeof name !== 'string') { console.warn('请输入正确的字段名'); return; } var flattenItem = (_a = flattenSchemaRef.current) === null || _a === void 0 ? void 0 : _a[name]; if (!flattenItem) { console.warn("\u672A\u627E\u5230\u5B57\u6BB5\u540D\u4E3A ".concat(name, " \u7684 schema")); return; } // 将 name 转换为路径,去掉开头的 # 和 [] var path = name === '#' ? '' : name.replace(/\[\]/g, ''); if (!path) { console.warn('根节点不支持通过 setSchemaByName 修改'); return; } xform.setSchemaByPath(path, _newSchema); }; // form.setSchemaByFullPath = (path: string, newSchema: any) => { // const schema = _cloneDeep(schemaRef.current); // const currSchema = _get(schema, path, {}); // const result = _mergeWith(currSchema, newSchema, (objValue, srcValue, key) => { // return srcValue; // }); // _set(schema, path, result); // handleSchemaUpdate(schema); // } // 将扁平数据转换为嵌套结构(与 filterVoidContainers 相反的操作) var unflattenValues = function unflattenValues(flatValues, flatten) { if (!flatten || !flatValues || !(0, _utils.isObject)(flatValues)) { return flatValues; } // 找出所有布局容器字段 var containerPaths = Object.keys(flatten).filter(function (key) { var _a; var schema = (_a = flatten[key]) === null || _a === void 0 ? void 0 : _a.schema; return (0, _constants.isLayoutContainer)(schema); }).sort(function (a, b) { // 按路径深度排序,从浅到深处理 var depthA = (a.match(/\./g) || []).length; var depthB = (b.match(/\./g) || []).length; return depthA - depthB; }); if (containerPaths.length === 0) { return flatValues; } var result = {}; var processedFields = new Set(); // 为每个容器路径构建嵌套结构 containerPaths.forEach(function (containerPath) { var _a; // 移除 [] 标记和开头的 # var cleanPath = containerPath.replace(/\[\]/g, '').replace(/^#\.?/, ''); if (!cleanPath) return; var pathParts = cleanPath.split('.'); // 获取该容器下的所有子字段 var containerChildren = ((_a = flatten[containerPath]) === null || _a === void 0 ? void 0 : _a.children) || []; if (containerChildren.length === 0) return; // 获取或创建容器对象的路径 var target = result; for (var i = 0; i < pathParts.length; i++) { var part = pathParts[i]; if (i === pathParts.length - 1) { // 最后一个部分是容器本身 if (!target[part]) { target[part] = {}; } target = target[part]; } else { // 中间路径 if (!target[part]) { target[part] = {}; } target = target[part]; } } // 将扁平数据中属于该容器的字段移动到容器内 containerChildren.forEach(function (childPath) { var childCleanPath = childPath.replace(/\[\]/g, '').replace(/^#\.?/, ''); var childKey = childCleanPath.split('.').pop(); if (!childKey) return; // 如果该字段在扁平数据中存在,移动到容器内 if ((0, _utils._has)(flatValues, childKey)) { target[childKey] = (0, _utils._get)(flatValues, childKey); processedFields.add(childKey); } }); }); // 将未处理的字段直接复制到结果中(可能是非容器内的字段) Object.keys(flatValues).forEach(function (key) { if (!processedFields.has(key)) { result[key] = flatValues[key]; } }); return result; }; // 设置表单数据 xform.setValues = function (_values) { var _a; var values = _values; // 如果启用了 flattenData,自动将扁平数据转换为嵌套结构 var _ref = ((_a = storeRef.current) === null || _a === void 0 ? void 0 : _a.getState()) || {}, flattenData = _ref.flattenData; if (flattenData) { values = unflattenValues(values, flattenSchemaRef.current); } values = (0, _bindValues.parseBindToValues)(values, flattenSchemaRef.current); form.setFieldsValue(values); }; // 设置扁平化的表单数据(显式转换,不依赖 flattenData 配置) xform.setFlatValues = function (_values) { // 先将扁平数据转换为嵌套结构 var nestedValues = unflattenValues(_values, flattenSchemaRef.current); // 然后调用原生的 setFieldsValue(跳过 flattenData 判断) var values = (0, _bindValues.parseBindToValues)(nestedValues, flattenSchemaRef.current); form.setFieldsValue(values); }; // 过滤掉 void 类型容器的数据层级(将子字段提升到父级) var filterVoidContainers = function filterVoidContainers(values, flatten) { var voidPaths = Object.keys(flatten).filter(function (key) { var _a; var schema = (_a = flatten[key]) === null || _a === void 0 ? void 0 : _a.schema; return (0, _constants.isLayoutContainer)(schema); }); if (voidPaths.length === 0) { return values; } var result = (0, _lodashEs.cloneDeep)(values); // 按路径深度排序,从深到浅处理 voidPaths.sort(function (a, b) { var depthA = (a.match(/\./g) || []).length; var depthB = (b.match(/\./g) || []).length; return depthB - depthA; }); voidPaths.forEach(function (voidPath) { // 移除 [] 标记和开头的 # var cleanPath = voidPath.replace(/\[\]/g, '').replace(/^#\.?/, ''); if (!cleanPath) return; var pathParts = cleanPath.split('.'); var voidKey = pathParts[pathParts.length - 1]; var parentPath = pathParts.slice(0, -1); // 获取父级对象 var parent = result; var _iterator = _createForOfIteratorHelper(parentPath), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var part = _step.value; if (!parent[part]) return; parent = parent[part]; } // 如果 void 容器存在且有值 } catch (err) { _iterator.e(err); } finally { _iterator.f(); } if (parent[voidKey] && (0, _utils.isObject)(parent[voidKey])) { var voidContainer = parent[voidKey]; // 将 void 容器的子字段提升到父级 Object.keys(voidContainer).forEach(function (childKey) { parent[childKey] = voidContainer[childKey]; }); // 删除 void 容器本身 delete parent[voidKey]; } }); return result; }; // 获取表单数据 xform.getValues = function (nameList, filterFunc) { var _a; var values = (0, _lodashEs.cloneDeep)(form.getFieldsValue(getFieldName(nameList), filterFunc)); var _ref2 = ((_a = storeRef.current) === null || _a === void 0 ? void 0 : _a.getState()) || {}, removeHiddenData = _ref2.removeHiddenData, flattenData = _ref2.flattenData; // 如果启用了 flattenData,需要先扁平化,让 hidden 表达式能正确访问字段值 if (flattenData) { values = (0, _bindValues.parseValuesToBind)(values, flattenSchemaRef.current); values = filterVoidContainers(values, flattenSchemaRef.current); // 然后再过滤隐藏字段(此时 formData 已经是扁平结构) if (removeHiddenData) { values = (0, _filterValuesHidden.default)(values, flattenSchemaRef.current); } values = (0, _filterValuesUndefined.default)(values); } else { // 不扁平化时,按原有顺序处理 if (removeHiddenData) { values = (0, _filterValuesHidden.default)(values, flattenSchemaRef.current); } values = (0, _filterValuesUndefined.default)(values); values = (0, _bindValues.parseValuesToBind)(values, flattenSchemaRef.current); } return values; }; // 获取扁平化的表单数据(自动移除 void 类型容器的层级,如 collapse、group 等布局容器) xform.getFlatValues = function (nameList, filterFunc, notFilterUndefined) { var _a; var values = (0, _lodashEs.cloneDeep)(form.getFieldsValue(getFieldName(nameList), filterFunc)); var _ref3 = ((_a = storeRef.current) === null || _a === void 0 ? void 0 : _a.getState()) || {}, removeHiddenData = _ref3.removeHiddenData; // 先扁平化 values = (0, _bindValues.parseValuesToBind)(values, flattenSchemaRef.current); values = filterVoidContainers(values, flattenSchemaRef.current); // 然后再过滤隐藏字段(此时 formData 已经是扁平结构,hidden 表达式能正确访问字段值) if (removeHiddenData) { values = (0, _filterValuesHidden.default)(values, flattenSchemaRef.current); } if (!notFilterUndefined) { values = (0, _filterValuesUndefined.default)(values); } return values; }; xform.setValueByPath = function (path, value) { var _a; var _ref4 = ((_a = storeRef.current) === null || _a === void 0 ? void 0 : _a.getState()) || {}, flattenData = _ref4.flattenData; // 如果启用了 flattenData,且路径不包含 '.',尝试在 flattenSchema 中查找完整路径 if (flattenData && typeof path === 'string' && !path.includes('.')) { // 在 flattenSchema 中查找匹配的字段 for (var key in flattenSchemaRef.current) { var cleanKey = key.replace(/\[\]/g, '').replace(/^#\.?/, ''); // 如果字段路径以 path 结尾(如 SoftwareLicense.state_dict 以 state_dict 结尾) if (cleanKey === path || cleanKey.endsWith('.' + path)) { var _name = getFieldName(cleanKey); form.setFieldValue(_name, value); return; } } } // 否则按原有逻辑处理 var name = getFieldName(path); form.setFieldValue(name, value); }; // 通过字段名设置值(从 flattenSchema 中查找对应路径) xform.setValueByName = function (name, value) { var _a, _b; if (typeof name !== 'string') { console.warn('请输入正确的字段名'); return; } // 尝试直接从 flattenSchema 中查找(带 # 前缀) var flattenItem = ((_a = flattenSchemaRef.current) === null || _a === void 0 ? void 0 : _a[name]) || ((_b = flattenSchemaRef.current) === null || _b === void 0 ? void 0 : _b["#.".concat(name)]); // 如果没找到,尝试在所有键中查找匹配的 if (!flattenItem) { for (var key in flattenSchemaRef.current) { var cleanKey = key.replace(/\[\]/g, '').replace(/^#\.?/, ''); if (cleanKey === name || cleanKey.endsWith('.' + name)) { flattenItem = flattenSchemaRef.current[key]; name = cleanKey; break; } } } if (!flattenItem) { console.warn("\u672A\u627E\u5230\u5B57\u6BB5\u540D\u4E3A ".concat(name, " \u7684 schema")); return; } // 将 name 转换为路径,去掉 # 和 [] var path = name.replace(/^#\.?/, '').replace(/\[\]/g, ''); if (!path) { console.warn('根节点不支持通过 setValueByName 修改'); return; } xform.setValueByPath(path, value); }; xform.getValueByPath = function (path) { var _a; var _ref5 = ((_a = storeRef.current) === null || _a === void 0 ? void 0 : _a.getState()) || {}, flattenData = _ref5.flattenData; // 如果启用了 flattenData,且路径不包含 '.',尝试在 flattenSchema 中查找完整路径 if (flattenData && typeof path === 'string' && !path.includes('.')) { // 在 flattenSchema 中查找匹配的字段 for (var key in flattenSchemaRef.current) { var cleanKey = key.replace(/\[\]/g, '').replace(/^#\.?/, ''); // 如果字段路径以 path 结尾 if (cleanKey === path || cleanKey.endsWith('.' + path)) { var _name2 = getFieldName(cleanKey); return form.getFieldValue(_name2); } } } // 否则按原有逻辑处理 var name = getFieldName(path); return form.getFieldValue(name); }; // 通过字段名获取值(从 flattenSchema 中查找对应路径) xform.getValueByName = function (name) { var _a, _b; if (typeof name !== 'string') { console.warn('请输入正确的字段名'); return; } // 尝试直接从 flattenSchema 中查找(带 # 前缀) var flattenItem = ((_a = flattenSchemaRef.current) === null || _a === void 0 ? void 0 : _a[name]) || ((_b = flattenSchemaRef.current) === null || _b === void 0 ? void 0 : _b["#.".concat(name)]); // 如果没找到,尝试在所有键中查找匹配的 if (!flattenItem) { for (var key in flattenSchemaRef.current) { var cleanKey = key.replace(/\[\]/g, '').replace(/^#\.?/, ''); if (cleanKey === name || cleanKey.endsWith('.' + name)) { flattenItem = flattenSchemaRef.current[key]; name = cleanKey; break; } } } if (!flattenItem) { console.warn("\u672A\u627E\u5230\u5B57\u6BB5\u540D\u4E3A ".concat(name, " \u7684 schema")); return; } // 将 name 转换为路径,去掉 # 和 [] var path = name.replace(/^#\.?/, '').replace(/\[\]/g, ''); if (!path) { return form.getFieldsValue(); } return xform.getValueByPath(path); }; xform.getSchemaByPath = function (_path) { if (typeof _path !== 'string') { console.warn('请输入正确的路径'); } var path = (0, _formCoreUtils.getSchemaFullPath)(_path, schemaRef.current); return (0, _utils._get)(schemaRef.current, path); }; // 通过字段名获取 schema(从 flattenSchema 中查找) xform.getSchemaByName = function (name) { var _a; if (typeof name !== 'string') { console.warn('请输入正确的字段名'); return; } var flattenItem = (_a = flattenSchemaRef.current) === null || _a === void 0 ? void 0 : _a[name]; if (!flattenItem) { console.warn("\u672A\u627E\u5230\u5B57\u6BB5\u540D\u4E3A ".concat(name, " \u7684 schema")); return; } return flattenItem.schema; }; xform.getSchema = function () { return schemaRef.current; }; // 设置一组字段错误 xform.setErrorFields = function (fieldsError) { var fieldsData = (0, _formCoreUtils.transformFieldsData)(fieldsError, getFieldName); if (!fieldsData) { return; } setFields(fieldsData); }; // 清空某个字段的错误 xform.removeErrorField = function (path) { setFields([{ name: getFieldName(path), errors: [] }]); }; // 获取对应字段名的错误信息 xform.getFieldError = function (path) { var name = getFieldName(path); return form.getFieldError(name); }; // 获取一组字段名对应的错误信息,返回为数组形式 xform.getFieldsError = function (path) { var name = getFieldName(path); return getFieldsError(name); }; // 获取隐藏字段数据 xform.getHiddenValues = function () { var values = xform.getValues(); var allValues = xform.getValues(true); var hiddenValues = {}; var _recursion = function recursion(obj1, obj2, path) { Object.keys(obj1).forEach(function (key) { var value = obj1[key]; var _path = path ? "".concat(path, ".").concat(key) : key; if (!obj2.hasOwnProperty(key)) { (0, _utils._set)(hiddenValues, _path, value); return; } if ((0, _utils.isObject)(value)) { _recursion(value, obj2[key], _path); } if ((0, _utils.isArray)(value)) { value.map(function (item, index) { _recursion(item, (0, _utils._get)(obj2, "".concat(key, "[").concat(index, "]"), []), "".concat(_path, "[").concat(index, "]")); }); } }); }; _recursion(allValues, values, null); return hiddenValues; }; // 设置一组字段状态 xform.setFields = function (nameList) { var fieldsData = (0, _formCoreUtils.transformFieldsData)(nameList, getFieldName); if (!fieldsData) { return; } setFields(fieldsData); }; // 检查一组字段是否被用户操作过,allTouched 为 true 时检查是否所有字段都被操作过 xform.isFieldsTouched = function (pathList, allTouched) { var nameList = (pathList || []).map(function (path) { return getFieldName(path); }); return isFieldsTouched(nameList, allTouched); }; // 检查对应字段是否被用户操作过 xform.isFieldTouched = function (path) { var name = getFieldName(path); return isFieldTouched(name); }; // 检查对应字段是否被用户操作过 xform.isFieldValidating = function (path) { var name = getFieldName(path); return isFieldValidating(name); }; xform.resetFields = function (pathList) { var nameList = (pathList || []).map(function (path) { return getFieldName(path); }); if (nameList.length > 0) { resetFields(nameList); } else { resetFields(); } }; // 触发表单验证 xform.validateFields = function (pathList) { var nameList = (pathList || []).map(function (path) { return getFieldName(path); }); if (nameList.length > 0) { return validateFields(nameList); } return validateFields(); }; // 获取扁平化 schema xform.getFlattenSchema = function (path) { var _a; if (!path) { return flattenSchemaRef.current; } return (_a = flattenSchemaRef.current) === null || _a === void 0 ? void 0 : _a[path]; }; xform.__initStore = function (store) { storeRef.current = store; }; xform.setFieldRef = function (path, ref) { if (!path) { return; } fieldRefs.current[path] = ref; }; xform.getFieldRef = function (path) { return fieldRefs.current[path]; }; return xform; }; var _default = exports.default = useForm;