﻿<template>
  <el-form
    ref="formRef"
    :model="{ tableData }"
    :rules="rules"
    class="editable-table-form"
  >
    <div
      v-if="showAddButton || showDeleteButton || searchFields.length > 0"
      class="editable-table-toolbar"
    >
      <div class="toolbar-left">
        <el-button
          v-if="showAddButton"
          type="primary"
          icon="Plus"
          @click="handleToolbarAdd"
        >
          添加行
        </el-button>
        <el-button
          v-if="showDeleteButton"
          type="danger"
          icon="Delete"
          :disabled="selectedRows.length === 0"
          @click="handleToolbarDelete"
        >
          删除行
        </el-button>
      </div>
      <div class="toolbar-right">
        <el-input
          v-if="searchFields.length > 0"
          v-model="searchKeyword"
          :placeholder="searchPlaceholder"
          clearable
          style="width: 300px"
          @input="handleSearch"
        >
          <template #prefix>
            <el-icon><Search /></el-icon>
          </template>
        </el-input>
      </div>
    </div>
    <vxe-table
      ref="tableRef"
      :data="filteredTableData"
      :border="border ? 'full' : false"
      :stripe="stripe"
      :max-height="maxHeight || undefined"
      :min-height="minHeight || undefined"
      :height="!maxHeight && !minHeight ? '100%' : undefined"
      :row-config="{ keyField: '_etKey' }"
      :scroll-x="{ enabled: true }"
      :scroll-y="{ enabled: true }"
      show-overflow="title"
      v-bind="$attrs"
      class="editable-table-inner"
      @checkbox-change="handleSelectionChange"
      @checkbox-all="handleSelectionChange"
    >
      <vxe-column
        v-if="showSelection"
        type="checkbox"
        width="55"
        align="center"
      />
      <vxe-column
        v-if="showRowActions"
        :width="rowActionsColumnWidth"
        align="center"
        fixed="left"
      >
        <template #header>
          <div
            v-if="showSelection && selectedRows.length > 0 && !showDeleteButton"
            style="display: flex; align-items: center; justify-content: center; gap: 4px"
          >
            <el-button
              type="danger"
              size="small"
              icon="Delete"
              link
              @click="handleDeleteSelected"
            >
              删除选中({{ selectedRows.length }})
            </el-button>
          </div>
          <span v-else />
        </template>
        <template #default="{ row, rowIndex }">
          <el-button
            v-if="showRowAddButton"
            type="primary"
            link
            icon="CirclePlus"
            class="action-btn"
            title="增加"
            @click="handleAdd(rowIndex)"
          />
          <el-button
            v-if="showRowDeleteButton"
            type="danger"
            link
            icon="Delete"
            class="action-btn"
            title="删除"
            @click="handleDelete(rowIndex)"
          />
        </template>
      </vxe-column>

      <vxe-column
        v-for="col in filteredColumns"
        :key="col.prop"
        :field="col.prop"
        :title="col.label"
        :width="col.width"
        :min-width="col.minWidth"
        :fixed="col.fixed"
        :align="col.align || 'center'"
      >
        <template #default="{ row, rowIndex }">
          <template v-if="col.type === 'input'">
            <el-form-item
              :prop="`tableData.${rowIndex}.${col.prop}`"
              :rules="col.rules"
              style="margin-bottom: 0"
            >
              <el-input
                v-model="row[col.prop]"
                :placeholder="col.placeholder || `请输入${col.label}`"
                :disabled="col.disabled"
                :clearable="col.clearable !== false"
                @blur="col.onBlur && col.onBlur(row, rowIndex)"
                @input="col.onInput && col.onInput(row, rowIndex)"
                @change="col.onChange && col.onChange(row, rowIndex)"
              >
                <template
                  v-if="col.suffix"
                  #suffix
                >
                  {{ col.suffix }}
                </template>
              </el-input>
            </el-form-item>
          </template>

          <template v-else-if="col.type === 'number'">
            <el-form-item
              :prop="`tableData.${rowIndex}.${col.prop}`"
              :rules="col.rules"
              style="margin-bottom: 0"
            >
              <el-input-number
                v-model="row[col.prop]"
                :placeholder="col.placeholder || `请输入${col.label}`"
                :disabled="col.disabled"
                :min="col.min"
                :max="col.max"
                :precision="col.precision"
                :controls="false"
                style="width: 100%"
                @change="col.onChange && col.onChange(row, rowIndex)"
              />
            </el-form-item>
          </template>

          <template v-else-if="col.type === 'select'">
            <el-form-item
              :prop="`tableData.${rowIndex}.${col.prop}`"
              :rules="col.rules"
              style="margin-bottom: 0"
            >
              <el-select
                v-model="row[col.prop]"
                :placeholder="col.placeholder || `请选择${col.label}`"
                :disabled="col.disabled"
                :clearable="col.clearable !== false"
                :filterable="col.filterable"
                :multiple="col.multiple"
                style="width: 100%"
                :class="row.error ? 'error-border' : ''"
                @change="
                  async (value: any) => {
                    const checkBeforeChange = col.extraprops?.checkBeforeChange;
                    if (checkBeforeChange && typeof checkBeforeChange === 'function') {
                      const result = await checkBeforeChange(row, rowIndex, value);
                      if (result === false) {
                        return;
                      }
                    }
                    if (col.onChange) {
                      col.onChange(row, rowIndex, value);
                    }
                  }
                "
              >
                <el-option
                  v-for="option in typeof col.options === 'function'
                    ? col.options(row, rowIndex)
                    : col.options || []"
                  :key="option.value"
                  :label="option.label"
                  :value="option.value"
                  @click="option.onClick && option.onClick(row, option)"
                />
              </el-select>
            </el-form-item>
          </template>

          <template v-else-if="col.type === 'date'">
            <el-form-item
              :prop="`tableData.${rowIndex}.${col.prop}`"
              :rules="col.rules"
              style="margin-bottom: 0"
            >
              <el-date-picker
                v-model="row[col.prop]"
                :type="col.dateType || 'date'"
                :placeholder="col.placeholder || `请选择${col.label}`"
                :disabled="col.disabled"
                :clearable="col.clearable !== false"
                :value-format="col.valueFormat || 'YYYY-MM-DD'"
                style="width: 100%"
                @change="col.onChange && col.onChange(row, rowIndex)"
              />
            </el-form-item>
          </template>

          <template v-else-if="col.type === 'slot'">
            <el-form-item
              :prop="`tableData.${rowIndex}.${col.prop}`"
              :rules="col.rules"
              style="margin-bottom: 0"
            >
              <slot
                :name="col.slot || col.prop"
                :row="row"
                :index="rowIndex"
              />
            </el-form-item>
          </template>

          <template v-else>
            <span>{{
              col.formatter
                ? col.formatter(row, { property: col.prop }, row[col.prop])
                : row[col.prop]
            }}</span>
          </template>
        </template>
      </vxe-column>
    </vxe-table>
    <div
      v-if="$slots.footer"
      class="editable-table-footer"
    >
      <slot
        name="footer"
        :table-data="tableData"
      />
    </div>
  </el-form>
