feat:添加识别策略

This commit is contained in:
dzc committed 2026-07-24 20:41:17 +08:00
1 parent 0d0924c314
commit 1c348fc18e
20 files changed
+1500 -74

No files matched your search

@@ -2,6 +2,8 @@ import 'dart:async';
import 'package:flutter/foundation.dart';
import '../models/face_recognition_display_models.dart';
import '../models/reservation_query_display_models.dart';
import 'customer_display_coordinator.dart';
import 'face_recognition_coordinator.dart';
import 'reservation_query_coordinator.dart';
@@ -27,6 +29,7 @@ class SubDisplayCoordinator extends ChangeNotifier {
static const _reservationUpdate = 'reservationQueryUpdate';
static const _reservationClear = 'reservationQueryClear';
static const _faceStart = 'faceRecognitionStart';
static const _settlementActions = {
'updateCard',
'jumpSubPage',
@@ -43,6 +46,10 @@ class SubDisplayCoordinator extends ChangeNotifier {
SubDisplayMode _mode = SubDisplayMode.settlement;
SubDisplayMode _modeBeforeFace = SubDisplayMode.settlement;
Timer? _faceRestoreTimer;
String? _reservationSessionAtFaceStart;
int _reservationRevisionAtFaceStart = -1;
bool _reservationSuccessDelayPassed = false;
bool _reservationResultReady = false;
bool _disposed = false;
SubDisplayMode get mode => _mode;
@@ -52,21 +59,42 @@ class SubDisplayCoordinator extends ChangeNotifier {
if (action.startsWith('faceRecognition')) {
final result = faceRecognitionCoordinator.handleAction(action, arguments);
if (!result.accepted) return false;
final faceState = faceRecognitionCoordinator.state;
switch (result.transition) {
case FaceRecognitionDisplayTransition.show:
_faceRestoreTimer?.cancel();
if (action == _faceStart) {
_resetReservationFaceHandoff();
if (faceState?.scene == FaceRecognitionDisplayScene.reservation) {
_beginReservationFaceHandoff();
}
}
if (_mode != SubDisplayMode.faceRecognition) _modeBeforeFace = _mode;
_replaceMode(SubDisplayMode.faceRecognition);
break;
case FaceRecognitionDisplayTransition.restoreNow:
_faceRestoreTimer?.cancel();
_resetReservationFaceHandoff();
_replaceMode(_modeBeforeFace);
break;
case FaceRecognitionDisplayTransition.restoreAfterSuccess:
_faceRestoreTimer?.cancel();
_faceRestoreTimer = Timer(const Duration(milliseconds: 700), () {
if (!_disposed) _replaceMode(_modeBeforeFace);
});
if (faceState?.scene == FaceRecognitionDisplayScene.reservation) {
// 预约查询必须在人脸成功提示展示满 700ms 且查询拿到最终结果后再恢复,
// 否则慢网络会先露出中间 loading,顾客看不到“人脸 -> 本人菜单”的完整顺序。
_reservationSuccessDelayPassed = false;
_reservationResultReady = _hasNewReservationTerminalState();
_faceRestoreTimer = Timer(const Duration(milliseconds: 700), () {
if (_disposed) return;
_reservationSuccessDelayPassed = true;
_restoreReservationAfterFaceIfReady();
});
} else {
_resetReservationFaceHandoff();
_faceRestoreTimer = Timer(const Duration(milliseconds: 700), () {
if (!_disposed) _replaceMode(_modeBeforeFace);
});
}
break;
case FaceRecognitionDisplayTransition.none:
break;
@@ -75,12 +103,18 @@ class SubDisplayCoordinator extends ChangeNotifier {
}
if (action == _reservationUpdate) {
final accepted = reservationCoordinator.handleUpdate(arguments);
if (accepted) _showOrRememberMode(SubDisplayMode.reservationQuery);
if (accepted) {
_showOrRememberMode(SubDisplayMode.reservationQuery);
_handleReservationUpdateDuringFace();
}
return accepted;
}
if (action == _reservationClear) {
final accepted = reservationCoordinator.handleClear(arguments);
if (accepted) _showOrRememberMode(SubDisplayMode.reservationQuery);
if (accepted) {
_showOrRememberMode(SubDisplayMode.reservationQuery);
_handleReservationClearDuringFace();
}
return accepted;
}
if (_settlementActions.contains(action)) {
@@ -98,6 +132,73 @@ class SubDisplayCoordinator extends ChangeNotifier {
return true;
}
void _beginReservationFaceHandoff() {
final reservationState = reservationCoordinator.state;
_reservationSessionAtFaceStart = reservationState.sessionId;
_reservationRevisionAtFaceStart = reservationState.revision;
_reservationSuccessDelayPassed = false;
_reservationResultReady = false;
}
void _handleReservationUpdateDuringFace() {
if (_mode != SubDisplayMode.faceRecognition) return;
final faceState = faceRecognitionCoordinator.state;
if (faceState?.scene != FaceRecognitionDisplayScene.reservation) return;
if (faceState?.status != FaceRecognitionDisplayStatus.success &&
faceState?.status != FaceRecognitionDisplayStatus.failed) {
return;
}
if (!_hasNewReservationTerminalState()) return;
_reservationResultReady = true;
if (faceState?.status == FaceRecognitionDisplayStatus.failed) {
// 可重试的人脸失败不会产生预约结果;只有业务已收口为 error 时才离开人脸页。
_faceRestoreTimer?.cancel();
_restoreReservationAfterFace();
return;
}
_restoreReservationAfterFaceIfReady();
}
void _handleReservationClearDuringFace() {
if (_mode != SubDisplayMode.faceRecognition) return;
final faceState = faceRecognitionCoordinator.state;
if (faceState?.scene != FaceRecognitionDisplayScene.reservation) return;
if (faceState?.status != FaceRecognitionDisplayStatus.success &&
faceState?.status != FaceRecognitionDisplayStatus.failed) {
return;
}
// 页面退出或隐私清屏不再等待查询结果,避免副屏停留在已结束的人脸成功页。
_restoreReservationAfterFace();
}
bool _hasNewReservationTerminalState() {
final state = reservationCoordinator.state;
final isNewer = state.sessionId != _reservationSessionAtFaceStart ||
state.revision > _reservationRevisionAtFaceStart;
if (!isNewer) return false;
return state.scenario == ReservationQueryDisplayScenario.success ||
state.scenario == ReservationQueryDisplayScenario.empty ||
state.scenario == ReservationQueryDisplayScenario.error;
}
void _restoreReservationAfterFaceIfReady() {
if (!_reservationSuccessDelayPassed || !_reservationResultReady) return;
_restoreReservationAfterFace();
}
void _restoreReservationAfterFace() {
_faceRestoreTimer?.cancel();
_replaceMode(SubDisplayMode.reservationQuery);
_resetReservationFaceHandoff();
}
void _resetReservationFaceHandoff() {
_reservationSessionAtFaceStart = null;
_reservationRevisionAtFaceStart = -1;
_reservationSuccessDelayPassed = false;
_reservationResultReady = false;
}
/// 人脸页显示期间,普通业务消息仍更新各自 Coordinator,但只修改待恢复页面。
/// 这样 success 的 700ms 提示和 failed 的重试引导不会被金额或查询消息提前顶掉。
bool _showOrRememberMode(SubDisplayMode next) {
@@ -118,6 +219,7 @@ class SubDisplayCoordinator extends ChangeNotifier {
if (_disposed) return;
_disposed = true;
_faceRestoreTimer?.cancel();
_resetReservationFaceHandoff();
customerCoordinator.removeListener(_notifyFromChild);
reservationCoordinator.removeListener(_notifyFromChild);
faceRecognitionCoordinator.removeListener(_notifyFromChild);