更新
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user