</template>

<script setup lang="ts">
import {computed, nextTick, ref, watch} from 'vue';
import {Search} from '@element-plus/icons-vue';
import type {EditableTableProps} from '../types/EditableTable.d';

defineOptions({
  name: 'EditableTable',
});

const props = withDefaults(defineProps<EditableTableProps>(), {
  modelValue: () => [],
  rules: () => ({}),
  defaultRow: () => ({}),
  border: true,
  stripe: false,
  showSelection: false,
  showAddButton: false,
  showDeleteButton: false,
  showRowActions: true,
  showRowAddButton: true,
  showRowDeleteButton: true,
  searchFields: () => [],
  virtualizedThreshold: 100,
});

const emit = defineEmits<{
  'update:modelValue': [value: Record<string, any>[]];
  add: [row: Record<string, any>, index: number];
  delete: [row: Record<string, any>, index: number, isClear: boolean];
  'selection-change': [selection: Record<string, any>[]];
  'toolbar-add': [];
  'toolbar-delete': [rows: Record<string, any>[]];
}>();

const formRef = ref<any>(null);
const tableRef = ref<any>(null);
const selectedRows = ref<Record<string, any>[]>([]);
const searchKeyword = ref('');

const tableData = ref([...props.modelValue]);

// 行唯一 key（用于虚拟滚动等）
const autoRowId = ref(0);
const getRowKey = (row: Record<string, any>) => {
  if (row.rowKey !== undefined && row.rowKey !== null) return row.rowKey;
  if (row.id !== undefined && row.id !== null) return row.id;
  if (!row._etKey) {
    row._etKey = `et-${autoRowId.value++}`;
  }
  return row._etKey;
};

// 是否开启虚拟滚动：优先使用外部传入，其次根据数据量自动开启
const useVirtualized = computed(() => {
  if (typeof props.virtualized === 'boolean') {
    return props.virtualized;
  }
  const threshold = props.virtualizedThreshold ?? 100;
  return tableData.value.length > threshold;
});

// 过滤列（支持条件显示）
const filteredColumns = computed(() => {
  return props.columns.filter((col) => !col.vIf || col.vIf());
});

// 行操作列宽度：同时显示"增加+删除"则宽一点；只显示一个则缩窄
const rowActionsColumnWidth = computed(() => {
  const showAdd = !!props.showRowAddButton;
  const showDel = !!props.showRowDeleteButton;
  if (showAdd && showDel) return 100;
  if (showAdd || showDel) return 60;
  return 0;
});

