feat: 新增物料/成品/半成品页面一键直达BOM管理功能
This commit is contained in:
@ -202,6 +202,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted, computed, nextTick } from 'vue'
|
import { ref, reactive, onMounted, computed, nextTick } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
import { ElMessage, ElMessageBox, FormInstance, FormRules } from 'element-plus'
|
import { ElMessage, ElMessageBox, FormInstance, FormRules } from 'element-plus'
|
||||||
import { Plus, Search } from '@element-plus/icons-vue'
|
import { Plus, Search } from '@element-plus/icons-vue'
|
||||||
import { getBomList, getBomDetail, saveBom, deleteBom } from '@/api/bom'
|
import { getBomList, getBomDetail, saveBom, deleteBom } from '@/api/bom'
|
||||||
@ -231,6 +232,7 @@ interface ChildRow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
const route = useRoute()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
@ -746,6 +748,55 @@ const submitForm = async () => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchBomList()
|
fetchBomList()
|
||||||
|
|
||||||
|
// 【新增】:处理外部跳转自动打开 BOM(带查重保护)
|
||||||
|
if (route.query.create_for_id) {
|
||||||
|
const parentId = Number(route.query.create_for_id);
|
||||||
|
const parentName = (route.query.parent_name as string) || '';
|
||||||
|
const parentSpec = (route.query.parent_spec as string) || '';
|
||||||
|
|
||||||
|
// 把名称填入背景搜索框,让背后的表格也只显示相关的BOM
|
||||||
|
searchKeyword.value = parentName;
|
||||||
|
|
||||||
|
// 延迟等待基础渲染
|
||||||
|
setTimeout(() => {
|
||||||
|
// 1. 先用 keyword 查询是否已有该父件的 BOM
|
||||||
|
getBomList({ keyword: parentName }).then((res: any) => {
|
||||||
|
const rows = res.data || [];
|
||||||
|
// 严格校验 parent_id
|
||||||
|
const existingBom = rows.find((b: any) => b.parent_id === parentId);
|
||||||
|
|
||||||
|
if (existingBom) {
|
||||||
|
// ★ 情况 A:已经有BOM了,直接打开编辑弹窗并拉取历史数据
|
||||||
|
ElMessage.success('检测到该物料已有 BOM,已自动为您打开编辑');
|
||||||
|
handleEdit(existingBom);
|
||||||
|
} else {
|
||||||
|
// ★ 情况 B:还没建过BOM,打开新建并注入父件
|
||||||
|
handleCreate();
|
||||||
|
|
||||||
|
// 强行注入父件远程搜索选项
|
||||||
|
parentOptions.value = [{
|
||||||
|
id: parentId,
|
||||||
|
name: parentName,
|
||||||
|
spec: parentSpec
|
||||||
|
}];
|
||||||
|
|
||||||
|
// 给表单赋值
|
||||||
|
form.parent_id = parentId;
|
||||||
|
|
||||||
|
// 触发联动逻辑(自动带出版本和生成编号)
|
||||||
|
if (typeof onParentChange === 'function') {
|
||||||
|
setTimeout(() => {
|
||||||
|
onParentChange(parentId);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('BOM 查重失败', err);
|
||||||
|
ElMessage.error('获取 BOM 状态失败,请手动操作');
|
||||||
|
});
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -326,7 +326,6 @@
|
|||||||
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="dialog.visible"
|
v-model="dialog.visible"
|
||||||
:title="dialog.title"
|
|
||||||
width="700px"
|
width="700px"
|
||||||
append-to-body
|
append-to-body
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
@ -335,6 +334,20 @@
|
|||||||
:close-on-press-escape="!isUploading"
|
:close-on-press-escape="!isUploading"
|
||||||
:show-close="!isUploading"
|
:show-close="!isUploading"
|
||||||
>
|
>
|
||||||
|
<template #header>
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; padding-right: 20px;">
|
||||||
|
<span style="font-size: 18px; font-weight: 500;">{{ dialog.title }}</span>
|
||||||
|
<el-link
|
||||||
|
v-if="form.id"
|
||||||
|
type="success"
|
||||||
|
:underline="false"
|
||||||
|
style="font-size: 14px;"
|
||||||
|
@click="createBomForMaterial"
|
||||||
|
>
|
||||||
|
<el-icon style="margin-right: 4px"><Plus /></el-icon>加入或查看BOM
|
||||||
|
</el-link>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="110px">
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="110px">
|
||||||
|
|
||||||
<el-row>
|
<el-row>
|
||||||
@ -597,8 +610,9 @@ import { Plus, Document, Refresh, Setting, Rank, Camera, Link, Download, Bell, C
|
|||||||
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
|
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
|
||||||
import type { FormInstance, FormRules } from 'element-plus';
|
import type { FormInstance, FormRules } from 'element-plus';
|
||||||
import { useUserStore } from '@/stores/user';
|
import { useUserStore } from '@/stores/user';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
import {
|
import {
|
||||||
listMaterialBase,
|
listMaterialBase,
|
||||||
@ -1307,6 +1321,22 @@ const cancel = () => {
|
|||||||
resetForm();
|
resetForm();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 快速基于此物料查看/创建 BOM
|
||||||
|
const createBomForMaterial = () => {
|
||||||
|
if (!form.value.id) {
|
||||||
|
return ElMessage.warning('请先保存物料基础信息后再操作');
|
||||||
|
}
|
||||||
|
const routeUrl = router.resolve({
|
||||||
|
path: '/bom',
|
||||||
|
query: {
|
||||||
|
create_for_id: form.value.id,
|
||||||
|
parent_name: form.value.name,
|
||||||
|
parent_spec: form.value.spec
|
||||||
|
}
|
||||||
|
});
|
||||||
|
window.open(routeUrl.href, '_blank');
|
||||||
|
};
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
form.value = JSON.parse(JSON.stringify(initForm));
|
form.value = JSON.parse(JSON.stringify(initForm));
|
||||||
fileListImage.value = [];
|
fileListImage.value = [];
|
||||||
|
|||||||
@ -421,7 +421,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-card production-card">
|
<div class="form-card production-card">
|
||||||
<div class="card-title"><el-icon class="icon"><Setting /></el-icon><span>3. 生产与销售信息</span></div>
|
<div class="card-title">
|
||||||
|
<el-icon class="icon"><Setting /></el-icon><span>3. 生产与销售信息</span>
|
||||||
|
<el-link type="success" :underline="false" style="margin-left: 15px; font-size: 13px;" @click="createBomForMaterial">
|
||||||
|
<el-icon style="margin-right: 4px"><Plus /></el-icon>加入或查看BOM
|
||||||
|
</el-link>
|
||||||
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
|
|
||||||
@ -557,6 +562,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive, onMounted, watch, computed } from 'vue'
|
import { ref, reactive, onMounted, watch, computed } from 'vue'
|
||||||
import { Plus, Setting, Refresh, Search, Box, House, Link, InfoFilled, Printer, Camera, Picture } from '@element-plus/icons-vue'
|
import { Plus, Setting, Refresh, Search, Box, House, Link, InfoFilled, Printer, Camera, Picture } from '@element-plus/icons-vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
import { ElMessage, ElLoading } from 'element-plus'
|
import { ElMessage, ElLoading } from 'element-plus'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
@ -614,6 +620,7 @@ const vLoadmore = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
const router = useRouter()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const submitting = ref(false)
|
const submitting = ref(false)
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
@ -1263,6 +1270,20 @@ const handleScannerConfirm = (result: string) => {
|
|||||||
ElMessage.success('序列号已提取')
|
ElMessage.success('序列号已提取')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 快速基于此物料创建 BOM
|
||||||
|
const createBomForMaterial = () => {
|
||||||
|
if (!form.base_id) return ElMessage.warning('请先锁定物料基础信息')
|
||||||
|
const routeUrl = router.resolve({
|
||||||
|
path: '/bom',
|
||||||
|
query: {
|
||||||
|
create_for_id: form.base_id,
|
||||||
|
parent_name: form.material_name,
|
||||||
|
parent_spec: form.spec_model
|
||||||
|
}
|
||||||
|
})
|
||||||
|
window.open(routeUrl.href, '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
await formRef.value.validate(async (valid: boolean) => {
|
await formRef.value.validate(async (valid: boolean) => {
|
||||||
if(valid) {
|
if(valid) {
|
||||||
|
|||||||
@ -489,6 +489,9 @@
|
|||||||
<div style="display: flex; align-items: center;">
|
<div style="display: flex; align-items: center;">
|
||||||
<el-icon class="icon"><Setting/></el-icon>
|
<el-icon class="icon"><Setting/></el-icon>
|
||||||
<span>3. 生产与成本信息</span>
|
<span>3. 生产与成本信息</span>
|
||||||
|
<el-link type="success" :underline="false" style="margin-left: 15px; font-size: 13px;" @click="createBomForMaterial">
|
||||||
|
<el-icon style="margin-right: 4px"><Plus /></el-icon>加入或查看BOM
|
||||||
|
</el-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
@ -614,6 +617,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref, reactive, onMounted, watch, computed} from 'vue'
|
import {ref, reactive, onMounted, watch, computed} from 'vue'
|
||||||
import {Plus, Setting, Refresh, Search, Lock, Box, House, InfoFilled, Link, Printer, Camera, Picture} from '@element-plus/icons-vue'
|
import {Plus, Setting, Refresh, Search, Lock, Box, House, InfoFilled, Link, Printer, Camera, Picture} from '@element-plus/icons-vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
import {ElMessage, ElLoading} from 'element-plus'
|
import {ElMessage, ElLoading} from 'element-plus'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
@ -673,6 +677,7 @@ const vLoadmore = {
|
|||||||
// 状态与变量
|
// 状态与变量
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
const router = useRouter()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const submitting = ref(false)
|
const submitting = ref(false)
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
@ -1346,6 +1351,20 @@ const handleScannerConfirm = (result: string) => {
|
|||||||
ElMessage.success('序列号已提取')
|
ElMessage.success('序列号已提取')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 快速基于此物料创建 BOM
|
||||||
|
const createBomForMaterial = () => {
|
||||||
|
if (!form.base_id) return ElMessage.warning('请先锁定物料基础信息')
|
||||||
|
const routeUrl = router.resolve({
|
||||||
|
path: '/bom',
|
||||||
|
query: {
|
||||||
|
create_for_id: form.base_id,
|
||||||
|
parent_name: form.material_name,
|
||||||
|
parent_spec: form.spec_model
|
||||||
|
}
|
||||||
|
})
|
||||||
|
window.open(routeUrl.href, '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
const submitForm = async () => {
|
const submitForm = async () => {
|
||||||
if (!formRef.value) return
|
if (!formRef.value) return
|
||||||
await formRef.value.validate(async (valid: boolean) => {
|
await formRef.value.validate(async (valid: boolean) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user