<template>
	<!--  搜索区域-->
	<template v-if="props.headerOperationPlace === 'behind'">
		<TableSearch ref="tableSearch" :pre-span="props.preSpan" :search="props.search" :use-keywords="props.useKeywords" @click-search="handleClickSearch">
			<slot class="dc-table-operation" name="operation"></slot>
		</TableSearch>
		<template v-if="props.search?.length === 0">
			<a-row class="dc-table-operation">
				<slot name="operation"></slot>
			</a-row>
		</template>
	</template>
	<a-row v-if="props.headerOperationPlace === 'right'">
		<a-col span="16">
			<TableSearch ref="tableSearch" :search="props.search" :use-keywords="props.useKeywords" @click-search="handleClickSearch" />
		</a-col>
		<a-col class="dc-table-operation">
			<!--  操作区域-->
			<slot class="dc-test" name="operation"></slot>
		</a-col>
	</a-row>
	<!--	<div v-if="!!props.title" v-once>-->
	<!--		<a-divider orientation="left">{{ props.title }}</a-divider>-->
	<!--	</div>-->
	<!--  表格数据-->
	<!--	<a-alert v-if="props.batchOperation?.length > 0 && useSelection.option.keys.length > 0" type="success">-->
	<!--		<template #message>-->
	<!--			已选择 <strong>{{ useSelection.option.keys.length }}</strong> 项-->
	<!--		</template>-->
	<!--	</a-alert>-->
	<br />
	<div ref="aBaseTable" :style="props.calculateHeight ? { overflow: 'hidden' } : {}" class="ant-table-container" style="flex: 1 1 auto">
		<a-table
			v-if="!props.defaultExpandAllRows || !loading"
			:bordered="props.bordered"
			:columns="realColumns"
			:data-source="list"
			:default-expand-all-rows="props.defaultExpandAllRows"
			:loading="loading"
			:pagination="false"
			:row-key="props.rowKey"
			:row-selection="props.batchOperation?.length > 0 ? useSelection.rowSelection : null"
			:scroll="props.calculateHeight ? scroll : null"
			:size="props.size"
		>
			<template #bodyCell="{ column, record }">
				<template v-if="column.key === 'operation' && props.operation && props.operation.length > 0">
					<TableLineOperation
						:max-operation="props.maxOperation"
						:operation="props.operation"
						:operation-width="props.operationWidth"
						:record="record"
					/>
				</template>
			</template>
			<template v-if="hasExpandedRowRender" #expandedRowRender="{ record }">
				<slot :record="record" name="expandedRowRender"></slot>
			</template>
		</a-table>
	</div>
	<br />
	<div v-if="props.isDisabled" style="display: flex">
		<TableBatchOperation
			v-if="props.batchOperation?.length && useSelection.option.keys.length > 0"
			:operation="props.batchOperation"
			:record-key-list="useSelection.option.keys"
			:record-list="useSelection.option.rows"
		/>
		<div class="spacer"></div>
		<a-pagination
			v-if="!props.hiddenPage"
			:current="pagination.page"
			:page-size="pagination.rows"
			:page-size-options="props.pageSizeOptions"
			:show-total="total => `共 ${total} 条数据`"
			:total="pagination.total"
			show-less-items
			show-quick-jumper
			show-size-changer
			style="text-align: right"
			@change="handleChangePage"
			@showSizeChange="handleChangePage"
		/>
	</div>
</template>

<script lang="ts" setup>
import { computed, defineAsyncComponent, onMounted, reactive, ref, watch, withDefaults, useSlots, onUnmounted } from 'vue'
import { getOperationColumns, TableLineOperationInterface } from './components/table-line-operation-check'
import { BatchOperationProps, ColumnsProps, OperationProps, SearchProps } from './table-helper'
import { PageModel, ResultModel } from '../../http/result-model'
import { QueryObjectType, QueryType } from '../../http/request-model'
import { resolveColumns } from './components/columns-handle'
import selection from './selection'
import { getQuery } from './components/search-method'

const TableLineOperation = defineAsyncComponent(() => import('./components/TableLineOperation.vue'))
const TableBatchOperation = defineAsyncComponent(() => import('./components/TableBatchOperation.vue'))
const TableSearch = defineAsyncComponent(() => import('./components/TableSearch.vue'))

