更新
This commit is contained in:
@@ -36,6 +36,7 @@ from ..dialogs.prescription import (
|
||||
PrescriptionOrderDialog,
|
||||
PrescriptionOrderListDialog,
|
||||
)
|
||||
from ..theme import crisp_pixmap
|
||||
from ..widgets import (
|
||||
BusinessPager,
|
||||
EmptyState,
|
||||
@@ -45,6 +46,7 @@ from ..widgets import (
|
||||
TableColumn,
|
||||
display_text,
|
||||
first_value,
|
||||
format_record_time,
|
||||
friendly_error,
|
||||
get_value,
|
||||
has_permission,
|
||||
@@ -105,6 +107,10 @@ PRESCRIPTIONS_PAGE_QSS = """
|
||||
padding: 0; border-radius: 7px; background: #FFFFFF;
|
||||
border: 1px solid #DCE3F5;
|
||||
}
|
||||
#PrescriptionsPage QPushButton[rowAction="true"][labeled="true"] {
|
||||
min-width: 64px; max-width: 64px; padding: 0 9px;
|
||||
color: #315CF4; font-weight: 600;
|
||||
}
|
||||
#PrescriptionsPage QPushButton[rowAction="true"]:hover {
|
||||
background: #F3F5FF; border-color: #AAB7FF;
|
||||
}
|
||||
@@ -157,8 +163,7 @@ PRESCRIPTIONS_PAGE_QSS = """
|
||||
def _painted_icon(kind: str, color: str = "#5265F6", size: int = 16) -> QIcon:
|
||||
"""Return a crisp page-local icon without relying on emoji or icon fonts."""
|
||||
|
||||
pixmap = QPixmap(size, size)
|
||||
pixmap.fill(Qt.GlobalColor.transparent)
|
||||
pixmap = crisp_pixmap(size)
|
||||
painter = QPainter(pixmap)
|
||||
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
|
||||
pen = QPen(QColor(color), max(1.25, size / 11.5))
|
||||
@@ -265,13 +270,20 @@ def _row_action_button(
|
||||
*,
|
||||
danger: bool = False,
|
||||
enabled: bool = True,
|
||||
label: str = "",
|
||||
mutation: bool = False,
|
||||
) -> QPushButton:
|
||||
button = QPushButton(parent)
|
||||
button.setProperty("rowAction", True)
|
||||
button.setProperty("danger", danger)
|
||||
button.setProperty("labeled", bool(label))
|
||||
button.setProperty("mutationAction", mutation)
|
||||
button.setProperty("rowAllowed", enabled)
|
||||
button.setText(label)
|
||||
button.setAccessibleName(tooltip)
|
||||
button.setToolTip(tooltip)
|
||||
button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
button.setFixedSize(64 if label else 28, 28)
|
||||
button.setIcon(_painted_icon(kind, "#F34E64" if danger else "#4965F5", 15))
|
||||
button.setIconSize(QSize(15, 15))
|
||||
button.setEnabled(enabled)
|
||||
@@ -427,6 +439,11 @@ def _doctor_cell(_value: Any, row: Any) -> str:
|
||||
return str(first_value(row, "doctor_name", "creator_name", default="—"))
|
||||
|
||||
|
||||
def _create_time_cell(value: Any, _row: Any) -> str:
|
||||
raw = first_value(_row, "create_time_text", "create_time", default=value)
|
||||
return format_record_time(raw)
|
||||
|
||||
|
||||
class DoctorMultiSelect(QWidget):
|
||||
"""Compact checkable doctor selector fed by list rows/extend data."""
|
||||
|
||||
@@ -682,6 +699,7 @@ class PrescriptionsPage(QWidget):
|
||||
[
|
||||
TableColumn("__selected__", "", 46, lambda _value, _row: ""),
|
||||
TableColumn("sn", "处方编号", 174, _sn_cell),
|
||||
TableColumn("__actions__", "操作", 150, lambda _value, _row: ""),
|
||||
TableColumn("prescription_type", "处方类型", 96),
|
||||
TableColumn("is_system_auto", "来源", 88, _source_cell),
|
||||
TableColumn("patient_name", "患者信息", 190, _patient_cell),
|
||||
@@ -689,8 +707,7 @@ class PrescriptionsPage(QWidget):
|
||||
TableColumn("void_status", "作废", 72, _void_cell),
|
||||
TableColumn("doctor_name", "医生信息", 180, _doctor_cell),
|
||||
TableColumn("assistant_name", "医助", 125),
|
||||
TableColumn("create_time", "创建时间", 180),
|
||||
TableColumn("__actions__", "操作", 150, lambda _value, _row: ""),
|
||||
TableColumn("create_time", "创建时间", 180, _create_time_cell),
|
||||
]
|
||||
)
|
||||
self.table.verticalHeader().setDefaultSectionSize(36)
|
||||
@@ -840,7 +857,7 @@ class PrescriptionsPage(QWidget):
|
||||
return
|
||||
rows = page_items(result)
|
||||
self.table.set_rows(rows)
|
||||
self._decorate_rows(rows)
|
||||
self._decorate_rows()
|
||||
total = page_total(result, len(rows))
|
||||
self.pager.update_state(requested_page, total)
|
||||
self.count_badge.setText(f"共 {total} 条")
|
||||
@@ -864,20 +881,27 @@ class PrescriptionsPage(QWidget):
|
||||
self.table.selectRow(0)
|
||||
self._selection_changed()
|
||||
|
||||
def _decorate_rows(self, rows: list[Any]) -> None:
|
||||
def _decorate_rows(self) -> None:
|
||||
"""Apply the reference table's tags, checkbox, avatar, and row actions."""
|
||||
|
||||
for row_index, row in enumerate(rows):
|
||||
for row_index in range(self.table.rowCount()):
|
||||
selector = self.table.item(row_index, 0)
|
||||
if selector is not None:
|
||||
selector.setFlags(
|
||||
selector.flags()
|
||||
| Qt.ItemFlag.ItemIsUserCheckable
|
||||
| Qt.ItemFlag.ItemIsEnabled
|
||||
| Qt.ItemFlag.ItemIsSelectable
|
||||
)
|
||||
selector.setCheckState(Qt.CheckState.Unchecked)
|
||||
selector.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
if selector is None:
|
||||
continue
|
||||
# Read the row back from the visual table. SortableTable may have
|
||||
# already reordered rows, so decorating the original result list
|
||||
# can bind an action button to the wrong visible prescription.
|
||||
row = selector.data(Qt.ItemDataRole.UserRole)
|
||||
if row is None:
|
||||
continue
|
||||
selector.setFlags(
|
||||
selector.flags()
|
||||
| Qt.ItemFlag.ItemIsUserCheckable
|
||||
| Qt.ItemFlag.ItemIsEnabled
|
||||
| Qt.ItemFlag.ItemIsSelectable
|
||||
)
|
||||
selector.setCheckState(Qt.CheckState.Unchecked)
|
||||
selector.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
sn_item = self.table.item(row_index, 1)
|
||||
if sn_item is not None:
|
||||
@@ -894,7 +918,7 @@ class PrescriptionsPage(QWidget):
|
||||
)
|
||||
self.table.setCellWidget(
|
||||
row_index,
|
||||
2,
|
||||
3,
|
||||
_style_row_host(
|
||||
_cell_host(_tag_label(prescription_type, "accent", self.table.viewport())),
|
||||
row_index,
|
||||
@@ -903,11 +927,11 @@ class PrescriptionsPage(QWidget):
|
||||
|
||||
audit_text, audit_kind = prescription_status(row)
|
||||
audit = _tag_label(audit_text, audit_kind, self.table.viewport())
|
||||
audit_item = self.table.item(row_index, 5)
|
||||
audit_item = self.table.item(row_index, 6)
|
||||
if audit_item is not None and "\n" in audit_item.text():
|
||||
audit.setToolTip(audit_item.text())
|
||||
self.table.setCellWidget(
|
||||
row_index, 5, _style_row_host(_cell_host(audit), row_index)
|
||||
row_index, 6, _style_row_host(_cell_host(audit), row_index)
|
||||
)
|
||||
|
||||
doctor_name = _doctor_cell(None, row)
|
||||
@@ -928,13 +952,13 @@ class PrescriptionsPage(QWidget):
|
||||
doctor_label.setStyleSheet("color:#31416A;background:transparent;border:0;")
|
||||
doctor_layout.addWidget(doctor_label)
|
||||
doctor_layout.addStretch(1)
|
||||
self.table.setCellWidget(row_index, 7, doctor_host)
|
||||
self.table.setCellWidget(row_index, 8, doctor_host)
|
||||
|
||||
actions_host = QWidget(self.table.viewport())
|
||||
_style_row_host(actions_host, row_index)
|
||||
actions = QHBoxLayout(actions_host)
|
||||
actions.setContentsMargins(7, 0, 7, 0)
|
||||
actions.setSpacing(7)
|
||||
actions.setContentsMargins(3, 0, 3, 0)
|
||||
actions.setSpacing(3)
|
||||
actions.addStretch(1)
|
||||
if has_permission(self.permissions, "cf.prescription/read"):
|
||||
actions.addWidget(
|
||||
@@ -957,6 +981,8 @@ class PrescriptionsPage(QWidget):
|
||||
),
|
||||
actions_host,
|
||||
enabled=can_edit_or_delete(row),
|
||||
label="编辑",
|
||||
mutation=True,
|
||||
)
|
||||
)
|
||||
if has_permission(self.permissions, "cf.prescription/del"):
|
||||
@@ -970,23 +996,31 @@ class PrescriptionsPage(QWidget):
|
||||
actions_host,
|
||||
danger=True,
|
||||
enabled=can_edit_or_delete(row),
|
||||
mutation=True,
|
||||
)
|
||||
)
|
||||
actions.addStretch(1)
|
||||
self.table.setCellWidget(row_index, 10, actions_host)
|
||||
self.table.setCellWidget(row_index, 2, actions_host)
|
||||
self._sync_row_mutation_actions()
|
||||
|
||||
def _run_row_action(self, row: Any, callback: Callable[[], None]) -> None:
|
||||
target_id = first_value(row, "id", "prescription_id", default=None)
|
||||
target_id = _int(first_value(row, "id", "prescription_id", default=None), 0)
|
||||
if target_id <= 0:
|
||||
self.banner.show_message("处方 ID 无效,请刷新列表后重试。", "warning")
|
||||
return
|
||||
for row_index in range(self.table.rowCount()):
|
||||
item = self.table.item(row_index, 0)
|
||||
candidate = item.data(Qt.ItemDataRole.UserRole) if item is not None else None
|
||||
candidate_id = first_value(candidate, "id", "prescription_id", default=None)
|
||||
candidate_id = _int(
|
||||
first_value(candidate, "id", "prescription_id", default=None), 0
|
||||
)
|
||||
if candidate is row or (
|
||||
target_id is not None and str(candidate_id) == str(target_id)
|
||||
candidate_id > 0 and candidate_id == target_id
|
||||
):
|
||||
self.table.selectRow(row_index)
|
||||
break
|
||||
callback()
|
||||
callback()
|
||||
return
|
||||
self.banner.show_message("该处方已不在当前列表,请刷新后重试。", "warning")
|
||||
|
||||
def _load_error(self, error: Exception, generation: int) -> None:
|
||||
if generation == self._generation:
|
||||
@@ -1013,8 +1047,17 @@ class PrescriptionsPage(QWidget):
|
||||
self._mutation_pending = pending
|
||||
self.add_button.setEnabled(not pending)
|
||||
self.orders_button.setEnabled(not pending)
|
||||
self._sync_row_mutation_actions()
|
||||
self._selection_changed()
|
||||
|
||||
def _sync_row_mutation_actions(self) -> None:
|
||||
for button in self.table.findChildren(QPushButton):
|
||||
if not bool(button.property("mutationAction")):
|
||||
continue
|
||||
button.setEnabled(
|
||||
not self._mutation_pending and bool(button.property("rowAllowed"))
|
||||
)
|
||||
|
||||
def _selected(self) -> Any:
|
||||
return self.table.current_data()
|
||||
|
||||
@@ -1054,6 +1097,10 @@ class PrescriptionsPage(QWidget):
|
||||
) -> None:
|
||||
if generation != self._detail_generation or prescription_id != self._detail_target:
|
||||
return
|
||||
detail_id = _int(first_value(detail, "id", "prescription_id"), 0)
|
||||
if detail_id != prescription_id:
|
||||
self.banner.show_message("处方详情与当前选择不一致,请刷新后重试。", "danger")
|
||||
return
|
||||
self.banner.clear()
|
||||
callback(detail)
|
||||
|
||||
@@ -1148,6 +1195,7 @@ class PrescriptionsPage(QWidget):
|
||||
row = self._selected()
|
||||
if (
|
||||
row is None
|
||||
or self._mutation_pending
|
||||
or not has_permission(self.permissions, "cf.prescription/edit")
|
||||
or not can_edit_or_delete(row)
|
||||
):
|
||||
@@ -1159,6 +1207,9 @@ class PrescriptionsPage(QWidget):
|
||||
)
|
||||
|
||||
def _open_editor(self, detail: Any) -> None:
|
||||
if not can_edit_or_delete(detail):
|
||||
self.banner.show_message("该处方状态已变化,当前不能编辑。", "warning")
|
||||
return
|
||||
dialog = PrescriptionEditorDialog(
|
||||
self.repository,
|
||||
detail,
|
||||
@@ -1208,6 +1259,7 @@ class PrescriptionsPage(QWidget):
|
||||
row = self._selected()
|
||||
if (
|
||||
row is None
|
||||
or self._mutation_pending
|
||||
or not has_permission(self.permissions, "cf.prescription/del")
|
||||
or not can_edit_or_delete(row)
|
||||
):
|
||||
@@ -1222,6 +1274,9 @@ class PrescriptionsPage(QWidget):
|
||||
if answer != QMessageBox.StandardButton.Yes:
|
||||
return
|
||||
prescription_id = _int(first_value(row, "id", "prescription_id"), 0)
|
||||
if prescription_id <= 0:
|
||||
self.banner.show_message("处方 ID 无效,请刷新列表后重试。", "warning")
|
||||
return
|
||||
self._set_mutation_pending(True)
|
||||
run_async(
|
||||
lambda: self.repository.delete_prescription(prescription_id),
|
||||
|
||||
Reference in New Issue
Block a user