<script setup lang="ts">
import { VbUtil } from "@@/vb-dom"
import apis from "@a"
import symbolKeys from "@@@/table/symbol"
import { getAssetPath } from "@@/utils"
import Toolbar from "@@@/table/partials/toolbar/TableToolbar.vue"
import Content from "@@@/table/partials/TableContent.vue"
import Footer from "@@@/table/partials/footer/TableFooter.vue"
import type { Sort, Header, Scroll, ToolBtn } from "@@@/table/models"
import type { VbFormItem, VbFormRowItem } from "@@@/form/models"
import type { AxiosRequestConfig } from "axios"
import type { WritableComputedRef } from "vue"

const formSlotSuffix = "tool-form_"

const props = withDefaults(
	defineProps<{
		columns: Header[]
		columnsFun?: () => Header[]
		tableTitle?: string
		emptyTableText?: string
		keyField?: string
		initSearch?: boolean // 页面加载时自动查询
		autoSearch?: boolean // 参数变动时自动查询(深监听)
		data?: any
		selectedRows?: any[]
		/* remote */
		remoteFun?: (q: any) => Promise<any>
		url?: string
		method?: string
		configs?: AxiosRequestConfig
		queryParams?: any
		loading?: boolean
		loadingText?: string
		sortField?: string // 排序字段
		sortOrder?: "asc" | "desc"
		/* modal form */
		modal?: any
		formData?: any
		exportUrl?: string
		exportName?: string
		getEntityFun?: (v: any) => Promise<any>
		deleteEntityFun?: (v: any) => Promise<any>
		resetFormFun?: () => void
		/* toolbar */
		showToolbar?: boolean // 是否显示toolbar
		/* searchbar */
		showSearchBar?: boolean // 是否显示Searchbar
		searchFormRowItems?: VbFormRowItem[]
		searchFormItems?: VbFormItem[]
		searchFormSpan?: number
		customSearchFun?: (query: any) => void
		resetSearchFormFun?: (query: any) => void
		/* left toolbar */
		handleBtns?: ToolBtn[]
		handlePerm?: string
		handleFuns?: object
		handleDisabledFuns?: object
		useCustomBtns?: boolean // 不从远程获取，直接使用自定义的Btns
		customBtns?: ToolBtn[]
		btnIconPrefix?: string
		/* right toolbar */
		showRightToolbar?: boolean // 是否显示右边的toolbar
		showRightSearchBtn?: boolean // 初始是否显示搜索栏
		showRightColumnBtn?: boolean // 是否显示右边toolbar的选择列按钮
		rightToolbarBtnGutter?: number // 右边toolbar按钮间距
		/* checkbox */
		checkMultiple?: boolean // 是否多选
		checkPageMultiple?: boolean // 是否跨页多选
		hasCheckbox?: boolean // 是否有选择框 (checkMultiple 和 checkPageMultiple 为true 时不起作用)
		/* pagination */
		pagination?: boolean
		noPage?: boolean // 查询不带分页参数
		total?: number
		currentPage?: number
		maxPageBtnCount?: number
		pageSize?: number
		pageSizeArray?: number[]
		pageSizeChange?: boolean
		/* fixed */
		fixedHeader?: boolean // 固定列头
		fixedNumber?: number // 左边固定列数
		fixedRightNumber?: number // 右边固定列数
		scroll?: Scroll
		/* rowspan */
		rowSpanSuffix?: string // rowspan 的字段后缀 后台应该组成 `${字段}${后缀}`
		/* tree */
		isTree?: boolean
		expandDepth?: number
		intervalLeft?: number
		parentField?: string
		iconField?: string
		childrenField?: string
		/* tree lazy */
		isLazy?: boolean
		isLazySearch?: boolean
		rootId?: string
		leafField?: string
		/* class & style */
		tableBoxClass?: string
		tableBoxStyle?: any
		tableBoxHeight?: number | string
		tableBoxWidth?: number | string
		tableClass?: string
		headerClass?: string
		bodyClass?: string
		thTrClass?: string
		tdTrClass?: string
		rowClick?: (row: any) => void
		rowDbClick?: (row: any) => void
	}>(),
	{
		tableTitle: "",
		emptyTableText: "未查询到数据",
		loadingText: "正在加载中,请稍后...",
		initSearch: true,
		autoSearch: false,
		selectedRows: () => [],
		method: "get",
		sortOrder: "asc",
		showToolbar: true,
		showSearchBar: true,
		searchFormRowItems: () => [],
		searchFormItems: () => [],
		searchFormSpan: 4,
		showRightToolbar: true,
		showRightColumnBtn: true,
		showRightSearchBtn: true,
		rightToolbarBtnGutter: 10,
		pagination: true,
		noPage: false,
		total: 0,
		currentPage: 1,
		pageSizeArray: () => {
			return [15, 25, 50]
		},
		pageSizeChange: true,
		maxPageBtnCount: 5,
		hasCheckbox: false,
		checkMultiple: false,
		checkPageMultiple: false,
		fixedHeader: false,
		fixedNumber: 0,
		fixedRightNumber: 0,
		rowSpanSuffix: "_rowSpan",
		isTree: false,
		parentField: "parent_id",
		childrenField: "children",
		iconField: "name",
		leafField: "isLeaf",
		expandDepth: 0,
		intervalLeft: 10,
		btnIconPrefix: "me-1 bi bi-",
		tableBoxClass: "w-100 p-5",
		tableClass: "table-bordered table-rounded",
		headerClass: "",
		bodyClass: "fw-semibold text-gray-600",
		thTrClass: "text-center text-gray-800 fw-bold fs-7",
		tdTrClass: "text-center fs-7 "
	}
)
const emits = defineEmits<{
	(e: "update:columns", v: Header[]): void
	(e: "update:selectedRows", v: any[]): void
	(e: "update:currentPage", v: number): void
	(e: "update:pageSize", v: number): void
	(e: "update:loading", v: boolean): void
	(e: "update:queryParams", v: any): void
	(e: "page-change", v: number): void
	(e: "update:formData", v: any): void
	(e: "sort", v: Sort[]): void
	(e: "row-click", row: any): void
	(e: "row-db-click", row: any): void
	(e: "checkbox-change", isChecked: boolean, row: any): void
	(e: "select", row: any): void
	(e: "unSelect", row: any): void
	(e: "checkbox-all", isChecked: boolean, rows: any[]): void
	(e: "select-all", rows: any[]): void
	(e: "unSelect-all", rows: any[]): void
}>()
const tableBoxRef = ref()
const tableContentRef = ref()
const id = ref("")

