| | |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <el-form :model="searchForm" |
| | | ref="queryRef" |
| | | :inline="true"> |
| | | <!-- 简化版搜索条件 --> |
| | | <el-form-item label="主生产计划号:"> |
| | | <el-form-item label="主生产计划号:" |
| | | prop="mpsNo"> |
| | | <el-input v-model="searchForm.mpsNo" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="需求日期范围:"> |
| | | <el-form-item label="需求日期范围:" |
| | | prop="dateRange"> |
| | | <el-date-picker v-model="searchForm.dateRange" |
| | | type="daterange" |
| | | range-separator="至" |
| | |
| | | style="width: 240px;" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="下发状态:"> |
| | | <el-form-item label="下发状态:" |
| | | prop="status"> |
| | | <el-select v-model="searchForm.status" |
| | | placeholder="请选择状态" |
| | | clearable |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | <!-- 展开版搜索条件 --> |
| | | <template v-if="searchFormExpanded"> |
| | | <el-form-item label="产品名称:"> |
| | | <el-input v-model="searchForm.productName" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="产品规格:"> |
| | | <el-input v-model="searchForm.model" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="物料编码:"> |
| | | <el-input v-model="searchForm.materialCode" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="申请单编号:"> |
| | | <el-input v-model="searchForm.applyNo" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | </template> |
| | | <el-form-item label="产品名称:" |
| | | prop="productName"> |
| | | <el-input v-model="searchForm.productName" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="产品规格:" |
| | | prop="model"> |
| | | <el-input v-model="searchForm.model" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | | @keyup.enter="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="handleQuery">搜索</el-button> |
| | |
| | | <el-button type="primary" |
| | | @click="handleAdd">新增</el-button> |
| | | <el-button type="warning" |
| | | @click="handleMerge">合并下发</el-button> |
| | | <el-button type="warning" |
| | | @click="handleImport">导入</el-button> |
| | | <el-button type="warning" |
| | | @click="handleExport">导出</el-button> |
| | |
| | | </el-form> |
| | | <div> |
| | | </div> |
| | | </div> |
| | | <div class="search-header"> |
| | | <el-button type="text" |
| | | @click="toggleSearchForm"> |
| | | <el-icon> |
| | | <ArrowUp v-if="searchFormExpanded" /> |
| | | <ArrowDown v-else /> |
| | | </el-icon> |
| | | {{ searchFormExpanded ? '收起搜索条件' : '展开搜索条件' }} |
| | | </el-button> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable rowKey="id" |
| | |
| | | label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="10"> |
| | | <el-form-item label="物料编码"> |
| | | <div class="info-display">{{ mergeForm.materialCode || '-' }}</div> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="10"> |
| | | <el-form-item label="产品名称"> |
| | | <el-tag class="info-display">{{ mergeForm.productName || '-' }}</el-tag> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="10"> |
| | | <el-col> |
| | | <el-form-item label="产品规格"> |
| | | <div class="info-display">{{ mergeForm.model || '-' }}</div> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="10"> |
| | | </el-col> |
| | | </el-row> |
| | | <el-form-item label="计划完成时间"> |
| | |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="生产方数"> |
| | | <el-form-item label="生产数量"> |
| | | <el-input-number v-model="mergeForm.totalAssignedQuantity" |
| | | :min="0" |
| | | :max="sumAssignedQuantity" |
| | |
| | | <el-form-item label="主生产计划号" |
| | | prop="mpsNo"> |
| | | <el-input v-model="form.mpsNo" |
| | | placeholder="请输入主生产计划号" /> |
| | | </el-form-item> |
| | | <el-form-item label="申请单编号" |
| | | prop="applyNo"> |
| | | <el-input v-model="form.applyNo" |
| | | placeholder="请输入申请单编号" /> |
| | | disabled |
| | | placeholder="新增后自动生成" /> |
| | | </el-form-item> |
| | | <el-form-item label="产品名称" |
| | | prop="productMaterialId"> |
| | | <el-tree-select v-model="form.productMaterialId" |
| | | prop="productId"> |
| | | <el-tree-select v-model="form.productId" |
| | | placeholder="请选择" |
| | | clearable |
| | | :data="productOptions" |
| | |
| | | productionPlanAdd, |
| | | productionPlanUpdate, |
| | | productionPlanDelete, |
| | | productionPlanCombine, |
| | | } from "@/api/productionPlan/productionPlan.js"; |
| | | import { productTreeList, modelListPage } from "@/api/basicData/product.js"; |
| | | import PIMTable from "./components/PIMTable.vue"; |
| | |
| | | return Promise.resolve(); |
| | | }; |
| | | |
| | | const productionPlanCombine = payload => { |
| | | console.log("Mock productionPlanCombine called with:", payload); |
| | | return Promise.resolve({ code: 200, msg: "合并下发成功" }); |
| | | }; |
| | | // const productionPlanCombine = payload => { |
| | | // console.log("Mock productionPlanCombine called with:", payload); |
| | | // return Promise.resolve({ code: 200, msg: "合并下发成功" }); |
| | | // }; |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | |
| | | width: "150px", |
| | | }, |
| | | { |
| | | label: "申请单编号", |
| | | prop: "applyNo", |
| | | label: "来源", |
| | | prop: "source", |
| | | width: "150px", |
| | | }, |
| | | { |
| | | label: "物料编码", |
| | | prop: "materialCode", |
| | | width: "150px", |
| | | dataType: "tag", |
| | | formatType: params => { |
| | | return params == "内部" ? "info" : "primary"; |
| | | }, |
| | | }, |
| | | { |
| | | label: "产品名称", |
| | |
| | | label: "操作", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 150, |
| | | width: 250, |
| | | operation: [ |
| | | { |
| | | name: "编辑", |
| | |
| | | }, |
| | | clickFun: row => { |
| | | handleEdit(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "下发", |
| | | type: "text", |
| | | showHide: row => { |
| | | return row.status == 0; |
| | | }, |
| | | clickFun: row => { |
| | | mergeForm.productName = row.productName || ""; |
| | | mergeForm.model = row.model || ""; |
| | | mergeForm.totalAssignedQuantity = Number(row.qtyRequired || 0); |
| | | mergeForm.planCompleteTime = row.requiredDate || ""; |
| | | mergeForm.productId = row.productId || ""; |
| | | mergeForm.ids = [row.id]; |
| | | sumAssignedQuantity.value = Number(row.qtyRequired || 0); |
| | | isShowNewModal.value = true; |
| | | }, |
| | | }, |
| | | { |
| | |
| | | const isShowNewModal = ref(false); |
| | | // 合并下发表单数据 |
| | | const mergeForm = reactive({ |
| | | materialCode: "", |
| | | productName: "", |
| | | model: "", |
| | | totalAssignedQuantity: 0, |
| | | planCompleteTime: "", |
| | | productMaterialId: "", |
| | | productId: "", |
| | | }); |
| | | |
| | | // 导入相关 |
| | |
| | | const operationType = ref("add"); // add | edit |
| | | const productOptions = ref([]); |
| | | const specificationOptions = ref([]); |
| | | const queryRef = ref(null); |
| | | const formRef = ref(null); |
| | | const form = reactive({ |
| | | id: undefined, |
| | | mpsNo: "", |
| | | applyNo: "", |
| | | productMaterialId: undefined, |
| | | productId: undefined, |
| | | productModelId: undefined, |
| | | productName: "", |
| | | model: "", |
| | | materialCode: "", |
| | | qtyRequired: 0, |
| | | unit: "方", |
| | | requiredDate: "", |
| | |
| | | remark: "", |
| | | }); |
| | | const rules = reactive({ |
| | | mpsNo: [{ required: true, message: "请输入主生产计划号", trigger: "blur" }], |
| | | applyNo: [{ required: true, message: "请输入申请单编号", trigger: "blur" }], |
| | | productMaterialId: [ |
| | | { required: true, message: "请选择产品", trigger: "change" }, |
| | | ], |
| | | productId: [{ required: true, message: "请选择产品", trigger: "change" }], |
| | | productModelId: [ |
| | | { required: true, message: "请选择产品规格", trigger: "change" }, |
| | | ], |
| | |
| | | path: "/productionPlan/trackProgress", |
| | | query: { |
| | | id: row.id, |
| | | applyNo: row.applyNo, |
| | | productName: row.productName, |
| | | model: row.model, |
| | | }, |
| | |
| | | const handleProductChange = value => { |
| | | form.productModelId = undefined; |
| | | form.model = undefined; |
| | | form.materialCode = undefined; |
| | | // 查找选中的产品名称 |
| | | const findProductName = (options, val) => { |
| | | for (const option of options) { |
| | |
| | | }; |
| | | |
| | | const handleChangeSpecification = value => { |
| | | form.materialCode = undefined; |
| | | form.model = undefined; |
| | | form.unit = ""; |
| | | const selectedModel = specificationOptions.value.find( |
| | | item => item.id === value |
| | | ); |
| | | if (selectedModel) { |
| | | form.materialCode = selectedModel.materialCode; |
| | | form.model = selectedModel.model; |
| | | form.unit = selectedModel.unit || "方"; |
| | | } |
| | |
| | | mpsNo: "", |
| | | productName: "", |
| | | model: "", |
| | | materialCode: "", |
| | | applyNo: "", |
| | | status: "", |
| | | dateRange: [], |
| | | }, |
| | | searchFormExpanded: false, |
| | |
| | | |
| | | /** 重置按钮操作 */ |
| | | const handleReset = () => { |
| | | if (proxy.resetForm) { |
| | | proxy.resetForm("queryRef"); |
| | | } |
| | | Object.assign(searchForm.value, { |
| | | mpsNo: "", |
| | | productName: "", |
| | | model: "", |
| | | materialCode: "", |
| | | applyNo: "", |
| | | status: "", |
| | | dateRange: [], |
| | | }); |
| | | page.current = 1; |
| | |
| | | |
| | | // 遍历表格数据,按产品类别汇总 |
| | | tableData.value.forEach(row => { |
| | | const category = row.materialCode; |
| | | const category = row.productName || "未知产品"; |
| | | if (!summary[category]) { |
| | | summary[category] = { |
| | | materialCode: category, |
| | | totalAssignedQuantity: 0, |
| | | }; |
| | | } |
| | | summary[category].totalAssignedQuantity += ( |
| | | Number(row.qtyRequired) - Number(row.assignedQuantity) |
| | | ).toFixed(4); |
| | | summary[category].totalAssignedQuantity += Number( |
| | | ( |
| | | Number(row.qtyRequired || 0) - Number(row.assignedQuantity || 0) |
| | | ).toFixed(4) |
| | | ); |
| | | }); |
| | | |
| | | // 转换为数组格式 |
| | |
| | | tableLoading.value = true; |
| | | // 构造搜索参数 |
| | | const params = { ...searchForm.value, ...page }; |
| | | params.requiredDateStart = params.dateRange ? params.dateRange[0] : ""; |
| | | params.requiredDateEnd = params.dateRange ? params.dateRange[1] : ""; |
| | | params.requiredDateStart = |
| | | params.dateRange && params.dateRange.length > 0 ? params.dateRange[0] : ""; |
| | | params.requiredDateEnd = |
| | | params.dateRange && params.dateRange.length > 1 ? params.dateRange[1] : ""; |
| | | delete params.dateRange; |
| | | productionPlanListPage(params) |
| | | .then(res => { |
| | |
| | | }); |
| | | }; |
| | | |
| | | // 选中的序列号 |
| | | const selectedserialNo = ref(""); |
| | | // 选中的产品规格ID |
| | | const selectedProductModelId = ref(""); |
| | | |
| | | // 表格选择数据 |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | // 如果有选中的行,记录第一个选中行的序列号 |
| | | // 如果有选中的行,记录第一个选中行的产品规格ID |
| | | if (selection.length > 0) { |
| | | selectedserialNo.value = selection[0].materialCode; |
| | | selectedProductModelId.value = selection[0].productModelId; |
| | | } else { |
| | | // 如果没有选中的行,清空序列号 |
| | | selectedserialNo.value = ""; |
| | | // 如果没有选中的行,清空产品规格ID |
| | | selectedProductModelId.value = ""; |
| | | } |
| | | }; |
| | | |
| | |
| | | return false; |
| | | } |
| | | // 如果没有选中的行,所有行都可选择 |
| | | if (!selectedserialNo.value) { |
| | | if (!selectedProductModelId.value) { |
| | | return true; |
| | | } |
| | | // 如果有选中的行,只有序列号相同的行才可选择 |
| | | return row.materialCode === selectedserialNo.value; |
| | | // 如果有选中的行,只有产品规格ID相同的行才可选择 |
| | | return row.productModelId === selectedProductModelId.value; |
| | | }; |
| | | // 拉取数据按钮操作 |
| | | const loadProdDataLoading = ref(false); |
| | |
| | | const firstRow = selectedRows.value[0]; |
| | | const productName = firstRow.productName || ""; |
| | | |
| | | // 计算总制造数量 |
| | | // 计算总制造数量 (默认qtyRequired的和) |
| | | const totalAssignedQuantity = selectedRows.value.reduce((sum, row) => { |
| | | return ( |
| | | sum + |
| | | (row.qtyRequired == null |
| | | ? 0 |
| | | : Number( |
| | | Number(row.qtyRequired) - Number(row.assignedQuantity).toFixed(4) |
| | | )) |
| | | ); |
| | | return sum + Number(row.qtyRequired || 0); |
| | | }, 0); |
| | | sumAssignedQuantity.value = totalAssignedQuantity; |
| | | console.log(totalAssignedQuantity); |
| | | // 设置表单数据 |
| | | mergeForm.materialCode = selectedserialNo.value; |
| | | mergeForm.productName = productName; |
| | | mergeForm.model = firstRow.model || ""; |
| | | mergeForm.totalAssignedQuantity = totalAssignedQuantity; |
| | | mergeForm.planCompleteTime = firstRow.planCompleteTime || ""; |
| | | mergeForm.productMaterialId = firstRow.productMaterialId || ""; |
| | | mergeForm.planCompleteTime = firstRow.requiredDate || ""; |
| | | mergeForm.productId = firstRow.productId || ""; |
| | | mergeForm.ids = selectedRows.value.map(row => row.id); |
| | | |
| | | // 打开弹窗 |
| | |
| | | // 处理合并下发提交 |
| | | const handleMergeSubmit = () => { |
| | | if (mergeForm.totalAssignedQuantity === 0) { |
| | | ElMessage.warning("请输入生产方数"); |
| | | ElMessage.warning("请输入生产数量"); |
| | | return; |
| | | } |
| | | console.log(sumAssignedQuantity.value, "sumAssignedQuantity"); |
| | | // 计算当前选中行的总数量 |
| | | const totalVolume = selectedRows.value.reduce((sum, row) => { |
| | | return sum + (Number(row.qtyRequired) - Number(row.assignedQuantity) || 0); |
| | | }, 0); |
| | | |
| | | // 验证totalAssignedQuantity不能大于总方数 |
| | | if (mergeForm.totalAssignedQuantity > sumAssignedQuantity.value) { |
| | | ElMessage.error("生产方数不能大于当前计算的总值"); |
| | | ElMessage.error("生产数量不能大于当前计算的总值"); |
| | | return; |
| | | } |
| | | |
| | |
| | | Object.assign(form, { |
| | | id: undefined, |
| | | mpsNo: "", |
| | | applyNo: "", |
| | | productName: "", |
| | | productMaterialId: undefined, |
| | | productId: undefined, |
| | | productModelId: undefined, |
| | | model: "", |
| | | materialCode: "", |
| | | qtyRequired: 0, |
| | | unit: "方", |
| | | requiredDate: "", |
| | |
| | | Object.assign(form, { |
| | | id: row.id, |
| | | mpsNo: row.mpsNo || "", |
| | | applyNo: row.applyNo || "", |
| | | productName: row.productName || "", |
| | | productMaterialId: row.productMaterialId || undefined, |
| | | productId: row.productId || undefined, |
| | | productModelId: row.productModelId || undefined, |
| | | model: row.model || "", |
| | | materialCode: row.materialCode || "", |
| | | qtyRequired: row.qtyRequired || 0, |
| | | unit: row.unit || "方", |
| | | requiredDate: row.requiredDate || "", |
| | |
| | | }); |
| | | dialogVisible.value = true; |
| | | fetchProductOptions(); |
| | | fetchSpecificationOptions(row.productMaterialId); |
| | | fetchSpecificationOptions(row.productId); |
| | | }; |
| | | |
| | | // 删除 |
| | |
| | | color: #303133; |
| | | font-size: 14px; |
| | | min-height: 32px; |
| | | width: 100%; |
| | | display: flex; |
| | | align-items: center; |
| | | } |