From 38f18f19261fb38f2d938877a020b68df926b8a4 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Wed, 29 Jul 2026 11:25:04 +0800 Subject: [PATCH] docs: mark storage-release ready filter as implemented Add design spec, plan checkboxes, and interactive filter demo for the pending readyForReviewOnly feature. Co-authored-by: Cursor --- ...se-pending-both-completed-filter-demo.html | 596 ++++++++++++++++++ ...29-storage-release-pending-ready-filter.md | 434 +++++++++++++ ...age-release-pending-ready-filter-design.md | 171 +++++ 3 files changed, 1201 insertions(+) create mode 100644 docs/superpowers/demos/2026-07-29-storage-release-pending-both-completed-filter-demo.html create mode 100644 docs/superpowers/plans/2026-07-29-storage-release-pending-ready-filter.md create mode 100644 docs/superpowers/specs/2026-07-29-storage-release-pending-ready-filter-design.md diff --git a/docs/superpowers/demos/2026-07-29-storage-release-pending-both-completed-filter-demo.html b/docs/superpowers/demos/2026-07-29-storage-release-pending-both-completed-filter-demo.html new file mode 100644 index 00000000..2460aa18 --- /dev/null +++ b/docs/superpowers/demos/2026-07-29-storage-release-pending-both-completed-filter-demo.html @@ -0,0 +1,596 @@ + + + + + + 入库放行审核 · 待审核双工单完成过滤 Demo + + + + + + +
+
+

入库放行审核 · 待审核过滤 Demo

+

+ 客户诉求:【待审核】默认只展示「质检工单」与「生产工单」均为完成的记录; + 增加一个选项,默认不勾选;勾选后展示全部待审核信息。 +

+
+ +
+ 默认(未勾选):仅双工单都完成 + 勾选后:展示全部待审核 + 默认会被隐藏的行 +
+ +
+
+

审核列表

+
+ +
+
+ + +
+
+ +
+
+
+ +
样本编码/入库编码/样本名称
+
+
+ +
全部
+
+
+ +
全部
+
+
+ +
全部
+
+
+ +
+ +
+ + +
+
+
+ +
+ 已选 0 项 + + +
+ +
+ 当前模式:仅展示质检 + 生产均已完成(默认) +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
样本编码样本名称质检工单生产工单审核结论说明
☐YB-202607-001脐带血样本 A已完成已完成待审核默认可见
☐YB-202607-002外周血样本 B已完成已完成待审核默认可见
☐YB-202607-003脂肪组织 C进行中已完成待审核质检未完成 → 默认隐藏
☐YB-202607-004胎盘组织 D已完成待配置待审核生产未完成 → 默认隐藏
☐YB-202607-005骨髓样本 E无工单进行中待审核无质检算完成,但生产未完成 → 默认隐藏
☐YB-202607-006脐带组织 F已完成无工单待审核无生产工单算完成 → 默认可见
☐YB-202607-007科研样本 G无工单无工单待审核双无工单均算完成 → 默认可见
+
+ +
+ 共 4 条(默认过滤后) + 第 1 页 / 10 条每页 +
+
+ +
+
+

现状(已上线)

+

待审核筛选区有「质检工单是否完成」下拉:是 / 否 / 全部,默认「是」。

+
    +
  • 只约束质检工单
  • +
  • 不约束生产工单
  • +
  • 三态下拉,交互偏重
  • +
+
+
+

本 Demo 提案 推荐方向

+

用一个复选框替换原下拉:未勾选 = 质检侧+生产侧均完成;勾选 = 全部。无工单算该侧完成。

+
    +
  • 与客户描述「默认不勾选 / 勾选展示全部」一致
  • +
  • 去掉「否」单独筛未完成的能力
  • +
  • 仅作用于「待审核」Tab;API 参数 readyForReviewOnly
  • +
+
+
+ +

+ 文件位置:docs/superpowers/demos/2026-07-29-storage-release-pending-both-completed-filter-demo.html + · 本地打开即可交互。本页仅演示交互,不接真实 API。 +