const { data, searchFormRowItems, searchFormItems } = toRefs(props)
const leftFixedRef = ref()
const tableResponsiveRef = ref()
const rightFixedRef = ref()
const emptyQueryParams = JSON.stringify(props.queryParams ? props.queryParams : {})

let treeData: any = []
let treeAllData: any = []
const remoteTotal = ref<number>(0)
const remoteData = ref<any[]>([])
const checkAll = ref<boolean>(false)
const toolbarHandleBtns = ref<ToolBtn[]>([])
const sortParams = ref<Sort[]>([
	{
		label: props.sortField ?? "",
		order: props.sortOrder == "asc" ? "asc" : "desc"
	}
])

const _columns = ref<Header[]>([])
const columns: WritableComputedRef<Header[]> = computed({
	get(): Header[] {
		if (_columns.value && _columns.value.length > 0) {
			if (props.columnsFun) {
				const cols = props.columnsFun() ?? []
				const newCols: Header[] = []
				cols.forEach((v: Header) => {
					const col = _columns.value.find((vv: Header) => vv.field == v.field)
					if (col) {
						v.visible = col.visible
					}
					newCols.push(v)
				})
				_columns.value = newCols
			}
		} else {
			_columns.value = props.columnsFun ? props.columnsFun() : props.columns ?? []
		}
		return _columns.value
	},
	set(value: Header[]): void {
		_columns.value = value
		emits("update:columns", value)
	}
})
const _selectedRows = ref<any[]>()
const selectedRows: WritableComputedRef<any[]> = computed({
	get(): any[] {
		return _selectedRows.value ?? props.selectedRows ?? []
	},
	set(value: any[]): void {
		_selectedRows.value = value
		emits("update:selectedRows", value)
	}
})
const _currentPage = ref<number>()
const currentPage: WritableComputedRef<number> = computed({
	get(): number {
		return _currentPage.value ?? props.currentPage
	},
	set(value: number): void {
		if (_currentPage.value != value) {
			_currentPage.value = value
			emits("update:currentPage", value)
			emits("page-change", value)
		}
	}
})
const _pageSize = ref<number>()
const pageSize: WritableComputedRef<number> = computed({
	get(): number {
		return _pageSize.value ?? props.pageSize ?? props.pageSizeArray[0]
	},
	set(value: number): void {
		_pageSize.value = value
		emits("update:pageSize", value)
	}
})
const _loading = ref<boolean>()
const loading: WritableComputedRef<boolean> = computed({
	get(): boolean {
		return _loading.value ?? props.loading
	},
	set(value: boolean): void {
		_loading.value = value
		emits("update:loading", value)
	}
})
const _innerQueryParams = ref<any>()
const innerQueryParams: WritableComputedRef<any> = computed({
	get(): boolean {
		return _innerQueryParams.value ?? props.queryParams
	},
	set(value: any): void {
		_innerQueryParams.value = value
	}
})

