<template>
  <div class="basic-table">
    <!-- 搜索栏 -->
    <basic-form
      v-if="searchColumns.length"
      ref="searchFormRef"
      :model-value="queryParams"
      :schemas="searchColumns"
      :rules="searchRules"
      :label-width="searchLabelWidth"
      :size="size"
      inline
      v-show="showSearch"
    >
      <template v-for="name in searchSlotNames" :key="name" #[toFormSlot(name)]>
        <slot :name="name" />
      </template>
      <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
      <el-button icon="Refresh" @click="resetQuery">重置</el-button>
      <slot name="search-extra" />
    </basic-form>

    <!-- 工具栏 -->
    <el-row v-if="showToolbar" :gutter="10" class="mb8">
      <slot name="toolbar" :selection="selectionList" :ids="selectionIds" />
      <el-col :span="1.5" v-if="!$slots.toolbar">
        <el-button type="primary" plain icon="Plus" @click="$emit('add')" v-if="showAdd">新增</el-button>
      </el-col>
      <right-toolbar
        v-model:showSearch="showSearchInternal"
        :columns="toolbarColumns"
        :search="searchColumns.length > 0"
        @query-table="getList"
      />
    </el-row>

    <!-- 表格 -->
    <el-table
      ref="tableRef"
      v-loading="loading"
      :data="tableData"
      :row-key="rowKey"
      :border="border"
      :stripe="stripe"
      :size="size"
      :height="height"
      :max-height="maxHeight"
      :default-sort="defaultSort"
      @selection-change="handleSelectionChange"
      @row-click="(row, col, e) => $emit('row-click', row, col, e)"
      @sort-change="(c) => $emit('sort-change', c)"
    >
      <!-- 多选列 -->
      <el-table-column v-if="selection" type="selection" width="55" align="center" />

      <!-- 序号列 -->
      <el-table-column v-if="showIndex" type="index" label="序号" width="55" align="center" />

      <!-- 动态列 -->
      <el-table-column
        v-for="col in visibleColumns"
        :key="col.key"
        :prop="col.prop"
        :label="col.label"
        :width="col.width"
        :min-width="col.minWidth"
        :align="col.align || 'center'"
        :fixed="col.fixed"
        :sortable="col.sortable"
        :show-overflow-tooltip="col.showOverflowTooltip !== false"
      >
        <template #header="scope">
          <slot :name="`header-${col.prop}`" v-bind="scope">{{ col.label }}</slot>
        </template>
        <template #default="scope">
          <slot :name="`col-${col.prop}`" v-bind="scope" :row="scope.row">
            <!-- 字典列 -->
            <dict-tag
              v-if="col.dict"
              :options="getDictOptions(col.dict)"
              :value="scope.row[col.prop]"
            />
            <!-- 时间格式化 -->
            <span v-else-if="col.parseTime">{{ parseTime(scope.row[col.prop], col.parseTime === true ? undefined : col.parseTime) }}</span>
            <!-- 自定义格式化 -->
            <span v-else-if="col.formatter">{{ col.formatter(scope.row, col, scope.row[col.prop], scope.$index) }}</span>
            <!-- 默认显示 -->
            <span v-else>{{ scope.row[col.prop] }}</span>
          </slot>
        </template>
      </el-table-column>

      <!-- 空数据 -->
      <template #empty>
        <slot name="empty"><el-empty /></slot>
      </template>
    </el-table>

    <!-- 分页 -->
    <pagination
      v-show="total > 0"
      :total="total"
      v-model:page="queryParams.pageNum"
      v-model:limit="queryParams.pageSize"
      :page-sizes="pageSizes"
      @pagination="getList"
    />
  </div>
</template>

