This commit is contained in:
Your Name
2026-09-01 10:42:16 +08:00
parent 456dd667df
commit 5bd5eae62d
358 changed files with 2276 additions and 495 deletions
@@ -4,10 +4,12 @@ from __future__ import annotations
from collections.abc import Callable, Mapping
from datetime import datetime, timedelta
from html import escape
from math import ceil
from typing import Any
from PySide6.QtCore import QDateTime, QRectF, QSize, Qt
from PySide6.QtGui import QColor, QFont, QIcon, QPainter, QPen, QPixmap
from PySide6.QtCore import QDateTime, QModelIndex, QRectF, QSize, Qt
from PySide6.QtGui import QColor, QFont, QIcon, QPainter, QPen, QPixmap, QTextDocument, QTextOption
from PySide6.QtWidgets import (
QComboBox,
QDateTimeEdit,
@@ -23,6 +25,9 @@ from PySide6.QtWidgets import (
QMessageBox,
QPushButton,
QStackedWidget,
QStyle,
QStyledItemDelegate,
QStyleOptionViewItem,
QVBoxLayout,
QWidget,
)
@@ -381,26 +386,81 @@ def _formula(value: Any) -> str:
def _order_warnings(row: Any) -> list[str]:
if not _truthy(first_value(row, "has_prescription_order", default=False)):
"""Match the PC list's linked-order checks, including blank herb rows."""
raw = getattr(row, "raw", None)
source = raw if isinstance(raw, Mapping) and raw else row
try:
has_order = float(get_value(source, "has_prescription_order", 0) or 0) == 1
except (TypeError, ValueError):
has_order = False
if not has_order:
return []
herbs = get_value(row, "herbs", None) or []
if not isinstance(herbs, (list, tuple)) or not herbs:
herbs = get_value(source, "herbs", None)
herbs = herbs if isinstance(herbs, (list, tuple)) else []
names = [str(get_value(herb, "name", "") or "").strip() for herb in herbs]
names = [name for name in names if name]
if not names:
return ["请开方,当前处方药材为空白"]
seen: set[str] = set()
duplicate: list[str] = []
for herb in herbs:
name = str(first_value(herb, "name", "medicine_name", default="")).strip()
for name in names:
key = "".join(name.split()).lower()
if key and key in seen and name not in duplicate:
duplicate.append(name)
seen.add(key)
return [f"已有关联业务订单,存在重复药材:{'、'.join(duplicate)}"] if duplicate else []
return [f"已有关联业务订单,当前处方存在重复药材:{'、'.join(duplicate)}"] if duplicate else []
def _sn_cell(_value: Any, row: Any) -> str:
return str(first_value(row, "sn", "prescription_no", "id", default="—"))
class _PrescriptionNumberDelegate(QStyledItemDelegate):
"""Paint visible PC-style reminders without changing the sortable SN value."""
def document(self, option: QStyleOptionViewItem, index: QModelIndex, width: int) -> QTextDocument:
row = index.data(Qt.ItemDataRole.UserRole)
number = str(index.data(Qt.ItemDataRole.DisplayRole) or "—")
record_id = display_text(first_value(row, "id", "prescription_id", default="—"))
document = QTextDocument()
document.setDocumentMargin(0)
document.setDefaultFont(option.font)
text_option = document.defaultTextOption()
text_option.setWrapMode(QTextOption.WrapMode.WrapAtWordBoundaryOrAnywhere)
document.setDefaultTextOption(text_option)
paragraphs = [
f'<p style="margin:0;color:#315CF4;font-size:12px;font-weight:600">{escape(number)}</p>',
f'<p style="margin:2px 0 0;color:#7481A3;font-size:11px;font-weight:400">ID: {escape(record_id)}</p>',
]
paragraphs.extend(
'<p style="margin:2px 0 0;color:#DC2626;font-size:12px;font-weight:400">'
+ escape(warning)
+ "</p>"
for warning in _order_warnings(row)
)
document.setHtml("".join(paragraphs))
document.setTextWidth(max(1, width - 16))
return document
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex) -> None:
styled = QStyleOptionViewItem(option)
self.initStyleOption(styled, index)
styled.text = ""
self.parent().style().drawControl(QStyle.ControlElement.CE_ItemViewItem, styled, painter)
document = self.document(option, index, option.rect.width())
painter.save()
painter.setClipRect(option.rect)
painter.translate(option.rect.left() + 8, option.rect.top() + 6)
document.drawContents(painter)
painter.restore()
def sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex) -> QSize: # noqa: N802
width = self.parent().columnWidth(index.column())
document = self.document(option, index, width)
return QSize(width, max(36, ceil(document.size().height()) + 12))
def _patient_cell(_value: Any, row: Any) -> str:
gender = first_value(row, "gender", default=None)
gender_text = "男" if gender in (1, "1") else "女" if gender in (0, "0") else "未知"
@@ -698,7 +758,7 @@ class PrescriptionsPage(QWidget):
self.table = SortableTable(
[
TableColumn("__selected__", "", 46, lambda _value, _row: ""),
TableColumn("sn", "处方编号", 174, _sn_cell),
TableColumn("sn", "处方编号", 260, _sn_cell),
TableColumn("__actions__", "操作", 150, lambda _value, _row: ""),
TableColumn("prescription_type", "处方类型", 96),
TableColumn("is_system_auto", "来源", 88, _source_cell),
@@ -713,6 +773,9 @@ class PrescriptionsPage(QWidget):
self.table.verticalHeader().setDefaultSectionSize(36)
self.table.horizontalHeader().setFixedHeight(38)
self.table.setWordWrap(False)
self.table.setItemDelegateForColumn(1, _PrescriptionNumberDelegate(self.table))
self.table.horizontalHeader().sectionResized.connect(self._number_column_resized)
self.table.model().layoutChanged.connect(self.table.resizeRowsToContents)
self.table.horizontalHeaderItem(0).setIcon(_painted_icon("checkbox", "#AEB9D4", 14))
self.table.horizontalHeaderItem(0).setTextAlignment(Qt.AlignmentFlag.AlignCenter)
self.table.itemSelectionChanged.connect(self._selection_changed)
@@ -729,6 +792,10 @@ class PrescriptionsPage(QWidget):
layout.addWidget(self.stack, 1)
return card
def _number_column_resized(self, column: int, _old_size: int, _new_size: int) -> None:
if column == 1:
self.table.resizeRowsToContents()
def _action_button(
self,
text: str,
@@ -910,8 +977,11 @@ class PrescriptionsPage(QWidget):
font.setWeight(QFont.Weight.DemiBold)
sn_item.setFont(font)
warnings = _order_warnings(row)
if warnings:
sn_item.setToolTip("\n".join(warnings))
description = "\n".join(
[sn_item.text(), f"ID: {first_value(row, 'id', 'prescription_id', default='—')}", *warnings]
)
sn_item.setToolTip(description)
sn_item.setData(Qt.ItemDataRole.AccessibleTextRole, description)
prescription_type = display_text(
first_value(row, "prescription_type", default="—")
@@ -1002,6 +1072,7 @@ class PrescriptionsPage(QWidget):
actions.addStretch(1)
self.table.setCellWidget(row_index, 2, actions_host)
self._sync_row_mutation_actions()
self.table.resizeRowsToContents()
def _run_row_action(self, row: Any, callback: Callable[[], None]) -> None:
target_id = _int(first_value(row, "id", "prescription_id", default=None), 0)