vue+element ui实现表单组件的封装

效果图:
在这里插入图片描述
在这里插入图片描述

主要是使用vue + elmentUi 的from的基础上进行封装
在这里插入图片描述

使用改组件,是需要自定义从父组件传入一下字段表单字段

export const topicTypeMainTaskEdit: any = new Map([
  // 主任务可编辑状态
  [
    'feasibleInstructions', // 督办件
    [
      {
        value: 'documentNum',
        formKey: ['documentNum'],
        rules: [
          { required: true, message: '请输入办文编号', trigger: 'blur' },
          { min: 0, max: 30, message: '办文编号字数长度超过限制' }
        ],
        label: '办文编号',
        class: 'half-item',
        type: 'text',
        maxlength: 30
      },
      {
        value: 'taskTitle',
        formKey: ['taskTitle'],
        rules: [
          { required: true, message: '请输入任务标题', trigger: 'blur' },
          { min: 0, max: 300, message: '任务标题字数长度超过限制' }
        ],
        label: '任务标题',
        class: 'half-item-all',
        isMate: true, // 填写时是否和关联任务的相应的字段匹配
        type: 'text',
        maxlength: 300
      },
      {
        value: 'taskSourceId',
        formKey: {
          value: 'taskSourceId',
          label: 'taskSource'
        },
        rules: [
          { required: true, message: '请选择事项类型', trigger: 'change' }
        ],
        hasSlot: {
          key: 'taskSource',
          label: '事项类型管理',
          type: 'managementMatters'
        },
        slotKey: 'taskSource',
        label: '事项类型',
        type: 'select',
        list: 'itemTypeList',
        options: () => JSON.parse(localStorage.getItem('store')).firstLevelTask.itemTypeData.filter(res => { return res.dicStatus * 1 === 1 })
      },
      {
        value: 'mainLeaderId',
        formKey: {
          value: 'mainLeaderId',
          label: 'mainLeader'
        },
        label: '批示领导',
        hasSlot: {
          key: 'mainLeader',
          label: '批示领导管理',
          type: 'managementMatters'
        },
        slotKey: 'mainLeader',
        type: 'select',
        multiple: true,
        list: 'leaderOptions',
        options: () => JSON.parse(localStorage.getItem('store')).firstLevelTask.mainLeaderData.filter(res => { return res.dicStatus * 1 === 1 })
      },
      {
        value: 'indicationTime',
        formKey: ['indicationTime'],
        label: '批示时间',
        class: 'half-item',
        type: 'date',
        noLimitCurrentDate: true // false为限制不能选当天以前的日期
      },
      {
        value: 'itemClaim',
        formKey: ['itemClaim'],
        rules: [
          { min: 0, max: 300, message: '省领导批示内容字数长度超过限制' }
        ],
        label: '省领导批示内容',
        class: '',
        type: 'textarea',
        showWordLimit: true,
        maxlength: 300,
        rows: 4
      },
      {
        value: 'workRequire',
        formKey: ['workRequire'],
        rules: [
          { min: 0, max: 300, message: '领导跟批情况字数长度超过限制' }
        ],
        label: '领导跟批情况',
        class: '',
        type: 'textarea',
        showWordLimit: true,
        maxlength: 300,
        rows: 4
      },
      {
        value: 'documentUrl',
        formKey: ['documentUrl'],
        // rules: [
        //   { required: true, message: '请输入相关公文', trigger: 'blur' }
        // ],
        label: '相关公文',
        class: 'half-item',
        type: 'text',
        maxlength: 300
      },
      // {
      //   value: 'documentUrl',
      //   label: '相关公文',
      //   formKey: ['documentUrl', 'mainDeptId', 'mainUnitId'],
      //   type: 'authPanel',
      //   authPanelType: 'department',
      //   deptArray: [],
      //   multiple: true
      // },
      {
        value: 'taskContent',
        formKey: ['taskContent'],
        rules: [
          { required: true, message: '请输入任务描述', trigger: 'blur' },
          { min: 0, max: 800, message: '任务描述字数长度超过限制' }
        ],
        label: '任务描述',
        class: '',
        type: 'textarea',
        showWordLimit: true,
        isMate: true, // 填写时是否和关联任务的相应的字段匹配
        maxlength: 800,
        rows: 4
      },
      {
        value: 'mainUnitName',
        rules: [
          { required: true, message: '请选择主办处室', trigger: 'blur' }
        ],
        label: '主办处室',
        formKey: ['mainUnitName', 'mainDeptId', 'mainUnitId'],
        type: 'authPanel',
        authPanelType: 'department',
        deptArray: [],
        multiple: true,
        linkage: 'mainUnitName',
        fn: (data: any, formData: any) => {
          let interrupt = false
          const departId = Array.isArray(data) && data.map(item => {
            return item.departId
          })
          formData && formData.forEach(i => {
            if (i.key === 'assistUnitNames') {
              i.deptArray.forEach(j => {
                if (departId.indexOf(j.departId) > -1) {
                  interrupt = true
                  Message({
                    message: `${j.name}不能同时作为主办、会办处室`,
                    type: 'error'
                  })
                }
              })
            }
          })
          return {
            interrupt
          }
        }
      },
      {
        value: 'assistUnitNames',
        label: '会办处室',
        formKey: ['assistUnitNames', 'assistDeptIds', 'assistUnitIds'],
        type: 'authPanel',
        authPanelType: 'department',
        deptArray: [],
        multiple: true,
        linkage: 'assistUnitNames',
        fn: (data: any, formData: any) => {
          let interrupt = false
          const departId = Array.isArray(data) && data.map(item => {
            return item.departId
          })
          formData && formData.forEach(i => {
            if (i.key === 'mainUnitName') {
              i.deptArray.forEach(j => {
                if (departId.indexOf(j.departId) > -1) {
                  interrupt = true
                  Message({
                    message: `${j.name}不能同时作为主办、会办处室`,
                    type: 'error'
                  })
                }
              })
            }
          })
          return {
            interrupt
          }
        }
      },
      {
        value: 'leaderId',
        formKey: {
          value: 'leaderId',
          label: 'leader'
        },
        rules: [
          { required: true, message: '请选择分管领导', trigger: 'change' }
        ],
        label: '分管领导',
        hasSlot: {
          key: 'leader',
          label: '分管领导管理',
          type: 'managementMatters'
        },
        slotKey: 'leader',
        type: 'select',
        multiple: true,
        list: 'leaderOptions',
        options: () => JSON.parse(localStorage.getItem('store')).firstLevelTask.leaderData.filter(res => { return res.dicStatus * 1 === 1 })
      },
      {
        value: 'supervisionCycle',
        formKey: ['cycleType', 'supervisionCycle', 'supervisionCycleIds', 'firstSubmitTime'],
        rules: [
          { required: true, message: '请选择报送时间' }
        ],
        label: '报送时间',
        class: 'half-item',
        type: 'deliveryTime'
      },
      {
        value: 'limitDate',
        formKey: ['limitDate'],
        label: '办结期限',
        class: 'half-item',
        type: 'date'
      },
      {
        value: 'peopleArray',
        formKey: ['sendCopys', 'sendCopysId', 'sendCopysDeptId'],
        label: '抄送人员',
        type: 'authPanel',
        authPanelType: 'people',
        deptArray: [],
        multiple: true,
        hasSameDataDefaultProps: { isSame: 'complexId', parentId: 'departId', childrenId: 'userId' }
      }
    ]
  ],
  [
    'keyWork', // 重点工作
    [
      {
        value: 'taskTitle',
        formKey: ['taskTitle'],
        rules: [
          { required: true, message: '请输入任务标题', trigger: 'blur' },
          { min: 0, max: 300, message: '任务标题字数长度超过限制' }
        ],
        label: '任务标题',
        type: 'text',
        maxlength: 300
      },
      {
        value: 'workRequire',
        formKey: ['workRequire'],
        rules: [
          { min: 0, max: 500, message: '描述字数长度超过限制' }
        ],
        label: '描述',
        type: 'textarea',
        showWordLimit: true,
        maxlength: 500,
        rows: 4
      },
      {
        value: 'taskSourceId',
        formKey: {
          value: 'taskSourceId',
          label: 'taskSource'
        },
        rules: [
          { required: true, message: '请选择事项类型', trigger: 'change' }
        ],
        hasSlot: {
          key: 'taskSource',
          label: '事项类型管理',
          type: 'managementMatters'
        },
        slotKey: 'taskSource',
        label: '事项类型',
        type: 'select',
        list: 'itemTypeList',
        options: () => JSON.parse(localStorage.getItem('store')).firstLevelTask.itemTypeData.filter(res => { return res.dicStatus * 1 === 1 })
      },
      // {
      //   value: 'documentUrl',
      //   label: '相关公文',
      //   formKey: ['documentUrl'],
      //   type: 'authPanel',
      //   authPanelType: 'department',
      //   deptArray: [],
      //   multiple: true
      // },
      {
        value: 'documentUrl',
        formKey: ['documentUrl'],
        label: '相关公文',
        class: 'half-item',
        type: 'text',
        maxlength: 300
      },
      {
        value: 'peopleArray',
        formKey: ['sendCopys', 'sendCopysId', 'sendCopysDeptId'],
        label: '抄送人员',
        type: 'authPanel',
        authPanelType: 'people',
        deptArray: [],
        multiple: true,
        hasSameDataDefaultProps: { isSame: 'complexId', parentId: 'departId', childrenId: 'userId' }
      }
    ]
  ]
])