<script setup>
/**
 * 公共表格组件 BasicTable
 * 集成搜索栏 + 工具栏 + 表格 + 分页，基于 columns/searchColumns 配置驱动，内置复用 BasicForm、RightToolbar、Pagination、DictTag。
 *
 * 用法示例：
 * <basic-table
 *   ref="tableRef"
 *   :columns="columns"
 *   :search-columns="searchColumns"
 *   :query="listPost"
 *   @add="handleAdd"
 * >
 *   <template #toolbar="{ selection, ids }">
 *     <el-button type="primary" icon="Plus" @click="handleAdd">新增</el-button>
 *   </template>
 *   <template #col-status="{ row }">
 *     <dict-tag :options="sys_normal_disable" :value="row.status" />
 *   </template>
 * </basic-table>
 *
 * column 配置：
 * {
 *   label: '岗位名称',           // 列标题
 *   prop: 'postName',            // 字段名
 *   width: 120,                  // 列宽
 *   minWidth: 120,
 *   align: 'center',             // 对齐（默认 center）
 *   fixed: 'left'|'right',
 *   sortable: true,
 *   showOverflowTooltip: true,    // 默认 true
 *   dict: 'sys_normal_disable',   // 用字典标签渲染
 *   parseTime: true | 'YYYY-MM-DD', // 时间格式化（true 用默认格式）
 *   formatter: (row,col,val,index)=> ..., // 自定义格式化
 *   show: true,                    // 是否显示（参与显隐列）
 *   showInToolbar: true,           // 是否在显隐列工具栏中显示（默认 true）
 *   visible: true                  // 初始是否可见（显隐列控制）
 * }
 *
 * searchColumns 配置：同 BasicForm 的 schemas。
 */

defineOptions({ name: 'BasicTable' })

const props = defineProps({
  // 列配置数组
  columns: {
    type: Array,
    default: () => []
  },
  // 搜索表单配置（同 BasicForm schemas）
  searchColumns: {
    type: Array,
    default: () => []
  },
  // 搜索表单校验规则
  searchRules: {
    type: Object,
    default: () => ({})
  },
  // 搜索表单标签宽度
  searchLabelWidth: {
    type: [String, Number],
    default: 'auto'
  },
  // 列表加载函数：(params) => Promise<{rows, total}> | {rows, total}
  query: {
    type: Function,
    required: true
  },
  // 额外固定查询参数（每次请求合并传入，不参与搜索表单重置）
  extraParams: {
    type: Object,
    default: () => ({})
  },
  // 初始查询参数（搜索字段的默认值）
  defaultParams: {
    type: Object,
    default: () => ({})
  },
  // 是否显示多选列
  selection: {
    type: Boolean,
    default: true
  },
  // 是否显示序号列
  showIndex: {
    type: Boolean,
    default: false
  },
  // 是否显示工具栏
  showToolbar: {
    type: Boolean,
    default: true
  },
  // 是否显示默认新增按钮（无 toolbar 插槽时生效）
  showAdd: {
    type: Boolean,
    default: false
  },
  // 是否显示搜索栏（可双向控制）
  showSearch: {
    type: Boolean,
    default: true
  },
  // 行 key
  rowKey: {
    type: [String, Function],
    default: undefined
  },
  // 边框
  border: {
    type: Boolean,
    default: false
  },
  // 斑马纹
  stripe: {
    type: Boolean,
    default: false
  },
  // 表格/表单尺寸（large/default/small）
  size: {
    type: String,
    default: undefined
  },
  // 表格高度
  height: { type: [String, Number], default: undefined },
  maxHeight: { type: [String, Number], default: undefined },
  // 默认排序（透传 el-table default-sort，如 { prop: 'createTime', order: 'descending' }）
  defaultSort: {
    type: Object,
    default: undefined
  },
  // 每页条数可选项
  pageSizes: {
    type: Array,
    default: () => [10, 20, 30, 50]
  },
  // 默认每页条数
  pageSize: {
    type: Number,
    default: 10
  },
  // 是否在挂载后自动加载
  autoLoad: {
    type: Boolean,
    default: true
  }
})

const emit = defineEmits(['add', 'update:showSearch', 'row-click', 'sort-change', 'selection-change'])

const { proxy } = getCurrentInstance()
const tableRef = ref()
const searchFormRef = ref()

const loading = ref(false)
const tableData = ref([])
const total = ref(0)
const selectionList = ref([])
const showSearchInternal = ref(props.showSearch)

// 查询参数：搜索字段 + 分页
const queryParams = reactive({
  pageNum: 1,
  pageSize: props.pageSize,
  ...props.defaultParams
})

