feat: 开源准备和功能优化
- 添加 MIT 许可证 - 创建完整的项目 README.md - 前端添加 GitHub 和 Twitter 链接 - 重构表名:copy_trading_accounts -> wallet_accounts - 更新 Account 实体类 - 添加数据库迁移脚本 V3 - 更新初始化脚本和文档 - 优化跟单订单类型:GTC -> FAK - 买入和卖出订单均使用 FAK (Fill-And-Kill) - 允许部分成交,未成交部分立即取消 - 提高跟单响应速度和价格匹配准确性
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 WrBug
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
# PolyHermes
|
||||||
|
|
||||||
|
[](https://github.com/WrBug/PolyHermes)
|
||||||
|
[](https://x.com/quant_tr)
|
||||||
|
|
||||||
|
一个功能强大的 Polymarket 预测市场跟单交易系统,支持自动化跟单、多账户管理、实时订单推送和统计分析。
|
||||||
|
|
||||||
|
## ✨ 功能特性
|
||||||
|
|
||||||
|
### 核心功能
|
||||||
|
- 🔐 **多账户管理**:支持通过私钥导入多个钱包账户,统一管理
|
||||||
|
- 👥 **Leader 管理**:添加和管理被跟单者(Leader),支持分类筛选(sports/crypto)
|
||||||
|
- 📊 **跟单配置**:灵活的跟单模板配置,支持比例跟单和固定金额跟单
|
||||||
|
- 🔄 **自动跟单**:实时监控 Leader 交易,自动复制订单(支持买入和卖出)
|
||||||
|
- 📈 **订单跟踪**:完整的订单生命周期跟踪,包括买入、卖出和匹配记录
|
||||||
|
- 📊 **统计分析**:全局统计、Leader 统计、分类统计,支持时间范围筛选
|
||||||
|
- 💼 **仓位管理**:实时查看和管理持仓,支持仓位推送
|
||||||
|
- ⚙️ **系统管理**:代理配置、API 健康检查、实时状态监控
|
||||||
|
|
||||||
|
### 技术特性
|
||||||
|
- 🌐 **WebSocket 实时推送**:订单和仓位数据实时推送
|
||||||
|
- 🔒 **安全存储**:私钥和 API 凭证加密存储
|
||||||
|
- 📱 **响应式设计**:完美支持移动端和桌面端
|
||||||
|
- 🚀 **高性能**:异步处理、并发优化
|
||||||
|
- 🛡️ **风险控制**:每日亏损限制、订单数限制、价格容忍度等
|
||||||
|
|
||||||
|
## 🏗️ 技术栈
|
||||||
|
|
||||||
|
### 后端
|
||||||
|
- **框架**: Spring Boot 3.2.0
|
||||||
|
- **语言**: Kotlin 1.9.20
|
||||||
|
- **数据库**: MySQL 8.2.0
|
||||||
|
- **ORM**: Spring Data JPA
|
||||||
|
- **数据库迁移**: Flyway
|
||||||
|
- **HTTP 客户端**: Retrofit 2.9.0 + OkHttp 4.12.0
|
||||||
|
- **WebSocket**: Spring WebSocket
|
||||||
|
|
||||||
|
### 前端
|
||||||
|
- **框架**: React 18 + TypeScript
|
||||||
|
- **构建工具**: Vite
|
||||||
|
- **UI 库**: Ant Design 5.12.0
|
||||||
|
- **HTTP 客户端**: axios
|
||||||
|
- **状态管理**: Zustand
|
||||||
|
- **路由**: React Router 6
|
||||||
|
- **以太坊库**: ethers.js 6.9.0
|
||||||
|
|
||||||
|
## 📦 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
polymarket-bot/
|
||||||
|
├── backend/ # 后端服务
|
||||||
|
│ ├── src/main/kotlin/ # Kotlin 源代码
|
||||||
|
│ │ ├── api/ # Polymarket API 接口定义
|
||||||
|
│ │ ├── controller/ # REST 控制器
|
||||||
|
│ │ ├── service/ # 业务逻辑服务
|
||||||
|
│ │ ├── entity/ # 数据库实体
|
||||||
|
│ │ ├── repository/ # 数据访问层
|
||||||
|
│ │ ├── dto/ # 数据传输对象
|
||||||
|
│ │ ├── websocket/ # WebSocket 处理
|
||||||
|
│ │ └── util/ # 工具类
|
||||||
|
│ └── src/main/resources/
|
||||||
|
│ ├── application.properties
|
||||||
|
│ └── db/migration/ # 数据库迁移脚本
|
||||||
|
├── frontend/ # 前端应用
|
||||||
|
│ ├── src/
|
||||||
|
│ │ ├── components/ # 公共组件
|
||||||
|
│ │ ├── pages/ # 页面组件
|
||||||
|
│ │ ├── services/ # API 服务
|
||||||
|
│ │ ├── types/ # TypeScript 类型
|
||||||
|
│ │ └── utils/ # 工具函数
|
||||||
|
│ └── package.json
|
||||||
|
├── docs/ # 文档
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 快速开始
|
||||||
|
|
||||||
|
### 前置要求
|
||||||
|
|
||||||
|
- JDK 17+
|
||||||
|
- Node.js 18+
|
||||||
|
- MySQL 8.0+
|
||||||
|
- Gradle 7.5+
|
||||||
|
|
||||||
|
### 安装步骤
|
||||||
|
|
||||||
|
1. **克隆仓库**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/WrBug/PolyHermes.git
|
||||||
|
cd PolyHermes
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **配置数据库**
|
||||||
|
|
||||||
|
创建 MySQL 数据库:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE DATABASE polymarket_bot CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **配置后端**
|
||||||
|
|
||||||
|
编辑 `backend/src/main/resources/application.properties`:
|
||||||
|
|
||||||
|
```properties
|
||||||
|
# 数据库配置
|
||||||
|
spring.datasource.url=jdbc:mysql://localhost:3306/polymarket_bot?useSSL=false&serverTimezone=UTC&characterEncoding=utf8mb4
|
||||||
|
spring.datasource.username=${DB_USERNAME:root}
|
||||||
|
spring.datasource.password=${DB_PASSWORD:your_password}
|
||||||
|
|
||||||
|
# 服务器端口
|
||||||
|
server.port=${SERVER_PORT:8000}
|
||||||
|
|
||||||
|
# Polygon RPC(用于查询链上余额)
|
||||||
|
polygon.rpc.url=${POLYGON_RPC_URL:https://polygon-rpc.com}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **启动后端**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
./gradlew bootRun
|
||||||
|
```
|
||||||
|
|
||||||
|
后端服务将在 `http://localhost:8000` 启动。
|
||||||
|
|
||||||
|
5. **启动前端**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
前端应用将在 `http://localhost:3000` 启动。
|
||||||
|
|
||||||
|
## 📖 使用指南
|
||||||
|
|
||||||
|
### 账户管理
|
||||||
|
|
||||||
|
1. 进入"账户管理"页面
|
||||||
|
2. 点击"导入账户"
|
||||||
|
3. 输入私钥(支持私钥字符串、助记词或 Keystore 文件)
|
||||||
|
4. 系统自动推导钱包地址并验证
|
||||||
|
5. 配置账户名称和是否默认账户
|
||||||
|
|
||||||
|
### 跟单配置
|
||||||
|
|
||||||
|
1. 进入"Leader 管理",添加被跟单者(Leader)地址
|
||||||
|
2. 进入"跟单模板",创建跟单模板(配置跟单比例、风险控制等)
|
||||||
|
3. 进入"跟单配置",将账户、模板和 Leader 关联
|
||||||
|
4. 启用跟单关系,系统将自动开始跟单
|
||||||
|
|
||||||
|
### 查看统计
|
||||||
|
|
||||||
|
- **全局统计**:查看所有跟单关系的汇总统计
|
||||||
|
- **Leader 统计**:查看特定 Leader 的统计信息
|
||||||
|
- **分类统计**:按分类(sports/crypto)查看统计
|
||||||
|
- **跟单关系统计**:查看单个跟单关系的详细统计
|
||||||
|
|
||||||
|
## 🔧 配置说明
|
||||||
|
|
||||||
|
### 环境变量
|
||||||
|
|
||||||
|
| 变量名 | 说明 | 默认值 |
|
||||||
|
|--------|------|--------|
|
||||||
|
| `DB_USERNAME` | 数据库用户名 | `root` |
|
||||||
|
| `DB_PASSWORD` | 数据库密码 | - |
|
||||||
|
| `SERVER_PORT` | 后端服务端口 | `8000` |
|
||||||
|
| `POLYGON_RPC_URL` | Polygon RPC 地址 | `https://polygon-rpc.com` |
|
||||||
|
| `JWT_SECRET` | JWT 密钥 | - |
|
||||||
|
|
||||||
|
### 代理配置
|
||||||
|
|
||||||
|
系统支持通过 Web UI 配置 HTTP 代理,无需修改环境变量:
|
||||||
|
|
||||||
|
1. 进入"系统管理"页面
|
||||||
|
2. 配置代理主机、端口、用户名和密码
|
||||||
|
3. 启用代理并测试连接
|
||||||
|
4. 配置实时生效,无需重启服务
|
||||||
|
|
||||||
|
## 📚 API 文档
|
||||||
|
|
||||||
|
详细的 API 文档请参考:
|
||||||
|
- [跟单系统需求文档](docs/copy-trading-requirements.md)
|
||||||
|
- [前端需求文档](docs/copy-trading-frontend-requirements.md)
|
||||||
|
|
||||||
|
## 🤝 贡献
|
||||||
|
|
||||||
|
欢迎贡献代码!请遵循以下步骤:
|
||||||
|
|
||||||
|
1. Fork 本仓库
|
||||||
|
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
|
||||||
|
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
|
||||||
|
4. 推送到分支 (`git push origin feature/AmazingFeature`)
|
||||||
|
5. 开启 Pull Request
|
||||||
|
|
||||||
|
## 📝 开发规范
|
||||||
|
|
||||||
|
- **后端**: 遵循 Kotlin 编码规范,使用 Spring Boot 最佳实践
|
||||||
|
- **前端**: 遵循 TypeScript 和 React 最佳实践
|
||||||
|
- **提交信息**: 使用清晰的提交信息,遵循 [Conventional Commits](https://www.conventionalcommits.org/)
|
||||||
|
|
||||||
|
详细开发规范请参考:
|
||||||
|
- [后端开发规范](.cursor/rules/backend.mdc)
|
||||||
|
- [前端开发规范](.cursor/rules/frontend.mdc)
|
||||||
|
|
||||||
|
## ⚠️ 免责声明
|
||||||
|
|
||||||
|
本软件仅供学习和研究使用。使用本软件进行交易的风险由用户自行承担。作者不对任何交易损失负责。
|
||||||
|
|
||||||
|
## 📄 许可证
|
||||||
|
|
||||||
|
本项目采用 MIT 许可证。详情请参阅 [LICENSE](LICENSE) 文件。
|
||||||
|
|
||||||
|
## 🔗 相关链接
|
||||||
|
|
||||||
|
- [GitHub 仓库](https://github.com/WrBug/PolyHermes)
|
||||||
|
- [Twitter](https://x.com/quant_tr)
|
||||||
|
- [Polymarket 官网](https://polymarket.com)
|
||||||
|
- [Polymarket API 文档](https://docs.polymarket.com)
|
||||||
|
|
||||||
|
## 🙏 致谢
|
||||||
|
|
||||||
|
感谢所有为本项目做出贡献的开发者和用户!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**⭐ 如果这个项目对你有帮助,请给个 Star!**
|
||||||
|
|
||||||
@@ -4,10 +4,10 @@ import jakarta.persistence.*
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 账户信息实体
|
* 账户信息实体
|
||||||
* 用于存储跟单者的账户信息(支持多账户)
|
* 用于存储钱包账户信息(支持多账户)
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "copy_trading_accounts")
|
@Table(name = "wallet_accounts")
|
||||||
data class Account(
|
data class Account(
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
|||||||
@@ -461,10 +461,12 @@ class CopyOrderTrackingService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 8. 构建订单请求
|
// 8. 构建订单请求
|
||||||
|
// 跟单订单使用 FAK (Fill-And-Kill),允许部分成交,未成交部分立即取消
|
||||||
|
// 这样可以快速响应 Leader 的交易,避免订单长期挂单导致价格不匹配
|
||||||
val orderRequest = NewOrderRequest(
|
val orderRequest = NewOrderRequest(
|
||||||
order = signedOrder,
|
order = signedOrder,
|
||||||
owner = account.apiKey!!,
|
owner = account.apiKey!!,
|
||||||
orderType = "GTC", // Good-Til-Cancelled
|
orderType = "FAK", // Fill-And-Kill
|
||||||
deferExec = false
|
deferExec = false
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -584,10 +586,12 @@ class CopyOrderTrackingService(
|
|||||||
)
|
)
|
||||||
|
|
||||||
// 构建订单请求(每次重试都使用新签名的订单)
|
// 构建订单请求(每次重试都使用新签名的订单)
|
||||||
|
// 跟单订单使用 FAK (Fill-And-Kill),允许部分成交,未成交部分立即取消
|
||||||
|
// 这样可以快速响应 Leader 的交易,避免订单长期挂单导致价格不匹配
|
||||||
val orderRequest = NewOrderRequest(
|
val orderRequest = NewOrderRequest(
|
||||||
order = signedOrder,
|
order = signedOrder,
|
||||||
owner = owner, // API Key
|
owner = owner, // API Key
|
||||||
orderType = "GTC", // Good-Til-Cancelled
|
orderType = "FAK", // Fill-And-Kill
|
||||||
deferExec = false
|
deferExec = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
-- ============================================
|
-- ============================================
|
||||||
-- 1. 创建账户表
|
-- 1. 创建账户表
|
||||||
-- ============================================
|
-- ============================================
|
||||||
CREATE TABLE IF NOT EXISTS copy_trading_accounts (
|
CREATE TABLE IF NOT EXISTS wallet_accounts (
|
||||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||||
private_key VARCHAR(500) NOT NULL COMMENT '私钥(加密存储)',
|
private_key VARCHAR(500) NOT NULL COMMENT '私钥(加密存储)',
|
||||||
wallet_address VARCHAR(42) NOT NULL UNIQUE COMMENT '钱包地址(从私钥推导)',
|
wallet_address VARCHAR(42) NOT NULL UNIQUE COMMENT '钱包地址(从私钥推导)',
|
||||||
@@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS copy_trading_accounts (
|
|||||||
updated_at BIGINT NOT NULL COMMENT '更新时间(毫秒时间戳)',
|
updated_at BIGINT NOT NULL COMMENT '更新时间(毫秒时间戳)',
|
||||||
INDEX idx_wallet_address (wallet_address),
|
INDEX idx_wallet_address (wallet_address),
|
||||||
INDEX idx_is_default (is_default)
|
INDEX idx_is_default (is_default)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='跟单系统账户表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='钱包账户表';
|
||||||
|
|
||||||
-- ============================================
|
-- ============================================
|
||||||
-- 2. 创建被跟单者(Leader)表
|
-- 2. 创建被跟单者(Leader)表
|
||||||
@@ -77,7 +77,7 @@ CREATE TABLE IF NOT EXISTS copy_trading (
|
|||||||
INDEX idx_template_id (template_id),
|
INDEX idx_template_id (template_id),
|
||||||
INDEX idx_leader_id (leader_id),
|
INDEX idx_leader_id (leader_id),
|
||||||
INDEX idx_enabled (enabled),
|
INDEX idx_enabled (enabled),
|
||||||
FOREIGN KEY (account_id) REFERENCES copy_trading_accounts(id) ON DELETE CASCADE,
|
FOREIGN KEY (account_id) REFERENCES wallet_accounts(id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (template_id) REFERENCES copy_trading_templates(id) ON DELETE RESTRICT,
|
FOREIGN KEY (template_id) REFERENCES copy_trading_templates(id) ON DELETE RESTRICT,
|
||||||
FOREIGN KEY (leader_id) REFERENCES copy_trading_leaders(id) ON DELETE CASCADE
|
FOREIGN KEY (leader_id) REFERENCES copy_trading_leaders(id) ON DELETE CASCADE
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='跟单关系表(钱包-模板关联)';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='跟单关系表(钱包-模板关联)';
|
||||||
|
|||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
-- ============================================
|
||||||
|
-- 重命名账户表:copy_trading_accounts -> wallet_accounts
|
||||||
|
-- ============================================
|
||||||
|
|
||||||
|
-- 检查表是否存在,如果存在则重命名
|
||||||
|
-- 注意:此迁移脚本假设表已经存在(从 V1 迁移创建)
|
||||||
|
|
||||||
|
-- 1. 查找外键约束名称并删除
|
||||||
|
SET @fk_name = NULL;
|
||||||
|
SELECT CONSTRAINT_NAME INTO @fk_name
|
||||||
|
FROM information_schema.KEY_COLUMN_USAGE
|
||||||
|
WHERE TABLE_SCHEMA = DATABASE()
|
||||||
|
AND TABLE_NAME = 'copy_trading'
|
||||||
|
AND COLUMN_NAME = 'account_id'
|
||||||
|
AND REFERENCED_TABLE_NAME = 'copy_trading_accounts'
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- 2. 如果找到外键,删除它
|
||||||
|
SET @drop_fk_sql = IF(@fk_name IS NOT NULL,
|
||||||
|
CONCAT('ALTER TABLE copy_trading DROP FOREIGN KEY `', @fk_name, '`'),
|
||||||
|
'SELECT 1');
|
||||||
|
PREPARE stmt FROM @drop_fk_sql;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
-- 3. 重命名表
|
||||||
|
RENAME TABLE copy_trading_accounts TO wallet_accounts;
|
||||||
|
|
||||||
|
-- 4. 重新添加外键约束
|
||||||
|
ALTER TABLE copy_trading
|
||||||
|
ADD CONSTRAINT fk_copy_trading_account_id
|
||||||
|
FOREIGN KEY (account_id) REFERENCES wallet_accounts(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
-- 5. 更新表注释
|
||||||
|
ALTER TABLE wallet_accounts COMMENT = '钱包账户表';
|
||||||
|
|
||||||
@@ -580,7 +580,7 @@
|
|||||||
### 3.1 Account(账户信息)
|
### 3.1 Account(账户信息)
|
||||||
```kotlin
|
```kotlin
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "copy_trading_accounts")
|
@Table(name = "wallet_accounts")
|
||||||
data class Account(
|
data class Account(
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@@ -1623,7 +1623,7 @@ const address = account.address;
|
|||||||
## 7. 数据库设计
|
## 7. 数据库设计
|
||||||
|
|
||||||
### 7.1 表结构
|
### 7.1 表结构
|
||||||
- `copy_trading_accounts`: 账户信息表
|
- `wallet_accounts`: 钱包账户表
|
||||||
- `copy_trading_leaders`: 被跟单者表
|
- `copy_trading_leaders`: 被跟单者表
|
||||||
- `copy_trading_templates`: 跟单模板表
|
- `copy_trading_templates`: 跟单模板表
|
||||||
- `copy_trading`: 跟单关系表(钱包-模板关联,多对多)
|
- `copy_trading`: 跟单关系表(钱包-模板关联,多对多)
|
||||||
@@ -1632,7 +1632,7 @@ const address = account.address;
|
|||||||
- `copy_trading_processed_trades`: 已处理交易表(用于去重)
|
- `copy_trading_processed_trades`: 已处理交易表(用于去重)
|
||||||
|
|
||||||
### 7.2 索引设计
|
### 7.2 索引设计
|
||||||
- `copy_trading_accounts.wallet_address`: UNIQUE 索引
|
- `wallet_accounts.wallet_address`: UNIQUE 索引
|
||||||
- `copy_trading_leaders.leader_address`: UNIQUE 索引
|
- `copy_trading_leaders.leader_address`: UNIQUE 索引
|
||||||
- `copy_trading_templates.template_name`: UNIQUE 索引
|
- `copy_trading_templates.template_name`: UNIQUE 索引
|
||||||
- `copy_trading.account_id + template_id + leader_id`: 联合唯一索引
|
- `copy_trading.account_id + template_id + leader_id`: 联合唯一索引
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ import {
|
|||||||
AppstoreOutlined,
|
AppstoreOutlined,
|
||||||
TeamOutlined,
|
TeamOutlined,
|
||||||
LogoutOutlined,
|
LogoutOutlined,
|
||||||
SettingOutlined
|
SettingOutlined,
|
||||||
|
GithubOutlined,
|
||||||
|
TwitterOutlined
|
||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import type { MenuProps } from 'antd'
|
import type { MenuProps } from 'antd'
|
||||||
import type { ReactNode } from 'react'
|
import type { ReactNode } from 'react'
|
||||||
@@ -172,12 +174,30 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
|||||||
<div style={{ color: '#fff', fontSize: '18px', fontWeight: 'bold' }}>
|
<div style={{ color: '#fff', fontSize: '18px', fontWeight: 'bold' }}>
|
||||||
PolyHermes
|
PolyHermes
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
|
||||||
type="text"
|
<a
|
||||||
icon={<MenuOutlined />}
|
href="https://github.com/WrBug/PolyHermes"
|
||||||
style={{ color: '#fff' }}
|
target="_blank"
|
||||||
onClick={() => setMobileMenuOpen(true)}
|
rel="noopener noreferrer"
|
||||||
/>
|
style={{ color: '#fff', fontSize: '18px' }}
|
||||||
|
>
|
||||||
|
<GithubOutlined />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://x.com/quant_tr"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
style={{ color: '#fff', fontSize: '18px' }}
|
||||||
|
>
|
||||||
|
<TwitterOutlined />
|
||||||
|
</a>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<MenuOutlined />}
|
||||||
|
style={{ color: '#fff' }}
|
||||||
|
onClick={() => setMobileMenuOpen(true)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</Header>
|
</Header>
|
||||||
<Content style={{
|
<Content style={{
|
||||||
padding: '12px 8px',
|
padding: '12px 8px',
|
||||||
@@ -225,13 +245,34 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
|||||||
height: '64px',
|
height: '64px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'space-between',
|
||||||
|
padding: '0 16px',
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
fontSize: '18px',
|
fontSize: '18px',
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
flexShrink: 0
|
flexShrink: 0
|
||||||
}}>
|
}}>
|
||||||
PolyHermes
|
<span>PolyHermes</span>
|
||||||
|
<div style={{ display: 'flex', gap: '12px' }}>
|
||||||
|
<a
|
||||||
|
href="https://github.com/WrBug/PolyHermes"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
style={{ color: '#fff', fontSize: '16px' }}
|
||||||
|
title="GitHub"
|
||||||
|
>
|
||||||
|
<GithubOutlined />
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://x.com/quant_tr"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
style={{ color: '#fff', fontSize: '16px' }}
|
||||||
|
title="Twitter"
|
||||||
|
>
|
||||||
|
<TwitterOutlined />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Menu
|
<Menu
|
||||||
mode="inline"
|
mode="inline"
|
||||||
|
|||||||
Reference in New Issue
Block a user