This commit is contained in:
Your Name
2026-09-10 15:33:21 +08:00
parent caab2cabe3
commit bbe3e870a1
2 changed files with 112 additions and 10 deletions
@@ -445,6 +445,21 @@ def _formula(value: Any) -> str:
return "辅方" if text in {"2", "aux", "auxiliary", "辅方"} else "主方"
def _is_blank_prescription(row: Any) -> bool:
if row is None or _truthy(get_value(row, "is_system_auto")):
return True
raw = getattr(row, "raw", None)
source = raw if isinstance(raw, Mapping) and raw else row
missing = object()
herbs = get_value(source, "herbs", missing)
# Compact historical rows may omit herbs; omission is not an empty prescription.
if herbs is missing:
return False
return not isinstance(herbs, (list, tuple)) or not any(
str(get_value(herb, "name", "") or "").strip() for herb in herbs
)
def _order_warnings(row: Any) -> list[str]:
"""Match the PC list's linked-order checks, including blank herb rows."""
@@ -1183,7 +1198,7 @@ class PrescriptionsPage(QWidget):
self.view_button = self._action_button("查看", "cf.prescription/read", self._view_selected)
toolbar.addWidget(self.view_button)
self.ai_report_button = self._action_button("AI 报告", "tcm.prescriptionAi/reports", self._open_ai_report)
self.ai_report_button.setVisible(can_open_issued_ai(self.permissions) and callable(getattr(self.repository, "list_prescription_ai_reports", None)))
self.ai_report_button.hide()
toolbar.addWidget(self.ai_report_button)
self.patch_button = self._action_button(
"修改患者", "tcm.prescription/patchPatient", self._patch_selected
@@ -1565,7 +1580,7 @@ class PrescriptionsPage(QWidget):
actions_host,
)
)
if self._ai_enabled and can_open_issued_ai(self.permissions):
if self._ai_enabled and can_open_issued_ai(self.permissions) and not _is_blank_prescription(row):
actions.addWidget(
_row_action_button(
"eye", "AI 报告",
@@ -1618,6 +1633,8 @@ class PrescriptionsPage(QWidget):
if item is None or top + self.table.rowHeight(index) <= 0 or top >= viewport.height():
continue
row = item.data(Qt.ItemDataRole.UserRole)
if _is_blank_prescription(row):
continue
value = _int(first_value(row, "id", "prescription_id"), 0)
if value > 0:
ids.append(value)
@@ -1628,6 +1645,15 @@ class PrescriptionsPage(QWidget):
self._ai_scroll_timer.start()
def _load_ai_statuses(self) -> None:
only_blank = self.table.rowCount() > 0 and all(
_is_blank_prescription(self.table.item(index, 0).data(Qt.ItemDataRole.UserRole))
for index in range(self.table.rowCount())
)
self.ai_status_notice.setVisible(not only_blank)
if only_blank:
self._ai_timer.stop()
self._set_ai_columns(False)
return
method = getattr(self.repository, "list_prescription_ai_statuses", None)
if not has_permission(self.permissions, "tcm.prescriptionAi/statuses", default=False):
self.ai_status_notice.setText("AI 分析:当前账号没有查看分析状态的权限,请联系管理员授权。")
@@ -1711,15 +1737,17 @@ class PrescriptionsPage(QWidget):
row = self.table.item(index, 0).data(Qt.ItemDataRole.UserRole)
value = _int(first_value(row, "id", "prescription_id"), 0)
batch = self._ai_statuses.get(value)
if batch is None:
blank = _is_blank_prescription(row)
if batch is None and not blank:
continue
state = state_text(batch) if batch else ("尚未开方" if _truthy(get_value(row, "is_system_auto")) else "尚无分析记录")
for column, text in ((11, state), (12, agreement_text(batch))):
state = "" if blank else (state_text(batch) if batch else "尚无分析记录")
agreement = "" if blank else agreement_text(batch)
for column, text in ((11, state), (12, agreement)):
item = self.table.item(index, column)
if item.text() != text:
item.setText(text)
changed = True
item.setToolTip(status_tooltip(batch))
item.setToolTip("" if blank else status_tooltip(batch))
item.setData(Qt.ItemDataRole.AccessibleTextRole, text)
if changed:
self.table.resizeRowsToContents()
@@ -1736,6 +1764,8 @@ class PrescriptionsPage(QWidget):
def _open_ai_report(self) -> None:
row = self._selected()
if _is_blank_prescription(row):
return
value = _int(first_value(row, "id", "prescription_id"), 0)
if value > 0:
present_issued_prescription_ai(self.repository, self.permissions, self, prescription_id=value)
@@ -1748,6 +1778,8 @@ class PrescriptionsPage(QWidget):
return
self.table.selectRow(item.row())
row = self._selected()
if _is_blank_prescription(row):
return
menu = QMenu(self.table)
action = menu.addAction("AI 报告 / 逐味对照")
action.triggered.connect(lambda: self._run_row_action(row, self._open_ai_report))
@@ -1795,7 +1827,13 @@ class PrescriptionsPage(QWidget):
row = self.table.current_data()
active = not self._mutation_pending
self.view_button.setEnabled(active and row is not None)
self.ai_report_button.setEnabled(row is not None)
ai_available = (
not _is_blank_prescription(row)
and can_open_issued_ai(self.permissions)
and callable(getattr(self.repository, "list_prescription_ai_reports", None))
)
self.ai_report_button.setVisible(ai_available)
self.ai_report_button.setEnabled(ai_available)
self.patch_button.setEnabled(active and can_patch_patient(row))
self.create_order_button.setEnabled(active and can_create_order(row))
self.edit_button.setEnabled(active and can_edit_or_delete(row))
+66 -2
View File
@@ -250,6 +250,69 @@ def test_list_batches_visible_ids_and_stops_on_hide(application: QApplication, i
assert repository.calls == calls
def test_blank_list_row_has_no_ai_display_or_entry_points(application: QApplication, immediate: None, monkeypatch: pytest.MonkeyPatch) -> None:
repository = Repository()
opened = []
monkeypatch.setattr(page_module, "present_issued_prescription_ai", lambda *args, **kwargs: opened.append(kwargs))
page = page_module.PrescriptionsPage(repository, ["*"])
page.resize(1366, 800)
page.show()
application.processEvents()
# Demo row 801 contains herbs; row 802 is an empty manual prescription.
assert all(call[1] == [801] for call in repository.calls if call[0] == "statuses")
assert not page.table.isColumnHidden(11) and not page.table.isColumnHidden(12)
page._ai_statuses[802] = batch(prescription_id=802)
page._render_ai_statuses()
for column in (11, 12):
item = page.table.item(1, column)
assert item.text() == item.toolTip() == item.data(Qt.ItemDataRole.AccessibleTextRole) == ""
assert not any(button.accessibleName() == "AI 报告" for button in page.table.cellWidget(1, 2).findChildren(QPushButton))
page.table.selectRow(1)
assert page.ai_report_button.isHidden() and not page.ai_report_button.isEnabled()
page._open_ai_report()
page.table.itemClicked.emit(page.table.item(1, 11))
page.table.itemClicked.emit(page.table.item(1, 12))
page._open_ai_context_menu(page.table.visualItemRect(page.table.item(1, 1)).center())
assert not hasattr(page, "_ai_context_menu")
assert opened == []
page.table.selectRow(0)
assert page.ai_report_button.isVisible() and page.ai_report_button.isEnabled()
page.ai_report_button.click()
assert opened == [{"prescription_id": 801}]
page.close()
@pytest.mark.parametrize("blank_fields", [
{"is_system_auto": "1", "herbs": []},
{"is_system_auto": True, "herbs": [{"name": "黄芪"}]},
{"is_system_auto": 0, "herbs": [{}, {"name": " "}]},
{"is_system_auto": 0, "herbs": None},
])
def test_all_blank_list_hides_ai_until_prescription_is_saved(application: QApplication, immediate: None, monkeypatch: pytest.MonkeyPatch, blank_fields: dict[str, Any]) -> None:
repository = Repository()
row = {"id": 803, "sn": "RX-BLANK", "patient_name": "测试患者", **blank_fields}
monkeypatch.setattr(repository, "list_prescriptions", lambda **_filters: {"lists": [row], "count": 1})
page = page_module.PrescriptionsPage(repository, ["*"])
page.resize(1366, 800)
page.show()
application.processEvents()
assert page.table.isColumnHidden(11) and page.table.isColumnHidden(12)
assert page.ai_report_button.isHidden() and page.ai_status_notice.isHidden()
assert not page._ai_timer.isActive()
assert not any(call[0] == "statuses" for call in repository.calls)
assert not any(button.accessibleName() == "AI 报告" for button in page.table.cellWidget(0, 2).findChildren(QPushButton))
row.update(is_system_auto=0, herbs=[{"name": "黄芪", "dosage": 12}])
page.refresh()
application.processEvents()
assert ("statuses", [803]) in repository.calls
assert not page.table.isColumnHidden(11) and not page.table.isColumnHidden(12)
assert page.ai_report_button.isVisible() and page.ai_status_notice.isVisible()
assert "千问 0%" in page.table.item(0, 12).text()
assert any(button.accessibleName() == "AI 报告" for button in page.table.cellWidget(0, 2).findChildren(QPushButton))
page.close()
def test_list_disabled_explains_availability_and_keeps_history(application: QApplication, immediate: None) -> None:
repository = Repository()
repository.enabled = False
@@ -447,8 +510,9 @@ def test_context_menu_targets_clicked_prescription(application: QApplication, im
page.resize(1366, 800)
page.show()
application.processEvents()
item = page.table.item(1, 1)
expected_id = page.table.item(1, 0).data(Qt.ItemDataRole.UserRole).id
page.table.selectRow(1)
item = page.table.item(0, 1)
expected_id = page.table.item(0, 0).data(Qt.ItemDataRole.UserRole).id
page._open_ai_context_menu(page.table.visualItemRect(item).center())
page._ai_context_menu.actions()[0].trigger()
assert opened == [{"prescription_id": expected_id}]