feat: 消息推送自定义模板与独立设置页

后端:
- 新增通知模板表与实体、DTO、Repository、NotificationTemplateService
- 支持 {{variable}} 模板语法,提供模板类型与变量接口
- TelegramNotificationService 改为通过模板渲染发送(ORDER_SUCCESS/ORDER_FAILED/ORDER_FILTERED/CRYPTO_TAIL_SUCCESS/REDEEM_SUCCESS/REDEEM_NO_RETURN)
- 模板 CRUD、重置默认、测试发送接口
- 补全订单过滤相关 i18n key(zh/en/zh-TW)

前端:
- 消息推送设置抽离为独立页 /system-settings/notification
- 系统设置概览改为入口卡片,侧栏增加「消息推送设置」菜单
- NotificationSettingsPage: 机器人配置 + 模板配置双卡片布局(与概览一致)
- 模板配置支持选择类型、编辑内容、变量面板(点击复制、悬停说明)、保存/重置/测试
- 多语言 key 补全(notificationSettings.templates.*、templateTypes.*)

Made-with: Cursor
This commit is contained in:
WrBug
2026-03-02 21:31:45 +08:00
parent 83bc209489
commit e7af4d4821
19 changed files with 2087 additions and 338 deletions
+46 -2
View File
@@ -1,5 +1,5 @@
import axios, { AxiosInstance, AxiosError } from 'axios'
import type { ApiResponse, NotificationConfig, NotificationConfigRequest, NotificationConfigUpdateRequest } from '../types'
import type { ApiResponse, NotificationConfig, NotificationConfigRequest, NotificationConfigUpdateRequest, NotificationTemplate, TemplateTypeInfo, TemplateVariablesResponse } from '../types'
import { getToken, setToken, removeToken } from '../utils'
import { wsManager } from './websocket'
import i18n from '../i18n/config'
@@ -686,7 +686,51 @@ export const apiService = {
* 获取 Telegram Chat IDs
*/
getTelegramChatIds: (data: { botToken: string }) =>
apiClient.post<ApiResponse<string[]>>('/system/notifications/telegram/get-chat-ids', data)
apiClient.post<ApiResponse<string[]>>('/system/notifications/telegram/get-chat-ids', data),
// ==================== 模板相关 API ====================
/**
* 获取所有模板类型
*/
getTemplateTypes: () =>
apiClient.post<ApiResponse<TemplateTypeInfo[]>>('/system/notifications/templates/types', {}),
/**
* 获取所有模板列表
*/
getTemplates: () =>
apiClient.post<ApiResponse<NotificationTemplate[]>>('/system/notifications/templates/list', {}),
/**
* 获取单个模板详情
*/
getTemplateDetail: (data: { templateType: string }) =>
apiClient.post<ApiResponse<NotificationTemplate>>('/system/notifications/templates/detail', data),
/**
* 获取模板可用变量
*/
getTemplateVariables: (data: { templateType: string }) =>
apiClient.post<ApiResponse<TemplateVariablesResponse>>('/system/notifications/templates/variables', data),
/**
* 更新模板
*/
updateTemplate: (data: { templateType: string; templateContent: string }) =>
apiClient.post<ApiResponse<NotificationTemplate>>('/system/notifications/templates/update', data),
/**
* 重置模板为默认
*/
resetTemplate: (data: { templateType: string }) =>
apiClient.post<ApiResponse<NotificationTemplate>>('/system/notifications/templates/reset', data),
/**
* 发送模板测试消息
*/
testTemplate: (data: { templateType: string; templateContent?: string }) =>
apiClient.post<ApiResponse<boolean>>('/system/notifications/templates/test', data)
},
/**