@lljj/vue2-form-core
Version:
基于 Vue 、JsonSchema快速构建一个带完整校验的form表单,vue2版本基础框架
239 lines (215 loc) • 8.37 kB
JavaScript
/**
* Created by Liu.Jun on 2020/4/24 11:23.
*/
import getDefaultFormState from '@lljj/vjsf-utils/schema/getDefaultFormState';
import {
allowAdditionalItems, isFixedItems, isMultiSelect, getUserUiOptions
} from '@lljj/vjsf-utils/formUtils';
import { getPathVal, setPathVal } from '@lljj/vjsf-utils/vueUtils';
import { genId, lowerCase } from '@lljj/vjsf-utils/utils';
import * as arrayMethods from '@lljj/vjsf-utils/arrayUtils';
import Widget from '../../components/Widget';
import vueProps from '../props';
import ArrayFieldNormal from './arrayTypes/ArrayFieldNormal';
import ArrayFieldMultiSelect from './arrayTypes/ArrayFieldMultiSelect';
import ArrayFieldTuple from './arrayTypes/ArrayFieldTuple';
import ArrayFieldSpecialFormat from './arrayTypes/ArrayFieldSpecialFormat';
export default {
name: 'ArrayField',
props: vueProps,
data() {
return {
// 通过维护一份key,一份值 来解决list key的问题
formKeys: this.getCuFormData().map(() => genId())
};
},
computed: {
uiOptions() {
const {
schema, uiSchema, rootFormData, curNodePath
} = this.$props;
return getUserUiOptions({
schema,
uiSchema,
curNodePath,
rootFormData
});
},
itemsFormData() {
const formKeys = this.$data.formKeys;
return this.curFormData.map((item, index) => ({
key: formKeys[index],
value: item
}));
},
curFormData() {
return this.getCuFormData();
}
},
watch: {
curFormData(newVal, oldVal) {
// 引用类型,当值不相等,说明是被重新赋值
if (newVal !== oldVal && Array.isArray(newVal)) {
this.formKeys = newVal.map(() => genId());
}
}
},
methods: {
// 获取当前的值
getCuFormData() {
const { rootFormData, curNodePath } = this.$props;
const value = getPathVal(rootFormData, curNodePath);
if (Array.isArray(value)) return value;
console.error('error: type array,值必须为 array 类型');
return [];
},
// 获取一个新item
getNewFormDataRow() {
const { schema, rootSchema } = this.$props;
let itemSchema = schema.items;
// https://json-schema.org/understanding-json-schema/reference/array.html#tuple-validation
// 数组为项的集合搭配additionalItems属性需要特殊处理
if (isFixedItems(this.schema) && allowAdditionalItems(this.schema)) {
itemSchema = schema.additionalItems;
}
return getDefaultFormState(itemSchema, undefined, rootSchema);
},
// 数组排序相关操作
handleArrayOperate({
command,
data
}) {
// 统一处理数组数据的 新增,删除,排序等变更
const strategyMap = {
moveUp(target, { index }) {
arrayMethods.moveUpAt(target, index);
},
moveDown(target, { index }) {
arrayMethods.moveDownAt(target, index);
},
remove(target, { index }) {
arrayMethods.removeAt(target, index);
},
add(target, { newRowData }) {
target.push(newRowData);
},
batchPush(target, { pushArray }) {
pushArray.forEach((item) => {
target.push(item);
});
},
setNewTarget(target, { formData, nodePath, newTarget }) {
setPathVal(formData, nodePath, newTarget);
}
};
const curStrategy = strategyMap[command];
if (curStrategy) {
let formDataPrams = data;
let keysParams = data;
if (command === 'add') {
// 单个添加
formDataPrams = { newRowData: this.getNewFormDataRow() };
keysParams = { newRowData: genId() };
} else if (command === 'batchPush') {
// 批量添加
keysParams = {
pushArray: formDataPrams.pushArray.map(item => genId())
};
} else if (command === 'setNewTarget') {
// 设置
formDataPrams = {
formData: this.rootFormData,
nodePath: this.curNodePath,
newTarget: formDataPrams.newTarget
};
keysParams = {
formData: this.$data,
nodePath: 'formKeys',
newTarget: formDataPrams.newTarget.map(item => genId())
};
}
// 同步修改 formData keys
curStrategy.apply(this, [this.$data.formKeys, keysParams]);
// 修改formData数据
curStrategy.apply(this, [this.curFormData, formDataPrams]);
// onArrayOperate
if (this.uiOptions.afterArrayOperate) {
this.uiOptions.afterArrayOperate.call(null, this.curFormData, command, data);
}
} else {
throw new Error(`错误 - 未知的操作:[${command}]`);
}
}
},
render(h) {
const self = this;
const {
schema,
uiSchema,
rootSchema,
rootFormData,
curNodePath,
globalOptions
} = this.$props;
if (!schema.hasOwnProperty('items')) {
throw new Error(`[${schema}] 请先定义 items属性`);
}
// 多选类型
if (isMultiSelect(schema, rootSchema)) {
// item 为枚举固定值
return h(ArrayFieldMultiSelect, {
props: this.$props,
class: {
[lowerCase(ArrayFieldMultiSelect.name)]: true
}
});
}
// 特殊处理 date datetime time url-upload
// array 支持配置 ui:widget
// 时间日期区间 或者 ui:widget 特殊配置
if (schema.format || schema['ui:widget'] || uiSchema['ui:widget']) {
return h(ArrayFieldSpecialFormat, {
props: this.$props,
class: {
[lowerCase(ArrayFieldSpecialFormat.name)]: true
}
});
}
// https://json-schema.org/understanding-json-schema/reference/array.html#list-validation
// https://json-schema.org/understanding-json-schema/reference/array.html#tuple-validation
const CurrentField = isFixedItems(schema) ? ArrayFieldTuple : ArrayFieldNormal;
return h('div', [
h(CurrentField, {
props: {
itemsFormData: this.itemsFormData,
...this.$props,
},
class: {
[lowerCase(CurrentField.name)]: true
},
on: {
onArrayOperate: this.handleArrayOperate
}
}),
// 插入一个Widget,校验 array - maxItems. minItems. uniqueItems 等items外的属性校验
this.needValidFieldGroup ? h(Widget, {
key: 'validateWidget-array',
class: {
validateWidget: true,
'validateWidget-array': true
},
props: {
schema: Object.entries(self.$props.schema).reduce((preVal, [key, value]) => {
if (key !== 'items') preVal[key] = value;
return preVal;
}, {}),
uiSchema,
errorSchema: this.errorSchema,
curNodePath,
rootFormData,
globalOptions
}
}) : null
]);
}
};