diff --git a/inventory-backend/app/api/v1/inbound/stock.py b/inventory-backend/app/api/v1/inbound/stock.py
index 1230e9f..53db8a1 100644
--- a/inventory-backend/app/api/v1/inbound/stock.py
+++ b/inventory-backend/app/api/v1/inbound/stock.py
@@ -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
diff --git a/inventory-web/src/views/stock/stocktake/index.vue b/inventory-web/src/views/stock/stocktake/index.vue
index 3fdcee5..bcdaf5e 100644
--- a/inventory-web/src/views/stock/stocktake/index.vue
+++ b/inventory-web/src/views/stock/stocktake/index.vue
@@ -321,6 +321,9 @@
已盘
未盘
+
+ {{ modeLabel(listMode) }}
+
总品项: {{ stats.total }} | 已盘: {{ stats.scanned }} | 未盘: {{ stats.total - stats.scanned }}
@@ -339,8 +342,16 @@
-
-
+
+
+
+ —
+ {{ row.stock_qty }}
+
+
-
+
@@ -576,6 +588,8 @@ const listLimit = ref(20)
const listKeyword = ref('')
const listLoading = ref(false)
const listData = ref([])
+// 当前列表的盘点模式(由后端下发),用于表头提示;数据屏蔽已在后端完成
+const listMode = ref(null)
const listStatusFilter = ref<'all' | 'counted' | 'uncounted'>('all')
const allStockItems = ref([]) // 全量应盘物资(盘点基数)
const totalStockCount = ref(0) // ★ 全量应盘物资总数(不受limit限制)
@@ -1334,6 +1348,7 @@ const fetchInventoryList = async (silent = false) => {
listData.value = data.list || []
listTotalFiltered.value = data.total || 0
totalScannedCount.value = data.total_scanned || 0
+ listMode.value = data.mode || null
} catch (e) {
if (!silent) ElMessage.error('获取盘点清单失败')
@@ -1566,6 +1581,9 @@ const goToVarianceReview = () => {
text-align: center;
line-height: 1.5;
}
+/* 盲盘时后端不下发账面数/差异,用「—」表示未下发(区别于真实的 0) */
+.cell-blinded { color: #c0c4cc; }
+
/* ★ 创建盘点任务表单(模式 / 范围) */
.task-form {
width: 100%;