import multiple custom bsod
This commit is contained in:
88
src/App.vue
88
src/App.vue
@@ -165,8 +165,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 隐藏的 BSOD 文件输入框 -->
|
||||
<input type="file" ref="bsodFileInput" @change="handleBsodFileImport" accept=".dmp" style="display: none" />
|
||||
<!-- 隐藏的 BSOD 文件输入框 (添加 multiple) -->
|
||||
<input type="file" ref="bsodFileInput" @change="handleBsodFileImport" accept=".dmp" style="display: none" multiple />
|
||||
|
||||
<div class="bsod-layout">
|
||||
<div class="bsod-list-panel">
|
||||
@@ -178,10 +178,10 @@
|
||||
v-for="file in bsodList"
|
||||
:key="file.path"
|
||||
class="file-item"
|
||||
:class="{ active: selectedBsod?.path === file.path }"
|
||||
:class="{ active: selectedBsod?.path === file.path, imported: !!file.fileRef }"
|
||||
@click="analyzeBsod(file)"
|
||||
>
|
||||
<div class="file-icon">📄</div>
|
||||
<div class="file-icon">{{ file.fileRef ? '📨' : '📄' }}</div>
|
||||
<div class="file-info">
|
||||
<div class="file-name">{{ file.filename }}</div>
|
||||
<div class="file-meta">{{ file.created_time }} · {{ file.size_kb }}KB</div>
|
||||
@@ -320,38 +320,58 @@ async function startScan() {
|
||||
// --- BSOD 功能 ---
|
||||
async function loadMinidumps() { bsodLoading.value = true; try { bsodList.value = await invoke('list_minidumps'); } catch (e) { triggerToast('加载失败', e, 'error'); } finally { bsodLoading.value = false; } }
|
||||
|
||||
async function analyzeBsod(file) { if (bsodAnalyzing.value) return; selectedBsod.value = file; bsodResult.value = null; bsodAnalyzing.value = true; try { bsodResult.value = await invoke('analyze_minidump', { filepath: file.path }); } catch (e) { triggerToast('分析失败', e, 'error'); } finally { bsodAnalyzing.value = false; } }
|
||||
|
||||
// [新增] BSOD 导入功能
|
||||
function triggerBsodImport() { bsodFileInput.value.click(); }
|
||||
function handleBsodFileImport(event) {
|
||||
const file = event.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
// 更新 UI 状态,模拟选中了一个“外部文件”
|
||||
selectedBsod.value = { path: 'external', filename: file.name, created_time: 'Imported', size_kb: Math.round(file.size / 1024) };
|
||||
async function analyzeBsod(file) {
|
||||
if (bsodAnalyzing.value) return;
|
||||
selectedBsod.value = file;
|
||||
bsodResult.value = null;
|
||||
bsodAnalyzing.value = true;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = async (e) => {
|
||||
try {
|
||||
// 将 ArrayBuffer 转换为 Uint8Array (Rust Vec<u8>)
|
||||
const arrayBuffer = e.target.result;
|
||||
try {
|
||||
// 判断是导入的文件还是本地文件
|
||||
if (file.fileRef) {
|
||||
// 导入的文件:读取 ArrayBuffer 并传给后端
|
||||
const arrayBuffer = await file.fileRef.arrayBuffer();
|
||||
const bytes = new Uint8Array(arrayBuffer);
|
||||
const byteArray = Array.from(bytes); // 转换为普通数组以便序列化传输
|
||||
|
||||
const result = await invoke('analyze_minidump_bytes', { fileContent: byteArray });
|
||||
bsodResult.value = result;
|
||||
triggerToast('分析成功', '已完成外部文件解析', 'success');
|
||||
} catch (err) {
|
||||
triggerToast('分析失败', err, 'error');
|
||||
} finally {
|
||||
bsodAnalyzing.value = false;
|
||||
const byteArray = Array.from(bytes);
|
||||
bsodResult.value = await invoke('analyze_minidump_bytes', { fileContent: byteArray });
|
||||
} else {
|
||||
// 本地文件:传路径
|
||||
bsodResult.value = await invoke('analyze_minidump', { filepath: file.path });
|
||||
}
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
event.target.value = '';
|
||||
} catch (e) {
|
||||
triggerToast('分析失败', e, 'error');
|
||||
} finally {
|
||||
bsodAnalyzing.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// [新增] BSOD 导入功能 (支持多选)
|
||||
function triggerBsodImport() { bsodFileInput.value.click(); }
|
||||
function handleBsodFileImport(event) {
|
||||
const files = event.target.files;
|
||||
if (!files || files.length === 0) return;
|
||||
|
||||
let importedCount = 0;
|
||||
// 倒序遍历,这样添加到数组头部后顺序是正确的
|
||||
for (let i = files.length - 1; i >= 0; i--) {
|
||||
const file = files[i];
|
||||
// 构造一个符合列表格式的虚拟对象
|
||||
const newItem = {
|
||||
filename: file.name,
|
||||
// 使用一个特殊的 path 标识,防止 key 冲突
|
||||
path: `imported-${file.name}-${Date.now()}-${i}`,
|
||||
size_kb: Math.round(file.size / 1024),
|
||||
// 使用浏览器读取到的修改时间
|
||||
created_time: new Date(file.lastModified).toLocaleString(),
|
||||
// 关键:保存文件引用,以便点击时读取
|
||||
fileRef: file
|
||||
};
|
||||
bsodList.value.unshift(newItem);
|
||||
importedCount++;
|
||||
}
|
||||
|
||||
triggerToast('导入成功', `已添加 ${importedCount} 个文件到列表`, 'success');
|
||||
event.target.value = ''; // 重置,允许再次导入同名文件
|
||||
}
|
||||
|
||||
watch(currentTab, (newVal) => { if (newVal === 'bsod' && bsodList.value.length === 0) loadMinidumps(); });
|
||||
@@ -443,7 +463,11 @@ body { margin: 0; padding: 0; background-color: #f4f6f9; overflow: hidden; }
|
||||
.bsod-list-panel { background: white; border-radius: 10px; border: 1px solid #eaecf0; overflow-y: auto; }
|
||||
.bsod-detail-panel { background: white; border-radius: 10px; border: 1px solid #eaecf0; padding: 25px; overflow-y: auto; position: relative; }
|
||||
.file-item { padding: 15px; border-bottom: 1px solid #f0f2f5; cursor: pointer; display: flex; gap: 12px; transition: background 0.2s; }
|
||||
.file-item:hover { background: #f8f9fa; } .file-item.active { background: #eafaf1; border-left: 4px solid #2ecc71; }
|
||||
.file-item:hover { background: #f8f9fa; }
|
||||
.file-item.active { background: #eafaf1; border-left: 4px solid #2ecc71; }
|
||||
/* 给导入的文件加一点特殊样式区分(可选) */
|
||||
.file-item.imported .file-name { color: #3498db; }
|
||||
|
||||
.file-icon { font-size: 1.5rem; } .file-name { font-weight: 600; font-size: 0.9rem; color: #2c3e50; margin-bottom: 4px; } .file-meta { font-size: 0.8rem; color: #95a5a6; }
|
||||
.empty-state { padding: 40px; text-align: center; color: #95a5a6; font-size: 0.9rem; line-height: 1.6; }
|
||||
.analyzing-state { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; color: #7f8c8d; }
|
||||
|
||||
Reference in New Issue
Block a user