Browse Source

联调扦样列表接口;

maqiang 1 year ago
parent
commit
cdea8546f7

+ 108 - 0
lib/base/base_vm.dart

@@ -0,0 +1,108 @@
1
+/// 自动导入ValueNotifier拓展
2
+export 'package:lszlgl/ext/value_notifier_ext.dart';
3
+
4
+///
5
+/// VM基类
6
+abstract class BaseVM {
7
+  /// 是否被销毁
8
+  bool _dispose = false;
9
+
10
+  get isDispose => _dispose;
11
+
12
+  /// 销毁时回调方法
13
+  void dispose() {
14
+    _dispose = true;
15
+  }
16
+}
17
+
18
+///
19
+/// 数据状态装饰类
20
+///
21
+/// ```
22
+/// 简单使用方法:
23
+/// // 数据
24
+/// var user = DataStatusModel<UserBean>();
25
+/// user = user.empty();
26
+/// user = user.loading();
27
+/// user = user.success(UserBean());
28
+/// user = user.error('网络异常');
29
+/// // 组件
30
+/// setState({});
31
+/// switch (user.status) {
32
+///   ...
33
+/// }
34
+/// ```
35
+///
36
+/// ```
37
+/// 配合ValueNotifierExt使用:
38
+/// // 数据
39
+/// final user = DataStatusModel<UserBean>().notifier<DataStatusModel<UserBean>>();
40
+/// user.update(user.value.empty());
41
+/// user.update(user.value.loading());
42
+/// user.update(user.value.success(UserBean()));
43
+/// user.update(user.value.error('网络异常'));
44
+/// // 组件
45
+/// user.builder((v) {
46
+///   switch (v.status) {
47
+///     ...
48
+///   }
49
+/// }
50
+/// ```
51
+class DataStatusModel<T> {
52
+  /// 数据状态
53
+  DataStatus status;
54
+
55
+  /// 数据内容
56
+  T? data;
57
+
58
+  /// 错误信息
59
+  Object? errorData;
60
+
61
+  DataStatusModel({
62
+    this.status = DataStatus.empty,
63
+    this.data,
64
+    this.errorData,
65
+  });
66
+
67
+  /// 加载中
68
+  DataStatusModel<T> loading({T? data, Object? error}) => DataStatusModel<T>(
69
+        status: DataStatus.loading,
70
+        data: data ?? this.data,
71
+        errorData: error ?? this.errorData,
72
+      );
73
+
74
+  /// 加载成功
75
+  DataStatusModel<T> success({T? data, Object? error}) => DataStatusModel<T>(
76
+        status: DataStatus.success,
77
+        data: data ?? this.data,
78
+        errorData: error ?? this.errorData,
79
+      );
80
+
81
+  /// 无数据
82
+  DataStatusModel<T> empty({T? data, Object? error}) => DataStatusModel<T>(
83
+        data: data ?? this.data,
84
+        errorData: error ?? this.errorData,
85
+      );
86
+
87
+  /// 加载失败
88
+  DataStatusModel<T> error({T? data, Object? error}) => DataStatusModel<T>(
89
+        status: DataStatus.error,
90
+        data: data ?? this.data,
91
+        errorData: error ?? this.errorData,
92
+      );
93
+}
94
+
95
+/// 数据状态
96
+enum DataStatus {
97
+  /// 无数据
98
+  empty,
99
+
100
+  /// 加载中
101
+  loading,
102
+
103
+  /// 加载成功
104
+  success,
105
+
106
+  /// 加载失败
107
+  error,
108
+}

+ 1 - 1
lib/ext/value_notifier_ext.dart

@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
2 2
 
3 3
 /// 万物皆可Notifier
4 4
 extension ObjectNotifierExt on Object? {
5
-  ValueNotifier<T?> notifier<T>() => ValueNotifier(this as T?);
5
+  ValueNotifier<T> notifier<T>() => ValueNotifier(this as T);
6 6
 }
7 7
 
8 8
 /// 拓展ValueNotifier

+ 64 - 126
lib/main.dart

@@ -1,3 +1,6 @@
1
+import 'dart:async';
2
+import 'dart:isolate';
3
+
1 4
 import 'package:easy_refresh/easy_refresh.dart';
2 5
 import 'package:flutter/material.dart';
3 6
 import 'package:flutter/services.dart';
@@ -9,135 +12,70 @@ import 'package:lszlgl/router/my_navigator.dart';
9 12
 import 'package:lszlgl/utils/sp_utils.dart';
10 13
 
11 14
 late Logger logger;
12
-const zhCN = {
13
-  'Sample': '示例',
14
-  'Style': '样式',
15
-  'More': '更多',
16
-  'Theme': '主题',
17
-  'System': '系统',
18
-  'Light': '明亮',
19
-  'Dark': '暗黑',
20
-  'Classic': '经典',
21
-  'Classic and default': '经典和默认',
22
-  'Direction': '方向',
23
-  'Vertical': '垂直',
24
-  'Horizontal': '水平',
25
-  'Clamping': '固定',
26
-  'Background': '背景',
27
-  'Alignment': '对齐',
28
-  'Center': '中心',
29
-  'Start': '开端',
30
-  'End': '结尾',
31
-  'Infinite': '无限',
32
-  'Message': '信息',
33
-  'Text': '文本',
34
-  'Animation': '动画',
35
-  'Bounce': '回弹',
36
-  'List Spring': '列表弹簧',
37
-  'Pull to refresh': '下拉刷新',
38
-  'Release ready': '释放开始',
39
-  'Refreshing...': '刷新中...',
40
-  'Succeeded': '成功了',
41
-  'No more': '没有更多',
42
-  'Failed': '失败了',
43
-  'Last updated at %T': '最后更新于 %T',
44
-  'Pull to load': '上拉加载',
45
-  'Loading...': '加载中...',
46
-  'Bezier curve': '贝塞尔曲线',
47
-  'Disable': '禁用',
48
-  'Display balls': '显示小球',
49
-  'Spin in center': 'Spin居中',
50
-  'Only show spin': '只显示Spin',
51
-  'Bezier circle': '弹出圆圈',
52
-  'Golden campus': '金色校园',
53
-  'Rush to the sky': '冲上云霄',
54
-  'Balloon delivery': '气球快递',
55
-  'Star track': '太空轨道',
56
-  'Lumberjack Squats': '暴力深蹲',
57
-  'Skating boy': '滑雪少年',
58
-  'Halloween horror': '万圣节惊魂',
59
-  'User profile': '个人中心',
60
-  'User personal center': '用户个人中心',
61
-  'QQ group': 'QQ群',
62
-  'Name': '名字',
63
-  'Age': '年龄',
64
-  'Not yet bald': '尚未秃顶',
65
-  'City': '城市',
66
-  'China - ChengDu': '中国 - 成都',
67
-  'Phone': '电话',
68
-  'Mail': '邮箱',
69
-  'NestedScrollView example': 'NestedScrollView示例',
70
-  'Carousel': '轮播',
71
-  'Carousel example': '轮播示例',
72
-  'Refresh on start': '启动时刷新',
73
-  'Refresh when the list is displayed and specify the Header': '列表显示时刷新并指定Header',
74
-  'Listener': '监听器',
75
-  'Use listener to respond anywhere': '使用监听器,在任意位置响应',
76
-  'Secondary': '二楼',
77
-  'Combine existing Header with secondary': '将已有的Header结合二楼',
78
-  'Open the second floor': '打开二楼',
79
-  'Chat': '聊天',
80
-  'Chat page example': '聊天页面示例',
81
-  'PageView example': 'PageView 示例',
82
-  'Join discussion': '加入讨论',
83
-  'Join the QQ group (554981921)': '加入QQ群(554981921)',
84
-  'Repository': '项目地址',
85
-  'Support me': '支持作者',
86
-  'Buy me a coffee ~': '请作者喝一杯咖啡~',
87
-  'Alipay': '支付宝',
88
-  'Alipay donation': '支付宝捐赠',
89
-  'Wechat': '微信',
90
-  'Wechat donation': '微信捐赠',
91
-  'Cryptocurrency': '加密货币',
92
-  'Cryptocurrency donation': '加密货币捐赠',
93
-  'Bitcoin donation': '比特币捐赠',
94
-  'Ethereum series, ETH, BNB, MATIC, USDT and other tokens': '以太坊系列,ETH、BNB、MATIC、USDT及其他代币',
95
-  'Tron chain, TRX, USDT, USDC and other tokens': '波场链,TRX、USDT、USDC及其他代币',
96
-  'Dogecoin donation': '狗狗币捐赠',
97
-  '%s copied!': '%s 已复制!',
98
-  'Trigger immediately': '立即触发',
99
-  'TabBarView example': 'NestedScrollView + TabBarView示例',
100
-  'Paging': '分页',
101
-  'Paging example': '分页示例',
102
-  'No Data': '暂无数据',
103
-  'Theme switch': '主题切换',
104
-  'Theme switch example': '主题切换示例',
105
-  'Theme switch describe': '下拉显示切换面板,左右滑动选中主题色,释放进行切换。',
106
-  'Bubbles launch': '泡泡发射',
107
-};
108 15
 
