修复工作人员作业预检状态与提示

This commit is contained in:
czl231
2026-09-05 20:17:07 +08:00
parent 1670d5880f
commit cec02c8887
8 changed files with 191 additions and 12 deletions

View File

@@ -29,7 +29,7 @@ class GeolocatorLocationService implements LocationService {
permission = await Geolocator.requestPermission();
}
if (permission == LocationPermission.denied || permission == LocationPermission.deniedForever) {
throw StateError('定位权限未授权,无法完成该在线动作');
throw StateError('定位权限未授权,请在浏览器站点权限或系统设置中允许定位后重试');
}
final position = await Geolocator.getCurrentPosition();
return LocationPoint(

View File

@@ -35,6 +35,12 @@ class PreflightResult {
final bool canWork;
final Map<String, Object?> checks;
/// 仅统计真正阻止进入工作台的检查项。
int get blockerCount => checks.values.where((value) {
final detail = _map(value);
return detail['status'] == 'blocked';
}).length;
factory PreflightResult.fromJson(Map<String, Object?> json) => PreflightResult(
roleCode: json['role_code'] as String? ?? '',
workStatus: json['work_status'] as String? ?? 'off_duty',

View File

@@ -46,7 +46,15 @@ class _PreflightPageState extends State<PreflightPage> {
return;
} catch (error) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(error.toString())));
final message = error is StateError ? error.message : error.toString();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
action: error is StateError
? SnackBarAction(label: '重新授权', onPressed: () => _attendance(action))
: null,
),
);
}
} finally {
if (mounted) setState(() => _busy = false);
@@ -107,7 +115,7 @@ class _PreflightPageState extends State<PreflightPage> {
else ...[
FilledButton(
onPressed: result.canWork ? () => context.go('/work') : null,
child: const Text('进入工作台'),
child: Text(result.canWork ? '进入工作台' : '完成 ${result.blockerCount} 项阻断后可进入'),
),
const SizedBox(height: 8),
TextButton(
@@ -200,17 +208,28 @@ class _CheckRow extends StatelessWidget {
final tone = passed
? StatusTone.success
: status == 'not_configured'
? StatusTone.warning
? StatusTone.neutral
: StatusTone.danger;
final text = status == 'not_configured'
? '平台暂未启用'
? '暂不检查'
: passed
? '已通过'
: '未通过';
final description = entry.key == 'credential' && !passed
? _credentialDescription(detail['reason']?.toString())
: null;
return ListTile(
leading: Icon(passed ? Icons.check_circle_outline : Icons.info_outline_rounded),
title: Text(label),
subtitle: description == null ? null : Text(description),
trailing: StatusPill(label: text, tone: tone),
);
}
/// 将服务端稳定原因码转换为可执行的中文处理说明。
String _credentialDescription(String? reason) => switch (reason) {
'expired' => '人员资质已过期,请联系所属组织管理员更新',
'disabled' => '人员资质已停用,请联系所属组织管理员处理',
_ => '尚未配置有效资质,请联系所属组织管理员补充或审核',
};
}