然后先初始化表单字段的数据

const getTopicTypeData = this.topicTypeData.length > 0 ? this.topicTypeData : topicTypeData[this.topicTypeDataKey].get(this.otherTask || this.topicType)
    // const getTopicTypeData = this.topicTypeData.length > 0 ? this.topicTypeData : topicTypeData[this.topicTypeDataKey].get(this.topicType || this.otherTask)
    this.topicTypeMainTask = [...getTopicTypeData.map(item => {
      return { ...item, type: item.type === 'text' ? 'input' : item.type, isEdit: !item.disabled, key: item.value, value: '', options: typeof item.options === 'function' ? item.options() : item.options || '' }
    }), { key: 'fileJson', type: 'upload', value: '' }]
    this.topicTypeMainTask.forEach(item => {
      // if (item.type === 'authPanel' && item.authPanelType === 'people') {
      if (item.type === 'authPanel' && item.authPanelType === 'people' && !item.mixedData) {
        item.deptArray = this.taskData.sendCopysId ? this.resestPeopleArray(this.taskData.sendCopysId, this.taskData.sendCopys, this.taskData.sendCopysDeptId) : []
        item.value = this.taskData[item.key]
      } else if (item.type === 'authPanel' && (item.authPanelType === 'department' || (item.mixedData === true && item.authPanelType === 'people'))) {
        // else if (item.type === 'authPanel' && item.authPanelType === 'department') {
        if (item.disabled && typeof item.disabled === 'function') {
          item.disabled = item.disabled(!!(this.taskData.status && this.taskData.status === '4'))
        }
        item.deptArray = this.resestDeptArr(item.formKey)
        item.value = this.taskData[item.key]
      } else if (item.type === 'deliveryTime') {
        item.deliveryTime = {
          supervisionCycleIds: this.taskData.supervisionCycleIds,
          cycleType: this.taskData.cycleType,
          supervisionCycle: this.taskData.supervisionCycle,
          firstSubmitTime: this.taskData.firstSubmitTime
        }
        item.value = this.taskData[item.key]
      } else if (item.type === 'select') {
        if (this.topicType === 'coordinatingCommittee' && item.key === 'meetingTypeId') {
          item.value = '1'
        } else {
          if (item.multiple) {
            item.value = (this.taskData[item.key] && this.taskData[item.key].split(',')) || []
          } else {
            item.value = this.taskData[item.key]
          }
        }
      } else if (item.type === 'upload') {
        item.value = this.taskData[item.key] ? this.taskData[item.key] : '[]'
      } else {
        item.value = this.taskData[item.key]
      }
    })

