diff --git a/app/src/doctor_workstation/ui/shell.py b/app/src/doctor_workstation/ui/shell.py index 4ec086680..de589122c 100644 --- a/app/src/doctor_workstation/ui/shell.py +++ b/app/src/doctor_workstation/ui/shell.py @@ -84,6 +84,13 @@ class NavigationItem: NAVIGATION = ( + NavigationItem( + "appointments", + "接诊台", + "号", + AppointmentsPage, + ("doctor.appointment/lists",), + ), NavigationItem( "reception", "接诊台", @@ -91,13 +98,6 @@ NAVIGATION = ( ReceptionPage, ("doctor.appointment/lists",), ), - NavigationItem( - "appointments", - "挂号列表", - "号", - AppointmentsPage, - ("doctor.appointment/lists",), - ), NavigationItem( "prescription_library", "处方库", @@ -114,7 +114,7 @@ NAVIGATION = ( ), NavigationItem( "patients", - "接诊台", + "我的患者", "患", PatientsPage, ("firstvisit.myPatient/lists",), @@ -301,9 +301,9 @@ def _resolve_navigation( continue if not _canonical_allowed(permissions, item.permissions[0]): continue - if item.key == "patients": - # The server menu can still carry the legacy label "我的患者". - # Keep the workstation's product-facing navigation title stable. + if item.key in {"appointments", "patients"}: + # Keep the two product-facing navigation titles stable even when + # the server still carries an older menu label. title = item.title else: title_value = first_value( @@ -312,6 +312,7 @@ def _resolve_navigation( title = str(title_value).strip() or item.title resolved.append((item, title)) seen.add(item.key) + resolved.sort(key=lambda entry: entry[0].key != "appointments") return resolved if demo_mode: return [ diff --git a/app/tests/test_patients_ui.py b/app/tests/test_patients_ui.py index 71f9bb7c5..a5397e01c 100644 --- a/app/tests/test_patients_ui.py +++ b/app/tests/test_patients_ui.py @@ -105,13 +105,13 @@ def test_shell_resolves_dynamic_menu_order_visibility_and_canonical_permissions( resolved = _resolve_navigation(menu, permissions, demo_mode=False) assert [(item.key, title) for item, title in resolved] == [ - ("patients", "接诊台"), + ("patients", "我的患者"), ("consultations", "问诊工作区"), ] assert _resolve_navigation([], permissions, demo_mode=False) == [] assert [item.key for item, _title in _resolve_navigation([], permissions, demo_mode=True)] == [ - "reception", "appointments", + "reception", "prescriptions", "patients", "consultations", diff --git a/app/tests/test_shell_contract.py b/app/tests/test_shell_contract.py index 8717f1a18..cb095155c 100644 --- a/app/tests/test_shell_contract.py +++ b/app/tests/test_shell_contract.py @@ -36,7 +36,7 @@ def application() -> QApplication: return QApplication.instance() or QApplication([]) -def test_patients_navigation_ignores_the_legacy_server_menu_title() -> None: +def test_patients_navigation_keeps_the_product_menu_title() -> None: resolved = shell_module._resolve_navigation( [ { @@ -49,7 +49,33 @@ def test_patients_navigation_ignores_the_legacy_server_menu_title() -> None: demo_mode=False, ) - assert [(item.key, title) for item, title in resolved] == [("patients", "接诊台")] + assert [(item.key, title) for item, title in resolved] == [("patients", "我的患者")] + + +def test_appointments_navigation_is_named_reception_and_always_first() -> None: + resolved = shell_module._resolve_navigation( + [ + { + "name": "我的患者", + "component": "first_visit/my_patients", + "perms": "firstvisit.myPatient/lists", + "sort": 99, + }, + { + "name": "挂号列表", + "component": "tcm/appointment/list", + "perms": "doctor.appointment/lists", + "sort": 1, + }, + ], + {"doctor.appointment/lists", "firstvisit.myPatient/lists"}, + demo_mode=False, + ) + + assert [(item.key, title) for item, title in resolved] == [ + ("appointments", "接诊台"), + ("patients", "我的患者"), + ] @pytest.fixture @@ -60,8 +86,8 @@ def shell_window( navigation = [ NavigationItem(key, title, glyph, _ShellPageDouble, (permission,)) for key, title, glyph, permission in ( + ("appointments", "接诊台", "号", "doctor.appointment/lists"), ("reception", "接诊台", "◎", "doctor.appointment/lists"), - ("appointments", "挂号列表", "号", "doctor.appointment/lists"), ( "prescription_library", "我的处方库", @@ -69,7 +95,7 @@ def shell_window( "tcm.prescriptionLibrary/lists", ), ("prescriptions", "已开处方", "笺", "tcm.prescription/lists"), - ("patients", "接诊台", "患", "firstvisit.myPatient/lists"), + ("patients", "我的患者", "患", "firstvisit.myPatient/lists"), ("consultations", "问诊列表", "询", "tcm.diagnosis/lists"), ) ] @@ -103,11 +129,11 @@ def test_shell_matches_reference_geometry_at_both_acceptance_sizes( shell_window.resize(width, height) application.processEvents() - assert shell_window.sidebar.width() == 199 + assert shell_window.sidebar.width() == 179 assert shell_window.topbar.height() == 62 assert shell_window.tabs_host.height() == 0 - assert shell_window.workspace.width() == width - 26 - 199 - assert shell_window.stack.width() == width - 26 - 199 + assert shell_window.workspace.width() == width - 26 - 179 + assert shell_window.stack.width() == width - 26 - 179 assert shell_window.stack.height() == height - 26 - 62 assert shell_window.stack.geometry().right() < shell_window.workspace.width() assert shell_window.stack.geometry().bottom() < shell_window.workspace.height() @@ -168,8 +194,8 @@ def test_every_visible_page_navigates_and_visited_tabs_track_active_page( assert shell_window.tab_bar.tabData(shell_window.tab_bar.currentIndex()) == key assert shell_window.visited_tab_keys() == ( - "reception", "appointments", + "reception", "prescription_library", "prescriptions", "patients", @@ -191,7 +217,7 @@ def test_non_fixed_tabs_close_and_active_close_renavigates( for key in ("patients", "consultations"): assert shell_window.navigate(key) - assert not shell_window.close_tab("reception") + assert not shell_window.close_tab("appointments") assert shell_window.close_tab("patients") assert "patients" not in shell_window.visited_tab_keys() assert ( @@ -201,14 +227,14 @@ def test_non_fixed_tabs_close_and_active_close_renavigates( assert shell_window.close_current_tab() assert ( - shell_window.tab_bar.tabData(shell_window.tab_bar.currentIndex()) == "reception" + shell_window.tab_bar.tabData(shell_window.tab_bar.currentIndex()) == "appointments" ) - assert shell_window.stack.currentWidget() is shell_window.pages["reception"] - assert shell_window.nav_buttons["reception"].isChecked() + assert shell_window.stack.currentWidget() is shell_window.pages["appointments"] + assert shell_window.nav_buttons["appointments"].isChecked() shell_window.close_all_tabs() - assert shell_window.visited_tab_keys() == ("reception",) - assert shell_window.stack.currentWidget() is shell_window.pages["reception"] + assert shell_window.visited_tab_keys() == ("appointments",) + assert shell_window.stack.currentWidget() is shell_window.pages["appointments"] def test_sidebar_collapse_preserves_active_navigation(