feat: 实现 Builder API Key 系统级配置和 Gasless 交易支持
- 新增系统配置表(SystemConfig)用于存储 Builder API Key - 实现 Builder API Key 的前端配置页面 - 集成 Builder Relayer API 支持 Gasless 交易 - 在 API 健康检查中添加 Builder Relayer API 检测 - 移除前端 API 测试功能,简化配置页面 - 修复赎回仓位时的 Builder API Key 检查逻辑 - 更新错误处理,引导用户配置 Builder API Key
This commit is contained in:
@@ -35,6 +35,7 @@ import LanguageSettings from './pages/LanguageSettings'
|
||||
import ApiHealthStatus from './pages/ApiHealthStatus'
|
||||
import ProxySettings from './pages/ProxySettings'
|
||||
import NotificationSettings from './pages/NotificationSettings'
|
||||
import BuilderApiKeySettings from './pages/BuilderApiKeySettings'
|
||||
import { wsManager } from './services/websocket'
|
||||
import type { OrderPushMessage } from './types'
|
||||
import { apiService } from './services/api'
|
||||
@@ -253,6 +254,7 @@ function App() {
|
||||
<Route path="/system-settings/api-health" element={<ProtectedRoute><ApiHealthStatus /></ProtectedRoute>} />
|
||||
<Route path="/system-settings/proxy" element={<ProtectedRoute><ProxySettings /></ProtectedRoute>} />
|
||||
<Route path="/system-settings/notifications" element={<ProtectedRoute><NotificationSettings /></ProtectedRoute>} />
|
||||
<Route path="/system-settings/builder-api-key" element={<ProtectedRoute><BuilderApiKeySettings /></ProtectedRoute>} />
|
||||
|
||||
{/* 默认重定向到登录页 */}
|
||||
<Route path="*" element={<Navigate to="/login" replace />} />
|
||||
|
||||
@@ -19,7 +19,8 @@ import {
|
||||
TwitterOutlined,
|
||||
GlobalOutlined,
|
||||
CheckCircleOutlined,
|
||||
NotificationOutlined
|
||||
NotificationOutlined,
|
||||
KeyOutlined
|
||||
} from '@ant-design/icons'
|
||||
import type { MenuProps } from 'antd'
|
||||
import type { ReactNode } from 'react'
|
||||
@@ -121,6 +122,11 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
icon: <SettingOutlined />,
|
||||
label: t('menu.systemSettings'),
|
||||
children: [
|
||||
{
|
||||
key: '/system-settings',
|
||||
icon: <SettingOutlined />,
|
||||
label: t('menu.systemOverview') || '概览'
|
||||
},
|
||||
{
|
||||
key: '/system-settings/language',
|
||||
icon: <GlobalOutlined />,
|
||||
@@ -136,6 +142,11 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
icon: <LinkOutlined />,
|
||||
label: t('menu.proxy')
|
||||
},
|
||||
{
|
||||
key: '/system-settings/builder-api-key',
|
||||
icon: <KeyOutlined />,
|
||||
label: t('menu.builderApiKey') || 'Builder API Key'
|
||||
},
|
||||
{
|
||||
key: '/system-settings/notifications',
|
||||
icon: <NotificationOutlined />,
|
||||
@@ -173,8 +184,8 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
}
|
||||
|
||||
const handleMenuClick = ({ key }: { key: string }) => {
|
||||
// 如果是父菜单,不导航
|
||||
if (key === '/copy-trading-management' || key === '/system-settings') {
|
||||
// 如果是父菜单,不导航(但 /system-settings 作为子菜单项时可以导航)
|
||||
if (key === '/copy-trading-management') {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -233,8 +233,10 @@
|
||||
"statistics": "Statistics",
|
||||
"users": "User Management",
|
||||
"systemSettings": "System",
|
||||
"systemOverview": "Overview",
|
||||
"language": "Language",
|
||||
"apiHealth": "API Health",
|
||||
"builderApiKey": "Builder API Key",
|
||||
"proxy": "Proxy",
|
||||
"notifications": "Notifications",
|
||||
"logout": "Logout",
|
||||
@@ -302,6 +304,49 @@
|
||||
"systemSettingsDesc": "Configure proxy, view API health status",
|
||||
"footer": "Please use the above pages for configuration management."
|
||||
},
|
||||
"builderApiKey": {
|
||||
"title": "Builder API Key Configuration",
|
||||
"alertTitle": "What is Builder API Key?",
|
||||
"description": "Builder API Key is a system-level configuration, not related to your account. It is an API credential for Polymarket's Builder service, used to execute Gasless (no gas fee) transactions.",
|
||||
"purposeTitle": "Main purposes:",
|
||||
"purpose1": "Execute Gasless transactions: Operations like redeeming positions and creating orders don't require gas fees",
|
||||
"purpose2": "Improve user experience: No need to prepare MATIC tokens in wallet for gas fees",
|
||||
"purpose3": "Reduce transaction costs: Gas fees are covered by Builder service",
|
||||
"getApiKey": "Get API Key:",
|
||||
"openSettings": "Go to Polymarket Settings",
|
||||
"apiKey": "Builder API Key",
|
||||
"secret": "Builder Secret",
|
||||
"passphrase": "Builder Passphrase",
|
||||
"apiKeyPlaceholder": "Please enter Builder API Key",
|
||||
"secretPlaceholder": "Please enter Builder Secret",
|
||||
"passphrasePlaceholder": "Please enter Builder Passphrase",
|
||||
"apiKeyHelp": "Configured, enter new value to update",
|
||||
"secretHelp": "Configured, enter new value to update",
|
||||
"passphraseHelp": "Configured, enter new value to update",
|
||||
"saveSuccess": "Builder API Key configuration saved successfully",
|
||||
"saveFailed": "Failed to save Builder API Key configuration",
|
||||
"getFailed": "Failed to get Builder API Key configuration",
|
||||
"notConfigured": "Builder API Key not configured, please go to System Settings to configure",
|
||||
"notConfiguredError": "Builder API Key not configured, cannot execute Gasless transactions. Please go to System Settings to configure Builder API Key.",
|
||||
"apiReference": "API Reference Documentation",
|
||||
"apiReferenceDesc": "Learn more about Builder API usage:",
|
||||
"relayerApiDocs": "Builder Relayer API Documentation",
|
||||
"builderDocs": "Builder Development Documentation",
|
||||
"apiTest": "API Test",
|
||||
"apiTestDesc": "Test if Builder API is working correctly",
|
||||
"testNonce": "Test Get Nonce",
|
||||
"testNonceHelp": "Enter Safe address (proxyAddress)",
|
||||
"testDeployed": "Test Check Deployed Status",
|
||||
"testDeployedHelp": "Enter Safe address (proxyAddress)",
|
||||
"testTransaction": "Test Get Transaction Status",
|
||||
"testTransactionHelp": "Enter transaction ID",
|
||||
"testAddressRequired": "Please enter address",
|
||||
"testTransactionIdRequired": "Please enter transaction ID",
|
||||
"testAddressPlaceholder": "Enter address, e.g., 0x...",
|
||||
"testTransactionIdPlaceholder": "Enter transaction ID",
|
||||
"testSuccess": "Test successful",
|
||||
"testFailed": "Test failed"
|
||||
},
|
||||
"resetPassword": {
|
||||
"title": "Reset Password",
|
||||
"firstUse": "First Time Using System",
|
||||
|
||||
@@ -150,8 +150,10 @@
|
||||
"statistics": "统计信息",
|
||||
"users": "用户管理",
|
||||
"systemSettings": "系统管理",
|
||||
"systemOverview": "概览",
|
||||
"language": "语言",
|
||||
"apiHealth": "API健康",
|
||||
"builderApiKey": "Builder API Key",
|
||||
"proxy": "代理",
|
||||
"notifications": "消息推送",
|
||||
"logout": "退出登录",
|
||||
@@ -214,6 +216,49 @@
|
||||
"systemSettingsDesc": "配置代理、查看 API 健康状态",
|
||||
"footer": "请使用上述页面进行配置管理。"
|
||||
},
|
||||
"builderApiKey": {
|
||||
"title": "Builder API Key 配置",
|
||||
"alertTitle": "什么是 Builder API Key?",
|
||||
"description": "Builder API Key 是系统级别的配置,与您的账户无关。它是 Polymarket 提供的 Builder 服务的 API 凭证,用于执行 Gasless(免 gas 费)交易。",
|
||||
"purposeTitle": "主要用途:",
|
||||
"purpose1": "执行 Gasless 交易:赎回仓位、创建订单等操作无需支付 gas 费用",
|
||||
"purpose2": "提升用户体验:无需在钱包中准备 MATIC 代币作为 gas 费",
|
||||
"purpose3": "降低交易成本:由 Builder 服务承担 gas 费用",
|
||||
"getApiKey": "获取 API Key:",
|
||||
"openSettings": "前往 Polymarket 设置页面",
|
||||
"apiKey": "Builder API Key",
|
||||
"secret": "Builder Secret",
|
||||
"passphrase": "Builder Passphrase",
|
||||
"apiKeyPlaceholder": "请输入 Builder API Key",
|
||||
"secretPlaceholder": "请输入 Builder Secret",
|
||||
"passphrasePlaceholder": "请输入 Builder Passphrase",
|
||||
"apiKeyHelp": "已配置,输入新值以更新",
|
||||
"secretHelp": "已配置,输入新值以更新",
|
||||
"passphraseHelp": "已配置,输入新值以更新",
|
||||
"saveSuccess": "保存 Builder API Key 配置成功",
|
||||
"saveFailed": "保存 Builder API Key 配置失败",
|
||||
"getFailed": "获取 Builder API Key 配置失败",
|
||||
"notConfigured": "Builder API Key 未配置,请前往系统设置页面配置",
|
||||
"notConfiguredError": "Builder API Key 未配置,无法执行 Gasless 交易。请前往系统设置页面配置 Builder API Key。",
|
||||
"apiReference": "API 参考文档",
|
||||
"apiReferenceDesc": "了解更多关于 Builder API 的使用方法:",
|
||||
"relayerApiDocs": "Builder Relayer API 文档",
|
||||
"builderDocs": "Builder 开发文档",
|
||||
"apiTest": "API 测试",
|
||||
"apiTestDesc": "测试 Builder API 是否正常工作",
|
||||
"testNonce": "测试获取 Nonce",
|
||||
"testNonceHelp": "输入 Safe 地址(proxyAddress)",
|
||||
"testDeployed": "测试检查部署状态",
|
||||
"testDeployedHelp": "输入 Safe 地址(proxyAddress)",
|
||||
"testTransaction": "测试获取交易状态",
|
||||
"testTransactionHelp": "输入交易ID",
|
||||
"testAddressRequired": "请输入地址",
|
||||
"testTransactionIdRequired": "请输入交易ID",
|
||||
"testAddressPlaceholder": "输入地址,例如:0x...",
|
||||
"testTransactionIdPlaceholder": "输入交易ID",
|
||||
"testSuccess": "测试成功",
|
||||
"testFailed": "测试失败"
|
||||
},
|
||||
"resetPassword": {
|
||||
"title": "重置密码",
|
||||
"firstUse": "首次使用系统",
|
||||
|
||||
@@ -233,8 +233,10 @@
|
||||
"statistics": "統計信息",
|
||||
"users": "用戶管理",
|
||||
"systemSettings": "系統管理",
|
||||
"systemOverview": "概覽",
|
||||
"language": "語言",
|
||||
"apiHealth": "API健康",
|
||||
"builderApiKey": "Builder API Key",
|
||||
"proxy": "代理",
|
||||
"notifications": "消息推送",
|
||||
"logout": "退出登錄",
|
||||
@@ -302,6 +304,49 @@
|
||||
"systemSettingsDesc": "配置代理、查看 API 健康狀態",
|
||||
"footer": "請使用上述頁面進行配置管理。"
|
||||
},
|
||||
"builderApiKey": {
|
||||
"title": "Builder API Key 配置",
|
||||
"alertTitle": "什麼是 Builder API Key?",
|
||||
"description": "Builder API Key 是系統級別的配置,與您的賬戶無關。它是 Polymarket 提供的 Builder 服務的 API 憑證,用於執行 Gasless(免 gas 費)交易。",
|
||||
"purposeTitle": "主要用途:",
|
||||
"purpose1": "執行 Gasless 交易:贖回倉位、創建訂單等操作無需支付 gas 費用",
|
||||
"purpose2": "提升用戶體驗:無需在錢包中準備 MATIC 代幣作為 gas 費",
|
||||
"purpose3": "降低交易成本:由 Builder 服務承擔 gas 費用",
|
||||
"getApiKey": "獲取 API Key:",
|
||||
"openSettings": "前往 Polymarket 設置頁面",
|
||||
"apiKey": "Builder API Key",
|
||||
"secret": "Builder Secret",
|
||||
"passphrase": "Builder Passphrase",
|
||||
"apiKeyPlaceholder": "請輸入 Builder API Key",
|
||||
"secretPlaceholder": "請輸入 Builder Secret",
|
||||
"passphrasePlaceholder": "請輸入 Builder Passphrase",
|
||||
"apiKeyHelp": "已配置,輸入新值以更新",
|
||||
"secretHelp": "已配置,輸入新值以更新",
|
||||
"passphraseHelp": "已配置,輸入新值以更新",
|
||||
"saveSuccess": "保存 Builder API Key 配置成功",
|
||||
"saveFailed": "保存 Builder API Key 配置失敗",
|
||||
"getFailed": "獲取 Builder API Key 配置失敗",
|
||||
"notConfigured": "Builder API Key 未配置,請前往系統設置頁面配置",
|
||||
"notConfiguredError": "Builder API Key 未配置,無法執行 Gasless 交易。請前往系統設置頁面配置 Builder API Key。",
|
||||
"apiReference": "API 參考文檔",
|
||||
"apiReferenceDesc": "了解更多關於 Builder API 的使用方法:",
|
||||
"relayerApiDocs": "Builder Relayer API 文檔",
|
||||
"builderDocs": "Builder 開發文檔",
|
||||
"apiTest": "API 測試",
|
||||
"apiTestDesc": "測試 Builder API 是否正常工作",
|
||||
"testNonce": "測試獲取 Nonce",
|
||||
"testNonceHelp": "輸入 Safe 地址(proxyAddress)",
|
||||
"testDeployed": "測試檢查部署狀態",
|
||||
"testDeployedHelp": "輸入 Safe 地址(proxyAddress)",
|
||||
"testTransaction": "測試獲取交易狀態",
|
||||
"testTransactionHelp": "輸入交易ID",
|
||||
"testAddressRequired": "請輸入地址",
|
||||
"testTransactionIdRequired": "請輸入交易ID",
|
||||
"testAddressPlaceholder": "輸入地址,例如:0x...",
|
||||
"testTransactionIdPlaceholder": "輸入交易ID",
|
||||
"testSuccess": "測試成功",
|
||||
"testFailed": "測試失敗"
|
||||
},
|
||||
"resetPassword": {
|
||||
"title": "重置密碼",
|
||||
"firstUse": "首次使用系統",
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Card, Form, Button, Input, message, Typography, Space, Alert } from 'antd'
|
||||
import { SaveOutlined, LinkOutlined } from '@ant-design/icons'
|
||||
import { apiService } from '../services/api'
|
||||
import { useMediaQuery } from 'react-responsive'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { SystemConfig, BuilderApiKeyUpdateRequest } from '../types'
|
||||
|
||||
const { Title, Paragraph, Text } = Typography
|
||||
|
||||
const BuilderApiKeySettings: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const isMobile = useMediaQuery({ maxWidth: 768 })
|
||||
const [builderApiKeyForm] = Form.useForm()
|
||||
const [builderApiKeyConfig, setBuilderApiKeyConfig] = useState<SystemConfig | null>(null)
|
||||
const [builderApiKeyLoading, setBuilderApiKeyLoading] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
fetchBuilderApiKeyConfig()
|
||||
}, [])
|
||||
|
||||
const fetchBuilderApiKeyConfig = async () => {
|
||||
try {
|
||||
const response = await apiService.systemConfig.get()
|
||||
if (response.data.code === 0 && response.data.data) {
|
||||
const config = response.data.data
|
||||
setBuilderApiKeyConfig(config)
|
||||
// 预填充字段(如果已配置,显示占位符)
|
||||
builderApiKeyForm.setFieldsValue({
|
||||
builderApiKey: config.builderApiKeyConfigured ? '***' : '',
|
||||
builderSecret: config.builderSecretConfigured ? '***' : '',
|
||||
builderPassphrase: config.builderPassphraseConfigured ? '***' : '',
|
||||
})
|
||||
} else {
|
||||
message.error(response.data.msg || t('builderApiKey.getFailed'))
|
||||
}
|
||||
} catch (error: any) {
|
||||
message.error(error.message || t('builderApiKey.getFailed'))
|
||||
}
|
||||
}
|
||||
|
||||
const handleBuilderApiKeySubmit = async (values: BuilderApiKeyUpdateRequest) => {
|
||||
setBuilderApiKeyLoading(true)
|
||||
try {
|
||||
// 如果值是 '***',表示已配置但未修改,不发送
|
||||
const updateData: BuilderApiKeyUpdateRequest = {}
|
||||
if (values.builderApiKey && values.builderApiKey !== '***') {
|
||||
updateData.builderApiKey = values.builderApiKey
|
||||
}
|
||||
if (values.builderSecret && values.builderSecret !== '***') {
|
||||
updateData.builderSecret = values.builderSecret
|
||||
}
|
||||
if (values.builderPassphrase && values.builderPassphrase !== '***') {
|
||||
updateData.builderPassphrase = values.builderPassphrase
|
||||
}
|
||||
|
||||
const response = await apiService.systemConfig.updateBuilderApiKey(updateData)
|
||||
if (response.data.code === 0) {
|
||||
message.success(t('builderApiKey.saveSuccess'))
|
||||
fetchBuilderApiKeyConfig()
|
||||
} else {
|
||||
message.error(response.data.msg || t('builderApiKey.saveFailed'))
|
||||
}
|
||||
} catch (error: any) {
|
||||
message.error(error.message || t('builderApiKey.saveFailed'))
|
||||
} finally {
|
||||
setBuilderApiKeyLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ marginBottom: '16px' }}>
|
||||
<Title level={2} style={{ margin: 0 }}>{t('builderApiKey.title')}</Title>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<Alert
|
||||
message={t('builderApiKey.alertTitle')}
|
||||
description={
|
||||
<div>
|
||||
<Paragraph style={{ marginBottom: '8px' }}>
|
||||
{t('builderApiKey.description')}
|
||||
</Paragraph>
|
||||
<Paragraph style={{ marginBottom: '8px' }}>
|
||||
<Text strong>{t('builderApiKey.purposeTitle')}</Text>
|
||||
<ul style={{ marginTop: '8px', marginBottom: 0, paddingLeft: '20px' }}>
|
||||
<li>{t('builderApiKey.purpose1')}</li>
|
||||
<li>{t('builderApiKey.purpose2')}</li>
|
||||
<li>{t('builderApiKey.purpose3')}</li>
|
||||
</ul>
|
||||
</Paragraph>
|
||||
<Paragraph style={{ marginBottom: 0 }}>
|
||||
<Text strong>{t('builderApiKey.getApiKey')}</Text>
|
||||
<Space style={{ marginLeft: '8px' }}>
|
||||
<a
|
||||
href="https://polymarket.com/settings?tab=builder"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<LinkOutlined /> {t('builderApiKey.openSettings')}
|
||||
</a>
|
||||
</Space>
|
||||
</Paragraph>
|
||||
</div>
|
||||
}
|
||||
type="info"
|
||||
showIcon
|
||||
style={{ marginBottom: '24px' }}
|
||||
/>
|
||||
|
||||
<Form
|
||||
form={builderApiKeyForm}
|
||||
layout="vertical"
|
||||
onFinish={handleBuilderApiKeySubmit}
|
||||
size={isMobile ? 'middle' : 'large'}
|
||||
>
|
||||
<Form.Item
|
||||
label={t('builderApiKey.apiKey')}
|
||||
name="builderApiKey"
|
||||
help={builderApiKeyConfig?.builderApiKeyConfigured ? t('builderApiKey.apiKeyHelp') : t('builderApiKey.apiKeyPlaceholder')}
|
||||
>
|
||||
<Input
|
||||
placeholder={builderApiKeyConfig?.builderApiKeyConfigured ? t('builderApiKey.apiKeyHelp') : t('builderApiKey.apiKeyPlaceholder')}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t('builderApiKey.secret')}
|
||||
name="builderSecret"
|
||||
help={builderApiKeyConfig?.builderSecretConfigured ? t('builderApiKey.secretHelp') : t('builderApiKey.secretPlaceholder')}
|
||||
>
|
||||
<Input
|
||||
placeholder={builderApiKeyConfig?.builderSecretConfigured ? t('builderApiKey.secretHelp') : t('builderApiKey.secretPlaceholder')}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t('builderApiKey.passphrase')}
|
||||
name="builderPassphrase"
|
||||
help={builderApiKeyConfig?.builderPassphraseConfigured ? t('builderApiKey.passphraseHelp') : t('builderApiKey.passphrasePlaceholder')}
|
||||
>
|
||||
<Input
|
||||
placeholder={builderApiKeyConfig?.builderPassphraseConfigured ? t('builderApiKey.passphraseHelp') : t('builderApiKey.passphrasePlaceholder')}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
icon={<SaveOutlined />}
|
||||
loading={builderApiKeyLoading}
|
||||
>
|
||||
{t('common.save') || '保存配置'}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BuilderApiKeySettings
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useState, useMemo } from 'react'
|
||||
import { Card, Table, Tag, message, Space, Input, Radio, Select, Button, Row, Col, Empty, Modal, Form, Descriptions } from 'antd'
|
||||
import { SearchOutlined, AppstoreOutlined, UnorderedListOutlined, UpOutlined, DownOutlined } from '@ant-design/icons'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { apiService } from '../services/api'
|
||||
import type { AccountPosition, Account, PositionPushMessage, PositionSellRequest, MarketPriceResponse, RedeemablePositionsSummary, PositionRedeemRequest } from '../types'
|
||||
import { getPositionKey } from '../types'
|
||||
@@ -13,6 +14,7 @@ type PositionFilter = 'current' | 'historical'
|
||||
type ViewMode = 'card' | 'list'
|
||||
|
||||
const PositionList: React.FC = () => {
|
||||
const navigate = useNavigate()
|
||||
const isMobile = useMediaQuery({ maxWidth: 768 })
|
||||
const [currentPositions, setCurrentPositions] = useState<AccountPosition[]>([])
|
||||
const [historyPositions, setHistoryPositions] = useState<AccountPosition[]>([])
|
||||
@@ -113,10 +115,34 @@ const PositionList: React.FC = () => {
|
||||
// 刷新可赎回统计
|
||||
await fetchRedeemableSummary()
|
||||
} else {
|
||||
message.error(response.data.msg || '赎回失败')
|
||||
// 检查是否是 Builder API Key 未配置的错误
|
||||
if (response.data.code === 2014 || response.data.msg?.includes('Builder API Key 未配置')) {
|
||||
message.error({
|
||||
content: response.data.msg || 'Builder API Key 未配置',
|
||||
duration: 5,
|
||||
})
|
||||
// 延迟跳转,让用户看到错误消息
|
||||
setTimeout(() => {
|
||||
navigate('/system-settings/builder-api-key')
|
||||
}, 1500)
|
||||
} else {
|
||||
message.error(response.data.msg || '赎回失败')
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
message.error('赎回失败: ' + (error.message || '未知错误'))
|
||||
// 检查是否是 Builder API Key 未配置的错误
|
||||
if (error.response?.data?.code === 2014 || error.message?.includes('Builder API Key 未配置')) {
|
||||
message.error({
|
||||
content: error.response?.data?.msg || error.message || 'Builder API Key 未配置,请前往系统设置页面配置',
|
||||
duration: 5,
|
||||
})
|
||||
// 延迟跳转,让用户看到错误消息
|
||||
setTimeout(() => {
|
||||
navigate('/system-settings/builder-api-key')
|
||||
}, 1500)
|
||||
} else {
|
||||
message.error('赎回失败: ' + (error.message || '未知错误'))
|
||||
}
|
||||
} finally {
|
||||
setRedeeming(false)
|
||||
}
|
||||
|
||||
@@ -578,6 +578,23 @@ export const apiService = {
|
||||
*/
|
||||
getTelegramChatIds: (data: { botToken: string }) =>
|
||||
apiClient.post<ApiResponse<string[]>>('/notifications/telegram/get-chat-ids', data)
|
||||
},
|
||||
|
||||
/**
|
||||
* 系统配置 API
|
||||
*/
|
||||
systemConfig: {
|
||||
/**
|
||||
* 获取系统配置
|
||||
*/
|
||||
get: () =>
|
||||
apiClient.post<ApiResponse<import('../types').SystemConfig>>('/system/config/get', {}),
|
||||
|
||||
/**
|
||||
* 更新 Builder API Key 配置
|
||||
*/
|
||||
updateBuilderApiKey: (data: import('../types').BuilderApiKeyUpdateRequest) =>
|
||||
apiClient.post<ApiResponse<import('../types').SystemConfig>>('/system/config/builder-api-key/update', data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -753,6 +753,24 @@ export interface NotificationConfigRequest {
|
||||
/**
|
||||
* 通知配置更新请求
|
||||
*/
|
||||
/**
|
||||
* 系统配置响应
|
||||
*/
|
||||
export interface SystemConfig {
|
||||
builderApiKeyConfigured: boolean
|
||||
builderSecretConfigured: boolean
|
||||
builderPassphraseConfigured: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder API Key 更新请求
|
||||
*/
|
||||
export interface BuilderApiKeyUpdateRequest {
|
||||
builderApiKey?: string
|
||||
builderSecret?: string
|
||||
builderPassphrase?: string
|
||||
}
|
||||
|
||||
export interface NotificationConfigUpdateRequest {
|
||||
id: number
|
||||
type: string
|
||||
|
||||
Reference in New Issue
Block a user