const rowColumns = computed(() => {
	const rowCols: Header[] = []
	function calcRowColumns(list: Header[], isVisible: boolean) {
		list.forEach((v) => {
			const visible = isVisible && (v.visible === undefined || v.visible)
			if (v.children && v.children.length > 0) {
				calcRowColumns(v.children, visible)
			} else {
				rowCols.push(Object.assign({}, v, { visible }))
			}
		})
	}
	calcRowColumns(columns.value, true)
	return rowCols
})
const keyField = ref(props.keyField ? props.keyField : rowColumns.value[0].field)

const displayData = computed(() => {
	let tableData: any = []
	if (!!props.remoteFun || !!props.url) {
		tableData = remoteData.value || []
	} else if (data?.value) {
		tableData = data.value
	}
	if (tableData.length <= pageSize.value) {
		return tableData
	} else {
		const sliceFrom = (currentPage.value - 1) * pageSize.value
		return tableData.slice(sliceFrom, sliceFrom + pageSize.value)
	}
})
const isMultipleCheck = computed(() => {
	return props.checkMultiple || props.checkPageMultiple
})
const dataTotalCount = computed(() => {
	return !!props.remoteFun || !!props.url ? remoteTotal.value : props.total
})
const selectedIds = computed(() => {
	return selectedRows.value.map((v) => v[keyField.value])
})
const selectedRowCount = computed(() => {
	return selectedRows.value.length
})
const tableBoxClass = computed(() => {
	let classStr = props.tableBoxClass
	if (props.isTree) {
		classStr += " vb-tree-table"
	}

	return classStr
})
const _tableBoxStyle = ref(calcTableBoxStyle())
const fixedColumn = computed(() => props.fixedNumber > 0 || props.fixedRightNumber > 0)
const tableStyle = computed(() => {
	let style = ""
	let x = props.scroll?.x
	const y = props.scroll?.y
	if (fixedColumn.value) {
		style += "overflow:auto;"
		x = x ?? 1920
	}
	if (x) {
		style += `width:${Number(x) ? x + "px" : x};`
	}
	if (y) {
		style += `height:${Number(y) ? y + "px" : y};`
	}
	return style
})
const tableRef = computed(() => {
	return tableContentRef.value.tableRef
})
const defaultHandleFuns = {
	handleCreate: () => {
		props.resetFormFun && props.resetFormFun()
		if (props.modal) {
			props.modal.show()
			props.modal.changePrefixTitle("添加")
		}
	},
	handleUpdate: (e?: any, row?: any) => {
		props.resetFormFun && props.resetFormFun()
		row = row || getSelected()
		if (!row) {
			return
		}
		if (props.getEntityFun) {
			props.getEntityFun(row[keyField.value]).then((res) => {
				emits("update:formData", res.data)
				if (props.modal) {
					props.modal.show()
					props.modal.changePrefixTitle("修改")
				}
			})
		} else {
			const _row = Object.assign({}, row)
			emits("update:formData", _row)
			if (props.modal) {
				props.modal.show()
				props.modal.changePrefixTitle("修改")
			}
		}
	},
	handleDelete: (e?: any, rows?: any) => {
		rows = rows || getSelecteds()
		if (!rows) {
			return
		}
		if (!props.deleteEntityFun) {
			message.alertError("删除接口方法未配置，请联系管理员")
			return
		}
		const ids = rows.map((v: any) => v[keyField.value])
		message
			.confirm('是否确认删除编号为"' + ids.join("，") + '"的数据项？')
			.then(() => {
				props.deleteEntityFun &&
					props.deleteEntityFun(ids).then(() => {
						customSearch()
					})
			})
			.catch(() => {
				//
			})
	},
	handleExport: () => {
		console.log("TE")
		if (props.exportUrl) {
			download(
				props.exportUrl,
				`${props.exportName ? props.exportName + "_" : ""}${new Date().getTime()}.xlsx`,
				{ method: "POST", params: { ...innerQueryParams.value } }
			)
		} else {
			message.alertError("导出接口方法未配置，请联系管理员")
		}
	}
}
const resetData = () => {
	currentPage.value = 1
	selectedRows.value = []
}