109 16
 void main() async {
110
-  WidgetsFlutterBinding.ensureInitialized();
111
-  SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light.copyWith(statusBarColor: Colors.transparent));
112
-  SystemChrome.setPreferredOrientations([
113
-    DeviceOrientation.portraitUp,
114
-    DeviceOrientation.portraitDown,
115
-  ]);
116
-  BaseDio.get().init();
117
-  logger = Logger(printer: PrettyPrinter(methodCount: 0));
118
-  await SPUtils.getInstance().init();
17
+  initReportException(() async {
18
+    logger = Logger(printer: PrettyPrinter(methodCount: 0));
19
+    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light.copyWith(statusBarColor: Colors.transparent));
20
+    SystemChrome.setPreferredOrientations([
21
+      DeviceOrientation.portraitUp,
22
+      DeviceOrientation.portraitDown,
23
+    ]);
24
+    BaseDio.get().init();
25
+
26
+    await SPUtils.getInstance().init();
27
+
28
+    EasyRefresh.defaultHeaderBuilder = () => const ClassicHeader(
29
+          dragText: '下拉刷新',
30
+          armedText: '释放开始',
31
+          readyText: '刷新中...',
32
+          processingText: '刷新中...',
33
+          processedText: '成功了',
34
+          noMoreText: '已加载全部',
35
+          failedText: '刷新失败',
36
+          messageText: '最后更新于 %T',
37
+        );
38
+    EasyRefresh.defaultFooterBuilder = () => const ClassicFooter(
39
+          dragText: '上拉加载',
40
+          armedText: '释放开始',
41
+          readyText: '加载中...',
42
+          processingText: '加载中...',
43
+          processedText: '成功了',
44
+          noMoreText: '已加载全部',
45
+          failedText: '加载失败',
46
+          messageText: '最后更新于 %T',
47
+        );
48
+    runApp(const MyApp());
49
+  });
50
+}
51
+
52
+/// 初始化异常上报 封装[runZonedGuarded]
53
+void initReportException(Function() callback) {
54
+  runZonedGuarded(() {
55
+    // 初始化Flutter
56
+    WidgetsFlutterBinding.ensureInitialized();
57
+    // 隔离线程异常
58
+    Isolate.current.addErrorListener(RawReceivePort((dynamic pair) {
59
+      var isolateError = pair as List<dynamic>;
60
+      onError(isolateError.first, isolateError.last);
61
+    }).sendPort);
62
+    // 捕获Flutter异常
63
+    FlutterError.onError = (FlutterErrorDetails error) {
64
+      FlutterError.presentError(error);
65
+      onError(error.exception, error.stack);
66
+    };
67
+    // 回调外部方法
68
+    callback.call();
69
+  }, (error, stack) {
70
+    // 捕获程序异常
71
+    onError(error, stack);
72
+  });
73
+}
119 74
 
120
-  EasyRefresh.defaultHeaderBuilder = () => const ClassicHeader(
121
-        dragText: '下拉刷新',
122
-        armedText: '释放开始',
123
-        readyText: '刷新中...',
124
-        processingText: '刷新中...',
125
-        processedText: '成功了',
126
-        noMoreText: '没有更多',
127
-        failedText: '失败了',
128
-        messageText: '最后更新于 %T',
129
-      );
130
-  EasyRefresh.defaultFooterBuilder = () => const ClassicFooter(
131
-        dragText: '上拉加载',
132
-        armedText: '释放开始',
133
-        readyText: '加载中...',
134
-        processingText: '加载中...',
135
-        processedText: '成功了',
136
-        noMoreText: '没有更多',
137
-        failedText: '失败了',
138
-        messageText: '最后更新于 %T',
139
-      );
140
-  runApp(const MyApp());
75
+/// 上报异常
76
+Future<void> onError(Object exception, StackTrace? stack) async {
77
+  if (stack == null) return;
78
+  logger.e('error:${exception.runtimeType.toString()}\n${exception.toString()}\n${stack.toString()}');
141 79
 }
142 80
 
