| | |
| | | class="material-requisition-dialog" |
| | | > |
| | | <div class="material-requisition-form"> |
| | | <!-- 原材料列表 --> |
| | | <el-table :data="materialList" border style="width: 100%" height="65vh"> |
| | | <el-table-column type="index" label="序号" width="60" align="center" /> |
| | | <el-table-column prop="productName" label="产品名称" min-width="150" /> |
| | | <el-table-column prop="model" label="型号" min-width="150" /> |
| | | <!-- <el-table-column prop="batchNo" label="批号" min-width="150"> |
| | | <template #default="{ row }"> |
| | | <el-select |
| | | v-model="row.batchNo" |
| | | placeholder="请选择批号" |
| | | clearable |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in row.batchOptions || []" |
| | | :key="item.batchNo" |
| | | :label="item.batchNo" |
| | | :value="item.batchNo" |
| | | /> |
| | | </el-select> |
| | | </template> |
| | | </el-table-column> --> |
| | | <el-table-column prop="unit" label="单位" width="80" align="center" /> |
| | | <el-table-column prop="qualitity" label="数量" width="100" align="center"> |
| | | <template #default="{ row }"> |
| | | {{ row.qualitity || 0 }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="requisitionQty" label="领用数量" width="120" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-input-number |
| | | v-model="row.requisitionQty" |
| | | :min="0" |
| | | :precision="2" |
| | | :controls="false" |
| | | :disabled="!row.qualitity || hasDrawMaterials" |
| | | style="width: 100%" |
| | | /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="remark" label="备注" min-width="150"> |
| | | </el-table-column> |
| | | </el-table> |
| | | <!-- 原材料 Tab --> |
| | | |
| | | <div class="operation-bar"> |
| | | <el-button type="primary" @click="handleAdd">新增</el-button> |
| | | </div> |
| | | <el-table :data="materialList" border style="width: 100%" height="50vh"> |
| | | <el-table-column type="index" label="序号" width="60" align="center" /> |
| | | <el-table-column prop="productName" label="产品名称" min-width="150" /> |
| | | <el-table-column prop="model" label="型号" min-width="150" /> |
| | | <el-table-column prop="unit" label="单位" width="80" align="center" /> |
| | | <el-table-column prop="qualitity" label="可领用数量" width="100" align="center"> |
| | | <template #default="{ row }"> |
| | | {{ row.qualitity || 0 }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="requisitionQty" label="领用数量" width="120" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-input-number |
| | | v-model="row.requisitionQty" |
| | | :min="0" |
| | | :max="row.qualitity || 0" |
| | | :precision="2" |
| | | :controls="false" |
| | | :disabled="!row.qualitity" |
| | | style="width: 100%" |
| | | /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="remark" label="备注" min-width="150"> |
| | | <template #default="{ row }"> |
| | | <el-input v-model="row.remark" placeholder="请输入备注" clearable /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="80" align="center"> |
| | | <template #default="{ $index }"> |
| | | <el-button type="danger" link @click="handleDelete($index)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <template #footer> |
| | |
| | | <el-button @click="handleCancel">取 消</el-button> |
| | | </span> |
| | | </template> |
| | | |
| | | <!-- 新增原材料弹窗 --> |
| | | <el-dialog |
| | | v-model="addDialogVisible" |
| | | title="选择原材料" |
| | | width="800px" |
| | | top="5vh" |
| | | :close-on-click-modal="false" |
| | | append-to-body |
| | | > |
| | | <el-table |
| | | :data="availableMaterials" |
| | | border |
| | | style="width: 100%" |
| | | height="50vh" |
| | | @selection-change="handleSelectionChange" |
| | | > |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column type="index" label="序号" width="60" align="center" /> |
| | | <el-table-column prop="productName" label="产品名称" min-width="150" /> |
| | | <el-table-column prop="model" label="型号" min-width="150" /> |
| | | <el-table-column prop="unit" label="单位" width="80" align="center" /> |
| | | <el-table-column prop="qualitity" label="可领用数量" width="100" align="center"> |
| | | <template #default="{ row }"> |
| | | {{ row.qualitity || 0 }} |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="primary" @click="handleAddConfirm">确 定</el-button> |
| | | <el-button @click="addDialogVisible = false">取 消</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, computed, watch } from 'vue'; |
| | | import { ref, computed, watch } from 'vue'; |
| | | import { ElMessage } from 'element-plus'; |
| | | import { getByBomId, drawMaterials } from '@/api/productionManagement/productionOrder.js'; |
| | | import { drawMaterials } from '@/api/productionManagement/productionOrder.js'; |
| | | import { getMaterials } from '@/api/inventoryManagement/stockInventory.js'; |
| | | |
| | | const props = defineProps({ |
| | | modelValue: { |
| | |
| | | |
| | | const loading = ref(false); |
| | | const saving = ref(false); |
| | | const activeTab = ref('material'); |
| | | const materialList = ref([]); |
| | | const hasDrawMaterials = ref(false); |
| | | |
| | | // 新增弹窗相关 |
| | | const addDialogVisible = ref(false); |
| | | const availableMaterials = ref([]); |
| | | const selectedMaterials = ref([]); |
| | | |
| | | // 监听弹框打开,加载数据 |
| | | watch(() => props.modelValue, (val) => { |
| | |
| | | const loadMaterialList = async () => { |
| | | const order = props.orderData; |
| | | const drawMaterialsData = order.drawMaterials; |
| | | const bomId = order?.bomId; |
| | | |
| | | // 如果已有领料数据,直接使用 |
| | | // 先获取getMaterials的最新数据 |
| | | let materialsFromApi = []; |
| | | if (bomId) { |
| | | try { |
| | | const res = await getMaterials({ bomId }); |
| | | materialsFromApi = res.data || []; |
| | | } catch (error) { |
| | | console.error('查询原材料列表失败:', error); |
| | | } |
| | | } |
| | | |
| | | // 加载已保存的领料数据 |
| | | if (drawMaterialsData) { |
| | | hasDrawMaterials.value = true; |
| | | try { |
| | | const list = typeof drawMaterialsData === 'string' |
| | | ? JSON.parse(drawMaterialsData) |
| | | : drawMaterialsData; |
| | | materialList.value = list.map(item => ({ |
| | | ...item, |
| | | requisitionQty: item.requisitionQty || 0 |
| | | })); |
| | | return; |
| | | // 合并数据:使用API的qualitity,使用保存的requisitionQty和remark |
| | | materialList.value = list.map(savedItem => { |
| | | const apiItem = materialsFromApi.find(m => m.id === savedItem.id || m.productModelId === savedItem.productModelId); |
| | | return { |
| | | ...savedItem, |
| | | qualitity: apiItem?.qualitity ?? savedItem.qualitity ?? 0, |
| | | requisitionQty: savedItem.requisitionQty || 0 |
| | | }; |
| | | }); |
| | | } catch (e) { |
| | | console.error('解析领料数据失败:', e); |
| | | materialList.value = []; |
| | | } |
| | | } else { |
| | | materialList.value = []; |
| | | } |
| | | }; |
| | | |
| | | // 没有领料数据,调用接口查询 |
| | | hasDrawMaterials.value = false; |
| | | // 打开新增弹窗 |
| | | const handleAdd = async () => { |
| | | const order = props.orderData; |
| | | const bomId = order?.bomId; |
| | | if (!bomId) { |
| | | ElMessage.warning('当前订单缺少BOM信息'); |
| | |
| | | |
| | | loading.value = true; |
| | | try { |
| | | const res = await getByBomId({ bomId }); |
| | | const data = res.data || []; |
| | | // 处理数据,添加领用数量字段和批号选项 |
| | | materialList.value = data.map(item => ({ |
| | | ...item, |
| | | requisitionQty: item.qualitity ? 0 : 0, |
| | | batchNo: item.batchNo || '', |
| | | remark: item.remark || '', |
| | | // 批号选项,从库存原材料信息中获取 |
| | | batchOptions: item.inventoryList || [] |
| | | })); |
| | | const res = await getMaterials({ bomId }); |
| | | console.log('getMaterials返回数据:', res.data); |
| | | // 直接展示所有数据,不过滤 |
| | | availableMaterials.value = res.data || []; |
| | | selectedMaterials.value = []; |
| | | addDialogVisible.value = true; |
| | | } catch (error) { |
| | | console.error('查询原材料列表失败:', error); |
| | | ElMessage.error('查询原材料列表失败'); |
| | | materialList.value = []; |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | // 选择变化 |
| | | const handleSelectionChange = (selection) => { |
| | | selectedMaterials.value = selection; |
| | | }; |
| | | |
| | | // 确认添加 |
| | | const handleAddConfirm = () => { |
| | | if (selectedMaterials.value.length === 0) { |
| | | ElMessage.warning('请选择至少一条记录'); |
| | | return; |
| | | } |
| | | |
| | | // 过滤掉已存在的(通过id和productModelId判断) |
| | | const existingIds = materialList.value.map(item => item.id); |
| | | const existingProductModelIds = materialList.value.map(item => item.productModelId); |
| | | |
| | | const newItems = selectedMaterials.value |
| | | .filter(item => !existingIds.includes(item.id) && !existingProductModelIds.includes(item.productModelId)) |
| | | .map(item => ({ |
| | | ...item, |
| | | requisitionQty: 0, |
| | | remark: '' |
| | | })); |
| | | |
| | | if (newItems.length === 0) { |
| | | ElMessage.warning('所选数据已存在,无需重复添加'); |
| | | return; |
| | | } |
| | | |
| | | materialList.value = [...materialList.value, ...newItems]; |
| | | addDialogVisible.value = false; |
| | | ElMessage.success(`成功添加 ${newItems.length} 条记录`); |
| | | }; |
| | | |
| | | // 删除 |
| | | const handleDelete = (index) => { |
| | | materialList.value.splice(index, 1); |
| | | }; |
| | | |
| | | const handleCancel = () => { |
| | | visible.value = false; |
| | | materialList.value = []; |
| | | hasDrawMaterials.value = false; |
| | | activeTab.value = 'material'; |
| | | }; |
| | | |
| | | const handleConfirm = async () => { |
| | |
| | | ElMessage.success('领料保存成功'); |
| | | visible.value = false; |
| | | materialList.value = []; |
| | | hasDrawMaterials.value = false; |
| | | activeTab.value = 'material'; |
| | | } catch (error) { |
| | | console.error('保存领料失败:', error); |
| | | ElMessage.error('保存领料失败'); |
| | |
| | | |
| | | <style scoped lang="scss"> |
| | | .material-requisition-form { |
| | | .operation-bar { |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .el-tabs { |
| | | height: 100%; |
| | | } |
| | | |
| | | .el-table { |
| | | margin-top: 10px; |
| | | } |
| | |
| | | padding: 15px 20px; |
| | | border-top: 1px solid #e4e7ed; |
| | | } |
| | | |
| | | :deep(.el-tabs__content) { |
| | | height: calc(100% - 55px); |
| | | } |
| | | |
| | | :deep(.el-tab-pane) { |
| | | height: 100%; |
| | | } |
| | | </style> |