这些字段都是存在在一个新ts文件中,如果对象有值,根据不用的表单类型进行赋值回显,没有的话就是空

表单组件中传入的值代表的意思
 props: {
    isShowSearchBtn: { // 是否显示查询按钮
      type: Boolean,
      default: true
    },
    labelPosition: { // 表单文本标题的位置
      type: String,
      default: 'right'
    },
    labelWidth: { // 表单文本标题的宽度
      type: String,
      default: ''
    },
    formItemWidth: {
      type: String,
      default: '100%'
    },
    setStyle: {
      type: Object,
      default: () => {
        return {}
      }
    },
    updateModel: {
      type: Object,
      default: () => {
        return {}
      }
    },
    isRules: { // 是否要校验
      type: Boolean,
      default: true
    },
    rules: { // 校验规则
      type: Object,
      default: () => {
        return {}
      }
    },
    formData: { // 表单数据
      type: Array,
      default: () => {
        return []
      }
    },
    inline: { // 是否是行内
      type: Boolean,
      default: true
    },
    flexWrap: {
      type: Boolean,
      default: false
    }, // 控制表单是否换行
    justifyContent: { // 布局
      type: String,
      default: 'space-between'
    }, // 表单布局风格
    noCheck: {
      type: Boolean,
      default: true
    },
    pickerOptions: { // 时间日期表单的时间限制
      type: Object,
      default: () => {
        return {
          disabledDate(time) {
            return time.getTime() < Date.now() - 8.64e7
          }
        }
      }
    }
  },

如果表单数据对象遍历中出现slotKey,代表这个字段是使用插槽
在这里插入图片描述

在父组件中使用插槽,然后将根据不用字段显示不同的内容
在这里插入图片描述