+
+ + + + diff --git a/docs/superpowers/plans/2026-07-29-storage-release-pending-ready-filter.md b/docs/superpowers/plans/2026-07-29-storage-release-pending-ready-filter.md new file mode 100644 index 00000000..04d4b8b8 --- /dev/null +++ b/docs/superpowers/plans/2026-07-29-storage-release-pending-ready-filter.md @@ -0,0 +1,434 @@ +# 入库放行审核 · 待审核双工单就绪过滤 Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 待审核 Tab 默认只展示质检侧与生产侧均「已完成」的入库放行记录;用「展示全部待审核」复选框替换原质检下拉,勾选后展示全部待审核。 + +**Architecture:** 列表 API 新增可选布尔参数 `readyForReviewOnly`;为 `true` 时在 `list_reviews` 上对质检/生产未完成状态做双 `NOT EXISTS`(无工单算该侧完成)。前端仅在待审核展示复选框,默认/重置/切回待审核均为不勾选,并停止传 `qcWorkOrderCompleted`。 + +**Tech Stack:** FastAPI + SQLAlchemy(backend)、Vue 3 + Element Plus(web-admin)、pytest + +**Spec:** `docs/superpowers/specs/2026-07-29-storage-release-pending-ready-filter-design.md` + +--- + +## File Map + +| 文件 | 职责 | +|------|------| +| `backend/tests/test_storage_release_review_ready_filter.py` | **新建** `normalize_ready_for_review_only` 单测 | +| `backend/app/crud/storage_release_review.py` | normalize + 生产未完成 EXISTS + `list_reviews` 过滤 | +| `backend/app/api/storage_release_review.py` | Query `readyForReviewOnly` | +| `web-admin/src/api/storage-release-review.ts` | 列表 params 增加 `readyForReviewOnly?: boolean` | +| `web-admin/src/views/quality-inspection/storage-release-review/index.vue` | 复选框替换下拉;默认/重置/切 Tab;请求传参 | + +--- + +### Task 1: Backend — normalize + 双 NOT EXISTS 过滤 + API + +**Files:** +- Create: `backend/tests/test_storage_release_review_ready_filter.py` +- Modify: `backend/app/crud/storage_release_review.py` +- Modify: `backend/app/api/storage_release_review.py` + +- [x] **Step 1: 写失败单测(规范化函数)** + +创建 `backend/tests/test_storage_release_review_ready_filter.py`: + +```python +from app.crud.storage_release_review import normalize_ready_for_review_only + + +def test_normalize_ready_for_review_only_true_values(): + assert normalize_ready_for_review_only(True) is True + assert normalize_ready_for_review_only("true") is True + assert normalize_ready_for_review_only("TRUE") is True + assert normalize_ready_for_review_only("1") is True + assert normalize_ready_for_review_only("yes") is True + assert normalize_ready_for_review_only(" YES ") is True + + +def test_normalize_ready_for_review_only_non_true_is_none(): + """Only explicit true enables the filter; false/unknown/absent → no filter.""" + assert normalize_ready_for_review_only(None) is None + assert normalize_ready_for_review_only(False) is None + assert normalize_ready_for_review_only("") is None + assert normalize_ready_for_review_only("false") is None + assert normalize_ready_for_review_only("0") is None + assert normalize_ready_for_review_only("no") is None + assert normalize_ready_for_review_only("maybe") is None +``` + +- [x] **Step 2: 跑单测确认失败** + +```bash +cd backend && source venv/bin/activate && pytest tests/test_storage_release_review_ready_filter.py -v +``` + +Expected: FAIL(`normalize_ready_for_review_only` 未定义或导入失败) + +- [x] **Step 3: 实现 normalize、生产未完成 EXISTS,并接入 `list_reviews`** + +在 `backend/app/crud/storage_release_review.py`,于 `normalize_qc_work_order_completed` **之后**增加: + +```python +def normalize_ready_for_review_only(raw) -> Optional[bool]: + """Return True when ready-only filter should apply; None means no filter.""" + if raw is None: + return None + if isinstance(raw, bool): + return True if raw else None + s = str(raw).strip().lower() + if s in ("true", "1", "yes"): + return True + return None + + +def _production_work_order_unfinished_exists_for_review_sample(tenant_no: str): + """True if sample has any unfinished inbound-side production WO (dpz/jxz).""" + conds = [ + BizProductionWorkOrder.tenant_no == tenant_no, + BizProductionWorkOrder.del_flag == 0, + BizProductionWorkOrder.sample_code.isnot(None), + BizProductionWorkOrder.sample_code != "", + eq_unicode( + BizProductionWorkOrder.sample_code, BizStorageReleaseReview.sample_code + ), + BizStorageReleaseReview.sample_code.isnot(None), + BizStorageReleaseReview.sample_code != "", + BizProductionWorkOrder.work_order_status.in_(("dpz", "jxz")), + ] + return ( + exists() + .where(and_(*conds)) + .correlate(BizStorageReleaseReview) + ) +``` + +(`BizProductionWorkOrder`、`eq_unicode`、`exists`、`and_` 已在文件中导入,无需新增 import。) + +在 `list_reviews` 签名中增加参数(放在 `qc_work_order_completed` 之后): + +```python + ready_for_review_only=None, +``` + +在现有 `qc_done = normalize_qc_work_order_completed(...)` 块**之后**、`if user_info:` **之前**插入: + +```python + if normalize_ready_for_review_only(ready_for_review_only) is True: + # 无未完成质检/生产工单 ⇒ 该侧完成(含零工单) + q0 = q0.filter( + ~_qc_work_order_exists_for_review_sample( + tenant_no, unfinished_only=True + ), + ~_production_work_order_unfinished_exists_for_review_sample(tenant_no), + ) +``` + +保留现有 `qc_work_order_completed` 逻辑不动(本页前端停用;API 兼容)。 + +- [x] **Step 4: API 增加 Query 并下传** + +修改 `backend/app/api/storage_release_review.py` 的 `list_storage_release_reviews`: + +在 `qcWorkOrderCompleted: Optional[bool] = Query(None),` 后增加: + +```python + readyForReviewOnly: Optional[bool] = Query(None), +``` + +在 `srr_svc.list_reviews(...)` 调用中增加: + +```python + ready_for_review_only=readyForReviewOnly, +``` + +- [x] **Step 5: 跑单测确认通过** + +```bash +cd backend && source venv/bin/activate && pytest tests/test_storage_release_review_ready_filter.py tests/test_storage_release_review_qc_completed.py -v +``` + +Expected: PASS(新旧 normalize 单测均绿) + +- [x] **Step 6: Commit** + +```bash +git add backend/tests/test_storage_release_review_ready_filter.py \ + backend/app/crud/storage_release_review.py \ + backend/app/api/storage_release_review.py +git commit -m "$(cat <<'EOF' +feat(storage-release): add readyForReviewOnly list filter + +Default pending list can exclude rows with unfinished QC or production work orders via SQL NOT EXISTS. +EOF +)" +``` + +--- + +### Task 2: Frontend — API 类型 + 复选框替换下拉 + +**Files:** +- Modify: `web-admin/src/api/storage-release-review.ts` +- Modify: `web-admin/src/views/quality-inspection/storage-release-review/index.vue` + +- [x] **Step 1: API params 增加 `readyForReviewOnly`** + +修改 `web-admin/src/api/storage-release-review.ts` 中 `fetchStorageReleaseReviewList`: + +```typescript +export function fetchStorageReleaseReviewList(params?: { + page?: number + pageSize?: number + receptionSource?: string + reviewConclusion?: string + storageStatus?: string + keyword?: string + reviewPhase?: 'pending' | 'reviewed' + qcWorkOrderCompleted?: boolean + readyForReviewOnly?: boolean +}) { + return request.get>({ + url: '/web/admin/storage-release-reviews', + params + }) +} +``` + +(保留 `qcWorkOrderCompleted` 类型以免其它调用方类型报错;本页不再传。) + +- [x] **Step 2: 模板 — 去掉质检下拉与 5 列栅格,加复选框** + +在 `index.vue` 模板中: + +1) 将 `filter-grid` 改回普通 4 列(去掉 `storage-release-filter-grid--5` 与内联 `gridTemplateColumns`): + +```vue +
+``` + +2) **删除**整块: + +```vue + + ... + +``` + +3) 在 `filter-actions-row` 内、`.filter-actions-end` **之前**插入(仅待审核): + +```vue +
+ +
+ ... +
+
+``` + +(若项目 `filter-actions-row` 默认把内容推到右侧,给 `.storage-release-ready-check` 设 `margin-right: auto`,见 Step 4 样式。) + +- [x] **Step 3: script — 状态、请求、重置、切 Tab** + +删除: + +```typescript + const qcWorkOrderCompletedOptions = [ ... ] +``` + +将 `searchForm` 改为: + +```typescript + const searchForm = reactive({ + receptionSource: '', + reviewConclusion: '', + storageStatus: '', + keyword: '', + showAllPending: false + }) +``` + +`loadData` 中替换 `qcParam` 逻辑: + +```typescript + async function loadData() { + loading.value = true + try { + const readyOnly = + activeTab.value === 'pending' && !searchForm.showAllPending ? true : undefined + const res = await fetchStorageReleaseReviewList({ + page: pagination.page, + pageSize: pagination.pageSize, + receptionSource: searchForm.receptionSource || undefined, + reviewConclusion: searchForm.reviewConclusion || undefined, + storageStatus: searchForm.storageStatus || undefined, + keyword: searchForm.keyword || undefined, + reviewPhase: activeTab.value, + readyForReviewOnly: readyOnly + }) + tableData.value = res.list || [] + pagination.total = res.total ?? 0 + } finally { + loading.value = false + } + } +``` + +`handleTabChange`: + +```typescript + function handleTabChange(name: ReviewTab) { + if (activeTab.value === name) return + activeTab.value = name + pagination.page = 1 + selectedRows.value = [] + if (name === 'pending') { + searchForm.showAllPending = false + } + loadData() + } +``` + +`handleReset`: + +```typescript + function handleReset() { + searchForm.receptionSource = '' + searchForm.reviewConclusion = '' + searchForm.storageStatus = '' + searchForm.keyword = '' + searchForm.showAllPending = false + pagination.page = 1 + loadData() + } +``` + +说明:`watchDebounced(searchForm, ...)` 已存在;勾选复选框会自动触发搜索,无需额外 `@change`。 + +- [x] **Step 4: 样式 — 复选框行 + 去掉 5 列窄屏规则** + +在 `