封装一个表单组件(ArcoDesign+vue3)

<template>
  <a-row :gutter="24">
    <a-col :span="24 / colNum" v-for="(cItem, cIndex) in list" :key="cIndex">
      <a-row :gutter="24">
        <a-col
          :span="24 / cItem.length"
          v-for="item in cItem"
          :key="item.value"
        >
          <a-form-item
            v-if="item.type != 'upload'"
            :field="item.value"
            :label="$t(item.label)"
            :label-col-flex="labelWidth"
            :rules="getFormRules(item.rule,item.label,item.type)"
          >
            <template v-if="type != 'detail'">
              <!--  下拉选择 -->
              <a-select
                v-if="item.type == 'select'"
                v-model="filterForm[item.value]"
                :placeholder="$t('numDigital.pleaseSelect')"
              >
                <a-option
                  v-for="option in optionsData.optionsObj[item.optionName]"
                  :value="option.code"
                  :key="option.code"
                  >{
   
   { option.value }}</a-option
                >
              </a-select>
              <!--  输入框 -->
              <template v-if="item.type == 'input'">
                <a-input
                  :max-length="20"
                  v-model="filterForm[item.value]"
                  :placeholder="$t('numDigital.pleaseEnter')"
                />
                <span class="normal" v-if="item.units">&nbsp;{
   
   {
                 $t(item.units)
                }}</span>
              </template>

              <!--  数字输入框 --> 
              <!-- :formatter="formatter" :parser="parser" -->
              <template v-if="item.type == 'numberInput'">  
                <a-input-number
                  max-length="13"
                  v-model="filterForm[item.value]"
                  :placeholder="$t('numDigital.pleaseEnter')"
                  :min="item.min"
                  :max="item.max"
                  :precision="getPrecision(item.precision)"
                />
                <span class="normal" v-if="item.units">&nbsp;{
   
   {
                  $t(item.units)
                }}</span>
              </template>
              <!-- 多行输入框 -->
              <a-textarea
                v-if="item.type == 'textArea'"
                class="textarea"
                :placeholder="$t('numDigital.pleaseEnter')"
                v-model="filterForm[item.value]"
                max-length="200"
              />
              <!-- 单选框 -->
              <a-space size="large" v-if="item.type == 'radio'">
                <a-radio-group v-model="filterForm[item.value]">
                  <a-radio :value="1">{
   
   { $t('common.yes') }}</a-radio>
                  <a-radio :value="0">{
   
   { $t('common.no') }}</a-radio>
                </a-radio-group>
              </a-space>
              <!-- 日期选择 -->
              <a-date-picker
                style="width:100%"
                value-format="YYYY-MM-DD "
                v-if="item.type == 'datePicker'"
                v-model="filterForm[item.value]"
              />
              <!--  日期范围 -->  <!-- :value-format="item.valueFormat?item.valueFormat:'YYYY-MM-DD'" -->
              <a-range-picker
                v-if="item.type == 'rangePicker'"  
                @change="timeChange(item)"
                v-model="filterForm[item.value]"
              />
              <!-- 月份选择 -->
              <a-month-picker  
              style="width:100%"
              v-if="item.type == 'monthPicker'"
               v-model="filterForm[item.value]"
              />
            <!--   月份范围 -->
            <a-range-picker
              mode="month"
              v-if="item.type == 'monthRangePicker'"
              v-model="filterForm[item.value]"
            />
              <!-- 输入范围 -->
              <template v-if="item.type == 'inputRange'">
                <a-input
                  max-length="20"
                  v-model="filterForm[item.value[0]]"
                  :placeholder="$t('numDigital.pleaseEnter')"
                />
                <span class="normal">&nbsp;{
   
   { $t('lease.to')}}&nbsp;</span>
                <a-input
                  max-length="20"
                  v-model="filterForm[item.value[1]]"
                  :placeholder="$t('numDigital.pleaseEnter')"
                />
                <span class="normal" v-if="item.units">&nbsp;{
   
   {
                  $t(item.units)
                }}</span>
              </template>
             <!--  输入数字范围 -->
              <template v-if="item.type == 'numberInputRange'">  <!-- :formatter="formatter" :parser="parser" -->
                <a-input-number
                  max-length="13"
                  v-model="filterForm[item.value[0]]"
                  
                  :placeholder="$t('numDigital.pleaseEnter')"
                  :precision="getPrecision(item.precision)"
                  :min="item.min"
                  :max="item.max"
                />
                <span class="normal">&nbsp;{
   
   { $t('lease.to') }}&nbsp;</span>
                <a-input-number
                  max-length="13"
                 
                  v-model="filterForm[item.value[1]]"
                  :placeholder="$t('numDigital.pleaseEnter')"
                  :precision="getPrecision(item.precision)"
                  :min="filterForm[item.value[0]]"
                  :max="item.max"
                />
                <span class="normal" v-if="item.units">&nbsp;{
   
   {
                 $t(item.units)
                }}</span>
              </template>
            </template>
            <slot name="detail" :data="item" />
          </a-form-item>
          <template v-if="item.type == 'upload'">
            <fileUploader ref="myfileUploader" @onsuccess="uploadOnsuccess" :type="type" :showUploadBtn="type=='detail'?false:true" :fileList="file.fileList" >
              <template #button> 
                <a-button type="primary">
                  <template #icon>
                    <icon-upload />
                  </template>
                   <template #default>{
   
   { $t('common.uploadAttach') }}</template>
                </a-button>
              </template>
            </fileUploader>
          </template>
        </a-col>
      </a-row>
    </a-col>
  </a-row>
