""" 외출 관리 화면 """ from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QTableWidget, QTableWidgetItem, QHeaderView, QMessageBox, QTimeEdit, QLineEdit, QWidget) from PyQt5.QtCore import Qt, QTime from datetime import datetime from core.i18n import tr from ui.styles import apply_dark_titlebar class BreakEditDialog(QDialog): """외출 기록 수정 다이얼로그""" def __init__(self, parent=None, break_record=None): super().__init__(parent) self.break_record = break_record self.init_ui() apply_dark_titlebar(self) def init_ui(self): """UI 초기화""" self.setWindowTitle(tr('dlg.break.edit_title')) self.setFixedSize(380, 180) layout = QVBoxLayout() layout.setSpacing(8) layout.setContentsMargins(12, 10, 12, 10) # 외출 시간 out_layout = QHBoxLayout() out_label = QLabel(tr('dlg.break.out_label')) out_label.setFixedWidth(80) self.out_time_edit = QTimeEdit() self.out_time_edit.setDisplayFormat("HH:mm:ss") out_layout.addWidget(out_label) out_layout.addWidget(self.out_time_edit) layout.addLayout(out_layout) # 복귀 시간 in_layout = QHBoxLayout() in_label = QLabel(tr('dlg.break.in_label')) in_label.setFixedWidth(80) self.in_time_edit = QTimeEdit() self.in_time_edit.setDisplayFormat("HH:mm:ss") in_layout.addWidget(in_label) in_layout.addWidget(self.in_time_edit) layout.addLayout(in_layout) # 사유 reason_layout = QHBoxLayout() reason_label = QLabel(tr('dlg.break.reason_label')) reason_label.setFixedWidth(80) self.reason_edit = QLineEdit() reason_layout.addWidget(reason_label) reason_layout.addWidget(self.reason_edit) layout.addLayout(reason_layout) # 기존 데이터 로드 if self.break_record: break_out = self.break_record.get('break_out', '00:00:00') h, m, s = map(int, break_out.split(':')) self.out_time_edit.setTime(QTime(h, m, s)) break_in = self.break_record.get('break_in') if break_in: h, m, s = map(int, break_in.split(':')) self.in_time_edit.setTime(QTime(h, m, s)) reason = self.break_record.get('reason', '') if reason: self.reason_edit.setText(reason) # 버튼 button_layout = QHBoxLayout() save_button = QPushButton(tr('btn.save')) cancel_button = QPushButton(tr('btn.cancel')) save_button.clicked.connect(self.accept) cancel_button.clicked.connect(self.reject) button_layout.addWidget(save_button) button_layout.addWidget(cancel_button) layout.addLayout(button_layout) self.setLayout(layout) def get_data(self): """입력된 데이터 반환""" out_time = self.out_time_edit.time() in_time = self.in_time_edit.time() reason = self.reason_edit.text() # 복귀 시간 처리: 기존 기록에 복귀 시간이 없으면 None 유지 # 자정(00:00:00)도 유효한 시간으로 처리 break_in_str = in_time.toString("HH:mm:ss") if self.break_record and not self.break_record.get('break_in'): # 기존에 복귀 시간이 없었고, 수정에서도 00:00:00이면 아직 복귀 안 한 것으로 간주 if break_in_str == "00:00:00": break_in_str = None return { 'break_out': out_time.toString("HH:mm:ss"), 'break_in': break_in_str, 'reason': reason } class BreakView(QDialog): """외출 관리 창""" def __init__(self, parent=None, db=None): super().__init__(parent) self.db = db self.parent_window = parent self.init_ui() self.load_break_records() apply_dark_titlebar(self) def init_ui(self): """UI 초기화""" self.setWindowTitle(tr('window.break_view')) self.setGeometry(200, 200, 550, 350) layout = QVBoxLayout() layout.setSpacing(6) layout.setContentsMargins(12, 10, 12, 10) # 제목 title = QLabel(tr('view.break.today_title')) title.setObjectName("dialog_subtitle") title.setAlignment(Qt.AlignCenter) layout.addWidget(title) # 외출 리스트 테이블 self.table = QTableWidget() self.table.setColumnCount(5) self.table.setHorizontalHeaderLabels([ tr('view.break.col_out'), tr('view.break.col_in'), tr('view.break.col_duration'), tr('view.break.col_reason'), "", ]) # 테이블 설정 header = self.table.horizontalHeader() header.setSectionResizeMode(0, QHeaderView.ResizeToContents) header.setSectionResizeMode(1, QHeaderView.ResizeToContents) header.setSectionResizeMode(2, QHeaderView.ResizeToContents) header.setSectionResizeMode(3, QHeaderView.Stretch) header.setSectionResizeMode(4, QHeaderView.ResizeToContents) self.table.setSelectionBehavior(QTableWidget.SelectRows) self.table.setEditTriggers(QTableWidget.NoEditTriggers) layout.addWidget(self.table) # 총 외출 시간 표시 self.total_label = QLabel(tr('view.break.total_zero')) self.total_label.setObjectName("section_title") self.total_label.setAlignment(Qt.AlignRight) layout.addWidget(self.total_label) # 버튼 button_layout = QHBoxLayout() self.refresh_button = QPushButton(tr('btn.refresh')) close_button = QPushButton(tr('btn.close')) self.refresh_button.clicked.connect(self.load_break_records) close_button.clicked.connect(self.accept) button_layout.addStretch() button_layout.addWidget(self.refresh_button) button_layout.addWidget(close_button) layout.addLayout(button_layout) self.setLayout(layout) def load_break_records(self): """외출 기록 로드""" records = self.db.get_today_break_records() self.table.setRowCount(len(records)) for i, record in enumerate(records): # 외출 시간 break_out = record.get('break_out', '') self.table.setItem(i, 0, QTableWidgetItem(break_out)) # 복귀 시간 break_in = record.get('break_in', '') if break_in: self.table.setItem(i, 1, QTableWidgetItem(break_in)) else: item = QTableWidgetItem(tr('view.break.in_progress')) item.setForeground(Qt.red) self.table.setItem(i, 1, item) # 소요 시간 total_minutes = record.get('total_minutes') if total_minutes: hours = total_minutes // 60 minutes = total_minutes % 60 if hours > 0: duration_str = tr('view.break.duration_fmt', h=hours, m=minutes) else: duration_str = tr('view.break.duration_min_only', m=minutes) self.table.setItem(i, 2, QTableWidgetItem(duration_str)) else: self.table.setItem(i, 2, QTableWidgetItem("-")) # 사유 reason = record.get('reason', '') self.table.setItem(i, 3, QTableWidgetItem(reason)) # 액션 버튼 action_widget = QWidget() action_layout = QHBoxLayout() action_layout.setContentsMargins(0, 0, 0, 0) action_layout.setSpacing(5) edit_button = QPushButton(tr('btn.edit_short')) delete_button = QPushButton(tr('btn.delete_short')) edit_button.setFixedSize(50, 25) delete_button.setFixedSize(50, 25) # 클릭 이벤트에 record id 전달 record_id = record['id'] edit_button.clicked.connect(lambda checked, rid=record_id: self.edit_record(rid)) delete_button.clicked.connect(lambda checked, rid=record_id: self.delete_record(rid)) action_layout.addWidget(edit_button) action_layout.addWidget(delete_button) action_widget.setLayout(action_layout) self.table.setCellWidget(i, 4, action_widget) # 총 외출 시간 업데이트 total_minutes = self.db.get_total_break_minutes_today() hours = total_minutes // 60 minutes = total_minutes % 60 if hours > 0: self.total_label.setText(tr('view.break.total_fmt', h=hours, m=minutes)) else: self.total_label.setText(tr('view.break.total_min_only', m=minutes)) def edit_record(self, record_id): """외출 기록 수정""" # 기존 기록 조회 records = self.db.get_today_break_records() record = next((r for r in records if r['id'] == record_id), None) if not record: return # 수정 다이얼로그 표시 dialog = BreakEditDialog(self, record) if dialog.exec_() == QDialog.Accepted: data = dialog.get_data() # DB 업데이트 self.db.update_break_record( record_id, data['break_out'], data['break_in'], data['reason'] ) # 리스트 새로고침 self.load_break_records() # 부모 창 업데이트 if self.parent_window and hasattr(self.parent_window, 'update_break_status'): self.parent_window.update_break_status() if self.parent_window and hasattr(self.parent_window, 'update_times'): self.parent_window.update_times() def delete_record(self, record_id): """외출 기록 삭제""" reply = QMessageBox.question( self, tr('msg.confirm_delete.title'), tr('view.break.delete_confirm'), QMessageBox.Yes | QMessageBox.No ) if reply == QMessageBox.Yes: self.db.delete_break_record(record_id) self.load_break_records() # 부모 창 업데이트 if self.parent_window and hasattr(self.parent_window, 'update_break_status'): self.parent_window.update_break_status() if self.parent_window and hasattr(self.parent_window, 'update_times'): self.parent_window.update_times()