表单组件里面的表单类型
<el-form
      ref="formRef"
      :inline="inline"
      :model="model"
      :rules="isRules ? rules : {}"
      :label-position="labelPosition"
      :label-width="labelWidth"
      :style="{'flex-wrap': flexWrap ? 'nowrap' : 'wrap', 'justify-content' : justifyContent}"
    >
      <el-form-item
        v-for="(item,i) in formData"
        :key="'form'+i"
        :class="item.type + '-form'"
        :label="item.label"
        :prop="item.key"
        :rules="isRules ? item.rules : []"
        :error="item.success ? '' : item.message"
        :style="{width: item.width ? item.width : formItemWidth, ...item.style }"
      >
        <!-- 插槽 -->
        <template v-if="item.slotKey">
          <slot :name="item.slotKey" :row="item" />
        </template>
        <template v-else>
          <!-- 输入框 -->
          <el-input
            v-if="item.type === 'input'"
            v-model="model[item.key]"
            :disabled="!item.isEdit"
            :maxlength="item.maxlength"
            :show-word-limit="item.showWordLimit"
            :placeholder="item.placeholder || '请输入'"
            @blur="handleBlur(item)"
          />
          <!-- 文本框 -->
          <el-input
            v-else-if="item.type === 'textarea'"
            v-model="model[item.key]"
            :disabled="!item.isEdit"
            :maxlength="item.maxlength"
            :show-word-limit="item.showWordLimit"
            type="textarea"
            :rows="3"
            :placeholder="item.placeholder || '请输入'"
            @blur="handleBlur(item)"
          />
          <!-- 下拉框 -->
          <el-select
            v-else-if="item.type === 'select'"
            v-model="model[item.key]"
            :disabled="!item.isEdit"
            :multiple="item.multiple"
            :placeholder="item.placeholder || '请选择'"
            @change="(val) => updateDeptArray(val, item)"
          >
            <el-option v-for="(option, j) in item.options" :key="'option'+j" :label="option.label" :value="option.value" />
          </el-select>
          <!-- 输入框(可以过滤) -->
          <el-autocomplete
            v-else-if="item.type === 'autocomplete'"
            v-model="model[item.key]"
            :fetch-suggestions="(a,b) => querySearch(a,b,item.options)"
            :placeholder="item.placeholder || '请输入'"
            @select="(val) => handleSelect(val, item)"
          />
          <!-- 单选框 -->
          <el-radio-group v-else-if="item.type === 'radio'" v-model="model[item.key]">
            <el-radio v-for="(option, z) in item.options" :key="'option'+z" :label="option.value">
              {{ option.label }}
            </el-radio>
          </el-radio-group>
          <!-- 日期 -->
          <el-date-picker
            v-else-if="item.type === 'date'"
            :key="'datePicker' + i"
            v-model="model[item.key]"
            :picker-options="!item.noLimitCurrentDate && pickerOptions"
            type="date"
            :placeholder="item.placeholder || '请选择'"
            value-format="yyyy-MM-dd"
            format="yyyy-MM-dd"
          />
          <!-- 日期时间 -->
          <el-date-picker
            v-else-if="item.type === 'daterange'"
            :key="'daterangePicker' + i"
            v-model="model[item.key]"
            :picker-options="!item.noLimitCurrentDate && pickerOptions"
            type="daterange"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            value-format="yyyy-MM-dd"
            format="yyyy-MM-dd"
          />
          <!-- 数字 -->
          <el-input-number
            v-else-if="item.type === 'inputNumber'"
            v-model="model[item.key]"
            :min="1"
          />
          <!-- 报送时间 -->
          <div v-else-if="item.type === 'deliveryTime'" class="module-timeInput" @click="showSubMission">
            <el-input v-model="model[item.key]" :disabled="!item.isEdit" :placeholder=" item.placeholder || '请选择报送时间'" readonly />
          </div>
          <!-- 单位或者人员组织构架 -->
          <auth-panel
            v-else-if="item.type === 'authPanel'"
            :auth-panel-params="item.params"
            :mixed-data="item.mixedData"
            :disabled="item.disabled"
            :type="item.authPanelType"
            :dept-array="item.deptArray"
            :has-same-data-default-props="item.hasSameDataDefaultProps"
            :multiple="item.multiple"
            :stage-single="item.stageSingle"
            :select-all="true"
            @update:deptArray="(val) => updateDeptArray(val, item)"
          />
          <!-- <auth-panel v-else-if="item.type === 'authPanel'" :disabled="!item.isEdit" :type="item.authPanelType" :dept-array="item.deptArray" :has-same-data-default-props="item.hasSameDataDefaultProps" :multiple="item.multiple" :select-all="true" @update:deptArray="(val) => updateDeptArray(val, item)" /> -->
          <!-- 文件上传 -->
          <template v-else-if="item.type === 'upload'">
            <el-form-item label="">
              <div class="group-item">
                <div class="exportFiles">
                  <upload :file-data="fileList" @changeFile="getFileList" /> <!--:file-type="fileFormat"-->
                </div>
              </div>
              <file-list v-for="file in fileList" :key="file.fileId" :file="file" :file-operate-btn="['eyes', 'closeBg']" @remove-file="removeFile" />
            </el-form-item>
          </template>
        </template>
      </el-form-item>
      <el-form-item>
        <template v-if="isShowSearchBtn">
          <el-button type="primary" size="middle" @click="submitForm('formRef')">查询</el-button>
          <el-button plain @click="resetForm('formRef')">重置</el-button>
        </template>
        <slot name="btnList" />
      </el-form-item>
    </el-form>

完整代码

