<template>  
 | 
  <div>  
 | 
    <a-table  
 | 
          :rowKey="(record) => record.key"  
 | 
          :loading="loading"  
 | 
          :columns="columns"  
 | 
          :dataSource="data"  
 | 
          :pagination="false"  
 | 
          :rowClassName="record => record.editable ? 'editable' : ''"  
 | 
        >  
 | 
  
 | 
        <template slot="name" slot-scope="text,record">  
 | 
          <a-input v-if="record.editable"  
 | 
                    :value="text"  
 | 
                    autoFocus  
 | 
                    @change="e => handleFieldChange(e, 'name', record.key)"  
 | 
                    @pressEnter="e => handleKeyPress(e, record.key)"  
 | 
                    placeholder="成员姓名"  
 | 
                />  
 | 
                <span v-else >{{text}}</span>  
 | 
        </template>  
 | 
  
 | 
        <template slot="workId" slot-scope="text,record">  
 | 
          <a-input v-if="record.editable"  
 | 
                    :value="text"  
 | 
                    autoFocus  
 | 
                    @change="e => handleFieldChange(e, 'workId', record.key)"  
 | 
                    @pressEnter="e => handleKeyPress(e, record.key)"  
 | 
                    placeholder="工号"  
 | 
                />  
 | 
                <span v-else >{{text}}</span>  
 | 
        </template>  
 | 
  
 | 
        <template slot="department" slot-scope="text,record">  
 | 
          <a-input v-if="record.editable"  
 | 
                    :value="text"  
 | 
                    autoFocus  
 | 
                    @change="e => handleFieldChange(e, 'department', record.key)"  
 | 
                    @pressEnter="e => handleKeyPress(e, record.key)"  
 | 
                    placeholder="所属部门"  
 | 
                />  
 | 
                <span v-else >{{text}}</span>  
 | 
        </template>  
 | 
        <template slot="action" slot-scope="text,record">  
 | 
            <span v-if="!record.editable">  
 | 
              <a @click="e=>toggleEditable(e, record.key)">编辑</a>  
 | 
              <a-divider type="vertical" />  
 | 
              <a-popconfirm title="是否要删除此行?" @confirm="remove(record.key)">  
 | 
                <a>删除</a>  
 | 
              </a-popconfirm>  
 | 
            </span>  
 | 
  
 | 
            <template v-else>  
 | 
              <span v-if="record.isNew">  
 | 
                  <a @click="e => saveRow(e, record.key)">添加</a>  
 | 
                  <a-divider type="vertical" />  
 | 
                  <a-popconfirm title="是否要删除此行?" @confirm="() => remove(record.key)">  
 | 
                    <a>删除</a>  
 | 
                  </a-popconfirm>  
 | 
              </span>  
 | 
              <span v-else>  
 | 
                <a @click="e => saveRow(e, record.key)">保存</a>  
 | 
                <a-divider type="vertical" />  
 | 
                <a @click="e => cancel(e, record.key)">取消</a>  
 | 
              </span>  
 | 
            </template>  
 | 
  
 | 
        </template>  
 | 
    </a-table>  
 | 
        <a-button  
 | 
          :style="{ width: '100%', marginTop: 16, marginBottom: 8 }"  
 | 
          type="dashed"  
 | 
          @click="newMember"  
 | 
          icon="plus"  
 | 
        >  
 | 
          新增成员  
 | 
        </a-button>  
 | 
  </div>  
 | 
</template>  
 | 
  
 | 
<script  lang="ts">  
 | 
import { Component, Prop, Vue } from 'vue-property-decorator';  
 | 
import { State, Mutation, namespace } from 'vuex-class';  
 | 
  
 | 
@Component({})  
 | 
export default class TableForm extends Vue {  
 | 
  @Prop({ type: Array, default: () => [] })  
 | 
  private value!: any[];  
 | 
  
 | 
  private loading: boolean = false;  
 | 
  
 | 
  private data: any[] = this.value;  
 | 
  
 | 
  private index: number = 0;  
 | 
  
 | 
  private clickedCancel: boolean = false;  
 | 
  
 | 
  private cacheOriginData: any = {};  
 | 
  
