diff --git a/lib/http/ApiService.dart b/lib/http/ApiService.dart index c7282e2..ba286f9 100644 --- a/lib/http/ApiService.dart +++ b/lib/http/ApiService.dart @@ -24,6 +24,7 @@ class ApiService { "http://192.168.20.240:8500/whb_stu_face/"; /// 登录及其他管理后台接口 // static const String basePath = "https://qaaqwh.qhdsafety.com/integrated_whb"; + // static const String basePath = "http://192.168.20.240:8500/integrated_whb"; static const String basePath = "http://192.168.20.240:8500/integrated_whb"; // static const String basePath = "http://192.168.0.37:8099/api"; @@ -1581,8 +1582,8 @@ U6Hzm1ninpWeE+awIDAQAB "CORPINFO_ID": SessionService.instance.corpinfoId, "USER_ID": SessionService.instance.loginUserId, "OPERATOR": SessionService.instance.loginUserId, - "NAME": SessionService.instance.loginUser?["USERNAME"] ?? "", - "USERNAME": SessionService.instance.loginUser?["USERNAME"] ?? "", + "NAME": SessionService.instance.username, + "USERNAME": SessionService.instance.username, }, ); } @@ -2481,7 +2482,7 @@ U6Hzm1ninpWeE+awIDAQAB String id, ) { return HttpManager().request( - basePath, + basePath, '/app/hidden/riskListCheckInspection', method: Method.post, data: { diff --git a/lib/pages/app/Danger_paicha/check_record_detail_page.dart b/lib/pages/app/Danger_paicha/check_record_detail_page.dart index 9625115..b362007 100644 --- a/lib/pages/app/Danger_paicha/check_record_detail_page.dart +++ b/lib/pages/app/Danger_paicha/check_record_detail_page.dart @@ -59,6 +59,8 @@ class _CheckRecordDetailPageState extends State { @override void initState() { super.initState(); + // 先初始化 webview controller,使其尽早准备好 + _initLocation(); // 启动时并行请求,UI 使用 setState 更新 _fetchAll(); } @@ -112,12 +114,114 @@ class _CheckRecordDetailPageState extends State { centerLng = lng; _loadingMap = false; }); + // 确保 controller 已初始化并注入最新参数,触发地图刷新 + if (_controller == null) { + // 如果 controller 还没创建,先创建 + await _initLocation(); + } else { + // controller 已存在,直接注入参数(页面若尚未完成加载,onPageFinished 会再次注入) + await _injectLocationParams(); + } } catch (e, st) { debugPrint('getMapData error: $e\n$st'); setState(() => _loadingMap = false); } } + + Future _initLocation() async { + try { + // 如果已经有 controller,直接返回(避免重复创建) + if (_controller != null) return; + + // 创建 controller 并 setState 以触发重建,使 BaiduMapWebView 能拿到 controller + setState(() { + _controller = WebViewController() + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..addJavaScriptChannel('JS', onMessageReceived: (JavaScriptMessage message) { + debugPrint('JS LOG: ${message.message}'); + }) + ..setNavigationDelegate( + NavigationDelegate( + onPageFinished: (String url) async { + debugPrint('网页加载完成: $url'); + // 页面加载完成后把最新的位置参数注入进去 + await _injectLocationParams(); + }, + onWebResourceError: (err) { + debugPrint('Web resource error: ${err.description}'); + }, + ), + ); + }); + + // 延迟一点再加载页面以确保 setState 已生效(非必需,但更稳健) + await Future.delayed(const Duration(milliseconds: 50)); + + try { + await _controller!.loadRequest(Uri.parse('http://47.92.102.56:7811/file/fluteightmap/index.html')); + } catch (e, st) { + debugPrint('loadRequest 错误: $e\n$st'); + } + } catch (e, st) { + debugPrint('_initLocation error: $e\n$st'); + } + } + + Future _injectLocationParams() async { + if (_controller == null) { + debugPrint('_injectLocationParams: controller 为空,跳过注入'); + return; + } + + // 构造参数,确保使用当前最新 centerLat/centerLng + final params = { + 'longitude': centerLng, + 'latitude': centerLat, + 'GSON': covers, // 你原来用空数组,这里把 covers 也注入给地图(可选) + 't': DateTime.now().millisecondsSinceEpoch, + }; + + final jsonParams = jsonEncode(params); + + try { + await _controller!.runJavaScript(''' + (function(){ + try { + if (typeof window.initWithData === 'function') { + window.initWithData($jsonParams); + } else if (typeof window.initMap === 'function') { + window.initMap($jsonParams); + } else { + console.error('initWithData / initMap function not found'); + } + } catch(e) { + console.error('call initWithData error', e); + } + })(); + '''); + debugPrint('已注入地图初始化参数: $jsonParams'); + } catch (e, st) { + debugPrint('注入位置参数失败: $e\n$st'); + // 如果注入失败且页面尚未加载,等待并重试一次(防止 race) + await Future.delayed(const Duration(milliseconds: 200)); + try { + if (_controller != null) { + await _controller!.runJavaScript(''' + (function(){ + try { + if (typeof window.initWithData === 'function') { + window.initWithData($jsonParams); + } else if (typeof window.initMap === 'function') { + window.initMap($jsonParams); + } + } catch(e) {} + })(); + '''); + } + } catch (_) {} + } + } List> buildCoversFromRes(Map res) { final list = >[]; @@ -378,72 +482,6 @@ class _CheckRecordDetailPageState extends State { ), ); } - /// 获取定位(并初始化 WebView 控制器) - Future _initLocation() async { - - // 允许多次赋值 - _controller = WebViewController() - ..setJavaScriptMode(JavaScriptMode.unrestricted) - ..addJavaScriptChannel('JS', onMessageReceived: (JavaScriptMessage message) { - debugPrint('JS LOG: ${message.message}'); - }) - ..setNavigationDelegate( - NavigationDelegate( - onPageFinished: (String url) async { - debugPrint('网页加载完成: $url'); - await _injectLocationParams(); - }, - onWebResourceError: (err) { - debugPrint('Web resource error: ${err.description}'); - }, - ), - ); - - // 加载页面(注意:如果 loadRequest 失败你可以捕获异常) - try { - await _controller!.loadRequest(Uri.parse('http://47.92.102.56:7811/file/fluteightmap/index.html')); - - } catch (e, st) { - debugPrint('loadRequest 错误: $e\n$st'); - } - } - - Future _injectLocationParams() async { - if (_controller == null) { - debugPrint('_injectLocationParams: controller 为空,跳过注入'); - return; - } - - final params = { - 'longitude': centerLng, - 'latitude': centerLat, - 'GSON': [], - 't': DateTime.now().millisecondsSinceEpoch, - }; - - final jsonParams = jsonEncode(params); - - try { - await _controller!.runJavaScript(''' - (function(){ - try { - if (typeof window.initWithData === 'function') { - window.initWithData($jsonParams); - } else if (typeof window.initMap === 'function') { - window.initMap($jsonParams); - } else { - console.error('initWithData / initMap function not found'); - } - } catch(e) { - console.error('call initWithData error', e); - } - })(); - '''); - debugPrint('已注入地图初始化参数'); - } catch (e) { - debugPrint('注入位置参数失败: $e'); - } - } Widget _buildTableHeaderCell(String text) { return Padding(padding: EdgeInsets.all(8), child: Center(child: Text(text, style: TextStyle(fontWeight: FontWeight.bold)))); diff --git a/lib/pages/home/SafeCheck/CheckPersonSign/safecheck_sign_detail.dart b/lib/pages/home/SafeCheck/CheckPersonSign/safecheck_sign_detail.dart index e9e566e..dc2f56f 100644 --- a/lib/pages/home/SafeCheck/CheckPersonSign/safecheck_sign_detail.dart +++ b/lib/pages/home/SafeCheck/CheckPersonSign/safecheck_sign_detail.dart @@ -68,9 +68,11 @@ class _SafecheckSignDetailState extends State { Future _getData() async { try { + LoadingDialogHelper.show(); final result = await ApiService.getSafeCheckSureList( widget.INSPECTION_ID, ); + LoadingDialogHelper.hide(); // 在 await 之后检查 mounted,避免页面已经被 pop 导致 setState 报错 if (!mounted) return; setState(() { diff --git a/lib/pages/home/SafeCheck/DangeCheck/safeCheck_assignment_detail_page.dart b/lib/pages/home/SafeCheck/DangeCheck/safeCheck_assignment_detail_page.dart index caaacbe..ee8fa1c 100644 --- a/lib/pages/home/SafeCheck/DangeCheck/safeCheck_assignment_detail_page.dart +++ b/lib/pages/home/SafeCheck/DangeCheck/safeCheck_assignment_detail_page.dart @@ -78,7 +78,6 @@ class _SafecheckAssignmentDetailPageState .map((item) => '${ApiService.baseImgPath}${item['FILEPATH']}') .toList(); files = data['hImgs']; - }); } } @@ -164,9 +163,8 @@ class _SafecheckAssignmentDetailPageState if (result['result'] == 'success') { ToastUtil.showNormal(context, '保存成功'); Navigator.of(context).pop(); - }else{ + } else { ToastUtil.showNormal(context, '保存失败'); - } LoadingDialogHelper.hide(); } catch (e) { @@ -213,6 +211,12 @@ class _SafecheckAssignmentDetailPageState ItemListWidget.singleLineTitleText( label: '隐患类型', isEditable: false, + text: form['HIDDENTYPE_NAME'] ?? '', + ), + const Divider(), + ItemListWidget.singleLineTitleText( + label: '整改类型', + isEditable: false, text: _rect_des[form['RECTIFICATIONTYPE'].toString()] ?? '', ), @@ -241,7 +245,6 @@ class _SafecheckAssignmentDetailPageState initialMediaPaths: hiddenVideo, onChanged: (files) {}, onAiIdentify: () {}, - ), ), ], @@ -322,13 +325,16 @@ class _SafecheckAssignmentDetailPageState ), ), SizedBox(height: 15), - Padding(padding: EdgeInsets.symmetric(horizontal: 50, vertical: 10), child: CustomButton( - text: _isEdit ? '保存' : '返回', - backgroundColor: Colors.blue, - onPressed: () { - _submit(); - }, - ),) + Padding( + padding: EdgeInsets.symmetric(horizontal: 50, vertical: 10), + child: CustomButton( + text: _isEdit ? '保存' : '返回', + backgroundColor: Colors.blue, + onPressed: () { + _submit(); + }, + ), + ), ], ), ), diff --git a/lib/pages/home/SafeCheck/DangeCheck/safecheck_danger_detail.dart b/lib/pages/home/SafeCheck/DangeCheck/safecheck_danger_detail.dart index 346dd76..f854ef0 100644 --- a/lib/pages/home/SafeCheck/DangeCheck/safecheck_danger_detail.dart +++ b/lib/pages/home/SafeCheck/DangeCheck/safecheck_danger_detail.dart @@ -67,9 +67,11 @@ class _SafecheckDangerDetailState extends State { Future _getData() async { try { + LoadingDialogHelper.show(); final result = await ApiService.getSafeCheckSureList( widget.INSPECTION_ID, ); + LoadingDialogHelper.hide(); // 在 await 之后检查 mounted,避免页面已经被 pop 导致 setState 报错 if (!mounted) return; setState(() { diff --git a/lib/pages/home/SafeCheck/Record/defend_record_detail_page.dart b/lib/pages/home/SafeCheck/Record/defend_record_detail_page.dart index b669922..f3e72c1 100644 --- a/lib/pages/home/SafeCheck/Record/defend_record_detail_page.dart +++ b/lib/pages/home/SafeCheck/Record/defend_record_detail_page.dart @@ -34,7 +34,10 @@ class _DefendRecordDetailPageState extends State { widget.INSPECTION_ID, ); if (result['result'] == 'success') { - _list = result['list']; + setState(() { + _list = result['list']; + + }); } LoadingDialogHelper.hide(); } catch (e) { @@ -53,6 +56,7 @@ class _DefendRecordDetailPageState extends State { '申辩意见:${item['INSPECTED_EXPLAIN'] ?? ''}', ), ), + const Divider(), ItemListWidget.singleLineTitleText( label: '申辩时间', isEditable: false, diff --git a/lib/pages/mine/mine_duty_application.dart b/lib/pages/mine/mine_duty_application.dart index 14a2048..bdd68b9 100644 --- a/lib/pages/mine/mine_duty_application.dart +++ b/lib/pages/mine/mine_duty_application.dart @@ -150,7 +150,7 @@ class _MineDutyApplicationPage extends State { borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( - color: Colors.grey.withOpacity(0.1), + color: Colors.blue.withOpacity(0.1), spreadRadius: 1, blurRadius: 6, offset: const Offset(0, 2), @@ -160,6 +160,7 @@ class _MineDutyApplicationPage extends State { child: TextField( controller: _reasonController, maxLines: 5, + maxLength: 120, // 限制最大字数为 200 decoration: const InputDecoration( hintText: "请输入离岗原因", hintStyle: TextStyle(color: Color(0xFF9E9E9E)), diff --git a/lib/pages/mine/mine_duty_management.dart b/lib/pages/mine/mine_duty_management.dart index bacf214..26ebf0c 100644 --- a/lib/pages/mine/mine_duty_management.dart +++ b/lib/pages/mine/mine_duty_management.dart @@ -36,12 +36,10 @@ class MineDutyManagementPage extends StatefulWidget { } class _MineDutyManagementPageState extends State { - - int showCount=-1; - int currentPage=1; + int showCount = -1; + int currentPage = 1; late List _list = []; - Future _onRefresh() async { // 模拟网络请求 await Future.delayed(const Duration(seconds: 2)); @@ -55,19 +53,16 @@ class _MineDutyManagementPageState extends State { @override void initState() { _getListData(); - } - void refreshData(){ - currentPage=1; + void refreshData() { + currentPage = 1; _list.clear(); _getListData(); } - @override Widget build(BuildContext context) { - // 模拟数据 // final leaveRecords = [ // LeaveRecord( @@ -110,82 +105,89 @@ class _MineDutyManagementPageState extends State { return Scaffold( backgroundColor: const Color(0xFFF5F7FA), - appBar: MyAppbar(title: "离岗管理",actions: [ - TextButton( + appBar: MyAppbar( + title: "离岗管理", + actions: [ + TextButton( onPressed: () { - Navigator.push( context, MaterialPageRoute( - builder: (context) => MineDutyApplicationPage( - onClose: (result) { - // print('详情页面已关闭,返回结果: $result'); - refreshData(); - }, - ), + builder: + (context) => MineDutyApplicationPage( + onClose: (result) { + // print('详情页面已关闭,返回结果: $result'); + refreshData(); + }, + ), ), ); // pushPage(MineDutyApplicationPage(), context); - }, - child: Text("申请",style: TextStyle(color: Colors.white,fontSize: 16,fontWeight:FontWeight.bold),)) - ],), - body: - RefreshIndicator( - onRefresh: _onRefresh, - child: - // Column( - // children: [ - // 顶部信息栏 - // Container( - // padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - // color: const Color(0xFFE3F2FD), - // child: const Row( - // children: [ - // Icon(Icons.info_outline, color: Color(0xFF1976D2)), - // SizedBox(width: 8), - // Text( - // "离岗记录显示最近30天内的申请记录", - // style: TextStyle(color: Color(0xFF1976D2), fontSize: 14), - // ), - // ], - // ), - // ), - - // 记录列表 - Expanded( - child: - _list.isEmpty - ? NoDataWidget.show() - : ListView.builder( - padding: const EdgeInsets.symmetric(vertical: 16), - itemCount: _list.length, - itemBuilder: (context, index) { - final record = _list[index]; - return _buildRecordCard(record,context); - }, + }, + child: Text( + "申请", + style: TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.bold, + ), ), - // ), - // ], + ), + ], + ), + body: RefreshIndicator( + onRefresh: _onRefresh, + child: + // Column( + // children: [ + // 顶部信息栏 + // Container( + // padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + // color: const Color(0xFFE3F2FD), + // child: const Row( + // children: [ + // Icon(Icons.info_outline, color: Color(0xFF1976D2)), + // SizedBox(width: 8), + // Text( + // "离岗记录显示最近30天内的申请记录", + // style: TextStyle(color: Color(0xFF1976D2), fontSize: 14), + // ), + // ], + // ), + // ), + // 记录列表 + Expanded( + child: + _list.isEmpty + ? NoDataWidget.show() + : ListView.builder( + padding: const EdgeInsets.symmetric(vertical: 16), + itemCount: _list.length, + itemBuilder: (context, index) { + final record = _list[index]; + return _buildRecordCard(record, context); + }, + ), + // ), + // ], + ), ), - ), ); } - Widget _buildRecordCard(final item , BuildContext context) { + Widget _buildRecordCard(final item, BuildContext context) { // final dateFormat = DateFormat('yyyy-MM-dd'); // final isSameDay = record.startDate == record.endDate; // final dateRange = isSameDay // ? dateFormat.format(record.startDate) // : "${dateFormat.format(record.startDate)} 至 ${dateFormat.format(record.endDate)}"; - final dateRange ="${item['STARTTIME']} 至 ${item['ENDTIME']}"; + final dateRange = "${item['STARTTIME']} 至 ${item['ENDTIME']}"; - return - GestureDetector( + return GestureDetector( onTap: () { pushPage(MineDutyDetailPage(item), context); }, - child: - Container( + child: Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: Colors.white, @@ -196,7 +198,7 @@ class _MineDutyManagementPageState extends State { spreadRadius: 1, blurRadius: 6, offset: const Offset(0, 2), - ) + ), ], ), child: Padding( @@ -230,16 +232,12 @@ class _MineDutyManagementPageState extends State { const SizedBox(height: 4), Text( "部门:${item['DEPARTMENTNAME']} \n岗位:${item['POSTNAME']}", - style: TextStyle( - fontSize: 13, - color: Colors.grey[600], - ), + style: TextStyle(fontSize: 13, color: Colors.grey[600]), ), - ], ), - // const Spacer(), + // const Spacer(), ], ), @@ -248,15 +246,18 @@ class _MineDutyManagementPageState extends State { // 离岗时间 Row( children: [ - const Icon(Icons.calendar_today, size: 18, color: Colors.grey), + const Icon( + Icons.calendar_today, + size: 18, + color: Colors.grey, + ), const SizedBox(width: 8), Expanded( - child: Text( - "离岗时间: $dateRange", - style: const TextStyle(color: Colors.grey), - ), + child: Text( + "离岗时间: $dateRange", + style: const TextStyle(color: Colors.grey), + ), ), - ], ), @@ -268,83 +269,91 @@ class _MineDutyManagementPageState extends State { // // borderRadius: BorderRadius.circular(20), // // ), // child: - Text( - "审核状态:${_getTypeReturn(item)}", - // record.status, - style: TextStyle( - color: Colors.black, - fontWeight: FontWeight.w500, - ), + Text( + "审核状态:${_getTypeReturn(item)}", + // record.status, + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.w500, ), - // ), + ), + // ), const SizedBox(height: 4), // 操作按钮 - if( item["REVIEW_STATUS"]=="0"&&DateTime.now().isBefore(item["ENDTIME"])&& - (item["REVIEW_USER_ID"]==SessionService.instance.loginUserId)&& - SessionService.instance.loginUser?["USERNAME"]=="1"&&item['REVIEW_STATUS']=="0") - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - ElevatedButton( - onPressed: () { - showDialog( - context: context, - builder: (context) => DutyDialog( - item,1, - onClose: (result) { - // print('详情页面已关闭,返回结果: $result'); - refreshData(); - }, - - ), - ); - }, - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF1976D2), - // padding: const EdgeInsets.symmetric(horizontal: 10), + if (item["REVIEW_STATUS"] == "0" && + isBeforeNow(item["ENDTIME"]) && + (item["REVIEW_USER_ID"] == + SessionService.instance.loginUserId) && + SessionService.instance.loginUser?["USERNAME"] == "1" && + item['REVIEW_STATUS'] == "0") + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + ElevatedButton( + onPressed: () { + showDialog( + context: context, + builder: + (context) => DutyDialog( + item, + 1, + onClose: (result) { + // print('详情页面已关闭,返回结果: $result'); + refreshData(); + }, + ), + ); + }, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF1976D2), + // padding: const EdgeInsets.symmetric(horizontal: 10), + ), + child: const Text( + "审 批", + style: TextStyle(color: Colors.white, fontSize: 12), + ), ), - child: const Text("审 批", style: TextStyle(color: Colors.white,fontSize: 12)), - ), - const SizedBox(width: 16), + const SizedBox(width: 16), ElevatedButton( onPressed: () { showDialog( context: context, - builder: (context) => DutyDialog( - item,2, - onClose: (result) { - // print('详情页面已关闭,返回结果: $result'); - refreshData(); - }, - - ), + builder: + (context) => DutyDialog( + item, + 2, + onClose: (result) { + // print('详情页面已关闭,返回结果: $result'); + refreshData(); + }, + ), ); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.red, // padding: const EdgeInsets.symmetric(horizontal: 10), ), - child: const Text("取 消", style: TextStyle(color: Colors.white,fontSize: 12)), - ) - - ], - ), + child: const Text( + "取 消", + style: TextStyle(color: Colors.white, fontSize: 12), + ), + ), + ], + ), ], ), ), ), ); - } Future _getListData() async { try { - - final result = await ApiService.getDutyManagement(showCount,currentPage); + final result = await ApiService.getDutyManagement(showCount, currentPage); if (result['result'] == 'success') { final List newList = result['varList'] ?? []; setState(() { @@ -356,56 +365,47 @@ class _MineDutyManagementPageState extends State { } } - String _getTypeReturn(final item) { - String type=item['REVIEW_STATUS']; - if("0"==type){ - return "待审批"; - }else if("1"==type){ - return "审批通过"; - }else if("2"==type){ - return "无需审批"; - }else if("-1"==type){ - String type2=item['ISDELETE']; - if("1"==type2){ - if(item['CREATOR']==item['OPERATOR']){ - return "申请人取消"; - }else{ - return "审批人取消"; - } - }else{ - return "审批打回"; - } - }else{ - return "审批错误"; - } + String type = item['REVIEW_STATUS']; + if ("0" == type) { + return "待审批"; + } else if ("1" == type) { + return "审批通过"; + } else if ("2" == type) { + return "无需审批"; + } else if ("-1" == type) { + String type2 = item['ISDELETE']; + if ("1" == type2) { + if (item['CREATOR'] == item['OPERATOR']) { + return "申请人取消"; + } else { + return "审批人取消"; + } + } else { + return "审批打回"; + } + } else { + return "审批错误"; + } } - - } - - -enum FeedbackType { - tongGuo, - Dahui, -} +enum FeedbackType { tongGuo, Dahui } class DutyDialog extends StatefulWidget { - const DutyDialog(this.item,this.type, {super.key,required this.onClose}); + const DutyDialog(this.item, this.type, {super.key, required this.onClose}); final Function(String) onClose; // 回调函数 final item; final int type; - @override State createState() => _DutyDialogState(); } class _DutyDialogState extends State { - final TextEditingController _reasonController = TextEditingController(); + // 反馈类型 FeedbackType? _selectedType = FeedbackType.tongGuo; @@ -419,18 +419,20 @@ class _DutyDialogState extends State { } } - Future _dutyApproval() async { try { - String typeString; - if(FeedbackType.tongGuo==_selectedType){ - typeString="1"; - }else{ - typeString="-1"; + if (FeedbackType.tongGuo == _selectedType) { + typeString = "1"; + } else { + typeString = "-1"; } - final result = await ApiService.dutyApproval(typeString,_reasonController.text,widget.item["OFFDUTY_ID"]); + final result = await ApiService.dutyApproval( + typeString, + _reasonController.text, + widget.item["OFFDUTY_ID"], + ); if (result['result'] == 'success') { widget.onClose('关闭提交'); // 触发回调 } @@ -441,8 +443,11 @@ class _DutyDialogState extends State { Future _dutyReturned() async { try { - - final result = await ApiService.dutyReturned("-1",_reasonController.text,widget.item["OFFDUTY_ID"]); + final result = await ApiService.dutyReturned( + "-1", + _reasonController.text, + widget.item["OFFDUTY_ID"], + ); if (result['result'] == 'success') { widget.onClose('关闭提交'); // 触发回调 } @@ -479,37 +484,39 @@ class _DutyDialogState extends State { // _buildActionButton('打印', Colors.blue), // ], // ), - if(1==widget.type) - Center( - child: Wrap( - spacing: 16, - children: - FeedbackType.values.map((type) { - return ChoiceChip( - label: Text(_getTypeName(type)), - selected: _selectedType == type, - onSelected: (selected) { - setState(() { - if (selected) { - _selectedType = type; - } - }); - }, - ); - }).toList(), + if (1 == widget.type) + Center( + child: Wrap( + spacing: 16, + children: + FeedbackType.values.map((type) { + return ChoiceChip( + label: Text(_getTypeName(type)), + selected: _selectedType == type, + onSelected: (selected) { + setState(() { + if (selected) { + _selectedType = type; + } + }); + }, + ); + }).toList(), + ), ), - ), - const SizedBox(height: 20), // 输入框 - TextField( + TextField( controller: _reasonController, decoration: InputDecoration( border: OutlineInputBorder(), - hintText: widget.type==1?'请输入审批意见':'请输入原因', - contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 16), + hintText: widget.type == 1 ? '请输入审批意见' : '请输入原因', + contentPadding: EdgeInsets.symmetric( + horizontal: 12, + vertical: 16, + ), ), maxLines: 4, ), @@ -522,39 +529,49 @@ class _DutyDialogState extends State { children: [ Expanded( child: ElevatedButton( - onPressed: (){ - if(_reasonController.text.isEmpty){ - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(widget.type==1?'请输入审批意见':'请输入原因')) - ); - return; - } + onPressed: () { + if (_reasonController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + widget.type == 1 ? '请输入审批意见' : '请输入原因', + ), + ), + ); + return; + } - if(1==widget.type){ - _dutyApproval();//审批 - }else{ - _dutyReturned();//打回 - } - Navigator.pop(context); - } , + if (1 == widget.type) { + _dutyApproval(); //审批 + } else { + _dutyReturned(); //打回 + } + Navigator.pop(context); + }, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, padding: const EdgeInsets.symmetric(vertical: 14), ), - child: const Text('提交',style: TextStyle(color: Colors.white),), + child: const Text( + '提交', + style: TextStyle(color: Colors.white), + ), ), ), const SizedBox(width: 15), Expanded( child: ElevatedButton( - onPressed: (){ + onPressed: () { Navigator.pop(context); - } , + }, style: ElevatedButton.styleFrom( backgroundColor: Colors.grey, padding: const EdgeInsets.symmetric(vertical: 14), ), - child: const Text('关闭',style: TextStyle(color: Colors.white),), + child: const Text( + '关闭', + style: TextStyle(color: Colors.white), + ), ), ), ], @@ -564,9 +581,4 @@ class _DutyDialogState extends State { ), ); } - - } - - - diff --git a/lib/pages/mine/mine_feedback_page.dart b/lib/pages/mine/mine_feedback_page.dart index 24a1513..236e242 100644 --- a/lib/pages/mine/mine_feedback_page.dart +++ b/lib/pages/mine/mine_feedback_page.dart @@ -101,6 +101,7 @@ class _FeedbackPageState extends State { const Text('标题', style: TextStyle(fontWeight: FontWeight.bold)), const SizedBox(height: 8), TextFormField( + maxLength: 50, controller: _titleController, decoration: const InputDecoration( hintText: '请输入标题...', @@ -124,6 +125,7 @@ class _FeedbackPageState extends State { TextFormField( controller: _descriptionController, maxLines: 5, + maxLength: 120, decoration: const InputDecoration( hintText: '请补充详细问题和意见...', diff --git a/lib/tools/tools.dart b/lib/tools/tools.dart index 2334d17..15ea21e 100644 --- a/lib/tools/tools.dart +++ b/lib/tools/tools.dart @@ -284,24 +284,29 @@ String formatDate(DateTime? date, String fmt) { /// 把 'yyyy-MM-dd HH:mm'(或 'yyyy-MM-ddTHH:mm')解析为 DateTime,失败返回 null DateTime? _parseYMdHm(String s) { if (s.isEmpty) return null; - // 允许传入 'yyyy-MM-dd HH:mm' 或 'yyyy-MM-ddTHH:mm' - // 如果没有秒,补上 :00 String t = s.trim(); - // 如果只有日期部分,直接返回 null(你也可以自行扩展) - if (!RegExp(r'^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}$').hasMatch(t)) { - // 试着容错:如果是 'yyyy-MM-dd HH:mm:ss' 也接受 - if (!RegExp(r'^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}$').hasMatch(t)) { - return null; - } else { - // 已经带秒,直接 parse - return DateTime.tryParse(t.replaceFirst(' ', 'T')); - } + + // 只包含日期的情况:yyyy-MM-dd + if (RegExp(r'^\d{4}-\d{2}-\d{2}$').hasMatch(t)) { + return DateTime.tryParse(t); // 默认 00:00:00 } - // 如果是 'yyyy-MM-dd HH:mm',补齐秒并使用 ISO 格式 - final iso = t.replaceFirst(' ', 'T') + ':00'; - return DateTime.tryParse(iso); + + // yyyy-MM-dd HH:mm 或 yyyy-MM-ddTHH:mm + if (RegExp(r'^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}$').hasMatch(t)) { + final iso = t.replaceFirst(' ', 'T') + ':00'; + return DateTime.tryParse(iso); + } + + // yyyy-MM-dd HH:mm:ss 或 yyyy-MM-ddTHH:mm:ss + if (RegExp(r'^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}$').hasMatch(t)) { + return DateTime.tryParse(t.replaceFirst(' ', 'T')); + } + + // 都不匹配,返回 null + return null; } + /// 比较两个 'yyyy-MM-dd HH:mm' 格式字符串 /// 返回 1 (a>b), 0 (a==b), -1 (a compareYMdHmStrings(a, b) == 1; /// 便捷:a 是否 早于 b bool isBeforeStr(String a, String b) => compareYMdHmStrings(a, b) == -1; - +/// 判断传入时间字符串 (yyyy-MM-dd HH:mm) 是否早于当前时间 +bool isBeforeNow(String timeStr) { + final dt = _parseYMdHm(timeStr); + if (dt == null) { + throw FormatException("时间格式错误,期望 'yyyy-MM-dd HH:mm' 或 'yyyy-MM-dd HH:mm:ss'"); + } + return dt.isBefore(DateTime.now()); +} /// ------------------------------------------------------ /// 防多次点击 /// ------------------------------------------------------ diff --git a/pubspec.lock b/pubspec.lock index 2435aa2..444a804 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -765,6 +765,70 @@ packages: url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" source: hosted version: "0.5.0" + open_file: + dependency: "direct main" + description: + name: open_file + sha256: d17e2bddf5b278cb2ae18393d0496aa4f162142ba97d1a9e0c30d476adf99c0e + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "3.5.10" + open_file_android: + dependency: transitive + description: + name: open_file_android + sha256: "58141fcaece2f453a9684509a7275f231ac0e3d6ceb9a5e6de310a7dff9084aa" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "1.0.6" + open_file_ios: + dependency: transitive + description: + name: open_file_ios + sha256: "02996f01e5f6863832068e97f8f3a5ef9b613516db6897f373b43b79849e4d07" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "1.0.3" + open_file_linux: + dependency: transitive + description: + name: open_file_linux + sha256: d189f799eecbb139c97f8bc7d303f9e720954fa4e0fa1b0b7294767e5f2d7550 + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "0.0.5" + open_file_mac: + dependency: transitive + description: + name: open_file_mac + sha256: "1440b1e37ceb0642208cfeb2c659c6cda27b25187a90635c9d1acb7d0584d324" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "1.0.3" + open_file_platform_interface: + dependency: transitive + description: + name: open_file_platform_interface + sha256: "101b424ca359632699a7e1213e83d025722ab668b9fd1412338221bf9b0e5757" + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "1.0.3" + open_file_web: + dependency: transitive + description: + name: open_file_web + sha256: e3dbc9584856283dcb30aef5720558b90f88036360bd078e494ab80a80130c4f + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "0.0.4" + open_file_windows: + dependency: transitive + description: + name: open_file_windows + sha256: d26c31ddf935a94a1a3aa43a23f4fff8a5ff4eea395fe7a8cb819cf55431c875 + url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/" + source: hosted + version: "0.0.3" package_info_plus: dependency: "direct main" description: