fix: 修复搜索跳转弹窗无法打开的问题

- AppMain.vue: 将 router-view 的 key 从 route.fullPath 改为 route.path,避免 query 参数变化导致组件销毁重建
- list.vue: watch 中 router.replace 增加 query 非空判断,防止不必要的 URL 清理
- list.vue: handleEdit 的 nextTick 增加 try-catch 防御性保护
- list.vue: 添加 onUnmounted 调试探针
This commit is contained in:
yueli
2026-08-03 13:25:54 +08:00
parent b84fffbd37
commit 6c7f8dbe61
2 changed files with 38 additions and 27 deletions

View File

@ -1,7 +1,7 @@
<template> <template>
<section class="app-main"> <section class="app-main">
<router-view v-slot="{ Component, route }"> <router-view v-slot="{ Component, route }">
<component :is="Component" :key="route.fullPath" /> <component :is="Component" :key="route.path" />
</router-view> </router-view>
</section> </section>
</template> </template>

View File

@ -711,7 +711,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted, nextTick, computed, watch } from 'vue'; import { ref, reactive, onMounted, onUnmounted, nextTick, computed, watch } from 'vue';
import { Plus, Document, DocumentCopy, Refresh, Setting, Rank, Camera, Download, Bell, CircleCheck, Files, ZoomIn, Delete, Picture, ShoppingCart, Upload } from '@element-plus/icons-vue'; import { Plus, Document, DocumentCopy, Refresh, Setting, Rank, Camera, Download, Bell, CircleCheck, Files, ZoomIn, Delete, Picture, ShoppingCart, Upload } from '@element-plus/icons-vue';
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'; import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
import type { FormInstance, FormRules } from 'element-plus'; import type { FormInstance, FormRules } from 'element-plus';
@ -1392,35 +1392,40 @@ const handleEdit = (row: MaterialBaseVO) => {
dialog.visible = true; dialog.visible = true;
nextTick(() => { nextTick(() => {
const data = JSON.parse(JSON.stringify(row)); console.log("🔍 nextTick 开始执行...");
Object.assign(form.value, data); try {
const data = JSON.parse(JSON.stringify(row));
Object.assign(form.value, data);
// 深拷贝保存原始数据用于脏检查 // 深拷贝保存原始数据用于脏检查
originalForm.value = JSON.parse(JSON.stringify(data)); originalForm.value = JSON.parse(JSON.stringify(data));
if (data.category) { if (data.category) {
const parts = data.category.split('/'); const parts = data.category.split('/');
if (parts.length > 0) { if (parts.length > 0) {
tempCategorySuffix.value = parts.pop() || ''; tempCategorySuffix.value = parts.pop() || '';
tempCategoryPrefix.value = parts; tempCategoryPrefix.value = parts;
} else {
tempCategoryPrefix.value = [];
tempCategorySuffix.value = data.category;
}
} else { } else {
tempCategoryPrefix.value = []; tempCategoryPrefix.value = [];
tempCategorySuffix.value = data.category; tempCategorySuffix.value = '';
} }
} else {
tempCategoryPrefix.value = []; const images = row.generalImage || [];
tempCategorySuffix.value = ''; const manuals = row.generalManual || [];
// 只显示真正的上传文件,备注字段已由 Object.assign 自动回显到 form.productImageRemark / form.manualLinkRemark
const imgFiles = images.filter(u => isInternalFile(u));
const manualFiles = manuals.filter(u => isInternalFile(u));
fileListImage.value = imgFiles.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }));
fileListManual.value = manualFiles.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }));
} catch (error) {
console.error("🚨 抓到凶手了nextTick 内部执行崩溃", error);
} }
const images = row.generalImage || [];
const manuals = row.generalManual || [];
// 只显示真正的上传文件,备注字段已由 Object.assign 自动回显到 form.productImageRemark / form.manualLinkRemark
const imgFiles = images.filter(u => isInternalFile(u));
const manualFiles = manuals.filter(u => isInternalFile(u));
fileListImage.value = imgFiles.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }));
fileListManual.value = manualFiles.map(url => ({ name: url.split('/').pop(), url: getImageUrl(url) }));
}); });
}; };
@ -1963,8 +1968,10 @@ watch(
queryParams.keyword = newKeyword as string; queryParams.keyword = newKeyword as string;
queryParams.searchField = 'all'; queryParams.searchField = 'all';
getList(); getList();
// 清理 URL 参数,防止刷新后重复触发搜索 // 清理 URL 参数,防止刷新后重复触发搜索(仅当 URL 确实带参时才清理,避免触发组件 key 变化)
router.replace({ path: route.path, query: {} }); if (Object.keys(route.query).length > 0) {
router.replace({ path: route.path, query: {} });
}
} }
}, },
{ immediate: true } { immediate: true }
@ -2010,6 +2017,10 @@ onMounted(() => {
}); });
} }
}); });
onUnmounted(() => {
console.warn("💀 警告当前 list.vue 组件被销毁了如果你看到这条日志说明 router.replace 把页面重置了");
});
</script> </script>
<style scoped> <style scoped>