<template>
  <div class="form" :style="setStyle">
    <el-form
      ref="formRef"
      :inline="inline"
      :model="model"
      :rules="isRules ? rules : {}"
      :label-position="labelPosition"
      :label-width="labelWidth"
      :style="{'flex-wrap': flexWrap ? 'nowrap' : 'wrap', 'justify-content' : justifyContent}"
    >
      <el-form-item
        v-for="(item,i) in formData"
        :key="'form'+i"
        :class="item.type + '-form'"
        :label="item.label"
        :prop="item.key"
        :rules="isRules ? item.rules : []"
        :error="item.success ? '' : item.message"
        :style="{width: item.width ? item.width : formItemWidth, ...item.style }"
      >
        <!-- 插槽 -->
        <template v-if="item.slotKey">
          <slot :name="item.slotKey" :row="item" />
        </template>
        <template v-else>
          <!-- 输入框 -->
          <el-input
            v-if="item.type === 'input'"
            v-model="model[item.key]"
            :disabled="!item.isEdit"
            :maxlength="item.maxlength"
            :show-word-limit="item.showWordLimit"
            :placeholder="item.placeholder || '请输入'"
            @blur="handleBlur(item)"
          />
          <!-- 文本框 -->
          <el-input
            v-else-if="item.type === 'textarea'"
            v-model="model[item.key]"
            :disabled="!item.isEdit"
            :maxlength="item.maxlength"
            :show-word-limit="item.showWordLimit"
            type="textarea"
            :rows="3"
            :placeholder="item.placeholder || '请输入'"
            @blur="handleBlur(item)"
          />
          <!-- 下拉框 -->
          <el-select
            v-else-if="item.type === 'select'"
            v-model="model[item.key]"
            :disabled="!item.isEdit"
            :multiple="item.multiple"
            :placeholder="item.placeholder || '请选择'"
            @change="(val) => updateDeptArray(val, item)"
          >
            <el-option v-for="(option, j) in item.options" :key="'option'+j" :label="option.label" :value="option.value" />
          </el-select>
          <!-- 输入框(可以过滤) -->
          <el-autocomplete
            v-else-if="item.type === 'autocomplete'"
            v-model="model[item.key]"
            :fetch-suggestions="(a,b) => querySearch(a,b,item.options)"
            :placeholder="item.placeholder || '请输入'"
            @select="(val) => handleSelect(val, item)"
          />
          <!-- 单选框 -->
          <el-radio-group v-else-if="item.type === 'radio'" v-model="model[item.key]">
            <el-radio v-for="(option, z) in item.options" :key="'option'+z" :label="option.value">
              {{ option.label }}
            </el-radio>
          </el-radio-group>
          <!-- 日期 -->
          <el-date-picker
            v-else-if="item.type === 'date'"
            :key="'datePicker' + i"
            v-model="model[item.key]"
            :picker-options="!item.noLimitCurrentDate && pickerOptions"
            type="date"
            :placeholder="item.placeholder || '请选择'"
            value-format="yyyy-MM-dd"
            format="yyyy-MM-dd"
          />
          <!-- 日期时间 -->
          <el-date-picker
            v-else-if="item.type === 'daterange'"
            :key="'daterangePicker' + i"
            v-model="model[item.key]"
            :picker-options="!item.noLimitCurrentDate && pickerOptions"
            type="daterange"
            range-separator="至"
            start-placeholder="开始日期"
            end-placeholder="结束日期"
            value-format="yyyy-MM-dd"
            format="yyyy-MM-dd"
          />
          <!-- 数字 -->
          <el-input-number
            v-else-if="item.type === 'inputNumber'"
            v-model="model[item.key]"
            :min="1"
          />
          <!-- 报送时间 -->
          <div v-else-if="item.type === 'deliveryTime'" class="module-timeInput" @click="showSubMission">
            <el-input v-model="model[item.key]" :disabled="!item.isEdit" :placeholder=" item.placeholder || '请选择报送时间'" readonly />
          </div>
          <!-- 单位或者人员组织构架 -->
          <auth-panel
            v-else-if="item.type === 'authPanel'"
            :auth-panel-params="item.params"
            :mixed-data="item.mixedData"
            :disabled="item.disabled"
            :type="item.authPanelType"
            :dept-array="item.deptArray"
            :has-same-data-default-props="item.hasSameDataDefaultProps"
            :multiple="item.multiple"
            :stage-single="item.stageSingle"
            :select-all="true"
            @update:deptArray="(val) => updateDeptArray(val, item)"
          />
          <!-- <auth-panel v-else-if="item.type === 'authPanel'" :disabled="!item.isEdit" :type="item.authPanelType" :dept-array="item.deptArray" :has-same-data-default-props="item.hasSameDataDefaultProps" :multiple="item.multiple" :select-all="true" @update:deptArray="(val) => updateDeptArray(val, item)" /> -->
          <!-- 文件上传 -->
          <template v-else-if="item.type === 'upload'">
            <el-form-item label="">
              <div class="group-item">
                <div class="exportFiles">
                  <upload :file-data="fileList" @changeFile="getFileList" /> <!--:file-type="fileFormat"-->
                </div>
              </div>
              <file-list v-for="file in fileList" :key="file.fileId" :file="file" :file-operate-btn="['eyes', 'closeBg']" @remove-file="removeFile" />
            </el-form-item>
          </template>
        </template>
      </el-form-item>
      <el-form-item>
        <template v-if="isShowSearchBtn">
          <el-button type="primary" size="middle" @click="submitForm('formRef')">查询</el-button>
          <el-button plain @click="resetForm('formRef')">重置</el-button>
        </template>
        <slot name="btnList" />
      </el-form-item>
    </el-form>
    <!--报送周期组件-->
    <submission-dialog ref="submissionDialog" :sub-mission-data="subMissionData" @confirm="confirmMission" />
  </div>
