style(history): 调整历史列表与操作区样式

This commit is contained in:
肖应宇 2026-04-13 17:56:13 +08:00
parent 8d5af9799c
commit f0fb54e41f
1 changed files with 29 additions and 28 deletions

View File

@ -71,10 +71,10 @@ document.addEventListener('DOMContentLoaded', function() {
const timeStr = `${timeObj.getMonth() + 1}/${timeObj.getDate()} ${String(timeObj.getHours()).padStart(2, '0')}:${String(timeObj.getMinutes()).padStart(2, '0')}`;
return `
<div class="group flex items-center gap-2 px-2 py-1.5 text-[13px] text-[#000f33] hover:bg-[#000f33] hover:text-[#ffffff] transition-colors cursor-pointer rounded-md mx-2 mb-0.5" onclick="showHistoryDetail('${safeId}')" title="${name}\n${timeObj.toLocaleString()}">
<div class="group h-[58px] flex flex-col px-[15px] py-[10px] text-[13px] text-[#666666] hover:bg-[#E6E7EB] transition-colors cursor-pointer rounded-md mb-0.5" onclick="showHistoryDetail('${safeId}')" title="${name}\n${timeObj.toLocaleString()}">
<span class="truncate flex-1">${name}</span>
<span class="text-[10px] text-slate-400 flex-shrink-0 opacity-0 group-hover:opacity-100 transition-opacity">${timeStr}</span>
<span class="text-[12px] text-[#999999] flex-shrink-0 ">${timeStr}</span>
</div>
`;
}).join('');
@ -854,18 +854,18 @@ document.addEventListener('DOMContentLoaded', function() {
function renderFolderListItem({ id, name, count, system }) {
const isActive = historyUIState.activeFolder === id;
const baseClasses = 'group flex items-center justify-between px-2 py-1.5 rounded-lg border transition-colors';
const activeClasses = isActive ? 'border-blue-200 bg-blue-50 text-blue-600' : 'border-transparent hover:bg-gray-100 text-gray-700';
const baseClasses = 'group flex items-center justify-between px-2 py-1.5 rounded-[5px] border transition-colors';
const activeClasses = isActive ? ' bg-[#E4E6EA] text-[#000F33]' : 'border-transparent hover:bg-gray-100 text-[#666666]';
const title = escapeAttr(name || '未命名');
const countBadge = `<span class="ml-2 inline-flex min-w-[1.5rem] justify-center rounded-full bg-gray-100 px-1.5 py-0.5 text-[11px] font-medium text-gray-500">${typeof count === 'number' ? count : 0}</span>`;
const selectButton = `
<button type="button" class="flex-1 text-left text-sm font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-300 focus-visible:ring-offset-1" data-folder-action="select" data-folder-id="${escapeAttr(id)}" title="查看${title}">
<button type="button" class="flex items-center justify-between flex-1 text-left text-sm font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-300 focus-visible:ring-offset-1" data-folder-action="select" data-folder-id="${escapeAttr(id)}" title="查看${title}">
<span>${escapeHtml(name || '未命名')}</span>
${countBadge}
</button>`;
const actionButtons = system ? '' : `
<div class="ml-2 flex items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100">
<button type="button" class="rounded p-1 text-gray-400 hover:text-blue-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-300" data-folder-action="rename" data-folder-id="${escapeAttr(id)}" title="重命名">
<button type="button" class="rounded p-1 text-gray-400 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-300" data-folder-action="rename" data-folder-id="${escapeAttr(id)}" title="重命名">
<iconify-icon icon="carbon:edit" width="14"></iconify-icon>
</button>
<button type="button" class="rounded p-1 text-gray-400 hover:text-red-500 focus:outline-none focus-visible:ring-2 focus-visible:ring-red-300" data-folder-action="delete" data-folder-id="${escapeAttr(id)}" title="删除">
@ -1059,10 +1059,10 @@ document.addEventListener('DOMContentLoaded', function() {
preserve: 'preserve',
flat: 'flat'
};
const ICON_BUTTON_CLASS = 'inline-flex items-center justify-center w-9 h-9 rounded-full border border-slate-200 bg-white text-gray-500 hover:text-blue-600 hover:border-blue-200 transition-colors focus:outline-none focus:ring-2 focus:ring-blue-300 focus:ring-offset-1';
const ICON_BUTTON_CLASS = 'inline-flex items-center justify-center w-9 h-9 text-gray-500 hover:text-[#000F33] hover:border-[#E4E6EA]transition-colors focus:outline-none focus:ring-2 focus:ring-blue-300 focus:ring-offset-1';
const ICON_BUTTON_DANGER_EXTRA = 'hover:text-red-500 hover:border-red-200 focus:ring-red-300';
const ICON_BUTTON_SUCCESS_EXTRA = 'hover:text-emerald-500 hover:border-emerald-200 focus:ring-emerald-300';
const ICON_BUTTON_SUCCESS_EXTRA = '';
// hover:text-emerald-500 hover:border-emerald-200 focus:ring-emerald-300
const historyListElement = document.getElementById('historyList');
if (historyListElement) {
historyListElement.addEventListener('click', handleHistoryListAction);
@ -1222,39 +1222,36 @@ document.addEventListener('DOMContentLoaded', function() {
const escapedRecordId = escapeAttr(record.id || '');
const exportBtnHtml = `
<button type="button" class="${ICON_BUTTON_CLASS}" data-history-action="open-record-export" data-record-id="${escapeAttr(record.id)}" data-target="${configId}" aria-label="配置导出" title="配置导出">
<iconify-icon icon="carbon:share" width="18"></iconify-icon>
导出
</button>`;
const downloadBtnHtml = `
<button type="button" class="${ICON_BUTTON_CLASS} ${ICON_BUTTON_SUCCESS_EXTRA}" onclick="downloadHistoryRecord('${escapedRecordId}')" aria-label="下载记录" title="下载记录">
<iconify-icon icon="carbon:download" width="18"></iconify-icon>
下载
</button>`;
const recordDisplayName = record.name || relativePathLabel || record.id || '历史记录';
const escapedRecordNameAttr = escapeAttr(recordDisplayName);
const deleteBtnHtml = withinBatch ? '' : `
<button type="button" class="${ICON_BUTTON_CLASS} ${ICON_BUTTON_DANGER_EXTRA}" data-history-action="delete-record" data-record-id="${escapedRecordId}" data-record-name="${escapedRecordNameAttr}" aria-label="删除记录" title="删除记录">
<iconify-icon icon="carbon:trash-can" width="18"></iconify-icon>
删除
</button>`;
const startReadingBtnHtml = `
<button type="button" class="inline-flex items-center gap-2 px-3 py-1.5 bg-blue-600 text-white rounded-md shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1" onclick="showHistoryDetail('${escapedRecordId}')">
<iconify-icon icon="carbon:document-view" width="18"></iconify-icon>
<button type="button" class="inline-flex items-center gap-2 px-5 py-2 bg-[#000F33] text-white rounded-md " onclick="showHistoryDetail('${escapedRecordId}')">
<span>开始阅读</span>
</button>`;
const containerClasses = withinBatch
? 'border border-slate-200 rounded-xl p-3 bg-white shadow-sm hover:border-blue-200 transition'
: 'border border-slate-200 rounded-xl p-4 bg-white shadow-sm hover:border-blue-200 hover:shadow-md transition';
? 'rounded-[20px] p-3 bg-[#F8F9FA] hover:border-blue-200 transition'
: 'rounded-[20px] p-4 bg-[#F8F9FA] hover:border-blue-200 transition';
return `
<div class="${containerClasses}" id="history-item-${safeId}" data-record-id="${escapeAttr(record.id)}">
<div class="flex flex-col gap-1">
<div class="flex flex-col gap-3 md:flex-row md:items-start md:justify-between md:gap-4">
<div class="min-w-0">
<div class="text-sm font-semibold text-gray-800 flex flex-wrap items-center gap-2 break-all">
<div class="text-sm text-[#333333] flex flex-wrap items-center gap-2 break-all">
<span>${escapeHtml(record.name || '未命名')}</span> ${statusBadge}
</div>
<div class="text-xs text-gray-500 mt-1">
${timeLabel}${targetLang ? ` · 语言:${escapeHtml(targetLang)}` : ''}
</div>
${(ocrLabel || (transLabel && transLabel !== '未翻译')) ? `
<div class="text-xs text-gray-500">
${ocrLabel ? `OCR${ocrLabel}` : ''}
@ -1269,7 +1266,6 @@ document.addEventListener('DOMContentLoaded', function() {
</div>
<div class="hidden md:flex flex-wrap gap-2 text-xs text-gray-600 justify-end md:text-sm items-center">
${exportBtnHtml}
${startReadingBtnHtml}
${downloadBtnHtml}
${deleteBtnHtml}
</div>
@ -1282,7 +1278,6 @@ document.addEventListener('DOMContentLoaded', function() {
</summary>
<div class="mt-2 flex flex-wrap gap-2 text-xs text-gray-600">
${exportBtnHtml}
${startReadingBtnHtml}
${downloadBtnHtml}
${deleteBtnHtml}
</div>
@ -1290,10 +1285,16 @@ document.addEventListener('DOMContentLoaded', function() {
</div>
<div class="text-xs text-gray-600 break-words">OCR${ocrSnippet}</div>
<div class="text-xs text-gray-600 break-words">翻译${translationSnippet}</div>
<div class="flex flex-wrap items-center gap-2 text-xs text-gray-600 mt-2">
<div class="flex flex-wrap justify-between items-center text-xs text-gray-600">
<div class="text-xs text-gray-500 mt-1">
${timeLabel}${targetLang ? ` · 语言:${escapeHtml(targetLang)}` : ''}
</div>
<div class="flex flex-wrap justify-between items-center gap-3">
<button id="retry-failed-btn-${safeId}" onclick="retryTranslateRecord('${record.id}','failed')" class="px-2 py-1 border border-gray-200 rounded hover:bg-gray-100 ${retryDisabled}">重试失败段</button>
<button id="retry-all-btn-${safeId}" onclick="retryTranslateRecord('${record.id}','all')" class="px-2 py-1 border border-gray-200 rounded hover:bg-gray-100">重新翻译全部</button>
${startReadingBtnHtml}
<span id="retry-status-${safeId}" class="text-xs text-gray-500"></span>
</div>
</div>
${renderExportConfigPanel({
id: configId,
@ -1501,22 +1502,22 @@ document.addEventListener('DOMContentLoaded', function() {
function buildStatusBadge(status) {
if (!status || status.total === 0) {
return '<span class="ml-2 inline-block text-[11px] px-2 py-0.5 rounded bg-gray-100 text-gray-500">未分块</span>';
return '<span class="ml-2 inline-block text-[11px] px-2 py-0.5 rounded bg-[#ffffff] text-gray-500">未分块</span>';
}
// 若没有任何成功块0/total改为“预览中无翻译块”
if (status.success === 0) {
// 结构化翻译下将提示文案替换为“PDF对照”
if (status.isStructured) {
return '<span class="ml-2 inline-block text-[11px] px-2 py-0.5 rounded bg-blue-100 text-blue-700">PDF对照</span>';
return '<span class="ml-2 inline-block text-[11px] px-2 py-0.5 rounded bg-[#ffffff] text-blue-700">PDF对照</span>';
}
return '<span class="ml-2 inline-block text-[11px] px-2 py-0.5 rounded bg-gray-100 text-gray-600">预览中,无翻译块</span>';
return '<span class="ml-2 inline-block text-[11px] px-2 py-0.5 rounded bg-[#ffffff] text-gray-600">预览中,无翻译块</span>';
}
// 有成功也有失败 → 部分失败
if (status.failed > 0) {
return `<span class="ml-2 inline-block text-[11px] px-2 py-0.5 rounded bg-amber-100 text-amber-700">部分失败 ${status.success}/${status.total}</span>`;
return `<span class="ml-2 inline-block text-[11px] px-2 py-0.5 rounded bg-[#ffffff] text-amber-700">部分失败 ${status.success}/${status.total}</span>`;
}
// 全部成功
return `<span class="ml-2 inline-block text-[11px] px-2 py-0.5 rounded bg-green-100 text-green-700">完成 ${status.success}/${status.total}</span>`;
return `<span class="ml-2 inline-block text-[11px] px-2 py-0.5 rounded bg-[#ffffff] text-green-700">完成 ${status.success}/${status.total}</span>`;
}
function buildSnippetText(text) {