feat: 添加 Toast 通知系统,替换所有 alert() 调用

This commit is contained in:
2026-06-20 00:05:56 +08:00
parent a66074e49c
commit 4eaf89219d
5 changed files with 55 additions and 13 deletions
+2 -2
View File
@@ -152,7 +152,7 @@ const NoteEditor = {
*/
async exportPDF() {
if (!this.analysisId) {
alert('请先完成审查再导出 PDF');
showToast('请先完成审查再导出 PDF', 'warning');
return;
}
@@ -189,7 +189,7 @@ const NoteEditor = {
document.body.removeChild(a);
URL.revokeObjectURL(url);
} catch (err) {
alert('PDF 导出失败: ' + err.message);
showToast('PDF 导出失败: ' + err.message, 'error');
} finally {
if (btn) {
btn.disabled = false;
+42
View File
@@ -6,6 +6,48 @@
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="/static/css/style.css">
<script src="/static/js/htmx.min.js"></script>
<style>
.toast-enter { transform: translateX(100%); opacity: 0; }
.toast-active { transform: translateX(0); opacity: 1; transition: transform 0.3s ease, opacity 0.3s ease; }
.toast-exit { transform: translateX(100%); opacity: 0; transition: transform 0.3s ease, opacity 0.3s ease; }
</style>
<script>
// Global toast notification system
(function() {
function ensureContainer() {
var c = document.getElementById('toast-container');
if (!c) {
c = document.createElement('div');
c.id = 'toast-container';
c.className = 'fixed top-4 right-4 z-50 flex flex-col items-end space-y-2';
document.body.appendChild(c);
}
return c;
}
window.showToast = function(message, type) {
type = type || 'info';
var colors = {
success: 'bg-green-50 border-green-200 text-green-800',
error: 'bg-red-50 border-red-200 text-red-800',
info: 'bg-blue-50 border-blue-200 text-blue-800',
warning: 'bg-yellow-50 border-yellow-200 text-yellow-800'
};
var icons = { success: '✓', error: '✗', info: 'ℹ', warning: '⚠' };
var container = ensureContainer();
var el = document.createElement('div');
el.className = 'px-4 py-3 rounded-md border text-sm shadow-lg max-w-sm toast-enter ' + (colors[type] || colors.info);
el.innerHTML = '<span class="mr-2 font-bold">' + (icons[type] || icons.info) + '</span>' +
'<span>' + message + '</span>' +
'<button onclick="this.parentElement.remove()" class="ml-3 text-current opacity-50 hover:opacity-100">&times;</button>';
container.appendChild(el);
requestAnimationFrame(function() { el.className = el.className.replace('toast-enter', 'toast-active'); });
setTimeout(function() {
el.className = el.className.replace('toast-active', 'toast-exit');
setTimeout(function() { el.remove(); }, 300);
}, 4000);
};
})();
</script>
</head>
{{end}}
+4 -4
View File
@@ -191,7 +191,7 @@
const headRef = document.getElementById('head-ref').value;
if (!baseRef || !headRef) {
alert('请选择 Base 和 Head 分支');
showToast('请选择 Base 和 Head 分支', 'warning');
return;
}
@@ -258,7 +258,7 @@
btn.textContent = '生成 PR 描述';
},
error(data) {
alert('生成失败: ' + (data.message || '未知错误'));
showToast('生成失败: ' + (data.message || '未知错误'), 'error');
streaming.classList.add('hidden');
output.classList.add('hidden');
btn.disabled = false;
@@ -275,7 +275,7 @@
function copyMarkdown() {
const markdown = markdownContent || document.getElementById('pr-markdown').textContent;
navigator.clipboard.writeText(markdown).then(() => {
alert('已复制到剪贴板');
showToast('已复制到剪贴板', 'success');
}).catch(() => {
const textarea = document.createElement('textarea');
textarea.value = markdown;
@@ -283,7 +283,7 @@
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
alert('已复制到剪贴板');
showToast('已复制到剪贴板', 'success');
});
}
+3 -3
View File
@@ -405,7 +405,7 @@
const base = document.getElementById('select-base').value;
const head = document.getElementById('select-head').value;
if (!base || !head) {
alert('请选择 Base 和 Head 分支');
showToast('请选择 Base 和 Head 分支', 'warning');
return;
}
DiffViewer.loadDiff(repoId, base, head);
@@ -436,7 +436,7 @@
const base = document.getElementById('select-base').value;
const head = document.getElementById('select-head').value;
if (!base || !head) {
alert('请先选择 Base 和 Head 并查看 Diff');
showToast('请先选择 Base 和 Head 并查看 Diff', 'warning');
return;
}
@@ -499,7 +499,7 @@
viewLink.href = `/repo/${repoId}/review?base=${encodeURIComponent(base)}&head=${encodeURIComponent(head)}`;
},
error(data) {
alert('审查失败: ' + (data.message || '未知错误'));
showToast('审查失败: ' + (data.message || '未知错误'), 'error');
progress.classList.add('hidden');
btn.disabled = false;
btn.textContent = '🤖 AI 评审';
+4 -4
View File
@@ -229,7 +229,7 @@
const topN = document.getElementById('top-n').value;
if (!baseRef || !headRef) {
alert('请选择 Base 和 Head 分支');
showToast('请选择 Base 和 Head 分支', 'warning');
return;
}
@@ -340,7 +340,7 @@
NoteEditor.loadNotes();
},
error(data) {
alert('审查失败: ' + (data.message || '未知错误'));
showToast('审查失败: ' + (data.message || '未知错误'), 'error');
progress.classList.add('hidden');
btn.disabled = false;
btn.textContent = '开始审查';
@@ -471,7 +471,7 @@
const result = data.result;
if (!result || !result.file_reviews) {
alert('该历史记录没有完整的评审数据');
showToast('该历史记录没有完整的评审数据', 'warning');
return;
}
@@ -533,7 +533,7 @@
} catch (e) {
console.error('Load history error:', e);
alert('加载历史评审失败: ' + e.message);
showToast('加载历史评审失败: ' + e.message, 'error');
}
}