|
@@ -0,0 +1,377 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <a-form
|
|
|
|
|
+ :model="form_values"
|
|
|
|
|
+ :style="{ width: '100%' }"
|
|
|
|
|
+ :rules="form_rules"
|
|
|
|
|
+ class="dynamic-form-container-jfsdjaklfjsfjsdkalfjskaljsk"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template v-for="(item, index) of form_fields">
|
|
|
|
|
+ <!-- 单行文本:数字 -->
|
|
|
|
|
+ <a-form-item v-if="item.type === FIELD_TYPE.NUMBER" :key="index" :field="item.variable" :label="item.label">
|
|
|
|
|
+ <a-input v-model="form_values[item.variable]" :placeholder="item.label" type="number" />
|
|
|
|
|
+ </a-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 单行文本:文字 -->
|
|
|
|
|
+ <a-form-item v-if="item.type === FIELD_TYPE.TEXT_INPUT" :key="index" :field="item.variable" :label="item.label">
|
|
|
|
|
+ <a-input v-model="form_values[item.variable]" :placeholder="item.label" />
|
|
|
|
|
+ </a-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 段落:多行文本 -->
|
|
|
|
|
+ <a-form-item v-if="item.type === FIELD_TYPE.PARAGRAPH" :key="index" :field="item.variable" :label="item.label">
|
|
|
|
|
+ <a-textarea v-model="form_values[item.variable]" :placeholder="item.label" :auto-size="item.autosize" />
|
|
|
|
|
+ </a-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 多选 -->
|
|
|
|
|
+ <a-form-item v-if="item.type === FIELD_TYPE.SELECT" :key="index" :field="item.variable" :label="item.label">
|
|
|
|
|
+ <a-select v-model="form_values[item.variable]" :placeholder="item.label" allow-clear>
|
|
|
|
|
+ <a-option v-for="(opt, idx) of item.options" :value="opt" :key="opt + '_' + idx">{{ opt }}</a-option>
|
|
|
|
|
+ </a-select>
|
|
|
|
|
+ </a-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 单文件上传 -->
|
|
|
|
|
+ <a-form-item
|
|
|
|
|
+ v-if="item.type === FIELD_TYPE.FILE"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ :field="item.variable"
|
|
|
|
|
+ :label="item.label"
|
|
|
|
|
+ :required="item.required"
|
|
|
|
|
+ :rules="[]"
|
|
|
|
|
+ :validate-trigger="[]"
|
|
|
|
|
+ >
|
|
|
|
|
+ <a-upload
|
|
|
|
|
+ v-model:file-list="form_values[item.variable]"
|
|
|
|
|
+ :multiple="false"
|
|
|
|
|
+ :limit="1"
|
|
|
|
|
+ :accept="item.accept"
|
|
|
|
|
+ :auto-upload="false"
|
|
|
|
|
+ @change="handleFileChange(item, $event)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #upload-button>
|
|
|
|
|
+ <BtnFileUpload :popmessage="item.popmessage" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <template #file-name="{ fileItem }">
|
|
|
|
|
+ <a-tooltip :content="fileItem.name">
|
|
|
|
|
+ <span>{{ fileItem.name }}</span>
|
|
|
|
|
+ </a-tooltip>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </a-upload>
|
|
|
|
|
+ </a-form-item>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 多文件上传 -->
|
|
|
|
|
+ <a-form-item
|
|
|
|
|
+ v-if="item.type === FIELD_TYPE.FILE_LIST"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ :field="item.variable"
|
|
|
|
|
+ :label="item.label"
|
|
|
|
|
+ :required="item.required"
|
|
|
|
|
+ :rules="[]"
|
|
|
|
|
+ :validate-trigger="[]"
|
|
|
|
|
+ >
|
|
|
|
|
+ <a-upload
|
|
|
|
|
+ v-model:file-list="form_values[item.variable]"
|
|
|
|
|
+ :multiple="true"
|
|
|
|
|
+ :auto-upload="false"
|
|
|
|
|
+ :limit="item.limit"
|
|
|
|
|
+ :accept="item.accept"
|
|
|
|
|
+ @change="handleFileChange(item, $event)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #upload-button>
|
|
|
|
|
+ <BtnFileUpload :popmessage="item.popmessage" />
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <template #file-name="{ fileItem }">
|
|
|
|
|
+ <a-tooltip :content="fileItem.name">
|
|
|
|
|
+ <span>{{ fileItem.name }}</span>
|
|
|
|
|
+ </a-tooltip>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </a-upload>
|
|
|
|
|
+ </a-form-item>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </a-form>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import { ref, reactive, computed, onMounted } from 'vue';
|
|
|
|
|
+import getFieldFileUplaodAcceptString from './file-accept';
|
|
|
|
|
+import getFieldFileUplaodMessageString from './file-message';
|
|
|
|
|
+
|
|
|
|
|
+import BtnFileUpload from './BtnFileUpload.vue';
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 表单类型
|
|
|
|
|
+ */
|
|
|
|
|
+const FIELD_TYPE = {
|
|
|
|
|
+ // 输入数字
|
|
|
|
|
+ NUMBER: 'number',
|
|
|
|
|
+ // 输入单行文本
|
|
|
|
|
+ TEXT_INPUT: 'text-input',
|
|
|
|
|
+ // 输入段落:多行文本
|
|
|
|
|
+ PARAGRAPH: 'paragraph',
|
|
|
|
|
+ // 下拉选项
|
|
|
|
|
+ SELECT: 'select',
|
|
|
|
|
+ // 单文件上传
|
|
|
|
|
+ // 允许的文件扩展名
|
|
|
|
|
+ FILE: 'file',
|
|
|
|
|
+ // 多文件上传
|
|
|
|
|
+ // 允许的文件扩展名
|
|
|
|
|
+ // 最大可上传的文件数量
|
|
|
|
|
+ FILE_LIST: 'file-list'
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const props = defineProps({
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 配置项
|
|
|
|
|
+ */
|
|
|
|
|
+ form_params: Array
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 表单的所有值
|
|
|
|
|
+ */
|
|
|
|
|
+const form_values = reactive(initFormValues());
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 文件数据
|
|
|
|
|
+ */
|
|
|
|
|
+const file_values = ref({});
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 表单的各字段参数
|
|
|
|
|
+ */
|
|
|
|
|
+const form_fields = computed(() => {
|
|
|
|
|
+ const forms_conf = props.form_params;
|
|
|
|
|
+
|
|
|
|
|
+ const conf_list = [];
|
|
|
|
|
+
|
|
|
|
|
+ const len = forms_conf.length;
|
|
|
|
|
+
|
|
|
|
|
+ for (let i = 0; i < len; i++) {
|
|
|
|
|
+ const item = forms_conf[i];
|
|
|
|
|
+
|
|
|
|
|
+ const itm_tp = item.type;
|
|
|
|
|
+
|
|
|
|
|
+ // 默认值
|
|
|
|
|
+ const conf = {
|
|
|
|
|
+ type: itm_tp,
|
|
|
|
|
+ label: item.label,
|
|
|
|
|
+ variable: item.variable,
|
|
|
|
|
+ options: item.options,
|
|
|
|
|
+ popmessage: item.label
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if (itm_tp === FIELD_TYPE.PARAGRAPH) {
|
|
|
|
|
+ // 段落
|
|
|
|
|
+ conf.autosize = {
|
|
|
|
|
+ minRows: 2,
|
|
|
|
|
+ maxRows: 5
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 文档 < 15.00MB, 图片 < 10.00MB, 音频 < 50.00MB, 视频 < 100.00MB
|
|
|
|
|
+ if (itm_tp === FIELD_TYPE.FILE) {
|
|
|
|
|
+ // 单文件上传
|
|
|
|
|
+ conf.required = item.required;
|
|
|
|
|
+ conf.accept = getFieldFileUplaodAcceptString(item.allowed_file_types, item.allowed_file_extensions);
|
|
|
|
|
+ conf.popmessage = getFieldFileUplaodMessageString(item.allowed_file_types, 1);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (itm_tp === FIELD_TYPE.FILE_LIST) {
|
|
|
|
|
+ // 多文件上传: 最多允许上传的数量
|
|
|
|
|
+ conf.limit = item.max_length;
|
|
|
|
|
+ conf.required = item.required;
|
|
|
|
|
+ conf.accept = getFieldFileUplaodAcceptString(item.allowed_file_types, item.allowed_file_extensions);
|
|
|
|
|
+ conf.popmessage = getFieldFileUplaodMessageString(item.allowed_file_types, item.max_length);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ conf_list.push(conf);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return conf_list;
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 初始化表单的所有数据项
|
|
|
|
|
+ */
|
|
|
|
|
+function initFormValues() {
|
|
|
|
|
+ const form_info = props.form_params;
|
|
|
|
|
+
|
|
|
|
|
+ const obj = {};
|
|
|
|
|
+ const len = form_info.length;
|
|
|
|
|
+
|
|
|
|
|
+ for (let i = 0; i < len; i++) {
|
|
|
|
|
+ const item = form_info[i];
|
|
|
|
|
+
|
|
|
|
|
+ const field_tp = item.type;
|
|
|
|
|
+ const field_name = item.variable;
|
|
|
|
|
+ const is_required = item.required;
|
|
|
|
|
+
|
|
|
|
|
+ if (field_tp === FIELD_TYPE.FILE || field_tp === FIELD_TYPE.FILE_LIST) {
|
|
|
|
|
+ obj[field_name] = [];
|
|
|
|
|
+ } else {
|
|
|
|
|
+ obj[field_name] = '';
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return obj;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 表单校验规则
|
|
|
|
|
+ */
|
|
|
|
|
+const form_rules = computed(() => {
|
|
|
|
|
+ const form_info = props.form_params;
|
|
|
|
|
+
|
|
|
|
|
+ const obj = {};
|
|
|
|
|
+ const len = form_info.length;
|
|
|
|
|
+
|
|
|
|
|
+ for (let i = 0; i < len; i++) {
|
|
|
|
|
+ const item = form_info[i];
|
|
|
|
|
+
|
|
|
|
|
+ const field_tp = item.type;
|
|
|
|
|
+ const field_name = item.variable;
|
|
|
|
|
+ const is_required = item.required;
|
|
|
|
|
+
|
|
|
|
|
+ if (field_tp === FIELD_TYPE.FILE || field_tp === FIELD_TYPE.FILE_LIST) {
|
|
|
|
|
+ // 文件上传: 文件上传的验证不通过表单,通过自定义验证方式进行验证
|
|
|
|
|
+ // if (is_required) {
|
|
|
|
|
+ // item_rule.push({
|
|
|
|
|
+ // required: is_required,
|
|
|
|
|
+ // message: ''
|
|
|
|
|
+ // });
|
|
|
|
|
+ // }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const item_rule = [];
|
|
|
|
|
+
|
|
|
|
|
+ // 是否是必填项
|
|
|
|
|
+ if (is_required) {
|
|
|
|
|
+ item_rule.push({
|
|
|
|
|
+ required: is_required,
|
|
|
|
|
+ message: `${item.label}是必填项`
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 不是必填项
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (field_tp === FIELD_TYPE.TEXT_INPUT || field_tp === FIELD_TYPE.PARAGRAPH) {
|
|
|
|
|
+ if (item.max_length > 0) {
|
|
|
|
|
+ // 配置最大值验证
|
|
|
|
|
+ item_rule.push({
|
|
|
|
|
+ maxLength: item.max_length,
|
|
|
|
|
+ message: `最大长度为${item.max_length}`
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ obj[field_name] = item_rule;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return obj;
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 处理文件响应
|
|
|
|
|
+ * @param item
|
|
|
|
|
+ * @param event
|
|
|
|
|
+ */
|
|
|
|
|
+const handleFileChange = (item, event) => {
|
|
|
|
|
+ const field_key = item.variable;
|
|
|
|
|
+
|
|
|
|
|
+ // 使用file_values保存文件
|
|
|
|
|
+ file_values.value[field_key] = event;
|
|
|
|
|
+
|
|
|
|
|
+ // // 保存文件的数据信息
|
|
|
|
|
+ // form_values[field_key] = event;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const handleSubmit = (data) => {
|
|
|
|
|
+ console.log(data);
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 获取表单里的所有数据
|
|
|
|
|
+ */
|
|
|
|
|
+const getFormFiledValues = () => {
|
|
|
|
|
+ const res_opts = {};
|
|
|
|
|
+
|
|
|
|
|
+ for (let key in form_values) {
|
|
|
|
|
+ const cur_val = form_values[key];
|
|
|
|
|
+
|
|
|
|
|
+ if (cur_val === undefined || cur_val === null || cur_val === '') {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ res_opts[key] = form_values[key];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const files = file_values.value;
|
|
|
|
|
+
|
|
|
|
|
+ const res_files = {};
|
|
|
|
|
+ for (let key in files) {
|
|
|
|
|
+ res_files[key] = files[key];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ // 键值对数据
|
|
|
|
|
+ options: res_opts,
|
|
|
|
|
+ // 文件数据
|
|
|
|
|
+ files: res_files
|
|
|
|
|
+ };
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 清空表单所有数据
|
|
|
|
|
+ */
|
|
|
|
|
+const clearFormFiledValues = () => {
|
|
|
|
|
+ // 初始化数据
|
|
|
|
|
+ const init_values = initFormValues();
|
|
|
|
|
+
|
|
|
|
|
+ for (let key in form_values) {
|
|
|
|
|
+ form_values[key] = init_values[key];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // TODO: 清除文件数据
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+defineExpose({
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 父组件通过ref,调用getValues方法,可以获取到表单里的所有数据
|
|
|
|
|
+ */
|
|
|
|
|
+ getValues: getFormFiledValues,
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 父组件通过ref,调用clear方法,可以将表单里数据清空
|
|
|
|
|
+ */
|
|
|
|
|
+ clear: clearFormFiledValues
|
|
|
|
|
+});
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped></style>
|
|
|
|
|
+
|
|
|
|
|
+<style>
|
|
|
|
|
+.dynamic-form-container-jfsdjaklfjsfjsdkalfjskaljsk .arco-upload-icon.arco-upload-icon-start {
|
|
|
|
|
+ display: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dynamic-form-container-jfsdjaklfjsfjsdkalfjskaljsk .arco-upload-progress {
|
|
|
|
|
+ display: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dynamic-form-container-jfsdjaklfjsfjsdkalfjskaljsk .arco-upload-list.arco-upload-list-type-text,
|
|
|
|
|
+.dynamic-form-container-jfsdjaklfjsfjsdkalfjskaljsk .arco-upload-list.arco-upload-list-type-picture {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ max-height: 400px;
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+ padding-right: 5px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dynamic-form-container-jfsdjaklfjsfjsdkalfjskaljsk .arco-upload-list.arco-upload-list-type-text,
|
|
|
|
|
+.dynamic-form-container-jfsdjaklfjsfjsdkalfjskaljsk .arco-upload-list.arco-upload-list-type-picture {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ max-height: 300px;
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+ padding-right: 5px;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|