feat(ui): 优化上传交互与首页样式
This commit is contained in:
parent
f0fb54e41f
commit
b7a9f8da9b
3248
index.html
3248
index.html
File diff suppressed because it is too large
Load Diff
88
js/app.js
88
js/app.js
|
|
@ -720,12 +720,28 @@ function setupEventListeners() {
|
|||
saveCurrentSettings();
|
||||
});
|
||||
|
||||
// 文件上传
|
||||
dropZone.addEventListener('dragover', handleDragOver);
|
||||
dropZone.addEventListener('dragleave', handleDragLeave);
|
||||
dropZone.addEventListener('drop', handleDrop);
|
||||
browseBtn.addEventListener('click', () => { if (!isProcessing) fileInput.click(); });
|
||||
fileInput.addEventListener('change', handleFileSelect);
|
||||
// 文件上传
|
||||
dropZone.addEventListener('dragover', handleDragOver);
|
||||
dropZone.addEventListener('dragleave', handleDragLeave);
|
||||
dropZone.addEventListener('drop', handleDrop);
|
||||
dropZone.addEventListener('click', (event) => {
|
||||
if (isProcessing) return;
|
||||
// 点击上传区空白区域时触发文件选择;避免与内部按钮重复触发。
|
||||
if (event.target.closest('button, a, input, label, select, textarea')) return;
|
||||
if (browseBtn) {
|
||||
browseBtn.click();
|
||||
return;
|
||||
}
|
||||
if (fileInput) {
|
||||
fileInput.click();
|
||||
}
|
||||
});
|
||||
if (browseBtn && fileInput) {
|
||||
browseBtn.addEventListener('click', () => { if (!isProcessing) fileInput.click(); });
|
||||
}
|
||||
if (fileInput) {
|
||||
fileInput.addEventListener('change', handleFileSelect);
|
||||
}
|
||||
if (browseFolderBtn && folderInput) {
|
||||
browseFolderBtn.addEventListener('click', () => { if (!isProcessing) folderInput.click(); });
|
||||
}
|
||||
|
|
@ -1103,14 +1119,14 @@ async function extractFilesFromDataTransfer(dataTransfer) {
|
|||
return fallbackSnapshot;
|
||||
}
|
||||
|
||||
function refreshFormatFilters() {
|
||||
const container = document.getElementById('fileFormatFilters');
|
||||
if (!container) return;
|
||||
const counts = new Map();
|
||||
pdfFiles.forEach(file => {
|
||||
const ext = deriveExtension(file.name || '') || '';
|
||||
counts.set(ext, (counts.get(ext) || 0) + 1);
|
||||
});
|
||||
function refreshFormatFilters() {
|
||||
const container = document.getElementById('fileFormatFilters');
|
||||
if (!container) return;
|
||||
const counts = new Map();
|
||||
pdfFiles.forEach(file => {
|
||||
const ext = deriveExtension(file.name || '') || '';
|
||||
counts.set(ext, (counts.get(ext) || 0) + 1);
|
||||
});
|
||||
// 清理不存在的扩展
|
||||
Array.from(excludedExtensions).forEach(ext => {
|
||||
if (!counts.has(ext)) {
|
||||
|
|
@ -1125,23 +1141,39 @@ function refreshFormatFilters() {
|
|||
|
||||
const fragments = [];
|
||||
const entries = Array.from(counts.entries()).sort((a, b) => a[0].localeCompare(b[0]));
|
||||
entries.forEach(([ext, count]) => {
|
||||
const checked = !isExtensionExcluded(ext) ? 'checked' : '';
|
||||
const label = ext ? ext.toUpperCase() : '未知';
|
||||
// XSS 防护:转义文件扩展名,防止恶意文件名注入
|
||||
const safeExt = escapeHtml(ext);
|
||||
const safeLabel = escapeHtml(label);
|
||||
fragments.push(`
|
||||
<label class="flex items-center space-x-1 bg-white border border-gray-200 rounded px-2 py-1 shadow-sm">
|
||||
<input type="checkbox" class="format-filter-checkbox" data-ext="${safeExt}" ${checked}>
|
||||
<span>${safeLabel} <span class="text-gray-400">(${count})</span></span>
|
||||
</label>
|
||||
entries.forEach(([ext, count]) => {
|
||||
const checked = !isExtensionExcluded(ext) ? 'checked' : '';
|
||||
const label = ext ? ext.toUpperCase() : '未知';
|
||||
// XSS 防护:转义文件扩展名,防止恶意文件名注入
|
||||
const safeExt = escapeHtml(ext);
|
||||
const safeLabel = escapeHtml(label);
|
||||
if ((ext || '').toLowerCase() === 'pdf') {
|
||||
excludedExtensions.delete(ext);
|
||||
fragments.push(`
|
||||
<!--
|
||||
<label class="flex items-center space-x-1 bg-white border border-gray-200 rounded px-2 py-1 shadow-sm">
|
||||
<input type="checkbox" class="format-filter-checkbox" data-ext="${safeExt}" ${checked}>
|
||||
<span>${safeLabel} <span class="text-gray-400">(${count})</span></span>
|
||||
</label>
|
||||
-->
|
||||
`);
|
||||
return;
|
||||
}
|
||||
fragments.push(`
|
||||
<label class="flex items-center space-x-1 bg-white border border-gray-200 rounded px-2 py-1 shadow-sm">
|
||||
<input type="checkbox" class="format-filter-checkbox" data-ext="${safeExt}" ${checked}>
|
||||
<span>${safeLabel} <span class="text-gray-400">(${count})</span></span>
|
||||
</label>
|
||||
`);
|
||||
});
|
||||
|
||||
// fragments.push('<div class="flex-grow"></div><button type="button" id="resetFormatFilters" class="text-xs text-blue-600">重置</button>');
|
||||
container.innerHTML = `<div class="flex flex-wrap gap-2 items-center">${fragments.join('')}</div>`;
|
||||
}
|
||||
// fragments.push('<div class="flex-grow"></div><button type="button" id="resetFormatFilters" class="text-xs text-blue-600">重置</button>');
|
||||
if (fragments.length === 0) {
|
||||
container.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
container.innerHTML = `<div class="flex flex-wrap gap-2 items-center">${fragments.join('')}</div>`;
|
||||
}
|
||||
|
||||
function getActiveFiles() {
|
||||
return pdfFiles.filter(file => {
|
||||
|
|
|
|||
|
|
@ -63,22 +63,22 @@
|
|||
<div class="flex items-center overflow-hidden mr-2">
|
||||
<iconify-icon icon="${icon}" class="${iconColor} mr-2 flex-shrink-0" width="20"></iconify-icon>
|
||||
<span class="flex flex-col overflow-hidden">
|
||||
<span class="text-sm text-gray-800 truncate" title="${displayName}">${displayName}</span>
|
||||
<span class="truncate text-[13px] text-[#999999]" title="${displayName} (${global.formatFileSize(file.size)})">${displayName} (${global.formatFileSize(file.size)})</span>
|
||||
${displayPath && displayPath !== displayName ? `<span class="text-[11px] text-gray-500 truncate" title="${displayPath}">${displayPath}</span>` : ''}
|
||||
</span>
|
||||
${virtualBadge}
|
||||
${isExcluded ? '<span class="ml-2 inline-block text-[10px] px-1.5 py-0.5 rounded bg-gray-200 text-gray-600 flex-shrink-0">已排除</span>' : ''}
|
||||
<span class="text-xs text-gray-500 ml-2 flex-shrink-0">(${global.formatFileSize(file.size)})</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<button data-index="${index}" class="preview-file-btn text-gray-400 hover:text-blue-600 flex-shrink-0" title="预览">
|
||||
<iconify-icon icon="carbon:search" width="16"></iconify-icon>
|
||||
</button>
|
||||
|
||||
<button data-index="${index}" class="remove-file-btn text-gray-400 hover:text-red-600 flex-shrink-0" title="移除">
|
||||
<iconify-icon icon="carbon:close" width="16"></iconify-icon>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
/* <button data-index="${index}" class="preview-file-btn text-gray-400 hover:text-blue-600 flex-shrink-0" title="预览">
|
||||
<iconify-icon icon="carbon:search" width="16"></iconify-icon>
|
||||
</button>*/
|
||||
if (isExcluded) {
|
||||
listItem.classList.add('opacity-60');
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue