From b937241a2c20f62f45b31b232b6cebdec03d41d7 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期二, 31 三月 2026 15:57:42 +0800
Subject: [PATCH] fix: 销售批号
---
src/views/productionManagement/productionOrder/MaterialRequisitionDialog.vue | 320 +++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 250 insertions(+), 70 deletions(-)
diff --git a/src/views/productionManagement/productionOrder/MaterialRequisitionDialog.vue b/src/views/productionManagement/productionOrder/MaterialRequisitionDialog.vue
index ab3bd63..497ea82 100644
--- a/src/views/productionManagement/productionOrder/MaterialRequisitionDialog.vue
+++ b/src/views/productionManagement/productionOrder/MaterialRequisitionDialog.vue
@@ -2,56 +2,49 @@
<el-dialog
v-model="visible"
title="棰嗘枡"
- width="1000px"
+ width="1400px"
top="3vh"
:close-on-click-modal="false"
destroy-on-close
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="customer" label="渚涘簲鍟�" min-width="160" show-overflow-tooltip />
+ <el-table-column prop="batchNo" label="鎵瑰彿" min-width="180" show-overflow-tooltip />
+ <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>
@@ -60,13 +53,82 @@
<el-button @click="handleCancel">鍙� 娑�</el-button>
</span>
</template>
+
+ <!-- 鏂板鍘熸潗鏂欏脊绐� -->
+ <el-dialog
+ v-model="addDialogVisible"
+ title="閫夋嫨鍘熸潗鏂�"
+ width="1000px"
+ top="5vh"
+ :close-on-click-modal="false"
+ append-to-body
+ >
+ <div class="material-filter" style="margin-bottom: 20px;">
+ <el-select
+ v-model="filterSupplier"
+ placeholder="渚涘簲鍟�"
+ clearable
+ filterable
+ style="width: 220px"
+ >
+ <el-option
+ v-for="opt in supplierFilterOptions"
+ :key="opt"
+ :label="opt"
+ :value="opt"
+ />
+ </el-select>
+ <el-select
+ v-model="filterBatchNo"
+ placeholder="鎵瑰彿"
+ clearable
+ filterable
+ style="width: 220px; margin-left: 12px"
+ >
+ <el-option
+ v-for="opt in batchFilterOptions"
+ :key="opt"
+ :label="opt"
+ :value="opt"
+ />
+ </el-select>
+ </div>
+ <el-table
+ :data="filteredMaterials"
+ 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="customer" label="渚涘簲鍟�" min-width="160" show-overflow-tooltip />
+ <el-table-column prop="batchNo" label="鎵瑰彿" min-width="180" show-overflow-tooltip />
+ <!-- <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: {
@@ -88,8 +150,52 @@
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([]);
+
+// 閫夋嫨寮圭獥绛涢�夋潯浠讹紙渚涘簲鍟�/鎵瑰彿锛�
+const filterSupplier = ref('');
+const filterBatchNo = ref('');
+
+// 灏嗗悗绔彲鑳借繑鍥炵殑瀛楁鍋氫竴涓嬪綊涓�鍖栵細渚涘簲鍟�/鎵瑰彿瀛楁鍚嶅彲鑳戒笉涓�鑷�
+const normalizeMaterial = (m) => {
+ return {
+ ...m,
+ customer: m.customer ?? m.supplierName ?? '',
+ batchNo: m.batchNo ?? m.batchNumber ?? m.batch_number ?? m.lotNo ?? '',
+ };
+};
+
+const supplierFilterOptions = computed(() => {
+ return Array.from(new Set(availableMaterials.value.map((m) => m.customer).filter(Boolean)));
+});
+
+const batchFilterOptions = computed(() => {
+ const list = filterSupplier.value
+ ? availableMaterials.value.filter((m) => m.customer === filterSupplier.value)
+ : availableMaterials.value;
+ return Array.from(new Set(list.map((m) => m.batchNo).filter(Boolean)));
+});
+
+const filteredMaterials = computed(() => {
+ return availableMaterials.value.filter((m) => {
+ if (filterSupplier.value && m.customer !== filterSupplier.value) return false;
+ if (filterBatchNo.value && m.batchNo !== filterBatchNo.value) return false;
+ return true;
+ });
+});
+
+watch(filterSupplier, () => {
+ // 濡傛灉褰撳墠鈥滄壒鍙封�濅笉灞炰簬鎵�閫変緵搴斿晢锛屽垯娓呯┖
+ if (filterBatchNo.value && !batchFilterOptions.value.includes(filterBatchNo.value)) {
+ filterBatchNo.value = '';
+ }
+});
// 鐩戝惉寮规鎵撳紑锛屽姞杞芥暟鎹�
watch(() => props.modelValue, (val) => {
@@ -101,26 +207,48 @@
const loadMaterialList = async () => {
const order = props.orderData;
const drawMaterialsData = order.drawMaterials;
+ const bomId = order?.bomId;
- // 濡傛灉宸叉湁棰嗘枡鏁版嵁锛岀洿鎺ヤ娇鐢�
+ // 鍏堣幏鍙杇etMaterials鐨勬渶鏂版暟鎹�
+ let materialsFromApi = [];
+ if (bomId) {
+ try {
+ const res = await getMaterials({ bomId });
+ materialsFromApi = (res.data || []).map(normalizeMaterial);
+ } 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;
+ // 鍚堝苟鏁版嵁锛氫娇鐢ˋPI鐨剄ualitity锛屼娇鐢ㄤ繚瀛樼殑requisitionQty鍜宺emark
+ 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,
+ customer: savedItem.customer ?? savedItem.supplierName ?? apiItem?.customer ?? '',
+ batchNo: savedItem.batchNo ?? savedItem.batchNumber ?? apiItem?.batchNo ?? '',
+ };
+ });
} catch (e) {
console.error('瑙f瀽棰嗘枡鏁版嵁澶辫触:', e);
+ materialList.value = [];
}
+ } else {
+ materialList.value = [];
}
+};
- // 娌℃湁棰嗘枡鏁版嵁锛岃皟鐢ㄦ帴鍙f煡璇�
- hasDrawMaterials.value = false;
+// 鎵撳紑鏂板寮圭獥
+const handleAdd = async () => {
+ const order = props.orderData;
const bomId = order?.bomId;
if (!bomId) {
ElMessage.warning('褰撳墠璁㈠崟缂哄皯BOM淇℃伅');
@@ -129,30 +257,65 @@
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 || []).map(normalizeMaterial);
+ filterSupplier.value = '';
+ filterBatchNo.value = '';
+ 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鍜宲roductModelId鍒ゆ柇锛�
+ 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 () => {
@@ -178,7 +341,8 @@
ElMessage.success('棰嗘枡淇濆瓨鎴愬姛');
visible.value = false;
materialList.value = [];
- hasDrawMaterials.value = false;
+ activeTab.value = 'material';
+ emit('confirm');
} catch (error) {
console.error('淇濆瓨棰嗘枡澶辫触:', error);
ElMessage.error('淇濆瓨棰嗘枡澶辫触');
@@ -190,6 +354,14 @@
<style scoped lang="scss">
.material-requisition-form {
+ .operation-bar {
+ margin-bottom: 15px;
+ }
+
+ .el-tabs {
+ height: 100%;
+ }
+
.el-table {
margin-top: 10px;
}
@@ -223,4 +395,12 @@
padding: 15px 20px;
border-top: 1px solid #e4e7ed;
}
+
+:deep(.el-tabs__content) {
+ height: calc(100% - 55px);
+}
+
+:deep(.el-tab-pane) {
+ height: 100%;
+}
</style>
--
Gitblit v1.9.3