Browse Source

增加二维码显示、保存相册、扦样列表筛选功能

mq 11 months ago
parent
commit
cd5418ff89

+ 2 - 1
android/app/src/main/AndroidManifest.xml

@@ -41,7 +41,8 @@
41 41
     <application
42 42
         android:name="${applicationName}"
43 43
         android:icon="@drawable/ic_launcher"
44
-        android:label="国粮质检">
44
+        android:label="国粮质检"
45
+        android:requestLegacyExternalStorage="true">
45 46
         <activity
46 47
             android:name=".MainActivity"
47 48
             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"

+ 5 - 5
lib/base/base_state.dart

@@ -8,6 +8,10 @@ export 'package:lszlgl/router/my_router.dart';
8 8
 export 'package:lszlgl/ext/value_notifier_ext.dart';
9 9
 
10 10
 abstract class BaseState<T extends StatefulWidget> extends State<T> {
11
+  EdgeInsets get mediaPadding => MediaQuery.of(context).padding;
12
+
13
+  double getBottomPadding(double defaultValue) => mediaPadding.bottom != 0 ? mediaPadding.bottom : defaultValue;
14
+
11 15
   /// 隐藏软键盘
12 16
   void hideKeyboard() {
13 17
     FocusScopeNode currentFocus = FocusScope.of(context);
@@ -40,11 +44,7 @@ abstract class BaseState<T extends StatefulWidget> extends State<T> {
40 44
       body: Stack(
41 45
         children: [
42 46
           SizedBox(width: double.infinity, child: Image.asset(imgHomeTopBg)),
43
-          Padding(
44
-            padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
45
-            child: child,
46
-          ),
47
-           // child,
47
+          child,
48 48
         ],
49 49
       ),
50 50
     );

+ 13 - 5
lib/model/req/sample_task_list_req.dart

@@ -16,19 +16,27 @@ class SampleTaskListReq {
16 16
   /// 环节类型:1收获环节,2库存环节
17 17
   int? rwlx;
18 18
 
19
-  /// 采样品种ID集合
20
-  List<int>? pzIdList;
19
+  /// 采样品种名称
20
+  String? cypzName;
21
+
22
+  /// 检验指标
23
+  String? jyzb;
24
+
25
+  /// 样品等级
26
+  int? ypdj;
21 27
 
22 28
   /// 行政区划
23
-  String? xzqh;
29
+  String? qydq;
24 30
 
25 31
   SampleTaskListReq({
26 32
     this.pageNo = 1,
27 33
     this.pageSize = 10,
28 34
     this.deliveryStatus,
29 35
     this.rwlx,
30
-    this.pzIdList,
31
-    this.xzqh,
36
+    this.cypzName,
37
+    this.jyzb,
38
+    this.ypdj,
39
+    this.qydq,
32 40
   });
33 41
 
34 42
   factory SampleTaskListReq.fromJson(Map<String, dynamic> json) => _$SampleTaskListReqFromJson(json);

+ 8 - 5
lib/model/req/sample_task_list_req.g.dart

@@ -12,9 +12,10 @@ SampleTaskListReq _$SampleTaskListReqFromJson(Map<String, dynamic> json) =>
12 12
       pageSize: json['pageSize'] as int? ?? 10,
13 13
       deliveryStatus: json['deliveryStatus'] as int?,
14 14
       rwlx: json['rwlx'] as int?,
15
-      pzIdList:
16
-          (json['pzIdList'] as List<dynamic>?)?.map((e) => e as int).toList(),
17
-      xzqh: json['xzqh'] as String?,
15
+      cypzName: json['cypzName'] as String?,
16
+      jyzb: json['jyzb'] as String?,
17
+      ypdj: json['ypdj'] as int?,
18
+      qydq: json['qydq'] as String?,
18 19
     );
19 20
 
20 21
 Map<String, dynamic> _$SampleTaskListReqToJson(SampleTaskListReq instance) =>
@@ -23,6 +24,8 @@ Map<String, dynamic> _$SampleTaskListReqToJson(SampleTaskListReq instance) =>
23 24
       'pageSize': instance.pageSize,
24 25
       'deliveryStatus': instance.deliveryStatus,
25 26
       'rwlx': instance.rwlx,
26
-      'pzIdList': instance.pzIdList,
27
-      'xzqh': instance.xzqh,
27
+      'cypzName': instance.cypzName,
28
+      'jyzb': instance.jyzb,
29
+      'ypdj': instance.ypdj,
30
+      'qydq': instance.qydq,
28 31
     };

+ 2 - 1
lib/model/rsp/sample_task_rsp.dart

@@ -297,9 +297,10 @@ class SampleTaskItem {
297 297
 
298 298
 @JsonSerializable()
299 299
 class UrlItem {
300
+  final String? name;
300 301
   final String? url;
301 302
 
302
-  const UrlItem({this.url});
303
+  const UrlItem({this.name,this.url});
303 304
 
304 305
   factory UrlItem.fromJson(Map<String, dynamic> json) => _$UrlItemFromJson(json);
305 306
 

+ 2 - 0
lib/model/rsp/sample_task_rsp.g.dart

@@ -234,10 +234,12 @@ Map<String, dynamic> _$SampleTaskItemToJson(SampleTaskItem instance) =>
234 234
     };
235 235
 
236 236
 UrlItem _$UrlItemFromJson(Map<String, dynamic> json) => UrlItem(
237
+      name: json['name'] as String?,
237 238
       url: json['url'] as String?,
238 239
     );
239 240
 
240 241
 Map<String, dynamic> _$UrlItemToJson(UrlItem instance) => <String, dynamic>{
242
+      'name': instance.name,
241 243
       'url': instance.url,
242 244
     };
243 245
 

+ 75 - 51
lib/page/filter/filter_page.dart

@@ -24,53 +24,59 @@ class _FilterPageState extends BaseState<FilterPage> {
24 24
   late SampleListVM vm;
25 25
 
26 26
   /// 采样品种
27
-  List<CardMenuData> cypzList = [];
28
-  final cypzNames = null.notifier<String?>();
29
-  List<CardMenuData> selectCypzList = [];
27
+  final cypzList = <CardMenuData>[].notifier<List<CardMenuData>>();
28
+  final cypz = null.notifier<CardMenuData?>();
29
+
30
+  /// 检验指标
31
+  final jyzbList = <CardMenuData>[].notifier<List<CardMenuData>>();
32
+  final jyzb = null.notifier<CardMenuData?>();
33
+
34
+  /// 样品等级
35
+  final ypdjList = <CardMenuData>[].notifier<List<CardMenuData>>();
36
+  final ypdj = null.notifier<CardMenuData?>();
30 37
 
31 38
   /// 扦样地区
32
-  String? xzqh;
39
+  String? qydq;
33 40
 
34 41
   void getCypzList() {
35
-    cypzList = (DictService.getDictList(DictType.cypz) ?? []).map((e) => CardMenuData(e.label, e.value)).toList();
36
-    if ((vm.reqList.first.pzIdList ?? []).isNotEmpty) {
37
-      for (var id in vm.reqList.first.pzIdList!) {
38
-        for (var menu in cypzList) {
39
-          if (int.parse(menu.value) == id) {
40
-            menu.select = true;
41
-            selectCypzList.add(menu);
42
-            break;
43
-          }
44
-        }
42
+    cypzList.value = (DictService.getDictList(DictType.cypz) ?? []).map((e) => CardMenuData(e.label, e.value)).toList();
43
+    for (var item in cypzList.value) {
44
+      if (vm.reqList.first.cypzName == item.name) {
45
+        cypz.value = item;
46
+        break;
45 47
       }
46 48
     }
47
-    cypzSelCallback(selectCypzList);
48 49
   }
49 50
 
50
-  void cypzSelCallback(List<CardMenuData> selectList) async {
51
-    selectCypzList = selectList;
52
-    if (selectList.isEmpty) {
53
-      cypzNames.value = null;
54
-      return;
51
+  void getJyzbList() {
52
+    jyzbList.value = (DictService.getDictList(DictType.jylx) ?? []).map((e) => CardMenuData(e.label, e.value)).toList();
53
+    if (vm.reqList.first.jyzb == null) return;
54
+
55
+    for (var item in jyzbList.value) {
56
+      if (vm.reqList.first.jyzb == item.name) {
57
+        jyzb.value = item;
58
+        break;
59
+      }
55 60
     }
56
-    var names = StringBuffer();
57
-    var ids = StringBuffer();
58
-    for (int i = 0; i < selectList.length; i++) {
59
-      var item = selectList[i];
60
-      names.write(item.name);
61
-      ids.write(item.value);
62
-      if (i < selectList.length - 1) {
63
-        names.write(',');
64
-        ids.write(',');
61
+  }
62
+
63
+  void getYpdjList() {
64
+    ypdjList.value = (DictService.getDictList(DictType.ypdj) ?? []).map((e) => CardMenuData(e.label, e.value)).toList();
65
+    if (vm.reqList.first.ypdj == null) return;
66
+    for (var item in ypdjList.value) {
67
+      if (vm.reqList.first.ypdj == item.value) {
68
+        ypdj.value = item;
69
+        break;
65 70
       }
66 71
     }
67
-    cypzNames.value = names.toString();
68 72
   }
69 73
 
70 74
   void onReset() {
71 75
     for (var req in vm.reqList) {
72
-      req.pzIdList = null;
73
-      req.xzqh = null;
76
+      req.cypzName = null;
77
+      req.jyzb = null;
78
+      req.ypdj = null;
79
+      req.qydq = null;
74 80
     }
75 81
     vm.refreshAll();
76 82
     MyNavigator.pop();
@@ -78,8 +84,10 @@ class _FilterPageState extends BaseState<FilterPage> {
78 84
 
79 85
   void onConfirm() {
80 86
     for (var req in vm.reqList) {
81
-      req.pzIdList = selectCypzList.map((e) => int.parse(e.value)).toList();
82
-      req.xzqh = xzqh;
87
+      req.cypzName = cypz.value?.name;
88
+      req.jyzb = jyzb.value?.name;
89
+      req.ypdj = ypdj.value == null ? null : int.parse(ypdj.value!.value);
90
+      req.qydq = qydq;
83 91
     }
84 92
     vm.refreshAll();
85 93
     MyNavigator.pop();
@@ -92,12 +100,15 @@ class _FilterPageState extends BaseState<FilterPage> {
92 100
 
93 101
     // 采样品种
94 102
     getCypzList();
95
-    xzqh = vm.reqList.first.xzqh;
103
+    // 检验指标
104
+    getJyzbList();
105
+    // 样品等级
106
+    getYpdjList();
107
+    qydq = vm.reqList.first.qydq;
96 108
   }
97 109
 
98 110
   @override
99 111
   void dispose() {
100
-    cypzNames.dispose();
101 112
     super.dispose();
102 113
   }
103 114
 
@@ -111,27 +122,40 @@ class _FilterPageState extends BaseState<FilterPage> {
111 122
           mainAxisSize: MainAxisSize.min,
112 123
           children: [
113 124
             buildTitle(),
114
-            cypzNames.builder(
115
-              (v) => CardWidgets.buildMenuDialog(
116
-                false,
117
-                '采样品种',
118
-                v,
119
-                cypzList,
120
-                cypzSelCallback,
121
-                multiple: true,
122
-                showTopLine: true,
123
-                hint: '请选择',
124
-              ),
125
+            CardWidgets.buildMenu(
126
+              false,
127
+              '采样品种',
128
+              cypzList,
129
+              cypz,
130
+              (_, sel) {},
131
+              hint: '请选择',
132
+            ),
133
+            CardWidgets.buildMenu(
134
+              false,
135
+              '检验指标',
136
+              jyzbList,
137
+              jyzb,
138
+              (_, sel) {},
139
+              hint: '请选择',
140
+            ),
141
+            CardWidgets.buildMenu(
142
+              false,
143
+              '样品等级',
144
+              ypdjList,
145
+              ypdj,
146
+              (_, sel) {},
147
+              hint: '请选择',
125 148
             ),
126 149
             CardWidgets.buildEdit(
127 150
               false,
128 151
               '扦样地区',
129
-              xzqh,
130
-              onChanged: (value) => xzqh = value,
131
-              hint: '请输入(模糊查询)',
152
+              qydq,
153
+              onChanged: (value) => qydq = value,
154
+              hint: '请输入',
155
+              bottomLine: false,
132 156
             ),
133 157
             Padding(
134
-              padding: const EdgeInsets.only(top: 64, bottom: 48, left: 16, right: 16),
158
+              padding: EdgeInsets.only(left: 16, right: 16, top: 64, bottom: getBottomPadding(12)),
135 159
               child: Row(
136 160
                 children: [
137 161
                   Expanded(child: MyButton('重置', onTap: onReset)),

+ 62 - 2
lib/page/sample_task/reap_sample_detail/reap_sample_task_page.dart

@@ -1,9 +1,11 @@
1 1
 import 'dart:io';
2 2
 import 'dart:typed_data';
3 3
 
4
-import 'package:flutter/cupertino.dart';
4
+import 'package:cached_network_image/cached_network_image.dart';
5
+import 'package:dio/dio.dart';
5 6
 import 'package:flutter/material.dart';
6 7
 import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart';
8
+import 'package:image_gallery_saver/image_gallery_saver.dart';
7 9
 import 'package:lszlgl/base/base_lifecycle_state.dart';
8 10
 import 'package:lszlgl/config/colors.dart';
9 11
 import 'package:lszlgl/model/rsp/sample_task_rsp.dart';
@@ -142,6 +144,61 @@ class _ReapSampleTaskPageState extends BaseLifecycleState<ReapSampleTaskPage> wi
142 144
     ];
143 145
   }
144 146
 
147
+  /// 查看二维码
148
+  void startQRCode() {
149
+    UrlItem picInfo = pageStatus.value.data!.ewmfilePictureList!.first;
150
+    MyNavigator.showDialog(
151
+      builder: (_) => Container(
152
+        padding: const EdgeInsets.all(16),
153
+        margin: const EdgeInsets.all(24),
154
+        decoration: const BoxDecoration(
155
+          color: Colors.white,
156
+          borderRadius: BorderRadius.all(Radius.circular(24)),
157
+        ),
158
+        child: Column(
159
+          mainAxisSize: MainAxisSize.min,
160
+          children: [
161
+            CachedNetworkImage(
162
+              width: double.infinity,
163
+              fit: BoxFit.cover,
164
+              imageUrl: picInfo.url!,
165
+              placeholder: (_, __) => const Center(child: CircularProgressIndicator()),
166
+              errorWidget: (context, url, error) => const Center(child: Icon(Icons.error)),
167
+            ),
168
+            Padding(
169
+              padding: const EdgeInsets.symmetric(vertical: 16),
170
+              child: Text(
171
+                picInfo.name ?? '',
172
+                style: const TextStyle(fontSize: 16, color: MyColor.c_333333),
173
+              ),
174
+            ),
175
+            Row(
176
+              children: [
177
+                const Expanded(child: MyButton('打印')),
178
+                const SizedBox(width: 16),
179
+                Expanded(child: MyButton('保存图片', onTap: savePic)),
180
+              ],
181
+            ),
182
+          ],
183
+        ),
184
+      ),
185
+    );
186
+  }
187
+
188
+  void savePic() async {
189
+    MyNavigator.showLoading(msg: '保存中...');
190
+    var response = await Dio().get(
191
+        'https://gd-hbimg.huaban.com/c7a22fb15d70a0a976e20fb810c048ec11c76fc31ac08-hajElf_fw658webp',
192
+        options: Options(responseType: ResponseType.bytes));
193
+    final result = await ImageGallerySaver.saveImage(Uint8List.fromList(response.data), quality: 60, name: "hello");
194
+    MyNavigator.dismiss();
195
+    if (result['isSuccess']) {
196
+      MyNavigator.showToast('保存成功');
197
+    } else {
198
+      MyNavigator.showToast('保存失败');
199
+    }
200
+  }
201
+
145 202
   @override
146 203
   void initState() {
147 204
     super.initState();
@@ -281,10 +338,13 @@ class _ReapSampleTaskPageState extends BaseLifecycleState<ReapSampleTaskPage> wi
281 338
 
282 339
   Widget buildButton() {
283 340
     Widget child;
284
-    EdgeInsets margin = const EdgeInsets.symmetric(horizontal: 16, vertical: 12);
341
+    EdgeInsets margin = EdgeInsets.only(left: 16, right: 16, top: 12, bottom: getBottomPadding(12));
285 342
     if (args.detail) {
286 343
       child = Row(
287 344
         children: [
345
+          (pageStatus.value.data?.ewmfilePictureList ?? []).isEmpty
346
+              ? const SizedBox.shrink()
347
+              : Expanded(child: MyButton('查看二维码', onTap: startQRCode, margin: margin)),
288 348
           Expanded(child: MyButton('重新录入', onTap: startEdit, margin: margin)),
289 349
         ],
290 350
       );

+ 43 - 58
lib/page/sample_task/reap_sample_detail/reap_sample_variety_detail_page.dart

@@ -111,7 +111,7 @@ class _ReapSampleVarietyDetailPageState extends BaseLifecycleState<ReapSampleVar
111 111
     });
112 112
   }
113 113
 
114
-  void onRemove(NonghuItem item) async {
114
+  void onRemove(int index, NonghuItem item) async {
115 115
     var delete = await showDialog(
116 116
       context: context,
117 117
       builder: (_) => AlertDialog(
@@ -163,6 +163,9 @@ class _ReapSampleVarietyDetailPageState extends BaseLifecycleState<ReapSampleVar
163 163
       if (menu.value == data?.tqqk) tqqk.value = menu;
164 164
       return menu;
165 165
     }).toList();
166
+    if (!isDetail && (data?.codeSamplingNonghuList ?? []).isEmpty) {
167
+      data?.codeSamplingNonghuList = [NonghuItem()];
168
+    }
166 169
   }
167 170
 
168 171
   @override
@@ -239,7 +242,7 @@ class _ReapSampleVarietyDetailPageState extends BaseLifecycleState<ReapSampleVar
239 242
   Widget buildNonghu(int index, NonghuItem item) {
240 243
     bool detail = item.id != null;
241 244
     return GestureDetector(
242
-      onLongPress: detail ? null : () => onRemove(item),
245
+      onLongPress: detail ? null : () => onRemove(index, item),
243 246
       child: Container(
244 247
         clipBehavior: Clip.hardEdge,
245 248
         decoration: const BoxDecoration(
@@ -247,62 +250,44 @@ class _ReapSampleVarietyDetailPageState extends BaseLifecycleState<ReapSampleVar
247 250
           borderRadius: BorderRadius.all(Radius.circular(8)),
248 251
         ),
249 252
         margin: const EdgeInsets.only(left: 12, right: 12, top: 8),
250
-        child: IntrinsicHeight(
251
-          child: Row(
252
-            mainAxisSize: MainAxisSize.min,
253
-            children: [
254
-              Container(
255
-                color: const Color(0xFF3ACEE6),
256
-                alignment: Alignment.center,
257
-                padding: const EdgeInsets.symmetric(horizontal: 2),
258
-                child: Text(
259
-                  '${index + 1}',
260
-                  style: const TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.w700),
261
-                ),
262
-              ),
263
-              Expanded(
264
-                child: Column(
265
-                  mainAxisSize: MainAxisSize.min,
266
-                  children: [
267
-                    CardWidgets.buildEdit(
268
-                      detail,
269
-                      '扦样数量(公斤)',
270
-                      item.qysl?.toString(),
271
-                      inputType: const TextInputType.numberWithOptions(decimal: true),
272
-                      formatters: [XNumberTextInputFormatter()],
273
-                      onChanged: (value) => item.qysl = value.isEmpty ? null : num.parse(value),
274
-                      backgroundColor: null,
275
-                    ),
276
-                    CardWidgets.buildEdit(
277
-                      detail,
278
-                      '扦样代表数量(公斤)',
279
-                      item.qydbsl?.toString(),
280
-                      inputType: const TextInputType.numberWithOptions(decimal: true),
281
-                      formatters: [XNumberTextInputFormatter()],
282
-                      onChanged: (value) => item.qydbsl = value.isEmpty ? null : num.parse(value),
283
-                      backgroundColor: null,
284
-                    ),
285
-                    CardWidgets.buildEdit(
286
-                      detail,
287
-                      '被调查农户或合作社',
288
-                      item.bdcnhhhzs,
289
-                      onChanged: (value) => item.bdcnhhhzs = value,
290
-                      backgroundColor: null,
291
-                    ),
292
-                    CardWidgets.buildEdit(
293
-                      detail,
294
-                      '联系方式',
295
-                      inputType: TextInputType.number,
296
-                      item.lxfs,
297
-                      onChanged: (value) => item.lxfs = value,
298
-                      backgroundColor: null,
299
-                      bottomLine: false,
300
-                    ),
301
-                  ],
302
-                ),
303
-              ),
304
-            ],
305
-          ),
253
+        child: Column(
254
+          mainAxisSize: MainAxisSize.min,
255
+          children: [
256
+            CardWidgets.buildEdit(
257
+              detail,
258
+              '扦样数量(公斤)',
259
+              item.qysl?.toString(),
260
+              inputType: const TextInputType.numberWithOptions(decimal: true),
261
+              formatters: [XNumberTextInputFormatter()],
262
+              onChanged: (value) => item.qysl = value.isEmpty ? null : num.parse(value),
263
+              backgroundColor: null,
264
+            ),
265
+            CardWidgets.buildEdit(
266
+              detail,
267
+              '扦样代表数量(公斤)',
268
+              item.qydbsl?.toString(),
269
+              inputType: const TextInputType.numberWithOptions(decimal: true),
270
+              formatters: [XNumberTextInputFormatter()],
271
+              onChanged: (value) => item.qydbsl = value.isEmpty ? null : num.parse(value),
272
+              backgroundColor: null,
273
+            ),
274
+            CardWidgets.buildEdit(
275
+              detail,
276
+              '被调查农户或合作社',
277
+              item.bdcnhhhzs,
278
+              onChanged: (value) => item.bdcnhhhzs = value,
279
+              backgroundColor: null,
280
+            ),
281
+            CardWidgets.buildEdit(
282
+              detail,
283
+              '联系方式',
284
+              inputType: TextInputType.number,
285
+              item.lxfs,
286
+              onChanged: (value) => item.lxfs = value,
287
+              backgroundColor: null,
288
+              bottomLine: false,
289
+            ),
290
+          ],
306 291
         ),
307 292
       ),
308 293
     );

+ 16 - 38
lib/page/signature/signature_page.dart

@@ -151,44 +151,22 @@ class _SignaturePageState extends BaseLifecycleState<SignaturePage> {
151 151
             ),
152 152
           ),
153 153
         ),
154
-        Row(
155
-          children: [
156
-            Expanded(
157
-              child: MyButton(
158
-                '清除重写',
159
-                onTap: clearCurrent,
160
-                margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
161
-              ),
162
-            ),
163
-            previousEnable.builder((v) => v
164
-                ? Expanded(
165
-                    child: MyButton(
166
-                      '上一位',
167
-                      onTap: previousPage,
168
-                      margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
169
-                    ),
170
-                  )
171
-                : const SizedBox.shrink()),
172
-            nextEnable.builder((v) => v
173
-                ? Expanded(
174
-                    child: MyButton(
175
-                      '下一位',
176
-                      onTap: nextPage,
177
-                      margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
178
-                    ),
179
-                  )
180
-                : const SizedBox.shrink()),
181
-            submitEnable.builder((v) => v
182
-                ? Expanded(
183
-                    child: MyButton(
184
-                      '提交',
185
-                      onTap: submit,
186
-                      margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
187
-                    ),
188
-                  )
189
-                : const SizedBox.shrink()),
190
-          ],
191
-        )
154
+        buildBottom(),
155
+      ],
156
+    );
157
+  }
158
+
159
+  Widget buildBottom() {
160
+    EdgeInsets margin = EdgeInsets.only(left: 8, right: 8, top: 8, bottom: getBottomPadding(8));
161
+    return Row(
162
+      children: [
163
+        Expanded(child: MyButton('清除重写', onTap: clearCurrent, margin: margin)),
164
+        previousEnable.builder(
165
+            (v) => v ? Expanded(child: MyButton('上一位', onTap: previousPage, margin: margin)) : const SizedBox.shrink()),
166
+        nextEnable.builder(
167
+            (v) => v ? Expanded(child: MyButton('下一位', onTap: nextPage, margin: margin)) : const SizedBox.shrink()),
168
+        submitEnable.builder(
169
+            (v) => v ? Expanded(child: MyButton('提交', onTap: submit, margin: margin)) : const SizedBox.shrink()),
192 170
       ],
193 171
     );
194 172
   }

+ 3 - 1
lib/service/dict_service.dart

@@ -26,7 +26,9 @@ enum DictType {
26 26
   // 重金属污染类型
27 27
   zjswrlx('zjswrlx'),
28 28
   // 采样品种
29
-  cypz('cypz');
29
+  cypz('cypz'),
30
+  // 检验类型
31
+  jylx('jylx');
30 32
 
31 33
   const DictType(this.type);
32 34
 

+ 6 - 2
lib/widget/card_item.dart

@@ -414,14 +414,17 @@ class CardWidgets {
414 414
     ValueNotifier<CardMenuData?> selNotifier,
415 415
     void Function(ValueNotifier<CardMenuData?>, CardMenuData)? onSelectTap, {
416 416
     String? hint,
417
+    bool showTopLine = false,
418
+    bool bottomLine = true,
417 419
   }) {
418 420
     if (isDetail) {
419 421
       return selNotifier.builder(
420 422
         (v) => CardItemWidget(
421 423
           title,
422 424
           rightText: v?.name,
423
-          bottomLine: true,
425
+          bottomLine: bottomLine,
424 426
           hint: hint,
427
+          showTopLine: showTopLine,
425 428
         ),
426 429
       );
427 430
     }
@@ -430,8 +433,9 @@ class CardWidgets {
430 433
       listNotifier,
431 434
       selNotifier,
432 435
       onSelectTap: onSelectTap,
433
-      bottomLine: true,
436
+      bottomLine: bottomLine,
434 437
       hint: hint,
438
+      showTopLine: showTopLine,
435 439
     );
436 440
   }
437 441
 }

+ 2 - 0
pubspec.yaml

@@ -87,6 +87,8 @@ dependencies:
87 87
   signature: ^5.4.1
88 88
   # loading集合
89 89
   flutter_spinkit: ^5.2.1
90
+  # 保存到相册
91
+  image_gallery_saver: ^2.0.3
90 92
 
91 93
 dev_dependencies:
92 94
   flutter_test: