时间允许未来

main
hs 2025-08-14 18:14:15 +08:00
parent b756e4e809
commit d14e56616e
13 changed files with 1549 additions and 71 deletions

View File

@ -37,16 +37,17 @@ class ListItemFactory {
),
],
),
if (isRight)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
_truncateText(rightText, 100),
Expanded(child: Text(
rightText,
// rightText,
style: TextStyle(fontSize: 15, color: Colors.grey),
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),),
SizedBox(width: 2),
Icon(
Icons.arrow_forward_ios_rounded,
@ -56,7 +57,8 @@ class ListItemFactory {
],
)
else
Text(rightText, style: TextStyle(fontSize: 15, color: Colors.grey)),
Expanded(child: Text(rightText, style: TextStyle(fontSize: 15, color: Colors.grey,),maxLines: 1,
overflow: TextOverflow.ellipsis, textAlign: TextAlign.right,)),
],
),
);

View File

@ -0,0 +1,46 @@
import 'dart:ffi';
import 'package:flutter/material.dart';
import 'package:dotted_border/dotted_border.dart';
class DottedBorderBox extends StatelessWidget {
final Widget? child;
final Color color;
final double strokeWidth;
final List<double> dashPattern;
final BorderRadius borderRadius;
final EdgeInsets padding;
final StrokeCap strokeCap;
const DottedBorderBox({
super.key,
this.child,
this.color = Colors.black26,
this.strokeWidth = 1.5,
this.dashPattern = const [6, 3],
this.borderRadius = const BorderRadius.all(Radius.circular(8)),
this.padding = const EdgeInsets.all(8),
this.strokeCap = StrokeCap.butt,
});
@override
Widget build(BuildContext context) {
return DottedBorder(
options: RoundedRectDottedBorderOptions(
// 线
borderPadding: EdgeInsets.zero,
// 线 child 线
padding: padding,
color: color,
strokeWidth: strokeWidth,
dashPattern: dashPattern,
strokeCap: strokeCap, radius: Radius.circular(0),
// gradient
),
child: ClipRRect(
borderRadius: borderRadius,
child: child ?? const SizedBox.shrink(),
),
);
}
}

View File