const slots = useSlots()
// 判断是否有展开插槽
const hasExpandedRowRender = computed<boolean>(() => !!slots.expandedRowRender)

interface TablePropsState {
	// 表格的名称
	title?: string
	// 列描述数据对象
	columns?: Array<ColumnsProps<unknown>>
	// 操作内容的位置
	headerOperationPlace?: 'right' | 'behind'
	// 每行的key
	rowKey?: string | (() => string)
	// 第一次进入的page
	page?: number
	// 每页行数
	rows?: number
	// 表格尺寸
	size?: 'default' | 'middle' | 'small'
	// 是否显示间隔斑马纹
	stripe?: boolean
	// 是否显示纵向边框
	bordered?: boolean
	// 表格宽度
	width?: string | number
	// 表格高度
	height?: string | number
	// 表格最大高度（固定表格表头时使用）
	maxHeight?: string | number
	// 导出时文件名
	exportFilename?: string
	// 导出时其他配置
	exportParams?: object
	// 是否禁用分页组件
	isDisabled?: boolean
	// 是否显示表头
	showHeader?: boolean
	// 表格数据（当父组件没有传递action时，表格的数据将交由该参数控制，不传它，可能表格初始数据为空）
	tableData?: Array<unknown>
	// 分页总大小（当父组件没有传递action时，表格的数据将交由该参数控制，不传它，可能表格初始数据为空）
	tableTotal?: number
	// 是否显示分页
	showSizer?: boolean
	// 是否显示总数
	showTotal?: boolean
	// 分页数据
	pageSizeOptions?: string[]
	// 是否显示快梯
	showElevator?: boolean
	// 是否自行处理分页数据处理，为true，当前组件将向父组件暴露处理分页的2个函数
	selfWithPage?: boolean
	// 父组件应该将搜索条件通过这个参数传递过来（不传可能造成分页与搜索条件无法同时使用）
	initParams?: { [key: string]: QueryType }
	// 分页必传参数配置
	pageParams?: Partial<{
		page: string
		rows: string
	}>
	// 是否隐藏分页信息
	hiddenPage?: boolean
	// 表格是否加载（当父组件没有传递action时，表格的加载状态将交由该参数控制）
	isLoading?: boolean
	// 是否要计算高度
	calculateHeight?: boolean
	defaultExpandAllRows?: boolean
	scroll?: { [key: string]: unknown }
	operation?: OperationProps<unknown>[]
	maxOperation?: number
	operationFixed?: 'left' | 'right' | ''
	operationWidth?: number
	useKeywords?: boolean
	preSpan?: number
	search?: SearchProps[]
	selectionType?: 'checkbox' | 'radio'
	// 批量操作
	batchOperation?: BatchOperationProps<unknown>[]

	// 请求api路径
	action?(query?: QueryType): Promise<ResultModel<PageModel<unknown>>>
}

const props = withDefaults(defineProps<TablePropsState>(), {
	title: '数据列表',
	rowKey: 'id',
	page: 1,
	rows: 10,
	width: 'auto',
	size: 'middle',
	hiddenPage: false,
	calculateHeight: true,
	headerOperationPlace: 'behind',
	search: () => [],
	columns: () => [],
	exportFilename: '表格数据',
	tableTotal: 0,
	showSizer: true,
	showTotal: true,
	showElevator: true,
	isDisabled: true,
	// 是否需要空格
	preSpan: 0,
	selectionType: 'checkbox',
	pageSizeOptions: () => ['10', '20', '50', '100'],
	scroll: () => ({ y: 500 }),
	pageParams: () => ({
		page: 'pageNum',
		rows: 'pageSize'
	})
})

const useSelection = selection({ type: props.selectionType })