143 81
 class MyApp extends StatelessWidget {

lib/network/api_rsp.dart → lib/model/api_rsp.dart


+ 28 - 0
lib/model/num_converter.dart

@@ -0,0 +1,28 @@
1
+import 'package:json_annotation/json_annotation.dart';
2
+
3
+/// Json解析num类型
4
+class NumConverter extends JsonConverter<num?, dynamic> {
5
+  const NumConverter();
6
+
7
+  @override
8
+  num? fromJson(json) {
9
+    if (json == null) return null;
10
+    if (json is num) return json;
11
+    // String
12
+    if (json is String) {
13
+      try {
14
+        return num.parse(json);
15
+      } catch (e) {
16
+        return null;
17
+      }
18
+    }
19
+    // boolean false=0 true=1
20
+    if (json is bool) {
21
+      return json ? 1 : 0;
22
+    }
23
+    return null;
24
+  }
25
+
26
+  @override
27
+  toJson(num? object) => object?.toString();
28
+}

lib/network/req/login_req.dart → lib/model/req/login_req.dart


+ 19 - 0
lib/model/rsp/dict_rsp.dart

@@ -0,0 +1,19 @@
1
+import 'package:json_annotation/json_annotation.dart';
2
+
3
+part 'dict_rsp.g.dart';
4
+
5
+@JsonSerializable(genericArgumentFactories: true)
6
+class DictRsp {
7
+  final String? dictType; //字典类型
8
+  final String? value; //字典键值
9
+  final String? label; //字典标签
10
+  const DictRsp({
11
+    this.dictType,
12
+    this.value,
13
+    this.label,
14
+  });
15
+
16
+  factory DictRsp.fromJson(Map<String, dynamic> json) => _$DictRspFromJson(json);
17
+
18
+  Map<String, dynamic> toJson() => _$DictRspToJson(this);
19
+}

lib/network/rsp/login_rsp.dart → lib/model/rsp/login_rsp.dart


+ 390 - 0
lib/model/rsp/sample_task_rsp.dart

@@ -0,0 +1,390 @@
1
+import 'package:json_annotation/json_annotation.dart';
2
+import 'package:lszlgl/model/num_converter.dart';
3
+import 'package:lszlgl/model/string_converter.dart';
4
+
5
+part 'sample_task_rsp.g.dart';
6
+
7
+@JsonSerializable(genericArgumentFactories: true)
8
+class SampleTaskListRsp {
9
+  final num? total;
10
+  final List<SampleTaskItem>? list;
11
+
12
+  const SampleTaskListRsp({
13
+    this.total,
14
+    this.list,
15
+  });
16
+
17
+  factory SampleTaskListRsp.fromJson(Map<String, dynamic> json) => _$SampleTaskListRspFromJson(json);
18
+
19
+  Map<String, dynamic> toJson() => _$SampleTaskListRspToJson(this);
20
+}
21
+
22
+@JsonSerializable(converters: [NumConverter(), StringConverter()])
23
+class SampleTaskItem {
24
+  final num? id;
25
+  final String? qyryName; // 人员名称
26
+  final String? fjrq; // 分解日期
27
+  final String? ypbh; // 样品编号
28
+  final String? jtpzmc; // 具体品种名称
29
+  final num? deliveryStatus; // 任务单任务状态:0是待扦样,1已扦样
30
+  final num? jhcysl; // 计划采样数量
31
+  final num? zljysl; // 质量检验数量
32
+  final num? pzjyjg; // 品质检验机构
33
+  final num? pzjysl; // 品质检验数量
34
+  final num? sajyjg; // 食安检验机构
35
+  final num? sajysl; // 食安检验数量
36
+  final num? jhcyjg; // 扦样机构
37
+  final String? lspz; // 粮食品种
38
+  final num? bchlx; // 病虫害类型
39
+  final String? bdcnhhhzs; // 被调查农户或合作社
40
+  final num? gcpwlx; // 工厂排污类型
41
+  final String? lxfs; // 联系方式
42
+  final num? qydbsl; // 扦样代表数量(公斤)
43
+  final String? qyddjwd; // 扦样地点经纬度
44
+  final String? qysj; // 扦样时间
45
+  final num? qysl; // 扦样数量(公斤)
46
+  final bool? scgczsffsbjyzdbch; // 生产过程中是否发生比较严重的病虫害
47
+  final String? sheng; // 省
48
+  final String? shi; // 市
49
+  final String? qu; // 区
50
+  final String? xian; // 县
51
+  final String? cun; // 村
52
+  final num? shidu; // 湿度
53
+  final String? shsj; // 收获时间
54
+  final num? trdllx; // 土壤地理类型
55
+  final num? wendu; // 温度
56
+  final num? wrwlx; // 污染物类型
57
+  final num? zzmj; // 种植面积(亩地)
58
+  final bool? zztdzwsfygcpw; // 种植土地周围是否有工厂排污
59
+  final bool? zztdzwsysytrsfywr; // 种植土地周围使用水源、土壤是否有污染
60
+  final num? zjBaseEnterpriseId; // 企业基本信息ID
61
+  final num? zjBasePersonnelId; // 人员基本信息表ID
62
+  final num? zjCodeSamplingTaskId;
63
+  final num? zjCodeSamplingPlanId; // 采样计划详情ID
64
+  final String? xzqh; // 行政区划
65
+  final num? zjBaseGrainInformationId; // 品种id
66
+  final num? cypzmc; // 采样品种名称
67
+  final String? cypzName; // 采样品种名称
68
+  final String? qyrwdh; // 扦样任务单号
69
+  final num? shengXzqh; // 省行政区划id
70
+  final num? shiXzqh; // 市行政区划id
71
+  final num? quXzqh; // 区行政区划id
72
+  final num? xiangXzqh; // 县行政区划id
73
+  final num? cunXzqh; // 村行政区划id
74
+  final num? createTime; // 创建时间
75
+  final num? state; // 0是待扦样,1已扦样,2已完成
76
+  final String? name; // 扦样人员姓名
77
+  final String? rwjssj; // 任务接收时间
78
+  final String? bsjzsj; // 报送截止时间
79
+  final num? rwlx; // 任务类型/监测环节
80
+  final num? jclb; // 监测类别
81
+  final String? dwmc; // 单位名称
82
+  final List<EnterpriseItem>? enterpriseList; // 机构信息
83
+  final List<UseMedicineItem>? codeUseMedicineList; // 种植期间农药使用情况
84
+  final String? zzpz; // 种植品种
85
+  final String? shengXzqhName; // 省
86
+  final String? shiXzqhName; // 市
87
+  final String? quXzqhName; // 区
88
+  final String? xiangXzqhName; // 县
89
+  final String? cunXzqhName; // 村
90
+  final String? cyjhbmCode; // 采样计划编号
91
+  final String? cyjhmc; // 采样计划名称
92
+  final String? niandu; // 年度
93
+  final List<SamplingTaskAllotSgjcItem>? codeSamplingTaskAllotSgjcRespList; // 任务分配
94
+  // final List<>? codeSamplingTaskDetailsKcjcRespVO; // 库存检测
95
+  // final List<>? fplist; // 分配多条信息
96
+  final num? sfyzpz; // 是否优质品种
97
+  final num? yzpzlx; // 优质品种类型
98
+  final num? shqjsffslyytq; // 收货期间是否发生连阴雨天气
99
+  final num? shlssfsfpg; // 收货粮食水分是否偏高
100
+  final num? jnlbdsffszmwr; // 近年来本地是否发生真菌毒素污染
101
+  final num? zjdswrlx; // 真菌毒素污染类型
102
+  final num? jnlbdsfzjswr; // 近年来本地是否发生重金属污染
103
+  final num? zjswrlx; // 重金属污染类型
104
+  final List<JyjgxxItem>? jyjgxxRespVOList; // 检验机构信息
105
+  final num? jypzStatus; // 检验品质按钮0显示1不显示
106
+
107
+  const SampleTaskItem({
108
+    this.id,
109
+    this.qyryName,
110
+    this.fjrq,
111
+    this.ypbh,
112
+    this.jtpzmc,
113
+    this.deliveryStatus,
114
+    this.jhcysl,
115
+    this.zljysl,
116
+    this.pzjyjg,
117
+    this.pzjysl,
118
+    this.sajyjg,
119
+    this.sajysl,
120
+    this.jhcyjg,
121
+    this.lspz,
122
+    this.bchlx,
123
+    this.bdcnhhhzs,
124
+    this.gcpwlx,
125
+    this.lxfs,
126
+    this.qydbsl,
127
+    this.qyddjwd,
128
+    this.qysj,
129
+    this.qysl,
130
+    this.scgczsffsbjyzdbch,
131
+    this.sheng,
132
+    this.shi,
133
+    this.qu,
134
+    this.xian,
135
+    this.cun,
136
+    this.shidu,
137
+    this.shsj,
138
+    this.trdllx,
139
+    this.wendu,
140
+    this.wrwlx,
141
+    this.zzmj,
142
+    this.zztdzwsfygcpw,
143
+    this.zztdzwsysytrsfywr,
144
+    this.zjBaseEnterpriseId,
145
+    this.zjBasePersonnelId,
146
+    this.zjCodeSamplingTaskId,
147
+    this.zjCodeSamplingPlanId,
148
+    this.xzqh,
149
+    this.zjBaseGrainInformationId,
150
+    this.cypzmc,
151
+    this.cypzName,
152
+    this.qyrwdh,
153
+    this.shengXzqh,
154
+    this.shiXzqh,
155
+    this.quXzqh,
156
+    this.xiangXzqh,
157
+    this.cunXzqh,
158
+    this.createTime,
159
+    this.state,
160
+    this.name,
161
+    this.rwjssj,
162
+    this.bsjzsj,
163
+    this.rwlx,
164
+    this.jclb,
165
+    this.dwmc,
166
+    this.enterpriseList,
167
+    this.codeUseMedicineList,
168
+    this.zzpz,
169
+    this.shengXzqhName,
170
+    this.shiXzqhName,
171
+    this.quXzqhName,
172
+    this.xiangXzqhName,
173
+    this.cunXzqhName,
174
+    this.cyjhbmCode,
175
+    this.cyjhmc,
176
+    this.niandu,
177
+    this.codeSamplingTaskAllotSgjcRespList,
178
+    this.sfyzpz,
179
+    this.yzpzlx,
180
+    this.shqjsffslyytq,
181
+    this.shlssfsfpg,
182
+    this.jnlbdsffszmwr,
183
+    this.zjdswrlx,
184
+    this.jnlbdsfzjswr,
185
+    this.zjswrlx,
186
+    this.jyjgxxRespVOList,
187
+    this.jypzStatus,
188
+  });
189
+
190
+  factory SampleTaskItem.fromJson(Map<String, dynamic> json) => _$SampleTaskItemFromJson(json);
191
+
192
+  Map<String, dynamic> toJson() => _$SampleTaskItemToJson(this);
193
+
194
+  String getDeliveryStatusText() {
195
+    return switch (deliveryStatus) { 0 => '待扦样', 1 => '已扦样', _ => '' };
196
+  }
197
+}
198
+
199
+@JsonSerializable(converters: [NumConverter(), StringConverter()])
200
+class EnterpriseItem {
201
+  final num? id; // 单位id
202
+  final String? address; // 具体地址
203
+  final String? beizhu; // 备注
204
+  final num? bgsmj; // 办公室面积(m²)
205
+  final num? cqlb; // 产权类别
206
+  final num? dnczbksr; // 当年财政拨款收入
207
+  final num? dnywwtsr; // 当年业务委托收入
208
+  final num? dwdzSheng; // 省id
209
+  final String? dwdzShengName; // 省名称
210
+  final num? dwdzShi; // 市id
211
+  final String? dwdzShiName; // 市名称
212
+  final num? dwdzXian; // 县id
213
+  final String? dwdzXianName; //县名称
214
+  final num? dwjb; // 单位级别
215
+  final String? dwmc; //单位名称
216
+  final num? dwxz; //单位性质
217
+  final String? frdb; //法人代表
218
+  final num? jglb; //机构类别
219
+  final num? jyyrs; //检验员人数
220
+  final String? lxfs; //联系方式
221
+  final num? rybzsl; //人员编制数量
222
+  final String? shtyxydm; //社会统一信用代码
223
+  final num? sysmj; //实验室面积(m²)
224
+  final num? zjzmj; //总建筑面积(m²)
225
+  final num? zrs; //总人数
226
+  final String? dwdz; //单位地址
227
+  final String? createTime; //创建时间
228
+  final String? creatorDeptId; //创建人所在部门id
229
+  final num? deptId; //隶属部门Id
230
+  final String? sjzgdw; //上级主管单位
231
+  // final List<>? jyllList; //检验能力集合
232
+  // final List<>? jyzsList; //检验证书集合
233
+  final String? flowCode; //审核编号
234
+  final num? flowStatus; //审核状态:0待发起,1审核中,2通过,3驳回
235
+  final String? flowCause; //审核意见
236
+  final num? flowCheckUserId; //审核人id
237
+  final String? flowTime; //审核时间
238
+  // final List<>? kycxtdList; //科研创新团队
239
+  // final List<>? xdbzList; //牵头或参与制修订标准
240
+  // final List<>? kyxmList; //牵头或参与负责科研项目
241
+  // final List<>? hdryList; //获得荣誉
242
+  // final List<>? personnelList; //人员信息
243
+  // final List<>? instrumentEquipmentList; //设备信息
244
+  final num? personnelCount; //人员数量
245
+  final num? instrumentEquipmentCount; //设备数量
246
+  // final List<>? filePictureList; //附件(图片)地址
247
+  // final List<>? filePictureTwoList; //附件(图片)地址
248
+  // final List<>? guaPaiDeptRespVoList; //挂牌部门集合
249
+
250
+  const EnterpriseItem({
251
+    this.id,
252
+    this.address,
253
+    this.beizhu,
254
+    this.bgsmj,
255
+    this.cqlb,
256
+    this.dnczbksr,
257
+    this.dnywwtsr,
258
+    this.dwdzSheng,
259
+    this.dwdzShengName,
260
+    this.dwdzShi,
261
+    this.dwdzShiName,
262
+    this.dwdzXian,
263
+    this.dwdzXianName,
264
+    this.dwjb,
265
+    this.dwmc,
266
+    this.dwxz,
267
+    this.frdb,
268
+    this.jglb,
269
+    this.jyyrs,
270
+    this.lxfs,
271
+    this.rybzsl,
272
+    this.shtyxydm,
273
+    this.sysmj,
274
+    this.zjzmj,
275
+    this.zrs,
276
+    this.dwdz,
277
+    this.createTime,
278
+    this.creatorDeptId,
279
+    this.deptId,
280
+    this.sjzgdw,
281
+    this.flowCode,
282
+    this.flowStatus,
283
+    this.flowCause,
284
+    this.flowCheckUserId,
285
+    this.flowTime,
286
+    this.personnelCount,
287
+    this.instrumentEquipmentCount,
288
+  });
289
+
290
+  factory EnterpriseItem.fromJson(Map<String, dynamic> json) => _$EnterpriseItemFromJson(json);
291
+
292
+  Map<String, dynamic> toJson() => _$EnterpriseItemToJson(this);
293
+}
294
+
295
+@JsonSerializable(converters: [NumConverter(), StringConverter()])
296
+class UseMedicineItem {
297
+  final num? id; //ID
298
+  final String? cjsj; //创建时间
299
+  final String? syff; //施药方式
300
+  final String? synypz; //使用农药品种
301
+  final num? synysl; //扦样使用农药的数量(公斤或毫升/每亩地)
302
+  final String? sysj; //施药时间
303
+  final num? zjCodeSamplingTaskDetailsKcjcId;
304
+  final num? zjCodeSamplingTaskDetailsSgjcId;
305
+  final String? createTime; //创建时间
306
+  final String? jcz; //检测值
307
+  final String? zczfw; //正常值范围
308
+
309
+  const UseMedicineItem({
310
+    this.id,
311
+    this.cjsj,
312
+    this.syff,
313
+    this.synypz,
314
+    this.synysl,
315
+    this.sysj,
316
+    this.zjCodeSamplingTaskDetailsKcjcId,
317
+    this.zjCodeSamplingTaskDetailsSgjcId,
318
+    this.createTime,
319
+    this.jcz,
320
+    this.zczfw,
321
+  });
322
+
323
+  factory UseMedicineItem.fromJson(Map<String, dynamic> json) => _$UseMedicineItemFromJson(json);
324
+
325
+  Map<String, dynamic> toJson() => _$UseMedicineItemToJson(this);
326
+}
327
+
328
+@JsonSerializable(converters: [NumConverter(), StringConverter()])
329
+class SamplingTaskAllotSgjcItem {
330
+  final num? id; //id
331
+  final num? zjBaseGrainInformationId; //品种id
332
+  final String? cypzmc; //采样品种名称
333
+  final num? samplingCount; //计划采样数量
334
+  final String? bsjzsj; //报送截至时间
335
+  final num? personnelId; // 人员id
336
+  final num? zjCodeSamplingPlanId; //计划id
337
+  final num? zjCodeSamplingTaskId; //任务id
338
+  final String? creater; //创建人
339
+  final String? createDate; //创建时间
340
+  final String? updateDate; //修改时间
341
+  final String? cyjhbmCode; //采样计划编号
342
+  final String? cyjhmc; //采样计划名称
343
+  final String? niandu; //年度
344
+  final String? zzpz; //种植品种
345
+  final num? jhcysl; //计划采样数量
346
+
347
+  const SamplingTaskAllotSgjcItem({
348
+    this.id,
349
+    this.zjBaseGrainInformationId,
350
+    this.cypzmc,
351
+    this.samplingCount,
352
+    this.bsjzsj,
353
+    this.personnelId,
354
+    this.zjCodeSamplingPlanId,
355
+    this.zjCodeSamplingTaskId,
356
+    this.creater,
357
+    this.createDate,
358
+    this.updateDate,
359
+    this.cyjhbmCode,
360
+    this.cyjhmc,
361
+    this.niandu,
362
+    this.zzpz,
363
+    this.jhcysl,
364
+  });
365
+
366
+  factory SamplingTaskAllotSgjcItem.fromJson(Map<String, dynamic> json) => _$SamplingTaskAllotSgjcItemFromJson(json);
367
+
368
+  Map<String, dynamic> toJson() => _$SamplingTaskAllotSgjcItemToJson(this);
369
+}
370
+
371
+@JsonSerializable(converters: [NumConverter(), StringConverter()])
372
+class JyjgxxItem {
373
+  final num? zjBaseEnterpriseId; //企业id
374
+  final String? dwmc; //单位名称
375
+  final String? address; //具体地址
376
+  final String? jydh; //检验单号
377
+  final String? ypjssj; //样品接收时间
378
+
379
+  JyjgxxItem({
380
+    this.zjBaseEnterpriseId,
381
+    this.dwmc,
382
+    this.address,
383
+    this.jydh,
384
+    this.ypjssj,
385
+  });
386
+
387
+  factory JyjgxxItem.fromJson(Map<String, dynamic> json) => _$JyjgxxItemFromJson(json);
388
+
389
+  Map<String, dynamic> toJson() => _$JyjgxxItemToJson(this);
390
+}

lib/network/rsp/user_rsp.dart → lib/model/rsp/user_rsp.dart


+ 25 - 0
lib/model/string_converter.dart

@@ -0,0 +1,25 @@
1
+import 'dart:convert';
2
+
3
+import 'package:json_annotation/json_annotation.dart';
4
+
5
+/// Json解析num类型
6
+class StringConverter extends JsonConverter<String?, dynamic> {
7
+  const StringConverter();
8
+
9
+  @override
10
+  String? fromJson(json) {
11
+    if (json == null) return null;
12
+    // String
13
+    if (json is String) return json;
14
+    // num boolean
15
+    if (json is num || json is bool) return json.toString();
16
+    // List Map Object 转换Json字符串
17
+    if (json is List || json is Map || json is Object)
18
+      return JsonEncoder().convert(json);
19
+    // 其他类型
20
+    return json.toString();
21
+  }
22
+
23
+  @override
24
+  toJson(String? object) => object;
25
+}

+ 15 - 7
lib/network/api.dart

@@ -1,9 +1,11 @@
1 1
 import 'package:dio/dio.dart';
2
+import 'package:lszlgl/model/api_rsp.dart';
3
+import 'package:lszlgl/model/req/login_req.dart';
4
+import 'package:lszlgl/model/rsp/dict_rsp.dart';
5
+import 'package:lszlgl/model/rsp/login_rsp.dart';
6
+import 'package:lszlgl/model/rsp/sample_task_rsp.dart';
7
+import 'package:lszlgl/model/rsp/user_rsp.dart';
2 8
 import 'package:lszlgl/network/base_dio.dart';
3
-import 'package:lszlgl/network/req/login_req.dart';
4
-import 'package:lszlgl/network/api_rsp.dart';
5
-import 'package:lszlgl/network/rsp/login_rsp.dart';
6
-import 'package:lszlgl/network/rsp/user_rsp.dart';
7 9
 import 'package:retrofit/retrofit.dart';
8 10
 
9 11
 part 'api.g.dart';
@@ -23,10 +25,16 @@ abstract class Api {
23 25
   @GET('/admin-api/system/user/profile/get')
24 26
   Future<ApiRsp<UserRsp>> userProfile();
25 27
 
28
+  /// 获取所有字典
29
+  @GET('/admin-api/system/dict-data/simple-list')
30
+  Future<ApiRsp<List<DictRsp>>> getAllDict();
31
+
26 32
   /// 扦样任务单列表
27 33
   @GET('/admin-api/zj/code-sampling-task-details-sgjc/sampling_task_detail_page')
28
-  Future<ApiRsp<UserRsp>> sampleTaskList(
34
+  Future<ApiRsp<SampleTaskListRsp>> sampleTaskList(
29 35
     @Query('pageNo') int pageNo,
30
-    @Query('pageSize') int pageSize,
31
-  );
36
+    @Query('pageSize') int pageSize, {
37
+    @Query('deliveryStatus') int? deliveryStatus,
38
+    @Query('rwlx') int? rwlx,
39
+  });
32 40
 }

+ 5 - 9
lib/network/base_dio.dart

@@ -47,6 +47,7 @@ class BaseDio {
47 47
     List<Interceptor>? interceptors,
48 48
   }) {
49 49
     dio.options.copyWith(
50
+      baseUrl: baseUrl,
50 51
       connectTimeout: connectTimeout,
51 52
       receiveTimeout: receiveTimeout,
52 53
       sendTimeout: sendTimeout,
@@ -124,7 +125,6 @@ class MyInterceptor extends Interceptor {
124 125
         err.copyWith(message: '当前网络不可用,请检查您的网络');
125 126
       }
126 127
     }
127
-    logger.e('ApiError: message:${err.message}');
128 128
     // error统一处理
129 129
     AppException appException = AppException.create(err);
130 130
     err.copyWith(error: appException);
@@ -132,8 +132,7 @@ class MyInterceptor extends Interceptor {
132 132
     Map<String, Object?> map = {};
133 133
     map['url'] = err.requestOptions.uri;
134 134
     map['statusCode'] = err.response?.statusCode;
135
-    map['message'] = err.message;
136
-    map['exceptionCode'] = appException.code;
135
+    map['data'] = err.response?.data;
137 136
     map['msg'] = appException.message;
138 137
     if (err.response?.extra.isNotEmpty ?? false) map['extra'] = err.response?.extra;
139 138
     logger.e('ApiError: $map');
@@ -168,12 +167,9 @@ class AppException implements Exception {
168 167
       case DioExceptionType.badCertificate:
169 168
         return AppException(-1, '证书错误');
170 169
       case DioExceptionType.badResponse:
171
-        try {
172
-          int? errCode = error.response!.statusCode;
173
-          return AppException(errCode!, error.response?.data ?? '');
174
-        } catch (_) {
175
-          return AppException(-1, "未知错误");
176
-        }
170
+        var code = error.response?.data['code'];
171
+        if (code == 401) UserService.get().logout();
172
+        return AppException(code, error.response?.data['msg'] ?? '');
177 173
       case DioExceptionType.cancel:
178 174
         return AppException(-1, "请求取消");
179 175
       case DioExceptionType.connectionError:

+ 3 - 3
lib/page/home/home_page.dart

@@ -3,7 +3,7 @@ import 'package:card_swiper/card_swiper.dart';
3 3
 import 'package:flutter/cupertino.dart';
4 4
 import 'package:flutter/material.dart';
5 5
 import 'package:lszlgl/base/base_state.dart';
6
-import 'package:lszlgl/page/reap_step/reap_step_tab_page.dart';
6
+import 'package:lszlgl/page/reap_step/sample_task_list_tab_page.dart';
7 7
 
8 8
 /// 首页
9 9
 class HomePage extends StatefulWidget {
@@ -22,11 +22,11 @@ class _HomePageState extends BaseState<HomePage> with AutomaticKeepAliveClientMi
22 22
   late List<ServiceModel> serviceList;
23 23
 
24 24
   void startReap() {
25
-    MyRouter.startReapStepList(const ReapStepTabPageArgs(type: StepType.reap));
25
+    MyRouter.startSampleTaskList(const SampleTaskListTabPageArgs(type: StepType.reap));
26 26
   }
27 27
 
28 28
   void startStore() {
29
-    MyRouter.startReapStepList(const ReapStepTabPageArgs(type: StepType.stock));
29
+    MyRouter.startSampleTaskList(const SampleTaskListTabPageArgs(type: StepType.stock));
30 30
   }
31 31
 
32 32
   @override

+ 25 - 9
lib/page/login/login_page.dart

@@ -1,9 +1,11 @@
1
+import 'package:dio/dio.dart';
1 2
 import 'package:flutter/material.dart';
2 3
 import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
3 4
 import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
4 5
 import 'package:lszlgl/base/base_lifecycle_state.dart';
6
+import 'package:lszlgl/model/req/login_req.dart';
5 7
 import 'package:lszlgl/network/api.dart';
6
-import 'package:lszlgl/network/req/login_req.dart';
8
+import 'package:lszlgl/service/dict_service.dart';
7 9
 import 'package:lszlgl/service/user_service.dart';
8 10
 import 'package:lszlgl/widget/button.dart';
9 11
 
@@ -28,19 +30,33 @@ class _LoginPageState extends BaseLifecycleState<LoginPage> {
28 30
       SmartDialog.showToast('请输入账号和密码');
29 31
       return;
30 32
     }
31
-    SmartDialog.showLoading();
33
+    SmartDialog.showLoading(clickMaskDismiss: false, backDismiss: false);
32 34
     try {
33 35
       // 登录
34 36
       var login = await Api().login(LoginReq(username: account, password: pwd));
35 37
       await UserService.get().saveLogin(login.data);
36
-      // 用户信息
38
+      getSystemData();
39
+    } on DioException catch (_) {
40
+      SmartDialog.dismiss(status: SmartStatus.loading);
41
+    }
42
+  }
43
+
44
+  /// 获取基础数据
45
+  void getSystemData() async {
46
+    SmartDialog.showLoading(clickMaskDismiss: false, backDismiss: false);
47
+    try {
48
+      // 获取用户数据
37 49
       var user = await Api().userProfile();
38 50
       await UserService.get().saveUser(user.data);
39
-      SmartDialog.dismiss();
51
+      // 获取字典
52
+      var dictData = await Api().getAllDict();
53
+      DictService.get().saveDictList(dictData.data);
40 54
       // 进入主页
55
+      SmartDialog.dismiss(status: SmartStatus.loading);
41 56
       startHome();
42
-    } catch (_) {
43
-      SmartDialog.dismiss();
57
+    } on DioException catch (_) {
58
+      // 获取数据失败
59
+      SmartDialog.dismiss(status: SmartStatus.loading);
44 60
     }
45 61
   }
46 62
 
@@ -56,10 +72,10 @@ class _LoginPageState extends BaseLifecycleState<LoginPage> {
56 72
   }
57 73
 
58 74
   @override
59
-  void onFirstShow(Duration timeStamp) {
60
-    // 已登录进入主页
75
+  void onFirstShow(Duration timeStamp) async {
76
+    // 已登录
61 77
     if (UserService.get().getLogin() != null) {
62
-      startHome();
78
+      getSystemData();
63 79
     }
64 80
   }
65 81
 

+ 0 - 3
lib/page/main_tab_page.dart

@@ -3,7 +3,6 @@ import 'dart:async';
3 3
 import 'package:flutter/material.dart';
4 4
 import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
5 5
 import 'package:lszlgl/base/base_state.dart';
6
-import 'package:lszlgl/network/api.dart';
7 6
 import 'package:lszlgl/page/home/home_page.dart';
8 7
 import 'package:lszlgl/page/user_center/user_center_page.dart';
9 8
 
@@ -47,8 +46,6 @@ class _MainTabPageState extends State<MainTabPage> {
47 46
     tabIconSelectList = [imgNavHomeSelect, imgNavUserCenterSelect];
48 47
     pageList = [const HomePage(), const UserCenterPage()];
49 48
     ctrl = PageController(initialPage: selectedIndex);
50
-    // 获取用户数据
51
-    Api().userProfile();
52 49
   }
53 50
 
54 51
   @override

+ 0 - 232
lib/page/reap_step/reap_step_list_page.dart

@@ -1,232 +0,0 @@
1
-import 'package:flutter/material.dart';
2
-import 'package:lszlgl/base/base_lifecycle_state.dart';
3
-import 'package:lszlgl/base/base_state.dart';
4
-import 'package:lszlgl/config/colors.dart';
5
-import 'package:lszlgl/page/reap_step/reap_step_tab_page.dart';
6
-import 'package:lszlgl/widget/button.dart';
7
-
8
-/// 扦样环节列表
9
-class ReapStepListPage extends StatefulWidget {
10
-  final StepType type;
11
-  final bool complete;
12
-
13
-  const ReapStepListPage({
14
-    super.key,
15
-    required this.type,
16
-    this.complete = false,
17
-  });
18
-
19
-  @override
20
-  State<ReapStepListPage> createState() => _ReapStepListPageState();
21
-}
22
-
23
-class _ReapStepListPageState extends BaseLifecycleState<ReapStepListPage> {
24
-  late List<Map<String, String>> infoList;
25
-
26
-  /// 详情
27
-  void startDetail() {
28
-    if (!widget.complete) return;
29
-    switch (widget.type) {
30
-      case StepType.reap:
31
-        MyRouter.startReapSampleTask(detail: true);
32
-        break;
33
-      case StepType.stock:
34
-        break;
35
-    }
36
-  }
37
-
38
-  /// 扦样
39
-  void startSample() {
40
-    switch (widget.type) {
41
-      case StepType.reap:
42
-        MyRouter.startReapSampleTask();
43
-        break;
44
-      case StepType.stock:
45
-        break;
46
-    }
47
-  }
48
-
49
-  @override
50
-  void onInit() {
51
-    String taskType = switch (widget.type) {
52
-      StepType.reap => '收购监测',
53
-      StepType.stock => '库存监测',
54
-      _ => '',
55
-    };
56
-    if (widget.complete) {
57
-      infoList = [
58
-        {'采样品种': '玉米'},
59
-        {'粮食品类': '粮食品类'},
60
-        {'监测类别': taskType},
61
-        {'扦样数量(kg)': '10'},
62
-        {'扦样人员': '李飞'},
63
-        {'扦样时间': '2024-01-01'},
64
-      ];
65
-    } else {
66
-      infoList = [
67
-        {'采样品种': '玉米'},
68
-        {'报送截止时间': '2024-01-01'},
69
-        {'监测类别': taskType},
70
-        {'扦样人员': '李飞'},
71
-      ];
72
-    }
73
-  }
74
-
75
-  @override
76
-  Widget build(BuildContext context) {
77
-    return Container(
78
-      clipBehavior: Clip.hardEdge,
79
-      decoration: const BoxDecoration(
80
-        color: Colors.white,
81
-        borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
82
-      ),
83
-      alignment: Alignment.center,
84
-      child: buildList(),
85
-    );
86
-  }
87
-
88
-  Widget buildList() {
89
-    return ListView.builder(
90
-      physics: const BouncingScrollPhysics(),
91
-      padding: EdgeInsets.zero,
92
-      itemCount: 10,
93
-      itemBuilder: (_, index) => buildItem(index),
94
-    );
95
-  }
96
-
97
-  Widget buildItem(int index) {
98
-    return GestureDetector(
99
-      behavior: HitTestBehavior.opaque,
100
-      onTap: () => startDetail(),
101
-      child: Container(
102
-        margin: const EdgeInsets.only(left: 12, right: 12, top: 12),
103
-        decoration: const BoxDecoration(
104
-          color: Color(0xFFF5FFFD),
105
-          borderRadius: BorderRadius.all(Radius.circular(8)),
106
-        ),
107
-        child: Column(
108
-          crossAxisAlignment: CrossAxisAlignment.start,
109
-          children: [
110
-            const SizedBox(height: 15),
111
-            buildTop(),
112
-            buildNumber(),
113
-            buildGrid(),
114
-            buildBottom(),
115
-            const SizedBox(height: 15),
116
-          ],
117
-        ),
118
-      ),
119
-    );
120
-  }
121
-
122
-  Widget buildTop() {
123
-    return Row(
124
-      children: [
125
-        buildVLine(),
126
-        const Expanded(
127
-          child: Text(
128
-            '扦样任务单号',
129
-            style: TextStyle(color: MyColor.c_333333, fontSize: 18, fontWeight: FontWeight.w500),
130
-          ),
131
-        ),
132
-        buildState(),
133
-      ],
134
-    );
135
-  }
136
-
137
-  Widget buildVLine() {
138
-    return Container(
139
-      width: 4,
140
-      height: 20,
141
-      margin: const EdgeInsets.only(right: 8),
142
-      decoration: const BoxDecoration(
143
-        color: MyColor.c_25A6EE,
144
-        borderRadius: BorderRadius.all(Radius.circular(2)),
145
-      ),
146
-    );
147
-  }
148
-
149
-  Widget buildState() {
150
-    String state = widget.complete ? '已扦样' : '待扦样';
151
-    return Container(
152
-      padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 4),
153
-      decoration: BoxDecoration(
154
-        color: MyColor.c_25A6EE.withOpacity(0.1),
155
-        borderRadius: const BorderRadius.horizontal(left: Radius.circular(100)),
156
-      ),
157
-      child: Text(
158
-        '状态:$state',
159
-        style: const TextStyle(color: MyColor.c_1383C2, fontSize: 16),
160
-      ),
161
-    );
162
-  }
163
-
164
-  Widget buildNumber() {
165
-    return const Padding(
166
-      padding: EdgeInsets.only(left: 12, top: 4, bottom: 6),
167
-      child: Text(
168
-        '***********',
169
-        style: TextStyle(color: MyColor.c_333333, fontSize: 18, fontWeight: FontWeight.w500),
170
-      ),
171
-    );
172
-  }
173
-
174
-  Widget buildGrid() {
175
-    return Padding(
176
-      padding: const EdgeInsets.symmetric(horizontal: 12),
177
-      child: LayoutBuilder(builder: (context, constraints) {
178
-        return Wrap(
179
-          spacing: 4,
180
-          runSpacing: 4,
181
-          children: infoList.map((item) {
182
-            return SizedBox(
183
-              width: constraints.maxWidth / 2 - 2,
184
-              child: Text(
185
-                '${item.keys.first}:${item.values.first}',
186
-                style: const TextStyle(fontSize: 16, color: MyColor.c_666666),
187
-              ),
188
-            );
189
-          }).toList(),
190
-        );
191
-      }),
192
-    );
193
-  }
194
-
195
-  Widget buildBottom() {
196
-    if (widget.complete) return const SizedBox.shrink();
197
-    return Column(
198
-      children: [
199
-        buildDivider(),
200
-        Row(
201
-          children: [
202
-            const SizedBox(width: 12),
203
-            const Expanded(
204
-              child: Text(
205
-                '[张三]创建于2024-01-01 00:00:00',
206
-                style: TextStyle(fontSize: 16, color: MyColor.c_666666),
207
-              ),
208
-            ),
209
-            const SizedBox(width: 4),
210
-            MyButton(
211
-              '开始扦样',
212
-              onTap: () => startSample(),
213
-              fountSize: 16,
214
-              alignment: null,
215
-              padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
216
-            ),
217
-            const SizedBox(width: 12),
218
-          ],
219
-        ),
220
-      ],
221
-    );
222
-  }
223
-
224
-  Widget buildDivider() {
225
-    return Container(
226
-      width: double.infinity,
227
-      height: 1,
228
-      color: MyColor.c_3BD2E5.withOpacity(0.15),
229
-      margin: const EdgeInsets.symmetric(vertical: 10),
230
-    );
231
-  }
232
-}

+ 21 - 0
lib/page/reap_step/sample_list_vm.dart

@@ -0,0 +1,21 @@
1
+import 'package:easy_refresh/easy_refresh.dart';
2
+import 'package:lszlgl/base/base_vm.dart';
3
+
4
+class SampleListVM extends BaseVM {
5
+  late final EasyRefreshController aCtrl;
6
+  late final EasyRefreshController bCtrl;
7
+
8
+  SampleListVM() {
9
+    aCtrl = EasyRefreshController(controlFinishRefresh: true, controlFinishLoad: true);
10
+    bCtrl = EasyRefreshController(controlFinishRefresh: true, controlFinishLoad: true);
11
+  }
12
+
13
+
14
+
15
+  @override
16
+  void dispose() {
17
+    aCtrl.dispose();
18
+    bCtrl.dispose();
19
+    super.dispose();
20
+  }
21
+}

+ 319 - 0
lib/page/reap_step/sample_task_list_page.dart

@@ -0,0 +1,319 @@
1
+import 'package:dio/dio.dart';
2
+import 'package:easy_refresh/easy_refresh.dart';
3
+import 'package:flutter/material.dart';
4
+import 'package:lszlgl/base/base_lifecycle_state.dart';
5
+import 'package:lszlgl/base/base_state.dart';
6
+import 'package:lszlgl/base/base_vm.dart';
7
+import 'package:lszlgl/config/colors.dart';
8
+import 'package:lszlgl/main.dart';
9
+import 'package:lszlgl/model/rsp/sample_task_rsp.dart';
10
+import 'package:lszlgl/network/api.dart';
11
+import 'package:lszlgl/page/reap_step/sample_task_list_tab_page.dart';
12
+import 'package:lszlgl/service/dict_service.dart';
13
+import 'package:lszlgl/widget/button.dart';
14
+import 'package:lszlgl/widget/page_widget.dart';
15
+
16
+/// 扦样环节列表
17
+class SampleTaskListPage extends StatefulWidget {
18
+  final StepType type;
19
+  final bool complete;
20
+
21
+  const SampleTaskListPage({
22
+    super.key,
23
+    required this.type,
24
+    this.complete = false,
25
+  });
26
+
27
+  @override
28
+  State<SampleTaskListPage> createState() => _SampleTaskListPageState();
29
+}
30
+
31
+class _SampleTaskListPageState extends BaseLifecycleState<SampleTaskListPage> with AutomaticKeepAliveClientMixin {
32
+  late EasyRefreshController refreshCtrl;
33
+
34
+  int pageNo = 1;
35
+  int pageSize = 10;
36
+
37
+  final pageState = DataStatusModel<List<SampleTaskItem>>().notifier<DataStatusModel<List<SampleTaskItem>>>();
38
+
39
+  /// 详情
40
+  void startDetail() {
41
+    if (!widget.complete) return;
42
+    switch (widget.type) {
43
+      case StepType.reap:
44
+        MyRouter.startReapSampleTask(detail: true);
45
+        break;
46
+      case StepType.stock:
47
+        break;
48
+    }
49
+  }
50
+
51
+  /// 扦样
52
+  void startSample() {
53
+    switch (widget.type) {
54
+      case StepType.reap:
55
+        MyRouter.startReapSampleTask();
56
+        break;
57
+      case StepType.stock:
58
+        break;
59
+    }
60
+  }
61
+
62
+  void getData({bool first = false, bool refresh = true}) async {
63
+    if (refresh) {
64
+      pageNo = 1;
65
+    }
66
+    try {
67
+      var value = await Api().sampleTaskList(
68
+        pageNo,
69
+        pageSize,
70
+        deliveryStatus: widget.complete ? 1 : 0,
71
+        rwlx: widget.type.value,
72
+      );
73
+      List<SampleTaskItem> data = value.data?.list ?? [];
74
+      var list = pageState.value.data ?? [];
75
+      if (refresh) {
76
+        list = data;
77
+        refreshCtrl.finishRefresh(IndicatorResult.success, true);
78
+        refreshCtrl.resetFooter();
79
+      } else {
80
+        list.addAll(data);
81
+      }
82
+      pageState.update(pageState.value.success(data: list));
83
+      if (data.isEmpty) {
84
+        refreshCtrl.finishLoad(IndicatorResult.noMore, true);
85
+      } else {
86
+        refreshCtrl.finishLoad(IndicatorResult.success, true);
87
+      }
88
+      pageNo++;
89
+    } on DioException catch (err) {
90
+      logger.e('${err.message}');
91
+      if (pageNo == 1) pageState.update(pageState.value.error());
92
+      if (refresh) {
93
+        refreshCtrl.finishRefresh(IndicatorResult.fail, true);
94
+      } else {
95
+        refreshCtrl.finishLoad(IndicatorResult.fail, true);
96
+      }
97
+    }
98
+  }
99
+
100
+  @override
101
+  void onInit() {
102
+    refreshCtrl = EasyRefreshController(
103
+      controlFinishRefresh: true,
104
+      controlFinishLoad: true,
105
+    );
106
+  }
107
+
108
+  @override
109
+  void onFirstShow(Duration timeStamp) {
110
+    refreshCtrl.callRefresh(overOffset: 200);
111
+  }
112
+
113
+  @override
114
+  void onDestroy() {
115
+    refreshCtrl.dispose();
116
+  }
117
+
118
+  @override
119
+  Widget build(BuildContext context) {
120
+    super.build(context);
121
+    return Container(
122
+      clipBehavior: Clip.hardEdge,
123
+      decoration: const BoxDecoration(
124
+        color: Colors.white,
125
+        borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
126
+      ),
127
+      alignment: Alignment.center,
128
+      child: buildBody(),
129
+    );
130
+  }
131
+
132
+  Widget buildBody() {
133
+    return EasyRefresh.builder(
134
+      controller: refreshCtrl,
135
+      onRefresh: () => getData(refresh: true),
136
+      onLoad: () => getData(refresh: false),
137
+      childBuilder: (_, physics) => buildList(physics),
138
+    );
139
+  }
140
+
141
+  Widget buildList(ScrollPhysics physics) {
142
+    var sliver = pageState.builder((v) {
143
+      var list = v.data;
144
+      if (v.status == DataStatus.error) {
145
+        // 加载失败
146
+        return SliverToBoxAdapter(child: PageLoadingWidget.error(onTap: () => refreshCtrl.callRefresh()));
147
+      } else if (list == null || list.isEmpty) {
148
+        // 无数据
149
+        return const SliverToBoxAdapter(child: PageLoadingWidget.empty());
150
+      } else {
151
+        return SliverList.builder(
152
+          itemCount: list.length,
153
+          itemBuilder: (_, index) => buildItem(index, list[index]),
154
+        );
155
+      }
156
+    });
157
+    return CustomScrollView(
158
+      physics: physics,
159
+      slivers: [sliver],
160
+    );
161
+  }
162
+
163
+  Widget buildItem(int index, SampleTaskItem item) {
164
+    return GestureDetector(
165
+      behavior: HitTestBehavior.opaque,
166
+      onTap: () => startDetail(),
167
+      child: Container(
168
+        margin: const EdgeInsets.only(left: 12, right: 12, top: 12),
169
+        decoration: const BoxDecoration(
170
+          color: Color(0xFFF5FFFD),
171
+          borderRadius: BorderRadius.all(Radius.circular(8)),
172
+        ),
173
+        child: Column(
174
+          crossAxisAlignment: CrossAxisAlignment.start,
175
+          children: [
176
+            const SizedBox(height: 15),
177
+            buildTop(item.getDeliveryStatusText()),
178
+            buildNumber(item.qyrwdh ?? ''),
179
+            buildGrid(item),
180
+            buildBottom(item),
181
+            const SizedBox(height: 15),
182
+          ],
183
+        ),
184
+      ),
185
+    );
186
+  }
187
+
188
+  Widget buildTop(String state) {
189
+    return Row(
190
+      children: [
191
+        buildVLine(),
192
+        const Expanded(
193
+          child: Text(
194
+            '扦样任务单号',
195
+            style: TextStyle(color: MyColor.c_333333, fontSize: 18, fontWeight: FontWeight.w500),
196
+          ),
197
+        ),
198
+        buildState(state),
199
+      ],
200
+    );
201
+  }
202
+
203
+  Widget buildVLine() {
204
+    return Container(
205
+      width: 4,
206
+      height: 20,
207
+      margin: const EdgeInsets.only(right: 8),
208
+      decoration: const BoxDecoration(
209
+        color: MyColor.c_25A6EE,
210
+        borderRadius: BorderRadius.all(Radius.circular(2)),
211
+      ),
212
+    );
213
+  }
214
+
215
+  Widget buildState(String state) {
216
+    return Container(
217
+      padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 4),
218
+      decoration: BoxDecoration(
219
+        color: MyColor.c_25A6EE.withOpacity(0.1),
220
+        borderRadius: const BorderRadius.horizontal(left: Radius.circular(100)),
221
+      ),
222
+      child: Text(
223
+        '状态:$state',
224
+        style: const TextStyle(color: MyColor.c_1383C2, fontSize: 16),
225
+      ),
226
+    );
227
+  }
228
+
229
+  Widget buildNumber(String number) {
230
+    return Padding(
231
+      padding: const EdgeInsets.only(left: 12, top: 4, bottom: 6),
232
+      child: Text(
233
+        number,
234
+        style: const TextStyle(color: MyColor.c_333333, fontSize: 18, fontWeight: FontWeight.w500),
235
+      ),
236
+    );
237
+  }
238
+
239
+  Widget buildGrid(SampleTaskItem item) {
240
+    List<Map<String, String>> infoList;
241
+    var jclb = DictService.get().getLabel(DictType.jclb, value: item.jclb)?.label;
242
+    if (widget.complete) {
243
+      infoList = [
244
+        {'采样品种': item.cypzName ?? ''},
245
+        {'粮食品类': item.lspz ?? ''},
246
+        {'监测类别': jclb ?? ''},
247
+        {'扦样数量(kg)': '${item.qysl ?? ''}'},
248
+        {'扦样人员': item.name ?? ''},
249
+        {'扦样时间': item.qysj ?? ''},
250
+      ];
251
+    } else {
252
+      infoList = [
253
+        {'采样品种': item.cypzName ?? ''},
254
+        {'报送截止时间': item.bsjzsj ?? ''},
255
+        {'监测类别': jclb ?? ''},
256
+        {'扦样人员': item.name ?? ''},
257
+      ];
258
+    }
259
+    return Padding(
260
+      padding: const EdgeInsets.symmetric(horizontal: 12),
261
+      child: LayoutBuilder(builder: (context, constraints) {
262
+        return Wrap(
263
+          spacing: 4,
264
+          runSpacing: 4,
265
+          children: infoList.map((item) {
266
+            return SizedBox(
267
+              width: constraints.maxWidth / 2 - 2,
268
+              child: Text(
269
+                '${item.keys.first}:${item.values.first}',
270
+                style: const TextStyle(fontSize: 16, color: MyColor.c_666666),
271
+              ),
272
+            );
273
+          }).toList(),
274
+        );
275
+      }),
276
+    );
277
+  }
278
+
279
+  Widget buildBottom(SampleTaskItem item) {
280
+    if (widget.complete) return const SizedBox.shrink();
281
+    return Column(
282
+      children: [
283
+        buildDivider(),
284
+        Row(
285
+          children: [
286
+            const SizedBox(width: 12),
287
+            Expanded(
288
+              child: Text(
289
+                '[${item.qyryName ?? ''}]创建于${item.createTime ?? ''}',
290
+                style: const TextStyle(fontSize: 16, color: MyColor.c_666666),
291
+              ),
292
+            ),
293
+            const SizedBox(width: 4),
294
+            MyButton(
295
+              '开始扦样',
296
+              onTap: () => startSample(),
297
+              fountSize: 16,
298
+              alignment: null,
299
+              padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12),
300
+            ),
301
+            const SizedBox(width: 12),
302
+          ],
303
+        ),
304
+      ],
305
+    );
306
+  }
307
+
308
+  Widget buildDivider() {
309
+    return Container(
310
+      width: double.infinity,
311
+      height: 1,
312
+      color: MyColor.c_3BD2E5.withOpacity(0.15),
313
+      margin: const EdgeInsets.symmetric(vertical: 10),
314
+    );
315
+  }
316
+
317
+  @override
318
+  bool get wantKeepAlive => true;
319
+}

+ 16 - 18
lib/page/reap_step/reap_step_tab_page.dart

@@ -1,22 +1,22 @@
1 1
 import 'package:flutter/material.dart';
2 2
 import 'package:lszlgl/base/base_lifecycle_state.dart';
3 3
 import 'package:lszlgl/config/colors.dart';
4
-import 'package:lszlgl/main.dart';
5
-import 'package:lszlgl/page/reap_step/reap_step_list_page.dart';
4
+import 'package:lszlgl/page/reap_step/sample_task_list_page.dart';
6 5
 
7 6
 enum StepType {
8
-  reap(title: '收获环节'),
9
-  stock(title: '库存环节');
7
+  reap('收获环节', 1),
8
+  stock('库存环节', 2);
10 9
 
11
-  const StepType({required this.title});
10
+  const StepType(this.title, this.value);
12 11
 
13 12
   final String title;
13
+  final int value;
14 14
 }
15 15
 
16
-class ReapStepTabPageArgs {
16
+class SampleTaskListTabPageArgs {
17 17
   final StepType type;
18 18
 
19
-  const ReapStepTabPageArgs({required this.type});
19
+  const SampleTaskListTabPageArgs({required this.type});
20 20
 
21 21
   @override
22 22
   String toString() {
@@ -25,20 +25,20 @@ class ReapStepTabPageArgs {
25 25
 }
26 26
 
27 27
 /// 收获环节
28
-class ReapStepTabPage extends StatefulWidget {
29
-  final ReapStepTabPageArgs args;
28
+class SampleTaskListTabPage extends StatefulWidget {
29
+  final SampleTaskListTabPageArgs args;
30 30
 
31
-  const ReapStepTabPage({
31
+  const SampleTaskListTabPage({
32 32
     Key? key,
33
-    ReapStepTabPageArgs? args,
34
-  })  : args = args ?? const ReapStepTabPageArgs(type: StepType.reap),
33
+    SampleTaskListTabPageArgs? args,
34
+  })  : args = args ?? const SampleTaskListTabPageArgs(type: StepType.reap),
35 35
         super(key: key);
36 36
 
37 37
   @override
38
-  State<ReapStepTabPage> createState() => _ReapStepTabPageState();
38
+  State<SampleTaskListTabPage> createState() => _SampleTaskListTabPageState();
39 39
 }
40 40
 
41
-class _ReapStepTabPageState extends BaseLifecycleState<ReapStepTabPage> with TickerProviderStateMixin {
41
+class _SampleTaskListTabPageState extends BaseLifecycleState<SampleTaskListTabPage> with TickerProviderStateMixin {
42 42
   late TabController tabCtrl;
43 43
   late PageController pageCtrl;
44 44
 
@@ -47,14 +47,13 @@ class _ReapStepTabPageState extends BaseLifecycleState<ReapStepTabPage> with Tic
47 47
 
48 48
   @override
49 49
   void onInit() {
50
-    logger.d('type:${widget.args.type}');
51 50
     tabCtrl = TabController(length: 2, vsync: this);
52 51
     pageCtrl = PageController();
53 52
 
54 53
     tabTextList = ['待扦样', '扦样完成'];
55 54
     pageList = [
56
-      ReapStepListPage(type: widget.args.type),
57
-      ReapStepListPage(type: widget.args.type, complete: true),
55
+      SampleTaskListPage(type: widget.args.type),
56
+      SampleTaskListPage(type: widget.args.type, complete: true),
58 57
     ];
59 58
   }
60 59
 
@@ -113,7 +112,6 @@ class _ReapStepTabPageState extends BaseLifecycleState<ReapStepTabPage> with Tic
113 112
   Widget buildPage() {
114 113
     return PageView.builder(
115 114
       controller: pageCtrl,
116
-      // physics: const BouncingScrollPhysics(),
117 115
       onPageChanged: (index) {
118 116
         if (index == tabCtrl.index) return;
119 117
         tabCtrl.animateTo(index);

+ 1 - 1
lib/page/user_center/account_manage_page.dart

@@ -2,7 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
2 2
 import 'package:flutter/material.dart';
3 3
 import 'package:lszlgl/base/base_lifecycle_state.dart';
4 4
 import 'package:lszlgl/base/base_state.dart';
5
-import 'package:lszlgl/network/rsp/user_rsp.dart';
5
+import 'package:lszlgl/model/rsp/user_rsp.dart';
6 6
 import 'package:lszlgl/service/user_service.dart';
7 7
 import 'package:lszlgl/widget/button.dart';
8 8
 import 'package:lszlgl/widget/card_item.dart';

+ 1 - 1
lib/page/user_center/user_center_page.dart

@@ -3,8 +3,8 @@ import 'package:easy_refresh/easy_refresh.dart';
3 3
 import 'package:flutter/material.dart';
4 4
 import 'package:lszlgl/base/base_lifecycle_state.dart';
5 5
 import 'package:lszlgl/base/base_state.dart';
6
+import 'package:lszlgl/model/rsp/user_rsp.dart';
6 7
 import 'package:lszlgl/network/api.dart';
7
-import 'package:lszlgl/network/rsp/user_rsp.dart';
8 8
 import 'package:lszlgl/service/user_service.dart';
9 9
 import 'package:lszlgl/widget/card_item.dart';
10 10
 

+ 5 - 5
lib/router/my_router.dart

@@ -1,7 +1,7 @@
1 1
 import 'package:lszlgl/page/login/login_page.dart';
2 2
 import 'package:lszlgl/page/main_tab_page.dart';
3 3
 import 'package:lszlgl/page/reap_step/reap_sample_task/reap_sample_task_page.dart';
4
-import 'package:lszlgl/page/reap_step/reap_step_tab_page.dart';
4
+import 'package:lszlgl/page/reap_step/sample_task_list_tab_page.dart';
5 5
 import 'package:lszlgl/page/user_center/account_manage_page.dart';
6 6
 import 'package:lszlgl/page/user_center/change_pwd_page.dart';
7 7
 import 'package:lszlgl/page/user_center/setting_page.dart';
@@ -18,7 +18,7 @@ const rSettingPage = '/SettingPage';
18 18
 // 修改密码
19 19
 const rChangePwdPage = '/ChangePwdPage';
20 20
 // 收获流程列表
21
-const rReapStepTabPage = '/ReapStepTabPage';
21
+const rSampleTaskListTabPage = '/SampleTaskListTabPage';
22 22
 // 收获扦样任务
23 23
 const rReapSampleTaskPage = '/ReapSampleTaskPage';
24 24
 
@@ -29,7 +29,7 @@ final Map<String, MyNavigatorBuilder> rRouteMap = {
29 29
   rAccountManagePage: (context, args) => const AccountManagePage(),
30 30
   rSettingPage: (context, args) => const SettingPage(),
31 31
   rChangePwdPage: (context, args) => const ChangePwdPage(),
32
-  rReapStepTabPage: (context, args) => ReapStepTabPage(args: args as ReapStepTabPageArgs?),
32
+  rSampleTaskListTabPage: (context, args) => SampleTaskListTabPage(args: args as SampleTaskListTabPageArgs?),
33 33
   rReapSampleTaskPage: (context, args) => ReapSampleTaskPage(detail: args as bool?),
34 34
 };
35 35
 
@@ -70,8 +70,8 @@ class MyRouter {
70 70
   }
71 71
 
72 72
   /// 收获环节列表
73
-  static void startReapStepList(ReapStepTabPageArgs args) {
74
-    MyNavigator.push(rReapStepTabPage, args: args);
73
+  static void startSampleTaskList(SampleTaskListTabPageArgs args) {
74
+    MyNavigator.push(rSampleTaskListTabPage, args: args);
75 75
   }
76 76
 
77 77
   /// 收获扦样任务

+ 47 - 0
lib/service/dict_service.dart

@@ -0,0 +1,47 @@
1
+import 'package:lszlgl/model/rsp/dict_rsp.dart';
2
+
3
+enum DictType {
4
+  /// 监测类别
5
+  jclb('jclb');
6
+
7
+  const DictType(this.type);
8
+
9
+  final String type;
10
+}
11
+
12
+class DictService {
13
+  DictService._();
14
+
15
+  static DictService? _instance;
16
+
17
+  static DictService get() => _instance ??= DictService._();
18
+
19
+  List<DictRsp>? _dictList;
20
+
21
+  List<DictRsp> get dictList => _dictList ??= [];
22
+
23
+  final Map<String, Map<String, DictRsp>> _dictMap = {};
24
+
25
+  void saveDictList(List<DictRsp>? list) {
26
+    if (list == null) return;
27
+    _dictList = list;
28
+    // 按类型存储字典
29
+    _dictMap.clear();
30
+    for (DictRsp dict in list) {
31
+      if (dict.dictType == null || dict.value == null) continue;
32
+      Map<String, DictRsp> map = _dictMap[dict.dictType!] ??= {};
33
+      map[dict.value!] = dict;
34
+    }
35
+  }
36
+
37
+  DictRsp? getLabel(DictType type, {num? value, String? valueStr}) {
38
+    String? v;
39
+    if (valueStr == null) {
40
+      if (value == null) return null;
41
+      v = value.toString();
42
+    } else {
43
+      v = valueStr;
44
+    }
45
+    return _dictMap[type.type]?[v];
46
+  }
47
+}

+ 2 - 2
lib/service/user_service.dart

@@ -1,7 +1,7 @@
1 1
 import 'dart:convert';
2 2
 
3
-import 'package:lszlgl/network/rsp/login_rsp.dart';
4
-import 'package:lszlgl/network/rsp/user_rsp.dart';
3
+import 'package:lszlgl/model/rsp/login_rsp.dart';
4
+import 'package:lszlgl/model/rsp/user_rsp.dart';
5 5
 import 'package:lszlgl/router/my_router.dart';
6 6
 import 'package:lszlgl/utils/sp_utils.dart';
7 7
 

+ 112 - 0
lib/utils/inject.dart

@@ -0,0 +1,112 @@
1
+import 'dart:async';
2
+
3
+import 'package:get_it/get_it.dart';
4
+import 'package:lszlgl/main.dart';
5
+
6
+/// 依赖注入管理
7
+///
8
+/// ```
9
+/// 简单使用
10
+/// 添加注入:
11
+/// var user = Inject.put<UserBean>(UserBean(), dispose: (v) => v.dispose());
12
+/// 添加注入(懒加载):
13
+/// Inject.putLazy(UserBean(), dispose: (v) => v.dispose());
14
+///
15
+/// 获取实例:
16
+/// var user = Inject.get<UserBean>();
17
+///
18
+/// 移除注入:
19
+/// Inject.remove<UserBean>();
20
+/// ```
21
+class Inject {
22
+  Inject._();
23
+
24
+  /// 添加依赖注入
25
+  /// 注入后得到实例化对象, 也可以通过[get]方法得到对象.
26
+  /// * [instance] 实例化对象
27
+  /// * [name] 注入多个同类型对象时,可以使用name来区分
28
+  /// * [dispose] 移除时回调方法
29
+  /// * [allowReassignment] 是否可以重复注册, 默认不可重复注册, 返回之前已有实例
30
+  ///
31
+  static T put<T extends Object>(
32
+    T instance, {
33
+    String? name,
34
+    FutureOr Function(T)? dispose,
35
+    bool allowReassignment = false,
36
+  }) {
37
+    GetIt.I.allowReassignment = true;
38
+    // 不可重复注册, 已注册,则返回之前实例
39
+    if (!allowReassignment && GetIt.I.isRegistered<T>(instanceName: name)) {
40
+      logger.d('Inject put:$T 已被注册');
41
+      return get<T>()!;
42
+    }
43
+    logger.d('Inject put:$T');
44
+    GetIt.I.registerSingleton<T>(
45
+      instance,
46
+      instanceName: name,
47
+      dispose: dispose,
48
+    );
49
+    return instance;
50
+  }
51
+
52
+  /// 添加依赖注入 懒加载
53
+  /// 注入后不会立即实例化对象, 当调用[get]时才会实例化.
54
+  /// * [factoryFunc] 实例化对象回调方法
55
+  /// * [name] 注入多个同类型对象时,可以使用name来区分
56
+  /// * [dispose] 移除时回调方法
57
+  static void putLazy<T extends Object>(
58
+    T Function() factoryFunc, {
59
+    String? name,
60
+    FutureOr Function(T)? dispose,
61
+    bool allowReassignment = false,
62
+  }) {
63
+    GetIt.I.allowReassignment = true;
64
+    if (!allowReassignment && GetIt.I.isRegistered<T>(instanceName: name)) {
65
+      logger.d('Inject putLazy:$T 已被注册');
66
+      return;
67
+    }
68
+    logger.d('Inject putLazy:$T');
69
+    GetIt.I.registerLazySingleton<T>(
70
+      factoryFunc,
71
+      instanceName: name,
72
+      dispose: dispose,
73
+    );
74
+  }
75
+
76
+  /// 移除依赖注入
77
+  /// * [instance] 通过实例移除
78
+  /// * [name] 通过名称移除
79
+  /// * [dispose] 移除时回调方法
80
+  static FutureOr remove<T extends Object>({
81
+    Object? instance,
82
+    String? name,
83
+    FutureOr Function(T)? dispose,
84
+  }) {
85
+    logger.d('Inject remove:$T');
86
+    return GetIt.I.unregister(
87
+      instance: instance,
88
+      instanceName: name,
89
+      disposingFunction: dispose,
90
+    );
91
+  }
92
+
93
+  /// 获取唯一实例
94
+  /// Model model = GdInject.get<Model>();
95
+  static T? get<T extends Object>({String? name}) {
96
+    logger.d('Inject get:$T');
97
+    return GetIt.I.get<T>(instanceName: name);
98
+  }
99
+
100
+  /// 获取唯一实例,如果未注入依赖,将自动注入依赖
101
+  static T getAndPut<T extends Object>(
102
+    T instance, {
103
+    String? name,
104
+    FutureOr Function(T)? dispose,
105
+  }) {
106
+    // 已注册
107
+    if (GetIt.I.isRegistered<T>(instanceName: name)) {
108
+      return get<T>(name: name)!;
109
+    }
110
+    return put<T>(instance, name: name, dispose: dispose);
111
+  }
112
+}

+ 1 - 1
lib/widget/button.dart

@@ -32,7 +32,7 @@ class MyButton extends StatelessWidget {
32 32
     this.fountColor = Colors.white,
33 33
     this.fontWeight,
34 34
     this.margin,
35
-    this.padding = const EdgeInsets.all(8),
35
+    this.padding = const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
36 36
     this.alignment = Alignment.center,
37 37
   }) : super(key: key);
38 38
 

+ 4 - 3
lib/widget/page_widget.dart

@@ -41,7 +41,7 @@ class PageLoadingWidget extends StatelessWidget {
41 41
   const PageLoadingWidget.empty({
42 42
     super.key,
43 43
     this.alignment,
44
-    this.message,
44
+    this.message = '暂无数据',
45 45
     this.padding = const EdgeInsets.only(top: 150),
46 46
   })  : isLoading = false,
47 47
         title = null,
@@ -51,7 +51,7 @@ class PageLoadingWidget extends StatelessWidget {
51 51
   const PageLoadingWidget.error({
52 52
     super.key,
53 53
     this.alignment,
54
-    this.title,
54
+    this.title = '加载失败, 请重试',
55 55
     this.onTap,
56 56
     this.btnText = '点击重试',
57 57
     this.padding = const EdgeInsets.only(top: 150),
@@ -99,7 +99,7 @@ class PageLoadingWidget extends StatelessWidget {
99 99
       padding: const EdgeInsets.only(bottom: 12),
100 100
       child: Text(
101 101
         message!,
102
-        style: const TextStyle(fontSize: 12, color: MyColor.c_666666),
102
+        style: const TextStyle(fontSize: 16, color: MyColor.c_666666),
103 103
       ),
104 104
     );
105 105
   }
@@ -109,6 +109,7 @@ class PageLoadingWidget extends StatelessWidget {
109 109
     return MyButton(
110 110
       btnText!,
111 111
       onTap: onTap,
112
+      alignment: null,
112 113
     );
113 114
   }
114 115
 }

+ 8 - 0
pubspec.lock

@@ -405,6 +405,14 @@ packages:
405 405
       url: "https://pub.dev"
406 406
     source: hosted
407 407
     version: "3.2.0"
408
+  get_it:
409
+    dependency: "direct main"
410
+    description:
411
+      name: get_it
412
+      sha256: e6017ce7fdeaf218dc51a100344d8cb70134b80e28b760f8bb23c242437bafd7
413
+      url: "https://pub.dev"
414
+    source: hosted
415
+    version: "7.6.7"
408 416
   glob:
409 417
     dependency: transitive
410 418
     description:

+ 2 - 0
pubspec.yaml

@@ -68,6 +68,8 @@ dependencies:
68 68
   shared_preferences: ^2.2.2
69 69
   # 下拉刷新上拉加载
70 70
   easy_refresh: ^3.3.4
71
+  # 依赖注入
72
+  get_it: ^7.1.3
71 73
 
72 74
 dev_dependencies:
73 75
   flutter_test: