<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>