const remote = (id?: string) => {
	const params = props.noPage
		? innerQueryParams.value
		: Object.assign(
				{ pageNum: currentPage.value, pageSize: pageSize.value },
				innerQueryParams.value
		  )
	if (sortParams.value.length) {
		params.orderByColumn = ""
		params.isAsc = ""
		sortParams.value.forEach((v: any) => {
			if (v.order && v.label) {
				params.orderByColumn += (params.orderByColumn ? "," : "") + v.label
				params.isAsc += (params.isAsc ? "," : "") + v.order
			}
		})
	}
	let curData: any = {}
	if (props.isLazy) {
		curData = treeAllData.find((v: any) => {
			return v[keyField.value] == id
		})

		if (!id && !curData) {
			throw new Error("懒加载模式,未获取到 parentId ,请检查")
		}

		if (curData?.children && curData?.children.length) {
			if (props.isLazySearch) {
				curData.children = []
			} else {
				return Promise.resolve(0)
			}
		}

		if (!props.keyField) {
			throw new Error("懒加载模式,请配置 keyField")
		}
		params[props.keyField] = id
	}
	loading.value = true

	return new Promise((resolve, reject) => {
		if (props.remoteFun) {
			props
				.remoteFun(params)
				.then((res: any) => {
					processData(res.rows || res.data, res.total)
				})
				.catch((err) => {
					loading.value = false
					reject(err)
				})
		} else if (props.url) {
			const qParam = props.method.toLocaleLowerCase() == "get" ? { params } : { data: params }

			const configs = Object.assign(
				{ url: props.url, method: props.method, successAlert: false },
				props.configs,
				qParam
			)
			Rs.request(configs)
				.then((res: any) => {
					processData(res.rows || res.data, res.total)
				})
				.catch(() => {
					loading.value = false
				})
		}
		function processData(data: any, total: number) {
			remoteTotal.value = total || 0
			loading.value = false
			if (props.isLazy) {
				if (props.isLazySearch) {
					Object.keys(innerQueryParams.value).forEach((v) => {
						innerQueryParams.value[v] = undefined
					})
					if (!data.length) {
						const item = {}
						item[props.iconField ?? ""] = "没有查询到字节点"
						item[props.leafField ?? ""] = true
						item[props.parentField ?? ""] = id
						data.push(item)
					}
					resolve(1)
				}

				if (curData) {
					curData.children = []
					data.forEach((v: any) => {
						const index = treeAllData.findIndex((vv: any) => {
							return vv[keyField.value] == v[keyField.value]
						})
						if (index < 0) {
							treeAllData.push(v)
							curData.children.push(treeAllData[treeAllData.length - 1])
						} else {
							curData.children.push(treeAllData[index])
						}
					})
				} else {
					treeData.push(...data)
					treeAllData.push(...treeData)
				}
				remoteData.value = JSON.parse(JSON.stringify(treeData))
			} else {
				remoteData.value = data
			}
		}
	})
}

