| | |
| | | <el-table-column label="总价" |
| | | prop="totalPrice" |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="运费" |
| | | prop="freight" |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="含运费单价" |
| | | prop="priceWithFreight" |
| | | :formatter="formattedNumber" /> |
| | | </template> |
| | | <!--操作--> |
| | | <!-- <el-table-column Width="60px" |
| | |
| | | style="text-align: right;"> |
| | | <el-button type="primary" |
| | | plain |
| | | :disabled="!form.customerId" |
| | | @click="openQuotationDialog"> |
| | | 从销售报价导入 |
| | | </el-button> |
| | |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="总价" |
| | | prop="totalPrice" |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="运费" |
| | | prop="freight" |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="含运费单价" |
| | | prop="priceWithFreight" |
| | | :formatter="formattedNumber" /> |
| | | </template> |
| | | <el-table-column fixed="right" |
| | |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <!-- <el-col :span="12"> |
| | | <el-form-item label="税率(%):" |
| | | prop="taxRate"> |
| | | <el-select v-model="productForm.taxRate" |
| | | placeholder="请选择" |
| | | clearable |
| | | @change="calculateFromTaxRate"> |
| | | <el-option label="1" |
| | | value="1" /> |
| | | <el-option label="6" |
| | | value="6" /> |
| | | <el-option label="13" |
| | | value="13" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> --> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | </el-row> |
| | |
| | | <el-select v-model="productForm.taxRate" |
| | | placeholder="请选择" |
| | | clearable |
| | | filterable |
| | | allow-create |
| | | default-first-option |
| | | style="width: 100%" |
| | | @change="calculateFromTaxRate"> |
| | | <el-option label="1" |
| | | value="1" /> |
| | |
| | | :precision="2" |
| | | placeholder="请输入" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="运费:" |
| | | prop="freight"> |
| | | <el-input-number :step="0.01" |
| | | :min="0" |
| | | v-model="productForm.freight" |
| | | style="width: 100%" |
| | | :precision="2" |
| | | placeholder="请输入" |
| | | clearable |
| | | @change="calculatePrivatePrice" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="含运费单价:" |
| | | prop="priceWithFreight"> |
| | | <el-input-number :step="0.01" |
| | | :min="0" |
| | | v-model="productForm.priceWithFreight" |
| | | style="width: 100%" |
| | | :precision="2" |
| | | placeholder="请输入" |
| | | clearable |
| | | @change="calculatePrivateTotal" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | const productFormVisible = ref(false); |
| | | const productOperationType = ref(""); |
| | | const currentId = ref(""); |
| | | const validateTaxRate = (_rule, value, callback) => { |
| | | if (value === null || value === undefined || value === "") { |
| | | callback(new Error("请选择税率")); |
| | | return; |
| | | } |
| | | const taxRateStr = String(value).trim(); |
| | | if (!/^\d+(\.\d+)?$/.test(taxRateStr)) { |
| | | callback(new Error("税率只能输入数字")); |
| | | return; |
| | | } |
| | | callback(); |
| | | }; |
| | | const productFormData = reactive({ |
| | | productForm: { |
| | | productCategory: "", |
| | |
| | | quantity: "", |
| | | // 对公字段 |
| | | taxInclusiveUnitPrice: "", |
| | | taxRate: "", |
| | | taxRate: null, |
| | | taxInclusiveTotalPrice: "", |
| | | taxExclusiveTotalPrice: "", |
| | | invoiceType: "", |
| | | // 对私字段 |
| | | unitPrice: "", |
| | | totalPrice: "", |
| | | freight: 0, |
| | | priceWithFreight: "", |
| | | |
| | | }, |
| | | productRules: { |
| | | productCategory: [{ required: true, message: "请选择", trigger: "change" }], |
| | |
| | | taxInclusiveUnitPrice: [ |
| | | { required: true, message: "请输入", trigger: "blur" }, |
| | | ], |
| | | taxRate: [{ required: true, message: "请选择", trigger: "change" }], |
| | | taxRate: [{ validator: validateTaxRate, trigger: "change" }], |
| | | taxInclusiveTotalPrice: [ |
| | | { required: true, message: "请输入", trigger: "blur" }, |
| | | ], |
| | |
| | | // 对私字段验证 |
| | | unitPrice: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | totalPrice: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | freight: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | priceWithFreight: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | }, |
| | | }); |
| | | const { productForm, productRules } = toRefs(productFormData); |
| | |
| | | // 打开报价单选择弹窗(仅审批通过) |
| | | const openQuotationDialog = async () => { |
| | | if (operationType.value === "view") return; |
| | | if (!form.value.customerId) { |
| | | proxy.$modal.msgWarning("请先选择客户名称"); |
| | | return; |
| | | } |
| | | quotationDialogVisible.value = true; |
| | | // 打开弹窗时重置分页到第一页 |
| | | quotationPage.current = 1; |
| | |
| | | form.value.salesman = (row.salesperson || "").trim(); |
| | | |
| | | // 客户名称 -> customerId |
| | | // 如果表单里还没有选客户,则尝试通过报价单客户名称匹配; |
| | | // 如果已经选了客户,则保持用户当前选择,不被报价单覆盖。 |
| | | if (!form.value.customerId) { |
| | | const qCustomerName = String(row.customer || "").trim(); |
| | | const customer = (customerOption.value || []).find(c => { |
| | | const name = String(c.customerName || "").trim(); |
| | |
| | | }); |
| | | if (customer?.id) { |
| | | form.value.customerId = customer.id; |
| | | } else { |
| | | // 如果找不到,保留原值(允许用户手动选择/不打断已有输入) |
| | | form.value.customerId = form.value.customerId || ""; |
| | | } |
| | | } |
| | | |
| | | // 产品信息映射:报价 products -> 台账 productData |
| | |
| | | proxy.resetForm("productFormRef"); |
| | | if (type === "edit") { |
| | | productForm.value = { ...row }; |
| | | if (productForm.value.taxRate !== undefined && productForm.value.taxRate !== null && productForm.value.taxRate !== "") { |
| | | productForm.value.taxRate = String(productForm.value.taxRate); |
| | | } |
| | | productIndex.value = index; |
| | | // 编辑时根据产品大类名称反查 tree 节点 id,并加载规格型号列表 |
| | | try { |
| | |
| | | // 对私字段不需要验证 |
| | | delete dynamicRules.unitPrice; |
| | | delete dynamicRules.totalPrice; |
| | | delete dynamicRules.freight; |
| | | delete dynamicRules.priceWithFreight; |
| | | } else if (currentCustomerType.value == 2) { |
| | | // 对公字段不需要验证 |
| | | delete dynamicRules.taxInclusiveUnitPrice; |
| | |
| | | // 对私字段不需要提交 |
| | | delete productDataToSubmit.unitPrice; |
| | | delete productDataToSubmit.totalPrice; |
| | | delete productDataToSubmit.freight; |
| | | delete productDataToSubmit.priceWithFreight; |
| | | } else if (currentCustomerType.value == 2) { |
| | | // 对公字段不需要提交 |
| | | delete productDataToSubmit.taxInclusiveUnitPrice; |
| | |
| | | isCalculating.value = false; |
| | | }; |
| | | |
| | | // 对私客户价格计算:单价和运费变化时计算含运费单价和总价 |
| | | // 对私客户价格计算:单价变化时计算总价 |
| | | const calculatePrivatePrice = () => { |
| | | if (currentCustomerType.value == 2) { |
| | | const unitPrice = parseFloat(productForm.value.unitPrice) || 0; |
| | | const freight = parseFloat(productForm.value.freight) || 0; |
| | | const quantity = parseFloat(productForm.value.quantity) || 0; |
| | | |
| | | // 计算含运费单价 |
| | | productForm.value.priceWithFreight = (unitPrice + freight).toFixed(2); |
| | | |
| | | // 计算总价 |
| | | productForm.value.totalPrice = ( |
| | | parseFloat(productForm.value.priceWithFreight) * quantity |
| | | ).toFixed(2); |
| | | } |
| | | }; |
| | | |
| | | // 对私客户价格计算:含运费单价变化时计算总价 |
| | | const calculatePrivateTotal = () => { |
| | | if (currentCustomerType.value == 2) { |
| | | const priceWithFreight = |
| | | parseFloat(productForm.value.priceWithFreight) || 0; |
| | | const quantity = parseFloat(productForm.value.quantity) || 0; |
| | | |
| | | // 计算总价 |
| | | productForm.value.totalPrice = (priceWithFreight * quantity).toFixed(2); |
| | | productForm.value.totalPrice = (unitPrice * quantity).toFixed(2); |
| | | } |
| | | }; |
| | | |
| | |
| | | } |
| | | |
| | | // 对公客户使用原有的计算逻辑 |
| | | if (!productForm.value.taxRate) { |
| | | if (productForm.value.taxRate === null || productForm.value.taxRate === undefined || productForm.value.taxRate === "") { |
| | | proxy.$modal.msgWarning("请先选择税率"); |
| | | return; |
| | | } |
| | | const taxRateStr = String(productForm.value.taxRate).trim(); |
| | | if (!/^\d+(\.\d+)?$/.test(taxRateStr)) { |
| | | proxy.$modal.msgWarning("税率只能输入数字"); |
| | | return; |
| | | } |
| | | if (isCalculating.value) return; |
| | |
| | | |
| | | isCalculating.value = false; |
| | | }; |
| | | |
| | | /** |
| | | * 获取发货状态文本 |
| | | * @param row 行数据 |
| | |
| | | justify-content: space-between; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .print-preview-dialog { |
| | | .el-dialog__body { |
| | | padding: 0; |