将半成品和成品跟bom表进行相关联
This commit is contained in:
@ -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>
|
||||
Reference in New Issue
Block a user