<template>
|
<div class="check-out-bound-page art-full-height">
|
<ArtSearchBar
|
v-model="searchForm"
|
:items="searchItems"
|
:showExpand="true"
|
@search="handleSearch"
|
@reset="handleReset"
|
/>
|
|
<ElCard class="art-table-card mb-4">
|
<div class="flex flex-wrap items-center gap-3">
|
<div class="text-sm text-[var(--art-text-gray-600)]">
|
已选择 <span class="font-medium text-[var(--art-text-gray-800)]">{{ selectedRows.length }}</span> 条库位物料
|
</div>
|
<ElSelect
|
v-model="siteNo"
|
class="min-w-56"
|
filterable
|
clearable
|
placeholder="请选择站点"
|
:loading="siteLoading"
|
:disabled="siteLoading"
|
>
|
<ElOption
|
v-for="item in siteOptions"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</ElSelect>
|
<ElButton
|
type="primary"
|
:loading="generateLoading"
|
:disabled="!canGenerateTask"
|
@click="handleGenerateTask"
|
>
|
生成盘点出库任务
|
</ElButton>
|
<ElButton :disabled="selectedRows.length === 0" @click="clearSelection">清空选择</ElButton>
|
</div>
|
</ElCard>
|
|
<ElCard class="art-table-card">
|
<ArtTableHeader v-model:columns="columnChecks" :loading="loading" @refresh="refreshData" />
|
|
<ArtTable
|
:loading="loading"
|
:data="data"
|
:columns="columns"
|
:pagination="pagination"
|
@selection-change="handleSelectionChange"
|
@pagination:size-change="handleSizeChange"
|
@pagination:current-change="handleCurrentChange"
|
/>
|
</ElCard>
|
|
<CheckOutBoundDetailDrawer
|
v-model:visible="detailDrawerVisible"
|
:loading="detailLoading"
|
:detail="detailData"
|
/>
|
</div>
|
</template>
|
|
<script setup>
|
import { computed, onMounted, ref, watch } from 'vue'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { useTable } from '@/hooks/core/useTable'
|
import { guardRequestWithMessage } from '@/utils/sys/requestGuard'
|
import {
|
buildCheckOutBoundPageQueryParams,
|
buildCheckOutBoundTaskPayload,
|
createCheckOutBoundSearchState,
|
normalizeCheckOutBoundRow,
|
resolveCheckOutBoundSiteOptions
|
} from './checkOutBoundPage.helpers'
|
import {
|
fetchCheckOutBoundPage,
|
fetchCheckOutBoundSites,
|
fetchGenerateCheckOutBoundTask,
|
fetchGetCheckOutBoundDetail
|
} from '@/api/check-out-bound'
|
import CheckOutBoundDetailDrawer from './modules/check-out-bound-detail-drawer.vue'
|
import { createCheckOutBoundTableColumns } from './checkOutBoundTable.columns'
|
|
defineOptions({ name: 'CheckOutBound' })
|
|
const searchForm = ref(createCheckOutBoundSearchState())
|
const selectedRows = ref([])
|
const siteOptions = ref([])
|
const siteLoading = ref(false)
|
const siteNo = ref('')
|
const memo = ref('')
|
const detailDrawerVisible = ref(false)
|
const detailLoading = ref(false)
|
const detailData = ref({})
|
const generateLoading = ref(false)
|
|
const searchItems = computed(() => [
|
{
|
label: '关键字',
|
key: 'condition',
|
type: 'input',
|
props: {
|
clearable: true,
|
placeholder: '请输入库位编码/物料编码/物料名称/批次'
|
}
|
},
|
{
|
label: '库位编码',
|
key: 'locCode',
|
type: 'input',
|
props: {
|
clearable: true,
|
placeholder: '请输入库位编码'
|
}
|
},
|
{
|
label: '物料编码',
|
key: 'matnrCode',
|
type: 'input',
|
props: {
|
clearable: true,
|
placeholder: '请输入物料编码'
|
}
|
},
|
{
|
label: '物料名称',
|
key: 'maktx',
|
type: 'input',
|
props: {
|
clearable: true,
|
placeholder: '请输入物料名称'
|
}
|
},
|
{
|
label: '库存批次',
|
key: 'batch',
|
type: 'input',
|
props: {
|
clearable: true,
|
placeholder: '请输入库存批次'
|
}
|
},
|
{
|
label: '追踪码',
|
key: 'trackCode',
|
type: 'input',
|
props: {
|
clearable: true,
|
placeholder: '请输入追踪码'
|
}
|
}
|
])
|
|
const {
|
columns,
|
columnChecks,
|
data,
|
loading,
|
pagination,
|
replaceSearchParams,
|
resetSearchParams,
|
handleSizeChange: handleTableSizeChange,
|
handleCurrentChange: handleTableCurrentChange,
|
refreshData
|
} = useTable({
|
core: {
|
apiFn: fetchCheckOutBoundPage,
|
apiParams: buildCheckOutBoundPageQueryParams(searchForm.value),
|
columnsFactory: () =>
|
createCheckOutBoundTableColumns({
|
handleActionClick
|
})
|
},
|
transform: {
|
dataTransformer: (records) => (Array.isArray(records) ? records.map((item) => normalizeCheckOutBoundRow(item)) : [])
|
}
|
})
|
|
const canGenerateTask = computed(() => selectedRows.value.length > 0 && Boolean(siteNo.value) && !generateLoading.value)
|
|
watch(
|
data,
|
() => {
|
selectedRows.value = []
|
},
|
{ deep: false }
|
)
|
|
onMounted(loadSiteOptions)
|
|
async function loadSiteOptions() {
|
siteLoading.value = true
|
try {
|
const response = await guardRequestWithMessage(fetchCheckOutBoundSites(), [], {
|
timeoutMessage: '站点选项加载超时,已停止等待'
|
})
|
siteOptions.value = resolveCheckOutBoundSiteOptions(response)
|
if (siteOptions.value.length > 0 && !siteOptions.value.some((item) => item.value === siteNo.value)) {
|
siteNo.value = ''
|
}
|
} catch (error) {
|
siteOptions.value = []
|
ElMessage.error(error?.message || '获取站点选项失败')
|
} finally {
|
siteLoading.value = false
|
}
|
}
|
|
async function openDetailDrawer(row) {
|
detailDrawerVisible.value = true
|
detailLoading.value = true
|
try {
|
const detail = await guardRequestWithMessage(fetchGetCheckOutBoundDetail(row.id), {}, {
|
timeoutMessage: '盘点出库明细加载超时,已停止等待'
|
})
|
detailData.value = normalizeCheckOutBoundRow(detail)
|
} catch (error) {
|
detailDrawerVisible.value = false
|
detailData.value = {}
|
ElMessage.error(error?.message || '获取盘点出库明细失败')
|
} finally {
|
detailLoading.value = false
|
}
|
}
|
|
async function handleActionClick(action, row) {
|
if (action?.disabled) return
|
if (action.key === 'view') {
|
await openDetailDrawer(row)
|
}
|
}
|
|
function handleSelectionChange(rows) {
|
selectedRows.value = Array.isArray(rows) ? rows : []
|
}
|
|
function clearSelection() {
|
selectedRows.value = []
|
}
|
|
function handleSearch(params) {
|
searchForm.value = {
|
...searchForm.value,
|
...params
|
}
|
selectedRows.value = []
|
replaceSearchParams(buildCheckOutBoundPageQueryParams(searchForm.value))
|
refreshData()
|
}
|
|
function handleReset() {
|
searchForm.value = createCheckOutBoundSearchState()
|
selectedRows.value = []
|
siteNo.value = ''
|
memo.value = ''
|
resetSearchParams()
|
}
|
|
function handleSizeChange(size) {
|
selectedRows.value = []
|
handleTableSizeChange(size)
|
}
|
|
function handleCurrentChange(current) {
|
selectedRows.value = []
|
handleTableCurrentChange(current)
|
}
|
|
async function handleGenerateTask() {
|
if (!siteNo.value) {
|
ElMessage.warning('请选择站点')
|
return
|
}
|
if (selectedRows.value.length === 0) {
|
ElMessage.warning('请选择库位物料')
|
return
|
}
|
|
try {
|
await ElMessageBox.confirm(
|
`确定基于当前所选 ${selectedRows.value.length} 条库位物料生成盘点出库任务吗?`,
|
'生成确认',
|
{
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning'
|
}
|
)
|
|
generateLoading.value = true
|
const payload = buildCheckOutBoundTaskPayload({
|
siteNo: siteNo.value,
|
memo: memo.value,
|
items: selectedRows.value
|
})
|
await fetchGenerateCheckOutBoundTask(payload)
|
ElMessage.success('任务生成成功')
|
selectedRows.value = []
|
refreshData()
|
} catch (error) {
|
if (error === 'cancel' || error?.message === 'cancel') return
|
ElMessage.error(error?.message || '任务生成失败')
|
} finally {
|
generateLoading.value = false
|
}
|
}
|
</script>
|