2026-01-15 16:32:49 +08:00

543 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div v-loading="syncLoading">
<el-form :model="queryParams" label-position="right" inline ref="queryRef" v-show="showSearch" @submit.prevent>
<el-form-item label="母件编码">
<el-input v-model.trim="queryParams.invCode" placeholder="请输入物料编码" />
</el-form-item>
<el-form-item label="子件编码">
<el-input v-model.trim="queryParams.subInvCode" placeholder="请输入物料名称" />
</el-form-item>
<el-form-item>
<el-button icon="search" type="primary" @click="handleQuery">{{ $t('btn.search') }}</el-button>
<el-button icon="refresh" @click="resetQuery">{{ $t('btn.reset') }}</el-button>
</el-form-item>
</el-form>
<!-- 工具区域 -->
<el-row :gutter="15" class="mb10">
<el-col :span="1.5">
<el-col :span="1.5">
<el-button class="tool-box" color="#626aef" icon="Download" @click="handleImport"> 导入
</el-button>
<el-button class="tool-box" color="#00aa00" icon="Upload" @click="handleDownload"> 导出 </el-button>
<el-button type="danger" icon="delete" @click="handleBatchDelete"
:disabled="ids.length === 0">批量删除</el-button>
</el-col>
</el-col>
</el-row>
<vxe-table border="inner" ref="tableRef" :column-config="{ resizable: true }" :expand-config="{
lazy: true,
loadMethod: loadContentMethod,
iconOpen: 'vxe-icon-square-minus-fill',
iconClose: 'vxe-icon-square-plus-fill'
}" :data="dataList" @checkbox-change="handleSelectionChange" @checkbox-all="handleSelectAll">
<vxe-column type="checkbox" width="60" fixed="left"></vxe-column>
<vxe-column type="seq" width="60"></vxe-column>
<vxe-column type="expand" width="80">
<template #content="{ row }">
<vxe-table border size="mini" stripe :data="row.children" @checkbox-change="handleSelectionChange2"
@checkbox-all="handleSelectAll2">
<vxe-column type="checkbox" width="60" fixed="left"></vxe-column>
<vxe-column type="seq" width="60"></vxe-column>
<vxe-column field="subInvCode" title="子件编码"></vxe-column>
<vxe-column field="subInvName" title="子件名称"></vxe-column>
<vxe-column field="iusequantity" title="使用数量"></vxe-column>
<vxe-column field="bomVersion" title="bom版本"></vxe-column>
<vxe-column field="iusequantity" title="操作">
<template #default="{ row }">
<el-button type="success" size="small" icon="edit" title="编辑" @click="handleSubEdit(row)"></el-button>
<el-button type="danger" @click="handleSubDelete(row)" size="small" icon="delete" title="删除" />
</template>
</vxe-column>
</vxe-table>
</template>
</vxe-column>
<vxe-column field="invCode" title="母件编码"></vxe-column>
<vxe-column field="invName" title="母件名称"></vxe-column>
<vxe-column field="bomVersion" title="bom版本"></vxe-column>
<vxe-column field="iusequantity" title="操作">
<template #default="{ row }">
<el-button type="success" size="small" icon="edit" title="编辑" @click="handleEdit(row)"></el-button>
<el-button type="danger" size="small" icon="delete" title="删除" @click="handleDelete(row)"></el-button>
</template>
</vxe-column>
</vxe-table>
<pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</div>
<!-- 主件编辑弹窗 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body draggable
:close-on-click-modal="false">
<el-form ref="editFormRef" :model="formData" :rules="rules" label-width="120px">
<el-form-item label="母件编码" prop="invCode">
<el-input v-model="formData.invCode" placeholder="请输入母件编码" />
</el-form-item>
<el-form-item label="母件名称" prop="invName">
<el-input v-model="formData.invName" placeholder="请输入母件名称" />
</el-form-item>
<el-form-item label="BOM版本" prop="bomVersion">
<el-input v-model="formData.bomVersion" placeholder="请输入BOM版本" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="cancel">{{ $t('btn.cancel') }}</el-button>
<el-button type="primary" @click="submitForm">{{ $t('btn.submit') }}</el-button>
</template>
</el-dialog>
<!-- 子件编辑弹窗 -->
<el-dialog :title="subDialog.title" v-model="subDialog.visible" width="600px" append-to-body draggable
:close-on-click-modal="false">
<el-form ref="subEditFormRef" :model="subFormData" :rules="subRules" label-width="120px">
<el-form-item label="子件编码" prop="subInvCode">
<el-input v-model="subFormData.subInvCode" placeholder="请输入子件编码" />
</el-form-item>
<el-form-item label="子件名称" prop="subInvName">
<el-input v-model="subFormData.subInvName" placeholder="请输入子件名称" />
</el-form-item>
<el-form-item label="使用数量" prop="iusequantity">
<el-input-number v-model="subFormData.iusequantity" :min="0" :precision="2" placeholder="请输入使用数量" />
</el-form-item>
<el-form-item label="BOM版本" prop="bomVersion">
<el-input v-model="subFormData.bomVersion" placeholder="请输入BOM版本" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="cancelSub">{{ $t('btn.cancel') }}</el-button>
<el-button type="primary" @click="submitSubForm">{{ $t('btn.submit') }}</el-button>
</template>
</el-dialog>
<!-- 导入对话框 -->
<el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body draggable
:close-on-click-modal="false">
<span v-if="show">数据正在导入中请稍等</span>
<el-upload name="file" ref="uploadRef" :limit="1" accept=".xlsx,.xls" :headers="upload.headers"
:action="`${upload.url}`" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress"
:on-success="handleFileSuccess" :on-error="handleFileError" :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>仅允许导入xlsxlsx格式文件</span>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline"
@click="importTemplate">下载模板</el-link>
</div>
</template>
</el-upload>
<template #footer>
<el-button @click="upload.open = false">{{ $t('btn.cancel') }}</el-button>
<el-button type="primary" @click="submitFileForm">{{ $t('btn.submit') }}</el-button>
</template>
</el-dialog>
</template>
<script setup name="BaseMaterialBOM">
import { listBaseMaterialBom, GetMonterInvList, GetSonInvList, updateBaseMaterialBom } from '@/api/baseManagement/basematerialBOM.js'
import { addBaseMaterialBom, updateBaseMaterialBom as updateMainBom } from '@/api/baseManagement/basematerialBOM.js'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
const userName = userStore.userName
const { proxy } = getCurrentInstance()
const ids = ref([])
const loading = ref(false)
const showSearch = ref(true)
// 弹窗相关数据
const dialog = reactive({
title: '',
visible: false,
isEdit: false
})
const subDialog = reactive({
title: '',
visible: false,
isEdit: false
})
const formData = ref({})
const subFormData = ref({})
const editFormRef = ref()
const subEditFormRef = ref()
const queryParams = reactive({
invCode: '',
subInvCode: '',
pageNum: 1,
pageSize: 10,
sort: 'createdTime',
sortType: 'desc'
})
const total = ref(0)
const dataList = ref([])
const tableRef = ref() // 添加表格引用
const queryRef = ref()
// 主件表单验证规则
const rules = {
invCode: [
{ required: true, message: '母件编码不能为空', trigger: 'blur' }
],
invName: [
{ required: true, message: '母件名称不能为空', trigger: 'blur' }
],
bomVersion: [
{ required: true, message: 'BOM版本不能为空', trigger: 'blur' }
]
}
// 子件表单验证规则
const subRules = {
subInvCode: [
{ required: true, message: '子件编码不能为空', trigger: 'blur' }
],
subInvName: [
{ required: true, message: '子件名称不能为空', trigger: 'blur' }
],
iusequantity: [
{ required: true, message: '使用数量不能为空', trigger: 'blur' },
{ type: 'number', message: '使用数量必须为数字值', trigger: 'blur' }
],
bomVersion: [
{ required: true, message: 'BOM版本不能为空', trigger: 'blur' }
]
}
// 初始化表单数据
function resetForm() {
formData.value = {
id: undefined,
invCode: '',
invName: '',
bomVersion: '',
createdBy: userName,
updatedBy: userName
}
editFormRef.value?.clearValidate()
}
function resetSubForm() {
subFormData.value = {
id: undefined,
subInvCode: '',
subInvName: '',
iusequantity: 0,
bomVersion: ''
}
subEditFormRef.value?.clearValidate()
}
// 获取数据列表
function getList() {
loading.value = true
GetMonterInvList(queryParams).then((res) => {
const { code, data } = res
if (code == 200) {
dataList.value = data.result
total.value = data.totalNum
loading.value = false
}
})
}
// 获取选中的行数据
function getSelectedRows() {
if (tableRef.value) {
const selectedRows = tableRef.value.getCheckboxRecords()
console.log('选中的行数据:', selectedRows)
return selectedRows
}
return []
}
// 处理单个复选框选中状态变化
function handleSelectionChange() {
const selectedRows = tableRef.value.getCheckboxRecords()
ids.value = selectedRows.map(row => row.id) // 假设有id字段
console.log('当前选中项ID:', ids.value)
}
// 处理全选/取消全选
function handleSelectAll({ records }) {
ids.value = records.map(row => row.id) // 假设有id字段
console.log('全选/取消全选后ID:', ids.value)
}
// 编辑主件
function handleEdit(row) {
resetForm()
const { id, invCode, invName, bomVersion } = row
formData.value = { id, invCode, invName, bomVersion }
dialog.title = '修改主件信息'
dialog.visible = true
dialog.isEdit = true
}
// 编辑子件
function handleSubEdit(row) {
resetSubForm()
const { id, subInvCode, subInvName, iusequantity, bomVersion } = row
subFormData.value = { id, subInvCode, subInvName, iusequantity, bomVersion }
subDialog.title = '修改子件信息'
subDialog.visible = true
subDialog.isEdit = true
}
// 提交主件表单
function submitForm() {
editFormRef.value.validate(valid => {
if (valid) {
if (dialog.isEdit) {
// 更新现有记录
updateBaseMaterialBom(formData.value).then(res => {
if (res.code === 200) {
proxy.$modal.msgSuccess('修改成功')
dialog.visible = false
resetForm()
getList()
}
})
} else {
// 添加新记录
addBaseMaterialBom(formData.value).then(res => {
if (res.code === 200) {
proxy.$modal.msgSuccess('新增成功')
dialog.visible = false
resetForm()
getList()
}
})
}
}
})
}
// 提交子件表单
function submitSubForm() {
subEditFormRef.value.validate(valid => {
if (valid) {
if (subDialog.isEdit) {
// 更新现有记录
updateBaseMaterialBom(subFormData.value).then(res => {
if (res.code === 200) {
proxy.$modal.msgSuccess('修改成功')
subDialog.visible = false
resetSubForm()
// 刷新父级数据
getList()
}
})
} else {
// 添加新记录
// 注意这里可能需要不同的API接口根据实际业务调整
addBaseMaterialBom(subFormData.value).then(res => {
if (res.code === 200) {
proxy.$modal.msgSuccess('新增成功')
subDialog.visible = false
resetSubForm()
getList()
}
})
}
}
})
}
// 取消主件编辑
function cancel() {
dialog.visible = false
resetForm()
}
// 取消子件编辑
function cancelSub() {
subDialog.visible = false
resetSubForm()
}
// 删除子件
function handleSubDelete(row) {
proxy.$modal.confirm('确认删除该子件数据?')
.then(() => {
// 实现删除逻辑
console.log('删除子件数据:', row.id)
// 示例API调用
// return deleteById(row.id)
})
.then(() => {
proxy.$modal.msgSuccess('删除成功')
getList()
})
}
// 删除单行
function handleDelete(row) {
proxy.$modal.confirm('确认删除该条数据?')
.then(() => {
// 实现删除逻辑
console.log('删除行数据:', row.id)
// 示例API调用
// return deleteById(row.id)
})
.then(() => {
proxy.$modal.msgSuccess('删除成功')
getList()
})
}
// 子数据懒加载
function loadContentMethod({ row }) {
return new Promise((resolve) => {
GetSonInvList({ invCode: row.invCode }).then((res) => {
if (res.code === 200) {
row.children = res.data
resolve()
}
})
})
}
function getToken() {
return localStorage.getItem('token') || '';
}
// 导入参数
const upload = reactive({
open: false,
title: '',
// isUploading: false,
updateSupport: 0,
uploadType: 1,
headers: { Authorization: 'Bearer ' + getToken() },
url: import.meta.env.VITE_APP_BASE_API + '/MasterDataManagement/Material/MaterialBom/importData'
})
function handleImport(type) {
upload.title = '导入'
upload.open = true
}
//导出
function handleDownload() {
proxy
.$confirm('是否确定要导出数据吗?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(async () => {
await proxy.downFile('/MasterDataManagement/Material/MaterialBom/exportData', { ...queryParams })
})
}
function submitFileForm() {
proxy.$refs['uploadRef'].submit()
}
//下砸模版
function importTemplate() {
proxy.download('/MasterDataManagement/Material/MaterialBom/importTemplate', '物料类别导入模板')
}
/** 文件上传异常处理 */
const handleFileError = (error, file, fileList) => {
// 修复:使用正确的响应对象
if (error) {
proxy.$message.error('模板导入异常!')
return
}
}
const show = ref(false)
const handleFileUploadProgress = (event, file, fileList) => {
upload.isUploading = true,
show.value = true
}
const dialogVisibleActualAssembly = ref(false)
/** 文件上传成功处理 */
const handleFileSuccess = (response, file, fileList) => {
const { code, msg, data } = response
if (code === 500) {
proxy.$message.error('模板存在异常!')
upload.isUploading = false
proxy.$refs['uploadRef'].clearFiles()
return
}
if (data === -1) {
proxy.$message.error('模板不匹配!')
upload.isUploading = false
proxy.$refs['uploadRef'].clearFiles()
return
}
upload.open = false
getList()
show.value = false
upload.isUploading = false
proxy.$refs['uploadRef'].clearFiles()
dialogVisibleActualAssembly.value = true
}
// 查询
function handleQuery() {
queryParams.pageNum = 1
getList()
}
// 重置查询操作
function resetQuery() {
proxy.resetForm('queryRef')
handleQuery()
}
// 自定义排序
function sortChange(column) {
var sort = undefined
var sortType = undefined
if (column.prop != null && column.order != null) {
sort = column.prop
sortType = column.order
}
queryParams.sort = sort
queryParams.sortType = sortType
handleQuery()
}
/// ======================= 数据同步 =============================
import { SynchERPBOM } from '@/api/erp/baseInteractERP.js'
const throttle = ref(false)
const syncLoading = ref(false)
function handleSync() {
syncLoading.value = true
throttle.value = true
setTimeout(() => {
throttle.value = false
}, 1000 * 60)
SynchERPBOM().then((res) => {
if (res.code === 200) {
proxy.$modal.msgSuccess('同步成功')
handleQuery()
syncLoading.value = false
} else {
proxy.$message.error('同步失败')
}
})
}
/// =================================================================
handleQuery()
</script>