Add Dispatch_V0.1.1
This commit is contained in:
153
Dispatch_V0.1.1/ui/pages/document_browser_page.py
Normal file
153
Dispatch_V0.1.1/ui/pages/document_browser_page.py
Normal file
@@ -0,0 +1,153 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# hub/ticket/ui/pages/document_browser_page.py
|
||||
|
||||
"""Общая страница просмотра документов Ticket."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from gui.components import Button, Label, TextInput
|
||||
from gui.containers import HContainer, SContainer, VContainer
|
||||
|
||||
from application import TaskApplicationService
|
||||
from domain import TicketDocumentSnapshot
|
||||
from ui.ticket_selection_list import TicketSelectionEntry, TicketSelectionList
|
||||
from .report_viewer import ReportViewer
|
||||
|
||||
|
||||
class DocumentBrowserPage(SContainer):
|
||||
"""Базовая страница списка документов и предпросмотра."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
application: TaskApplicationService,
|
||||
title: str,
|
||||
empty_message: str,
|
||||
document_type: str,
|
||||
parent=None,
|
||||
):
|
||||
super().__init__(width_percent=100, height_percent=100, parent=parent)
|
||||
self._application = application
|
||||
self._title = title
|
||||
self._empty_message = empty_message
|
||||
self._document_type = document_type
|
||||
self._documents: dict[str, TicketDocumentSnapshot] = {}
|
||||
self._list_widget: TicketSelectionList | None = None
|
||||
self._preview: TextInput | None = None
|
||||
self._open_button: Button | None = None
|
||||
self._setup_ui()
|
||||
self._connect_signals()
|
||||
self._reload_documents()
|
||||
|
||||
def _setup_ui(self) -> None:
|
||||
# Root-контейнер страницы документов: заголовок плюс двухпанельная область.
|
||||
main_container = VContainer(margin=12, spacing=10, parent=self)
|
||||
title_label = Label(self._title, alignment="left", style="TICKET_LIST_HEADER")
|
||||
# Content-row документов: раскладывает список документов и их предпросмотр.
|
||||
content_row = HContainer(spacing=10, parent=main_container)
|
||||
|
||||
# Левая панель списка документов
|
||||
list_panel = SContainer(style="TICKET_LIST_CONTAINER")
|
||||
# List-layout: внутренний контейнер заголовка и списка документов.
|
||||
list_layout = VContainer(margin=12, spacing=8, parent=list_panel)
|
||||
list_title_label = Label("Список документов",
|
||||
margin=[0, 0, 0, 8],
|
||||
alignment="left",
|
||||
style="TICKET_LIST_TITLE")
|
||||
|
||||
self._list_widget = TicketSelectionList()
|
||||
list_layout.add_widget(list_title_label)
|
||||
list_layout.add_widget(self._list_widget)
|
||||
|
||||
# Правая панель предпросмотра
|
||||
preview_panel = SContainer(style="TICKET_LIST_CONTAINER")
|
||||
# Preview-layout: внутренний контейнер заголовка, preview-поля и кнопки открытия.
|
||||
preview_layout = VContainer(margin=12, spacing=8, parent=preview_panel)
|
||||
preview_title_label = Label("Предпросмотр", alignment="left", style="TICKET_LIST_TITLE")
|
||||
self._preview = TextInput(style="TICKET_PREVIEW_AREA", multiline=True)
|
||||
self._preview.set_read_only(True)
|
||||
self._open_button = Button("Открыть документ", style="FILTER_BUTTON", content_fit=True)
|
||||
self._open_button.set_enabled(False)
|
||||
preview_layout.add_widget(preview_title_label)
|
||||
preview_layout.add_widget(self._preview)
|
||||
preview_layout.add_widget(self._open_button)
|
||||
|
||||
content_row.add_widget_with_stretch(list_panel, 4)
|
||||
content_row.add_widget_with_stretch(preview_panel, 7)
|
||||
main_container.add_widget(title_label)
|
||||
main_container.add_widget(content_row)
|
||||
|
||||
def _connect_signals(self) -> None:
|
||||
# Application-состояние
|
||||
self._application.task_updated.connect(self._reload_documents)
|
||||
self._application.state_loaded.connect(self._reload_documents)
|
||||
|
||||
# UI-события страницы
|
||||
if self._list_widget is not None:
|
||||
self._list_widget.selection_changed.connect(self._update_preview)
|
||||
self._list_widget.item_activated.connect(self._open_current_document)
|
||||
if self._open_button is not None:
|
||||
self._open_button.clicked.connect(self._open_current_document)
|
||||
|
||||
def _reload_documents(self, *_args) -> None:
|
||||
if self._list_widget is None or self._preview is None:
|
||||
return
|
||||
current_document_id = self._current_document_id()
|
||||
self._documents = {
|
||||
document.document_id: document
|
||||
for document in self._application.list_documents(self._document_type)
|
||||
}
|
||||
entries = [
|
||||
TicketSelectionEntry(
|
||||
entry_id=document.document_id,
|
||||
title=document.title,
|
||||
subtitle=document.created_at.strftime("%d.%m.%Y %H:%M"),
|
||||
)
|
||||
for document in self._documents.values()
|
||||
]
|
||||
self._list_widget.set_entries(entries)
|
||||
if not self._documents:
|
||||
self._preview.set_text(self._empty_message)
|
||||
if self._open_button is not None:
|
||||
self._open_button.set_enabled(False)
|
||||
return
|
||||
self._restore_selection(current_document_id)
|
||||
self._update_preview()
|
||||
|
||||
def _restore_selection(self, document_id: str | None) -> None:
|
||||
if self._list_widget is None:
|
||||
return
|
||||
self._list_widget.set_current_entry(document_id)
|
||||
|
||||
def _update_preview(self, *_args) -> None:
|
||||
if self._preview is None:
|
||||
return
|
||||
document = self._current_document()
|
||||
if document is None:
|
||||
self._preview.set_text(self._empty_message)
|
||||
if self._open_button is not None:
|
||||
self._open_button.set_enabled(False)
|
||||
return
|
||||
self._preview.set_text(document.content or document.summary or document.title)
|
||||
if self._open_button is not None:
|
||||
self._open_button.set_enabled(True)
|
||||
|
||||
def _current_document(self) -> TicketDocumentSnapshot | None:
|
||||
document_id = self._current_document_id()
|
||||
if document_id is None:
|
||||
return None
|
||||
return self._documents.get(document_id)
|
||||
|
||||
def _current_document_id(self) -> str | None:
|
||||
if self._list_widget is None:
|
||||
return None
|
||||
entry_id = self._list_widget.current_entry_id()
|
||||
return str(entry_id) if entry_id is not None else None
|
||||
|
||||
def _open_current_document(self, *_args) -> None:
|
||||
document = self._current_document()
|
||||
if document is not None:
|
||||
ReportViewer(document, parent=self).exec()
|
||||
|
||||
def showEvent(self, event) -> None:
|
||||
super().showEvent(event)
|
||||
self._reload_documents()
|
||||
Reference in New Issue
Block a user