cw-form-render-mobile
Version:
通过 JSON Schema 生成标准 Form,常用于自定义搭建配置界面生成
593 lines (592 loc) • 25.2 kB
JavaScript
;
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;