zoukankan      html  css  js  c++  java
  • el-table——可编辑、拖拽排序与校验的formTableDrag

    背景:

    1.利用form进行校验输入;

    2.利用sortable操作Dom替换表格数据顺序;

    3.利用lodash实现数据深拷贝与参数替换等

    一:最外层的数组校验

    <template>
      <el-form :rules="rules" :model="form" ref="rulesForm">
        <el-form-item prop="table">
          <formTableDrag
            :table-data="form.table"
            :drop-col="column"
            tab-show
            dialog-title="编辑"
            @save-drag-table="saveDragTable"
          />
        </el-form-item>
      </el-form>
    </template>
    
    <script>
    import formTableDrag from './formTableDrag'
    export default {
      components: {
        dragTableDialog
      },
      data () {
        return {
          rules: {
            table: { type: 'array', required: true, message: '输出列表不可为空', trigger: 'blur' }
          },
          form: {
            table: []
          },
          column: [
            {
              default: '',
              label: '字段',
              prop: 'field_name'
            },
            {
              default: 'string',
              label: '类型',
              prop: 'field_type'
            },
            {
              default: '',
              label: '描述',
              prop: 'field_desc'
            }
          ]
        }
      },
      methods: {
        saveDragTable (val) {this.form.table= val
          if(val.length===0){
            this.$refs['rulesForm'].validateField('schema') //校验某个字段
          }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
                v-model="strSplit"
                type="textarea"
                :rows="6"
                placeholder="例:a,int,描述a,类型int。"
                spellcheck="false"
              />
              <h4 style="margin:5px 0">注意:</h4>
              <ul style="text-align:left">
                <li>1、可将导出的csv文件内容,直接复制过来使用,若有数据类型且不符合规范,转换后默认为string;</li>
                <li>2、手动编辑时,注意分隔符为英文逗号(第3个逗号后面的内容合并到最后一列),新的一行用Enter键换行。</li>
              </ul>
            </el-tab-pane>
          </el-tabs>
          <!--保存操作  -->
          <span slot="footer" class="dialog-footer">
            <el-button size="mini" 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: []
        }
      },
      created () {
        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.tableDataBeigin = tableData
        this.tableDataDialog = _.cloneDeep(tableData)
      },
      watch: {
        tableData () {
          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.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
        },
        submitDialog () {
          if (this.activeName === 'txt') {
            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)
          })
          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>
    /***
    * 通用的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
          id="kp_but_2982"
          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() // 拖拽
              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.去重
          this.fieldName = this.fieldName.filter(item => item !== row[this.tableColumn[0].prop])
        },
        isRepeat (arr) {
          return _.uniq(arr).length !== arr.length;
        }
      }
    }
    </script>
  • 相关阅读:
    查看mongodb的状态
    superset----缓存之redis
    superset--presto sql
    linux----之tcpdump小用
    Git版本回退的最佳方式
    SpringBoot 热部署
    不使用Tomcat,手写简单的web服务
    Spring Security 入门
    Maven总结
    git高级用法
  • 原文地址:https://www.cnblogs.com/wheatCatcher/p/11432590.html
Copyright © 2011-2022 走看看