@ -1,14 +1,16 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
///
/// DateTime? picked = await BottomDateTimePicker.show(context);
/// DateTime? picked = await BottomDateTimePicker.showDate(
/// context,
/// allowFuture: true, //
/// );
/// if (picked != null) {
/// print('用户选择的时间:$picked');
/// }
class BottomDateTimePicker {
static Future<DateTime?> showDate(BuildContext context) {
static Future<DateTime?> showDate(BuildContext context, {bool allowFuture = false}) {
return showModalBottomSheet<DateTime>(
context: context,
backgroundColor: Colors.white,
@ -16,12 +18,16 @@ class BottomDateTimePicker {
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
),
builder: (_) => _InlineDateTimePickerContent(),
builder: (_) => _InlineDateTimePickerContent(allowFuture: allowFuture),
);
}
}
class _InlineDateTimePickerContent extends StatefulWidget {
final bool allowFuture; //
const _InlineDateTimePickerContent({Key? key, this.allowFuture = false}) : super(key: key);
@override
State<_InlineDateTimePickerContent> createState() => _InlineDateTimePickerContentState();
}
@ -30,10 +36,12 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
//
final List<int> years = List.generate(101, (i) => 1970 + i);
final List<int> months = List.generate(12, (i) => i + 1);
final List<int> days = List.generate(31, (i) => i + 1);
final List<int> hours = List.generate(24, (i) => i);
final List<int> minutes = List.generate(60, (i) => i);
//
late List<int> days;
// Controllers
late FixedExtentScrollController yearCtrl;
late FixedExtentScrollController monthCtrl;
@ -58,6 +66,9 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
selectedHour = now.hour;
selectedMinute = now.minute;
//
days = _getDaysInMonth(selectedYear, selectedMonth);
yearCtrl = FixedExtentScrollController(initialItem: years.indexOf(selectedYear));
monthCtrl = FixedExtentScrollController(initialItem: selectedMonth - 1);
dayCtrl = FixedExtentScrollController(initialItem: selectedDay - 1);
@ -65,19 +76,33 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
minuteCtrl = FixedExtentScrollController(initialItem: selectedMinute);
}
@override
void dispose() {
yearCtrl.dispose();
monthCtrl.dispose();
dayCtrl.dispose();
hourCtrl.dispose();
minuteCtrl.dispose();
super.dispose();
//
List<int> _getDaysInMonth(int year, int month) {
final lastDay = DateUtils.getDaysInMonth(year, month);
return List.generate(lastDay, (i) => i + 1);
}
//
void _updateDays() {
final newDays = _getDaysInMonth(selectedYear, selectedMonth);
final isDayValid = selectedDay <= newDays.length;
setState(() {
days = newDays;
if (!isDayValid) {
selectedDay = newDays.last;
dayCtrl.jumpToItem(selectedDay - 1);
}
});
}
//
void _checkAndClampToNow() {
if (widget.allowFuture) return; //
final picked = DateTime(selectedYear, selectedMonth, selectedDay, selectedHour, selectedMinute);
final now = DateTime.now();
if (picked.isAfter(now)) {
//
selectedYear = now.year;
@ -92,9 +117,22 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
dayCtrl.jumpToItem(selectedDay - 1);
hourCtrl.jumpToItem(selectedHour);
minuteCtrl.jumpToItem(selectedMinute);
//
_updateDays();
}
}
@override
void dispose() {
yearCtrl.dispose();
monthCtrl.dispose();
dayCtrl.dispose();
hourCtrl.dispose();
minuteCtrl.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SizedBox(
@ -140,6 +178,7 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
onSelected: (idx) {
setState(() {
selectedYear = years[idx];
_updateDays(); //
_checkAndClampToNow();
});
},
@ -152,6 +191,7 @@ class _InlineDateTimePickerContentState extends State<_InlineDateTimePickerConte
onSelected: (idx) {
setState(() {
selectedMonth = months[idx];
_updateDays(); //
_checkAndClampToNow();
});
},

View File

@ -1174,6 +1174,61 @@ U6Hzm1ninpWeE+awIDAQAB
);
}
///TODO --------------------------------- ---------------------------------
static Future<Map<String, dynamic>> getSafeCheckCount() {
return HttpManager().request(
basePath,
'/app/safetyenvironmental/countCheck',
method: Method.post,
data: {
"CORPINFO_ID":SessionService.instance.corpinfoId,
'INSPECTION_USER_ID': SessionService.instance.loginUserId,
'INSPECTED_SITEUSER_ID': SessionService.instance.loginUserId,
'INSPECTION_ORIGINATOR_ID': SessionService.instance.loginUserId,
"tm": DateTime.now().millisecondsSinceEpoch,
},
);
}
///
static Future<Map<String, dynamic>> safeCheckFlowList(String ID) {
return HttpManager().request(
basePath,
'/app/safetyenvironmental/showFlowChart',
method: Method.post,
data: {
'ID' :ID
},
);
}
///
static Future<Map<String, dynamic>> getSafeCheckSearchList(Map data, String url) {
return HttpManager().request(
basePath,
url,
method: Method.post,
data: {
"CORPINFO_ID":SessionService.instance.corpinfoId,
"loginUserId":SessionService.instance.loginUserId,
'tm': DateTime.now().millisecondsSinceEpoch.toString(),
'roleLevel' : SessionService.instance.loginUser?['roleLevel'] ?? '',
'supDeparIds' : SessionService.instance.loginUser?['supDeparIds'] ?? '',
...data
},
);
}
//
static Future<Map<String, dynamic>> getSafeCheckStartGoEdit(String INSPECTION_ID) {
return HttpManager().request(
basePath,
'/app/safetyenvironmental/goEdit',
method: Method.post,
data: {
"INSPECTION_ID":INSPECTION_ID,
},
);
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/dotted_border_box.dart';
class MultiTextFieldWithTitle extends StatefulWidget {
final String label;
@ -160,14 +161,12 @@ class _MultiTextFieldWithTitleState extends State<MultiTextFieldWithTitle> {
...widget.texts.map((c) {
return Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(
padding: const EdgeInsets.all(12),
child: SizedBox(
width: double.maxFinite,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(4),
),
child: Text(
child: DottedBorderBox(
child:
Text(
c,
style: TextStyle(
fontSize: widget.fontSize,
@ -175,6 +174,7 @@ class _MultiTextFieldWithTitleState extends State<MultiTextFieldWithTitle> {
),
),
),
)
);
}).toList(),
],
@ -192,12 +192,9 @@ class _MultiTextFieldWithTitleState extends State<MultiTextFieldWithTitle> {
//
Padding(
padding: EdgeInsets.symmetric(horizontal: 7, vertical: 7),
child: Container(
decoration: BoxDecoration(
border: BoxBorder.all(color: Colors.grey.shade300, width: 1),
borderRadius: BorderRadius.circular(4),
),
padding: EdgeInsets.symmetric(vertical: 10),
child: SizedBox(
width: double.maxFinite,
child: DottedBorderBox(
child: TextField(
controller: _controllers[index],
decoration: InputDecoration(hintText: widget.hintText),
@ -207,6 +204,7 @@ class _MultiTextFieldWithTitleState extends State<MultiTextFieldWithTitle> {
minLines: 3,
style: TextStyle(fontSize: widget.fontSize),
),
)
),
),

View File

@ -0,0 +1,848 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/dotted_border_box.dart';
import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.dart';
import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/http/ApiService.dart';
import 'package:qhd_prevention/pages/KeyProjects/SafeCheck/custom/MultiTextFieldWithTitle.dart';
import 'package:qhd_prevention/pages/KeyProjects/SafeCheck/custom/safeCheck_table.dart';
import 'package:qhd_prevention/pages/KeyProjects/SafeCheck/custom/safe_drawer_page.dart';
import 'package:qhd_prevention/pages/app/Danger_paicha/quick_report_page.dart';
import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/tools.dart';
class SafecheckStartDetail extends StatefulWidget {
const SafecheckStartDetail({
super.key,
required this.INSPECTION_ID,
required this.isEdit,
});
final String INSPECTION_ID;
final bool isEdit;
@override
State<SafecheckStartDetail> createState() => _SafecheckStartDetailState();
}
class _SafecheckStartDetailState extends State<SafecheckStartDetail> {
///
late List<dynamic> personList = [];
///
late List<dynamic> typeList = [];
///
late List<dynamic> toCheckUnitList = [];
bool? chooseTitleType = null;
late List<dynamic> inspectorList = [];
//
List<String> multiTexts = [];
List<String> delInspectors = [];
List<String> delSituations = [];
List<String> delHiddens = [];
List<String> delHiddenFiles = [];
// rules : [{ 'name': 'INSPECTION_CATEGORY', 'message': '请填写检查题目' }, ...]
List<Map<String, String>> rules = [
{'name': 'INSPECTION_CATEGORY', 'message': '请选择检查题目'},
{'name': 'UNITS_ID', 'message': '请选择被检查单位'},
{'name': 'PERSONNELMANAGEMENT_ID', 'message': '请选择被检查单位现场负责人'},
{'name': 'INSPECTION_TYPE', 'message': '请选择检查类型不能为空'},
{'name': 'INSPECTION_PLACE', 'message': '请输入检查场所'},
{'name': 'INSPECTION_TIME_START', 'message': '请选择检查开始时间'},
{'name': 'INSPECTION_TIME_END', 'message': '请选择作业结束时间'},
{'name': 'INSPECTION_USERS', 'message': '请输入检查人员'},
];
Map<String, dynamic> form = {
'INSPECTION_SOURCE': '5', // 4- 5-
'hiddenList': [
{
'ISRELEVANT': '2',
'SOURCE': '5', //
'RECTIFICATIONTYPE': '2',
},
],
'INSPECTION_USER_SIGN_TIME': '',
'INSPECTION_USER_OPINION': '',
};
@override
void initState() {
super.initState();
form['INSPECTION_ID'] = widget.INSPECTION_ID;
form['hiddenList'] = [];
WidgetsBinding.instance.addPostFrameCallback((_) {
_getData();
});
}
Future<void> _getData() async {
try {
final result = await ApiService.getSafeCheckStartGoEdit(
widget.INSPECTION_ID,
);
// await mounted pop setState
if (!mounted) return;
setState(() {
form = result['pd'] ?? {};
inspectorList =
FormUtils.hasValue(form, 'inspectorList')
? form['inspectorList']
: [];
_syncMultiTextsFromForm();
});
} catch (e, st) {
print('加载单条数据失败: $e\n$st');
if (mounted) {
ToastUtil.showNormal(context, '加载数据失败:$e');
}
}
}
Future<void> _choosePerson() async {
final choice = await BottomPicker.show<String>(
context,
items: personList.map((val) => val['NAME'] as String).toList(),
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
initialIndex: 0,
);
if (choice != null) {
// choice
setState(() {
form['INSPECTED_SITEUSER_INDEX'] = choice;
final data = FormUtils.findMapForKeyValue(personList, 'NAME', choice);
form['INSPECTED_SITEUSER_ID'] = data['USER_ID'];
form['INSPECTED_SITEUSER_NAME'] = data['NAME'];
FocusHelper.clearFocus(context);
});
}
}
Future<void> _chooseType() async {
final choice = await BottomPicker.show<String>(
context,
items: typeList.map((val) => val['name'] as String).toList(),
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
initialIndex: 0,
);
if (choice != null) {
// choice
setState(() {
form['INSPECTION_TYPE_NAME'] = choice;
final data = FormUtils.findMapForKeyValue(typeList, 'name', choice);
form['INSPECTION_TYPE'] = data['id'];
FocusHelper.clearFocus(context);
});
}
}
Future<void> _openDrawer(Map<String, dynamic> hiddenForm, int index) async {
try {
final result = await openCustomDrawer<Map>(
context,
SafeDrawerPage(
initialHidden: hiddenForm,
editType:
widget.isEdit
? (index < 0 ? SafeEditType.add : SafeEditType.edit)
: SafeEditType.see,
toCheckUnitList: toCheckUnitList,
),
);
if (result != null && mounted) {
setState(() {
if (index < 0) {
//
form['hiddenList'].add(result);
} else {
//
form['hiddenList'][index] = result;
}
});
}
} catch (e) {
print("打开抽屉失败: $e");
ToastUtil.showNormal(context, "打开抽屉失败");
}
}
Future<T?> openCustomDrawer<T>(BuildContext context, Widget child) {
return Navigator.of(context).push<T>(
PageRouteBuilder(
opaque: false,
barrierDismissible: true,
barrierColor: Colors.black54,
pageBuilder: (_, __, ___) {
return Align(
alignment: Alignment.centerRight,
child: FractionallySizedBox(
widthFactor: 4 / 5,
child: Material(color: Colors.white, child: child),
),
);
},
transitionsBuilder: (_, anim, __, child) {
return SlideTransition(
position: Tween(
begin: const Offset(1, 0),
end: Offset.zero,
).animate(CurvedAnimation(parent: anim, curve: Curves.easeOut)),
child: child,
);
},
),
);
}
/// form['situationList'] List<String>
List<String> _situationListToStrings() {
final List<dynamic> cur = List<dynamic>.from(form['situationList'] ?? []);
if (cur.isEmpty) return ['']; // uni-app
return cur.map((e) {
if (e is Map && e['SITUATION'] != null) return e['SITUATION'].toString();
return '';
}).toList();
}
/// List<String> situationList INSPECTION_SITUATION_ID
List<Map<String, dynamic>> _stringsToSituationList(List<String> texts) {
final List<dynamic> existing = List<dynamic>.from(
form['situationList'] ?? [],
);
final List<Map<String, dynamic>> out = [];
for (int i = 0; i < texts.length; i++) {
final s = texts[i] ?? '';
if (i < existing.length && existing[i] is Map) {
// INSPECTION_SITUATION_ID SITUATION
final Map<String, dynamic> copy = Map<String, dynamic>.from(
existing[i],
);
copy['SITUATION'] = s;
// INSPECTION_SITUATION_ID uni-app
copy['INSPECTION_SITUATION_ID'] = copy['INSPECTION_SITUATION_ID'] ?? '';
out.add(copy);
} else {
//
out.add({'INSPECTION_SITUATION_ID': '', 'SITUATION': s});
}
}
// existing id delSituations
// ID delSituations便
if (existing.isNotEmpty && existing.length > texts.length) {
for (int j = texts.length; j < existing.length; j++) {
final ex = existing[j];
if (ex is Map) {
final id = (ex['INSPECTION_SITUATION_ID'] ?? '').toString();
if (id.isNotEmpty) {
delSituations.add(id);
}
}
}
}
return out;
}
/// form['situationList'] multiTexts MultiTextFieldWithTitle
void _syncMultiTextsFromForm() {
final List<String> arr = _situationListToStrings();
setState(() {
multiTexts = arr;
});
}
// ------------ ------------
Future<void> _submit() async {
if (!widget.isEdit) {
Navigator.of(context).pop();
return;
}
bool required = true;
// rules
for (final r in rules) {
final name = r['name'] ?? '';
final message = r['message'] ?? '请完善表单';
final v = form[name];
if (v == null || v.toString().isEmpty || v.toString() == '请选择') {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, message);
required = false;
break;
}
}
if (!required) return;
// situationList SITUATION
final situations = (form['situationList'] as List<dynamic>?) ?? [];
for (var i = 0; i < situations.length; i++) {
final s = Map<String, dynamic>.from(situations[i]);
if ((s['SITUATION'] ?? '').toString().trim().isEmpty) {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, '请填写第${i + 1}项检查情况');
return;
}
}
// inspectorList INSPECTION_USER_ID
final List<Map<String, String>> inspectors = form['inspectorList'] ?? [];
final seenIds = <String>{};
for (final it in inspectors) {
final id = (it as Map)['INSPECTION_USER_ID']?.toString() ?? '';
if (id.isNotEmpty) {
if (seenIds.contains(id)) {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, '检查人重复!请检查数据');
return;
}
seenIds.add(id);
}
}
// hiddenList
final origHiddenList = (form['hiddenList'] as List<dynamic>?) ?? [];
final List<List<Map<String, dynamic>>> hiddenFilesPerHidden = [];
for (var i = 0; i < origHiddenList.length; i++) {
final hidden = Map<String, dynamic>.from(origHiddenList[i] as Map);
final List<Map<String, dynamic>> fileList = [];
// hiddenImgs ()
final hiddenImgs = (hidden['hiddenImgs'] as List<dynamic>?) ?? [];
for (var j = 0; j < hiddenImgs.length; j++) {
final img = hiddenImgs[j];
//
if (img is String) {
fileList.add({'type': 3, 'FILEPATH': img});
} else if (img is Map) {
final hasId = (img['IMGFILES_ID'] ?? '').toString().isNotEmpty;
if (!hasId) {
fileList.add({
'type': 3,
'FILEPATH': img['FILEPATH'] ?? img['path'] ?? '',
});
}
}
}
// zgImgs ()
final zgImgs = (hidden['zgImgs'] as List<dynamic>?) ?? [];
for (var j = 0; j < zgImgs.length; j++) {
final img = zgImgs[j];
if (img is String) {
fileList.add({'type': 4, 'FILEPATH': img});
} else if (img is Map) {
final hasId = (img['IMGFILES_ID'] ?? '').toString().isNotEmpty;
if (!hasId) {
fileList.add({
'type': 4,
'FILEPATH': img['FILEPATH'] ?? img['path'] ?? '',
});
}
}
}
// hiddenVideos ()
final hiddenVideos = (hidden['hiddenVideos'] as List<dynamic>?) ?? [];
if (hiddenVideos.isNotEmpty) {
final v = hiddenVideos[0];
if (v is String) {
fileList.add({'type': 102, 'FILEPATH': v});
} else if (v is Map) {
final hasId = (v['IMGFILES_ID'] ?? '').toString().isNotEmpty;
if (!hasId) {
fileList.add({
'type': 102,
'FILEPATH': v['FILEPATH'] ?? v['path'] ?? '',
});
}
}
}
hiddenFilesPerHidden.add(fileList);
}
// inspectorList SessionService
final loginUser = SessionService.instance.loginUser ?? {};
final loginUserId = SessionService.instance.loginUserId ?? '';
final idx = inspectors.indexWhere((item) {
final m = Map<String, dynamic>.from(item as Map);
return (m['INSPECTION_USER_ID'] ?? '') ==
(loginUser['USER_ID'] ?? loginUserId);
});
if (idx < 0) {
inspectors.add({
'INSPECTION_INSPECTOR_ID': '',
'INSPECTION_DEPARTMENT_ID': loginUser['DEPARTMENT_ID'] ?? '',
'INSPECTION_DEPARTMENT_NAME': loginUser['DEPARTMENT_NAME'] ?? '',
'INSPECTION_USER_ID': loginUser['USER_ID'] ?? loginUserId,
'INSPECTION_USER_INDEX': '',
'INSPECTION_USER_NAME': loginUser['NAME'] ?? '',
});
}
// form JSON
form['INSPECTORJSON'] = jsonEncode(inspectors);
form['SITUATIONJSON'] = jsonEncode(situations);
form['HIDDENJSON'] = jsonEncode(origHiddenList);
form['delInspectors'] = delInspectors.join(',');
form['delSituations'] = delSituations.join(',');
form['delHiddens'] = delHiddens.join(',');
form['delHiddenFiles'] = delHiddenFiles.join(',');
form['CREATOR'] = loginUser['USER_ID'] ?? loginUserId;
form['CORPINFO_ID'] = SessionService.instance.corpinfoId ?? '';
form['ACTION_USER'] = loginUser['NAME'] ?? '';
LoadingDialogHelper.show(); // loading
//
try {
final requestData = <String, dynamic>{
'CORPINFO_ID': form['CORPINFO_ID'],
...form,
};
final res = await ApiService.safeKeyprojectCheckSubmit(requestData);
// ApiService
if (res != null && res['result'] == 'success') {
final pd = res['pd'] ?? {};
final List<dynamic> returnedHiddenList = pd['hiddenList'] ?? [];
//
final hasFiles = hiddenFilesPerHidden.any((lst) => lst.isNotEmpty);
if (!hasFiles) {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, '提交成功');
Navigator.of(context).pop();
return;
}
// hidden punishForm
for (var i = 0; i < returnedHiddenList.length; i++) {
if (i < (form['hiddenList'] as List).length) {
final hidden = Map<String, dynamic>.from(
(form['hiddenList'] as List)[i],
);
final punishForm = hidden['punishForm'];
if (punishForm != null) {
final hid = (returnedHiddenList[i]['HIDDEN_ID'] ?? '').toString();
punishForm['HIDDEN_ID'] = hid;
// await
await fnSubmit(Map<String, dynamic>.from(punishForm));
}
}
}
// hiddenId
// hiddenList Map
final returnedHiddenMapList =
returnedHiddenList
.map((e) => Map<String, dynamic>.from(e))
.toList();
await uploadHiddenFiles(hiddenFilesPerHidden, returnedHiddenMapList);
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, '提交成功');
Navigator.of(context).pop();
} else {
LoadingDialogHelper.hide();
final msg =
res != null
? (res['msg'] ?? res['msaesge'] ?? res['message'] ?? '提交失败')
: '提交失败';
ToastUtil.showNormal(context, msg);
}
} catch (e) {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, '提交异常:$e');
}
}
// ========== ==========
Future<void> uploadHiddenFiles(
List<List<Map<String, dynamic>>> hiddenFilesPerHidden,
List<Map<String, dynamic>> returnedHiddenList,
) async {
for (var i = 0; i < hiddenFilesPerHidden.length; i++) {
final filesForHidden = hiddenFilesPerHidden[i];
if (filesForHidden.isEmpty) continue;
final hiddenId =
i < returnedHiddenList.length
? (returnedHiddenList[i]['HIDDEN_ID']?.toString() ?? '')
: '';
if (hiddenId.isEmpty) continue;
for (final f in filesForHidden) {
final filePath = f['FILEPATH']?.toString() ?? '';
final type = f['type']?.toString() ?? '';
if (filePath.isEmpty) continue;
try {
await ApiService.addImgFiles(filePath, type, hiddenId);
} catch (e) {
//
print('上传文件失败: $e (path=$filePath)');
}
}
}
}
// ========== fnSubmit ==========
Future<bool> fnSubmit(Map<String, dynamic>? ordForm) async {
if (ordForm == null) return false;
final Map<String, String> punishRules = {
'REASON': '请填写处罚原因',
'AMOUT': '请填写处罚金额',
'DATE': '请选择下发处罚时间',
};
//
for (final entry in punishRules.entries) {
final key = entry.key;
final msg = entry.value;
final val = ordForm[key];
if (val == null || val.toString().trim().isEmpty) {
ToastUtil.showNormal(context, msg);
return false;
}
}
final requestData = Map<String, dynamic>.from(ordForm);
requestData['CORPINFO_ID'] = SessionService.instance.corpinfoId ?? '';
requestData['CREATOR'] = SessionService.instance.loginUserId ?? '';
requestData['OPERATOR'] = SessionService.instance.loginUserId ?? '';
try {
LoadingDialogHelper.show();
final res = await ApiService.safeCheckPunishSubmit(requestData);
LoadingDialogHelper.hide();
if (FormUtils.hasValue(res, 'result') && res['result'] == 'success') {
return true;
} else {
final msg =
res != null
? (res['msg'] ?? res['msaesge'] ?? res['message'] ?? '提交失败')
: '提交失败';
ToastUtil.showNormal(context, msg);
return false;
}
} catch (e) {
LoadingDialogHelper.hide();
ToastUtil.showNormal(context, '罚单提交异常:$e');
return false;
}
}
Widget _personUnitItem(Map item, int index) {
return DottedBorderBox(
child: Column(
children: [
ItemListWidget.selectableLineTitleTextRightButton(
isRequired: widget.isEdit,
label: '${index + 1}.检查人员单位:',
isEditable: widget.isEdit,
onTapClean: () {
setState(() {});
},
text: item['INSPECTION_DEPARTMENT_NAME'] ?? '请选择',
onTap: () {},
),
Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
isRequired: widget.isEdit,
label: 'type.personName',
isEditable: widget.isEdit,
text: item['INSPECTION_USER_NAME'] ?? '请选择',
onTap: () {},
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppbar(title: "安全检查发起", actions: []),
body: SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12),
child:
form.isNotEmpty
? ListView(
children: [
Column(
children: [
ItemListWidget.itemContainer(
horizontal: 0,
Column(
children: [
ListItemFactory.createYesNoSection(
title: '检查题目:',
groupValue: chooseTitleType,
yesLabel: '安全',
noLabel: '综合',
isEdit: widget.isEdit,
isRequired: true,
horizontalPadding: 5,
verticalPadding: 0,
text:
'${form['INSPECTION_SUBJECT'] ?? ''}现场检查记录',
onChanged: (val) {
setState(() {
chooseTitleType = val;
form['INSPECTION_SUBJECT'] =
val == true ? '安全' : '综合';
});
},
),
const Divider(),
ItemListWidget.singleLineTitleText(
label: '被检查单位:',
isEditable: false,
text: form['INSPECTED_DEPARTMENT_NAMES'],
onChanged: (val) {
setState(() {
form['INSPECTED_DEPARTMENT_NAME'] = val;
});
},
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '被检查单位现场负责人:',
isEditable: widget.isEdit,
onTap: () {
_choosePerson();
},
text: form['INSPECTED_SITEUSER_INDEX'] ?? '',
),
const Divider(),
ItemListWidget.singleLineTitleText(
label: '检查场所:',
isEditable: widget.isEdit,
text: form['INSPECTION_PLACE'],
hintText: '请输入检查场所',
onChanged: (val) {
setState(() {
form['INSPECTION_PLACE'] = val;
});
},
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '检查类型:',
onTap: () {
_chooseType();
},
isEditable: widget.isEdit,
text: form['INSPECTION_TYPE_NAME'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '检查开始时间:',
isEditable: widget.isEdit,
text: form['INSPECTION_TIME_START'] ?? '',
onTap: () async {
DateTime? picked =
await BottomDateTimePicker.showDate(
context,
);
if (picked != null) {
setState(() {
form['INSPECTION_TIME_START'] =
DateFormat(
'yyyy-MM-dd HH:mm',
).format(picked);
});
FocusHelper.clearFocus(context);
}
},
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '检查结束时间:',
isEditable: widget.isEdit,
text: form['INSPECTION_TIME_END'] ?? '',
onTap: () async {
DateTime? picked =
await BottomDateTimePicker.showDate(
context,
);
if (picked != null) {
setState(() {
form['INSPECTION_TIME_END'] =
DateFormat(
'yyyy-MM-dd HH:mm',
).format(picked);
});
FocusHelper.clearFocus(context);
}
},
),
const Divider(),
MultiTextFieldWithTitle(
label: "检查情况",
//
isEditable: widget.isEdit,
// 使
hintText: "请输入检查情况...",
texts: multiTexts,
onTextsChanged: (texts) {
setState(() {
multiTexts = texts; //
form['situationList'] =
_stringsToSituationList(texts);
});
},
),
const Divider(),
ItemListWidget.itemContainer(
Column(
children: [
ListItemFactory.headerTitle('检查人员'),
Expanded(child: ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: inspectorList.length,
itemBuilder: (context, index) {
return _personUnitItem(inspectorList[index], index);
},
),)
],
),
),
const Divider(),
ItemListWidget.itemContainer(
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
ListItemFactory.headerTitle('发现问题'),
if (widget.isEdit)
CustomButton(
text: " 添加 ",
height: 30,
padding: const EdgeInsets.symmetric(
vertical: 2,
horizontal: 5,
),
backgroundColor: Colors.blue,
onPressed: () {
_openDrawer(
form,
-1,
); // await
FocusHelper.clearFocus(context);
},
),
],
),
),
HiddenListTable(
hiddenList: form['hiddenList'] ?? [],
forbidEdit: widget.isEdit,
baseImgPath: ApiService.baseImgPath,
personSignImg: form['PERSON_SIGN_IMG'] ?? '',
personSignTime:
form['PERSON_SIGN_TIME'] ?? '',
showHidden: (item, idx) {
_openDrawer(item, idx);
},
removeHidden: (item, idx) {
/* 删除逻辑 */
},
context: context,
),
if (!widget.isEdit)
Column(
children: [
const Divider(),
ItemListWidget.twoRowTitleAndImages(
title: '签字',
onTapCallBack: (p) {
presentOpaque(
SingleImageViewer(imageUrl: p),
context,
);
},
imageUrls: [
'${form['PERSON_SIGN_IMG'] ?? ''}',
],
),
const Divider(),
ItemListWidget.singleLineTitleText(
label: '签字时间',
isEditable: false,
text: form['PERSON_SIGN_TIME'] ?? '',
),
],
),
],
),
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (widget.isEdit)
SizedBox(
width: 150,
child: CustomButton(
text: '返回',
textStyle: TextStyle(
color: Colors.white,
fontSize: 17,
),
backgroundColor: Colors.black38,
onPressed: () => Navigator.pop(context),
),
),
SizedBox(
width: 150,
child: CustomButton(
text: widget.isEdit ? '提交' : '返回',
textStyle: TextStyle(
color: Colors.white,
fontSize: 17,
),
backgroundColor: Colors.blue,
onPressed: _submit,
),
),
],
),
],
),
],
)
: SizedBox(),
),
),
);
}
}

