flu-cli-core 1.0.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.
Files changed (56) hide show
  1. package/README.md +60 -0
  2. package/dist/chunk-FOMWV2YP.js +378 -0
  3. package/dist/chunk-SW6YDKXI.js +112 -0
  4. package/dist/factory-6DDXZYQP.js +6 -0
  5. package/dist/index.cjs +4668 -0
  6. package/dist/index.d.cts +644 -0
  7. package/dist/index.d.ts +644 -0
  8. package/dist/index.js +4037 -0
  9. package/dist/upgrade_snippets-XFR7Q444.js +8 -0
  10. package/locales/en-US.json +59 -0
  11. package/locales/zh-CN.json +59 -0
  12. package/package.json +52 -0
  13. package/templates/README.md +129 -0
  14. package/templates/core_files/base/base_list_page.dart.template +225 -0
  15. package/templates/core_files/base/base_list_viewmodel.dart.template +164 -0
  16. package/templates/core_files/base/base_page.dart.template +252 -0
  17. package/templates/core_files/base/base_viewmodel.dart.template +68 -0
  18. package/templates/core_files/base/index.dart.template +5 -0
  19. package/templates/core_files/config/app_config.dart.template +142 -0
  20. package/templates/core_files/config/app_initializer.dart.template +74 -0
  21. package/templates/core_files/config/index.dart.template +3 -0
  22. package/templates/core_files/index.dart.template +8 -0
  23. package/templates/core_files/network/README.md +378 -0
  24. package/templates/core_files/network/app_error_code.dart.template +49 -0
  25. package/templates/core_files/network/app_http.dart.template +306 -0
  26. package/templates/core_files/network/app_response.dart.template +81 -0
  27. package/templates/core_files/network/index.dart.template +12 -0
  28. package/templates/core_files/network/interceptors/app_response_interceptor.dart.template +44 -0
  29. package/templates/core_files/network/interceptors/auth_interceptor.dart.template +30 -0
  30. package/templates/core_files/network/interceptors/error_interceptor.dart.template +48 -0
  31. package/templates/core_files/network/interceptors/index.dart.template +6 -0
  32. package/templates/core_files/network/interceptors/log_interceptor.dart.template +97 -0
  33. package/templates/core_files/network/interceptors/network_error_interceptor.dart.template +58 -0
  34. package/templates/core_files/network/interceptors/retry_interceptor.dart.template +69 -0
  35. package/templates/core_files/network/response_adapter.dart.template +69 -0
  36. package/templates/core_files/router/app_routes.dart.template +32 -0
  37. package/templates/core_files/router/index.dart.template +3 -0
  38. package/templates/core_files/router/navigator_util_getx.dart.template +131 -0
  39. package/templates/core_files/router/navigator_util_material.dart.template +191 -0
  40. package/templates/core_files/storage/index.dart.template +3 -0
  41. package/templates/core_files/storage/storage_keys.dart.template +34 -0
  42. package/templates/core_files/storage/storage_util.dart.template +102 -0
  43. package/templates/core_files/theme/app_theme.dart.template +37 -0
  44. package/templates/core_files/theme/index.dart.template +3 -0
  45. package/templates/core_files/theme/status_views_theme.dart.template +40 -0
  46. package/templates/core_files/utils/index.dart.template +2 -0
  47. package/templates/core_files/utils/loading_util.dart.template +55 -0
  48. package/templates/core_files/utils/toast_util.dart.template +128 -0
  49. package/templates/examples/eg_list_page.dart.template +340 -0
  50. package/templates/examples/eg_list_viewmodel.dart.template +31 -0
  51. package/templates/examples/eg_service.dart.template +78 -0
  52. package/templates/examples/mock_data.dart.template +50388 -0
  53. package/templates/examples/tu_chong_model.dart.template +633 -0
  54. package/templates/request_helper.dart.template +59 -0
  55. package/templates/snippets/flu-cli.code-snippets +268 -0
  56. package/templates/snippets/flu-cli.code-snippets.backup +268 -0
