""" 반복 연차 등록/관리 다이얼로그. 지원: 매주/격주 요일, 매월 N일. """ from __future__ import annotations from datetime import date from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QComboBox, QDateEdit, QSpinBox, QDoubleSpinBox, QLineEdit, QGroupBox, QListWidget, QListWidgetItem, QMessageBox, QCheckBox, QButtonGroup, QRadioButton) from PyQt5.QtCore import QDate, Qt from core.recurring_leaves import describe_pattern from ui.styles import apply_dark_titlebar _KO_WEEKDAYS = [('월', 'mon'), ('화', 'tue'), ('수', 'wed'), ('목', 'thu'), ('금', 'fri'), ('토', 'sat'), ('일', 'sun')] class RecurringLeaveDialog(QDialog): """반복 연차 패턴 추가/삭제.""" def __init__(self, parent=None, db=None): super().__init__(parent) self.db = db self.setWindowTitle("반복 연차 관리") self.setMinimumSize(540, 480) self._build_ui() self._reload_list() apply_dark_titlebar(self) def _build_ui(self): layout = QVBoxLayout() # 기존 패턴 목록 list_group = QGroupBox("등록된 반복 패턴") lg = QVBoxLayout() self.list_widget = QListWidget() self.list_widget.setMinimumHeight(160) lg.addWidget(self.list_widget) del_btn = QPushButton("선택 삭제") del_btn.clicked.connect(self._delete_selected) lg.addWidget(del_btn) list_group.setLayout(lg) layout.addWidget(list_group) # 신규 등록 add_group = QGroupBox("신규 패턴 추가") ag = QVBoxLayout() # 패턴 종류 kind_row = QHBoxLayout() kind_row.addWidget(QLabel("주기:")) self.kind_group = QButtonGroup(self) self.rb_weekly = QRadioButton("매주") self.rb_weekly.setChecked(True) self.rb_biweekly = QRadioButton("격주") self.rb_monthly = QRadioButton("매월 N일") for rb in (self.rb_weekly, self.rb_biweekly, self.rb_monthly): self.kind_group.addButton(rb) kind_row.addWidget(rb) kind_row.addStretch() ag.addLayout(kind_row) # 요일 체크박스 (weekly/biweekly) wd_row = QHBoxLayout() wd_row.addWidget(QLabel("요일:")) self.weekday_checks = [] for ko, en in _KO_WEEKDAYS: cb = QCheckBox(ko) self.weekday_checks.append((cb, en)) wd_row.addWidget(cb) wd_row.addStretch() ag.addLayout(wd_row) # 매월 N일 month_row = QHBoxLayout() month_row.addWidget(QLabel("매월:")) self.day_of_month = QSpinBox() self.day_of_month.setRange(1, 31) self.day_of_month.setValue(15) self.day_of_month.setSuffix("일") month_row.addWidget(self.day_of_month) month_row.addStretch() ag.addLayout(month_row) # 차감 일수 days_row = QHBoxLayout() days_row.addWidget(QLabel("차감:")) self.days_combo = QComboBox() self.days_combo.addItem("1.0일 (종일)", 1.0) self.days_combo.addItem("0.5일 (반차)", 0.5) self.days_combo.addItem("0.25일 (반반차)", 0.25) days_row.addWidget(self.days_combo) days_row.addStretch() ag.addLayout(days_row) # 시작/종료 날짜 date_row = QHBoxLayout() date_row.addWidget(QLabel("시작:")) self.start_edit = QDateEdit() self.start_edit.setDate(QDate.currentDate()) self.start_edit.setCalendarPopup(True) date_row.addWidget(self.start_edit) date_row.addWidget(QLabel("종료:")) self.end_edit = QDateEdit() self.end_edit.setDate(QDate.currentDate().addMonths(6)) self.end_edit.setCalendarPopup(True) date_row.addWidget(self.end_edit) self.no_end_check = QCheckBox("종료 없음 (무기한)") self.no_end_check.toggled.connect( lambda v: self.end_edit.setEnabled(not v) ) date_row.addWidget(self.no_end_check) date_row.addStretch() ag.addLayout(date_row) # 메모 memo_row = QHBoxLayout() memo_row.addWidget(QLabel("메모:")) self.memo_edit = QLineEdit() self.memo_edit.setPlaceholderText("예: 육아 단축근무") memo_row.addWidget(self.memo_edit) ag.addLayout(memo_row) # 추가 버튼 add_btn = QPushButton("추가") add_btn.setObjectName("btn_primary") add_btn.clicked.connect(self._save) ag.addWidget(add_btn) add_group.setLayout(ag) layout.addWidget(add_group) # 닫기 close_btn = QPushButton("닫기") close_btn.clicked.connect(self.close) layout.addWidget(close_btn) self.setLayout(layout) def _reload_list(self): self.list_widget.clear() for r in self.db.get_recurring_leaves(): desc = describe_pattern(r['pattern']) end = r.get('end_date') or '무기한' text = (f"[{r['id']}] {desc} · {r['days']}일 ({r['leave_type']}) " f"· {r['start_date']} ~ {end}") if r.get('memo'): text += f" — {r['memo']}" item = QListWidgetItem(text) item.setData(Qt.UserRole, r['id']) self.list_widget.addItem(item) def _delete_selected(self): item = self.list_widget.currentItem() if not item: return rec_id = item.data(Qt.UserRole) reply = QMessageBox.question( self, "삭제 확인", f"이 반복 패턴을 삭제하시겠습니까?\n\n{item.text()}", QMessageBox.Yes | QMessageBox.No, ) if reply == QMessageBox.Yes: self.db.delete_recurring_leave(rec_id) self._reload_list() def _build_pattern(self) -> str | None: if self.rb_monthly.isChecked(): return f"monthly:{self.day_of_month.value()}" # weekly/biweekly chosen = [en for cb, en in self.weekday_checks if cb.isChecked()] if not chosen: return None prefix = 'weekly' if self.rb_weekly.isChecked() else 'biweekly' return f"{prefix}:" + ",".join(chosen) def _save(self): pattern = self._build_pattern() if not pattern: QMessageBox.warning(self, "입력 오류", "최소 한 개 요일을 선택하세요.") return days = self.days_combo.currentData() leave_type = self.days_combo.currentText().split(' ')[1].strip('()') start = self.start_edit.date().toString('yyyy-MM-dd') end = None if self.no_end_check.isChecked() else self.end_edit.date().toString('yyyy-MM-dd') memo = self.memo_edit.text().strip() self.db.add_recurring_leave(pattern, leave_type, days, start, end, memo) QMessageBox.information(self, "추가 완료", f"반복 패턴이 등록되었습니다.\n{describe_pattern(pattern)}") self.memo_edit.clear() self._reload_list()