fix(stocktake): 拉开主副按钮层级防误触,明细增加库位列

【按钮层级】场景 A(已有进行中的盘点)
原实现主按钮是「加入当前盘点」,次入口是个不起眼的文字链接
「开启新一轮盘点」—— 二者视觉权重接近,而后者会终结本司其他 PDA
正在使用的会话,误触代价高。

现改为:
- 主按钮:绿色「继续当前盘点」,高度放到 66px、字号 19px
  (新增 .action-btn-hero),平板大屏上一眼可辨、一按即中
- 次按钮:红色镂空「结束当前并开启新盘点」,点击走 10 秒倒计时强确认
- 确认弹窗措辞由「原有数据将保留」改为明确告知**会话将被终结**:
  「该会话将标记为已结束,其他设备不能再加入」
- 倒计时确认通过后展开配置表单(而非直接开会话),让用户仍能选模式/范围;
  表单提交不再二次弹窗,避免重复确认

【库位列】明细抽屉新增「库位」列,紧跟规格之后 —— 找货刚需。
后端 merged-list 已下发该字段,实测单行返回含 warehouse_location='Y2/4/3/4',
无需改动。
This commit is contained in:
yueli
2026-09-11 13:53:53 +08:00
parent eabe70b00a
commit 325cc44469

View File

