diff --git a/.github/workflows/telegram-notify.yml b/.github/workflows/telegram-notify.yml deleted file mode 100644 index 7ae205c..0000000 --- a/.github/workflows/telegram-notify.yml +++ /dev/null @@ -1,103 +0,0 @@ -name: Telegram Notification on PR Merge - -on: - pull_request: - types: - - closed # 当 PR 被关闭(合并或关闭)时触发 - -jobs: - notify: - runs-on: ubuntu-latest - - # 只在 PR 被合并到 main 分支时执行 - if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main' - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Get PR details - id: pr_details - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - PR_NUMBER="${{ github.event.pull_request.number }}" - REPO="${{ github.repository }}" - - # 获取 PR 详细信息 - PR_RESPONSE=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \ - -H "Accept: application/vnd.github.v3+json" \ - "https://api.github.com/repos/${REPO}/pulls/${PR_NUMBER}") - - # 获取 PR 变更的文件列表 - FILES_RESPONSE=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \ - -H "Accept: application/vnd.github.v3+json" \ - "https://api.github.com/repos/${REPO}/pulls/${PR_NUMBER}/files") - - # 提取 PR 描述(body),保留换行,限制长度 - PR_BODY=$(echo "$PR_RESPONSE" | jq -r '.body // ""') - if [ ${#PR_BODY} -gt 500 ]; then - PR_BODY="${PR_BODY:0:500}..." - fi - - # 保存到输出变量(使用 base64 编码避免特殊字符问题) - echo "pr_body<> $GITHUB_OUTPUT - echo "$PR_BODY" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - - - name: Send Telegram notification - env: - TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }} - TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }} - run: | - # 检查 PR 是否被合并(而不是仅关闭) - PR_MERGED="${{ github.event.pull_request.merged }}" - if [ "$PR_MERGED" != "true" ]; then - echo "ℹ️ PR 仅关闭,未合并,跳过通知" - exit 0 - fi - - # 检查必要的环境变量 - # 注意:TELEGRAM_CHAT_ID 可以是个人聊天 ID(正数)或群组 ID(负数,如 -1001234567890) - if [ -z "$TELEGRAM_BOT_TOKEN" ] || [ -z "$TELEGRAM_CHAT_ID" ]; then - echo "⚠️ Telegram Bot Token 或 Chat ID 未配置,跳过通知" - exit 0 - fi - - # 获取 PR 基本信息 - PR_NUMBER="${{ github.event.pull_request.number }}" - PR_TITLE="${{ github.event.pull_request.title }}" - PR_URL="${{ github.event.pull_request.html_url }}" - PR_MERGE_COMMIT="${{ github.event.pull_request.merge_commit_sha }}" - - # 获取 PR 详细信息 - PR_BODY="${{ steps.pr_details.outputs.pr_body }}" - - # 转义 PR 标题中的 HTML 特殊字符 - PR_TITLE_ESCAPED=$(echo "$PR_TITLE" | sed 's/&/\&/g' | sed 's//\>/g') - - # 构建消息内容(仅包含关键信息) - MESSAGE="🚀 main 分支代码更新"$'\n'$'\n'"📝 PR #${PR_NUMBER}: ${PR_TITLE_ESCAPED}"$'\n'"🔗 查看 PR" - - # 发送 Telegram 消息(使用 jq 转义 JSON) - curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ - -H "Content-Type: application/json" \ - -d "$(jq -n \ - --arg chat_id "$TELEGRAM_CHAT_ID" \ - --arg text "$MESSAGE" \ - '{chat_id: $chat_id, text: $text, parse_mode: "HTML", disable_web_page_preview: false}')" > /tmp/telegram_response.json - - # 检查发送结果 - if [ $? -eq 0 ]; then - RESPONSE=$(cat /tmp/telegram_response.json) - if echo "$RESPONSE" | grep -q '"ok":true'; then - echo "✅ Telegram 通知发送成功" - else - echo "❌ Telegram 通知发送失败: $RESPONSE" - exit 1 - fi - else - echo "❌ 发送 Telegram 消息时发生错误" - exit 1 - fi - diff --git a/RELEASE_NOTES_v2.0.3.md b/RELEASE_NOTES_v2.0.3.md new file mode 100644 index 0000000..db6382a --- /dev/null +++ b/RELEASE_NOTES_v2.0.3.md @@ -0,0 +1,241 @@ +# PolyHermes v2.0.3 Release Notes + +## 📋 版本信息 +- **版本号**: v2.0.3 +- **发布日期**: 2026-01-31 +- **基础版本**: v2.0.2 + +## 🎯 改动摘要 + +本次版本主要优化了用户界面显示,包括数值格式化、Leader列表优化、移除不必要的配置项,提升了用户体验。 + +--- + +## ✨ 新功能 + +### 1. 为所有数值显示添加千分位分隔符 + +**功能描述**: +- ✅ 重构 `formatNumber` 和 `formatUSDC` 函数,默认添加千分位分隔符 +- ✅ 所有数值(金额、数量、价格等)现在默认显示千分位 +- ✅ 自动去除尾随零,提升可读性 +- ✅ 示例:`1234567.89` 显示为 `1,234,567.89` + +**影响范围**: +- `frontend/src/utils/index.ts` - 工具函数 +- `frontend/src/pages/Statistics.tsx` - 统计页面 +- `frontend/src/pages/CopyTradingStatistics.tsx` - 跟单统计页面 +- `frontend/src/pages/PositionList.tsx` - 持仓列表 +- `frontend/src/pages/AccountList.tsx` - 账户列表 + +**提交**: 40081c2 + +--- + +### 2. 在创建跟单配置时显示Leader资产信息 + +**功能描述**: +- ✅ 选择Leader后自动获取并显示资产信息 +- ✅ 显示总资产、可用余额、仓位资产 +- ✅ 使用Card和Statistic组件美观展示 +- ✅ 支持中英文多语言 +- ✅ 使用formatUSDC格式化显示金额 + +**影响范围**: +- `frontend/src/pages/CopyTradingOrders/AddModal.tsx` - 添加跟单配置弹窗 +- `frontend/src/pages/CopyTradingOrders/EditModal.tsx` - 编辑跟单配置弹窗 +- `frontend/src/locales/**/common.json` - 多语言文件 + +**提交**: 390b3ee + +--- + +### 3. Leader列表显示仓位资产 + +**功能描述**: +- ✅ Leader列表新增仓位资产显示 +- ✅ 显示Leader的总资产、可用余额、仓位资产 +- ✅ 优化资产信息展示方式 + +**影响范围**: +- `frontend/src/pages/LeaderList.tsx` - Leader列表页面 +- `backend/src/main/kotlin/com/wrbug/polymarketbot/dto/LeaderDto.kt` - Leader DTO +- `backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/leaders/LeaderService.kt` - Leader服务 + +**提交**: 3350039 + +--- + +## 🔧 优化改进 + +### 1. Leader列表优化 + +**改进内容**: +- ✅ 后端过滤价值为0的仓位 +- ✅ 持仓列表显示市场名称而非ID +- ✅ 列表移除分类和创建时间列 +- ✅ 文案'跟单关系数'改为'跟单数' +- ✅ 持仓DTO添加title字段 + +**影响范围**: +- `frontend/src/pages/LeaderList.tsx` - Leader列表页面 +- `backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/leaders/LeaderService.kt` - Leader服务 +- `backend/src/main/kotlin/com/wrbug/polymarketbot/service/common/BlockchainService.kt` - 区块链服务 + +**提交**: 0bdc0c7 + +--- + +### 2. 列表只显示可用余额 + +**改进内容**: +- ✅ 账户列表和Leader列表只显示可用余额 +- ✅ 简化界面,减少信息冗余 + +**影响范围**: +- `frontend/src/pages/AccountList.tsx` - 账户列表 +- `backend/src/main/kotlin/com/wrbug/polymarketbot/service/accounts/AccountService.kt` - 账户服务 + +**提交**: 17eea01 + +--- + +### 3. 移除仓位资产列 + +**改进内容**: +- ✅ 移除不必要的仓位资产列显示 +- ✅ 简化界面布局 + +**影响范围**: +- `frontend/src/pages/PositionList.tsx` - 持仓列表 + +**提交**: 6980781 + +--- + +## 🗑️ 移除功能 + +### 移除跟单最大仓位数量(maxPositionCount)配置 + +**移除原因**: +- 该配置项使用频率低,且增加了系统复杂度 +- 简化跟单配置,提升用户体验 + +**移除内容**: +- ✅ 数据库:创建迁移文件 V26 删除 `max_position_count` 字段 +- ✅ 后端:移除实体类、DTO、服务中的 `maxPositionCount` 相关代码 +- ✅ 后端:移除 `FilterResult` 中的 `FAILED_MAX_POSITION_COUNT` 状态 +- ✅ 后端:移除 `CopyTradingFilterService` 中的最大仓位数量检查逻辑 +- ✅ 前端:移除类型定义、表单字段和国际化翻译 +- ✅ 前端:移除过滤订单列表中的 `MAX_POSITION_COUNT` 类型 + +**影响范围**: +- `backend/src/main/resources/db/migration/V26__remove_max_position_count.sql` - 数据库迁移 +- `backend/src/main/kotlin/com/wrbug/polymarketbot/entity/CopyTrading.kt` - 实体类 +- `backend/src/main/kotlin/com/wrbug/polymarketbot/dto/CopyTradingDto.kt` - DTO +- `backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/configs/CopyTradingFilterService.kt` - 过滤服务 +- `frontend/src/pages/CopyTradingOrders/AddModal.tsx` - 添加表单 +- `frontend/src/pages/CopyTradingOrders/EditModal.tsx` - 编辑表单 +- `frontend/src/types/index.ts` - 类型定义 + +**提交**: e8fd1b5 + +--- + +## 🐛 Bug 修复 + +### 修复TypeScript类型错误 + +**修复内容**: +- ✅ 修复编译时的TypeScript类型错误 +- ✅ 修复Spin导入问题 +- ✅ 修复Table fixed类型问题 +- ✅ 修复size类型问题 + +**影响范围**: +- `frontend/src/pages/LeaderList.tsx` - Leader列表页面 + +**提交**: 8097660 + +--- + +## ⚠️ 潜在问题和注意事项 + +### 1. 数值格式化变更 + +**影响**: +- 所有数值现在默认显示千分位分隔符 +- 如果之前有代码依赖特定的数值格式,可能需要调整 + +**建议**: +- 检查是否有代码依赖特定的数值格式 +- 确认数值显示是否符合预期 + +### 2. 移除maxPositionCount配置 + +**影响**: +- 如果之前使用了最大仓位数量限制功能,升级后将不再可用 +- 需要手动调整跟单策略 + +**建议**: +- 升级前检查是否有跟单配置使用了最大仓位数量限制 +- 如有需要,可以手动调整跟单策略 + +### 3. Leader列表显示变更 + +**影响**: +- Leader列表现在只显示价值大于0的仓位 +- 列表布局和显示内容有所调整 + +**建议**: +- 升级后检查Leader列表显示是否符合预期 +- 确认仓位信息是否正确显示 + +--- + +## 📊 文件变更统计 + +- **修改文件数**: 28 +- **新增行数**: 1490 +- **删除行数**: 897 + +--- + +## 🔄 升级建议 + +1. **检查数值显示**: + - 升级后检查所有数值显示是否符合预期 + - 确认千分位分隔符显示正确 + +2. **检查跟单配置**: + - 如果有使用最大仓位数量限制的配置,需要手动调整 + - 确认跟单功能正常工作 + +3. **检查Leader列表**: + - 升级后检查Leader列表显示是否正确 + - 确认仓位信息是否完整 + +4. **数据库迁移**: + - 升级时会自动执行数据库迁移 V26 + - 迁移会删除 `max_position_count` 字段 + - 建议在升级前备份数据库 + +--- + +## 📝 完整提交列表 + +- 40081c2 - feat: 为所有数值显示添加千分位分隔符 +- e8fd1b5 - 移除跟单最大仓位数量(maxPositionCount)配置 +- 390b3ee - feat: 在创建跟单配置时显示Leader资产信息 +- 8097660 - fix: 修复TypeScript类型错误 +- 17eea01 - refactor: 列表只显示可用余额 +- 6980781 - refactor: 移除仓位资产列 +- 3350039 - feat: Leader列表显示仓位资产 +- 0bdc0c7 - feat: Leader列表优化 + +--- + +## 🙏 致谢 + +感谢所有贡献者和用户的支持与反馈! + diff --git a/frontend/src/pages/AccountList.tsx b/frontend/src/pages/AccountList.tsx index 3314493..4066038 100644 --- a/frontend/src/pages/AccountList.tsx +++ b/frontend/src/pages/AccountList.tsx @@ -26,18 +26,18 @@ const AccountList: React.FC = () => { const [editLoading, setEditLoading] = useState(false) const [accountImportModalVisible, setAccountImportModalVisible] = useState(false) const [accountImportForm] = Form.useForm() - + useEffect(() => { fetchAccounts() }, [fetchAccounts]) - + const handleAccountImportSuccess = async () => { message.success(t('accountImport.importSuccess')) setAccountImportModalVisible(false) accountImportForm.resetFields() fetchAccounts() } - + // 加载所有账户的余额 useEffect(() => { const loadBalances = async () => { @@ -46,8 +46,8 @@ const AccountList: React.FC = () => { setBalanceLoading(prev => ({ ...prev, [account.id]: true })) try { const balanceData = await fetchAccountBalance(account.id) - setBalanceMap(prev => ({ - ...prev, + setBalanceMap(prev => ({ + ...prev, [account.id]: { total: balanceData.totalBalance || '0', available: balanceData.availableBalance || '0', @@ -56,8 +56,8 @@ const AccountList: React.FC = () => { })) } catch (error) { console.error(`获取账户 ${account.id} 余额失败:`, error) - setBalanceMap(prev => ({ - ...prev, + setBalanceMap(prev => ({ + ...prev, [account.id]: { total: '-', available: '-', position: '-' } })) } finally { @@ -66,12 +66,12 @@ const AccountList: React.FC = () => { } } } - + if (accounts.length > 0) { loadBalances() } }, [accounts]) - + const handleDelete = async (account: Account) => { try { await deleteAccount(account.id) @@ -80,13 +80,13 @@ const AccountList: React.FC = () => { message.error(error.message || t('accountList.deleteFailed')) } } - + const handleCopy = (text: string) => { if (!text) { message.warning(t('accountList.copyFailed') || '复制失败:地址为空') return } - + if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(text).then(() => { message.success({ @@ -103,7 +103,7 @@ const AccountList: React.FC = () => { fallbackCopyTextToClipboard(text) } } - + const fallbackCopyTextToClipboard = (text: string) => { const textArea = document.createElement('textarea') textArea.value = text @@ -113,7 +113,7 @@ const AccountList: React.FC = () => { document.body.appendChild(textArea) textArea.focus() textArea.select() - + try { const successful = document.execCommand('copy') if (successful) { @@ -131,19 +131,19 @@ const AccountList: React.FC = () => { document.body.removeChild(textArea) } } - + const handleShowDetail = async (account: Account) => { try { setDetailModalVisible(true) setDetailAccount(account) setDetailBalance(null) setDetailBalanceLoading(false) - + // 加载详情和余额 try { const accountDetail = await fetchAccountDetail(account.id) setDetailAccount(accountDetail) - + // 加载余额 setDetailBalanceLoading(true) try { @@ -173,10 +173,10 @@ const AccountList: React.FC = () => { setDetailAccount(null) } } - + const handleRefreshDetailBalance = async () => { if (!detailAccount) return - + setDetailBalanceLoading(true) try { const balanceData = await fetchAccountBalance(detailAccount.id) @@ -193,16 +193,16 @@ const AccountList: React.FC = () => { setDetailBalanceLoading(false) } } - + const handleShowEdit = async (account: Account) => { try { setEditModalVisible(true) setEditAccount(account) - + // 加载账户详情并设置表单初始值 const accountDetail = await fetchAccountDetail(account.id) setEditAccount(accountDetail) - + editForm.setFieldsValue({ accountName: accountDetail.accountName || '', apiKey: '', // 不显示实际值,留空表示不修改 @@ -216,10 +216,10 @@ const AccountList: React.FC = () => { setEditAccount(null) } } - + const handleEditSubmit = async (values: any) => { if (!editAccount) return - + setEditLoading(true) try { // 构建更新请求,只支持编辑账户名称 @@ -227,17 +227,17 @@ const AccountList: React.FC = () => { accountId: editAccount.id, accountName: values.accountName || undefined } - + await updateAccount(updateData) - + message.success(t('accountList.updateSuccess')) setEditModalVisible(false) setEditAccount(null) editForm.resetFields() - + // 刷新账户列表 await fetchAccounts() - + // 如果详情 Modal 打开着,也刷新详情 if (detailModalVisible && detailAccount && detailAccount.id === editAccount.id) { const accountDetail = await fetchAccountDetail(editAccount.id) @@ -249,7 +249,7 @@ const AccountList: React.FC = () => { setEditLoading(false) } } - + const columns = [ { title: t('accountList.accountName'), @@ -339,7 +339,7 @@ const AccountList: React.FC = () => { { ) } ] - + const mobileColumns = [ { title: t('accountList.accountName'), @@ -364,16 +364,16 @@ const AccountList: React.FC = () => { render: (_: any, record: Account) => { return (
-
{record.accountName || `${t('accountList.accountName')} ${record.id}`}
-
{ />
-
{ )}
{balanceMap[record.id] && balanceMap[record.id].available !== '-' && ( -
{ { cancelText={t('common.cancel')} okButtonProps={{ danger: true }} > -
- - @@ -544,7 +544,7 @@ const AccountList: React.FC = () => { /> )} - + {/* 账户详情 Modal */} { setDetailBalance(null) }} footer={[ - , - , -