</template>
<script lang="ts" setup>
import { defineProps, defineEmits, ref,computed, onMounted, watch,onBeforeMount,defineExpose ,nextTick,reactive,getCurrentInstance} from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
import useLoading from '@/hooks/loading';
const { loading, setLoading } = useLoading();
import {  getWebDictList } from '@/api/user';
import fileUploader from '@/components/uploader/FileUploader.vue';
import { valid } from 'mockjs';
const emit = defineEmits(['uploadOnsuccess']);

const props = defineProps({
  labelWidth: {
    type: String,
    default: '130px'
  },
  type: {
    type: String,
    default: 'search'
  },
  list: Array,
  filterForm: Object,
  colNum: Number,
});
onMounted(()=>{
  getAllOptions();
})
/****文件列表处理****/
watch(
()=>props.filterForm.attachment,
(val)=>{
  getFileList(val);
},
{deep:true, }
);
const file=reactive({fileList:[]});
const getFileList=(attachment:any)=>{
  if(attachment){
   let attachment=props.filterForm.attachment;
   let attachmentName=props.filterForm.attachmentName;
   const attachmentArr=attachment.split(',');
   const attachmentNameArr=attachmentName?attachmentName.split(','):[];
    let saveArr=[];
    for(let i=0;i<attachmentArr.length;i++){
      let name=attachmentArr[i].substring(attachmentArr[i].lastIndexOf('/') + 1);
      let itemObj={
        id:i,
        name:attachmentNameArr[i]||name,
        url:attachmentArr[i]
      }
       saveArr.push(itemObj);
    }
    file.fileList=saveArr;
  }else{
    file.fileList=[];
  }
}
const timeChange = (item:any) => {
  if(props.filterForm[item.value]&&props.filterForm[item.value].length>0){
    props.filterForm[item.startTimeField || "startTime"] =props.filterForm[item.value][0] + " 00:00:00";
    props.filterForm[item.endTimeField || "endTime"] =props.filterForm[item.value][1] + " 23:59:59";
  }else{
     props.filterForm[item.startTimeField || "startTime"]="";
     props.filterForm[item.endTimeField || "endTime"] =""
  }
  
};
//对下拉框选项处理
let optionsData=reactive({
  optionsObj:{}
});
const getAllOptions=()=>{
  const lists=props.list;
  lists.forEach(row=>{
    row.forEach(col=> {
      if(col.type=='select'){
          getOptionsFun(col.optionName);
      }
    });
  })
}
const getOptionsFun=async(typeName:any)=>{
  setLoading(true);
      try {
        const res = await getWebDictList({
           type: typeName
         });
          if (res.code == 0) {
            const list:any|undefined|null=res.data||[];
            optionsData.optionsObj=Object.assign(optionsData.optionsObj,{[typeName]:list});
          
          }
         
      }catch(err){
   
      } finally {
       setLoading(false);
     }
}
watch(
()=>props.filterForm,
(val)=>{
  transFormToNumber(props.list);
},
{deep:true}
);
//转换成数字
const transFormToNumber=(rowList:any)=>{
  for(let i=0;i<rowList.length;i++){
    for(let j=0;j<rowList[i].length;j++){
      const itemType=rowList[i][j].type;
      const itemValue=rowList[i][j].value;
      if(itemType=="numberInput"&&props.filterForm[itemValue]){
        const _val=props.filterForm[itemValue];
        props.filterForm[itemValue]=Number(_val);
      }
       if(itemType=="numberInputRange"&&props.filterForm[itemValue[0]]&&props.filterForm[itemValue[1]]){
        const _val1=props.filterForm[itemValue[0]];
        const _val2=props.filterForm[itemValue[1]];
         props.filterForm[itemValue[0]]=Number(_val1)
         props.filterForm[itemValue[1]]=Number(_val2)
       }
      
    }
  }
}
//上传附件
const uploadOnsuccess = (files: any) => {
  emit('uploadOnsuccess', files);
};
const formatter = (value:any) => {
  const values = value.split('.');
  values[0] = values[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');

  return values.join('.');
};

const parser = (value:any) => {
  const val=value.replace(/,/g, '');
  return val;
};
//数字输入精度
const getPrecision=computed(()=>{
   return (precisionVal:Number)=>{
     if(precisionVal){
       return precisionVal
     }else if(precisionVal==0){
       return precisionVal
     }else{
       return 2;
     }
   }
 })
 const toNumber=computed(()=>{
   return (val:any)=>{
     return Number(val)
   }
 })
//表单校验规则
const getFormRules=computed(()=>{
  return (rule:any,label:any,type:any)=>{
     let typeMessage="";
     if(type=='select'||type=='radio'||type=='datePicker'||type=='rangePicker'){
       typeMessage='numDigital.pleaseSelect'
     }else{
       typeMessage='numDigital.pleaseEnter'
     }
     if(rule&&rule.required){
        let ruleArr:any=[{required:true,message:t(typeMessage) + t(label)}];
        return ruleArr;
     }else{
       return []
     }
  }
 //
 
 
 
})
</script>
<style lang="less" scoped>
.normal {
  font-size: 14px;
  color: var(--color-text-2);
  flex: none;
}
 .textarea {
    /*   width: 464px;
      height: 120px; */
    }
  :deep{
    .arco-form-item-label-col > .arco-form-item-label{
      white-space: nowrap;
      
      overflow: hidden;
    }
    .arco-radio-group .arco-radio{
      margin-right:0;
    }
  }
</style>

页面引入使用

 <a-form>
      <a-row :gutter="24">
        <a-col :span="buttonStyle=='column'?22:20">
          <formItem :colNum='colNum' :list="formList" :filterForm="form" :labelWidth="labelWidth" />
        </a-col>
        <a-col :span="buttonStyle=='column'?2:4">
          <div class="btn-wrap">
            <template v-if="buttonStyle=='column'">
              <a-row justify="right">
              <a-form-item>
                <a-button @click="submitForm(filterForm)" type="primary">{
   
   {
                  $t('common.search')
                }}</a-button>
              </a-form-item>
            </a-row>
            <a-row class="resert">
              <a-form-item>
                <a-button @click="resetForm">{
   
   { $t('common.reset') }}</a-button>
              </a-form-item>
            </a-row>
            </template>
            <template v-else>
              <a-space :size="gutter">
                 <a-button @click="submitForm(filterForm)" type="primary">{
   
   {
                  $t('common.search')
                }}</a-button>
                 <a-button @click="resetForm">{
   
   { $t('common.reset') }}</a-button>
              </a-space>
            </template>
          </div>
        </a-col>
      </a-row>
    </a-form>
form: {
    schoolName: '',
    assetName: '',
    acquisitionDate: '',
    isByEducation: '',
    isEducationBuilding: '',
    isHire: '',
    area: '',
    situation: '',
    startDate: '',
    endDate: '',
    price: '',
    annualIncome: '',
    tenantry: '',
    leasePurpose: '',
    approvalDepartment: '',
    remark: '',
    attachment: '',
    attachmentName:"",
    fileIds: []
  },
formList: [
    {
      id: 1,
      title: 'lease.add.basicInformation',
      rows: [
        [
          {
            type: 'select',
            value: 'schoolName',
            label: 'lease.campusName',
            options: [],
            optionName:'campus_name',
            rule: {
              required: true
            }
          }
        ],
        [
          {
            type: 'input',
            value: 'assetName',
            label: 'lease.assetName',
            rule: { required: true }
          }
        ],
        [
          {
            type: 'datePicker',
            value: 'acquisitionDate',
            label: 'lease.acquisitionDate',
            rule: { required: true }
          }
        ],
        [
          {
            type: 'input',
            value: 'propertyOwner',
            label: 'lease.possessor',
            rule: { required: true }
          }
        ],
        [
          {
            type: 'radio',
            value: 'isEducationBuilding',
            label: 'lease.teachingBuilding',
            rule: { required: true }
          }
        ],
        [
          {
            type: 'numberInput',
            value: 'area',
            label: 'lease.area',
            units: 'lease.squareMeter',
            min: '0',
            max: '',
            rule: { required: true }
          }
        ],
        [
          {
            type: 'input',
            value: 'situation',
            label: 'lease.situation',
            rule: { required: true }
          }
        ]
      ]
    },
    {
      id: 2,
      title: 'lease.add.leasingAndLendingAssets',
      rows: [
        [
          {
            type: 'datePicker',
            value: 'startDate',
            label: 'lease.startDate',
            rule: { required: true }
          }
        ],
        [
          {
            type: 'datePicker',
            value: 'endDate',
            label: 'lease.endDate',
            rule: { required: true }
          }
        ],
        [
          {
            type: 'numberInput',
            value: 'price',
            label: 'lease.add.unitPrice',
            units: 'lease.add.priceUnits',
            min: '0',
            rule: { required: true }
          }
        ],
        [
          {
            type: 'numberInput',
            value: 'annualIncome',
            label: 'lease.add.income',
            units: 'lease.add.incomeUnits',
            min: '0',
            precision: 6,
            rule: { required: true }
          }
        ],
        [
          {
            type: 'input',
            value: 'tenantry',
            label: 'lease.lessee',
            rule: { required: true }
          }
        ],
        [
          {
            type: 'input',
            value: 'leasePurpose',
            label: 'lease.lendLease',
            rule: { required: true }
          }
        ]
      ]
    },
    {
      id: 3,
      title: 'lease.add.otherInformation',
      rows: [
        [
          {
            type: 'input',
            value: 'approvalDepartment',
            label: 'lease.department',
            rule: { required: true }
          }
        ],
        [
          {
            type: 'radio',
            value: 'isByEducation',
            label: 'lease.add.educationAudited',
            rule: { required: true }
          },
          {
            type: 'radio',
            value: 'isHire',
            label: 'lease.publicRent',
            rule: { required: true }
          }
        ],
        [
          {
            type: 'textArea',
            value: 'remark',
            label: 'common.remarks',
            rule: { required: false }
          }
        ]
      ]
    },
    {
      id: 4,
      title: 'lease.add.attachment',
      rows: [
        [
          {
            type: 'upload',
            value: 'fileIds',
            label: '',
            rule: { required: false }
          }
        ]
      ]
    }
  ],

页面效果:

猜你喜欢

转载自blog.csdn.net/Holly31/article/details/128845069