Newer
Older
smart-metering-front / src / components / MultiHeaderTable / index.vue
<script lang="ts" setup name="MultiHeaderTableIndex">
import TableColumn from './tableColumn.vue'
const props = defineProps({
  // 表格的数据
  tableData: {
    type: Array,
    default: () => [],
  },
  // 多级表头的数据
  tableHeader: {
    type: Array as any,
    default: () => [],
  },
  // 是否需要多选
  multiSelected: {
    type: Boolean,
    default: false,
  },
  // 是否显示 总计行
  showSummary: {
    type: Boolean,
    default: false,
  },
  // 设置Table的最大高度
  maxHeight: {
    type: String,
    default: 'auto',
    // default: '400',
  },
  height: {
    type: String,
    // default: 'auto',
    // default: '300',
  },
  width: {
    type: String,
    defualt: '100%',
  },
  // 集合中的指定列有重复的值合并
  mergeRows: {
    type: Array,
    default: () => [],
  },
  // 是否单选
  highlightCurrentRow: {
    type: Boolean,
    default: false,
  },
  // inputNumber最小数量
  min: {
    type: Number,
  },
  showOverflowTooltip: {
    type: Boolean,
    default: false,
  },
  needIndex: { // 为否需要序号
    type: Boolean,
    default: false,
  },
})
const emits = defineEmits([
  'handleSelectionChange',
  'rowClick',
  'dbclick',
  'row-dbclick',
  'cellDblclick',
  'cellClick',
  'rowContextmenu',
  'headerClick',
  'headerContextmenu',
  'handleCurrentChange',
  'handleInputNumberChange',
  'handleClickHeader',
  'selectChange',
])

const tableList = ref([]) // 处理后的table数据
// 多选数组集合
const multipleSelection = ref([])
// 监听
watch(() => props.tableData, (newValue) => {
  if (newValue && newValue?.length) {
    if (Array.isArray(newValue) && newValue?.length) {
      const data = newValue[newValue.length - 1]
    }
    init(newValue)
    // useMergeTableRow(newValue, props.mergeRows)
  }
}, { deep: true, immediate: true })

function init(val: any) {
  // 对数据合并指定行处理
  mergeTableRowMethod(val, props.mergeRows) // 意思是name的列有重复的值就要合并
}
// 多选方法
function handleSelectionChange(val: any) {
  multipleSelection.value = val
  emits('handleSelectionChange', val)
}
// 手动勾选数据行的checkBox会触发
function handleSelect(val: any, row: any) {
  console.log('手动勾选触发')
  console.log(val, row)
}
// elementUI的合并行方法
function mergeTableRow({ row, column, rowIndex, columnIndex }: any) {
  // console.log(row, column, rowIndex, columnIndex);
  const span = `${column.property}-span`
  if (row[span]) {
    return row[span]
  }
}
// 封装合并指定行逻辑
function mergeTableRowMethod(data: any, merge: any) {
  if (!merge || merge.length === 0) {
    tableList.value = data
  }
  merge.forEach((m: any) => {
    const mList = {} as any
    data = data.map((v: any, index: number) => {
      const rowVal = v[m]
      if (mList[rowVal] && mList[rowVal].newIndex === index) {
        mList[rowVal].num++
        mList[rowVal].newIndex++
        data[mList[rowVal].index][`${m}-span`].rowspan++
        v[`${m}-span`] = {
          rowspan: 0,
          colspan: 0,
        }
      }
      else {
        mList[rowVal] = { num: 1, index, newIndex: index + 1 }
        v[`${m}-span`] = {
          rowspan: 1,
          colspan: 1,
        }
      }
      return v
    })
  })
  tableList.value = data
}

function handleInputChange(val: any) {
  console.log(val, 'handleInputChange')
}
function handleInputBlur(row: any) {
  console.log(row, 'handleInputBlur')
}
function rowClick(row: any, column: any) {
  emits('rowClick', row, column)
}
function rowDoubleClick(row: any, column: any) {
  console.log('dbclick')
  emits('dbclick', row, column)
}
function cellDblclick(row: any, column: any, cell: any, event: any) {
  emits('cellDblclick', row, column, cell, event)
}
function cellClick(row: any, column: any, cell: any, event: any) {
  emits('cellClick', row, column, cell, event)
}
function rowContextmenu(row: any, column: any) {
  emits('rowContextmenu', row, column)
}
// 当某一列的表头被点击时会触发该事件
function headerClick(column: any) {
  emits('headerClick', column)
}
// 当某一列的表头被鼠标右键点击时触发该事件
function headerContextmenu(column: any) {
  emits('headerContextmenu', column)
}
function currentChange(currentRow: any) {
  emits('handleCurrentChange', currentRow)
}
function handleInputNumberChange(currentRow: any) {
  emits('handleInputNumberChange', currentRow)
}
// 监听点击多级表头事件(此事件在子组件重触发)
function handleClickHeader(column: any, checkDateDetailId: string) {
  emits('handleClickHeader', column, checkDateDetailId)
}

