UNPKG

@ithinkdt/core

Version:

iThinkDT Core

188 lines (159 loc) 5.79 kB
import { computed, markRaw, readonly, reactive, shallowReactive, ref, isRef, unref, watch } from 'vue' import { useI18n } from '../../i18n' import { pageInit } from '../plugin' import { isRequiredRule, required } from './rules/require.rule' export * from './rules' export function useForm(options) { let { multiStep, items, model: _model = {}, initial, defaultSpan = 6, formRef = ref() } = options const model = reactive(_model) const reset = (_initial) => { if (!_initial || _initial instanceof Event) { _initial = { ..._model, ...initial } } initial = _initial for (const k of [...Object.keys(model), ...Object.keys(_initial)]) { model[k] = _initial[k] ?? undefined } } if (initial) { reset(initial) } if (Array.isArray(options) || typeof options === 'function') { items = options } if (typeof items === 'function') { const fi = (k, t, requiredOrOptions) => ({ ...(typeof requiredOrOptions === 'boolean' || isRef(requiredOrOptions) ? { required: requiredOrOptions } : requiredOrOptions), name: k, type: t, }) const group = (show, items) => { return items.map((it) => { return { ...it, hidden: computed(() => !unref(show) || unref(it.hidden) === true), } }) } items = items({ model, formRef, reset, fi, group }) } const { t, locale } = useI18n() let _items function _map(items) { return items.map((it) => { if (it.step) { return reactive({ ...it, items: _map(it.items), }) } if (!it) { return { hidden: true } } if (!it.props) { it.props = {} } const rules = it.rule ? [it.rule].flat() : it.rule if (it.name && !it.name.startsWith('$')) { // eslint-disable-next-line unicorn/no-null model[it.name] ??= null } let [_type, param] = typeof it.type === 'string' ? it.type.split('|') : [] const preset = (_type && pageInit.formPresets?.[_type]?.(it, param)) || {} let type = preset.component || it.type const _submit = it.submit && preset._submit ? ($) => Promise.resolve(preset.submit($)).then(() => it.submit($)) : it.submit ?? preset.submit ?? preset._submit return reactive({ ...preset, ...it, label: typeof it.label === 'function' ? computed(() => it.label(locale.value)) : it.label, span: it.span ?? preset.span ?? defaultSpan, type: type && typeof type === 'object' ? markRaw(type) : type, props: { ...preset.props, ...it.props, ref: ($) => { it.$ = $ if (isRef(it.props?.ref)) { it.props.ref.value = $ } else if (typeof it.props?.ref === 'function') { it.props.ref($) } }, }, parse: it.parse && preset._parse ? (v) => it.parse(preset._parse(v)) : it.parse ?? preset.parse ?? preset._parse, transform: it.transform && preset._transform ? (v) => preset.transform(it.transform(v)) : it.transform ?? preset.transform ?? preset._transform, submit: () => _submit?.(it.$), rule: [ rules?.find((r) => isRequiredRule(r)) ? undefined : required( computed(() => t('form.validate.required', unref(it.label))), { required: it.required ?? false }, ), ...(rules && preset._rule ? [...preset.rule, ...rules] : rules ?? preset.rule ?? preset._rule ?? []), ].filter(Boolean), }) }) } if (isRef(items)) { watch(items, (its) => { if (!_items) return _items = _map([...its]) updateIts() }) } const _its = shallowReactive([]) const step = ref(0) const hasNext = computed(() => _items?.reduceRight((has, it, index) => { if (index === step.value) return false return has || !it.skip }, false), ) function updateIts() { _its.length = 0 if (unref(multiStep)) { _its.push(...(_items[step.value]?.items ?? [])) } else { _its.push(..._items) } } const init = () => { _items = _map([...unref(items)]) updateIts() } pageInit.__$ ? init() : pageInit.$init.then(init) return { model, formRef, items: _its, reset, hasNext, step: readonly(step), next() { while (_items[step.value + 1]?.skip) { step.value = Math.min(step.value + 1, _items.length - 1) } updateIts() }, prev() { while (_items[step.value - 1]?.skip) { step.value = Math.max(step.value - 1, 0) } updateIts() }, } }