| | |
| | | :bound-route-name="processFlowSelectBoundRouteName" |
| | | @confirm="handleProcessFlowSelectConfirm" |
| | | /> |
| | | <div> |
| | | <el-button type="primary" @click="openForm('add')"> |
| | | 新增台账 |
| | | </el-button> |
| | | <el-button type="primary" @click="handleBulkDelivery"> |
| | | 发货 |
| | | </el-button> |
| | | <el-button type="primary" plain @click="handleImport">导入</el-button> |
| | | <el-button @click="handleOut">导出</el-button> |
| | | <el-button type="danger" plain @click="handleDelete">删除</el-button> |
| | | <el-dropdown @command="handlePrintCommand"> |
| | | <el-button type="primary" plain> |
| | | 打印单据<el-icon class="el-icon--right"><ArrowDown /></el-icon> |
| | | </el-button> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item command="finishedProcessCard">打印生产流程卡(成品)</el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | </div> |
| | | <el-space wrap> |
| | | <el-button type="primary" @click="openForm('add')">新增台账</el-button> |
| | | <el-button type="primary" @click="handleBulkDelivery">发货</el-button> |
| | | <el-button type="primary" plain @click="handleImport">导入</el-button> |
| | | <el-button @click="handleOut">导出</el-button> |
| | | |
| | | <el-button type="danger" plain @click="handleDelete">删除</el-button> |
| | | |
| | | <el-dropdown @command="handlePrintCommand"> |
| | | <el-button type="primary" plain> |
| | | 打印单据<el-icon class="el-icon--right"> |
| | | <ArrowDown /> |
| | | </el-icon> |
| | | </el-button> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item command="finishedProcessCard">生产流程卡(成品)</el-dropdown-item> |
| | | <el-dropdown-item command="salesOrder">销售订单</el-dropdown-item> |
| | | <el-dropdown-item command="salesDeliveryNote">销售发货单</el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | <el-button type="primary" plain @click="handlePrintLabel">打印标签</el-button> |
| | | </el-space> |
| | | </div> |
| | | <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange" |
| | | :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" :row-class-name="tableRowClassName" show-summary style="width: 100%" |
| | |
| | | <template #default="props"> |
| | | <el-table :data="props.row.children" border show-summary :summary-method="summarizeChildrenTable"> |
| | | <el-table-column align="center" label="序号" type="index"/> |
| | | <el-table-column label="楼层编号" prop="floorCode" min-width="100" show-overflow-tooltip /> |
| | | <el-table-column label="产品大类" prop="productCategory" /> |
| | | <el-table-column label="规格型号" prop="specificationModel" /> |
| | | <el-table-column label="厚度" prop="thickness" min-width="90"> |
| | | <template #default="scope"> |
| | | {{ scope.row.thickness ?? "" }} |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> |
| | | <el-table-column label="宽(mm)" prop="width" min-width="80"> |
| | | <template #default="scope"> |
| | | {{ scope.row.width ?? "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="高(mm)" prop="height" min-width="80"> |
| | | <template #default="scope"> |
| | | {{ scope.row.height ?? "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="周长(cm)" prop="perimeter" min-width="90"> |
| | | <template #default="scope"> |
| | | {{ scope.row.perimeter ?? "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="总面积(cm²)" prop="actualTotalArea" min-width="100"> |
| | | <template #default="scope"> |
| | | {{ scope.row.actualTotalArea ?? "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="加工要求" prop="processRequirement" min-width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="备注" prop="remark" min-width="120" show-overflow-tooltip /> |
| | | <el-table-column label="重箱" prop="heavyBox" min-width="80"> |
| | | <template #default="scope"> |
| | | {{ scope.row.heavyBox ?? "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="产品状态" |
| | | width="100px" |
| | | align="center"> |
| | |
| | | <el-table-column label="厚度" prop="thickness" min-width="90"> |
| | | <template #default="scope"> |
| | | {{ scope.row.thickness ?? "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="宽(mm)" prop="width" min-width="80"> |
| | | <template #default="scope"> |
| | | {{ scope.row.width ?? "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="高(mm)" prop="height" min-width="80"> |
| | | <template #default="scope"> |
| | | {{ scope.row.height ?? "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="面积(m²)" prop="actualTotalArea" min-width="100"> |
| | | <template #default="scope"> |
| | | {{ scope.row.actualTotalArea ?? "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="数量" prop="quantity" /> |
| | |
| | | style="width: 100%" |
| | | placeholder="请输入" |
| | | clearable |
| | | @change="recalcAreaTotals" |
| | | @change="() => { recalcAreaTotals(); calculateFromUnitPrice(true); }" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | saleProcessBind, |
| | | getSaleProcessBindInfo, |
| | | getProcessCard, |
| | | getSalesOrder, |
| | | getSalesInvoices, |
| | | getSalesLabel, |
| | | } from "@/api/salesManagement/salesLedger.js"; |
| | | import { modelList, productTreeList } from "@/api/basicData/product.js"; |
| | | import useFormData from "@/hooks/useFormData.js"; |
| | | import dayjs from "dayjs"; |
| | | import { getCurrentDate } from "@/utils/index.js"; |
| | | import { printFinishedProcessCard } from "./components/processCardPrint.js"; |
| | | import { printSalesOrder } from "./components/salesOrderPrint.js"; |
| | | import { printSalesDeliveryNote } from "./components/salesDeliveryPrint.js"; |
| | | import { printSalesLabel } from "./components/salesLabelPrint.js"; |
| | | // import { salesLedgerProductSetProcessFlowConfig } from "@/api/salesManagement/salesProcessFlowConfig.js"; |
| | | |
| | | const userStore = useUserStore(); |
| | |
| | | productData.value = products.map((p) => { |
| | | const quantity = Number(p.quantity ?? 0) || 0; |
| | | const unitPrice = Number(p.unitPrice ?? 0) || 0; |
| | | const settlePieceArea = Number(p.settlePieceArea ?? 0) || 1; |
| | | const taxRate = "13"; // 默认 13%,便于直接提交(如需可在产品中自行修改) |
| | | const taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2); |
| | | const taxInclusiveTotalPrice = (unitPrice * settlePieceArea * quantity).toFixed(2); |
| | | const taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(taxInclusiveTotalPrice, taxRate); |
| | | return { |
| | | // 台账字段 |
| | |
| | | }; |
| | | |
| | | const handlePrintCommand = async (command) => { |
| | | if (command !== "finishedProcessCard") return; |
| | | if (selectedRows.value.length !== 1) { |
| | | if (command !== "finishedProcessCard" && command !== "salesOrder" && command !== "salesDeliveryNote") return; |
| | | if (command === "salesDeliveryNote") { |
| | | if (selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("请至少选择一条销售台账数据进行打印"); |
| | | return; |
| | | } |
| | | const customerNames = Array.from( |
| | | new Set(selectedRows.value.map((item) => String(item?.customerName ?? "").trim())) |
| | | ); |
| | | if (customerNames.length > 1) { |
| | | proxy.$modal.msgWarning("仅支持相同客户名称的销售台账合并发货打印"); |
| | | return; |
| | | } |
| | | } else if (selectedRows.value.length !== 1) { |
| | | proxy.$modal.msgWarning("请选择一条销售台账数据进行打印"); |
| | | return; |
| | | } |
| | | |
| | | const selectedRow = selectedRows.value[0]; |
| | | const selectedId = selectedRow?.id; |
| | | if (command === "salesDeliveryNote") { |
| | | const selectedIds = selectedRows.value |
| | | .map((item) => item?.id) |
| | | .filter((id) => id !== null && id !== undefined && id !== ""); |
| | | if (selectedIds.length !== selectedRows.value.length) { |
| | | proxy.$modal.msgWarning("当前选择数据存在缺少ID的记录,无法打印"); |
| | | return; |
| | | } |
| | | const loadingText = |
| | | command === "salesOrder" |
| | | ? "正在获取销售订单数据,请稍候..." |
| | | : command === "salesDeliveryNote" |
| | | ? "正在获取销售发货单数据,请稍候..." |
| | | : "正在获取生产流程卡数据,请稍候..."; |
| | | proxy.$modal.loading(loadingText); |
| | | try { |
| | | const res = await getSalesInvoices(selectedIds); |
| | | const salesInvoiceData = res?.data ?? {}; |
| | | printSalesDeliveryNote(salesInvoiceData, selectedRow); |
| | | } catch (error) { |
| | | console.error("打印销售发货单失败:", error); |
| | | proxy.$modal.msgError("打印失败,请稍后重试"); |
| | | } finally { |
| | | proxy.$modal.closeLoading(); |
| | | } |
| | | return; |
| | | } |
| | | if (!selectedId) { |
| | | proxy.$modal.msgWarning("当前选择数据缺少ID,无法打印"); |
| | | return; |
| | | } |
| | | |
| | | proxy.$modal.loading("正在获取生产流程卡数据,请稍候..."); |
| | | const loadingText = |
| | | command === "salesOrder" |
| | | ? "正在获取销售订单数据,请稍候..." |
| | | : command === "salesDeliveryNote" |
| | | ? "正在获取销售发货单数据,请稍候..." |
| | | : "正在获取生产流程卡数据,请稍候..."; |
| | | proxy.$modal.loading(loadingText); |
| | | try { |
| | | const res = await getProcessCard(selectedId); |
| | | const processCardData = res?.data ?? {}; |
| | | printFinishedProcessCard(processCardData); |
| | | if (command === "salesOrder") { |
| | | const res = await getSalesOrder(selectedId); |
| | | const salesOrderData = res?.data ?? {}; |
| | | printSalesOrder(salesOrderData); |
| | | } else { |
| | | const res = await getProcessCard(selectedId); |
| | | const processCardData = res?.data ?? {}; |
| | | printFinishedProcessCard(processCardData); |
| | | } |
| | | } catch (error) { |
| | | console.error("打印生产流程卡失败:", error); |
| | | console.error( |
| | | command === "salesOrder" |
| | | ? "打印销售订单失败:" |
| | | : command === "salesDeliveryNote" |
| | | ? "打印销售发货单失败:" |
| | | : "打印生产流程卡失败:", |
| | | error |
| | | ); |
| | | proxy.$modal.msgError("打印失败,请稍后重试"); |
| | | } finally { |
| | | proxy.$modal.closeLoading(); |
| | | } |
| | | }; |
| | | |
| | | const handlePrintLabel = async () => { |
| | | if (selectedRows.value.length !== 1) { |
| | | proxy.$modal.msgWarning("请选择一条销售台账数据进行标签打印"); |
| | | return; |
| | | } |
| | | |
| | | const selectedId = selectedRows.value[0]?.id; |
| | | if (!selectedId) { |
| | | proxy.$modal.msgWarning("当前选择数据缺少ID,无法打印标签"); |
| | | return; |
| | | } |
| | | |
| | | proxy.$modal.loading("正在获取标签数据,请稍候..."); |
| | | try { |
| | | const res = await getSalesLabel(selectedId); |
| | | const labelList = res?.data ?? []; |
| | | if (!Array.isArray(labelList) || labelList.length === 0) { |
| | | proxy.$modal.msgWarning("暂无可打印标签数据"); |
| | | return; |
| | | } |
| | | printSalesLabel(labelList); |
| | | } catch (error) { |
| | | console.error("打印标签失败:", error); |
| | | proxy.$modal.msgError("打印标签失败,请稍后重试"); |
| | | } finally { |
| | | proxy.$modal.closeLoading(); |
| | | } |
| | |
| | | if (!productForm.value.quantity) { |
| | | return; |
| | | } |
| | | // 含税总价计算 |
| | | const settlePieceArea = parseFloat(productForm.value.settlePieceArea) || 1; |
| | | // 含税总价计算 = 单价 * 结算面积 * 数量 |
| | | productForm.value.taxInclusiveTotalPrice = |
| | | proxy.calculateTaxIncludeTotalPrice( |
| | | productForm.value.taxInclusiveUnitPrice, |
| | | productForm.value.taxInclusiveUnitPrice * settlePieceArea, |
| | | productForm.value.quantity |
| | | ); |
| | | if (productForm.value.taxRate) { |
| | |
| | | const computed = Number(computedPieceArea.toFixed(5)); |
| | | |
| | | productForm.value.actualPieceArea = computed; |
| | | |
| | | // settlePieceArea:若用户未填写/为0,则默认使用宽高计算值 |
| | | const settlePieceRaw = Number(productForm.value.settlePieceArea ?? 0) || 0; |
| | | if (!settlePieceRaw) { |
| | | productForm.value.settlePieceArea = computed; |
| | | } |
| | | productForm.value.settlePieceArea = computed; |
| | | |
| | | recalcPerimeterFromWidthHeight(); |
| | | recalcAreaTotals(); |
| | | // 面积更新后,重新计算含税总价 = 单价 * 结算面积 * 数量 |
| | | calculateFromUnitPrice(true); |
| | | }; |
| | | |
| | | // 根据含税总价计算含税单价和数量 |
| | |
| | | return; |
| | | } |
| | | if (isCalculating.value) return; |
| | | |
| | | |
| | | const quantity = parseFloat(productForm.value.quantity); |
| | | const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice); |
| | | |
| | | const settlePieceArea = parseFloat(productForm.value.settlePieceArea) || 1; |
| | | |
| | | if (!quantity || quantity <= 0 || !unitPrice) { |
| | | return; |
| | | } |
| | | |
| | | |
| | | isCalculating.value = true; |
| | | |
| | | // 计算含税总价 |
| | | productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2); |
| | | |
| | | |
| | | // 计算含税总价 = 单价 * 结算面积 * 数量 |
| | | productForm.value.taxInclusiveTotalPrice = (unitPrice * settlePieceArea * quantity).toFixed(2); |
| | | |
| | | // 如果有税率,计算不含税总价 |
| | | if (productForm.value.taxRate) { |
| | | productForm.value.taxExclusiveTotalPrice = |
| | |
| | | productForm.value.taxRate |
| | | ); |
| | | } |
| | | |
| | | |
| | | isCalculating.value = false; |
| | | }; |
| | | |
| | | // 根据含税单价变化计算总价 |
| | | const calculateFromUnitPrice = () => { |
| | | const calculateFromUnitPrice = (silent = false) => { |
| | | if (!productForm.value.taxRate) { |
| | | proxy.$modal.msgWarning("请先选择税率"); |
| | | if (!silent) proxy.$modal.msgWarning("请先选择税率"); |
| | | return; |
| | | } |
| | | if (isCalculating.value) return; |
| | | |
| | | |
| | | const quantity = parseFloat(productForm.value.quantity); |
| | | const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice); |
| | | |
| | | const settlePieceArea = parseFloat(productForm.value.settlePieceArea) || 1; |
| | | |
| | | if (!quantity || quantity <= 0 || !unitPrice) { |
| | | return; |
| | | } |
| | | |
| | | |
| | | isCalculating.value = true; |
| | | |
| | | // 计算含税总价 |
| | | productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2); |
| | | |
| | | |
| | | // 计算含税总价 = 单价 * 结算面积 * 数量 |
| | | productForm.value.taxInclusiveTotalPrice = (unitPrice * settlePieceArea * quantity).toFixed(2); |
| | | |
| | | // 如果有税率,计算不含税总价 |
| | | if (productForm.value.taxRate) { |
| | | productForm.value.taxExclusiveTotalPrice = |
| | |
| | | productForm.value.taxRate |
| | | ); |
| | | } |
| | | |
| | | |
| | | isCalculating.value = false; |
| | | }; |
| | | |