// 表格高度
const scroll = reactive({
	scrollToFirstRowOnChange: true,
	y: 500
})
// 获取表格组件
const aBaseTable = ref<HTMLInputElement | null>(null)
// 监听组件尺寸变化
const resizeObserver = new ResizeObserver(() => {
	if (props.calculateHeight) {
		// 获取表头
		let headerHeight = 0

		// 获取表格表头高度
		const tableHeader = aBaseTable.value?.querySelector('.ant-table-header')
		if (tableHeader) {
			// 多减一点点，否则不太对
			headerHeight = tableHeader.clientHeight
		}

		let tableHeight = aBaseTable.value?.clientHeight || 500

		if (aBaseTable.value?.parentElement) {
			// 获取表格的父组件，检查是否是flex布局，并且direction是column
			let computedStyle = getComputedStyle(aBaseTable.value.parentElement)
			if (computedStyle.display !== 'flex' && computedStyle.flexDirection !== 'column') {
				if (import.meta.env.DEV) console.warn('表格父组件不是flex布局或direction不是column')
			}
		}

		// 获取表格总高度 - 表头高度
		scroll.y = tableHeight - headerHeight
	}
})
onMounted(() => {
	aBaseTable.value && resizeObserver.observe(aBaseTable.value)
})
// 记得销毁
onUnmounted(() => {
	aBaseTable.value && resizeObserver.unobserve(aBaseTable.value)
})

// 最终展示到页面的列项
const realColumns = computed<Array<ColumnsProps<unknown>>>(
	(): Array<ColumnsProps<unknown>> =>
		<ColumnsProps<unknown>[]>[...resolveColumns(props.columns), getOperationColumns(<TableLineOperationInterface<unknown>>props)].filter(item => item)
)

// 加载动画
const loading = ref<boolean>(true)
// 数据列表
const list = ref<unknown>([])
// 分页数据
const pagination = reactive({
	page: 1,
	rows: 10,
	total: 0,
	isLast: false
})

// 请求的参数
let params = ref<QueryType>({})

/**
 * 查询数据
 */
const pageRequest = () => {
	if (props.action) {
		// 打开加载动画
		loading.value = true
		// 执行数据请求
		props
			.action({
				...(params.value as QueryObjectType),
				// 分页数据
				[props.pageParams.page || 'pageNum']: pagination.page,
				[props.pageParams.rows || 'pageSize']: pagination.rows,
				// 默认的数据
				...(props.initParams || {})
			} as QueryType)
			.then((response: ResultModel<PageModel<unknown>>) => {
				pagination.isLast = response.data.isLastPage
				pagination.page = response.data.pageNum
				// pagination.rows = response.data.pageSize
				pagination.total = response.data.total
				list.value = response?.data?.list ?? response?.data
			})
			.finally(() => {
				// 关闭加载动画
				loading.value = false
			})
	}
}

/**
 * 点击搜索之后的查询
 */
function handleClickSearch(e: QueryType): void {
	params.value = e
	handleChangePage()
}

/**
 * 改变页数和分页
 * @param page 当前页
 * @param rows 每页行数
 */
function handleChangePage(page = 1, rows: number = pagination.rows): void {
	pagination.page = page
	pagination.rows = rows
	pageRequest()
}

// 获取当前的搜索框内容
const tableSearch = ref<InstanceType<typeof TableSearch>>(null)

// 暴露方法参数给父组件
defineExpose({
	/**
	 * 调取查询的事件
	 */
	pageRequest: () => {
		pageRequest()
	},
	/**
	 * 渲染的源数据
	 */
	dataList: (): unknown => list.value,
	/**
	 * 搜索条件列表
	 */
	queryList: (): QueryType => ({
		// 搜索条件
		...tableSearch.value.getQueryParams(),
		// 默认的数据
		...(props.initParams || {})
	}),
	/**
	 * 替换数据
	 * @param array
	 */
	setDataList: (array: unknown[]) => {
		list.value = array
	},
	getParams: () => params.value,
	...useSelection.exposeMethod
})

onMounted(() => {
	pagination.page = props.page
	pagination.rows = props.rows
	if (props.action) {
		// 获取默认的数据信息
		params.value = getQuery(props.search || [])
		// 分页请求
		pageRequest()
	} else {
		list.value = props.tableData
		pagination.total = props.tableTotal
		loading.value = false
	}
})

// 设置tableData变化时的信息
const resultData = computed<unknown[]>(() => props.tableData || [])
watch(resultData, () => {
	list.value = props.tableData
})
</script>

<style scoped>
::v-deep(.ant-spin-blur) {
	opacity: 1;
}
</style>

<style lang="scss">
.dc-table-operation {
	display: flex;
	align-items: center;
	user-select: none;

	& > * {
		margin-left: 10px;

		&:first-child {
			margin-left: 0;
		}
	}
}

// 去掉滚动条
.ant-table-container {
	.ant-table-body {
		overflow-y: auto !important;
	}
}
</style>
