mrr.sj.front/components/dynamic-form/dynamic-form.vue

198 lines
5.0 KiB
Vue

<template>
<view class="dynamic-form">
<view v-for="(field, index) in fields" :key="field.id || index" class="form-item"
:class="{ 'form-item-up': isUpType(field.type) }">
<view class="form-header">
<text class="form-label" :class="{ required: field.is_required == 1 }">{{ field.label }}</text>
<text v-if="field.tips" class="form-tips">{{ field.tips }}</text>
</view>
<view class="form-control">
<!-- 单行文本 -->
<form-item-text v-if="field.type === 'text'" :value="formData[field.key]"
:placeholder="field.placeholder" @input="onInput(field.key, $event)" />
<!-- 多行文本 -->
<form-item-textarea v-else-if="field.type === 'textarea'" :value="formData[field.key]"
:placeholder="field.placeholder" @input="onInput(field.key, $event)" />
<!-- 数字输入 -->
<form-item-number v-else-if="field.type === 'number'" :value="formData[field.key]"
:placeholder="field.placeholder" @input="onInput(field.key, $event)" />
<!-- 多图上传 -->
<form-item-image v-else-if="field.type === 'image_multi'" :value="formData[field.key]"
:maxCount="field.maxCount || 9" @input="onInput(field.key, $event)" />
<!-- 视频上传 -->
<form-item-video v-else-if="field.type === 'video'" :value="formData[field.key]"
@input="onInput(field.key, $event)" />
<!-- 下拉选择 -->
<form-item-select v-else-if="field.type === 'select'" :value="formData[field.key]"
:options="field.options" :placeholder="field.placeholder" @input="onInput(field.key, $event)" />
<!-- 单选 -->
<form-item-radio v-else-if="field.type === 'single_select'" :value="formData[field.key]"
:options="field.options" @input="onInput(field.key, $event)" />
<!-- 多选 -->
<form-item-checkbox v-else-if="field.type === 'multi_select'" :value="formData[field.key]"
:options="field.options" @input="onInput(field.key, $event)" />
<!-- 图文编辑器 -->
<form-item-richtext v-else-if="field.type === 'richtext_editor'" :value="formData[field.key]"
@input="onInput(field.key, $event)" />
</view>
</view>
</view>
</template>
<script>
import FormItemText from './FormItemText.vue';
import FormItemTextarea from './FormItemTextarea.vue';
import FormItemNumber from './FormItemNumber.vue';
import FormItemImage from './FormItemImage.vue';
import FormItemVideo from './FormItemVideo.vue';
import FormItemSelect from './FormItemSelect.vue';
import FormItemRadio from './FormItemRadio.vue';
import FormItemCheckbox from './FormItemCheckbox.vue';
import FormItemRichtext from './FormItemRichtext.vue';
export default {
name: 'DynamicForm',
components: {
FormItemText,
FormItemTextarea,
FormItemNumber,
FormItemImage,
FormItemVideo,
FormItemSelect,
FormItemRadio,
FormItemCheckbox,
FormItemRichtext
},
props: {
fields: {
type: Array,
default: function () {
return [];
}
},
value: {
type: Object,
default: function () {
return {};
}
}
},
data: function () {
return {
formData: {}
};
},
watch: {
value: {
handler: function (val) {
this.formData = Object.assign({}, val);
},
immediate: true,
deep: true
},
fields: {
handler: function (val) {
var self = this;
if (val && val.length > 0) {
val.forEach(function (field) {
if (self.formData[field.key] === undefined) {
self.$set(self.formData, field.key, self.getDefaultValue(field.type));
}
});
}
},
immediate: true
}
},
methods: {
isUpType: function (type) {
return type === 'image_multi' || type === 'video';
},
getDefaultValue: function (type) {
if (type === 'multi_select') {
return [];
}
if (type === 'image_multi') {
return [];
}
return '';
},
onInput: function (key, val) {
this.$set(this.formData, key, val);
this.$emit('input', Object.assign({}, this.formData));
},
validate: function () {
for (var i = 0; i < this.fields.length; i++) {
var field = this.fields[i];
if (field.is_required == 1) {
var val = this.formData[field.key];
if (val === undefined || val === null || val === '' || (Array.isArray(val) && val.length === 0)) {
uni.showToast({
title: '请填写' + field.label,
icon: 'none'
});
return false;
}
}
}
return true;
},
getData: function () {
return Object.assign({}, this.formData);
}
}
};
</script>
<style scoped>
.dynamic-form {
width: 100%;
}
.form-item {
background-color: #fff;
padding: 24rpx;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
border-radius: 10rpx;
margin-bottom: 24rpx;
}
.form-item-up {
flex-flow: column nowrap;
justify-content: space-between;
align-items: flex-start;
}
.form-header {
display: flex;
align-items: center;
margin-bottom: 16rpx;
}
.form-label {
font-size: 28rpx;
color: #333333;
}
.form-label.required::before {
content: '*';
color: #e8101e;
margin-right: 4rpx;
}
.form-tips {
font-size: 24rpx;
color: #999999;
margin-left: 10rpx;
}
.form-control {
width: 100%;
flex: 1;
}
</style>