更新
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
__all__ = ["DEBUG_MODE", "ONLINE_API_BASE_URL", "__version__"]
|
||||
|
||||
# Single source of truth for runtime, package, installer, and executable versions.
|
||||
__version__ = "1.3.0"
|
||||
__version__ = "1.2.0"
|
||||
|
||||
# 调试模式开启时,登录页显示“演示模式”和“服务器设置”。
|
||||
# 正式发布请保持 False;此时程序只使用下面配置的线上域名。
|
||||
|
||||
@@ -714,7 +714,10 @@ def _spawn_inno_setup_applier(
|
||||
if exit_code is not None:
|
||||
raise OSError(f"更新助手启动后提前退出(代码 {exit_code})")
|
||||
time.sleep(0.05)
|
||||
process.terminate()
|
||||
try: # noqa: SIM105 - best-effort cleanup before reporting the handshake timeout
|
||||
process.terminate()
|
||||
except OSError:
|
||||
pass
|
||||
raise OSError(f"更新助手启动超时,未生成就绪标记:{ready_file}")
|
||||
|
||||
|
||||
|
||||
@@ -7,9 +7,10 @@ object names and dynamic properties so adjacent pages keep their own styling.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import weakref
|
||||
from collections.abc import Mapping, Sequence
|
||||
from dataclasses import dataclass
|
||||
import weakref
|
||||
from collections.abc import Mapping, Sequence
|
||||
from dataclasses import dataclass
|
||||
from math import ceil
|
||||
from typing import Any
|
||||
|
||||
from PySide6.QtCore import (
|
||||
@@ -1257,7 +1258,7 @@ class DiagnosisLineEdit(QLineEdit):
|
||||
self.setText(text)
|
||||
|
||||
|
||||
class DiagnosisTextEdit(QPlainTextEdit):
|
||||
class DiagnosisTextEdit(QPlainTextEdit):
|
||||
"""Multiline editor using the same scoped field state as line inputs."""
|
||||
|
||||
def __init__(self, rows: int = 3, parent: QWidget | None = None) -> None:
|
||||
@@ -1273,11 +1274,113 @@ class DiagnosisTextEdit(QPlainTextEdit):
|
||||
# QPlainTextEdit defaults to ~80 columns; that blows past the drawer width.
|
||||
return QSize(48, self._hint_height)
|
||||
|
||||
def sizeHint(self) -> QSize: # noqa: N802 - Qt virtual
|
||||
return QSize(160, self._hint_height)
|
||||
|
||||
|
||||
class DiagnosisComboBox(QComboBox):
|
||||
def sizeHint(self) -> QSize: # noqa: N802 - Qt virtual
|
||||
return QSize(160, self._hint_height)
|
||||
|
||||
|
||||
class ExpandableDiagnosisTextEdit(DiagnosisTextEdit):
|
||||
"""An inline long-text editor without an inner scrollbar when expanded."""
|
||||
|
||||
def __init__(self, rows: int = 3, parent: QWidget | None = None) -> None:
|
||||
super().__init__(rows, parent)
|
||||
self._collapsed_height = self._hint_height
|
||||
self._caption = "内容"
|
||||
self._expand_host: QWidget | None = None
|
||||
self.expand_button = QPushButton("展开全部", self)
|
||||
self.expand_button.setObjectName("DiagnosisTextExpandButton")
|
||||
self.expand_button.setProperty("variant", "link")
|
||||
self.expand_button.setCheckable(True)
|
||||
self.expand_button.setAutoDefault(False)
|
||||
self.expand_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
self.expand_button.setToolTip("展开文本框,查看和编辑全部内容")
|
||||
self.expand_button.hide()
|
||||
self.expand_button.toggled.connect(self._toggle_expanded)
|
||||
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
|
||||
self._height_sync = QTimer(self)
|
||||
self._height_sync.setSingleShot(True)
|
||||
self._height_sync.setInterval(0)
|
||||
self._height_sync.timeout.connect(self._sync_content_height)
|
||||
self.textChanged.connect(self._height_sync.start)
|
||||
self.document().documentLayout().documentSizeChanged.connect(
|
||||
lambda _size: self._height_sync.start()
|
||||
)
|
||||
|
||||
def wrap_with_expander(self, caption: str) -> QWidget:
|
||||
"""Keep the original plain-text editor as the form's save/readonly target."""
|
||||
|
||||
if self._expand_host is None:
|
||||
self._caption = caption
|
||||
self.setAccessibleName(caption)
|
||||
self.expand_button.setAccessibleName(f"展开{caption}全部内容")
|
||||
self._expand_host = QWidget()
|
||||
self._expand_host.setMinimumWidth(0)
|
||||
self._expand_host.setFocusProxy(self)
|
||||
layout = QVBoxLayout(self._expand_host)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setSpacing(2)
|
||||
layout.addWidget(self)
|
||||
layout.addWidget(self.expand_button, 0, Qt.AlignmentFlag.AlignRight)
|
||||
return self._expand_host
|
||||
|
||||
def setPlainText(self, text: str) -> None: # noqa: N802 - Qt API
|
||||
# A newly loaded record starts compact; typing/paste/undo keep its state.
|
||||
self.expand_button.setChecked(False)
|
||||
super().setPlainText(text)
|
||||
|
||||
def _toggle_expanded(self, expanded: bool) -> None:
|
||||
self.expand_button.setText("收起" if expanded else "展开全部")
|
||||
self.expand_button.setAccessibleName(
|
||||
f"收起{self._caption}" if expanded else f"展开{self._caption}全部内容"
|
||||
)
|
||||
self.expand_button.setToolTip(
|
||||
"收起为紧凑文本框,内容不会丢失" if expanded else "展开文本框,查看和编辑全部内容"
|
||||
)
|
||||
self.setVerticalScrollBarPolicy(
|
||||
Qt.ScrollBarPolicy.ScrollBarAlwaysOff
|
||||
if expanded
|
||||
else Qt.ScrollBarPolicy.ScrollBarAsNeeded
|
||||
)
|
||||
self.verticalScrollBar().setValue(0)
|
||||
self._height_sync.start()
|
||||
|
||||
def _sync_content_height(self) -> None:
|
||||
expanded = self.expand_button.isChecked()
|
||||
document = self.document()
|
||||
document_layout = document.documentLayout()
|
||||
# QPlainTextDocumentLayout.documentSize().height() counts lines, not
|
||||
# pixels. Measure the actual wrapped blocks, including offscreen ones.
|
||||
height = self.height() - self.viewport().height() + 2 * document.documentMargin()
|
||||
block = document.begin()
|
||||
while block.isValid():
|
||||
height += document_layout.blockBoundingRect(block).height()
|
||||
if not expanded and height > self._collapsed_height:
|
||||
break
|
||||
block = block.next()
|
||||
self.expand_button.setVisible(expanded or height > self._collapsed_height)
|
||||
target = max(self._collapsed_height, ceil(height)) if expanded else self._collapsed_height
|
||||
if self._hint_height != target:
|
||||
self._hint_height = target
|
||||
self.setFixedHeight(target)
|
||||
self.updateGeometry()
|
||||
|
||||
def resizeEvent(self, event: QResizeEvent) -> None: # noqa: N802 - Qt API
|
||||
super().resizeEvent(event)
|
||||
if hasattr(self, "_height_sync"):
|
||||
self._height_sync.start()
|
||||
|
||||
def showEvent(self, event: QShowEvent) -> None: # noqa: N802 - Qt API
|
||||
super().showEvent(event)
|
||||
self._height_sync.start()
|
||||
|
||||
def changeEvent(self, event: QEvent) -> None: # noqa: N802 - Qt API
|
||||
super().changeEvent(event)
|
||||
if event.type() in (QEvent.Type.FontChange, QEvent.Type.StyleChange) and hasattr(
|
||||
self, "_height_sync"
|
||||
):
|
||||
self._height_sync.start()
|
||||
|
||||
|
||||
class DiagnosisComboBox(QComboBox):
|
||||
"""Choice editor with the legacy text API used by diagnosis saving."""
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -46,6 +46,7 @@ from ..diagnosis_drawer import (
|
||||
DiagnosisSwitch,
|
||||
DiagnosisTabWidget,
|
||||
DiagnosisTextEdit,
|
||||
ExpandableDiagnosisTextEdit,
|
||||
LoadingOverlay,
|
||||
MessageStrip,
|
||||
NotesTimeline,
|
||||
@@ -300,7 +301,7 @@ _FORM_SECTIONS: tuple[tuple[str, tuple[tuple[tuple[str, str, int, str], ...], ..
|
||||
("渠道", "create_source", 12, "create_source"),
|
||||
),
|
||||
(("统计端就诊卡", "show_card", 12, "show_card"),),
|
||||
(("在用药物", "current_medications", 24, "textarea3"),),
|
||||
(("在用药物", "current_medications", 24, "expandable_textarea3"),),
|
||||
),
|
||||
),
|
||||
(
|
||||
@@ -331,7 +332,7 @@ _FORM_SECTIONS: tuple[tuple[str, tuple[tuple[tuple[str, str, int, str], ...], ..
|
||||
(("小便情况", "urine_condition", 24, "urine_condition_choices"),),
|
||||
(("大便情况", "stool_condition", 24, "stool_condition_choices"),),
|
||||
(("腰肾情况", "kidney_condition", 24, "kidney_condition_choices"),),
|
||||
(("其他补充", "symptoms", 24, "textarea3"),),
|
||||
(("其他补充", "symptoms", 24, "expandable_textarea3"),),
|
||||
),
|
||||
),
|
||||
("既往史", ((("既往史", "past_history", 24, "past_history_choices"),),)),
|
||||
@@ -1234,11 +1235,12 @@ class DiagnosisDialog(QDialog):
|
||||
occupied = 0
|
||||
for label, key, span, field_kind in row_fields:
|
||||
editor = self._ensure_editor(key, field_kind)
|
||||
display = (
|
||||
editor.wrap_with_unit()
|
||||
if isinstance(editor, DiagnosisNumberEdit)
|
||||
else editor
|
||||
)
|
||||
if isinstance(editor, DiagnosisNumberEdit):
|
||||
display = editor.wrap_with_unit()
|
||||
elif isinstance(editor, ExpandableDiagnosisTextEdit):
|
||||
display = editor.wrap_with_expander(label)
|
||||
else:
|
||||
display = editor
|
||||
container = self._field_container(label, display, span, editor=editor)
|
||||
row_layout.addWidget(container, span)
|
||||
fields.append(container)
|
||||
@@ -1371,9 +1373,13 @@ class DiagnosisDialog(QDialog):
|
||||
columns=4 if multiple else 5,
|
||||
)
|
||||
self._choice_fields[key] = editor
|
||||
elif field_kind.startswith("textarea"):
|
||||
elif field_kind.startswith(("textarea", "expandable_textarea")):
|
||||
rows = int(field_kind[-1])
|
||||
editor = DiagnosisTextEdit(rows)
|
||||
editor = (
|
||||
ExpandableDiagnosisTextEdit(rows)
|
||||
if field_kind.startswith("expandable_")
|
||||
else DiagnosisTextEdit(rows)
|
||||
)
|
||||
else:
|
||||
editor = DiagnosisLineEdit()
|
||||
editor.setObjectName(f"DiagnosisField_{key.removeprefix('__')}")
|
||||
|
||||
@@ -259,6 +259,7 @@ QWidget#ReceptionPage QLabel#StatusBadge {
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
}
|
||||
QWidget#ReceptionPage QPushButton#ReceptionNotifyButton,
|
||||
QWidget#ReceptionPage QPushButton#ReceptionHistoryButton,
|
||||
QWidget#ReceptionPage QPushButton#ReceptionImButton {
|
||||
min-height: 34px;
|
||||
@@ -282,6 +283,7 @@ QWidget#ReceptionPage QPushButton#ReceptionMoreButton {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
QWidget#ReceptionPage QPushButton#ReceptionNotifyButton:hover,
|
||||
QWidget#ReceptionPage QPushButton#ReceptionHistoryButton:hover,
|
||||
QWidget#ReceptionPage QPushButton#ReceptionImButton:hover {
|
||||
color: #5469F0;
|
||||
@@ -3832,6 +3834,10 @@ class ReceptionPage(QWidget):
|
||||
self.complete_button.clicked.connect(self._complete_appointment)
|
||||
self.complete_button.setVisible(self._can_complete)
|
||||
patient_head.addWidget(self.complete_button)
|
||||
self.notify_button = QPushButton("通知医助", hero)
|
||||
self.notify_button.setObjectName("ReceptionNotifyButton")
|
||||
self.notify_button.clicked.connect(self._notify_assistant)
|
||||
patient_head.addWidget(self.notify_button)
|
||||
self.history_button = QPushButton("查看历史", hero)
|
||||
self.history_button.setObjectName("ReceptionHistoryButton")
|
||||
self.history_button.setIcon(_painted_reception_action_icon("info", "#3F4E75"))
|
||||
@@ -3847,7 +3853,6 @@ class ReceptionPage(QWidget):
|
||||
self.more_button = QPushButton("更多", hero)
|
||||
self.more_button.setObjectName("ReceptionMoreButton")
|
||||
more_menu = QMenu(self.more_button)
|
||||
more_menu.addAction("通知医助").triggered.connect(self._notify_assistant)
|
||||
edit_action = more_menu.addAction("编辑病历")
|
||||
edit_action.setVisible(self._can_edit)
|
||||
edit_action.triggered.connect(self._edit_diagnosis)
|
||||
@@ -3865,8 +3870,6 @@ class ReceptionPage(QWidget):
|
||||
action_compat = QWidget(hero)
|
||||
action_compat.setFixedSize(0, 0)
|
||||
action_compat.move(-100, -100)
|
||||
self.notify_button = QPushButton("通知医助", action_compat)
|
||||
self.notify_button.clicked.connect(self._notify_assistant)
|
||||
self.edit_button = QPushButton("编辑病历", action_compat)
|
||||
self.edit_button.setProperty("variant", "secondary")
|
||||
self.edit_button.clicked.connect(self._edit_diagnosis)
|
||||
|
||||
Reference in New Issue
Block a user