handOver2/ui/dialogs/duty_dialog.py

334 lines
12 KiB
Python

# -*- coding: utf-8 -*-
"""
당무 변경 다이얼로그
오늘의 당무자(부팀장, 운용)를 선택합니다.
"""
from datetime import date
from typing import Optional
from PySide6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QLabel
)
from PySide6.QtCore import Qt, Signal
from PySide6.QtGui import QFont
from ui.base.base_dialog import BaseDialog
from ui.components.custom_input import CustomComboBox, LabeledInput
from ui.styles.style_manager import StyleManager
from database.crud import CRUDManager
from database.models import TeamMember
from core.logger import get_logger
logger = get_logger(__name__)
class DutyChangeDialog(BaseDialog):
"""
당무 변경 다이얼로그
오늘의 당무자를 선택합니다.
부팀장과 운용을 각각 선택할 수 있습니다.
"""
duty_changed = Signal(str, str) # vice_leader_name, operator_name
def __init__(
self,
parent=None,
team: str = "",
shift: str = ""
):
self.team = team
self.shift = shift
self.crud = CRUDManager()
self.style_manager = StyleManager()
super().__init__(
parent,
title=f"당무 변경 - {team} {shift}",
width=400,
height=350,
min_width=350,
min_height=600,
resizable=True
)
self._setup_content()
self.add_confirm_cancel_buttons("저장", "취소")
self._load_current_duty()
def change_UI_Info(self, team: str, shift: str):
"""UI 정보 변경"""
self.team = team
self.shift = shift
self.title = f"당무 변경 - {team} {shift}"
self.setWindowTitle(self.title)
self._setup_content()
self._load_current_duty()
self.add_confirm_cancel_buttons("저장", "취소")
def _setup_content(self):
"""컨텐츠 설정"""
colors = self.style_manager.get_colors()
# 날짜 표시
today = date.today()
date_label = QLabel(f"📅 {today.year}{today.month}{today.day}")
date_font = self.style_manager.get_font("dialog", "title")
date_label.setFont(date_font)
date_label.setAlignment(Qt.AlignCenter)
date_height = self.style_manager.calculate_label_height(
font=date_font, area="dialog", style="title"
)
date_label.setStyleSheet(f"""
color: {colors['text_primary']};
min-height: {date_height}px;
""")
self.content_layout.addWidget(date_label)
# 팀/근무 정보
info_label = QLabel(f"🏢 {self.team} | {self.shift}")
info_font = self.style_manager.get_font("dialog", "label")
info_label.setFont(info_font)
info_label.setAlignment(Qt.AlignCenter)
info_height = self.style_manager.calculate_label_height(
font=info_font, area="dialog", style="label"
)
info_label.setStyleSheet(f"""
color: {colors['text_tertiary']};
min-height: {info_height}px;
margin-bottom: 16px;
""")
self.content_layout.addWidget(info_label)
# 부팀장 선택
self.vice_leader_combo = CustomComboBox(
placeholder="부팀장 선택"
)
self._load_vice_leaders()
self.content_layout.addWidget(
LabeledInput("부팀장 당무", self.vice_leader_combo)
)
# 운용 선택
self.operator_combo = CustomComboBox(
placeholder="운용 선택"
)
self._load_operators()
self.content_layout.addWidget(
LabeledInput("운용 당무", self.operator_combo)
)
# 자동 선택 버튼들
auto_section = QWidget()
auto_layout = QHBoxLayout(auto_section)
auto_layout.setContentsMargins(0, 16, 0, 0)
auto_layout.setSpacing(8)
from ui.components.custom_button import CustomButton
# 다음 순번 버튼
next_btn = CustomButton(
"다음 순번 자동선택",
style_type="outline",
fixed_height=36
)
next_btn.clicked.connect(self._select_next_duty)
auto_layout.addWidget(next_btn)
self.content_layout.addWidget(auto_section)
self.content_layout.addStretch()
def _on_text_scale_changed(self, scale: float, label_font, input_font):
"""
텍스트 스케일 변경 시 호출
당무 변경 다이얼로그의 텍스트만 동적으로 조정합니다.
"""
colors = self.style_manager.get_colors()
# 날짜 라벨 폰트 조정
base_date_font = self.style_manager.get_font("dialog", "title")
date_size = int(base_date_font.pointSize() * scale)
date_font = QFont(base_date_font.family(), date_size, base_date_font.weight())
date_height = self.style_manager.calculate_label_height(
font=date_font, area="dialog", style="title"
)
# 날짜 라벨 찾기 및 업데이트
for i in range(self.content_layout.count()):
widget = self.content_layout.itemAt(i).widget()
if isinstance(widget, QLabel) and "📅" in widget.text():
widget.setFont(date_font)
widget.setStyleSheet(f"""
color: {colors['text_primary']};
min-height: {date_height}px;
""")
break
# 팀/근무 정보 라벨 폰트 조정
base_info_font = self.style_manager.get_font("dialog", "label")
info_size = int(base_info_font.pointSize() * scale)
info_font = QFont(base_info_font.family(), info_size, base_info_font.weight())
info_height = self.style_manager.calculate_label_height(
font=info_font, area="dialog", style="label"
)
# 팀/근무 정보 라벨 찾기 및 업데이트
for i in range(self.content_layout.count()):
widget = self.content_layout.itemAt(i).widget()
if isinstance(widget, QLabel) and "🏢" in widget.text():
widget.setFont(info_font)
widget.setStyleSheet(f"""
color: {colors['text_tertiary']};
min-height: {info_height}px;
margin-bottom: 16px;
""")
break
# LabeledInput 내부 라벨 및 입력 필드도 조정
for i in range(self.content_layout.count()):
item = self.content_layout.itemAt(i)
if item and item.widget():
widget = item.widget()
if isinstance(widget, LabeledInput):
# 라벨 폰트 조정
label = widget.label
label.setFont(label_font)
label_height = self.style_manager.calculate_label_height(
font=label_font, area="dialog", style="label"
)
label.setStyleSheet(f"""
color: {colors['text_primary']};
font-family: '{label_font.family()}';
font-size: {label_font.pointSize()}pt;
min-height: {label_height}px;
""")
# 입력 필드 폰트 및 높이 조정
input_widget = widget.input_widget
if hasattr(input_widget, 'setFont'):
input_widget.setFont(input_font)
input_height = self.style_manager.calculate_input_height(
font=input_font, area="dialog", style="input"
)
if hasattr(input_widget, 'setMinimumHeight'):
input_widget.setMinimumHeight(input_height)
def _load_vice_leaders(self):
"""부팀장 목록 로드"""
members = self.crud.get_team_members_by_team(
self.team,
"부팀장",
active_only=True
)
for member in members:
self.vice_leader_combo.addItem(member.name, member.id)
def _load_operators(self):
"""운용 목록 로드"""
members = self.crud.get_team_members_by_team(
self.team,
"운용",
active_only=True
)
for member in members:
self.operator_combo.addItem(member.name, member.id)
def _load_current_duty(self):
"""현재 당무 정보 로드"""
today = date.today()
duty = self.crud.get_duty_schedule(today, self.team, self.shift)
if duty:
# 부팀장 선택
if duty.vice_leader_name:
idx = self.vice_leader_combo.findText(duty.vice_leader_name)
if idx >= 0:
self.vice_leader_combo.setCurrentIndex(idx)
# 운용 선택
if duty.operator_name:
idx = self.operator_combo.findText(duty.operator_name)
if idx >= 0:
self.operator_combo.setCurrentIndex(idx)
def _select_next_duty(self):
"""다음 순번 자동 선택"""
today = date.today()
# 현재 당무 정보 조회
current_duty = self.crud.get_duty_schedule(today, self.team, self.shift)
# 부팀장 다음 순번
current_vice_leader_id = current_duty.vice_leader_id if current_duty else None
next_vice_leader = self.crud.get_next_duty_member(
self.team,
"부팀장",
current_vice_leader_id
)
if next_vice_leader:
idx = self.vice_leader_combo.findText(next_vice_leader.name)
if idx >= 0:
self.vice_leader_combo.setCurrentIndex(idx)
# 운용 다음 순번
current_operator_id = current_duty.operator_id if current_duty else None
next_operator = self.crud.get_next_duty_member(
self.team,
"운용",
current_operator_id
)
if next_operator:
idx = self.operator_combo.findText(next_operator.name)
if idx >= 0:
self.operator_combo.setCurrentIndex(idx)
def _on_confirm(self):
"""저장 버튼 클릭"""
today = date.today()
# 선택된 부팀장
vice_leader_name = self.vice_leader_combo.currentText()
vice_leader_id = self.vice_leader_combo.currentData()
# 선택된 운용
operator_name = self.operator_combo.currentText()
operator_id = self.operator_combo.currentData()
# placeholder 체크
if self.vice_leader_combo.currentIndex() == 0:
vice_leader_name = ""
vice_leader_id = None
if self.operator_combo.currentIndex() == 0:
operator_name = ""
operator_id = None
# DB에 저장
self.crud.upsert_duty_schedule(
duty_date=today,
team=self.team,
shift_type=self.shift,
vice_leader_id=vice_leader_id,
operator_id=operator_id,
vice_leader_name=vice_leader_name,
operator_name=operator_name
)
logger.info(
"당무 변경: %s %s - 부팀장: %s, 운용: %s",
self.team, self.shift, vice_leader_name, operator_name
)
self.duty_changed.emit(vice_leader_name, operator_name)
self.accept()