const isContentSlots = (name: string | number): boolean => {
	const str = name.toString()
	return (
		rowColumns.value.find((v) => {
			return v.field == str || v.field + "_header" == str
		}) != null
	)
}
const loadHandleBtns = () => {
	toolbarHandleBtns.value = []
	if (!props.useCustomBtns && props.handlePerm) {
		const _handleFuns = Object.assign({}, defaultHandleFuns, props.handleFuns ?? {})
		apis.system.menuApi.menuChildrenByPerms(props.handlePerm).then((res) => {
			if (res.data && res.data.length > 0) {
				res.data.forEach((v: any) => {
					if (v.btnScript && v.btnScript != "hide") {
						const scripts = v.btnScript.split("@")
						const _btn = props.handleBtns?.find((v) => {
							return v.key == scripts[0]
						})
						const btn: ToolBtn = {
							key: scripts[0],
							show: _btn?.show == undefined ? true : _btn?.show,
							name: _btn?.name ?? v.menuName,
							permission: _btn?.permission ?? v.perms,
							clickFun: _btn?.clickFun ?? _handleFuns[scripts[0]],
							icon: _btn?.icon ?? `${props.btnIconPrefix}${v.icon}`,
							iconType: _btn?.iconType ?? "class",
							btnClass: _btn?.btnClass ?? v.btnClass,
							disabledFun: _btn?.disabledFun
						}
						if (scripts.length > 1) {
							btn.disabledFun = (r: number) => {
								const temp = Number(scripts[1])
								if (temp == 0) {
									return r == 0
								}
								return r != Number(scripts[1])
							}
						}
						if (props.handleDisabledFuns && props.handleDisabledFuns[scripts[0]]) {
							btn.disabledFun = props.handleDisabledFuns[scripts[0]]
						}
						toolbarHandleBtns.value.push(btn)
					}
				})
			}
			toolbarHandleBtns.value.push(...(props.customBtns ?? []))
		})
	} else {
		toolbarHandleBtns.value = props.customBtns ?? []
	}
}
const customSearch = () => {
	if (props.customSearchFun) {
		props.customSearchFun(innerQueryParams.value)
	} else {
		search()
	}
}
function calcTableBoxStyle() {
	const style = props.tableBoxStyle ?? {}
	if (props.tableBoxHeight) {
		style.height = Number(props.tableBoxHeight) ? props.tableBoxHeight + "px" : props.tableBoxHeight
	} else {
		nextTick(() => {
			const tableBoxAutoHeight =
				document.documentElement.clientHeight -
				(document.querySelector(".app-header")?.clientHeight ?? 0) -
				(document.querySelector(".app-footer")?.clientHeight ?? 0) -
				5
			style.height = tableBoxAutoHeight + "px"
		})
	}
	if (props.tableBoxWidth) {
		style.width = Number(props.tableBoxWidth) ? props.tableBoxWidth + "px" : props.tableBoxWidth
	} else {
		style.width = "100%"
	}
	return style
}
function query(query?: any) {
	if (query) {
		innerQueryParams.value = Object.assign({}, query)
	}
	search()
}
function search(isReset = true) {
	if (isReset) {
		resetData()
	}
	if (!!props.remoteFun || !!props.url) {
		remoteData.value = []
		treeData = []
		treeAllData = []
		remote(props.isLazy ? props.rootId : undefined)
	}
}
function getQueryParams() {
	return innerQueryParams.value
}
function getSelected() {
	return getSelecteds()[0]
}
function getSelecteds() {
	return selectedRows.value
}
function getSelectedIds() {
	return selectedIds.value
}
function getData() {
	return remoteData.value
}
function setSelecteds(rows: any[] | any, isSelected: boolean) {
	if (!Array.isArray(rows)) {
		rows = [rows]
	}
	if (isSelected) {
		selectedRows.value = [...new Set([...selectedRows.value, ...rows])]
	} else {
		selectedRows.value = selectedRows.value.filter((item: any) => !rows.includes(item))
	}
}
function clearSelecteds() {
	selectedRows.value = []
}
provide(symbolKeys.tableBox, tableBoxRef)
provide(symbolKeys.searchFrom, {
	queryParams: innerQueryParams,
	searchFormRowItems,
	searchFormItems,
	searchFormSpan: props.searchFormSpan
})
provide(symbolKeys.toolBtns, toolbarHandleBtns)
provide(symbolKeys.selectedRowCount, selectedRowCount)
provide(symbolKeys.rightToolbar, {
	columns,
	showSearchBtn:
		props.showRightSearchBtn && (!!props.searchFormItems || !!props.searchFormRowItems),
	showColumnBtn: props.showRightColumnBtn,
	gutter: props.rightToolbarBtnGutter
})
provide(symbolKeys.content, {
	loading,
	tableClass: props.tableClass,
	tableStyle: tableStyle.value
})
provide(symbolKeys.checkAll, checkAll)
provide(symbolKeys.header, {
	columns,
	hasCheckbox: isMultipleCheck.value || props.hasCheckbox,
	isMultipleCheck: isMultipleCheck.value,
	sortField: props.sortField ?? "",
	sortOrder: props.sortOrder,
	headerClass: props.fixedHeader ? props.headerClass + " fixed" : props.headerClass,
	thTrClass: props.thTrClass
})
provide(symbolKeys.body, {
	isTree: props.isTree,
	childrenField: props.childrenField,
	bodyClass: props.bodyClass
})
provide(symbolKeys.bodyTr, {
	selectedIds,
	isTree: props.isTree,
	keyField: keyField.value,
	hasCheckbox: isMultipleCheck.value || props.hasCheckbox,
	isMultipleCheck: isMultipleCheck.value,
	expandDepth: props.expandDepth,
	intervalLeft: props.intervalLeft,
	iconField: props.iconField,
	parentField: props.parentField,
	childrenField: props.childrenField,
	leafField: props.leafField,
	isLazy: props.isLazy,
	lazySearch: props.isLazySearch,
	tdTrClass: props.tdTrClass
})
provide(symbolKeys.bodyTds, {
	columns: rowColumns,
	rowSpanSuffix: props.rowSpanSuffix,
	expandDepth: props.expandDepth,
	intervalLeft: props.intervalLeft,
	iconField: props.iconField,
	parentField: props.parentField,
	childrenField: props.childrenField,
	leafField: props.leafField,
	isLazy: props.isLazy
})
provide(symbolKeys.displayData, displayData)
provide(symbolKeys.pagination, {
	total: dataTotalCount,
	currentPage,
	pageSize,
	maxPageBtnCount: props.maxPageBtnCount
})
provide(symbolKeys.pagePerItems, {
	total: dataTotalCount,
	currentPage,
	pageSize,
	pageSizeArray: props.pageSizeArray,
	pageSizeChange: props.pageSizeChange
})
provide(symbolKeys.formSlotSuffix, formSlotSuffix)

