更新
This commit is contained in:
@@ -1694,8 +1694,8 @@ class PrescriptionsPage(QWidget):
|
|||||||
def _set_ai_columns(self, enabled: bool) -> None:
|
def _set_ai_columns(self, enabled: bool) -> None:
|
||||||
changed = enabled != self._ai_enabled
|
changed = enabled != self._ai_enabled
|
||||||
self._ai_enabled = enabled
|
self._ai_enabled = enabled
|
||||||
self.table.setColumnHidden(11, not enabled)
|
for column in (11, 12):
|
||||||
self.table.setColumnHidden(12, not (enabled and self._agreement_visible))
|
self.table.setColumnHidden(column, not (enabled and self._agreement_visible))
|
||||||
if enabled:
|
if enabled:
|
||||||
header = self.table.horizontalHeader()
|
header = self.table.horizontalHeader()
|
||||||
header.moveSection(header.visualIndex(11), header.visualIndex(4) + 1)
|
header.moveSection(header.visualIndex(11), header.visualIndex(4) + 1)
|
||||||
@@ -1708,7 +1708,8 @@ class PrescriptionsPage(QWidget):
|
|||||||
|
|
||||||
def _set_agreement_visible(self, visible: bool) -> None:
|
def _set_agreement_visible(self, visible: bool) -> None:
|
||||||
self._agreement_visible = visible
|
self._agreement_visible = visible
|
||||||
self.table.setColumnHidden(12, not (self._ai_enabled and visible))
|
for column in (11, 12):
|
||||||
|
self.table.setColumnHidden(column, not (self._ai_enabled and visible))
|
||||||
self.ai_statistics_button.setVisible(
|
self.ai_statistics_button.setVisible(
|
||||||
visible and has_permission(self.permissions, "tcm.prescriptionAi/statistics", default=False)
|
visible and has_permission(self.permissions, "tcm.prescriptionAi/statistics", default=False)
|
||||||
and callable(getattr(self.repository, "prescription_ai_statistics", None)))
|
and callable(getattr(self.repository, "prescription_ai_statistics", None)))
|
||||||
|
|||||||
@@ -794,6 +794,33 @@ def test_revoked_agreement_cache_discards_flat_comparison_metadata() -> None:
|
|||||||
assert value["models"]["qwen"]["reason"] == sentinel
|
assert value["models"]["qwen"]["reason"] == sentinel
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("flag", [False, None, 1, "true"])
|
||||||
|
def test_unlisted_account_hides_ai_analysis_column_and_keeps_reports(
|
||||||
|
application: QApplication, immediate: None, monkeypatch: pytest.MonkeyPatch, flag: Any,
|
||||||
|
) -> None:
|
||||||
|
repository = Repository()
|
||||||
|
repository.agreement_visible = flag
|
||||||
|
opened = []
|
||||||
|
monkeypatch.setattr(page_module, "present_issued_prescription_ai", lambda *_args, **kwargs: opened.append(kwargs))
|
||||||
|
page = page_module.PrescriptionsPage(repository, ["*"], {"root": 1})
|
||||||
|
try:
|
||||||
|
page.resize(1366, 800)
|
||||||
|
page.show()
|
||||||
|
application.processEvents()
|
||||||
|
page.table.selectRow(0)
|
||||||
|
assert page.table.isColumnHidden(11) and page.table.isColumnHidden(12)
|
||||||
|
# Later status refreshes must not re-expose the analysis column.
|
||||||
|
page._set_ai_columns(True)
|
||||||
|
assert page.table.isColumnHidden(11) and page.table.isColumnHidden(12)
|
||||||
|
assert page.ai_report_button.isVisible() and page.ai_report_button.isEnabled()
|
||||||
|
assert any(button.accessibleName() == "AI 报告"
|
||||||
|
for button in page.table.cellWidget(0, 2).findChildren(QPushButton))
|
||||||
|
page.ai_report_button.click()
|
||||||
|
assert opened == [{"prescription_id": 801}]
|
||||||
|
finally:
|
||||||
|
page.close()
|
||||||
|
|
||||||
|
|
||||||
def test_list_capability_failure_revocation_and_late_status_cannot_restore_scores(
|
def test_list_capability_failure_revocation_and_late_status_cannot_restore_scores(
|
||||||
application: QApplication, immediate: None, monkeypatch: pytest.MonkeyPatch,
|
application: QApplication, immediate: None, monkeypatch: pytest.MonkeyPatch,
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -810,7 +837,7 @@ def test_list_capability_failure_revocation_and_late_status_cannot_restore_score
|
|||||||
page._load_ai_capabilities()
|
page._load_ai_capabilities()
|
||||||
page._ai_statuses_ready(old_statuses, [801, 802], old_token, page._generation)
|
page._ai_statuses_ready(old_statuses, [801, 802], old_token, page._generation)
|
||||||
page._ai_capabilities_ready({"agreement_visible": True}, old_capability_token, page._generation)
|
page._ai_capabilities_ready({"agreement_visible": True}, old_capability_token, page._generation)
|
||||||
assert page.table.isColumnHidden(12) and not page.table.isColumnHidden(11)
|
assert page.table.isColumnHidden(12) and page.table.isColumnHidden(11)
|
||||||
assert page.ai_statistics_button.isHidden()
|
assert page.ai_statistics_button.isHidden()
|
||||||
assert page.ai_report_button.isVisible()
|
assert page.ai_report_button.isVisible()
|
||||||
assert page._ai_statuses
|
assert page._ai_statuses
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
@@ -0,0 +1,26 @@
|
|||||||
|
# AI 分析列显隐只读复核
|
||||||
|
|
||||||
|
日期:2026-10-17。已读根目录 `AGENTS.md`;项目没有 `.trellis/`,因此没有可读的 workflow/spec。本次只读代码与既有测试;仅新增本报告,未改业务代码或测试,未连接生产。
|
||||||
|
|
||||||
|
## 结论与最小修复
|
||||||
|
|
||||||
|
- `prescriptions.py:1276` 初始化隐藏第 11 列;`1697` 是唯一运行时直接修改第 11 列显隐的位置。目前 `_set_ai_columns()` 仅按服务开关 `enabled` 显示“AI 分析”,因此一致度未授权时仍显示该列。
|
||||||
|
- 建议第 11、12 列统一使用 `self._ai_enabled and self._agreement_visible` 决定显示。在 `_set_ai_columns()` 中按新条件处理两列;在 `_set_agreement_visible()` 中同时更新两列,覆盖能力查询开始、失败、撤权、授权恢复及 statuses 顶层 flag 变化。只改前者会遗漏撤权立即隐藏与后续授权恢复。
|
||||||
|
- 保留 `_ai_enabled = enabled` 的服务状态含义,不能改成 `enabled and agreement_visible`。行内“AI 报告”在 `1589` 依赖 `_ai_enabled`;复用该变量表示授权会误删用户要求保留的按钮。
|
||||||
|
- 第 11 列除此之外没有 `hideColumn/showColumn/setColumnHidden` 路径。`_render_ai_statuses()` 只更新内容;表头移动/列宽设置不会改变显隐,无需修改。
|
||||||
|
|
||||||
|
## AI 报告入口条件
|
||||||
|
|
||||||
|
- 行内按钮:`1589`,服务启用、同时具备 reports/detail 权限、非空白处方;不依赖一致度授权,应保持。
|
||||||
|
- 工具栏按钮:`1884–1890`,非空白处方、reports/detail 权限、仓库支持 `list_prescription_ai_reports`;不依赖服务开关或一致度授权,应保持。
|
||||||
|
- 右键菜单:`1828–1838`,reports/detail 权限、仓库支持 reports、非空白处方;受限时仍显示“AI 报告”。
|
||||||
|
- `can_open_issued_ai()` 在 `issued_prescription_ai.py:402` 只检查 reports/detail 权限。现有统计与报告详情的一致度门禁不需要因本次列显隐要求改动。
|
||||||
|
|
||||||
|
## 必要回归
|
||||||
|
|
||||||
|
1. 服务启用但 capability 为 false、缺失或非布尔 true,以及 capability 查询失败:第 11、12 列均隐藏,工具栏与行内“AI 报告”仍存在;root/`*` 不豁免。
|
||||||
|
2. capability 已允许但 statuses 顶层 `agreement_visible` 未明确 true:两列隐藏;statuses 的 `enabled` 仍为 true,报告入口可用。
|
||||||
|
3. 已授权显示两列 → 重新查询能力时立即隐藏 → 撤权或失败保持隐藏,旧回调不能恢复;重新明确授权且 statuses 允许后恢复两列。
|
||||||
|
4. 保留服务关闭、无 statuses 权限、空白处方原行为;服务关闭仍可查看历史报告。
|
||||||
|
|
||||||
|
现有 `app/tests/test_issued_prescription_ai.py:813` 明确断言受限时第 11 列仍显示,需随新要求反转;该测试已覆盖能力失败、撤权、旧回调、工具栏报告保留,可扩展行内按钮断言。`test_list_rechecks_completed_scores_after_hide_and_show` 可补两列恢复断言。建议离线更新/目视检查 `artifacts/prescription-ai-visibility/list-restricted.png`;原截图脚本已有受限列表 fixture。
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# 未授权账号隐藏 AI 分析列
|
||||||
|
|
||||||
|
2026-10-17。用户补充范围:未被指定授权的账号隐藏已开处方列表“AI 分析”列,保留“AI 报告”按钮。
|
||||||
|
|
||||||
|
修改 `app/src/doctor_workstation/ui/pages/prescriptions.py` 的两个列显隐入口,统一按分析服务启用且当前账号获授权显示第 11/12 列。能力查询开始、失败、撤销、后续状态响应均会更新两列;服务状态仍独立保留,工具栏及行内报告入口继续可用。
|
||||||
|
|
||||||
|
验证结果:
|
||||||
|
|
||||||
|
- 修复前定向 5 个场景失败,复现未授权及能力查询失败后 AI 分析列仍显示。
|
||||||
|
- `test_issued_prescription_ai.py`:142 passed。
|
||||||
|
- `test_prescription_ui.py`:23 passed。
|
||||||
|
- 最终补充行内报告入口断言后,定向 5 个场景通过,含 toolbar 报告点击、root 不豁免、缺失/非布尔能力及旧回调。
|
||||||
|
- Ruff、限定变更文件 `git diff --check` 通过。
|
||||||
|
- 使用真实主题与内存数据离屏核对 [预览](ai-analysis-column-hidden.png):两列已隐藏,AI 报告入口保留。
|
||||||
|
|
||||||
|
本次仅修改桌面端源码和测试,未打包部署、不涉及新增 SQL;前次授权配置迁移若已执行,本次无需再执行数据库变更。更新桌面端后生效。
|
||||||
Reference in New Issue
Block a user