</template>
<script>
import authPanel from '@/components/authPanel/index.vue'
import submissionDialog from '@/components/Dialog/submissionDialog.vue'
import upload from '@/components/UploadCom/index.vue'
import fileList from '@/components/fileList/index.vue'
export default {
  name: 'InitForm',
  components: { authPanel, upload, fileList, submissionDialog },
  props: {
    isShowSearchBtn: { // 是否显示查询按钮
      type: Boolean,
      default: true
    },
    labelPosition: { // 表单文本标题的位置
      type: String,
      default: 'right'
    },
    labelWidth: { // 表单文本标题的宽度
      type: String,
      default: ''
    },
    formItemWidth: {
      type: String,
      default: '100%'
    },
    setStyle: {
      type: Object,
      default: () => {
        return {}
      }
    },
    updateModel: {
      type: Object,
      default: () => {
        return {}
      }
    },
    isRules: { // 是否要校验
      type: Boolean,
      default: true
    },
    rules: { // 校验规则
      type: Object,
      default: () => {
        return {}
      }
    },
    formData: { // 表单数据
      type: Array,
      default: () => {
        return []
      }
    },
    inline: { // 是否是行内
      type: Boolean,
      default: true
    },
    flexWrap: {
      type: Boolean,
      default: false
    }, // 控制表单是否换行
    justifyContent: { // 布局
      type: String,
      default: 'space-between'
    }, // 表单布局风格
    noCheck: {
      type: Boolean,
      default: true
    },
    pickerOptions: { // 时间日期表单的时间限制
      type: Object,
      default: () => {
        return {
          disabledDate(time) {
            return time.getTime() < Date.now() - 8.64e7
          }
        }
      }
    }
  },
  data() {
    return {
      model: {},
      fileList: [],
      linkageDataKey: {},
      subMissionData: { // 报送时间回显的参数格式
        supervisionCycleIds: '',
        cycleType: '',
        firstSubmitTime: '',
        supervisionCycle: ''
      },
      defaultProps: { // 初始化表单key值
        value: 'value', // 表单显示的值
        authPanel: 'list' // 获取选择单位/选择人员所选择的对象值
      }
    }
  },
  watch: {
    updateModel: {
      handler(newV) {
        if (newV) {
          this.model[Object.keys(newV)[0]] = newV[Object.keys(newV)[0]]
        }
      },
      deep: true
    }
  },
  created() {
    this.init()
  },
  methods: {
    init() {
      this.formData.forEach(item => {
        !item.defaultProps && (item.defaultProps = this.defaultProps)
        if (item.type === 'deliveryTime') {
          this.subMissionData = item.deliveryTime ? item.deliveryTime : this.subMissionData
        }
        if (item.linkage) {
          this.linkageDataKey[item.linkage] = this.formData.find(data => {
            return data.key === item.linkage
          })
          const linkageType = Array.isArray(this.linkageDataKey[item.linkage].value)
          if ((linkageType && this.linkageDataKey[item.linkage].value.length > 0) || (!linkageType && this.linkageDataKey[item.linkage].value)) {
            if (item.fn(this.linkageDataKey[item.linkage].value).then) {
              item.fn(this.linkageDataKey[item.linkage].value).then(() => {
                this.$set(this.model, item.key, Array.isArray(item.value) ? item.value.map(String) : item.value)
              })
            } else {
              this.$set(this.model, item.key, Array.isArray(item.value) ? item.value.map(String) : item.value)
            }
          }
        } else {
          this.$set(this.model, item.key, item.value)
          // if (item.type === 'select' && item.multiple) {
          //   if (item.value && item.value.length > 0) {
          //     this.$set(this.model, item.key, item.value)
          //   } else {
          //     this.$set(this.model, item.key, [])
          //     if (!item.message) {
          //       this.$nextTick(() => {
          //         this.$refs['formRef'].clearValidate([item.key])
          //       })
          //     }
          //   }
          // } else {
          //   this.$set(this.model, item.key, item.value)
          // }
          // this.model[item.key] = item.value
        }
        if (item.type === 'upload') {
          this.fileList = item.value ? JSON.parse(item.value) : []
        }
      })
    },
    // 清除校验
    // clearRules(value) {
    //   this.$nextTick(() => {
    //     if (value) {
    //       this.$refs['formRef'].clearValidate([value])
    //     } else {
    //       this.$refs['formRef'].resetFields()
    //     }
    //   })
    // },
    querySearch(queryString, cb, options) {
      const option = options || []
      cb(option.filter(item => {
        return item.value.indexOf(queryString) > -1
      }))
    },
    handleSelect(val, data) {
      data.formKey.forEach(item => {
        if (item.indexOf('Id') > -1) {
          this.$set(this.model, item, val.id)
        } else {
          this.$set(this.model, item, val.value)
        }
      })
    },
    submitForm(formEl) {
      if (!formEl) return
      this.$emit('submit', this.model)
    },
    resetForm(formEl) {
      if (!formEl) return
      this.$refs[formEl].resetFields()
      this.$emit('reset', this.model)
    },
    getTreeSelectData(data) {
      this.$set(this.model, 'treeSelectData', data)
    },
    updateDeptArray(data, formItem) {
      let interrupt = false // 是否中断赋值
      formItem.type === 'authPanel' && this.$set(this.model, formItem.key, data.map(item => { return item.name }).join(','))
      this.$refs.formRef.clearValidate(formItem.key)
      this.formData.forEach(item => {
        if (item.linkage === formItem.key) {
          interrupt = item.fn(data, this.formData).interrupt
        }
        if (item.type === 'authPanel' && item.key === formItem.key && !interrupt) {
          item.deptArray = data
        }
      })
      if (!interrupt) {
        this.$emit('update:formData', this.formData)
      }
    },
    async getFormData(callback) {
      if (!this.$refs.formRef) return
      const initFormData = this.initSaveFormData(JSON.parse(JSON.stringify(this.formData)))
      let data = {}
      await this.$refs.formRef.validate((valid) => {
        const errmsg = '验证不通过'
        if (valid) {
          data = callback ? callback({ data: initFormData, valid: true }) : { data: initFormData, valid: true }
        } else {
          data = { valid: false }
        }
      })
      return data
      // if (noCheck) {
      //   return this.checkFormData(callback, initFormData)
      // }
    },
    getFormDataNoCheck(callback) { // 获取数据不需要校验
      if (!this.$refs.formRef) return
      const initFormData = this.initSaveFormData(JSON.parse(JSON.stringify(this.formData)))
      this.$refs.formRef.clearValidate()
      return (callback ? callback({ data: initFormData, valid: true }) : { data: initFormData, valid: true })
    },
    initSaveFormData(initFormData) {
      Object.keys(this.model).forEach(modelKey => {
        initFormData.forEach(formData => {
          if (formData.key === modelKey) {
            if (formData.key === 'supervisionCycle') {
              formData.deliveryTime = this.subMissionData
            }
            formData[formData.defaultProps.value] = this.model[modelKey]
          }
        })
      })
      return initFormData
    },
    // 显示报送周期
    showSubMission() {
      this.$refs.submissionDialog.showVisilie()
    },
    // 回显周期数据
    confirmMission(callData) {
      this.$set(this.model, 'supervisionCycle', callData['supervisionCycle'])
      Object.keys(this.subMissionData).forEach(item => {
        this.$set(this.subMissionData, item, callData[item])
      })
    },
    getFileList(fileList) {
      this.fileList = fileList.map((item, index) => {
        return {
          source: item.source || '',
          fileId: item.fileId,
          fileName: item.name,
          name: item.name,
          fileSize: item.fileSize,
          sort: index + 1,
          suffixName: item.iconType
        }
      })
      this.$set(this.model, 'fileJson', JSON.stringify(this.fileList))
    },
    removeFile(data) {
      this.fileList = this.fileList.filter(item => {
        return item.fileId !== data.fileId
      })
      this.$set(this.model, 'fileJson', JSON.stringify(this.fileList))
    },
    // 输入框失去焦点
    handleBlur(data) {
      if (data.isMate) {
        console.log('1440', data, this.model[data.key], this.formData)
        this.$emit('getMatched', data, this.model, this.formData)
      }
    }
  }
}
</script>
  <style lang="scss" scoped>
  // .el-form{
  //   padding: 27px 16px 9px;
  // }
  .form{
    ::v-deep .el-autocomplete{
      width: 100%;
    }
    ::v-deep .el-form-item{
      &:last-of-type{
        margin-right: 0;
      }
    }
    ::v-deep .el-form--inline{
      display: flex;
      justify-content: space-between;
    }
    ::v-deep .el-form--inline{
      .el-form-item{
        display: flex;
        margin-right: 0;
      }
    }
    ::v-deep .el-tag{
      line-height: initial;
    }
    ::v-deep .el-form-item__content{
      width: 100%;
      flex: 1
    }
    ::v-deep .el-date-editor.el-input, ::v-deep .el-date-editor.el-input__inner{
      width: inherit;
    }
  }
  .el-select{
    width: 100%;
  }

  .hint{
    margin-left: 6px;
  }
  // .dialogObj-text-box {
  //   margin-left: 12px;
  //   min-width: 60px;
  //   &:hover {
  //     color: #1a8af9;
  //     cursor: pointer;
  //   }
  // }
  </style>


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/509702.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