const onPageChange = (page: number) => {
	currentPage.value = page
	search(false)
}
const onPageSizeChange = (count: number) => {
	pageSize.value = count
	search()
}
const onColumnsChange = (headers: Header[]) => {
	columns.value = headers
}
const onSort = (v: Sort[]) => {
	const sorts = toValue(v)
	sortParams.value = sorts
	emits("sort", sorts)
	search(false)
}
const onSelectAll = (isChecked: boolean) => {
	let sRows: any = []
	if (isChecked) {
		sRows = [...new Set([...selectedRows.value, ...displayData.value])]
		selectedRows.value = sRows
		emits("select-all", sRows)
		emits("checkbox-all", true, sRows)
	} else {
		if (props.checkPageMultiple) {
			sRows = selectedRows.value.filter(
				(v: any) => !displayData.value.find((vv: any) => v[keyField.value] == vv[keyField.value])
			)
		} else {
			sRows = []
		}
		selectedRows.value = sRows
		emits("unSelect-all", sRows)
		emits("checkbox-all", false, displayData.value)
	}
}
const onSelect = (v: { isChecked: boolean; row: any }) => {
	let sRows: any = []
	const row = toValue(v.row)
	if (v.isChecked) {
		sRows = isMultipleCheck.value ? [...new Set([...selectedRows.value, row])] : [row]
		selectedRows.value = sRows
		emits("select", row)
		emits("checkbox-change", true, row)
	} else {
		sRows = isMultipleCheck.value
			? selectedRows.value.filter((vv) => vv[keyField.value] != row[keyField.value])
			: []
		selectedRows.value = sRows
		emits("unSelect", row)
		emits("checkbox-change", false, row)
	}
}
const onQuery = () => {
	emits("update:queryParams", innerQueryParams.value)
}
const onRowClick = (v: any) => {
	const row = toValue(v)
	props.rowClick && props.rowClick(row)
	emits("row-click", row)
}
const onRowDbClick = (v: any) => {
	const row = toValue(v)
	props.rowDbClick && props.rowDbClick(row)
	emits("row-db-click", row)
}
const onReset = () => {
	innerQueryParams.value = JSON.parse(emptyQueryParams)
	props.resetSearchFormFun && props.resetSearchFormFun(innerQueryParams.value)
	emits("update:queryParams", innerQueryParams.value)
}
const onTreeToggle = (v: any) => {
	const row = toValue(v)
	const id = "tr_" + row[keyField.value]
	const tr = tableBoxRef.value?.querySelector(`#${id}`)
	const icon = tr?.querySelector(".icon")
	if (!tr || !icon) {
		return
	}
	if (props.isLazy) {
		// 已有children可展开的直接展开,不在调用懒加载
		if (tr.className.search("hasChildren") >= 0) {
			if (tr.className.search("tr-expand") >= 0 || !props.isLazySearch) {
				toggle(tr, icon, id)
				return
			}
		}
		remote(id).then((res) => {
			if (res == 1 && props.isLazySearch) {
				nextTick(() => {
					showChildren(id)
				})
			}
		})
		tr.className = tr.className.replace("tr-collapse", "tr-expand")
		icon.className = icon.className.replace("ki-add-folder", "ki-minus-folder")
	} else {
		toggle(tr, icon, id)
	}
	function toggle(_tr: HTMLElement, _icon: HTMLElement, id: string) {
		if (_tr.className.search("tr-expand") >= 0) {
			_tr.className = _tr.className.replace("tr-expand", "tr-collapse")
			_icon.className = _icon.className.replace("ki-minus-folder", "ki-add-folder")
			hideChildren(id)
		} else if (_tr.className.search("tr-collapse") >= 0) {
			_tr.className = _tr.className.replace("tr-collapse", "tr-expand")
			_icon.className = _icon.className.replace("ki-add-folder", "ki-minus-folder")
			showChildren(id)
		}
	}
	function hideChildren(parentId: string) {
		const children = document.querySelectorAll(`[data-parent="${parentId}"]`)

		if (children && children.length) {
			children.forEach((v) => {
				v.className = v.className.replace("show", "hide")
				v.className = v.className.replace("tr-expand", "tr-collapse")
				const iconEl = v.querySelector(".icon")
				if (iconEl) {
					iconEl.className = iconEl.className.replace("ki-minus-folder", "ki-add-folder")
				}
				hideChildren(v.id)
			})
		}
	}
	function showChildren(parentId: string) {
		const children = document.querySelectorAll(`[data-parent="${parentId}"]`)
		if (children && children.length) {
			children.forEach((v) => {
				v.className = v.className.replace("hide", "show")
			})
		}
	}
}
const onFixedScrollX = () => {
	leftFixedRef.value.className = leftFixedRef.value.className.replace("no-shadow", "")
	rightFixedRef.value.className = rightFixedRef.value.className.replace("no-shadow", "")
	if (tableResponsiveRef.value) {
		const left = tableResponsiveRef.value.scrollLeft
		if (left == 0) {
			leftFixedRef.value.className += " no-shadow"
		}
		if (left >= tableRef.value.clientWidth - tableResponsiveRef.value.clientWidth) {
			rightFixedRef.value.className += " no-shadow"
		}
	}
}
function BindInterEvent() {
	VbUtil.EventHandlerUtil.on(tableBoxRef.value, "vbtable.row.click", onRowClick)
	VbUtil.EventHandlerUtil.on(tableBoxRef.value, "vbtable.row.dbclick", onRowDbClick)
	VbUtil.EventHandlerUtil.on(tableBoxRef.value, "vbtable.query", onQuery)
	VbUtil.EventHandlerUtil.on(tableBoxRef.value, "vbtable.reset", onReset)
	VbUtil.EventHandlerUtil.on(tableBoxRef.value, "vbtable.sort", onSort)
	VbUtil.EventHandlerUtil.on(tableBoxRef.value, "vbtable.select-all", onSelectAll)
	VbUtil.EventHandlerUtil.on(tableBoxRef.value, "vbtable.select", onSelect)
	VbUtil.EventHandlerUtil.on(tableBoxRef.value, "vbtable.page-size-change", onPageSizeChange)
	VbUtil.EventHandlerUtil.on(tableBoxRef.value, "vbtable.page-change", onPageChange)
	VbUtil.EventHandlerUtil.on(tableBoxRef.value, "vbtable.columns-change", onColumnsChange)
	VbUtil.EventHandlerUtil.on(tableBoxRef.value, "vbtable.row.tree-toggle", onTreeToggle)
	if (fixedColumn.value && tableResponsiveRef.value) {
		tableResponsiveRef.value.addEventListener("scroll", onFixedScrollX, true)
	}
}

