<template>
	<!--  搜索区域-->
	<template v-if="props.headerOperationPlace === 'behind'">
		<TableSearch ref="tableSearch" :search="props.search" :use-keywords="props.useKeywords" @click-search="handleClickSearch" :pre-span="props.preSpan">
			<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>
	<br />
	<div ref="aBaseGrid" style="overflow-y: auto" class="base-grid">
		<slot v-if="list.length > 0" name="data" :list="list"></slot>
		<a-empty v-else />
		<!--		<template v-for="item in list" :key="item[typeof props.rowKey === 'string' ? props.rowKey : props.rowKey()]">-->
		<!--			<slot name="data" :list="list"></slot>-->
		<!--		</template>-->
	</div>
	<br />
	<div v-if="props.isDisabled" style="text-align: right">
		<a-pagination
			v-if="!props.hiddenPage"
			:current="pagination.page"
			:page-size="pagination.rows"
			:show-total="total => `共 ${total} 条数据`"
			:total="pagination.total"
			:page-size-options="props.pageSizeOptions"
			show-less-items
			show-quick-jumper
			show-size-changer
			style="text-align: right"
			@change="handleChangePage"
			@showSizeChange="handleChangePage"
		/>
	</div>
</template>

<script lang="ts" setup>
import { defineAsyncComponent, onMounted, onUnmounted, reactive, ref, withDefaults } from 'vue'
import { SearchProps } from './table-helper'
import { PageModel, ResultModel } from '../../http/result-model'
import { QueryObjectType, QueryType } from '../../http/request-model'
import selection from './selection'
import { getQuery } from './components/search-method'

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

export interface TablePropsState {
	// 表格的名称
	title?: string
	// 操作内容的位置
	headerOperationPlace?: 'right' | 'behind'
	// 每行的key
	rowKey?: string | (() => string)
	// 第一次进入的page
	page?: number
	// 每页行数
	rows?: number
	// 是否禁用分页组件
	isDisabled?: boolean
	// 分页总大小（当父组件没有传递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
	useKeywords?: boolean
	preSpan?: number
	search?: SearchProps[]

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

const props = withDefaults(defineProps<TablePropsState>(), {
	title: '数据列表',
	rowKey: 'id',
	page: 1,
	rows: 10,
	width: 'auto',
	hiddenPage: false,
	calculateHeight: true,
	headerOperationPlace: 'behind',
	search: () => [],
	columns: () => [],
	tableTotal: 0,
	showSizer: true,
	showTotal: true,
	showElevator: true,
	isDisabled: true,
	preSpan: 0,
	pageSizeOptions: () => ['10', '20', '50', '100'],
	pageParams: () => ({
		page: 'pageNum',
		rows: 'pageSize'
	})
})

const useSelection = selection({})

// 获取表格组件
const aBaseGrid = ref<HTMLInputElement | null>(null)

// 加载动画
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()
	}
})
</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;
		}
	}
}

.base-grid {
	flex: 1 1 auto;
}
</style>
