dzkcc-mflow 0.0.18 → 0.0.20
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 +94 -11
- package/dist/App.d.ts +2 -2
- package/dist/App.js +3 -1
- package/dist/core/Api.d.ts +15 -0
- package/dist/core/Core.d.ts +2 -1
- package/dist/core/Core.js +4 -0
- package/dist/core/ICocosResManager.d.ts +2 -2
- package/dist/libs/BaseView.js +1 -2
- package/dist/libs/CocosCore.js +2 -0
- package/dist/libs/HttpManager.d.ts +72 -0
- package/dist/libs/HttpManager.js +278 -0
- package/dist/libs/ResLoader.d.ts +2 -2
- package/dist/libs/ResLoader.js +24 -14
- package/dist/libs/UIManager.js +13 -1
- package/dist/libs/index.d.ts +1 -0
- package/dist/libs/index.js +1 -0
- package/dist/mflow-tools.zip +0 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ Cocos模块化流程框架(Modular Flow Framework)是一个为Cocos Creator
|
|
|
12
12
|
- **UI管理系统**:完整的UI界面管理方案
|
|
13
13
|
- **事件系统**:强大的事件广播和监听机制
|
|
14
14
|
- **资源加载系统**:统一的资源加载和释放管理
|
|
15
|
+
- **HTTP网络请求系统**:简洁易用的HTTP客户端
|
|
15
16
|
- **开发工具**:配套的Cocos Creator编辑器插件
|
|
16
17
|
|
|
17
18
|
### 1.3 安装说明
|
|
@@ -176,7 +177,87 @@ const spineData = await mf.res.loadSpine(spineComponent, 'path/to/spine');
|
|
|
176
177
|
mf.res.release('path/to/asset');
|
|
177
178
|
```
|
|
178
179
|
|
|
179
|
-
## 6.
|
|
180
|
+
## 6. HTTP网络请求系统
|
|
181
|
+
|
|
182
|
+
### 6.1 HttpManager HTTP管理器
|
|
183
|
+
|
|
184
|
+
HttpManager提供了简洁易用的HTTP客户端功能,支持常见的HTTP方法:
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
// GET 请求
|
|
188
|
+
const userData = await mf.http.get('/api/users/123', { includeProfile: true });
|
|
189
|
+
|
|
190
|
+
// POST 请求
|
|
191
|
+
const newUser = await mf.http.post('/api/users', {
|
|
192
|
+
name: 'John',
|
|
193
|
+
email: 'john@example.com'
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// PUT 请求
|
|
197
|
+
const updatedUser = await mf.http.put('/api/users/123', {
|
|
198
|
+
name: 'John Doe'
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// DELETE 请求
|
|
202
|
+
await mf.http.delete('/api/users/123');
|
|
203
|
+
|
|
204
|
+
// 自定义请求
|
|
205
|
+
const result = await mf.http.request({
|
|
206
|
+
url: '/api/upload',
|
|
207
|
+
method: 'POST',
|
|
208
|
+
data: formData,
|
|
209
|
+
headers: {
|
|
210
|
+
'Authorization': 'Bearer token'
|
|
211
|
+
},
|
|
212
|
+
timeout: 30000
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 6.2 功能特性
|
|
217
|
+
|
|
218
|
+
1. **Promise-based API**:所有请求都返回Promise,支持async/await
|
|
219
|
+
2. **超时控制**:默认10秒超时,可自定义
|
|
220
|
+
3. **自动JSON解析**:自动解析JSON响应
|
|
221
|
+
4. **错误处理**:统一的错误处理机制
|
|
222
|
+
5. **请求拦截**:支持自定义请求头
|
|
223
|
+
6. **URL参数处理**:自动处理GET请求的查询参数
|
|
224
|
+
|
|
225
|
+
### 6.3 使用示例
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
// 在Manager中使用
|
|
229
|
+
@manager()
|
|
230
|
+
export class UserManager extends AbstractManager {
|
|
231
|
+
async getUserProfile(userId: string): Promise<any> {
|
|
232
|
+
try {
|
|
233
|
+
const profile = await mf.http.get(`/api/users/${userId}/profile`);
|
|
234
|
+
return profile;
|
|
235
|
+
} catch (error) {
|
|
236
|
+
console.error('Failed to fetch user profile:', error);
|
|
237
|
+
throw error;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async updateUser(userId: string, data: any): Promise<any> {
|
|
242
|
+
try {
|
|
243
|
+
const result = await mf.http.put(`/api/users/${userId}`, data, {
|
|
244
|
+
'Authorization': `Bearer ${this.getAuthToken()}`
|
|
245
|
+
});
|
|
246
|
+
return result;
|
|
247
|
+
} catch (error) {
|
|
248
|
+
console.error('Failed to update user:', error);
|
|
249
|
+
throw error;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private getAuthToken(): string {
|
|
254
|
+
// 获取认证令牌的逻辑
|
|
255
|
+
return 'your-auth-token';
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## 7. 开发工具
|
|
180
261
|
|
|
181
262
|
框架配套了Cocos Creator编辑器插件`mflow-tools`,可以:
|
|
182
263
|
|
|
@@ -184,7 +265,7 @@ mf.res.release('path/to/asset');
|
|
|
184
265
|
2. 自动引用Prefab上需要操作的元素
|
|
185
266
|
3. 自动挂载脚本组件
|
|
186
267
|
|
|
187
|
-
###
|
|
268
|
+
### 7.1 使用方法
|
|
188
269
|
|
|
189
270
|
1. 在Prefab中,将需要引用的节点重命名为`#属性名#组件类型`格式,例如:
|
|
190
271
|
- `#titleLabel#Label` 表示引用Label组件
|
|
@@ -195,9 +276,9 @@ mf.res.release('path/to/asset');
|
|
|
195
276
|
|
|
196
277
|
3. 插件会自动生成基础脚本和业务脚本,并自动设置引用关系
|
|
197
278
|
|
|
198
|
-
##
|
|
279
|
+
## 8. 完整示例
|
|
199
280
|
|
|
200
|
-
###
|
|
281
|
+
### 8.1 创建Manager
|
|
201
282
|
|
|
202
283
|
```typescript
|
|
203
284
|
@manager()
|
|
@@ -220,7 +301,7 @@ export class GameManager extends AbstractManager {
|
|
|
220
301
|
}
|
|
221
302
|
```
|
|
222
303
|
|
|
223
|
-
###
|
|
304
|
+
### 8.2 创建Model
|
|
224
305
|
|
|
225
306
|
```typescript
|
|
226
307
|
@model()
|
|
@@ -241,7 +322,7 @@ export class GameModel implements IModel {
|
|
|
241
322
|
}
|
|
242
323
|
```
|
|
243
324
|
|
|
244
|
-
###
|
|
325
|
+
### 8.3 创建UI界面
|
|
245
326
|
|
|
246
327
|
```typescript
|
|
247
328
|
// BaseHomeView.ts (由工具自动生成)
|
|
@@ -299,7 +380,7 @@ export class HomeView extends BaseHomeView {
|
|
|
299
380
|
}
|
|
300
381
|
```
|
|
301
382
|
|
|
302
|
-
###
|
|
383
|
+
### 8.4 在场景中使用
|
|
303
384
|
|
|
304
385
|
```typescript
|
|
305
386
|
// 在游戏启动时
|
|
@@ -311,18 +392,20 @@ export class GameApp extends Component {
|
|
|
311
392
|
}
|
|
312
393
|
```
|
|
313
394
|
|
|
314
|
-
##
|
|
395
|
+
## 9. 最佳实践
|
|
315
396
|
|
|
316
397
|
1. **模块化设计**:将相关的业务逻辑封装在对应的Manager中
|
|
317
398
|
2. **数据驱动**:使用Model管理数据状态
|
|
318
399
|
3. **事件解耦**:通过事件系统实现模块间通信
|
|
319
400
|
4. **资源管理**:使用BaseView自动管理资源加载和释放
|
|
320
401
|
5. **依赖注入**:使用装饰器简化依赖管理
|
|
321
|
-
6.
|
|
402
|
+
6. **网络请求**:使用HttpManager统一管理网络请求
|
|
403
|
+
7. **工具辅助**:使用mflow-tools提高开发效率
|
|
322
404
|
|
|
323
|
-
##
|
|
405
|
+
## 10. 注意事项
|
|
324
406
|
|
|
325
407
|
1. 确保在使用框架功能前Core已经初始化
|
|
326
408
|
2. 注意资源的正确加载和释放,避免内存泄漏
|
|
327
409
|
3. 合理使用事件系统,避免事件监听过多影响性能
|
|
328
|
-
4. 使用BaseView的子类时,确保正确实现所有抽象方法
|
|
410
|
+
4. 使用BaseView的子类时,确保正确实现所有抽象方法
|
|
411
|
+
5. 网络请求时注意错误处理和超时设置
|
package/dist/App.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ICore, IUIManager, IEventManager, ICocosResManager } from "./core";
|
|
1
|
+
import { ICore, IUIManager, IEventManager, ICocosResManager, IHttpManager } from "./core";
|
|
2
2
|
/**
|
|
3
3
|
* 对外暴露的全局app对像,用于访问基础能力,为上层业务提供了简洁的访问方式
|
|
4
4
|
*
|
|
@@ -9,7 +9,7 @@ export declare class App {
|
|
|
9
9
|
static readonly log: any;
|
|
10
10
|
static readonly config: any;
|
|
11
11
|
static get gui(): IUIManager;
|
|
12
|
-
static
|
|
12
|
+
static get http(): IHttpManager;
|
|
13
13
|
static readonly socket: any;
|
|
14
14
|
static get res(): ICocosResManager;
|
|
15
15
|
static get event(): IEventManager;
|
package/dist/App.js
CHANGED
|
@@ -13,6 +13,9 @@ class App {
|
|
|
13
13
|
static get gui() {
|
|
14
14
|
return ServiceLocator.getService('UIManager');
|
|
15
15
|
}
|
|
16
|
+
static get http() {
|
|
17
|
+
return ServiceLocator.getService('HttpManager');
|
|
18
|
+
}
|
|
16
19
|
static get res() {
|
|
17
20
|
return ServiceLocator.getService('ResLoader');
|
|
18
21
|
}
|
|
@@ -22,7 +25,6 @@ class App {
|
|
|
22
25
|
}
|
|
23
26
|
App.log = null;
|
|
24
27
|
App.config = null;
|
|
25
|
-
App.http = null;
|
|
26
28
|
App.socket = null;
|
|
27
29
|
App.storage = null;
|
|
28
30
|
App.audio = null;
|
package/dist/core/Api.d.ts
CHANGED
|
@@ -28,6 +28,21 @@ export interface IUIManager {
|
|
|
28
28
|
}
|
|
29
29
|
export interface IResManager {
|
|
30
30
|
}
|
|
31
|
+
export interface IHttpManager extends IManager {
|
|
32
|
+
get<T = any>(url: string, params?: Record<string, any>, headers?: Record<string, string>): Promise<T>;
|
|
33
|
+
post<T = any>(url: string, data?: any, headers?: Record<string, string>): Promise<T>;
|
|
34
|
+
put<T = any>(url: string, data?: any, headers?: Record<string, string>): Promise<T>;
|
|
35
|
+
delete<T = any>(url: string, params?: Record<string, any>, headers?: Record<string, string>): Promise<T>;
|
|
36
|
+
request<T = any>(options: HttpRequestOptions): Promise<T>;
|
|
37
|
+
}
|
|
38
|
+
export interface HttpRequestOptions {
|
|
39
|
+
url: string;
|
|
40
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
|
|
41
|
+
headers?: Record<string, string>;
|
|
42
|
+
params?: Record<string, any>;
|
|
43
|
+
data?: any;
|
|
44
|
+
timeout?: number;
|
|
45
|
+
}
|
|
31
46
|
export interface IEventMsgKey {
|
|
32
47
|
}
|
|
33
48
|
export type ToAnyIndexKey<IndexKey, AnyType> = IndexKey extends keyof AnyType ? IndexKey : keyof AnyType;
|
package/dist/core/Core.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ICore, IEventManager, IManager, IModel } from "./Api";
|
|
1
|
+
import { ICore, IEventManager, IManager, IModel, IHttpManager } from "./Api";
|
|
2
2
|
export declare abstract class AbstractCore<T extends AbstractCore<T>> implements ICore {
|
|
3
3
|
private readonly container;
|
|
4
4
|
constructor();
|
|
@@ -14,5 +14,6 @@ export declare abstract class AbstractManager implements IManager {
|
|
|
14
14
|
dispose(): void;
|
|
15
15
|
protected getModel<T extends IModel>(ctor: new () => T): T;
|
|
16
16
|
protected getEventManager(): IEventManager;
|
|
17
|
+
protected getHttpManager(): IHttpManager;
|
|
17
18
|
private releaseEventManager;
|
|
18
19
|
}
|
package/dist/core/Core.js
CHANGED
|
@@ -6,6 +6,6 @@ export interface ICocosResManager extends IResManager {
|
|
|
6
6
|
loadPrefab(path: string, nameOrUrl?: string): Promise<Prefab>;
|
|
7
7
|
loadSpriteFrame(ref: Sprite, path: string, nameOrUrl?: string): Promise<SpriteFrame>;
|
|
8
8
|
loadSpine(ref: sp.Skeleton, path: string, nameOrUrl?: string): Promise<sp.SkeletonData>;
|
|
9
|
-
release(asset: Asset): void;
|
|
10
|
-
release(path: string, type?: AssetType<Asset>, nameOrUrl?: string): void;
|
|
9
|
+
release(asset: Asset, force?: boolean): void;
|
|
10
|
+
release(path: string, type?: AssetType<Asset>, nameOrUrl?: string, force?: boolean): void;
|
|
11
11
|
}
|
package/dist/libs/BaseView.js
CHANGED
|
@@ -65,8 +65,7 @@ class BaseView extends Component {
|
|
|
65
65
|
onDestroy() {
|
|
66
66
|
// 自动清理加载的资源
|
|
67
67
|
this._loaderHandlers.forEach(({ path, asset }) => {
|
|
68
|
-
mf.res.release(
|
|
69
|
-
// mf.res.release(asset);
|
|
68
|
+
mf.res.release(asset);
|
|
70
69
|
});
|
|
71
70
|
this._loaderHandlers = [];
|
|
72
71
|
}
|
package/dist/libs/CocosCore.js
CHANGED
|
@@ -5,6 +5,7 @@ import { ServiceLocator } from '../core/ServiceLocator.js';
|
|
|
5
5
|
import { UIManager } from './UIManager.js';
|
|
6
6
|
import { ResLoader } from './ResLoader.js';
|
|
7
7
|
import { Broadcaster } from './Broadcaster.js';
|
|
8
|
+
import { HttpManager } from './HttpManager.js';
|
|
8
9
|
import '../App.js';
|
|
9
10
|
|
|
10
11
|
class Core extends AbstractCore {
|
|
@@ -14,6 +15,7 @@ class Core extends AbstractCore {
|
|
|
14
15
|
ServiceLocator.regService('EventManager', new Broadcaster());
|
|
15
16
|
ServiceLocator.regService('ResLoader', new ResLoader());
|
|
16
17
|
ServiceLocator.regService('UIManager', new UIManager());
|
|
18
|
+
ServiceLocator.regService('HttpManager', new HttpManager());
|
|
17
19
|
// 注册业务模块(通过装饰器自动注册)
|
|
18
20
|
// 推迟到构造函数执行完毕
|
|
19
21
|
queueMicrotask(() => autoRegister(this));
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { IHttpManager, HttpRequestOptions } from "../core";
|
|
2
|
+
/**
|
|
3
|
+
* HTTP 管理器实现类
|
|
4
|
+
*
|
|
5
|
+
* 发起请求
|
|
6
|
+
↓
|
|
7
|
+
【请求拦截器】修改请求参数(如添加 token、签名等)
|
|
8
|
+
↓
|
|
9
|
+
发送到服务器
|
|
10
|
+
↓
|
|
11
|
+
收到响应
|
|
12
|
+
↓
|
|
13
|
+
【响应拦截器】处理响应数据(如提取数据、转换格式等)
|
|
14
|
+
↓
|
|
15
|
+
返回结果 ✅
|
|
16
|
+
|
|
17
|
+
如果出错 ❌
|
|
18
|
+
↓
|
|
19
|
+
【错误拦截器】统一处理错误(如显示提示、记录日志等)
|
|
20
|
+
*/
|
|
21
|
+
export declare class HttpManager implements IHttpManager {
|
|
22
|
+
private baseURL;
|
|
23
|
+
private defaultTimeout;
|
|
24
|
+
private defaultHeaders;
|
|
25
|
+
private requestInterceptors;
|
|
26
|
+
private responseInterceptors;
|
|
27
|
+
private errorInterceptors;
|
|
28
|
+
private pendingRequests;
|
|
29
|
+
initialize(): void;
|
|
30
|
+
dispose(): void;
|
|
31
|
+
/**
|
|
32
|
+
* 设置基础 URL
|
|
33
|
+
*/
|
|
34
|
+
setBaseURL(url: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* 设置默认请求头
|
|
37
|
+
*/
|
|
38
|
+
setDefaultHeader(key: string, value: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* 添加请求拦截器
|
|
41
|
+
*/
|
|
42
|
+
addRequestInterceptor(interceptor: (options: HttpRequestOptions) => HttpRequestOptions | Promise<HttpRequestOptions>): void;
|
|
43
|
+
/**
|
|
44
|
+
* 添加响应拦截器
|
|
45
|
+
*/
|
|
46
|
+
addResponseInterceptor(interceptor: (response: any) => any | Promise<any>): void;
|
|
47
|
+
/**
|
|
48
|
+
* 添加错误拦截器
|
|
49
|
+
*/
|
|
50
|
+
addErrorInterceptor(interceptor: (error: Error) => void | Promise<void>): void;
|
|
51
|
+
/**
|
|
52
|
+
* 取消指定请求
|
|
53
|
+
*/
|
|
54
|
+
cancelRequest(requestKey: string): void;
|
|
55
|
+
/**
|
|
56
|
+
* 取消所有请求
|
|
57
|
+
*/
|
|
58
|
+
cancelAllRequests(): void;
|
|
59
|
+
get<T = any>(url: string, params?: Record<string, any>, headers?: Record<string, string>): Promise<T>;
|
|
60
|
+
post<T = any>(url: string, data?: any, headers?: Record<string, string>): Promise<T>;
|
|
61
|
+
put<T = any>(url: string, data?: any, headers?: Record<string, string>): Promise<T>;
|
|
62
|
+
delete<T = any>(url: string, params?: Record<string, any>, headers?: Record<string, string>): Promise<T>;
|
|
63
|
+
request<T = any>(options: HttpRequestOptions): Promise<T>;
|
|
64
|
+
/**
|
|
65
|
+
* 构建带参数的 URL
|
|
66
|
+
*/
|
|
67
|
+
private _buildUrlWithParams;
|
|
68
|
+
/**
|
|
69
|
+
* 标准化请求头
|
|
70
|
+
*/
|
|
71
|
+
private _normalizeHeaders;
|
|
72
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { __awaiter } from '../_virtual/_tslib.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* HTTP 管理器实现类
|
|
5
|
+
*
|
|
6
|
+
* 发起请求
|
|
7
|
+
↓
|
|
8
|
+
【请求拦截器】修改请求参数(如添加 token、签名等)
|
|
9
|
+
↓
|
|
10
|
+
发送到服务器
|
|
11
|
+
↓
|
|
12
|
+
收到响应
|
|
13
|
+
↓
|
|
14
|
+
【响应拦截器】处理响应数据(如提取数据、转换格式等)
|
|
15
|
+
↓
|
|
16
|
+
返回结果 ✅
|
|
17
|
+
|
|
18
|
+
如果出错 ❌
|
|
19
|
+
↓
|
|
20
|
+
【错误拦截器】统一处理错误(如显示提示、记录日志等)
|
|
21
|
+
*/
|
|
22
|
+
class HttpManager {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.baseURL = ''; // 基础 URL
|
|
25
|
+
this.defaultTimeout = 10000; // 默认超时时间 10 秒
|
|
26
|
+
this.defaultHeaders = {
|
|
27
|
+
'Content-Type': 'application/json',
|
|
28
|
+
};
|
|
29
|
+
// 请求拦截器
|
|
30
|
+
// 在请求发送之前修改请求参数,可以:
|
|
31
|
+
// 添加认证信息(Token)
|
|
32
|
+
// 添加通用参数(时间戳、版本号、签名等)
|
|
33
|
+
// 修改请求头
|
|
34
|
+
// 记录请求日志
|
|
35
|
+
// 加密请求数据
|
|
36
|
+
// 等等
|
|
37
|
+
this.requestInterceptors = [];
|
|
38
|
+
// 响应拦截器
|
|
39
|
+
// 在收到响应后处理数据,可以:
|
|
40
|
+
// 提取实际数据(去除包装层)
|
|
41
|
+
// 统一处理错误码
|
|
42
|
+
// 转换数据格式
|
|
43
|
+
// 缓存响应结果
|
|
44
|
+
// 等等
|
|
45
|
+
this.responseInterceptors = [];
|
|
46
|
+
// 错误拦截器
|
|
47
|
+
// 在请求出错时处理错误,可以:
|
|
48
|
+
// 显示错误提示
|
|
49
|
+
// 记录错误日志
|
|
50
|
+
// 重试请求
|
|
51
|
+
// 等等
|
|
52
|
+
this.errorInterceptors = [];
|
|
53
|
+
// 正在进行的请求管理
|
|
54
|
+
this.pendingRequests = new Map();
|
|
55
|
+
}
|
|
56
|
+
initialize() {
|
|
57
|
+
// 初始化逻辑(如果需要)
|
|
58
|
+
}
|
|
59
|
+
dispose() {
|
|
60
|
+
// 取消所有正在进行的请求
|
|
61
|
+
this.cancelAllRequests();
|
|
62
|
+
// 清空拦截器
|
|
63
|
+
this.requestInterceptors = [];
|
|
64
|
+
this.responseInterceptors = [];
|
|
65
|
+
this.errorInterceptors = [];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 设置基础 URL
|
|
69
|
+
*/
|
|
70
|
+
setBaseURL(url) {
|
|
71
|
+
this.baseURL = url;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 设置默认请求头
|
|
75
|
+
*/
|
|
76
|
+
setDefaultHeader(key, value) {
|
|
77
|
+
this.defaultHeaders[key] = value;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 添加请求拦截器
|
|
81
|
+
*/
|
|
82
|
+
addRequestInterceptor(interceptor) {
|
|
83
|
+
this.requestInterceptors.push(interceptor);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 添加响应拦截器
|
|
87
|
+
*/
|
|
88
|
+
addResponseInterceptor(interceptor) {
|
|
89
|
+
this.responseInterceptors.push(interceptor);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 添加错误拦截器
|
|
93
|
+
*/
|
|
94
|
+
addErrorInterceptor(interceptor) {
|
|
95
|
+
this.errorInterceptors.push(interceptor);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 取消指定请求
|
|
99
|
+
*/
|
|
100
|
+
cancelRequest(requestKey) {
|
|
101
|
+
const controller = this.pendingRequests.get(requestKey);
|
|
102
|
+
if (controller) {
|
|
103
|
+
controller.abort();
|
|
104
|
+
this.pendingRequests.delete(requestKey);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 取消所有请求
|
|
109
|
+
*/
|
|
110
|
+
cancelAllRequests() {
|
|
111
|
+
this.pendingRequests.forEach(controller => controller.abort());
|
|
112
|
+
this.pendingRequests.clear();
|
|
113
|
+
}
|
|
114
|
+
get(url, params, headers) {
|
|
115
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
116
|
+
const fullUrl = this._buildUrlWithParams(url, params);
|
|
117
|
+
return this.request({
|
|
118
|
+
url: fullUrl,
|
|
119
|
+
method: 'GET',
|
|
120
|
+
headers: Object.assign(Object.assign({}, this.defaultHeaders), headers)
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
post(url, data, headers) {
|
|
125
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
126
|
+
return this.request({
|
|
127
|
+
url,
|
|
128
|
+
method: 'POST',
|
|
129
|
+
headers: Object.assign(Object.assign({}, this.defaultHeaders), headers),
|
|
130
|
+
data
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
put(url, data, headers) {
|
|
135
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
136
|
+
return this.request({
|
|
137
|
+
url,
|
|
138
|
+
method: 'PUT',
|
|
139
|
+
headers: Object.assign(Object.assign({}, this.defaultHeaders), headers),
|
|
140
|
+
data
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
delete(url, params, headers) {
|
|
145
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
146
|
+
const fullUrl = this._buildUrlWithParams(url, params);
|
|
147
|
+
return this.request({
|
|
148
|
+
url: fullUrl,
|
|
149
|
+
method: 'DELETE',
|
|
150
|
+
headers: Object.assign(Object.assign({}, this.defaultHeaders), headers)
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
request(options) {
|
|
155
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
156
|
+
let { url, method, headers = {}, params, data, timeout = this.defaultTimeout } = options;
|
|
157
|
+
// 应用请求拦截器
|
|
158
|
+
let requestOptions = Object.assign({}, options);
|
|
159
|
+
for (const interceptor of this.requestInterceptors) {
|
|
160
|
+
requestOptions = yield interceptor(requestOptions);
|
|
161
|
+
}
|
|
162
|
+
// 更新变量(拦截器可能修改了请求参数)
|
|
163
|
+
({ url, method, headers = {}, params, data, timeout = this.defaultTimeout } = requestOptions);
|
|
164
|
+
// 处理 baseURL
|
|
165
|
+
let fullUrl = url;
|
|
166
|
+
if (this.baseURL && !url.startsWith('http')) {
|
|
167
|
+
fullUrl = this.baseURL + (url.startsWith('/') ? url : '/' + url);
|
|
168
|
+
}
|
|
169
|
+
// 构建完整的 URL(如果还有未处理的 params)
|
|
170
|
+
if (params && (method === 'GET' || method === 'DELETE')) {
|
|
171
|
+
fullUrl = this._buildUrlWithParams(fullUrl, params);
|
|
172
|
+
}
|
|
173
|
+
// 生成请求唯一标识(用于取消请求)
|
|
174
|
+
const requestKey = `${method}:${fullUrl}`;
|
|
175
|
+
// 构建 fetch 选项
|
|
176
|
+
const fetchOptions = {
|
|
177
|
+
method,
|
|
178
|
+
headers: this._normalizeHeaders(Object.assign(Object.assign({}, this.defaultHeaders), headers)),
|
|
179
|
+
};
|
|
180
|
+
// 添加请求体(仅适用于允许请求体的方法)
|
|
181
|
+
if (data && ['POST', 'PUT', 'PATCH'].includes(method)) {
|
|
182
|
+
if (data instanceof FormData) {
|
|
183
|
+
// FormData 不需要设置 Content-Type,浏览器会自动设置
|
|
184
|
+
fetchOptions.body = data;
|
|
185
|
+
// 移除 Content-Type,让浏览器自动设置正确的 boundary
|
|
186
|
+
delete fetchOptions.headers['content-type'];
|
|
187
|
+
}
|
|
188
|
+
else if (typeof data === 'object') {
|
|
189
|
+
fetchOptions.body = JSON.stringify(data);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
fetchOptions.body = data.toString();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
// 创建 AbortController(每个请求都需要独立的 controller)
|
|
197
|
+
const controller = new AbortController();
|
|
198
|
+
this.pendingRequests.set(requestKey, controller);
|
|
199
|
+
const timeoutId = setTimeout(() => {
|
|
200
|
+
controller.abort();
|
|
201
|
+
this.pendingRequests.delete(requestKey);
|
|
202
|
+
}, timeout);
|
|
203
|
+
fetchOptions.signal = controller.signal;
|
|
204
|
+
// 发起请求
|
|
205
|
+
const response = yield fetch(fullUrl, fetchOptions);
|
|
206
|
+
clearTimeout(timeoutId);
|
|
207
|
+
this.pendingRequests.delete(requestKey);
|
|
208
|
+
// 检查响应状态
|
|
209
|
+
if (!response.ok) {
|
|
210
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
211
|
+
}
|
|
212
|
+
// 尝试解析 JSON,如果失败则返回文本
|
|
213
|
+
let result;
|
|
214
|
+
try {
|
|
215
|
+
result = yield response.json();
|
|
216
|
+
}
|
|
217
|
+
catch (_a) {
|
|
218
|
+
result = yield response.text();
|
|
219
|
+
}
|
|
220
|
+
// 应用响应拦截器
|
|
221
|
+
for (const interceptor of this.responseInterceptors) {
|
|
222
|
+
result = yield interceptor(result);
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
this.pendingRequests.delete(requestKey);
|
|
228
|
+
let finalError;
|
|
229
|
+
if (error instanceof Error) {
|
|
230
|
+
if (error.name === 'AbortError') {
|
|
231
|
+
finalError = new Error(`Request timeout after ${timeout}ms`);
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
finalError = new Error(`Network error: ${error.message}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
finalError = new Error('Unknown network error');
|
|
239
|
+
}
|
|
240
|
+
// 应用错误拦截器
|
|
241
|
+
for (const interceptor of this.errorInterceptors) {
|
|
242
|
+
yield interceptor(finalError);
|
|
243
|
+
}
|
|
244
|
+
throw finalError;
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* 构建带参数的 URL
|
|
250
|
+
*/
|
|
251
|
+
_buildUrlWithParams(url, params) {
|
|
252
|
+
if (!params)
|
|
253
|
+
return url;
|
|
254
|
+
const urlObj = new URL(url, typeof window !== 'undefined' ? window.location.href : 'http://localhost');
|
|
255
|
+
Object.keys(params).forEach(key => {
|
|
256
|
+
if (params[key] !== undefined && params[key] !== null) {
|
|
257
|
+
urlObj.searchParams.append(key, String(params[key]));
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
// 如果原始 URL 没有协议和主机,只返回路径和查询参数
|
|
261
|
+
if (!url.startsWith('http')) {
|
|
262
|
+
return urlObj.pathname + urlObj.search;
|
|
263
|
+
}
|
|
264
|
+
return urlObj.toString();
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* 标准化请求头
|
|
268
|
+
*/
|
|
269
|
+
_normalizeHeaders(headers) {
|
|
270
|
+
const normalized = {};
|
|
271
|
+
Object.keys(headers).forEach(key => {
|
|
272
|
+
normalized[key.toLowerCase()] = headers[key];
|
|
273
|
+
});
|
|
274
|
+
return normalized;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export { HttpManager };
|
package/dist/libs/ResLoader.d.ts
CHANGED
|
@@ -5,6 +5,6 @@ export declare class ResLoader implements ICocosResManager {
|
|
|
5
5
|
loadPrefab(path: string, nameOrUrl?: string): Promise<Prefab>;
|
|
6
6
|
loadSpriteFrame(ref: Sprite, path: string, nameOrUrl?: string): Promise<SpriteFrame>;
|
|
7
7
|
loadSpine(ref: sp.Skeleton, path: string, nameOrUrl?: string): Promise<sp.SkeletonData>;
|
|
8
|
-
release(asset: Asset): void;
|
|
9
|
-
release(path: string, type?: AssetType<Asset>, nameOrUrl?: string): void;
|
|
8
|
+
release(asset: Asset, force?: boolean): void;
|
|
9
|
+
release(path: string, type?: AssetType<Asset>, nameOrUrl?: string, force?: boolean): void;
|
|
10
10
|
}
|
package/dist/libs/ResLoader.js
CHANGED
|
@@ -4,8 +4,6 @@ import { assetManager, Prefab, Asset, SpriteFrame, sp } from 'cc';
|
|
|
4
4
|
const DefaultBundle = "resources";
|
|
5
5
|
class ResLoader {
|
|
6
6
|
loadAsset(path, type, nameOrUrl = DefaultBundle) {
|
|
7
|
-
//TODO: bundle.release和assetManager.releaseAsset的区别?
|
|
8
|
-
//TODO: prefab是否需要addRef,prefab被克隆出来的节点被销毁时,对应的prefab如何处理?
|
|
9
7
|
if (assetManager.assets.has(path)) {
|
|
10
8
|
const asset = assetManager.assets.get(path);
|
|
11
9
|
asset.addRef();
|
|
@@ -31,6 +29,7 @@ class ResLoader {
|
|
|
31
29
|
});
|
|
32
30
|
}
|
|
33
31
|
loadPrefab(path, nameOrUrl = DefaultBundle) {
|
|
32
|
+
//refCount 记录的是持有者数量,不是资源份数,所以prefab也需要addRef
|
|
34
33
|
return this.loadAsset(path, Prefab, nameOrUrl);
|
|
35
34
|
}
|
|
36
35
|
loadSpriteFrame(ref, path, nameOrUrl = DefaultBundle) {
|
|
@@ -41,7 +40,7 @@ class ResLoader {
|
|
|
41
40
|
return Promise.resolve(sf);
|
|
42
41
|
}
|
|
43
42
|
else {
|
|
44
|
-
//
|
|
43
|
+
// 没有引用对象,释放掉资源
|
|
45
44
|
this.release(path, SpriteFrame, nameOrUrl);
|
|
46
45
|
return Promise.reject(new Error("Sprite is not valid"));
|
|
47
46
|
}
|
|
@@ -55,26 +54,37 @@ class ResLoader {
|
|
|
55
54
|
return Promise.resolve(spine);
|
|
56
55
|
}
|
|
57
56
|
else {
|
|
58
|
-
//
|
|
57
|
+
// 没有引用对象,释放掉资源
|
|
59
58
|
this.release(path, sp.SkeletonData, nameOrUrl);
|
|
60
59
|
return Promise.reject(new Error("Spine is not valid"));
|
|
61
60
|
}
|
|
62
61
|
});
|
|
63
62
|
}
|
|
64
|
-
release(pathOrAsset,
|
|
63
|
+
release(pathOrAsset, typeOrForce, nameOrUrl = DefaultBundle, forceParam = false) {
|
|
64
|
+
var _a;
|
|
65
|
+
let asset;
|
|
66
|
+
let force = false;
|
|
65
67
|
if (typeof pathOrAsset === "string") {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
asset === null || asset === void 0 ? void 0 : asset.decRef();
|
|
69
|
-
if ((asset === null || asset === void 0 ? void 0 : asset.refCount) === 0) {
|
|
70
|
-
bundle === null || bundle === void 0 ? void 0 : bundle.release(pathOrAsset, type);
|
|
68
|
+
if (!typeOrForce || typeof typeOrForce === "boolean") {
|
|
69
|
+
throw new Error('typeOrForce is undefined, or typeOrForce is boolean! typeOrForce must be AssetType<Asset>!');
|
|
71
70
|
}
|
|
71
|
+
force = forceParam;
|
|
72
|
+
asset = (_a = assetManager.getBundle(nameOrUrl)) === null || _a === void 0 ? void 0 : _a.get(pathOrAsset, typeOrForce);
|
|
72
73
|
}
|
|
73
74
|
else if (pathOrAsset instanceof Asset) {
|
|
74
|
-
pathOrAsset
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
asset = pathOrAsset;
|
|
76
|
+
force = typeof typeOrForce === 'boolean' ? typeOrForce : forceParam;
|
|
77
|
+
}
|
|
78
|
+
if (!asset) {
|
|
79
|
+
console.warn(`${pathOrAsset} Release asset failed, asset is null or undefined`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (force) {
|
|
83
|
+
assetManager.releaseAsset(asset);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// decRef原型:decRef (autoRelease = true),所以引用数量为 0,则将自动释放该资源。
|
|
87
|
+
asset.decRef();
|
|
78
88
|
}
|
|
79
89
|
}
|
|
80
90
|
}
|
package/dist/libs/UIManager.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { __awaiter } from '../_virtual/_tslib.js';
|
|
2
|
-
import { director, Node, Sprite, Widget, Input, input, instantiate } from 'cc';
|
|
2
|
+
import { director, Node, Sprite, Widget, Input, input, Prefab, instantiate } from 'cc';
|
|
3
3
|
import { ServiceLocator } from '../core/ServiceLocator.js';
|
|
4
4
|
import 'reflect-metadata';
|
|
5
5
|
|
|
@@ -144,6 +144,7 @@ class UIManager extends CcocosUIManager {
|
|
|
144
144
|
target = instantiate(prefab);
|
|
145
145
|
this._cache.set(viewType.name, target);
|
|
146
146
|
}
|
|
147
|
+
target.active = true;
|
|
147
148
|
return target.getComponent(viewType);
|
|
148
149
|
});
|
|
149
150
|
}
|
|
@@ -163,10 +164,21 @@ class UIManager extends CcocosUIManager {
|
|
|
163
164
|
}
|
|
164
165
|
viewortype.onExit();
|
|
165
166
|
viewortype.node.removeFromParent();
|
|
167
|
+
viewortype.node.active = false;
|
|
166
168
|
if (destroy) {
|
|
167
169
|
let cacheKey = viewortype.constructor.name;
|
|
168
170
|
(_a = this._cache.get(cacheKey)) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
169
171
|
this._cache.delete(cacheKey);
|
|
172
|
+
// 销毁被克隆出的UI后Node后,尝试释放 Prefab 资源
|
|
173
|
+
try {
|
|
174
|
+
const viewType = viewortype.constructor;
|
|
175
|
+
const prefabPath = this._getPrefabPath(viewType);
|
|
176
|
+
const ResMgr = ServiceLocator.getService('ResLoader');
|
|
177
|
+
ResMgr.release(prefabPath, Prefab);
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
console.error(`Failed to release prefab for ${cacheKey}:`, error);
|
|
181
|
+
}
|
|
170
182
|
}
|
|
171
183
|
}
|
|
172
184
|
internalGetTopView() {
|
package/dist/libs/index.d.ts
CHANGED
package/dist/libs/index.js
CHANGED
package/dist/mflow-tools.zip
CHANGED
|
Binary file
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
package/package.json
CHANGED