diff --git a/docs/telegram-bot-setup.md b/docs/telegram-bot-setup.md deleted file mode 100644 index b7ecb6b..0000000 --- a/docs/telegram-bot-setup.md +++ /dev/null @@ -1,98 +0,0 @@ -# Telegram 机器人申请和配置指南 - -## 1. 申请 Telegram 机器人 - -### 步骤 1: 创建机器人 -1. 打开 Telegram,搜索 `@BotFather` -2. 点击开始对话,发送 `/newbot` 命令 -3. 按照提示设置机器人名称(例如:`Polymarket Bot`) -4. 设置机器人用户名(必须以 `bot` 结尾,例如:`polymarket_notification_bot`) -5. BotFather 会返回一个 **Bot Token**,格式类似:`123456789:ABCdefGHIjklMNOpqrsTUVwxyz` - -### 步骤 2: 获取 Chat ID -有两种方式获取 Chat ID: - -#### 方式 1: 通过 @userinfobot -1. 在 Telegram 中搜索 `@userinfobot` -2. 点击开始对话,它会自动返回你的 Chat ID(例如:`123456789`) - -#### 方式 2: 通过 API 获取 -1. 使用你的 Bot Token,访问以下 URL: - ``` - https://api.telegram.org/bot/getUpdates - ``` -2. 向你的机器人发送一条消息(例如:`/start`) -3. 再次访问上面的 URL,在返回的 JSON 中找到 `chat.id` 字段 - -### 步骤 3: 配置环境变量 -将 Bot Token 和 Chat ID 配置到系统环境变量或配置文件中: - -```properties -# Telegram Bot 配置 -telegram.bot.token=YOUR_BOT_TOKEN -telegram.bot.chat-id=YOUR_CHAT_ID -``` - -## 2. 测试机器人 -使用 curl 测试机器人是否正常工作: - -```bash -curl -X POST "https://api.telegram.org/bot/sendMessage" \ - -H "Content-Type: application/json" \ - -d '{ - "chat_id": "", - "text": "测试消息" - }' -``` - -如果返回 `{"ok":true,"result":{...}}`,说明配置成功。 - -## 3. 分享机器人给其他用户 - -### 3.1 分享方式 -机器人创建后是公开的,可以通过以下方式分享: - -1. **分享用户名**:`@your_bot_name` -2. **分享链接**:`https://t.me/your_bot_name` -3. **分享二维码**:在 Telegram 中生成机器人二维码 - -### 3.2 用户添加步骤 -其他用户需要: -1. 点击分享的链接或搜索机器人用户名 -2. 点击"开始"按钮或发送 `/start` 命令 -3. 向机器人发送任意消息(如:`hello`) -4. 获取用户的 Chat ID(见下方说明) - -### 3.3 获取其他用户的 Chat ID -**方式 1: 通过 @userinfobot(推荐)** -- 让用户搜索 `@userinfobot` 并开始对话 -- 机器人会自动返回用户的 Chat ID - -**方式 2: 通过你的机器人获取** -- 用户向你的机器人发送消息后 -- 访问:`https://api.telegram.org/bot/getUpdates` -- 在返回的 JSON 中找到 `message.chat.id` 字段 - -**方式 3: 在代码中实现获取(高级)** -- 实现 Webhook 接收用户消息 -- 从消息中提取 `chat.id` - -### 3.4 多用户配置 -支持多个用户接收通知,配置方式: - -```properties -# 单个用户(旧方式,兼容) -telegram.bot.chat-id=123456789 - -# 多个用户(新方式,推荐) -telegram.bot.chat-ids=123456789,987654321,111222333 -``` - -多个 Chat ID 用逗号分隔。 - -## 4. 安全建议 -- **不要将 Bot Token 提交到 Git**:使用环境变量或配置文件(不提交到版本控制) -- **限制机器人权限**:只允许特定用户使用 -- **定期更换 Token**:如果 Token 泄露,可以通过 BotFather 重新生成 -- **保护 Chat ID**:Chat ID 是私密信息,不要公开分享 - diff --git a/docs/telegram-notification-implementation.md b/docs/telegram-notification-implementation.md deleted file mode 100644 index f884df0..0000000 --- a/docs/telegram-notification-implementation.md +++ /dev/null @@ -1,166 +0,0 @@ -# Telegram 订单通知实现方案 - -## 1. 架构设计 - -### 1.1 整体架构 -``` -订单处理流程 - ↓ -订单成功/失败事件 - ↓ -TelegramNotificationService (异步发送) - ↓ -Telegram Bot API - ↓ -用户 Telegram 客户端 -``` - -### 1.2 核心组件 -1. **TelegramNotificationService**: 负责发送 Telegram 消息 -2. **TelegramConfig**: 配置类,读取 Bot Token 和 Chat ID -3. **订单处理服务集成**: 在订单成功/失败时调用通知服务 - -## 2. 实现方案 - -### 2.1 方案选择 -- **方案 A(推荐)**: 使用 OkHttp 直接调用 Telegram Bot API - - 优点:轻量级,无需额外依赖,项目已有 OkHttp - - 缺点:需要手动处理 API 调用 - -- **方案 B**: 使用 Telegram Bot Java 库(如 `telegrambots`) - - 优点:功能完整,支持更多特性 - - 缺点:增加依赖,可能功能过于复杂 - -**推荐使用方案 A**,因为: -1. 项目已有 OkHttp 依赖 -2. 只需要发送消息功能,不需要接收消息 -3. 减少依赖,保持项目轻量 - -### 2.2 消息格式设计 - -#### 订单成功消息 -``` -✅ 订单创建成功 - -📊 订单信息: -• 订单ID: order_123456 -• 市场: Market Title -• 方向: BUY -• 价格: 0.50 -• 数量: 100 USDC -• 账户: Account 1 (0x1234...5678) - -⏰ 时间: 2024-01-01 12:00:00 -``` - -#### 订单失败消息 -``` -❌ 订单创建失败 - -📊 订单信息: -• 市场: Market Title -• 方向: BUY -• 价格: 0.50 -• 数量: 100 USDC -• 账户: Account 1 (0x1234...5678) - -⚠️ 错误信息: 余额不足 - -⏰ 时间: 2024-01-01 12:00:00 -``` - -### 2.3 集成点设计 - -需要在以下位置集成通知功能: - -1. **CopyOrderTrackingService.createOrder()** - - 订单创建成功时发送成功通知 - - 订单创建失败时发送失败通知 - -2. **AccountService.createPositionSellOrder()** - - 卖出订单成功/失败时发送通知 - -3. **PolymarketClobService.createSignedOrder()** - - 手动订单创建成功/失败时发送通知(可选) - -### 2.4 异步处理 -- 使用 Kotlin Coroutines 异步发送消息 -- 不阻塞订单处理流程 -- 发送失败不影响订单处理结果 - -## 3. 配置设计 - -### 3.1 配置文件 -在 `application.properties` 中添加: - -```properties -# Telegram Bot 配置 -telegram.bot.enabled=true -telegram.bot.token=${TELEGRAM_BOT_TOKEN:} -telegram.bot.chat-id=${TELEGRAM_CHAT_ID:} # 单个用户(兼容旧配置) -telegram.bot.chat-ids=${TELEGRAM_CHAT_IDS:} # 多个用户,逗号分隔(推荐) -telegram.bot.timeout=5000 -``` - -**配置说明**: -- `telegram.bot.chat-id`: 单个用户 Chat ID(兼容旧配置) -- `telegram.bot.chat-ids`: 多个用户 Chat ID,用逗号分隔(如:`123456789,987654321`) -- 如果同时配置了 `chat-id` 和 `chat-ids`,会同时发送给所有用户 - -### 3.2 功能开关 -- 支持通过配置开启/关闭通知功能 -- 如果未配置 Token 或 Chat ID,自动禁用通知 - -## 4. 错误处理 - -### 4.1 发送失败处理 -- 记录错误日志,但不抛出异常 -- 不影响订单处理流程 -- 支持重试机制(可选) - -### 4.2 网络超时 -- 设置合理的超时时间(5秒) -- 超时后记录日志,不重试 - -## 5. 扩展功能(可选) - -### 5.1 消息类型扩展 -- 订单状态变更通知(filled, cancelled) -- 每日统计报告 -- 风险告警通知 - -### 5.2 多用户支持 -- **支持多个 Chat ID**:配置多个用户接收通知 - - 配置格式:`telegram.bot.chat-ids=123456789,987654321,111222333` - - 所有用户都会收到相同的通知 -- **按账户配置不同的通知接收者**(高级功能) - - 在账户表中添加 `telegram_chat_id` 字段 - - 不同账户的订单通知发送给不同的用户 - -### 5.3 消息模板 -- 支持自定义消息模板 -- 支持多语言消息 - -## 6. 实现步骤 - -1. **创建 TelegramNotificationService** - - 实现发送消息方法 - - 实现消息格式化方法 - -2. **创建 TelegramConfig** - - 读取配置 - - 验证配置有效性 - -3. **集成到订单处理服务** - - 在订单成功/失败时调用通知服务 - - 异步发送,不阻塞主流程 - -4. **添加配置项** - - 在 application.properties 中添加配置 - - 支持环境变量 - -5. **测试** - - 单元测试 - - 集成测试 - - 端到端测试 - diff --git a/frontend/src/components/LanguageSwitcher.tsx b/frontend/src/components/LanguageSwitcher.tsx index f2d08df..7c4bd9d 100644 --- a/frontend/src/components/LanguageSwitcher.tsx +++ b/frontend/src/components/LanguageSwitcher.tsx @@ -22,7 +22,9 @@ const LanguageSwitcher: React.FC = () => { const handleChange = async (value: string) => { setCurrentLang(value) await i18n.changeLanguage(value) - // 保存到 localStorage + // 保存到 localStorage(统一使用 i18n_language) + localStorage.setItem('i18n_language', value) + // 同时保存到 i18nextLng(i18next 默认使用的 key,用于兼容) localStorage.setItem('i18nextLng', value) // 刷新页面以应用 Ant Design 的 locale 和所有翻译 window.location.reload() diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index 008803b..4a6b01a 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -27,6 +27,35 @@ const apiClient: AxiosInstance = axios.create({ } }) +/** + * 获取当前语言设置(优先从 localStorage 读取,确保获取最新值) + */ +const getCurrentLanguage = (): string => { + // 优先从 localStorage 读取用户设置的语言(统一使用 i18n_language) + let savedLanguage = localStorage.getItem('i18n_language') + + // 如果 i18n_language 不存在,尝试从 i18nextLng 读取(i18next 默认使用的 key) + if (!savedLanguage) { + savedLanguage = localStorage.getItem('i18nextLng') + } + + // 如果设置了具体语言,使用设置的语言 + if (savedLanguage && savedLanguage !== 'auto' && ['zh-CN', 'zh-TW', 'en'].includes(savedLanguage)) { + return savedLanguage + } + + // 如果设置为 auto 或未设置,使用 i18n 的当前语言 + // 如果 i18n.language 也没有,使用默认值 'en' + const currentLang = i18n.language || 'en' + + // 确保返回的语言格式正确(移除可能的区域代码,如 'en-US' -> 'en') + if (currentLang.startsWith('zh-CN')) return 'zh-CN' + if (currentLang.startsWith('zh-TW') || currentLang.startsWith('zh-HK')) return 'zh-TW' + if (currentLang.startsWith('en')) return 'en' + + return 'en' +} + /** * 请求拦截器 */ @@ -37,8 +66,8 @@ apiClient.interceptors.request.use( if (token) { config.headers.Authorization = `Bearer ${token}` } - // 添加语言 Header - const language = i18n.language || 'en' + // 添加语言 Header(每次请求都获取最新值) + const language = getCurrentLanguage() config.headers['X-Language'] = language return config },