 | 
  private columns: any[] = [  
 | 
    {  
 | 
      title: '成员姓名',  
 | 
      dataIndex: 'name',  
 | 
      key: 'name',  
 | 
      width: '20%',  
 | 
      scopedSlots: {  
 | 
        customRender: 'name',  
 | 
      },  
 | 
    },  
 | 
    {  
 | 
      title: '工号',  
 | 
      dataIndex: 'workId',  
 | 
      key: 'workId',  
 | 
      width: '20%',  
 | 
      scopedSlots: {  
 | 
        customRender: 'workId',  
 | 
      },  
 | 
    },  
 | 
    {  
 | 
      title: '所属部门',  
 | 
      dataIndex: 'department',  
 | 
      key: 'department',  
 | 
      width: '40%',  
 | 
      scopedSlots: {  
 | 
        customRender: 'department',  
 | 
      },  
 | 
    },  
 | 
    {  
 | 
      title: '操作',  
 | 
      key: 'action',  
 | 
      scopedSlots: {  
 | 
        customRender: 'action',  
 | 
      },  
 | 
    },  
 | 
  ];  
 | 
  
 | 
  constructor() {  
 | 
    super();  
 | 
  }  
 | 
  
 | 
  private handleFieldChange(e: any, fieldName: string, key: any) {  
 | 
    const newData = this.data.map((item: any) => ({ ...item }));  
 | 
  
 | 
    const target = this.getRowByKey(key, newData);  
 | 
  
 | 
    if (target) {  
 | 
      target[fieldName] = e.target.value;  
 | 
      this.data = newData;  
 | 
    }  
 | 
  }  
 | 
  
 | 
  private handleKeyPress(e: any, key: any) {  
 | 
    if (e.key === 'Enter') {  
 | 
      this.saveRow(e, key);  
 | 
    }  
 | 
  }  
 | 
  
 | 
  private newMember(e: any) {  
 | 
    const newData = this.data.map((item: any) => ({ ...item }));  
 | 
    newData.push({  
 | 
      key: `NEW_TEMP_ID_${this.index}`,  
 | 
      workId: '',  
 | 
      name: '',  
 | 
      department: '',  
 | 
      editable: true,  
 | 
      isNew: true,  
 | 
    });  
 | 
    this.index += 1;  
 | 
    this.data = newData;  
 | 
  }  
 | 
  
 | 
  private saveRow(e: any, key: any) {  
 | 
    e.preventDefault();  
 | 
    this.loading = true;  
 | 
    setTimeout(() => {  
 | 
      if (this.clickedCancel) {  
 | 
        this.clickedCancel = false;  
 | 
        return;  
 | 
      }  
 | 
      const target = this.getRowByKey(key, null) || {};  
 | 
      if (!target.workId || !target.name || !target.department) {  
 | 
        // message.error('请填写完整成员信息。');  
 | 
        e.target.focus();  
 | 
        this.loading = false;  
 | 
        return;  
 | 
      }  
 | 
  
 | 
      delete target.isNew;  
 | 
      this.toggleEditable(e, key);  
 | 
      this.loading = false;  
 | 
    }, 500);  
 | 
  }  
 | 
  
 | 
  private toggleEditable(e: any, key: any) {  
 | 
    e.preventDefault();  
 | 
    const newData = this.data.map((item: any) => ({ ...item }));  
 | 
    const target = this.getRowByKey(key, newData);  
 | 
    if (target) {  
 | 
      if (!target.editable) {  
 | 
        this.cacheOriginData[key] = { ...target };  
 | 
      }  
 | 
      target.editable = !target.editable;  
 | 
      this.data = newData;  
 | 
    }  
 | 
  }  
 | 
  
 | 
  private cancel(e: any, key: any) {  
 | 
    this.clickedCancel = true;  
 | 
    e.preventDefault();  
 | 
    const newData = this.data.map((item: any) => ({ ...item }));  
 | 
    const target = this.getRowByKey(key, newData);  
 | 
    if (this.cacheOriginData[key]) {  
 | 
      Object.assign(target, this.cacheOriginData[key]);  
 | 
      delete this.cacheOriginData[key];  
 | 
    }  
 | 
    target.editable = false;  
 | 
    this.data = newData;  
 | 
    this.clickedCancel = false;  
 | 
  }  
 | 
  
 | 
  private remove(key: any) {  
 | 
    const newData = this.data.filter((item: any) => item.key !== key);  
 | 
    this.data = newData;  
 | 
  }  
 | 
  
 | 
  private getRowByKey(key: any, newData: any) {  
 | 
    return (newData || this.data).filter((item: any) => item.key === key)[0];  
 | 
  }  
 | 
}  
 | 
</script> 
 |