// select选择器选中值变化
function selectChange(value: any, row: any) {
  emits('selectChange', value, row)
}
</script>

<template>
  <div class="multi-header-table">
    <el-table
      ref="csTable"
      :data="tableList"
      :max-height="maxHeight"
      :span-method="mergeTableRow"
      :show-summary="showSummary"
      :highlight-current-row="highlightCurrentRow"
      stripe
      @selection-change="handleSelectionChange"
      @current-change="currentChange"
      @row-click="rowClick"
      @row-dblclick="rowDoubleClick"
      @cell-dblclick="cellDblclick"
      @cell-click="cellClick"
      @select="handleSelect"
      @row-contextmenu="rowContextmenu"
      @header-click="headerClick"
      @header-contextmenu="headerContextmenu"
    >
      <!-- @cell-dblclick="handleTableCellClick" -->
      <el-table-column v-if="needIndex" label="序号" align="center" type="index" width="55" />
      <el-table-column v-if="multiSelected" type="selection" width="85" />
      <!-- 需要加在表最前方的插槽 -->
      <slot name="preColumns" />
      <template v-for="(item, index) in tableHeader">
        <table-column
          v-if="item.children && item.children.length"
          :key="item.id"
          :width="item.width"
          :coloumn-header="item"
          :min="min"
          :align="item.align"
          :show-overflow-tooltip="showOverflowTooltip"
          @handle-input-number-change="handleInputNumberChange"
          @handleClickHeader="handleClickHeader"
        />
        <!-- icon类型 -->
        <el-table-column
          v-else-if="item.type === 'icon'"
          :key="`c_${index}`"
          :label="item.text"
          :prop="item.value"
          :width="item.width"
          :fixed="item.fixed"
        >
          <template #default="scope">
            <i
              :class="item.icon"
              :style="{ color: item.colorList[parseInt(scope.row[item.value])], fontSize: item.size }"
            />
          </template>
        </el-table-column>
        <el-table-column
          v-else
          :key="index"
          :label="item.text"
          :width="item.width"
          :prop="item.value"
          :align="item.align"
          :show-overflow-tooltip="showOverflowTooltip"
        >
          <template #header>
            <span v-show="item.required" style="color: red;">*</span><span>{{ item.text }}</span>
          </template>
          <template #default="scope">
            <el-select
              v-if="item.type === 'select' && scope.row.editable"
              v-model="scope.row[item.value]"
              placeholder="请选择"
              @change="(value) => selectChange(value, scope.row)"
            >
              <el-option
                v-for="opt in item.options"
                :key="opt.value"
                :label="opt.text"
                :value="opt.value"
              />
            </el-select>
            <el-date-picker
              v-else-if="item.type === 'date' && scope.row.editable"
              v-model="scope.row[item.value]"
              type="date"
              style="width: 100%;"
              placeholder="选择日期"
              format="YYYY-MM-DD"
              value-format="YYYY-MM-DD"
            />
            <el-input
              v-else-if="item.type === 'input' && scope.row.editable"
              v-model="scope.row[item.value]"
              @change="handleInputChange(scope)"
              @blur="handleInputBlur(scope.row)"
            />
            <!-- <precision-input-number
              v-else-if="item.type === 'inputNumber' && scope.row.editable"
              v-model="scope.row[item.value]"
              :precision="item.precision || scope.row.useRowPrecisionData || scope.row.validDigit"
              :min="min"
            /> -->
            <el-input-number
              v-else-if="item.type === 'inputNumber' && scope.row.editable "
              v-model="scope.row[item.value]"
              :precision="item.precision"
              :min="min"
              @change="handleInputNumberChange(scope)"
            />

            <template v-else-if="item.type === 'text'">
              <span>{{ scope.row[item.value] }}
              </span>
            </template>
            <template v-else>
              <span v-show="!scope.row.editable">{{ scope.row[item.value] }}
              </span>
            </template>
            <!-- 单位 -->
            <template v-if="scope.row[item.value] && item.unit">
              {{ scope.row[item.unit] }}
            </template>
            <span v-show="scope.row.exceedMark === 1 && item.needMark" style="color: red;">*</span>
          </template>
        </el-table-column>
      </template>
      <!-- 自定义的放这里 -->
      <slot name="columns" />
    </el-table>
  </div>
</template>

<style lang="scss" scoped>
.multi-header-table {
  width: 100%;
  // 隐藏全选按钮

  :deep(.el-radio__label) {
    // display: none;
  }

  :deep(.el-table thead.is-group th.el-table__cell) {
    background: #f2f6ff;
  }
}

.single-table {
  width: 100%;

  :deep(.el-table th.el-table__cell:nth-child(1) .cell) {
    visibility: hidden;
  }
}
</style>