feat: fix stocktake deletion bug, and add pagination, search, sorting to stocktake lists
This commit is contained in:
@ -154,6 +154,23 @@
|
||||
<!-- 盘点差异审核弹窗 -->
|
||||
<el-dialog v-model="showReviewDialog" title="盘点差异审核" width="1200px" :close-on-click-modal="false">
|
||||
<div v-loading="reviewLoading">
|
||||
<!-- 搜索栏 -->
|
||||
<div style="margin-bottom: 16px; display: flex; gap: 12px;">
|
||||
<el-input
|
||||
v-model="reviewKeyword"
|
||||
placeholder="搜索 SKU..."
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter="handleReviewSearch"
|
||||
@clear="handleReviewSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon><Search /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button type="primary" @click="handleReviewSearch">搜索</el-button>
|
||||
</div>
|
||||
|
||||
<el-table :data="reviewList" border stripe ref="reviewTableRef" @selection-change="handleReviewSelectionChange">
|
||||
<el-table-column type="selection" width="50" />
|
||||
<el-table-column prop="sku" label="SKU" width="140" />
|
||||
@ -182,6 +199,20 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div style="margin-top: 16px; display: flex; justify-content: flex-end;">
|
||||
<el-pagination
|
||||
v-model:current-page="reviewPage"
|
||||
v-model:page-size="reviewLimit"
|
||||
:page-sizes="[20, 50, 100, 200]"
|
||||
:total="reviewTotal"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleReviewLimitChange"
|
||||
@current-change="handleReviewPageChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="reviewList.length === 0" style="text-align: center; padding: 40px; color: #909399">
|
||||
暂无盘点差异记录
|
||||
</div>
|
||||
@ -223,6 +254,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import request from '@/utils/request'
|
||||
|
||||
@ -273,6 +305,10 @@ const selectedStock = ref<any>(null)
|
||||
const showReviewDialog = ref(false)
|
||||
const reviewLoading = ref(false)
|
||||
const reviewList = ref<any[]>([])
|
||||
const reviewTotal = ref(0)
|
||||
const reviewPage = ref(1)
|
||||
const reviewLimit = ref(20)
|
||||
const reviewKeyword = ref('')
|
||||
const selectedReviewRows = ref<any[]>([])
|
||||
const reviewTableRef = ref()
|
||||
const importLoading = ref(false)
|
||||
@ -345,7 +381,12 @@ async function fetchReviewList() {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/v1/stock/adjustment/stocktake-discrepancies',
|
||||
method: 'get'
|
||||
method: 'get',
|
||||
params: {
|
||||
page: reviewPage.value,
|
||||
limit: reviewLimit.value,
|
||||
keyword: reviewKeyword.value
|
||||
}
|
||||
})
|
||||
if (res.code === 200) {
|
||||
// 为每条记录设置默认原因
|
||||
@ -353,6 +394,7 @@ async function fetchReviewList() {
|
||||
...item,
|
||||
reason: item.remark || '盘点差异导入'
|
||||
}))
|
||||
reviewTotal.value = res.data.total || 0
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('获取盘点差异失败')
|
||||
@ -361,10 +403,30 @@ async function fetchReviewList() {
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索 SKU
|
||||
function handleReviewSearch() {
|
||||
reviewPage.value = 1
|
||||
fetchReviewList()
|
||||
}
|
||||
|
||||
// 分页变化
|
||||
function handleReviewPageChange(page: number) {
|
||||
reviewPage.value = page
|
||||
fetchReviewList()
|
||||
}
|
||||
|
||||
function handleReviewLimitChange(limit: number) {
|
||||
reviewLimit.value = limit
|
||||
reviewPage.value = 1
|
||||
fetchReviewList()
|
||||
}
|
||||
|
||||
// 打开审核弹窗
|
||||
async function openReviewDialog() {
|
||||
showReviewDialog.value = true
|
||||
selectedReviewRows.value = []
|
||||
reviewPage.value = 1
|
||||
reviewKeyword.value = ''
|
||||
await fetchReviewList()
|
||||
}
|
||||
|
||||
|
||||
@ -211,57 +211,50 @@
|
||||
destroy-on-close
|
||||
class="inventory-drawer"
|
||||
>
|
||||
<div class="drawer-layout">
|
||||
<div class="drawer-layout" v-loading="listLoading">
|
||||
<div class="search-bar">
|
||||
<el-input v-model="searchKeyword" placeholder="搜索 SKU/名称..." :prefix-icon="Search" clearable />
|
||||
<el-select v-model="filterType" placeholder="状态" style="width: 100px; margin-left: 8px;">
|
||||
<el-option label="全部" value="all" />
|
||||
<el-option label="已盘" value="scanned" />
|
||||
<el-option label="未盘" value="missing" />
|
||||
</el-select>
|
||||
<el-input v-model="listKeyword" placeholder="搜索 SKU..." :prefix-icon="Search" clearable @keyup.enter="handleListSearch" @clear="handleListSearch" style="width: 240px" />
|
||||
<el-button type="primary" @click="handleListSearch">搜索</el-button>
|
||||
</div>
|
||||
|
||||
<div class="table-container">
|
||||
<el-table
|
||||
:data="filteredList"
|
||||
:data="listData"
|
||||
height="100%"
|
||||
stripe
|
||||
border
|
||||
row-key="uniqueKey"
|
||||
row-key="id"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column prop="name" label="名称" min-width="90" show-overflow-tooltip />
|
||||
|
||||
<el-table-column prop="sku" label="SKU" width="110" show-overflow-tooltip />
|
||||
<el-table-column label="序列号/批次" min-width="150" show-overflow-tooltip>
|
||||
<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 />
|
||||
<el-table-column prop="stock_qty" label="账面数" width="80" align="center" />
|
||||
<el-table-column prop="quantity" label="实盘数" width="80" align="center" />
|
||||
<el-table-column label="差异" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.serial_number || row.batch_number || row.batch_no || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="实盘" width="60" align="center">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.scanned" class="actual-qty-text">{{ scope.row.qty_actual }}</span>
|
||||
<span v-else class="text-gray">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="90" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
v-if="userStore.hasPermission('inventory_stocktake:operation')"
|
||||
type="primary"
|
||||
link
|
||||
icon="Edit"
|
||||
@click.stop="openQtyDialog(scope.row)"
|
||||
>
|
||||
修改
|
||||
</el-button>
|
||||
<span :style="{ color: row.diff_qty > 0 ? '#67C23A' : row.diff_qty < 0 ? '#F56C6C' : '#909399' }">
|
||||
{{ row.diff_qty > 0 ? '+' : '' }}{{ row.diff_qty || 0 }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="120" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="drawer-footer" style="display: flex; justify-content: flex-end; padding: 10px;">
|
||||
<el-pagination
|
||||
v-model:current-page="listPage"
|
||||
v-model:page-size="listLimit"
|
||||
:page-sizes="[20, 50, 100, 200]"
|
||||
:total="listTotal"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleListLimitChange"
|
||||
@current-change="handleListPageChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="drawer-footer">
|
||||
<el-button @click="showList = false" style="width: 100%">关闭列表</el-button>
|
||||
</div>
|
||||
@ -443,6 +436,14 @@ const showVarianceDialog = ref(false)
|
||||
// ★ 新增: 差异列表搜索
|
||||
const searchSku = ref('')
|
||||
|
||||
// ★ 新增: 盘点清单弹窗分页
|
||||
const listPage = ref(1)
|
||||
const listLimit = ref(20)
|
||||
const listTotal = ref(0)
|
||||
const listKeyword = ref('')
|
||||
const listLoading = ref(false)
|
||||
const listData = ref<any[]>([])
|
||||
|
||||
// ★ 新增: 盘点开始防呆倒计时
|
||||
const countdown = ref(0)
|
||||
let countdownTimer: any = null
|
||||
@ -606,9 +607,10 @@ const checkServerDraft = async () => {
|
||||
const res: any = await request({
|
||||
url: '/v1/inbound/stock/draft/list',
|
||||
method: 'get',
|
||||
params: {}
|
||||
params: { page: 1, limit: 1 } // 只获取一条记录来获取总数
|
||||
})
|
||||
serverDraftCount.value = (res && res.length) || 0
|
||||
// 后端返回格式已改为 { items: [], total: number }
|
||||
serverDraftCount.value = (res && res.total) || 0
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
@ -670,12 +672,15 @@ const resumeSession = async () => {
|
||||
btnLoading.value = true
|
||||
try {
|
||||
// 获取最新的会话(后端已移除 is_finished 字段)
|
||||
const drafts: any = await request({
|
||||
// 后端返回格式已改为 { items: [], total: number }
|
||||
const res: any = await request({
|
||||
url: '/v1/inbound/stock/draft/list',
|
||||
method: 'get',
|
||||
params: {}
|
||||
params: { page: 1, limit: 10000 } // 获取足够多的数据
|
||||
})
|
||||
|
||||
const drafts = res && res.items ? res.items : []
|
||||
|
||||
if (!drafts || drafts.length === 0) {
|
||||
ElMessage.warning('没有找到未完成的盘点记录')
|
||||
return
|
||||
@ -981,7 +986,55 @@ const filteredVarianceList = computed(() => {
|
||||
)
|
||||
})
|
||||
|
||||
const openInventoryList = () => { showList.value = true }
|
||||
// ★ 新增: 获取盘点清单数据(后端分页)
|
||||
const fetchInventoryList = async () => {
|
||||
listLoading.value = true
|
||||
try {
|
||||
const res: any = await request({
|
||||
url: '/v1/inbound/stock/draft/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
page: listPage.value,
|
||||
limit: listLimit.value,
|
||||
keyword: listKeyword.value
|
||||
}
|
||||
})
|
||||
if (res) {
|
||||
listData.value = res.items || []
|
||||
listTotal.value = res.total || 0
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('获取盘点清单失败')
|
||||
} finally {
|
||||
listLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// ★ 修改: 打开盘点清单弹窗
|
||||
const openInventoryList = async () => {
|
||||
showList.value = true
|
||||
listPage.value = 1
|
||||
listKeyword.value = ''
|
||||
await fetchInventoryList()
|
||||
}
|
||||
|
||||
// ★ 新增: 盘点清单搜索
|
||||
const handleListSearch = () => {
|
||||
listPage.value = 1
|
||||
fetchInventoryList()
|
||||
}
|
||||
|
||||
// ★ 新增: 盘点清单分页变化
|
||||
const handleListPageChange = (page: number) => {
|
||||
listPage.value = page
|
||||
fetchInventoryList()
|
||||
}
|
||||
|
||||
const handleListLimitChange = (limit: number) => {
|
||||
listLimit.value = limit
|
||||
listPage.value = 1
|
||||
fetchInventoryList()
|
||||
}
|
||||
|
||||
// ★ 修改:结束盘点按钮直接调用 finishStocktake,跳过二次确认弹窗
|
||||
const openFinishDialog = () => {
|
||||
|
||||
Reference in New Issue
Block a user