const searchPlaceholder = computed(() => {
  if (props.searchFields.length === 0) {
    return '请输入搜索关键词';
  }

  const fieldLabels = props.searchFields
    .map((field) => {
      const column = props.columns.find((col) => col.prop === field);
      return column?.label || field;
    })
    .filter(Boolean);

  if (fieldLabels.length === 0) {
    return '请输入搜索关键词';
  }

  if (fieldLabels.length === 1) {
    return `请输入${fieldLabels[0]}`;
  }

  return `请输入${fieldLabels.join('|')}`;
});

// 根据搜索关键词过滤表格数据
const filteredTableData = computed(() => {
  if (!searchKeyword.value || props.searchFields.length === 0) {
    return tableData.value;
  }

  const keyword = searchKeyword.value.toLowerCase();
  return tableData.value.filter((row) => {
    return props.searchFields.some((field) => {
      const value = row[field];
      if (value === null || value === undefined) {
        return false;
      }
      return String(value).toLowerCase().includes(keyword);
    });
  });
});

watch(
  () => props.modelValue,
  (newVal) => {
    if (newVal !== tableData.value) {
      tableData.value = [...newVal];
    }
  },
  { deep: true }
);

watch(
  tableData,
  (newVal) => {
    emit('update:modelValue', newVal);
  },
  { deep: true }
);

const handleAdd = (index: number) => {
  const newRow = { ...props.defaultRow };
  tableData.value.splice(index + 1, 0, newRow);
  nextTick(() => {
    emit('add', newRow, index + 1);
  });
};

const handleDelete = (index: number) => {
  if (tableData.value.length === 1) {
    Object.keys(tableData.value[0]).forEach((key) => {
      tableData.value[0][key] = '';
    });
    Object.assign(tableData.value[0], { ...props.defaultRow });
    emit('delete', tableData.value[0], index, true);
  } else {
    const deletedRow = tableData.value.splice(index, 1)[0];
    emit('delete', deletedRow, index, false);
  }
};

const handleSelectionChange = ({ records }: { records: Record<string, any>[] }) => {
  selectedRows.value = records;
  emit('selection-change', records);
};

// 删除所有选中的行
const handleDeleteSelected = () => {
  if (selectedRows.value.length === 0) {
    return;
  }

  // 获取选中行的索引
  const selectedIndexes = selectedRows.value.map((row) => tableData.value.indexOf(row));
  // 从后往前删除，避免索引变化问题
  selectedIndexes.sort((a, b) => b - a);

  // 如果选中了所有行且只剩一行，清空数据而不是删除
  if (tableData.value.length === selectedRows.value.length && tableData.value.length === 1) {
    Object.keys(tableData.value[0]).forEach((key) => {
      tableData.value[0][key] = '';
    });
    Object.assign(tableData.value[0], { ...props.defaultRow });
    emit('delete', tableData.value[0], 0, true);
  } else {
    // 删除选中的行
    selectedIndexes.forEach((index) => {
      if (index !== -1 && tableData.value.length > 1) {
        const deletedRow = tableData.value.splice(index, 1)[0];
        emit('delete', deletedRow, index, false);
      }
    });
  }

  // 清空选中状态
  if (tableRef.value) {
    tableRef.value.clearCheckboxRow();
  }
  selectedRows.value = [];
};

// 工具栏新增按钮
const handleToolbarAdd = () => {
  const newRow = { ...props.defaultRow };
  tableData.value.push(newRow);
  nextTick(() => {
    emit('toolbar-add');
    emit('add', newRow, tableData.value.length - 1);
  });
};

// 工具栏删除按钮
const handleToolbarDelete = () => {
  if (selectedRows.value.length === 0) {
    return;
  }
  emit('toolbar-delete', selectedRows.value);
  handleDeleteSelected();
};

// 搜索处理
const handleSearch = () => {
  // 搜索逻辑已在 computed 中处理
};

const validate = (callback: any) => {
  if (formRef.value) {
    return formRef.value.validate(callback);
  }
};

const validateField = (props: any, callback: any) => {
  if (formRef.value) {
    return formRef.value.validateField(props, callback);
  }
};

const resetFields = () => {
  if (formRef.value) {
    formRef.value.resetFields();
  }
};

const clearValidate = (props: any) => {
  if (formRef.value) {
    formRef.value.clearValidate(props);
  }
};

defineExpose({
  formRef,
  tableRef,
  validate,
  validateField,
  resetFields,
  clearValidate,
  tableData,
});
</script>

<style scoped lang="scss">
.editable-table-form {
  display: flex;
  flex-direction: column;
  height: 100%;

  .editable-table-toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;
    padding: 0 4px;

    .toolbar-left {
      display: flex;
      gap: 8px;
    }
  }

  .editable-table-inner {
    flex: 1;
    min-height: 0;
  }

  .editable-table-footer {
    margin-top: 16px;
    padding: 0 4px;
  }

  .action-btn {
    padding: 2px 4px;
  }
}
</style>