<template>
|
<div class="app-container">
|
<div style="text-align: right; margin-bottom: 10px;">
|
<el-button type="info"
|
plain
|
icon="Upload"
|
@click="handleImport"
|
v-hasPermi="['product:bom:import']">导入</el-button>
|
<el-button type="warning"
|
plain
|
icon="Download"
|
@click="handleExport"
|
:disabled="selectedRows.length !== 1"
|
v-hasPermi="['product:bom:export']">导出</el-button>
|
<el-button type="primary"
|
@click="handleAdd">新增</el-button>
|
<el-button type="danger"
|
plain
|
@click="handleBatchDelete"
|
:disabled="selectedRows.length === 0">删除</el-button>
|
</div>
|
<PIMTable rowKey="id"
|
:column="tableColumn"
|
:tableData="tableData"
|
:page="page"
|
:isSelection="true"
|
@selection-change="handleSelectionChange"
|
:tableLoading="tableLoading"
|
@pagination="pagination">
|
<template #detail="{ row }">
|
<el-button type="primary"
|
text
|
@click="showDetail(row)">{{ row.bomNo }}
|
</el-button>
|
</template>
|
</PIMTable>
|
<StructureEdit v-if="showEdit"
|
v-model:show-model="showEdit"
|
:record="currentRow" />
|
<!-- 新增/编辑弹窗 -->
|
<el-dialog v-model="dialogVisible"
|
:title="operationType === 'add' ? '新增BOM' : '编辑BOM'"
|
width="600px"
|
@close="closeDialog">
|
<el-form ref="formRef"
|
:model="form"
|
:rules="rules"
|
label-width="120px">
|
<el-form-item label="产品名称"
|
prop="productModelId">
|
<el-button type="primary"
|
@click="showProductSelectDialog = true">
|
{{ form.productName || '选择产品' }}
|
</el-button>
|
</el-form-item>
|
<el-form-item label="版本号"
|
prop="version">
|
<el-input v-model="form.version"
|
placeholder="请输入版本号"
|
clearable />
|
</el-form-item>
|
<el-form-item label="备注"
|
prop="remark">
|
<el-input v-model="form.remark"
|
type="textarea"
|
:rows="3"
|
placeholder="请输入备注"
|
clearable />
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<el-button @click="closeDialog">取消</el-button>
|
<el-button type="primary"
|
@click="handleSubmit">确定</el-button>
|
</template>
|
</el-dialog>
|
<!-- 产品选择弹窗 -->
|
<ProductSelectDialog v-model="showProductSelectDialog"
|
@confirm="handleProductSelect"
|
single />
|
<!-- BOM导入对话框 -->
|
<ImportDialog ref="uploadRef"
|
v-model="upload.open"
|
:title="upload.title"
|
:action="upload.url"
|
:headers="upload.headers"
|
:disabled="upload.isUploading"
|
:on-progress="handleFileUploadProgress"
|
:on-success="handleFileSuccess"
|
:show-download-template="true"
|
@confirm="submitFileForm"
|
@download-template="handleDownloadTemplate"
|
@close="handleImportClose" />
|
</div>
|
</template>
|
|
<script setup>
|
import {
|
ref,
|
reactive,
|
toRefs,
|
onMounted,
|
getCurrentInstance,
|
defineAsyncComponent,
|
} from "vue";
|
import { getToken } from "@/utils/auth";
|
import {
|
listPage,
|
add,
|
update,
|
batchDelete,
|
exportBom,
|
downloadTemplate,
|
} from "@/api/productionManagement/productBom.js";
|
import { useRouter } from "vue-router";
|
import { ElMessageBox } from "element-plus";
|
import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
|
import ImportDialog from "@/components/Dialog/ImportDialog.vue";
|
|
const router = useRouter();
|
const { proxy } = getCurrentInstance();
|
const StructureEdit = defineAsyncComponent(() =>
|
import("@/views/productionManagement/productStructure/StructureEdit.vue")
|
);
|
|
const tableColumn = ref([
|
{
|
label: "BOM编号",
|
prop: "bomNo",
|
dataType: "slot",
|
slot: "detail",
|
minWidth: 140,
|
},
|
{
|
label: "产品名称",
|
prop: "productName",
|
|
minWidth: 160,
|
},
|
{
|
label: "规格型号",
|
prop: "productModelName",
|
minWidth: 140,
|
},
|
{
|
label: "版本号",
|
prop: "version",
|
width: 100,
|
},
|
{
|
label: "备注",
|
prop: "remark",
|
minWidth: 160,
|
},
|
{
|
dataType: "action",
|
label: "操作",
|
align: "center",
|
fixed: "right",
|
width: 150,
|
operation: [
|
{
|
name: "编辑",
|
type: "text",
|
clickFun: row => {
|
handleEdit(row);
|
},
|
},
|
{
|
name: "删除",
|
type: "danger",
|
link: true,
|
clickFun: row => {
|
handleDelete(row);
|
},
|
},
|
],
|
},
|
]);
|
|
const tableData = ref([]);
|
const tableLoading = ref(false);
|
const showEdit = ref(false);
|
const selectedRows = ref([]);
|
const currentRow = ref({});
|
const dialogVisible = ref(false);
|
const operationType = ref("add"); // add | edit
|
const formRef = ref(null);
|
const showProductSelectDialog = ref(false);
|
|
// BOM导入参数
|
const upload = reactive({
|
// 是否显示弹出层(BOM导入)
|
open: false,
|
// 弹出层标题(BOM导入)
|
title: "",
|
// 是否禁用上传
|
isUploading: false,
|
// 设置上传的请求头部
|
headers: { Authorization: "Bearer " + getToken() },
|
// 上传的地址
|
url: import.meta.env.VITE_APP_BASE_API + "/productBom/uploadBom",
|
});
|
|
const page = reactive({
|
current: 1,
|
size: 10,
|
total: 0,
|
});
|
|
const data = reactive({
|
form: {
|
id: undefined,
|
productName: "",
|
productModelName: "",
|
productModelId: "",
|
remark: "",
|
version: "",
|
},
|
rules: {
|
productModelId: [
|
{ required: true, message: "请选择产品", trigger: "change" },
|
],
|
version: [{ required: true, message: "请输入版本号", trigger: "blur" }],
|
},
|
});
|
|
const { form, rules } = toRefs(data);
|
|
// 表格选择数据
|
const handleSelectionChange = selection => {
|
selectedRows.value = selection;
|
};
|
|
// 分页
|
const pagination = obj => {
|
page.current = obj.page;
|
page.size = obj.limit;
|
getList();
|
};
|
|
// 查询列表
|
const getList = () => {
|
tableLoading.value = true;
|
listPage({
|
current: page.current,
|
size: page.size,
|
})
|
.then(res => {
|
const records = res?.data?.records || [];
|
tableData.value = records;
|
page.total = res?.data?.total || 0;
|
})
|
.catch(err => {
|
console.error("获取列表失败:", err);
|
})
|
.finally(() => {
|
tableLoading.value = false;
|
});
|
};
|
|
// 新增
|
const handleAdd = () => {
|
operationType.value = "add";
|
Object.assign(form.value, {
|
id: undefined,
|
productName: "",
|
productModelName: "",
|
productModelId: "",
|
remark: "",
|
version: "",
|
});
|
dialogVisible.value = true;
|
};
|
|
// 编辑
|
const handleEdit = row => {
|
operationType.value = "edit";
|
Object.assign(form.value, {
|
id: row.id,
|
productName: row.productName || "",
|
productModelName: row.productModelName || "",
|
productModelId: row.productModelId || "",
|
remark: row.remark || "",
|
version: row.version || "",
|
});
|
dialogVisible.value = true;
|
};
|
|
// 删除(单条)
|
const handleDelete = row => {
|
ElMessageBox.confirm("确认删除该BOM?", "提示", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
batchDelete([row.id])
|
.then(() => {
|
proxy.$modal.msgSuccess("删除成功");
|
getList();
|
})
|
.catch(() => {
|
proxy.$modal.msgError("删除失败");
|
});
|
})
|
.catch(() => {});
|
};
|
|
// 批量删除
|
const handleBatchDelete = () => {
|
if (!selectedRows.value.length) {
|
proxy.$modal.msgWarning("请选择数据");
|
return;
|
}
|
const ids = selectedRows.value.map(item => item.id);
|
ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "删除提示", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
batchDelete(ids)
|
.then(() => {
|
proxy.$modal.msgSuccess("删除成功");
|
getList();
|
})
|
.catch(() => {
|
proxy.$modal.msgError("删除失败");
|
});
|
})
|
.catch(() => {});
|
};
|
|
// 产品选择
|
const handleProductSelect = products => {
|
if (products && products.length > 0) {
|
const product = products[0];
|
form.value.productModelId = product.skuId;
|
form.value.productName = product.materialName;
|
form.value.productModelName = product.specification;
|
}
|
showProductSelectDialog.value = false;
|
};
|
|
// 提交表单
|
const handleSubmit = () => {
|
formRef.value.validate(valid => {
|
if (valid) {
|
const payload = { ...form.value };
|
if (operationType.value === "add") {
|
add(payload)
|
.then(() => {
|
proxy.$modal.msgSuccess("新增成功");
|
closeDialog();
|
getList();
|
})
|
.catch(() => {
|
proxy.$modal.msgError("新增失败");
|
});
|
} else {
|
update(payload)
|
.then(() => {
|
proxy.$modal.msgSuccess("修改成功");
|
closeDialog();
|
getList();
|
})
|
.catch(() => {
|
proxy.$modal.msgError("修改失败");
|
});
|
}
|
}
|
});
|
};
|
|
// 关闭弹窗
|
const closeDialog = () => {
|
dialogVisible.value = false;
|
formRef.value?.resetFields();
|
};
|
|
// 导入按钮操作
|
const handleImport = () => {
|
upload.title = "BOM导入";
|
upload.open = true;
|
};
|
|
// 关闭导入对话框时清除文件
|
const handleImportClose = () => {
|
proxy.$refs["uploadRef"].clearFiles();
|
};
|
|
// 文件上传中处理
|
const handleFileUploadProgress = (event, file, fileList) => {
|
upload.isUploading = true;
|
};
|
|
// 文件上传成功处理
|
const handleFileSuccess = (response, file, fileList) => {
|
upload.open = false;
|
upload.isUploading = false;
|
proxy.$refs["uploadRef"].clearFiles();
|
if (response.code === 200) {
|
proxy.$modal.msgSuccess(response.msg || "导入成功");
|
getList();
|
} else {
|
proxy.$alert(
|
"<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" +
|
response.msg +
|
"</div>",
|
"导入结果",
|
{ dangerouslyUseHTMLString: true }
|
);
|
}
|
};
|
|
// 提交上传文件
|
const submitFileForm = () => {
|
proxy.$refs["uploadRef"].submit();
|
};
|
|
// 导出按钮操作
|
const handleExport = () => {
|
if (selectedRows.value.length !== 1) {
|
proxy.$modal.msgWarning("请选择一条数据进行导出");
|
return;
|
}
|
|
const bomId = selectedRows.value[0].id;
|
const fileName = `BOM_${selectedRows.value[0].bomNo || bomId}.xlsx`;
|
|
exportBom(bomId)
|
.then(res => {
|
// 返回的数据是否为空
|
if (!res) {
|
proxy.$modal.msgError("导出失败,返回数据为空");
|
return;
|
}
|
|
const blob = new Blob([res], {
|
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
});
|
const downloadElement = document.createElement("a");
|
const href = window.URL.createObjectURL(blob);
|
|
downloadElement.style.display = "none";
|
downloadElement.href = href;
|
downloadElement.download = fileName;
|
|
document.body.appendChild(downloadElement);
|
downloadElement.click();
|
|
document.body.removeChild(downloadElement);
|
window.URL.revokeObjectURL(href);
|
|
proxy.$modal.msgSuccess("导出成功");
|
})
|
.catch(err => {
|
console.error("导出异常:", err);
|
proxy.$modal.msgError("系统异常,导出失败");
|
});
|
};
|
|
// 下载模板
|
const handleDownloadTemplate = async () => {
|
const res = await downloadTemplate();
|
// 返回的数据是否为空
|
if (!res) {
|
proxy.$modal.msgError("下载失败,返回数据为空");
|
return;
|
}
|
|
const blob = new Blob([res], {
|
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
});
|
const downloadElement = document.createElement("a");
|
const href = window.URL.createObjectURL(blob);
|
|
downloadElement.href = href;
|
downloadElement.download = "BOM模板.xlsx";
|
|
document.body.appendChild(downloadElement);
|
downloadElement.click();
|
|
document.body.removeChild(downloadElement);
|
window.URL.revokeObjectURL(href);
|
|
proxy.$modal.msgSuccess("下载成功");
|
};
|
|
// 查看详情
|
const showDetail = row => {
|
router.push({
|
path: "/productionManagement/productStructureDetail",
|
query: {
|
id: row.id,
|
bomNo: row.bomNo || "",
|
productName: row.productName || "",
|
productModelName: row.productModelName || "",
|
},
|
});
|
};
|
|
onMounted(() => {
|
getList();
|
});
|
</script>
|