<template>
|
<div class="task-page art-full-height">
|
<ArtSearchBar
|
v-model="searchForm"
|
:items="searchItems"
|
:showExpand="true"
|
@search="handleSearch"
|
@reset="handleReset"
|
/>
|
|
<ElCard class="art-table-card">
|
<ArtTableHeader v-model:columns="columnChecks" :loading="loading" @refresh="loadPageData" />
|
|
<ArtTable
|
:loading="loading"
|
:data="tableData"
|
:columns="columns"
|
:pagination="pagination"
|
@pagination:size-change="handleSizeChange"
|
@pagination:current-change="handleCurrentChange"
|
/>
|
</ElCard>
|
|
<TaskDetailDrawer
|
v-model:visible="detailDrawerVisible"
|
:loading="detailLoading"
|
:detail="detailData"
|
:data="detailTableData"
|
:columns="detailColumns"
|
:pagination="detailPagination"
|
@refresh="loadDetailResources"
|
@size-change="handleDetailSizeChange"
|
@current-change="handleDetailCurrentChange"
|
/>
|
</div>
|
</template>
|
|
<script setup>
|
import { ElMessage } from 'element-plus'
|
import { computed, onMounted, reactive, ref } from 'vue'
|
import { useTableColumns } from '@/hooks/core/useTableColumns'
|
import { guardRequestWithMessage } from '@/utils/sys/requestGuard'
|
import {
|
fetchCheckTask,
|
fetchCompleteTask,
|
fetchPickTask,
|
fetchRemoveTask,
|
fetchTaskDetail,
|
fetchTaskItemPage,
|
fetchTaskPage,
|
fetchTopTask
|
} from '@/api/task'
|
import TaskDetailDrawer from './modules/task-detail-drawer.vue'
|
import { createTaskTableColumns } from './taskTable.columns'
|
import {
|
buildTaskPageQueryParams,
|
confirmTaskAction,
|
createTaskSearchState,
|
normalizeTaskItemRow,
|
normalizeTaskRow
|
} from './taskPage.helpers'
|
|
defineOptions({ name: 'Task' })
|
|
const loading = ref(false)
|
const tableData = ref([])
|
const searchForm = ref(createTaskSearchState())
|
const detailDrawerVisible = ref(false)
|
const detailLoading = ref(false)
|
const detailData = ref({})
|
const detailTableData = ref([])
|
const activeTaskRow = ref(null)
|
|
const pagination = reactive({
|
current: 1,
|
size: 20,
|
total: 0
|
})
|
|
const detailPagination = reactive({
|
current: 1,
|
size: 20,
|
total: 0
|
})
|
|
const searchItems = computed(() => [
|
{
|
label: '关键字',
|
key: 'condition',
|
type: 'input',
|
props: { clearable: true, placeholder: '请输入任务号/库位/托盘码' }
|
},
|
{
|
label: '任务号',
|
key: 'taskCode',
|
type: 'input',
|
props: { clearable: true, placeholder: '请输入任务号' }
|
},
|
{
|
label: '源库位',
|
key: 'orgLoc',
|
type: 'input',
|
props: { clearable: true, placeholder: '请输入源库位' }
|
},
|
{
|
label: '目标库位',
|
key: 'targLoc',
|
type: 'input',
|
props: { clearable: true, placeholder: '请输入目标库位' }
|
},
|
{
|
label: '托盘码',
|
key: 'barcode',
|
type: 'input',
|
props: { clearable: true, placeholder: '请输入托盘码' }
|
}
|
])
|
|
const detailColumns = computed(() => [
|
{
|
type: 'globalIndex',
|
label: '序号',
|
width: 72,
|
align: 'center'
|
},
|
{
|
prop: 'orderTypeLabel',
|
label: '单据类型',
|
minWidth: 120,
|
showOverflowTooltip: true
|
},
|
{
|
prop: 'wkTypeLabel',
|
label: '业务类型',
|
minWidth: 120,
|
showOverflowTooltip: true
|
},
|
{
|
prop: 'platWorkCode',
|
label: '工单号',
|
minWidth: 150,
|
showOverflowTooltip: true
|
},
|
{
|
prop: 'platItemId',
|
label: '行号',
|
minWidth: 100,
|
showOverflowTooltip: true
|
},
|
{
|
prop: 'matnrCode',
|
label: '物料编码',
|
minWidth: 150,
|
showOverflowTooltip: true
|
},
|
{
|
prop: 'maktx',
|
label: '物料名称',
|
minWidth: 220,
|
showOverflowTooltip: true
|
},
|
{
|
prop: 'batch',
|
label: '批次',
|
minWidth: 140,
|
showOverflowTooltip: true
|
},
|
{
|
prop: 'unit',
|
label: '单位',
|
width: 100
|
},
|
{
|
prop: 'anfme',
|
label: '数量',
|
width: 100,
|
align: 'right'
|
},
|
{
|
prop: 'updateByText',
|
label: '更新人',
|
minWidth: 120,
|
showOverflowTooltip: true
|
},
|
{
|
prop: 'updateTimeText',
|
label: '更新时间',
|
minWidth: 180,
|
showOverflowTooltip: true
|
}
|
])
|
|
async function openDetailDrawer(row) {
|
activeTaskRow.value = row
|
detailPagination.current = 1
|
detailDrawerVisible.value = true
|
await loadDetailResources()
|
}
|
|
async function handleActionClick(action, row) {
|
try {
|
if (action.key === 'view') {
|
await openDetailDrawer(row)
|
return
|
}
|
|
if (action.key === 'complete') {
|
await confirmTaskAction(`确定完成任务 ${row.taskCode || ''} 吗?`)
|
await fetchCompleteTask(row.id)
|
ElMessage.success('任务完成成功')
|
} else if (action.key === 'remove') {
|
await confirmTaskAction(`确定取消任务 ${row.taskCode || ''} 吗?`)
|
await fetchRemoveTask(row.id)
|
ElMessage.success('任务取消成功')
|
} else if (action.key === 'check') {
|
await confirmTaskAction(`确定执行盘点出库任务 ${row.taskCode || ''} 吗?`)
|
await fetchCheckTask(row.id)
|
ElMessage.success('盘点出库成功')
|
} else if (action.key === 'pick') {
|
await confirmTaskAction(`确定执行拣料出库任务 ${row.taskCode || ''} 吗?`)
|
await fetchPickTask(row.id)
|
ElMessage.success('拣料出库成功')
|
} else if (action.key === 'top') {
|
await fetchTopTask(row.id)
|
ElMessage.success('任务置顶成功')
|
}
|
|
await loadPageData()
|
if (detailDrawerVisible.value && activeTaskRow.value?.id === row.id) {
|
await loadDetailResources()
|
}
|
} catch (error) {
|
if (error === 'cancel') {
|
return
|
}
|
ElMessage.error(error?.message || '任务操作失败')
|
}
|
}
|
|
const { columns, columnChecks } = useTableColumns(() => createTaskTableColumns(handleActionClick))
|
|
function updatePaginationState(target, response, fallbackCurrent, fallbackSize) {
|
target.total = Number(response?.total || 0)
|
target.current = Number(response?.current || fallbackCurrent || 1)
|
target.size = Number(response?.size || fallbackSize || target.size || 20)
|
}
|
|
async function loadPageData() {
|
loading.value = true
|
try {
|
const response = await guardRequestWithMessage(
|
fetchTaskPage(
|
buildTaskPageQueryParams({
|
...searchForm.value,
|
current: pagination.current,
|
pageSize: pagination.size
|
})
|
),
|
{
|
records: [],
|
total: 0,
|
current: pagination.current,
|
size: pagination.size
|
},
|
{ timeoutMessage: '任务列表加载超时,已停止等待' }
|
)
|
tableData.value = Array.isArray(response?.records)
|
? response.records.map((record) => normalizeTaskRow(record))
|
: []
|
updatePaginationState(pagination, response, pagination.current, pagination.size)
|
} finally {
|
loading.value = false
|
}
|
}
|
|
async function loadDetailResources() {
|
if (!activeTaskRow.value?.id) {
|
return
|
}
|
|
detailLoading.value = true
|
try {
|
const [detailResponse, taskItemResponse] = await Promise.all([
|
guardRequestWithMessage(fetchTaskDetail(activeTaskRow.value.id), {}, {
|
timeoutMessage: '任务详情加载超时,已停止等待'
|
}),
|
guardRequestWithMessage(
|
fetchTaskItemPage({
|
taskId: activeTaskRow.value.id,
|
current: detailPagination.current,
|
pageSize: detailPagination.size
|
}),
|
{
|
records: [],
|
total: 0,
|
current: detailPagination.current,
|
size: detailPagination.size
|
},
|
{ timeoutMessage: '任务明细加载超时,已停止等待' }
|
)
|
])
|
|
detailData.value = normalizeTaskRow(detailResponse)
|
detailTableData.value = Array.isArray(taskItemResponse?.records)
|
? taskItemResponse.records.map((record) => normalizeTaskItemRow(record))
|
: []
|
updatePaginationState(detailPagination, taskItemResponse, detailPagination.current, detailPagination.size)
|
} finally {
|
detailLoading.value = false
|
}
|
}
|
|
function handleSearch(params) {
|
searchForm.value = {
|
...searchForm.value,
|
...params
|
}
|
pagination.current = 1
|
loadPageData()
|
}
|
|
function handleReset() {
|
searchForm.value = createTaskSearchState()
|
pagination.current = 1
|
pagination.size = 20
|
loadPageData()
|
}
|
|
function handleSizeChange(size) {
|
pagination.size = size
|
pagination.current = 1
|
loadPageData()
|
}
|
|
function handleCurrentChange(current) {
|
pagination.current = current
|
loadPageData()
|
}
|
|
function handleDetailSizeChange(size) {
|
detailPagination.size = size
|
detailPagination.current = 1
|
loadDetailResources()
|
}
|
|
function handleDetailCurrentChange(current) {
|
detailPagination.current = current
|
loadDetailResources()
|
}
|
|
onMounted(loadPageData)
|
</script>
|