watch(() => props.showSearch, (v) => (showSearchInternal.value = v))
watch(showSearchInternal, (v) => emit('update:showSearch', v))

// ====== 列显隐状态 ======
// 内部维护列状态（带 key/visible），供 RightToolbar 控制显隐
const tableColumns = ref([])
function initColumns() {
  tableColumns.value = props.columns.map((col, index) => ({
    ...col,
    key: col.key || col.prop || index,
    visible: col.visible !== false && col.show !== false
  }))
}
initColumns()
watch(
  () => props.columns,
  () => initColumns(),
  { deep: false }
)

// 实际渲染的列（visible !== false）
const visibleColumns = computed(() => tableColumns.value.filter((c) => c.visible !== false))

// 参与显隐工具栏的列（有 label 且未禁用工具栏显示）
const toolbarColumns = computed(() =>
  tableColumns.value.filter((c) => c.label && c.showInToolbar !== false)
)

// ====== 字典加载（用于表格列 dict 渲染） ======
const dictMap = reactive({})
const dictTypes = computed(() => {
  const set = new Set()
  props.columns.forEach((c) => c.dict && set.add(c.dict))
  props.searchColumns.forEach((c) => c.dict && set.add(c.dict))
  return [...set]
})
watch(
  dictTypes,
  (types) => {
    if (!types.length) return
    const dictRefs = proxy.useDict(...types)
    types.forEach((t) => {
      const d = dictRefs[t]
      dictMap[t] = isRef(d) ? d : ref(d)
    })
  },
  { immediate: true }
)
function getDictOptions(type) {
  const d = dictMap[type]
  return isRef(d) ? d.value : d || []
}

// ====== 搜索栏插槽透传：search-xxx -> form-xxx ======
const slots = useSlots()
const searchSlotNames = computed(() =>
  Object.keys(slots).filter((n) => n.startsWith('search-') && n !== 'search-extra')
)
function toFormSlot(name) {
  return 'form-' + name.slice('search-'.length)
}

// ====== 数据加载 ======
async function getList() {
  loading.value = true
  try {
    const params = { ...queryParams, ...props.extraParams }
    const res = await props.query(params)
    tableData.value = res?.rows || []
    total.value = res?.total || 0
  } catch (e) {
    console.error('BasicTable 加载失败', e)
  } finally {
    loading.value = false
  }
}

// 搜索
function handleQuery() {
  queryParams.pageNum = 1
  getList()
}

// 重置搜索
function resetQuery() {
  searchFormRef.value?.resetFields()
  Object.keys(props.defaultParams || {}).forEach((k) => {
    queryParams[k] = props.defaultParams[k]
  })
  queryParams.pageNum = 1
  getList()
}

// 选中变化
function handleSelectionChange(val) {
  selectionList.value = val
  emit('selection-change', val)
}
const selectionIds = computed(() =>
  selectionList.value.map((r) => (props.rowKey ? r[props.rowKey] : r.id)).filter((v) => v !== undefined)
)

// ====== 暴露方法 ======
function refresh() {
  getList()
}
function reload() {
  queryParams.pageNum = 1
  getList()
}
function getSelection() {
  return selectionList.value
}
function getSelectionIds() {
  return selectionIds.value
}
function clearSelection() {
  tableRef.value?.clearSelection()
}
function toggleRowSelection(row, selected) {
  tableRef.value?.toggleRowSelection(row, selected)
}
function getTableRef() {
  return tableRef.value
}
function getSearchFormRef() {
  return searchFormRef.value
}
function getQueryParams() {
  return { ...queryParams, ...props.extraParams }
}
function setQueryParams(p) {
  Object.assign(queryParams, p)
}

defineExpose({
  refresh,
  reload,
  getList,
  handleQuery,
  resetQuery,
  getSelection,
  getSelectionIds,
  clearSelection,
  toggleRowSelection,
  getTableRef,
  getSearchFormRef,
  getQueryParams,
  setQueryParams
})

if (props.autoLoad) {
  onMounted(getList)
}
</script>

<style scoped>
.basic-table {
  width: 100%;
}
</style>
