feat(wms/linkage): 实现调拨分包打印功能

- 新增调拨分包打印对话框和相关逻辑
- 实现平均分包和自定义分包模式
- 添加分包数量、每包数量等配置选项
- 集成打印任务创建和编辑功能
- 优化任务列表展示和打印流程
master
zangch@mesnac.com 5 months ago
parent 5c60930261
commit 9bc9569fa0

@ -18,17 +18,10 @@
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="parentTableAdd"></el-button>
</el-col>
<!-- <el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="ids.length !== 1" @click="parentTableUpdate(null)">
</el-button>
</el-col>-->
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="ids.length < 1" @click="parentTableDelete(null)">
</el-button>
</el-col>
<!-- <el-col :span="1.5">-->
<!-- <el-button type="warning" plain icon="Download" @click="handleExport"></el-button>-->
<!-- </el-col>-->
<right-toolbar v-model:showSearch="showSearch" :columns="columns" :search="true"
@queryTable="getParentTable"></right-toolbar>
</el-row>
@ -39,8 +32,6 @@
<el-table-column type="selection" width="55"/>
<el-table-column label="表主键" align="center" prop="aoId" v-if="false"/>
<el-table-column label="调拨单号" align="center" prop="allocateOrderCode"/>
<!-- <el-table-column label="物料大类" align="center" prop="materialCategoryName">
</el-table-column>-->
<el-table-column label="出库仓库" align="center" prop="planWarehouseName"/>
<el-table-column label="工单状态" align="center" prop="orderStatus">
<template #default="scope">
@ -60,18 +51,6 @@
</template>
</el-table-column>
<el-table-column label="审核意见" align="center" prop="auditComments"/>
<!-- <el-table-column label="是否创建出库单" align="center" prop="createOut">
<template #default="scope">
<dict-tag :options="wms_allocate_create" :value="scope.row.createOut"/>
</template>
</el-table-column>
<el-table-column label="出库单号" align="center" prop="outCode"/>
<el-table-column label="是否创建入库单" align="center" prop="createIn">
<template #default="scope">
<dict-tag :options="wms_allocate_create" :value="scope.row.createIn"/>
</template>
</el-table-column>
<el-table-column label="入库单号" align="center" prop="inCode"/> -->
<el-table-column label="入库方式" align="center" prop="inMethod">
<template #default="scope">
<dict-tag :options="wms_allocate_way" :value="scope.row.inMethod"/>
@ -79,9 +58,9 @@
</el-table-column>
<el-table-column label="操作" fixed="right" width="200">
<template #default="scope">
<!-- <el-button size="small" @click.stop="viewDetails(scope.row)">-->
<!-- 查看-->
<!-- </el-button>-->
<el-button size="small" @click.stop="viewDetails(scope.row)">
查看
</el-button>
<!-- <el-button size="small" @click.stop="parentTableUpdate(scope.row)">
修改
</el-button>-->
@ -115,18 +94,12 @@
</el-table-column>
<el-table-column label="erp同步数量" align="center" prop="erpSynchronousQty"/>
<el-table-column label="已分包数量" align="center" prop="printedQty" />
<el-table-column label="操作" fixed="right" width="400">
<el-table-column label="操作" fixed="right" width="300">
<template #default="scope">
<el-button size="small" @click="childrenTablePrint(scope.row)"
v-if="partntTableSelectCell && partntTableSelectCell.auditStatus == '1' && !hasExistingTasks(scope.row)"
<el-button size="small" @click="handleAllocatePrint(scope.row)"
v-if="partntTableSelectCell && partntTableSelectCell.auditStatus == '1' && canPrint(scope.row)"
type="primary">
创建任务
</el-button>
<el-button size="small" @click="deleteAllTasks(scope.row)"
v-if="hasExistingTasks(scope.row)"
type="danger"
:disabled="!canDelete(scope.row)">
删除任务
分包打印
</el-button>
<el-button size="small" @click="viewPrintTasks(scope.row)">
查看任务
@ -143,6 +116,86 @@
</el-table>
</el-card>
<!-- 调拨分包打印对话框 -->
<el-dialog title="调拨分包打印" v-model="allocatePrintDialogVisible" width="40%">
<el-form :model="allocatePrintForm" label-width="120px">
<el-form-item label="物料编码">
<el-input v-model="allocatePrintForm.materialCode" readonly />
</el-form-item>
<el-form-item label="物料名称">
<el-input v-model="allocatePrintForm.materialName" readonly />
</el-form-item>
<el-form-item label="调拨数量">
<el-input v-model="allocatePrintForm.allocateOrderQty" readonly />
</el-form-item>
<el-form-item label="出库数量">
<el-input v-model="allocatePrintForm.outSum" readonly />
</el-form-item>
<el-form-item label="已分包数量" prop="printedQty">
<el-input v-model="allocatePrintForm.printedQty" readonly />
</el-form-item>
<el-form-item label="分包数量" prop="splitPackageCount">
<el-input-number v-model="allocatePrintForm.splitPackageCount" :min="1" :max="allocateOrderQty" placeholder="请输入分包数量" @change="onAllocateSplitPackageCountChange" />
</el-form-item>
<!-- 当分包数量大于1时显示分包模式选择和每包数量配置 -->
<el-form-item v-if="allocatePrintForm.splitPackageCount > 1" label="分包模式">
<el-radio-group v-model="allocatePackageMode" @change="onAllocatePackageModeChange">
<el-radio value="average">平均分包</el-radio>
<el-radio value="custom">自定义每包数量</el-radio>
</el-radio-group>
</el-form-item>
<!-- 平均分包模式显示分包预览 -->
<el-form-item v-if="allocatePrintForm.splitPackageCount > 1 && allocatePackageMode === 'average'" label="分包预览">
<div class="package-preview-container">
<div class="package-preview-item" v-for="(qty, index) in allocateAveragePackageList" :key="index">
<span class="package-label">{{index + 1}}</span>
<span class="package-qty">{{qty}}</span>
</div>
<div class="total-qty-info">
<span :class="{'error-text': allocateAverageTotal !== allocateOrderQty}">总计{{allocateAverageTotal}} / {{allocateOrderQty}}</span>
<span v-if="allocateAverageTotal !== allocateOrderQty" class="error-text"> - </span>
</div>
</div>
</el-form-item>
<!-- 自定义每包数量模式显示输入框 -->
<el-form-item v-if="allocatePrintForm.splitPackageCount > 1 && allocatePackageMode === 'custom'" label="每包数量分配">
<div class="package-qty-container">
<div v-for="(qty, index) in allocatePackageQtyList" :key="index" class="package-qty-item">
<label>{{index + 1}}</label>
<el-input-number
v-model="allocatePackageQtyList[index]"
:min="1"
:max="allocateOrderQty"
placeholder="请输入数量"
@change="validateAllocateTotalQty"
size="small"
style="width: 120px;"
/>
</div>
<div class="total-qty-info">
<span :class="{'error-text': allocateTotalPackageQty !== allocateOrderQty}">总计{{allocateTotalPackageQty}} / {{allocateOrderQty}}</span>
<span v-if="allocateTotalPackageQty !== allocateOrderQty" class="error-text"> - </span>
</div>
</div>
</el-form-item>
<el-form-item label="打印数量" prop="printCopies" v-if="allocatePrintForm.splitPackageCount === 1 || !allocatePrintForm.splitPackageCount">
<el-input-number v-model="allocatePrintForm.printCopies" :min="1" :max="20" placeholder="请输入打印条码数量" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="allocatePrintDialogVisible = false">关闭</el-button>
<el-button type="primary" @click="submitAllocatePrintForm" :disabled="!isValidAllocatePackage">
确定打印
</el-button>
</div>
</template>
</el-dialog>
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="80%">
<el-card shadow="never">
<el-form :model="dialogForm" :inline="true" label-width="120px" :disabled="isView">
@ -689,10 +742,6 @@ const partntTableSelectCell = ref<any>({})
//
const printDialogVisible = ref(false)
const taskDialogVisible = ref(false)
const editTaskDialogVisible = ref(false)
const taskList = ref([])
const currentTasksMap = ref(new Map()) //
const printForm = ref({
aoDId: null,
allocateCode: '',
@ -704,12 +753,50 @@ const printForm = ref({
printCopies: 1,
packageQtyList: []
})
//
const allocatePrintDialogVisible = ref(false)
const taskDialogVisible = ref(false)
const editTaskDialogVisible = ref(false)
const taskList = ref([])
const currentTasksMap = ref(new Map()) //
const allocatePrintForm = ref({
aoDId: null,
allocateCode: '',
materialCode: '',
materialName: '',
allocateOrderQty: 0,
outSum: 0,
printedQty: 0,
splitPackageCount: 1,
printCopies: 1,
packageQtyList: []
})
const editTaskForm = ref({
allocateTaskId: null,
batchCode: '',
materialQty: 1
})
//
const allocatePackageQtyList = ref([])
const allocatePackageMode = ref('average') // 'average' 'custom'
const allocateTotalPackageQty = computed(() => {
return allocatePackageQtyList.value.reduce((sum, qty) => sum + (Number(qty) || 0), 0)
})
//
const allocateAveragePackageList = ref([])
const allocateAverageTotal = computed(() => {
return allocateAveragePackageList.value.reduce((sum, qty) => sum + (Number(qty) || 0), 0)
})
//
const allocateOrderQty = computed(() => {
return Number(allocatePrintForm.value.allocateOrderQty) || 0
})
//
let baseStoreList = ref([]);
getBaseWarehouseList(null).then(e => {
@ -1208,18 +1295,6 @@ const childrenTablePrint = async (row) => {
}
}
/** 查看任务按钮点击事件 */
const viewPrintTasks = async (row) => {
try {
const result = await queryTasksByDetailId(row.aoDId);
taskList.value = result.data || [];
taskDialogVisible.value = true;
} catch (error) {
console.error('查询任务错误:', error);
ElMessage.error('查询任务失败');
}
}
/** 打印模式变化事件 */
const onPrintModeChange = () => {
if (printForm.value.printMode === 'package') {
@ -1313,54 +1388,7 @@ const deleteAllTasks = async (row) => {
}
}
/** 任务打印按钮点击 */
const handleTaskPrint = async (task) => {
try {
await triggerPrint(task.allocateTaskId);
ElMessage.success('打印成功');
} catch (error) {
console.error('打印错误:', error);
ElMessage.error('打印失败:' + ((error as any).response?.data?.msg || (error as any).message || '未知错误'));
}
}
/** 任务编辑按钮点击 */
const handleTaskEdit = (task) => {
editTaskForm.value = {
allocateTaskId: task.allocateTaskId,
batchCode: task.batchCode,
materialQty: task.materialQty
};
editTaskDialogVisible.value = true;
}
/** 任务更新 */
const handleTaskUpdate = async () => {
try {
if (!editTaskForm.value.batchCode) {
ElMessage.error('请输入批次码');
return;
}
if (!editTaskForm.value.materialQty || editTaskForm.value.materialQty <= 0) {
ElMessage.error('请输入正确的数量');
return;
}
await updateTaskBarcode(editTaskForm.value);
ElMessage.success('修改成功');
editTaskDialogVisible.value = false;
//
const currentDetailId = taskList.value[0]?.aoDId;
if (currentDetailId) {
const result = await queryTasksByDetailId(currentDetailId);
taskList.value = result.data || [];
}
} catch (error) {
console.error('修改任务错误:', error);
ElMessage.error('修改失败:' + ((error as any).response?.data?.msg || (error as any).message || '未知错误'));
}
}
const handlePrintSubmit = async () => {
try {
if (!isValidPackage.value) {
@ -1414,6 +1442,202 @@ const canDelete = (row) => {
// outSumdoubleallocateOrderQtyBigDecimal
return Number(row.outSum) === Number(row.allocateOrderQty);
}
/** 判断是否可以打印 */
const canPrint = (row) => {
//
return Number(row.outSum) === Number(row.allocateOrderQty);
}
/** 调拨分包打印按钮点击事件 */
const handleAllocatePrint = (row) => {
//
if (!canPrint(row)) {
ElMessage.error(`只有出库数量等于调拨数量时才能打印,当前出库数量:${row.outSum},调拨数量:${row.allocateOrderQty}`);
return;
}
//
allocatePrintForm.value = {
aoDId: row.aoDId,
allocateCode: row.allocateCode,
materialCode: row.materialCode,
materialName: row.materialName || '',
allocateOrderQty: Number(row.allocateOrderQty),
outSum: Number(row.outSum),
printedQty: Number(row.printedQty || 0),
splitPackageCount: 1,
printCopies: 1,
packageQtyList: []
};
allocatePrintDialogVisible.value = true;
}
/** 分包数量变化时的处理函数 */
const onAllocateSplitPackageCountChange = (count) => {
if (count > 1) {
// 使
allocatePackageMode.value = 'average'
//
allocatePackageQtyList.value = new Array(count).fill(1)
allocateAveragePackageList.value = new Array(count).fill(1)
//
calculateAllocateAveragePackage(count)
//
allocatePackageQtyList.value = [...allocateAveragePackageList.value]
} else {
allocatePackageQtyList.value = []
allocateAveragePackageList.value = []
allocatePackageMode.value = 'average'
}
}
/** 计算平均分包数量 */
const calculateAllocateAveragePackage = (count) => {
const totalQty = allocateOrderQty.value // 使
if (totalQty > 0 && count > 0) {
const avgQty = Math.floor(totalQty / count)
const remainder = totalQty % count
allocateAveragePackageList.value = []
for (let i = 0; i < count; i++) {
// avgQty + 1 avgQty
allocateAveragePackageList.value[i] = avgQty + (i < remainder ? 1 : 0)
}
}
}
/** 分包模式变化时的处理 */
const onAllocatePackageModeChange = (mode) => {
if (mode === 'custom') {
// 使
allocatePackageQtyList.value = [...allocateAveragePackageList.value]
}
//
}
/** 验证总数量是否超出限制 */
const validateAllocateTotalQty = () => {
const total = allocateTotalPackageQty.value
const totalQty = allocateOrderQty.value
if (total > totalQty) {
ElMessage.warning(`每包数量总计不能超过调拨数量 ${totalQty}`)
}
// 1
if (allocatePrintForm.value.splitPackageCount > 1 && total !== totalQty) {
ElMessage.warning(`分包数量大于1时每包数量总计必须等于调拨数量 ${totalQty}`)
}
}
/** 计算属性:验证分包是否有效 */
const isValidAllocatePackage = computed(() => {
if (allocatePrintForm.value.splitPackageCount === 1) {
return allocatePrintForm.value.printCopies > 0;
} else {
return allocateAverageTotal.value === allocateOrderQty.value &&
allocateAveragePackageList.value.every(qty => Number(qty) > 0);
}
})
/** 提交调拨分包打印 */
const submitAllocatePrintForm = async () => {
try {
if (!isValidAllocatePackage.value) {
ElMessage.error('请正确设置打印参数');
return;
}
const params = {
aoDId: allocatePrintForm.value.aoDId,
allocateCode: allocatePrintForm.value.allocateCode,
splitPackageCount: allocatePrintForm.value.splitPackageCount,
printCopies: allocatePrintForm.value.printCopies || 1,
packageQtyList: allocatePrintForm.value.splitPackageCount > 1
? (allocatePackageMode.value === 'average' ? allocateAveragePackageList.value : allocatePackageQtyList.value)
: null
};
await allocatePackagePrint(params);
ElMessage.success('分包打印成功');
allocatePrintDialogVisible.value = false;
//
if (partntTableSelectCell.value?.allocateOrderCode) {
await getChildrenTable({allocateCode: partntTableSelectCell.value.allocateOrderCode});
}
} catch (error) {
console.error('分包打印错误:', error);
ElMessage.error('分包打印失败:' + ((error as any).response?.data?.msg || (error as any).message || '未知错误'));
}
}
/** 查看任务按钮点击事件 */
const viewPrintTasks = async (row) => {
try {
const result = await queryTasksByDetailId(row.aoDId);
taskList.value = result.data || [];
taskDialogVisible.value = true;
} catch (error) {
console.error('查询任务错误:', error);
ElMessage.error('查询任务失败');
}
}
/** 任务打印按钮点击 */
const handleTaskPrint = async (task) => {
try {
await triggerPrint(task.allocateTaskId);
ElMessage.success('打印成功');
} catch (error) {
console.error('打印错误:', error);
ElMessage.error('打印失败:' + ((error as any).response?.data?.msg || (error as any).message || '未知错误'));
}
}
/** 任务编辑按钮点击 */
const handleTaskEdit = (task) => {
editTaskForm.value = {
allocateTaskId: task.allocateTaskId,
batchCode: task.batchCode,
materialQty: task.materialQty
};
editTaskDialogVisible.value = true;
}
/** 任务更新 */
const handleTaskUpdate = async () => {
try {
if (!editTaskForm.value.batchCode) {
ElMessage.error('请输入批次码');
return;
}
if (!editTaskForm.value.materialQty || editTaskForm.value.materialQty <= 0) {
ElMessage.error('请输入正确的数量');
return;
}
await updateTaskBarcode(editTaskForm.value);
ElMessage.success('修改成功');
editTaskDialogVisible.value = false;
//
const currentDetailId = taskList.value[0]?.aoDId;
if (currentDetailId) {
const result = await queryTasksByDetailId(currentDetailId);
taskList.value = result.data || [];
}
} catch (error) {
console.error('修改任务错误:', error);
ElMessage.error('修改失败:' + ((error as any).response?.data?.msg || (error as any).message || '未知错误'));
}
}
</script>
<style>
.demo-form-inline .el-input {
@ -1428,4 +1652,69 @@ const canDelete = (row) => {
border-color: #f56c6c !important;
box-shadow: 0 0 0 1px #f56c6c inset !important;
}
.package-qty-container {
display: flex;
flex-direction: column;
gap: 8px;
max-height: 200px;
overflow-y: auto;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 12px;
background-color: #fafafa;
}
.package-qty-item {
display: flex;
align-items: center;
gap: 10px;
}
.package-qty-item label {
min-width: 60px;
font-size: 14px;
color: #606266;
}
.package-preview-container {
display: flex;
flex-direction: column;
gap: 6px;
border: 1px solid #e4e7ed;
border-radius: 4px;
padding: 12px;
background-color: #f9f9f9;
}
.package-preview-item {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 0;
}
.package-label {
min-width: 60px;
font-size: 14px;
color: #606266;
font-weight: 500;
}
.package-qty {
font-size: 14px;
color: #409EFF;
font-weight: bold;
}
.total-qty-info {
padding-top: 8px;
border-top: 1px solid #e4e7ed;
font-weight: bold;
text-align: right;
}
.error-text {
color: #f56c6c;
}
</style>

Loading…
Cancel
Save