@ -46,23 +46,31 @@
</el-button>
</template>
<!-- 场景 A:已有进行中的盘点,且未主动选择「开启新一轮」 → 绿色「加入」 -->
<!-- 场景 A:已有进行中的盘点
主按钮 = 继续当前盘点(绿、加大),次按钮 = 结束当前并开启新盘点(红、镂空)。
两者视觉层级必须拉开 —— 次按钮会终结本司其他人正在用的会话,误触代价高。 -->
<template v-else-if="activeSession && !creatingNew">
<el-button
type="success"
size="large"
class="action-btn-full"
class="action-btn-full action-btn-hero"
@click="joinActiveSession"
:loading="btnLoading"
>
加入当前盘点
继续当前盘点
</el-button>
<div class="active-session-tip">
{{ modeLabel(activeSession.mode) }} · {{ scopeLabel(activeSession.scope_type) }},已扫 {{ activeSession.scanned }} 件<template v-if="activeSession.initiator">,发起人:{{ activeSession.initiator }}</template>
</div>
<!-- 次要入口:缺了它,本司一旦有过会话就永远开不了新一轮 -->
<el-button link type="primary" class="secondary-entry" @click="creatingNew = true">
开启新一轮盘点
<el-button
type="danger"
plain
size="large"
class="action-btn-full"
@click="endCurrentAndCreate"
:loading="btnLoading"
>
结束当前并开启新盘点
</el-button>
</template>
@ -90,7 +98,7 @@
抽盘:仅盘点近 30 天有出入库/借还记录的前 50 个活跃库位
</div>
<div v-if="creatingNew" class="task-form-warn">
开启新一轮会把当前进行中的盘点置为已结束(历史数据仍保留)
⚠️ 开启新一轮将<strong>终结当前会话</strong>:已扫数据完整保留,但其他设备不能再加入该会话
</div>
</div>
@ -215,7 +223,7 @@
<!-- ★ 新增: 防呆确认弹窗 -->
<el-dialog
v-model="showConfirmDialog"
title="⚠️ 确认开启新一轮盘点"
title="⚠️ 结束当前盘点"
width="400"
destroy-on-close
:close-on-click-modal="false"
@ -225,16 +233,20 @@
>
<div class="confirm-content">
<el-icon :size="48" color="#E6A23C"><WarningFilled /></el-icon>
<p class="confirm-text">当前公司已有盘点在进行中。开启新一轮会生成新的会话,<strong>原有数据将保留</strong>,但之后「加入当前盘点」只会进入最新的这个会话。确定开始吗?</p>
<p class="confirm-text">
即将<strong>结束当前进行中的盘点</strong>。<br />
已扫数据会完整保留,但该会话将标记为已结束,<strong>其他设备不能再加入</strong>。<br />
随后你可以配置并开启新一轮。确定继续吗?
</p>
</div>
<template #footer>
<el-button @click="cancelConfirm">取消</el-button>
<el-button
type="primary"
type="danger"
:disabled="countdown > 0"
@click="confirmStartNew"
>
{{ countdown > 0 ? `确认开启 (${countdown}s)` : '确认开启' }}
{{ countdown > 0 ? `确认结束 (${countdown}s)` : '确认结束' }}
</el-button>
</template>
</el-dialog>
@ -344,6 +356,9 @@
<el-table-column prop="sku" label="SKU" width="140" show-overflow-tooltip />
<el-table-column prop="material_name" label="名称" min-width="120" show-overflow-tooltip />
<el-table-column prop="spec_model" label="规格" width="120" show-overflow-tooltip />
<!-- ★ 库位:找货刚需,放在名称/规格后面。
后端 merged-list 已下发(SELECT cs.warehouse_location → 组装进 JSON) -->
<el-table-column prop="warehouse_location" label="库位" min-width="120" show-overflow-tooltip />
<!-- ★ 账面数与差异由**后端**按会话 mode 决定是否下发:
盲盘时这两个字段返回 null,前端不再做任何屏蔽。
注意 null 必须显示为「—」而不是 0 —— 用 `|| 0` 会把「未下发」
@ -890,26 +905,39 @@ const enterScanning = async (message: string) => {
ElMessage.success(message)
}
// 点击「开始新盘点」或次要入口「开启新一轮盘点」
// ★ 场景 A 次按钮「结束当前并开启新盘点」。
// 它会终结本司其他 PDA 正在使用的会话,代价高,必须走 10 秒倒计时强确认。
const endCurrentAndCreate = () => {
if (!activeSession.value) {
// 没有活跃会话(理论到不了这里),直接展开表单
creatingNew.value = true
return
}
showConfirmDialog.value = true
countdown.value = 10
if (countdownTimer) clearInterval(countdownTimer)
countdownTimer = setInterval(() => {
countdown.value--
if (countdown.value <= 0) {
clearInterval(countdownTimer!)
countdownTimer = null
}
}, 1000)
}
// 倒计时确认通过:先展开配置表单选模式/范围,不直接开会话
const confirmStartNew = () => {
if (countdown.value > 0) return
showConfirmDialog.value = false
creatingNew.value = true
}
// 创建表单提交。是否终结当前会话已在 endCurrentAndCreate 处确认过,这里不再二次弹窗
const startNewSession = async () => {
if (!selectedCompany.value) {
ElMessage.warning('请先选择公司')
return
}
// ★ 该公司已有进行中的盘点 → 二次确认(不删数据,只签发新会话)
if (activeSession.value) {
showConfirmDialog.value = true
countdown.value = 10
if (countdownTimer) clearInterval(countdownTimer)
countdownTimer = setInterval(() => {
countdown.value--
if (countdown.value <= 0) {
clearInterval(countdownTimer!)
countdownTimer = null
}
}, 1000)
return
}
await doStartNewSession()
}
@ -950,12 +978,6 @@ const joinActiveSession = async () => {
} finally { btnLoading.value = false }
}
// 弹窗确认后开启新一轮盘点(不再删除任何数据,故不叫 confirmClear)
const confirmStartNew = () => {
if (countdown.value > 0) return
doStartNewSession()
}
const cancelConfirm = () => {
showConfirmDialog.value = false
if (countdownTimer) {
@ -1560,6 +1582,12 @@ const goToVarianceReview = () => {
font-weight: bold;
margin: 0 !important;
}
/* 主按钮:平板大屏上要一眼可辨、一按即中,故比常规按钮再放大一档 */
.action-btn-hero {
height: 66px;
font-size: 19px;
letter-spacing: 1px;
}
.sub-text { font-size: 12px; opacity: 0.8; margin-left: 5px; }
/* ★ 公司选择器:多人协同的隔离维度 */