hailin
e328c75fc1
fix(pre-planting): 修复前后端 API 路径不匹配导致预种页面打不开
...
后端 PrePlantingController 缺少 eligibility 端点,前端请求 404 导致
Future.wait 整体失败,页面显示"加载数据失败"。
修复:
1. 后端: 在 PrePlantingController 添加 GET eligibility 端点
2. 前端: createOrder 路径从 /orders 改为 /purchase(匹配后端)
3. 前端: signMergeContract 路径从 /merges/:no/sign 改为 /sign-contract
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:07:47 -08:00
hailin
c0ac63d40a
feat(pre-planting): 重命名预种持仓→预种明细 + 购买协议弹窗
...
- mobile-app: "预种持仓"按钮和页面标题改为"预种明细"
- admin-service: 新增预种协议文本 API (GET/PUT agreement),存储于 system_configs 表
- admin-service: 公开 config API 响应增加 agreementText 字段
- planting-service: 新建 PrePlantingPublicController (无需 JWT),暴露 GET /pre-planting/config
- admin-web: 预种管理页面新增协议文本编辑器(textarea + 保存按钮)
- mobile-app: 购买流程增加协议弹窗,用户需勾选同意后才能继续
- mobile-app: 协议文本优先使用后台配置,未配置时使用默认文本
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 21:14:24 -08:00
hailin
8bafb0a8d4
fix(mobile-app): 增加切换账号全局防护,彻底解决切换期间自动退出登录
...
根因:切换账号时 saveCurrentAccountData() 耗时 ~7 秒,期间定时器仍在发 API 请求,
clear 阶段 token 被删除后 in-flight 请求收到 401 → 触发 tokenExpired →
logoutCurrentAccount() 把刚恢复的新账号数据全部擦除。
修复(两层防护):
1. 全局锁 isSwitchingAccount:MultiAccountService 在 switchToAccount 整个过程中
设为 true,app.dart _handleTokenExpired 检测到该标志直接 return,不执行 logout
2. 定时器提前停止:将定时器停止从 onBeforeRestore(save 之后)移到 switchToAccount
调用之前,确保 save 期间无新 API 请求
3. try/finally 保证标志位必定清除,异常情况不会锁死后续 tokenExpired 事件
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:41:45 -08:00
hailin
a5cc3fdc5b
fix(mobile-app): 修复切换账号时 token 过期导致自动退出登录
...
根因:switchToAccount() 流程中,定时器在 _clearCurrentAccountData()
之后才停止。clear 阶段会删除 token,但此时定时器仍在运行,
in-flight 的 API 请求收到 401 → 触发 _handleTokenExpired()
→ 调用 logoutCurrentAccount() 把正在恢复的新账号数据全部清掉
→ 用户被自动踢到登录页面。
修复:将 onBeforeRestore 回调(停止定时器)移到 _clearCurrentAccountData()
之前执行,确保所有 API 请求停止后再清除 token。
修改前: save → clear(删token) → 停定时器 → restore
修改后: save → 停定时器 → clear(删token) → restore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:21:57 -08:00
hailin
12004d1c2e
fix(mobile-app): 修复账号切换后自动退出登录的问题
...
根因:ref.invalidate(authProvider) 销毁旧 AuthNotifier 后,新实例的构造函数
仅设置 AuthState(status: AuthStatus.initial),从不自动调用 checkAuthStatus()
从 SecureStorage 重新加载认证数据。导致 auth 状态停留在 initial(未认证),
依赖 auth 状态的组件误判为"未登录",触发页面跳转到登录页。
修复:
- account_switch_page: invalidate 后立即调用 loadAuthState() 从 storage
读取新账号数据,确保 auth 状态为 authenticated 后再导航
- account_switch_page: 切换后重置 ApiClient 的 tokenExpired 标记,防止
旧会话的 401 状态阻塞新账号的请求
- app.dart: _handleTokenExpired() 增加醒目日志和调用栈打印,便于排查
切换期间是否有 token 过期事件被误触发
切换流程更新为 6 步:
[1/6] switchToAccount() - 保存旧账号、清空、恢复新账号 storage
[2/6] onBeforeRestore - 停止所有定时器
[3/6] invalidate Provider - 销毁旧 Provider 实例
[4/6] loadAuthState() - 从 storage 加载新账号 auth 状态 ← 新增关键步骤
[5/6] 恢复遥测上传
[6/6] 导航到 ranking 页面
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:39:31 -08:00
hailin
3a307b5db7
fix(planting): 修复认种页面动态定价不生效 + 添加涨价倒计时
...
- 修复 admin-service PublicTreePricingController 路由双重前缀问题
(@Controller('api/v1/tree-pricing') → @Controller('tree-pricing'))
- Kong 网关新增 /api/v1/tree-pricing 路由到 admin-service
- mobile-app 认种页面添加涨价倒计时功能:
显示"距下次涨价还有 X天 X小时 X分钟"及涨价后价格
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:22:27 -08:00
hailin
acf55b26a7
feat(pricing): 预种每份价格从 3171 调整为 3566 绿积分
...
分配规则:按 reward-service RIGHT_AMOUNTS(15831 整棵树)各项 /5 取整,
余额全归总部社区(HQ_BASE_FEE)。5 份合成一棵树 = 17830。
10 类分配金额变更:
- COST_FEE: 576 (不变, floor(2880/5))
- OPERATION_FEE: 420 (不变, floor(2100/5))
- HQ_BASE_FEE: 29.4 → 427 (3566 - 3139, 吸收全部余额)
- RWAD_POOL: 1152 (不变, floor(5760/5))
- SHARE_RIGHT: 720 (不变, floor(3600/5))
- PROVINCE_AREA: 21.6 → 21 (floor(108/5))
- PROVINCE_TEAM: 28.8 → 28 (floor(144/5))
- CITY_AREA: 50.4 → 50 (floor(252/5))
- CITY_TEAM: 57.6 → 57 (floor(288/5))
- COMMUNITY: 115.2 → 115 (floor(576/5))
- 合计: 3171 → 3566 ✓
涉及服务:planting-service, admin-service, contribution-service
涉及前端:admin-web, mobile-app (Flutter)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 08:02:17 -08:00
hailin
ed6b48562a
feat(pricing): 认种树动态定价涨价系统(总部运营成本压力涨价)
...
基础价 15831 USDT/棵不变,新增 HQ_PRICE_SUPPLEMENT 加价项全额归总部(S0000000001)。
支持手动调价+自动周期涨价,所有变更可审计,移动端动态展示价格及涨价预告。
- admin-service: TreePricingConfig/ChangeLog 表 + Service + Controller + 定时任务
- planting-service: 正式认种和预种订单快照 priceSupplement,动态价格校验
- reward-service: HQ_PRICE_SUPPLEMENT 分配类型,涨价金额直接入总部账户
- admin-web: Settings 页面新增定价配置区间(手动调价/自动涨价/变更历史)
- mobile-app: TreePricingService + 动态价格加载 + 涨价预告展示
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 03:02:56 -08:00
hailin
eda39b982d
fix(mobile-app): 修复切换窗口期 NotificationBadge 混账号请求问题
...
问题(通过日志发现):
账号切换时存在一个 storage 空窗期(旧数据已清除、新数据尚未恢复完成)。
在此期间,NotificationBadgeNotifier 的 30s 定时器恰好触发,导致:
- _loadUnreadCount() 从 authProvider 内存读到旧账号 userSerialNum
- HTTP interceptor 从 storage 读到已恢复的新账号 accessToken
- 发出混账号请求:?userSerialNum=旧账号 + Authorization: Bearer 新账号token
日志证据:
_restoreAccountData() 执行期间出现
GET /notifications/unread-count?userSerialNum=D26022600000
Authorization: Bearer [D26022600001的token]
修复:
1. notification_badge_provider.dart
新增 stopAutoRefresh() 公开方法,取消 30s 定时器而不 dispose,
Provider invalidate 重建后会自动重启定时器。
2. account_switch_page.dart - _switchToAccount
在 onBeforeRestore 中补加:
ref.read(notificationBadgeProvider.notifier).stopAutoRefresh()
确保切换空窗期内 notificationBadge 定时器不触发。
同时移除 UI 层冗余的 saveCurrentAccountData() 调用——
switchToAccount() 内部已有此步骤,无需重复。
日志步骤从 [1/6]...[6/6] 更新为 [1/5]...[5/5],
并在 onBeforeRestore 注释中说明停止各定时器的原因。
切换空窗期现在所有定时器均已停止:
✓ walletStatusProvider (60s)
✓ pendingActionPollingService (4s)
✓ notificationBadgeProvider (30s) ← 本次新增
✓ TelemetryUploader (30s)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 09:09:37 -08:00
hailin
825c8a32e4
chore(mobile-app): 补全多账号切换流程的关键日志,便于验证与排查
...
切换流程中的每一步现在都有清晰的日志输出,方便通过 adb logcat
或 flutter logs 验证切换行为是否符合预期。
account_switch_page.dart - 三条路径全部覆盖:
_switchToAccount(切换账号):
[1/6] 保存当前账号数据
[2/6] 调用 switchToAccount()
[3/6] onBeforeRestore - 停止 walletStatus/pendingAction 轮询、暂停遥测
[4/6] invalidate authProvider / walletStatusProvider / notificationBadgeProvider
[5/6] 恢复遥测上传
[6/6] 导航到 ranking 页面
_addNewAccount(添加新账号):
[1/5] 保存当前账号数据
[2/5] 停止定时器
[3/5] 调用 logoutCurrentAccount()
[4/5] invalidate 三个 Provider
[5/5] 导航到 guide 页面
_deleteAccount(删除账号):
删除前打印目标账号,删除后打印剩余账号数
profile_page.dart - _performLogout(退出登录):
[1/4] 停止 walletStatus/pendingAction 轮询
[2/4] 调用 logoutCurrentAccount()
[3/4] invalidate 三个 Provider
[4/4] 导航到 guide 页面
每条关键操作完成后打印 ✓ 确认符号,便于逐步验证。
每条路径用 ========== 分隔符标识开始/完成,日志易于 grep 过滤。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 09:04:14 -08:00
hailin
e02bcf418c
fix(mobile-app): 升级弹窗禁止点击外部或返回键关闭,必须通过按钮操作
...
问题:
检测到新版本弹出升级对话框时,用户点击弹窗外部区域或按系统返回键
即可直接关闭弹窗,绕过升级提示,导致用户可能永远不会注意到更新。
修复:
对所有 3 个升级弹窗统一加两层防护:
- barrierDismissible: false — 禁止点击弹窗外部区域关闭
- PopScope(canPop: false) — 禁止系统返回键关闭
涉及弹窗:
1. self_hosted_updater.dart - _showSelfHostedUpdateDialog(自建APK更新)
2. self_hosted_updater.dart - _showMarketUpdateDialog(应用市场引导更新)
3. update_service.dart - _checkGooglePlayUpdate(Google Play 更新)
用户必须通过弹窗内按钮操作:
- 非强制更新:点击「稍后」/「暂时不更新」关闭,或点击「立即更新」开始更新
- 强制更新:只有「立即更新」按钮,无法跳过
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 08:01:52 -08:00
hailin
8f8a9230d0
fix(mobile-app): 修复多账号切换数据串号问题,完善存储隔离与状态重置
...
问题:
多账号切换时,前一个账号的推荐码、种植省市、缓存数据等会串到下一个账号,
同时定时器(钱包轮询、通知刷新、遥测上传)未正确停止/重启,
导致旧账号的 API 请求混入新账号上下文。
修复内容:
1. StorageKeys 补充种植省市常量(storage_keys.dart)
- 新增 plantingProvinceName/Code、plantingCityName/Code 4个常量
- 将硬编码的 key 统一收口,确保隔离列表引用一致
2. MultiAccountService 补全隔离列表(multi_account_service.dart)
- _accountSecureKeys 新增 inviterReferralCode(修复邀请码串号)
- _accountLocalKeys 新增 4个种植省市key + cachedAppAssets +
cachedCustomerServiceContacts(修复种植/缓存数据串号)
- switchToAccount() 新增 onBeforeRestore 回调参数,用于在
storage清空后、恢复新数据前 停止定时器
3. AccountSwitchPage 三层状态重置(account_switch_page.dart)
- _switchToAccount: onBeforeRestore 内停止 walletStatus 轮询、
pendingAction 轮询、telemetry 上传;返回后 invalidate
authProvider/walletStatusProvider/notificationBadgeProvider,
最后 resumeAfterLogin 恢复遥测
- _addNewAccount: 退出前停止定时器,退出后 invalidate Provider
4. ProfilePage 退出登录补全清理(profile_page.dart)
- _performLogout: 退出前停止 walletStatus/pendingAction 轮询,
退出后 invalidate 三个 Provider
5. 页面 key 统一引用 StorageKeys 常量
- planting_location_page.dart 和 authorization_apply_page.dart
将硬编码 key 替换为 StorageKeys.plantingXxx 常量
关键时序(switchToAccount 内部):
save → clear → onBeforeRestore(停timer) → restore → 返回
→ invalidate Provider(此时storage已恢复新数据)→ resume telemetry → navigate
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 06:13:05 -08:00
hailin
e690a55c8e
style(transfer): 树转让 3 页面从暗夜主题改为 App 标准浅色棕金主题
...
问题:树转让的 transfer_list_page、transfer_initiate_page、
transfer_detail_page 三个页面使用了深色暗夜主题(#1A1A2E 背景 +
#16213E 卡片),与 App 其余 40+ 功能页面的浅色棕金主题不一致。
修改内容(3 个文件,纯样式重写,零业务逻辑变更):
1. 页面背景:#1A1A2E → 渐变 #FFF7E6 → #EAE0C8(与 planting_quantity_page 一致)
2. 卡片背景:#16213E → #99FFFFFF 半透明白 + boxShadow(与认种页一致)
3. AppBar:深色背景白字 → 透明背景 + 金色返回键(#D4AF37) + 棕色标题(#5D4037)
4. 正文文字:Colors.white/white70 → #5D4037 棕色 / #745D43 次级棕色
5. 输入框:#16213E 填充 → #99FFFFFF 填充 + #EAE0C8 边框
6. 按钮:ElevatedButton → GestureDetector+Container(高度 56,与全局一致)
7. 分割线:Colors.white24 → #EAE0C8
8. Tab 栏:暗色系 → 半透明白卡片容器 + 金色指示器
9. Saga 时间线未完成节点:white 20% → #EAE0C8 暖色
10. 对话框:系统默认 → #FFF7E6 背景 + 棕色文字
样式参考基准:planting_quantity_page.dart(现有认种数量页)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 20:25:25 -08:00
hailin
b3a3652f21
feat(transfer): 树转让功能全量实现(纯新增,零侵入)
...
实现已认种果树所有权在用户间转让的完整功能。采用方案一:
独立 transfer-service 微服务 + Saga 编排器模式。
=== 架构设计 ===
- Saga 编排器 8 步正向流程:卖方确认 → 冻结资金 → 锁定树 →
变更所有权 → 调整算力 → 更新统计 → 结算资金 → 完成
- 补偿回滚:任一步骤失败自动反向补偿(解冻资金 → 解锁树)
- 13 种状态:PENDING → SELLER_CONFIRMED → PAYMENT_FROZEN →
TREES_LOCKED → OWNERSHIP_TRANSFERRED → CONTRIBUTION_ADJUSTED →
STATS_UPDATED → PAYMENT_SETTLED → COMPLETED / CANCELLED /
FAILED / ROLLING_BACK / ROLLED_BACK
=== Phase 1-2: transfer-service(独立微服务) ===
新建文件:
- Prisma Schema:transfer_orders + transfer_status_logs + outbox_events
- Domain:TransferOrder 聚合根 + TransferFeeService(5% 手续费)
- Application:TransferApplicationService + SagaOrchestratorService
- Infrastructure:Kafka 事件消费/生产 + Outbox Pattern
- API:TransferController(用户端)+ AdminTransferController(管理端)
- External Clients:wallet/planting/identity-service HTTP 客户端
- Docker + 环境配置
=== Phase 3: 现有微服务扩展(纯追加) ===
planting-service:
- Prisma schema 追加 transferLockId 可空字段
- InternalTransferController:锁定/解锁/执行 3 个新端点
- Kafka handlers:transfer-lock/execute/rollback 事件处理
- main.ts 追加 Kafka consumer group 配置
referral-service:
- PlantingTransferredHandler:处理转让后团队统计更新
- TeamStatisticsAggregate 追加 handleTransfer() 方法
- TeamStatisticsRepository 追加 adjustForTransfer() 方法
- ProvinceCityDistribution 追加 transferTrees() 方法
contribution-service:
- TransferOwnershipHandler:处理所有权变更事件
- TransferAdjustmentService:算力调整(879 行核心逻辑)
- Prisma schema 追加 transferOrderId 可空字段
- ContributionAccount 追加 applyTransferAdjustment() 方法
=== Phase 4A: wallet-service(3 个新内部端点) ===
新建文件:
- FreezeForTransferDto / UnfreezeForTransferDto / SettleTransferDto
- FreezeForTransferCommand / UnfreezeForTransferCommand / SettleTransferPaymentCommand
- InternalTransferWalletController(POST freeze/unfreeze/settle-transfer)
修改文件:
- wallet-application.service.ts 追加 3 组方法(+437 行):
freezeForTransfer / unfreezeForTransfer / settleTransferPayment
(乐观锁 + 3 次重试 + Prisma $transaction + 幂等检查)
- 结算操作:单事务内更新 3 个钱包(买方扣减 + 卖方入账 + 手续费归集)
=== Phase 4B: admin-web(转让管理页面) ===
新建文件:
- transferService.ts:API 调用服务 + 完整类型定义
- useTransfers.ts:React Query hooks(list/detail/stats/forceCancel)
- /transfers/page.tsx:列表页(统计卡片 + 搜索筛选 + 分页 + 13 种状态 badge)
- /transfers/[transferOrderNo]/page.tsx:详情页(Saga 时间线 + 状态日志 + 强制取消)
- transfers.module.scss:完整样式
修改文件:
- endpoints.ts 追加 TRANSFERS 端点配置
- Sidebar.tsx 追加「转让管理」菜单项
- hooks/index.ts 追加 useTransfers 导出
=== Phase 4C: mobile-app(转让 UI) ===
新建文件:
- transfer_service.dart:Flutter API 服务 + Model(TransferOrder/Detail/StatusLog)
- transfer_list_page.dart:转让记录列表(全部/转出/转入 Tab + 下拉刷新)
- transfer_detail_page.dart:转让详情(Saga 时间线 + 确认/取消操作)
- transfer_initiate_page.dart:发起转让表单(手续费自动计算)
修改文件:
- injection_container.dart 追加 transferServiceProvider
- route_paths.dart + route_names.dart 追加 3 个路由
- app_router.dart 追加 3 个 GoRoute
- profile_page.dart 追加「发起转让」+「转让记录」按钮行
=== 基础设施 ===
- docker-compose.yml 追加 transfer-service 容器配置
- deploy.sh 追加 transfer-service 部署
- init-databases.sh 追加 transfer_db 数据库初始化
=== 纯新增原则 ===
所有变更均为追加式修改,不修改任何现有业务逻辑:
- 新增 nullable 字段(不影响现有数据)
- 新增 enum 值(不影响现有枚举使用)
- 新增 providers/controllers(不影响现有依赖注入)
- 新增页面/路由(不影响现有页面行为)
回滚方式:删除 transfer-service 目录 + 移除各服务中带 [2026-02-19] 标记的代码
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 03:44:02 -08:00
hailin
03f5c4af28
feat(pre-planting): Profile 页面添加预种计划入口
...
[2026-02-17] 在 Profile 页面认种按钮下方新增预种计划入口
新增内容(纯新增,不改现有逻辑):
- _goToPrePlantingPurchase():跳转预种购买页
- _goToPrePlantingPosition():跳转预种持仓页
- _buildPrePlantingButtons():两个并排按钮
- 左侧「预种购买」:金色主题,跳转购买页
- 右侧「预种持仓」:棕色主题,跳转持仓页
布局位置:认种按钮正下方,主内容卡片上方
现有功能零影响,仅新增 3 个方法 + 1 处布局插入
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 05:44:48 -08:00
hailin
d248f92443
feat(pre-planting): Mobile App 预种合并详情页完整实现
...
[2026-02-17] 预种合并详情页面 (pre_planting_merge_detail_page.dart)
完整功能:
- 合并信息卡片:合并号、合并时间、份数→树数、总价值、省市
- 合同签署状态卡片:待签署/已签署/已过期,含签署时间
- 挖矿状态卡片:已开启/未开启,含开启时间
- 来源订单列表:编号圆标 + 订单号 + 金额,逐条展示 5 笔订单
- 签约确认弹窗:列出签约后解锁的权限(交易/提现/授权/挖矿)
- 底部签约按钮:仅待签署状态显示,含加载状态
- 签约成功后自动刷新页面状态
UI 风格与全局一致:渐变背景、金色主色调、卡片容器
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 05:43:17 -08:00
hailin
99f5070552
feat(pre-planting): Mobile App 预种持仓页面完整实现
...
[2026-02-17] 预种持仓页面 (pre_planting_position_page.dart)
完整功能:
- 持仓概览卡片:累计份数、待合并份数、已合成树数(三列统计)
- 合并进度条:当前 N/5 份进度可视化 + 文字提示
- 省市信息显示(已锁定的省市)
- Tab 切换:预种订单 / 合并记录
- 预种订单列表:订单号、份数、金额、状态标签(待支付/已支付/已合并)
- 合并记录列表:合并号、树数、来源订单数、合同状态标签
- 待签约合并记录高亮显示 + "点击签署合同"提示
- 点击合并记录跳转到合并详情页
- 顶部快捷购买按钮
- 下拉刷新、错误重试、空状态提示
UI 风格与全局一致:渐变背景、金色主色调、卡片阴影
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 05:41:34 -08:00
hailin
8a4508fe0d
feat(pre-planting): Mobile App 预种购买页面完整实现
...
[2026-02-17] 预种计划购买页面 (pre_planting_purchase_page.dart)
完整功能:
- 并行加载数据(余额 + 配置 + 资格 + 持仓)
- 余额卡片:显示绿积分可用余额,支持刷新
- 合并进度卡片:显示当前 N/5 份进度条 + 已合成树数
- 省市选择:首次购买使用 city_pickers 选择,续购自动锁定复用
- 份数选择器:+/- 按钮 + 输入框,自动校验余额和资格限制
- 价格明细:单价 3171 USDT、最大可购买数、本次总价
- 购买确认弹窗:含合并预告(购买后将自动合成提示)
- 开关关闭禁用态:显示不可购买原因
- 错误重试、加载中状态完备
UI 风格与现有认种页面 (planting_quantity_page) 完全一致:
- 渐变背景 (#FFF7E6 → #EAE0C8)
- 金色主色调 (#D4AF37)
- 棕色文字 (#5D4037)
- 卡片容器带阴影
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 05:38:44 -08:00
hailin
1f9129d220
feat(pre-planting): Mobile App 预种计划路由注册 + 占位页面
...
[2026-02-17] 新增预种计划的 GoRouter 路由和占位页面:
1. route_paths.dart / route_names.dart(各 +5 行)
- /pre-planting/purchase 购买页
- /pre-planting/position 持仓页
- /pre-planting/merge/:mergeNo 合并详情页
2. app_router.dart(+28 行)
- 3 个 GoRoute 注册
3. 占位页面(3 个新文件)
- pre_planting_purchase_page.dart
- pre_planting_position_page.dart
- pre_planting_merge_detail_page.dart
后续将逐步填充完整 UI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 05:33:26 -08:00
hailin
27751731e8
feat(pre-planting): Mobile App 预种计划 Service 层
...
[2026-02-17] 新增预种计划的 Flutter 端 API 服务层:
1. pre_planting_service.dart(新增)
- PrePlantingService:预种 API 调用(配置/资格/持仓/订单/合并/签约)
- 数据模型:PrePlantingPosition、PrePlantingOrder、PrePlantingMerge 等
- 与现有 PlantingService 完全独立
2. api_endpoints.dart(+10 行)
- 添加 /pre-planting/* 端点常量
3. injection_container.dart(+9 行)
- 注册 prePlantingServiceProvider
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 05:31:39 -08:00
hailin
5bacd21840
feat(mobile-app): 为3个主导航页面添加下拉刷新功能
...
- TradingPage (兑换): 添加 RefreshIndicator,刷新时重新加载钱包和收益数据
- RankingPage (龙虎榜): 添加 RefreshIndicator,刷新时 invalidate leaderboardStatusProvider
- 列表视图和待开启状态视图均支持下拉刷新
- MiningPage (监控): 使用 LayoutBuilder + IntrinsicHeight 模式实现
- 刷新时并行加载用户数据、授权数据和钱包状态
注:ProfilePage 已有完整的下拉刷新实现,无需修改
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 21:50:43 -08:00
hailin
1c621c32ec
feat(mobile-app): 暂时隐藏自助申请授权页面的"省团队"选项
...
- 在 _buildAuthorizationTypes() 方法中过滤掉 AuthorizationType.provinceTeam
- 现在"自助申请授权"页面只显示"社区"和"市团队"两个选项
- 原代码以注释形式保留,方便未来需要时快速恢复
- 相关枚举和后端逻辑保持不变,仅前端UI隐藏
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:46:02 -08:00
hailin
207b522754
feat(customer-service): 客服联系方式从硬编码改为后台可配置
...
将 mobile-app "联系客服" 弹窗的微信/QQ联系方式从硬编码改为
admin-web 后台动态配置,支持任意数量的联系方式管理。
## Backend (admin-service)
- 新增 Prisma 模型: ContactType 枚举(WECHAT/QQ) + CustomerServiceContact
- 新增迁移 SQL: 建表 + 2条索引 + 4条种子数据(保留现有硬编码联系方式)
- 新增双 Controller (参考 app-asset.controller.ts 模式):
- AdminCustomerServiceContactController (admin/customer-service-contacts)
GET 列表 / POST 新增 / PUT 更新 / DELETE 删除
- PublicCustomerServiceContactController (customer-service-contacts)
GET 仅返回 isEnabled=true,按 sortOrder 排序
- 注意: 公开 Controller 用 @Controller('customer-service-contacts')
避免与全局前缀 api/v1 双重叠加
## Kong 网关
- 新增路由 admin-customer-service-contacts-public
路径 /api/v1/customer-service-contacts → admin-service:3010
- Admin 端点由已有 admin-api 路由 (/api/v1/admin) 覆盖
## Admin-web
- endpoints.ts: 新增 CUSTOMER_SERVICE_CONTACTS 端点组
- customerServiceContactService.ts: CRUD 服务 (list/create/update/delete)
- settings/page.tsx: 新增"客服联系方式管理"区块
表格展示(排序/类型/标签/联系方式/启停/操作) + 内联新增/编辑表单
- settings.module.scss: contactTable / contactForm / contactFormFields 样式
## Flutter Mobile-app
- storage_keys.dart: 新增 cachedCustomerServiceContacts 缓存 key
- customer_service_contact_service.dart: API + 缓存服务
(内存5分钟TTL + SharedPreferences持久化 + 后台静默刷新)
- injection_container.dart: 注册 customerServiceContactServiceProvider
- profile_page.dart: _showCustomerServiceDialog() 从硬编码改为
动态 API 加载,contacts 为空时显示"暂无客服联系方式"占位符
## 文件清单 (4 新建 + 9 修改)
新建:
- backend/.../migrations/20260205100000_add_customer_service_contacts/migration.sql
- backend/.../controllers/customer-service-contact.controller.ts
- frontend/admin-web/src/services/customerServiceContactService.ts
- frontend/mobile-app/lib/core/services/customer_service_contact_service.dart
修改:
- backend/.../prisma/schema.prisma
- backend/.../src/app.module.ts
- backend/api-gateway/kong.yml
- frontend/admin-web/src/infrastructure/api/endpoints.ts
- frontend/admin-web/src/app/(dashboard)/settings/page.tsx
- frontend/admin-web/src/app/(dashboard)/settings/settings.module.scss
- frontend/mobile-app/lib/core/storage/storage_keys.dart
- frontend/mobile-app/lib/core/di/injection_container.dart
- frontend/mobile-app/lib/features/profile/presentation/pages/profile_page.dart
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 05:00:25 -08:00
hailin
34ba209e44
fix(app-assets): 修复公开API路径双重前缀 + Kong网关路由缺失
...
问题:移动端配置的开屏图/引导图无效
根因:
1. PublicAppAssetController 和 PublicSystemConfigController 的
@Controller('api/v1/xxx') 与 NestJS 全局前缀 api/v1 叠加,
导致实际端点为 api/v1/api/v1/xxx(双重前缀)
2. Kong 网关缺少 /api/v1/app-assets 和 /api/v1/system-config 路由
3. Flutter 端使用 /admin-service/api/v1/xxx 路径,不匹配任何 Kong 路由
修复:
- 后端:Controller 路径去掉 api/v1 前缀,由全局前缀统一添加
- Kong:新增 admin-app-assets-public 和 admin-system-config-public 路由
- Flutter:API 路径改为 /app-assets 和 /system-config/display/settings
受影响文件:
- backend/api-gateway/kong.yml (新增2条路由)
- backend/.../app-asset.controller.ts (Controller路径修正)
- backend/.../system-config.controller.ts (Controller路径修正)
- frontend/.../app_asset_service.dart (API路径修正)
- frontend/.../system_config_service.dart (API路径修正)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 04:36:53 -08:00
hailin
f13814e577
fix(mobile-app): 排名详情页隐藏敏感统计字段
...
火柴人排名详情页 (UserProfilePage) 暂时隐藏以下显示元素(代码保留,注释隐藏):
- 统计卡片:引荐数、同伴数、本人认种数(仅保留"同伴认种")
- 基本信息卡片:用户ID (accountSequence)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 17:41:11 -08:00
hailin
d075853a7f
feat(app-assets): 应用图片管理 — 开屏图/引导图可从 admin-web 配置
...
新增从 admin-web 后台管理开屏图(2张)和引导图(5张+标题/副标题)的完整功能链路。
移动端优先使用后台配置的远程图片,无配置或加载失败时自动回退到本地 asset。
### Backend (admin-service)
- Prisma schema 新增 AppAssetType 枚举 + AppAsset 模型 (type/sortOrder 唯一约束)
- 新增 AdminAppAssetController: 图片上传(multipart)、列表查询、元数据更新、删除
- 新增 PublicAppAssetController: 公开查询接口供移动端消费 (仅返回 isEnabled=true)
- 新增数据库 migration: 20260204100000_add_app_assets
### Admin-web
- endpoints.ts 新增 APP_ASSETS 端点组
- 新增 appAssetService.ts: list/upload/update/delete 方法
- Settings 页新增"应用图片管理"区块: 开屏图 2 卡槽 + 引导图 5 卡槽
- 每个卡槽支持: 图片上传预览、启用/禁用开关、删除、引导图额外支持标题和副标题编辑
### Mobile-app (Flutter)
- 新增 AppAssetService: 3 级缓存策略 (内存 5min TTL → SharedPreferences → 后台静默刷新)
- splash_page.dart: 支持远程开屏图 (CachedNetworkImage),fallback 到本地 asset
- guide_page.dart: 支持远程引导图+标题/副标题覆盖,fallback 到本地 asset
- 替换 2 张开屏图为新版 (1280x1826/1834, ~245KB)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 11:20:26 -08:00
hailin
57239e81dd
chore(mobile-app): 优化开屏资源和UI文案
...
- 删除36张帧动画图片减小包体积
- 静态开屏图片从3张改为2张
- 将"权益激活"改为"权益已激活"
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 10:29:37 -08:00
hailin
dab4b0674d
fix(mobile-app): 修复引荐列表展开无法显示更多数据的问题
...
- 使用实际总数作为limit参数请求API
- 添加调试日志便于排查
- 优化:已加载全部数据时直接展开不重复请求
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 09:13:07 -08:00
hailin
8eb5b410cc
feat(mobile-app): 引荐列表支持展开/收拢功能
...
- 初始只显示前10条引荐记录
- 超过10人时显示"..."按钮可点击展开全部
- 展开后显示"收起"按钮可点击收拢
- 加载更多时显示loading指示器
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 08:59:03 -08:00
hailin
4ee355a7cd
fix(mobile-app): 开屏图片改为保持原比例不拉伸
...
使用 BoxFit.contain 替代 BoxFit.cover,
图片保持原比例显示,不足部分用黑边填充。
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 08:51:26 -08:00
hailin
96695575d5
feat(mobile-app): 启用兑换页面的划转功能
...
移除划转按钮的临时禁用标志,恢复正常功能。
用户点击划转按钮后将跳转到划转页面。
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 08:48:45 -08:00
hailin
414fe95d04
feat(mobile-app): 开屏页改为随机静态图片模式
...
- 禁用帧动画,改为显示随机静态图片(3张中随机选1张)
- 显示3秒后自动跳转,保留跳过按钮
- 帧动画代码保留备用,可通过 _useStaticImage 开关切换
- 新增 splash_static 目录存放静态图片
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 08:19:25 -08:00
hailin
fabfbb73fe
fix(mobile-app): 修复开机动画卡住问题
...
问题原因:
1. TelemetryConfig.syncFromRemote() URL拼接错误,导致请求无效路径
2. 遥测配置同步使用await阻塞,即使失败也要等待超时
修复内容:
1. 修正URL拼接:apiBaseUrl已包含/api/v1,不再重复添加
2. 将超时时间从10秒缩短为5秒
3. 将遥测配置同步改为非阻塞,不再await等待
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 08:08:21 -08:00
hailin
7a4a207bed
feat(mobile-app): 增强合同PDF下载可靠性和用户体验
...
- PDF下载增加10次自动重试机制,使用指数退避策略
- 超时时间延长至300秒,适应大文件和慢网络
- 新增下载进度显示(百分比圆环)
- 失败后显示重试按钮,区分任务加载错误和PDF下载错误
- ApiClient.get方法新增cancelToken和onReceiveProgress参数支持
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 07:12:21 -08:00
hailin
f7b2267583
feat(mobile-app): 临时禁用划转功能
...
划转功能暂时维护中,点击按钮会显示提示信息。
恢复时将 isTransferDisabled 改为 false 即可。
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 02:56:26 -08:00
hailin
990f218051
fix(mobile-app): 修复认种订单解析和状态检查问题
...
1. 修复 getMyOrders 解析:兼容后端直接返回数组格式
2. 添加 MINING_ENABLED 订单状态枚举和解析
3. 在 ADOPTION_WIZARD 完成检查中包含 miningEnabled 状态
问题原因:
- 后端返回订单列表格式是直接数组 [...],前端期望的是 {items: [...]}
- 后端返回的 MINING_ENABLED 状态未在前端枚举中定义
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 02:49:31 -08:00
hailin
96a84cc281
fix(mobile-app): 修复认种向导完成后无法返回待办页面的问题
...
问题:认种向导完成后使用 context.go() 跳转到合同签署页面,
替换了整个导航栈,导致合同签署完成后无法返回待办页面继续处理其他待办。
修复:改用 context.push() 跳转到合同签署页面,保留导航栈,
合同签署完成后可以正确返回待办页面。
同时添加了详细的调试日志,便于排查问题。
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 02:43:23 -08:00
hailin
1a617e02f8
fix(mobile-app): 将授权申请页面的'伞下'改为'下'
2026-01-09 02:23:20 -08:00
hailin
d1a52e74a0
fix(mobile-app): 修复认种向导待办操作无法正确标记完成的问题
...
问题:用户完成认种并签署合同后,ADOPTION_WIZARD待办操作没有被标记为完成,
导致用户被卡在待办操作页面无法进入App。
原因:原来的检查逻辑只检查是否有"待签合同",当用户已签署合同后,
pendingTasks为空,返回false,导致待办操作无法完成。
修复方案:
- 改为检查用户是否有已支付的认种订单(PAID/FUND_ALLOCATED状态)
- 通过比较订单创建时间和待办操作创建时间来判断
- 订单在待办操作之后创建 → 已完成
- 订单在待办操作之前但相差不超过24小时 → 也认为已完成(兼容延迟)
- 保留待签合同的备用检查逻辑
影响范围:仅影响ADOPTION_WIZARD待办操作的完成检测
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 02:03:22 -08:00
hailin
4f55d86050
feat(mobile-app): 更新客服联系方式
...
- 客服微信1: liulianhuanghou1
- 客服微信2: liulianhuanghou2
- 客服QQ1: 1502109619
- 客服QQ2: 2171447109
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 03:10:50 -08:00
hailin
1b237778ee
feat(mobile-app): 添加联系客服功能
...
在个人中心设置菜单中添加"联系客服"入口,点击后显示弹窗,
用户可以查看客服的QQ号和微信号,并支持一键复制到剪贴板。
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 23:56:59 -08:00
hailin
5419b15bf1
fix(mobile-app): 已结算数据改为从流水统计API获取
...
- 从 wallet-service 的 getLedgerStatistics() 获取 REWARD_SETTLED 类型的总金额
- 与流水明细中的结算记录统计来自同一数据源,确保数据一致性
- 添加调试日志对比 summary 和流水统计的数据
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 19:38:37 -08:00
hailin
81ad8adf93
fix(mobile-app): 用户资料页术语修改
...
- 直推 → 引荐
- 伞下 → 同伴
- 个人认种 → 本人认种
- 团队认种 → 同伴认种
- 推荐人 → 引荐人
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 19:11:36 -08:00
hailin
2a31e1ba6d
Revert "feat(mobile-app): 用户资料页添加"同伴认种"标题和快捷标签"
...
This reverts commit d274444ca9 .
2026-01-05 19:06:43 -08:00
hailin
d274444ca9
feat(mobile-app): 用户资料页添加"同伴认种"标题和快捷标签
...
- 在统计卡片上方添加"同伴认种"标题(紫色)
- 在统计卡片下方添加"引荐"、"同伴"、"本人"快捷标签
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 18:35:21 -08:00
hailin
e6da0cbb05
fix(mobile-app): 修复 Token 刷新并发竞态导致的意外过期问题
...
- 添加 Token 刷新锁,确保多个 401 请求只触发一次刷新
- 添加过期通知去重,避免重复弹出登录过期提示
- 增强 deviceId 校验,缺失时记录日志
- 添加详细调试日志便于排查问题
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 07:20:31 -08:00
hailin
bdc6ba524f
fix(authorization): 火柴人排名改为按区域过滤
...
修改排名逻辑,只显示获得相同省/市公司授权的用户排名。
- 后端 getStickmanRanking 改用 findRankingsByMonthAndRegion
- 简化实时创建评估逻辑,只为当前区域创建
- 更新前端注释说明
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 05:56:30 -08:00
hailin
2136b7a144
feat(mobile-app): 添加待办操作轮询机制
...
解决老版本 App 升级后不重启导致无法激活待办事项的问题。
- 新增 PendingActionPollingService 定时轮询服务(每4秒检查)
- App启动时无待办则启动轮询,有待办则直接进入待办页面
- 轮询检测到待办后自动停止并跳转,防止重入问题
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 05:36:18 -08:00
hailin
99b2b10ba0
fix(mobile-app): always fetch deposit address from server in deposit_service
...
Remove local storage cache priority to avoid returning wrong address
after account switching. Always fetch from server API to ensure the
address belongs to the currently logged-in user.
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 10:17:41 -08:00
hailin
04545c86a5
fix(mobile-app): fetch wallet address from server API instead of local storage
...
The wallet address displayed in long-press mode was incorrectly showing
another user's address from local storage cache. Now fetches the correct
address from the /me API endpoint for the currently logged-in user.
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-04 10:00:33 -08:00