import 'dart:async'; import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; import 'package:qhd_prevention/customWidget/custom_button.dart'; import 'package:qhd_prevention/pages/my_appbar.dart'; import 'package:qhd_prevention/tools/tools.dart'; import '../../../http/ApiService.dart'; /// 人脸识别模式 enum FaceMode { auto, manual } class FaceRecognitionPage extends StatefulWidget { final String studentId; final FaceMode mode; const FaceRecognitionPage({ Key? key, this.studentId = '', required this.mode, }) : super(key: key); @override _FaceRecognitionPageState createState() => _FaceRecognitionPageState(); } class _FaceRecognitionPageState extends State { CameraController? _cameraController; Timer? _timer; int _attempts = 0; String _message = ''; String _tip = '请将人脸置于圆圈内'; static const int _maxAttempts = 8; static const Duration _interval = Duration(seconds: 2); bool get _isManualMode => widget.mode == FaceMode.manual; @override void initState() { super.initState(); _initCamera(); } @override void dispose() { _timer?.cancel(); _cameraController?.dispose(); super.dispose(); } Future _initCamera() async { final cams = await availableCameras(); final front = cams.firstWhere((c) => c.lensDirection == CameraLensDirection.front); _cameraController = CameraController(front, ResolutionPreset.medium, enableAudio: false); await _cameraController!.initialize(); if (!mounted) return; setState(() {}); if (!_isManualMode) { _timer = Timer.periodic(_interval, (_) => _captureAndUpload()); } } Future _captureAndUpload() async { if (_isManualMode) { setState(() => _message = '请将人脸置于圆圈内'); } else { if (_attempts >= _maxAttempts) return _onTimeout(); _attempts++; } try { final pic = await _cameraController!.takePicture(); final res = await ApiService.getUserFace(pic.path, widget.studentId); if (res['result'] == 'success') { _onSuccess(); } else { setState(() => _message = '识别失败,请重试'); } } catch (_) { setState(() => _message = '发生错误,请重试'); } } Future _captureAndReload() async { setState(() => _message = '上传中...'); try { final pic = await _cameraController!.takePicture(); final res = await ApiService.reloadMyFace(pic.path); if (res['result'] == 'success') { _onSuccess(); } else { setState(() => _message = '验证失败,请重试'); } } catch (_) { setState(() => _message = '发生错误,请重试'); } } void _onSuccess() { _timer?.cancel(); ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('验证成功'))); Future.delayed(const Duration(milliseconds: 800), () => Navigator.of(context).pop(true)); } void _onTimeout() { _timer?.cancel(); setState(() => _message = '人脸超时,请重新识别!'); Future.delayed(const Duration(seconds: 3), () => Navigator.of(context).pop(false)); } @override Widget build(BuildContext context) { if (_cameraController == null || !_cameraController!.value.isInitialized) { return const Scaffold( backgroundColor: Colors.white, body: Center(child: CircularProgressIndicator()), ); } final previewSize = _cameraController!.value.previewSize!; final previewAspect = previewSize.height / previewSize.width; final radius = (screenWidth(context) - 100) / 2; return Scaffold( backgroundColor: Colors.white, appBar: MyAppbar(title: '人脸识别'), body: Stack( children: [ Positioned.fill(child: Container(color: Colors.white)), Transform.translate( offset: const Offset(0, -100), child: Stack( children: [ Center( child: ClipOval( child: AspectRatio( aspectRatio: previewAspect, child: CameraPreview(_cameraController!), ), ), ), Positioned.fill( child: CustomPaint( painter: _WhiteMaskPainter(radius: radius), ), ), ], ), ), Align( alignment: Alignment.center, child: Padding( padding: const EdgeInsets.only(top: 250), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( _tip, style: const TextStyle(fontSize: 18, color: Colors.black87), textAlign: TextAlign.center, ), const SizedBox(height: 20), if (_isManualMode) CustomButton(text: '拍照/上传', backgroundColor: Colors.blue,onPressed: _captureAndReload,) ], ), ), ), ], ), ); } } class _WhiteMaskPainter extends CustomPainter { final double radius; _WhiteMaskPainter({required this.radius}); @override void paint(Canvas canvas, Size size) { canvas.saveLayer(Offset.zero & size, Paint()); canvas.drawRect(Offset.zero & size, Paint()..color = Colors.white); canvas.drawCircle( size.center(Offset.zero), radius, Paint()..blendMode = BlendMode.clear, ); canvas.restore(); } @override bool shouldRepaint(covariant CustomPainter old) => false; }