2025-12-24 发版,具体内容见发版日志
This commit is contained in:
143
openhis-ui-vue3/src/components/TableLayout/FormLayout.vue
Normal file
143
openhis-ui-vue3/src/components/TableLayout/FormLayout.vue
Normal file
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="model"
|
||||
:rules="rules"
|
||||
:label-width="labelWidth"
|
||||
:label-position="labelPosition"
|
||||
class="form-layout-form"
|
||||
>
|
||||
<div class="form-items-container" :class="columns > 0 ? `form-layout-${columns}col` : ''">
|
||||
<template v-for="(item, index) in normalizedFormItems" :key="item.prop">
|
||||
<FormItem
|
||||
:item="item"
|
||||
:model-value="model[item.prop]"
|
||||
@update:model-value="
|
||||
async (value) => {
|
||||
if (item.onChange && typeof item.onChange === 'function') {
|
||||
const result = await item.onChange(value);
|
||||
if (result === false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
model[item.prop] = value;
|
||||
}
|
||||
"
|
||||
>
|
||||
<template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
|
||||
<slot :name="slotName" v-bind="slotProps" />
|
||||
</template>
|
||||
</FormItem>
|
||||
<span
|
||||
v-if="
|
||||
columns > 0 &&
|
||||
index > 0 &&
|
||||
(index + 1) % columns === 0 &&
|
||||
index < normalizedFormItems.length - 1
|
||||
"
|
||||
class="form-item-break"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import FormItem from './FormItem.vue';
|
||||
import type { FormLayoutProps } from '../types/FormLayout.d';
|
||||
|
||||
defineOptions({
|
||||
name: 'FormLayout',
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<FormLayoutProps>(), {
|
||||
formItems: () => [],
|
||||
rules: () => ({}),
|
||||
labelWidth: '120px',
|
||||
labelPosition: 'right',
|
||||
showLabelColon: true,
|
||||
columns: 0,
|
||||
});
|
||||
|
||||
const formRef = ref<InstanceType<typeof import('element-plus').ElForm> | null>(null);
|
||||
|
||||
const normalizedFormItems = computed(() =>
|
||||
(props.formItems || []).map((item) => ({
|
||||
...item,
|
||||
labelSuffix: item.labelSuffix ?? (props.showLabelColon ? ':' : ''),
|
||||
}))
|
||||
);
|
||||
|
||||
const validate = (callback) => {
|
||||
if (formRef.value) {
|
||||
return formRef.value.validate(callback);
|
||||
}
|
||||
};
|
||||
|
||||
const validateField = (props, callback) => {
|
||||
if (formRef.value) {
|
||||
return formRef.value.validateField(props, callback);
|
||||
}
|
||||
};
|
||||
|
||||
const resetFields = () => {
|
||||
if (formRef.value) {
|
||||
formRef.value.resetFields();
|
||||
}
|
||||
};
|
||||
|
||||
const clearValidate = (props) => {
|
||||
if (formRef.value) {
|
||||
formRef.value.clearValidate(props);
|
||||
}
|
||||
};
|
||||
|
||||
const scrollToField = (prop) => {
|
||||
if (formRef.value) {
|
||||
formRef.value.scrollToField(prop);
|
||||
}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
formRef,
|
||||
validate,
|
||||
validateField,
|
||||
resetFields,
|
||||
clearValidate,
|
||||
scrollToField,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.form-layout-form {
|
||||
width: 100%;
|
||||
|
||||
.form-items-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
column-gap: 16px;
|
||||
row-gap: 16px;
|
||||
|
||||
.form-item-break {
|
||||
flex-basis: 100%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
justify-content: flex-start;
|
||||
flex: 0 0 auto;
|
||||
|
||||
.el-form-item__content {
|
||||
justify-content: flex-start;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user