zoukankan      html  css  js  c++  java
  • 对话框的表单校验——模板笔记

    目的:

    减少重复工作、简化开发速度

    案例:

    1.设置一个对话框:

    <el-dialog
        width="50%"
        top="60px"
        :title='dialogTitle'
        :visible.sync="dialogVisible"
        :show-close="false"
        :append-to-body="false"
        :close-on-click-modal='false'
        :lock-scroll="false"
    >
      111
    </el-dialog>

    2.抽离表单:

    <template>
      <div>
        <el-form
          :model="form"
          :rules="rules"
          ref="ruleForm"
          label-width="120px"
        >
          <el-form-item
            label="中文名"
            prop="name">
            <template slot="label">
              <span>
                <span>特征中文名</span>
                <el-tooltip
                  content="同一业务下'中文名'不可重名"
                  placement="bottom"><i class="fa fa-info-circle"/>
                </el-tooltip>
              </span>
            </template>
            <el-input
              v-model="form.name"
              placeholder="请输入中文名"/>
          </el-form-item>
          <el-form-item>
            <span class="form-item-submit">
              <el-button
                @click="cancelForm">取消</el-button>
              <el-button
                type="primary"
                :loading="loadSubmit"
                @click="submitForm">确定</el-button>
            </span>
          </el-form-item>
        </el-form>
        <!--嵌套的对话框-->
        <el-dialog
          title="特征模板列表"
          width="50%"
          top="60px"
          :visible.sync="dialogVisibleNest"
          :append-to-body="true"
          :show-close="false"
          :close-on-click-modal='false'
          :lock-scroll="false"
        >
          <div>222
          </div>
        </el-dialog>
      </div>
    </template>
    
    <script>
    
    export default {
      props: {// 需要的参数统一传过来
        formInfo: {
          type: Object,
          default () {
            return {
              isEdit: false, // 新建与编辑
              allName: [],
              form: {
                name: ''
              }
            }
          }
        }
      },
      data () {
        const validateName = (rule, value, callback) => {
          if (value) {
            const rtx = /^[u4E00-u9FA5a-zA-Z0-9_]+$/
            if (!value.match(rtx)) {
              callback(new Error('只允许中英文、数字、下划线'))
            } else if (this.formInfo.allName.indexOf(value) !== -1) {
              callback(new Error('该命名已存在'))
            } else {
              callback()
            }
          } else {
            callback(new Error('不能为空'))
          }
        }
        const validateType = (rule, value, callback) => {
          if (value) {
            const rtx = /^[a-zA-Z][a-zA-Z0-9_]{4,15}$/
            if (!value.match(rtx)) {
              callback(new Error('字母开头,允许5-16字节,允许字母数字下划线'))
            } else if (this.formInfo.allName.indexOf(value) !== -1) {
              callback(new Error('该命名已存在'))
            } else {
              callback()
            }
          } else {
            callback(new Error('不能为空'))
          }
        }
        // const validatePass = (rule, value, callback) => {
        //   if (value === '') {
        //     callback(new Error('不可为空'))
        //   } else {
        //     let result = this.removeStrNotes(value) // 去除注释
        //     if (typeof result === 'string') {
        //       try {
        //         let obj = JSON.parse(result) // 转换成json对象
        //         if (typeof obj === 'object' && obj) {
        //           callback()
        //         } else {
        //           callback(new Error('json格式有误'))
        //         }
        //       } catch (e) {
        //         callback(new Error(e))
        //       }
        //     } else {
        //       callback(new Error('json格式有误'))
        //     }
        //   }
        // }
        return {
          form: {
            name: '',
            type: '',
            user: '',
            checked: 0
          },
          rules: {
            name: [
              { required: true, validator: validateName, trigger: 'blur' }
            ],
            type: [
              { required: true, validator: validateType, trigger: 'blur' }
            ],
            checked: [
              { required: true, message: '请选择是否使用模板', trigger: 'change' }
            ],
            user: [// 多选是数组
              { required: false, type: 'array', message: '请输入关键字,匹配特征关系人,可多选', trigger: 'change' }
            ]
          },
          dialogVisibleNest: false, // 查看嵌套的对话框
          loadSubmit: false // 提交
        }
      },
      watch: {
        'formInfo': {
          immediate: true,
          handler (val) { // 初始化
            console.log(val, '初始化')
            if (!val.isEdit) {
              this.allName = val.allName
              this.form = {
                name: '',
              }
            } else{
              this.allName = []
              this.form = val.form
            }
            this.$nextTick(function () {
              // this.$refs['ruleForm'].resetFields()// 清空表单内容
              this.$refs['ruleForm'].clearValidate()// 清空报错
              this.$refs['inputFocus'].$el.querySelector('input').focus()
            })
          }
        }
      },
      methods: {
        submitForm () {
          this.$refs['ruleForm'].validate((valid) => {
            if (valid) {
              this.$emit('form-change', this.form, this.formInfo.type)// 回调:成功提交
            }
          })
        },
        cancelForm () {
          this.$emit('form-change')// 回调:关闭对话框
          this.$refs['ruleForm'].resetFields()// 清空表单内容
          this.$refs['ruleForm'].clearValidate()// 清空报错
        }
      }
    }
    </script>

    【实例】:可编辑的表格:对话框形式+下拉选项+表格内容编辑

    <template>
      <div>
        <el-table 
        ref="multipleTable" 
        :data="tableData" 
        border 
        @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55">
        </el-table-column>
          <el-table-column label="名称(弹框编辑)" align="center" prop="name">
            <template slot-scope="scope">
                <editRowDialog :allName="allName" :scope="scope" @dialog-change="dialogChange"></editRowDialog>
            </template>
          </el-table-column>
          <el-table-column label="类型(点击切换)" align="center" prop="type">
            <template slot-scope="scope">
              <editRowSelect :options="options" :scope="scope" @select-change="selectChange"></editRowSelect>
            </template>
          </el-table-column>
          <el-table-column label="描述(点击编辑)" align="center" prop="desc">
            <template slot-scope="scope">
              <editRowInput :scope="scope" @input-change="inputChange"></editRowInput>
            </template>
          </el-table-column>
        </el-table>
        <el-button @click="handleCheck">手动选中</el-button>
      </div>
    </template>
    
    <script>
    import editRowDialog from './editRowDialog'
    import editRowSelect from './editRowSelect'
    import editRowInput from './editRowInput'
    export default {
      components:{
        editRowDialog,
        editRowSelect,
        editRowInput,
      },
      data () {
        return {
          saveFlag:false,
          options: ['int', 'string', 'number'],
          tableData: [{
            name:'a',
            type:'int',
            desc:0,
          }],
        }
      },
      computed: {
        allName () {
          return this.tableData.map(item =>item.name)
        }
      },
      methods: {
        handleSelectionChange (val) {
          console.log(val,"全选");
        },
         // 手动触发
        handleCheck () {
          const rows = [this.tableData[0]]
          if (rows) {
            rows.forEach(row => {
              this.$refs.multipleTable.toggleRowSelection(row);
            });
          } else {
            this.$refs.multipleTable.clearSelection();
          }
        },
        // 抽离编辑的组件
        dialogChange (val,index) {
          this.$message.success("修改成功")
          this.tableData[index].name = val.name
        },
        selectChange (val,index) {
          this.$message.success("修改成功")
          this.tableData[index].type = val
        },
        inputChange (val,index) {
          this.$message.success("修改成功")
          // this.tableData[index].desc = val
          this.tableData[index].name = val
        }
      }
    }
    </script>

    1.新建或重命名:对话框或表格内操作表单

    <template>
      <div @click.self="dialogVisible = true">
        <span>
          {{scope.row.name}}
          <i class="el-icon-edit" />
        </span>
        <el-dialog
          style="text-align: left;"
          title="重命名:"
          width="30%"
          :visible.sync="dialogVisible"
          :show-close="false"
          :append-to-body="false"
          :close-on-click-modal="false"
          :lock-scroll="false"
        >
          <newEditForm :dialogVisible="dialogVisible" :data="data" @form-call-back="formCallBack" />
        </el-dialog>
      </div>
    </template>
    
    <script>
    import newEditForm from './newEditForm'
    export default {
      components: {
        newEditForm
      },
      props: {
        scope: {
          type: Object,
          default(){
            return {
              $index:0,
              row:{name:''}
            }
          }
        },
        allName: {
          type: Array,
          default(){
            return []
          }
        },
        isEdit: {
          type: Boolean,
          default: false
        }
      },
      computed:{
        data(){
          return {
            isEdit: this.isEdit,
            allName: this.allName,
            form: {
              name: this.scope.row.name
            },
          }
        }
      },
      data () {
        return {
          dialogVisible: false,
        }
      },
      methods: {
        formCallBack (val) {
          console.log(val,"提交或取消");
          if(val && val.name){
            this.$emit('dialog-change', val, this.scope.$index)
          }else{
            this.$message("已取消修改")
          }
          this.dialogVisible = false
        }
      }
    }
    </script>

    设置了对话框的话,把表单抽离:

    <template>
      <div>
        <el-form
          :model="form"
          :rules="rules"
          ref="ruleForm"
          label-position="left"
          label-width="80px"
          @submit.native.prevent
          @keyup.enter.native="submitForm('ruleForm')"
        >
        <el-form-item
          label="画布名:"
          prop="name">
          <el-input
            placeholder="请输入画布名"
            clearable
            v-model="form.name"
            ref="inputFocus"
            spellcheck="false"/>
        </el-form-item>
          <el-form-item>
            <span class="form-item-submit">
              <el-button
                @click="cancelForm">取消</el-button>
              <el-button
                type="primary"
                :loading="loadSubmit"
                @click="submitForm('ruleForm')">确定</el-button>
            </span>
          </el-form-item>
        </el-form>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        dialogVisible:{
          type:Boolean,
          default:false
        },
        data: {
          type: Object,
          default () {
            return {
              isEdit:false,
              allName: [],
              form: {
                name: ''
              }
            }
          }
        }
      },
      data () {
        const validateName = (rule, value, callback) => {
          if (value) {
            const rtx = /^[u4E00-u9FA5a-zA-Z0-9_]+$/
            if (!value.match(rtx)) {
              callback(new Error('只允许中英文、数字、下划线'))
            } else if (this.allName.indexOf(value) !== -1) {
              callback(new Error('该命名已存在'))
            } else if (this.oldName === value) {
              callback(new Error('该命名未修改'))
            } else {
              callback()
            }
          } else {
            callback(new Error('不能为空'))
          }
        }
        return {
          allName:[],
          oldName:'',
          form: {
            name: '',
          },
          rules: {
            name: [
              { required: true, validator: validateName, trigger: 'blur' }
            ]
          },
          loadSubmit: false // 提交
        }
      },
      watch: {
        'dialogVisible': {
          immediate: true,
          // deep:true,
          handler (val) { // 初始化
            if(val){
              this.$nextTick(function () {
                // this.$refs['ruleForm'].resetFields()// 清空表单内容
                this.$refs['ruleForm'].clearValidate()// 清空报错
                this.$refs['inputFocus'].$el.querySelector('input').focus()
              })
              if (this.data && this.data.isEdit) { //新建
                this.allName = this.data.allName
                this.form = {name: ''}
              } else { // 编辑:默认
                this.allName = []
                this.oldName = this.form.name = this.data.form.name
              }
            }
          }
        },
        'data': {
          immediate: false,
          // deep:true,
          handler (val) {
            if (val && val.isEdit) { //新建
              this.allName = val.allName
              this.form = {name: ''}
            } else { // 编辑:默认
              this.allName = []
              this.oldName = this.form.name = val.form.name
            }
          }
        },
      },
      methods: {
        submitForm () {
          this.$refs['ruleForm'].validate((valid) => {
            if (valid) {
              this.$emit('form-call-back', this.form)// 回调:成功提交
              this.$refs['ruleForm'].resetFields()// 清空表单内容
              this.$refs['ruleForm'].clearValidate()// 清空报错
            }else{
              return
            }
          })
        },
        cancelForm () {
          this.$emit('form-call-back')// 回调:关闭对话框
          this.$refs['ruleForm'].resetFields()// 清空表单内容
          this.$refs['ruleForm'].clearValidate()// 清空报错
        }
      }
    }
    </script>
    <!-- 不校验去除低栏边距 -->
    <style scoped>
    .form-item-bottom{
      margin-bottom: 0;
    }
    .form-item-submit{
      margin-top: 20px;
      float: right
    }
    </style>

    2.表格内编辑,不需要进行表单校验,即:未修改直接提示,不拦截

    <template>
      <div @click="getInputFocus(scope.row.name)">
        <span v-if="!isEdit">
          {{scope.row.name}}
          <i class="el-icon-edit"/>
        </span> 
        <el-input
          v-else
          :ref="`focusInput${scope.$index}`"
          v-model="inputVal"
          @blur="blurChange(inputVal)"
          spellcheck="false"
        />
      </div>
    </template>
    
    <script>
    export default {
      props: {
        scope: {
          type: Object,
          default(){
            return {
              $index:0,
              row:{name:''}
            }
          }
        }
      },
      data () {
        return {
          isEdit:false,
          oldName:'',
          inputVal:''
        }
      },
      methods:{
        getInputFocus(val){ // 获取焦点
          this.oldName = this.inputVal = val
          this.isEdit = true
          this.$nextTick(() => {
            this.$refs[`focusInput${this.scope.$index}`].focus()
          })
        },
        blurChange(val){ // 失去焦点
          if(val !== this.oldName){
            this.$emit('input-change', val,this.scope.$index) 
          }else{
            this.$message.warning("内容未修改")
          }
          this.isEdit = false
        }
      }
    }
    </script>

    3.表格内操作:下拉选项

    <template>
      <div @click="getSelectFocus(scope.row.type)">
        <span v-if="!isEdit">
          {{scope.row.type}}
          <i class="el-icon-edit"/>
        </span>      
        <el-select
          v-else
          :ref="`toFoucus${scope.$index}`"
          automatic-dropdown
          v-model="selectedVal"
          placeholder="请选择"
          style="text-align:center; 100%"
          @change='selectChange'
          @visible-change='visibleChange'
        >
          <el-option v-for="item in options" :key="item" :label="item" :value="item" />
        </el-select>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        scope: {
          type: Object,
          default(){
            return {
              $index:0,
              row:{type:'int'}
            }
          }
        },
        options: {
          type: Array,
          default () {
            return []
          }
        }
      },
      data () {
        return {
          isEdit:false,
          selectedOld: '',
          selectedVal: ''
        }
      },
      methods:{
        getSelectFocus(val){ // 获取焦点
          this.selectedOld = this.selectedVal = val
          this.isEdit = true
          this.$nextTick(() => {
            this.$refs[`toFoucus${this.scope.$index}`].focus()
          })
        },
        selectChange(val){ //提交
          this.$emit('select-change', val,this.scope.$index) 
        },
        visibleChange(val){ // 失去焦点
          if(!val){
            if(this.selectedOld === this.selectedVal){
              this.$message.warning("内容未修改")
            }
            this.isEdit = false
          }
        }
      }
    
    }
    </script>

    其他:新增一行、删除一行的校验与重置按钮(禁止添加或校验重名)

    最外层的结构:

    <template>
      <el-form :rules="rules" :model="form" ref="rulesForm">
        <el-form-item prop="tableData">
          <dragTableDialog
            :table-data="form.tableData"
            :drop-col="column"
            tab-show
            dialog-title="编辑"
            @save-drag-table="saveDragTable"
          />
        </el-form-item>
      </el-form>
    </template>
    
    <script>
    import dragTableDialog from './module-components/formTable/dragTableDialog'
    export default {
      components: {
        dragTableDialog
      },
      data () {
        return {
          rules: {
            tableData: { type: 'array', required: true, message: '输出列表不可为空', trigger: 'blur' }
          },
          form: {
            tableData: []
          },
          column: [
            {
              default: '',
              label: '字段',
              prop: 'field_name'
            },
            {
              default: 'string',
              label: '类型',
              prop: 'field_type'
            },
            {
              default: '',
              label: '描述',
              prop: 'field_desc'
            }
          ]
        }
      },
      methods: {
        saveDragTable (val) {
          this.form.tableData = val
          if(val.length===0){
            this.$refs['rulesForm'].validateField('tableData') //校验某个字段
          }else{
            // this.$refs['copyForm'].resetFields()// 清空表单内容
            this.$refs['rulesForm'].clearValidate()// 清空报错
          }
        },
      }
    }
    </script>

    表格与字符串的切换:

    <!--可拖拽的表格:表格内容+行参数+按钮名称(对话框标题)
    -->
    <template>
      <div>
        <el-button type="primary" @click="showDialog">{{ dialogTitle }}</el-button>
        <CommonTable style="marginTop:10px" :table-data="tableDataBeigin" :table-column="dropCol" />
        <el-dialog
          :visible.sync="dialogVisible"
          :close-on-click-modal="false"
          append-to-body
          show-close
          :before-close="beforeClose"
          :title="dialogTitle"
          width="40%"
        >
          <div v-if="!tabShow" style="margin-top:-20px;">
            <dragTableForm
              :table-data="tableDataDialog"
              :table-column="dropCol"
              :save-disabled="saveDisabled"
              @save-call-back="saveCallBack"
              @save-data-back="saveDataBack"
            />
          </div>
          <el-tabs
            v-else
            @tab-click="handleClickTab"
            style="margin-top:-20px;"
            v-model="activeName"
            type="card"
          >
            <el-tab-pane label="表格编辑模式" name="table">
              <dragTableForm
                :size="size"
                :table-data="tableDataDialog"
                :drop-col="dropCol"
                :save-disabled="saveDisabled"
                @save-call-back="saveCallBack"
                @save-data-back="saveDataBack"
              />
            </el-tab-pane>
            <el-tab-pane label="文本编辑模式" name="txt">
              <el-input
                @change="inputChange"
                v-model="strSplit"
                type="textarea"
                :rows="6"
                placeholder="例:a,int,描述a,类型int。"
                spellcheck="false"
              />
              <h4 style="margin:5px 0">注意:</h4>
              <ol style="text-align:left">
                <li>可将导出的csv文件内容,直接复制过来使用,若有数据类型且不符合规范,转换后默认为string;</li>
                <li>手动编辑时,注意分隔符为英文逗号(第3个逗号后面的内容合并到最后一列),新的一行用Enter键换行。</li>
              </ol>
            </el-tab-pane>
          </el-tabs>
          <!--保存操作  -->
          <span slot="footer" class="dialog-footer">
            <el-button :size="size" type="primary" @click="submitDialog" :disabled="saveDisabled">保存</el-button>
          </span>
        </el-dialog>
      </div>
    </template>
    <script>
    import _ from 'lodash'
    import CommonTable from './commonTable'
    import dragTableForm from './dragTableForm'
    export default {
      components: {
        CommonTable,
        dragTableForm
      },
      props: {
        'size': {
          type: String,
          default: 'mini'
        },
        'tableData': {
          type: Array,
          default () {
            return []
          }
        },
        'dropCol': {
          type: Array,
          default () {
            return [
              {
                default: '',
                label: '字段',
                prop: 'field_name'
              },
              {
                default: 'string',
                label: '类型',
                prop: 'field_type'
              },
              {
                default: '',
                label: '描述',
                prop: 'field_desc'
              }
            ]
          }
        },
        'dialogTitle': {
          type: String,
          default: '新建'
        },
        'tabShow': {
          type: Boolean,
          default: false
        }
      },
      data () {
        return {
          strSplit: '',
          activeName: 'table',
          dialogVisible: false,
          saveDisabled: false,
          tableDataBeigin: [],
          tableDataDialog: []
        }
      },
      watch: {
        'tableData': {
          immediate: true,
          handler (val) {
            const tableData = []
            val.forEach((item, index) => {
              const obj = {}
              obj.id = index
              this.dropCol.forEach(e => {
                obj[e.prop] = item[e.prop]
              })
              tableData.push(obj)
            })
            console.log("监听提交");
            this.tableDataBeigin = tableData
            this.tableDataDialog = _.cloneDeep(tableData)
          }
        }
      },
      methods: {
        showDialog () {
          if (this.activeName === 'txt') {
            let str = ''
            this.tableDataDialog.forEach(item => {
              delete item.id
              str += Object.values(item) + '
    '
            })
            this.strSplit = str
          }
          this.dialogVisible = true
        },
        beforeClose () {
          const tableData = []
          this.tableData.forEach((item, index) => {
            const obj = {}
            obj.id = index
            this.dropCol.forEach(e => {
              obj[e.prop] = item[e.prop]
            })
            tableData.push(obj)
          })
          this.tableDataDialog = _.cloneDeep(tableData)
          this.dialogVisible = false
          this.saveDisabled = false
        },
        findStrIndex (str, cha, num) {
          var x = str.indexOf(cha)
          for (var i = 0; i < num; i++) {
            x = str.indexOf(cha, x + 1)
          }
          return x
        },
        handleClickTab (tab, event) {
          if (tab.name === 'txt') {
            let str = ''
            this.tableDataDialog.forEach(item => {
              delete item.id
              str += Object.values(item) + '
    '
            })
            this.strSplit = str
          } else {
            const array = this.strSplit.split('
    ')
            if (!array[array.length - 1]) {
              array.pop()
            }
            const tableDataDialog = []
            array.forEach((item, index) => {
              const allIndex = this.findStrIndex(item, ',', 1)
              let array2 = []
              if (item.split(',').length > 3) {
                array2 = item.substring(0, allIndex).split(',')
                array2.push(item.substring(allIndex + 1))
              } else {
                if (item.split(',').length === 1) {
                  array2 = [item, this.dropCol[1].prop === 'field_type' ? 'string' : '', '']
                } else {
                  array2 = item.split(',')
                }
              }
              const obj = {}
              array2.forEach((e, i) => {
                obj.id = index
                if (this.dropCol[i].prop === 'field_type') {
                  const options = ['tinyint', 'smallint', 'int', 'bigint', 'boolean', 'float', 'double', 'string']
                  obj[this.dropCol[i].prop] = options.indexOf(array2[i]) !== -1 ? array2[i] : 'string'
                } else if (this.dropCol[i].prop === 'field_key') {
                  const keyOptions = ['qq', 'area', 'roleid', 'os', 'commid', 'openid', 'null']
                  obj[this.dropCol[i].prop] = keyOptions.indexOf(array2[i]) !== -1 ? array2[i] : 'null'
                } else {
                  obj[this.dropCol[i].prop] = array2[i] ? array2[i] : ''
                }
              })
              tableDataDialog.push(obj)
            })
    
            this.tableDataDialog = tableDataDialog
          }
        },
        saveCallBack (disabled) {
          this.saveDisabled = disabled
        },
        saveDataBack (data) {
          this.tableDataDialog = data
        },
        inputChange (val) { // 转换+校验
          const array = this.strSplit.split('
    ')
          if (!array[array.length - 1]) {
            array.pop()
          }
          const tableDataDialog = []
          array.forEach((item, index) => {
            const allIndex = this.findStrIndex(item, ',', 1)
            let array2 = []
            if (item.split(',').length > 3) {
              array2 = item.substring(0, allIndex).split(',')
              array2.push(item.substring(allIndex + 1))
            } else {
              if (item.split(',').length === 1) {
                array2 = [item, this.dropCol[1].prop === 'field_type' ? 'string' : '', '']
              } else {
                array2 = item.split(',')
              }
            }
            const obj = {}
            array2.forEach((e, i) => {
              obj.id = index
              if (this.dropCol[i].prop === 'field_type') {
                const options = ['tinyint', 'smallint', 'int', 'bigint', 'boolean', 'float', 'double', 'string']
                obj[this.dropCol[i].prop] = options.indexOf(array2[i]) !== -1 ? array2[i] : 'string'
              } else if (this.dropCol[i].prop === 'field_key') {
                const keyOptions = ['qq', 'area', 'roleid', 'os', 'commid', 'openid', 'null']
                obj[this.dropCol[i].prop] = keyOptions.indexOf(array2[i]) !== -1 ? array2[i] : 'null'
              } else {
                obj[this.dropCol[i].prop] = array2[i] ? array2[i] : ''
              }
            })
            tableDataDialog.push(obj)
          })
          this.tableDataDialog = tableDataDialog
          //校验
          const tableData = []
          this.tableDataDialog.forEach((item, index) => {
            const obj = {}
            this.dropCol.forEach(e => {
              obj[e.prop] = item[e.prop]
            })
            tableData.push(obj)
          })
          const arr = tableData.map(item => item[this.dropCol[0].prop])
          if ((new Set(arr)).size !== arr.length) {
            this.$message.warning(this.dropCol[0].label + '不可重名')
          }
        },
        submitDialog () {
          console.log("提交");
          const tableData = []
          this.tableDataDialog.forEach((item, index) => {
            const obj = {}
            this.dropCol.forEach(e => {
              obj[e.prop] = item[e.prop]
            })
            tableData.push(obj)
          })
          this.tableDataBeigin = tableData
          const arr = tableData.map(item => item[this.dropCol[0].prop])
          if ((new Set(arr)).size !== arr.length) {
            this.$message.warning(this.dropCol[0].label + '不可重名')
          } else {
            this.$emit('save-drag-table', tableData)
            this.dialogVisible = false
          }
        }
      }
    }
    </script>

    设置公共组件:el-table

    /***
    * 通用的table展示
    * @param  {Array} tableData
    * @param  {Array} tableColumn
    * @return {Number/String} height(参考element)
    * @return {String} size(参考element)
    * @return {Boolean} stripe 默认显示
    * @return {Boolean} sortable 默认显示
    * @return {Boolean} loading
    * @return {Function} filterChange
    * @return {Function / String} tableRowClassName 底色
    * @return {String} slot 插入的位置:header、footer
    * */
    <template>
      <div>
        <el-table
          ref="commonTable"
          :data="tableData"
          :size="size"
          :stripe="stripe"
          border
          highlight-current-row
          v-loading="loading"
          :row-class-name="tableRowClassName"
          @filter-change="filterChange"
          @selection-change="handleSelectionChange"
          :row-key="rowKey"
        >
          <!--自定义插入-->
          <slot name="header" />
          <el-table-column
            v-for="(item, index) in tableColumn"
            :key="`key_${index}`"
            :prop="item.prop"
            :label="item.label"
            show-overflow-tooltip
            :sortable="sortable"
            align="center"
          >
            <template slot-scope="scope">
              <div v-if="tableColumn[index].prop === 'field_key'">
                <span>{{ keyOptionsObj[scope.row.field_key] || '-空-' }}</span>
              </div>
              <div v-else>
                <span>{{ scope.row[tableColumn[index].prop] || '-空-' }}</span>
              </div>
            </template>
          </el-table-column>
          <!--自定义插入-->
          <slot name="footer" />
        </el-table>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        tableData: {
          type: Array,
          default () {
            return []
          }
        },
        tableColumn: {
          type: Array,
          default () {
            return [
              {
                default: '',
                label: '字段名称',
                prop: 'field_name'
              }, {
                default: 'string',
                label: '字段类型',
                prop: 'field_type'
              }, {
                default: '',
                label: '字段描述',
                prop: 'field_desc'
              }
            ]
          }
        },
        size: {
          type: String,
          default: 'mini'
        },
        sortable: {
          type: Boolean,
          default: true
        },
        stripe: {
          type: Boolean,
          default: true
        },
        loading: {
          type: Boolean,
          default: false
        },
        filterChange: {
          type: Function,
          default () {
            return ''
          }
        },
        tableRowClassName: {
          type: Function,
          default () {
            return ''
          }
        },
        rowKey: {
          type: String,
          default: ''
        },
        initSelection: {
          type: Boolean,
          default: false
        }
      },
      data () {
        return {
          keyOptionsObj: {
            qq: 'QQ号',
            area: '大区ID',
            roleid: '角色ID',
            os: '手机操作系统',
            commid: '微信Commid',
            openid: 'Open ID',
            null: '不关联'
          }
        }
      },
      watch: {
        initSelection: {
          immediate: true,
          handler (val) {
            if (val) {
              this.$nextTick(() => {
                this.$refs.commonTable.clearSelection()
              })
            }
          }
        }
      },
      methods: {
        handleSelectionChange (val) {
          this.$emit('handleSelectionChange', val)
        }
      }
    }
    </script>

    设置可拖拽的表格:

    <template>
      <div>
        <el-button
          :size="size"
          type="primary"
          @click="addRow"
          style="margin-bottom: 10px"
          :disabled="disabledAdd"
        >新增一行</el-button>
        <el-form :model="form" :rules="rules" ref="form">
          <el-table
            border
            :size="size"
            id="dragTable_sql"
            :row-key="getRowKeys"
            :data="form.tableData"
            style=" 100%;"
          >
            <!-- 拖拽图标 -->
            <el-table-column width="40" align="center">
              <template>
                <i class="el-icon-rank" style="font-size:large;cursor:grab" />
              </template>
            </el-table-column>
            <!-- 输入选择 -->
            <el-table-column
              v-for="(item, index) in tableColumn"
              :key="index"
              :prop="item.prop"
              :label="item.label"
              align="center"
            >
              <template slot-scope="scope">
                <el-form-item
                  v-if="index===0"
                  :size="size"
                  :prop="`tableData.${scope.$index}.${item.prop}`"
                  :rules="rules[item.prop]"
                >
                  <el-input
                    v-focus
                    clearable
                    v-model="scope.row[item.prop]"
                    :placeholder="`请输入${item.label}`"
                    @change="inputChange"
                    @clear="inputChange"
                  />
                </el-form-item>
                <el-form-item v-else-if="item.prop === 'field_type'" :size="size">
                  <el-select
                    @change="saveChange"
                    :size="size"
                    v-model="scope.row[item.prop]"
                    :placeholder="'请选择'+item.label"
                  >
                    <el-option
                      v-for="item in options"
                      :key="item"
                      :label="item"
                      :value="item"
                      style="text-align: center;"
                    />
                  </el-select>
                </el-form-item>
                <el-form-item v-else-if="item.prop === 'field_key'" :size="size">
                  <el-select
                    clearable
                    v-model="scope.row[item.prop]"
                    :placeholder="'请选择'+item.label"
                    @change="saveChange"
                  >
                    <el-option
                      style="text-align: center;"
                      v-for="(item,index) in keyOptions"
                      :key="index"
                      :label="item.label"
                      :value="item.value"
                    />
                  </el-select>
                </el-form-item>
                <el-form-item v-else :size="size">
                  <el-input
                    clearable
                    v-model="scope.row[item.prop]"
                    :placeholder="`请输入${item.label}`"
                    @change="saveChange"
                    @clear="saveChange"
                  />
                </el-form-item>
              </template>
            </el-table-column>
            <!--操作  -->
            <el-table-column width="80" align="center" label="操作" fixed="right">
              <template slot-scope="scope">
                <el-button :size="size" type="danger" @click="deleteRow(scope.$index, scope.row)">删除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-form>
        <el-link type="danger" v-show="isRepeatName">{{tableColumn[0].label}}命名已存在!</el-link>
      </div>
    </template>
    
    <script>
    import _ from 'lodash'
    import Sortable from 'sortablejs'
    export default {
      directives: {
        focus: {
          inserted: function (el) {
            el.querySelector('input').focus()
          }
        }
      },
      props: {
        'size': {
          type: String,
          default: 'mini'
        },
        'tableData': {
          type: Array,
          default () {
            return []
          }
        },
        'tableColumn': {
          type: Array,
          default () {
            return [
              {
                default: '',
                label: '字段',
                prop: 'field_name'
              },
              {
                default: 'string',
                label: '类型',
                prop: 'field_type'
              },
              {
                default: '',
                label: '描述',
                prop: 'field_desc'
              }
            ]
          }
        }
      },
      watch: {
        'form.tableData': {
          immediate: false,
          handler (val) {
            this.$emit('save-data-back', val)
            if (val.length > 0) {
              const fieldName = val.map(item => item[this.tableColumn[0].prop])
              this.isRepeatName = this.isRepeat(fieldName)
              val.forEach(item => {
                if (!item[this.tableColumn[0].prop]) {// 只有有空就禁止提交
                  this.disabledAdd = true
                  this.$emit('save-call-back', true)
                } else {
                  this.disabledAdd = false
                  this.$emit('save-call-back', false)
                }
              })
              if (this.isRepeatName) { // 有重复值
                this.disabledAdd = true
                this.$emit('save-call-back', true)
              }
            }
          }
        },
        'tableData': {
          immediate: true,
          handler (val) {
            this.$nextTick(function () {
              this.rowDropDialog()
            })
            if(val.length > 0){
              this.form.tableData = val
            }
          }
        }
      },
      computed: {
        rules () {
          const rules = {}
          this.tableColumn.forEach((item, index) => {
            rules[item.prop] = [
              { required: true, message: '请输入' + item.label, trigger: 'blur' },
              { pattern: /^[a-zA-Z][a-zA-Z0-9_]*$/, message: '须字母开头,不含特殊符号', trigger: 'blur' },
            ]
          })
          return rules
        }
      },
      data () {
        return {
          getRowKeys (row) {
            return row.id
          },
          form: {
            tableData: []
          },
          fieldName: [],
          disabledAdd: false,
          isRepeatName: false,
          options: [
            'tinyint',
            'smallint',
            'int',
            'bigint',
            'boolean',
            'float',
            'double',
            'string'
          ],
          keyOptions: [
            { value: 'qq', label: 'QQ号' },
            { value: 'area', label: '大区ID' },
            { value: 'roleid', label: '角色ID' },
            { value: 'os', label: '手机操作系统' },
            { value: 'commid', label: '微信Commid' },
            { value: 'openid', label: 'Open ID' },
            { value: 'null', label: '不关联' }
          ]
        }
      },
      methods: {
        rowDropDialog () {
          const tbody = document.querySelector('#dragTable_sql tbody')
          const _this = this
          Sortable.create(tbody, {
            handle: '.el-icon-rank',
            animation: 150,
            onEnd ({ newIndex, oldIndex }) {
              const currRow = _this.form.tableData.splice(oldIndex, 1)[0]
              _this.form.tableData.splice(newIndex, 0, currRow)
            }
          })
        },
        inputChange (val) {
          if (val) { //必要字段更新
            this.disabledAdd = this.fieldName.indexOf(val) !== -1
            this.isRepeatName = this.fieldName.indexOf(val) !== -1
            this.$emit('save-call-back', this.disabledAdd)
            this.$emit('save-data-back', this.form.tableData)
          } else {
            this.$refs['form'].validate(valid => {
              if (valid) {
                //清除不计重复
                this.$emit('save-data-back', this.form.tableData)
              } else {
                this.disabledAdd = true
                this.$emit('save-call-back', true)
                return valid
              }
            });
          }
        },
        saveChange () {
          this.$emit('save-data-back', this.form.tableData)
        },
        addRow () {
          this.$refs['form'].validate((valid) => {
            if (valid) {
              // 1.读取已有命名
              if (this.form.tableData.length > 0) {
                this.fieldName = this.form.tableData.map(item => item[this.tableColumn[0].prop])
              }
              // 2.添加一行:id++1
              const tableRowKey = this.tableColumn.map(item => item.prop)
              const tableRowVal = this.tableColumn.map(item => item.default)
              const tableRow = _.zipObject(tableRowKey, tableRowVal) // 映射
              tableRow.id = _.uniqueId(Date.now().toString()) // 拖拽
              this.form.tableData.push(tableRow)
              this.disabledAdd = true
              this.$emit('save-call-back', true)
            } else {
              return false;
            }
          });
        },
        deleteRow (index, row) {
          //1.删除
          this.form.tableData.splice(index, 1)
          // 2.去重
          if(this.form.tableData.length === 0){
            this.fieldName = []
          }else{
            this.fieldName = this.fieldName.filter(item => item !== row[this.tableColumn[0].prop])
          }
        },
        isRepeat (arr) {
          return _.uniq(arr).length !== arr.length;
        }
      }
    }
    </script>

    -end-

  • 相关阅读:
    Cocos2dx-背景无限循环播放
    centos 7端口和防火墙
    图片裁剪
    spring-boot图片压缩
    vue cli简介
    spring-boot的配置(实时生效)
    spring-boot打成war包放入tomcat运行
    spring-boot上传图片并访问
    linux链接ssh
    mysql远程访问
  • 原文地址:https://www.cnblogs.com/wheatCatcher/p/11453423.html
Copyright © 2011-2022 走看看