useTableCheck.ts 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import { ref, computed, watch, nextTick, unref, onMounted, onBeforeUnmount } from 'vue'
  2. import { isDefine, toggleClass } from '@/utils/common'
  3. import type { Ref, ShallowRef, UnwrapRef } from 'vue'
  4. import type { InstanceTable } from 'global-type'
  5. import type { MultipleResult } from '@/api/api'
  6. import { throttle } from 'lodash-es'
  7. import useMainStore from '@/store/main'
  8. import bus from '@/utils/bus'
  9. import { ElMessage } from 'element-plus'
  10. type ArrayObjectType = Array<Record<string, any>>
  11. type MultipleResultType<T = Record<string, any>> = MultipleResult<T>
  12. type InputDataType = MultipleResultType | ArrayObjectType
  13. type TableDataType<T> = Ref<T> | ShallowRef<T>
  14. type ArrayData<T extends InputDataType> = T extends MultipleResultType<infer D> ? D : ExtractArrayValue<T>
  15. type RowType<T extends TableDataType<InputDataType>> = ArrayData<UnwrapRef<T>> & {
  16. index: number
  17. }
  18. const mainStore = useMainStore()
  19. function isMultipleData(data: any): data is MultipleResultType {
  20. return isDefine(data?.result) && isDefine(data?.totalCount)
  21. }
  22. const useTableCheck = <T extends TableDataType<InputDataType>>(data: T, auto = true) => {
  23. const tableRef = ref<InstanceTable>()
  24. const elTableRef = computed(() => {
  25. return tableRef?.value?.tableRef
  26. })
  27. const totalCount = ref<any>(null)
  28. const pageSize = ref<any>(null)
  29. const pageNumber = ref<any>(null)
  30. const initPaginationParams = () => {
  31. const _data: any = unref(data)
  32. if (isMultipleData(_data)) {
  33. totalCount.value = _data.totalCount
  34. pageSize.value = _data.pageSize
  35. pageNumber.value = _data.pageNumber
  36. }
  37. }
  38. initPaginationParams()
  39. watch(data, () => {
  40. initPaginationParams()
  41. })
  42. const tableData = computed(() => {
  43. const d = unref(data)
  44. // let result: RowType<T>[] = []
  45. let result: any[] = []
  46. if (d) {
  47. if (isMultipleData(d)) {
  48. result = d?.result?.map((d, index) => ({ ...d, index: d.index ?? index }))
  49. } else {
  50. result = d?.map((d, index) => ({ ...d, index: d.index ?? index }))
  51. }
  52. }
  53. return result
  54. })
  55. // const current = ref<RowType<T>>()
  56. const current = ref<any>()
  57. // const currentView = ref<RowType<T>>()
  58. const currentView = ref<any>()
  59. const visibleHistory = ref<boolean>(false)
  60. watch(
  61. tableData,
  62. () => {
  63. current.value = void 0
  64. currentView.value = void 0
  65. if (tableData?.value?.length && auto) {
  66. nextTick(() => {
  67. elTableRef?.value?.setCurrentRow(tableData.value[0])
  68. })
  69. }
  70. },
  71. { immediate: true }
  72. )
  73. /** 表格选中 */
  74. // const onCurrentChange = (row: RowType<T>) => {
  75. const onCurrentChange = (row: any) => {
  76. current.value = row
  77. }
  78. /** 表格行双击 */
  79. // const onDbClick = (row: RowType<T>) => {
  80. const onDbClick = (row: any) => {
  81. currentView.value = row
  82. visibleHistory.value = true
  83. }
  84. /** 下一份 */
  85. const next = () => {
  86. // elTableRef?.value?.setCurrentRow(tableData.value[((current.value?.index || 0) + 1) % tableData.value.length])
  87. const rightTableViewDom = document.querySelector('.table-view')
  88. if (rightTableViewDom) {
  89. toggleClass(rightTableViewDom, 'collapse')
  90. }
  91. }
  92. const nextRow = throttle(() => {
  93. console.log('current.value?.index:', current.value?.index)
  94. console.log('tableData.value.length:', tableData.value.length)
  95. if (current.value?.index == tableData.value.length - 1) {
  96. //说明高亮正处于最后一行了,需要提示用户是否需要翻到下一页。
  97. if (totalCount.value !== null && pageSize.value !== null) {
  98. // 说明页面只使用了useTableCheck,而未使用useTable。
  99. //注意:这里只处理只使用了useTableCheck而未使用useTable的情况。另外一种情况在useTable里处理。避免重复
  100. //只使用了useTableCheck,而未使用useTable的情况,基本上是pageSize传了99999这种情况,所以一页就是全部的数据,最后一行就是到底了
  101. if (pageNumber.value * pageSize.value + 1 > totalCount.value) {
  102. ElMessage.warning('当前页已是最后一页')
  103. } else {
  104. //该情况应该不可能出现,因为只使用了useTableCheck而未使用useTable的情况,是只有一页的,即pageSize传的999999之类
  105. // mainStore.setRowNextBottomDialogStatus(true)
  106. }
  107. } else {
  108. //在useTable里才能拿到分页相关信息,所以要对useTable进行通信,告诉它到了最后一行了,是否需要弹框诱导到下一页
  109. bus.emit('atBottomRowFromUseTableCheck')
  110. }
  111. return
  112. }
  113. const index = (current.value?.index || 0) + 1
  114. elTableRef?.value?.setCurrentRow(tableData.value[index % tableData.value.length])
  115. const tBodyDomWrap: any = elTableRef?.value?.$refs.bodyWrapper
  116. if (tBodyDomWrap) {
  117. if (index % tableData.value.length == 0) {
  118. elTableRef?.value?.scrollTo({ left: 0, top: 0, behavior: 'smooth' })
  119. } else {
  120. const wrap = tBodyDomWrap.getElementsByClassName('el-scrollbar__wrap')[0]
  121. const oHeight = wrap.offsetHeight
  122. const sTop = wrap.scrollTop
  123. const sHeight = wrap.scrollHeight
  124. const targetRowAsHeight = 36 * ((current.value?.index || 0) + 1)
  125. if (sHeight > oHeight && targetRowAsHeight - sTop > oHeight) {
  126. const t = sHeight - targetRowAsHeight
  127. elTableRef?.value?.scrollTo({ left: 0, top: sTop + 36, behavior: 'smooth' })
  128. }
  129. }
  130. }
  131. // elTableRef?.value?.scrollTo(0, (current.value?.index || 0) * 36)
  132. }, 300)
  133. const prevRow = throttle(() => {
  134. console.log('current.value?.index:', current.value?.index)
  135. if (current.value?.index > 0) {
  136. const index = current.value?.index
  137. elTableRef?.value?.setCurrentRow(tableData.value[index - 1])
  138. const tBodyDomWrap: any = elTableRef?.value?.$refs.bodyWrapper
  139. if (tBodyDomWrap) {
  140. if (index % tableData.value.length == 0) {
  141. elTableRef?.value?.scrollTo({ left: 0, top: 0, behavior: 'smooth' })
  142. } else {
  143. const wrap = tBodyDomWrap.getElementsByClassName('el-scrollbar__wrap')[0]
  144. const oHeight = wrap.offsetHeight
  145. const sTop = wrap.scrollTop
  146. const sHeight = wrap.scrollHeight
  147. const targetRowAsHeight = 36 * (current.value?.index || 0)
  148. if (targetRowAsHeight - 36 < sTop) {
  149. elTableRef?.value?.scrollTo({ left: 0, top: targetRowAsHeight - 36, behavior: 'smooth' })
  150. }
  151. }
  152. }
  153. }
  154. }, 300)
  155. const arrowDownToNextRow = (e: any) => {
  156. // if (e.target.tagName === 'INPUT' || (e.target.className || '').includes('contenteditable-ele')) {
  157. // return false
  158. // }
  159. if ((e.target.className || '').includes('contenteditable-ele')) {
  160. return false
  161. }
  162. // e.preventDefault()
  163. if (e.key === 'ArrowDown') {
  164. e.preventDefault()
  165. nextRow()
  166. } else if (e.key === 'ArrowUp') {
  167. e.preventDefault()
  168. prevRow()
  169. }
  170. }
  171. onMounted(() => {
  172. document.addEventListener('keydown', arrowDownToNextRow)
  173. })
  174. onBeforeUnmount(() => {
  175. document.removeEventListener('keydown', arrowDownToNextRow)
  176. })
  177. return {
  178. tableRef,
  179. elTableRef,
  180. tableData,
  181. current,
  182. currentView,
  183. visibleHistory,
  184. onCurrentChange,
  185. onDbClick,
  186. next,
  187. nextRow,
  188. }
  189. }
  190. export default useTableCheck