feat: enhance stocktake UX with 10s delay, sku search, sku retention and remove adjust btn
This commit is contained in:
@ -111,6 +111,32 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
|
<!-- ★ 新增: 防呆确认弹窗 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="showConfirmDialog"
|
||||||
|
title="⚠️ 确认清除盘点数据"
|
||||||
|
width="400"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
show-close
|
||||||
|
align-center
|
||||||
|
>
|
||||||
|
<div class="confirm-content">
|
||||||
|
<el-icon :size="48" color="#E6A23C"><WarningFilled /></el-icon>
|
||||||
|
<p class="confirm-text">存在未完成记录,开始新盘点将清除它们,确定吗?</p>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="cancelConfirm">取消</el-button>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
:disabled="countdown > 0"
|
||||||
|
@click="confirmClear"
|
||||||
|
>
|
||||||
|
{{ countdown > 0 ? `确认清除 (${countdown}s)` : '确认清除' }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="showQtyDialog"
|
v-model="showQtyDialog"
|
||||||
title="🔢 录入实盘数量"
|
title="🔢 录入实盘数量"
|
||||||
@ -266,12 +292,24 @@
|
|||||||
style="margin-bottom: 15px;"
|
style="margin-bottom: 15px;"
|
||||||
>
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
以下列表显示所有已结束盘点但尚未平账的差异记录。请逐条核实后,点击"确认平账"按钮调整系统库存。
|
以下列表显示所有已结束盘点但尚未平账的差异记录。请核实后进行后续处理。
|
||||||
</template>
|
</template>
|
||||||
</el-alert>
|
</el-alert>
|
||||||
|
|
||||||
|
<!-- ★ 新增: 差异列表搜索 -->
|
||||||
|
<el-input
|
||||||
|
v-model="searchSku"
|
||||||
|
placeholder="输入 SKU/条码/名称快速定位"
|
||||||
|
clearable
|
||||||
|
style="width: 250px; margin-bottom: 15px;"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<el-icon><Search /></el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
:data="varianceList"
|
:data="filteredVarianceList"
|
||||||
height="500"
|
height="500"
|
||||||
border
|
border
|
||||||
stripe
|
stripe
|
||||||
@ -315,22 +353,9 @@
|
|||||||
<el-tag v-else type="warning">待审核</el-tag>
|
<el-tag v-else type="warning">待审核</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" width="120" align="center" fixed="right">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button
|
|
||||||
v-if="!scope.row.is_processed && userStore.hasPermission('inventory_stocktake:operation')"
|
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
@click="handleAdjust(scope.row)"
|
|
||||||
>
|
|
||||||
确认平账
|
|
||||||
</el-button>
|
|
||||||
<span v-else class="text-gray">-</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<el-empty v-if="varianceList.length === 0" description="暂无待审核的差异记录" />
|
<el-empty v-if="filteredVarianceList.length === 0" :description="searchSku ? '未找到匹配的差异记录' : '暂无待审核的差异记录'" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -353,7 +378,7 @@ import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
|
|||||||
import { getAllStock } from '@/api/inbound/stock'
|
import { getAllStock } from '@/api/inbound/stock'
|
||||||
import QrScanner from '@/components/QrScanner/index.vue'
|
import QrScanner from '@/components/QrScanner/index.vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { Search, VideoPlay, VideoPause, List, Checked, Download, ArrowRight, Cloudy, Edit, EditPen, CameraFilled, Close } from '@element-plus/icons-vue'
|
import { Search, VideoPlay, VideoPause, List, Checked, Download, ArrowRight, Cloudy, Edit, EditPen, CameraFilled, Close, WarningFilled } from '@element-plus/icons-vue'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
|
|
||||||
@ -402,6 +427,16 @@ const showQtyDialog = ref(false)
|
|||||||
// ★ 新增: 差异审核对话框
|
// ★ 新增: 差异审核对话框
|
||||||
const showVarianceDialog = ref(false)
|
const showVarianceDialog = ref(false)
|
||||||
|
|
||||||
|
// ★ 新增: 差异列表搜索
|
||||||
|
const searchSku = ref('')
|
||||||
|
|
||||||
|
// ★ 新增: 盘点开始防呆倒计时
|
||||||
|
const countdown = ref(0)
|
||||||
|
let countdownTimer: any = null
|
||||||
|
|
||||||
|
// ★ 新增: 防呆确认弹窗显示状态
|
||||||
|
const showConfirmDialog = ref(false)
|
||||||
|
|
||||||
const allData = ref<StockItem[]>([])
|
const allData = ref<StockItem[]>([])
|
||||||
const scannedMap = ref<Map<string, number>>(new Map())
|
const scannedMap = ref<Map<string, number>>(new Map())
|
||||||
const borrowedQuantities = ref<Record<string, number>>({})
|
const borrowedQuantities = ref<Record<string, number>>({})
|
||||||
@ -492,19 +527,6 @@ const api = {
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
params: {}
|
params: {}
|
||||||
}),
|
}),
|
||||||
// ★ 新增: 单条库存调整
|
|
||||||
adjustStock: (draftId: number, stockId: number, diffQty: number, sourceTable: string, remark: string) => request({
|
|
||||||
url: '/v1/inbound/stock/adjust',
|
|
||||||
method: 'post',
|
|
||||||
data: {
|
|
||||||
draft_id: draftId,
|
|
||||||
stock_id: stockId, // 库存项ID
|
|
||||||
diff_qty: diffQty, // 差异数量(支持无草稿模式)
|
|
||||||
source_table: sourceTable, // 必须:stock_buy / stock_semi / stock_product
|
|
||||||
operator_name: currentUser,
|
|
||||||
remark: remark
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
// ★ 保留清除功能(用于兼容性)
|
// ★ 保留清除功能(用于兼容性)
|
||||||
clearDraft: () => request({
|
clearDraft: () => request({
|
||||||
url: '/v1/inbound/stock/draft/clear',
|
url: '/v1/inbound/stock/draft/clear',
|
||||||
@ -571,11 +593,27 @@ const checkServerDraft = async () => {
|
|||||||
|
|
||||||
// ★ 重写: 开始新盘点 - 使用新 API
|
// ★ 重写: 开始新盘点 - 使用新 API
|
||||||
const startNewSession = async () => {
|
const startNewSession = async () => {
|
||||||
try {
|
// ★ 新增: 防呆确认弹窗
|
||||||
if (serverDraftCount.value > 0) {
|
if (serverDraftCount.value > 0) {
|
||||||
await ElMessageBox.confirm('存在未完成记录,开始新盘点将清除它们,确定吗?', '警告', { type: 'warning' })
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
const doStartNewSession = async () => {
|
||||||
|
showConfirmDialog.value = false
|
||||||
btnLoading.value = true
|
btnLoading.value = true
|
||||||
|
try {
|
||||||
// 调用新 API 开始新会话
|
// 调用新 API 开始新会话
|
||||||
const res: any = await api.startNewSession()
|
const res: any = await api.startNewSession()
|
||||||
currentSessionId.value = res.session_id || ''
|
currentSessionId.value = res.session_id || ''
|
||||||
@ -592,6 +630,20 @@ const startNewSession = async () => {
|
|||||||
} finally { btnLoading.value = false }
|
} finally { btnLoading.value = false }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const confirmClear = () => {
|
||||||
|
if (countdown.value > 0) return
|
||||||
|
doStartNewSession()
|
||||||
|
}
|
||||||
|
|
||||||
|
const cancelConfirm = () => {
|
||||||
|
showConfirmDialog.value = false
|
||||||
|
if (countdownTimer) {
|
||||||
|
clearInterval(countdownTimer)
|
||||||
|
countdownTimer = null
|
||||||
|
}
|
||||||
|
countdown.value = 0
|
||||||
|
}
|
||||||
|
|
||||||
// ★ 重写: 继续上次盘点 - 恢复扫码作业
|
// ★ 重写: 继续上次盘点 - 恢复扫码作业
|
||||||
const resumeSession = async () => {
|
const resumeSession = async () => {
|
||||||
btnLoading.value = true
|
btnLoading.value = true
|
||||||
@ -760,7 +812,6 @@ const handleManualInput = async () => {
|
|||||||
ElMessage.error(`不在库条码: ${code}`)
|
ElMessage.error(`不在库条码: ${code}`)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
barcodeInput.value = ''
|
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -888,6 +939,18 @@ const varianceList = computed(() => {
|
|||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ★ 新增: 本地搜索过滤后的差异列表
|
||||||
|
const filteredVarianceList = computed(() => {
|
||||||
|
if (!searchSku.value) return varianceList.value
|
||||||
|
const kw = searchSku.value.toLowerCase()
|
||||||
|
return varianceList.value.filter(i =>
|
||||||
|
(i.uuid && i.uuid.toLowerCase().includes(kw)) ||
|
||||||
|
(i.sku && i.sku.toLowerCase().includes(kw)) ||
|
||||||
|
(i.stock_name && i.stock_name.toLowerCase().includes(kw)) ||
|
||||||
|
(i.stock_spec && i.stock_spec.toLowerCase().includes(kw))
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
const openInventoryList = () => { showList.value = true }
|
const openInventoryList = () => { showList.value = true }
|
||||||
|
|
||||||
// ★ 修改:结束盘点按钮直接调用 finishStocktake,跳过二次确认弹窗
|
// ★ 修改:结束盘点按钮直接调用 finishStocktake,跳过二次确认弹窗
|
||||||
@ -946,35 +1009,6 @@ const openVarianceDialog = async () => {
|
|||||||
varianceLoading.value = false
|
varianceLoading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ★ 新增: 确认平账
|
|
||||||
const handleAdjust = async (row: any) => {
|
|
||||||
try {
|
|
||||||
// ===== 调试代码 =====
|
|
||||||
console.warn('---- 准备平账参数检查 ----');
|
|
||||||
console.warn('当前点击行的完整数据:', row);
|
|
||||||
console.warn(`将要发送的 draftId: ${row.id}, stockId: ${row.stock_id}, sourceTable: ${row.source_table}`);
|
|
||||||
// ===== 调试结束 =====
|
|
||||||
|
|
||||||
await ElMessageBox.confirm(
|
|
||||||
`确定要对 "${row.uuid}" 进行平账调整吗?\n\n差异: ${row.diff_qty > 0 ? '盘盈 +' : '盘亏 '}${row.diff_qty}`,
|
|
||||||
'确认平账',
|
|
||||||
{ type: 'warning', confirmButtonText: '确认调整', cancelButtonText: '取消' }
|
|
||||||
)
|
|
||||||
|
|
||||||
const remark = `盘点差异调整 - ${row.diff_qty > 0 ? '盘盈入库' : '盘亏出库'}`
|
|
||||||
|
|
||||||
const res: any = await api.adjustStock(row.id, row.stock_id, row.diff_qty, row.source_table || 'stock_buy', remark)
|
|
||||||
|
|
||||||
ElMessage.success(res.message || '调整成功')
|
|
||||||
|
|
||||||
// 刷新数据并重新打开差异列表
|
|
||||||
await loadData()
|
|
||||||
await openVarianceDialog()
|
|
||||||
} catch (e: any) {
|
|
||||||
if (e !== 'cancel') ElMessage.error(e?.message || '操作失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ★ 新增: 跳转到差异审核页面
|
// ★ 新增: 跳转到差异审核页面
|
||||||
const goToVarianceReview = () => {
|
const goToVarianceReview = () => {
|
||||||
openVarianceDialog()
|
openVarianceDialog()
|
||||||
@ -1239,4 +1273,14 @@ const goToVarianceReview = () => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.confirm-content {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
.confirm-content .confirm-text {
|
||||||
|
margin-top: 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
Reference in New Issue
Block a user