SimplePagerDataLoader.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import { watch, ref, computed, type Ref } from "vue"
  2. import type { ILoaderCommon, LoaderLoadType } from "./LoaderCommon";
  3. import { formatError } from "~/components/error/ErrorReporterIs";
  4. export interface ISimplePageListLoader<T, P> extends ILoaderCommon<P> {
  5. list: Ref<T[]>;
  6. page: Ref<number>;
  7. next: () => Promise<void>;
  8. prev: () => Promise<void>;
  9. total: Ref<number>;
  10. totalPages: Ref<number>;
  11. }
  12. /**
  13. * 简单分页数据封装。
  14. *
  15. * 该封装了分页数据的加载、分页、上一页、下一页等功能。当页码发生变化时,会自动调用加载函数。
  16. * 简单分页同时只能显示一页数据,重新加载会覆盖之前的数据。
  17. *
  18. * 使用示例:
  19. * ```ts
  20. * const { data, page, total, loading } = useSimplePagerDataLoader(10, async (page, pageSize) => {
  21. * const res = await fetch(`/api/data?page=${page}&pageSize=${pageSize}`);
  22. * const data = await res.json();
  23. * return {
  24. * data,
  25. * page: res.page,
  26. * total: res.total,
  27. * };
  28. * });
  29. * ```
  30. *
  31. * @param pageSize 一页的数量
  32. * @param loader 加载函数
  33. * @returns
  34. */
  35. export function useSimplePagerDataLoader<T, P = any>(
  36. pageSize: number|Ref<number>,
  37. loader: (page: number, pageSize: number, params?: P) => Promise<{
  38. data: T[],
  39. total: number,
  40. }>) : ISimplePageListLoader<T, P>
  41. {
  42. const page = ref(0);
  43. const list = ref<T[]>([]) as Ref<T[]>;
  44. const total = ref(0);
  45. const totalPages = computed(() => Math.ceil(total.value / getPageSize()));
  46. const loadStatus = ref<LoaderLoadType>('loading');
  47. const loadError = ref('');
  48. function getPageSize() {
  49. return typeof pageSize == 'object'? pageSize.value : pageSize;
  50. }
  51. watch(page, async () => {
  52. await loadData(lastParams, false);
  53. });
  54. let lastParams: P | undefined;
  55. let loading = false;
  56. async function loadData(params?: P, refresh: boolean = false) {
  57. if (loading)
  58. return;
  59. if (params)
  60. lastParams = params;
  61. if (refresh) {
  62. page.value = 1;
  63. }
  64. list.value = [];
  65. loadStatus.value = 'loading';
  66. loading = true;
  67. try {
  68. const res = (await loader(page.value, getPageSize(), lastParams));
  69. list.value = list.value.concat(res.data);
  70. total.value = res.total;
  71. loadStatus.value = res.data.length > 0 ? 'finished' : 'nomore';
  72. loadError.value = '';
  73. loading = false;
  74. } catch(e) {
  75. loadError.value = '' + e;
  76. loadStatus.value = 'error';
  77. loading = false;
  78. }
  79. }
  80. /**
  81. * 下一页
  82. */
  83. async function next() {
  84. if (page.value > total.value)
  85. return;
  86. page.value++;
  87. await loadData(lastParams, false);
  88. }
  89. /**
  90. * 上一页
  91. */
  92. async function prev() {
  93. if (page.value <= 1)
  94. return;
  95. page.value--;
  96. await loadData(lastParams, false);
  97. }
  98. return {
  99. loadData,
  100. next,
  101. prev,
  102. /**
  103. * 数据
  104. */
  105. list,
  106. /**
  107. * 当前页码
  108. */
  109. page,
  110. /**
  111. * 总数据条数
  112. */
  113. total,
  114. /**
  115. * 总页数
  116. */
  117. totalPages,
  118. loadError,
  119. loadStatus,
  120. }
  121. }
  122. export async function useSSrSimplePagerDataLoader<T, P = any>(
  123. name: string,
  124. startPage: number,
  125. pageSize: number|Ref<number>,
  126. loader: (page: number, pageSize: number, params?: P) => Promise<{
  127. data: T[],
  128. total: number,
  129. }>,
  130. params : P|undefined = undefined,
  131. ) : Promise<ISimplePageListLoader<T, P>>
  132. {
  133. const route = useRoute();
  134. let lastParams: P | undefined = params;
  135. const page = ref(startPage);
  136. const {
  137. data,
  138. error
  139. } = (await useAsyncData(route.fullPath + '/' + name, () => loader(page.value, getPageSize(), lastParams)))
  140. const list = ref<T[]>([]) as Ref<T[]>;
  141. const total = ref(0);
  142. const totalPages = computed(() => Math.ceil(total.value / getPageSize()));
  143. const loadStatus = ref<LoaderLoadType>('finished');
  144. const loadError = ref('');
  145. if (error.value) {
  146. loadError.value = '' + formatError (error.value);
  147. loadStatus.value = 'error';
  148. } else if (data.value) {
  149. list.value = data.value.data as any;
  150. total.value = data.value.total as any;
  151. loadError.value = '';
  152. loadStatus.value = 'finished';
  153. }
  154. function getPageSize() {
  155. return typeof pageSize == 'object'? pageSize.value : pageSize;
  156. }
  157. watch(page, async () => {
  158. await loadData(lastParams, false);
  159. });
  160. let loading = false;
  161. async function loadData(params?: P, refresh: boolean = false) {
  162. if (loading)
  163. return;
  164. if (params)
  165. lastParams = params;
  166. if (refresh) {
  167. page.value = 1;
  168. }
  169. list.value = [];
  170. loadStatus.value = 'loading';
  171. loading = true;
  172. try {
  173. const res = (await loader(page.value, getPageSize(), lastParams));
  174. list.value = list.value.concat(res.data);
  175. total.value = res.total;
  176. loadStatus.value = list.value.length > 0 ? 'finished' : 'nomore';
  177. loadError.value = '';
  178. loading = false;
  179. } catch(e) {
  180. loadError.value = '' + formatError(e);
  181. loadStatus.value = 'error';
  182. loading = false;
  183. }
  184. }
  185. /**
  186. * 下一页
  187. */
  188. async function next() {
  189. if (page.value > total.value)
  190. return;
  191. page.value++;
  192. await loadData(lastParams, false);
  193. }
  194. /**
  195. * 上一页
  196. */
  197. async function prev() {
  198. if (page.value <= 1)
  199. return;
  200. page.value--;
  201. await loadData(lastParams, false);
  202. }
  203. return {
  204. loadData,
  205. next,
  206. prev,
  207. list: list as any as Ref<T[]>,
  208. page,
  209. total,
  210. totalPages,
  211. loadError,
  212. loadStatus,
  213. }
  214. }