feat(stocktake): 明/盲盘由后端强制驱动,前端解除屏蔽

原实现是前端把「账面数」「差异」两列用 HTML 注释藏掉 —— 数据仍在
HTTP 响应里明文下发,抓包或用改过的客户端即可看到,等于没有屏蔽。

【后端】/draft/merged-list 先查该 session_id 的 StocktakeSession.mode:
- blind:stock_qty 与 diff_qty 一律置 None,真实账面数不出现在响应中
- open :正常下发
差异必须一并置空 —— diff_qty 由账面数算出,下发差异等于变相泄漏账面数。
响应新增 data.mode 供前端提示。

Fail-Safe:查不到会话行时按盲盘处理。宁可界面少显示两列,也不能因为
会话记录缺失就把账面数泄漏出去。

【前端】删除屏蔽用的 HTML 注释,恢复两列正常渲染,不再承担数据屏蔽职责。
但 null 必须渲染为「—」而非 0:原 差异 模板用 `row.diff_qty || 0`,
会把「未下发」显示成「无差异」,工人会误以为账实相符。
另在抽屉表头加模式标签,便于核对。

实测:
  盲盘 → 账面数=None 差异=None   mode=blind
  明盘 → 账面数=1.0  差异=-1.0   mode=open
  未知 session_id → 同盲盘(Fail-Safe 生效)
This commit is contained in:
yueli
2026-09-11 13:34:36 +08:00
parent 091847596e
commit 97c1a9131c
2 changed files with 38 additions and 9 deletions

View File

@ -1900,6 +1900,12 @@ def get_draft_merged_list():
params['offset'] = offset
rows = db.session.execute(db.text(data_sql), params).fetchall()
# ── 明/盲盘控制:账面数与差异由后端强制决定是否下发 ──
# ★ Fail-Safe:查不到会话配置时按盲盘处理。宁可让界面少显示两列,
# 也不能因为会话行缺失就把真实账面数泄漏出去。
session = StocktakeSession.query.filter_by(session_id=session_id).first()
is_blind = True if session is None else (session.mode == STOCKTAKE_MODE_BLIND)
# ── 组装结果 ──
items = []
for row in rows:
@ -1915,9 +1921,12 @@ def get_draft_merged_list():
'sku': row.sku or '',
'material_name': row.mat_name or '',
'spec_model': row.mat_spec or '',
'stock_qty': stock_qty,
# ★ 盲盘:账面数置空,真实值不得出现在 HTTP 响应里
'stock_qty': None if is_blind else stock_qty,
'quantity': draft_qty,
'diff_qty': round(diff_qty, 4),
# ★ 盲盘:差异同样置空 —— diff_qty 由账面数算出,
# 下发差异等于变相泄漏账面数
'diff_qty': None if is_blind else round(diff_qty, 4),
'remark': row.draft_remark or '',
'warehouse_location': row.warehouse_location or '',
})
@ -1927,7 +1936,9 @@ def get_draft_merged_list():
'data': {
'list': items, 'total': total,
'total_scanned': total_scanned,
'page': page, 'pageSize': page_size
'page': page, 'pageSize': page_size,
# 前端据此决定表头提示;真正的数据屏蔽已经在上面做完了
'mode': session.mode if session is not None else STOCKTAKE_MODE_BLIND,
}
}), 200