View File

@ -0,0 +1,481 @@
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/toast_util.dart';
import 'package:qhd_prevention/pages/home/SafeCheck/Start/safeCheck_start_detail.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/dh_work/dh_work_detai/hotwork_apply_detail.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:qhd_prevention/customWidget/bottom_picker.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/customWidget/search_bar_widget.dart';
import 'package:qhd_prevention/http/ApiService.dart';
class SafecheckStartListPage extends StatefulWidget {
final String flow;
const SafecheckStartListPage({Key? key, required this.flow})
: super(key: key);
@override
_SafecheckStartListPageState createState() => _SafecheckStartListPageState();
}
class _SafecheckStartListPageState extends State<SafecheckStartListPage> {
// Data and state variables
List<dynamic> list = [];
int currentPage = 1;
int rows = 10;
int totalPage = 1;
bool isLoading = false;
List stepList = [
{'id': '', 'name': '请选择'},
{'id': '0', 'name': '待检查人核实'},
{'id': '1', 'name': '检查人核实中'},
{'id': '2', 'name': '待被检查人确认'},
{'id': '3', 'name': '待指派'},
{'id': '4', 'name': '指派中'},
{'id': '5', 'name': '指派完成'},
{'id': '6', 'name': '检查待验收'},
{'id': '7', 'name': '检查已验收'},
{'id': '8', 'name': '已归档'},
{'id': '-1', 'name': '检查人核实打回'},
{'id': '-2', 'name': '被检查人申辩'},
];
final TextEditingController _searchController = TextEditingController();
int sindex = 0;
String searchKeywords = '';
List<Map<String, dynamic>> flowList = [];
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final ScrollController _scrollController = ScrollController();
@override
void initState() {
super.initState();
_fetchData();
_scrollController.addListener(_onScroll);
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
void _onScroll() {
if (_scrollController.position.pixels >=
_scrollController.position.maxScrollExtent &&
!isLoading) {
if (currentPage < totalPage) {
currentPage++;
_fetchData();
}
}
}
Future<void> _fetchData() async {
if (isLoading) return;
setState(() => isLoading = true);
try {
final data = {
'INSPECTION_STATUS': sindex > 0 ? stepList[sindex]['id'] : '',
'KEYWORDS': searchKeywords,
};
final url =
'/app/safetyenvironmental/list?showCount=-1&currentPage=$currentPage';
final response = await ApiService.getSafeCheckSearchList(data, url);
setState(() {
if (currentPage == 1) {
list = response['varList'];
} else {
list.addAll(response['varList']);
}
Map<String, dynamic> page = response['page'];
totalPage = page['totalPage'] ?? 1;
isLoading = false;
});
} catch (e) {
print('Error fetching data: $e');
setState(() => isLoading = false);
}
}
void _search() {
searchKeywords = _searchController.text.trim();
currentPage = 1;
list.clear();
_fetchData();
}
///
void _handleApply() {
//
pushPage(SafecheckStartDetail(INSPECTION_ID: '', isEdit: true), context);
}
///
Future<void> _openFlowDrawer(String ID) async {
try {
final response = await ApiService.safeCheckFlowList(ID);
final List<dynamic>? newFlow = response['varList'];
if (newFlow == null || newFlow.isEmpty) {
ToastUtil.showNormal(context, '暂无流程图数据');
return;
}
setState(() {
flowList = List<Map<String, dynamic>>.from(newFlow);
});
Future.microtask(() {
_scaffoldKey.currentState?.openEndDrawer();
});
} catch (e) {
print('Error fetching flow data: $e');
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('获取流程图失败: $e')));
}
}
void _goToDetail(Map<String, dynamic> item) async {
pushPage(SafecheckStartDetail(INSPECTION_ID: item['INSPECTION_ID'] ?? '', isEdit: false), context);
setState(() {
_fetchData();
});
}
Widget _buildFlowStepItem({
required Map<String, dynamic> item,
required bool isFirst,
required bool isLast,
required int status, // 1 = , 0 = , -1 =
}) {
//
final Color dotColor =
status == 1 ? Colors.blue : (status == 0 ? Colors.blue : Colors.grey);
final Color textColor =
status == 1
? Colors.blue
: (status == 0 ? Colors.blue : Colors.black54);
return ListTile(
visualDensity: VisualDensity(vertical: -4),
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
leading: Container(
width: 24,
alignment: Alignment.center,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
// 线
isFirst
? SizedBox(height: 6 + 5)
: Expanded(child: Container(width: 1, color: Colors.grey[300])),
//
CircleAvatar(radius: 6, backgroundColor: dotColor),
// 线
isLast
? SizedBox(height: 6 + 5)
: Expanded(child: Container(width: 1, color: Colors.grey[300])),
],
),
),
title: Text(
item['title'] ?? '',
style: TextStyle(color: textColor, fontSize: 15),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (item['desc'] != null)
Text(
item['desc'],
style: TextStyle(color: textColor, fontSize: 13),
),
],
),
);
}
String _checkStatusWithId(String id) {
for (Map item in stepList) {
if (item['id'] == id) {
return item['name'];
}
}
return '';
}
Widget _buildListItem(Map<String, dynamic> item) {
return Card(
color: Colors.white,
margin: const EdgeInsets.all(8.0),
child: InkWell(
onTap: () => _goToDetail(item),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"安全检查记录",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"检查状态: ${_checkStatusWithId(item['INSPECTION_STATUS'].toString())}",
),
Text("检查类型: ${item['INSPECTION_TYPE_NAME'] ?? ''}"),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("检查人: ${item['INSPECTION_USER_NAME'] ?? ''}"),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"检查发起人: ${item['INSPECTION_ORIGINATOR_NAME'] ?? ''}",
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("被检查人: ${item['INSPECTED_SITEUSER_NAME'] ?? ''}"),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"检查时间: ${item['INSPECTION_TIME_START'] ?? ''}${item['INSPECTION_TIME_END'] ?? ''}",
),
],
),
const SizedBox(height: 8),
Row(
children: [
CustomButton(
text: '流程图',
height: 35,
padding: EdgeInsets.symmetric(horizontal: 12),
margin: EdgeInsets.only(left: 0),
backgroundColor: Colors.blue,
onPressed: () => _openFlowDrawer(item['INSPECTION_ID']),
),
SizedBox(width: 1),
],
),
],
),
),
),
);
}
//
Future<void> _showStepPicker() async {
if (stepList.isEmpty) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('正在加载步骤数据,请稍后...')));
if (stepList.isEmpty) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('无法加载步骤数据')));
return;
}
}
//
final options = stepList.map((e) => e['name'] as String).toList();
//
final choice = await BottomPicker.show<String>(
context,
items: options,
itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
initialIndex: sindex,
);
if (choice != null) {
//
final newIndex = options.indexOf(choice);
if (newIndex != -1) {
setState(() {
sindex = newIndex;
});
_search();
}
}
}
Widget _buildListContent() {
if (isLoading && list.isEmpty) {
//
return Center(child: CircularProgressIndicator());
} else if (list.isEmpty) {
//
return NoDataWidget.show();
} else {
//
return ListView.builder(
padding: EdgeInsets.zero,
controller: _scrollController,
itemCount: list.length + (isLoading ? 1 : 0),
itemBuilder: (context, index) {
if (index >= list.length) {
//
return Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Center(child: CircularProgressIndicator()),
);
}
return _buildListItem(list[index]);
},
);
}
}
@override
Widget build(BuildContext context) {
final int lastDoneIndex = flowList.lastIndexWhere((e) => e['STATUS'] == 1);
return Scaffold(
key: _scaffoldKey,
appBar: MyAppbar(
title: '${widget.flow}',
actions: [
TextButton(
onPressed: _handleApply,
child: const Text(
'发起',
style: TextStyle(color: Colors.white, fontSize: 17),
),
),
],
),
endDrawer: Drawer(
child: SafeArea(
child:
flowList.isEmpty
? Center(child: Text('暂无流程图数据'))
: ListView.builder(
padding: const EdgeInsets.symmetric(vertical: 16),
itemCount: flowList.length + 1, // +1
itemBuilder: (context, i) {
if (i == 0) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
child: Text(
'查看流程图',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
);
}
final idx = i - 1;
final item = flowList[idx];
final bool isFirst = idx == 0;
final bool isLast = idx == flowList.length - 1;
// lastDoneIndex
final int status = item['active'] == '1' ? 1 : -1;
return _buildFlowStepItem(
item: item,
isFirst: isFirst,
isLast: isLast,
status: status,
);
},
),
),
),
body: Column(
children: [
// Filter bar
Container(
color: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 8),
child: Row(
children: [
//
SizedBox(
width: 65,
child: TextButton(
onPressed: _showStepPicker,
style: TextButton.styleFrom(
padding: EdgeInsets.symmetric(
vertical: 12,
horizontal: 5,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'筛选',
style: TextStyle(color: Colors.black87, fontSize: 16),
),
Icon(Icons.arrow_drop_down, color: Colors.grey),
],
),
),
),
Expanded(
flex: 2,
child: SearchBarWidget(
showResetButton: false,
hintText: "请输入关键字",
// isClickableOnly: true,
onSearch: (text) {
_search();
},
controller: _searchController,
),
),
],
),
),
const Divider(height: 1),
// List
Expanded(child: _buildListContent()),
],
),
);
}
}

