"""Doctor's patient list ("red zones", idea 2) and, with `?patient=`, the patient card.""" from __future__ import annotations from html import escape import streamlit as st from dashboard.components import helpers as h from dashboard.components import patient_card, state, ui NAV_ICON = ":material/groups:" COLOR_FILTERS = { "Все пациенты": None, "Срочно": "red", "Внимание": "yellow", "Нет ответа": "grey", "Без уведомлений": "green", } def _open(token: str) -> None: st.session_state["patient_list_state"] = { key: st.session_state[key] for key in ("status_filter", "patient_query", "patient_details") if key in st.session_state } st.query_params["patient"] = token def _close() -> None: st.query_params.pop("patient", None) st.session_state.update(st.session_state.pop("patient_list_state", {})) def _reset_filters() -> None: st.session_state["status_filter"] = "Все пациенты" st.session_state["patient_query"] = "" def render_card(token: str) -> None: st.button("Все пациенты", icon=":material/arrow_back:", type="tertiary", on_click=_close) card = state.call(lambda: state.client().patient_card(token)) if card is None: return patient_card.render(card, state.today()) def render_list() -> None: _, doctor_gen = state.doctor_names() today = state.today() patients = state.call(lambda: state.client().patients()) subtitle = "Всё важное о состоянии пациентов — в одном месте." if today: subtitle += f" · данные на {h.short_date(today)}" head, action = st.columns([4, 1.4], vertical_alignment="bottom") with head: st.html(ui.page_header("Пациенты под наблюдением", subtitle, kicker="Рабочее пространство")) with action: if st.button("Подключить пациента", icon=":material/person_add:", type="primary", width="stretch"): st.switch_page(state.CONNECT_PAGE) if patients is None: st.button("Повторить загрузку", icon=":material/refresh:") return items = h.sort_patients(patients) st.html(ui.kpi_tiles(h.kpis(items))) st.html( f'

Ваши пациенты {len(items)}

' "Сначала — пациенты с более высоким риском
" ) with st.container(key="patient-list"): f1, f2 = st.columns([3, 1.4], vertical_alignment="bottom") with f1: st.session_state.setdefault("status_filter", "Все пациенты") choice = st.segmented_control( "Статус", list(COLOR_FILTERS), key="status_filter", label_visibility="collapsed" ) with f2: query = st.text_input( "Поиск пациента", placeholder="Имя или препарат…", key="patient_query", label_visibility="collapsed" ) detailed = st.toggle( "Подробный список", key="patient_details", help="Назначение, последнее событие и факторы риска" ) shown = h.filter_patients(items, COLOR_FILTERS.get(choice or "Все пациенты"), query or "") if not items: st.html(ui.empty_state("Пациентов пока нет", "Подключите первого пациента кнопкой вверху страницы.")) elif not shown: st.html(ui.empty_state("Пациенты не найдены", "Измените имя, препарат или выбранный статус.")) st.button("Сбросить фильтры", on_click=_reset_filters) else: head_cols = st.columns([11, 1.4]) with head_cols[0]: st.html(ui.list_header()) for p in shown: with st.container(key=f"prow-{p.status_color}-{p.token}"): row, btn = st.columns([11, 1.4], vertical_alignment="center") with row: st.html(ui.patient_row(p, detailed=detailed)) with btn: st.button( "Открыть", key=f"open-{p.token}", on_click=_open, args=(p.token,), help=f"Открыть карточку: {p.display_name}", width="stretch", ) st.html( '" ) st.caption("Статус указан цветом и текстом. Риск прерывания терапии рассчитан по правилам; детали — в карточке.") token = st.query_params.get("patient") if token: render_card(token) else: render_list()