需求背景
页面miTab引用了两个组件A和B, 以tab切换方式显示,在tab页面A提交表单保存成功后跳转到tab页面B,并且tab页面B自动刷新表格列表能显示刚才保存成功的数据
出现的问题
跳转成功了,但是列表没刷新,排查后发现是没有在跳转后调用 tab B 的数据获取函数
解决方案
在页面miTab调用tab B组件的 getData 方法,前提是用 B页面提供注入功能来让父组件能够访问子组件的方法。
主要还得是在父组件中把逻辑处理好
关键代码
- miTab.vue
html
<template>
<div>
<el-tabs :model-value="activeName" @tab-click="handleClick">
<el-tab-pane label="CAD-BOM" name="CAD-BOM">
<CADBOMComponent @a-reuse-success="switchToaTab" />
</el-tab-pane>
<el-tab-pane label="a" name="a" >
<aComponent ref="aComponent"/>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import { ref } from 'vue';
import CADBOMComponent from './CADBOMComponent.vue'; // 导入 CAD-BOM 组件
import aComponent from './aComponent.vue'; // 导入 a 组件
export default {
name: 'part',
components: {
CADBOMComponent,
aComponent
},
setup() {
const activeName = ref('CAD-BOM');
const aComponent = ref(null); // 用于引用 aComponent 实例
const handleClick = (tab, event) => {
activeName.value = tab.props.name;
};
const switchToaTab = () => {
// 当收到子组件的 a-reuse-success 事件时,切换到 a tab
activeName.value = 'a';
if (aComponent.value) {
aComponent.value.getData(); // 直接调用 aComponent 的 getData 方法
}
};
return {
activeName,
handleClick,
switchToaTab,
aComponent
};
}
};
</script>
- aTab
表格表单代码以及其他逻辑处理太多,此处省略一万字...
html
export default {
name: 'aTab',
setup(_,context) {
}
const emit = context.emit;
const MBOMaddEdit = () => {
const data = {
partNo: MBOMForm.partNo,
partRev: MBOMForm.partRev,
name: MBOMForm.name,
cName: MBOMForm.cName,
material: MBOMForm.material,
gauge: MBOMForm.gauge,
massqty: MBOMForm.massqty,
partType: MBOMForm.partType
}
addMBom(data).then(res => {
if (res.code !== 500) {
ElMessage.success('恭喜您,添加成功!')
//通知父组件切换到 MBOM tab
emit('mbom-reuse-success');
} else {
ElMessage.error(res.msg)
}
})
}
- bTab
html
<template>
<div class="part">
<div class="common-query">
<div class="common-query-demo">
<span>零部件名称</span>
<el-input placeholder="请输入零部件名称" v-model="query.name"></el-input>
</div>
<div class="common-query-demo">
<el-button icon="el-icon-search" @click="handleQuery">查询</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery"
style="margin-left: 20px !important;">重置</el-button>
</div>
</div>
<div class="line-body">
<el-button type="primary" class="handle-btn" icon="el-icon-circle-plus-outline"
@click="addEdit">新建</el-button>
<el-button type="primary" class="handle-btn" icon="el-icon-delete" @click="deleteBatch">批量删除</el-button>
<el-table :data="tableData" :max-height="tableHeight" @selection-change="handleSelectionChange" stripe
border>
<el-table-column type="selection" width="55" fixed></el-table-column>
<el-table-column type="index" label="序号" width="50"></el-table-column>
<el-table-column prop="name" label="名称" sortable min-width="100"></el-table-column>
<el-table-column prop="cName" label="中文名称" min-width="100"></el-table-column>
<el-table-column prop="partNo" label="数模号 " min-width="100"></el-table-column>
<el-table-column prop="partRev" label="版本号" min-width="100"></el-table-column>
<el-table-column prop="material" label="材料" min-width="100"></el-table-column>
<el-table-column prop="gauge" label="规格" min-width="100"></el-table-column>
<el-table-column prop="massqty" label="重量" min-width="100"></el-table-column>
<el-table-column prop="partType" label="数据类型" min-width="100"></el-table-column>
<el-table-column prop="status" label="状态" min-width="100">
<template #default="scope">
{{ scope.row.isLock == 0 ? '未锁定' : '已锁定' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="400">
<template #default="scope">
<el-button type="primary" icon="el-icon-view" @click="showTree(scope.row)">树形结构</el-button>
<el-button type="primary" icon="el-icon-view" @click="MBOMMux(scope.row)">MBOM复用</el-button>
<!-- 下载 -->
<el-button type="primary" icon="el-icon-download" @click="download(scope.row)">下载文件</el-button>
<i class="el-icon-delete" @click="deletePart(scope.row)"></i>
</template>
</el-table-column>
</el-table>
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
:current-page="query.pageNum" :page-sizes="[10, 15, 20, 25, 30]" :page-size="query.pageSize"
layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
<el-dialog :title="title" v-model="drawer" width="600px">
<el-form :model="partForm" :rules="rules" ref="partFormsss" label-width="120px" class="demo-partForm">
<el-form-item label="数模号:" prop="partNo">
<el-input v-model="partForm.partNo" clearable></el-input>
</el-form-item>
<el-form-item label="版本号:" prop="partRev">
<el-input v-model="partForm.partRev" clearable></el-input>
</el-form-item>
<el-form-item label="名称:" prop="name">
<el-input v-model="partForm.name" clearable></el-input>
</el-form-item>
<el-form-item label="上级节点:" v-if="partForm.parentName">
<el-input v-model="partForm.parentName" disabled></el-input>
</el-form-item>
<el-form-item label="中文名称:" prop="cName">
<el-input v-model="partForm.cName" clearable></el-input>
</el-form-item>
<el-form-item label="材料:" prop="material">
<el-input v-model="partForm.material" clearable></el-input>
</el-form-item>
<el-form-item label="规格:" prop="gauge">
<el-input v-model="partForm.gauge" clearable></el-input>
</el-form-item>
<el-form-item label="重量:" prop="massqty">
<el-input v-model="partForm.massqty" clearable></el-input>
</el-form-item>
<el-form-item label="数据类型:" prop="partType">
<el-input v-model="partForm.partType" clearable></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="cancelEdit">取 消</el-button>
<el-button type="primary" @click="saveEdit">确 定</el-button>
</span>
</template>
</el-dialog>
</div>
</div>
</template>
<script>
import { reactive, ref, toRefs, unref, onMounted, nextTick, onUnmounted } from 'vue'
import { add, remove, listByPage, listAll, downloadFile } from '@api/pdm/part'
import { addMBom, getMBomDdata } from '@api/pdm/mbom'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useRouter } from 'vue-router'
import axios from 'axios';
export default {
name: 'bTab',
setup() {
// 定义的变量
const state = reactive({
query: {
pageNum: 1,
pageSize: 10,
name: ''
},
statusList: [],
title: '',
drawer: false, // 新建对话框
handleId: '', // 编辑id
// 表数据
tableData: [],
total: 0,
selectList: [],
multipleSelection: []
})
const router = useRouter()
// 通过计算表格距离页面底部的距离来实现表格高自适应
const tableHeight = ref(window.innerHeight - 342)
const partForm = reactive({
partNo: '',
partRev: '',
name: '',
cName: '',
material: '',
gauge: '',
massqty: '',
partType: '',
parentId: '',
parentName: ''
})
const partFormsss = ref(null)
const rules = {
name: [{ required: true, message: "此处为必填项" }],
partNo: [{ required: true, message: "此处为必填项" }],
partRev: [{ required: true, message: "此处为必填项" }]
}
//零部件表格
function getData() {
getMBomDdata(state.query).then(res => {
state.total = res.data.total
state.tableData = res.data.list
})
}
// 新建零部件
const addEdit = () => {
state.drawer = true
partForm.parentName = ''
state.title = '添加零部件'
partForm.parentId = ''
partForm.partNo = ''
partForm.partRev = ''
partForm.name = ''
partForm.cName = ''
partForm.material = ''
partForm.gauge = ''
partForm.massqty = ''
partForm.partType = ''
}
//展示零部件
const showTree = (row) => {
// state.title = '编辑零部件'
// state.drawer = true
// state.btnShow = true
// state.handleId = row.id
// partForm.partNo = row.partNo
// partForm.partRev = row.partRev
// partForm.name = row.name
// partForm.cName = row.cName
// partForm.material = row.cName
// partForm.gauge = row.gauge
// partForm.massqty = row.massqty
// partForm.partType = row.partType
// router.push({path: '/pdm/property?partId='+row.id})
router.push({
path: '/pdm/property',
query: {
id: row.id
}
})
}
//断点续传
// const download = async (row) => {
// const fileName = '11.png'; // 文件名
// const chunkSize = 1024 * 1024; // 分块大小,例如1MB
// let startByte = localStorage.getItem(`${fileName}-downloaded`) || 0;
// const config = {
// responseType: 'blob',
// headers: {
// 'Range': `bytes=${startByte}-${startByte + chunkSize - 1}`,
// },
// };
// try {
// const response = await axios.get('/mes/file/download', config);
// // 直接处理响应,不再依赖于状态码检查
// const url = window.URL.createObjectURL(new Blob([response]));
// const link = document.createElement('a');
// link.href = url;
// link.download = fileName;
// document.body.appendChild(link);
// link.click();
// document.body.removeChild(link);
// // 更新已下载的字节数
// startByte += chunkSize;
// if (startByte < response.size) {
// localStorage.setItem(`${fileName}-downloaded`, startByte);
// } else {
// localStorage.removeItem(`${fileName}-downloaded`);
// }
// } catch (error) {
// console.error('Download error:', error);
// }
// };
const download = async (row) => {
try {
const data = {
id: row.id
}
downloadFile(data).then(response => {
if (response.code && response.code == 500) {
ElMessage.error(response.msg)
} else {
// 创建一个URL表示Blob对象
// const url = window.URL.createObjectURL(new Blob([response]));
const url = '/mes/pdm/cadDownloadPart?id=' + row.id;
// let fileName = response.headers['Content-Disposition'].split('filename=')[1];
// 创建隐藏的可下载链接
const link = document.createElement('a');
link.href = url
link.style.display = 'none';
// 将链接添加到DOM中,然后模拟点击下载
document.body.appendChild(link);
link.click();
// 清理工作,释放URL对象
window.URL.revokeObjectURL(url);
link.remove();
}
})
} catch (error) {
// console.error('下载失败:', error);
// alert('文件不存在或下载过程中出现问题!');
ElMessage.error('下载失败')
}
};
// 新建/编辑零部件
const saveEdit = async () => {
const form = unref(partFormsss)
if (!form) return
try {
await form.validate()
if (state.title == '添加零部件') {
addSavePart()
}
if (state.title == '编辑零部件') {
updateSavePart()
}
state.drawer = false
} catch (error) {
console.error(error)
ElMessage.error('抱歉,您有必填项未填!')
}
}
const addSavePart = () => {
const data = {
partNo: partForm.partNo,
partRev: partForm.partRev,
name: partForm.name,
cName: partForm.cName,
material: partForm.material,
gauge: partForm.gauge,
massqty: partForm.massqty,
partType: partForm.partType,
}
add(data).then(res => {
state.drawer = false
ElMessage.success('恭喜您,添加成功!')
getData()
})
}
const updateSavePart = () => {
const data = {
id: state.handleId,
partNo: partForm.partNo,
partRev: partForm.partRev,
name: partForm.name,
cName: partForm.cName,
material: partForm.material,
gauge: partForm.gauge,
massqty: partForm.massqty,
partType: partForm.partType
}
update(data).then(res => {
state.drawer = false
getData()
ElMessage.success('恭喜您,保存成功!')
})
}
// 删除零部件
const deletePart = (row) => {
const ids = []
ids.push(row.id)
deleteProData(ids)
}
// 调用删除零部件接口
const deleteProData = (data) => {
remove(data).then(res => {
getData(state.query)
ElMessage.success('恭喜您,删除成功!')
})
}
//批量删除零部件
function deleteBatch() {
const sels = state.multipleSelection
if (sels.length != 0) {
// 获取所有选中行的id组成的字符串,以逗号分隔
const strIds = sels.map((item) => item.id).join()
// split() 方法用于把一个字符串分割成字符串数组。
const ids = strIds.split(',')
deleteProData(ids)
// ElMessage.success('您刪除了' + ids + '!')
} else {
ElMessage.error('您当前未选中!')
}
}
// 新建取消
const cancelEdit = () => {
state.drawer = false
setTimeout(() => {
const form = unref(partFormsss)
form.resetFields()
}, 100)
}
const statusFormat = (row) => {
for (let i = 0; i < state.statusList.length; i++) {
if (row == state.statusList[i].dictValue) {
return state.statusList[i].dictLabel
}
}
}
// 批量删除选中
function handleSelectionChange(val) {
state.multipleSelection = val
}
function handleQuery() {
queryEdit(state.query)
}
function resetQuery() {
state.query.name = ''
}
// 查询
function queryEdit(query) {
getData(query)
ElMessage.success('恭喜您,查询成功!')
}
// 分页页数
function handleSizeChange(val) {
state.query.pageSize = val
queryEdit(state.query)
}
function handleCurrentChange(val) {
state.query.pageNum = val
queryEdit(state.query)
}
function getHeight() {
tableHeight.value = window.innerHeight - 342
}
// 页面加载时调用函数
onMounted(() => {
// 注册监听器
window.addEventListener('resize', getHeight)
// 调用函数
getHeight()
getData()
})
onUnmounted(() => {
// 注销监听器
window.removeEventListener('resize', getHeight)
})
return {
...toRefs(state),
tableHeight,
rules,
partFormsss,
partForm,
cancelEdit,
saveEdit,
handleSelectionChange,
handleQuery,
resetQuery,
handleSizeChange,
handleCurrentChange,
showTree,
addEdit,
deletePart,
deleteBatch,
statusFormat,
download,
getData
}
}
}
</script>
<style lang="scss">
.part {
width: 100%;
height: 100%;
.line-body {
height: calc(100% - 120px);
margin-top: 20px;
box-shadow: $box-shadow;
background: #fff;
padding: 20px;
.handle-btn {
min-height: 32px;
height: 32px;
padding: 0 10px;
margin-right: 10px;
}
.el-table {
margin-top: 20px;
td:last-child {
.cell {
display: flex;
justify-content: space-between;
padding: 0 10px;
}
}
.cell {
padding: 0;
.head-url {
height: 36px;
position: relative;
.el-image {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
border-radius: 5px;
}
}
.el-tag {
height: 25px;
line-height: 25px;
padding: 0 7px;
}
}
.el-icon-delete {
cursor: pointer;
color: #EB7A40;
font-size: 22px;
}
.el-icon-delete:hover {
opacity: 0.9;
}
}
}
}
</style>
希望我的解决方案能帮助到遇到同样问题的同学,奥利给!