You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

584 lines
21 KiB
Vue

<template>
<div class="p-2">
<el-row :gutter="20">
<!-- 生产bom树 -->
<el-col :lg="6" :xs="24" style="" v-loading="treeLoading">
<el-card shadow="hover">
<el-input v-model="materialName" placeholder="请输入物料名称" prefix-icon="Search" clearable/>
<el-tree
ref="materialBomTreeRef"
class="mt-2"
node-key="id"
:data="materialBomOptions"
:props="{ label: 'label', children: 'children' }"
:expand-on-click-node="false"
:filter-node-method="filterNode"
highlight-current
default-expand-all
@node-click="handleNodeClick"
/>
</el-card>
</el-col>
<el-col :lg="18" :xs="24" v-loading="loading">
<div>
<el-divider content-position="left">物料</el-divider>
<el-form ref="parentMaterialBomFormRef" label-width="120px">
<el-row>
<el-form-item label="BOM版本" v-if="parentMaterialBomVersion">
{{ parentMaterialBomVersion }}
</el-form-item>
<el-form-item label="父物料类型名称" v-if="parentMaterialTypeName">
{{ parentMaterialTypeName }}
</el-form-item>
<el-form-item label="父物料名称">
{{ parentMaterialName }}
</el-form-item>
</el-row>
</el-form>
</div>
<el-divider content-position="left">子级物料</el-divider>
<transition :enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="子物料类型编号" prop="materialTypeCode" label-width="120px">
<el-input v-model="queryParams.materialTypeCode" placeholder="请输入物料类型编号" clearable
@keyup.enter="handleQuery"/>
</el-form-item>
<el-form-item label="子物料类型名称" prop="materialTypeName" label-width="120px">
<el-input v-model="queryParams.materialTypeName" placeholder="请输入物料类型名称" clearable
@keyup.enter="handleQuery"/>
</el-form-item>
<el-form-item label="子物料名称" prop="materialName" label-width="120px">
<el-input v-model="queryParams.materialName" placeholder="请输入物料名称" clearable
@keyup.enter="handleQuery"/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery"></el-button>
<el-button icon="Refresh" @click="resetQuery"></el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="hover">
<template #header>
<el-row :gutter="10">
<el-col :span="1.5">
<el-button v-has-permi="['mes:materialBom:add']" type="success" plain icon="CircleCheck"
@click="submitBatchSaveMaterialBoms()" :loading="btnLoading">保存
</el-button>
</el-col>
<el-col :span="1.5">
<el-button v-has-permi="['mes:materialBom:add']" type="primary" plain icon="Plus"
@click="handleAdd()" :loading="btnLoading">新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button v-has-permi="['mes:materialBom:remove']" type="danger" plain :disabled="multiple"
icon="Delete" @click="handleDelete()" :loading="btnLoading">
删除
</el-button>
</el-col>
</el-row>
</template>
<el-table :data="materialBomList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center"/>
<el-table-column type="index" width="50" align="center" label="序号"/>
<el-table-column v-if="columns[0].visible" key="materialBomId" label="生产BOM_ID" align="center"
prop="materialBomId" width="110px"/>
<el-table-column v-if="columns[1].visible" key="materialTypeCode" label="子物料类型编号" align="center"
prop="materialTypeCode" :show-overflow-tooltip="true" width="130px"/>
<el-table-column v-if="columns[2].visible" key="materialTypeName" label="子物料类型名称" align="center"
prop="materialTypeName" :show-overflow-tooltip="true" width="130px"/>
<el-table-column v-if="columns[3].visible" key="materialBomVersion" label="BOM版本" align="center"
prop="materialBomVersion" :show-overflow-tooltip="true" width="90px">
<template #default='scope'>
<el-input v-model='scope.row.materialBomVersion'/>
</template>
</el-table-column>
<el-table-column v-if="columns[4].visible" key="materialId" label="子物料ID" align="center"
prop="materialId" :show-overflow-tooltip="true" />
<el-table-column v-if="columns[5].visible" key="materialName" label="子物料名称" align="center"
prop="materialName" :show-overflow-tooltip="true" width="300px">
<template #default='scope'>
<el-input v-model='scope.row.materialName' placeholder='请点击检索物料'
@click='handleMaterialSelect(scope.row)' readonly/>
</template>
</el-table-column>
<el-table-column v-if="columns[6].visible" key="standardAmount" label="子物料数量" align="center"
prop="standardAmount" :show-overflow-tooltip="true" width="100px">
<template #default='scope'>
<el-input v-model='scope.row.standardAmount'/>
</template>
</el-table-column>
<el-table-column v-if="columns[7].visible" key="unitName" label="子物料单位" align="center"
prop="unitName" :show-overflow-tooltip="true" width="100px"/>
</el-table>
<!-- <pagination-->
<!-- v-show="total > 0"-->
<!-- v-model:page="queryParams.pageNum"-->
<!-- v-model:limit="queryParams.pageSize"-->
<!-- :total="total"-->
<!-- @pagination="getList"-->
<!-- />-->
</el-card>
</el-col>
</el-row>
<!-- 添加或修改生产bom配置对话框 -->
<el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="600px" append-to-body
@close="closeDialog">
<el-form ref="materialBomFormRef" :model="form" :rules="rules" label-width="98px">
<el-form-item label="子物料类型" prop='materialTypeId'>
<el-select v-model="form.materialTypeId" placeholder="请选择" style="width:360px">
<el-option
v-for="item in materialTypeOptions"
:key="item.materialTypeId"
:label="item.materialTypeName"
:value="item.materialTypeId"
></el-option>
</el-select>
</el-form-item>
<el-form-item label='BOM版本' prop='materialBomVersion' v-if="parentMaterialId===0">
<el-input v-model='form.materialBomVersion' placeholder='请输入BOM版本' style="width:360px"/>
</el-form-item>
<el-form-item label='子物料ID' prop='materialId' v-if="false">
<el-input v-model='form.materialId' placeholder='' style="width:360px"/>
</el-form-item>
<el-form-item label='子物料名称' prop='materialName'>
<el-input v-model='form.materialName' placeholder='请点击检索物料' @click='handleMaterialSelect(form)'
style="width:360px"/>
</el-form-item>
<el-form-item label='子物料数量' prop='standardAmount'>
<el-input-number v-model='form.standardAmount' :precision="2" :step="0.1" placeholder='请输入子物料数量'
style="width:360px"/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm" :loading="submitLoading"> </el-button>
<el-button @click="cancel()"> </el-button>
</div>
</template>
</el-dialog>
<!-- 添加物料信息对话框 -->
<el-dialog title="选择物料信息" v-model='materialOpen' append-to-body>
<MaterialSelect @selection="handleSelection" ref="materialSelectRef"
:materialTypeId="materialTypeId"
v-if="materialOpen"></MaterialSelect>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitMaterialForm"> </el-button>
<el-button @click="materialOpen = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script setup name="ProdMaterialBom" lang="ts">
import {
materialBomTreeSelect,
listMaterialBomJoinStructure,
addBatchMaterialBom, updateMaterialBom, addMaterialBom, delMaterialBom
} from "@/api/mes/materialBom";
import {MaterialBomVO, MaterialBomForm, MaterialBomQuery} from '@/api/mes/materialBom/types';
import {BaseMaterialTypeVO} from '@/api/mes/baseMaterialType/types';
import MaterialSelect from '@/views/mes/baseMaterialInfo/addMaterial.vue';
import {to} from 'await-to-js';
import {nextTick} from "vue";
const materialTypeId = ref(0);
const router = useRouter();
const {proxy} = getCurrentInstance() as ComponentInternalInstance;
const materialBomList = ref<MaterialBomVO[]>();
const saveMaterialBomList = ref<MaterialBomVO[]>([]);
const treeLoading = ref(false);
const loading = ref(false);
const materialSelectRef = ref();
const materialOpen = ref(false);
const editedRow = ref();
const submitLoading = ref(false);
const btnLoading = ref(false);
const showSearch = ref(true);
const selectedMaterialBoms = ref<MaterialBomVO[]>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
const parentFormDisplay = ref(false);
const childTableTitle = ref('');
const materialName = ref('');
const materialBomOptions = ref<MaterialBomVO[]>([]);
const materialTypeOptions = ref<BaseMaterialTypeVO[]>([]);
const parentMaterialId = ref(1);
const parentParentMaterialId = ref();
const parentMaterialTypeName = ref('');
const parentMaterialName = ref('');
const parentMaterialBomVersion = ref('');
// 列显隐信息
const columns = ref<FieldOption[]>([
{key: 0, label: `生产BOM_ID`, visible: false, children: []},
{key: 1, label: `子物料类型编号`, visible: true, children: []},
{key: 2, label: `子物料类型名称`, visible: true, children: []},
{key: 3, label: `BOM版本`, visible: false, children: []},
{key: 4, label: `子物料ID`, visible: false, children: []},
{key: 5, label: `子物料名称`, visible: true, children: []},
{key: 6, label: `子物料数量`, visible: true, children: []},
{key: 7, label: `子物料单位`, visible: true, children: []}
]);
const materialBomTreeRef = ref<ElTreeInstance>();
const queryFormRef = ref<ElFormInstance>();
const materialBomFormRef = ref<ElFormInstance>();
const formDialogRef = ref<ElDialogInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: MaterialBomForm = {
materialBomId: undefined,
parentId: undefined,
materialId: undefined,
materialName: undefined,
materialTypeId: undefined,
materialBomDesc: undefined,
materialBomVersion: undefined,
ancestors: undefined,
standardAmount: undefined,
topFlag: undefined,
checkType: '1',
projectId: undefined,
assembleTime: undefined,
materialClassfication: undefined,
attachId: undefined,
activeFlag: '1',
remark: undefined,
materialTypeName: undefined,
};
const data = reactive<PageData<MaterialBomForm, MaterialBomQuery>>({
form: {...initFormData},
queryParams: {
materialBomId: undefined,
parentId: undefined,
materialTypeCode: undefined,
materialTypeName: undefined,
materialName: undefined,
materialBomVersion: undefined,
bomStructureParentId: undefined,
params: {}
},
rules: {
materialTypeId: [
{required: true, message: "物料类型不能为空", trigger: "blur"}
],
materialBomVersion: [
{required: true, message: "BOM版本不能为空", trigger: "blur"}
],
materialName: [
{required: true, message: "物料名称不能为空", trigger: "blur"}
],
standardAmount: [
{required: true, message: "子物料数量不能为空", trigger: "blur"}
]
}
});
const {queryParams, form, rules} = toRefs(data);
/** 通过条件过滤节点 */
const filterNode = (value: string, data: any) => {
if (!value) return true;
return data.label?.toLowerCase().includes(value.toLowerCase());
};
/** 根据名称筛选部门树 */
watchEffect(
() => {
materialBomTreeRef.value?.filter(materialName.value);
},
{
flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发此属性控制在DOM元素更新后运行
}
);
/** 查询物料类型bom结构树下拉树结构 */
const getTreeSelect = async () => {
treeLoading.value = true;
loading.value = true;
const res = await materialBomTreeSelect();
// alert(JSON.stringify(res))
materialBomOptions.value = res.data;
//此处的parentid是materialtypeid
columns.value[3].visible = false;
if (queryParams.value.parentId === null || queryParams.value.parentId === undefined) {
const topMaterialBom = materialBomOptions.value.find(item => item.id === 0);
queryParams.value.bomStructureParentId = 1;//赋值结构bom的parentId
queryParams.value.parentId = 0;
parentMaterialId.value = 0;
parentParentMaterialId.value = undefined;
parentMaterialName.value = topMaterialBom.materialName;
// parentParentMaterialTypeName.value = "顶级";
}
if (queryParams.value.parentId === 0) {
columns.value[3].visible = true;
}
nextTick(function () {
materialBomTreeRef.value?.setCurrentKey(queryParams.value.parentId, true);
handleQuery();
})
// const dd = {"id":"1","parentId":-1,"label":"dd"};
// materialTypeOptions.value[0].children.push(dd);
};
/** 查询生产bom列表 */
const getList = async () => {
loading.value = true;
const res = await listMaterialBomJoinStructure(queryParams.value);
materialBomList.value = res.data;
loading.value = false;
treeLoading.value = false;
// total.value = res.total;
};
/** 节点单击事件 */
const handleNodeClick = (data: MaterialBomVO) => {
queryParams.value.bomStructureParentId = data.materialTypeId;
queryParams.value.parentId = data.id;
parentMaterialId.value = data.id;
parentParentMaterialId.value = data.parentId;
parentMaterialName.value = data.materialName;
parentMaterialTypeName.value = data.materialTypeName;
parentMaterialBomVersion.value = data.materialBomVersion;
columns.value[3].visible = false;
if (data.id === 0) {
columns.value[3].visible = true;
}
handleQuery();
};
const clickDisplay = () => {
if (queryParams.value.parentId === 0) {
parentFormDisplay.value = false;
childTableTitle.value = "顶级物料";
} else {
parentFormDisplay.value = true;
childTableTitle.value = "子级物料";
}
};
/** 搜索按钮操作 */
const handleQuery = () => {
// queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
// dateRange.value = ['', ''];
queryFormRef.value?.resetFields();
// queryParams.value.pageNum = 1;
// queryParams.value.parentId = undefined;
// structureBomTreeRef.value?.setCurrentKey(undefined);
handleQuery();
};
/** 删除按钮操作 */
const handleDelete = async (row?: MaterialBomVO) => {
btnLoading.value = true;
const materialBomIds = [];
selectedMaterialBoms.value.forEach(item => {
if (item.materialBomId && item.materialBomId !== '') {
materialBomIds.push(item.materialBomId);
} else {
deleteReset(item);
}
});
if (materialBomIds.length > 0) {
try {
const [err] = await to(proxy?.$modal.confirm('是否确认删除生产BOM编号为"' + materialBomIds + '"的数据项?') as any);
if (!err) {
await delMaterialBom(materialBomIds)
await getTreeSelect();
proxy?.$modal.msgSuccess('删除成功');
}
} catch {
btnLoading.value = false;
}
}
btnLoading.value = false;
};
const deleteReset = (item) => {
item.materialId = undefined;
item.materialName = undefined;
item.materialBomVersion = undefined;
item.standardAmount = undefined;
};
/** 选择条数 */
const handleSelectionChange = (selection: MaterialBomVO[]) => {
selectedMaterialBoms.value = selection.map((item) => item);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 重置操作表单 */
const reset = () => {
form.value = {...initFormData};
materialBomFormRef.value?.resetFields();
};
/** 取消按钮 */
const cancel = () => {
dialog.visible = false;
reset();
};
/** 新增按钮操作 */
const handleAdd = async () => {
reset();
materialTypeOptions.value = Array.from(
new Map(materialBomList.value.map(item => [item['materialTypeId'], item]))
).map(([_, item]) => item);
dialog.visible = true;
dialog.title = '新增';
form.value.parentId = queryParams.value.parentId;
};
/** 提交按钮 */
const submitForm = () => {
materialBomFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
submitLoading.value = true;
try {
form.value.materialBomId ? await updateMaterialBom(form.value) : await addMaterialBom(form.value);
proxy?.$modal.msgSuccess('操作成功');
await getTreeSelect();
dialog.visible = false;
submitLoading.value = false;
} catch {
submitLoading.value = false;
}
// const child = {"id":"1","parentId":-1,"label":"dd"};
// alert(materialTypeOptions.value[0])
// materialTypeOptions.value[0].children.push(dd);
}
});
};
/**
* 关闭用户弹窗
*/
const closeDialog = () => {
dialog.visible = false;
resetForm();
};
/**
* 重置表单
*/
const resetForm = () => {
materialBomFormRef.value?.resetFields();
materialBomFormRef.value?.clearValidate();
form.value.materialBomId = undefined;
form.value.activeFlag = '1';
};
onMounted(() => {
getTreeSelect(); // 初始化物料类型结构bom数据
// initMaterialTypeData();
});
const handleSelection = () => {
// this.ids = selection.map(item => item.materialBomId)
// this.single = selection.length !== 1
// this.multiple = !selection.length
};
const handleMaterialSelect = (row) => {
editedRow.value = row;
materialTypeId.value = row.materialTypeId;
materialOpen.value = true;
};
/** 提交物料信息按钮 */
const submitMaterialForm = () => {
let selectedRow = materialSelectRef.value.tableRef.store.states.currentRow.value;
editedRow.value.materialId = selectedRow.materialId;
editedRow.value.materialName = selectedRow.materialName;
materialOpen.value = false;
};
const submitBatchSaveMaterialBoms = async () => {
try {
btnLoading.value = true;
saveMaterialBomList.value = [];
for (let i = 0; i < materialBomList.value.length; i++) {
let item = materialBomList.value[i];
if (item.materialId) {
if (!item.materialBomVersion && parentMaterialId.value === 0) {
proxy?.$modal.msgWarning('序号为[' + parseInt(i) + 1 + ']请填写BOM版本');
btnLoading.value = false;
return;
}
if (!item.standardAmount) {
proxy?.$modal.msgWarning('序号为[' + parseInt(i) + 1 + '],请填写子物料数量');
btnLoading.value = false;
return;
}
item.parentId = parentMaterialId.value;
saveMaterialBomList.value.push(item);
}
}
if (saveMaterialBomList.value.length <= 0) {
proxy?.$modal.msgWarning('无可保存子级物料');
btnLoading.value = false;
return;
}
await addBatchMaterialBom(saveMaterialBomList.value);
proxy?.$modal.msgSuccess('操作成功');
await getTreeSelect();
btnLoading.value = false;
} catch (e) {
alert(e)
btnLoading.value = false;
}
}
</script>
<style lang="scss" scoped></style>