function initFixedColumns() {
	if (fixedColumn.value) {
		const tr = tableRef.value?.querySelector("tr")
		if (tr && tr.children) {
			let width = 0
			if (leftFixedRef.value) {
				let num = props.fixedNumber
				if (props.hasCheckbox || props.checkMultiple || props.checkPageMultiple) {
					num += 1
				}
				for (let i = 0; i < num; i++) {
					width += tr.children[i]?.clientWidth ?? 0
				}
				leftFixedRef.value.style.width = width + "px"
				leftFixedRef.value.firstElementChild.style.width = tableRef.value.clientWidth + "px"
			}
			if (rightFixedRef.value) {
				width = 0
				const trLength = tr.children.length
				for (let i = trLength - 1; i >= trLength - props.fixedRightNumber; i--) {
					width += tr.children[i]?.clientWidth ?? 0
				}
				rightFixedRef.value.style.width = width + "px"
				rightFixedRef.value.firstElementChild.style.width = tableRef.value.clientWidth + "px"
				rightFixedRef.value.firstElementChild.style.transform = `translateX(-${
					tableRef.value.clientWidth - width
				}px)`
				if (tableRef.value.clientWidth <= tableResponsiveRef.value.clientWidth) {
					rightFixedRef.value.className += " no-shadow"
				}
			}
		}
	}
}
function init() {
	id.value = VbUtil.getUniqueIdWithPrefix("vb-table")
	if (props.initSearch) {
		customSearch()
	}
	loadHandleBtns()
	nextTick(() => {
		initFixedColumns()
		BindInterEvent()
	})
	window.addEventListener("resize", () => {
		_tableBoxStyle.value = calcTableBoxStyle()
	})
}
onMounted(init)
onUnmounted(() => {
	tableResponsiveRef.value?.removeEventListener("scroll", onFixedScrollX, true)
})
watch(selectedRows, (val: any) => {
	if (val.length > 0 && val.length == displayData.value.length) {
		let flag = true
		displayData.value.forEach((item: any) => {
			if (
				selectedRows.value.find((row: any) => row[keyField.value] == item[keyField.value]) == null
			) {
				flag = false
				return
			}
		})
		checkAll.value = flag
	} else {
		checkAll.value = false
	}
})
watch(
	() => props.queryParams,
	(val: any) => {
		innerQueryParams.value = val
		customSearch()
	},
	{ deep: props.autoSearch }
)
defineExpose({
	tableRef: tableBoxRef,
	query,
	getSelected,
	getSelectedIds,
	getSelecteds,
	getData,
	getQueryParams,
	setSelecteds,
	clearSelecteds,
	defaultHandleFuns
})
</script>
<template>
	<div ref="tableBoxRef" class="vb-table" :id="id" :class="tableBoxClass" :style="_tableBoxStyle">
		<Toolbar
			v-if="showToolbar"
			:tableTitle="tableTitle"
			:showSearchBar="showSearchBar"
			:showRightToolbar="showRightToolbar">
			<template v-for="(_, name) in $slots" #[name]>
				<slot v-if="name.toString().search(formSlotSuffix) == 0" :name="name" />
			</template>
		</Toolbar>
		<div class="table-box">
			<div
				v-if="props.fixedNumber > 0"
				ref="leftFixedRef"
				class="fixed-columns fixed-columns-left no-shadow">
				<Content>
					<template v-for="(_, name) in $slots" #[name]="{ row }">
						<slot v-if="isContentSlots(name)" :name="name" :row="row" />
					</template>
				</Content>
			</div>
			<div ref="tableResponsiveRef" class="table-responsive">
				<Content ref="tableContentRef">
					<template v-for="(_, name) in $slots" #[name]="{ row }">
						<slot v-if="isContentSlots(name)" :name="name" :row="row" />
					</template>
				</Content>
				<template v-if="loading">
					<div class="h-100px d-flex justify-content-center flex-column align-items-center">
						<div class="spinner-border text-gray-700 mb-5"></div>
						<span class="text-gray-700">{{ loadingText }}</span>
					</div>
				</template>
				<div
					v-else-if="displayData.length == 0 && !loading"
					class="h-100px d-flex justify-content-center flex-column align-items-center">
					<img class="mb-2" :src="getAssetPath('media/table/empty.svg')" />
					<span class="text-gray-700">{{ emptyTableText }}</span>
				</div>
			</div>
			<div v-if="props.fixedRightNumber > 0" ref="rightFixedRef" class="fixed-columns-right">
				<Content>
					<template v-for="(_, name) in $slots" #[name]="{ row }">
						<slot v-if="isContentSlots(name)" :name="name" :row="row" />
					</template>
				</Content>
			</div>
		</div>

		<Footer :loading="loading" :pagination="pagination && !noPage" />
	</div>
</template>
