功能:新增托盘业务报表页面
This commit is contained in:
@@ -490,6 +490,6 @@ class ReportDao:
|
||||
.outerjoin(after_line, after_line.line_id == BizPalletEvent.after_line_id)
|
||||
.outerjoin(operator_user, operator_user.user_id == BizPalletEvent.operator_id)
|
||||
.where(*conditions)
|
||||
.order_by(BizPalletEvent.pallet_id, BizPalletEvent.event_seq, BizPalletEvent.event_id)
|
||||
.order_by(BizPalletEvent.occurred_at, BizPalletEvent.event_id)
|
||||
)
|
||||
return await cls._paginate(db, statement, query_object)
|
||||
|
||||
@@ -603,7 +603,7 @@ class TestReportDaoQueries(unittest.IsolatedAsyncioTestCase):
|
||||
self.assertIn('biz_pallet_event.occurred_at >=', sql)
|
||||
self.assertIn('biz_pallet_event.occurred_at <', sql)
|
||||
self.assertIn(
|
||||
'order by biz_pallet_event.pallet_id, biz_pallet_event.event_seq, biz_pallet_event.event_id',
|
||||
'order by biz_pallet_event.occurred_at, biz_pallet_event.event_id',
|
||||
sql,
|
||||
)
|
||||
|
||||
|
||||
@@ -253,6 +253,83 @@ const businessPageContracts = {
|
||||
}
|
||||
}
|
||||
|
||||
const reportPageContracts = {
|
||||
palletInventory: {
|
||||
relativePath: 'src/views/report/palletInventory/index.vue',
|
||||
apiName: 'listPalletInventory',
|
||||
permission: 'report:palletinventory:list',
|
||||
queryKeys: [
|
||||
'pageNum', 'pageSize', 'beginTime', 'endTime', 'palletCode', 'flowState',
|
||||
'warehouseId', 'siteId', 'lineId', 'strainId', 'batchNo'
|
||||
],
|
||||
columnKeys: [
|
||||
'palletCode', 'flowState', 'warehouseName', 'siteName', 'lineName',
|
||||
'strainName', 'batchNo', 'initialPackages', 'remainingPackages'
|
||||
]
|
||||
},
|
||||
filling: {
|
||||
relativePath: 'src/views/report/filling/index.vue',
|
||||
apiName: 'listFillingReport',
|
||||
permission: 'report:filling:list',
|
||||
queryKeys: ['pageNum', 'pageSize', 'beginTime', 'endTime', 'warehouseId', 'palletCode', 'strainId', 'batchNo'],
|
||||
columnKeys: [
|
||||
'operatedAt', 'warehouseName', 'palletCode', 'strainCodeSnapshot',
|
||||
'strainNameSnapshot', 'batchNo', 'packageSpec', 'initialPackages'
|
||||
]
|
||||
},
|
||||
shipment: {
|
||||
relativePath: 'src/views/report/shipment/index.vue',
|
||||
apiName: 'listShipmentReport',
|
||||
permission: 'report:shipment:list',
|
||||
queryKeys: [
|
||||
'pageNum', 'pageSize', 'beginTime', 'endTime', 'shipmentNo',
|
||||
'sourceWarehouseId', 'targetSiteId', 'palletCode', 'status'
|
||||
],
|
||||
columnKeys: [
|
||||
'shipmentNo', 'confirmedAt', 'sourceWarehouseName', 'customerName',
|
||||
'targetSiteName', 'palletCode', 'packageQty'
|
||||
]
|
||||
},
|
||||
consumption: {
|
||||
relativePath: 'src/views/report/consumption/index.vue',
|
||||
apiName: 'listConsumptionReport',
|
||||
permission: 'report:consumption:list',
|
||||
queryKeys: [
|
||||
'pageNum', 'pageSize', 'beginTime', 'endTime', 'customerId',
|
||||
'siteId', 'lineId', 'palletCode', 'strainId', 'batchNo'
|
||||
],
|
||||
columnKeys: [
|
||||
'occurredAt', 'customerName', 'siteName', 'lineName', 'palletCode',
|
||||
'strainName', 'batchNo', 'usedPackages', 'remainingPackagesAfter'
|
||||
]
|
||||
},
|
||||
return: {
|
||||
relativePath: 'src/views/report/return/index.vue',
|
||||
apiName: 'listReturnReport',
|
||||
permission: 'report:return:list',
|
||||
queryKeys: [
|
||||
'pageNum', 'pageSize', 'beginTime', 'endTime', 'returnNo',
|
||||
'sourceSiteId', 'targetWarehouseId', 'palletCode', 'status'
|
||||
],
|
||||
columnKeys: [
|
||||
'returnNo', 'status', 'requestedAt', 'confirmedAt', 'sourceSiteName',
|
||||
'targetWarehouseName', 'palletCode', 'remainingPackagesSnapshot'
|
||||
]
|
||||
},
|
||||
palletTrace: {
|
||||
relativePath: 'src/views/report/palletTrace/index.vue',
|
||||
apiName: 'listPalletTrace',
|
||||
permission: 'report:pallettrace:list',
|
||||
queryKeys: ['pageNum', 'pageSize', 'beginTime', 'endTime', 'palletCode', 'eventType'],
|
||||
columnKeys: [
|
||||
'occurredAt', 'eventType', 'sourceType', 'sourceId', 'palletCode',
|
||||
'beforeState', 'afterState', 'beforeWarehouseName', 'beforeSiteName',
|
||||
'beforeLineName', 'afterWarehouseName', 'afterSiteName', 'afterLineName',
|
||||
'beforeRemainingPackages', 'afterRemainingPackages', 'operatorName'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
const delimiterPairs = { '(': ')', '[': ']', '{': '}' }
|
||||
|
||||
function sanitizeSource(source, { allowTemplateInterpolation = false } = {}) {
|
||||
@@ -680,6 +757,66 @@ test('六个报表 API 只提供 GET /list,不提供导出接口', async () =>
|
||||
}
|
||||
})
|
||||
|
||||
test('六个只读报表页面逐页满足 API、权限、筛选、列和异步分页契约', async (t) => {
|
||||
for (const [resource, contract] of Object.entries(reportPageContracts)) {
|
||||
await t.test(contract.relativePath, async () => {
|
||||
const source = await readFile(path.join(frontendRoot, contract.relativePath), 'utf8')
|
||||
const importedApiModules = [...source.matchAll(/from\s*['"]@\/api\/(report|master|business)\/([A-Za-z]+)['"]/g)]
|
||||
.map((match) => `${match[1]}/${match[2]}`)
|
||||
|
||||
assert.deepEqual(importedApiModules, [`report/${resource}`], `${resource} 页面只能导入自己的报表 API`)
|
||||
assert.deepEqual(extractImportedNames(source, `@/api/report/${resource}`), [contract.apiName])
|
||||
assert.doesNotMatch(source, /@\/api\/(?:master|business)\//)
|
||||
assert.match(source, new RegExp(`${contract.apiName}\\(listContext\\.query\\)`))
|
||||
|
||||
const actualPermissions = [...new Set(
|
||||
[...source.matchAll(/['"](report:[a-z]+:[a-z]+)['"]/g)].map((match) => match[1])
|
||||
)]
|
||||
assert.deepEqual(actualPermissions, [contract.permission], `${resource} 页面只能出现自己的 list 权限`)
|
||||
assertButtonsUsePermission(source, 'handleQuery', contract.permission)
|
||||
assertButtonsUsePermission(source, 'resetQuery', contract.permission)
|
||||
assert.doesNotMatch(source, /report:[a-z]+:(?:add|edit|remove|export|print)/)
|
||||
assert.doesNotMatch(source, /\bhandle(?:Add|Edit|Delete|Remove|Export|Print|Download)\b|proxy\.download\s*\(/)
|
||||
|
||||
for (const queryKey of contract.queryKeys) {
|
||||
assert.match(source, new RegExp(`\\b${queryKey}\\b`), `${resource} 缺少筛选键 ${queryKey}`)
|
||||
}
|
||||
for (const columnKey of contract.columnKeys) {
|
||||
assert.match(source, new RegExp(`\\b${columnKey}\\b`), `${resource} 缺少核心列 ${columnKey}`)
|
||||
}
|
||||
|
||||
assert.match(source, /<el-date-picker\b[\s\S]*?type="daterange"[\s\S]*?value-format="YYYY-MM-DD"/)
|
||||
assert.match(source, /<el-table\b[^>]*v-loading="loading"[^>]*:data="reportList"/)
|
||||
assert.match(source, /<template\s+#empty>[\s\S]*?<el-empty\b/)
|
||||
assert.match(source, /<el-alert\b[^>]*v-if="loadError"/)
|
||||
assert.match(source, /<pagination\b[\s\S]*?:total="total"[\s\S]*?:page="queryParams\.pageNum"[\s\S]*?:limit="queryParams\.pageSize"/)
|
||||
assert.match(source, /@update:page="handleCurrentChange"/)
|
||||
assert.match(source, /@update:limit="handleSizeChange"/)
|
||||
assert.match(source, /@pagination="getList"/)
|
||||
|
||||
assert.match(source, /let listGeneration = 0;?/)
|
||||
assert.match(source, /function invalidateListRequest\(\)\s*{[\s\S]*?listGeneration \+= 1[\s\S]*?loading\.value = false/)
|
||||
assert.match(source, /function isCurrentListRequest\(listContext\)/)
|
||||
const listSource = extractNamedFunction(source, 'getList')
|
||||
assert.match(listSource, /generation: \+\+listGeneration/)
|
||||
assert.match(listSource, /query:/)
|
||||
assertPromiseCallbacksStartWithGuard(listSource, 'isCurrentListRequest')
|
||||
assert.match(listSource, /reportList\.value = Array\.isArray\(response\.rows\) \? response\.rows : \[\]/)
|
||||
assert.match(listSource, /total\.value = response\.total/)
|
||||
assert.match(listSource, /loadError\.value\s*=/)
|
||||
|
||||
assert.match(extractNamedFunction(source, 'handleQuery'), /queryParams\.value\.pageNum = 1[\s\S]*?getList\(\)/)
|
||||
const resetSource = extractNamedFunction(source, 'resetQuery')
|
||||
assert.match(resetSource, /dateRange\.value = \[\]/)
|
||||
assert.match(resetSource, /resetForm\(['"]queryRef['"]\)/)
|
||||
assert.match(resetSource, /queryParams\.value\.pageNum = 1[\s\S]*?getList\(\)/)
|
||||
assert.match(extractNamedFunction(source, 'handleSizeChange'), /queryParams\.value\.pageSize = pageSize[\s\S]*?queryParams\.value\.pageNum = 1/)
|
||||
assert.match(extractNamedFunction(source, 'handleCurrentChange'), /queryParams\.value\.pageNum = pageNum/)
|
||||
assert.match(source, /onBeforeUnmount\(\(\) => \{\s*invalidateListRequest\(\)\s*}\)/)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('扫码组件声明交互契约并保持触控尺寸', async () => {
|
||||
const source = await readFile(path.join(frontendRoot, 'src/components/PalletScanInput/index.vue'), 'utf8')
|
||||
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="queryRef" :model="queryParams" :inline="true" label-width="76px">
|
||||
<el-form-item label="使用时间">
|
||||
<el-date-picker v-model="dateRange" type="daterange" value-format="YYYY-MM-DD" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="客户ID" prop="customerId">
|
||||
<el-input-number v-model="queryParams.customerId" :min="1" :controls="false" placeholder="请输入客户ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="现场ID" prop="siteId">
|
||||
<el-input-number v-model="queryParams.siteId" :min="1" :controls="false" placeholder="请输入现场ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="产线ID" prop="lineId">
|
||||
<el-input-number v-model="queryParams.lineId" :min="1" :controls="false" placeholder="请输入产线ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="托盘编号" prop="palletCode">
|
||||
<el-input v-model="queryParams.palletCode" placeholder="请输入托盘编号" clearable maxlength="64" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="菌种ID" prop="strainId">
|
||||
<el-input-number v-model="queryParams.strainId" :min="1" :controls="false" placeholder="请输入菌种ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="生产批次" prop="batchNo">
|
||||
<el-input v-model="queryParams.batchNo" placeholder="请输入生产批次" clearable maxlength="64" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['report:consumption:list']">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery" v-hasPermi="['report:consumption:list']">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-alert v-if="loadError" :title="loadError" type="error" :closable="false" show-icon class="mb8" />
|
||||
<el-table v-loading="loading" :data="reportList">
|
||||
<template #empty><el-empty description="暂无产线消耗数据" /></template>
|
||||
<el-table-column label="使用记录号" prop="usageNo" min-width="150" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="使用时间" prop="occurredAt" width="180">
|
||||
<template #default="scope">{{ parseTime(scope.row.occurredAt) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="客户" min-width="130" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ scope.row.customerName || `#${scope.row.customerId}` }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="现场" min-width="130" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ scope.row.siteName || `#${scope.row.siteId}` }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="产线" min-width="130" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ scope.row.lineName || `#${scope.row.lineId}` }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="托盘" prop="palletCode" min-width="130" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="菌种" min-width="150" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ scope.row.strainName || scope.row.strainCode || `#${scope.row.strainId}` }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="生产批次" prop="batchNo" min-width="130" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="使用包数" prop="usedPackages" width="100" align="right" />
|
||||
<el-table-column label="使用后余量" prop="remainingPackagesAfter" width="110" align="right" />
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page="queryParams.pageNum"
|
||||
:limit="queryParams.pageSize"
|
||||
@update:page="handleCurrentChange"
|
||||
@update:limit="handleSizeChange"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ReportConsumption">
|
||||
import { listConsumptionReport } from '@/api/report/consumption'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const reportList = ref([])
|
||||
const loading = ref(false)
|
||||
const loadError = ref('')
|
||||
const total = ref(0)
|
||||
const dateRange = ref([])
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
beginTime: undefined,
|
||||
endTime: undefined,
|
||||
customerId: undefined,
|
||||
siteId: undefined,
|
||||
lineId: undefined,
|
||||
palletCode: undefined,
|
||||
strainId: undefined,
|
||||
batchNo: undefined
|
||||
})
|
||||
let listGeneration = 0
|
||||
|
||||
function invalidateListRequest() {
|
||||
listGeneration += 1
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
function isCurrentListRequest(listContext) {
|
||||
return listContext.generation === listGeneration
|
||||
}
|
||||
|
||||
function getList() {
|
||||
const listContext = {
|
||||
generation: ++listGeneration,
|
||||
query: proxy.addDateRange({ ...queryParams.value }, dateRange.value)
|
||||
}
|
||||
loading.value = true
|
||||
loadError.value = ''
|
||||
listConsumptionReport(listContext.query).then((response) => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
reportList.value = Array.isArray(response.rows) ? response.rows : []
|
||||
total.value = response.total
|
||||
}).catch(() => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
reportList.value = []
|
||||
total.value = 0
|
||||
loadError.value = '产线消耗报表加载失败,请稍后重试'
|
||||
}).finally(() => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
dateRange.value = []
|
||||
proxy.resetForm('queryRef')
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function handleSizeChange(pageSize) {
|
||||
queryParams.value.pageSize = pageSize
|
||||
queryParams.value.pageNum = 1
|
||||
}
|
||||
|
||||
function handleCurrentChange(pageNum) {
|
||||
queryParams.value.pageNum = pageNum
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
invalidateListRequest()
|
||||
})
|
||||
|
||||
getList()
|
||||
</script>
|
||||
@@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="queryRef" :model="queryParams" :inline="true" label-width="76px">
|
||||
<el-form-item label="装填时间">
|
||||
<el-date-picker v-model="dateRange" type="daterange" value-format="YYYY-MM-DD" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="仓库ID" prop="warehouseId">
|
||||
<el-input-number v-model="queryParams.warehouseId" :min="1" :controls="false" placeholder="请输入仓库ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="托盘编号" prop="palletCode">
|
||||
<el-input v-model="queryParams.palletCode" placeholder="请输入托盘编号" clearable maxlength="64" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="菌种ID" prop="strainId">
|
||||
<el-input-number v-model="queryParams.strainId" :min="1" :controls="false" placeholder="请输入菌种ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="生产批次" prop="batchNo">
|
||||
<el-input v-model="queryParams.batchNo" placeholder="请输入生产批次" clearable maxlength="64" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['report:filling:list']">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery" v-hasPermi="['report:filling:list']">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-alert v-if="loadError" :title="loadError" type="error" :closable="false" show-icon class="mb8" />
|
||||
<el-table v-loading="loading" :data="reportList">
|
||||
<template #empty><el-empty description="暂无装填记录" /></template>
|
||||
<el-table-column label="装填单号" prop="fillingNo" min-width="160" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="装填时间" prop="operatedAt" width="180">
|
||||
<template #default="scope">{{ parseTime(scope.row.operatedAt) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="仓库" min-width="140" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ scope.row.warehouseName || `#${scope.row.warehouseId}` }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="托盘" prop="palletCode" min-width="130" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="菌种" min-width="170" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ scope.row.strainNameSnapshot || scope.row.strainCodeSnapshot || `#${scope.row.strainId}` }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="菌种编码快照" prop="strainCodeSnapshot" min-width="140" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="生产批次" prop="batchNo" min-width="130" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="包装规格" prop="packageSpec" min-width="120" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="包数" prop="initialPackages" width="90" align="right" />
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page="queryParams.pageNum"
|
||||
:limit="queryParams.pageSize"
|
||||
@update:page="handleCurrentChange"
|
||||
@update:limit="handleSizeChange"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ReportFilling">
|
||||
import { listFillingReport } from '@/api/report/filling'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const reportList = ref([])
|
||||
const loading = ref(false)
|
||||
const loadError = ref('')
|
||||
const total = ref(0)
|
||||
const dateRange = ref([])
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
beginTime: undefined,
|
||||
endTime: undefined,
|
||||
warehouseId: undefined,
|
||||
palletCode: undefined,
|
||||
strainId: undefined,
|
||||
batchNo: undefined
|
||||
})
|
||||
let listGeneration = 0
|
||||
|
||||
function invalidateListRequest() {
|
||||
listGeneration += 1
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
function isCurrentListRequest(listContext) {
|
||||
return listContext.generation === listGeneration
|
||||
}
|
||||
|
||||
function getList() {
|
||||
const listContext = {
|
||||
generation: ++listGeneration,
|
||||
query: proxy.addDateRange({ ...queryParams.value }, dateRange.value)
|
||||
}
|
||||
loading.value = true
|
||||
loadError.value = ''
|
||||
listFillingReport(listContext.query).then((response) => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
reportList.value = Array.isArray(response.rows) ? response.rows : []
|
||||
total.value = response.total
|
||||
}).catch(() => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
reportList.value = []
|
||||
total.value = 0
|
||||
loadError.value = '装填记录报表加载失败,请稍后重试'
|
||||
}).finally(() => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
dateRange.value = []
|
||||
proxy.resetForm('queryRef')
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function handleSizeChange(pageSize) {
|
||||
queryParams.value.pageSize = pageSize
|
||||
queryParams.value.pageNum = 1
|
||||
}
|
||||
|
||||
function handleCurrentChange(pageNum) {
|
||||
queryParams.value.pageNum = pageNum
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
invalidateListRequest()
|
||||
})
|
||||
|
||||
getList()
|
||||
</script>
|
||||
@@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="queryRef" :model="queryParams" :inline="true" label-width="76px">
|
||||
<el-form-item label="更新时间">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
value-format="YYYY-MM-DD"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="托盘编号" prop="palletCode">
|
||||
<el-input v-model="queryParams.palletCode" placeholder="请输入托盘编号" clearable maxlength="64" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="流转状态" prop="flowState">
|
||||
<el-select v-model="queryParams.flowState" placeholder="请选择状态" clearable style="width: 190px">
|
||||
<el-option v-for="option in flowStateOptions" :key="option.value" :label="option.label" :value="option.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="仓库ID" prop="warehouseId">
|
||||
<el-input-number v-model="queryParams.warehouseId" :min="1" :controls="false" placeholder="请输入仓库ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="现场ID" prop="siteId">
|
||||
<el-input-number v-model="queryParams.siteId" :min="1" :controls="false" placeholder="请输入现场ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="产线ID" prop="lineId">
|
||||
<el-input-number v-model="queryParams.lineId" :min="1" :controls="false" placeholder="请输入产线ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="菌种ID" prop="strainId">
|
||||
<el-input-number v-model="queryParams.strainId" :min="1" :controls="false" placeholder="请输入菌种ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="生产批次" prop="batchNo">
|
||||
<el-input v-model="queryParams.batchNo" placeholder="请输入生产批次" clearable maxlength="64" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['report:palletinventory:list']">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery" v-hasPermi="['report:palletinventory:list']">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-alert v-if="loadError" :title="loadError" type="error" :closable="false" show-icon class="mb8" />
|
||||
<el-table v-loading="loading" :data="reportList">
|
||||
<template #empty><el-empty description="暂无托盘库存数据" /></template>
|
||||
<el-table-column label="托盘编号" prop="palletCode" min-width="140" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="状态" prop="flowState" min-width="150">
|
||||
<template #default="scope">{{ flowStateLabel(scope.row.flowState) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="当前位置" min-width="180" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ currentLocation(scope.row) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="菌种" min-width="160" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ scope.row.strainName || scope.row.strainCode || idFallback(scope.row.strainId) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="生产批次" prop="batchNo" min-width="130" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="初始包数" prop="initialPackages" width="100" align="right" />
|
||||
<el-table-column label="剩余包数" prop="remainingPackages" width="100" align="right" />
|
||||
<el-table-column label="更新时间" prop="updatedAt" width="180">
|
||||
<template #default="scope">{{ parseTime(scope.row.updatedAt) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page="queryParams.pageNum"
|
||||
:limit="queryParams.pageSize"
|
||||
@update:page="handleCurrentChange"
|
||||
@update:limit="handleSizeChange"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ReportPalletInventory">
|
||||
import { listPalletInventory } from '@/api/report/palletInventory'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const reportList = ref([])
|
||||
const loading = ref(false)
|
||||
const loadError = ref('')
|
||||
const total = ref(0)
|
||||
const dateRange = ref([])
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
beginTime: undefined,
|
||||
endTime: undefined,
|
||||
palletCode: undefined,
|
||||
flowState: undefined,
|
||||
warehouseId: undefined,
|
||||
siteId: undefined,
|
||||
lineId: undefined,
|
||||
strainId: undefined,
|
||||
batchNo: undefined
|
||||
})
|
||||
const flowStateOptions = [
|
||||
{ value: 'UNSTOCKED', label: '未入库' },
|
||||
{ value: 'EMPTY_IN_WAREHOUSE', label: '仓库空托盘' },
|
||||
{ value: 'FILLED_IN_WAREHOUSE', label: '仓库有料' },
|
||||
{ value: 'AT_SITE_UNUSED', label: '现场未使用' },
|
||||
{ value: 'AT_SITE_PARTIAL', label: '现场部分使用' },
|
||||
{ value: 'AT_SITE_EMPTY', label: '现场空托盘' },
|
||||
{ value: 'RETURNING', label: '退回中' }
|
||||
]
|
||||
let listGeneration = 0
|
||||
|
||||
function idFallback(id) {
|
||||
return id ? `#${id}` : '—'
|
||||
}
|
||||
|
||||
function flowStateLabel(value) {
|
||||
return flowStateOptions.find((option) => option.value === value)?.label || value || '—'
|
||||
}
|
||||
|
||||
function currentLocation(row) {
|
||||
return row.lineName || row.siteName || row.warehouseName ||
|
||||
idFallback(row.lineId || row.siteId || row.warehouseId)
|
||||
}
|
||||
|
||||
function invalidateListRequest() {
|
||||
listGeneration += 1
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
function isCurrentListRequest(listContext) {
|
||||
return listContext.generation === listGeneration
|
||||
}
|
||||
|
||||
function getList() {
|
||||
const listContext = {
|
||||
generation: ++listGeneration,
|
||||
query: proxy.addDateRange({ ...queryParams.value }, dateRange.value)
|
||||
}
|
||||
loading.value = true
|
||||
loadError.value = ''
|
||||
listPalletInventory(listContext.query).then((response) => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
reportList.value = Array.isArray(response.rows) ? response.rows : []
|
||||
total.value = response.total
|
||||
}).catch(() => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
reportList.value = []
|
||||
total.value = 0
|
||||
loadError.value = '托盘库存报表加载失败,请稍后重试'
|
||||
}).finally(() => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
dateRange.value = []
|
||||
proxy.resetForm('queryRef')
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function handleSizeChange(pageSize) {
|
||||
queryParams.value.pageSize = pageSize
|
||||
queryParams.value.pageNum = 1
|
||||
}
|
||||
|
||||
function handleCurrentChange(pageNum) {
|
||||
queryParams.value.pageNum = pageNum
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
invalidateListRequest()
|
||||
})
|
||||
|
||||
getList()
|
||||
</script>
|
||||
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="queryRef" :model="queryParams" :inline="true" label-width="76px">
|
||||
<el-form-item label="发生时间">
|
||||
<el-date-picker v-model="dateRange" type="daterange" value-format="YYYY-MM-DD" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="托盘编号" prop="palletCode">
|
||||
<el-input v-model="queryParams.palletCode" placeholder="请输入托盘编号" clearable maxlength="64" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="事件类型" prop="eventType">
|
||||
<el-select v-model="queryParams.eventType" placeholder="请选择事件类型" clearable style="width: 190px">
|
||||
<el-option v-for="option in eventTypeOptions" :key="option.value" :label="option.label" :value="option.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['report:pallettrace:list']">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery" v-hasPermi="['report:pallettrace:list']">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-alert v-if="loadError" :title="loadError" type="error" :closable="false" show-icon class="mb8" />
|
||||
<el-table v-loading="loading" :data="reportList">
|
||||
<template #empty><el-empty description="暂无托盘追溯数据" /></template>
|
||||
<el-table-column label="发生时间" prop="occurredAt" width="180">
|
||||
<template #default="scope">{{ parseTime(scope.row.occurredAt) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="事件类型" prop="eventType" min-width="130">
|
||||
<template #default="scope">{{ eventTypeLabel(scope.row.eventType) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来源" min-width="150" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ sourceLabel(scope.row.sourceType, scope.row.sourceId) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="托盘" prop="palletCode" min-width="130" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="变更前状态" prop="beforeState" min-width="140" />
|
||||
<el-table-column label="变更后状态" prop="afterState" min-width="140" />
|
||||
<el-table-column label="变更前位置" min-width="180" :show-overflow-tooltip="true">
|
||||
<template #default="scope">
|
||||
{{ locationLabel(scope.row.beforeWarehouseName, scope.row.beforeSiteName, scope.row.beforeLineName) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="变更后位置" min-width="180" :show-overflow-tooltip="true">
|
||||
<template #default="scope">
|
||||
{{ locationLabel(scope.row.afterWarehouseName, scope.row.afterSiteName, scope.row.afterLineName) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="变更前数量" prop="beforeRemainingPackages" width="110" align="right" />
|
||||
<el-table-column label="变更后数量" prop="afterRemainingPackages" width="110" align="right" />
|
||||
<el-table-column label="操作人" min-width="120" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ scope.row.operatorName || `#${scope.row.operatorId}` }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page="queryParams.pageNum"
|
||||
:limit="queryParams.pageSize"
|
||||
@update:page="handleCurrentChange"
|
||||
@update:limit="handleSizeChange"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ReportPalletTrace">
|
||||
import { listPalletTrace } from '@/api/report/palletTrace'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const reportList = ref([])
|
||||
const loading = ref(false)
|
||||
const loadError = ref('')
|
||||
const total = ref(0)
|
||||
const dateRange = ref([])
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
beginTime: undefined,
|
||||
endTime: undefined,
|
||||
palletCode: undefined,
|
||||
eventType: undefined
|
||||
})
|
||||
const eventTypeOptions = [
|
||||
{ value: 'INBOUND_CONFIRMED', label: '入库确认' },
|
||||
{ value: 'FILLING_CONFIRMED', label: '装填确认' },
|
||||
{ value: 'SHIPMENT_CONFIRMED', label: '发货确认' },
|
||||
{ value: 'USAGE_RECORDED', label: '使用记录' },
|
||||
{ value: 'RETURN_REQUESTED', label: '退回申请' },
|
||||
{ value: 'RETURN_CONFIRMED', label: '退回确认' }
|
||||
]
|
||||
let listGeneration = 0
|
||||
|
||||
function eventTypeLabel(value) {
|
||||
return eventTypeOptions.find((option) => option.value === value)?.label || value || '—'
|
||||
}
|
||||
|
||||
function sourceLabel(sourceType, sourceId) {
|
||||
return sourceType ? `${sourceType} #${sourceId}` : '—'
|
||||
}
|
||||
|
||||
function locationLabel(warehouseName, siteName, lineName) {
|
||||
return [warehouseName, siteName, lineName].filter(Boolean).join(' / ') || '—'
|
||||
}
|
||||
|
||||
function invalidateListRequest() {
|
||||
listGeneration += 1
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
function isCurrentListRequest(listContext) {
|
||||
return listContext.generation === listGeneration
|
||||
}
|
||||
|
||||
function getList() {
|
||||
const listContext = {
|
||||
generation: ++listGeneration,
|
||||
query: proxy.addDateRange({ ...queryParams.value }, dateRange.value)
|
||||
}
|
||||
loading.value = true
|
||||
loadError.value = ''
|
||||
listPalletTrace(listContext.query).then((response) => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
reportList.value = Array.isArray(response.rows) ? response.rows : []
|
||||
total.value = response.total
|
||||
}).catch(() => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
reportList.value = []
|
||||
total.value = 0
|
||||
loadError.value = '托盘追溯报表加载失败,请稍后重试'
|
||||
}).finally(() => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
dateRange.value = []
|
||||
proxy.resetForm('queryRef')
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function handleSizeChange(pageSize) {
|
||||
queryParams.value.pageSize = pageSize
|
||||
queryParams.value.pageNum = 1
|
||||
}
|
||||
|
||||
function handleCurrentChange(pageNum) {
|
||||
queryParams.value.pageNum = pageNum
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
invalidateListRequest()
|
||||
})
|
||||
|
||||
getList()
|
||||
</script>
|
||||
@@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="queryRef" :model="queryParams" :inline="true" label-width="88px">
|
||||
<el-form-item label="申请时间">
|
||||
<el-date-picker v-model="dateRange" type="daterange" value-format="YYYY-MM-DD" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="退回单号" prop="returnNo">
|
||||
<el-input v-model="queryParams.returnNo" placeholder="请输入退回单号" clearable maxlength="64" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="来源现场ID" prop="sourceSiteId">
|
||||
<el-input-number v-model="queryParams.sourceSiteId" :min="1" :controls="false" placeholder="请输入现场ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="目标仓库ID" prop="targetWarehouseId">
|
||||
<el-input-number v-model="queryParams.targetWarehouseId" :min="1" :controls="false" placeholder="请输入仓库ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="托盘编号" prop="palletCode">
|
||||
<el-input v-model="queryParams.palletCode" placeholder="请输入托盘编号" clearable maxlength="64" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="退回状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 160px">
|
||||
<el-option label="已申请" value="REQUESTED" />
|
||||
<el-option label="已确认" value="CONFIRMED" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['report:return:list']">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery" v-hasPermi="['report:return:list']">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-alert v-if="loadError" :title="loadError" type="error" :closable="false" show-icon class="mb8" />
|
||||
<el-table v-loading="loading" :data="reportList">
|
||||
<template #empty><el-empty description="暂无退回仓库数据" /></template>
|
||||
<el-table-column label="退回单号" prop="returnNo" min-width="160" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="状态" prop="status" width="100">
|
||||
<template #default="scope">{{ scope.row.status === 'CONFIRMED' ? '已确认' : '已申请' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请时间" prop="requestedAt" width="180">
|
||||
<template #default="scope">{{ parseTime(scope.row.requestedAt) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="确认时间" prop="confirmedAt" width="180">
|
||||
<template #default="scope">{{ parseTime(scope.row.confirmedAt) || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来源现场" min-width="140" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ scope.row.sourceSiteName || `#${scope.row.sourceSiteId}` }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="目标仓库" min-width="140" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ scope.row.targetWarehouseName || `#${scope.row.targetWarehouseId}` }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="托盘" prop="palletCode" min-width="130" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="剩余包数快照" prop="remainingPackagesSnapshot" width="130" align="right" />
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page="queryParams.pageNum"
|
||||
:limit="queryParams.pageSize"
|
||||
@update:page="handleCurrentChange"
|
||||
@update:limit="handleSizeChange"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ReportReturn">
|
||||
import { listReturnReport } from '@/api/report/return'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const reportList = ref([])
|
||||
const loading = ref(false)
|
||||
const loadError = ref('')
|
||||
const total = ref(0)
|
||||
const dateRange = ref([])
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
beginTime: undefined,
|
||||
endTime: undefined,
|
||||
returnNo: undefined,
|
||||
sourceSiteId: undefined,
|
||||
targetWarehouseId: undefined,
|
||||
palletCode: undefined,
|
||||
status: undefined
|
||||
})
|
||||
let listGeneration = 0
|
||||
|
||||
function invalidateListRequest() {
|
||||
listGeneration += 1
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
function isCurrentListRequest(listContext) {
|
||||
return listContext.generation === listGeneration
|
||||
}
|
||||
|
||||
function getList() {
|
||||
const listContext = {
|
||||
generation: ++listGeneration,
|
||||
query: proxy.addDateRange({ ...queryParams.value }, dateRange.value)
|
||||
}
|
||||
loading.value = true
|
||||
loadError.value = ''
|
||||
listReturnReport(listContext.query).then((response) => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
reportList.value = Array.isArray(response.rows) ? response.rows : []
|
||||
total.value = response.total
|
||||
}).catch(() => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
reportList.value = []
|
||||
total.value = 0
|
||||
loadError.value = '退回仓库报表加载失败,请稍后重试'
|
||||
}).finally(() => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
dateRange.value = []
|
||||
proxy.resetForm('queryRef')
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function handleSizeChange(pageSize) {
|
||||
queryParams.value.pageSize = pageSize
|
||||
queryParams.value.pageNum = 1
|
||||
}
|
||||
|
||||
function handleCurrentChange(pageNum) {
|
||||
queryParams.value.pageNum = pageNum
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
invalidateListRequest()
|
||||
})
|
||||
|
||||
getList()
|
||||
</script>
|
||||
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form ref="queryRef" :model="queryParams" :inline="true" label-width="88px">
|
||||
<el-form-item label="确认时间">
|
||||
<el-date-picker v-model="dateRange" type="daterange" value-format="YYYY-MM-DD" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="发货单号" prop="shipmentNo">
|
||||
<el-input v-model="queryParams.shipmentNo" placeholder="请输入发货单号" clearable maxlength="64" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="来源仓库ID" prop="sourceWarehouseId">
|
||||
<el-input-number v-model="queryParams.sourceWarehouseId" :min="1" :controls="false" placeholder="请输入仓库ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="目标现场ID" prop="targetSiteId">
|
||||
<el-input-number v-model="queryParams.targetSiteId" :min="1" :controls="false" placeholder="请输入现场ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="托盘编号" prop="palletCode">
|
||||
<el-input v-model="queryParams.palletCode" placeholder="请输入托盘编号" clearable maxlength="64" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="单据状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 160px">
|
||||
<el-option label="草稿" value="DRAFT" />
|
||||
<el-option label="已确认" value="CONFIRMED" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['report:shipment:list']">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery" v-hasPermi="['report:shipment:list']">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-alert v-if="loadError" :title="loadError" type="error" :closable="false" show-icon class="mb8" />
|
||||
<el-table v-loading="loading" :data="reportList">
|
||||
<template #empty><el-empty description="暂无发货出库数据" /></template>
|
||||
<el-table-column label="发货单号" prop="shipmentNo" min-width="160" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="确认时间" prop="confirmedAt" width="180">
|
||||
<template #default="scope">{{ parseTime(scope.row.confirmedAt) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来源仓库" min-width="140" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ scope.row.sourceWarehouseName || `#${scope.row.sourceWarehouseId}` }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="客户" min-width="140" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ scope.row.customerName || `#${scope.row.customerId}` }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="目标现场" min-width="140" :show-overflow-tooltip="true">
|
||||
<template #default="scope">{{ scope.row.targetSiteName || `#${scope.row.targetSiteId}` }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="托盘" prop="palletCode" min-width="130" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="发货包数" prop="packageQty" width="100" align="right" />
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page="queryParams.pageNum"
|
||||
:limit="queryParams.pageSize"
|
||||
@update:page="handleCurrentChange"
|
||||
@update:limit="handleSizeChange"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ReportShipment">
|
||||
import { listShipmentReport } from '@/api/report/shipment'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const reportList = ref([])
|
||||
const loading = ref(false)
|
||||
const loadError = ref('')
|
||||
const total = ref(0)
|
||||
const dateRange = ref([])
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
beginTime: undefined,
|
||||
endTime: undefined,
|
||||
shipmentNo: undefined,
|
||||
sourceWarehouseId: undefined,
|
||||
targetSiteId: undefined,
|
||||
palletCode: undefined,
|
||||
status: undefined
|
||||
})
|
||||
let listGeneration = 0
|
||||
|
||||
function invalidateListRequest() {
|
||||
listGeneration += 1
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
function isCurrentListRequest(listContext) {
|
||||
return listContext.generation === listGeneration
|
||||
}
|
||||
|
||||
function getList() {
|
||||
const listContext = {
|
||||
generation: ++listGeneration,
|
||||
query: proxy.addDateRange({ ...queryParams.value }, dateRange.value)
|
||||
}
|
||||
loading.value = true
|
||||
loadError.value = ''
|
||||
listShipmentReport(listContext.query).then((response) => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
reportList.value = Array.isArray(response.rows) ? response.rows : []
|
||||
total.value = response.total
|
||||
}).catch(() => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
reportList.value = []
|
||||
total.value = 0
|
||||
loadError.value = '发货出库报表加载失败,请稍后重试'
|
||||
}).finally(() => {
|
||||
if (!isCurrentListRequest(listContext)) return
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
dateRange.value = []
|
||||
proxy.resetForm('queryRef')
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function handleSizeChange(pageSize) {
|
||||
queryParams.value.pageSize = pageSize
|
||||
queryParams.value.pageNum = 1
|
||||
}
|
||||
|
||||
function handleCurrentChange(pageNum) {
|
||||
queryParams.value.pageNum = pageNum
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
invalidateListRequest()
|
||||
})
|
||||
|
||||
getList()
|
||||
</script>
|
||||
Reference in New Issue
Block a user