B端:别看分页你天天用,你未必能摸清分页门道,一文告诉你.

在B端系统中&#xff0c;分页的作用是在处理大量数据时&#xff0c;将数据分成多个页面进行展示&#xff0c;以提高系统的性能和用户体验。 分页可以有效减少单个页面加载的数据量&#xff0c;加快页面加载速度&#xff0c;减少服务器和客户端的压力&#xff0c;并且方便用户浏…

vue使用i18n

&#x1f388;个人主页&#xff1a;靓仔很忙i &#x1f4bb;B 站主页&#xff1a;&#x1f449;B站&#x1f448; &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;前端 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#x…

如何使用cobbler定制安装

cobbler批量安装 客户端安装 新建虚拟机从pxe启动&#xff0c;若出现以下界面则表示成功&#xff1a; uos9安装 rockylinux9安装&#xff1a; 切换镜像 [rootcjy ~]# umount /mnt [rootcjy ~]# mount /dev/cdrom /mnt 升级 [rootcjy ~]# cobbler signature update task sta…

【御控物联】JavaScript JSON结构转换(16):对象To数组——综合应用

文章目录 一、JSON结构转换是什么&#xff1f;二、术语解释三、案例之《JSON对象 To JSON数组》四、代码实现五、在线转换工具六、技术资料 一、JSON结构转换是什么&#xff1f; JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换&#xff0…

Redis数据库常用命令和数据类型

文章目录 一、Redis数据库常用命令1、set/get2、keys3、exists4、del5、type6、rename6.1 重命名6.2 覆盖 7、renamenx8、dbsize9、密码设置10、密码验证11、查看密码12、取消密码13、Redis多数据库常用命令13.1 多数据库间切换13.2 多数据库间移动数据13.3 清除数据库数据 二、…

可视化大屏的行业应用(1):智慧生产和智能制造

可视化大屏在生产制造行业中具有重要的应用价值&#xff0c;主要表现在以下几个方面&#xff1a; 生产监控&#xff1a;可视化大屏可以实时显示生产线的运行状态和生产数据&#xff0c;包括设备运行状态、生产效率、产品质量等&#xff0c;帮助管理人员及时监控生产情况&#…

【新手适用】手把手教你从零开始实现一个基于Pytorch的卷积神经网络CNN三: 如何验证和测试模型

