flutter 识别身份证
import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:flutter/widgets.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:image_picker/image_picker.dart'; import 'dart:io'; import 'package:path_provider/path_provider.dart'; // import 'package:google_ml_kit/google_ml_kit.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:google_mlkit_text_recognition/google_mlkit_text_recognition.dart'; // 启动界面 class SplashScreen extends StatefulWidget { @override _SplashScreenState createState() => _SplashScreenState(); } class _SplashScreenState extends State<SplashScreen> { @override void initState() { super.initState(); Future.delayed(Duration(seconds: 3), () { _checkLoginStatus(); }); } Future<void> _checkLoginStatus() async { SharedPreferences prefs = await SharedPreferences.getInstance(); String? isLoggedIn = prefs.getString('islogin'); if (isLoggedIn == '登录') { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => HomePage()), ); } else { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => LoginPage()), ); } } @override Widget build(BuildContext context) { return Scaffold( body: Stack( fit: StackFit.expand, children: [ // 添加背景图 Image.asset( 'assets/images/welcome.png', fit: BoxFit.cover, ), ], ), ); } } // 定义轮播图信息类 class BannerInfo { String createTime; int id; int isDelete; int location; String name; int status; int type; String url; BannerInfo({ required this.createTime, required this.id, required this.isDelete, required this.location, required this.name, required this.status, required this.type, required this.url, }); factory BannerInfo.fromJson(Map<String, dynamic> json) { return BannerInfo( createTime: json['createTime'], id: json['id'], isDelete: json['isDelete'], location: json['location'], name: json['name'], status: json['status'], type: json['type'], url: json['url'], ); } } // 定义响应数据类 class ResponseData { int code; List<BannerInfo> data; String msg; ResponseData({ required this.code, required this.data, required this.msg, }); factory ResponseData.fromJson(Map<String, dynamic> json) { return ResponseData( code: json['code'], data: (json['data'] as List<dynamic>) .map((item) => BannerInfo.fromJson(item)) .toList(), msg: json['msg'], ); } } // 主页 class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { int _currentIndex = 0; final List<Widget> _pages = [ HomeFragment(), WaybillFragment(), MessageFragment(), ProfileFragment(), ]; @override Widget build(BuildContext context) { return Scaffold( body: _pages[_currentIndex], bottomNavigationBar: BottomNavigationBar( currentIndex: _currentIndex, onTap: (index) { setState(() { _currentIndex = index; }); }, selectedItemColor: Color(0xFF57bd6b), // 选中状态颜色 unselectedItemColor: Color(0xFF808080), // 未选中状态颜色 items: [ BottomNavigationBarItem( icon: Icon(Icons.home), label: '首页', ), BottomNavigationBarItem( icon: Icon(Icons.list), label: '运单', ), BottomNavigationBarItem( icon: Icon(Icons.message), label: '消息', ), BottomNavigationBarItem( icon: Icon(Icons.person), label: '我的', ), ], ), ); } } // 首页碎片 //实体类 上传二维码 class BillModelResult { int code; String msg; BillModel data; BillModelResult({ required this.code, required this.msg, required this.data, }); factory BillModelResult.fromJson(Map<String, dynamic> json) { return BillModelResult( code: json['code'], msg: json['msg'], data: BillModel.fromJson(json['data']), ); } } class BillModel { bool allowEditCarInfo; String forwardingUnit; int id; int isDangerous; String receivingUnit; int wayBillType; String wlName; String carNum; String nodesName; String outFactoryTime; // 出厂时间 String wlNameOut; String ywType; String yfjz; String yfmz; String yfpz; String waitCount; String currentNodeName; List<FlowDTO> flow; String flowName; String remark; String sfhddName; String ywName; // 业务名称 String startTime; // 开始时间 String backHigh; String carLong; String carWide; String frontHigh; String tieBarNum; String gross; String mzBridge; String mzTime; String net; String pzBridge; String pzTime; String tare; bool internal; String unloadingPoint; // 内运卸货地点 int ywId; String kz; BillModel({ required this.allowEditCarInfo, required this.forwardingUnit, required this.id, required this.isDangerous, required this.receivingUnit, required this.wayBillType, required this.wlName, required this.carNum, required this.nodesName, required this.outFactoryTime, required this.wlNameOut, required this.ywType, required this.yfjz, required this.yfmz, required this.yfpz, required this.waitCount, required this.currentNodeName, required this.flow, required this.flowName, required this.remark, required this.sfhddName, required this.ywName, required this.startTime, required this.backHigh, required this.carLong, required this.carWide, required this.frontHigh, required this.tieBarNum, required this.gross, required this.mzBridge, required this.mzTime, required this.net, required this.pzBridge, required this.pzTime, required this.tare, required this.internal, required this.unloadingPoint, required this.ywId, required this.kz, }); // 从 JSON 数据创建 BillModel 实例 factory BillModel.fromJson(Map<String, dynamic> json) { return BillModel( allowEditCarInfo: json['allowEditCarInfo'], forwardingUnit: json['forwardingUnit'], id: json['id'], isDangerous: json['isDangerous'], receivingUnit: json['receivingUnit'], wayBillType: json['wayBillType'], wlName: json['wlName'], carNum: json['carNum'], nodesName: json['nodesName'], outFactoryTime: json['outFactoryTime'], wlNameOut: json['wlNameOut'], ywType: json['ywType'], yfjz: json['yfjz'], yfmz: json['yfmz'], yfpz: json['yfpz'], waitCount: json['waitCount'], currentNodeName: json['currentNodeName'], flow: (json['flow'] as List<dynamic>?) ?.map((e) => FlowDTO.fromJson(e)) .toList() ?? [], flowName: json['flowName'], remark: json['remark'], sfhddName: json['sfhddName'], ywName: json['ywName'], startTime: json['startTime'], backHigh: json['backHigh'], carLong: json['carLong'], carWide: json['carWide'], frontHigh: json['frontHigh'], tieBarNum: json['tieBarNum'], gross: json['gross'], mzBridge: json['mzBridge'], mzTime: json['mzTime'], net: json['net'], pzBridge: json['pzBridge'], pzTime: json['pzTime'], tare: json['tare'], internal: json['internal'], unloadingPoint: json['unloadingPoint'], ywId: json['ywId'], kz: json['kz'], ); } // 将 BillModel 实例转换为 JSON 数据 Map<String, dynamic> toJson() { return { 'allowEditCarInfo': allowEditCarInfo, 'forwardingUnit': forwardingUnit, 'id': id, 'isDangerous': isDangerous, 'receivingUnit': receivingUnit, 'wayBillType': wayBillType, 'wlName': wlName, 'carNum': carNum, 'nodesName': nodesName, 'outFactoryTime': outFactoryTime, 'wlNameOut': wlNameOut, 'ywType': ywType, 'yfjz': yfjz, 'yfmz': yfmz, 'yfpz': yfpz, 'waitCount': waitCount, 'currentNodeName': currentNodeName, 'flow': flow.map((e) => e.toJson()).toList(), 'flowName': flowName, 'remark': remark, 'sfhddName': sfhddName, 'ywName': ywName, 'startTime': startTime, 'backHigh': backHigh, 'carLong': carLong, 'carWide': carWide, 'frontHigh': frontHigh, 'tieBarNum': tieBarNum, 'gross': gross, 'mzBridge': mzBridge, 'mzTime': mzTime, 'net': net, 'pzBridge': pzBridge, 'pzTime': pzTime, 'tare': tare, 'internal': internal, 'unloadingPoint': unloadingPoint, 'ywId': ywId, 'kz': kz, }; } } class FlowDTO { List<String> address; String dateTime; String nodeName; FlowDTO({ required this.address, required this.dateTime, required this.nodeName, }); // 从 JSON 数据创建 FlowDTO 实例 factory FlowDTO.fromJson(Map<String, dynamic> json) { return FlowDTO( address: (json['address'] as List<dynamic>?) ?.map((e) => e.toString()) .toList() ?? [], dateTime: json['dateTime'], nodeName: json['nodeName'], ); } // 将 FlowDTO 实例转换为 JSON 数据 Map<String, dynamic> toJson() { return { 'address': address, 'dateTime': dateTime, 'nodeName': nodeName, }; } } // 定义运单数据类 class DataDTO { bool allowEditCarInfo; String backHigh; String carLong; String carNum; String carWide; String forwardingUnit; String frontHigh; int id; String nodesName; String receivingUnit; String tieBarNum; int waitCount; String wlName; String yfjz; String yfmz; String yfpz; String ywType; bool internal; int? ywId; String unloadingPoint; DataDTO({ required this.allowEditCarInfo, required this.backHigh, required this.carLong, required this.carNum, required this.carWide, required this.forwardingUnit, required this.frontHigh, required this.id, required this.nodesName, required this.receivingUnit, required this.tieBarNum, required this.waitCount, required this.wlName, required this.yfjz, required this.yfmz, required this.yfpz, required this.ywType, required this.internal, required this.ywId, required this.unloadingPoint, }); factory DataDTO.fromJson(Map<String, dynamic> json) { return DataDTO( allowEditCarInfo: json['allowEditCarInfo'], backHigh: json['backHigh'], carLong: json['carLong'], carNum: json['carNum'], carWide: json['carWide'], forwardingUnit: json['forwardingUnit'], frontHigh: json['frontHigh'], id: json['id'], nodesName: json['nodesName'], receivingUnit: json['receivingUnit'], tieBarNum: json['tieBarNum'], waitCount: json['waitCount'], wlName: json['wlName'], yfjz: json['yfjz'], yfmz: json['yfmz'], yfpz: json['yfpz'], ywType: json['ywType'], internal: json['internal'], ywId: json['ywId'], unloadingPoint: json['unloadingPoint'], ); } } // 首页碎片 class HomeFragment extends StatefulWidget { @override _HomeFragmentState createState() => _HomeFragmentState(); } class _HomeFragmentState extends State<HomeFragment> { bool start = true; bool fromStart = true; int step = 5; int loop = 1000000; // Dart 没有 Infinity,用一个大数字模拟 String src = " 欢迎您使用九江——快速物流,九江快速物流祝您所行化坦途,所求皆如愿。"; List<BannerInfo> bannerList = []; List<DataDTO> wayBillList = []; String? userId; @override void initState() { super.initState(); loadData(); _loadUserId(); _fetchWayBillList(); } String name = ''; String account = ''; String idNo = ''; Future<void> _loadUserId() async { SharedPreferences prefs = await SharedPreferences.getInstance(); setState(() { userId = prefs.getString('id'); name = prefs.getString('name') ?? ''; account = prefs.getString('account') ?? ''; idNo = prefs.getString('idNo') ?? ''; }); } BillModel? billModel; String errorMessage = ''; //二维码上报 Future<void> fetchData(String qrCodeResult) async { print('添加运单 扫描结果: ${qrCodeResult}'); try { final url = Uri.parse('http://60.2.186.18:10021/api/appUser/taskEcho?id=${Uri.encodeComponent(qrCodeResult)}'); final response = await http.post( url, headers: {'Content-Type': 'application/json'}, body: jsonEncode({'id': qrCodeResult}), ); if (response.statusCode == 200) { print('添加运单 ${response.body}'); final result = BillModelResult.fromJson(jsonDecode(response.body)); if (result.code == 0) { setState(() { billModel = result.data; print('添加运单 ${result.data}'); if (billModel != null) { Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => AddBillPage(billModel: billModel!), ), ); } else { // 处理 billModel 为 null 的情况,例如显示一个错误提示 print('billModel 为 null,无法跳转'); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('二维码为 null,无法跳转')), ); } }); } else { print('上传二维码失败,原因: ${result.msg}'); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(result.msg)), ); } print('二维码${result}'); // setState(() { // Navigator.pop(context); // }); } else { setState(() { errorMessage = '请求失败,状态码: ${response.statusCode}'; }); } } catch (e) { } } Future<void> loadData() async { const baseUrl = 'http://60.2.186.18:10021/api/slideshow/getSlideshowList'; const queryParams = '?location=1&type=1'; final fullUrl = baseUrl + queryParams; try { final response = await http.get( Uri.parse(fullUrl), headers: { 'Content-Type': 'application/json', }, ); if (response.statusCode == 200) { final result = ResponseData.fromJson(jsonDecode(response.body)); if (result.code == 0) { setState(() { bannerList = result.data; }); } else { print('获取轮播图列表失败,原因: ${result.msg}'); } } else { print('请求出错,状态码: ${response.statusCode}'); } } catch (error) { print('请求出错: $error'); } } Future<void> _fetchWayBillList() async { if (userId != null) { const baseUrl = 'http://60.2.186.18:10021/api/appUser/wayBillInfo/onWayBillList'; final queryParams = '?userId=$userId'; final fullUrl = baseUrl + queryParams; try { final response = await http.get( Uri.parse(fullUrl), headers: { 'Content-Type': 'application/json', }, ); if (response.statusCode == 200) { final Map<String, dynamic> result = jsonDecode(response.body); if (result['code'] == 0) { final List<dynamic> dataList = result['data']; setState(() { wayBillList = dataList.map((item) => DataDTO.fromJson(item)).toList(); }); } else { print('获取运单列表失败,原因: ${result['msg']}'); } } else { print('请求运单列表出错,状态码: ${response.statusCode}'); } } catch (error) { print('请求运单列表出错: $error'); } } } Widget buildIconColumn(String text, String imagePath) { return GestureDetector( onTap: () { if(text == '危化司机认证'){ Navigator.push( context, MaterialPageRoute( builder: (context) => HazardousDriverAuthenticationPage()), ); }else if (text == '实名认证') { // Navigator.pushReplacement( // context, // MaterialPageRoute(builder: (context) => RealNameAuthenticationPage()), // ); Navigator.push( context, MaterialPageRoute( builder: (context) => RealNameAuthenticationPage()), ); }else if(text == '押运员管理'){ Navigator.push( context, MaterialPageRoute( builder: (context) => EscortManagementPage()), ); }else if(text == '车辆管理'){ Navigator.push( context, MaterialPageRoute( builder: (context) => VehicleManagementPage()), ); } }, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset( imagePath, width: 50, ), SizedBox(height: 10), Text( text, textAlign: TextAlign.center, style: TextStyle(fontSize: 15), ), ], ), ); } bool _isButtonDisabled = false; // 用于防止短时间内重复点击 static const int _clickInterval = 2000; // 点击间隔时间,单位毫秒 Future<void> _requestPermissions() async { Map<Permission, PermissionStatus> statuses = await [ Permission.camera, Permission.photos, // 用于 iOS 相册权限 Permission.storage, // 用于 Android 存储权限 ].request(); bool allPermissionsGranted = true; statuses.forEach((permission, status) { if (status.isDenied) { print('$permission 权限被拒绝'); allPermissionsGranted = false; print('$permission 权限被拒绝'); showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('权限不足'), content: Text('请在设置中授予相机和存储权限以使用此功能。'), actions: [ TextButton( onPressed: () { Navigator.pop(context); }, child: Text('确定'), ), ], ); }, ); allPermissionsGranted = false; } else if (status.isGranted) { print('$permission 权限已授予'); } else if (status.isPermanentlyDenied) { print('$permission 权限被永久拒绝,需要在设置中手动开启'); allPermissionsGranted = false; print('$permission 权限被拒绝'); showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('权限不足'), content: Text('请在设置中授予相机和存储权限以使用此功能,权限被永久拒绝,需要在设置中手动开启。'), actions: [ TextButton( onPressed: () { Navigator.pop(context); }, child: Text('确定'), ), ], ); }, ); allPermissionsGranted = false; } }); if (allPermissionsGranted) { _startQrScan(); } } Future<void> _handleLayoutTap() async { if(idNo==null || idNo.isEmpty){ showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('认证提示'), content: const Text('您还未进行市民认证,请先完成认证。'), actions: <Widget>[ TextButton( child: const Text('取消'), onPressed: () { Navigator.of(context).pop(); }, ), TextButton( child: const Text('确定'), onPressed: () { Navigator.of(context).pop(); // 这里跳转到实名认证界面 Navigator.push( context, MaterialPageRoute( builder: (context) => RealNameAuthenticationPage()), ); }, ), ], ); }, ); return; } if (_isButtonDisabled) return; setState(() { _isButtonDisabled = true; }); await _requestPermissions(); Future.delayed(Duration(milliseconds: _clickInterval), () { setState(() { _isButtonDisabled = false; }); }); } void _startQrScan() { Navigator.push( context, MaterialPageRoute( builder: (context) => Scaffold( appBar: AppBar( title: Text('扫描二维码'), ), body: MobileScanner( onDetect: (BarcodeCapture barcodes) { if (barcodes != null) { var firstBarcode = barcodes.barcodes.first; if (firstBarcode.rawValue != null) { fetchData('${firstBarcode.rawValue}'); } } }, ), ), ), ); } @override Widget build(BuildContext context) { return Column( children: [ Stack( children: [ // 最上面的图片 Image.asset( 'assets/images/home_top_backgroup.png', // 替换为实际图片路径 width: double.infinity, height: 200, fit: BoxFit.fill, ), // Banner if (bannerList.isNotEmpty) CarouselSlider( options: CarouselOptions( height: 300, autoPlay: true, autoPlayInterval: Duration(seconds: 3), autoPlayAnimationDuration: Duration(milliseconds: 800), pauseAutoPlayOnTouch: true, viewportFraction: 0.9, initialPage: 0, enableInfiniteScroll: true, reverse: false, enlargeCenterPage: true, scrollDirection: Axis.horizontal, ), items: bannerList.map((banner) { return Builder( builder: (BuildContext context) { return Container( margin: EdgeInsets.only( left: 0, right: 0, top: 80, bottom: 10), width: double.infinity, child: ClipRRect( borderRadius: BorderRadius.circular(10), child: Image.network( 'http://60.2.186.18:10021/api/${banner.url}', fit: BoxFit.cover, ), ), ); }, ); }).toList(), ), ], ), // 背景图和滚动文本 // Stack( // children: [ // SizedBox( // width: MediaQuery.of(context).size.width * 0.9, // child: Image.asset( // 'assets/images/home_ad_backgroup.png', // 替换为实际图片路径 // width: double.infinity, // ), // ), // Container( // width: MediaQuery.of(context).size.width * 0.6, // margin: EdgeInsets.only( // left: MediaQuery.of(context).size.width * 0.15, // 调整左侧边距与Banner对齐 // ), // height: 80, // child: Align( // alignment: Alignment.center, // 使文本上下居中 // child: SingleChildScrollView( // scrollDirection: Axis.horizontal, // physics: const NeverScrollableScrollPhysics(), // child: Text( // src, // style: TextStyle(fontSize: 14), // ), // ), // ), // ), // ], // ), // 四个功能按钮 Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ buildIconColumn('实名认证', 'assets/images/my_icon_id_auth.png'), buildIconColumn('危化司机认证', 'assets/images/my_icon_id_auth.png'), buildIconColumn('押运员管理', 'assets/images/my_icon_id_auth.png'), buildIconColumn('车辆管理', 'assets/images/my_icon_id_auth.png'), ], ), // 添加一行间距 SizedBox(height: 16), // 运单布局 if (wayBillList.isNotEmpty) Column( children: wayBillList.map((data) { return Card( margin: EdgeInsets.all(10), child: Padding( padding: EdgeInsets.all(10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('车号: ${data.carNum}', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold)), Text('货物名称: ${data.wlName}'), Text('运输类型: ${data.ywType}'), // 其他数据展示... ], ), ), ); }).toList(), ) else Container( width: MediaQuery.of(context).size.width * 0.94, height: 160, margin: EdgeInsets.only(left: MediaQuery.of(context).size.width * 0.03), decoration: BoxDecoration( border: Border.all( width: 2, color: Color(0xFF57bd6b), ), borderRadius: BorderRadius.circular(5), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( '您还没有运单,快来添加一个吧', style: TextStyle( fontSize: 24, color: Color(0xFF57bd6b), ), textAlign: TextAlign.center, ), ElevatedButton( onPressed: _isButtonDisabled ? null : _handleLayoutTap, style: ElevatedButton.styleFrom( primary: Color(0xFF57bd6b), onPrimary: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(5), ), padding: EdgeInsets.symmetric( horizontal: 10, vertical: 4, ), ), child: Text('添加运单'), ), ], ), ), ], ); } } // 运单碎片 // 定义 Waybill 类型 class Waybill { final int id; final String waybillNumber; final String status; Waybill({ required this.id, required this.waybillNumber, required this.status, }); } class WaybillFragment extends StatefulWidget { @override _WaybillFragmentState createState() => _WaybillFragmentState(); } class _WaybillFragmentState extends State<WaybillFragment> { List<Waybill> waybillList = []; @override void initState() { super.initState(); fetchWaybillData(); } void fetchWaybillData() { // 这里暂时用模拟数据替代网络请求 generateMockData(); // 以下是模拟网络请求的代码结构,你可以根据实际情况修改 // final httpRequest = http.Client(); // httpRequest.get(Uri.parse('https://api.wzj.net.cn/api/')).then((response) { // if (response.statusCode == 200) { // try { // final result = json.decode(response.body) as List<dynamic>; // setState(() { // waybillList = result.map((e) => Waybill( // id: e['id'], // waybillNumber: e['waybillNumber'], // status: e['status'], // )).toList(); // }); // } catch (parseError) { // print('数据解析失败: $parseError'); // generateMockData(); // } // } else { // print('请求失败: ${response.statusCode}'); // generateMockData(); // } // }).catchError((err) { // print('请求失败: $err'); // generateMockData(); // }).whenComplete(() { // httpRequest.close(); // }); } void generateMockData() { List<Waybill> mockData = []; for (int i = 1; i <= 20; i++) { mockData.add(Waybill( id: i, waybillNumber: '主焦煤 斯坦大 嘉能可 百丽 赢戌20250207 (翅冀)存储-${i.toString().padLeft(4, '0')}', status: i % 2 == 0 ? '已完成' : '运输中', )); } setState(() { waybillList = mockData; }); } @override Widget build(BuildContext context) { return Scaffold( body: Column( children: [ // 标题栏部分 Container( width: double.infinity, padding: EdgeInsets.only( top: MediaQuery.of(context).padding.top + 20, // 考虑状态栏高度 bottom: 10, ), color: Theme.of(context).primaryColor, child: Text( '历史运单', style: TextStyle( fontSize: 24, color: Colors.white, ), textAlign: TextAlign.center, ), ), // 运单列表部分 Expanded( child: ListView.builder( itemCount: waybillList.length, itemBuilder: (context, index) { Waybill waybill = waybillList[index]; return Container( width: MediaQuery.of(context).size.width * 0.9, margin: EdgeInsets.fromLTRB( MediaQuery.of(context).size.width * 0.05, 10, MediaQuery.of(context).size.width * 0.05, 0, ), padding: EdgeInsets.fromLTRB(20, 10, 0, 10), decoration: BoxDecoration( color: Color(0xFF57bd6b), borderRadius: BorderRadius.circular(10), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( '创建时间: 2025年2月24日12点00分00秒', style: TextStyle(fontSize: 18), ), Text( '物资名称: ${waybill.waybillNumber}', style: TextStyle(fontSize: 18), ), Text( '车辆:冀B44444 ', style: TextStyle(fontSize: 16), ), Text( '状态: ${waybill.status}', style: TextStyle(fontSize: 16), ), Row( children: [ Text( '毛:140.00吨 ', style: TextStyle(fontSize: 16), ), Text( '皮:140.00吨 ', style: TextStyle(fontSize: 16), ), Text( '净:140.00吨 ', style: TextStyle(fontSize: 16), ), ], ), Text( '收货单位:迁安市九江煤炭储运有限公司 ', style: TextStyle(fontSize: 16), ), Text( '进厂路线:4号门--小三门--7号门--小三门--测试路线很长的情况效果样式 ', style: TextStyle(fontSize: 16), ), ], ), ); }, ), ), ], ), ); } } //消息碎片 // class MessageFragment extends StatelessWidget { // @override // Widget build(BuildContext context) { // return Center( // child: Text('消息'), // ); // } // } // 定义 MessageBean 类型 class MessageBean { final int id; final String title; final String text; final String timer; MessageBean({ required this.id, required this.title, required this.text, required this.timer, }); } class MessageFragment extends StatefulWidget { @override _MessageFragmentState createState() => _MessageFragmentState(); } class _MessageFragmentState extends State<MessageFragment> { List<MessageBean> messageList = []; int currentPage = 1; final int pageSize = 20; bool isLoadingMore = false; @override void initState() { super.initState(); fetchWaybillData(currentPage); } Future<void> fetchWaybillData(int page) async { // 这里暂时用模拟数据替代网络请求 await Future.delayed(Duration(milliseconds: 500)); // 模拟网络延迟 generateMockData(page); // 以下是模拟网络请求的代码结构,你可以根据实际情况修改 // final httpRequest = http.Client(); // httpRequest.get(Uri.parse('https://api.wzj.net.cn/api/?page=$page&pageSize=$pageSize')).then((response) { // if (response.statusCode == 200) { // try { // final result = json.decode(response.body) as List<dynamic>; // setState(() { // if (page == 1) { // messageList = result.map((e) => MessageBean( // id: e['id'], // title: e['title'], // text: e['text'], // timer: e['timer'], // )).toList(); // } else { // messageList.addAll(result.map((e) => MessageBean( // id: e['id'], // title: e['title'], // text: e['text'], // timer: e['timer'], // )).toList()); // } // }); // } catch (parseError) { // print('数据解析失败: $parseError'); // generateMockData(page); // } // } else { // print('请求失败: ${response.statusCode}'); // generateMockData(page); // } // }).catchError((err) { // print('请求失败: $err'); // generateMockData(page); // }).whenComplete(() { // httpRequest.close(); // }); } void generateMockData(int page) { List<MessageBean> mockData = []; DateTime now = DateTime.now(); String formattedTime = '${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')} ${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}:${now.second.toString().padLeft(2, '0')}'; int startIndex = (page - 1) * pageSize + 1; int endIndex = startIndex + pageSize; for (int i = startIndex; i < endIndex; i++) { mockData.add(MessageBean( id: i, title: '进厂通知:-${i.toString().padLeft(4, '0')}', text: '冀B44444 主焦煤20251213 准备进厂!!!', timer: formattedTime, )); } setState(() { if (page == 1) { messageList = mockData; } else { messageList.addAll(mockData); } }); } Future<void> onRefresh() async { currentPage = 1; await fetchWaybillData(currentPage); } Future<void> loadMore() async { if (isLoadingMore) return; setState(() { isLoadingMore = true; }); currentPage++; await fetchWaybillData(currentPage); setState(() { isLoadingMore = false; }); } @override Widget build(BuildContext context) { return Scaffold( body: RefreshIndicator( onRefresh: onRefresh, child: NotificationListener<ScrollNotification>( onNotification: (ScrollNotification scrollInfo) { if (!isLoadingMore && scrollInfo.metrics.pixels == scrollInfo.metrics.maxScrollExtent) { loadMore(); } return true; }, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // 标题部分 Container( width: double.infinity, padding: EdgeInsets.only( top: MediaQuery.of(context).padding.top + 20, // 考虑状态栏高度 bottom: 10, ), color: Theme.of(context).primaryColor, child: Text( '消息', style: TextStyle( fontSize: 24, color: Colors.white, ), textAlign: TextAlign.center, ), ), // 消息列表 Expanded( child: ListView.builder( itemCount: messageList.length + (isLoadingMore ? 1 : 0), itemBuilder: (context, index) { if (index < messageList.length) { MessageBean message = messageList[index]; return Container( width: MediaQuery.of(context).size.width * 0.9, margin: EdgeInsets.fromLTRB( MediaQuery.of(context).size.width * 0.05, 10, MediaQuery.of(context).size.width * 0.05, 0, ), padding: EdgeInsets.fromLTRB(20, 10, 20, 10), decoration: BoxDecoration( color: Theme.of(context).primaryColor, borderRadius: BorderRadius.circular(10), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( message.title, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white, ), ), Text( message.text, style: TextStyle(fontSize: 16,color: Colors.white), ), Text( '时间:${message.timer}', style: TextStyle(fontSize: 16,color: Colors.white), ), ], ), ); } else { return Center( child: Padding( padding: EdgeInsets.all(16.0), child: CircularProgressIndicator(), ), ); } }, ), ), ], ), ), ), ); } } // 我的碎片 class ProfileFragment extends StatefulWidget { @override _ProfileFragmentState createState() => _ProfileFragmentState(); } class _ProfileFragmentState extends State<ProfileFragment> { String name = ''; String account = ''; String idNo = ''; String avatarUrl = ''; bool isCheckingUpdate = false; @override void initState() { super.initState(); _loadUserData(); } Future<void> _loadUserData() async { SharedPreferences prefs = await SharedPreferences.getInstance(); setState(() { name = prefs.getString('name') ?? ''; account = prefs.getString('account') ?? ''; idNo = prefs.getString('idNo') ?? ''; avatarUrl = prefs.getString('url') ?? ''; }); } // 检测更新调用登录接口(示例,需替换为实际登录接口调用) Future<void> _checkUpdate() async { setState(() { isCheckingUpdate = true; }); try { // 这里添加登录接口调用逻辑 await Future.delayed(Duration(seconds: 2)); // 模拟接口调用耗时 print('调用登录接口进行检测更新'); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('检测更新完成')), ); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('检测更新失败: $e')), ); } finally { setState(() { isCheckingUpdate = false; }); } } // 联系我们拨打电话(示例,需替换为实际电话号码) Future<void> _contactUs() async { const phoneNumber = '10086'; // 替换为实际电话号码 final uri = Uri.parse('tel:$phoneNumber'); if (await canLaunchUrl(uri)) { await launchUrl(uri); } else { print('无法拨打电话'); } } // 退出登录确认弹框 Future<void> _showLogoutConfirmation() async { return showDialog<void>( context: context, barrierDismissible: false, // user must tap button! builder: (BuildContext context) { return AlertDialog( title: const Text('确认退出登录'), content: SingleChildScrollView( child: ListBody( children: const <Widget>[ Text('你确定要退出登录吗?'), ], ), ), actions: <Widget>[ TextButton( child: const Text('取消'), onPressed: () { Navigator.of(context).pop(); }, ), TextButton( child: const Text('确认'), onPressed: () async { SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.clear(); // 清空本地缓存 Navigator.of(context).pop(); // 跳转到登录界面并销毁其他界面 Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => LoginPage()), ); }, ), ], ); }, ); } @override Widget build(BuildContext context) { return Scaffold( body: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // 标题栏 Container( padding: EdgeInsets.fromLTRB( 16, 24 + MediaQuery.of(context).padding.top, 16, 16), color: Color(0xFF57bd6b), child: Center( child: Text( '我的', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ), // 头像和文字信息,改成白色圆角卡片样式 Card( elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), margin: EdgeInsets.all(16), child: Container( padding: EdgeInsets.all(16), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 头像 avatarUrl.isNotEmpty ? CachedNetworkImage( imageUrl: avatarUrl, imageBuilder: (context, imageProvider) => Container( width: 60, height: 60, decoration: BoxDecoration( shape: BoxShape.circle, image: DecorationImage( image: imageProvider, fit: BoxFit.cover, ), ), ), placeholder: (context, url) => Container( width: 60, height: 60, decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.grey[300], ), ), errorWidget: (context, url, error) => Container( width: 60, height: 60, decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.grey[300], ), ), ) : CircleAvatar( radius: 30, backgroundImage: AssetImage( 'assets/default_avatar.png'), // 替换为实际头像路径或网络图片加载方式 ), SizedBox(width: 16), // 文字信息容器 Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('姓名:$name'), SizedBox(height: 8), Text('账号:$account'), SizedBox(height: 8), if (idNo.isNotEmpty) Text('ID号:$idNo') else Text('ID号:暂无'), ], ), ], ), ), ), // 功能菜单容器 Card( elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), margin: EdgeInsets.symmetric(horizontal: 16), child: Column( children: [ ListTile( title: Text('修改密码'), trailing: Icon(Icons.arrow_forward_ios), onTap: () { // 跳转到修改密码界面 Navigator.pushNamed(context, '/changePassword'); }, ), Divider(), ListTile( title: Text('实名信息'), trailing: Icon(Icons.arrow_forward_ios), onTap: () { // 跳转到实名信息界面 // Navigator.pushReplacement( // context, // MaterialPageRoute(builder: (context) => RealNameAuthenticationPage()), // ); Navigator.push( context, MaterialPageRoute( builder: (context) => RealNameAuthenticationPage()), ); }, ), Divider(), ListTile( title: Text('检测更新'), onTap: isCheckingUpdate ? null : _checkUpdate, trailing: isCheckingUpdate ? CircularProgressIndicator() : null, ), Divider(), ListTile( title: Text('联系我们'), onTap: _contactUs, ), ], ), ), // 圆角按钮 Container( margin: EdgeInsets.all(16), child: ElevatedButton( onPressed: _showLogoutConfirmation, style: ElevatedButton.styleFrom( primary: Color(0xFF57bd6b), shape: RoundedRectangleBorder( borderRadius: BorderRadius.horizontal( left: Radius.circular(30), right: Radius.circular(30), ), ), minimumSize: Size(double.infinity, 50), // 增加按钮高度 ), child: Text('退出登录'), ), ), ], ), ); } } // 注册界面 class RegisterPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('注册界面'), ), body: Center( child: Text('注册页面内容'), ), ); } } // 忘记密码界面 class ForgotPasswordPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('忘记密码界面'), ), body: Center( child: Text('忘记密码页面内容'), ), ); } } // 假设 LoginResult 类的结构如下 class LoginResult { int code; String msg; Map<String, dynamic> data; LoginResult({ required this.code, required this.msg, required this.data, }); factory LoginResult.fromJson(Map<String, dynamic> json) { return LoginResult( code: json['code'], msg: json['msg'], data: json['data'], ); } } // 登录界面 class LoginPage extends StatefulWidget { @override _LoginPageState createState() => _LoginPageState(); } class _LoginPageState extends State<LoginPage> { final TextEditingController _phoneController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); bool _isPasswordVisible = false; Future<bool> _login(String phone, String password) async { // 模拟网络请求 final response = await http.post( Uri.parse( 'http://60.2.186.18:10021/api/appUser/appLogin?account=${Uri.encodeComponent(phone)}&password=${Uri.encodeComponent(password)}'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({'account': phone, 'password': password}), ); // 打印响应状态码和响应体 print('登录请求响应状态码: ${response.statusCode}'); print('登录请求响应体: ${response.body}'); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('r=${response.statusCode}${response.body}')), ); if (response.statusCode == 200) { final data = jsonDecode(response.body); try { final result = LoginResult.fromJson(jsonDecode(response.body)); print('解析后的数据: $result'); if (result.code == 0) { print('登录成功,用户名: ${result.data['name']}'); SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString('islogin', '登录'); prefs.setString('account', result.data['account']); prefs.setString('documentNo', result.data['documentNo']); prefs.setString('explain', result.data['explain']); prefs.setString('id', result.data['id'].toString()); prefs.setString('idNo', result.data['idNo']); prefs.setString('name', result.data['name']); prefs.setString('password', result.data['password']); prefs.setString('token', result.data['token']); prefs.setString('type', result.data['type'].toString()); prefs.setString('url', result.data['url']); prefs.setString('version', result.data['version']); // 这里需要替换为实际的页面跳转逻辑 Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => HomePage()), ); print('跳转到主页'); } } catch (parseError) {} return data['success'] as bool; } else { return false; } } void _handleLogin() async { String phone = _phoneController.text.trim(); String password = _passwordController.text.trim(); if (phone.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('手机号不能为空')), ); return; } if (phone.length != 11) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('手机号必须为 11 位')), ); return; } if (password.length < 8 || password.length > 20) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('密码长度必须在 8 到 20 位之间')), ); return; } bool isSuccess = await _login(phone, password); if (isSuccess) { SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setBool('isLoggedIn', true); Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => HomePage()), ); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('登录失败,请检查手机号和密码')), ); } } @override Widget build(BuildContext context) { final loginButtonColor = Color(0xFF57bd6b); return Scaffold( appBar: AppBar( title: Text('登录界面'), ), body: Padding( padding: EdgeInsets.all(16.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ TextField( controller: _phoneController, keyboardType: TextInputType.phone, decoration: InputDecoration( labelText: '手机号/账号', border: OutlineInputBorder(), ), ), SizedBox(height: 16.0), TextField( controller: _passwordController, obscureText: !_isPasswordVisible, decoration: InputDecoration( labelText: '密码', border: OutlineInputBorder(), suffixIcon: IconButton( icon: Icon( _isPasswordVisible ? Icons.visibility : Icons.visibility_off, ), onPressed: () { setState(() { _isPasswordVisible = !_isPasswordVisible; }); }, ), ), ), SizedBox(height: 24.0), ElevatedButton( onPressed: _handleLogin, child: Text('登录'), style: ElevatedButton.styleFrom( primary: Color(0xFF57bd6b), // 设置按钮颜色 onPrimary: Colors.white, // 设置按钮文本颜色 ), ), SizedBox(height: 16.0), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ TextButton( onPressed: () { Navigator.push( context, MaterialPageRoute(builder: (context) => RegisterPage()), ); }, child: Text('注册'), ), TextButton( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ForgotPasswordPage()), ); }, child: Text('忘记密码'), ), ], ), ], ), ), ); } } //实名认证 class RealNameAuthenticationPage extends StatefulWidget { @override _RealNameAuthenticationPageState createState() => _RealNameAuthenticationPageState(); } class _RealNameAuthenticationPageState extends State<RealNameAuthenticationPage> { File? _idCardFrontImage; File? _idCardBackImage; String _name = ''; String _idNumber = ''; // 身份证尺寸相关常量 static const double idCardWidth = 85.6; // 身份证宽度(mm) static const double idCardHeight = 54.0; // 身份证高度(mm) final _textRecognizer = TextRecognizer(script: TextRecognitionScript.chinese); Future<void> _requestCameraAndPhotoPermissions() async { Map<Permission, PermissionStatus> statuses = await [ Permission.camera, Permission.photos, ].request(); bool allPermissionsGranted = true; statuses.forEach((permission, status) { if (status.isDenied) { allPermissionsGranted = false; showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('权限不足'), content: Text('请在设置中授予相机和相册权限以使用此功能。'), actions: [ TextButton( onPressed: () { Navigator.pop(context); }, child: Text('确定'), ), ], ); }, ); } else if (status.isPermanentlyDenied) { allPermissionsGranted = false; showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('权限不足'), content: Text('请在设置中授予相机和相册权限以使用此功能,权限被永久拒绝,需要在设置中手动开启。'), actions: [ TextButton( onPressed: () { Navigator.pop(context); }, child: Text('确定'), ), ], ); }, ); } }); if (allPermissionsGranted) { // 权限已授予,执行后续操作 } } Future<void> _pickImage(ImageSource source, bool isFront) async { await _requestCameraAndPhotoPermissions(); final picker = ImagePicker(); final pickedFile = await picker.getImage(source: source); if (pickedFile != null) { File file = File(pickedFile.path); setState(() async { if (isFront) { _idCardFrontImage = file; } else { _idCardBackImage = file; } // 模拟身份证信息识别 if (isFront) { // // 将文件转换为 InputImage 对象 InputImage inputImage = InputImage.fromFile(file); // // // // 调用识别方法 // _recognizeText(inputImage); // recognizeTextFromImage(inputImage); // final inputImage = InputImage.fromFilePath(image.path); // // final textDetector = GoogleMlKit.vision.textDetector(); // // final RecognisedText recognisedText = await textDetector.processImage(inputImage); // // print(recognisedText.blocks); // // _name = '模拟姓名'; // // _idNumber = '123456789012345678'; try { final recognizedText = await _textRecognizer.processImage(inputImage); // if(recognizedText.text.isNotEmpty){ // _name = recognizedText.text; // setState(() {}); // } // 处理识别结果 for (TextBlock block in recognizedText.blocks) { for (TextLine line in block.lines) { for (TextElement element in line.elements) { String text = element.text; // if (text.contains("身份证号")) { print('IDCardNumber: $text'); // setState(() { // _recognizedText = text; // }); // } } } } } catch (e) { // _name = "识别失败:$e"; // setState(() {}); } } }); } } @override void dispose() { _textRecognizer.close(); super.dispose(); } Future<void> initializeTextRecognizer() async { } Future<void> recognizeTextFromImage(InputImage inputImage) async { // TextRecognizer recognizer = TextRecognizer(script: TextRecognitionScript.chinese); // TextRecognizer recognizer = GoogleMlKit.vision.textRecognizer(script: TextRecognitionScript.chinese); // RecognizedText recognizedText = await recognizer.processImage(inputImage); // print('别身份证号码姓名: ${recognizedText.blocks}'); // 打印识别的文本块信息 // WidgetsFlutterBinding.ensureInitialized(); // final textRecognizer = GoogleMlKit.vision.textRecognizer(script: [TextRecognitionScript.chinese]); // // final recognizedText = await textRecognizer.processImage(inputImage); // print('身份证 text: ${recognizedText.text}'); } Future<void> _recognizeText(InputImage inputImage) async { // final textDetector = GoogleMlKit.vision.textRecognizer(); // try { // final recognizedText = await textDetector.processImage(inputImage); // for (TextBlock block in recognizedText.blocks) { // for (TextLine line in block.lines) { // print('识别身份证号码3:${line.text}'); // _idNumber = recognizedText.text; // } // } // // } catch (e) { // print('识别过程中出现异常:$e'); // } finally { // textDetector.close(); // } } // Future<void> _performOCR() async { // var textDetector = GoogleMlKit.vision.textDetector(); // textDetector.processImage(inputImage) // if (_image != null) { // final textRecognizer = GoogleMlKit.vision.textRecognizer(); // final inputImage = InputImage.fromFile(_image!); // // try { // final recognizedText = await textRecognizer.processImage(inputImage); // _recognizedText = recognizedText.text; // setState(() {}); // // // 查找身份证号 // for (var block in recognizedText.blocks) { // for (var line in block.lines) { // for (var element in line.elements) { // String text = element.text; // if (text.contains("身份证号")) { // print('识别到身份证号相关内容: $text'); // } // } // } // } // } catch (e) { // print('OCR 识别出错: $e'); // } finally { // textRecognizer.close(); // } // } // } Future<void> _showImageSourceDialog(bool isFront) async { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('选择图片来源'), content: Text('请选择是拍照还是从相册中选择图片'), actions: [ TextButton( onPressed: () async { Navigator.pop(context); await _pickImage(ImageSource.camera, isFront); }, child: Text('拍照'), ), TextButton( onPressed: () async { Navigator.pop(context); await _pickImage(ImageSource.gallery, isFront); }, child: Text('从相册选择'), ), ], ); }, ); } Widget buildIdCardContainer(bool isFront) { final double screenWidth = MediaQuery.of(context).size.width; final double containerWidth = screenWidth - 40; // 左右外间距 15 final double containerHeight = containerWidth * (idCardHeight / idCardWidth); String bgImagePath = isFront ? 'assets/images/sfzbg1.png' : 'assets/images/sfzbg2.png'; return GestureDetector( onTap: () => _showImageSourceDialog(isFront), child: Container( width: containerWidth, height: containerHeight, margin: EdgeInsets.symmetric(horizontal: 20), decoration: BoxDecoration( image: DecorationImage( image: AssetImage(bgImagePath), fit: BoxFit.cover, ), ), child: Center( child: isFront ? _idCardFrontImage == null ? SizedBox() : Image.file( _idCardFrontImage!, fit: BoxFit.cover, width: double.infinity, height: double.infinity, ) : _idCardBackImage == null ? SizedBox() : Image.file( _idCardBackImage!, fit: BoxFit.cover, width: double.infinity, height: double.infinity, ), ), ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( leading: IconButton( icon: Icon(Icons.arrow_back), onPressed: () { Navigator.pop(context); }, ), title: Text('实名认证'), centerTitle: true, ), body: SingleChildScrollView( // 添加 SingleChildScrollView child: Padding( padding: EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '上传身份证正面', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), SizedBox(height: 10), buildIdCardContainer(true), SizedBox(height: 20), Text( '上传身份证反面', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), SizedBox(height: 10), buildIdCardContainer(false), SizedBox(height: 20), Row( children: [ Expanded( flex: 2, child: Text( '姓名:', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ), Expanded( flex: 5, child: TextField( readOnly: false, controller: TextEditingController(text: _name), decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), ), ), ), ), ], ), SizedBox(height: 10), Row( children: [ Expanded( flex: 2, child: Text( '身份证号:', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ), Expanded( flex: 5, child: TextField( readOnly: true, controller: TextEditingController(text: _idNumber), decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), ), ), ), ), ], ), SizedBox(height: 20), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () { // 这里可以添加提交逻辑 }, style: ElevatedButton.styleFrom( primary: Color(0xFF57bd6b), // 颜色设置 shape: RoundedRectangleBorder( borderRadius: BorderRadius.horizontal( left: Radius.circular(30), right: Radius.circular(30), ), ), minimumSize: Size(double.infinity, 50), // 高度设置为50 ), child: Text('提交'), ), ), ], ), ), ), ); } } //危化司机认证 class HazardousDriverAuthenticationPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( leading: IconButton( icon: Icon(Icons.arrow_back), onPressed: () { Navigator.pop(context); }, ), title: Text('危化司机认证'), centerTitle: true, ), body: Padding( padding: EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 50), Row( children: [ Expanded( flex: 2, child: Text( '证件号:', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ), Expanded( flex: 5, child: TextField( decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), ), contentPadding: EdgeInsets.symmetric(vertical: 16), ), ), ), ], ), SizedBox(height: 20), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () { // 这里可以添加绑定逻辑 }, style: ElevatedButton.styleFrom( primary: Color(0xFF57bd6b), shape: RoundedRectangleBorder( borderRadius: BorderRadius.horizontal( left: Radius.circular(30), right: Radius.circular(30), ), ), minimumSize: Size(double.infinity, 50), ), child: Text('绑定'), ), ), ], ), ), ); } } class EscortManagementPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( leading: IconButton( icon: Icon(Icons.arrow_back), onPressed: () { Navigator.pop(context); }, ), title: Text('押运员管理'), centerTitle: true, ), body: Padding( padding: EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 50), // 姓名输入框 Row( children: [ Expanded( flex: 2, child: Text( '姓名:', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ), Expanded( flex: 5, child: TextField( decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), ), contentPadding: EdgeInsets.symmetric(vertical: 16), ), ), ), ], ), SizedBox(height: 10), // 证件号输入框 Row( children: [ Expanded( flex: 2, child: Text( '证件号:', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ), Expanded( flex: 5, child: TextField( decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(8.0), ), contentPadding: EdgeInsets.symmetric(vertical: 16), ), ), ), ], ), SizedBox(height: 20), // 提交按钮 SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () { // 这里可以添加提交逻辑 }, style: ElevatedButton.styleFrom( primary: Color(0xFF57bd6b), shape: RoundedRectangleBorder( borderRadius: BorderRadius.horizontal( left: Radius.circular(30), right: Radius.circular(30), ), ), minimumSize: Size(double.infinity, 50), ), child: Text('提交'), ), ), ], ), ), ); } } //添加车辆 车辆类型 class VehicleManagementPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: () { Navigator.pop(context); }, ), title: const Text('车辆管理'), centerTitle: true, ), body: Column( children: [ _buildVehicleTypeItem(context, '煤|焦炭|其他 货品运输车辆'), _buildVehicleTypeItem(context, '危化车头'), _buildVehicleTypeItem(context, '危化车挂'), ], ), ); } Widget _buildVehicleTypeItem(BuildContext context, String title) { return GestureDetector( onTap: () { // 这里可以添加点击事件的逻辑,比如跳转到对应类型的详情页 print('点击了 $title'); }, child: Container( height: 80, // 可根据需要调整高度 margin: const EdgeInsets.all(16), decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), border: Border.all(color: Colors.grey), ), child: Center( child: Text( title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), ), ), ); } } class AddBillPage extends StatefulWidget { final BillModel billModel; const AddBillPage({super.key, required this.billModel}); @override _AddBillPageState createState() => _AddBillPageState(); } class _AddBillPageState extends State<AddBillPage> { final TextEditingController _goodsNameController = TextEditingController(); final TextEditingController _truckTeamController = TextEditingController(); final TextEditingController _vehicleNumberController = TextEditingController(); final TextEditingController _grossWeightController = TextEditingController(); final TextEditingController _tareWeightController = TextEditingController(); final TextEditingController _netWeightController = TextEditingController(); final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); bool _hasCameraPermission = false; bool _hasGalleryPermission = false; String _selectedImagePath = ""; @override void initState() { super.initState(); _goodsNameController.text = widget.billModel.wlName; _truckTeamController.text = "无"; _grossWeightController.text = ""; _tareWeightController.text = ""; _netWeightController.text = ""; _checkPermissions(); } Future<void> _checkPermissions() async { final cameraStatus = await Permission.camera.status; final galleryStatus = await Permission.photos.status; setState(() { _hasCameraPermission = cameraStatus.isGranted; _hasGalleryPermission = galleryStatus.isGranted; }); } Future<void> _requestPermissions() async { final cameraResult = await Permission.camera.request(); final galleryResult = await Permission.photos.request(); setState(() { _hasCameraPermission = cameraResult.isGranted; _hasGalleryPermission = galleryResult.isGranted; }); } Future<void> _selectImage() async { if (!_hasCameraPermission &&!_hasGalleryPermission) { await _requestPermissions(); } final picker = ImagePicker(); final pickedImage = await picker.pickImage(source: ImageSource.gallery); if (pickedImage!= null) { setState(() { _selectedImagePath = pickedImage.path; }); } } @override Widget build(BuildContext context) { return Scaffold( key: _scaffoldKey, appBar: AppBar( title: Text("添加运单"), ), body: Column( children: [ // 货物名称 ListTile( title: Text("货物名称"), trailing: TextField( controller: _goodsNameController, enabled: false, ), ), // 车队 ListTile( title: Text("车队"), trailing: TextField( controller: _truckTeamController, ), ), // 车辆 ListTile( title: Text("车辆"), trailing: TextField( controller: _vehicleNumberController, ), ), // 毛重 ListTile( title: Text("毛重"), trailing: TextField( controller: _grossWeightController, ), ), // 皮重 ListTile( title: Text("皮重"), trailing: TextField( controller: _tareWeightController, ), ), // 净重 ListTile( title: Text("净重"), trailing: TextField( controller: _netWeightController, enabled: false, ), ), // 图片展示容器 Container( width: double.infinity, height: 200, decoration: BoxDecoration( border: Border.all(color: Colors.grey), ), child: _selectedImagePath.isNotEmpty ? Image.file( File(_selectedImagePath), fit: BoxFit.cover, ) : Image.asset( "assets/default_image.png", fit: BoxFit.cover, ), ), // 提交按钮 ElevatedButton( onPressed: () { // _submit();提交运单 }, style: ElevatedButton.styleFrom( minimumSize: Size(double.infinity, 50), backgroundColor: Colors.green, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), child: Text("提交"), ), ], ), ); } } // 主程序 void main() { runApp(MaterialApp( theme: ThemeData( primaryColor: Color(0xFF57bd6b), colorScheme: ColorScheme.fromSwatch().copyWith( secondary: Color(0xFF57bd6b), ), appBarTheme: AppBarTheme( backgroundColor: Color(0xFF57bd6b), ), floatingActionButtonTheme: FloatingActionButtonThemeData( backgroundColor: Color(0xFF57bd6b), ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( primary: Color(0xFF57bd6b), // 设置文本按钮的文本颜色 ), ), ), home: SplashScreen(), )); }
name: flutter_shuqi description: A new Flutter project. # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning # In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. version: 1.0.0+1 environment: sdk: '>=2.19.6 <3.0.0' # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions # consider running `flutter pub upgrade --major-versions`. Alternatively, # dependencies can be manually updated by changing the version numbers below to # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter # google_ml_kit: ^0.7.2 # google_mlkit_image_labeling: any # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.4 http: ^0.13.5 shared_preferences: ^2.0.15 cached_network_image: ^3.2.3 url_launcher: ^6.1.10 permission_handler: ^10.4.4 carousel_slider: ^4.2.1 mobile_scanner: ^3.2.0 image_picker: ^0.8.5 path_provider: ^2.0.11 google_mlkit_text_recognition: ^0.14.0 # google_ml_kit: ^0.14.0 # flutter_cache_manager: ^3.3.0 # # palette_generator: ^0.3.2 # ## flutter_webview_plugin: 0.4.0 ## ## webview_flutter: ^3.0.0 # # video_player: ^2.2.17 # # # # 用来模拟网络返回的数据,这些数据是真实的,这里模拟 # dio: ^4.0.4 # fluttertoast: ^8.0.8 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. # cupertino_icons: ^1.0.2 dev_dependencies: flutter_test: sdk: flutter # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^2.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter packages. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true assets: - assets/images/ - assets/images/sfzbg1.png - assets/images/sfzbg2.png # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware # For details regarding adding assets from package dependencies, see # https://flutter.dev/assets-and-images/#from-packages # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages
def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { localPropertiesFile.withReader('UTF-8') { reader -> localProperties.load(reader) } } def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { flutterVersionCode = '1' } def flutterVersionName = localProperties.getProperty('flutter.versionName') if (flutterVersionName == null) { flutterVersionName = '1.0' } apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { compileSdkVersion 34 ndkVersion flutter.ndkVersion compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } sourceSets { main.java.srcDirs += 'src/main/kotlin' } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.example.qcjl_jj" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdkVersion 24 targetSdkVersion 34 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } buildTypes { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. signingConfig signingConfigs.debug } } } flutter { source '../..' } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'com.google.mlkit:text-recognition-chinese:16.0.0' implementation 'com.google.mlkit:text-recognition-devanagari:16.0.0' implementation 'com.google.mlkit:text-recognition-japanese:16.0.0' implementation 'com.google.mlkit:text-recognition-korean:16.0.0' }