将半成品和成品跟bom表进行相关联

This commit is contained in:
dxc
2026-02-12 17:16:24 +08:00
parent b682d4b02f
commit 853374de5d
8 changed files with 292 additions and 192 deletions

View File

@ -373,8 +373,36 @@
<div class="divider-text">生产任务信息</div>
<el-row :gutter="24">
<el-col :span="8"><el-form-item label="工单号"><el-input v-model="form.work_order_code" placeholder="WO-xxx"/></el-form-item></el-col>
<el-col :span="8"><el-form-item label="BOM编号"><el-input v-model="form.bom_code" placeholder="BOM-xxx"/></el-form-item></el-col>
<el-col :span="8"><el-form-item label="BOM版本"><el-input v-model="form.bom_version" placeholder="v1.0"/></el-form-item></el-col>
<el-col :span="8">
<el-form-item label="BOM编号">
<el-select
v-model="form.bom_code"
filterable
remote
clearable
placeholder="搜规格/编号"
:remote-method="handleSearchBom"
:loading="bomSearchLoading"
@change="handleBomSelect"
style="width: 100%"
>
<el-option
v-for="item in bomOptions"
:key="`${item.bom_no}_${item.version}`"
:label="item.bom_no"
:value="`${item.bom_no}###${item.version}`"
>
<span style="float: left; font-weight: bold;">{{ item.bom_no }}</span>
<span style="float: right; color: #8492a6; font-size: 13px; margin-left: 10px;">
{{ item.version }} <span v-if="item.parent_spec">({{ item.parent_spec }})</span>
</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8"><el-form-item label="BOM版本"><el-input v-model="form.bom_version" placeholder="自动填充" readonly/></el-form-item></el-col>
</el-row>
<el-row :gutter="24">
@ -452,6 +480,7 @@ import {
updateSemiInbound,
deleteSemiInbound,
searchMaterialBase,
searchBom, // [新增]
getFilterOptions
} from '@/api/inbound/semi'
import { uploadFile, deleteFile } from '@/api/inbound/buy'
@ -474,6 +503,10 @@ const categoryOptions = ref<string[]>([])
const typeOptions = ref<string[]>([])
const materialOptions = ref<any[]>([])
// BOM 搜索相关
const bomSearchLoading = ref(false)
const bomOptions = ref<any[]>([])
// 打印相关变量
const printVisible = ref(false)
const printLoading = ref(false)
@ -542,15 +575,35 @@ const form = reactive({
production_manager: '', production_time_range: [] as string[], arrival_photo: [] as string[], quality_report_link: [] as string[], detail_link: ''
})
// ------------------------------------
// BOM Search Logic
// ------------------------------------
const handleSearchBom = async (query: string) => {
bomSearchLoading.value = true
try {
const res: any = await searchBom(query)
bomOptions.value = res.data || []
} finally { bomSearchLoading.value = false }
}
const handleBomSelect = (val: string) => {
// val 格式为 bom_no###version
if (!val) {
form.bom_code = ''
form.bom_version = ''
return
}
const [code, version] = val.split('###')
form.bom_code = code
form.bom_version = version
}
// ------------------------------------
// Autocomplete & Search Logic (后端 API 驱动)
// ------------------------------------
const querySearchManager = async (query: string, cb: any) => {
// 后续会从后端获取用户建议,暂时先返回空列表
cb([])
}
const handleManagerSelect = (item: any) => {
// 无需保存历史
}
// ------------------------------------
@ -568,13 +621,11 @@ const handleSearchMaterial = async (query: string) => {
const onMaterialSelected = (val: number) => {
const item = materialOptions.value.find(i => i.id === val)
if (item) {
// Populate form fields
form.material_name = item.name
form.spec_model = item.spec
form.category = item.category
form.unit = item.unit
form.material_type = item.type
// Trigger batch/serial logic specific to Semi
checkHistoryAndSetMode(item.id)
}
}
@ -587,7 +638,6 @@ const validateUnique = (rule: any, value: string, callback: any) => {
const isDuplicate = tableData.value.some((row: any) => {
if (dialogStatus.value === 'update' && row.id === form.id) return false
if (rule.field === 'serial_number' && row.serial_number === value) return true
// 批号校验需要同时匹配物料
if (rule.field === 'batch_number' && row.batch_number === value && row.base_id === form.base_id) return true
return false
})
@ -699,6 +749,10 @@ const handleUpdate = (row: any) => {
if (row.serial_number) { entryMode.value = 'serial'; form.serial_number = row.serial_number; form.batch_number = '' }
else { entryMode.value = 'batch'; form.batch_number = row.batch_number; form.serial_number = '' }
materialOptions.value = [{ id: row.base_id, name: row.material_name, spec: row.spec_model, category: row.category, isHistory: false }]
// 回显BOM如果存在
if (form.bom_code) {
bomOptions.value = [{ bom_no: form.bom_code, version: form.bom_version }]
}
visible.value = true
}
@ -741,10 +795,7 @@ const handleCameraConfirm = async (file: File) => {
}
const formData = new FormData();
formData.append('file', file);
// 修复点:使用 ElLoading
const loadingMsg = ElLoading.service({ text: '照片上传中...', background: 'rgba(0, 0, 0, 0.7)' });
let success = false;
try {
const res: any = await uploadFile(formData);
@ -796,7 +847,6 @@ const submitForm = async () => {
} else { await updateSemiInbound(form.id!, payload); ElMessage.success('更新成功') }
await fetchData(); visible.value = false
} catch (e: any) {
// 捕获后端报错
ElMessage.error(e.msg || '操作失败')
} finally { submitting.value = false }
}
@ -811,7 +861,7 @@ const handlePrint = async (row: any) => {
}
const confirmPrint = async () => { printing.value = true; try { await executePrint(currentPrintData.value); ElMessage.success('指令已发送'); printVisible.value = false } catch (e: any) { ElMessage.error(e.msg || '打印失败') } finally { printing.value = false } }
const resetForm = () => {
materialOptions.value = []; arrivalFileList.value = []; reportFileList.value = []; quality_report_url.value = ''
materialOptions.value = []; bomOptions.value = []; arrivalFileList.value = []; reportFileList.value = []; quality_report_url.value = ''
Object.assign(form, { id: undefined, base_id: undefined, material_name: '', spec_model: '', category: '', unit: '', material_type: '', sku: '', barcode: '', in_date: '', serial_number: '', batch_number: '', status: '在库', quality_status: '合格', in_quantity: 1, stock_quantity: 1, available_quantity: 1, warehouse_location: '', bom_code: '', bom_version: '', work_order_code: '', raw_material_cost: 0, manual_cost: 0, unit_total_cost: 0, production_manager: '', production_time_range: [], arrival_photo: [], quality_report_link: [], detail_link: '' })
}
const getStatusType = (status: string) => { const map: any = { '在库': 'success', '出库': 'info', '借库': 'warning', '损耗': 'danger' }; return map[status] || 'warning' }
@ -872,4 +922,4 @@ onMounted(() => {
.camera-card:hover { border-color: #409EFF; color: #409EFF; }
.camera-card .text { font-size: 12px; margin-top: 5px; }
.camera-card .el-icon { font-size: 24px; }
</style>
</style>