@@ -0,0 +1,8 @@
1
+ // 导出核心模块 (按字母顺序排列)
2
+ export 'base/index.dart';
3
+ export 'config/index.dart';
4
+ export 'network/index.dart';
5
+ export 'router/index.dart';
6
+ export 'storage/index.dart';
7
+ export 'theme/index.dart';
8
+ export 'utils/index.dart';
@@ -0,0 +1,378 @@
1
+ # AppNetwork 网络层
2
+
3
+ 基于 Dio 封装的企业级 Flutter 网络请求方案。
4
+
5
+ ---
6
+
7
+ ## 目录结构
8
+
9
+ ```
10
+ lib/core/network/
11
+ ├── app_error_code.dart # 统一错误码常量
12
+ ├── app_http.dart # 核心请求类 (单例)
13
+ ├── app_response.dart # 统一响应模型
14
+ ├── response_adapter.dart # 响应适配器 (格式转换)
15
+ ├── index.dart # 统一导出
16
+ └── interceptors/ # 拦截器
17
+ ├── app_response_interceptor.dart # 响应处理 + 业务错误弹窗
18
+ ├── network_error_interceptor.dart# 网络错误处理 + 自动弹窗
19
+ ├── auth_interceptor.dart # Token 注入
20
+ ├── retry_interceptor.dart # 失败重试
21
+ └── error_interceptor.dart # HTTP 错误处理
22
+ ```
23
+
24
+ ### 文件说明
25
+
26
+ | 文件 | 职责 |
27
+ | -------------------------------- | ------------------------------------------------------------------- |
28
+ | `app_error_code.dart` | 统一错误码常量定义,避免魔法数字 |
29
+ | `app_http.dart` | 核心请求客户端,封装 GET/POST/PUT/DELETE,统一返回 `AppResponse<T>` |
30
+ | `app_response.dart` | 响应数据模型,包含 `code`、`msg`、`data`,提供多种便捷判断方法 |
31
+ | `response_adapter.dart` | 将不同后端格式统一转换为标准结构 |
32
+ | `app_response_interceptor.dart` | 业务错误拦截器:数据适配 + 业务错误自动弹窗 |
33
+ | `network_error_interceptor.dart` | 网络错误拦截器:统一处理超时、连接失败等网络异常 |
34
+ | `auth_interceptor.dart` | 自动注入 `Authorization: Bearer xxx` |
35
+ | `retry_interceptor.dart` | 网络超时自动重试 |
36
+ | `error_interceptor.dart` | 处理 401/403 等 HTTP 状态码 |
37
+
38
+ ---
39
+
40
+ ## 架构分层
41
+
42
+ ```
43
+ ┌─────────────────────────────────────┐
44
+ │ UI Layer (Page) │ ← Loading 展示 / 用户交互
45
+ └─────────────────────────────────────┘
46
+
47
+ ┌─────────────────────────────────────┐
48
+ │ ViewModel Layer │ ← 业务逻辑 / 状态管理
49
+ └─────────────────────────────────────┘
50
+
51
+ ┌─────────────────────────────────────┐
52
+ │ Service Layer │ ← 数据获取 / 调用网络工具
53
+ └─────────────────────────────────────┘
54
+
55
+ ┌─────────────────────────────────────┐
56
+ │ Interceptor Layer │ ← 自动 Toast / 格式适配
57
+ └─────────────────────────────────────┘
58
+
59
+ ┌─────────────────────────────────────┐
60
+ │ Network Layer (AppHttp) │ ← 发送请求 / 接收响应
61
+ └─────────────────────────────────────┘
62
+ ```
63
+
64
+ ### 各层职责
65
+
66
+ | 层级 | 职责 | 不应该做 |
67
+ | -------------- | ---------------------------------- | ------------------------- |
68
+ | **网络请求层** | 发送 HTTP 请求,返回 `AppResponse` | 不处理 UI,不抛异常 |
69
+ | **响应处理层** | 格式转换,自动弹出错误 Toast | 不处理 Loading |
70
+ | **业务层** | 封装接口调用,数据转换 | 不处理 UI,不写 try-catch |
71
+ | **状态层** | 管理页面状态,调用 Service | 不直接调用网络层 |
72
+ | **UI 层** | 展示 Loading/数据/错误,用户交互 | 不写业务逻辑 |
73
+
74
+ ### Loading 和 Toast 放哪里?
75
+
76
+ | UI 类型 | 位置 | 原因 |
77
+ | -------------- | ----------------- | ------------------------------ |
78
+ | **错误 Toast** | 拦截器自动处理 | 统一管理,无需重复代码 |
79
+ | **Loading** | UI 层 / ViewModel | 与页面状态绑定,需根据业务展示 |
80
+
81
+ **设计原则:网络层是纯工具,不感知 UI。Loading 是页面状态,由 ViewModel 控制。**
82
+
83
+ ---
84
+
85
+ ## 快速开始
86
+
87
+ ### 1. 初始化
88
+
89
+ 在 `main.dart` 中调用一次:
90
+
91
+ ```dart
92
+ import 'core/network/app_http.dart';
93
+ import 'core/network/interceptors/auth_interceptor.dart';
94
+ import 'core/network/interceptors/retry_interceptor.dart';
95
+
96
+ void main() {
97
+ // 初始化网络层
98
+ AppHttp.init(
99
+ autoShowError: true, // 全局开启错误弹窗
100
+ interceptors: [
101
+ AuthInterceptor(getToken: () => ''), // Token 注入
102
+ RetryInterceptor(dio: AppHttp().dio), // 自动重试
103
+ ],
104
+ );
105
+
106
+ runApp(const MyApp());
107
+ }
108
+ ```
109
+
110
+ ### 2. 发起请求
111
+
112
+ 在 Service 层直接调用,**无需 try-catch**:
113
+
114
+ ```dart
115
+ class UserService {
116
+ final _http = AppHttp();
117
+
118
+ Future<AppResponse<User>> getUser(String id) async {
119
+ return await _http.get<User>(
120
+ '/users/$id',
121
+ fromJson: (json) => User.fromJson(json),
122
+ );
123
+ }
124
+
125
+ Future<AppResponse> createUser(Map<String, dynamic> data) async {
126
+ return await _http.post('/users', data: data);
127
+ }
128
+ }
129
+ ```
130
+
131
+ ### 3. 处理响应
132
+
133
+ 在 ViewModel 层判断状态:
134
+
135
+ ```dart
136
+ final res = await _service.getUser('123');
137
+
138
+ if (res.isSuccess) {
139
+ // 成功 - 使用 res.data
140
+ user.value = res.data;
141
+ } else {
142
+ // 失败 - 错误已自动弹窗,这里可做额外处理
143
+ if (res.isUnauthorized) {
144
+ // 跳转登录页
145
+ Get.offAllNamed('/login');
146
+ } else if (res.isForbidden) {
147
+ // 权限不足提示
148
+ }
149
+ }
150
+ ```
151
+
152
+ ---
153
+
154
+ ## 核心功能
155
+
156
+ ### AppResponse 响应模型
157
+
158
+ 所有请求返回此对象,不再抛出异常:
159
+
160
+ ```dart
161
+ class AppResponse<T> {
162
+ final int code; // 状态码 (0/200 = 成功)
163
+ final String msg; // 消息
164
+ final T? data; // 业务数据
165
+ final dynamic originalData; // 原始数据
166
+
167
+ // 状态判断方法
168
+ bool get isSuccess => code == AppErrorCode.success || code == AppErrorCode.successAlt;
169
+ bool get isFailed => !isSuccess;
170
+ bool get isUnauthorized => code == AppErrorCode.unauthorized;
171
+ bool get isForbidden => code == AppErrorCode.forbidden;
172
+ bool get isNetworkError => code == AppErrorCode.networkError;
173
+ bool get isParseError => code == AppErrorCode.parseError;
174
+ }
175
+ ```
176
+
177
+ ### fromJson 自动解析
178
+
179
+ 传入解析函数,自动将 `data` 转为对象:
180
+
181
+ ```dart
182
+ // 解析单个对象
183
+ final res = await _http.get<User>(
184
+ '/user/1',
185
+ fromJson: (json) => User.fromJson(json),
186
+ );
187
+ User? user = res.data;
188
+
189
+ // 解析列表
190
+ final res = await _http.get<List<User>>(
191
+ '/users',
192
+ fromJson: (json) => (json as List).map((e) => User.fromJson(e)).toList(),
193
+ );
194
+ List<User>? users = res.data;
195
+ ```
196
+
197
+ ### showError 错误控制
198
+
199
+ 控制是否自动弹出错误提示:
200
+
201
+ ```dart
202
+ // 跟随全局配置 (默认)
203
+ await _http.get('/api');
204
+
205
+ // 强制弹窗
206
+ await _http.get('/api', showError: true);
207
+
208
+ // 静默模式 - 失败不弹窗
209
+ await _http.get('/api', showError: false);
210
+ ```
211
+
212
+ ---
213
+
214
+ ## 参数配置
215
+
216
+ ### AppHttp.init() 参数
217
+
218
+ | 参数 | 类型 | 默认值 | 说明 |
219
+ | --------------- | -------------------- | ------------------------ | ---------------- |
220
+ | `adapter` | `AppResponseAdapter` | `DefaultResponseAdapter` | 响应格式适配器 |
221
+ | `interceptors` | `List<Interceptor>` | `[]` | 自定义拦截器 |
222
+ | `autoShowError` | `bool` | `true` | 全局错误弹窗开关 |
223
+
224
+ ### 请求方法参数
225
+
226
+ | 参数 | 类型 | 说明 |
227
+ | ----------------- | ---------------------- | ------------------------ |
228
+ | `path` | `String` | 请求路径 |
229
+ | `data` | `dynamic` | 请求体 (POST/PUT/DELETE) |
230
+ | `queryParameters` | `Map<String, dynamic>` | URL 查询参数 |
231
+ | `fromJson` | `T Function(dynamic)` | 数据解析函数 |
232
+ | `showError` | `bool?` | 单次请求的错误弹窗控制 |
233
+ | `options` | `Options` | Dio 原生配置 |
234
+ | `cancelToken` | `CancelToken` | 取消令牌 |
235
+
236
+ ---
237
+
238
+ ## 自定义扩展
239
+
240
+ ### 自定义响应适配器
241
+
242
+ 如果后端返回格式不是 `{code, msg, data}`,需要创建适配器:
243
+
244
+ ```dart
245
+ // 后端格式: { "status": 0, "message": "ok", "result": {...} }
246
+ class MyAdapter extends AppResponseAdapter {
247
+ @override
248
+ Map<String, dynamic> adapt(dynamic json) {
249
+ return {
250
+ 'code': json['status'] == 0 ? 200 : json['status'],
251
+ 'msg': json['message'] ?? '',
252
+ 'data': json['result'],
253
+ };
254
+ }
255
+ }
256
+
257
+ // 使用
258
+ AppHttp.init(adapter: MyAdapter());
259
+ ```
260
+
261
+ ### 内置适配器
262
+
263
+ | 适配器 | 支持格式 |
264
+ | ------------------------ | --------------------------------------------------- |
265
+ | `DefaultResponseAdapter` | `{ "code": 200, "msg": "ok", "data": {...} }` |
266
+ | `WanAndroidAdapter` | `{ "errorCode": 0, "errorMsg": "", "data": {...} }` |
267
+
268
+ ### 自定义拦截器
269
+
270
+ 继承 `Interceptor` 类:
271
+
272
+ ```dart
273
+ class LoggingInterceptor extends Interceptor {
274
+ @override
275
+ void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
276
+ print('REQUEST: ${options.uri}');
277
+ handler.next(options);
278
+ }
279
+
280
+ @override
281
+ void onResponse(Response response, ResponseInterceptorHandler handler) {
282
+ print('RESPONSE: ${response.statusCode}');
283
+ handler.next(response);
284
+ }
285
+ }
286
+
287
+ // 使用
288
+ AppHttp.init(interceptors: [LoggingInterceptor()]);
289
+ ```
290
+
291
+ ---
292
+
293
+ ## 内置拦截器
294
+
295
+ ### NetworkErrorInterceptor (核心)
296
+
297
+ 统一处理所有网络异常并自动弹窗:
298
+
299
+ ```dart
300
+ NetworkErrorInterceptor(
301
+ autoShowError: true, // 是否自动弹窗
302
+ )
303
+ ```
304
+
305
+ **说明**:此拦截器已在 `AppHttp.init()` 中自动添加,无需手动配置。处理超时、连接失败等所有 Dio 网络异常。
306
+
307
+ ### AppResponseInterceptor (核心)
308
+
309
+ 处理业务错误并自动弹窗:
310
+
311
+ ```dart
312
+ AppResponseInterceptor(
313
+ adapter: DefaultResponseAdapter(), // 响应适配器
314
+ autoShowError: true, // 是否自动弹窗
315
+ )
316
+ ```
317
+
318
+ **说明**:此拦截器已在 `AppHttp.init()` 中自动添加,无需手动配置。处理业务层错误(如 code != 200)。
319
+
320
+ ### AuthInterceptor
321
+
322
+ 自动注入 Token:
323
+
324
+ ```dart
325
+ AuthInterceptor(
326
+ getToken: () => StorageUtil.getString('token') ?? '',
327
+ )
328
+ ```
329
+
330
+ ### RetryInterceptor
331
+
332
+ 网络超时自动重试:
333
+
334
+ ```dart
335
+ RetryInterceptor(
336
+ dio: AppHttp().dio,
337
+ maxRetries: 3, // 最大重试次数
338
+ retryDelay: Duration(seconds: 1), // 重试间隔
339
+ )
340
+ ```
341
+
342
+ ### ErrorInterceptor
343
+
344
+ 处理 HTTP 错误:
345
+
346
+ ```dart
347
+ ErrorInterceptor(
348
+ onUnauthorized: (_) => Navigator.pushNamed(context, '/login'),
349
+ onForbidden: (_) => showToast('无访问权限'),
350
+ )
351
+ ```
352
+
353
+ ---
354
+
355
+ ## 错误码常量
356
+
357
+ 使用 `AppErrorCode` 统一管理错误码,避免魔法数字:
358
+
359
+ ```dart
360
+ class AppErrorCode {
361
+ // 成功码
362
+ static const int success = 200;
363
+ static const int successAlt = 0;
364
+
365
+ // HTTP 状态码
366
+ static const int unauthorized = 401;
367
+ static const int forbidden = 403;
368
+ static const int notFound = 404;
369
+ static const int serverError = 500;
370
+
371
+ // 自定义错误码
372
+ static const int networkError = -1; // 网络错误
373
+ static const int parseError = -2; // 数据解析失败
374
+ static const int timeout = -3; // 请求超时
375
+ static const int canceled = -4; // 请求取消
376
+ static const int unknown = -99; // 未知错误
377
+ }
378
+ ```
@@ -0,0 +1,49 @@
1
+ /// 统一错误码定义
2
+ ///
3
+ /// 规范化所有网络请求和业务逻辑中的错误码,避免魔法数字
4
+ class AppErrorCode {
5
+ // ========================================================================
6
+ // 成功码
7
+ // ========================================================================
8
+
9
+ /// 标准成功码
10
+ static const int success = 200;
11
+
12
+ /// 备用成功码 (兼容某些后端使用 0 表示成功)
13
+ static const int successAlt = 0;
14
+
15
+ // ========================================================================
16
+ // HTTP 标准状态码
17
+ // ========================================================================
18
+
19
+ /// 未授权 - 需要登录
20
+ static const int unauthorized = 401;
21
+
22
+ /// 禁止访问 - 权限不足
23
+ static const int forbidden = 403;
24
+
25
+ /// 资源不存在
26
+ static const int notFound = 404;
27
+
28
+ /// 服务器内部错误
29
+ static const int serverError = 500;
30
+
31
+ // ========================================================================
32
+ // 自定义错误码 (负数区间)
33
+ // ========================================================================
34
+
35
+ /// 网络连接错误
36
+ static const int networkError = -1;
37
+
38
+ /// 数据解析失败
39
+ static const int parseError = -2;
40
+
41
+ /// 请求超时
42
+ static const int timeout = -3;
43
+
44
+ /// 请求被取消
45
+ static const int canceled = -4;
46
+
47
+ /// 未知错误
48
+ static const int unknown = -99;
49
+ }