feat: 添加 Telegram 通知支持,更新配置和文档

This commit is contained in:
cita
2026-03-03 17:25:27 +08:00
parent cf6b2285fb
commit 9ff138f0b5
13 changed files with 295 additions and 4 deletions
+66
View File
@@ -9,6 +9,8 @@ type RuntimeSettings = {
webhookEnabled: boolean;
barkEnabled: boolean;
serverChanEnabled: boolean;
telegramEnabled: boolean;
telegramChatId: string;
smtpEnabled: boolean;
smtpHost: string;
smtpPort: number;
@@ -18,6 +20,7 @@ type RuntimeSettings = {
smtpFrom: string;
smtpTo: string;
serverChanKeyMasked?: string;
telegramBotTokenMasked?: string;
notifyCooldownSec: number;
};
@@ -28,6 +31,8 @@ export default function NotificationSettings() {
webhookEnabled: true,
barkEnabled: true,
serverChanEnabled: false,
telegramEnabled: false,
telegramChatId: '',
smtpEnabled: false,
smtpHost: '',
smtpPort: 587,
@@ -39,6 +44,7 @@ export default function NotificationSettings() {
});
const [serverChanKey, setServerChanKey] = useState('');
const [telegramBotToken, setTelegramBotToken] = useState('');
const [smtpPass, setSmtpPass] = useState('');
const [loading, setLoading] = useState(true);
const [savingNotify, setSavingNotify] = useState(false);
@@ -67,6 +73,8 @@ export default function NotificationSettings() {
webhookEnabled: runtimeInfo.webhookEnabled ?? true,
barkEnabled: runtimeInfo.barkEnabled ?? true,
serverChanEnabled: !!runtimeInfo.serverChanEnabled,
telegramEnabled: !!runtimeInfo.telegramEnabled,
telegramChatId: runtimeInfo.telegramChatId || '',
smtpEnabled: !!runtimeInfo.smtpEnabled,
smtpHost: runtimeInfo.smtpHost || '',
smtpPort: Number(runtimeInfo.smtpPort) || 587,
@@ -76,6 +84,7 @@ export default function NotificationSettings() {
smtpFrom: runtimeInfo.smtpFrom || '',
smtpTo: runtimeInfo.smtpTo || '',
serverChanKeyMasked: runtimeInfo.serverChanKeyMasked || '',
telegramBotTokenMasked: runtimeInfo.telegramBotTokenMasked || '',
notifyCooldownSec: Number.isFinite(Number(runtimeInfo.notifyCooldownSec))
? Math.max(0, Math.trunc(Number(runtimeInfo.notifyCooldownSec)))
: 300,
@@ -100,6 +109,8 @@ export default function NotificationSettings() {
webhookEnabled: runtime.webhookEnabled,
barkEnabled: runtime.barkEnabled,
serverChanEnabled: runtime.serverChanEnabled,
telegramEnabled: runtime.telegramEnabled,
telegramChatId: runtime.telegramChatId,
smtpEnabled: runtime.smtpEnabled,
smtpHost: runtime.smtpHost,
smtpPort: runtime.smtpPort,
@@ -110,15 +121,18 @@ export default function NotificationSettings() {
notifyCooldownSec: Math.max(0, Math.trunc(Number(runtime.notifyCooldownSec) || 0)),
};
if (serverChanKey.trim()) payload.serverChanKey = serverChanKey.trim();
if (telegramBotToken.trim()) payload.telegramBotToken = telegramBotToken.trim();
if (smtpPass.trim()) payload.smtpPass = smtpPass.trim();
const res = await api.updateRuntimeSettings(payload);
setRuntime((prev) => ({
...prev,
serverChanKeyMasked: res.serverChanKeyMasked || prev.serverChanKeyMasked,
telegramBotTokenMasked: res.telegramBotTokenMasked || prev.telegramBotTokenMasked,
smtpPassMasked: res.smtpPassMasked || prev.smtpPassMasked,
}));
setServerChanKey('');
setTelegramBotToken('');
setSmtpPass('');
toast.success('通知设置已保存');
} catch (err: any) {
@@ -286,6 +300,58 @@ export default function NotificationSettings() {
</div>
</div>
{/* 卡片:Telegram */}
<div className="card animate-slide-up stagger-4" style={{ padding: 24, border: runtime.telegramEnabled ? '1px solid var(--color-primary)' : '1px solid var(--color-border-light)' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
<div style={{ width: 32, height: 32, borderRadius: 8, background: 'var(--color-primary-light)', color: 'var(--color-primary)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<svg width="18" height="18" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 11l18-8-6 18-3-7-9-3z" /></svg>
</div>
<div>
<div style={{ fontWeight: 600, fontSize: 15 }}>Telegram Bot</div>
<div style={{ fontSize: 12, color: 'var(--color-text-muted)' }}>通过 Telegram 机器人推送消息通知</div>
</div>
</div>
<label style={{ display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
<span style={{ fontSize: 13, fontWeight: 500, color: runtime.telegramEnabled ? 'var(--color-primary)' : 'var(--color-text-muted)' }}>启用 Telegram</span>
<input
type="checkbox"
style={{ width: 16, height: 16, cursor: 'pointer' }}
checked={runtime.telegramEnabled}
onChange={(e) => setRuntime((prev) => ({ ...prev, telegramEnabled: e.target.checked }))}
/>
</label>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)', gap: '16px 20px', opacity: runtime.telegramEnabled ? 1 : 0.6, transition: 'opacity 0.2s' }}>
<div>
<div style={{ fontSize: 13, fontWeight: 500, marginBottom: 8, color: 'var(--color-text-secondary)' }}>Telegram Chat ID</div>
<input
value={runtime.telegramChatId}
onChange={(e) => setRuntime((prev) => ({ ...prev, telegramChatId: e.target.value }))}
placeholder="例如: -1001234567890 或 @your_channel"
style={inputStyle}
disabled={!runtime.telegramEnabled}
/>
</div>
<div>
<div style={{ fontSize: 13, fontWeight: 500, marginBottom: 8, color: 'var(--color-text-secondary)' }}>
Telegram Bot Token
{runtime.telegramBotTokenMasked && <span style={{ color: 'var(--color-primary)', marginLeft: 8, fontSize: 12 }}>(当前已设置)</span>}
</div>
<input
type="password"
value={telegramBotToken}
onChange={(e) => setTelegramBotToken(e.target.value)}
placeholder="输入新的 Bot Token(留空则不改)"
style={inputStyle}
disabled={!runtime.telegramEnabled}
/>
</div>
</div>
</div>
{/* 卡片:SMTP 邮件设置 */}
<div className="card animate-slide-up stagger-4" style={{ padding: 24, border: runtime.smtpEnabled ? '1px solid var(--color-primary)' : '1px solid var(--color-border-light)' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 }}>