| | |
| | | <el-form :model="searchForm" |
| | | :inline="true"> |
| | | <!-- 简化版搜索条件 --> |
| | | <el-form-item label="产品名称:"> |
| | | <el-input v-model="searchForm.productName" |
| | | <el-form-item label="主生产计划号:"> |
| | | <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="需求日期范围:"> |
| | | <el-date-picker v-model="searchForm.dateRange" |
| | | type="daterange" |
| | | range-separator="至" |
| | |
| | | </el-form-item> |
| | | <!-- 展开版搜索条件 --> |
| | | <template v-if="searchFormExpanded"> |
| | | <el-form-item label="客户名称:"> |
| | | <el-input v-model="searchForm.customerName" |
| | | <el-form-item label="产品名称:"> |
| | | <el-input v-model="searchForm.productName" |
| | | placeholder="请输入" |
| | | clearable |
| | | style="width: 160px;" |
| | |
| | | <el-button type="primary" |
| | | @click="handleAdd">新增</el-button> |
| | | <el-button type="warning" |
| | | @click="getLoadProdData" |
| | | :loading="loadProdDataLoading">拉取数据</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> |
| | |
| | | :selectable="isSelectable" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="pagination"> |
| | | <template #quantity="{ row }"> |
| | | {{ row.quantity || '-' }}<span style="color:rgb(63, 95, 211)"> 块</span> |
| | | </template> |
| | | <template #volume="{ row }"> |
| | | {{ row.volume || '-' }}<span style="color:rgba(12, 46, 40, 0.76)"> 方</span> |
| | | <template #qtyRequired="{ row }"> |
| | | {{ row.qtyRequired || '-' }}<span style="color:rgba(12, 46, 40, 0.76)"> {{ row.unit || '方' }}</span> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="10"> |
| | | <el-form-item label="长*宽*高"> |
| | | <div class="info-display">{{ mergeForm.length || '-' }}*{{ mergeForm.width || '-' }}*{{ mergeForm.height || '-' }}</div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-form-item label="计划完成时间"> |
| | |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="强度" |
| | | v-if="mergeForm.productName === '砌块'"> |
| | | <div v-if="strengthError" |
| | | class="strength-error" |
| | | style="color: red; margin-bottom: 8px;">{{ strengthError }}</div> |
| | | <el-select v-model="mergeForm.strength" |
| | | placeholder="请选择强度" |
| | | style="width: 100%" |
| | | required> |
| | | <el-option v-for="item in block_strength" |
| | | :key="item.id" |
| | | :label="item.label" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="生产方数"> |
| | | <el-input-number v-model="mergeForm.totalAssignedQuantity" |
| | | :min="0" |
| | |
| | | @change="onBlur" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | <!-- <el-form-item label="备注"> |
| | | <el-input v-model="mergeForm.remark" |
| | | type="textarea" /> |
| | | </el-form-item> --> |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | |
| | | :model="form" |
| | | :rules="rules" |
| | | label-width="120px"> |
| | | <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="请输入申请单编号" /> |
| | | </el-form-item> |
| | | <el-form-item label="客户名称" |
| | | prop="customerName"> |
| | | <el-input v-model="form.customerName" |
| | | placeholder="请输入客户名称" /> |
| | | </el-form-item> |
| | | <el-form-item label="产品名称" |
| | | prop="productMaterialId"> |
| | |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="产品规格" |
| | | prop="productMaterialSkuId"> |
| | | <el-select v-model="form.productMaterialSkuId" |
| | | prop="productModelId"> |
| | | <el-select v-model="form.productModelId" |
| | | @change="handleChangeSpecification" |
| | | filterable |
| | | style="width: 100%" |
| | | placeholder="请选择"> |
| | | <el-option v-for="item in specificationOptions" |
| | | :key="item.id" |
| | |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="块数" |
| | | prop="quantity"> |
| | | <el-input-number v-model="form.quantity" |
| | | <el-form-item label="所需数量" |
| | | prop="qtyRequired"> |
| | | <el-input-number v-model="form.qtyRequired" |
| | | :min="0" |
| | | placeholder="请输入块数" /> |
| | | style="width: 100%" |
| | | placeholder="请输入数量" /> |
| | | </el-form-item> |
| | | <el-form-item label="方数" |
| | | prop="volume"> |
| | | <el-input-number v-model="form.volume" |
| | | :min="0" |
| | | placeholder="请输入方数" /> |
| | | <el-form-item label="单位" |
| | | prop="unit"> |
| | | <el-input v-model="form.unit" |
| | | placeholder="请输入单位" /> |
| | | </el-form-item> |
| | | <el-form-item label="长" |
| | | prop="length"> |
| | | <el-input-number v-model="form.length" |
| | | :min="0" |
| | | placeholder="请输入长度" /> |
| | | </el-form-item> |
| | | <el-form-item label="宽" |
| | | prop="width"> |
| | | <el-input-number v-model="form.width" |
| | | :min="0" |
| | | placeholder="请输入宽度" /> |
| | | </el-form-item> |
| | | <el-form-item label="高" |
| | | prop="height"> |
| | | <el-input-number v-model="form.height" |
| | | :min="0" |
| | | placeholder="请输入高度" /> |
| | | </el-form-item> |
| | | <el-form-item label="计划开始日期" |
| | | prop="startDate"> |
| | | <el-date-picker v-model="form.startDate" |
| | | <el-form-item label="需求日期" |
| | | prop="requiredDate"> |
| | | <el-date-picker v-model="form.requiredDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | placeholder="请选择计划开始日期" /> |
| | | style="width: 100%" |
| | | placeholder="请选择需求日期" /> |
| | | </el-form-item> |
| | | <el-form-item label="计划结束日期" |
| | | prop="endDate"> |
| | | <el-date-picker v-model="form.endDate" |
| | | <el-form-item label="承诺日期" |
| | | prop="promisedDeliveryDate"> |
| | | <el-date-picker v-model="form.promisedDeliveryDate" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | placeholder="请选择计划结束日期" /> |
| | | style="width: 100%" |
| | | placeholder="请选择承诺日期" /> |
| | | </el-form-item> |
| | | <el-form-item label="强度" |
| | | prop="strength" |
| | | v-if="form.productName === '砌块'"> |
| | | <el-select v-model="form.strength" |
| | | placeholder="请选择强度" |
| | | style="width: 100%"> |
| | | <el-option v-for="item in block_strength" |
| | | :key="item.label" |
| | | :label="item.label" |
| | | :value="item.label" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="备注 1" |
| | | prop="remarkOne"> |
| | | <el-input v-model="form.remarkOne" |
| | | placeholder="请输入备注 1" /> |
| | | </el-form-item> |
| | | <el-form-item label="备注 2" |
| | | prop="remarkTwo"> |
| | | <el-input v-model="form.remarkTwo" |
| | | placeholder="请输入备注 2" /> |
| | | <el-form-item label="备注" |
| | | prop="remark"> |
| | | <el-input v-model="form.remark" |
| | | type="textarea" |
| | | placeholder="请输入备注" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, ref, reactive, getCurrentInstance, toRefs } from "vue"; |
| | | import { |
| | | reactive, |
| | | ref, |
| | | onMounted, |
| | | toRefs, |
| | | getCurrentInstance, |
| | | computed, |
| | | } from "vue"; |
| | | import { useRouter } from "vue-router"; |
| | | import dayjs from "dayjs"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { ArrowUp, ArrowDown } from "@element-plus/icons-vue"; |
| | | import dayjs from "dayjs"; |
| | | import ImportDialog from "@/components/Dialog/ImportDialog.vue"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import { useDict } from "@/utils/dict"; |
| | | import { useRouter } from "vue-router"; |
| | | import { |
| | | productionPlanListPage, |
| | | loadProdData, |
| | | exportProductionPlan, |
| | | productionPlanAdd, |
| | | productionPlanUpdate, |
| | | productionPlanDelete, |
| | | productionPlanCombine, |
| | | } from "@/api/productionPlan/productionPlan.js"; |
| | | |
| | | // Mock data and functions removed |
| | | import { productTreeList, modelListPage } from "@/api/basicData/product.js"; |
| | | import PIMTable from "./components/PIMTable.vue"; |
| | | // import { |
| | | // modelListPage, |
| | | // productTreeList, |
| | | // productTreeListQuery, |
| | | // } from "@/api/basicData/newProduct.js"; |
| | | import ImportDialog from "@/components/Dialog/ImportDialog.vue"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const router = useRouter(); |
| | | |
| | | const loadProdData = () => { |
| | | console.log("Mock loadProdData called"); |
| | | return Promise.resolve({ code: 200, msg: "同步成功" }); |
| | | }; |
| | | |
| | | const exportProductionPlan = () => { |
| | | console.log("Mock exportProductionPlan called"); |
| | | return Promise.resolve(); |
| | | }; |
| | | |
| | | const productionPlanCombine = payload => { |
| | | console.log("Mock productionPlanCombine called with:", payload); |
| | | return Promise.resolve({ code: 200, msg: "合并下发成功" }); |
| | | }; |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "数据来源", |
| | | width: "100px", |
| | | prop: "dataSourceType", |
| | | dataType: "tag", |
| | | formatType: params => { |
| | | const typeMap = { |
| | | 2: "warning", |
| | | 1: "primary", |
| | | }; |
| | | return typeMap[params] || "info"; |
| | | }, |
| | | formatData: cell => (cell == 1 ? "钉钉同步" : "手动新增"), |
| | | label: "主生产计划号", |
| | | prop: "mpsNo", |
| | | width: "150px", |
| | | }, |
| | | { |
| | | label: "申请单编号", |
| | |
| | | width: "150px", |
| | | }, |
| | | { |
| | | label: "客户名称", |
| | | prop: "customerName", |
| | | label: "物料编码", |
| | | prop: "materialCode", |
| | | width: "150px", |
| | | }, |
| | | { |
| | |
| | | width: "200px", |
| | | dataType: "tag", |
| | | formatType: params => { |
| | | // const typeMap = { |
| | | // 板材: "primary", |
| | | // 砌块: "warning", |
| | | // }; |
| | | // return typeMap[params] || "info"; |
| | | return "primary"; |
| | | }, |
| | | }, |
| | |
| | | className: "spec-cell", |
| | | }, |
| | | { |
| | | label: "物料编码", |
| | | prop: "materialCode", |
| | | width: "150px", |
| | | label: "单位", |
| | | prop: "unit", |
| | | width: "100px", |
| | | }, |
| | | { |
| | | label: "块数", |
| | | prop: "quantity", |
| | | align: "right", |
| | | dataType: "slot", |
| | | slot: "quantity", |
| | | }, |
| | | { |
| | | label: "方数", |
| | | prop: "volume", |
| | | label: "所需数量", |
| | | prop: "qtyRequired", |
| | | width: "150px", |
| | | align: "right", |
| | | dataType: "slot", |
| | | slot: "volume", |
| | | slot: "qtyRequired", |
| | | className: "volume-cell", |
| | | }, |
| | | { |
| | | label: "下发状态", |
| | | prop: "status", |
| | | width: "150px", |
| | | width: "120px", |
| | | className: "status-cell", |
| | | dataType: "tag", |
| | | formatType: params => { |
| | |
| | | }, |
| | | }, |
| | | { |
| | | label: "已下发方数", |
| | | label: "已下发数量", |
| | | prop: "assignedQuantity", |
| | | width: "150px", |
| | | width: "120px", |
| | | className: "spec-cell", |
| | | formatData: cell => (cell ? `${cell}方` : 0), |
| | | // formatData: (cell, row) => (cell ? `${cell}${row.unit || "方"}` : 0), |
| | | }, |
| | | { |
| | | label: "长", |
| | | prop: "length", |
| | | className: "dimension-cell", |
| | | formatData: cell => (cell ? `${cell}mm` : ""), |
| | | }, |
| | | { |
| | | label: "宽", |
| | | prop: "width", |
| | | className: "dimension-cell", |
| | | formatData: cell => (cell ? `${cell}mm` : ""), |
| | | }, |
| | | { |
| | | label: "高", |
| | | prop: "height", |
| | | className: "dimension-cell", |
| | | formatData: cell => (cell ? `${cell}mm` : ""), |
| | | }, |
| | | // { |
| | | // label: "流水号", |
| | | // prop: "serialNo", |
| | | // width: "150px", |
| | | // className: "code-cell", |
| | | // }, |
| | | { |
| | | label: "计划开始日期", |
| | | prop: "startDate", |
| | | width: "150px", |
| | | label: "需求日期", |
| | | prop: "requiredDate", |
| | | width: "160px", |
| | | className: "date-cell", |
| | | formatData: cell => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""), |
| | | }, |
| | | { |
| | | label: "计划结束日期", |
| | | prop: "endDate", |
| | | width: "150px", |
| | | label: "承诺日期", |
| | | prop: "promisedDeliveryDate", |
| | | width: "160px", |
| | | className: "date-cell", |
| | | formatData: cell => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""), |
| | | }, |
| | | { |
| | | label: "强度", |
| | | prop: "strength", |
| | | formatData: cell => { |
| | | if (!cell) return ""; |
| | | const strengthItem = block_strength.value.find(item => item.id === cell); |
| | | return strengthItem ? strengthItem.label : cell; |
| | | }, |
| | | }, |
| | | |
| | | { |
| | | label: "备注 1", |
| | | label: "备注", |
| | | width: "150px", |
| | | prop: "remarkOne", |
| | | prop: "remark", |
| | | }, |
| | | { |
| | | label: "备注 2", |
| | | width: "150px", |
| | | prop: "remarkTwo", |
| | | }, |
| | | |
| | | { |
| | | dataType: "action", |
| | | label: "操作", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 300, |
| | | width: 150, |
| | | operation: [ |
| | | { |
| | | name: "编辑", |
| | | type: "primary", |
| | | link: true, |
| | | showHide: row => { |
| | | return row.status == 0 && row.dataSourceType != 1; |
| | | //status,0:待下发,1:部分下发,2:已下发 |
| | | return row.status == 0; |
| | | }, |
| | | clickFun: row => { |
| | | handleEdit(row); |
| | |
| | | handleDelete(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "下发", |
| | | type: "text", |
| | | showHide: row => { |
| | | // 计算剩余方数 |
| | | const remainingVolume = |
| | | (row.volume || 0) - (row.assignedQuantity || 0); |
| | | // 如果剩余方数小于等于0,禁止选择 |
| | | return remainingVolume > 0; |
| | | }, |
| | | clickFun: row => { |
| | | // 单独下发操作 |
| | | // 设置表单数据 |
| | | strengthError.value = ""; |
| | | mergeForm.id = null; // Creation |
| | | mergeForm.ids = [row.id]; |
| | | mergeForm.materialCode = row.materialCode; |
| | | mergeForm.productName = row.productName || ""; |
| | | mergeForm.model = row.model || ""; |
| | | mergeForm.length = row.length || 0; |
| | | mergeForm.width = row.width || 0; |
| | | mergeForm.height = row.height || 0; |
| | | mergeForm.totalAssignedQuantity = |
| | | (Number(row.volume) - Number(row.assignedQuantity)).toFixed(4) || 0; |
| | | mergeForm.planCompleteTime = row.planCompleteTime || ""; |
| | | mergeForm.productMaterialId = row.productMaterialId || ""; |
| | | mergeForm.strength = row.strength || ""; |
| | | mergeForm.applyNo = row.applyNo || ""; |
| | | mergeForm.requiredDate = dayjs().format("YYYY-MM-DD HH:mm:ss"); |
| | | mergeForm.promisedDeliveryDate = dayjs().format( |
| | | "YYYY-MM-DD HH:mm:ss" |
| | | ); |
| | | sumAssignedQuantity.value = mergeForm.totalAssignedQuantity; |
| | | // 打开弹窗 |
| | | isShowNewModal.value = true; |
| | | }, |
| | | }, |
| | | // { |
| | | // name: "追踪进度", |
| | | // type: "text", |
| | | // clickFun: row => { |
| | | // handleTrackProgress(row); |
| | | // }, |
| | | // }, |
| | | ], |
| | | }, |
| | | ]); |
| | |
| | | const isShowNewModal = ref(false); |
| | | // 合并下发表单数据 |
| | | const mergeForm = reactive({ |
| | | id: null, |
| | | materialCode: "", |
| | | productName: "", |
| | | model: "", |
| | | unit: "", |
| | | ids: [], |
| | | totalAssignedQuantity: 0, |
| | | planCompleteTime: "", |
| | | productMaterialId: "", |
| | | strength: "", |
| | | mpsNo: "", |
| | | requiredDate: "", |
| | | remark: "", |
| | | productModelId: "", |
| | | qtyRequired: 0, |
| | | state: "", |
| | | issued: true, |
| | | source: "", |
| | | isAudit: "", |
| | | promisedDeliveryDate: "", |
| | | applyNo: "", |
| | | status: 1, |
| | | }); |
| | | |
| | | // 导入相关 |
| | |
| | | const productOptions = ref([]); |
| | | const specificationOptions = ref([]); |
| | | const formRef = ref(null); |
| | | // 获取强度字典 |
| | | const { block_strength } = useDict("block_strength"); |
| | | const form = reactive({ |
| | | id: undefined, |
| | | mpsNo: "", |
| | | applyNo: "", |
| | | customerName: "", |
| | | productMaterialId: undefined, |
| | | productMaterialSkuId: undefined, |
| | | productModelId: undefined, |
| | | productName: "", |
| | | model: "", |
| | | materialCode: "", |
| | | quantity: 0, |
| | | volume: 0, |
| | | length: 0, |
| | | width: 0, |
| | | height: 0, |
| | | startDate: "", |
| | | endDate: "", |
| | | status: "", |
| | | strength: "", |
| | | remarkOne: "", |
| | | remarkTwo: "", |
| | | qtyRequired: 0, |
| | | unit: "方", |
| | | requiredDate: "", |
| | | promisedDeliveryDate: "", |
| | | remark: "", |
| | | }); |
| | | const rules = reactive({ |
| | | mpsNo: [{ required: true, message: "请输入主生产计划号", trigger: "blur" }], |
| | | applyNo: [{ required: true, message: "请输入申请单编号", trigger: "blur" }], |
| | | customerName: [ |
| | | { required: true, message: "请输入客户名称", trigger: "blur" }, |
| | | ], |
| | | productMaterialSkuId: [ |
| | | { required: true, message: "请选择产品规格", trigger: "change" }, |
| | | ], |
| | | volume: [{ required: true, message: "请输入方数", trigger: "blur" }], |
| | | productMaterialId: [ |
| | | { required: true, message: "请选择产品", trigger: "change" }, |
| | | ], |
| | | strength: [ |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | if (form.productName === "砌块" && !value) { |
| | | callback(new Error("砌块产品的强度为必填项")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | trigger: ["blur", "change"], |
| | | required: false, |
| | | }, |
| | | productModelId: [ |
| | | { required: true, message: "请选择产品规格", trigger: "change" }, |
| | | ], |
| | | qtyRequired: [{ required: true, message: "请输入数量", trigger: "blur" }], |
| | | requiredDate: [ |
| | | { required: true, message: "请选择需求日期", trigger: "change" }, |
| | | ], |
| | | }); |
| | | |
| | |
| | | }; |
| | | |
| | | const fetchProductOptions = () => { |
| | | // return productTreeList({ type: 2 }).then(res => { |
| | | // productOptions.value = convertIdToValue(res.data); |
| | | // return res; |
| | | // }); |
| | | return productTreeList().then(res => { |
| | | productOptions.value = convertIdToValue(res || []); |
| | | }); |
| | | }; |
| | | |
| | | const convertIdToValue = data => { |
| | | return data.map(item => { |
| | | const newItem = { |
| | | value: `config_${item.configId}`, // 使用config_前缀确保唯一性 |
| | | label: item.configName, |
| | | disabled: item.materialList.length === 0, |
| | | value: item.id, |
| | | label: item.label, |
| | | }; |
| | | if (item.materialList && item.materialList.length > 0) { |
| | | newItem.children = item.materialList.map(material => ({ |
| | | value: material.id, // 使用material的id作为value |
| | | label: material.productName, // 使用materialName作为label |
| | | })); |
| | | if (item.children && item.children.length > 0) { |
| | | newItem.children = convertIdToValue(item.children); |
| | | } |
| | | |
| | | return newItem; |
| | | }); |
| | | }; |
| | | |
| | | const handleProductChange = value => { |
| | | form.productMaterialSkuId = undefined; |
| | | form.productModelId = undefined; |
| | | form.model = undefined; |
| | | form.materialCode = undefined; |
| | | // 查找选中的产品名称 |
| | | const findProductName = (options, value) => { |
| | | const findProductName = (options, val) => { |
| | | for (const option of options) { |
| | | if (option.value === value) { |
| | | if (option.value === val) { |
| | | return option.label; |
| | | } |
| | | if (option.children) { |
| | | const found = findProductName(option.children, value); |
| | | const found = findProductName(option.children, val); |
| | | if (found) { |
| | | return found; |
| | | } |
| | |
| | | return ""; |
| | | }; |
| | | form.productName = findProductName(productOptions.value, value); |
| | | // 触发强度字段验证 |
| | | if (formRef.value) { |
| | | formRef.value.validateField("strength"); |
| | | } |
| | | fetchSpecificationOptions(value); |
| | | }; |
| | | |
| | | const fetchSpecificationOptions = productId => { |
| | | specificationOptions.value = []; |
| | | if (productId) { |
| | | // modelListPage({ productId: productId, size: -1, current: -1 }).then(res => { |
| | | // specificationOptions.value = res.data.records; |
| | | // }); |
| | | modelListPage({ id: productId, size: 1000, current: 1 }).then(res => { |
| | | specificationOptions.value = res.records || []; |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | 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; |
| | | // 解析规格字符串获取长宽高 |
| | | const model = selectedModel.model; |
| | | if (model) { |
| | | const dimensions = model.match(/^(\d+)\*(\d+)\*(\d+)$/); |
| | | if (dimensions && dimensions.length === 4) { |
| | | form.length = parseInt(dimensions[1]); |
| | | form.width = parseInt(dimensions[2]); |
| | | form.height = parseInt(dimensions[3]); |
| | | } |
| | | } |
| | | form.model = selectedModel.model; |
| | | form.unit = selectedModel.unit || "方"; |
| | | } |
| | | }; |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | customerName: "", |
| | | mpsNo: "", |
| | | productName: "", |
| | | model: "", |
| | | materialCode: "", |
| | |
| | | /** 重置按钮操作 */ |
| | | const handleReset = () => { |
| | | Object.assign(searchForm.value, { |
| | | customerName: "", |
| | | mpsNo: "", |
| | | productName: "", |
| | | model: "", |
| | | materialCode: "", |
| | |
| | | }; |
| | | } |
| | | summary[category].totalAssignedQuantity += ( |
| | | Number(row.volume) - Number(row.assignedQuantity) |
| | | Number(row.qtyRequired) - Number(row.assignedQuantity) |
| | | ).toFixed(4); |
| | | }); |
| | | |
| | |
| | | tableLoading.value = true; |
| | | // 构造搜索参数 |
| | | const params = { ...searchForm.value, ...page }; |
| | | params.startDate = params.dateRange ? params.dateRange[0] : ""; |
| | | params.endDate = params.dateRange ? params.dateRange[1] : ""; |
| | | params.requiredDateStart = params.dateRange ? params.dateRange[0] : ""; |
| | | params.requiredDateEnd = params.dateRange ? params.dateRange[1] : ""; |
| | | delete params.dateRange; |
| | | productionPlanListPage(params) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | // 计算产品类别汇总统计 |
| | |
| | | |
| | | // 判断行是否可选择 |
| | | const isSelectable = row => { |
| | | // 计算剩余方数 |
| | | const remainingVolume = (row.volume || 0) - (row.assignedQuantity || 0); |
| | | // 如果剩余方数小于等于0,禁止选择 |
| | | if (remainingVolume <= 0) { |
| | | // 计算剩余数量 |
| | | const remainingQty = (row.qtyRequired || 0) - (row.assignedQuantity || 0); |
| | | // 如果剩余数量小于等于0,禁止选择 |
| | | if (remainingQty <= 0) { |
| | | return false; |
| | | } |
| | | // 如果没有选中的行,所有行都可选择 |
| | |
| | | }; |
| | | // 拉取数据按钮操作 |
| | | const loadProdDataLoading = ref(false); |
| | | const getLoadProdData = () => { |
| | | // 显示加载提示 |
| | | loadProdDataLoading.value = true; |
| | | proxy.$modal.loading("正在拉取数据,请稍候..."); |
| | | |
| | | loadProdData() |
| | | .then(res => { |
| | | proxy.$modal.closeLoading(); |
| | | getList(); |
| | | proxy.$modal.msgSuccess("数据拉取成功"); |
| | | }) |
| | | .catch(err => { |
| | | proxy.$modal.closeLoading(); |
| | | console.error("拉取失败:", err); |
| | | proxy.$modal.msgError("数据拉取失败,请重试"); |
| | | }) |
| | | .finally(() => { |
| | | loadProdDataLoading.value = false; |
| | | }); |
| | | }; |
| | | const sumAssignedQuantity = ref(0); |
| | | // 响应式数据 |
| | | const strengthError = ref(""); |
| | | |
| | | // 处理合并下发按钮点击 |
| | | const handleMerge = () => { |
| | |
| | | return; |
| | | } |
| | | console.log(selectedRows.value); |
| | | // 检查强度一致性 |
| | | const firstRow = selectedRows.value[0]; |
| | | const productName = firstRow.productName || ""; |
| | | let strengthConsistent = true; |
| | | let firstStrength = firstRow.strength || ""; |
| | | strengthError.value = ""; |
| | | |
| | | if (productName === "砌块") { |
| | | for (const row of selectedRows.value) { |
| | | if (row.strength !== firstStrength) { |
| | | strengthConsistent = false; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (!strengthConsistent) { |
| | | strengthError.value = "选择的砌块强度不一致,请重新选择"; |
| | | } |
| | | } |
| | | |
| | | // 计算总制造数量 |
| | | const totalAssignedQuantity = selectedRows.value.reduce((sum, row) => { |
| | | return ( |
| | | sum + |
| | | (row.volume == null |
| | | (row.qtyRequired == null |
| | | ? 0 |
| | | : Number(Number(row.volume) - Number(row.assignedQuantity).toFixed(4))) |
| | | : Number( |
| | | Number(row.qtyRequired) - Number(row.assignedQuantity).toFixed(4) |
| | | )) |
| | | ); |
| | | }, 0); |
| | | sumAssignedQuantity.value = totalAssignedQuantity; |
| | | console.log(totalAssignedQuantity); |
| | | // 设置表单数据 |
| | | mergeForm.id = null; // Creation |
| | | mergeForm.materialCode = selectedserialNo.value; |
| | | mergeForm.productName = productName; |
| | | mergeForm.model = firstRow.model || ""; |
| | | mergeForm.length = firstRow.length || 0; |
| | | mergeForm.width = firstRow.width || 0; |
| | | mergeForm.height = firstRow.height || 0; |
| | | mergeForm.totalAssignedQuantity = totalAssignedQuantity; |
| | | mergeForm.planCompleteTime = firstRow.planCompleteTime || ""; |
| | | mergeForm.productMaterialId = firstRow.productMaterialId || ""; |
| | | mergeForm.strength = firstStrength; |
| | | mergeForm.ids = selectedRows.value.map(row => row.id); |
| | | mergeForm.applyNo = firstRow.applyNo || ""; |
| | | mergeForm.requiredDate = dayjs().format("YYYY-MM-DD HH:mm:ss"); |
| | | mergeForm.promisedDeliveryDate = dayjs().format("YYYY-MM-DD HH:mm:ss"); |
| | | |
| | | // 打开弹窗 |
| | | isShowNewModal.value = true; |
| | |
| | | ElMessage.warning("请输入生产方数"); |
| | | return; |
| | | } |
| | | // 验证砌块产品的强度 |
| | | if (mergeForm.productName === "砌块" && !mergeForm.strength) { |
| | | ElMessage.error("砌块产品的强度为必填项"); |
| | | return; |
| | | } |
| | | if (mergeForm.productName != "砌块") { |
| | | mergeForm.strength = ""; |
| | | } |
| | | console.log(sumAssignedQuantity.value, "sumAssignedQuantity"); |
| | | // 计算当前选中行的总方数 |
| | | // 计算当前选中行的总数量 |
| | | const totalVolume = selectedRows.value.reduce((sum, row) => { |
| | | return sum + (Number(row.volume) - Number(row.assignedQuantity) || 0); |
| | | return sum + (Number(row.qtyRequired) - Number(row.assignedQuantity) || 0); |
| | | }, 0); |
| | | |
| | | // 验证totalAssignedQuantity不能大于总方数 |
| | |
| | | } |
| | | |
| | | console.log(mergeForm, "mergeForm"); |
| | | const strengthItem = block_strength.value.find( |
| | | item => item.id === mergeForm.strength |
| | | ); |
| | | const payload = { |
| | | ...mergeForm, |
| | | id: mergeForm.id || null, // Ensure id is present, null for creation |
| | | strength: strengthItem ? strengthItem.label : mergeForm.strength, |
| | | }; |
| | | productionPlanCombine(payload) |
| | | .then(res => { |
| | |
| | | const handleAdd = () => { |
| | | operationType.value = "add"; |
| | | Object.assign(form, { |
| | | id: undefined, |
| | | mpsNo: "", |
| | | applyNo: "", |
| | | customerName: "", |
| | | productName: "", |
| | | productMaterialId: undefined, |
| | | productMaterialSkuId: undefined, |
| | | productModelId: undefined, |
| | | model: "", |
| | | materialCode: "", |
| | | quantity: 0, |
| | | volume: 0, |
| | | length: 0, |
| | | width: 0, |
| | | height: 0, |
| | | startDate: "", |
| | | endDate: "", |
| | | strength: "", |
| | | remarkOne: "", |
| | | remarkTwo: "", |
| | | qtyRequired: 0, |
| | | unit: "方", |
| | | requiredDate: "", |
| | | promisedDeliveryDate: "", |
| | | remark: "", |
| | | }); |
| | | dialogVisible.value = true; |
| | | fetchProductOptions(); |
| | |
| | | operationType.value = "edit"; |
| | | Object.assign(form, { |
| | | id: row.id, |
| | | mpsNo: row.mpsNo || "", |
| | | applyNo: row.applyNo || "", |
| | | customerName: row.customerName || "", |
| | | productName: row.productName || "", |
| | | productMaterialId: row.productMaterialId || undefined, |
| | | productMaterialSkuId: row.productMaterialSkuId || undefined, |
| | | productModelId: row.productModelId || undefined, |
| | | model: row.model || "", |
| | | materialCode: row.materialCode || "", |
| | | quantity: row.quantity || 0, |
| | | volume: row.volume || 0, |
| | | length: row.length || 0, |
| | | width: row.width || 0, |
| | | height: row.height || 0, |
| | | startDate: row.startDate || "", |
| | | endDate: row.endDate || "", |
| | | strength: row.strength || "", |
| | | remarkOne: row.remarkOne || "", |
| | | remarkTwo: row.remarkTwo || "", |
| | | qtyRequired: row.qtyRequired || 0, |
| | | unit: row.unit || "方", |
| | | requiredDate: row.requiredDate || "", |
| | | promisedDeliveryDate: row.promisedDeliveryDate || "", |
| | | remark: row.remark || "", |
| | | }); |
| | | dialogVisible.value = true; |
| | | fetchProductOptions(); |
| | |
| | | const handleSubmit = () => { |
| | | formRef.value.validate(valid => { |
| | | if (valid) { |
| | | if (form.volume === 0) { |
| | | proxy.$modal.msgError("方数不能为0"); |
| | | if (form.qtyRequired === 0) { |
| | | proxy.$modal.msgError("数量不能为0"); |
| | | return; |
| | | } |
| | | const payload = { ...form }; |
| | | const isAdd = operationType.value === "add"; |
| | | if (isAdd) { |
| | | if (operationType.value === "add") { |
| | | payload.id = null; |
| | | productionPlanAdd(payload) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("新增成功"); |
| | | dialogVisible.value = false; |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("新增失败"); |
| | | }); |
| | | } |
| | | |
| | | const apiCall = isAdd ? productionPlanAdd : productionPlanUpdate; |
| | | |
| | | apiCall(payload) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess(isAdd ? "新增成功" : "修改成功"); |
| | | dialogVisible.value = false; |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError(isAdd ? "新增失败" : "修改失败"); |
| | | }); |
| | | if (operationType.value === "edit") { |
| | | productionPlanUpdate(payload) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("修改成功"); |
| | | dialogVisible.value = false; |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("修改失败"); |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | |
| | | } |
| | | |
| | | // 数值字段样式 |
| | | .quantity-cell, |
| | | .volume-cell, |
| | | .dimension-cell { |
| | | font-weight: 600; |