<template>
<div>
<div class="placeholder-layer" v-if="!formModel || !formModel?.id">请选择表单模型</div>
<tiny-form v-else ref="formRef" label-width="120" label-position="left" :model="modelData" v-bind="$attrs">
<tiny-row>
<tiny-col :span="colNumber" v-for="(item, index) in formModel?.parameters" :key="index">
<tiny-form-item :prop="item.prop">
<template #label>
<div class="custom-label" v-auto-tip>
{{ item.label }}
</div>
</template>
<div v-if="item.isModel && item.defaultValue !== null">
<tiny-form label-width="100" label-position="left" :model="modelData[item.prop]">
<tiny-row>
<tiny-col
:span="insideColNumber"
v-for="(insideItem, insideIndex) in item.defaultValue"
:key="insideIndex"
>
<tiny-form-item :prop="insideItem.prop">
<template #label>
<div class="custom-label" v-auto-tip>
{{ insideItem.label }}
</div>
</template>
<component
:is="componentsMap[insideItem.component]"
v-model="modelData[item.prop][insideItem.prop]"
:disabled="viewOnly"
v-bind="insideItem"
></component>
</tiny-form-item>
</tiny-col>
</tiny-row>
</tiny-form>
</div>
<component
v-else
:is="componentsMap[item.component]"
v-model="modelData[item.prop]"
:disabled="viewOnly"
v-bind="item"
></component>
</tiny-form-item>
</tiny-col>
</tiny-row>
</tiny-form>
</div>
</template>
<script setup>
import { ref, defineProps, defineExpose, computed, watch, reactive } from 'vue'
import {
Form as TinyForm,
FormItem as TinyFormItem,
Input as TinyInput,
Select as TinySelect,
Checkbox as TinyCheckbox,
Radio as TinyRadio,
DatePicker as TinyDatePicker,
Numeric as TinyNumeric,
Row as TinyRow,
Col as TinyCol
} from '@opentiny/vue'
import axios from 'axios'
const props = defineProps({
style: {
type: String
},
className: {
type: String
},
layout: {
type: Number,
default: 2
},
viewOnly: {
type: Boolean,
default: false
},
modelValue: {
type: Object
},
serviceModel: {
type: Object
},
modelApis: {
type: Array,
default: () => []
}
})
const modelData = ref()
const formRef = ref(null)
const colNumber = computed(() => 12 / props.layout)
const insideColNumber = computed(() => (props.layout === 1 ? 6 : 12))
const formModel = computed(() => props.serviceModel)
const componentsMap = reactive({
TinyInput,
TinySelect,
TinyCheckbox,
TinyRadio,
TinyDatePicker,
TinyNumeric
})
const insertApi = (data = modelData.value) => {
const apiInfo = props.modelApis.find((api) => api.nameEn === 'insertApi')
if (!apiInfo) {
return undefined
}
return axios.post(apiInfo.url, { nameEn: formModel.value.nameEn, params: data }).catch((err) => {
throw new Error(err)
})
}
const updateApi = (data = modelData.value) => {
const apiInfo = props.modelApis.find((api) => api.nameEn === 'updateApi')
if (!apiInfo) {
return undefined
}
const id = data.id
delete data.id
return axios
.post(apiInfo.url, {
nameEn: formModel.value.nameEn,
data: data,
params: { id }
})
.catch((err) => {
throw new Error(err)
})
}
const queryApi = ({ currentPage, pageSize, data } = {}) => {
const apiInfo = props.modelApis.find((api) => api.nameEn === 'queryApi')
if (!apiInfo) {
return undefined
}
const params = Object.fromEntries(formModel.value.parameters.map((item) => [item.prop, null]))
return axios
.post(apiInfo.url, {
currentPage: currentPage || 1,
pageSize: pageSize || 10,
nameEn: formModel.value.nameEn,
nameCn: formModel.value.nameCn,
params: {
...params,
...(data || modelData.value)
}
})
.catch((err) => {
throw new Error(err)
})
}
const deleteApi = () => {
const apiInfo = props.modelApis.find((api) => api.nameEn === 'deleteApi')
if (!apiInfo) {
return undefined
}
return axios.post(apiInfo.url, { id: modelData.value?.id, nameEn: formModel.value.nameEn }).catch((err) => {
throw new Error(err)
})
}
const initFormData = () => {
modelData.value = Object.fromEntries(
(formModel.value?.parameters || []).map((item) => {
return [
item.prop,
item?.isModel
? Object.fromEntries(
item.defaultValue.map((insideItem) => [insideItem.prop, insideItem.defaultValue || null])
)
: item.defaultValue || null
]
})
)
}
watch(
() => props.modelValue,
(value) => {
if (value) {
modelData.value = props.modelValue
}
},
{ deep: true, immediate: true }
)
watch(
() => props.serviceModel,
() => {
if (!modelData.value) {
initFormData()
}
},
{ immediate: true }
)
const exposedData = {
formData: () => modelData.value,
formRef,
insertApi,
updateApi,
queryApi,
deleteApi
}
defineExpose({
...exposedData
})
</script>
<style lang="less" scoped>
.placeholder-layer {
height: 40px;
background-color: #f5f5f5;
width: 100%;
text-align: center;
line-height: 40px;
}
</style>