This commit is contained in:
Your Name
2026-08-20 17:56:08 +08:00
parent 5794f60c5d
commit cc6173e5b0
393 changed files with 1320 additions and 1041 deletions
@@ -2696,11 +2696,15 @@ class DemoDoctorRepository:
) -> dict[str, Any]:
"""Return the demo archive in the server response envelope shape."""
with self._lock:
consultation = self._find_consultation(diagnosis_id)
return deepcopy(
{
"lists": self._im_messages.get(diagnosis_id, []),
with self._lock:
consultation = self._find_consultation(diagnosis_id)
rows = [
{**row, "diagnosis_id": diagnosis_id}
for row in self._im_messages.get(diagnosis_id, [])
]
return deepcopy(
{
"lists": rows,
"patient_im_id": f"patient_{consultation.patient_id}",
"patient_name": consultation.patient_name,
"doctor_accounts_queried": [] if only_archived else ["doctor_1001"],
@@ -2192,7 +2192,9 @@ class AiConsultDialog(QDialog):
"messages", {"value": None, "error": "未返回资料。"}
)
message_rows, rejected_messages = _owned_rows(
message_section.get("value"), self.diagnosis_id
message_section.get("value"),
self.diagnosis_id,
require_owner=True,
)
message_section["value"] = message_rows
if rejected_messages:
@@ -1575,9 +1575,17 @@ class AppointmentsPage(QWidget):
)
present_diagnosis_ai_report(self.repository, self.permissions, self, payload)
def _open_ai_consult(self) -> None:
def open_selected_ai_consult(self) -> bool:
"""Open the diagnosis-scoped assistant for the selected appointment."""
row = self._current_row()
diagnosis_id = _diagnosis_id(row)
if (
row is None
or diagnosis_id <= 0
or not can_open_ai_consult(self.permissions)
):
return False
present_ai_consult(
self.repository,
self.permissions,
@@ -1587,6 +1595,11 @@ class AppointmentsPage(QWidget):
seed=row,
source_title="问诊列表",
)
return True
def _open_ai_consult(self) -> None:
if not self.open_selected_ai_consult():
show_toast(self, "请先选择一条有关联诊单的问诊记录。", "warning")
def _request_video(self) -> None:
if not _canonical_allowed(
@@ -2977,9 +2977,17 @@ class ConsultationsPage(QWidget):
return
self._diagnosis_dialog.open_view_only(diagnosis_id, seed=record)
def _open_ai_consult(self) -> None:
def open_selected_ai_consult(self) -> bool:
"""Open the assistant with the selected diagnosis as its authority key."""
record = self.table.current_data()
diagnosis_id = _as_int(first_value(record, "diagnosis_id", "id", default=0))
if (
record is None
or diagnosis_id <= 0
or not can_open_ai_consult(self.permissions)
):
return False
present_ai_consult(
self.repository,
self.permissions,
@@ -2989,8 +2997,13 @@ class ConsultationsPage(QWidget):
first_value(record, "source_patient_id", "patient_id", default=0)
),
seed=record,
source_title="患者列表",
source_title="问诊列表",
)
return True
def _open_ai_consult(self) -> None:
if not self.open_selected_ai_consult():
show_toast(self, "请先选择一条有效诊单。", "warning")
def _open_edit(self) -> None:
if not _canonical_allowed(self.permissions, "tcm.diagnosis/edit"):
@@ -2740,6 +2740,24 @@ class PatientsPage(QWidget):
source_title="我的患者",
)
def open_selected_ai_consult(self) -> bool:
"""Open AI chat for the selected row in the active patient workspace."""
if not can_open_ai_consult(self.permissions):
return False
workspace = self.tabs.currentWidget()
row = None
for table_name in ("table", "queue_table"):
table = getattr(workspace, table_name, None)
current_data = getattr(table, "current_data", None)
if callable(current_data):
row = current_data()
break
if row is None or self._diagnosis_id(row) <= 0:
return False
self._open_ai_consult(row)
return True
def _open_order_diagnosis(self, row: Any) -> None:
editable = _canonical_allowed(self.permissions, "tcm.diagnosis/edit")
readable = _canonical_allowed(self.permissions, "tcm.diagnosis/readonlyDetail")
@@ -8647,17 +8647,14 @@ class ReceptionPage(QWidget):
task=diagnosis_ai_task(prompt),
)
def _open_ai_consult(self) -> None:
if not self._can_ai_assistant:
show_toast(self, "当前账号没有使用 AI 问诊助手的权限。", "danger")
return
if self._detail_loading:
show_toast(self, "患者病历仍在加载,请稍候。", "warning")
return
def open_selected_ai_consult(self) -> bool:
"""Open AI chat only when the reception selection has a diagnosis."""
if not self._can_ai_assistant or self._detail_loading:
return False
context = self._selection_context()
if context is None or context[2] is None:
show_toast(self, "当前患者缺少诊单编号。", "danger")
return
return False
seed = self._selected_detail or self._selected_record or {}
present_ai_consult(
self.repository,
@@ -8668,6 +8665,17 @@ class ReceptionPage(QWidget):
seed=seed,
source_title="接诊台",
)
return True
def _open_ai_consult(self) -> None:
if self.open_selected_ai_consult():
return
if not self._can_ai_assistant:
show_toast(self, "当前账号没有使用 AI 问诊助手的权限。", "danger")
elif self._detail_loading:
show_toast(self, "患者病历仍在加载,请稍候。", "warning")
else:
show_toast(self, "请先选择一位有诊单的患者。", "warning")
def _open_ai_report(
self,
+33 -4
View File
@@ -40,6 +40,7 @@ from PySide6.QtWidgets import (
QWidget,
)
from .dialogs.ai_consult import can_open_ai_consult
from .dialogs.local_audio_queue import LocalAudioQueueDialog
from .pages import (
AppointmentsPage,
@@ -872,6 +873,7 @@ class ShellWindow(QMainWindow):
if session_permissions is not None
else get_value(self.current_user, "permissions", None)
)
self._can_ai_assistant = can_open_ai_consult(self.permissions)
session_menu = get_value(self.session, "menu", None)
self.menu = (
session_menu if session_menu is not None else get_value(session, "menu", [])
@@ -1116,6 +1118,7 @@ class ShellWindow(QMainWindow):
outer_assistant.setContentsMargins(13, 0, 13, 0)
outer_assistant.addWidget(self.assistant_card)
layout.addLayout(outer_assistant)
self.assistant_card.setVisible(self._can_ai_assistant)
self.upload_settings_button = QPushButton("设置 ›", sidebar)
self.upload_settings_button.setObjectName("ShellSettingsButton")
@@ -1288,6 +1291,7 @@ class ShellWindow(QMainWindow):
self.ai_top_button.setAccessibleName("AI 助手")
self.ai_top_button.clicked.connect(self._open_ai_assistant)
layout.addWidget(self.ai_top_button)
self.ai_top_button.setVisible(self._can_ai_assistant)
self.notification_button = _PaintedIconButton(
"notification", size=38, parent=topbar
@@ -1456,7 +1460,9 @@ class ShellWindow(QMainWindow):
else self._expanded_sidebar_width()
)
self.brand_copy.setVisible(not self._sidebar_collapsed)
self.assistant_card.setVisible(not self._sidebar_collapsed)
self.assistant_card.setVisible(
self._can_ai_assistant and not self._sidebar_collapsed
)
self.upload_settings_button.setVisible(not self._sidebar_collapsed)
margins = (7, 14, 7, 0) if self._sidebar_collapsed else (12, 19, 12, 0)
self.nav_layout.setContentsMargins(*margins)
@@ -1542,12 +1548,35 @@ class ShellWindow(QMainWindow):
show_toast(self, f"正在当前页面搜索“{query}”。", "info")
def _open_ai_assistant(self) -> None:
self.navigate("reception")
if not self._can_ai_assistant:
show_toast(self, "当前账号没有使用 AI 问诊助手的权限。", "danger")
return
current_page = self.stack.currentWidget()
opener = getattr(current_page, "open_selected_ai_consult", None)
if callable(opener) and bool(opener()):
return
reception = self.pages.get("reception")
if reception is None or not self.navigate("reception"):
show_toast(
self,
"当前账号没有可用的接诊台;请从问诊列表或患者列表选择诊单后使用 AI 分析。",
"warning",
4800,
)
return
if reception is not current_page:
reception_opener = getattr(reception, "open_selected_ai_consult", None)
if callable(reception_opener) and bool(reception_opener()):
return
show_toast(
self,
"已进入接诊台;选择患者后可查看 AI 报告与辅助分析。",
"请先在接诊台选择一位有诊单的患者,再点击“开始对话”。",
"info",
3600,
4200,
)
def _open_local_audio_settings(self) -> None: