<div id="app">
    <el-table :data="tableData" :span-method="tableSpanMethod" row-key="id">
        <el-table-column align="center" prop="product" label="产品" width="320"></el-table-column>
        <el-table-column align="center" prop="progress" label="积分加权(进度)" width="150">
            <template slot-scope="scope">
                <editable-cell :text="scope.row.progress" @change-value="onCellChange(arguments, scope)"></editable-cell>
            </template>
        </el-table-column>
        <el-table-column align="center" prop="quality" label="积分加权(质量)" width="150">
            <template slot-scope="scope">
                <editable-cell :text="scope.row.quality" @change-value="onCellChange(arguments, scope)"></editable-cell>
            </template>
        </el-table-column>
        <el-table-column align="center" prop="scoreTotal" label="综合积分累计" width="120"></el-table-column>
        <el-table-column align="center" prop="handler" label="处理人"></el-table-column>
        <el-table-column align="center" prop="summary" label="汇总"></el-table-column>
        <el-table-column align="center" prop="workingTime" label="考勤累计工时" width="150"></el-table-column>
        <el-table-column align="center" prop="floatingIntegral" label="浮动积分" width="150">
            <template slot-scope="scope">
                <editable-cell :text="scope.row.floatingIntegral" @change-value="onCellChange(arguments, scope)"></editable-cell>
            </template>
        </el-table-column>
        <el-table-column align="center" prop="reason" label="浮动原因" width="150" class-name="textareaColumn">
            <template slot-scope="scope">
                <editable-cell :text="scope.row.reason" input-type="textarea" @change-value="onCellChange(arguments, scope)"></editable-cell>
            </template>
        </el-table-column>
        <el-table-column align="center" prop="finalScore" label="最终得分" width="150"></el-table-column>
        <el-table-column align="center" prop="finalPerformance" label="最终绩效" width="150" class-name="textareaColumn">
            <template slot-scope="scope">
                <editable-cell :text="scope.row.finalPerformance" input-type="textarea" @change-value="onCellChange(arguments, scope)"></editable-cell>
            </template>
        </el-table-column>
    </el-table>
<script>
    export default{
        components: {
            EditableCell: () => import('@/components/EditableCell/EditableCell.vue'),
        data() {
            return {
                tableData:[] // 自行填充数据
        methods: {
             * 如果单元格存在跨行,并且想要获取当前单元格的跨行跨列的值
             * @param {Object} val 
             * @param {Object} row
             * @param {Object} column
             * @param {Object} $index
            onCellChange(val, { row, column, $index }) {
                let tr = document.querySelectorAll('.el-table .el-table__body-wrapper tbody tr');
                let td = tr[$index].getElementsByClassName(column.id)[0];
                let rowspan = td.getAttribute('rowspan');
                for(let i = 0; i < rowspan; i++){
                    this.tableData[$index + i][column.property] = val[0];
                val[1](); // 调用关闭输入框的回调方法
             * 合并行或列的计算方法
            tableSpanMethod({row, column, rowIndex, columnIndex}){
                return {
                    rowspan: columnIndex >= 4 ? this.mergeRows(row[column.property], this.tableData, rowIndex, column.property) : 1,
                    colspan: 1
             * 表格单元格合并-----行
             * @param {Object} value      当前单元格的值
             * @param {Object} data       当前表格所有数据
             * @param {Object} index      当前单元格的值所在 行 索引
             * @param {Object} property   当前列的property
             * @returns {number}          待合并单元格数量
            mergeRows(value, data, index, property) {
                // 判断 当前行的该列数据 与 上一行的该列数据 是否相等
                if (index !== 0 && value === data[index - 1][property] && data[index].name === data[index - 1].name) {
                    // 返回 0 使表格被跨 行 的那个单元格不会渲染
                    return 0;
                // 判断 当前行的该列数据 与 下一行的该列数据 是否相等
                let rowSpan = 1;
                for (let i = index + 1; i < data.length; i++) {
                    if (value == data[i][property] && data[i].name == data[i - 1].name){
                        rowSpan++;
                    }else{
                        break;
                return rowSpan;
</script>
<template>
    <div class="editable-cell">
        <div v-if="editable" class="editable-cell-input-wrapper clearfix">
            <el-input v-if="inputType == 'input'" class="editable-input" ref="editableInput" v-model="value" size="mini" @input="handleInput" @keyup.enter.native="check"></el-input>
            <el-input v-if="inputType == 'textarea'" type="textarea" autosize ref="editableTextarea" v-model="value" @input="handleInput" @keyup.enter.native="check"></el-input>
            <i class="editable-cell-icon-check el-icon-check" @click="check"></i>
        <div v-else class="editable-cell-text-wrapper">
            {{ value || ' ' }}
            <i class="editable-cell-icon el-icon-edit" @click="edit"></i>
</template>
<script>
    export default{
        props: {
            text: [String, Number],
            inputType: {
                type: String,
                default: () => 'input'
        watch: {
            text(newValue, oldValue){
                this.value = newValue;
        data() {
            return {
                value: this.text,
                editable: false,
        methods: {
            handleInput(e) {
                const value = e;
                this.value = value;
            check() {
                this.$emit('changeValue', this.value, () => {
                    this.editable = false;
            edit() {
                this.editable = true;
                this.$nextTick(() => {
                    this.$refs.editableInput?.focus();
                    this.$refs.editableTextarea?.focus();
</script>
<style>
    .cl:after,.clearfix:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; }.cl,.clearfix{ zoom: 1; }
    .editable-cell {
        position: relative;
    .editable-cell-input-wrapper,.editable-cell-text-wrapper {
        padding-right: 24px;
        height: 28px;
        line-height: 28px;
    .editable-cell-text-wrapper {
        /* padding: 5px 24px 5px 5px; */
    .editable-cell-input-wrapper .editable-input{
        float: left;
    .editable-cell-input-wrapper .el-textarea{
        height: 100%;
    .editable-cell-input-wrapper .el-textarea textarea{
        height: 100%;
        overflow: hidden;
    .editable-cell-icon,.editable-cell-icon-check {
        position: absolute;
        top:0;
        bottom:0;
        right: 0;
        margin:auto;
        cursor: pointer;
    .editable-cell-icon {
        width:16px;
        height:16px;
        line-height: 16px;
        text-align: center;
        display: none;
    .editable-cell-icon-check {
        width:16px;
        height:16px;
        line-height: 16px;
        text-align: center;
    .editable-cell:hover .editable-cell-icon {
        display: inline-block;
    .editable-cell-icon:hover,.editable-cell-icon-check:hover {
        color: #108ee9;
    td.textareaColumn *:not(i){
        height: 100%;