This commit is contained in:
Your Name
2026-08-13 11:54:00 +08:00
parent 07188e82f8
commit 72a5300b08
19 changed files with 1441 additions and 577 deletions
@@ -228,19 +228,18 @@ def _status_value(row: Any) -> int:
return _as_int(first_value(row, "status", default=0))
def prescription_action_label(row: Any) -> str:
audit = _as_int(first_value(row, "prescription_audit_status", "audit_status"), -1)
voided = _as_int(first_value(row, "prescription_void_status", "void_status"), 0)
explicit = first_value(row, "has_prescription", default=None)
has_prescription = (
_as_bool(explicit)
if explicit is not None
else _as_int(first_value(row, "prescription_id", default=0), 0) > 0
or audit in {0, 1, 2}
)
if not has_prescription:
return "开方"
return "查看" if audit == 1 and voided != 1 else "编辑处方"
def prescription_action_label(row: Any) -> str:
audit = _as_int(first_value(row, "prescription_audit_status", "audit_status"), -1)
voided = _as_int(first_value(row, "prescription_void_status", "void_status"), 0)
explicit = first_value(row, "has_prescription", default=None)
has_prescription = (
_as_bool(explicit)
if explicit is not None
else _as_int(first_value(row, "prescription_id", default=0), 0) > 0 or audit in {0, 1, 2}
)
if not has_prescription:
return "开方"
return "查看" if audit == 1 and voided != 1 else "编辑处方"
def _patient_cell(_value: Any, row: Any, *, can_plain: bool) -> str:
@@ -270,9 +269,8 @@ def _patient_cell(_value: Any, row: Any, *, can_plain: bool) -> str:
)
if part and part != "—"
)
return (
f"{display_text(first_value(row, 'patient_name'), '—')}\n{phone}"
+ (f"\n{extras}" if extras else "")
return f"{display_text(first_value(row, 'patient_name'), '—')}\n{phone}" + (
f"\n{extras}" if extras else ""
)
@@ -284,7 +282,9 @@ def _datetime_cell(_value: Any, row: Any) -> str:
def _confirmed_cell(_value: Any, row: Any) -> str:
return "已确认" if _as_bool(first_value(row, "diagnosis_confirmed", default=False)) else "未确认"
return (
"已确认" if _as_bool(first_value(row, "diagnosis_confirmed", default=False)) else "未确认"
)
def _prescription_cell(_value: Any, row: Any) -> str:
@@ -296,7 +296,9 @@ def _prescription_cell(_value: Any, row: Any) -> str:
def _status_cell(_value: Any, row: Any) -> str:
return display_text(first_value(row, "status_desc"), str(first_value(row, "status", default="—")))
return display_text(
first_value(row, "status_desc"), str(first_value(row, "status", default="—"))
)
def _offset_date(preset: str) -> date | None:
@@ -374,8 +376,6 @@ class AppointmentsPage(QWidget):
)
self._native_video_capable = _supports_native_video(repository)
self._is_admin = _is_admin_user(current_user)
self.diagnosis_dialog = DiagnosisDialog(repository, self, permissions=permissions)
self.diagnosis_dialog.saved.connect(lambda: self.refresh(silent=True))
root = QVBoxLayout(self)
root.setContentsMargins(24, 20, 24, 24)
@@ -396,6 +396,14 @@ class AppointmentsPage(QWidget):
self.poll_timer.setInterval(LIST_POLL_MS)
self.poll_timer.timeout.connect(lambda: self.refresh(silent=True))
def _diagnosis_dialog(self) -> DiagnosisDialog:
dialog = getattr(self, "_diagnosis_dialog_impl", None)
if dialog is None:
dialog = DiagnosisDialog(self.repository, self, permissions=self.permissions)
dialog.saved.connect(lambda: self.refresh(silent=True))
self._diagnosis_dialog_impl = dialog
return dialog
def _build_toolbar(self) -> QWidget:
frame = QFrame()
frame.setObjectName("FilterBar")
@@ -457,7 +465,9 @@ class AppointmentsPage(QWidget):
button = QPushButton(label)
button.setCheckable(True)
button.setProperty("variant", "chip")
button.clicked.connect(lambda _checked=False, value=preset: self._set_date_preset(value))
button.clicked.connect(
lambda _checked=False, value=preset: self._set_date_preset(value)
)
self.date_buttons[preset] = button
date_row.addWidget(button)
date_row.addStretch(1)
@@ -490,9 +500,7 @@ class AppointmentsPage(QWidget):
layout.setSpacing(8)
actions = QHBoxLayout()
self.edit_button = self._action_button(
"编辑患者", "tcm.diagnosis/edit", self._edit_patient
)
self.edit_button = self._action_button("编辑患者", "tcm.diagnosis/edit", self._edit_patient)
actions.addWidget(self.edit_button)
self.qr_button = self._action_button(
"视频二维码", "tcm.diagnosis/videoQr", self._request_video_qr
@@ -510,9 +518,7 @@ class AppointmentsPage(QWidget):
"开方", "tcm.diagnosis/kaifang", self._open_prescription
)
actions.addWidget(self.prescription_button)
self.case_button = self._action_button(
"病历", "tcm.diagnosis/kaifang", self._view_case
)
self.case_button = self._action_button("病历", "tcm.diagnosis/kaifang", self._view_case)
actions.addWidget(self.case_button)
self.cancel_button = self._action_button(
"取消挂号",
@@ -601,7 +607,9 @@ class AppointmentsPage(QWidget):
dialog = QDialog(self)
dialog.setWindowTitle("自定义日期")
layout = QVBoxLayout(dialog)
start = QDateEdit(QDate.fromString(self._start_date or date.today().isoformat(), "yyyy-MM-dd"))
start = QDateEdit(
QDate.fromString(self._start_date or date.today().isoformat(), "yyyy-MM-dd")
)
start.setCalendarPopup(True)
start.setDisplayFormat("yyyy-MM-dd")
end = QDateEdit(QDate.fromString(self._end_date or date.today().isoformat(), "yyyy-MM-dd"))
@@ -719,9 +727,7 @@ class AppointmentsPage(QWidget):
self._fit_table_rows()
for row_index in range(self.table.rowCount()):
source_item = self.table.item(row_index, 0)
source = (
source_item.data(Qt.ItemDataRole.UserRole) if source_item is not None else None
)
source = source_item.data(Qt.ItemDataRole.UserRole) if source_item is not None else None
status = _status_value(source)
status_kind = {
1: "warning",
@@ -822,7 +828,7 @@ class AppointmentsPage(QWidget):
if diagnosis_id <= 0:
show_toast(self, "该预约没有关联诊单信息。", "warning")
return
self.diagnosis_dialog.open_for(diagnosis_id, editable=True, seed=row)
self._diagnosis_dialog().open_for(diagnosis_id, editable=True, seed=row)
def _request_video(self) -> None:
if not _canonical_allowed(
@@ -882,6 +888,7 @@ class AppointmentsPage(QWidget):
self._action_generation += 1
generation = self._action_generation
self.banner.show_message("正在生成视频二维码…", "info")
def _worker() -> dict[str, Any]:
config = invoke(self.repository, "get_mini_program_config")
if not str(first_value(config, "app_id", default="") or "").strip():
@@ -901,9 +908,7 @@ class AppointmentsPage(QWidget):
if not url:
raise ValueError("服务器未返回可用的二维码地址")
try:
result["_image_bytes"] = invoke(
self.repository, "download_public_image", url=url
)
result["_image_bytes"] = invoke(self.repository, "download_public_image", url=url)
except Exception as exc:
result["_image_error"] = friendly_error(exc)
return result
@@ -962,8 +967,7 @@ class AppointmentsPage(QWidget):
else:
reason = str(first_value(result, "_image_error", default="") or "").strip()
image_label.setText(
"二维码图片加载失败\n请重新生成或在浏览器中打开"
+ (f"\n{reason}" if reason else "")
"二维码图片加载失败\n请重新生成或在浏览器中打开" + (f"\n{reason}" if reason else "")
)
image_row = QHBoxLayout()
image_row.addStretch(1)
@@ -1186,64 +1190,64 @@ class AppointmentsPage(QWidget):
def _prescription_loaded(self, existing: Any, row: Any, generation: int) -> None:
if generation != self._prescription_generation:
return
self.banner.clear()
if existing is not None and _as_int(first_value(existing, "id", default=0)) > 0:
approved = _as_int(first_value(existing, "audit_status", "status"), -1) == 1
voided = _as_int(first_value(existing, "void_status", "is_void"), 0) == 1
if not approved or voided:
self._open_existing_prescription_editor(existing)
else:
dialog = PrescriptionDetailDialog(
existing,
can_open_diagnosis=_canonical_allowed(
self.permissions, "tcm.diagnosis/readonlyDetail", default=False
),
parent=self,
)
dialog.diagnosis_requested.connect(self._open_diagnosis_id)
dialog.exec()
return
self._begin_case_record_load(row)
def _open_existing_prescription_editor(self, prescription: Any) -> None:
prescription_id = _as_int(first_value(prescription, "id", "prescription_id", default=0))
if prescription_id <= 0:
self.banner.show_message("处方编号不完整,无法编辑。", "danger")
return
dialog = PrescriptionEditorDialog(
self.repository,
prescription,
mode="edit",
current_user=self.current_user,
parent=self,
)
diagnosis_signal = getattr(dialog, "diagnosis_requested", None)
if diagnosis_signal is not None:
diagnosis_signal.connect(self._open_diagnosis_id)
if dialog.exec() != QDialog.DialogCode.Accepted:
return
frozen_payload = MappingProxyType(dialog.payload())
self._mutation_pending = True
self._action_generation += 1
generation = self._action_generation
self.banner.show_message("正在保存处方…", "info")
run_async(
lambda: invoke(
self.repository,
"update_prescription",
prescription=prescription_id,
changes=frozen_payload,
),
on_success=lambda _result: self._prescription_updated(generation),
on_error=lambda error: self._action_error(error, generation),
on_finished=lambda: self._mutation_finished(generation),
)
def _prescription_updated(self, generation: int) -> None:
if generation != self._action_generation:
return
self.banner.show_message("处方已保存并重新进入待审核。", "success")
self.refresh(silent=True)
self.banner.clear()
if existing is not None and _as_int(first_value(existing, "id", default=0)) > 0:
approved = _as_int(first_value(existing, "audit_status", "status"), -1) == 1
voided = _as_int(first_value(existing, "void_status", "is_void"), 0) == 1
if not approved or voided:
self._open_existing_prescription_editor(existing)
else:
dialog = PrescriptionDetailDialog(
existing,
can_open_diagnosis=_canonical_allowed(
self.permissions, "tcm.diagnosis/readonlyDetail", default=False
),
parent=self,
)
dialog.diagnosis_requested.connect(self._open_diagnosis_id)
dialog.exec()
return
self._begin_case_record_load(row)
def _open_existing_prescription_editor(self, prescription: Any) -> None:
prescription_id = _as_int(first_value(prescription, "id", "prescription_id", default=0))
if prescription_id <= 0:
self.banner.show_message("处方编号不完整,无法编辑。", "danger")
return
dialog = PrescriptionEditorDialog(
self.repository,
prescription,
mode="edit",
current_user=self.current_user,
parent=self,
)
diagnosis_signal = getattr(dialog, "diagnosis_requested", None)
if diagnosis_signal is not None:
diagnosis_signal.connect(self._open_diagnosis_id)
if dialog.exec() != QDialog.DialogCode.Accepted:
return
frozen_payload = MappingProxyType(dialog.payload())
self._mutation_pending = True
self._action_generation += 1
generation = self._action_generation
self.banner.show_message("正在保存处方…", "info")
run_async(
lambda: invoke(
self.repository,
"update_prescription",
prescription=prescription_id,
changes=frozen_payload,
),
on_success=lambda _result: self._prescription_updated(generation),
on_error=lambda error: self._action_error(error, generation),
on_finished=lambda: self._mutation_finished(generation),
)
def _prescription_updated(self, generation: int) -> None:
if generation != self._action_generation:
return
self.banner.show_message("处方已保存并重新进入待审核。", "success")
self.refresh(silent=True)
def _begin_case_record_load(self, row: Any) -> None:
snapshot = deepcopy(row)
@@ -1304,10 +1308,10 @@ class AppointmentsPage(QWidget):
"visit_no": build_prescription_visit_no(
diagnosis_id=diagnosis_id, appointment_id=appointment_id
),
"tongue": authoritative("tongue", "tongue_coating", default=""),
"tongue_image": authoritative("tongue_image", default=""),
"pulse": authoritative("pulse", default=""),
"pulse_condition": authoritative("pulse_condition", default=""),
"tongue": authoritative("tongue", "tongue_coating", default=""),
"tongue_image": authoritative("tongue_image", default=""),
"pulse": authoritative("pulse", default=""),
"pulse_condition": authoritative("pulse_condition", default=""),
"clinical_diagnosis": build_prescription_clinical_diagnosis(
diagnosis, patient, record, case_record
),
@@ -1318,21 +1322,21 @@ class AppointmentsPage(QWidget):
def _open_diagnosis_id(self, diagnosis_id: int) -> None:
if diagnosis_id > 0:
self.diagnosis_dialog.open_view_only(diagnosis_id)
self._diagnosis_dialog().open_view_only(diagnosis_id)
def _open_prescription_editor(self, record: Any, case_record: Any) -> None:
seed = self._prescription_seed(record, case_record)
dialog = PrescriptionEditorDialog(
dialog = PrescriptionEditorDialog(
self.repository,
seed,
mode="add",
current_user=self.current_user,
parent=self,
)
diagnosis_signal = getattr(dialog, "diagnosis_requested", None)
if diagnosis_signal is not None:
diagnosis_signal.connect(self._open_diagnosis_id)
if dialog.exec() != QDialog.DialogCode.Accepted:
parent=self,
)
diagnosis_signal = getattr(dialog, "diagnosis_requested", None)
if diagnosis_signal is not None:
diagnosis_signal.connect(self._open_diagnosis_id)
if dialog.exec() != QDialog.DialogCode.Accepted:
return
payload = dialog.payload()
payload["diagnosis_id"] = seed["diagnosis_id"]