<template>
|
<div class="app-container">
|
<div style="text-align: right; margin-bottom: 10px;">
|
<el-button type="info" plain icon="Upload" @click="handleImport">导入</el-button>
|
<el-button type="warning" plain icon="Download" @click="handleExport"
|
:disabled="selectedRows.length !== 1">导出</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导入对话框 -->
|
<el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
|
<el-upload ref="uploadRef" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url"
|
:disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess"
|
:auto-upload="false" drag>
|
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
<template #tip>
|
<div class="el-upload__tip text-center">
|
<span>仅允许导入xls、xlsx格式文件。</span>
|
</div>
|
</template>
|
</el-upload>
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button type="primary" @click="submitFileForm">确 定</el-button>
|
<el-button @click="upload.open = false">取 消</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive, toRefs, onMounted, getCurrentInstance, defineAsyncComponent } from "vue";
|
import { getToken } from "@/utils/auth";
|
import { listPage, add, update, batchDelete, exportBom } from "@/api/productionManagement/productBom.js";
|
import { useRouter } from 'vue-router'
|
import { ElMessageBox } from 'element-plus'
|
import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.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.id;
|
form.value.productName = product.productName;
|
form.value.productModelName = product.model;
|
}
|
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 handleFileUploadProgress = (event, file, fileList) => {
|
upload.isUploading = true;
|
};
|
|
// 文件上传成功处理
|
const handleFileSuccess = (response, file, fileList) => {
|
upload.open = false;
|
upload.isUploading = false;
|
proxy.$refs["uploadRef"].handleRemove(file);
|
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 showDetail = (row) => {
|
router.push({
|
path: '/productionManagement/productStructureDetail',
|
query: {
|
id: row.id,
|
bomNo: row.bomNo || '',
|
productName: row.productName || '',
|
productModelName: row.productModelName || ''
|
}
|
});
|
};
|
|
onMounted(() => {
|
getList();
|
});
|
</script>
|