<template>
  <!--table表格组件-->
  <div class="def-table">
    <!--table表格-->
    <el-table
      :data="tableData"
      :list="tableColumnList"
      v-bind="$attrs"
      @click.stop
    >
      <template v-for="item in tableColumnList" :key="item.prop">
        <!--正常栏-->
        <template v-if="!item.action">
          <el-table-column align="center" v-bind="item">
            <template #default="scope">
              <div class="cell-content">
                <!--无编辑行-->
                <template v-if="rowScopeIndex !== scope.$index">
                  <!--无编辑单元格-->
                  <template v-if="!item.editable">
                    <!--前置图标-->
                    <def-icon
                      v-if="item.icon"
                      :icon="item.icon"
                      :style="item.iconStyle"
                    />
                    <slot
                      :name="item.prop"
                      :row="scope.row"
                      :$index="scope.$index"
                    >
                      <span>{{ scope.row[item.prop] }}</span>
                    </slot>
                  </template>
                  <!--编辑单元格-->
                  <template v-else>
                    <!--编辑前-->
                    <template
                      v-if="cellEditId !== scope.column.id + '_' + scope.$index"
                    >
                      <!--前置图标-->
                      <def-icon
                        v-if="item.icon"
                        :icon="item.icon"
                        :style="item.iconStyle"
                      />
                      <slot
                        :name="item.prop"
                        :row="scope.row"
                        :$index="scope.$index"
                      >
                        <span>{{ scope.row[item.prop] }}</span>
                      </slot>
                      <!--编辑图标-->
                      <def-icon
                        class="icon-edit"
                        icon="edit"
                        @click.stop="onCellSet(scope, item.prop)"
                      />
                    </template>
                    <!--编辑后-->
                    <template v-else>
                      <div class="cell-edit">
                        <el-input
                          :size="$attrs.size"
                          type="text"
                          v-model="scope.row[item.prop]"
                          clearable
                        ></el-input>
                        <div class="cell-edit-icons" @click="onCellClear">
                          <def-icon
                            class="icon-confirm"
                            icon="check"
                            @click="onCellConfirm(scope.row, item.prop)"
                          />
                          <def-icon
                            class="icon-close"
                            icon="close"
                            @click="onCellClose(scope.row, item.prop)"
                          />
                        </div>
                      </div>
                    </template>
                  </template>
                </template>
                <!--编辑行-->
                <template v-else>
                  <div class="cell-edit">
                    <el-input
                      :size="$attrs.size"
                      type="text"
                      v-model="scope.row[item.prop]"
                      clearable
                    ></el-input>
                  </div>
                </template>
              </div>
            </template>
          </el-table-column>
        </template>
        <!--操作栏-->
        <template v-else>
          <el-table-column align="right" width="220">
            <!--操作栏表头-->
            <template #header>
              <slot name="header">
                <el-button :size="$attrs.size" type="primary" @click="onRowAdd">
                  <def-icon icon="CirclePlus" />
                  <span>添加</span>
                </el-button>
              </slot>
            </template>
            <!--操作栏按钮-->
            <template #default="scope">
              <slot name="action" :scope="scope">
                <template v-if="scope.$index !== rowScopeIndex">
                  <el-button
                    :size="$attrs.size"
                    type="success"
                    @click="onRowEdit(scope)"
                  >
                    <def-icon icon="edit" />
                    <span>编辑</span>
                  </el-button>
                  <el-button
                    :size="$attrs.size"
                    type="danger"
                    @click="onRowDelete(scope.row)"
                  >
                    <def-icon icon="delete" />
                    <span>删除</span>
                  </el-button>
                </template>
                <template v-else>
                  <el-button
                    :size="$attrs.size"
                    type="info"
                    @click="onRowCancel"
                  >
                    <def-icon icon="CircleClose" />
                    <span>取消</span>
                  </el-button>
                  <el-button
                    :size="$attrs.size"
                    type="primary"
                    @click="onRowConfirm(scope.row)"
                  >
                    <def-icon icon="CircleCheck" />
                    <span>确认</span>
                  </el-button>
                </template>
              </slot>
            </template>
          </el-table-column>
        </template>
      </template>
    </el-table>
    <!--分页-->
  </div>
</template>

<script lang="ts" setup>
import { onBeforeMount, onMounted, PropType, ref, watch } from 'vue'
import { ITableColumn } from './types'
import { addEvent, removeEvent } from '@/utils'
import { ElMessage, ElMessageBox } from 'element-plus/es'

/* 参数声明 */
const props = defineProps({
  data: {
    // 表格数据
    type: Array as PropType<any[]>,
    required: true
  },
  list: {
    // 表格项配置数组
    type: Array as PropType<ITableColumn[]>,
    required: true
  }
})
const emits = defineEmits(['cellConfirm', 'rowAdd', 'rowConfirm', 'rowDelete'])

/* 数据处理 */
const tableData = ref<any[]>(props.data)
const tableColumnList = ref<ITableColumn[]>(props.list)
watch(
  () => props.data,
  (val) => {
    tableData.value = val
  }
)

