@ithinkdt/core
Version:
iThinkDT Core
198 lines (177 loc) • 5.39 kB
JavaScript
import { ref, computed, toValue, reactive, unref } from 'vue'
import { $msg } from '../feedback'
import { useI18n } from '../i18n'
import { useForm } from './form'
import { useModal } from './use-modal'
import { pageInit } from './plugin'
export function useFormModal({
save,
form,
cols = 24,
defaultSpan = form?.defaultSpan || 24,
model: _model = form?.model,
formRef: _formRef = form?.ref,
multiStep,
items: _items = form?.items || form || [],
type = 'dialog',
title,
actions,
onClose,
width = type === 'drawer' ? 477 : 488,
submitText = '保 存',
cancelText = '取 消',
...options
}) {
const { t } = useI18n()
if (form) {
console.warn(`[use-modal-form]: 'form' is deprecated`)
}
form = {
multiStep,
defaultSpan,
model: _model,
formRef: _formRef,
items: _items,
}
const { model, items, formRef, reset, step, next, prev, hasNext } = useForm(form)
const readonly = ref(false)
const submiting = ref(false)
let resolve, reject
const submit = () => {
if (!visible.value || submiting.value) return false
submiting.value = true
return formRef.value
?.validate()
.catch((error) => {
$msg.error(t('form.validate.error'))
throw error
})
.then(async () => {
if (hasNext.value) {
next()
return
}
const req = await save?.(model)
close()
if (req && 'id' in req) {
Object.assign(model, req)
}
resolve?.(model)
return req
})
.catch((error) => {
console.debug('form: error on submit', error)
})
.finally(() => {
submiting.value = false
})
}
async function _close() {
if (!visible.value || submiting.value) return false
if (step.value !== 0) {
prev()
return
}
if ((await onClose?.()) === false) return false
close()
reject?.({
__alert_ignore: true,
})
}
if (!actions) {
actions = ({ readonly }) => ['cancel', readonly ? undefined : 'submit']
}
const btns = computed(() => {
let btns = actions
if (typeof btns === 'function') {
btns = btns({
model,
readonly: readonly.value,
submiting: submiting.value,
onSubmit: submit,
onClose: _close,
})
}
return btns.map((act) => {
if (!act) return
if (act === 'submit') {
return reactive({
type: 'primary',
onClick: submit,
loading: submiting,
disabled: submiting,
text: computed(() => (unref(multiStep) && hasNext.value ? '下一步' : toValue(submitText))),
})
}
if (act === 'cancel') {
return reactive({
onClick: _close,
disabled: submiting,
text: computed(() => (unref(multiStep) && step.value ? '上一步' : toValue(cancelText))),
})
}
let click = act.onClick
act.onClick = () => click?.({ ...model })
return reactive(act)
})
})
const { modal: modalOps, form: formOps } = pageInit.handleFormModalOptions(options)
const { show, close, visible } = useModal({
...modalOps,
type: type === 'dialog' ? 'modal' : type,
width,
onClose: _close,
content: () =>
pageInit.renderFormModal({
...formOps,
type,
cols,
model,
items,
formRef,
title: toValue(title),
submiting: submiting.value,
readonly: readonly.value,
submitText,
cancelText,
btns: btns.value.filter((it) => !!it && it.text),
onClose: _close,
onSubmit: submit,
onReset: reset,
}),
})
return {
submiting,
model,
formRef,
close,
visible,
open(init, readonly0) {
if (init instanceof Event) {
init = {}
readonly0 = false
}
reset()
readonly.value = !!readonly0
show()
if (init instanceof Promise) {
submiting.value = true
Promise.resolve(init)
.then((data) => {
reset(data ?? {})
if (readonly.value) resolve(model)
})
.finally(() => {
submiting.value = false
})
} else {
reset(init ?? {})
}
const p = new Promise((_resolve, _reject) => {
resolve = _resolve
reject = _reject
})
return p
},
}
}