【新手适用】手把手教你从零开始实现一个基于Pytorch的卷积神经网络CNN二&#xff1a; 如何训练模型&#xff0c;内附详细损失、准确率、均值计算-CSDN博客 从零开始实现一个基于Pytorch的卷积神经网络 - 知乎 (zhihu.com) 1 初始化、导入模型和数据集 新建一个test.py文件&a…

Android的图片加载框架

Android的图片加载框架 为什么要使用图片加载框架&#xff1f;图片加载框架1. Universal Image Loader [https://github.com/nostra13/Android-Universal-Image-Loader](https://github.com/nostra13/Android-Universal-Image-Loader)2. Glide [https://muyangmin.github.io/gl…

SWM341系列SDRAM应用

SWM341系列SDRAM应用 1、不同的时钟频率下&#xff0c;SDRAM的初始化参数设置 现象&#xff1a;驱屏应用&#xff0c;显示一段时间后出现卡住的现象 分析&#xff1a;SDRAM的初始 化参数优化 主频150Mhz,建议配置CASL 3&#xff0c;TRFC ≥8。 主频100Mhz,ClkDiv可配置为1…

低压500kW 发电机组测试交流干式负载箱的工作方式

低压500kW发电机组测试交流干式负载箱是一种专门用于测试发电机组性能的设备&#xff0c;其主要功能是在发电机组运行过程中&#xff0c;通过模拟实际负载情况&#xff0c;对发电机组的输出功率、电压、电流等参数进行实时监测和调整&#xff0c;以确保发电机组在各种工况下的稳…

手写瀑布流

之前用vue-masonry实现瀑布流 <!DOCTYPE html> <html><head><meta http-equiv"content-type" content"text/html; charsetutf-8"><meta name"viewport" content"widthdevice-width,initial-scale1,maximum-sc…

算法——矩阵,被围绕的区域

. - 力扣&#xff08;LeetCode&#xff09; 最开始也是考虑使用dfs&#xff0c;对于矩阵中的每个点&#xff0c;如果能到达边界的O&#xff0c;则跳过继续dfs。否则如果上下左右四个方向都无法到达边界的O&#xff0c;则说明当前的无法到达&#xff0c;在一个set中记录他的行数…

AcWing刷题-游戏

游戏 DP l lambda: [int(x) for x in input().split()]n l()[0] w [0] while len(w) < n:w l()s [0] * (n 1) for i in range(1, n 1): s[i] s[i - 1] w[i]f [[0] * (n 1) for _ in range(n 1)]for i in range(1, n 1): f[i][i] w[i]for length in range(2, …

WordPress外贸建站Astra免费版教程指南(2024)

在WordPress的外贸建站主题中&#xff0c;有许多备受欢迎的主题&#xff0c;如Avada、Astra、Hello、Kadence等最佳WordPress外贸主题&#xff0c;它们都能满足建站需求并在市场上广受认可。然而&#xff0c;今天我要介绍的是一个不断颠覆建站人员思维的黑马——Astra主题。 原…

Java

1.学生和老师都会有work方法&#xff0c;学生的工作是学习&#xff0c;老师的工作是教书&#xff0c;我利用了一个接口来实现&#xff1b; 2.同时&#xff0c;老师和学生都是人&#xff0c;并且都有姓名&#xff0c;姓名&#xff0c;年龄和身高等特征&#xff0c;我用了一个继承…

Python基于PyQt5制作的一个上位机软件,用来控制一个Arduino四自由度机械臂

PyQt_Arduino 介绍 用PyQt5制作的一个上位机软件&#xff0c;用来控制一个Arduino四自由度机械臂。当然&#xff0c;为了扩展的需要&#xff0c;界面是按照六自由度机械臂制作的。 开发环境 系统&#xff1a; windows10 处理器: Intel Core™i7-8550U CPU 1.8GHz 2.00GHz …

服务器远程桌面连接不上怎么办?

随着互联网的发展和远程办公的兴起&#xff0c;服务器远程桌面连接成为了许多企业和个人不可或缺的工具。偶尔我们可能会碰到服务器远程桌面连接不上的情况&#xff0c;这时候我们需要找到解决办法&#xff0c;确保高效地远程访问服务器。 天联组网——突破远程连接障碍 在我们…

isaacgym 渲染黑屏

问题描述&#xff1a; isaacgym安装完IsaacGym_Preview_4_Package.tar.gz之后&#xff0c;运行python joint_monkey.py没有任何内容现实&#xff0c;但是终端还是正常输出信息。 环境是ubuntu22服务器&#xff0c;python3.8&#xff0c;nvidia Driver Version: 515.65.01 CUDA…

Linux shell编程学习笔记45:uname命令-获取Linux系统信息

0 前言 linux 有多个发行版本&#xff0c;不同的版本都有自己的版本号。 如何知道自己使用的Linux的系统信息呢&#xff1f; 使用uname命令、hostnamectl命令&#xff0c;或者通过查看/proc/version文件来了解这些信息。 我们先看看uname命令。 1 uname 命令的功能和格式 …

如何合理利用chatgpt写高质量新闻稿,10分钟速成(五)

演示站点&#xff1a; https://www.cnsai.net/ 论文模块 官方论坛&#xff1a; www.jingyuai.com 京娱AI下载源码 人工智能&#xff08;AI&#xff09;技术作为当今科技创新的前沿领域&#xff0c;为创业者提供了广阔的机会和挑战。随着AI技术的快速发展和应用领域的不断拓展&a…