index.vue 4.33 KB
<style>
.eagle-form-table .eagle-form-table__body td {
  padding: 5px;
}
.eagle-form-table__label {
  text-align: right !important;
  padding: 5px 15px !important;
  font-weight: bold;
  background-color: #F5F7FA;
}
.eagle-form-table__value {
  overflow: hidden;
}
.eagle-form-table__value .el-input__inner,
.eagle-form-table__value .el-textarea__inner {
  border-left: 0;
  border-right: 0;
  border-top: 0;
  border-bottom: 0;
}
</style>

<template>
  <div class="eagle-form-table el-table el-table--fit el-table--border el-table--enable-row-transition el-table--small">
    <div v-if="fullProps.title || $scopedSlots['title'] || $slots['title']" class="el-table__header-wrapper">
      <table class="el-table__header w-full" cellspacing="0" cellpadding="0">
        <thead>
          <tr class="el-table__row">
            <!-- 标题插槽 -->
            <th v-if="$scopedSlots['title'] || $slots['title']">
              <slot name="title"></slot>
            </th>
            <th v-else class="is-center">{{ fullProps.title }}</th>
          </tr>
        </thead>
      </table>
    </div>
    <div class="el-table__body-wrapper text-lg">
      <table class="el-table__body w-full" cellspacing="0" cellpadding="0">
        <tbody class="eagle-form-table__body">
          <tr v-for="(item, index) in fullProps.list" :key="index" class="el-table__row">
            <template v-if="(item instanceof Array)">
              <template v-for="(col, idx) in item">
                <td class="eagle-form-table__label" :style="labelStyle" :key="`${index}-${idx}-label`" :rowspan="col.rowspan">{{ col.label }}</td>
                <td class="eagle-form-table__value" :key="`${index}-${idx}-value`" :colspan="getColspan({ item, col, idx })" :rowspan="col.rowspan">
                  <component :is="col.type" v-model="model[col.key]" v-bind="col.props" v-on="bindItemEvent(col)" size="mini" />
                </td>
              </template>
            </template>
            <template v-else>
              <td class="eagle-form-table__label" :style="labelStyle" :rowspan="item.rowspan">{{ item.label }}</td>
              <td class="eagle-form-table__value" :colspan="maxColSpan - 1" :rowspan="item.rowspan">
                <component :is="item.type" v-model="model[item.key]" v-bind="item.props" v-on="bindItemEvent(item)" size="mini" />
              </td>
            </template>
          </tr>
        </tbody>
      </table>
    </div>
    <div v-if="$scopedSlots['footer'] || $slots['footer']" class="el-table__footer-wrapper">
      <table class="el-table__header w-full" cellspacing="0" cellpadding="0">
        <tbody>
          <tr>
            <td class="eagle-form-table__value" :colspan="maxColSpan" style="text-align: center">
              <slot name="footer"></slot>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

<script>
export default {
  name: 'form-table',
  props: {
    value: Object,
    list: Array,
    title: String
  },
  data() {
    return {
      model: this.value || {},
      fullProps: { ...this.$attrs, ...this.$props },
      labelStyle: { width: '100px' },
    }
  },
  watch: {
    value(val = {}) {
      this.model = val;
    },
    model: {
      handler(val) {
        this.$emit("input", val);
      },
      deep: true,
    }
  },
  computed: {
    // 配置列表中的最大列数
    maxColNum() {
      let number = 1;
      this.list.forEach(item => {
        if (item instanceof Array) {
          if (item.length > number) {
            number = item.length;
          }
        }
      });
      return number;
    },
    // 配置列表的最大占位数
    maxColSpan() {
      return this.maxColNum * 2;
    },
  },
  methods: {
    getColspan({ item, col, idx }) {
      // 如果存在列数小于最大列数的行
      if (item.length < this.maxColNum) {
        const normalColSpan = Math.floor((this.maxColSpan - item.length) / item.length);
        return col.colspan || normalColSpan;
      }
      return 1;
    },
    /**
     * @description 绑定表单项事件
     * @param {Object} item 表单项配置
     * @returns {Function} 事件函数
     */
    bindItemEvent(item) {
      if (item.on) {
        if (typeof item.on === 'function') {
          return item.on(this.model);
        } else {
          return item.on
        }
      } else {
        return undefined
      }
    },
  }
}
</script>