refactor(notification): 优化模板配置布局并完善多语言支持
- 布局优化:模板类型改为顶部Tabs,内容区70%+变量面板30% - 变量Tag UI优化:更精致的样式和悬浮效果 - 多语言:添加模板类型描述、变量label/description的i18n key(三语言) - 后端精简:移除DTO中冗余的label/description/templateTypeName字段 - 清理:移除未使用的templates状态和fetchTemplates方法 Made-with: Cursor
This commit is contained in:
@@ -17,8 +17,6 @@ data class NotificationTemplateDto(
|
||||
*/
|
||||
data class TemplateVariableDto(
|
||||
val key: String, // 变量名,如 account_name
|
||||
val label: String, // 显示名称,如 账户名称
|
||||
val description: String, // 变量说明
|
||||
val category: String, // 分类:common, order, copy_trading, redeem, error
|
||||
val sortOrder: Int = 0 // 排序顺序
|
||||
)
|
||||
@@ -28,7 +26,6 @@ data class TemplateVariableDto(
|
||||
*/
|
||||
data class TemplateVariableCategoryDto(
|
||||
val key: String, // 分类 key
|
||||
val label: String, // 分类名称
|
||||
val sortOrder: Int = 0 // 排序顺序
|
||||
)
|
||||
|
||||
@@ -37,7 +34,6 @@ data class TemplateVariableCategoryDto(
|
||||
*/
|
||||
data class TemplateVariablesResponse(
|
||||
val templateType: String, // 模板类型
|
||||
val templateTypeName: String, // 模板类型名称
|
||||
val categories: List<TemplateVariableCategoryDto>, // 分类列表
|
||||
val variables: List<TemplateVariableDto> // 变量列表
|
||||
)
|
||||
|
||||
+68
-69
@@ -56,104 +56,104 @@ class NotificationTemplateService(
|
||||
|
||||
// 变量分类
|
||||
val VARIABLE_CATEGORIES = listOf(
|
||||
TemplateVariableCategoryDto("common", "通用变量", 0),
|
||||
TemplateVariableCategoryDto("order", "订单变量", 10),
|
||||
TemplateVariableCategoryDto("copy_trading", "跟单变量", 20),
|
||||
TemplateVariableCategoryDto("redeem", "赎回变量", 30),
|
||||
TemplateVariableCategoryDto("error", "错误变量", 40),
|
||||
TemplateVariableCategoryDto("filter", "过滤变量", 50),
|
||||
TemplateVariableCategoryDto("strategy", "策略变量", 60)
|
||||
TemplateVariableCategoryDto("common", 0),
|
||||
TemplateVariableCategoryDto("order", 10),
|
||||
TemplateVariableCategoryDto("copy_trading", 20),
|
||||
TemplateVariableCategoryDto("redeem", 30),
|
||||
TemplateVariableCategoryDto("error", 40),
|
||||
TemplateVariableCategoryDto("filter", 50),
|
||||
TemplateVariableCategoryDto("strategy", 60)
|
||||
)
|
||||
|
||||
// 各模板类型可用的变量
|
||||
val TEMPLATE_VARIABLES = mapOf(
|
||||
"ORDER_SUCCESS" to listOf(
|
||||
// 通用变量
|
||||
TemplateVariableDto("account_name", "账户名称", "执行订单的账户名称", "common", 1),
|
||||
TemplateVariableDto("wallet_address", "钱包地址", "钱包地址(已脱敏)", "common", 2),
|
||||
TemplateVariableDto("time", "时间", "通知发送时间", "common", 3),
|
||||
TemplateVariableDto("account_name", "common", 1),
|
||||
TemplateVariableDto("wallet_address", "common", 2),
|
||||
TemplateVariableDto("time", "common", 3),
|
||||
// 订单变量
|
||||
TemplateVariableDto("order_id", "订单ID", "订单唯一标识", "order", 10),
|
||||
TemplateVariableDto("market_title", "市场标题", "市场/事件名称", "order", 11),
|
||||
TemplateVariableDto("market_link", "市场链接", "Polymarket 市场链接", "order", 12),
|
||||
TemplateVariableDto("side", "方向", "订单方向(买入/卖出)", "order", 13),
|
||||
TemplateVariableDto("outcome", "市场方向", "市场方向(YES/NO 等)", "order", 14),
|
||||
TemplateVariableDto("price", "价格", "订单价格", "order", 15),
|
||||
TemplateVariableDto("quantity", "数量", "订单数量(shares)", "order", 16),
|
||||
TemplateVariableDto("amount", "金额", "订单金额(USDC)", "order", 17),
|
||||
TemplateVariableDto("available_balance", "可用余额", "账户可用余额(USDC)", "order", 18),
|
||||
TemplateVariableDto("order_id", "order", 10),
|
||||
TemplateVariableDto("market_title", "order", 11),
|
||||
TemplateVariableDto("market_link", "order", 12),
|
||||
TemplateVariableDto("side", "order", 13),
|
||||
TemplateVariableDto("outcome", "order", 14),
|
||||
TemplateVariableDto("price", "order", 15),
|
||||
TemplateVariableDto("quantity", "order", 16),
|
||||
TemplateVariableDto("amount", "order", 17),
|
||||
TemplateVariableDto("available_balance", "order", 18),
|
||||
// 跟单变量
|
||||
TemplateVariableDto("leader_name", "Leader 名称", "跟单的 Leader 名称/备注", "copy_trading", 21),
|
||||
TemplateVariableDto("config_name", "跟单配置名", "跟单配置名称", "copy_trading", 22)
|
||||
TemplateVariableDto("leader_name", "copy_trading", 21),
|
||||
TemplateVariableDto("config_name", "copy_trading", 22)
|
||||
),
|
||||
"ORDER_FAILED" to listOf(
|
||||
// 通用变量
|
||||
TemplateVariableDto("account_name", "账户名称", "执行订单的账户名称", "common", 1),
|
||||
TemplateVariableDto("wallet_address", "钱包地址", "钱包地址(已脱敏)", "common", 2),
|
||||
TemplateVariableDto("time", "时间", "通知发送时间", "common", 3),
|
||||
TemplateVariableDto("account_name", "common", 1),
|
||||
TemplateVariableDto("wallet_address", "common", 2),
|
||||
TemplateVariableDto("time", "common", 3),
|
||||
// 订单变量
|
||||
TemplateVariableDto("market_title", "市场标题", "市场/事件名称", "order", 10),
|
||||
TemplateVariableDto("market_link", "市场链接", "Polymarket 市场链接", "order", 11),
|
||||
TemplateVariableDto("side", "方向", "订单方向(买入/卖出)", "order", 12),
|
||||
TemplateVariableDto("outcome", "市场方向", "市场方向(YES/NO 等)", "order", 13),
|
||||
TemplateVariableDto("price", "价格", "订单价格", "order", 14),
|
||||
TemplateVariableDto("quantity", "数量", "订单数量(shares)", "order", 15),
|
||||
TemplateVariableDto("amount", "金额", "订单金额(USDC)", "order", 16),
|
||||
TemplateVariableDto("market_title", "order", 10),
|
||||
TemplateVariableDto("market_link", "order", 11),
|
||||
TemplateVariableDto("side", "order", 12),
|
||||
TemplateVariableDto("outcome", "order", 13),
|
||||
TemplateVariableDto("price", "order", 14),
|
||||
TemplateVariableDto("quantity", "order", 15),
|
||||
TemplateVariableDto("amount", "order", 16),
|
||||
// 错误变量
|
||||
TemplateVariableDto("error_message", "错误信息", "订单失败原因", "error", 20)
|
||||
TemplateVariableDto("error_message", "error", 20)
|
||||
),
|
||||
"ORDER_FILTERED" to listOf(
|
||||
// 通用变量
|
||||
TemplateVariableDto("account_name", "账户名称", "执行订单的账户名称", "common", 1),
|
||||
TemplateVariableDto("wallet_address", "钱包地址", "钱包地址(已脱敏)", "common", 2),
|
||||
TemplateVariableDto("time", "时间", "通知发送时间", "common", 3),
|
||||
TemplateVariableDto("account_name", "common", 1),
|
||||
TemplateVariableDto("wallet_address", "common", 2),
|
||||
TemplateVariableDto("time", "common", 3),
|
||||
// 订单变量
|
||||
TemplateVariableDto("market_title", "市场标题", "市场/事件名称", "order", 10),
|
||||
TemplateVariableDto("market_link", "市场链接", "Polymarket 市场链接", "order", 11),
|
||||
TemplateVariableDto("side", "方向", "订单方向(买入/卖出)", "order", 12),
|
||||
TemplateVariableDto("outcome", "市场方向", "市场方向(YES/NO 等)", "order", 13),
|
||||
TemplateVariableDto("price", "价格", "订单价格", "order", 14),
|
||||
TemplateVariableDto("quantity", "数量", "订单数量(shares)", "order", 15),
|
||||
TemplateVariableDto("amount", "金额", "订单金额(USDC)", "order", 16),
|
||||
TemplateVariableDto("market_title", "order", 10),
|
||||
TemplateVariableDto("market_link", "order", 11),
|
||||
TemplateVariableDto("side", "order", 12),
|
||||
TemplateVariableDto("outcome", "order", 13),
|
||||
TemplateVariableDto("price", "order", 14),
|
||||
TemplateVariableDto("quantity", "order", 15),
|
||||
TemplateVariableDto("amount", "order", 16),
|
||||
// 过滤变量
|
||||
TemplateVariableDto("filter_type", "过滤类型", "订单被过滤的类型", "filter", 20),
|
||||
TemplateVariableDto("filter_reason", "过滤原因", "订单被过滤的详细原因", "filter", 21)
|
||||
TemplateVariableDto("filter_type", "filter", 20),
|
||||
TemplateVariableDto("filter_reason", "filter", 21)
|
||||
),
|
||||
"CRYPTO_TAIL_SUCCESS" to listOf(
|
||||
// 通用变量
|
||||
TemplateVariableDto("account_name", "账户名称", "执行订单的账户名称", "common", 1),
|
||||
TemplateVariableDto("wallet_address", "钱包地址", "钱包地址(已脱敏)", "common", 2),
|
||||
TemplateVariableDto("time", "时间", "通知发送时间", "common", 3),
|
||||
TemplateVariableDto("account_name", "common", 1),
|
||||
TemplateVariableDto("wallet_address", "common", 2),
|
||||
TemplateVariableDto("time", "common", 3),
|
||||
// 订单变量
|
||||
TemplateVariableDto("order_id", "订单ID", "订单唯一标识", "order", 10),
|
||||
TemplateVariableDto("market_title", "市场标题", "市场/事件名称", "order", 11),
|
||||
TemplateVariableDto("market_link", "市场链接", "Polymarket 市场链接", "order", 12),
|
||||
TemplateVariableDto("side", "方向", "订单方向(买入/卖出)", "order", 13),
|
||||
TemplateVariableDto("outcome", "市场方向", "市场方向(YES/NO 等)", "order", 14),
|
||||
TemplateVariableDto("price", "价格", "订单价格", "order", 15),
|
||||
TemplateVariableDto("quantity", "数量", "订单数量(shares)", "order", 16),
|
||||
TemplateVariableDto("amount", "金额", "订单金额(USDC)", "order", 17),
|
||||
TemplateVariableDto("order_id", "order", 10),
|
||||
TemplateVariableDto("market_title", "order", 11),
|
||||
TemplateVariableDto("market_link", "order", 12),
|
||||
TemplateVariableDto("side", "order", 13),
|
||||
TemplateVariableDto("outcome", "order", 14),
|
||||
TemplateVariableDto("price", "order", 15),
|
||||
TemplateVariableDto("quantity", "order", 16),
|
||||
TemplateVariableDto("amount", "order", 17),
|
||||
// 策略变量
|
||||
TemplateVariableDto("strategy_name", "策略名称", "加密价差策略名称", "strategy", 20)
|
||||
TemplateVariableDto("strategy_name", "strategy", 20)
|
||||
),
|
||||
"REDEEM_SUCCESS" to listOf(
|
||||
// 通用变量
|
||||
TemplateVariableDto("account_name", "账户名称", "执行赎回的账户名称", "common", 1),
|
||||
TemplateVariableDto("wallet_address", "钱包地址", "钱包地址(已脱敏)", "common", 2),
|
||||
TemplateVariableDto("time", "时间", "通知发送时间", "common", 3),
|
||||
TemplateVariableDto("account_name", "common", 1),
|
||||
TemplateVariableDto("wallet_address", "common", 2),
|
||||
TemplateVariableDto("time", "common", 3),
|
||||
// 赎回变量
|
||||
TemplateVariableDto("transaction_hash", "交易哈希", "赎回交易的哈希值", "redeem", 10),
|
||||
TemplateVariableDto("total_value", "赎回总价值", "赎回的总价值(USDC)", "redeem", 11),
|
||||
TemplateVariableDto("available_balance", "可用余额", "账户可用余额(USDC)", "redeem", 12)
|
||||
TemplateVariableDto("transaction_hash", "redeem", 10),
|
||||
TemplateVariableDto("total_value", "redeem", 11),
|
||||
TemplateVariableDto("available_balance", "redeem", 12)
|
||||
),
|
||||
"REDEEM_NO_RETURN" to listOf(
|
||||
// 通用变量
|
||||
TemplateVariableDto("account_name", "账户名称", "执行赎回的账户名称", "common", 1),
|
||||
TemplateVariableDto("wallet_address", "钱包地址", "钱包地址(已脱敏)", "common", 2),
|
||||
TemplateVariableDto("time", "时间", "通知发送时间", "common", 3),
|
||||
TemplateVariableDto("account_name", "common", 1),
|
||||
TemplateVariableDto("wallet_address", "common", 2),
|
||||
TemplateVariableDto("time", "common", 3),
|
||||
// 赎回变量
|
||||
TemplateVariableDto("transaction_hash", "交易哈希", "赎回交易的哈希值", "redeem", 10),
|
||||
TemplateVariableDto("available_balance", "可用余额", "账户可用余额(USDC)", "redeem", 11)
|
||||
TemplateVariableDto("transaction_hash", "redeem", 10),
|
||||
TemplateVariableDto("available_balance", "redeem", 11)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -285,7 +285,7 @@ class NotificationTemplateService(
|
||||
* 获取模板可用变量
|
||||
*/
|
||||
fun getTemplateVariables(templateType: String): TemplateVariablesResponse? {
|
||||
val typeInfo = TEMPLATE_TYPES[templateType] ?: return null
|
||||
if (!TEMPLATE_TYPES.containsKey(templateType)) return null
|
||||
val variables = TEMPLATE_VARIABLES[templateType] ?: emptyList()
|
||||
|
||||
// 获取使用的分类
|
||||
@@ -294,7 +294,6 @@ class NotificationTemplateService(
|
||||
|
||||
return TemplateVariablesResponse(
|
||||
templateType = templateType,
|
||||
templateTypeName = typeInfo.name,
|
||||
categories = categories,
|
||||
variables = variables
|
||||
)
|
||||
|
||||
@@ -1193,7 +1193,52 @@
|
||||
"redeemVariables": "Redeem Variables",
|
||||
"errorVariables": "Error Variables",
|
||||
"filterVariables": "Filter Variables",
|
||||
"strategyVariables": "Strategy Variables"
|
||||
"strategyVariables": "Strategy Variables",
|
||||
"contentPlaceholder": "Enter template content here, use {{variable}} to insert dynamic content",
|
||||
"variableLabels": {
|
||||
"account_name": "Account Name",
|
||||
"wallet_address": "Wallet Address",
|
||||
"time": "Time",
|
||||
"order_id": "Order ID",
|
||||
"market_title": "Market Title",
|
||||
"market_link": "Market Link",
|
||||
"side": "Side",
|
||||
"outcome": "Outcome",
|
||||
"price": "Price",
|
||||
"quantity": "Quantity",
|
||||
"amount": "Amount",
|
||||
"available_balance": "Available Balance",
|
||||
"leader_name": "Leader Name",
|
||||
"config_name": "Copy Trading Config Name",
|
||||
"error_message": "Error Message",
|
||||
"filter_type": "Filter Type",
|
||||
"filter_reason": "Filter Reason",
|
||||
"strategy_name": "Strategy Name",
|
||||
"transaction_hash": "Transaction Hash",
|
||||
"total_value": "Total Redeem Value"
|
||||
},
|
||||
"variableDescriptions": {
|
||||
"account_name": "Account name executing the order",
|
||||
"wallet_address": "Wallet address (masked)",
|
||||
"time": "Notification send time",
|
||||
"order_id": "Unique order identifier",
|
||||
"market_title": "Market/Event name",
|
||||
"market_link": "Polymarket market link",
|
||||
"side": "Order direction (Buy/Sell)",
|
||||
"outcome": "Market outcome (YES/NO, etc.)",
|
||||
"price": "Order price",
|
||||
"quantity": "Order quantity (shares)",
|
||||
"amount": "Order amount (USDC)",
|
||||
"available_balance": "Account available balance (USDC)",
|
||||
"leader_name": "Leader name/alias being copied",
|
||||
"config_name": "Copy trading configuration name",
|
||||
"error_message": "Order failure reason",
|
||||
"filter_type": "Type of order filter",
|
||||
"filter_reason": "Detailed reason for order filtering",
|
||||
"strategy_name": "Crypto spread strategy name",
|
||||
"transaction_hash": "Redeem transaction hash",
|
||||
"total_value": "Total redeem value (USDC)"
|
||||
}
|
||||
},
|
||||
"templateTypes": {
|
||||
"ORDER_SUCCESS": "Order Success",
|
||||
@@ -1202,6 +1247,14 @@
|
||||
"CRYPTO_TAIL_SUCCESS": "Crypto Spread Strategy Success",
|
||||
"REDEEM_SUCCESS": "Position Redeem Success",
|
||||
"REDEEM_NO_RETURN": "Position Settled (No Return)"
|
||||
},
|
||||
"templateTypeDescriptions": {
|
||||
"ORDER_SUCCESS": "Notification sent when order is successfully created",
|
||||
"ORDER_FAILED": "Notification sent when order creation fails",
|
||||
"ORDER_FILTERED": "Notification sent when order is filtered by risk control",
|
||||
"CRYPTO_TAIL_SUCCESS": "Notification sent when crypto spread strategy order succeeds",
|
||||
"REDEEM_SUCCESS": "Notification sent when position is successfully redeemed",
|
||||
"REDEEM_NO_RETURN": "Notification sent when position is settled with no return"
|
||||
}
|
||||
},
|
||||
"telegramConfig": {
|
||||
|
||||
@@ -1193,7 +1193,52 @@
|
||||
"redeemVariables": "赎回变量",
|
||||
"errorVariables": "错误变量",
|
||||
"filterVariables": "过滤变量",
|
||||
"strategyVariables": "策略变量"
|
||||
"strategyVariables": "策略变量",
|
||||
"contentPlaceholder": "在此输入模板内容,使用 {{变量名}} 插入动态内容",
|
||||
"variableLabels": {
|
||||
"account_name": "账户名称",
|
||||
"wallet_address": "钱包地址",
|
||||
"time": "时间",
|
||||
"order_id": "订单ID",
|
||||
"market_title": "市场标题",
|
||||
"market_link": "市场链接",
|
||||
"side": "方向",
|
||||
"outcome": "市场方向",
|
||||
"price": "价格",
|
||||
"quantity": "数量",
|
||||
"amount": "金额",
|
||||
"available_balance": "可用余额",
|
||||
"leader_name": "Leader 名称",
|
||||
"config_name": "跟单配置名",
|
||||
"error_message": "错误信息",
|
||||
"filter_type": "过滤类型",
|
||||
"filter_reason": "过滤原因",
|
||||
"strategy_name": "策略名称",
|
||||
"transaction_hash": "交易哈希",
|
||||
"total_value": "赎回总价值"
|
||||
},
|
||||
"variableDescriptions": {
|
||||
"account_name": "执行订单的账户名称",
|
||||
"wallet_address": "钱包地址(已脱敏)",
|
||||
"time": "通知发送时间",
|
||||
"order_id": "订单唯一标识",
|
||||
"market_title": "市场/事件名称",
|
||||
"market_link": "Polymarket 市场链接",
|
||||
"side": "订单方向(买入/卖出)",
|
||||
"outcome": "市场方向(YES/NO 等)",
|
||||
"price": "订单价格",
|
||||
"quantity": "订单数量(shares)",
|
||||
"amount": "订单金额(USDC)",
|
||||
"available_balance": "账户可用余额(USDC)",
|
||||
"leader_name": "跟单的 Leader 名称/备注",
|
||||
"config_name": "跟单配置名称",
|
||||
"error_message": "订单失败原因",
|
||||
"filter_type": "订单被过滤的类型",
|
||||
"filter_reason": "订单被过滤的详细原因",
|
||||
"strategy_name": "加密价差策略名称",
|
||||
"transaction_hash": "赎回交易的哈希值",
|
||||
"total_value": "赎回的总价值(USDC)"
|
||||
}
|
||||
},
|
||||
"templateTypes": {
|
||||
"ORDER_SUCCESS": "订单成功通知",
|
||||
@@ -1202,6 +1247,14 @@
|
||||
"CRYPTO_TAIL_SUCCESS": "加密价差策略成功通知",
|
||||
"REDEEM_SUCCESS": "仓位赎回成功通知",
|
||||
"REDEEM_NO_RETURN": "仓位结算(无收益)通知"
|
||||
},
|
||||
"templateTypeDescriptions": {
|
||||
"ORDER_SUCCESS": "订单创建成功时发送的通知",
|
||||
"ORDER_FAILED": "订单创建失败时发送的通知",
|
||||
"ORDER_FILTERED": "订单被风控过滤时发送的通知",
|
||||
"CRYPTO_TAIL_SUCCESS": "加密价差策略下单成功时发送的通知",
|
||||
"REDEEM_SUCCESS": "仓位赎回成功时发送的通知",
|
||||
"REDEEM_NO_RETURN": "仓位结算但无收益时发送的通知"
|
||||
}
|
||||
},
|
||||
"telegramConfig": {
|
||||
|
||||
@@ -1193,7 +1193,52 @@
|
||||
"redeemVariables": "贖回變量",
|
||||
"errorVariables": "錯誤變量",
|
||||
"filterVariables": "過濾變量",
|
||||
"strategyVariables": "策略變量"
|
||||
"strategyVariables": "策略變量",
|
||||
"contentPlaceholder": "在此輸入模板內容,使用 {{變量名}} 插入動態內容",
|
||||
"variableLabels": {
|
||||
"account_name": "賬戶名稱",
|
||||
"wallet_address": "錢包地址",
|
||||
"time": "時間",
|
||||
"order_id": "訂單ID",
|
||||
"market_title": "市場標題",
|
||||
"market_link": "市場鏈接",
|
||||
"side": "方向",
|
||||
"outcome": "市場方向",
|
||||
"price": "價格",
|
||||
"quantity": "數量",
|
||||
"amount": "金額",
|
||||
"available_balance": "可用餘額",
|
||||
"leader_name": "Leader 名稱",
|
||||
"config_name": "跟單配置名",
|
||||
"error_message": "錯誤信息",
|
||||
"filter_type": "過濾類型",
|
||||
"filter_reason": "過濾原因",
|
||||
"strategy_name": "策略名稱",
|
||||
"transaction_hash": "交易哈希",
|
||||
"total_value": "贖回總價值"
|
||||
},
|
||||
"variableDescriptions": {
|
||||
"account_name": "執行訂單的賬戶名稱",
|
||||
"wallet_address": "錢包地址(已脫敏)",
|
||||
"time": "通知發送時間",
|
||||
"order_id": "訂單唯一標識",
|
||||
"market_title": "市場/事件名稱",
|
||||
"market_link": "Polymarket 市場鏈接",
|
||||
"side": "訂單方向(買入/賣出)",
|
||||
"outcome": "市場方向(YES/NO 等)",
|
||||
"price": "訂單價格",
|
||||
"quantity": "訂單數量(shares)",
|
||||
"amount": "訂單金額(USDC)",
|
||||
"available_balance": "賬戶可用餘額(USDC)",
|
||||
"leader_name": "跟單的 Leader 名稱/備註",
|
||||
"config_name": "跟單配置名稱",
|
||||
"error_message": "訂單失敗原因",
|
||||
"filter_type": "訂單被過濾的類型",
|
||||
"filter_reason": "訂單被過濾的詳細原因",
|
||||
"strategy_name": "加密價差策略名稱",
|
||||
"transaction_hash": "贖回交易的哈希值",
|
||||
"total_value": "贖回的總價值(USDC)"
|
||||
}
|
||||
},
|
||||
"templateTypes": {
|
||||
"ORDER_SUCCESS": "訂單成功通知",
|
||||
@@ -1202,6 +1247,14 @@
|
||||
"CRYPTO_TAIL_SUCCESS": "加密價差策略成功通知",
|
||||
"REDEEM_SUCCESS": "倉位贖回成功通知",
|
||||
"REDEEM_NO_RETURN": "倉位結算(無收益)通知"
|
||||
},
|
||||
"templateTypeDescriptions": {
|
||||
"ORDER_SUCCESS": "訂單創建成功時發送的通知",
|
||||
"ORDER_FAILED": "訂單創建失敗時發送的通知",
|
||||
"ORDER_FILTERED": "訂單被風控過濾時發送的通知",
|
||||
"CRYPTO_TAIL_SUCCESS": "加密價差策略下單成功時發送的通知",
|
||||
"REDEEM_SUCCESS": "倉位贖回成功時發送的通知",
|
||||
"REDEEM_NO_RETURN": "倉位結算但無收益時發送的通知"
|
||||
}
|
||||
},
|
||||
"telegramConfig": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState, useCallback } from 'react'
|
||||
import { Card, Table, Button, Space, Tag, Popconfirm, message, Typography, Modal, Form, Input, Switch, Tooltip, Row, Col, Menu } from 'antd'
|
||||
import { Card, Table, Button, Space, Tag, Popconfirm, message, Typography, Modal, Form, Input, Switch, Tooltip, Row, Col, Tabs } from 'antd'
|
||||
import { PlusOutlined, EditOutlined, DeleteOutlined, SendOutlined, CopyOutlined, ReloadOutlined, CheckOutlined, RobotOutlined, FormOutlined } from '@ant-design/icons'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { apiService } from '../services/api'
|
||||
@@ -10,28 +10,27 @@ import TextArea from 'antd/es/input/TextArea'
|
||||
|
||||
const { Title, Text, Paragraph } = Typography
|
||||
|
||||
const templateTypeMenuStyle: React.CSSProperties = {
|
||||
border: 'none',
|
||||
background: 'transparent',
|
||||
}
|
||||
|
||||
const variableChipStyle: React.CSSProperties = {
|
||||
display: 'inline-block',
|
||||
const variableTagStyle: React.CSSProperties = {
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
cursor: 'pointer',
|
||||
marginBottom: 8,
|
||||
marginRight: 8,
|
||||
borderRadius: 16,
|
||||
padding: '6px 12px',
|
||||
fontSize: 13,
|
||||
transition: 'all 0.2s',
|
||||
border: '1px solid #d9d9d9',
|
||||
background: '#fafafa',
|
||||
marginBottom: 6,
|
||||
marginRight: 6,
|
||||
borderRadius: 6,
|
||||
padding: '4px 10px',
|
||||
fontSize: 12,
|
||||
transition: 'all 0.2s ease',
|
||||
border: '1px solid #e8e8e8',
|
||||
background: '#ffffff',
|
||||
color: 'rgba(0, 0, 0, 0.65)',
|
||||
}
|
||||
|
||||
const variableChipHoverStyle: React.CSSProperties = {
|
||||
const variableTagHoverStyle: React.CSSProperties = {
|
||||
borderColor: '#1890ff',
|
||||
background: '#e6f7ff',
|
||||
color: '#1890ff',
|
||||
transform: 'translateY(-1px)',
|
||||
boxShadow: '0 2px 4px rgba(24, 144, 255, 0.2)',
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,12 +60,10 @@ const NotificationSettingsPage: React.FC = () => {
|
||||
|
||||
// 模板配置相关状态
|
||||
const [templateTypes, setTemplateTypes] = useState<TemplateTypeInfo[]>([])
|
||||
const [templates, setTemplates] = useState<NotificationTemplate[]>([])
|
||||
const [selectedTemplateType, setSelectedTemplateType] = useState<string>('ORDER_SUCCESS')
|
||||
const [currentTemplate, setCurrentTemplate] = useState<NotificationTemplate | null>(null)
|
||||
const [templateVariables, setTemplateVariables] = useState<TemplateVariablesResponse | null>(null)
|
||||
const [templateContent, setTemplateContent] = useState('')
|
||||
const [templateLoading, setTemplateLoading] = useState(false)
|
||||
const [testTemplateLoading, setTestTemplateLoading] = useState(false)
|
||||
|
||||
// 加载机器人配置
|
||||
@@ -79,11 +76,6 @@ const NotificationSettingsPage: React.FC = () => {
|
||||
fetchTemplateTypes()
|
||||
}, [])
|
||||
|
||||
// 加载模板数据
|
||||
useEffect(() => {
|
||||
fetchTemplates()
|
||||
}, [])
|
||||
|
||||
// 当选中的模板类型改变时,加载模板详情和变量
|
||||
useEffect(() => {
|
||||
if (selectedTemplateType) {
|
||||
@@ -119,20 +111,6 @@ const NotificationSettingsPage: React.FC = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const fetchTemplates = async () => {
|
||||
setTemplateLoading(true)
|
||||
try {
|
||||
const response = await apiService.notifications.getTemplates()
|
||||
if (response.data.code === 0 && response.data.data) {
|
||||
setTemplates(response.data.data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取模板列表失败:', error)
|
||||
} finally {
|
||||
setTemplateLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const fetchTemplateDetail = async (templateType: string) => {
|
||||
try {
|
||||
const response = await apiService.notifications.getTemplateDetail({ templateType })
|
||||
@@ -332,7 +310,6 @@ const NotificationSettingsPage: React.FC = () => {
|
||||
})
|
||||
if (response.data.code === 0) {
|
||||
message.success(t('notificationSettings.templates.saveSuccess'))
|
||||
fetchTemplates()
|
||||
fetchTemplateDetail(selectedTemplateType)
|
||||
} else {
|
||||
message.error(response.data.msg || t('notificationSettings.templates.saveFailed'))
|
||||
@@ -349,7 +326,6 @@ const NotificationSettingsPage: React.FC = () => {
|
||||
})
|
||||
if (response.data.code === 0) {
|
||||
message.success(t('notificationSettings.templates.resetSuccess'))
|
||||
fetchTemplates()
|
||||
fetchTemplateDetail(selectedTemplateType)
|
||||
} else {
|
||||
message.error(response.data.msg || t('notificationSettings.templates.resetFailed'))
|
||||
@@ -387,19 +363,21 @@ const NotificationSettingsPage: React.FC = () => {
|
||||
|
||||
const renderVariableItem = (variable: TemplateVariable) => {
|
||||
const isHover = variableHoverKey === variable.key
|
||||
const label = t(`notificationSettings.templates.variableLabels.${variable.key}`)
|
||||
const description = t(`notificationSettings.templates.variableDescriptions.${variable.key}`)
|
||||
return (
|
||||
<Tooltip key={variable.key} title={variable.description || `{{${variable.key}}}`}>
|
||||
<Tooltip key={variable.key} title={description || `{{${variable.key}}}`} placement="top">
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
style={{ ...variableChipStyle, ...(isHover ? variableChipHoverStyle : {}) }}
|
||||
style={{ ...variableTagStyle, ...(isHover ? variableTagHoverStyle : {}) }}
|
||||
onClick={() => handleCopyVariable(variable.key)}
|
||||
onMouseEnter={() => setVariableHoverKey(variable.key)}
|
||||
onMouseLeave={() => setVariableHoverKey(null)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && handleCopyVariable(variable.key)}
|
||||
>
|
||||
<CopyOutlined style={{ marginRight: 6, fontSize: 12 }} />
|
||||
{variable.label}
|
||||
<CopyOutlined style={{ marginRight: 4, fontSize: 11, opacity: 0.6 }} />
|
||||
<span style={{ fontFamily: 'monospace' }}>{label}</span>
|
||||
</span>
|
||||
</Tooltip>
|
||||
)
|
||||
@@ -412,20 +390,20 @@ const NotificationSettingsPage: React.FC = () => {
|
||||
<Card
|
||||
size="small"
|
||||
title={
|
||||
<span style={{ fontSize: 14, fontWeight: 600 }}>
|
||||
<span style={{ fontSize: 13, fontWeight: 500 }}>
|
||||
{t('notificationSettings.templates.variables')}
|
||||
</span>
|
||||
}
|
||||
style={{ height: '100%', borderRadius: 8 }}
|
||||
bodyStyle={{ paddingTop: 12 }}
|
||||
bodyStyle={{ padding: '12px 16px', maxHeight: 420, overflowY: 'auto' }}
|
||||
>
|
||||
{templateVariables.categories.map(category => {
|
||||
const categoryVariables = templateVariables.variables.filter(v => v.category === category.key)
|
||||
if (categoryVariables.length === 0) return null
|
||||
return (
|
||||
<div key={category.key} style={{ marginBottom: 20 }}>
|
||||
<Text strong style={{ marginBottom: 10, display: 'block', fontSize: 13, color: 'rgba(0,0,0,0.65)' }}>
|
||||
{t(CATEGORY_LABELS[category.key] || category.label)}
|
||||
<div key={category.key} style={{ marginBottom: 16 }}>
|
||||
<Text type="secondary" style={{ marginBottom: 8, display: 'block', fontSize: 12 }}>
|
||||
{t(CATEGORY_LABELS[category.key])}
|
||||
</Text>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
{categoryVariables.sort((a, b) => a.sortOrder - b.sortOrder).map(renderVariableItem)}
|
||||
@@ -433,7 +411,7 @@ const NotificationSettingsPage: React.FC = () => {
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
<Paragraph type="secondary" style={{ marginTop: 16, marginBottom: 0, fontSize: 12 }}>
|
||||
<Paragraph type="secondary" style={{ marginTop: 12, marginBottom: 0, fontSize: 11, textAlign: 'center' }}>
|
||||
{t('notificationSettings.templates.clickToCopy')}
|
||||
</Paragraph>
|
||||
</Card>
|
||||
@@ -544,14 +522,12 @@ const NotificationSettingsPage: React.FC = () => {
|
||||
}
|
||||
]
|
||||
|
||||
const templateTypeMenuItems = templateTypes.map(type => ({
|
||||
const templateTypeTabItems = templateTypes.map(type => ({
|
||||
key: type.type,
|
||||
icon: <FormOutlined />,
|
||||
label: (
|
||||
<div>
|
||||
<div style={{ fontWeight: 500 }}>{t(`notificationSettings.templateTypes.${type.type}`)}</div>
|
||||
<div style={{ fontSize: 12, color: 'rgba(0,0,0,0.45)', marginTop: 2 }}>{type.description}</div>
|
||||
</div>
|
||||
<Tooltip title={t(`notificationSettings.templateTypeDescriptions.${type.type}`)} placement="top">
|
||||
<span>{t(`notificationSettings.templateTypes.${type.type}`)}</span>
|
||||
</Tooltip>
|
||||
),
|
||||
}))
|
||||
|
||||
@@ -594,31 +570,26 @@ const NotificationSettingsPage: React.FC = () => {
|
||||
<span>{t('notificationSettings.templateConfig')}</span>
|
||||
</Space>
|
||||
}
|
||||
loading={templateLoading}
|
||||
style={{ marginBottom: '16px' }}
|
||||
>
|
||||
<Row gutter={[20, 20]}>
|
||||
<Col xs={24} sm={24} md={6}>
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
<Text strong style={{ display: 'block', marginBottom: 12, fontSize: 14 }}>
|
||||
{t('notificationSettings.templates.templateType')}
|
||||
</Text>
|
||||
<Menu
|
||||
mode="inline"
|
||||
selectedKeys={[selectedTemplateType]}
|
||||
style={{ ...templateTypeMenuStyle, minHeight: 320 }}
|
||||
items={templateTypeMenuItems}
|
||||
onClick={({ key }) => handleTemplateTypeChange(key)}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={10}>
|
||||
<Card size="small" bordered style={{ marginBottom: 12 }}>
|
||||
<Tabs
|
||||
activeKey={selectedTemplateType}
|
||||
onChange={handleTemplateTypeChange}
|
||||
items={templateTypeTabItems}
|
||||
style={{ marginBottom: 16 }}
|
||||
tabBarStyle={{ marginBottom: 0 }}
|
||||
type={isMobile ? 'line' : 'card'}
|
||||
size={isMobile ? 'small' : 'middle'}
|
||||
/>
|
||||
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col xs={24} sm={24} md={17}>
|
||||
<Card size="small" bordered={false} style={{ background: '#fafafa', marginBottom: 12, borderRadius: 8 }} bodyStyle={{ padding: '10px 16px' }}>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center', justifyContent: 'space-between' }}>
|
||||
<Space wrap size="small">
|
||||
<Text strong style={{ fontSize: 14 }}>{t('notificationSettings.templates.templateContent')}</Text>
|
||||
<Text type="secondary" style={{ fontSize: 13 }}>{t('notificationSettings.templates.templateContent')}</Text>
|
||||
{currentTemplate && (
|
||||
<Tag color={currentTemplate.isDefault ? 'green' : 'blue'}>
|
||||
<Tag color={currentTemplate.isDefault ? 'green' : 'blue'} style={{ margin: 0 }}>
|
||||
{currentTemplate.isDefault ? t('notificationSettings.templates.isDefault') : t('notificationSettings.templates.isCustom')}
|
||||
</Tag>
|
||||
)}
|
||||
@@ -630,14 +601,14 @@ const NotificationSettingsPage: React.FC = () => {
|
||||
okText={t('common.confirm')}
|
||||
cancelText={t('common.cancel')}
|
||||
>
|
||||
<Button size={isMobile ? 'small' : 'middle'} icon={<ReloadOutlined />}>
|
||||
<Button size="small" icon={<ReloadOutlined />}>
|
||||
{t('notificationSettings.templates.resetToDefault')}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
<Button size={isMobile ? 'small' : 'middle'} type="primary" icon={<CheckOutlined />} onClick={handleSaveTemplate}>
|
||||
<Button size="small" type="primary" icon={<CheckOutlined />} onClick={handleSaveTemplate}>
|
||||
{t('common.save')}
|
||||
</Button>
|
||||
<Button size={isMobile ? 'small' : 'middle'} icon={<SendOutlined />} loading={testTemplateLoading} onClick={handleTestTemplate}>
|
||||
<Button size="small" icon={<SendOutlined />} loading={testTemplateLoading} onClick={handleTestTemplate}>
|
||||
{t('notificationSettings.test')}
|
||||
</Button>
|
||||
</Space>
|
||||
@@ -646,11 +617,12 @@ const NotificationSettingsPage: React.FC = () => {
|
||||
<TextArea
|
||||
value={templateContent}
|
||||
onChange={handleTemplateContentChange}
|
||||
rows={14}
|
||||
style={{ fontFamily: 'monospace', fontSize: 13 }}
|
||||
rows={isMobile ? 10 : 16}
|
||||
style={{ fontFamily: 'monospace', fontSize: 13, borderRadius: 8, resize: 'none' }}
|
||||
placeholder={t('notificationSettings.templates.contentPlaceholder')}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8}>
|
||||
<Col xs={24} sm={24} md={7}>
|
||||
{renderVariablesPanel()}
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
@@ -1287,8 +1287,6 @@ export interface TemplateTypeInfo {
|
||||
*/
|
||||
export interface TemplateVariable {
|
||||
key: string // 变量名
|
||||
label: string // 显示名称
|
||||
description: string // 变量说明
|
||||
category: string // 分类
|
||||
sortOrder: number // 排序顺序
|
||||
}
|
||||
@@ -1298,7 +1296,6 @@ export interface TemplateVariable {
|
||||
*/
|
||||
export interface TemplateVariableCategory {
|
||||
key: string // 分类 key
|
||||
label: string // 分类名称
|
||||
sortOrder: number // 排序顺序
|
||||
}
|
||||
|
||||
@@ -1307,7 +1304,6 @@ export interface TemplateVariableCategory {
|
||||
*/
|
||||
export interface TemplateVariablesResponse {
|
||||
templateType: string // 模板类型
|
||||
templateTypeName: string // 模板类型名称
|
||||
categories: TemplateVariableCategory[] // 分类列表
|
||||
variables: TemplateVariable[] // 变量列表
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user