support select dir

This commit is contained in:
Julian Freeman
2026-02-26 13:06:19 -04:00
parent 353a9cb449
commit bdf83f705b

View File

@@ -57,6 +57,14 @@
</div> </div>
<div class="container"> <div class="container">
<div id="file-selector-container" style="margin-bottom: 20px; background: white; padding: 15px; border-radius: 12px; box-shadow: 0 4px 6px rgba(0,0,0,0.05); display: flex; align-items: center; gap: 15px;">
<button id="btnSelectDir" class="btn btn-primary" onclick="pickDirectory()"></button>
<span id="t-label-files" style="font-weight: 600; color: #636e72;"></span>
<select id="fileDropdown" style="flex-grow: 1; padding: 8px 12px; border-radius: 8px; border: 1px solid #ddd; outline: none; cursor: pointer;" onchange="loadSelectedFile(this.value)">
<option value="" disabled selected id="t-select-placeholder"></option>
</select>
</div>
<div id="drop-zone"> <div id="drop-zone">
<p id="t-drop-hint"></p> <p id="t-drop-hint"></p>
<span id="t-click-hint" style="color: #95a5a6;"></span> <span id="t-click-hint" style="color: #95a5a6;"></span>
@@ -86,8 +94,8 @@
<script> <script>
// 内置默认语言 // 内置默认语言
const defaultI18n = { const defaultI18n = {
zh: { name: "简体中文", dropHint: "📂 <b>拖入</b>生成的文件到这里", clickHint: "或者 点击此处手动选择", labelMatch: "一致 (Match)", labelMismatch: "损坏 (Mismatch)", labelMissing: "缺失 (Missing)", labelExtra: "多余 (Extra)", btnExpand: "全部展开", btnCollapse: "全部收起", modeFull: "显示模式:完整清单", modeError: "显示模式:只看异常", loadSuccess: "✅ 已加载:", files: " 个文件" }, zh: { name: "简体中文", dropHint: "📂 <b>拖入</b>生成的文件到这里", clickHint: "或者 点击此处手动选择", labelMatch: "一致 (Match)", labelMismatch: "损坏 (Mismatch)", labelMissing: "缺失 (Missing)", labelExtra: "多余 (Extra)", btnExpand: "全部展开", btnCollapse: "全部收起", modeFull: "显示模式:完整清单", modeError: "显示模式:只看异常", loadSuccess: "✅ 已加载:", files: " 个文件", labelFiles: "切换文件:", selectPlaceholder: "--- 请选择已加载的报告 ---", btnPickDir: "📂 选择结果目录" },
en: { name: "English", dropHint: "📂 <b>Drag</b> your file here", clickHint: "or click to select manually", labelMatch: "Match", labelMismatch: "Mismatch", labelMissing: "Missing", labelExtra: "Extra", btnExpand: "Expand All", btnCollapse: "Collapse All", modeFull: "View: All Files", modeError: "View: Errors Only", loadSuccess: "✅ Loaded: ", files: " files" } en: { name: "English", dropHint: "📂 <b>Drag</b> your file here", clickHint: "or click to select manually", labelMatch: "Match", labelMismatch: "Mismatch", labelMissing: "Missing", labelExtra: "Extra", btnExpand: "Expand All", btnCollapse: "Collapse All", modeFull: "View: All Files", modeError: "View: Errors Only", loadSuccess: "✅ Loaded: ", files: " files", labelFiles: "Switch File:", selectPlaceholder: "--- Select a loaded report ---", btnPickDir: "📂 Open Directory" }
}; };
// 合并外部语言 // 合并外部语言
@@ -95,8 +103,46 @@
let currentLang = 'zh'; let currentLang = 'zh';
let globalData = ""; let globalData = "";
let errorMode = false; let errorMode = false;
let fileHandles = {}; // 存储文件句柄
// 文件夹选择器逻辑 (File System Access API)
async function pickDirectory() {
try {
const directoryHandle = await window.showDirectoryPicker();
const dropdown = document.getElementById('fileDropdown');
dropdown.innerHTML = `<option value="" disabled selected>${allI18n[currentLang].selectPlaceholder}</option>`;
fileHandles = {};
for await (const entry of directoryHandle.values()) {
if (entry.kind === 'file' && entry.name.endsWith('.txt')) {
fileHandles[entry.name] = entry;
const opt = document.createElement('option');
opt.value = entry.name;
opt.innerText = entry.name;
dropdown.appendChild(opt);
}
}
alert(`已成功加载 ${Object.keys(fileHandles).length} 个报告文件。`);
} catch (err) {
if (err.name !== 'AbortError') {
console.error('选择目录失败:', err);
alert('浏览器不支持该功能或选择失败,请确保使用 Chrome/Edge 并授予权限。');
}
}
}
async function loadSelectedFile(fileName) {
const handle = fileHandles[fileName];
if (handle) {
const file = await handle.getFile();
const text = await file.text();
globalData = text;
processData(globalData);
}
}
// 初始化语言选择器 // 初始化语言选择器
const langSelect = document.getElementById('langSelect'); const langSelect = document.getElementById('langSelect');
Object.keys(allI18n).forEach(key => { Object.keys(allI18n).forEach(key => {
const opt = document.createElement('option'); const opt = document.createElement('option');
@@ -121,6 +167,9 @@
document.getElementById('t-label-extra').innerText = t.labelExtra; document.getElementById('t-label-extra').innerText = t.labelExtra;
document.getElementById('t-btn-expand').innerText = t.btnExpand; document.getElementById('t-btn-expand').innerText = t.btnExpand;
document.getElementById('t-btn-collapse').innerText = t.btnCollapse; document.getElementById('t-btn-collapse').innerText = t.btnCollapse;
document.getElementById('t-label-files').innerText = t.labelFiles;
document.getElementById('t-select-placeholder').innerText = t.selectPlaceholder;
document.getElementById('btnSelectDir').innerText = t.btnPickDir;
const filterBtn = document.getElementById('toggleFilterBtn'); const filterBtn = document.getElementById('toggleFilterBtn');
filterBtn.innerText = errorMode ? t.modeError : t.modeFull; filterBtn.innerText = errorMode ? t.modeError : t.modeFull;
filterBtn.className = errorMode ? 'btn btn-danger' : 'btn btn-primary'; filterBtn.className = errorMode ? 'btn btn-danger' : 'btn btn-primary';
@@ -152,6 +201,11 @@
} }
function processData(text) { function processData(text) {
if (!text) return;
// 处理 PowerShell 偶尔可能返回数组或非字符串对象的情况
if (Array.isArray(text)) text = text.join('\n');
if (typeof text !== 'string') text = String(text);
const lines = text.split(/\r?\n/); const lines = text.split(/\r?\n/);
const tree = {}; const tree = {};
const stats = {'=':0, '*':0, '-':0, '+':0}; const stats = {'=':0, '*':0, '-':0, '+':0};