@yh-ui/request 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +274 -0
- package/dist/adapters/fetch.cjs +157 -0
- package/dist/adapters/fetch.d.ts +25 -0
- package/dist/adapters/fetch.mjs +148 -0
- package/dist/adapters/index.cjs +27 -0
- package/dist/adapters/index.d.ts +5 -0
- package/dist/adapters/index.mjs +2 -0
- package/dist/adapters/platform.cjs +394 -0
- package/dist/adapters/platform.d.ts +72 -0
- package/dist/adapters/platform.mjs +369 -0
- package/dist/cache/index.cjs +56 -0
- package/dist/cache/index.d.ts +21 -0
- package/dist/cache/index.mjs +14 -0
- package/dist/cache/indexedDB.cjs +188 -0
- package/dist/cache/indexedDB.d.ts +58 -0
- package/dist/cache/indexedDB.mjs +176 -0
- package/dist/cache/localStorage.cjs +158 -0
- package/dist/cache/localStorage.d.ts +58 -0
- package/dist/cache/localStorage.mjs +153 -0
- package/dist/cache/memory.cjs +112 -0
- package/dist/cache/memory.d.ts +71 -0
- package/dist/cache/memory.mjs +103 -0
- package/dist/graphql.cjs +255 -0
- package/dist/graphql.d.ts +192 -0
- package/dist/graphql.mjs +235 -0
- package/dist/http-cache.cjs +248 -0
- package/dist/http-cache.d.ts +156 -0
- package/dist/http-cache.mjs +233 -0
- package/dist/index.cjs +181 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.mjs +16 -0
- package/dist/interceptors/debug.cjs +139 -0
- package/dist/interceptors/debug.d.ts +92 -0
- package/dist/interceptors/debug.mjs +130 -0
- package/dist/interceptors/index.cjs +38 -0
- package/dist/interceptors/index.d.ts +6 -0
- package/dist/interceptors/index.mjs +3 -0
- package/dist/interceptors/progress.cjs +185 -0
- package/dist/interceptors/progress.d.ts +97 -0
- package/dist/interceptors/progress.mjs +177 -0
- package/dist/interceptors/security.cjs +154 -0
- package/dist/interceptors/security.d.ts +83 -0
- package/dist/interceptors/security.mjs +134 -0
- package/dist/plugin.cjs +166 -0
- package/dist/plugin.d.ts +106 -0
- package/dist/plugin.mjs +163 -0
- package/dist/request.cjs +396 -0
- package/dist/request.d.ts +111 -0
- package/dist/request.mjs +339 -0
- package/dist/types.cjs +13 -0
- package/dist/types.d.ts +157 -0
- package/dist/types.mjs +7 -0
- package/dist/useAIStream.cjs +125 -0
- package/dist/useAIStream.d.ts +89 -0
- package/dist/useAIStream.mjs +108 -0
- package/dist/useLoadMore.cjs +136 -0
- package/dist/useLoadMore.d.ts +84 -0
- package/dist/useLoadMore.mjs +134 -0
- package/dist/usePagination.cjs +141 -0
- package/dist/usePagination.d.ts +89 -0
- package/dist/usePagination.mjs +132 -0
- package/dist/useQueue.cjs +243 -0
- package/dist/useQueue.d.ts +118 -0
- package/dist/useQueue.mjs +239 -0
- package/dist/useRequest.cjs +325 -0
- package/dist/useRequest.d.ts +126 -0
- package/dist/useRequest.mjs +329 -0
- package/dist/useRequestQueue.cjs +36 -0
- package/dist/useRequestQueue.d.ts +52 -0
- package/dist/useRequestQueue.mjs +27 -0
- package/dist/useSSE.cjs +241 -0
- package/dist/useSSE.d.ts +74 -0
- package/dist/useSSE.mjs +226 -0
- package/dist/websocket.cjs +325 -0
- package/dist/websocket.d.ts +163 -0
- package/dist/websocket.mjs +316 -0
- package/package.json +61 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { ref, reactive, computed, onUnmounted } from "vue";
|
|
2
|
+
let taskIdCounter = 0;
|
|
3
|
+
function generateTaskId() {
|
|
4
|
+
return `task_${Date.now()}_${++taskIdCounter}`;
|
|
5
|
+
}
|
|
6
|
+
export function useQueue(options = {}) {
|
|
7
|
+
const {
|
|
8
|
+
concurrency = 1,
|
|
9
|
+
autoStart = false,
|
|
10
|
+
continueOnError = false,
|
|
11
|
+
onTaskComplete,
|
|
12
|
+
onTaskError,
|
|
13
|
+
onAllComplete
|
|
14
|
+
} = options;
|
|
15
|
+
const taskList = reactive([]);
|
|
16
|
+
const taskMap = /* @__PURE__ */ new Map();
|
|
17
|
+
const isRunning = ref(false);
|
|
18
|
+
const isPaused = ref(false);
|
|
19
|
+
const currentTaskIds = /* @__PURE__ */ new Set();
|
|
20
|
+
const version = ref(0);
|
|
21
|
+
const triggerUpdate = () => {
|
|
22
|
+
version.value++;
|
|
23
|
+
};
|
|
24
|
+
const tasks = computed(() => {
|
|
25
|
+
void version.value;
|
|
26
|
+
return [...taskList];
|
|
27
|
+
});
|
|
28
|
+
const pendingTasks = computed(
|
|
29
|
+
() => tasks.value.filter((t) => t.status === "pending").sort((a, b) => (b.priority || 0) - (a.priority || 0))
|
|
30
|
+
);
|
|
31
|
+
const runningTasks = computed(() => tasks.value.filter((t) => t.status === "running"));
|
|
32
|
+
const completedTasks = computed(() => tasks.value.filter((t) => t.status === "fulfilled"));
|
|
33
|
+
const failedTasks = computed(() => tasks.value.filter((t) => t.status === "rejected"));
|
|
34
|
+
const isEmpty = computed(() => tasks.value.length === 0);
|
|
35
|
+
const isAllComplete = computed(() => {
|
|
36
|
+
if (tasks.value.length === 0) return false;
|
|
37
|
+
return tasks.value.every((t) => t.status === "fulfilled" || t.status === "rejected");
|
|
38
|
+
});
|
|
39
|
+
const completedCount = computed(() => completedTasks.value.length);
|
|
40
|
+
const totalCount = computed(() => tasks.value.length);
|
|
41
|
+
const executeTask = async (task) => {
|
|
42
|
+
if (task.status === "canceled" || task.status === "running") return;
|
|
43
|
+
task.status = "running";
|
|
44
|
+
task.startTime = Date.now();
|
|
45
|
+
currentTaskIds.add(task.id);
|
|
46
|
+
triggerUpdate();
|
|
47
|
+
try {
|
|
48
|
+
if (task.delay && task.delay > 0) {
|
|
49
|
+
await new Promise((resolve) => setTimeout(resolve, task.delay));
|
|
50
|
+
}
|
|
51
|
+
if (task.status === "canceled") return;
|
|
52
|
+
const result = await task.task();
|
|
53
|
+
if (task.status === "canceled") return;
|
|
54
|
+
task.status = "fulfilled";
|
|
55
|
+
task.result = result;
|
|
56
|
+
task.endTime = Date.now();
|
|
57
|
+
triggerUpdate();
|
|
58
|
+
onTaskComplete?.(task);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
task.status = "rejected";
|
|
61
|
+
task.error = error instanceof Error ? error : new Error(String(error));
|
|
62
|
+
task.endTime = Date.now();
|
|
63
|
+
triggerUpdate();
|
|
64
|
+
onTaskError?.(task, task.error);
|
|
65
|
+
if (!continueOnError) {
|
|
66
|
+
pause();
|
|
67
|
+
}
|
|
68
|
+
} finally {
|
|
69
|
+
currentTaskIds.delete(task.id);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const processQueue = () => {
|
|
73
|
+
if (isPaused.value || !isRunning.value) return;
|
|
74
|
+
let launched = 0;
|
|
75
|
+
const available = concurrency - currentTaskIds.size;
|
|
76
|
+
if (available <= 0) return;
|
|
77
|
+
const pending = taskList.filter((t) => t.status === "pending").sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
|
78
|
+
for (let i = 0; i < pending.length && launched < available; i++) {
|
|
79
|
+
const nextTask = pending[i];
|
|
80
|
+
if (nextTask) {
|
|
81
|
+
launched++;
|
|
82
|
+
executeTask(nextTask).finally(() => {
|
|
83
|
+
if (isRunning.value && !isPaused.value) {
|
|
84
|
+
setTimeout(processQueue, 0);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (currentTaskIds.size === 0 && pending.length === 0 && isRunning.value) {
|
|
90
|
+
isRunning.value = false;
|
|
91
|
+
onAllComplete?.(tasks.value);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const add = (task, addOptions = {}) => {
|
|
95
|
+
const id = generateTaskId();
|
|
96
|
+
const newTask = {
|
|
97
|
+
id,
|
|
98
|
+
key: addOptions.key,
|
|
99
|
+
task,
|
|
100
|
+
priority: addOptions.priority,
|
|
101
|
+
delay: addOptions.delay,
|
|
102
|
+
metadata: addOptions.metadata,
|
|
103
|
+
status: "pending",
|
|
104
|
+
createdAt: Date.now()
|
|
105
|
+
};
|
|
106
|
+
taskMap.set(id, newTask);
|
|
107
|
+
taskList.push(newTask);
|
|
108
|
+
triggerUpdate();
|
|
109
|
+
if (autoStart && !isRunning.value) {
|
|
110
|
+
start();
|
|
111
|
+
} else if (isRunning.value && !isPaused.value) {
|
|
112
|
+
setTimeout(processQueue, 0);
|
|
113
|
+
}
|
|
114
|
+
return id;
|
|
115
|
+
};
|
|
116
|
+
const remove = (taskId) => {
|
|
117
|
+
const task = taskMap.get(taskId);
|
|
118
|
+
if (task && task.status === "pending") {
|
|
119
|
+
task.status = "canceled";
|
|
120
|
+
taskMap.delete(taskId);
|
|
121
|
+
const index = taskList.findIndex((t) => t.id === taskId);
|
|
122
|
+
if (index > -1) taskList.splice(index, 1);
|
|
123
|
+
triggerUpdate();
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const clear = () => {
|
|
127
|
+
taskMap.forEach((task) => {
|
|
128
|
+
if (task.status === "pending" || task.status === "running") {
|
|
129
|
+
task.status = "canceled";
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
taskMap.clear();
|
|
133
|
+
taskList.length = 0;
|
|
134
|
+
currentTaskIds.clear();
|
|
135
|
+
isRunning.value = false;
|
|
136
|
+
triggerUpdate();
|
|
137
|
+
};
|
|
138
|
+
const start = () => {
|
|
139
|
+
if (isRunning.value) return;
|
|
140
|
+
isRunning.value = true;
|
|
141
|
+
isPaused.value = false;
|
|
142
|
+
processQueue();
|
|
143
|
+
};
|
|
144
|
+
const pause = () => {
|
|
145
|
+
isPaused.value = true;
|
|
146
|
+
};
|
|
147
|
+
const resume = () => {
|
|
148
|
+
isPaused.value = false;
|
|
149
|
+
if (!isRunning.value) {
|
|
150
|
+
start();
|
|
151
|
+
} else {
|
|
152
|
+
processQueue();
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const cancel = (taskId) => {
|
|
156
|
+
const task = taskMap.get(taskId);
|
|
157
|
+
if (task) {
|
|
158
|
+
if (task.status === "pending") {
|
|
159
|
+
task.status = "canceled";
|
|
160
|
+
taskMap.delete(taskId);
|
|
161
|
+
const index = taskList.findIndex((t) => t.id === taskId);
|
|
162
|
+
if (index > -1) taskList.splice(index, 1);
|
|
163
|
+
triggerUpdate();
|
|
164
|
+
} else if (task.status === "running") {
|
|
165
|
+
task.status = "canceled";
|
|
166
|
+
triggerUpdate();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
const cancelAll = () => {
|
|
171
|
+
taskMap.forEach((task) => {
|
|
172
|
+
if (task.status === "pending" || task.status === "running") {
|
|
173
|
+
task.status = "canceled";
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
currentTaskIds.clear();
|
|
177
|
+
isRunning.value = false;
|
|
178
|
+
triggerUpdate();
|
|
179
|
+
};
|
|
180
|
+
const retry = (taskId) => {
|
|
181
|
+
const task = taskMap.get(taskId);
|
|
182
|
+
if (task && (task.status === "rejected" || task.status === "canceled")) {
|
|
183
|
+
task.status = "pending";
|
|
184
|
+
task.error = void 0;
|
|
185
|
+
task.result = void 0;
|
|
186
|
+
task.startTime = void 0;
|
|
187
|
+
task.endTime = void 0;
|
|
188
|
+
version.value++;
|
|
189
|
+
if (isRunning.value && !isPaused.value) {
|
|
190
|
+
setTimeout(processQueue, 0);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
const retryAll = () => {
|
|
195
|
+
taskMap.forEach((task) => {
|
|
196
|
+
if (task.status === "rejected" || task.status === "canceled") {
|
|
197
|
+
task.status = "pending";
|
|
198
|
+
task.error = void 0;
|
|
199
|
+
task.result = void 0;
|
|
200
|
+
task.startTime = void 0;
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
triggerUpdate();
|
|
204
|
+
if (!isRunning.value) {
|
|
205
|
+
start();
|
|
206
|
+
} else if (isPaused.value) {
|
|
207
|
+
resume();
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
const getTask = (taskId) => {
|
|
211
|
+
return taskMap.get(taskId);
|
|
212
|
+
};
|
|
213
|
+
onUnmounted(() => {
|
|
214
|
+
cancelAll();
|
|
215
|
+
});
|
|
216
|
+
return {
|
|
217
|
+
tasks,
|
|
218
|
+
pendingTasks,
|
|
219
|
+
runningTasks,
|
|
220
|
+
completedTasks,
|
|
221
|
+
failedTasks,
|
|
222
|
+
isRunning,
|
|
223
|
+
isEmpty,
|
|
224
|
+
isAllComplete,
|
|
225
|
+
completedCount,
|
|
226
|
+
totalCount,
|
|
227
|
+
add,
|
|
228
|
+
remove,
|
|
229
|
+
clear,
|
|
230
|
+
start,
|
|
231
|
+
pause,
|
|
232
|
+
resume,
|
|
233
|
+
cancel,
|
|
234
|
+
cancelAll,
|
|
235
|
+
retry,
|
|
236
|
+
retryAll,
|
|
237
|
+
getTask
|
|
238
|
+
};
|
|
239
|
+
}
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useRequest = useRequest;
|
|
7
|
+
exports.useRequestPolling = useRequestPolling;
|
|
8
|
+
exports.useRequestSWR = useRequestSWR;
|
|
9
|
+
var _vue = require("vue");
|
|
10
|
+
var _utils = require("@yh-ui/utils");
|
|
11
|
+
const globalCache = /* @__PURE__ */new Map();
|
|
12
|
+
function setCache(key, value, cacheTime) {
|
|
13
|
+
const expireTime = Date.now() + (cacheTime || 5 * 60 * 1e3);
|
|
14
|
+
globalCache.set(key, {
|
|
15
|
+
data: value,
|
|
16
|
+
expireTime
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function useRequest(service, options = {}) {
|
|
20
|
+
const {
|
|
21
|
+
manual = false,
|
|
22
|
+
defaultParams = [],
|
|
23
|
+
debounceWait,
|
|
24
|
+
throttleWait,
|
|
25
|
+
formatResult,
|
|
26
|
+
onSuccess,
|
|
27
|
+
onError,
|
|
28
|
+
onFinally
|
|
29
|
+
} = options;
|
|
30
|
+
const loading = (0, _vue.ref)(false);
|
|
31
|
+
const loadingMore = (0, _vue.ref)(false);
|
|
32
|
+
const data = (0, _vue.shallowRef)(void 0);
|
|
33
|
+
const error = (0, _vue.shallowRef)(void 0);
|
|
34
|
+
const params = (0, _vue.ref)(defaultParams);
|
|
35
|
+
const noMore = (0, _vue.ref)(false);
|
|
36
|
+
const runCount = (0, _vue.ref)(0);
|
|
37
|
+
let abortController = null;
|
|
38
|
+
const format = response => {
|
|
39
|
+
if (formatResult) {
|
|
40
|
+
return formatResult(response);
|
|
41
|
+
}
|
|
42
|
+
if (response && typeof response === "object" && !("config" in response && "requestId" in response)) {
|
|
43
|
+
return response;
|
|
44
|
+
}
|
|
45
|
+
const res = response;
|
|
46
|
+
return res?.data ?? res;
|
|
47
|
+
};
|
|
48
|
+
const run = async (...runParams) => {
|
|
49
|
+
const currentRunCount = ++runCount.value;
|
|
50
|
+
if (abortController) {
|
|
51
|
+
abortController.abort();
|
|
52
|
+
}
|
|
53
|
+
abortController = new AbortController();
|
|
54
|
+
params.value = runParams;
|
|
55
|
+
loading.value = true;
|
|
56
|
+
error.value = void 0;
|
|
57
|
+
try {
|
|
58
|
+
const response = await service(...runParams);
|
|
59
|
+
if (currentRunCount !== runCount.value) {
|
|
60
|
+
const cancelError = new Error("Request canceled");
|
|
61
|
+
cancelError.isCanceled = true;
|
|
62
|
+
throw cancelError;
|
|
63
|
+
}
|
|
64
|
+
const formattedData = format(response);
|
|
65
|
+
data.value = formattedData;
|
|
66
|
+
if (onSuccess) {
|
|
67
|
+
onSuccess(formattedData, runParams);
|
|
68
|
+
}
|
|
69
|
+
return response;
|
|
70
|
+
} catch (err) {
|
|
71
|
+
const cancelableErr = err;
|
|
72
|
+
if (cancelableErr?.isCanceled || cancelableErr?.name === "AbortError") {
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
error.value = err;
|
|
76
|
+
if (onError) {
|
|
77
|
+
onError(err, runParams);
|
|
78
|
+
}
|
|
79
|
+
throw err;
|
|
80
|
+
} finally {
|
|
81
|
+
if (currentRunCount === runCount.value) {
|
|
82
|
+
loading.value = false;
|
|
83
|
+
if (onFinally) {
|
|
84
|
+
onFinally(runParams);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const mutate = newData => {
|
|
90
|
+
if (typeof newData === "function") {
|
|
91
|
+
const oldData = data.value;
|
|
92
|
+
data.value = newData(oldData);
|
|
93
|
+
} else if (newData !== void 0) {
|
|
94
|
+
data.value = newData;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const cancel = () => {
|
|
98
|
+
if (abortController) {
|
|
99
|
+
abortController.abort();
|
|
100
|
+
abortController = null;
|
|
101
|
+
}
|
|
102
|
+
loading.value = false;
|
|
103
|
+
};
|
|
104
|
+
const refresh = async () => {
|
|
105
|
+
await run(...params.value).catch(() => {});
|
|
106
|
+
};
|
|
107
|
+
const loadMore = async () => {
|
|
108
|
+
if (loadingMore.value || noMore.value) return;
|
|
109
|
+
loadingMore.value = true;
|
|
110
|
+
try {
|
|
111
|
+
await run(...params.value).catch(() => {});
|
|
112
|
+
} finally {
|
|
113
|
+
loadingMore.value = false;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
let wrappedRun = run;
|
|
117
|
+
let cancelFn;
|
|
118
|
+
if (debounceWait) {
|
|
119
|
+
const debounced = (0, _utils.debounce)((...args) => {
|
|
120
|
+
run(...args).catch(() => {});
|
|
121
|
+
}, debounceWait);
|
|
122
|
+
wrappedRun = (...args) => {
|
|
123
|
+
debounced(...args);
|
|
124
|
+
return Promise.resolve();
|
|
125
|
+
};
|
|
126
|
+
wrappedRun.cancel = () => debounced.cancel();
|
|
127
|
+
cancelFn = () => debounced.cancel();
|
|
128
|
+
} else if (throttleWait) {
|
|
129
|
+
const throttled = (0, _utils.throttle)((...args) => {
|
|
130
|
+
run(...args).catch(() => {});
|
|
131
|
+
}, throttleWait);
|
|
132
|
+
wrappedRun = (...args) => {
|
|
133
|
+
throttled(...args);
|
|
134
|
+
return Promise.resolve();
|
|
135
|
+
};
|
|
136
|
+
wrappedRun.cancel = () => throttled.cancel();
|
|
137
|
+
cancelFn = () => throttled.cancel();
|
|
138
|
+
}
|
|
139
|
+
(0, _vue.onUnmounted)(() => {
|
|
140
|
+
cancelFn?.();
|
|
141
|
+
});
|
|
142
|
+
if (!manual && defaultParams.length > 0) {
|
|
143
|
+
(0, _vue.onMounted)(() => {
|
|
144
|
+
if (!debounceWait && !throttleWait) {
|
|
145
|
+
run(...defaultParams).catch(() => {});
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
const disabled = (0, _vue.computed)(() => loading.value);
|
|
150
|
+
return {
|
|
151
|
+
loading,
|
|
152
|
+
loadingMore,
|
|
153
|
+
data,
|
|
154
|
+
error,
|
|
155
|
+
params,
|
|
156
|
+
noMore,
|
|
157
|
+
run: wrappedRun,
|
|
158
|
+
mutate,
|
|
159
|
+
cancel,
|
|
160
|
+
refresh,
|
|
161
|
+
loadMore,
|
|
162
|
+
disabled
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function useRequestSWR(cacheKey, service, options = {}) {
|
|
166
|
+
const {
|
|
167
|
+
cacheTime = 10 * 60 * 1e3,
|
|
168
|
+
setCache: customSetCache,
|
|
169
|
+
refreshOnWindowFocus = false,
|
|
170
|
+
refreshDepsWait = 1e3,
|
|
171
|
+
refreshDeps = [],
|
|
172
|
+
manual = false,
|
|
173
|
+
...requestOptions
|
|
174
|
+
} = options;
|
|
175
|
+
const setCacheFn = customSetCache || ((key, value) => setCache(key, value, cacheTime));
|
|
176
|
+
const getKey = () => {
|
|
177
|
+
const key = typeof cacheKey === "function" ? cacheKey() : cacheKey;
|
|
178
|
+
return key;
|
|
179
|
+
};
|
|
180
|
+
const {
|
|
181
|
+
loading,
|
|
182
|
+
data,
|
|
183
|
+
error,
|
|
184
|
+
params,
|
|
185
|
+
run,
|
|
186
|
+
mutate,
|
|
187
|
+
cancel,
|
|
188
|
+
refresh,
|
|
189
|
+
disabled
|
|
190
|
+
} = useRequest(key => service(key), {
|
|
191
|
+
manual,
|
|
192
|
+
defaultParams: manual ? [] : [getKey()],
|
|
193
|
+
...requestOptions
|
|
194
|
+
});
|
|
195
|
+
const updateCache = newData => {
|
|
196
|
+
const key = getKey();
|
|
197
|
+
if (key) {
|
|
198
|
+
setCacheFn(key, newData);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
(0, _vue.watch)(() => data.value, newData => {
|
|
202
|
+
if (newData !== void 0) {
|
|
203
|
+
updateCache(newData);
|
|
204
|
+
}
|
|
205
|
+
}, {
|
|
206
|
+
immediate: true
|
|
207
|
+
});
|
|
208
|
+
if (refreshOnWindowFocus && !manual) {
|
|
209
|
+
(0, _vue.onMounted)(() => {
|
|
210
|
+
const handleFocus = () => {
|
|
211
|
+
const key = getKey();
|
|
212
|
+
if (key && !loading.value) {
|
|
213
|
+
refresh();
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
window.addEventListener("visibilitychange", handleFocus);
|
|
217
|
+
window.addEventListener("focus", handleFocus);
|
|
218
|
+
(0, _vue.onUnmounted)(() => {
|
|
219
|
+
window.removeEventListener("visibilitychange", handleFocus);
|
|
220
|
+
window.removeEventListener("focus", handleFocus);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
if (refreshDeps && refreshDeps.length > 0 && !manual) {
|
|
225
|
+
(0, _vue.watch)(() => refreshDeps.map(dep => dep.value), () => {
|
|
226
|
+
const key = getKey();
|
|
227
|
+
if (key) {
|
|
228
|
+
setTimeout(() => run(key).catch(() => {}), refreshDepsWait);
|
|
229
|
+
}
|
|
230
|
+
}, {
|
|
231
|
+
deep: true
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
loading,
|
|
236
|
+
data,
|
|
237
|
+
error,
|
|
238
|
+
params,
|
|
239
|
+
loadingMore: (0, _vue.ref)(false),
|
|
240
|
+
noMore: (0, _vue.ref)(false),
|
|
241
|
+
run,
|
|
242
|
+
mutate,
|
|
243
|
+
cancel,
|
|
244
|
+
refresh,
|
|
245
|
+
loadMore: async () => {
|
|
246
|
+
return Promise.resolve();
|
|
247
|
+
},
|
|
248
|
+
disabled
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
function useRequestPolling(service, options = {}) {
|
|
252
|
+
const {
|
|
253
|
+
polling = false,
|
|
254
|
+
pollingInterval = 3e3,
|
|
255
|
+
pollingWhenHidden = false,
|
|
256
|
+
...requestOptions
|
|
257
|
+
} = options;
|
|
258
|
+
const {
|
|
259
|
+
loading,
|
|
260
|
+
data,
|
|
261
|
+
error,
|
|
262
|
+
params,
|
|
263
|
+
loadingMore,
|
|
264
|
+
noMore,
|
|
265
|
+
run,
|
|
266
|
+
mutate,
|
|
267
|
+
cancel,
|
|
268
|
+
refresh,
|
|
269
|
+
loadMore,
|
|
270
|
+
disabled
|
|
271
|
+
} = useRequest(service, {
|
|
272
|
+
manual: true,
|
|
273
|
+
...requestOptions
|
|
274
|
+
});
|
|
275
|
+
const isPolling = (0, _vue.ref)(false);
|
|
276
|
+
const pollingTimer = (0, _vue.ref)(null);
|
|
277
|
+
const startPolling = () => {
|
|
278
|
+
if (pollingTimer.value) return;
|
|
279
|
+
isPolling.value = true;
|
|
280
|
+
run(...params.value).catch(() => {});
|
|
281
|
+
pollingTimer.value = setInterval(() => {
|
|
282
|
+
if (!pollingWhenHidden && document.hidden) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
run(...params.value).catch(() => {});
|
|
286
|
+
}, pollingInterval);
|
|
287
|
+
};
|
|
288
|
+
const pause = () => {
|
|
289
|
+
if (pollingTimer.value) {
|
|
290
|
+
clearInterval(pollingTimer.value);
|
|
291
|
+
pollingTimer.value = null;
|
|
292
|
+
}
|
|
293
|
+
isPolling.value = false;
|
|
294
|
+
};
|
|
295
|
+
const resume = () => {
|
|
296
|
+
if (polling && !pollingTimer.value) {
|
|
297
|
+
startPolling();
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
(0, _vue.onUnmounted)(() => {
|
|
301
|
+
pause();
|
|
302
|
+
cancel();
|
|
303
|
+
});
|
|
304
|
+
if (polling) {
|
|
305
|
+
(0, _vue.onMounted)(() => {
|
|
306
|
+
startPolling();
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
loading,
|
|
311
|
+
data,
|
|
312
|
+
error,
|
|
313
|
+
params,
|
|
314
|
+
loadingMore,
|
|
315
|
+
noMore,
|
|
316
|
+
run,
|
|
317
|
+
mutate,
|
|
318
|
+
cancel,
|
|
319
|
+
refresh,
|
|
320
|
+
loadMore,
|
|
321
|
+
disabled,
|
|
322
|
+
pause,
|
|
323
|
+
resume
|
|
324
|
+
};
|
|
325
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { type Ref, type ComputedRef, type ShallowRef } from 'vue';
|
|
2
|
+
import { type RequestOptions, type RequestResponse, type RequestError } from './types';
|
|
3
|
+
import { Request } from './request';
|
|
4
|
+
/** 请求 Hook 配置 */
|
|
5
|
+
export interface UseRequestOptions<TData, TParams extends unknown[] = unknown[]> extends RequestOptions {
|
|
6
|
+
/** 手动触发 */
|
|
7
|
+
manual?: boolean;
|
|
8
|
+
/** 默认参数 */
|
|
9
|
+
defaultParams?: TParams;
|
|
10
|
+
/** 防抖等待时间 (ms) */
|
|
11
|
+
debounceWait?: number;
|
|
12
|
+
/** 节流等待时间 (ms) */
|
|
13
|
+
throttleWait?: number;
|
|
14
|
+
/** 请求实例 */
|
|
15
|
+
request?: Request;
|
|
16
|
+
/** 请求函数 */
|
|
17
|
+
service?: (...args: TParams) => Promise<RequestResponse<TData>>;
|
|
18
|
+
/** 格式化返回数据 */
|
|
19
|
+
formatResult?: (response: RequestResponse<TData>) => TData;
|
|
20
|
+
/** 成功回调 */
|
|
21
|
+
onSuccess?: (data: TData, params: TParams) => void;
|
|
22
|
+
/** 错误回调 */
|
|
23
|
+
onError?: (error: RequestError, params: TParams) => void;
|
|
24
|
+
/** 完成回调 */
|
|
25
|
+
onFinally?: (params: TParams) => void;
|
|
26
|
+
}
|
|
27
|
+
/** SWR 配置 */
|
|
28
|
+
export interface UseRequestSWROptions<TData, TParams extends unknown[]> extends UseRequestOptions<TData, TParams> {
|
|
29
|
+
/** SWR 模式 */
|
|
30
|
+
swr?: boolean;
|
|
31
|
+
/** 缓存 key */
|
|
32
|
+
cacheKey?: string;
|
|
33
|
+
/** 缓存数据过期时间 (ms) */
|
|
34
|
+
staleTime?: number;
|
|
35
|
+
/** 缓存数据存活时间 (ms) */
|
|
36
|
+
cacheTime?: number;
|
|
37
|
+
/** 缓存数据 */
|
|
38
|
+
getCache?: (key: string) => TData | undefined;
|
|
39
|
+
/** 设置缓存 */
|
|
40
|
+
setCache?: (key: string, value: TData) => void;
|
|
41
|
+
/** 窗口聚焦重新请求 */
|
|
42
|
+
refreshOnWindowFocus?: boolean;
|
|
43
|
+
/** 重新请求防抖等待 (ms) */
|
|
44
|
+
refreshDepsWait?: number;
|
|
45
|
+
/** 依赖变化时重新请求 */
|
|
46
|
+
refreshDeps?: Ref<unknown>[];
|
|
47
|
+
}
|
|
48
|
+
/** 轮询配置 */
|
|
49
|
+
export interface UseRequestPollingOptions<TData, TParams extends unknown[]> extends UseRequestOptions<TData, TParams> {
|
|
50
|
+
/** 轮询模式 */
|
|
51
|
+
polling?: boolean;
|
|
52
|
+
/** 轮询间隔 (ms) */
|
|
53
|
+
pollingInterval?: number;
|
|
54
|
+
/** 轮询在页面隐藏时暂停 */
|
|
55
|
+
pollingWhenHidden?: boolean;
|
|
56
|
+
}
|
|
57
|
+
/** 请求状态 */
|
|
58
|
+
export interface UseRequestState<TData, TParams extends unknown[]> {
|
|
59
|
+
/** 加载状态 */
|
|
60
|
+
loading: Ref<boolean>;
|
|
61
|
+
/** 数据 */
|
|
62
|
+
data: ShallowRef<TData | undefined>;
|
|
63
|
+
/** 错误 */
|
|
64
|
+
error: ShallowRef<RequestError | undefined>;
|
|
65
|
+
/** 请求参数 */
|
|
66
|
+
params: Ref<TParams>;
|
|
67
|
+
/** 是否网络忙 */
|
|
68
|
+
loadingMore: Ref<boolean>;
|
|
69
|
+
/** 是否没有更多 */
|
|
70
|
+
noMore: Ref<boolean>;
|
|
71
|
+
}
|
|
72
|
+
/** 请求返回类型 */
|
|
73
|
+
export interface UseRequestReturn<TData, TParams extends unknown[]> extends UseRequestState<TData, TParams> {
|
|
74
|
+
/** 执行请求 */
|
|
75
|
+
run: (...params: TParams) => Promise<RequestResponse<TData>>;
|
|
76
|
+
/** 手动修改数据 */
|
|
77
|
+
mutate: (newData?: TData | ((oldData?: TData) => TData)) => void;
|
|
78
|
+
/** 取消请求 */
|
|
79
|
+
cancel: () => void;
|
|
80
|
+
/** 刷新请求 */
|
|
81
|
+
refresh: () => Promise<void>;
|
|
82
|
+
/** 加载更多 */
|
|
83
|
+
loadMore: () => Promise<void>;
|
|
84
|
+
/** 按钮禁用状态 */
|
|
85
|
+
disabled: ComputedRef<boolean>;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* useRequest - 强大的请求 Hook
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* const { data, loading, error, run, refresh, cancel } = useRequest(
|
|
92
|
+
* (id) => request.get(`/api/user/${id}`),
|
|
93
|
+
* {
|
|
94
|
+
* manual: false,
|
|
95
|
+
* defaultParams: [1],
|
|
96
|
+
* onSuccess: (data) => console.log(data),
|
|
97
|
+
* }
|
|
98
|
+
* )
|
|
99
|
+
*/
|
|
100
|
+
export declare function useRequest<TData = unknown, TParams extends unknown[] = unknown[]>(service: (...args: TParams) => Promise<RequestResponse<TData>>, options?: UseRequestOptions<TData, TParams>): UseRequestReturn<TData, TParams>;
|
|
101
|
+
/**
|
|
102
|
+
* useRequestSWR - 带 SWR 缓存的请求 Hook
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* const { data, loading } = useRequestSWR(
|
|
106
|
+
* () => `/api/user/${id.value}`,
|
|
107
|
+
* (url) => request.get(url),
|
|
108
|
+
* { cacheKey: 'user' }
|
|
109
|
+
* )
|
|
110
|
+
*/
|
|
111
|
+
export declare function useRequestSWR<TData = unknown>(cacheKey: string | (() => string), service: (key: string) => Promise<RequestResponse<TData>>, options?: UseRequestSWROptions<TData, [string]>): UseRequestReturn<TData, [string]>;
|
|
112
|
+
/**
|
|
113
|
+
* useRequestPolling - 带轮询的请求 Hook
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* const { data, pause, resume } = useRequestPolling(
|
|
117
|
+
* () => request.get('/api/status'),
|
|
118
|
+
* { pollingInterval: 5000 }
|
|
119
|
+
* )
|
|
120
|
+
*/
|
|
121
|
+
export declare function useRequestPolling<TData = unknown, TParams extends unknown[] = unknown[]>(service: (...args: TParams) => Promise<RequestResponse<TData>>, options?: UseRequestPollingOptions<TData, TParams>): UseRequestReturn<TData, TParams> & {
|
|
122
|
+
/** 暂停轮询 */
|
|
123
|
+
pause: () => void;
|
|
124
|
+
/** 恢复轮询 */
|
|
125
|
+
resume: () => void;
|
|
126
|
+
};
|