diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 53deead2..1b2fcabf 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -428,7 +428,19 @@ "Bash(dir /b \"c:\\\\Users\\\\dong\\\\Desktop\\\\rwadurian\")", "Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(reward-service\\): 权益分配memo显示触发用户ID\n\n所有权益类型的memo现在统一显示\"来自用户xxx的认种\"格式:\n- 省团队权益:来自用户xxx的认种\n- 省区域权益:来自用户xxx的认种\n- 市团队权益:来自用户xxx的认种\n- 市区域权益:来自用户xxx的认种\n- 社区权益:来自用户xxx的认种\n\n修改前只显示\"xx权益已激活\",现在与分享权益格式保持一致\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", "Bash(echo \"请运行以下命令查看 D25122600005 的认种记录:\n\ndocker exec -it rwa-postgres psql -U rwa_user -d rwa_planting -c \"\"\nSELECT order_no, account_sequence, tree_count, status, created_at\nFROM planting_orders\nWHERE account_sequence = ''D25122600005''\nORDER BY created_at DESC;\n\"\"\")", - "Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(wallet-service\\): 修复社区权益根据 targetId 正确分配\n\n问题:社区权益\\(COMMUNITY_RIGHT\\)无论 targetId 是什么,都强制分配到\n总部账户 S0000000001,导致社区授权人无法在流水明细中看到社区权益。\n\n修复:\n- 将 allocateToHeadquartersCommunity 方法重命名为 allocateCommunityRight\n- 根据 targetId 判断分配目标:\n - D 开头(用户账户): 分配到社区授权人账户\n - S 开头或 ''1''(系统账户): 分配到总部社区账户\n- 更新流水备注以区分用户分配和总部分配\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")" + "Bash(git commit -m \"$\\(cat <<''EOF''\nfix\\(wallet-service\\): 修复社区权益根据 targetId 正确分配\n\n问题:社区权益\\(COMMUNITY_RIGHT\\)无论 targetId 是什么,都强制分配到\n总部账户 S0000000001,导致社区授权人无法在流水明细中看到社区权益。\n\n修复:\n- 将 allocateToHeadquartersCommunity 方法重命名为 allocateCommunityRight\n- 根据 targetId 判断分配目标:\n - D 开头(用户账户): 分配到社区授权人账户\n - S 开头或 ''1''(系统账户): 分配到总部社区账户\n- 更新流水备注以区分用户分配和总部分配\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", + "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(mobile-app\\): 优化流水明细筛选选项\n\n- 将\"奖励转可结算\"改为\"分享收益\",更准确描述分享权益\n- 新增\"权益收入\"筛选项\\(SYSTEM_ALLOCATION\\),用于筛选:\n - 社区权益\n - 市/省团队权益\n - 市/省区域权益\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", + "Bash(chcp 65001)", + "Bash(cmd /c \"chcp 65001 && python -c \"\"import openpyxl; import sys; sys.stdout.reconfigure\\(encoding=''utf-8''\\); wb = openpyxl.load_workbook\\(r''c:\\\\Users\\\\dong\\\\Desktop\\\\rwadurian\\\\榴莲皇后数据.xlsx''\\); print\\(''Sheets:'', wb.sheetnames\\); sheet = wb.active; print\\(''Rows:'', sheet.max_row, ''Cols:'', sheet.max_column\\); [print\\(f''Row {i}:'', row\\) for i, row in enumerate\\(sheet.iter_rows\\(max_row=5, values_only=True\\), 1\\)]\"\"\")", + "Bash(node scripts/batch-register.js:*)", + "Bash(node batch-register.js:*)", + "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(mobile-app\\): 隐藏\"我的团队\"功能,需秘密点击解锁\n\n- 默认隐藏\"我的团队\"树形组件\n- 在\"团队种植数\"区域连续点击19次后显示\n- 点击间隔超过1秒自动重置计数器\n- 退出页面后状态自动重置\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", + "Bash(git commit -m \"$\\(cat <<''EOF''\nrefactor\\(mobile-app\\): 修改\"我的\"页面文案\n\n- \"直推人数\" → \"引荐\"\n- \"个人种植数\" → \"个人种植树\"\n- \"团队种植数\" → \"团队种植树\"\n- \"直推列表\" → \"引荐列表\"\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", + "Bash(git commit -m \"$\\(cat <<''EOF''\nrefactor\\(mobile-app\\): 修改\"我的团队\"文案为\"我的同僚\"\n\n- \"我的团队\" → \"我的同僚\"\n- \"暂无团队成员\" → \"暂无同僚\"\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", + "Bash(npx jest --testPathPattern=\"referral\" --passWithNoTests)", + "Bash(npx jest --testPathPattern=\"wallet\" --passWithNoTests)", + "Bash(git commit -m \"$\\(cat <<''EOF''\nrefactor\\(mobile-app\\): 修改\"我的\"页面文案\n\n- \"个人种植树\" → \"本人种植树\"\n- 引荐列表中 \"个人/团队\" → \"本人/同僚\"\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")", + "Bash(git commit -m \"$\\(cat <<''EOF''\nfeat\\(identity-service\\): 增强钱包生成可靠性,确保100%生成成功\n\n核心改进:\n- 基于数据库扫描代替Redis扫描,防止状态丢失后无法重试\n- 指数退避策略\\(1分钟→60分钟\\),无时间限制持续重试\n- 分布式锁保护,防止多实例/并发重复触发\n- getWalletStatus API 检测失败状态并自动触发重试\n\n修改内容:\n- RedisService: 添加 tryLock/unlock 分布式锁方法\n- UserAccountRepository: 添加 findUsersWithIncompleteWallets 查询\n- getWalletStatus: 增强状态检测,失败/超时时自动触发重试\n- WalletRetryTask: 完全重写,基于数据库驱动+指数退避\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Opus 4.5 \nEOF\n\\)\")" ], "deny": [], "ask": [] diff --git a/backend/services/scripts/accounts.json b/backend/services/scripts/accounts.json new file mode 100644 index 00000000..e37f4020 --- /dev/null +++ b/backend/services/scripts/accounts.json @@ -0,0 +1,184 @@ +[ + { + "i": 1, + "phone": "14052927714", + "seq": "D25122700001", + "code": "PHQZKV", + "inviter": "SEED01", + "wallet": { + "kava": "0x345b8839b942f841e76ee103b4c7089d704acbfd", + "dst": "dst1u5dmj4h3u087mlc36r5njx24eqmq5m20nc2r9t", + "bsc": "0x345b8839b942f841e76ee103b4c7089d704acbfd" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMCIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAwMSIsImRldmljZUlkIjoiZGV2LTE3NjY3NzcyODU3NjQiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3Mjg2LCJleHAiOjE3NjY3ODQ0ODZ9.KV34psoB-uig1wiSUsKG9mE1BVNOBMTaxq7wwXk46r4" + }, + { + "i": 2, + "phone": "18027595478", + "seq": "D25122700002", + "code": "JUEG1A", + "inviter": "PHQZKV", + "wallet": { + "kava": "0xe4c66acff372d084433984228773ad07932f8205", + "dst": "dst18etce0jkll3kfs8fxj5e6tneqlnx9cmx5l8wzz", + "bsc": "0xe4c66acff372d084433984228773ad07932f8205" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMSIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAwMiIsImRldmljZUlkIjoiZGV2LTE3NjY3NzczMTY3NjIiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3MzE3LCJleHAiOjE3NjY3ODQ1MTd9.5_PF-8of02cPrXqrHWk67eHW77Nr6vBtvNONDs2_eUo" + }, + { + "i": 3, + "phone": "17862239357", + "seq": "D25122700003", + "code": "DVRBF0", + "inviter": "JUEG1A", + "wallet": { + "kava": "0x3ff86b1f8e81df00e680fccaa075cce3853864a6", + "dst": "dst1umw0d6ncxwqy2072jmtwc5fcd69sczsrju5eeq", + "bsc": "0x3ff86b1f8e81df00e680fccaa075cce3853864a6" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMiIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAwMyIsImRldmljZUlkIjoiZGV2LTE3NjY3NzczNDEyNDIiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3MzQxLCJleHAiOjE3NjY3ODQ1NDF9.H6oQNKoV9LVdP-2tEEzfgj0ShThQqcs9hgUjrAumD6I" + }, + { + "i": 4, + "phone": "19297857036", + "seq": "D25122700004", + "code": "2UEPMU", + "inviter": "DVRBF0", + "wallet": { + "kava": "0x0f533a8c69d4217c66cb6c971d8e40fb2fcdda75", + "dst": "dst1cxjk6hwnftegk45h0xzsjlrruqgwvxjsh65wg7", + "bsc": "0x0f533a8c69d4217c66cb6c971d8e40fb2fcdda75" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMyIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAwNCIsImRldmljZUlkIjoiZGV2LTE3NjY3NzczNzA3MDMiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3MzcxLCJleHAiOjE3NjY3ODQ1NzF9.2LUwgMITQvohGzloegEFpNWfKb8DCtrIVy6xTyBzn-8" + }, + { + "i": 5, + "phone": "15320937126", + "seq": "D25122700005", + "code": "5J8V3C", + "inviter": "2UEPMU", + "wallet": { + "kava": "0xde2b2fbf8a4c9a1b10a9b6a16978eafa2737538e", + "dst": "dst18sdgdrmvnwhh2sdq4dswhw3lmhjcqp4gwdhf26", + "bsc": "0xde2b2fbf8a4c9a1b10a9b6a16978eafa2737538e" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxNCIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAwNSIsImRldmljZUlkIjoiZGV2LTE3NjY3Nzc0NDg1NzIiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3NDQ5LCJleHAiOjE3NjY3ODQ2NDl9.HzJWZWEmUoXlPJ6A5IMrGKslWfKcVpIQY_PSdNrPKE4" + }, + { + "i": 6, + "phone": "19355687135", + "seq": "D25122700006", + "code": "3O9FCJ", + "inviter": "5J8V3C", + "wallet": { + "kava": "0x0c2ca44714fefb4071b7edd9809824cb3647cff8", + "dst": "dst1nt2au5cjl97kysgejjqnph77zh95ll23jgga7z", + "bsc": "0x0c2ca44714fefb4071b7edd9809824cb3647cff8" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxNSIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAwNiIsImRldmljZUlkIjoiZGV2LTE3NjY3Nzc1MjYyMzciLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3NTI2LCJleHAiOjE3NjY3ODQ3MjZ9.m-F-CK8U4eO5WYCljq0r3AOqvaxgEebp1is6DuYFVQg" + }, + { + "i": 7, + "phone": "18059815900", + "seq": "D25122700007", + "code": "4RQGK4", + "inviter": "3O9FCJ", + "wallet": { + "kava": "0x604853c11307a1eed056ab740dd8b4739d57deb3", + "dst": "dst1pwjr4xeayfn04et6lqxhltn84ck52rl033vkxr", + "bsc": "0x604853c11307a1eed056ab740dd8b4739d57deb3" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxNiIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAwNyIsImRldmljZUlkIjoiZGV2LTE3NjY3Nzc1NTcxODIiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3NTU3LCJleHAiOjE3NjY3ODQ3NTd9.I3S5R52fgzVf7nLbYrXZw3-WQBY_RYdrBLYsCPiyxaQ" + }, + { + "i": 8, + "phone": "18476247786", + "seq": "D25122700008", + "code": "GO0DHS", + "inviter": "4RQGK4", + "wallet": { + "kava": "0xd97f33f0507fd94ee6aed4631193becb5400d47f", + "dst": "dst190dxd7cn0cq6mjrtetzn7cfh0muyv5h7ess6xp", + "bsc": "0xd97f33f0507fd94ee6aed4631193becb5400d47f" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxNyIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAwOCIsImRldmljZUlkIjoiZGV2LTE3NjY3Nzc1ODE2MjEiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3NTgyLCJleHAiOjE3NjY3ODQ3ODJ9.8xgV-o-9fUVDtktks0acjRlZpTZ6KjZqH7nKBgYIkpQ" + }, + { + "i": 9, + "phone": "14264197292", + "seq": "D25122700009", + "code": "PQZEYG", + "inviter": "GO0DHS", + "wallet": { + "kava": "0xce1b26b410e53c7d278633058f325f8b975adf15", + "dst": "dst16sksskyr5fv9r0j900un9kvqzjyl207nfklewe", + "bsc": "0xce1b26b410e53c7d278633058f325f8b975adf15" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxOCIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAwOSIsImRldmljZUlkIjoiZGV2LTE3NjY3Nzc2MTI1MzQiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3NjEzLCJleHAiOjE3NjY3ODQ4MTN9.mtx2xe8pGDNEAHcj5etePV74qWq5rIZndu32LAaJTRM" + }, + { + "i": 10, + "phone": "13214866463", + "seq": "D25122700010", + "code": "W8FP57", + "inviter": "PQZEYG", + "wallet": { + "kava": "0xc47e127874232ab99456d4b04d2ada0834d6f850", + "dst": "dst1y0acpufm7w0gcf8nulw7ukz6guf8zd7dypxrap", + "bsc": "0xc47e127874232ab99456d4b04d2ada0834d6f850" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxOSIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAxMCIsImRldmljZUlkIjoiZGV2LTE3NjY3Nzc2NDM0NTYiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3NjQzLCJleHAiOjE3NjY3ODQ4NDN9.HxJIUnUJLUq67D-AXLAkjIvT4E9iOgq4TYSXq07wE58" + }, + { + "i": 11, + "phone": "18420065907", + "seq": "D25122700011", + "code": "WEGSDK", + "inviter": "W8FP57", + "wallet": { + "kava": "0x8ffe3fdb54c1af21bcd5df17667fd09f6487f9f2", + "dst": "dst1ujjydyar0l0d8krp7mxfvf5g47m0m2gdw4v5tk", + "bsc": "0x8ffe3fdb54c1af21bcd5df17667fd09f6487f9f2" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIyMCIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAxMSIsImRldmljZUlkIjoiZGV2LTE3NjY3Nzc2NjU2MzMiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3NjY2LCJleHAiOjE3NjY3ODQ4NjZ9.8s-NKcmkZF5nM6TvqWAFEa6LukM6Ov6tR2dQedt48tg" + }, + { + "i": 12, + "phone": "19542401963", + "seq": "D25122700012", + "code": "SLN8Y7", + "inviter": "WEGSDK", + "wallet": { + "kava": "0x01d7f0eec627c24ea72ed0a3c1ba87528dc6b265", + "dst": "dst1wd30zj03z2emqhpzewrwnm70p6c8ll56z2f8av", + "bsc": "0x01d7f0eec627c24ea72ed0a3c1ba87528dc6b265" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIyMSIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAxMiIsImRldmljZUlkIjoiZGV2LTE3NjY3Nzc2OTY2MDIiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3Njk3LCJleHAiOjE3NjY3ODQ4OTd9.TlZ3e8A3Zwl0ORdetLSGAD8ZxfqVQiGAHaiarSvgyCs" + }, + { + "i": 13, + "phone": "16807660295", + "seq": "D25122700013", + "code": "HZXFFL", + "inviter": "SLN8Y7", + "wallet": { + "kava": "0xab334497c564518990c73e6ae450802ab815c0c2", + "dst": "dst1ypl3cf38zs5dwdfxjgg006m2f7zcj6mqkf8ktc", + "bsc": "0xab334497c564518990c73e6ae450802ab815c0c2" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIyMiIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAxMyIsImRldmljZUlkIjoiZGV2LTE3NjY3Nzc3Mjc1ODMiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3NzI4LCJleHAiOjE3NjY3ODQ5Mjh9.e6vhB7NudLxARynW8XwGcHGeZnEufSBafPTsgiXALKo" + }, + { + "i": 14, + "phone": "19266490703", + "seq": "D25122700014", + "code": "4RTM9B", + "inviter": "HZXFFL", + "wallet": { + "kava": "0xd259dbd13804f587d9c158b4053ab950af92d12c", + "dst": "dst16ue0dkca0jt5ceu3v4865f07lfyvxku4n63dl3", + "bsc": "0xd259dbd13804f587d9c158b4053ab950af92d12c" + }, + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIyMyIsImFjY291bnRTZXF1ZW5jZSI6IkQyNTEyMjcwMDAxNCIsImRldmljZUlkIjoiZGV2LTE3NjY3Nzc3NTg1NDEiLCJ0eXBlIjoiYWNjZXNzIiwiaWF0IjoxNzY2Nzc3NzU5LCJleHAiOjE3NjY3ODQ5NTl9.G8phCWhNiNycZ4FhXpTLT0u07H_FTtP23Tj-V8hf8eQ" + } +] \ No newline at end of file diff --git a/backend/services/scripts/batch-register.js b/backend/services/scripts/batch-register.js new file mode 100644 index 00000000..f1064b62 --- /dev/null +++ b/backend/services/scripts/batch-register.js @@ -0,0 +1,85 @@ +/** + * 批量注册账号脚本 + * + * node batch-register.js [数量] [初始推荐码] + * + * 输出保存到当前目录 accounts.json + */ + +const fs = require('fs'); +const path = require('path'); + +const COUNT = parseInt(process.argv[2]) || 14; +const START_CODE = process.argv[3] || 'SEED01'; +const API = 'https://rwaapi.szaiai.com/api/v1'; +const PASSWORD = 'Test123456'; +const OUTPUT_FILE = path.join(__dirname, 'accounts.json'); + +function randomPhone() { + return '1' + (Math.floor(Math.random() * 7) + 3) + Array(9).fill(0).map(() => Math.floor(Math.random() * 10)).join(''); +} + +async function waitWallet(token) { + for (let i = 0; i < 30; i++) { + const res = await fetch(`${API}/user/wallet`, { + headers: { 'Authorization': `Bearer ${token}` } + }); + if (res.ok) { + const d = (await res.json()).data; + if (d?.status?.toUpperCase() === 'READY') return d.walletAddresses; + } + process.stdout.write('.'); + await new Promise(r => setTimeout(r, 2000)); + } + return null; // 超时返回null,不抛错 +} + +async function register(code, i) { + const phone = randomPhone(); + console.log(`\n[${i}] ${phone} <- ${code}`); + + const res = await fetch(`${API}/user/register-without-sms-verify`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + phoneNumber: phone, + password: PASSWORD, + deviceId: `dev-${Date.now()}`, + inviterReferralCode: code + }) + }); + + if (!res.ok) throw new Error(await res.text()); + + const d = (await res.json()).data; + console.log(` -> ${d.userSerialNum} | ${d.referralCode}`); + + process.stdout.write(' 钱包'); + const wallet = await waitWallet(d.accessToken); + console.log(wallet ? ' OK' : ' 超时'); + + return { i, phone, seq: d.userSerialNum, code: d.referralCode, inviter: code, wallet, token: d.accessToken }; +} + +async function main() { + console.log(`注册 ${COUNT} 个账号,起始码: ${START_CODE}\n`); + + const list = []; + let code = START_CODE; + + for (let i = 1; i <= COUNT; i++) { + if (i > 1) { + console.log('\n等待10秒...'); + await new Promise(r => setTimeout(r, 10000)); + } + const acc = await register(code, i); + list.push(acc); + code = acc.code; + fs.writeFileSync(OUTPUT_FILE, JSON.stringify(list, null, 2)); + } + + console.log(`\n完成,最后推荐码: ${code}`); + console.log(`保存到: ${OUTPUT_FILE}`); +} + +main(); diff --git a/frontend/mobile-app/lib/features/auth/presentation/pages/import_mnemonic_page.dart b/frontend/mobile-app/lib/features/auth/presentation/pages/import_mnemonic_page.dart index c0682630..c23414ec 100644 --- a/frontend/mobile-app/lib/features/auth/presentation/pages/import_mnemonic_page.dart +++ b/frontend/mobile-app/lib/features/auth/presentation/pages/import_mnemonic_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../../core/di/injection_container.dart'; +import '../../../../core/services/multi_account_service.dart'; import '../../../../routes/route_paths.dart'; /// 导入助记词页面 - 用于恢复已有账户 @@ -104,6 +105,21 @@ class _ImportMnemonicPageState extends ConsumerState { if (!mounted) return; + // 将账号添加到多账号列表 + final multiAccountService = ref.read(multiAccountServiceProvider); + await multiAccountService.addAccount( + AccountSummary( + userSerialNum: response.userSerialNum, + username: response.username, + avatarSvg: response.avatarSvg, + createdAt: DateTime.now(), + ), + ); + await multiAccountService.setCurrentAccountId(response.userSerialNum); + debugPrint('[ImportMnemonicPage] 已添加到多账号列表'); + + if (!mounted) return; + // 恢复成功,跳转到主页 ScaffoldMessenger.of(context).showSnackBar( SnackBar( diff --git a/frontend/mobile-app/lib/features/auth/presentation/pages/phone_login_page.dart b/frontend/mobile-app/lib/features/auth/presentation/pages/phone_login_page.dart index 5d776335..8e3b2aae 100644 --- a/frontend/mobile-app/lib/features/auth/presentation/pages/phone_login_page.dart +++ b/frontend/mobile-app/lib/features/auth/presentation/pages/phone_login_page.dart @@ -4,6 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:go_router/go_router.dart'; import '../../../../core/di/injection_container.dart'; +import '../../../../core/services/multi_account_service.dart'; import '../../../../routes/route_paths.dart'; import '../providers/auth_provider.dart'; @@ -104,6 +105,38 @@ class _PhoneLoginPageState extends ConsumerState { debugPrint('[PhoneLoginPage] 登录成功 - accountSequence: ${response.accountSequence}'); + if (!mounted) return; + + // 获取用户资料并添加到多账号列表 + try { + final profile = await accountService.getMyProfile(); + final multiAccountService = ref.read(multiAccountServiceProvider); + + await multiAccountService.addAccount( + AccountSummary( + userSerialNum: response.accountSequence, + username: profile['nickname'] as String? ?? '用户${response.accountSequence}', + avatarSvg: profile['avatarSvg'] as String?, + avatarUrl: profile['avatarUrl'] as String?, + createdAt: DateTime.now(), + ), + ); + await multiAccountService.setCurrentAccountId(response.accountSequence); + debugPrint('[PhoneLoginPage] 已添加到多账号列表'); + } catch (e) { + debugPrint('[PhoneLoginPage] 获取用户资料失败,使用默认信息: $e'); + // 即使获取资料失败,也添加到账号列表(使用默认信息) + final multiAccountService = ref.read(multiAccountServiceProvider); + await multiAccountService.addAccount( + AccountSummary( + userSerialNum: response.accountSequence, + username: '用户${response.accountSequence}', + createdAt: DateTime.now(), + ), + ); + await multiAccountService.setCurrentAccountId(response.accountSequence); + } + if (mounted) { // 更新认证状态 await ref.read(authProvider.notifier).checkAuthStatus(); diff --git a/frontend/mobile-app/lib/features/auth/presentation/pages/sms_verify_page.dart b/frontend/mobile-app/lib/features/auth/presentation/pages/sms_verify_page.dart index 9de39f98..671a9b68 100644 --- a/frontend/mobile-app/lib/features/auth/presentation/pages/sms_verify_page.dart +++ b/frontend/mobile-app/lib/features/auth/presentation/pages/sms_verify_page.dart @@ -6,6 +6,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:go_router/go_router.dart'; import '../../../../core/di/injection_container.dart'; import '../../../../core/services/account_service.dart'; +import '../../../../core/services/multi_account_service.dart'; import '../../../../routes/route_paths.dart'; import 'set_password_page.dart'; @@ -221,6 +222,38 @@ class _SmsVerifyPageState extends ConsumerState { if (!mounted) return; + // 获取用户资料并添加到多账号列表 + try { + final profile = await accountService.getMyProfile(); + final multiAccountService = ref.read(multiAccountServiceProvider); + + await multiAccountService.addAccount( + AccountSummary( + userSerialNum: response.accountSequence, + username: profile['nickname'] as String? ?? '用户${response.accountSequence}', + avatarSvg: profile['avatarSvg'] as String?, + avatarUrl: profile['avatarUrl'] as String?, + createdAt: DateTime.now(), + ), + ); + await multiAccountService.setCurrentAccountId(response.accountSequence); + debugPrint('[SmsVerifyPage] 已添加到多账号列表'); + } catch (e) { + debugPrint('[SmsVerifyPage] 获取用户资料失败,使用默认信息: $e'); + // 即使获取资料失败,也添加到账号列表(使用默认信息) + final multiAccountService = ref.read(multiAccountServiceProvider); + await multiAccountService.addAccount( + AccountSummary( + userSerialNum: response.accountSequence, + username: '用户${response.accountSequence}', + createdAt: DateTime.now(), + ), + ); + await multiAccountService.setCurrentAccountId(response.accountSequence); + } + + if (!mounted) return; + // 跳转到主页 context.go(RoutePaths.mining); } diff --git a/榴莲皇后数据.xlsx b/榴莲皇后数据.xlsx new file mode 100644 index 00000000..118fbc07 Binary files /dev/null and b/榴莲皇后数据.xlsx differ