版博士V2.0程序
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

1225 linhas
32 KiB

  1. import { defineComponent, provide, unref, ref, computed, inject, reactive, watch, onUnmounted, watchEffect } from 'vue';
  2. const GLOBAL_OPTIONS = {};
  3. const GLOBAL_OPTIONS_PROVIDE_KEY = Symbol('GLOBAL_OPTIONS_PROVIDE_KEY');
  4. const setGlobalOptions = config => {
  5. Object.keys(config).forEach(key => {
  6. GLOBAL_OPTIONS[key] = config[key];
  7. });
  8. };
  9. const getGlobalOptions = () => {
  10. return GLOBAL_OPTIONS;
  11. };
  12. const RequestConfig = defineComponent({
  13. name: 'RequestConfig',
  14. props: {
  15. config: {
  16. type: Object,
  17. required: true
  18. }
  19. },
  20. setup(props, {
  21. slots
  22. }) {
  23. const {
  24. config
  25. } = props;
  26. provide(GLOBAL_OPTIONS_PROVIDE_KEY, config);
  27. return () => {
  28. var _slots$default;
  29. return (_slots$default = slots.default) === null || _slots$default === void 0 ? void 0 : _slots$default.call(slots);
  30. };
  31. }
  32. });
  33. const objectToString = Object.prototype.toString;
  34. const toTypeString = val => objectToString.call(val);
  35. const isString = val => toTypeString(val) === '[object String]';
  36. const isPlainObject = val => toTypeString(val) === '[object Object]';
  37. const isArray = val => Array.isArray(val);
  38. const isObject = val => val !== null && typeof val === 'object';
  39. const isPromise = fn => isObject(fn) && isFunction(fn.then) && isFunction(fn.catch);
  40. const isFunction = fn => fn instanceof Function;
  41. const isNil = val => val === null || val === undefined;
  42. const isServer = typeof window === 'undefined';
  43. const isDocumentVisibility = () => {
  44. var _window, _window$document;
  45. return !isServer && ((_window = window) === null || _window === void 0 ? void 0 : (_window$document = _window.document) === null || _window$document === void 0 ? void 0 : _window$document.visibilityState) === 'visible';
  46. };
  47. const isOnline = () => {
  48. var _ref, _window2, _window2$navigator;
  49. return (_ref = !isServer && ((_window2 = window) === null || _window2 === void 0 ? void 0 : (_window2$navigator = _window2.navigator) === null || _window2$navigator === void 0 ? void 0 : _window2$navigator.onLine)) !== null && _ref !== void 0 ? _ref : true;
  50. };
  51. const unRefObject = val => {
  52. const obj = {};
  53. Object.keys(val).forEach(key => {
  54. obj[key] = unref(val[key]);
  55. });
  56. return obj;
  57. };
  58. const resolvedPromise = Promise.resolve(null);
  59. const requestProxy = async (...args) => {
  60. const res = await fetch(...args);
  61. if (res.ok) {
  62. return res.json();
  63. }
  64. throw new Error(res.statusText);
  65. };
  66. const get = (source, path, defaultValue = undefined) => {
  67. // a[3].b -> a.3.b
  68. const paths = path.replace(/\[(\d+)\]/g, '.$1').split('.');
  69. let result = source;
  70. for (const p of paths) {
  71. result = Object(result)[p];
  72. if (result === undefined) {
  73. return defaultValue;
  74. }
  75. }
  76. return result;
  77. };
  78. function omit(object, keys) {
  79. const result = Object.assign({}, object);
  80. for (const key of keys) {
  81. delete result[key];
  82. }
  83. return result;
  84. }
  85. const warning = (message, throwError = false) => {
  86. const msg = `Warning: [vue-request] ${message}`;
  87. if (throwError) {
  88. return new Error(msg);
  89. } else {
  90. console.error(msg);
  91. }
  92. };
  93. const limitTrigger = (fn, timeInterval) => {
  94. let running = false;
  95. return (...args) => {
  96. if (running) return;
  97. running = true;
  98. fn(...args);
  99. setTimeout(() => {
  100. running = false;
  101. }, timeInterval);
  102. };
  103. };
  104. var _window;
  105. const FOCUS_LISTENER = new Set();
  106. const VISIBLE_LISTENER = new Set();
  107. const RECONNECT_LISTENER = new Set();
  108. const subscriber = (listenerType, event) => {
  109. let listeners;
  110. switch (listenerType) {
  111. case 'FOCUS_LISTENER':
  112. listeners = FOCUS_LISTENER;
  113. break;
  114. case 'RECONNECT_LISTENER':
  115. listeners = RECONNECT_LISTENER;
  116. break;
  117. case 'VISIBLE_LISTENER':
  118. listeners = VISIBLE_LISTENER;
  119. break;
  120. }
  121. if (listeners.has(event)) return;
  122. listeners.add(event);
  123. return () => {
  124. listeners.delete(event);
  125. };
  126. };
  127. const observer = listeners => {
  128. listeners.forEach(event => {
  129. event();
  130. });
  131. };
  132. /* istanbul ignore else */
  133. if (!isServer && (_window = window) !== null && _window !== void 0 && _window.addEventListener) {
  134. window.addEventListener('visibilitychange', () => {
  135. /* istanbul ignore else */
  136. if (isDocumentVisibility()) {
  137. observer(VISIBLE_LISTENER);
  138. }
  139. }, false);
  140. window.addEventListener('focus', () => observer(FOCUS_LISTENER), false);
  141. window.addEventListener('online', () => observer(RECONNECT_LISTENER), false);
  142. }
  143. /**
  144. * source by `lodash`
  145. * https://github.com/lodash/lodash.git
  146. */
  147. function debounce(func, wait, options) {
  148. let lastArgs, lastThis, maxWait, result, timerId, lastCallTime;
  149. let lastInvokeTime = 0;
  150. let leading = false;
  151. let maxing = false;
  152. let trailing = true; // Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
  153. const useRAF = !wait && wait !== 0 && typeof window.requestAnimationFrame === 'function';
  154. if (typeof func !== 'function') {
  155. throw new TypeError('Expected a function');
  156. }
  157. wait = +wait || 0;
  158. if (isObject(options)) {
  159. leading = !!options.leading;
  160. maxing = 'maxWait' in options;
  161. maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait;
  162. trailing = 'trailing' in options ? !!options.trailing : trailing;
  163. }
  164. function invokeFunc(time) {
  165. const args = lastArgs;
  166. const thisArg = lastThis;
  167. lastArgs = lastThis = undefined;
  168. lastInvokeTime = time;
  169. result = func.apply(thisArg, args);
  170. return result;
  171. }
  172. function startTimer(pendingFunc, wait) {
  173. if (useRAF) {
  174. window.cancelAnimationFrame(timerId);
  175. return window.requestAnimationFrame(pendingFunc);
  176. }
  177. return setTimeout(pendingFunc, wait);
  178. }
  179. function cancelTimer(id) {
  180. if (useRAF) {
  181. return window.cancelAnimationFrame(id);
  182. }
  183. clearTimeout(id);
  184. }
  185. function leadingEdge(time) {
  186. // Reset any `maxWait` timer.
  187. lastInvokeTime = time; // Start the timer for the trailing edge.
  188. timerId = startTimer(timerExpired, wait); // Invoke the leading edge.
  189. return leading ? invokeFunc(time) : result;
  190. }
  191. function remainingWait(time) {
  192. const timeSinceLastCall = time - lastCallTime;
  193. const timeSinceLastInvoke = time - lastInvokeTime;
  194. const timeWaiting = wait - timeSinceLastCall;
  195. return maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
  196. }
  197. function shouldInvoke(time) {
  198. const timeSinceLastCall = time - lastCallTime;
  199. const timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the
  200. // trailing edge, the system time has gone backwards and we're treating
  201. // it as the trailing edge, or we've hit the `maxWait` limit.
  202. return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
  203. }
  204. function timerExpired() {
  205. const time = Date.now();
  206. if (shouldInvoke(time)) {
  207. return trailingEdge(time);
  208. } // Restart the timer.
  209. timerId = startTimer(timerExpired, remainingWait(time));
  210. }
  211. function trailingEdge(time) {
  212. timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been
  213. // debounced at least once.
  214. if (trailing && lastArgs) {
  215. return invokeFunc(time);
  216. }
  217. lastArgs = lastThis = undefined;
  218. return result;
  219. }
  220. function cancel() {
  221. if (timerId !== undefined) {
  222. cancelTimer(timerId);
  223. }
  224. lastInvokeTime = 0;
  225. lastArgs = lastCallTime = lastThis = timerId = undefined;
  226. }
  227. function flush() {
  228. return timerId === undefined ? result : trailingEdge(Date.now());
  229. }
  230. function pending() {
  231. return timerId !== undefined;
  232. }
  233. function debounced(...args) {
  234. const time = Date.now();
  235. const isInvoking = shouldInvoke(time);
  236. lastArgs = args;
  237. lastThis = this;
  238. lastCallTime = time;
  239. if (isInvoking) {
  240. if (timerId === undefined) {
  241. return leadingEdge(lastCallTime);
  242. }
  243. if (maxing) {
  244. // Handle invocations in a tight loop.
  245. timerId = startTimer(timerExpired, wait);
  246. return invokeFunc(lastCallTime);
  247. }
  248. }
  249. if (timerId === undefined) {
  250. timerId = startTimer(timerExpired, wait);
  251. }
  252. return result;
  253. }
  254. debounced.cancel = cancel;
  255. debounced.flush = flush;
  256. debounced.pending = pending;
  257. return debounced;
  258. }
  259. function baseMerge(origin, target) {
  260. for (const key in target) {
  261. if (target[key] === undefined) {
  262. continue;
  263. }
  264. if (!isObject(target[key]) || // `target[key]` is not an object
  265. !isObject(origin[key]) || // `target[key]` is not an object
  266. !(key in origin) // `key` is not in the origin object
  267. ) {
  268. origin[key] = target[key];
  269. continue;
  270. }
  271. if (isPlainObject(target[key]) || isArray(target[key])) {
  272. baseMerge(origin[key], target[key]);
  273. }
  274. }
  275. }
  276. function merge(origin, ...others) {
  277. const result = Object.assign({}, origin);
  278. if (!others.length) return result;
  279. for (const item of others) {
  280. baseMerge(result, item);
  281. }
  282. return result;
  283. }
  284. /**
  285. * source by `lodash`
  286. * https://github.com/lodash/lodash.git
  287. */
  288. function throttle(func, wait, options) {
  289. let leading = true;
  290. let trailing = true;
  291. if (typeof func !== 'function') {
  292. throw new TypeError('Expected a function');
  293. }
  294. if (isObject(options)) {
  295. leading = 'leading' in options ? !!options.leading : leading;
  296. trailing = 'trailing' in options ? !!options.trailing : trailing;
  297. }
  298. return debounce(func, wait, {
  299. leading,
  300. trailing,
  301. maxWait: wait
  302. });
  303. }
  304. const setStateBind = (oldState, publicCb) => {
  305. return newState => {
  306. Object.keys(newState).forEach(key => {
  307. oldState[key].value = newState[key];
  308. });
  309. publicCb.forEach(fun => fun(oldState));
  310. };
  311. };
  312. const createQuery = (query, config, initialState) => {
  313. var _initialState$loading, _initialState$data, _initialState$params;
  314. const {
  315. initialAutoRunFlag,
  316. initialData,
  317. loadingDelay,
  318. pollingInterval,
  319. debounceInterval,
  320. debounceOptions,
  321. throttleInterval,
  322. throttleOptions,
  323. pollingWhenHidden,
  324. pollingWhenOffline,
  325. errorRetryCount,
  326. errorRetryInterval,
  327. stopPollingWhenHiddenOrOffline,
  328. refreshOnWindowFocus,
  329. refocusTimespan,
  330. updateCache,
  331. formatResult,
  332. onSuccess,
  333. onError,
  334. onBefore,
  335. onAfter
  336. } = config;
  337. const retriedCount = ref(0);
  338. const loading = ref((_initialState$loading = initialState === null || initialState === void 0 ? void 0 : initialState.loading) !== null && _initialState$loading !== void 0 ? _initialState$loading : false);
  339. const data = ref((_initialState$data = initialState === null || initialState === void 0 ? void 0 : initialState.data) !== null && _initialState$data !== void 0 ? _initialState$data : initialData);
  340. const error = ref(initialState === null || initialState === void 0 ? void 0 : initialState.error);
  341. const params = ref((_initialState$params = initialState === null || initialState === void 0 ? void 0 : initialState.params) !== null && _initialState$params !== void 0 ? _initialState$params : []);
  342. const setState = setStateBind({
  343. loading,
  344. data,
  345. error,
  346. params
  347. }, [state => updateCache(state)]); // reset retried count
  348. const resetRetriedCount = () => {
  349. retriedCount.value = 0;
  350. };
  351. const count = ref(0);
  352. const pollingTimer = ref();
  353. const retryTimer = ref();
  354. const delayLoadingTimer = ref();
  355. const clearAllTimer = () => {
  356. // clear pollingTimer
  357. if (pollingTimer.value) {
  358. pollingTimer.value();
  359. } // clear delayLoadingTimer
  360. if (delayLoadingTimer.value) {
  361. delayLoadingTimer.value();
  362. } // clear retryTimer
  363. if (retryTimer.value) {
  364. retryTimer.value();
  365. }
  366. };
  367. const delayLoading = () => {
  368. let timerId;
  369. if (loadingDelay) {
  370. timerId = setTimeout(setState, loadingDelay, {
  371. loading: true
  372. });
  373. }
  374. return () => timerId && clearTimeout(timerId);
  375. };
  376. const polling = pollingFunc => {
  377. // if errorRetry is enabled, then skip this method
  378. if (error.value && errorRetryCount !== 0) return;
  379. let timerId;
  380. if (!isNil(pollingInterval) && pollingInterval >= 0) {
  381. if ((pollingWhenHidden || isDocumentVisibility()) && (pollingWhenOffline || isOnline())) {
  382. timerId = setTimeout(pollingFunc, pollingInterval);
  383. } else {
  384. // stop polling
  385. stopPollingWhenHiddenOrOffline.value = true;
  386. return;
  387. }
  388. }
  389. return () => timerId && clearTimeout(timerId);
  390. };
  391. const actualErrorRetryInterval = computed(() => {
  392. if (errorRetryInterval) return errorRetryInterval;
  393. const baseTime = 1000;
  394. const minCoefficient = 1;
  395. const maxCoefficient = 9; // When retrying for the first time, in order to avoid the coefficient being 0
  396. // so replace 0 with 2, the coefficient range will become 1 - 2
  397. const coefficient = Math.floor(Math.random() * 2 ** Math.min(retriedCount.value, maxCoefficient) + minCoefficient);
  398. return baseTime * coefficient;
  399. });
  400. const errorRetryHooks = retryFunc => {
  401. let timerId;
  402. const isInfiniteRetry = errorRetryCount === -1;
  403. const hasRetryCount = retriedCount.value < errorRetryCount; // if errorRetryCount is -1, it will retry the request until it success
  404. if (error.value && (isInfiniteRetry || hasRetryCount)) {
  405. if (!isInfiniteRetry) retriedCount.value += 1;
  406. timerId = setTimeout(retryFunc, actualErrorRetryInterval.value);
  407. }
  408. return () => timerId && clearTimeout(timerId);
  409. };
  410. const _run = (...args) => {
  411. setState({
  412. loading: !loadingDelay,
  413. params: args
  414. });
  415. delayLoadingTimer.value = delayLoading();
  416. count.value += 1;
  417. const currentCount = count.value; // onBefore hooks
  418. onBefore === null || onBefore === void 0 ? void 0 : onBefore(args);
  419. return query(...args).then(res => {
  420. if (currentCount === count.value) {
  421. const formattedResult = formatResult ? formatResult(res) : res;
  422. setState({
  423. data: formattedResult,
  424. loading: false,
  425. error: undefined
  426. });
  427. if (onSuccess) {
  428. onSuccess(formattedResult, args);
  429. }
  430. resetRetriedCount();
  431. return formattedResult;
  432. }
  433. return resolvedPromise;
  434. }).catch(error => {
  435. if (currentCount === count.value) {
  436. setState({
  437. data: undefined,
  438. loading: false,
  439. error: error
  440. });
  441. if (onError) {
  442. onError(error, args);
  443. }
  444. console.error(error);
  445. }
  446. return resolvedPromise;
  447. }).finally(() => {
  448. if (currentCount === count.value) {
  449. // clear delayLoadingTimer
  450. delayLoadingTimer.value(); // retry
  451. retryTimer.value = errorRetryHooks(() => _run(...args)); // run for polling
  452. pollingTimer.value = polling(() => _run(...args)); // onAfter hooks
  453. onAfter === null || onAfter === void 0 ? void 0 : onAfter(args);
  454. }
  455. });
  456. };
  457. const debouncedRun = !isNil(debounceInterval) && debounce(_run, debounceInterval, debounceOptions);
  458. const throttledRun = !isNil(throttleInterval) && throttle(_run, throttleInterval, throttleOptions);
  459. const run = (...args) => {
  460. clearAllTimer(); // initial auto run should not debounce
  461. if (!initialAutoRunFlag.value && debouncedRun) {
  462. debouncedRun(...args);
  463. return resolvedPromise;
  464. }
  465. if (throttledRun) {
  466. throttledRun(...args);
  467. return resolvedPromise;
  468. }
  469. resetRetriedCount();
  470. return _run(...args);
  471. };
  472. const cancel = () => {
  473. count.value += 1;
  474. setState({
  475. loading: false
  476. });
  477. if (debouncedRun) {
  478. debouncedRun.cancel();
  479. }
  480. if (throttledRun) {
  481. throttledRun.cancel();
  482. }
  483. clearAllTimer();
  484. };
  485. const refresh = () => {
  486. return run(...params.value);
  487. };
  488. const mutate = x => {
  489. const mutateData = isFunction(x) ? x(data.value) : x;
  490. setState({
  491. data: mutateData
  492. });
  493. }; // collect subscribers, in order to unsubscribe when the component unmounted
  494. const unsubscribeList = [];
  495. const addUnsubscribeList = event => {
  496. event && unsubscribeList.push(event);
  497. };
  498. const rePolling = () => {
  499. if (stopPollingWhenHiddenOrOffline.value && (pollingWhenHidden || isDocumentVisibility()) && (pollingWhenOffline || isOnline())) {
  500. refresh();
  501. stopPollingWhenHiddenOrOffline.value = false;
  502. }
  503. }; // subscribe polling
  504. if (!pollingWhenHidden) {
  505. addUnsubscribeList(subscriber('VISIBLE_LISTENER', rePolling));
  506. } // subscribe online when pollingWhenOffline is false
  507. if (!pollingWhenOffline) {
  508. addUnsubscribeList(subscriber('RECONNECT_LISTENER', rePolling));
  509. }
  510. const limitRefresh = limitTrigger(refresh, refocusTimespan); // subscribe window focus or visible
  511. if (refreshOnWindowFocus) {
  512. addUnsubscribeList(subscriber('VISIBLE_LISTENER', limitRefresh));
  513. addUnsubscribeList(subscriber('FOCUS_LISTENER', limitRefresh));
  514. }
  515. const unmount = () => {
  516. unsubscribeList.forEach(unsubscribe => unsubscribe());
  517. };
  518. return {
  519. loading,
  520. data,
  521. error,
  522. params,
  523. run,
  524. cancel,
  525. refresh,
  526. mutate,
  527. unmount
  528. };
  529. };
  530. const CACHE_MAP = new Map();
  531. const getCache = cacheKey => {
  532. if (isNil(cacheKey)) return;
  533. const data = CACHE_MAP.get(cacheKey);
  534. if (!data) return;
  535. return {
  536. data: data.data,
  537. cacheTime: data.cacheTime
  538. };
  539. };
  540. const setCache = (cacheKey, data, cacheTime) => {
  541. const oldCache = CACHE_MAP.get(cacheKey);
  542. if (oldCache !== null && oldCache !== void 0 && oldCache.timer) {
  543. clearTimeout(oldCache.timer);
  544. }
  545. const timer = setTimeout(() => CACHE_MAP.delete(cacheKey), cacheTime);
  546. CACHE_MAP.set(cacheKey, {
  547. data,
  548. timer,
  549. cacheTime: new Date().getTime()
  550. });
  551. };
  552. const QUERY_DEFAULT_KEY = '__QUERY_DEFAULT_KEY__';
  553. function useAsyncQuery(query, options) {
  554. const injectedGlobalOptions = inject(GLOBAL_OPTIONS_PROVIDE_KEY, {});
  555. const {
  556. cacheKey,
  557. defaultParams = [],
  558. manual = false,
  559. ready = ref(true),
  560. refreshDeps = [],
  561. loadingDelay = 0,
  562. pollingWhenHidden = false,
  563. pollingWhenOffline = false,
  564. refreshOnWindowFocus = false,
  565. refocusTimespan = 5000,
  566. cacheTime = 600000,
  567. staleTime = 0,
  568. errorRetryCount = 0,
  569. errorRetryInterval = 0,
  570. queryKey,
  571. ...rest
  572. } = { ...getGlobalOptions(),
  573. ...injectedGlobalOptions,
  574. ...options
  575. };
  576. const stopPollingWhenHiddenOrOffline = ref(false); // skip debounce when initail run
  577. const initialAutoRunFlag = ref(false);
  578. const updateCache = state => {
  579. var _getCache, _queryKey;
  580. if (!cacheKey) return;
  581. const cacheData = (_getCache = getCache(cacheKey)) === null || _getCache === void 0 ? void 0 : _getCache.data;
  582. const cacheQueries = cacheData === null || cacheData === void 0 ? void 0 : cacheData.queries;
  583. const queryData = unRefObject(state);
  584. const currentQueryKey = (_queryKey = queryKey === null || queryKey === void 0 ? void 0 : queryKey(...state.params.value)) !== null && _queryKey !== void 0 ? _queryKey : QUERY_DEFAULT_KEY;
  585. setCache(cacheKey, {
  586. queries: { ...cacheQueries,
  587. [currentQueryKey]: { ...(cacheQueries === null || cacheQueries === void 0 ? void 0 : cacheQueries[currentQueryKey]),
  588. ...queryData
  589. }
  590. },
  591. latestQueriesKey: currentQueryKey
  592. }, cacheTime);
  593. };
  594. const config = {
  595. initialAutoRunFlag,
  596. loadingDelay,
  597. pollingWhenHidden,
  598. pollingWhenOffline,
  599. stopPollingWhenHiddenOrOffline,
  600. cacheKey,
  601. errorRetryCount,
  602. errorRetryInterval,
  603. refreshOnWindowFocus,
  604. refocusTimespan,
  605. updateCache,
  606. ...omit(rest, ['pagination', 'listKey'])
  607. };
  608. const loading = ref(false);
  609. const data = ref();
  610. const error = ref();
  611. const params = ref();
  612. const queries = reactive({
  613. [QUERY_DEFAULT_KEY]: reactive(createQuery(query, config))
  614. });
  615. const latestQueriesKey = ref(QUERY_DEFAULT_KEY);
  616. const latestQuery = computed(() => {
  617. var _queries$latestQuerie;
  618. return (_queries$latestQuerie = queries[latestQueriesKey.value]) !== null && _queries$latestQuerie !== void 0 ? _queries$latestQuerie : {};
  619. }); // sync state
  620. watch(latestQuery, queryData => {
  621. loading.value = queryData.loading;
  622. data.value = queryData.data;
  623. error.value = queryData.error;
  624. params.value = queryData.params;
  625. }, {
  626. immediate: true,
  627. deep: true
  628. }); // init queries from cache
  629. if (cacheKey) {
  630. var _cache$data;
  631. const cache = getCache(cacheKey);
  632. if (cache !== null && cache !== void 0 && (_cache$data = cache.data) !== null && _cache$data !== void 0 && _cache$data.queries) {
  633. Object.keys(cache.data.queries).forEach(key => {
  634. const cacheQuery = cache.data.queries[key];
  635. queries[key] = reactive(createQuery(query, config, {
  636. loading: cacheQuery.loading,
  637. params: cacheQuery.params,
  638. data: cacheQuery.data,
  639. error: cacheQuery.error
  640. }));
  641. });
  642. /* istanbul ignore else */
  643. if (cache.data.latestQueriesKey) {
  644. latestQueriesKey.value = cache.data.latestQueriesKey;
  645. }
  646. }
  647. }
  648. const tempReadyParams = ref();
  649. const hasTriggerReady = ref(false);
  650. const run = (...args) => {
  651. var _queryKey2;
  652. if (!ready.value && !hasTriggerReady.value) {
  653. tempReadyParams.value = args;
  654. return resolvedPromise;
  655. }
  656. const newKey = (_queryKey2 = queryKey === null || queryKey === void 0 ? void 0 : queryKey(...args)) !== null && _queryKey2 !== void 0 ? _queryKey2 : QUERY_DEFAULT_KEY;
  657. if (!queries[newKey]) {
  658. queries[newKey] = reactive(createQuery(query, config));
  659. }
  660. latestQueriesKey.value = newKey;
  661. return latestQuery.value.run(...args);
  662. };
  663. const reset = () => {
  664. unmountQueries();
  665. latestQueriesKey.value = QUERY_DEFAULT_KEY;
  666. queries[QUERY_DEFAULT_KEY] = reactive(createQuery(query, config));
  667. }; // unmount queries
  668. const unmountQueries = () => {
  669. Object.keys(queries).forEach(key => {
  670. queries[key].cancel();
  671. queries[key].unmount();
  672. delete queries[key];
  673. });
  674. };
  675. const cancel = () => latestQuery.value.cancel();
  676. const refresh = () => latestQuery.value.refresh();
  677. const mutate = arg => latestQuery.value.mutate(arg); // initial run
  678. if (!manual) {
  679. var _cache$data$queries;
  680. initialAutoRunFlag.value = true; // TODO: need refactor
  681. const cache = getCache(cacheKey);
  682. const cacheQueries = (_cache$data$queries = cache === null || cache === void 0 ? void 0 : cache.data.queries) !== null && _cache$data$queries !== void 0 ? _cache$data$queries : {};
  683. const isFresh = cache && (staleTime === -1 || cache.cacheTime + staleTime > new Date().getTime());
  684. const hasCacheQueries = Object.keys(cacheQueries).length > 0;
  685. if (!isFresh) {
  686. if (hasCacheQueries) {
  687. Object.keys(queries).forEach(key => {
  688. var _queries$key;
  689. (_queries$key = queries[key]) === null || _queries$key === void 0 ? void 0 : _queries$key.refresh();
  690. });
  691. } else {
  692. run(...defaultParams);
  693. }
  694. }
  695. initialAutoRunFlag.value = false;
  696. } // watch ready
  697. const stopReady = ref();
  698. stopReady.value = watch(ready, val => {
  699. hasTriggerReady.value = true;
  700. if (val && tempReadyParams.value) {
  701. run(...tempReadyParams.value); // destroy current watch
  702. stopReady.value();
  703. }
  704. }, {
  705. flush: 'sync'
  706. }); // watch refreshDeps
  707. if (refreshDeps.length) {
  708. watch(refreshDeps, () => {
  709. !manual && latestQuery.value.refresh();
  710. });
  711. }
  712. onUnmounted(() => {
  713. unmountQueries();
  714. });
  715. return {
  716. loading,
  717. data,
  718. error,
  719. params,
  720. cancel,
  721. refresh,
  722. mutate,
  723. run,
  724. reset,
  725. queries
  726. };
  727. }
  728. const generateService = service => {
  729. return (...args) => {
  730. if (isFunction(service)) {
  731. return generateService(service(...args))();
  732. } else if (isPromise(service)) {
  733. return service;
  734. } else if (isPlainObject(service)) {
  735. const {
  736. url,
  737. ...rest
  738. } = service;
  739. return requestProxy(url, rest);
  740. } else if (isString(service)) {
  741. return requestProxy(service);
  742. } else {
  743. throw warning('Unknown service type', true);
  744. }
  745. };
  746. };
  747. function useLoadMore(service, options) {
  748. var _injectedGlobalOption;
  749. if (!isFunction(service)) {
  750. warning('useLoadMore only support function service');
  751. }
  752. const promiseQuery = generateService(service);
  753. const injectedGlobalOptions = inject(GLOBAL_OPTIONS_PROVIDE_KEY, {});
  754. const {
  755. queryKey,
  756. isNoMore,
  757. listKey = 'list',
  758. ...restOptions
  759. } = Object.assign({
  760. listKey: (_injectedGlobalOption = injectedGlobalOptions.listKey) !== null && _injectedGlobalOption !== void 0 ? _injectedGlobalOption : getGlobalOptions().listKey
  761. }, options !== null && options !== void 0 ? options : {});
  762. if (queryKey) {
  763. warning('useLoadMore does not support concurrent request');
  764. }
  765. const refreshing = ref(false);
  766. const loadingMore = ref(false);
  767. const reloading = ref(false);
  768. const initailIncreaseQueryKey = 0;
  769. const increaseQueryKey = ref(initailIncreaseQueryKey);
  770. const {
  771. data,
  772. params,
  773. queries,
  774. run,
  775. reset,
  776. cancel: _cancel,
  777. ...rest
  778. } = useAsyncQuery(promiseQuery, { ...restOptions,
  779. onSuccess: (...p) => {
  780. var _restOptions$onSucces;
  781. loadingMore.value = false;
  782. increaseQueryKey.value++;
  783. restOptions === null || restOptions === void 0 ? void 0 : (_restOptions$onSucces = restOptions.onSuccess) === null || _restOptions$onSucces === void 0 ? void 0 : _restOptions$onSucces.call(restOptions, ...p);
  784. },
  785. onError: (...p) => {
  786. var _restOptions$onError;
  787. loadingMore.value = false;
  788. restOptions === null || restOptions === void 0 ? void 0 : (_restOptions$onError = restOptions.onError) === null || _restOptions$onError === void 0 ? void 0 : _restOptions$onError.call(restOptions, ...p);
  789. },
  790. queryKey: () => String(increaseQueryKey.value)
  791. });
  792. const latestData = ref(data.value);
  793. watchEffect(() => {
  794. if (data.value !== undefined) {
  795. latestData.value = data.value;
  796. }
  797. });
  798. const noMore = computed(() => {
  799. return isNoMore && isFunction(isNoMore) ? isNoMore(latestData.value) : false;
  800. });
  801. const dataList = computed(() => {
  802. let list = [];
  803. Object.values(queries).forEach(h => {
  804. const dataList = get(h.data, listKey);
  805. if (dataList && Array.isArray(dataList)) {
  806. list = list.concat(dataList);
  807. }
  808. });
  809. return list;
  810. });
  811. const loadMore = () => {
  812. if (noMore.value) {
  813. return;
  814. }
  815. loadingMore.value = true;
  816. const [, ...restParams] = params.value;
  817. const mergerParams = [{
  818. dataList: dataList.value,
  819. data: latestData.value
  820. }, ...restParams];
  821. run(...mergerParams);
  822. };
  823. const unmountQueries = () => {
  824. Object.keys(queries).forEach(key => {
  825. if (key !== initailIncreaseQueryKey.toString()) {
  826. queries[key].cancel();
  827. queries[key].unmount();
  828. delete queries[key];
  829. }
  830. });
  831. };
  832. const refresh = async () => {
  833. refreshing.value = true;
  834. const latestKey = increaseQueryKey.value - 1;
  835. const key = latestKey < initailIncreaseQueryKey ? initailIncreaseQueryKey : latestKey;
  836. latestData.value = queries[key].data;
  837. increaseQueryKey.value = initailIncreaseQueryKey;
  838. const [, ...restParams] = params.value;
  839. const mergerParams = [undefined, ...restParams];
  840. await run(...mergerParams);
  841. unmountQueries();
  842. refreshing.value = false;
  843. };
  844. const reload = async () => {
  845. reloading.value = true;
  846. reset();
  847. increaseQueryKey.value = initailIncreaseQueryKey;
  848. latestData.value = undefined;
  849. const [, ...restParams] = params.value;
  850. const mergerParams = [undefined, ...restParams];
  851. await run(...mergerParams);
  852. reloading.value = false;
  853. };
  854. const cancel = () => {
  855. _cancel();
  856. loadingMore.value = false;
  857. refreshing.value = false;
  858. };
  859. return {
  860. data: latestData,
  861. dataList: dataList,
  862. params,
  863. noMore,
  864. loadingMore,
  865. refreshing,
  866. reloading,
  867. run,
  868. reload,
  869. loadMore,
  870. reset,
  871. refresh,
  872. cancel,
  873. ...omit(rest, ['refresh', 'mutate'])
  874. };
  875. }
  876. function usePagination(service, options) {
  877. var _getGlobalOptions$pag, _injectedGlobalOption;
  878. const promiseQuery = generateService(service);
  879. const defaultOptions = {
  880. pagination: {
  881. currentKey: 'current',
  882. pageSizeKey: 'pageSize',
  883. totalKey: 'total',
  884. totalPageKey: 'totalPage'
  885. }
  886. };
  887. const injectedGlobalOptions = inject(GLOBAL_OPTIONS_PROVIDE_KEY, {});
  888. const {
  889. pagination: {
  890. currentKey,
  891. pageSizeKey,
  892. totalKey,
  893. totalPageKey
  894. },
  895. queryKey,
  896. ...restOptions
  897. } = merge(defaultOptions, {
  898. pagination: (_getGlobalOptions$pag = getGlobalOptions().pagination) !== null && _getGlobalOptions$pag !== void 0 ? _getGlobalOptions$pag : {}
  899. }, {
  900. pagination: (_injectedGlobalOption = injectedGlobalOptions.pagination) !== null && _injectedGlobalOption !== void 0 ? _injectedGlobalOption : {}
  901. }, options !== null && options !== void 0 ? options : {});
  902. if (queryKey) {
  903. warning('usePagination does not support concurrent request');
  904. }
  905. const finallyOptions = merge({
  906. defaultParams: [{
  907. [currentKey]: 1,
  908. [pageSizeKey]: 10
  909. }]
  910. }, restOptions);
  911. const {
  912. data,
  913. params,
  914. queries,
  915. run,
  916. reset,
  917. ...rest
  918. } = useAsyncQuery(promiseQuery, finallyOptions);
  919. const paging = paginationParams => {
  920. const [oldPaginationParams, ...restParams] = params.value;
  921. const newPaginationParams = { ...oldPaginationParams,
  922. ...paginationParams
  923. };
  924. const mergerParams = [newPaginationParams, ...restParams];
  925. run(...mergerParams);
  926. }; // changeCurrent change current page (current: number) => void
  927. const changeCurrent = current => {
  928. paging({
  929. [currentKey]: current
  930. });
  931. }; // changePageSize change pageSize (pageSize: number) => void
  932. const changePageSize = pageSize => {
  933. paging({
  934. [pageSizeKey]: pageSize
  935. });
  936. }; // changePagination change current and pageSize (current: number, pageSize: number) => void
  937. const changePagination = (current, pageSize) => {
  938. paging({
  939. [currentKey]: current,
  940. [pageSizeKey]: pageSize
  941. });
  942. };
  943. const reloading = ref(false);
  944. const reload = async () => {
  945. const {
  946. defaultParams,
  947. manual
  948. } = finallyOptions;
  949. reset();
  950. if (!manual) {
  951. reloading.value = true;
  952. await run(...defaultParams);
  953. reloading.value = false;
  954. }
  955. };
  956. const total = computed(() => get(data.value, totalKey, 0));
  957. const current = computed({
  958. get: () => {
  959. var _params$value$0$curre, _params$value$;
  960. return (_params$value$0$curre = (_params$value$ = params.value[0]) === null || _params$value$ === void 0 ? void 0 : _params$value$[currentKey]) !== null && _params$value$0$curre !== void 0 ? _params$value$0$curre : finallyOptions.defaultParams[0][currentKey];
  961. },
  962. set: val => {
  963. changeCurrent(val);
  964. }
  965. });
  966. const pageSize = computed({
  967. get: () => {
  968. var _params$value$0$pageS, _params$value$2;
  969. return (_params$value$0$pageS = (_params$value$2 = params.value[0]) === null || _params$value$2 === void 0 ? void 0 : _params$value$2[pageSizeKey]) !== null && _params$value$0$pageS !== void 0 ? _params$value$0$pageS : finallyOptions.defaultParams[0][pageSizeKey];
  970. },
  971. set: val => {
  972. changePageSize(val);
  973. }
  974. });
  975. const totalPage = computed(() => get(data.value, totalPageKey, Math.ceil(total.value / pageSize.value)));
  976. return {
  977. data,
  978. params,
  979. current,
  980. pageSize,
  981. total,
  982. totalPage,
  983. reloading,
  984. run,
  985. changeCurrent,
  986. changePageSize,
  987. changePagination,
  988. reload,
  989. ...rest
  990. };
  991. }
  992. function useRequest(service, options) {
  993. const promiseQuery = generateService(service);
  994. const {
  995. reset,
  996. run,
  997. ...rest
  998. } = useAsyncQuery(promiseQuery, options !== null && options !== void 0 ? options : {});
  999. const reloading = ref(false);
  1000. const reload = async () => {
  1001. const {
  1002. defaultParams = [],
  1003. manual
  1004. } = options;
  1005. reset();
  1006. if (!manual) {
  1007. reloading.value = true;
  1008. await run(...defaultParams);
  1009. reloading.value = false;
  1010. }
  1011. };
  1012. return {
  1013. reload,
  1014. run,
  1015. reloading,
  1016. ...rest
  1017. };
  1018. }
  1019. export { RequestConfig, setGlobalOptions, useLoadMore, usePagination, useRequest };