# -*- coding: utf-8 -*- """ 작업 섹션 모듈 전동차 관련 작업일정을 관리하는 섹션입니다. """ from datetime import date from typing import List, Optional, Any from PySide6.QtWidgets import QDialog from PySide6.QtCore import Qt, QPoint from ui.base.base_section import BaseSection, FieldConfig from ui.dialogs.input_dialog import SectionInputDialog from ui.widgets.clickableLabel import ClickableLabel from ui.components.popup_widget import PopupWidget from database.models import Work from core.logger import get_logger logger = get_logger(__name__) class WorkSection(BaseSection): """ 작업 섹션 전동차 관련 작업일정을 표시하고 관리합니다. 필드: - 작업일정, 작업주체, 대상편성, 대상기기, 작업내용, 특이사항, 팀확인, 완료 """ def __init__(self, parent=None): super().__init__(parent, "works", Work) # 필드 설정 self._setup_fields() # 초기화 후 처리 (설정 로드) self._post_init() # 팝업 추적용 self._current_popup: Optional[PopupWidget] = None self._current_team_popup: Optional[PopupWidget] = None # 초기 데이터 로드 self.load_data() logger.info("작업 섹션 초기화 완료") def _setup_fields(self): """필드 설정""" self.fields = [ FieldConfig("work_date", "작업일", width=80, field_type="date"), FieldConfig("work_entity", "작업주체", width=90), FieldConfig("target_train", "대상편성", width=70), FieldConfig("target_device", "대상기기", width=90), FieldConfig("work_content", "작업내용", width=280), FieldConfig("remarks", "특이사항", width=180), FieldConfig("team_confirmations", "확인팀", width=110), FieldConfig("is_completed", "완료", width=40, field_type="checkbox"), ] def _fetch_data(self, **filters) -> List[Work]: """데이터 조회""" return self.crud.get_all_works() def on_add_clicked(self): """추가 버튼 클릭""" dialog = WorkInputDialog(self) if dialog.exec() == QDialog.Accepted: data = dialog.get_data() self.crud.create_work(**data) self.refresh_data() def on_edit_clicked(self, record_id: int): """편집 버튼 클릭""" record = self.crud.get_work(record_id) if record: dialog = WorkInputDialog(self, record) if dialog.exec() == QDialog.Accepted: data = dialog.get_data() self.crud.update_work(record_id, **data) self.refresh_data() def _delete_record(self, record_id: int): """레코드 삭제""" self.crud.delete_work(record_id) self.refresh_data() def on_search_changed(self, text: str): """검색어 변경""" if text: results = self.crud._search( "works", Work, ["work_entity", "target_train", "work_content", "remarks"], text ) self.current_records = results self._update_table() else: self.load_data() def _update_team_confirmations(self, record_id: int, confirmations: dict): """팀확인 상태 업데이트""" import json self.crud.update_work(record_id, team_confirmations=json.dumps(confirmations, ensure_ascii=False)) self.signals.data_changed.emit(self.table_name) def _mark_as_completed(self, record_id: int): """레코드를 완료로 표시""" from datetime import datetime self.crud.update_work(record_id, is_completed=True, completed_at=datetime.now()) self.signals.data_changed.emit(self.table_name) def _on_double_clicked(self, item): """더블클릭 이벤트 오버라이드""" row = item.row() col = item.column() # 위젯인 경우 (ClickableLabel 등) widget = self.table.cellWidget(row, col) if widget: record_id = widget.property("record_id") if not record_id: # 첫 번째 셀에서 레코드 ID 가져오기 first_item = self.table.item(row, 0) if first_item: record_id = first_item.data(Qt.UserRole) if record_id: visible_fields = [f for f in self.fields if f.visible] if col < len(visible_fields): field = visible_fields[col] record = self.crud.get_work(record_id) if record: self._edit_field_inline(row, col, field, record) return # 일반 아이템인 경우 부모 클래스 처리 super()._on_double_clicked(item) def _edit_field_inline(self, row: int, col: int, field: FieldConfig, record: Work): """인라인 필드 편집""" if field.name == "work_date": self._edit_work_date(row, col, record) elif field.name == "work_entity": self._edit_work_entity(row, col, record) elif field.name == "target_train": self._edit_target_train(row, col, record) elif field.name == "target_device": self._edit_target_device(row, col, record) elif field.name == "work_content": self._edit_work_content(row, col, record) elif field.name == "remarks": self._edit_remarks(row, col, record) elif field.name == "team_confirmations": self._edit_team_confirmations(row, col, record) else: # 기본 편집 모드 self._enable_cell_editing(row, col, field) def _edit_work_date(self, row: int, col: int, record: Work): """작업일 편집 (캘린더 팝업)""" from ui.components.custom_calendar import CustomCalendar from PySide6.QtWidgets import QDialog, QVBoxLayout, QDialogButtonBox from PySide6.QtCore import QDate dialog = QDialog(self) dialog.setWindowTitle("작업일 선택") dialog.setModal(True) layout = QVBoxLayout(dialog) # 캘린더 위젯 생성 calendar = CustomCalendar(show_range_toggle=False, show_time=False) if record.work_date: qdate = QDate.fromString(record.work_date.isoformat(), Qt.ISODate) calendar.calendar.setSelectedDate(qdate) layout.addWidget(calendar) buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttons.accepted.connect(dialog.accept) buttons.rejected.connect(dialog.reject) layout.addWidget(buttons) if dialog.exec() == QDialog.Accepted: selected_date = calendar.get_selected_date() if selected_date: self.crud.update_work(record.id, work_date=selected_date) self.refresh_data() def _edit_work_entity(self, row: int, col: int, record: Work): """작업주체 편집""" from ui.components.custom_input import CustomLineEdit from PySide6.QtWidgets import QDialog, QVBoxLayout, QDialogButtonBox dialog = QDialog(self) dialog.setWindowTitle("작업주체 입력") dialog.setModal(True) layout = QVBoxLayout(dialog) input_field = CustomLineEdit(placeholder="작업주체") if record.work_entity: input_field.setText(record.work_entity) layout.addWidget(input_field) buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttons.accepted.connect(dialog.accept) buttons.rejected.connect(dialog.reject) layout.addWidget(buttons) if dialog.exec() == QDialog.Accepted: work_entity = input_field.text() self.crud.update_work(record.id, work_entity=work_entity) self.refresh_data() def _edit_target_train(self, row: int, col: int, record: Work): """대상편성 편집""" from ui.components.custom_input import CustomLineEdit from PySide6.QtWidgets import QDialog, QVBoxLayout, QDialogButtonBox dialog = QDialog(self) dialog.setWindowTitle("대상편성 입력") dialog.setModal(True) layout = QVBoxLayout(dialog) input_field = CustomLineEdit(placeholder="대상편성") if record.target_train: input_field.setText(record.target_train) layout.addWidget(input_field) buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttons.accepted.connect(dialog.accept) buttons.rejected.connect(dialog.reject) layout.addWidget(buttons) if dialog.exec() == QDialog.Accepted: target_train = input_field.text() self.crud.update_work(record.id, target_train=target_train) self.refresh_data() def _edit_target_device(self, row: int, col: int, record: Work): """대상기기 편집""" from ui.components.custom_input import CustomLineEdit from PySide6.QtWidgets import QDialog, QVBoxLayout, QDialogButtonBox dialog = QDialog(self) dialog.setWindowTitle("대상기기 입력") dialog.setModal(True) layout = QVBoxLayout(dialog) input_field = CustomLineEdit(placeholder="대상기기") if record.target_device: input_field.setText(record.target_device) layout.addWidget(input_field) buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttons.accepted.connect(dialog.accept) buttons.rejected.connect(dialog.reject) layout.addWidget(buttons) if dialog.exec() == QDialog.Accepted: target_device = input_field.text() self.crud.update_work(record.id, target_device=target_device) self.refresh_data() def _edit_work_content(self, row: int, col: int, record: Work): """작업내용 편집""" from ui.components.custom_input import CustomTextEdit, LabeledInput from PySide6.QtWidgets import QDialog, QVBoxLayout, QDialogButtonBox dialog = QDialog(self) dialog.setWindowTitle("작업내용 편집") dialog.setModal(True) layout = QVBoxLayout(dialog) text_input = CustomTextEdit(placeholder="작업 내용을 입력하세요", min_height=150) text_input.set_text(record.work_content or "") layout.addWidget(LabeledInput("작업내용", text_input, required=True)) buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttons.accepted.connect(dialog.accept) buttons.rejected.connect(dialog.reject) layout.addWidget(buttons) if dialog.exec() == QDialog.Accepted: new_content = text_input.get_text() self.crud.update_work(record.id, work_content=new_content) self.refresh_data() def _edit_remarks(self, row: int, col: int, record: Work): """특이사항 편집""" from ui.components.custom_input import CustomTextEdit, LabeledInput from PySide6.QtWidgets import QDialog, QVBoxLayout, QDialogButtonBox dialog = QDialog(self) dialog.setWindowTitle("특이사항 편집") dialog.setModal(True) layout = QVBoxLayout(dialog) text_input = CustomTextEdit(placeholder="특이사항을 입력하세요", min_height=100) text_input.set_text(record.remarks or "") layout.addWidget(LabeledInput("특이사항", text_input)) buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttons.accepted.connect(dialog.accept) buttons.rejected.connect(dialog.reject) layout.addWidget(buttons) if dialog.exec() == QDialog.Accepted: new_remarks = text_input.get_text() self.crud.update_work(record.id, remarks=new_remarks) self.refresh_data() def _edit_team_confirmations(self, row: int, col: int, record: Work): """확인팀 편집 (다중선택)""" widget = self.table.cellWidget(row, col) if widget: label = widget.findChild(ClickableLabel) if label: self._show_team_confirmations_popup(record, label) def _update_table(self): """테이블 업데이트 (오버라이드)""" self.table.setRowCount(0) # 표시할 필드만 필터링 visible_fields = [f for f in self.fields if f.visible] # 컬럼 설정 self.table.setColumnCount(len(visible_fields)) self.table.setHorizontalHeaderLabels([f.label for f in visible_fields]) # 컬럼 너비 설정 for i, field in enumerate(visible_fields): self.table.setColumnWidth(i, field.width) # 데이터 채우기 (완료된 레코드는 제외) for record in self.current_records: # 완료된 레코드는 섹션에서 숨김 (DB에는 유지) if hasattr(record, 'is_completed') and record.is_completed: continue row = self.table.rowCount() self.table.insertRow(row) max_height = int(40 * 1.15) # 기본 높이 15% 증가 (46px) for col, field in enumerate(visible_fields): value = getattr(record, field.name, "") # 완료 필드는 버튼 위젯으로 표시 if field.name == "is_completed": self._set_completion_button(row, col, record) # 확인팀은 ClickableLabel로 표시 elif field.name == "team_confirmations": self._set_team_label(row, col, field, value, record) # 작업일, 작업주체, 대상편성, 대상기기는 ClickableLabel로 표시 elif field.name in ["work_date", "work_entity", "target_train", "target_device"]: self._set_clickable_label(row, col, field, value, record) # 작업내용, 특이사항은 줄바꿈이 가능한 위젯으로 표시 elif field.name in ["work_content", "remarks"]: content_height = self._set_content_label(row, col, field, value, record) if content_height: max_height = max(max_height, content_height) else: item = self._create_table_item(field, value, record) self.table.setItem(row, col, item) # 행 높이 설정 self.table.setRowHeight(row, max_height) # 레코드 ID 저장 (첫 번째 셀에) first_item = self.table.item(row, 0) if first_item: first_item.setData(Qt.UserRole, record.id) else: # 첫 번째 셀이 위젯인 경우 widget = self.table.cellWidget(row, 0) if widget: widget.setProperty("record_id", record.id) def _set_clickable_label(self, row: int, col: int, field: FieldConfig, value: Any, record: Work): """ClickableLabel 설정""" from PySide6.QtWidgets import QWidget, QHBoxLayout display_value = self._format_value(field, value) if value else "" # ClickableLabel 생성 label = ClickableLabel(display_value or "미지정", enable_hover=True) label.setAlignment(Qt.AlignCenter) label.setWordWrap(True) # 통일된 색상 적용 theme = self.config.theme unified_color = "#64748b" if theme == 'dark': label.setStyleSheet(f""" QLabel {{ background-color: {unified_color}; color: #ffffff; border: 1px solid rgba(255,255,255,0.2); border-radius: 0px; padding: 0px; margin: 0px; font-weight: 600; font-size: 12px; }} QLabel:hover {{ background-color: {unified_color}; border-color: rgba(255,255,255,0.4); }} """) else: label.setStyleSheet(f""" QLabel {{ background-color: {unified_color}; color: #ffffff; border: 1px solid rgba(0,0,0,0.1); border-radius: 0px; padding: 0px; margin: 0px; font-weight: 600; font-size: 12px; }} QLabel:hover {{ background-color: {unified_color}; border-color: rgba(0,0,0,0.2); }} """) # 더블클릭 시 편집 def on_double_clicked(): self._edit_field_inline(row, col, field, record) label.double_clicked.connect(on_double_clicked) # 레코드 정보 저장 label.setProperty("record_id", record.id) label.setProperty("field_name", field.name) label.setProperty("field_value", value or "") # 컨테이너 위젯으로 감싸서 구분선 적용 container = QWidget() container_layout = QHBoxLayout(container) container_layout.setContentsMargins(0, 0, 0, 0) container_layout.setSpacing(0) container_layout.addWidget(label) # 구분선 스타일 적용 gridline_color = "#475569" if theme == 'dark' else "#cbd5e1" container.setStyleSheet(f"border-right: 1px solid {gridline_color};") # 셀에 위젯 설정 self.table.setCellWidget(row, col, container) def _set_team_label(self, row: int, col: int, field: FieldConfig, value: Any, record: Work): """확인팀 라벨 설정 (공간 효율 최대화)""" from PySide6.QtWidgets import QWidget, QHBoxLayout import json theme = self.config.theme unified_color = "#64748b" # 확인팀: 확인된 팀 숫자만 표시 (예: "1 2 4") try: confirmations = json.loads(value) if isinstance(value, str) else value if isinstance(confirmations, dict): # 팀 이름에서 숫자만 추출하여 정렬 confirmed_nums = sorted([ team.replace("팀", "") for team, confirmed in confirmations.items() if confirmed ]) display_value = " ".join(confirmed_nums) if confirmed_nums else "-" else: display_value = "-" except Exception: display_value = "-" # ClickableLabel 생성 label = ClickableLabel(display_value, enable_hover=False) label.setAlignment(Qt.AlignCenter) # 통일된 스타일 적용 if theme == 'dark': label.setStyleSheet(f""" QLabel {{ background-color: {unified_color}; color: #ffffff; border: 1px solid rgba(255,255,255,0.2); border-radius: 0px; padding: 0px; margin: 0px; font-weight: 600; font-size: 12px; }} QLabel:hover {{ background-color: {unified_color}; border-color: rgba(255,255,255,0.4); }} """) else: label.setStyleSheet(f""" QLabel {{ background-color: {unified_color}; color: #ffffff; border: 1px solid rgba(0,0,0,0.1); border-radius: 0px; padding: 0px; margin: 0px; font-weight: 600; font-size: 12px; }} QLabel:hover {{ background-color: {unified_color}; border-color: rgba(0,0,0,0.2); }} """) # 클릭/더블클릭 이벤트 연결 def on_clicked(): self._show_team_confirmations_popup(record, label) def on_double_clicked(): self._edit_field_inline(row, col, field, record) label.clicked.connect(on_clicked) label.double_clicked.connect(on_double_clicked) # 레코드 정보 저장 label.setProperty("record_id", record.id) label.setProperty("field_name", field.name) # 컨테이너 위젯으로 감싸기 container = QWidget() container_layout = QHBoxLayout(container) container_layout.setContentsMargins(0, 0, 0, 0) container_layout.setSpacing(0) container_layout.addWidget(label) # 구분선 스타일 적용 gridline_color = "#475569" if theme == 'dark' else "#cbd5e1" container.setStyleSheet(f"border-right: 1px solid {gridline_color};") # 셀에 위젯 설정 self.table.setCellWidget(row, col, container) def _set_content_label(self, row: int, col: int, field: FieldConfig, value: Any, record: Work) -> int: """작업내용/특이사항 라벨 설정 (줄바꿈 지원) Returns: 계산된 셀 높이 (픽셀) """ from PySide6.QtWidgets import QWidget, QVBoxLayout display_value = self._format_value(field, value) if value else "" # ClickableLabel 생성 (줄바꿈 지원) label = ClickableLabel(display_value or "", enable_hover=False, enable_double_click=True, enable_right_click=True) label.setWordWrap(True) label.setAlignment(Qt.AlignLeft | Qt.AlignTop) label.setTextInteractionFlags(Qt.TextSelectableByMouse) # 레코드 정보 저장 label.setProperty("record_id", record.id) label.setProperty("field_name", field.name) label.setProperty("field_value", value or "") # 더블클릭 시 편집 def on_double_clicked(): self._edit_field_inline(row, col, field, record) label.double_clicked.connect(on_double_clicked) # 우클릭 컨텍스트 메뉴 def on_right_clicked(pos): from PySide6.QtWidgets import QMenu menu = QMenu(self) edit_action = menu.addAction("편집") edit_action.triggered.connect(lambda: self._edit_field_inline(row, col, field, record)) menu.exec_(label.mapToGlobal(pos)) label.right_clicked.connect(on_right_clicked) # 컨테이너 위젯으로 감싸기 container = QWidget() container_layout = QVBoxLayout(container) container_layout.setContentsMargins(8, 4, 8, 4) container_layout.setSpacing(0) container_layout.addWidget(label) # 구분선 및 텍스트 색상 스타일 적용 theme = self.config.theme gridline_color = "#475569" if theme == 'dark' else "#cbd5e1" text_color = "#f8fafc" if theme == 'dark' else "#1e293b" # 높이 계산 font_metrics = self.table.fontMetrics() base_font_size = 13 col_width = self.table.columnWidth(col) needs_wrap = False calculated_height = int(40 * 1.15) if display_value and col_width > 0: available_width = col_width - 16 text_width = font_metrics.horizontalAdvance(display_value) if text_width > available_width: needs_wrap = True wrap_font_size = base_font_size - 2 from PySide6.QtGui import QFont, QFontMetrics small_font = QFont(self.table.font()) small_font.setPointSize(wrap_font_size) small_font_metrics = QFontMetrics(small_font) chars_per_line = max(1, available_width // small_font_metrics.averageCharWidth()) lines = max(1, (len(display_value) // chars_per_line) + 1) line_height = small_font_metrics.height() + 6 calculated_height = max(int(40 * 1.15), lines * line_height + 8) else: calculated_height = int(40 * 1.15) # 라벨에 스타일 적용 if needs_wrap: wrap_font_size = base_font_size - 2 label.setStyleSheet(f""" QLabel {{ color: {text_color}; background-color: transparent; font-size: {wrap_font_size}px; }} """) else: label.setStyleSheet(f""" QLabel {{ color: {text_color}; background-color: transparent; }} """) container.setStyleSheet(f"border-right: 1px solid {gridline_color};") # 셀에 위젯 설정 self.table.setCellWidget(row, col, container) return calculated_height def _show_team_confirmations_popup(self, record: Work, label: ClickableLabel): """확인팀 선택 팝업 표시 (다중선택)""" from ui.components.chips.choice_chip_button import ChoiceChipButton from ui.components.popup_widget import PopupWidget from core.constants import TEAMS from PySide6.QtWidgets import QHBoxLayout, QWidget import json # 기존 팝업이 있으면 닫기 if self._current_team_popup: self._current_team_popup.hide_popup() self._current_team_popup = None # 현재 확인된 팀 찾기 current_confirmations = {} try: confirmations = json.loads(record.team_confirmations) if isinstance(record.team_confirmations, str) else record.team_confirmations if isinstance(confirmations, dict): current_confirmations = confirmations except Exception: pass # 팝업 생성 popup = PopupWidget(self, title="확인팀 선택", width=320, auto_hide=False) self._current_team_popup = popup # 칩 그룹 생성 (다중선택용) chip_group = {} chip_container = QWidget() chip_layout = QHBoxLayout(chip_container) chip_layout.setContentsMargins(0, 0, 0, 0) chip_layout.setSpacing(8) def update_confirmations(): """확인 상태 업데이트""" confirmations = {team: chip.isChecked() for team, chip in chip_group.items()} self._update_team_confirmations(record.id, confirmations) self.refresh_data() for team in TEAMS: is_checked = current_confirmations.get(team, False) chip_bg = "#64748b" if is_checked else "#00bfa5" chip = ChoiceChipButton( text=team, key=team, bg=chip_bg ) chip_group[team] = chip chip_layout.addWidget(chip) if is_checked: chip.setChecked(True) def make_toggle_handler(team_key: str): def handler(_key: str, checked: bool): chip = chip_group[team_key] if checked: chip.set_bg("#64748b") else: chip.set_bg("#00bfa5") update_confirmations() return handler chip.toggled_key.connect(make_toggle_handler(team)) chip_layout.addStretch() popup.content_layout.addWidget(chip_container) # 팝업 크기 자동 조정 chip_container.adjustSize() chip_width = chip_container.sizeHint().width() popup_width = max(200, min(400, chip_width + 40)) popup.container.setFixedWidth(popup_width) # 팝업이 마우스 밖으로 나가면 닫기 original_leave_event = popup.leaveEvent def on_popup_leave(event): if self._current_team_popup == popup: popup.hide_popup() self._current_team_popup = None original_leave_event(event) popup.leaveEvent = on_popup_leave # 마우스 추적 활성화 popup.setMouseTracking(True) popup.container.setMouseTracking(True) # 라벨 위치 기준으로 팝업 위치 계산 label_pos = label.mapToGlobal(QPoint(0, 0)) popup_pos = QPoint(label_pos.x(), label_pos.y() + label.height() + 5) popup.show_at(popup_pos) class WorkInputDialog(SectionInputDialog): """작업 입력 다이얼로그""" def __init__(self, parent=None, record: Work = None): super().__init__( parent, title="작업 추가" if record is None else "작업 편집", record=record, width=450, height=700 ) self._setup_work_fields() if record: self._load_record(record) def _setup_work_fields(self): """작업 필드 설정""" from ui.components.custom_input import CustomLineEdit, CustomTextEdit, LabeledInput from PySide6.QtWidgets import QDateEdit, QHBoxLayout, QWidget from PySide6.QtCore import QDate # 작업일정 self.date_input = QDateEdit() self.date_input.setDate(QDate.currentDate()) self.date_input.setCalendarPopup(True) self.content_layout.addWidget(LabeledInput("작업일정", self.date_input)) # 작업주체 + 대상편성 (가로 배치) entity_widget = QWidget() entity_layout = QHBoxLayout(entity_widget) entity_layout.setContentsMargins(0, 0, 0, 0) entity_layout.setSpacing(12) self.entity_input = CustomLineEdit(placeholder="작업주체") entity_layout.addWidget(LabeledInput("작업주체", self.entity_input)) self.train_input = CustomLineEdit(placeholder="대상편성") entity_layout.addWidget(LabeledInput("대상편성", self.train_input)) self.content_layout.addWidget(entity_widget) # 대상기기 self.device_input = CustomLineEdit(placeholder="대상기기") self.content_layout.addWidget(LabeledInput("대상기기", self.device_input)) # 작업내용 self.work_content_input = CustomTextEdit(placeholder="작업 내용을 입력하세요", min_height=80) self.content_layout.addWidget(LabeledInput("작업내용", self.work_content_input, required=True)) # 특이사항 self.remarks_input = CustomTextEdit(placeholder="특이사항을 입력하세요", min_height=60) self.content_layout.addWidget(LabeledInput("특이사항", self.remarks_input)) def _load_record(self, record: Work): """레코드 데이터 로드""" from PySide6.QtCore import QDate if record.work_date: if isinstance(record.work_date, date): self.date_input.setDate(QDate( record.work_date.year, record.work_date.month, record.work_date.day )) self.entity_input.setText(record.work_entity or "") self.train_input.setText(record.target_train or "") self.device_input.setText(record.target_device or "") self.work_content_input.set_text(record.work_content or "") self.remarks_input.set_text(record.remarks or "") def get_data(self) -> dict: """입력 데이터 반환""" qdate = self.date_input.date() work_date = date(qdate.year(), qdate.month(), qdate.day()) return { "created_date": date.today().isoformat(), "created_team": self.config.current_team, "work_date": work_date.isoformat(), "work_entity": self.entity_input.text(), "target_train": self.train_input.text(), "target_device": self.device_input.text(), "work_content": self.work_content_input.get_text(), "remarks": self.remarks_input.get_text(), }