接入tgbot

This commit is contained in:
mtvpls
2026-06-29 16:40:03 +08:00
parent b1aad6a9bc
commit 5d605710f3
27 changed files with 2079 additions and 11 deletions
+70 -3
View File
@@ -1,6 +1,6 @@
'use client';
import { Bell, Info, Mail, MonitorSmartphone, X } from 'lucide-react';
import { Bell, Info, Mail, MonitorSmartphone, Send, X } from 'lucide-react';
import { createPortal } from 'react-dom';
interface EmailSettingsPanelProps {
@@ -16,6 +16,13 @@ interface EmailSettingsPanelProps {
pushNotificationsSupported: boolean;
pushNotificationsConfigured: boolean;
pushNotificationsBusy: boolean;
telegramEnabled?: boolean;
telegramBound?: boolean;
telegramUsername?: string;
telegramBindCode?: string;
telegramDeepLink?: string;
telegramBindingBusy?: boolean;
onCreateTelegramBindCode?: () => void;
emailSettingsLoading: boolean;
emailSettingsSaving: boolean;
onSave: () => void;
@@ -74,6 +81,13 @@ export function EmailSettingsPanel({
pushNotificationsSupported,
pushNotificationsConfigured,
pushNotificationsBusy,
telegramEnabled,
telegramBound,
telegramUsername,
telegramBindCode,
telegramDeepLink,
telegramBindingBusy,
onCreateTelegramBindCode,
emailSettingsLoading,
emailSettingsSaving,
onSave,
@@ -113,7 +127,7 @@ export function EmailSettingsPanel({
</h3>
<p className='mt-1 text-sm text-gray-500 dark:text-gray-400'>
Telegram Bot
</p>
</div>
<button
@@ -228,6 +242,59 @@ export function EmailSettingsPanel({
</div>
</section>
{telegramEnabled && (
<section className='rounded-2xl border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-800'>
<div className='mb-4 flex items-start gap-3'>
<div className='flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-sky-100 text-sky-600 dark:bg-sky-900/30 dark:text-sky-300'>
<Send className='h-5 w-5' />
</div>
<div className='min-w-0 flex-1'>
<h4 className='text-base font-semibold text-gray-900 dark:text-gray-100'>Telegram Bot </h4>
<p className='mt-1 text-sm text-gray-500 dark:text-gray-400'>
Telegram 使 Telegram
</p>
</div>
</div>
<div className='space-y-3 rounded-xl bg-white p-3 dark:bg-gray-900/70'>
<div className='flex items-center justify-between gap-3 text-sm'>
<span className='text-gray-600 dark:text-gray-400'></span>
<span className={`font-medium ${telegramBound ? 'text-green-600 dark:text-green-400' : 'text-amber-600 dark:text-amber-400'}`}>
{telegramBound ? `已绑定${telegramUsername ? ` @${telegramUsername}` : ''}` : '未绑定'}
</span>
</div>
{!telegramBound && (
<>
{telegramBindCode && (
<div className='rounded-lg bg-sky-50 p-3 text-sm text-sky-800 dark:bg-sky-900/30 dark:text-sky-200'>
<span className='font-mono text-base font-bold'>{telegramBindCode}</span>
<p className='mt-1 text-xs'> Bot /bind {telegramBindCode} Telegram</p>
</div>
)}
<div className='flex gap-2'>
<button
type='button'
onClick={onCreateTelegramBindCode}
disabled={telegramBindingBusy}
className='flex-1 rounded-lg bg-sky-600 px-3 py-2 text-sm font-medium text-white transition-colors hover:bg-sky-700 disabled:cursor-not-allowed disabled:bg-sky-400'
>
{telegramBindingBusy ? '生成中...' : '生成绑定码'}
</button>
{telegramDeepLink && (
<button
type='button'
onClick={() => window.open(telegramDeepLink, '_blank', 'noopener,noreferrer')}
className='flex-1 rounded-lg border border-sky-300 px-3 py-2 text-sm font-medium text-sky-700 transition-colors hover:bg-sky-50 dark:border-sky-700 dark:text-sky-300 dark:hover:bg-sky-900/30'
>
Telegram
</button>
)}
</div>
</>
)}
</div>
</section>
)}
<button
onClick={onSave}
disabled={emailSettingsSaving}
@@ -261,7 +328,7 @@ export function EmailSettingsPanel({
<div className='mt-6 flex gap-2 rounded-xl border border-blue-200 bg-blue-50 p-3 dark:border-blue-800 dark:bg-blue-900/20'>
<Info className='mt-0.5 h-4 w-4 shrink-0 text-blue-600 dark:text-blue-300' />
<p className='text-xs leading-5 text-blue-800 dark:text-blue-200'>
</p>
</div>
</div>
+43
View File
@@ -231,6 +231,12 @@ export const UserMenu: React.FC = () => {
const [emailSettingsMessageType, setEmailSettingsMessageType] = useState<
'success' | 'error' | null
>(null);
const [telegramEnabled, setTelegramEnabled] = useState(false);
const [telegramBound, setTelegramBound] = useState(false);
const [telegramUsername, setTelegramUsername] = useState('');
const [telegramBindCode, setTelegramBindCode] = useState('');
const [telegramDeepLink, setTelegramDeepLink] = useState('');
const [telegramBindingBusy, setTelegramBindingBusy] = useState(false);
// 设备管理状态
const [devices, setDevices] = useState<any[]>([]);
@@ -896,6 +902,14 @@ export const UserMenu: React.FC = () => {
);
setPushNotifications(Boolean(pushData.pushNotifications));
}
const telegramResponse = await fetch('/api/telegram/bind');
if (telegramResponse.ok) {
const telegramData = await telegramResponse.json();
setTelegramEnabled(Boolean(telegramData.enabled));
setTelegramBound(Boolean(telegramData.binding));
setTelegramUsername(telegramData.binding?.telegramUsername || '');
}
} catch (error) {
console.error('加载通知设置失败:', error);
} finally {
@@ -903,6 +917,28 @@ export const UserMenu: React.FC = () => {
}
};
const handleCreateTelegramBindCode = async () => {
setTelegramBindingBusy(true);
setEmailSettingsMessage('');
setEmailSettingsMessageType(null);
try {
const response = await fetch('/api/telegram/bind', { method: 'POST' });
const data = await response.json().catch(() => ({}));
if (!response.ok) {
throw new Error(data.error || '生成 Telegram 绑定码失败');
}
setTelegramBindCode(data.code || '');
setTelegramDeepLink(data.deepLink || '');
setEmailSettingsMessage('Telegram 绑定码已生成,请在 10 分钟内完成绑定');
setEmailSettingsMessageType('success');
} catch (error) {
setEmailSettingsMessage(error instanceof Error ? error.message : '生成 Telegram 绑定码失败');
setEmailSettingsMessageType('error');
} finally {
setTelegramBindingBusy(false);
}
};
const urlBase64ToUint8Array = (base64String: string) => {
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding)
@@ -5276,6 +5312,13 @@ export const UserMenu: React.FC = () => {
pushNotificationsSupported={pushNotificationsSupported}
pushNotificationsConfigured={pushNotificationsConfigured}
pushNotificationsBusy={pushNotificationsBusy}
telegramEnabled={telegramEnabled}
telegramBound={telegramBound}
telegramUsername={telegramUsername}
telegramBindCode={telegramBindCode}
telegramDeepLink={telegramDeepLink}
telegramBindingBusy={telegramBindingBusy}
onCreateTelegramBindCode={handleCreateTelegramBindCode}
emailSettingsLoading={emailSettingsLoading}
emailSettingsSaving={emailSettingsSaving}
onSave={handleSaveEmailSettings}