@rjgfny/utils 0.1.0
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/README.md +83 -0
- package/dist/index.cjs +373 -0
- package/dist/index.d.cts +149 -0
- package/dist/index.d.ts +149 -0
- package/dist/index.js +326 -0
- package/package.json +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# rjgfNY Utils
|
|
2
|
+
|
|
3
|
+
以 `D:\rjgfCode\rjgfNYUtils` 为根目录的通用工具库,聚焦:
|
|
4
|
+
|
|
5
|
+
- HTTP 请求封装
|
|
6
|
+
- 浏览器存储封装
|
|
7
|
+
- 权限能力封装
|
|
8
|
+
- 视频/图表/地图领域封装
|
|
9
|
+
- WebSocket 通信封装(重连 + 心跳)
|
|
10
|
+
|
|
11
|
+
## 安装
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm install
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 构建
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pnpm run build
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 测试
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm run test
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## HTTP(axios 适配器)
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { createAxiosAdapter, createHttpClient } from "@rjgfny/utils";
|
|
33
|
+
import axios from "axios";
|
|
34
|
+
|
|
35
|
+
const axiosInstance = axios.create({ baseURL: "/api", timeout: 10000 });
|
|
36
|
+
const adapter = createAxiosAdapter({
|
|
37
|
+
axiosInstance,
|
|
38
|
+
requestHooks: [
|
|
39
|
+
(config) => {
|
|
40
|
+
config.headers.Authorization = "Bearer token";
|
|
41
|
+
return config;
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
responseHooks: [
|
|
45
|
+
(payload: any) => ({ ...payload, hooked: true }),
|
|
46
|
+
],
|
|
47
|
+
business: {
|
|
48
|
+
successCode: 0,
|
|
49
|
+
getCode: (res: any) => res.code,
|
|
50
|
+
getMessage: (res: any) => res.message,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const http = createHttpClient({}, adapter);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## WebSocket
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { createWebSocketClient } from "@rjgfny/utils";
|
|
61
|
+
|
|
62
|
+
const ws = createWebSocketClient({
|
|
63
|
+
url: "wss://echo.websocket.events",
|
|
64
|
+
reconnect: true,
|
|
65
|
+
heartbeatInterval: 10000,
|
|
66
|
+
});
|
|
67
|
+
ws.onMessage((event) => console.log("ws message:", event.data));
|
|
68
|
+
ws.connect();
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 用法
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import {
|
|
75
|
+
createHttpClient,
|
|
76
|
+
createTokenStorage,
|
|
77
|
+
createPermissionGuard,
|
|
78
|
+
createVideoSourceResolver,
|
|
79
|
+
createChartThemeManager,
|
|
80
|
+
createMapLayerManager,
|
|
81
|
+
} from "@rjgfny/utils";
|
|
82
|
+
```
|
|
83
|
+
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
buildEChartsBaseOption: () => buildEChartsBaseOption,
|
|
34
|
+
createAxiosAdapter: () => createAxiosAdapter,
|
|
35
|
+
createChartThemeManager: () => createChartThemeManager,
|
|
36
|
+
createHttpClient: () => createHttpClient,
|
|
37
|
+
createHttpError: () => createHttpError,
|
|
38
|
+
createJSONStorage: () => createJSONStorage,
|
|
39
|
+
createMapLayerManager: () => createMapLayerManager,
|
|
40
|
+
createPermissionGuard: () => createPermissionGuard,
|
|
41
|
+
createTokenStorage: () => createTokenStorage,
|
|
42
|
+
createVideoSourceResolver: () => createVideoSourceResolver,
|
|
43
|
+
createWebSocketClient: () => createWebSocketClient
|
|
44
|
+
});
|
|
45
|
+
module.exports = __toCommonJS(index_exports);
|
|
46
|
+
|
|
47
|
+
// src/http/client.ts
|
|
48
|
+
function buildQuery(params) {
|
|
49
|
+
if (!params) return "";
|
|
50
|
+
const query = new URLSearchParams();
|
|
51
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
52
|
+
if (value !== void 0 && value !== null) query.append(key, String(value));
|
|
53
|
+
});
|
|
54
|
+
const text = query.toString();
|
|
55
|
+
return text ? `?${text}` : "";
|
|
56
|
+
}
|
|
57
|
+
function createFetchAdapter(config = {}) {
|
|
58
|
+
return {
|
|
59
|
+
async request(options) {
|
|
60
|
+
const { method, url, params, data } = options;
|
|
61
|
+
const finalUrl = `${config.baseURL ?? ""}${url}${buildQuery(params)}`;
|
|
62
|
+
const res = await fetch(finalUrl, {
|
|
63
|
+
method,
|
|
64
|
+
headers: {
|
|
65
|
+
"Content-Type": "application/json",
|
|
66
|
+
...config.headers ?? {}
|
|
67
|
+
},
|
|
68
|
+
body: data === void 0 ? void 0 : JSON.stringify(data)
|
|
69
|
+
});
|
|
70
|
+
if (!res.ok) {
|
|
71
|
+
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
72
|
+
}
|
|
73
|
+
return await res.json();
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function createHttpError(message, payload) {
|
|
78
|
+
const err = new Error(message);
|
|
79
|
+
err.code = payload?.code;
|
|
80
|
+
err.status = payload?.status;
|
|
81
|
+
err.raw = payload?.raw;
|
|
82
|
+
return err;
|
|
83
|
+
}
|
|
84
|
+
function normalizeBusinessResponse(response, business) {
|
|
85
|
+
if (!business || !business.getCode) return response;
|
|
86
|
+
const successCode = business.successCode ?? 0;
|
|
87
|
+
const code = business.getCode(response);
|
|
88
|
+
if (code !== void 0 && code !== successCode) {
|
|
89
|
+
throw createHttpError(
|
|
90
|
+
business.getMessage?.(response) ?? "Business code is not success",
|
|
91
|
+
{ code, raw: response }
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return response;
|
|
95
|
+
}
|
|
96
|
+
function createHttpClient(config = {}, adapter, business) {
|
|
97
|
+
const realAdapter = adapter ?? createFetchAdapter(config);
|
|
98
|
+
return {
|
|
99
|
+
get: async (url, params) => normalizeBusinessResponse(
|
|
100
|
+
await realAdapter.request({ method: "GET", url, params }),
|
|
101
|
+
business
|
|
102
|
+
),
|
|
103
|
+
post: async (url, data) => normalizeBusinessResponse(
|
|
104
|
+
await realAdapter.request({ method: "POST", url, data }),
|
|
105
|
+
business
|
|
106
|
+
),
|
|
107
|
+
put: async (url, data) => normalizeBusinessResponse(
|
|
108
|
+
await realAdapter.request({ method: "PUT", url, data }),
|
|
109
|
+
business
|
|
110
|
+
),
|
|
111
|
+
delete: async (url) => normalizeBusinessResponse(
|
|
112
|
+
await realAdapter.request({ method: "DELETE", url }),
|
|
113
|
+
business
|
|
114
|
+
)
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/http/axios-adapter.ts
|
|
119
|
+
var import_axios = __toESM(require("axios"), 1);
|
|
120
|
+
function createAxiosAdapter(options = {}) {
|
|
121
|
+
const instance = options.axiosInstance ?? import_axios.default.create(options.axiosConfig ?? {});
|
|
122
|
+
instance.interceptors.request.use(async (config) => {
|
|
123
|
+
let next = config;
|
|
124
|
+
for (const hook of options.requestHooks ?? []) {
|
|
125
|
+
next = await hook(next);
|
|
126
|
+
}
|
|
127
|
+
return next;
|
|
128
|
+
});
|
|
129
|
+
instance.interceptors.response.use(
|
|
130
|
+
(response) => response,
|
|
131
|
+
async (error) => {
|
|
132
|
+
for (const hook of options.errorHooks ?? []) {
|
|
133
|
+
await hook(error);
|
|
134
|
+
}
|
|
135
|
+
const status = error.response?.status;
|
|
136
|
+
const msg = error.message || "Network request failed";
|
|
137
|
+
return Promise.reject(
|
|
138
|
+
createHttpError(msg, {
|
|
139
|
+
status,
|
|
140
|
+
raw: error.response?.data ?? error
|
|
141
|
+
})
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
return {
|
|
146
|
+
async request(requestOptions) {
|
|
147
|
+
const { method, url, params, data } = requestOptions;
|
|
148
|
+
const response = await instance.request({
|
|
149
|
+
method,
|
|
150
|
+
url,
|
|
151
|
+
params,
|
|
152
|
+
data
|
|
153
|
+
});
|
|
154
|
+
let payload = options.unwrapData ?? true ? response.data : response;
|
|
155
|
+
for (const hook of options.responseHooks ?? []) {
|
|
156
|
+
payload = await hook(
|
|
157
|
+
payload,
|
|
158
|
+
response
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
if (options.business?.getCode) {
|
|
162
|
+
const businessPayload = payload;
|
|
163
|
+
const code = options.business.getCode(businessPayload);
|
|
164
|
+
const successCode = options.business.successCode ?? 0;
|
|
165
|
+
if (code !== void 0 && code !== successCode) {
|
|
166
|
+
throw createHttpError(
|
|
167
|
+
options.business.getMessage?.(businessPayload) ?? "Business code is not success",
|
|
168
|
+
{ code, raw: businessPayload }
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return payload;
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/storage/index.ts
|
|
178
|
+
function createTokenStorage(key = "access_token", storage = localStorage) {
|
|
179
|
+
return {
|
|
180
|
+
getToken: () => storage.getItem(key),
|
|
181
|
+
setToken: (token) => storage.setItem(key, token),
|
|
182
|
+
clearToken: () => storage.removeItem(key)
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function createJSONStorage(storage = localStorage) {
|
|
186
|
+
return {
|
|
187
|
+
set(key, value) {
|
|
188
|
+
storage.setItem(key, JSON.stringify(value));
|
|
189
|
+
},
|
|
190
|
+
get(key) {
|
|
191
|
+
const raw = storage.getItem(key);
|
|
192
|
+
if (!raw) return null;
|
|
193
|
+
try {
|
|
194
|
+
return JSON.parse(raw);
|
|
195
|
+
} catch {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
remove(key) {
|
|
200
|
+
storage.removeItem(key);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/auth/index.ts
|
|
206
|
+
function createPermissionGuard(state) {
|
|
207
|
+
return {
|
|
208
|
+
hasRole(role) {
|
|
209
|
+
return state.roles.includes(role);
|
|
210
|
+
},
|
|
211
|
+
hasPermission(permission) {
|
|
212
|
+
return state.permissions.includes(permission);
|
|
213
|
+
},
|
|
214
|
+
canAny(permissions) {
|
|
215
|
+
return permissions.some((p) => state.permissions.includes(p));
|
|
216
|
+
},
|
|
217
|
+
canAll(permissions) {
|
|
218
|
+
return permissions.every((p) => state.permissions.includes(p));
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/video/index.ts
|
|
224
|
+
function createVideoSourceResolver() {
|
|
225
|
+
return {
|
|
226
|
+
resolve(url) {
|
|
227
|
+
const lower = url.toLowerCase();
|
|
228
|
+
if (lower.endsWith(".flv")) return { url, protocol: "flv" };
|
|
229
|
+
if (lower.endsWith(".m3u8")) return { url, protocol: "hls" };
|
|
230
|
+
return { url, protocol: "mp4" };
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/chart/index.ts
|
|
236
|
+
function createChartThemeManager(initial = "light") {
|
|
237
|
+
let current = initial;
|
|
238
|
+
return {
|
|
239
|
+
getTheme() {
|
|
240
|
+
return current;
|
|
241
|
+
},
|
|
242
|
+
setTheme(theme) {
|
|
243
|
+
current = theme;
|
|
244
|
+
},
|
|
245
|
+
toggleTheme() {
|
|
246
|
+
current = current === "light" ? "dark" : "light";
|
|
247
|
+
return current;
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
function buildEChartsBaseOption(title) {
|
|
252
|
+
return {
|
|
253
|
+
title: { text: title },
|
|
254
|
+
tooltip: { trigger: "axis" },
|
|
255
|
+
grid: { left: 12, right: 12, top: 48, bottom: 16, containLabel: true }
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// src/map/index.ts
|
|
260
|
+
function createMapLayerManager(initialLayers = []) {
|
|
261
|
+
const layers = [...initialLayers];
|
|
262
|
+
return {
|
|
263
|
+
list() {
|
|
264
|
+
return [...layers];
|
|
265
|
+
},
|
|
266
|
+
add(layer) {
|
|
267
|
+
if (layers.some((item) => item.id === layer.id)) return;
|
|
268
|
+
layers.push(layer);
|
|
269
|
+
},
|
|
270
|
+
remove(layerId) {
|
|
271
|
+
const idx = layers.findIndex((item) => item.id === layerId);
|
|
272
|
+
if (idx >= 0) layers.splice(idx, 1);
|
|
273
|
+
},
|
|
274
|
+
setVisible(layerId, visible) {
|
|
275
|
+
const target = layers.find((item) => item.id === layerId);
|
|
276
|
+
if (target) target.visible = visible;
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// src/websocket/index.ts
|
|
282
|
+
function createWebSocketClient(options) {
|
|
283
|
+
let ws = null;
|
|
284
|
+
let reconnectAttempts = 0;
|
|
285
|
+
let reconnectTimer = null;
|
|
286
|
+
let heartbeatTimer = null;
|
|
287
|
+
const onOpenHandlers = [];
|
|
288
|
+
const onMessageHandlers = [];
|
|
289
|
+
const onErrorHandlers = [];
|
|
290
|
+
const onCloseHandlers = [];
|
|
291
|
+
const clearTimers = () => {
|
|
292
|
+
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
293
|
+
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
294
|
+
reconnectTimer = null;
|
|
295
|
+
heartbeatTimer = null;
|
|
296
|
+
};
|
|
297
|
+
const startHeartbeat = () => {
|
|
298
|
+
const interval = options.heartbeatInterval ?? 0;
|
|
299
|
+
if (interval <= 0) return;
|
|
300
|
+
heartbeatTimer = setInterval(() => {
|
|
301
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
302
|
+
ws.send(options.heartbeatMessage ?? "ping");
|
|
303
|
+
}
|
|
304
|
+
}, interval);
|
|
305
|
+
};
|
|
306
|
+
const connect = () => {
|
|
307
|
+
clearTimers();
|
|
308
|
+
ws = options.createSocket ? options.createSocket(options.url, options.protocols) : new WebSocket(options.url, options.protocols);
|
|
309
|
+
ws.onopen = () => {
|
|
310
|
+
reconnectAttempts = 0;
|
|
311
|
+
startHeartbeat();
|
|
312
|
+
onOpenHandlers.forEach((fn) => fn());
|
|
313
|
+
};
|
|
314
|
+
ws.onmessage = (event) => onMessageHandlers.forEach((fn) => fn(event));
|
|
315
|
+
ws.onerror = (event) => onErrorHandlers.forEach((fn) => fn(event));
|
|
316
|
+
ws.onclose = (event) => {
|
|
317
|
+
clearTimers();
|
|
318
|
+
onCloseHandlers.forEach((fn) => fn(event));
|
|
319
|
+
const shouldReconnect = options.reconnect ?? true;
|
|
320
|
+
const max = options.maxReconnectAttempts ?? 5;
|
|
321
|
+
if (shouldReconnect && reconnectAttempts < max) {
|
|
322
|
+
reconnectAttempts += 1;
|
|
323
|
+
reconnectTimer = setTimeout(
|
|
324
|
+
connect,
|
|
325
|
+
options.reconnectInterval ?? 3e3
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
};
|
|
330
|
+
return {
|
|
331
|
+
connect,
|
|
332
|
+
disconnect(code = 1e3, reason = "manual close") {
|
|
333
|
+
clearTimers();
|
|
334
|
+
ws?.close(code, reason);
|
|
335
|
+
ws = null;
|
|
336
|
+
},
|
|
337
|
+
send(data) {
|
|
338
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
339
|
+
throw new Error("WebSocket is not open");
|
|
340
|
+
}
|
|
341
|
+
ws.send(data);
|
|
342
|
+
},
|
|
343
|
+
getStatus() {
|
|
344
|
+
return ws?.readyState ?? WebSocket.CLOSED;
|
|
345
|
+
},
|
|
346
|
+
onOpen(handler) {
|
|
347
|
+
onOpenHandlers.push(handler);
|
|
348
|
+
},
|
|
349
|
+
onMessage(handler) {
|
|
350
|
+
onMessageHandlers.push(handler);
|
|
351
|
+
},
|
|
352
|
+
onError(handler) {
|
|
353
|
+
onErrorHandlers.push(handler);
|
|
354
|
+
},
|
|
355
|
+
onClose(handler) {
|
|
356
|
+
onCloseHandlers.push(handler);
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
361
|
+
0 && (module.exports = {
|
|
362
|
+
buildEChartsBaseOption,
|
|
363
|
+
createAxiosAdapter,
|
|
364
|
+
createChartThemeManager,
|
|
365
|
+
createHttpClient,
|
|
366
|
+
createHttpError,
|
|
367
|
+
createJSONStorage,
|
|
368
|
+
createMapLayerManager,
|
|
369
|
+
createPermissionGuard,
|
|
370
|
+
createTokenStorage,
|
|
371
|
+
createVideoSourceResolver,
|
|
372
|
+
createWebSocketClient
|
|
373
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { AxiosInstance, AxiosRequestConfig, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
|
|
2
|
+
export { AxiosInstance, AxiosRequestConfig } from 'axios';
|
|
3
|
+
|
|
4
|
+
interface HttpRequestConfig {
|
|
5
|
+
baseURL?: string;
|
|
6
|
+
timeout?: number;
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
interface HttpBusinessConfig<T = unknown> {
|
|
10
|
+
successCode?: number | string;
|
|
11
|
+
getCode?: (response: T) => number | string | undefined;
|
|
12
|
+
getMessage?: (response: T) => string | undefined;
|
|
13
|
+
}
|
|
14
|
+
interface HttpError extends Error {
|
|
15
|
+
code?: number | string;
|
|
16
|
+
status?: number;
|
|
17
|
+
raw?: unknown;
|
|
18
|
+
}
|
|
19
|
+
interface HttpClient {
|
|
20
|
+
get<T = unknown>(url: string, params?: Record<string, unknown>): Promise<T>;
|
|
21
|
+
post<T = unknown>(url: string, data?: unknown): Promise<T>;
|
|
22
|
+
put<T = unknown>(url: string, data?: unknown): Promise<T>;
|
|
23
|
+
delete<T = unknown>(url: string): Promise<T>;
|
|
24
|
+
}
|
|
25
|
+
interface HttpRequestOptions {
|
|
26
|
+
method: "GET" | "POST" | "PUT" | "DELETE";
|
|
27
|
+
url: string;
|
|
28
|
+
params?: Record<string, unknown>;
|
|
29
|
+
data?: unknown;
|
|
30
|
+
}
|
|
31
|
+
interface HttpAdapter {
|
|
32
|
+
request<T = unknown>(options: HttpRequestOptions): Promise<T>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
declare function createHttpError(message: string, payload?: {
|
|
36
|
+
code?: number | string;
|
|
37
|
+
status?: number;
|
|
38
|
+
raw?: unknown;
|
|
39
|
+
}): HttpError;
|
|
40
|
+
declare function createHttpClient(config?: HttpRequestConfig, adapter?: HttpAdapter, business?: HttpBusinessConfig): HttpClient;
|
|
41
|
+
|
|
42
|
+
type AxiosRequestHook = (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>;
|
|
43
|
+
type AxiosResponseHook<T = unknown> = (payload: T, response: AxiosResponse<T>) => T | Promise<T>;
|
|
44
|
+
type AxiosErrorHook = (error: AxiosError | Error) => void | Promise<void>;
|
|
45
|
+
interface AxiosAdapterOptions<T = unknown> {
|
|
46
|
+
axiosInstance?: AxiosInstance;
|
|
47
|
+
axiosConfig?: AxiosRequestConfig;
|
|
48
|
+
business?: HttpBusinessConfig<T>;
|
|
49
|
+
unwrapData?: boolean;
|
|
50
|
+
requestHooks?: AxiosRequestHook[];
|
|
51
|
+
responseHooks?: AxiosResponseHook<T>[];
|
|
52
|
+
errorHooks?: AxiosErrorHook[];
|
|
53
|
+
}
|
|
54
|
+
declare function createAxiosAdapter<T = unknown>(options?: AxiosAdapterOptions<T>): HttpAdapter;
|
|
55
|
+
|
|
56
|
+
interface StorageLike {
|
|
57
|
+
getItem(key: string): string | null;
|
|
58
|
+
setItem(key: string, value: string): void;
|
|
59
|
+
removeItem(key: string): void;
|
|
60
|
+
}
|
|
61
|
+
interface TokenStorage {
|
|
62
|
+
getToken(): string | null;
|
|
63
|
+
setToken(token: string): void;
|
|
64
|
+
clearToken(): void;
|
|
65
|
+
}
|
|
66
|
+
declare function createTokenStorage(key?: string, storage?: StorageLike): TokenStorage;
|
|
67
|
+
declare function createJSONStorage(storage?: StorageLike): {
|
|
68
|
+
set<T>(key: string, value: T): void;
|
|
69
|
+
get<T>(key: string): T | null;
|
|
70
|
+
remove(key: string): void;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
interface UserPermissionState {
|
|
74
|
+
roles: string[];
|
|
75
|
+
permissions: string[];
|
|
76
|
+
}
|
|
77
|
+
declare function createPermissionGuard(state: UserPermissionState): {
|
|
78
|
+
hasRole(role: string): boolean;
|
|
79
|
+
hasPermission(permission: string): boolean;
|
|
80
|
+
canAny(permissions: string[]): boolean;
|
|
81
|
+
canAll(permissions: string[]): boolean;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
type VideoProtocol = "flv" | "hls" | "mp4";
|
|
85
|
+
interface VideoSource {
|
|
86
|
+
url: string;
|
|
87
|
+
protocol: VideoProtocol;
|
|
88
|
+
}
|
|
89
|
+
declare function createVideoSourceResolver(): {
|
|
90
|
+
resolve(url: string): VideoSource;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
type ChartTheme = "light" | "dark";
|
|
94
|
+
declare function createChartThemeManager(initial?: ChartTheme): {
|
|
95
|
+
getTheme(): ChartTheme;
|
|
96
|
+
setTheme(theme: ChartTheme): void;
|
|
97
|
+
toggleTheme(): ChartTheme;
|
|
98
|
+
};
|
|
99
|
+
declare function buildEChartsBaseOption(title: string): {
|
|
100
|
+
title: {
|
|
101
|
+
text: string;
|
|
102
|
+
};
|
|
103
|
+
tooltip: {
|
|
104
|
+
trigger: string;
|
|
105
|
+
};
|
|
106
|
+
grid: {
|
|
107
|
+
left: number;
|
|
108
|
+
right: number;
|
|
109
|
+
top: number;
|
|
110
|
+
bottom: number;
|
|
111
|
+
containLabel: boolean;
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
interface MapLayer {
|
|
116
|
+
id: string;
|
|
117
|
+
type: string;
|
|
118
|
+
visible?: boolean;
|
|
119
|
+
}
|
|
120
|
+
declare function createMapLayerManager(initialLayers?: MapLayer[]): {
|
|
121
|
+
list(): MapLayer[];
|
|
122
|
+
add(layer: MapLayer): void;
|
|
123
|
+
remove(layerId: string): void;
|
|
124
|
+
setVisible(layerId: string, visible: boolean): void;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
interface WebSocketClientOptions {
|
|
128
|
+
url: string;
|
|
129
|
+
protocols?: string | string[];
|
|
130
|
+
reconnect?: boolean;
|
|
131
|
+
reconnectInterval?: number;
|
|
132
|
+
maxReconnectAttempts?: number;
|
|
133
|
+
heartbeatInterval?: number;
|
|
134
|
+
heartbeatMessage?: string;
|
|
135
|
+
createSocket?: (url: string, protocols?: string | string[]) => WebSocket;
|
|
136
|
+
}
|
|
137
|
+
interface WebSocketClient {
|
|
138
|
+
connect(): void;
|
|
139
|
+
disconnect(code?: number, reason?: string): void;
|
|
140
|
+
send(data: string): void;
|
|
141
|
+
getStatus(): number;
|
|
142
|
+
onOpen(handler: () => void): void;
|
|
143
|
+
onMessage(handler: (event: MessageEvent) => void): void;
|
|
144
|
+
onError(handler: (event: Event) => void): void;
|
|
145
|
+
onClose(handler: (event: CloseEvent) => void): void;
|
|
146
|
+
}
|
|
147
|
+
declare function createWebSocketClient(options: WebSocketClientOptions): WebSocketClient;
|
|
148
|
+
|
|
149
|
+
export { type AxiosAdapterOptions, type AxiosErrorHook, type AxiosRequestHook, type AxiosResponseHook, type ChartTheme, type HttpAdapter, type HttpBusinessConfig, type HttpClient, type HttpError, type HttpRequestConfig, type HttpRequestOptions, type MapLayer, type StorageLike, type TokenStorage, type UserPermissionState, type VideoProtocol, type VideoSource, type WebSocketClient, type WebSocketClientOptions, buildEChartsBaseOption, createAxiosAdapter, createChartThemeManager, createHttpClient, createHttpError, createJSONStorage, createMapLayerManager, createPermissionGuard, createTokenStorage, createVideoSourceResolver, createWebSocketClient };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { AxiosInstance, AxiosRequestConfig, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
|
|
2
|
+
export { AxiosInstance, AxiosRequestConfig } from 'axios';
|
|
3
|
+
|
|
4
|
+
interface HttpRequestConfig {
|
|
5
|
+
baseURL?: string;
|
|
6
|
+
timeout?: number;
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
interface HttpBusinessConfig<T = unknown> {
|
|
10
|
+
successCode?: number | string;
|
|
11
|
+
getCode?: (response: T) => number | string | undefined;
|
|
12
|
+
getMessage?: (response: T) => string | undefined;
|
|
13
|
+
}
|
|
14
|
+
interface HttpError extends Error {
|
|
15
|
+
code?: number | string;
|
|
16
|
+
status?: number;
|
|
17
|
+
raw?: unknown;
|
|
18
|
+
}
|
|
19
|
+
interface HttpClient {
|
|
20
|
+
get<T = unknown>(url: string, params?: Record<string, unknown>): Promise<T>;
|
|
21
|
+
post<T = unknown>(url: string, data?: unknown): Promise<T>;
|
|
22
|
+
put<T = unknown>(url: string, data?: unknown): Promise<T>;
|
|
23
|
+
delete<T = unknown>(url: string): Promise<T>;
|
|
24
|
+
}
|
|
25
|
+
interface HttpRequestOptions {
|
|
26
|
+
method: "GET" | "POST" | "PUT" | "DELETE";
|
|
27
|
+
url: string;
|
|
28
|
+
params?: Record<string, unknown>;
|
|
29
|
+
data?: unknown;
|
|
30
|
+
}
|
|
31
|
+
interface HttpAdapter {
|
|
32
|
+
request<T = unknown>(options: HttpRequestOptions): Promise<T>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
declare function createHttpError(message: string, payload?: {
|
|
36
|
+
code?: number | string;
|
|
37
|
+
status?: number;
|
|
38
|
+
raw?: unknown;
|
|
39
|
+
}): HttpError;
|
|
40
|
+
declare function createHttpClient(config?: HttpRequestConfig, adapter?: HttpAdapter, business?: HttpBusinessConfig): HttpClient;
|
|
41
|
+
|
|
42
|
+
type AxiosRequestHook = (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>;
|
|
43
|
+
type AxiosResponseHook<T = unknown> = (payload: T, response: AxiosResponse<T>) => T | Promise<T>;
|
|
44
|
+
type AxiosErrorHook = (error: AxiosError | Error) => void | Promise<void>;
|
|
45
|
+
interface AxiosAdapterOptions<T = unknown> {
|
|
46
|
+
axiosInstance?: AxiosInstance;
|
|
47
|
+
axiosConfig?: AxiosRequestConfig;
|
|
48
|
+
business?: HttpBusinessConfig<T>;
|
|
49
|
+
unwrapData?: boolean;
|
|
50
|
+
requestHooks?: AxiosRequestHook[];
|
|
51
|
+
responseHooks?: AxiosResponseHook<T>[];
|
|
52
|
+
errorHooks?: AxiosErrorHook[];
|
|
53
|
+
}
|
|
54
|
+
declare function createAxiosAdapter<T = unknown>(options?: AxiosAdapterOptions<T>): HttpAdapter;
|
|
55
|
+
|
|
56
|
+
interface StorageLike {
|
|
57
|
+
getItem(key: string): string | null;
|
|
58
|
+
setItem(key: string, value: string): void;
|
|
59
|
+
removeItem(key: string): void;
|
|
60
|
+
}
|
|
61
|
+
interface TokenStorage {
|
|
62
|
+
getToken(): string | null;
|
|
63
|
+
setToken(token: string): void;
|
|
64
|
+
clearToken(): void;
|
|
65
|
+
}
|
|
66
|
+
declare function createTokenStorage(key?: string, storage?: StorageLike): TokenStorage;
|
|
67
|
+
declare function createJSONStorage(storage?: StorageLike): {
|
|
68
|
+
set<T>(key: string, value: T): void;
|
|
69
|
+
get<T>(key: string): T | null;
|
|
70
|
+
remove(key: string): void;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
interface UserPermissionState {
|
|
74
|
+
roles: string[];
|
|
75
|
+
permissions: string[];
|
|
76
|
+
}
|
|
77
|
+
declare function createPermissionGuard(state: UserPermissionState): {
|
|
78
|
+
hasRole(role: string): boolean;
|
|
79
|
+
hasPermission(permission: string): boolean;
|
|
80
|
+
canAny(permissions: string[]): boolean;
|
|
81
|
+
canAll(permissions: string[]): boolean;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
type VideoProtocol = "flv" | "hls" | "mp4";
|
|
85
|
+
interface VideoSource {
|
|
86
|
+
url: string;
|
|
87
|
+
protocol: VideoProtocol;
|
|
88
|
+
}
|
|
89
|
+
declare function createVideoSourceResolver(): {
|
|
90
|
+
resolve(url: string): VideoSource;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
type ChartTheme = "light" | "dark";
|
|
94
|
+
declare function createChartThemeManager(initial?: ChartTheme): {
|
|
95
|
+
getTheme(): ChartTheme;
|
|
96
|
+
setTheme(theme: ChartTheme): void;
|
|
97
|
+
toggleTheme(): ChartTheme;
|
|
98
|
+
};
|
|
99
|
+
declare function buildEChartsBaseOption(title: string): {
|
|
100
|
+
title: {
|
|
101
|
+
text: string;
|
|
102
|
+
};
|
|
103
|
+
tooltip: {
|
|
104
|
+
trigger: string;
|
|
105
|
+
};
|
|
106
|
+
grid: {
|
|
107
|
+
left: number;
|
|
108
|
+
right: number;
|
|
109
|
+
top: number;
|
|
110
|
+
bottom: number;
|
|
111
|
+
containLabel: boolean;
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
interface MapLayer {
|
|
116
|
+
id: string;
|
|
117
|
+
type: string;
|
|
118
|
+
visible?: boolean;
|
|
119
|
+
}
|
|
120
|
+
declare function createMapLayerManager(initialLayers?: MapLayer[]): {
|
|
121
|
+
list(): MapLayer[];
|
|
122
|
+
add(layer: MapLayer): void;
|
|
123
|
+
remove(layerId: string): void;
|
|
124
|
+
setVisible(layerId: string, visible: boolean): void;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
interface WebSocketClientOptions {
|
|
128
|
+
url: string;
|
|
129
|
+
protocols?: string | string[];
|
|
130
|
+
reconnect?: boolean;
|
|
131
|
+
reconnectInterval?: number;
|
|
132
|
+
maxReconnectAttempts?: number;
|
|
133
|
+
heartbeatInterval?: number;
|
|
134
|
+
heartbeatMessage?: string;
|
|
135
|
+
createSocket?: (url: string, protocols?: string | string[]) => WebSocket;
|
|
136
|
+
}
|
|
137
|
+
interface WebSocketClient {
|
|
138
|
+
connect(): void;
|
|
139
|
+
disconnect(code?: number, reason?: string): void;
|
|
140
|
+
send(data: string): void;
|
|
141
|
+
getStatus(): number;
|
|
142
|
+
onOpen(handler: () => void): void;
|
|
143
|
+
onMessage(handler: (event: MessageEvent) => void): void;
|
|
144
|
+
onError(handler: (event: Event) => void): void;
|
|
145
|
+
onClose(handler: (event: CloseEvent) => void): void;
|
|
146
|
+
}
|
|
147
|
+
declare function createWebSocketClient(options: WebSocketClientOptions): WebSocketClient;
|
|
148
|
+
|
|
149
|
+
export { type AxiosAdapterOptions, type AxiosErrorHook, type AxiosRequestHook, type AxiosResponseHook, type ChartTheme, type HttpAdapter, type HttpBusinessConfig, type HttpClient, type HttpError, type HttpRequestConfig, type HttpRequestOptions, type MapLayer, type StorageLike, type TokenStorage, type UserPermissionState, type VideoProtocol, type VideoSource, type WebSocketClient, type WebSocketClientOptions, buildEChartsBaseOption, createAxiosAdapter, createChartThemeManager, createHttpClient, createHttpError, createJSONStorage, createMapLayerManager, createPermissionGuard, createTokenStorage, createVideoSourceResolver, createWebSocketClient };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
// src/http/client.ts
|
|
2
|
+
function buildQuery(params) {
|
|
3
|
+
if (!params) return "";
|
|
4
|
+
const query = new URLSearchParams();
|
|
5
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
6
|
+
if (value !== void 0 && value !== null) query.append(key, String(value));
|
|
7
|
+
});
|
|
8
|
+
const text = query.toString();
|
|
9
|
+
return text ? `?${text}` : "";
|
|
10
|
+
}
|
|
11
|
+
function createFetchAdapter(config = {}) {
|
|
12
|
+
return {
|
|
13
|
+
async request(options) {
|
|
14
|
+
const { method, url, params, data } = options;
|
|
15
|
+
const finalUrl = `${config.baseURL ?? ""}${url}${buildQuery(params)}`;
|
|
16
|
+
const res = await fetch(finalUrl, {
|
|
17
|
+
method,
|
|
18
|
+
headers: {
|
|
19
|
+
"Content-Type": "application/json",
|
|
20
|
+
...config.headers ?? {}
|
|
21
|
+
},
|
|
22
|
+
body: data === void 0 ? void 0 : JSON.stringify(data)
|
|
23
|
+
});
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
26
|
+
}
|
|
27
|
+
return await res.json();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function createHttpError(message, payload) {
|
|
32
|
+
const err = new Error(message);
|
|
33
|
+
err.code = payload?.code;
|
|
34
|
+
err.status = payload?.status;
|
|
35
|
+
err.raw = payload?.raw;
|
|
36
|
+
return err;
|
|
37
|
+
}
|
|
38
|
+
function normalizeBusinessResponse(response, business) {
|
|
39
|
+
if (!business || !business.getCode) return response;
|
|
40
|
+
const successCode = business.successCode ?? 0;
|
|
41
|
+
const code = business.getCode(response);
|
|
42
|
+
if (code !== void 0 && code !== successCode) {
|
|
43
|
+
throw createHttpError(
|
|
44
|
+
business.getMessage?.(response) ?? "Business code is not success",
|
|
45
|
+
{ code, raw: response }
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
return response;
|
|
49
|
+
}
|
|
50
|
+
function createHttpClient(config = {}, adapter, business) {
|
|
51
|
+
const realAdapter = adapter ?? createFetchAdapter(config);
|
|
52
|
+
return {
|
|
53
|
+
get: async (url, params) => normalizeBusinessResponse(
|
|
54
|
+
await realAdapter.request({ method: "GET", url, params }),
|
|
55
|
+
business
|
|
56
|
+
),
|
|
57
|
+
post: async (url, data) => normalizeBusinessResponse(
|
|
58
|
+
await realAdapter.request({ method: "POST", url, data }),
|
|
59
|
+
business
|
|
60
|
+
),
|
|
61
|
+
put: async (url, data) => normalizeBusinessResponse(
|
|
62
|
+
await realAdapter.request({ method: "PUT", url, data }),
|
|
63
|
+
business
|
|
64
|
+
),
|
|
65
|
+
delete: async (url) => normalizeBusinessResponse(
|
|
66
|
+
await realAdapter.request({ method: "DELETE", url }),
|
|
67
|
+
business
|
|
68
|
+
)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/http/axios-adapter.ts
|
|
73
|
+
import axios from "axios";
|
|
74
|
+
function createAxiosAdapter(options = {}) {
|
|
75
|
+
const instance = options.axiosInstance ?? axios.create(options.axiosConfig ?? {});
|
|
76
|
+
instance.interceptors.request.use(async (config) => {
|
|
77
|
+
let next = config;
|
|
78
|
+
for (const hook of options.requestHooks ?? []) {
|
|
79
|
+
next = await hook(next);
|
|
80
|
+
}
|
|
81
|
+
return next;
|
|
82
|
+
});
|
|
83
|
+
instance.interceptors.response.use(
|
|
84
|
+
(response) => response,
|
|
85
|
+
async (error) => {
|
|
86
|
+
for (const hook of options.errorHooks ?? []) {
|
|
87
|
+
await hook(error);
|
|
88
|
+
}
|
|
89
|
+
const status = error.response?.status;
|
|
90
|
+
const msg = error.message || "Network request failed";
|
|
91
|
+
return Promise.reject(
|
|
92
|
+
createHttpError(msg, {
|
|
93
|
+
status,
|
|
94
|
+
raw: error.response?.data ?? error
|
|
95
|
+
})
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
return {
|
|
100
|
+
async request(requestOptions) {
|
|
101
|
+
const { method, url, params, data } = requestOptions;
|
|
102
|
+
const response = await instance.request({
|
|
103
|
+
method,
|
|
104
|
+
url,
|
|
105
|
+
params,
|
|
106
|
+
data
|
|
107
|
+
});
|
|
108
|
+
let payload = options.unwrapData ?? true ? response.data : response;
|
|
109
|
+
for (const hook of options.responseHooks ?? []) {
|
|
110
|
+
payload = await hook(
|
|
111
|
+
payload,
|
|
112
|
+
response
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (options.business?.getCode) {
|
|
116
|
+
const businessPayload = payload;
|
|
117
|
+
const code = options.business.getCode(businessPayload);
|
|
118
|
+
const successCode = options.business.successCode ?? 0;
|
|
119
|
+
if (code !== void 0 && code !== successCode) {
|
|
120
|
+
throw createHttpError(
|
|
121
|
+
options.business.getMessage?.(businessPayload) ?? "Business code is not success",
|
|
122
|
+
{ code, raw: businessPayload }
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return payload;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/storage/index.ts
|
|
132
|
+
function createTokenStorage(key = "access_token", storage = localStorage) {
|
|
133
|
+
return {
|
|
134
|
+
getToken: () => storage.getItem(key),
|
|
135
|
+
setToken: (token) => storage.setItem(key, token),
|
|
136
|
+
clearToken: () => storage.removeItem(key)
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function createJSONStorage(storage = localStorage) {
|
|
140
|
+
return {
|
|
141
|
+
set(key, value) {
|
|
142
|
+
storage.setItem(key, JSON.stringify(value));
|
|
143
|
+
},
|
|
144
|
+
get(key) {
|
|
145
|
+
const raw = storage.getItem(key);
|
|
146
|
+
if (!raw) return null;
|
|
147
|
+
try {
|
|
148
|
+
return JSON.parse(raw);
|
|
149
|
+
} catch {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
remove(key) {
|
|
154
|
+
storage.removeItem(key);
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/auth/index.ts
|
|
160
|
+
function createPermissionGuard(state) {
|
|
161
|
+
return {
|
|
162
|
+
hasRole(role) {
|
|
163
|
+
return state.roles.includes(role);
|
|
164
|
+
},
|
|
165
|
+
hasPermission(permission) {
|
|
166
|
+
return state.permissions.includes(permission);
|
|
167
|
+
},
|
|
168
|
+
canAny(permissions) {
|
|
169
|
+
return permissions.some((p) => state.permissions.includes(p));
|
|
170
|
+
},
|
|
171
|
+
canAll(permissions) {
|
|
172
|
+
return permissions.every((p) => state.permissions.includes(p));
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/video/index.ts
|
|
178
|
+
function createVideoSourceResolver() {
|
|
179
|
+
return {
|
|
180
|
+
resolve(url) {
|
|
181
|
+
const lower = url.toLowerCase();
|
|
182
|
+
if (lower.endsWith(".flv")) return { url, protocol: "flv" };
|
|
183
|
+
if (lower.endsWith(".m3u8")) return { url, protocol: "hls" };
|
|
184
|
+
return { url, protocol: "mp4" };
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// src/chart/index.ts
|
|
190
|
+
function createChartThemeManager(initial = "light") {
|
|
191
|
+
let current = initial;
|
|
192
|
+
return {
|
|
193
|
+
getTheme() {
|
|
194
|
+
return current;
|
|
195
|
+
},
|
|
196
|
+
setTheme(theme) {
|
|
197
|
+
current = theme;
|
|
198
|
+
},
|
|
199
|
+
toggleTheme() {
|
|
200
|
+
current = current === "light" ? "dark" : "light";
|
|
201
|
+
return current;
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function buildEChartsBaseOption(title) {
|
|
206
|
+
return {
|
|
207
|
+
title: { text: title },
|
|
208
|
+
tooltip: { trigger: "axis" },
|
|
209
|
+
grid: { left: 12, right: 12, top: 48, bottom: 16, containLabel: true }
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// src/map/index.ts
|
|
214
|
+
function createMapLayerManager(initialLayers = []) {
|
|
215
|
+
const layers = [...initialLayers];
|
|
216
|
+
return {
|
|
217
|
+
list() {
|
|
218
|
+
return [...layers];
|
|
219
|
+
},
|
|
220
|
+
add(layer) {
|
|
221
|
+
if (layers.some((item) => item.id === layer.id)) return;
|
|
222
|
+
layers.push(layer);
|
|
223
|
+
},
|
|
224
|
+
remove(layerId) {
|
|
225
|
+
const idx = layers.findIndex((item) => item.id === layerId);
|
|
226
|
+
if (idx >= 0) layers.splice(idx, 1);
|
|
227
|
+
},
|
|
228
|
+
setVisible(layerId, visible) {
|
|
229
|
+
const target = layers.find((item) => item.id === layerId);
|
|
230
|
+
if (target) target.visible = visible;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/websocket/index.ts
|
|
236
|
+
function createWebSocketClient(options) {
|
|
237
|
+
let ws = null;
|
|
238
|
+
let reconnectAttempts = 0;
|
|
239
|
+
let reconnectTimer = null;
|
|
240
|
+
let heartbeatTimer = null;
|
|
241
|
+
const onOpenHandlers = [];
|
|
242
|
+
const onMessageHandlers = [];
|
|
243
|
+
const onErrorHandlers = [];
|
|
244
|
+
const onCloseHandlers = [];
|
|
245
|
+
const clearTimers = () => {
|
|
246
|
+
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
247
|
+
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
248
|
+
reconnectTimer = null;
|
|
249
|
+
heartbeatTimer = null;
|
|
250
|
+
};
|
|
251
|
+
const startHeartbeat = () => {
|
|
252
|
+
const interval = options.heartbeatInterval ?? 0;
|
|
253
|
+
if (interval <= 0) return;
|
|
254
|
+
heartbeatTimer = setInterval(() => {
|
|
255
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
256
|
+
ws.send(options.heartbeatMessage ?? "ping");
|
|
257
|
+
}
|
|
258
|
+
}, interval);
|
|
259
|
+
};
|
|
260
|
+
const connect = () => {
|
|
261
|
+
clearTimers();
|
|
262
|
+
ws = options.createSocket ? options.createSocket(options.url, options.protocols) : new WebSocket(options.url, options.protocols);
|
|
263
|
+
ws.onopen = () => {
|
|
264
|
+
reconnectAttempts = 0;
|
|
265
|
+
startHeartbeat();
|
|
266
|
+
onOpenHandlers.forEach((fn) => fn());
|
|
267
|
+
};
|
|
268
|
+
ws.onmessage = (event) => onMessageHandlers.forEach((fn) => fn(event));
|
|
269
|
+
ws.onerror = (event) => onErrorHandlers.forEach((fn) => fn(event));
|
|
270
|
+
ws.onclose = (event) => {
|
|
271
|
+
clearTimers();
|
|
272
|
+
onCloseHandlers.forEach((fn) => fn(event));
|
|
273
|
+
const shouldReconnect = options.reconnect ?? true;
|
|
274
|
+
const max = options.maxReconnectAttempts ?? 5;
|
|
275
|
+
if (shouldReconnect && reconnectAttempts < max) {
|
|
276
|
+
reconnectAttempts += 1;
|
|
277
|
+
reconnectTimer = setTimeout(
|
|
278
|
+
connect,
|
|
279
|
+
options.reconnectInterval ?? 3e3
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
};
|
|
284
|
+
return {
|
|
285
|
+
connect,
|
|
286
|
+
disconnect(code = 1e3, reason = "manual close") {
|
|
287
|
+
clearTimers();
|
|
288
|
+
ws?.close(code, reason);
|
|
289
|
+
ws = null;
|
|
290
|
+
},
|
|
291
|
+
send(data) {
|
|
292
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
293
|
+
throw new Error("WebSocket is not open");
|
|
294
|
+
}
|
|
295
|
+
ws.send(data);
|
|
296
|
+
},
|
|
297
|
+
getStatus() {
|
|
298
|
+
return ws?.readyState ?? WebSocket.CLOSED;
|
|
299
|
+
},
|
|
300
|
+
onOpen(handler) {
|
|
301
|
+
onOpenHandlers.push(handler);
|
|
302
|
+
},
|
|
303
|
+
onMessage(handler) {
|
|
304
|
+
onMessageHandlers.push(handler);
|
|
305
|
+
},
|
|
306
|
+
onError(handler) {
|
|
307
|
+
onErrorHandlers.push(handler);
|
|
308
|
+
},
|
|
309
|
+
onClose(handler) {
|
|
310
|
+
onCloseHandlers.push(handler);
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
export {
|
|
315
|
+
buildEChartsBaseOption,
|
|
316
|
+
createAxiosAdapter,
|
|
317
|
+
createChartThemeManager,
|
|
318
|
+
createHttpClient,
|
|
319
|
+
createHttpError,
|
|
320
|
+
createJSONStorage,
|
|
321
|
+
createMapLayerManager,
|
|
322
|
+
createPermissionGuard,
|
|
323
|
+
createTokenStorage,
|
|
324
|
+
createVideoSourceResolver,
|
|
325
|
+
createWebSocketClient
|
|
326
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rjgfny/utils",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "rjgfNY 通用工具库(HTTP、存储、权限、视频/图表/地图)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup src/index.ts --format esm,cjs --dts --clean",
|
|
22
|
+
"dev": "tsup src/index.ts --format esm,cjs --dts --watch",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"test": "vitest run",
|
|
25
|
+
"test:watch": "vitest",
|
|
26
|
+
"prepublishOnly": "pnpm run build && pnpm run test"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"utils",
|
|
30
|
+
"http",
|
|
31
|
+
"storage",
|
|
32
|
+
"auth",
|
|
33
|
+
"video",
|
|
34
|
+
"chart",
|
|
35
|
+
"map"
|
|
36
|
+
],
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public",
|
|
40
|
+
"registry": "https://registry.npmjs.org/"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"tsup": "^8.2.4",
|
|
44
|
+
"typescript": "^5.6.3",
|
|
45
|
+
"vitest": "^2.1.8"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"axios": "^1.8.2"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"echarts": ">=5.5.0",
|
|
52
|
+
"video.js": ">=8.0.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependenciesMeta": {
|
|
55
|
+
"echarts": {
|
|
56
|
+
"optional": true
|
|
57
|
+
},
|
|
58
|
+
"video.js": {
|
|
59
|
+
"optional": true
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|