@form-create/core
Version:
FormCreate低代码表单渲染引擎,可以通过 JSON 生成具有动态渲染、数据收集、验证和提交功能的低代码表单。支持6个UI框架,适配移动端,并且支持生成任何 Vue 组件。
439 lines (426 loc) • 13.7 kB
JavaScript
import {byCtx, invoke, mergeRule, toJson} from './util';
import {$set} from '@form-create/utils/lib/modify';
import {deepCopy} from '@form-create/utils/lib/deepextend';
import is, {hasProperty} from '@form-create/utils/lib/type';
import extend from '@form-create/utils/lib/extend';
import {format} from '@form-create/utils/lib/console';
import {asyncFetch} from './fetch';
function copy(value) {
return deepCopy(value);
}
export default function Api(h) {
function tidyFields(fields) {
if (is.Undef(fields))
fields = h.fields();
else if (!Array.isArray(fields))
fields = [fields];
return fields;
}
function props(fields, key, val) {
tidyFields(fields).forEach(field => {
h.getCtxs(field).forEach(ctx => {
$set(ctx.rule, key, val);
h.$render.clearCache(ctx);
});
})
}
function allSubForm() {
const subs = h.subForm;
return Object.keys(subs).reduce((initial, k) => {
const sub = subs[k];
if (!sub) return initial;
if (Array.isArray(sub))
initial.push(...sub);
else
initial.push(sub);
return initial;
}, []);
}
const api = {
get config() {
return h.options
},
get options() {
return h.options
},
get form() {
return h.form
},
get rule() {
return h.rules
},
get parent() {
return h.vm.$pfc && h.vm.$pfc.$f
},
get top() {
if (api.parent) {
return api.parent.top;
}
return api;
},
get children() {
return allSubForm();
},
formData(fields) {
return tidyFields(fields).reduce((initial, id) => {
const ctx = h.getFieldCtx(id);
if (!ctx) return initial;
initial[ctx.field] = copy(ctx.rule.value);
return initial;
}, h.options.appendValue !== false ? copy(h.appendData) : {});
},
getValue(field) {
const ctx = h.getFieldCtx(field);
if (!ctx) return;
return copy(ctx.rule.value);
},
coverValue(formData) {
const data = {...(formData || {})};
h.deferSyncValue(() => {
api.fields().forEach(key => {
const ctxs = h.fieldCtx[key];
if (ctxs) {
const flag = hasProperty(data, key);
ctxs.forEach(ctx => {
ctx.rule.value = flag ? data[key] : undefined;
})
delete data[key];
}
});
extend(h.appendData, data);
})
},
setValue(field) {
let formData = field;
if (arguments.length >= 2)
formData = {[field]: arguments[1]};
h.deferSyncValue(() => {
Object.keys(formData).forEach(key => {
const ctxs = h.fieldCtx[key];
if (!ctxs) return h.appendData[key] = formData[key];
ctxs.forEach(ctx => {
ctx.rule.value = formData[key];
});
});
})
},
removeField(field) {
const ctx = h.getCtx(field);
h.deferSyncValue(() => {
h.getCtxs(field).forEach(ctx => {
ctx.rm();
});
}, true);
return ctx ? ctx.origin : undefined;
},
removeRule(rule) {
const ctx = rule && byCtx(rule);
if (!ctx) return;
ctx.rm();
return ctx.origin;
},
destroy: () => {
h.vm.$el.parentNode && h.vm.$el.parentNode.removeChild(h.vm.$el);
h.vm.$destroy();
},
fields: () => h.fields(),
append: (rule, after, child) => {
let index = h.sort.length - 1, rules;
const ctx = h.getCtx(after);
if (ctx) {
if (child) {
rules = ctx.rule.children;
index = ctx.rule.children.length - 1;
} else {
index = ctx.root.indexOf(ctx.origin);
rules = ctx.root;
}
} else rules = h.rules;
rules.splice(index + 1, 0, rule);
},
prepend: (rule, after, child) => {
let index = 0, rules;
const ctx = h.getCtx(after);
if (ctx) {
if (child) {
rules = ctx.rule.children;
} else {
index = ctx.root.indexOf(ctx.origin);
rules = ctx.root;
}
} else rules = h.rules;
rules.splice(index, 0, rule);
},
hidden(state, fields) {
props(fields, 'hidden', !!state);
h.refresh();
},
hiddenStatus(id) {
const ctx = h.getCtx(id);
if (!ctx) return;
return !!ctx.rule.hidden;
},
display(state, fields) {
props(fields, 'display', !!state);
h.refresh();
},
displayStatus(id) {
const ctx = h.getCtx(id);
if (!ctx) return;
return !!ctx.rule.display;
},
disabled(disabled, fields) {
tidyFields(fields).forEach((field) => {
h.getCtxs(field).forEach(ctx => {
ctx.rule.props && $set(ctx.rule.props, 'disabled', !!disabled);
});
});
h.refresh();
},
all(origin) {
return Object.keys(h.ctxs).map(k => {
const ctx = h.ctxs[k];
return origin ? ctx.origin : ctx.rule;
});
},
model(origin) {
return h.fields().reduce((initial, key) => {
const ctx = h.fieldCtx[key][0];
initial[key] = origin ? ctx.origin : ctx.rule;
return initial;
}, {});
},
component(origin) {
return Object.keys(h.nameCtx).reduce((initial, key) => {
const ctx = h.nameCtx[key].map(ctx => origin ? ctx.origin : ctx.rule);
initial[key] = ctx.length === 1 ? ctx[0] : ctx;
return initial;
}, {});
},
bind() {
return api.form;
},
reload: (rules) => {
h.reloadRule(rules)
},
updateOptions(options) {
h.fc.updateOptions(options);
api.refresh();
},
onSubmit(fn) {
api.updateOptions({onSubmit: fn});
},
sync: (field) => {
if (Array.isArray(field)) {
field.forEach(v => api.sync(v));
return;
}
let ctxs = is.Object(field) ? byCtx(field) : h.getCtxs(field);
if (!ctxs) {
return;
}
ctxs = Array.isArray(ctxs) ? ctxs : [ctxs];
ctxs.forEach(ctx => {
if (!ctx.deleted) {
const subForm = h.subForm[ctx.id];
if (subForm) {
if (Array.isArray(subForm)) {
subForm.forEach(form => {
form.refresh();
})
} else if (subForm) {
subForm.refresh();
}
}
//ctx.updateKey(true);
h.$render.clearCache(ctx);
}
});
h.refresh();
},
refresh: () => {
allSubForm().forEach(sub => {
sub.refresh();
});
h.$render.clearCacheAll();
h.refresh();
},
refreshOptions() {
h.$manager.updateOptions(h.options);
api.refresh();
},
hideForm: (hide) => {
$set(h.vm, 'isShow', !hide);
},
changeStatus: () => {
return h.changeStatus;
},
clearChangeStatus: () => {
h.changeStatus = false;
},
updateRule(id, rule) {
h.getCtxs(id).forEach(ctx => {
extend(ctx.rule, rule);
});
},
updateRules(rules) {
Object.keys(rules).forEach(id => {
api.updateRule(id, rules[id]);
})
},
mergeRule: (id, rule) => {
h.getCtxs(id).forEach(ctx => {
mergeRule(ctx.rule, rule);
});
},
mergeRules(rules) {
Object.keys(rules).forEach(id => {
api.mergeRule(id, rules[id]);
})
},
getRule: (id, origin) => {
const ctx = h.getCtx(id);
if (ctx) {
return origin ? ctx.origin : ctx.rule;
}
},
getRenderRule: (id) => {
const ctx = h.getCtx(id);
if (ctx) {
return ctx.prop;
}
},
getRefRule: (id) => {
const ctxs = h.getCtxs(id);
if (ctxs && ctxs.length) {
const rules = ctxs.map(ctx => {
return ctx.rule;
})
return rules.length === 1 ? rules[0] : rules;
}
},
setEffect(id, attr, value) {
const ctx = h.getCtx(id);
if (ctx && attr) {
if (attr[0] === '$') {
attr = attr.substr(1);
}
if (hasProperty(ctx.rule, '$' + attr)) {
$set(ctx.rule, '$' + attr, value);
}
if (!hasProperty(ctx.rule, 'effect')) {
$set(ctx.rule, 'effect', {});
}
$set(ctx.rule.effect, attr, value);
}
},
clearEffectData(id, attr) {
const ctx = h.getCtx(id);
if (ctx) {
if (attr && attr[0] === '$') {
attr = attr.substr(1);
}
ctx.clearEffectData(attr);
api.sync(id);
}
},
updateValidate(id, validate, merge) {
if (merge) {
api.mergeRule(id, {validate})
} else {
props(id, 'validate', validate);
}
},
updateValidates(validates, merge) {
Object.keys(validates).forEach(id => {
api.updateValidate(id, validates[id], merge);
})
},
refreshValidate() {
h.vm.validate = {};
api.refresh();
},
resetFields(fields) {
tidyFields(fields).forEach(field => {
h.getCtxs(field).forEach(ctx => {
h.$render.clearCache(ctx);
ctx.rule.value = copy(ctx.defaultValue);
});
});
h.vm.$nextTick(() => {
api.clearValidateState();
});
if (fields == null) {
is.Function(h.options.onReset) && invoke(() => h.options.onReset(api));
h.vm.$emit('reset', api);
}
},
method(id, name) {
const el = api.el(id);
if (!el || !el[name])
throw new Error(format('err', `${name}方法不存在`));
return (...args) => {
return el[name](...args);
}
},
exec(id, name, ...args) {
return invoke(() => api.method(id, name)(...args));
},
toJson(space) {
return toJson(api.rule, space);
},
trigger(id, event, ...args) {
const el = api.el(id);
el && el.$emit(event, ...args);
},
el(id) {
const ctx = h.getCtx(id);
if (ctx) return ctx.exportEl || ctx.el || h.vm.$refs[ctx.ref];
},
closeModal: (id) => {
const el = api.el(id);
el && el.$emit && el.$emit('close-modal');
},
getSubForm(field) {
const ctx = h.getCtx(field);
return ctx ? h.subForm[ctx.id] : undefined;
},
nextTick(fn) {
h.bus.$once('next-tick', fn);
h.refresh();
},
nextRefresh(fn) {
h.nextRefresh();
fn && invoke(fn);
},
emit(name, ...args) {
h.vm.$emit(name, ...args);
},
deferSyncValue(fn, sync) {
h.deferSyncValue(fn, sync);
},
fetch(opt) {
return new Promise((resolve, reject) => {
h.beforeFetch(opt).then(() => {
return asyncFetch(opt).then(resolve).catch(reject);
});
});
},
getData(id, def) {
return h.fc.getData(id, def);
},
setData(id, data) {
return h.fc.setData(id, data);
},
helper: {
tidyFields, props
}
};
['on', 'once', 'off', 'set', 'emit'].forEach(n => {
api[n] = function (...args) {
h.vm[`$${n}`](...args);
}
});
api.changeValue = api.changeField = api.setValue;
return api;
}