feat(wms): 添加钢卷暂存单据管理功能

- 新增钢卷暂存单据列表展示界面
- 实现创建、删除、编辑暂存单据功能
- 添加钢卷选择对话框及查询筛选功能
- 实现已选钢卷列表查看和移除功能
- 集成本地存储管理暂存单据数据
- 添加钢卷重量统计和计算功能
- 实现钢卷去重选择机制防止重复添加
This commit is contained in:
2026-05-11 16:18:07 +08:00
parent 7b1827ed83
commit 2871089799

View File

@@ -607,6 +607,178 @@
</div> </div>
</div> </div>
</el-dialog> </el-dialog>
<!-- 钢卷暂存单据管理 -->
<el-card class="box-card" style="margin-top: 20px;" :body-style="{ padding: '20px' }">
<div slot="header" class="clearfix">
<span>钢卷暂存单据管理</span>
<el-button style="float: right; padding: 3px 0" type="text" @click="createTempOrder">创建暂存单据</el-button>
</div>
<!-- 暂存单据列表 -->
<el-table :data="tempOrderList" style="width: 100%" :height="'calc(100vh - 500px)'">
<el-table-column prop="orderName" label="单据名称">
<template slot-scope="scope">
<div style="display: flex; align-items: center; gap: 5px;">
<el-link type="primary" @click="viewSelectedCoils(scope.row)">{{ scope.row.orderName }}</el-link>
<el-button size="mini" type="text" icon="el-icon-edit" @click="editOrderName(scope.row)"></el-button>
</div>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column prop="coilCount" label="钢卷数量">
<template slot-scope="scope">
<el-tag size="small">{{ (scope.row.coils && scope.row.coils.length) ? scope.row.coils.length : 0 }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="totalWeight" label="总重量(t)">
<template slot-scope="scope">
{{ calculateTotalWeight(scope.row.coils || []).toFixed(3) }}
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" type="text" @click="openCoilSelection(scope.row)">选择钢卷</el-button>
<el-button size="mini" type="text" style="color: #f56c6c;" @click="deleteTempOrder(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 当没有数据时显示提示 -->
<div v-if="!tempOrderList || tempOrderList.length === 0" style="text-align: center; padding: 50px; color: #909399;">
<i class="el-icon-document" style="font-size: 48px; margin-bottom: 10px;"></i>
<div>暂无暂存单据</div>
<div style="font-size: 12px; margin-top: 5px;">点击右上角"创建暂存单据"开始使用</div>
</div>
</el-card>
<!-- 钢卷选择对话框 -->
<el-dialog title="选择钢卷" :visible.sync="coilSelectionVisible" width="95%" append-to-body>
<!-- 上方查询条件 -->
<el-card class="query-card" style="margin-bottom: 15px;">
<el-form :model="coilQueryParams" size="small" :inline="true">
<el-form-item label="入场卷号">
<el-input v-model="coilQueryParams.enterCoilNo" placeholder="请输入入场钢卷号" clearable style="width: 200px;" />
</el-form-item>
<el-form-item label="当前卷号">
<el-input v-model="coilQueryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable style="width: 200px;" />
</el-form-item>
<el-form-item label="产品名称">
<el-input v-model="coilQueryParams.itemName" placeholder="请选择物料" clearable style="width: 200px;" />
</el-form-item>
<el-form-item label="规格">
<el-input v-model="coilQueryParams.itemSpecification" placeholder="请选择规格" clearable style="width: 200px;" />
</el-form-item>
<el-form-item label="材质">
<el-input v-model="coilQueryParams.itemMaterial" placeholder="请选择材质" clearable style="width: 200px;" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="searchCoils">查询</el-button>
<el-button @click="resetCoilQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 下方钢卷列表 -->
<div style="height: 500px;">
<el-table v-loading="coilLoading" :data="availableCoils" @selection-change="handleCoilSelection" border height="450">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="入场钢卷号" align="center" prop="enterCoilNo">
<template slot-scope="scope">
<coil-no :coil-no="scope.row.enterCoilNo"></coil-no>
</template>
</el-table-column>
<el-table-column label="当前钢卷号" align="center" prop="currentCoilNo">
<template slot-scope="scope">
<current-coil-no :current-coil-no="scope.row.currentCoilNo"></current-coil-no>
</template>
</el-table-column>
<el-table-column label="净重" align="center" prop="netWeight" />
<el-table-column label="逻辑库位" align="center" prop="warehouseName" />
<el-table-column label="实际库区" align="center" prop="actualWarehouseName" />
<el-table-column label="产品类型" align="center" width="180">
<template slot-scope="scope">
<ProductInfo v-if="scope.row.itemType == 'product'" :product="scope.row" />
<RawMaterialInfo v-else-if="scope.row.itemType === 'raw_material'" :material="scope.row" />
</template>
</el-table-column>
<el-table-column label="规格" prop="specification"></el-table-column>
<el-table-column label="物料" prop="itemName"></el-table-column>
<el-table-column label="材质" prop="material"></el-table-column>
<el-table-column label="厂家" prop="manufacturer"></el-table-column>
<el-table-column label="表面处理" prop="surfaceTreatmentDesc"></el-table-column>
<el-table-column label="品质" prop="qualityStatus"></el-table-column>
<el-table-column label="切边" prop="trimmingRequirement"></el-table-column>
<el-table-column label="包装" prop="packagingRequirement"></el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<el-tag v-if="scope.row.status === 0" type="info" size="mini">未发货</el-tag>
<el-tag v-else type="success" size="mini">已发货</el-tag>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
</el-table>
<div style="margin-top: 10px; text-align: center;">
<el-pagination
@size-change="handleCoilSizeChange"
@current-change="handleCoilCurrentChange"
:current-page="coilQueryParams.pageNum"
:page-sizes="[10, 20, 50, 100]"
:page-size="coilQueryParams.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="coilTotal">
</el-pagination>
</div>
</div>
<div slot="footer" class="dialog-footer">
<div style="margin-bottom: 10px;">
<span>已选择 {{ selectedCoils.length }} 个钢卷总重量{{ calculateSelectedWeight().toFixed(3) }}t</span>
</div>
<el-button @click="coilSelectionVisible = false">取消</el-button>
<el-button type="primary" @click="saveSelectedCoils">确认选择</el-button>
</div>
</el-dialog>
<!-- 已选钢卷列表对话框 -->
<el-dialog title="已选钢卷列表" :visible.sync="selectedCoilsVisible" width="90%" append-to-body>
<el-table :data="currentTempOrder ? (currentTempOrder.coils || []) : []" border>
<el-table-column label="入场钢卷号" align="center" prop="enterCoilNo">
<template slot-scope="scope">
<coil-no :coil-no="scope.row.enterCoilNo"></coil-no>
</template>
</el-table-column>
<el-table-column label="当前钢卷号" align="center" prop="currentCoilNo">
<template slot-scope="scope">
<current-coil-no :current-coil-no="scope.row.currentCoilNo"></current-coil-no>
</template>
</el-table-column>
<el-table-column label="净重" align="center" prop="netWeight" />
<el-table-column label="逻辑库位" align="center" prop="warehouseName" />
<el-table-column label="实际库区" align="center" prop="actualWarehouseName" />
<el-table-column label="产品类型" align="center" width="180">
<template slot-scope="scope">
<ProductInfo v-if="scope.row.itemType == 'product'" :product="scope.row" />
<RawMaterialInfo v-else-if="scope.row.itemType === 'raw_material'" :material="scope.row" />
</template>
</el-table-column>
<el-table-column label="规格" prop="specification"></el-table-column>
<el-table-column label="物料" prop="itemName"></el-table-column>
<el-table-column label="材质" prop="material"></el-table-column>
<el-table-column label="厂家" prop="manufacturer"></el-table-column>
<el-table-column label="表面处理" prop="surfaceTreatmentDesc"></el-table-column>
<el-table-column label="品质" prop="qualityStatus"></el-table-column>
<el-table-column label="切边" prop="trimmingRequirement"></el-table-column>
<el-table-column label="包装" prop="packagingRequirement"></el-table-column>
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
<el-table-column label="操作" align="center" width="100">
<template slot-scope="scope">
<el-button size="mini" type="text" style="color: #f56c6c;" @click="removeCoilFromOrder(scope.$index)">移除</el-button>
</template>
</el-table-column>
</el-table>
</el-dialog>
</div> </div>
</template> </template>
@@ -994,6 +1166,31 @@ export default {
// 调拨记录弹窗 // 调拨记录弹窗
transferRecordVisible: false, transferRecordVisible: false,
transferRecordList: [], transferRecordList: [],
// 暂存单据管理相关数据
tempOrderList: [],
currentTempOrder: null,
coilSelectionVisible: false,
selectedCoilsVisible: false,
coilLoading: false,
availableCoils: [],
selectedCoils: [],
coilTotal: 0,
coilQueryParams: {
pageNum: 1,
pageSize: 20,
enterCoilNo: '',
currentCoilNo: '',
itemName: '',
itemSpecification: '',
itemMaterial: '',
status: 0,
orderBy: true,
dataType: 1,
materialType: '成品',
itemType: 'product',
excludeBound: true,
selectType: 'product'
},
}; };
}, },
computed: { computed: {
@@ -1021,8 +1218,257 @@ export default {
this.warehouseIds = this.warehouseOptions.map(item => item.value).join(','); this.warehouseIds = this.warehouseOptions.map(item => item.value).join(',');
} }
this.getList(); this.getList();
// 初始化暂存单据列表
this.loadTempOrderList();
}, },
methods: { methods: {
// === 暂存单据管理相关方法 ===
// 加载暂存单据列表
loadTempOrderList() {
const savedOrders = localStorage.getItem('tempCoilOrders');
if (savedOrders) {
this.tempOrderList = JSON.parse(savedOrders);
} else {
this.tempOrderList = [];
}
},
// 保存暂存单据列表到本地存储
saveTempOrderList() {
localStorage.setItem('tempCoilOrders', JSON.stringify(this.tempOrderList));
},
// 创建暂存单据
createTempOrder() {
const orderName = `暂存单据_${new Date().toLocaleString().replace(/[/:]/g, '-')}`;
const newOrder = {
orderId: Date.now().toString(),
orderName: orderName,
createTime: new Date().toLocaleString(),
coils: []
};
this.tempOrderList.unshift(newOrder);
this.saveTempOrderList();
this.$message.success('暂存单据创建成功');
},
// 删除暂存单据
deleteTempOrder(order) {
this.$confirm(`确认删除暂存单据"${order.orderName}"吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const index = this.tempOrderList.findIndex(item => item.orderId === order.orderId);
if (index > -1) {
this.tempOrderList.splice(index, 1);
this.saveTempOrderList();
this.$message.success('删除成功');
}
}).catch(() => {
this.$message.info('已取消删除');
});
},
// 查看已选钢卷列表
viewSelectedCoils(order) {
this.currentTempOrder = order;
this.selectedCoilsVisible = true;
},
// 编辑单据名称
editOrderName(order) {
this.$prompt('请输入新的单据名称', '编辑单据名称', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputValue: order.orderName,
inputValidator: (value) => {
if (!value || value.trim() === '') {
return '单据名称不能为空';
}
return true;
}
}).then(({ value }) => {
const newName = value.trim();
// 检查名称是否重复
const duplicateOrder = this.tempOrderList.find(item =>
item.orderId !== order.orderId && item.orderName === newName
);
if (duplicateOrder) {
this.$message.warning('单据名称已存在,请使用其他名称');
return;
}
// 更新单据名称
order.orderName = newName;
this.saveTempOrderList();
this.$message.success('单据名称修改成功');
}).catch(() => {
this.$message.info('已取消编辑');
});
},
// 打开钢卷选择对话框
openCoilSelection(order) {
this.currentTempOrder = order;
this.coilSelectionVisible = true;
this.searchCoils();
},
// 计算总重量
calculateTotalWeight(coils) {
if (!coils || coils.length === 0) return 0;
return coils.reduce((total, coil) => {
return total + (parseFloat(coil.netWeight) || 0);
}, 0);
},
// 计算选中钢卷的总重量
calculateSelectedWeight() {
return this.calculateTotalWeight(this.selectedCoils);
},
// 查询钢卷
async searchCoils() {
this.coilLoading = true;
try {
// 构建查询参数
const params = { ...this.coilQueryParams };
// 移除空值参数
Object.keys(params).forEach(key => {
if (params[key] === '' || params[key] === null || params[key] === undefined) {
delete params[key];
}
});
// 调用接口查询钢卷
const response = await listMaterialCoil(params);
this.availableCoils = response.rows || [];
this.coilTotal = response.total || 0;
// 过滤掉所有单据中已选择的钢卷,确保钢卷在所有单据中唯一
const allExistingCoilIds = [];
this.tempOrderList.forEach(order => {
if (order.coils && Array.isArray(order.coils)) {
order.coils.forEach(coil => {
if (coil.coilId) {
allExistingCoilIds.push(coil.coilId);
}
});
}
});
// 如果是当前正在编辑的单据排除当前单据中的钢卷因为它们已经在allExistingCoilIds中了
// 这样可以确保其他单据不能选择当前单据已选的钢卷
this.availableCoils = this.availableCoils.filter(coil => !allExistingCoilIds.includes(coil.coilId));
} catch (error) {
console.error('查询钢卷失败:', error);
this.$message.error('查询钢卷失败');
} finally {
this.coilLoading = false;
}
},
// 重置钢卷查询条件
resetCoilQuery() {
this.coilQueryParams = {
pageNum: 1,
pageSize: 20,
enterCoilNo: '',
currentCoilNo: '',
itemName: '',
itemSpecification: '',
itemMaterial: '',
status: 0,
orderBy: true,
dataType: 1,
materialType: '成品',
itemType: 'product',
excludeBound: true,
selectType: 'product'
};
this.searchCoils();
},
// 处理钢卷选择变化
handleCoilSelection(selection) {
this.selectedCoils = selection;
},
// 保存选中的钢卷
saveSelectedCoils() {
if (!this.currentTempOrder) {
this.$message.error('请先选择暂存单据');
return;
}
if (this.selectedCoils.length === 0) {
this.$message.warning('请选择要添加的钢卷');
return;
}
// 确保coils数组存在
if (!this.currentTempOrder.coils) {
this.currentTempOrder.coils = [];
}
// 由于在查询阶段已经过滤了所有重复的钢卷,这里不需要再次检查
// 但为了安全起见,保留基本的检查逻辑
if (this.currentTempOrder.coils && this.currentTempOrder.coils.length > 0) {
const existingCoilIds = this.currentTempOrder.coils.map(coil => coil.coilId);
const duplicateCoils = this.selectedCoils.filter(coil => existingCoilIds.includes(coil.coilId));
if (duplicateCoils.length > 0) {
this.$message.warning(`钢卷 ${duplicateCoils.map(coil => coil.enterCoilNo).join(', ')} 已存在,不能重复添加`);
return;
}
}
// 添加钢卷到当前单据
this.currentTempOrder.coils.push(...this.selectedCoils);
this.saveTempOrderList();
this.$message.success(`成功添加 ${this.selectedCoils.length} 个钢卷`);
// 关闭对话框并重置选择
this.coilSelectionVisible = false;
this.selectedCoils = [];
},
// 从单据中移除钢卷
removeCoilFromOrder(index) {
if (!this.currentTempOrder || !this.currentTempOrder.coils || !this.currentTempOrder.coils[index]) return;
this.$confirm('确认移除该钢卷吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.currentTempOrder.coils.splice(index, 1);
this.saveTempOrderList();
this.$message.success('移除成功');
}).catch(() => {
this.$message.info('已取消移除');
});
},
// 钢卷分页相关方法
handleCoilSizeChange(val) {
this.coilQueryParams.pageSize = val;
this.coilQueryParams.pageNum = 1;
this.searchCoils();
},
handleCoilCurrentChange(val) {
this.coilQueryParams.pageNum = val;
this.searchCoils();
},
// 进入数字钢卷页面 // 进入数字钢卷页面
handleNumberCoilClick(row) { handleNumberCoilClick(row) {
this.$router.push({ this.$router.push({