diff --git a/inventory-backend/app/services/inbound/product_service.py b/inventory-backend/app/services/inbound/product_service.py
index d2284ff..b814296 100644
--- a/inventory-backend/app/services/inbound/product_service.py
+++ b/inventory-backend/app/services/inbound/product_service.py
@@ -137,6 +137,11 @@ class ProductInboundService:
in_date_val = current_time
in_qty = float(data.get('in_quantity') or 0)
+ raw_cost = float(data.get('raw_material_cost') or 0)
+ manual_cost = 0.0 # 字段已弃用,保持向后兼容
+ unit_total_cost = float(data.get('unit_total_cost') or raw_cost or 0)
+ total_price = unit_total_cost * in_qty
+
p_start = data.get('production_start_time', '')
p_end = data.get('production_end_time', '')
time_range = f"{p_start} ~ {p_end}" if p_start or p_end else None
@@ -175,8 +180,10 @@ class ProductInboundService:
work_order_code=data.get('work_order_code'),
production_manager=data.get('production_manager'),
production_time_range=time_range,
- raw_material_cost=float(data.get('raw_material_cost') or 0),
- manual_cost=float(data.get('manual_cost') or 0),
+ raw_material_cost=raw_cost,
+ manual_cost=manual_cost,
+ unit_total_cost=unit_total_cost,
+ total_price=total_price,
quality_status=data.get('quality_status', '合格'),
product_photo=json.dumps(photo_list),
quality_report_link=json.dumps(quality_list),
@@ -230,7 +237,7 @@ class ProductInboundService:
if 'sale_price' in data: stock.sale_price = float(data['sale_price'])
if 'raw_material_cost' in data: stock.raw_material_cost = float(data['raw_material_cost'])
- if 'manual_cost' in data: stock.manual_cost = float(data['manual_cost'])
+ if 'unit_total_cost' in data: stock.unit_total_cost = float(data['unit_total_cost'])
if 'in_quantity' in data:
new_qty = float(data['in_quantity'])
@@ -239,6 +246,10 @@ class ProductInboundService:
stock.stock_quantity = float(stock.stock_quantity) + diff
stock.available_quantity = float(stock.available_quantity) + diff
+ if 'unit_total_cost' in data or 'in_quantity' in data:
+ qty = float(data.get('in_quantity', stock.in_quantity or 1))
+ stock.total_price = float(stock.unit_total_cost or 0) * qty
+
if 'production_start_time' in data or 'production_end_time' in data:
old_range = stock.production_time_range or " ~ "
parts = old_range.split(' ~ ')
@@ -415,4 +426,4 @@ class ProductInboundService:
return [r[0] for r in records if r[0]]
except Exception:
traceback.print_exc()
- return []
\ No newline at end of file
+ return []
diff --git a/inventory-backend/app/services/inbound/semi_service.py b/inventory-backend/app/services/inbound/semi_service.py
index 95099fb..ed4c86c 100644
--- a/inventory-backend/app/services/inbound/semi_service.py
+++ b/inventory-backend/app/services/inbound/semi_service.py
@@ -172,8 +172,8 @@ class SemiInboundService:
in_qty = float(data.get('in_quantity') or 0)
raw_cost = float(data.get('raw_material_cost') or 0)
- manual_cost = float(data.get('manual_cost') or 0)
- unit_total_cost = raw_cost + manual_cost
+ manual_cost = 0.0 # 字段已弃用,保持向后兼容
+ unit_total_cost = float(data.get('unit_total_cost') or raw_cost or 0)
total_value = unit_total_cost * in_qty
next_global_id = 0
@@ -220,7 +220,8 @@ class SemiInboundService:
production_end_time=p_end,
production_time_range=time_range_str,
raw_material_cost=raw_cost,
- manual_cost=manual_cost,
+ manual_cost=manual_cost, # 保持 0.0
+ unit_total_cost=unit_total_cost,
total_price=total_value,
arrival_photo=json.dumps(arrival_list),
quality_report_link=json.dumps(quality_report_list),
@@ -312,7 +313,6 @@ class SemiInboundService:
stock.production_time_range = raw_range
qty_changed = False
- cost_changed = False
if 'in_quantity' in data:
new_qty = float(data['in_quantity'])
diff = new_qty - float(stock.in_quantity)
@@ -321,15 +321,15 @@ class SemiInboundService:
stock.stock_quantity = float(stock.stock_quantity) + diff
stock.available_quantity = float(stock.available_quantity) + diff
qty_changed = True
+
if 'raw_material_cost' in data:
stock.raw_material_cost = float(data['raw_material_cost'])
- cost_changed = True
- if 'manual_cost' in data:
- stock.manual_cost = float(data['manual_cost'])
- cost_changed = True
- if cost_changed or qty_changed:
- unit_total = float(stock.raw_material_cost) + float(stock.manual_cost)
- stock.total_price = float(stock.in_quantity) * unit_total
+ if 'unit_total_cost' in data:
+ stock.unit_total_cost = float(data['unit_total_cost'])
+
+ if 'unit_total_cost' in data or qty_changed:
+ qty = float(stock.in_quantity or 1)
+ stock.total_price = float(stock.unit_total_cost or 0) * qty
db.session.commit()
return stock
@@ -503,4 +503,4 @@ class SemiInboundService:
return [r[0] for r in records if r[0]]
except Exception:
traceback.print_exc()
- return []
\ No newline at end of file
+ return []
diff --git a/inventory-web/src/views/stock/inbound/product.vue b/inventory-web/src/views/stock/inbound/product.vue
index 81150f4..bc7afe7 100644
--- a/inventory-web/src/views/stock/inbound/product.vue
+++ b/inventory-web/src/views/stock/inbound/product.vue
@@ -467,7 +467,8 @@ import {
searchMaterialBase,
searchBom,
getFilterOptions,
- getManagerHistory // [新增]
+ getManagerHistory, // [新增]
+ calculateBomCost
} from '@/api/inbound/product'
import { uploadFile, deleteFile } from '@/api/inbound/buy'
import WebRtcCamera from '@/components/Camera/WebRtcCamera.vue'
@@ -657,7 +658,7 @@ const handleSearchBom = async (query: string) => {
bomOptions.value = res.data || []
} finally { bomSearchLoading.value = false }
}
-const handleBomSelect = (val: string) => {
+const handleBomSelect = async (val: string) => {
if (!val) {
form.bom_code = ''
form.bom_version = ''
@@ -666,6 +667,17 @@ const handleBomSelect = (val: string) => {
const [code, version] = val.split('###')
form.bom_code = code
form.bom_version = version
+ // 自动计算 BOM 成本并填入 raw_material_cost 和 unit_total_cost
+ try {
+ const res: any = await calculateBomCost({ bom_code: code, bom_version: version })
+ if (res.code === 200 && typeof res.data === 'number') {
+ form.raw_material_cost = res.data
+ form.unit_total_cost = res.data
+ }
+ } catch (e) {
+ // 计算失败不影响现有输入
+ console.warn('BOM 成本计算失败', e)
+ }
}
// ------------------------------------
@@ -1087,4 +1099,4 @@ onMounted(() => {
.product-dropdown { width: 580px !important; }
.product-dropdown .el-select-dropdown__wrap { max-height: 320px !important; }
.product-dropdown .el-input__suffix { z-index: 10; }
-
\ No newline at end of file
+
diff --git a/inventory-web/src/views/stock/inbound/semi.vue b/inventory-web/src/views/stock/inbound/semi.vue
index a8e3e68..7182b08 100644
--- a/inventory-web/src/views/stock/inbound/semi.vue
+++ b/inventory-web/src/views/stock/inbound/semi.vue
@@ -473,13 +473,13 @@
-
-
+
+
-
+
@@ -539,7 +539,8 @@ import {
searchMaterialBase,
searchBom,
getFilterOptions,
- getManagerHistory // [新增]
+ getManagerHistory, // [新增]
+ calculateBomCost
} from '@/api/inbound/semi'
import { uploadFile, deleteFile } from '@/api/inbound/buy'
import WebRtcCamera from '@/components/Camera/WebRtcCamera.vue'
@@ -731,13 +732,11 @@ const form = reactive({
production_manager: '', production_time_range: [] as string[], arrival_photo: [] as string[], quality_report_link: [] as string[], detail_link: ''
})
-// === 新增:监听计算总成本 ===
-watch([() => form.in_quantity, () => form.manual_cost], ([qty, manual_cost]) => {
- if (manual_cost !== undefined && manual_cost !== null) {
- form.unit_total_cost = Number((qty * manual_cost).toFixed(2))
- } else {
- form.unit_total_cost = undefined
- }
+// === 监听计算总成本 ===
+watch([() => form.unit_total_cost, () => form.in_quantity], ([unit, qty]) => {
+ const unitNum = Number(unit || 0)
+ const qtyNum = Number(qty || 1)
+ form.total_price = Number((unitNum * qtyNum).toFixed(2))
})
// ------------------------------------
@@ -750,7 +749,7 @@ const handleSearchBom = async (query: string) => {
bomOptions.value = res.data || []
} finally { bomSearchLoading.value = false }
}
-const handleBomSelect = (val: string) => {
+const handleBomSelect = async (val: string) => {
// val 格式为 bom_no###version
if (!val) {
form.bom_code = ''
@@ -760,6 +759,17 @@ const handleBomSelect = (val: string) => {
const [code, version] = val.split('###')
form.bom_code = code
form.bom_version = version
+ // 自动计算 BOM 成本并填入 raw_material_cost 和 unit_total_cost
+ try {
+ const res: any = await calculateBomCost({ bom_code: code, bom_version: version })
+ if (res.code === 200 && typeof res.data === 'number') {
+ form.raw_material_cost = res.data
+ form.unit_total_cost = res.data
+ }
+ } catch (e) {
+ // 计算失败不影响现有输入
+ console.warn('BOM 成本计算失败', e)
+ }
}
// ------------------------------------
@@ -1221,4 +1231,4 @@ onMounted(() => {
.long-dropdown { width: 580px !important; }
.long-dropdown .el-select-dropdown__wrap { max-height: 320px !important; }
.long-dropdown .el-input__suffix { z-index: 10; }
-
\ No newline at end of file
+