View File

@ -4,6 +4,7 @@ import 'package:qhd_prevention/http/ApiService.dart';
import 'package:qhd_prevention/pages/KeyProjects/Danger/danger_list_page.dart';
import 'package:qhd_prevention/pages/KeyProjects/KeyProject/keyProject_list_page.dart';
import 'package:qhd_prevention/pages/KeyProjects/SafeCheck/safeCheck_list_page.dart';
import 'package:qhd_prevention/pages/home/SafeCheck/Start/safeCheck_start_list_page.dart';
import 'package:qhd_prevention/pages/home/tap/tabList/work_tab_icon_grid.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/tools/tools.dart';
@ -52,31 +53,38 @@ class _SafecheckTabListState extends State<SafecheckTabList> {
_getData();
}
Future<void> _getData() async {
LoadingDialogHelper.show();
final data = await ApiService.getKeyProjectCount();
LoadingDialogHelper.hide();
final data = await ApiService.getSafeCheckCount();
setState(() {
final eight_work_count = data['pd'] ?? {};
final checkedCount = data['checkedCount']['checkedCount'] ?? '';
final repulseAndCheckCount = data['repulseAndCheckCount']['repulseAndCheckCount'] ?? '';
final confirmCount = data['confirmCount']['confirmCount'] ?? '';
final repulseCount = data['repulseCount']['repulseCount'] ?? '';
buttonInfos = [
{
"icon": "assets/icon-apps/icon-yxkj-1.png",
"title": "重点工程管理",
"unreadCount": eight_work_count['GC_COUNT'] ?? '0',
"title": "安全检查\n发起",
"unreadCount": repulseCount,
},
{
"icon": "assets/icon-apps/icon-yxkj-1.png",
"title": "安全检查管理",
"unreadCount": '0',
"icon": "assets/icon-apps/icon-yxkj-4.png",
"title": "检查人\n确认",
"unreadCount": confirmCount,
},
{
"icon": "assets/icon-apps/icon-yxkj-1.png",
"title": "隐患管理",
"unreadCount": eight_work_count['CF_COUNT'] ?? '0',
"icon": "assets/icon-apps/icon-yxkj-2.png",
"title": "被检查人\n签字/申辩",
"unreadCount":checkedCount,
},
{
"icon": "assets/icon-apps/icon-yxkj-1.png",
"title": "处罚管理",
"unreadCount": eight_work_count['HIDDEN_COUNT'] ?? '0',
"icon": "assets/icon-apps/icon-yxkj-2.png",
"title": "隐患指派\n及验收",
"unreadCount":repulseAndCheckCount,
},
{
"icon": "assets/icon-apps/icon-yxkj-2.png",
"title": "申辩记录",
"unreadCount":'0',
},
];
@ -88,7 +96,7 @@ class _SafecheckTabListState extends State<SafecheckTabList> {
switch (index) {
case 0: {
title = '安全检查发起';
// await pushPage(KeyprojectListPage(flow: title), context);
await pushPage(SafecheckStartListPage(flow: title), context);
} break;
case 1: {
title = '安全检查核实';

View File

@ -1,5 +1,5 @@
import 'dart:io';
import 'package:dotted_line/dotted_line.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';

View File

@ -1,5 +1,5 @@
import 'dart:io';
import 'package:dotted_line/dotted_line.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';

View File

@ -1,6 +1,6 @@
import 'dart:io';
import 'package:qhd_prevention/pages/home/tap/tabList/special_wrok/sxkj_work/qtfx_work_detail/spacework_gas_list.dart';
import 'package:dotted_line/dotted_line.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';

View File

@ -177,14 +177,14 @@ packages:
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "2.1.1"
dotted_line:
dotted_border:
dependency: "direct main"
description:
name: dotted_line
sha256: "41e3d655939559815daa1370fc1e07673a205fa628cf40ce3af45d90029a77b6"
name: dotted_border
sha256: "99b091ec6891ba0c5331fdc2b502993c7c108f898995739a73c6845d71dad70c"
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
source: hosted
version: "3.2.3"
version: "3.1.0"
encrypt:
dependency: "direct main"
description:

View File

@ -73,8 +73,8 @@ dependencies:
geolocator: ^10.0.0
#打开外部预览app
url_launcher: ^6.0.9
#虚线
dotted_line: ^3.2.3
#虚线
dotted_border: ^3.1.0
#未读角标
flutter_new_badger: ^1.1.1
#loading