2023-06-08 21:09:28 +08:00
|
|
|
<template>
|
|
|
|
|
<div class="w-full">
|
2024-09-06 10:48:22 +08:00
|
|
|
<a-spin :loading="formLoading" :tip="options.loadingText" class="w-full ma-form-spin">
|
2023-06-08 21:09:28 +08:00
|
|
|
<div
|
|
|
|
|
v-if="options.showFormTitle"
|
|
|
|
|
:class="['ma-form-title', options.formTitleClass]"
|
|
|
|
|
:style="options.formTitleStyle"
|
|
|
|
|
>
|
|
|
|
|
{{ options.formTitle }}
|
|
|
|
|
</div>
|
|
|
|
|
<a-form
|
|
|
|
|
ref="maFormRef"
|
|
|
|
|
:model="form"
|
|
|
|
|
:class="['ma-form', options?.customClass]"
|
|
|
|
|
:label-align="options?.labelAlign"
|
|
|
|
|
:layout="options?.layout"
|
|
|
|
|
:size="options?.size"
|
|
|
|
|
:disabled="options?.disabled"
|
|
|
|
|
:rules="options?.rules"
|
|
|
|
|
@submit="formSubmit"
|
|
|
|
|
>
|
2024-09-06 10:48:22 +08:00
|
|
|
<slot name="formContent">
|
|
|
|
|
<template v-for="(component, componentIndex) in columns" :key="componentIndex">
|
|
|
|
|
<component
|
|
|
|
|
:is="getComponentName(component?.formType ?? 'input')"
|
|
|
|
|
:component="component"
|
|
|
|
|
:ref="setDialogRef"
|
|
|
|
|
>
|
|
|
|
|
<template v-for="slot in Object.keys($slots)" #[slot]="component">
|
|
|
|
|
<slot :name="slot" v-bind="component" />
|
|
|
|
|
</template>
|
|
|
|
|
</component>
|
|
|
|
|
</template>
|
|
|
|
|
<div class="text-center" v-if="options.showButtons">
|
|
|
|
|
<a-space>
|
|
|
|
|
<slot name="formBeforeButtons" />
|
|
|
|
|
<slot name="formButtons">
|
|
|
|
|
<a-button
|
|
|
|
|
:type="options.submitType"
|
|
|
|
|
:status="options.submitStatus"
|
|
|
|
|
v-if="options.submitShowBtn"
|
|
|
|
|
html-type="submit"
|
|
|
|
|
>
|
|
|
|
|
<template #icon v-if="options?.submitIcon">
|
|
|
|
|
<component :is="options.submitIcon" />
|
|
|
|
|
</template>
|
|
|
|
|
{{ options.submitText }}
|
|
|
|
|
</a-button>
|
|
|
|
|
<a-button
|
|
|
|
|
:type="options.resetType"
|
|
|
|
|
:status="options.resetStatus"
|
|
|
|
|
v-if="options.resetShowBtn"
|
|
|
|
|
@click="resetForm"
|
|
|
|
|
>
|
|
|
|
|
<template #icon v-if="options?.resetIcon">
|
|
|
|
|
<component :is="options.resetIcon" />
|
|
|
|
|
</template>
|
|
|
|
|
{{ options.resetText }}
|
|
|
|
|
</a-button>
|
|
|
|
|
</slot>
|
|
|
|
|
<slot name="formAfterButtons" />
|
|
|
|
|
</a-space>
|
|
|
|
|
</div>
|
|
|
|
|
</slot>
|
2023-06-08 21:09:28 +08:00
|
|
|
</a-form>
|
|
|
|
|
</a-spin>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { ref, watch, provide, onMounted, nextTick, getCurrentInstance } from "vue"
|
2024-09-06 11:31:32 +08:00
|
|
|
import { isNil, set, get, cloneDeep } from "lodash-es"
|
2023-06-08 21:09:28 +08:00
|
|
|
import defaultOptions from "./js/defaultOptions.js"
|
2024-09-06 10:48:22 +08:00
|
|
|
import {
|
|
|
|
|
getComponentName,
|
|
|
|
|
toHump,
|
|
|
|
|
interactiveControl,
|
|
|
|
|
handleFlatteningColumns,
|
|
|
|
|
insertGlobalCssToHead,
|
|
|
|
|
insertGlobalFunctionsToHtml
|
|
|
|
|
} from "./js/utils.js"
|
2023-06-08 21:09:28 +08:00
|
|
|
import { loadDict, handlerCascader } from "./js/networkRequest.js"
|
|
|
|
|
import arrayComponentDefault from "./js/defaultArrayComponent.js"
|
2024-09-06 10:48:22 +08:00
|
|
|
import ColumnService from "./js/columnService.js"
|
2023-06-08 21:09:28 +08:00
|
|
|
|
2024-09-06 10:48:22 +08:00
|
|
|
import { runEvent } from "./js/event.js"
|
2023-06-08 21:09:28 +08:00
|
|
|
import { Message } from "@arco-design/web-vue"
|
|
|
|
|
|
|
|
|
|
const formLoading = ref(false)
|
|
|
|
|
const maFormRef = ref()
|
2024-09-06 10:48:22 +08:00
|
|
|
const dialogRefs = ref({})
|
2023-06-08 21:09:28 +08:00
|
|
|
const flatteningColumns = ref([])
|
|
|
|
|
const dictList = ref({})
|
|
|
|
|
const cascaderList = ref([])
|
|
|
|
|
const form = ref({})
|
|
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
modelValue: { type: Object, default: {} },
|
|
|
|
|
columns: { type: Array },
|
|
|
|
|
options: { type: Object, default: {} }
|
|
|
|
|
})
|
2024-09-06 10:48:22 +08:00
|
|
|
const emit = defineEmits(["submit", "update:modelValue"])
|
2023-06-08 21:09:28 +08:00
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
() => props.modelValue,
|
|
|
|
|
(vl) => (form.value = vl),
|
|
|
|
|
{ immediate: true, deep: true }
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
() => form.value,
|
|
|
|
|
(vl) => {
|
2024-09-06 10:48:22 +08:00
|
|
|
interactiveControl(vl, flatteningColumns.value, { getColumnService, dictList })
|
2023-06-08 21:09:28 +08:00
|
|
|
emit("update:modelValue", vl)
|
|
|
|
|
},
|
|
|
|
|
{ deep: true }
|
|
|
|
|
)
|
|
|
|
|
|
2024-09-06 10:48:22 +08:00
|
|
|
const options = ref({})
|
2023-06-08 21:09:28 +08:00
|
|
|
|
|
|
|
|
// 初始化
|
|
|
|
|
const init = async () => {
|
2024-09-06 10:48:22 +08:00
|
|
|
const containerList = import.meta.glob("./containerItem/*.vue", { eager: true })
|
|
|
|
|
const componentList = import.meta.glob("./formItem/*.vue", { eager: true })
|
|
|
|
|
const _this = getCurrentInstance()?.appContext ?? undefined
|
|
|
|
|
|
|
|
|
|
if (_this) {
|
|
|
|
|
for (const path in containerList) {
|
|
|
|
|
const name = path.match(/([A-Za-z0-9_-]+)/g)[1]
|
|
|
|
|
const containerName = `Ma${toHump(name)}`
|
|
|
|
|
if (!_this.components[containerName]) {
|
|
|
|
|
_this.app.component(containerName, containerList[path].default)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const path in componentList) {
|
|
|
|
|
const name = path.match(/([A-Za-z0-9_-]+)/g)[1]
|
|
|
|
|
const componentName = `Ma${toHump(name)}`
|
|
|
|
|
if (!_this.components[componentName]) {
|
|
|
|
|
_this.app.component(componentName, componentList[path].default)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-08 21:09:28 +08:00
|
|
|
formLoading.value = true
|
|
|
|
|
|
|
|
|
|
handleFlatteningColumns(props.columns, flatteningColumns.value)
|
|
|
|
|
|
|
|
|
|
// 收集数据列表
|
|
|
|
|
flatteningColumns.value.map((item) => {
|
|
|
|
|
if (item.cascaderItem && item.cascaderItem.length > 0) {
|
|
|
|
|
cascaderList.value.push(...item.cascaderItem)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// 初始化数据
|
|
|
|
|
flatteningColumns.value.map(async (item) => {
|
2024-09-06 10:48:22 +08:00
|
|
|
if (isNil(form.value[item.dataIndex])) {
|
2023-06-08 21:09:28 +08:00
|
|
|
form.value[item.dataIndex] = undefined
|
2024-09-06 10:48:22 +08:00
|
|
|
if (arrayComponentDefault.includes(item.formType)) {
|
2023-06-08 21:09:28 +08:00
|
|
|
form.value[item.dataIndex] = []
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-06 10:48:22 +08:00
|
|
|
// 处理带点的字段
|
|
|
|
|
if (typeof item.dataIndex === "string") {
|
|
|
|
|
if (item.dataIndex.indexOf(".") > -1) {
|
|
|
|
|
const value = cloneDeep(form.value[item.dataIndex])
|
|
|
|
|
delete form.value[item.dataIndex]
|
|
|
|
|
set(form.value, item.dataIndex, value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-08 21:09:28 +08:00
|
|
|
// 字典
|
|
|
|
|
if (!cascaderList.value.includes(item.dataIndex) && item.dict) {
|
2024-09-06 10:48:22 +08:00
|
|
|
await loadDict(dictList.value, item, options.value.sourceList, {
|
|
|
|
|
formModel: form.value,
|
|
|
|
|
getColumnService,
|
|
|
|
|
columns: flatteningColumns.value
|
|
|
|
|
})
|
2023-06-08 21:09:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 联动
|
|
|
|
|
await handlerCascader(
|
|
|
|
|
get(form.value, item.dataIndex),
|
|
|
|
|
item,
|
|
|
|
|
flatteningColumns.value,
|
|
|
|
|
dictList.value,
|
|
|
|
|
form.value,
|
|
|
|
|
false
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
await nextTick(() => {
|
2024-09-06 10:48:22 +08:00
|
|
|
interactiveControl(form.value, flatteningColumns.value, { getColumnService, dictList })
|
2023-06-08 21:09:28 +08:00
|
|
|
formLoading.value = false
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-06 10:48:22 +08:00
|
|
|
const setDialogRef = async (ref) => {
|
|
|
|
|
await nextTick(() => {
|
|
|
|
|
if (ref?.getDataIndex) {
|
|
|
|
|
dialogRefs.value[ref.getDataIndex()] = ref
|
|
|
|
|
if (!form.value[ref.getDataIndex()]) {
|
|
|
|
|
form.value[ref.getDataIndex()] = {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
2023-06-08 21:09:28 +08:00
|
|
|
|
2024-09-06 10:48:22 +08:00
|
|
|
// maEvent.handleCommonEvent(options.value, 'onCreated')
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
updateOptions()
|
|
|
|
|
insertGlobalCssToHead(options.value.globalCss)
|
|
|
|
|
insertGlobalFunctionsToHtml(options.value.globalFunction)
|
|
|
|
|
// maEvent.handleCommonEvent(options.value, 'onMounted')
|
|
|
|
|
options.value.init && (await init())
|
|
|
|
|
// maEvent.handleCommonEvent(options.value, 'onInit')
|
2023-06-08 21:09:28 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const done = (status) => (formLoading.value = status)
|
|
|
|
|
const validateForm = async () => {
|
|
|
|
|
const valid = await maFormRef.value.validate()
|
|
|
|
|
if (valid) {
|
|
|
|
|
let message = ""
|
|
|
|
|
for (let name in valid) message += valid[name].message + "、"
|
|
|
|
|
Message.error(message.substring(0, message.length - 1))
|
|
|
|
|
}
|
|
|
|
|
return valid
|
|
|
|
|
}
|
|
|
|
|
const resetForm = async () => await maFormRef.value.resetFields()
|
|
|
|
|
const clearValidate = async () => await maFormRef.value.clearValidate()
|
|
|
|
|
|
2024-09-06 10:48:22 +08:00
|
|
|
const formSubmit = async () => {
|
|
|
|
|
if (await validateForm()) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
emit("submit", form.value, done)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取column属性服务类
|
|
|
|
|
* @returns ColumnService
|
|
|
|
|
*/
|
|
|
|
|
const getColumnService = (strictMode = true) => {
|
|
|
|
|
return new ColumnService(
|
|
|
|
|
{
|
|
|
|
|
columns: flatteningColumns.value,
|
|
|
|
|
cascaders: cascaderList.value,
|
|
|
|
|
dicts: dictList.value,
|
|
|
|
|
refs: dialogRefs.value
|
|
|
|
|
},
|
|
|
|
|
strictMode
|
|
|
|
|
)
|
|
|
|
|
}
|
2023-06-08 21:09:28 +08:00
|
|
|
|
|
|
|
|
const getFormRef = () => maFormRef.value
|
|
|
|
|
const getDictList = () => dictList.value
|
|
|
|
|
const getColumns = () => flatteningColumns.value
|
|
|
|
|
const getCascaderList = () => cascaderList.value
|
|
|
|
|
const getFormData = () => form.value
|
2024-09-06 10:48:22 +08:00
|
|
|
const updateOptions = () => (options.value = Object.assign(cloneDeep(defaultOptions), props.options))
|
|
|
|
|
|
|
|
|
|
provide("options", options.value)
|
|
|
|
|
provide("columns", flatteningColumns)
|
|
|
|
|
provide("dictList", dictList)
|
|
|
|
|
provide("formModel", form)
|
|
|
|
|
provide("formLoading", formLoading)
|
|
|
|
|
provide("getColumnService", getColumnService)
|
|
|
|
|
provide("maFormRef", maFormRef)
|
2023-06-08 21:09:28 +08:00
|
|
|
|
|
|
|
|
defineExpose({
|
|
|
|
|
init,
|
|
|
|
|
getFormRef,
|
|
|
|
|
getColumns,
|
|
|
|
|
getDictList,
|
2024-09-06 10:48:22 +08:00
|
|
|
getColumnService,
|
2023-06-08 21:09:28 +08:00
|
|
|
getCascaderList,
|
|
|
|
|
getFormData,
|
|
|
|
|
validateForm,
|
|
|
|
|
resetForm,
|
2024-09-06 10:48:22 +08:00
|
|
|
clearValidate,
|
|
|
|
|
updateOptions
|
2023-06-08 21:09:28 +08:00
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
|
.ma-form-title {
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
</style>
|