Files
cdTestPlant3/cdTMP/src/components/ma-form/index.vue

334 lines
11 KiB
Vue
Raw Normal View History

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"
2025-05-15 18:54:14 +08:00
:key="componentKey"
2023-06-08 21:09:28 +08:00
>
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"
2025-05-15 18:54:14 +08:00
@swichTableAndGroup="handleChangeDisplay"
2024-09-06 10:48:22 +08:00
>
<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>
<!-- 修改源码判断是否传入parentKey -->
<template v-if="parentKey">
<ParentPreview :parent-key="parentKey"></ParentPreview>
</template>
2023-06-08 21:09:28 +08:00
</a-spin>
</div>
</template>
<script setup>
import { ref, watch, provide, onMounted, nextTick, getCurrentInstance, inject, computed } 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({})
2025-05-15 18:54:14 +08:00
// ~~~custom start - 新增功能利用key强制更新form表单组件
const componentKey = ref(0)
const updateKey = () => {
componentKey.value += 1
if (componentKey.value > 20000) {
componentKey.value = 0
}
}
const handleChangeDisplay = (type) => {
updateKey()
}
// ~~~custom end
// ~~~~custom start
// 2025年5月14日新增功能hover查看上级节点
import ParentPreview from "@/views/project/ParentPreview/index.vue"
// 判断是否有
const formKey = computed(() => {
// 去掉双击被测件即key.split("").length > 1
if (form.value.key && form.value.key.split("-").length > 2) {
// 如果存在则取前面的
return form.value.key.slice(0, -2)
}
return ""
})
const parentKey = computed(() => {
return props.parentKey || formKey.value || ""
})
2025-05-15 18:54:14 +08:00
// ~~~~custom end
2023-06-08 21:09:28 +08:00
const props = defineProps({
modelValue: { type: Object, default: {} },
columns: { type: Array },
options: { type: Object, default: {} },
// 2025年5月14日新增属性-非必须,后面根据非必须判断
parentKey: { type: String, default: "" }
2023-06-08 21:09:28 +08:00
})
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>