// 单元格编辑处理
const cellEditId = ref<string>('')
const cellEditRow = ref<any>()
const cellEditProp = ref<string>('')
const cellEditOldVal = ref<string | any>()
const onCellSet = (scope: any, prop: string) => {
  // 点击编辑其他单元格时还原上个单元格的值
  if (cellEditOldVal.value)
    cellEditRow.value[cellEditProp.value] = cellEditOldVal.value
  // if (cellEditRow.value && cellEditProp.value) onCellClose(cellEditRow.value, cellEditProp.value)
  // 保存当前row与prop与编辑时的旧值
  cellEditRow.value = scope.row
  cellEditProp.value = prop
  cellEditOldVal.value = scope.row[prop]
  // 保证只有一个单元格可以编辑
  cellEditId.value = scope.column.id + '_' + scope.$index
}
const onCellConfirm = (row: any, prop: string) => {
  console.log('√', row)
  // 如果修改前与修改后内容一致就直接return
  if (cellEditOldVal.value && cellEditOldVal.value === row[prop]) return
  // 触发外层事件
  emits('cellConfirm', row)
  ElMessage.success('操作成功')
  // 清空旧值
  cellEditOldVal.value = ''
}
const onCellClose = (row: any, prop: string) => {
  console.log('×', row)
  if (cellEditOldVal.value) row[prop] = cellEditOldVal.value
}
const onCellClear = () => {
  // 还原上个单元格的值
  if (cellEditOldVal.value)
    cellEditRow.value[cellEditProp.value] = cellEditOldVal.value
  // if (cellEditRow.value && cellEditProp.value) onCellClose(cellEditRow.value, cellEditProp.value)
  // 清空默认值
  cellEditId.value = ''
  cellEditRow.value = null
  cellEditProp.value = ''
  cellEditOldVal.value = ''
}

// 行操作处理
const rowScope = ref<any>()
const rowScopeIndex = ref<number>(-1)
const rowScopeRow = ref<any>()
const onRowEdit = (scope: any) => {
  console.log('行编辑', scope)
  // 清除单元格编辑遗留数据
  onCellClear()
  // 恢复行数据
  if (rowScopeRow.value) {
    for (const key of Object.keys(rowScope.value.row)) {
      rowScope.value.row[key] = rowScopeRow.value[key]
    }
  }
  // 保存行数据
  rowScope.value = scope
  rowScopeRow.value = JSON.parse(JSON.stringify(scope.row))
  // 保证只有一行可以编辑
  rowScopeIndex.value = scope.$index
}
const onRowDelete = (row: any) => {
  console.log('行删除', row)
  ElMessageBox.confirm('是否删除该行？', '行删除', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(() => {
    // 触发外层事件
    console.log('emit rowDelete')
    emits('rowDelete', row)
    ElMessage.success('删除成功')
  })
}
const onRowConfirm = (row: any) => {
  console.log('行确认', row)
  // 触发外层事件
  console.log('emit rowConfirm')
  emits('rowConfirm', row)
  ElMessage.success('操作成功')
  // 清空保存数据
  rowScopeRow.value = null
  onRowCancel()
}
const onRowCancel = () => {
  console.log('行取消', rowScopeRow.value)
  // 恢复行数据
  if (rowScopeRow.value) {
    for (const key of Object.keys(rowScope.value.row)) {
      rowScope.value.row[key] = rowScopeRow.value[key]
    }
  }
  rowScope.value = null
  rowScopeRow.value = null
  rowScopeIndex.value = -1
}
const onRowAdd = () => {
  console.log('行新增')
  // 触发外层事件
  emits('rowAdd')
  // console.log(tableData.value)
}

// 点击屏幕关闭编辑单元格与恢复编辑之前的值
onMounted(() => {
  addEvent(document.body, 'click', onCellClear, false)
  addEvent(document.body, 'click', onRowCancel, false)
})
onBeforeMount(() => {
  removeEvent(document.body, 'click', onCellClear, false)
  removeEvent(document.body, 'click', onRowCancel, false)
})
</script>

<style scoped lang="scss">
.def-table {
  flex: 1;
  .def-icon {
    margin-right: 5px;
  }
  .icon-edit {
    margin-right: 0;
    margin-left: 10px;
    font-size: 1.2em;
    &:hover {
      opacity: 0.7;
      cursor: pointer;
    }
  }
  .cell-edit {
    @include flexRow;
    .cell-edit-icons {
      margin-left: 15px;
      width: 80px;
      font-size: 1.5em;

      @include flexRow;
      .icon-confirm,
      .icon-close {
        flex: 1;
        color: green;
        &:hover {
          opacity: 0.7;
          cursor: pointer;
        }
      }
      .icon-close {
        margin-right: 0;
        color: red;
      }
    }
  }
  :deep(.el-button) {
    // 解决按钮点击后移开鼠标颜色仍然聚焦的解决方法
    &:focus {
      color: var(--el-button-text-color);
      background-color: var(--el-button-bg-color);
      border: var(--el-border);
      border-color: var(--el-button-border-color);
    }
    &:hover {
      color: var(--el-button-hover-text-color);
      background-color: var(--el-button-hover-bg-color);
      border-color: var(--el-button-hover-border-color);
      outline: 0;
    }
  }
}
</style>
