| | |
| | | prop="specificationModel" /> |
| | | <el-table-column label="单位" |
| | | prop="unit" /> |
| | | <el-table-column label="件数" |
| | | prop="packagingSpec" /> |
| | | <el-table-column label="产品状态" |
| | | width="100px" |
| | | align="center"> |
| | |
| | | <el-tag :type="getShippingStatusType(scope.row)" |
| | | size="small"> |
| | | {{ getShippingStatusText(scope.row) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="发货类型" |
| | | width="100" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-tag v-if="getShippingTypeText(scope.row)" |
| | | :type="getShippingTypeTag(scope.row)" |
| | | size="small"> |
| | | {{ getShippingTypeText(scope.row) }} |
| | | </el-tag> |
| | | <el-tag v-else |
| | | type="info" |
| | | size="small">- |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | type="primary" |
| | | @click="openForm('view', scope.row)">详情 |
| | | </el-button> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openForm('edit', scope.row)" |
| | | :disabled="!scope.row.isEdit || scope.row.hasProductionRecord || !canEditLedger(scope.row)">编辑 |
| | | </el-button> |
| | | <el-tooltip :content="editDisabledReason(scope.row)" |
| | | :disabled="!editDisabledReason(scope.row)" |
| | | placement="top"> |
| | | <span> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openForm('edit', scope.row)" |
| | | :disabled="isLedgerEditDisabled(scope.row)">编辑 |
| | | </el-button> |
| | | </span> |
| | | </el-tooltip> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openFileDialog(scope.row)">附件 |
| | |
| | | prop="specificationModel" /> |
| | | <el-table-column label="单位" |
| | | prop="unit" /> |
| | | <el-table-column label="件数" |
| | | prop="packagingSpec" /> |
| | | <el-table-column label="数量" |
| | | prop="quantity" /> |
| | | <el-table-column label="税率(%)" |
| | |
| | | :label="dict.label" |
| | | :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="件数:" |
| | | prop="packagingSpec"> |
| | | <el-input v-model="productForm.packagingSpec" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | value="货车" /> |
| | | <el-option label="快递" |
| | | value="快递" /> |
| | | <el-option label="自送" |
| | | value="自送" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="已选择发货数量:"> |
| | | <el-input :model-value="selectedDeliveryQuantity" |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24" |
| | | v-if="deliveryForm.type === '货车'"> |
| | | <el-row :gutter="30" |
| | | v-if="deliveryForm.type === '货车'"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="发货车牌号:" |
| | | prop="shippingCarNumber"> |
| | | <el-input v-model="deliveryForm.shippingCarNumber" |
| | |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24" |
| | | v-else> |
| | | </el-row> |
| | | <el-row :gutter="30" |
| | | v-else-if="deliveryForm.type === '快递'"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="快递公司:" |
| | | prop="expressCompany"> |
| | | <el-input v-model="deliveryForm.expressCompany" |
| | |
| | | tableAmountFormatter, |
| | | formatDecimal, |
| | | buildAmountSummaryFormat, |
| | | roundAmount, |
| | | } from "@/utils/numberFormat"; |
| | | import ImageUpload from "@/components/AttachmentUpload/image/index.vue"; |
| | | import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue"; |
| | |
| | | productModelId: "", |
| | | specificationModel: "", |
| | | unit: "", |
| | | packagingSpec: "", |
| | | quantity: "", |
| | | taxInclusiveUnitPrice: "", |
| | | taxRate: "", |
| | |
| | | rawList.forEach(item => { |
| | | total += Number(getDeliveryBatchQuantity(item) || 0); |
| | | }); |
| | | currentStock.value = total; |
| | | currentStock.value = roundAmount(total); |
| | | } catch (e) { |
| | | console.error(e); |
| | | currentStock.value = 0; |
| | |
| | | const getCurrentDeliveryRowQuantity = () => { |
| | | return Number(currentDeliveryRow.value?.noQuantity || 0); |
| | | }; |
| | | const selectedDeliveryQuantity = computed(() => { |
| | | return roundAmount( |
| | | (deliveryForm.value.batchNoList || []).reduce( |
| | | (sum, item) => sum + Number(item?.deliveryQuantity || 0), |
| | | 0 |
| | | ) |
| | | ); |
| | | }); |
| | | const getDeliveryBatchDeliveryMax = row => { |
| | | const productQuantity = getCurrentDeliveryRowQuantity(); |
| | | const batchQuantity = Number(getDeliveryBatchQuantity(row) || 0); |
| | | const otherBatchTotal = (deliveryForm.value.batchNoList || []).reduce( |
| | | (sum, item) => { |
| | | if (item?.id === row?.id) return sum; |
| | | return sum + Number(item?.deliveryQuantity || 0); |
| | | }, |
| | | 0 |
| | | const otherBatchTotal = roundAmount( |
| | | (deliveryForm.value.batchNoList || []).reduce( |
| | | (sum, item) => { |
| | | if (item?.id === row?.id) return sum; |
| | | return sum + Number(item?.deliveryQuantity || 0); |
| | | }, |
| | | 0 |
| | | ) |
| | | ); |
| | | const remainingProductQuantity = Math.max( |
| | | 0, |
| | | productQuantity - otherBatchTotal |
| | | const remainingProductQuantity = roundAmount( |
| | | Math.max(0, productQuantity - otherBatchTotal) |
| | | ); |
| | | return Math.max(0, Math.min(batchQuantity, remainingProductQuantity)); |
| | | }; |
| | | const handleDeliveryBatchQuantityChange = row => { |
| | | const productQuantity = getCurrentDeliveryRowQuantity(); |
| | | const batchQuantity = Number(getDeliveryBatchQuantity(row) || 0); |
| | | const otherBatchTotal = (deliveryForm.value.batchNoList || []).reduce( |
| | | (sum, item) => { |
| | | if (item?.id === row?.id) return sum; |
| | | return sum + Number(item?.deliveryQuantity || 0); |
| | | }, |
| | | 0 |
| | | const otherBatchTotal = roundAmount( |
| | | (deliveryForm.value.batchNoList || []).reduce( |
| | | (sum, item) => { |
| | | if (item?.id === row?.id) return sum; |
| | | return sum + Number(item?.deliveryQuantity || 0); |
| | | }, |
| | | 0 |
| | | ) |
| | | ); |
| | | const remainingProductQuantity = Math.max( |
| | | 0, |
| | | productQuantity - otherBatchTotal |
| | | const remainingProductQuantity = roundAmount( |
| | | Math.max(0, productQuantity - otherBatchTotal) |
| | | ); |
| | | const currentValue = Number(row?.deliveryQuantity || 0); |
| | | |
| | |
| | | shippingCarNumber: "", |
| | | expressCompany: "", |
| | | expressNumber: "", |
| | | type: "货车", // 货车, 快递 |
| | | type: "货车", // 货车, 快递, 自送 |
| | | }, |
| | | deliveryRules: { |
| | | shippingCarNumber: [ |
| | |
| | | }; |
| | | const canEditLedger = row => isCurrentUserMaintainer(row); |
| | | const canDeleteLedger = row => isCurrentUserMaintainer(row); |
| | | /** |
| | | * 需要生产的订单:生产计划已下发(含部分下发)后不可编辑; |
| | | * 走库存的订单:已发货后不可编辑,否则可以编辑。 |
| | | */ |
| | | const editDisabledReason = row => { |
| | | if (!row) return ""; |
| | | if (!canEditLedger(row)) return "当前系统登录人不是维护人,不能编辑数据"; |
| | | if (row.hasProductionRecord) return "生产计划已下发,不能编辑"; |
| | | if (!row.isEdit) return "订单已发货,不能编辑"; |
| | | return ""; |
| | | }; |
| | | const isLedgerEditDisabled = row => !!editDisabledReason(row); |
| | | const sensitiveAmountFormatter = (row, column, cellValue) => { |
| | | if (!isCurrentUserMaintainer(row)) { |
| | | return "*****"; |
| | |
| | | }; |
| | | // 打开弹框 |
| | | const openForm = async (type, row) => { |
| | | if (type === "edit" && row && !canEditLedger(row)) { |
| | | proxy.$modal.msgWarning("当前系统登录人不是维护人,不能编辑数据"); |
| | | return; |
| | | if (type === "edit" && row) { |
| | | const disabledReason = editDisabledReason(row); |
| | | if (disabledReason) { |
| | | proxy.$modal.msgWarning(disabledReason); |
| | | return; |
| | | } |
| | | } |
| | | operationType.value = type; |
| | | form.value = {}; |
| | |
| | | }; |
| | | |
| | | /** |
| | | * 获取发货类型文本(货车/快递/自送) |
| | | * 子表行未返回发货类型字段,依据互斥的发货信息推断: |
| | | * 有车牌为货车,有快递公司/单号为快递,已发货但两者皆无为自送 |
| | | */ |
| | | const getShippingTypeText = row => { |
| | | if (!row) return ""; |
| | | if (row.shippingCarNumber) return "货车"; |
| | | if (row.expressCompany || row.expressNumber) return "快递"; |
| | | if (row.shippingDate) return "自送"; |
| | | return ""; |
| | | }; |
| | | |
| | | const getShippingTypeTag = row => { |
| | | const type = getShippingTypeText(row); |
| | | const typeTagMap = { |
| | | 货车: "warning", |
| | | 快递: "primary", |
| | | 自送: "success", |
| | | }; |
| | | return typeTagMap[type] || "info"; |
| | | }; |
| | | |
| | | /** |
| | | * 判断是否可以发货 |
| | | * 只有在产品状态是充足,发货状态是待发货和审核拒绝的时候才可以发货 |
| | | * @param row 行数据 |
| | | */ |
| | | const canShip = row => { |
| | | // 产品状态必须是充足(approveStatus === 1) |
| | | if (row.approveStatus !== 1) { |
| | | return false; |
| | | } |
| | | |
| | | // 获取发货状态 |
| | | const shippingStatus = row.shippingStatus; |
| | | |
| | |
| | | // 检查是否可以发货 |
| | | if (!canShip(row)) { |
| | | proxy.$modal.msgWarning( |
| | | "只有在产品状态是充足,发货状态是待发货或审核拒绝的时候才可以发货" |
| | | "只有在发货状态是待发货、审核拒绝或部分发货的时候才可以发货" |
| | | ); |
| | | return; |
| | | } |
| | |
| | | proxy.$modal.msgWarning("请至少填写一个批号的发货数量"); |
| | | return; |
| | | } |
| | | const totalDeliveryQuantity = selectedBatchRows.reduce( |
| | | (sum, item) => sum + Number(item.deliveryQuantity || 0), |
| | | 0 |
| | | const totalDeliveryQuantity = roundAmount( |
| | | selectedBatchRows.reduce( |
| | | (sum, item) => sum + Number(item.deliveryQuantity || 0), |
| | | 0 |
| | | ) |
| | | ); |
| | | const currentRowNoQuantity = Number( |
| | | currentDeliveryRow.value?.noQuantity || 0 |
| | |
| | | if (val === "货车") { |
| | | deliveryForm.value.expressCompany = ""; |
| | | deliveryForm.value.expressNumber = ""; |
| | | } else if (val === "快递") { |
| | | deliveryForm.value.shippingCarNumber = ""; |
| | | } else { |
| | | deliveryForm.value.shippingCarNumber = ""; |
| | | deliveryForm.value.expressCompany = ""; |
| | | deliveryForm.value.expressNumber = ""; |
| | | } |
| | | }; |
| | | |