스마트기기 반출 대장: 1시간 59분 이상 요청은 목록에서 빨간 테두리로 표시
기존엔 "많은 시간요청 학생" 팝업에서만 2시간 기준으로 걸러냈는데, 메인 목록 카드 자체에도 (대기중/승인/거절 등 상태 무관하게) 빨간 테두리를 씌워서 바로 눈에 띄게 함. 기준을 2시간 → 1시간 59분(119분)으로 낮춰서 두 기능이 같은 기준을 쓰도록 통일. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,25 +16,38 @@ class DeviceCheckoutLedgerController extends ChangeNotifier {
|
|||||||
bool get isLoading => _isLoading;
|
bool get isLoading => _isLoading;
|
||||||
bool get isWorking => _isWorking;
|
bool get isWorking => _isWorking;
|
||||||
|
|
||||||
/// ⏰ 요청 시간이 얼마나 되는지(시간 단위). 형식이 이상하면 null.
|
// 🚨 [장시간 요청 기준] 1시간 59분(119분) 이상이면 "많은 시간요청"으로 본다.
|
||||||
double? durationHours(dynamic request) {
|
static const int longRequestMinutes = 119;
|
||||||
|
|
||||||
|
int? _durationMinutes(dynamic request) {
|
||||||
try {
|
try {
|
||||||
final start = DateTime.parse(request['requestedStart']);
|
final start = DateTime.parse(request['requestedStart']);
|
||||||
final end = DateTime.parse(request['requestedEnd']);
|
final end = DateTime.parse(request['requestedEnd']);
|
||||||
final minutes = end.difference(start).inMinutes;
|
final minutes = end.difference(start).inMinutes;
|
||||||
return minutes > 0 ? minutes / 60.0 : null;
|
return minutes > 0 ? minutes : null;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 🚨 [장시간 요청 감지] 2시간 넘게 신청한, 아직 대기 중인 요청 목록.
|
/// ⏰ 요청 시간이 얼마나 되는지(시간 단위). 형식이 이상하면 null.
|
||||||
/// 학생이 시간을 비정상적으로 길게 적어냈을 수 있으니 전체 승인 전에 따로 훑어볼 수 있게 한다.
|
double? durationHours(dynamic request) {
|
||||||
List<dynamic> get longPendingRequests => _requests.where((r) {
|
final minutes = _durationMinutes(request);
|
||||||
if (r['status'] != 'PENDING') return false;
|
return minutes == null ? null : minutes / 60.0;
|
||||||
final hours = durationHours(r);
|
}
|
||||||
return hours != null && hours >= 2;
|
|
||||||
}).toList();
|
/// 🚨 [장시간 요청 감지] 1시간 59분 넘게 신청했는지. 상태(대기/승인 등)와 무관하게 판단한다 -
|
||||||
|
/// 목록 카드에 빨간 테두리를 씌우는 데 쓴다.
|
||||||
|
bool isLongRequest(dynamic request) {
|
||||||
|
final minutes = _durationMinutes(request);
|
||||||
|
return minutes != null && minutes >= longRequestMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 학생이 시간을 비정상적으로 길게 적어냈을 수 있으니, 아직 대기 중인 장시간 요청만
|
||||||
|
/// 따로 모아서 전체 승인 전에 훑어볼 수 있게 한다.
|
||||||
|
List<dynamic> get longPendingRequests => _requests
|
||||||
|
.where((r) => r['status'] == 'PENDING' && isLongRequest(r))
|
||||||
|
.toList();
|
||||||
|
|
||||||
void _safeNotify() {
|
void _safeNotify() {
|
||||||
if (!_disposed) notifyListeners();
|
if (!_disposed) notifyListeners();
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class _DeviceCheckoutLedgerPageState extends State<DeviceCheckoutLedgerPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🚨 [많은 시간요청 학생] 2시간 넘게 신청한 대기 중인 요청만 따로 모아 보여준다.
|
// 🚨 [많은 시간요청 학생] 1시간 59분 넘게 신청한 대기 중인 요청만 따로 모아 보여준다.
|
||||||
// 학생이 시간을 비정상적으로 길게 적어냈을 수 있으니, 전체 승인 전에 훑어보는 용도.
|
// 학생이 시간을 비정상적으로 길게 적어냈을 수 있으니, 전체 승인 전에 훑어보는 용도.
|
||||||
void _showLongRequestsDialog() {
|
void _showLongRequestsDialog() {
|
||||||
showDialog(
|
showDialog(
|
||||||
@@ -113,7 +113,7 @@ class _DeviceCheckoutLedgerPageState extends State<DeviceCheckoutLedgerPage> {
|
|||||||
return const Padding(
|
return const Padding(
|
||||||
padding: EdgeInsets.symmetric(vertical: 16),
|
padding: EdgeInsets.symmetric(vertical: 16),
|
||||||
child: Text(
|
child: Text(
|
||||||
'2시간 넘게 신청한 대기 중인 요청이 없습니다.',
|
'1시간 59분 넘게 신청한 대기 중인 요청이 없습니다.',
|
||||||
style: TextStyle(color: Colors.grey),
|
style: TextStyle(color: Colors.grey),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -320,6 +320,10 @@ class _DeviceCheckoutLedgerPageState extends State<DeviceCheckoutLedgerPage> {
|
|||||||
final String status = r['status'];
|
final String status = r['status'];
|
||||||
final info = _statusInfo(status);
|
final info = _statusInfo(status);
|
||||||
final bool isPending = status == 'PENDING';
|
final bool isPending = status == 'PENDING';
|
||||||
|
// 🚨 1시간 59분 넘게 신청했으면 상태와 무관하게 빨간 테두리로 눈에 띄게.
|
||||||
|
final bool isLong = _controller.isLongRequest(
|
||||||
|
r,
|
||||||
|
);
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
@@ -327,9 +331,18 @@ class _DeviceCheckoutLedgerPageState extends State<DeviceCheckoutLedgerPage> {
|
|||||||
margin: const EdgeInsets.only(bottom: 10),
|
margin: const EdgeInsets.only(bottom: 10),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
side: isPending
|
side: isLong
|
||||||
? BorderSide(color: Colors.orange[300]!)
|
? BorderSide(
|
||||||
: BorderSide(color: AppPalette.sage),
|
color: Colors.red[400]!,
|
||||||
|
width: 2,
|
||||||
|
)
|
||||||
|
: (isPending
|
||||||
|
? BorderSide(
|
||||||
|
color: Colors.orange[300]!,
|
||||||
|
)
|
||||||
|
: BorderSide(
|
||||||
|
color: AppPalette.sage,
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
|
|||||||
Reference in New Issue
Block a user