diff --git a/backend/app/services/order_service.py b/backend/app/services/order_service.py index c3d17d1..9f43dce 100644 --- a/backend/app/services/order_service.py +++ b/backend/app/services/order_service.py @@ -816,7 +816,7 @@ class OrderService: sale_total = sum(item["quantity"] * item["sale_price"] for item in items) cost_total = sum(item["quantity"] * item["cost_price"] for item in items) - income_amount = payload.get("contract_amount") or order.contract_amount or sale_total + income_amount = payload.get("contract_amount", 0) or sale_total rebate_total = payload.get("rebate_total", float(order.rebate_total or 0)) freight_total = payload.get("freight_total", float(order.freight_total or 0)) tax_total = payload.get("tax_total", float(order.tax_total or 0)) @@ -824,7 +824,7 @@ class OrderService: profit_total = income_amount - cost_total - rebate_total - freight_total - tax_total - other_fee_total profit_rate = round((profit_total / income_amount) * 100, 2) if income_amount else 0 - self.order_repository.update_order_with_items( + self.order_repository.update_order_financials_with_items( session, order, { diff --git a/frontend/mini-app/pages/manager/approve-detail/approve-detail.js b/frontend/mini-app/pages/manager/approve-detail/approve-detail.js index 6826807..eb914f5 100644 --- a/frontend/mini-app/pages/manager/approve-detail/approve-detail.js +++ b/frontend/mini-app/pages/manager/approve-detail/approve-detail.js @@ -171,6 +171,7 @@ Page({ // 费用明细:有值才显示 var feeItems = [ { label: "合同金额", value: fmt(data.contract_amount), isIncome: true }, + { label: "销售总价", value: fmt(sale) }, { label: "成本", value: fmt(cost) }, ]; if (rebate > 0) feeItems.push({ label: "回扣", value: fmt(rebate) }); @@ -198,6 +199,8 @@ Page({ unit: ci.unit || "", baseUnitPrice: fmt(ci.base_unit_price || ci.cost_price), pricingUnit: ci.pricing_unit || "", + saleUnitPrice: fmt(ci.sale_price || 0), + costUnitPrice: fmt(ci.cost_price || 0), costPrice: fmt(ci.cost_price), costAmount: fmt(Number(ci.quantity || 0) * Number(ci.cost_price || 0)), pricingType: pricingTypeMap[ci.pricing_type] || "", diff --git a/frontend/mini-app/pages/manager/approve-detail/approve-detail.wxml b/frontend/mini-app/pages/manager/approve-detail/approve-detail.wxml index 0ca319c..8dcbec3 100644 --- a/frontend/mini-app/pages/manager/approve-detail/approve-detail.wxml +++ b/frontend/mini-app/pages/manager/approve-detail/approve-detail.wxml @@ -95,8 +95,9 @@ 计价过程: {{item.formulaDetail}} - 单价: ¥{{item.baseUnitPrice}}{{item.pricingUnit ? '/' + item.pricingUnit : ''}} - 成本: ¥{{item.costAmount}} + 售价: ¥{{item.saleUnitPrice}} + 成本: ¥{{item.costUnitPrice}}{{item.pricingUnit ? '/' + item.pricingUnit : ''}} + 小计: ¥{{item.costAmount}} diff --git a/frontend/mini-app/pages/manager/approve-detail/approve-detail.wxss b/frontend/mini-app/pages/manager/approve-detail/approve-detail.wxss index dbdd335..fb29443 100644 --- a/frontend/mini-app/pages/manager/approve-detail/approve-detail.wxss +++ b/frontend/mini-app/pages/manager/approve-detail/approve-detail.wxss @@ -284,3 +284,79 @@ background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%); color: #ffffff; } + + +/* 成本核算编辑弹窗 */ +.edit-modal { + width: 100%; + max-height: 85vh; + padding: 28rpx; + border-radius: 20rpx; + background: #ffffff; + box-shadow: 0 24rpx 60rpx rgba(15, 23, 42, 0.18); + display: flex; + flex-direction: column; +} + +.edit-items-scroll { + max-height: 60vh; + margin-top: 16rpx; +} + +.edit-item-card { + background: #f8fafc; + border: 1rpx solid #e5eaf1; + border-radius: 14rpx; + padding: 20rpx; + margin-bottom: 16rpx; +} + +.edit-item-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12rpx; +} + +.edit-item-index { + font-size: 26rpx; + font-weight: 600; + color: #0f172a; +} + +.edit-item-delete { + font-size: 24rpx; + color: #dc2626; +} + +.edit-item-row { + display: flex; + gap: 12rpx; + margin-bottom: 20rpx; +} + +.edit-item-col { + flex: 1; +} + +.field-readonly { + padding: 16rpx 20rpx; + background: #f1f5f9; + border: 1rpx solid #e2e8f0; + border-radius: 12rpx; + font-size: 28rpx; + color: #64748b; +} + +.add-item-btn { + margin-top: 12rpx; + margin-bottom: 8rpx; + text-align: center; + background: #f8fafc; + color: #2563eb; + border: 2rpx dashed #93c5fd; + border-radius: 12rpx; + font-size: 28rpx; + height: 72rpx; + line-height: 72rpx; +} \ No newline at end of file diff --git a/frontend/web-admin/src/views/OrdersPage.vue b/frontend/web-admin/src/views/OrdersPage.vue index c04f10a..697ab0e 100644 --- a/frontend/web-admin/src/views/OrdersPage.vue +++ b/frontend/web-admin/src/views/OrdersPage.vue @@ -314,7 +314,7 @@ 需求规格 单位 数量 - 销售单价 + 销售单价 成本单价 计价过程 成本金额 @@ -328,6 +328,7 @@ {{ item.demand_specification || "-" }} {{ item.unit || '-' }} {{ computeTotalDemand(item) || item.quantity }} + ¥{{ Number(item.sale_price || 0).toFixed(2) }} ¥{{ Number(item.base_unit_price || item.cost_price || 0).toFixed(2) }}{{ item.pricing_unit ? '/' + item.pricing_unit : '' }} {{ formatPricingProcess(item) }} @@ -393,6 +394,10 @@ ¥{{ isEditing ? editFinanceSummary.contractAmount : detail.order.contractAmount }} +
+ + ¥{{ isEditing ? editFinanceSummary.salePriceTotal : detail.order.salePriceTotal }} +
¥{{ isEditing ? editFinanceSummary.costPriceTotal : detail.order.costPriceTotal }} @@ -1228,16 +1233,19 @@ const productOptions = ref([]); const editFinanceSummary = computed(() => { const contractAmount = Number(editForm.contract_amount) || 0; + const salePriceTotal = editItems.value.reduce((sum, item) => (Number(item.quantity) || 0) * (Number(item.sale_price) || 0) + sum, 0); const costPriceTotal = editItems.value.reduce((sum, item) => sum + itemCostTotal(item), 0); const rebateTotal = Number(editForm.rebate_total) || 0; const freightTotal = Number(editForm.freight_total) || 0; const taxTotal = Number(editForm.tax_total) || 0; const otherFeeTotal = Number(editForm.other_fee_total) || 0; - const profitTotal = contractAmount - costPriceTotal - rebateTotal - freightTotal - taxTotal - otherFeeTotal; - const profitRate = contractAmount ? (profitTotal / contractAmount) * 100 : 0; + const incomeAmount = contractAmount || salePriceTotal; + const profitTotal = incomeAmount - costPriceTotal - rebateTotal - freightTotal - taxTotal - otherFeeTotal; + const profitRate = incomeAmount ? (profitTotal / incomeAmount) * 100 : 0; return { contractAmount: formatMoney(contractAmount), + salePriceTotal: formatMoney(salePriceTotal), costPriceTotal: formatMoney(costPriceTotal), profitTotal: formatMoney(profitTotal), profitRate: `${formatMoney(profitRate)}%`, @@ -1530,7 +1538,6 @@ async function saveEdit() { const payload = { items: itemsPayload, revision_reason: editForm.revision_reason?.trim() || '管理员修改', - contract_amount: Number(editForm.contract_amount) || undefined, rebate_total: Number(editForm.rebate_total) || 0, freight_total: Number(editForm.freight_total) || 0, tax_total: Number(editForm.tax_total) || 0,