更新bug

This commit is contained in:
Your Name
2026-08-20 17:47:14 +08:00
parent 35f91ee37a
commit 5794f60c5d
67 changed files with 9257 additions and 1287 deletions
@@ -3,6 +3,7 @@
from __future__ import annotations
import re
import sqlite3
from collections.abc import Mapping, Sequence
from contextlib import suppress
from typing import Any
@@ -69,6 +70,7 @@ from ..widgets import (
page_total,
run_async,
)
from .local_audio_queue import LocalAudioQueueDialog
from .prescription_ai import can_open_diagnosis_ai_report, present_diagnosis_ai_report
_PHONE_PERMISSION = "tcm.diagnosis/phonePlain"
@@ -747,6 +749,7 @@ class DiagnosisDialog(QDialog):
"""
saved = Signal()
_local_audio_upload_completed = Signal(int, int)
def __init__(
self,
@@ -841,6 +844,10 @@ class DiagnosisDialog(QDialog):
self._recording_players: list[RecordingPlayerDialog] = []
self._inline_recording_cells: list[RecordingPlaybackCell] = []
self._last_order_detail_dialog: QDialog | None = None
self._local_audio_dialog: LocalAudioQueueDialog | None = None
self._local_audio_upload_manager: Any = None
self._local_audio_upload_listener: Any = None
self._video_reload_pending = False
self._orders_page = 1
self._orders_page_size = 10
self._orders_total = 0
@@ -868,6 +875,10 @@ class DiagnosisDialog(QDialog):
self._daily_panels: list[DailyRecordPanel] = []
self._owner = None
self._owner_filter_installed = False
self._local_audio_upload_completed.connect(
self._local_audio_upload_succeeded,
type=Qt.ConnectionType.QueuedConnection,
)
self.setObjectName("DiagnosisDialogRoot")
self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.FramelessWindowHint)
@@ -1433,6 +1444,11 @@ class DiagnosisDialog(QDialog):
hint.setWordWrap(True)
toolbar.addWidget(hint, 1)
toolbar.addStretch(1)
self.local_audio_queue_button = QPushButton("本机录音文件")
self.local_audio_queue_button.setObjectName("DiagnosisLocalAudioQueueButton")
self.local_audio_queue_button.setAccessibleName("查看本机录音文件及上传状态")
self.local_audio_queue_button.clicked.connect(self._open_local_audio_queue)
toolbar.addWidget(self.local_audio_queue_button)
self.video_upload_button = QPushButton("上传本地回放")
self.video_upload_button.setProperty("variant", "primary")
self.video_upload_button.clicked.connect(
@@ -1556,10 +1572,10 @@ class DiagnosisDialog(QDialog):
),
"video": (
("录制回放", 440),
("房间号", 180),
("开始时间", 170),
("结束时间", 170),
("通话类型", 100),
("房间号", 180),
("时长", 110),
("状态", 90),
("录制 / 文字", 120),
@@ -1695,6 +1711,10 @@ class DiagnosisDialog(QDialog):
)
self.prescribe_button.setVisible(self._editable and self._can_prescribe)
self.video_upload_button.setVisible(self._editable and self._can_video_upload)
self.local_audio_queue_button.setVisible(self._can_video_upload)
self.local_audio_queue_button.setEnabled(
self._diagnosis_id > 0 and self._can_video_upload
)
offset_visible = self._editable and self._can_offset
self.order_offset.setVisible(offset_visible)
self.order_offset_save.setVisible(offset_visible)
@@ -1914,6 +1934,10 @@ class DiagnosisDialog(QDialog):
with suppress(RuntimeError):
self._last_order_detail_dialog.close()
self._last_order_detail_dialog = None
if self._local_audio_dialog is not None:
with suppress(RuntimeError):
self._local_audio_dialog.close()
self._local_audio_dialog = None
self._diagnosis_id = int(diagnosis_id)
self._patient_id = 0
self._editable = bool(
@@ -1939,6 +1963,7 @@ class DiagnosisDialog(QDialog):
self._tab_generations[key] += 1
self._loaded_tabs.clear()
self._loading_tabs.clear()
self._video_reload_pending = False
self._daily_todo_status = None
self._orders_page = 1
self._orders_total = 0
@@ -2208,6 +2233,8 @@ class DiagnosisDialog(QDialog):
self._ensure_tab_loaded(self._current_tab_key(), force=True)
def _invalidate_requests(self) -> None:
self._stop_watching_local_audio_uploads()
self._video_reload_pending = False
self._generation += 1
self._save_generation += 1
self._orders_generation += 1
@@ -2232,6 +2259,11 @@ class DiagnosisDialog(QDialog):
with suppress(RuntimeError):
order_dialog.close()
self._last_order_detail_dialog = None
local_audio_dialog = getattr(self, "_local_audio_dialog", None)
if local_audio_dialog is not None:
with suppress(RuntimeError):
local_audio_dialog.close()
self._local_audio_dialog = None
if hasattr(self, "readonly_loading"):
self.readonly_loading.hide()
if hasattr(self, "drawer_loading"):
@@ -2474,7 +2506,11 @@ class DiagnosisDialog(QDialog):
def _tab_changed(self, _index: int) -> None:
self._sync_save_button()
if self._authoritative_detail_loaded and not self._standalone_readonly:
self._ensure_tab_loaded(self._current_tab_key())
key = self._current_tab_key()
if key == "video":
self._reload_video_records(self._diagnosis_id)
else:
self._ensure_tab_loaded(key)
def _load_visible_readonly_sections(self) -> None:
permission_map = {key: codes for key, _label, codes in _TAB_DEFINITIONS}
@@ -2635,6 +2671,8 @@ class DiagnosisDialog(QDialog):
panel.set_messages(rows)
if not self._standalone_readonly and self._current_tab_key() == key:
self._clear_message()
if key == "video":
self._flush_video_reload_if_pending(diagnosis_id)
def _tab_load_error(
self,
@@ -2650,6 +2688,8 @@ class DiagnosisDialog(QDialog):
self._set_tab_error(key, text)
if not self._standalone_readonly and self._current_tab_key() == key:
self._show_message(text, "danger", action_text="重试")
if key == "video":
self._flush_video_reload_if_pending(diagnosis_id)
def _load_daily_range(self, start: str, end: str, *, force: bool = False) -> None:
key = "daily"
@@ -3116,6 +3156,91 @@ class DiagnosisDialog(QDialog):
"video",
)
def _open_local_audio_queue(self) -> None:
if self._diagnosis_id <= 0 or not self._can_video_upload:
self._show_message("当前账号无本机录音上传权限或接口不可用。", "warning")
return
current = self._local_audio_dialog
if current is not None and current.isVisible():
current.raise_()
current.activateWindow()
return
try:
dialog = LocalAudioQueueDialog(
self.repository,
self._diagnosis_id,
self,
)
except (OSError, RuntimeError, sqlite3.Error) as error:
self._show_message(f"无法打开本机录音文件:{error}", "danger")
return
self._local_audio_dialog = dialog
opened_diagnosis_id = self._diagnosis_id
self._watch_local_audio_uploads(dialog.manager)
def clear_dialog(_result: int) -> None:
if self._local_audio_dialog is dialog:
self._local_audio_dialog = None
dialog.finished.connect(clear_dialog)
dialog.open()
# Opening the queue commonly follows a background upload that completed
# before this dialog existed, so also refresh the server-backed rows now.
self._reload_video_records(opened_diagnosis_id)
def _local_audio_upload_succeeded(
self,
diagnosis_id: int,
_call_record_id: int,
) -> None:
if self._local_audio_upload_manager is None:
return
self._reload_video_records(diagnosis_id)
def _reload_video_records(self, diagnosis_id: int) -> None:
if int(diagnosis_id) != self._diagnosis_id:
return
if "video" in self._loading_tabs:
self._video_reload_pending = True
return
self._video_reload_pending = False
self._loaded_tabs.discard("video")
self._ensure_tab_loaded("video", force=True)
def _watch_local_audio_uploads(self, manager: Any) -> None:
if self._local_audio_upload_manager is manager:
return
self._stop_watching_local_audio_uploads()
def notify(record: Any) -> None:
with suppress(RuntimeError):
self._local_audio_upload_completed.emit(
int(record.diagnosis_id),
int(record.call_record_id or 0),
)
manager.add_upload_listener(notify)
self._local_audio_upload_manager = manager
self._local_audio_upload_listener = notify
def _stop_watching_local_audio_uploads(self) -> None:
manager = self._local_audio_upload_manager
listener = self._local_audio_upload_listener
self._local_audio_upload_manager = None
self._local_audio_upload_listener = None
if manager is not None and listener is not None:
with suppress(Exception):
manager.remove_upload_listener(listener)
def _flush_video_reload_if_pending(self, diagnosis_id: int) -> None:
if not self._video_reload_pending or diagnosis_id != self._diagnosis_id:
return
self._video_reload_pending = False
QTimer.singleShot(
0,
lambda expected_id=diagnosis_id: self._reload_video_records(expected_id),
)
def _sync_chat_archive(self) -> None:
if not self._can_chat_sync or self._diagnosis_id <= 0:
self._show_message("当前账号无聊天归档同步权限或接口不可用。", "warning")
@@ -3616,6 +3741,7 @@ class DiagnosisDialog(QDialog):
self._stop_inline_recordings()
matrix: list[tuple[Any, ...]] = []
row_urls: list[list[str]] = []
row_audio_urls: list[list[str]] = []
record_ids: list[int] = []
transcripts: list[str] = []
for row in rows:
@@ -3629,6 +3755,22 @@ class DiagnosisDialog(QDialog):
if url and url not in normalized:
normalized.append(url)
row_urls.append(normalized)
raw_audio_urls = first_value(
row,
"local_audio_urls_list",
"local_audio_urls",
default=[],
) or []
if isinstance(raw_audio_urls, str) or not isinstance(
raw_audio_urls, Sequence
):
raw_audio_urls = [raw_audio_urls]
normalized_audio: list[str] = []
for candidate in raw_audio_urls:
url = str(candidate or "").strip()
if url and url not in normalized_audio:
normalized_audio.append(url)
row_audio_urls.append(normalized_audio)
record_ids.append(_int(first_value(row, "id", "call_record_id"), 0))
transcript = self._call_transcript_text(row)
transcripts.append(transcript)
@@ -3651,22 +3793,41 @@ class DiagnosisDialog(QDialog):
recording_status = first_value(
row, "recording_status_text", "record_status_text", "record_status"
)
local_audio_status = first_value(
row,
"local_audio_status_text",
default="本机录音已保存" if normalized_audio else "无本机录音",
)
transcript_status = first_value(
row,
"transcription_status_text",
"transcript_status_text",
default="文字已生成" if transcript else "未生成文字",
)
room_id = str(
first_value(
row,
"room_id_text",
"room_id",
"room_no",
default="",
)
or ""
).strip()
matrix.append(
(
"" if normalized else "暂无录制回放",
room_id or "历史记录未保存",
first_value(row, "start_time_text", "start_time"),
first_value(row, "end_time_text", "end_time"),
call_type,
first_value(row, "room_id", "room_no"),
first_value(row, "duration_text", "duration"),
status,
f"{display_text(recording_status)}\n{display_text(transcript_status)}",
(
f"云端视频:{display_text(recording_status)}\n"
f"本机录音:{display_text(local_audio_status)}\n"
f"转写文字:{display_text(transcript_status)}"
),
"",
)
)
@@ -3692,6 +3853,19 @@ class DiagnosisDialog(QDialog):
item.setText("")
call_record_id = record_ids[row_index]
actions: list[QPushButton] = []
audio_urls = row_audio_urls[row_index]
if audio_urls and call_record_id > 0:
play_audio = self._action_button(
"播放录音", f"播放通话记录 #{call_record_id} 的本机混音录音"
)
play_audio.setObjectName("DiagnosisLocalAudioPlayback")
play_audio.setProperty("callRecordId", call_record_id)
play_audio.clicked.connect(
lambda _checked=False, target=audio_urls[0]: self._open_recording_player(
target
)
)
actions.append(play_audio)
transcript = transcripts[row_index]
if transcript and call_record_id > 0:
view_transcript = self._action_button(