From 383de8b3a169ff0dea549d9cbc8ad5636a58672d Mon Sep 17 00:00:00 2001 From: sihoo Date: Tue, 1 Sep 2026 13:20:28 +0900 Subject: [PATCH] =?UTF-8?q?=EC=8A=A4=EB=A7=88=ED=8A=B8=EA=B8=B0=EA=B8=B0?= =?UTF-8?q?=20=EB=B0=98=EC=B6=9C:=20=EC=A0=80=EC=9A=B8=20=ED=95=98?= =?UTF-8?q?=EB=93=9C=EC=9B=A8=EC=96=B4=20=EC=A0=9C=EA=B1=B0,=20=EC=8A=B9?= =?UTF-8?q?=EC=9D=B8=20=EC=84=A0=EC=83=9D=EB=8B=98=20=EC=A7=80=EC=A0=95=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 계획 변경에 따라 저울/아두이노 기반 픽업·반납·무단반출 감지를 없애고 순수 시간 기반 알림만 남김 (백엔드는 별도 저장소에서 이미 배포 완료). - 승인 시 현재 로그인한 선생님의 teacherId/teacherName을 서버에 함께 전송하여 저장하고, 대장에 "OOO 선생님이 허용했습니다" 표시 - 반납 시간 초과 알림은 승인한 선생님에게만 전송 (서버가 해당 선생님의 등록된 기기를 못 찾으면 전체 선생님에게 대체 발송) - 대장 카드의 상태 표시에서 IN_USE/RETURNED(픽업 대기) 문구 제거 Co-Authored-By: Claude Sonnet 5 --- .../device_checkout_ledger_controller.dart | 20 +++++++++---- lib/ui/device_checkout_ledger_page.dart | 30 ++++++++++++++----- lib/ui/teacher_dashboard.dart | 6 ++-- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/lib/function/device_checkout_ledger_controller.dart b/lib/function/device_checkout_ledger_controller.dart index 69e5af9..3184651 100644 --- a/lib/function/device_checkout_ledger_controller.dart +++ b/lib/function/device_checkout_ledger_controller.dart @@ -49,17 +49,27 @@ class DeviceCheckoutLedgerController extends ChangeNotifier { } } - Future<(bool success, String message)> approve(int requestId) async { - return _postAction('/api/device-checkout/approve', requestId); + // ✅ 승인 시 승인한 선생님 계정을 함께 보낸다 (대장에 "OOO 선생님이 허용했습니다" 표시 + + // 미반납 알림을 그 선생님에게만 보내기 위함). + Future<(bool success, String message)> approve( + int requestId, { + required String teacherId, + required String teacherName, + }) async { + return _postAction('/api/device-checkout/approve', { + "requestId": requestId, + "teacherId": teacherId, + "teacherName": teacherName, + }); } Future<(bool success, String message)> reject(int requestId) async { - return _postAction('/api/device-checkout/reject', requestId); + return _postAction('/api/device-checkout/reject', {"requestId": requestId}); } Future<(bool success, String message)> _postAction( String path, - int requestId, + Map body, ) async { _isWorking = true; _safeNotify(); @@ -67,7 +77,7 @@ class DeviceCheckoutLedgerController extends ChangeNotifier { final response = await http.post( Uri.parse('$baseUrl$path'), headers: {"Content-Type": "application/json"}, - body: jsonEncode({"requestId": requestId}), + body: jsonEncode(body), ); final result = jsonDecode(utf8.decode(response.bodyBytes)); if (response.statusCode == 200 && result['status'] == 'success') { diff --git a/lib/ui/device_checkout_ledger_page.dart b/lib/ui/device_checkout_ledger_page.dart index b31acef..d4d8597 100644 --- a/lib/ui/device_checkout_ledger_page.dart +++ b/lib/ui/device_checkout_ledger_page.dart @@ -4,7 +4,10 @@ import 'package:flutter/material.dart'; import '../function/device_checkout_ledger_controller.dart'; class DeviceCheckoutLedgerPage extends StatefulWidget { - const DeviceCheckoutLedgerPage({super.key}); + final String? teacherId; + final String? teacherName; + + const DeviceCheckoutLedgerPage({super.key, this.teacherId, this.teacherName}); @override State createState() => @@ -28,7 +31,11 @@ class _DeviceCheckoutLedgerPageState extends State { } Future _approve(int id) async { - final (_, message) = await _controller.approve(id); + final (_, message) = await _controller.approve( + id, + teacherId: widget.teacherId ?? '간편인증', + teacherName: widget.teacherName ?? '간편인증 선생', + ); if (!mounted) return; ScaffoldMessenger.of( context, @@ -48,11 +55,7 @@ class _DeviceCheckoutLedgerPageState extends State { case 'PENDING': return (color: Colors.orange, label: '⏳ 대기중'); case 'APPROVED': - return (color: Colors.blue, label: '✅ 승인됨 (픽업 대기)'); - case 'IN_USE': - return (color: Colors.teal, label: '📱 사용중'); - case 'RETURNED': - return (color: Colors.grey, label: '↩️ 반납완료'); + return (color: Colors.blue, label: '✅ 승인됨'); case 'REJECTED': return (color: Colors.red, label: '🚫 거절됨'); default: @@ -205,6 +208,19 @@ class _DeviceCheckoutLedgerPageState extends State { fontSize: 13, ), ), + if (status == 'APPROVED' && + r['approvedByTeacherName'] != + null) ...[ + const SizedBox(height: 2), + Text( + '👤 ${r['approvedByTeacherName']} 선생님이 허용했습니다', + style: TextStyle( + color: Colors.blue[700], + fontSize: 12, + fontWeight: FontWeight.w600, + ), + ), + ], if (isPending) ...[ const SizedBox(height: 12), Row( diff --git a/lib/ui/teacher_dashboard.dart b/lib/ui/teacher_dashboard.dart index 7cc97be..9eef3ce 100644 --- a/lib/ui/teacher_dashboard.dart +++ b/lib/ui/teacher_dashboard.dart @@ -187,8 +187,10 @@ class _TeacherDashboardState extends State { onTap: () => Navigator.push( context, MaterialPageRoute( - builder: (context) => - const DeviceCheckoutLedgerPage(), + builder: (context) => DeviceCheckoutLedgerPage( + teacherId: widget.teacherId, + teacherName: widget.teacherName, + ), ), ), ),