Commit Graph

892 Commits

Author SHA1 Message Date
hailin a68fe5e999 feat(mining-app): 兑换页面"流通池"改名及"已销毁量"点击查看销毁明细
1. 将市场数据卡片中的"流通池"标签改名为"已分配积分股"
   - 展示值不变,仍为 totalMined(全网已挖矿产出总量)

2. "已销毁量"新增点击交互,点击弹出"销毁明细"对话框:
   - 系统总销毁量(blackHoleAmount):当前页面已展示的黑洞销毁总量
   - 全网兑换销毁量(circulationPool):卖出交易实际产生的流通池金额
   - 标签旁显示 info_outline 图标提示可点击

3. 重构 _buildMarketDataItem,拆分出 _buildMarketDataItemContent:
   - _buildMarketDataItem:包含 Expanded 包裹,供普通数据项使用
   - _buildMarketDataItemContent:纯内容组件,支持 showTapHint 参数
   - 避免 Row > GestureDetector > Expanded 的布局冲突

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:55:37 -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 a5a69645b4 fix(trading): 流通池改为显示已挖矿产出总量,解决显示为0的问题
前端"流通池"原来读取 circulationPool(交易流通池),因系统尚无卖出交易故为 0。
现改为读取 totalMined(全网已挖矿产出的积分股总量 = 用户已挖 + 系统已挖)。

后端新增 getTotalMinedFromMiningService() 方法,调用 mining-service 的
GET /mining/progress 接口获取 totalDistributed。

注意:价格公式中的 circulationPool 保持不变,仍用交易流通池参与计算。
新增的 totalMined 字段仅用于前端展示。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 02:54:26 -08:00
hailin 18675f083c fix(admin-web): 滚动区域改到 nav 内部,避免裁掉 toggle 按钮
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 06:55:32 -08:00
hailin 31d3eabcf8 fix(admin-web): 侧边栏菜单项过多时支持滚动,底部不再被截断
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 06:46:15 -08:00
hailin e32ef9b9ff fix(frontend): snapshot.types 补充 MPC_POSTGRES 类型和标签
后端新增了 MPC_POSTGRES 备份目标,前端 BackupTarget 类型和
BACKUP_TARGET_LABELS 缺少对应项导致复选框无法渲染。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 04:19:57 -08:00
hailin 26e55a649f feat(snapshot): 进度显示增加文件大小信息,完成项显示 "完成 (29.4 MB)"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 02:59:07 -08:00
hailin ff28615fc3 fix(admin-web): Dockerfile 构建时传入 SNAPSHOT_SERVICE_URL build arg
Next.js rewrites 在构建阶段烘焙,运行时环境变量不生效

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 02:53:03 -08:00
hailin de361e24f6 fix(infra): 网关 nginx 添加 snapshot-api 代理 + admin-web 配置 SNAPSHOT_SERVICE_URL
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 02:44:46 -08:00
hailin 30f1355bb4 fix(admin-web): snapshots 页面补上 PageContainer 包裹,恢复侧边栏
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 02:27:43 -08:00
hailin 8855491637 feat(snapshot): 进度精度升级 — Float百分比 + MB消息存DB
- schema: progress Int→Float,新增 progressMsg 字段
- PG handler: 百分比保留2位小数(toFixed(2)),不再 Math.floor
- orchestrator: 每2秒写DB时同时写 progressMsg (含MB信息)
- 前端: 百分比显示 toFixed(1),message 优先读 progressMsg

效果: 113GB库每次轮询进度条和MB数都有变化,不再卡在整数百分比

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 01:57:47 -08:00
hailin 38efa891b8 fix(snapshot): Dockerfile 添加 SNAPSHOT_SERVICE_URL build ARG
Next.js rewrites 在 build 时烘焙到 routes-manifest.json,
运行时环境变量无法覆盖。需要通过 Docker build ARG 在构建时传入。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 00:43:33 -08:00
hailin ee94f1420d fix(snapshot): 前端 API 改走 Next.js rewrites 代理 + WebSocket 改 REST 轮询
- snapshot.api.ts: 从直连 localhost:port 改为 /api/snapshots/* 走 Next.js 代理
- next.config: 两个前端都添加 /api/snapshots/:path* → snapshot-service 代理规则
- docker-compose.2.0-snapshot.yml: overlay 中追加 mining-admin-web 的 SNAPSHOT_SERVICE_URL
- useSnapshotWebSocket → useSnapshotPolling: 2秒轮询 GET /snapshots/:id 获取进度
- 移除 socket.io-client 依赖(Next.js standalone 不支持 WebSocket proxy)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 00:37:41 -08:00
hailin ef2f0f67bf chore: 更新前端 package-lock.json 同步 socket.io-client 依赖
添加 socket.io-client 到 package.json 后未同步 lock 文件,
导致 Docker 构建时 npm ci 报 EUSAGE 错误。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 21:56:28 -08:00
hailin cf07eb03be feat(snapshot): 数据快照备份服务全量实现(纯新增,零侵入)
一套代码两处部署的在线备份编排服务,为 1.0 认种分配系统和 2.0 算力挖矿系统
分别提供 PostgreSQL / Redis / Kafka / ZooKeeper / MinIO / Uploads 的在线备份能力。
管理员在 admin-web / mining-admin-web 中选择备份目标和存储方式,点击备份后系统
串行执行各组件备份,通过 Socket.IO WebSocket 实时推送进度到前端。

## 后端 snapshot-service(NestJS 10 + Prisma 5 + SQLite)

架构: DDD 四层(api / application / domain / infrastructure)

- api 层:
  · SnapshotController — REST API(创建/查询/删除/下载)含 Range/206 断点续传
  · SnapshotGateway — Socket.IO WebSocket 实时推送 5 类事件
  · HealthController — 健康检查
  · CreateSnapshotDto — class-validator 验证
  · toSnapshotResponse — BigInt→string 序列化

- application 层:
  · SnapshotOrchestratorService — 核心编排引擎
    - startSnapshot() 异步启动,不阻塞 HTTP
    - 按 PG→Redis→Kafka→ZK→MinIO→Uploads 顺序串行执行
    - 单目标失败不中断整体任务
    - MinIO 模式: 备份完上传到 MinIO 后删除本地临时文件
    - LOCAL 模式: 保留在服务器临时目录供下载
    - @Cron(EVERY_HOUR) 自动清理过期本地备份(默认 72h)
    - runningTaskId 防止并发执行

- domain 层:
  · BackupTarget 枚举(6 种目标)+ BACKUP_TARGET_ORDER 执行顺序
  · SnapshotStatus 枚举(PENDING/RUNNING/COMPLETED/FAILED)
  · StorageType 枚举(MINIO/LOCAL)
  · BackupHandler 接口 + BACKUP_HANDLER_TOKEN

- infrastructure 层:
  · 6 个备份 Handler(均实现 BackupHandler 接口):
    - PostgresBackupHandler: pg_basebackup 通过网络流式备份,解析 stderr 进度
    - RedisBackupHandler: BGSAVE + LASTSAVE 轮询 + 打包 dump.rdb/AOF
    - KafkaBackupHandler: archiver 打包数据卷,按字节计算进度
    - ZookeeperBackupHandler: archiver 打包 data/ + log/
    - MinioBackupHandler: SDK 列举并下载所有桶(排除备份桶)后打包
    - UploadsBackupHandler: archiver 打包上传文件目录
  · 2 个存储适配器:
    - MinioStorageAdapter: fPutObject 上传 / removeObjects 批量删除
    - LocalStorageAdapter: 本地临时目录管理 + 过期清理
  · PrismaService (SQLite) + SnapshotRepository (完整 CRUD)
  · BACKUP_HANDLER_TOKEN 工厂: 根据 AVAILABLE_TARGETS 环境变量过滤可用 handler

- Prisma Schema (SQLite):
  · SnapshotTask: 主表,targets 存 JSON 字符串,totalSize 用 BigInt
  · SnapshotDetail: 明细表,每个目标一行,@@index([taskId])
  · onDelete: Cascade 级联删除

- Dockerfile: 多阶段构建,生产镜像安装 postgresql-client + mc (MinIO CLI)
  SQLite 使用 prisma db push 而非 migrate deploy

- 部署端口: 1.0 系统 = 3099,2.0 系统 = 3199

## Docker Compose overlay(纯新增,不修改现有 docker-compose)

- docker-compose.snapshot.yml (1.0):
  · 挂载 redis_data/kafka_data/zookeeper_data/zookeeper_log/admin_uploads_data 只读卷
  · AVAILABLE_TARGETS=POSTGRES,REDIS,KAFKA,ZOOKEEPER,MINIO,UPLOADS
  · 依赖 postgres + redis 健康检查

- docker-compose.2.0-snapshot.yml (2.0 standalone):
  · 挂载 redis_2_data/mining-admin-uploads/trading-uploads 只读卷
  · AVAILABLE_TARGETS=POSTGRES,REDIS,UPLOADS
  · 依赖 postgres-2 + redis-2 健康检查

## 前端 admin-web(Next.js 15 + SCSS)

- 新增 /snapshots 页面: 创建备份表单 + 实时进度条 + 历史列表 + 下载/删除
- 新增 useSnapshotWebSocket hook: Socket.IO 连接 + 5 类事件监听
- 新增 snapshot.api.ts: 独立 fetch(不走通用 apiClient,snapshot 服务独立端口)
- 新增 snapshot.types.ts: 共享类型定义
- 新增 page.module.scss: 表单/进度条/表格样式
- 修改 Sidebar.tsx: 添加「数据快照」菜单项
- package.json: 添加 socket.io-client 依赖

## 前端 mining-admin-web(Next.js 14 + Tailwind CSS)

- 新增 /snapshots 页面: 同 admin-web 功能,Tailwind CSS 风格
- 新增 useSnapshotWebSocket hook
- 新增 snapshot.api.ts + snapshot.types.ts
- 修改 sidebar.tsx: 添加「数据快照」菜单项 + HardDrive 图标
- package.json: 添加 socket.io-client 依赖

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 21:53:09 -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 765a4f41d3 feat(pre-planting): Admin Web 预种管理页面 + Sidebar 入口
[2026-02-17] Admin Web 预种计划管理页面完整实现

新增文件:
- (dashboard)/pre-planting/page.tsx: 预种管理页面
  - 预种开关控制卡片(开启/关闭 + 状态徽章)
  - 四格统计卡片(总订单、总份数、总金额、合成树数)
  - Tab 切换:预种订单 / 用户持仓 / 合并记录
  - 订单表格:订单号、用户、份数、金额、状态标签、时间
  - 持仓表格:用户、累计份数、待合并进度、合成树数、省市
  - 合并表格:合并号、用户、树数、来源订单、合同状态、挖矿状态
  - 搜索过滤、刷新、加载/错误/空状态处理
- pre-planting.module.scss: 页面样式
  - 开关状态卡片(渐变背景,开/关不同主题色)
  - 统计网格(4列响应式)
  - Tab、表格、状态标签样式

修改文件:
- Sidebar.tsx: 新增"预种管理"菜单项(数据统计与系统维护之间)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 05:54:21 -08:00
hailin 63ae7662a4 feat(pre-planting): Admin Web 预种计划 Service 层
[2026-02-17] Admin Web 预种管理 API 服务 + React Query Hooks

新增文件:
- endpoints.ts: PRE_PLANTING 端点组(config/toggle/orders/positions/merges/stats)
- prePlantingService.ts: 预种管理服务(开关配置、订单/持仓/合并查询、统计汇总)
  - 完整 TypeScript 类型定义(Config, Stats, Order, Position, Merge)
  - 分页列表请求/响应类型
- usePrePlanting.ts: React Query hooks
  - Query key factory(层级化参数化)
  - usePrePlantingConfig/Stats/Orders/Positions/Merges
  - useTogglePrePlantingConfig(mutation + 自动刷新)
- hooks/index.ts: 导出新 hooks

所有端点走 admin-service 的 PrePlantingAdminModule
与现有认种管理完全独立

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 05:48:58 -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 d27f327f9c fix(mining-app): 资产页面数据一致性修复与冗余估值隐藏
问题:
1. 总资产估值(顶部)使用 WebSocket 实时推送的价格和销毁倍数计算,
   而积分股列表项中的"≈ xxx 积分值"使用 API 返回的静态值计算,
   导致两处显示的积分值不一致(因自动销毁每分钟改变价格参数)。
2. 修复数据源统一后,积分股下方的"≈ xxx 积分值"与顶部总资产估值
   完全相同,显示冗余。

修改:
- _buildAssetList 中的 multiplier 和 currentPrice 改为优先使用
  WebSocket 实时值(_currentBurnMultiplier / _currentPrice),
  API 值仅作为 fallback,确保与 _calculateTotalAssetValue 一致
- 暂时隐藏积分股条目下方的"≈ xxx 积分值"显示(注释保留,便于恢复)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 22:57:41 -08:00
hailin 07f7f26948 feat(mining-app): 已销毁量去掉小数位显示
- format_utils.dart: 新增 formatIntWithCommas(),逗号千位分隔但不保留小数
- trading_page.dart: 已销毁量改用 formatIntWithCommas()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 07:47:05 -08:00
hailin bc3d800936 feat(mining-app): 贡献值730天失效倒计时功能
将贡献值页面的"贡献值失效倒计时"从硬编码静态文字改为基于用户
首次挖矿时间的真实730天倒计时。纯新增方式实现,不影响现有功能。

后端 (mining-service):
- get-mining-account.query.ts: MiningAccountDto 新增 firstMiningDate
  字段,在 Promise.all 中并行查询用户最早的 miningRecord,利用
  @@unique([accountSequence, miningMinute]) 索引高效查询

前端实体/模型:
- share_account.dart: 新增 DateTime? firstMiningDate(可空,向后兼容)
- share_account_model.dart: fromJson/toJson 解析和序列化 firstMiningDate

前端 UI (contribution_page.dart):
- watch shareAccountProvider 获取首次挖矿时间
- 计算已过天数和剩余天数(730 - 已过天数)
- 进度条显示实际已用时间占比
- 显示具体失效日期和剩余天数
- 无挖矿记录 → 显示"暂无挖矿记录"
- 已过期 → 显示"贡献值已失效"
- 剩余 ≤30 天 → 进度条和文字变红色警告

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 07:30:01 -08:00
hailin 6082725c80 feat(mining-app): 兑换页面积分股池和已销毁量改为原始数字显示
将"市场数据"中的"积分股池"和"已销毁量"从缩写单位(万/亿)
改为原始十进制数字显示,使用逗号千位分隔符。

- format_utils.dart: 新增 formatWithCommas() 函数,直接显示原始
  数值并用逗号每3位分隔,不再缩写为万/亿
- trading_page.dart: 积分股池和已销毁量两个字段从 formatCompact()
  改为 formatWithCommas()

示例: 52.38亿 → 5,238,000,000

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 07:29:43 -08:00
hailin 7564c1151d feat(admin-web): 做市商充值记录流水查询功能
在"充值现金(积分值)"弹窗底部新增"查看充值记录"入口按钮,
点击后打开独立的充值流水记录弹窗,支持以下功能:

- 筛选 Tab:全部 / 中心化充值 / 区块链充值(通过 memo 字段区分)
- 表格列:时间、充值方式(Badge)、金额、变动前余额、变动后余额、备注
- 分页控件:上一页/下一页 + 页码显示 + 总记录数

改动文件:
- market-maker.api.ts: 新增 LedgerEntry 类型定义和 getLedgers() API 函数
- use-market-maker.ts: 新增 useCashDepositLedgers() hook
- page.tsx: 充值弹窗底部入口 + 充值记录 Dialog UI

后端 API(GET /admin/market-maker/{name}/ledgers)已存在,无需改动。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 00:46:41 -08:00
hailin 254796b08d feat(mining-app): 提升价格显示小数精度
- K线详情弹窗(开/高/低/收):小数位数增加5位
  - 价格≥1: 4位 → 9位
  - 价格0.0001~1: 6位 → 11位
  - 超小价格有效数字: 4位 → 9位
- 兑换页面"当前积分股价值":小数位数增加2位
  - formatPriceFull 新增 extraDecimals 可选参数,支持按需增加精度
  - 调用时传入 extraDecimals: 2
- 资产页面"总资产估值":小数位数从4位增加到6位
  - formatAmount(4位) → formatDecimal(6位)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 07:46:28 -08:00
hailin cd1d16fc7f feat(admin-web): 批量下载支持断点续传
- 下载前检查文件是否已存在
- 已存在的文件自动跳过
- 显示跳过数量和新下载数量

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 00:22:04 -08:00
hailin b2bace1687 feat(admin-web): 批量下载改为逐个下载到用户选择的目录
- 先弹出目录选择对话框让用户指定保存位置
- 逐个下载合同 PDF 到指定目录
- 显示下载进度(已下载数/总数)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 00:20:13 -08:00
hailin 9771a3d69d fix(admin-web): 修复 TypeScript 类型错误
将 Uint8Array[] 改为 ArrayBuffer[] 以兼容 Blob 构造函数

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 00:07:18 -08:00
hailin 91132ec167 feat(admin-web): 批量下载增加进度条显示
- 显示打包进度和下载进度两个阶段
- 进度条实时更新百分比
- 使用 File System Access API 支持用户选择保存位置

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 00:04:02 -08:00
hailin f97eacdc70 feat(admin-web): 批量下载支持选择保存路径
使用 File System Access API 让管理员可以选择文件保存位置,
而不是自动下载到默认目录。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 00:01:40 -08:00
hailin 8b7872d205 fix(admin-web): 批量下载完成后直接触发浏览器另存为对话框
- 创建任务后自动轮询等待完成
- 完成后使用 <a download> 触发浏览器下载对话框
- 按钮显示打包进度
- 打包期间禁用按钮防止重复点击

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 23:59:04 -08:00
hailin 15019206c8 fix(admin-web): 修复合同下载URL环境变量名错误
使用 NEXT_PUBLIC_API_BASE_URL 替代 NEXT_PUBLIC_API_URL,
与 .env.production 配置保持一致。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 23:37:46 -08:00
hailin d108d2c693 fix(admin-web): 合同管理省份筛选只使用6位代码
PROVINCE_CODE_NAMES 同时包含2位和6位省份代码,但数据库存储的是6位代码。
筛选下拉菜单只使用6位代码,避免查询不到数据。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 23:32:55 -08:00
hailin 86461a052d feat(contracts): 合同管理功能 - 查询/下载/批量打包
新增功能:
- 合同列表查询(支持省市、状态、时间筛选)
- 单个合同 PDF 下载(支持断点续传)
- 批量下载 ZIP 打包(异步任务处理)
- 增量下载(基于上次下载时间)
- 用户详情页合同 Tab

后端:
- planting-service: 内部合同查询 API
- admin-service: 合同管理控制器、服务、批量下载 Job
- 新增 contract_batch_download_tasks 表

前端:
- 新增独立合同管理页面 /contracts
- 用户详情页新增合同信息 Tab
- 侧边栏新增合同管理入口

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 22:50:17 -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 a1aba14ccf feat(trade-password): 实现卖出交易的支付密码验证功能
## 后端改动

### auth-service
- user.aggregate.ts: 添加支付密码相关方法 (setTradePassword, verifyTradePassword, hasTradePassword)
- trade-password.service.ts: 新建支付密码业务逻辑服务
- trade-password.controller.ts: 新建支付密码 REST API (status/set/change/verify)
- user.repository.ts: 添加 tradePasswordHash 字段的持久化
- schema.prisma: 添加 trade_password_hash 字段
- migration 0003: 添加支付密码字段迁移

### trading-service
- audit-ledger.service.ts: 新建审计分类账服务 (Append-Only设计,仅INSERT)
- schema.prisma: 添加 AuditLedger 模型和 AuditActionType 枚举
- migration 0008: 添加审计分类账表迁移

## 前端改动 (mining-app)

### 新增页面/组件
- trade_password_page.dart: 支付密码设置/修改页面 (6位数字)
- trade_password_dialog.dart: 交易时的支付密码验证弹窗

### 功能集成
- trading_page.dart: 卖出时检查支付密码
  - 未设置: 提示用户跳转设置页面
  - 已设置: 弹出验证弹窗,验证通过后才能卖出
- profile_page.dart: 账户设置增加"支付密码"入口
- user_providers.dart: 添加支付密码相关 Provider
- auth_remote_datasource.dart: 添加支付密码 API 调用
- api_endpoints.dart: 添加支付密码 API 端点
- routes.dart/app_router.dart: 添加支付密码页面路由

## 安全设计
- 支付密码独立于登录密码 (6位纯数字)
- 审计分类账采用链式哈希保证完整性
- 所有敏感操作记录不可变审计日志

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 18:12:39 -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 d29454fc74 feat(admin-web): 省团队收益汇总明细增加来源用户列并修复账户名称显示
问题描述:
1. 省团队收益汇总的详细明细中缺少收益来源用户信息
2. 账户类型显示为数字(如7440000)而不是省名称

修改内容:

1. 后端 reward-service (reward-application.service.ts)
   - getRewardEntriesByType 方法返回值新增 sourceAccountSequence 字段
   - 该字段表示触发此收益的用户账户序列号(来自认种用户)

2. 后端 reporting-service (reward-service.client.ts)
   - RewardEntryDTO 接口新增 sourceAccountSequence 字段

3. 前端 admin-web
   - system-account.types.ts: RewardEntryDTO 新增 sourceAccountSequence 字段
   - system-account.types.ts: getAccountDisplayName 函数支持7开头的省团队账户
     示例:7440000 → "广东省团队 (7440000)"
   - SystemAccountsTab.tsx: 详细明细表格新增"来源用户"列

效果:
- 省团队收益明细现在显示:时间、账户(省名称)、来源用户、订单号、金额、状态
- 账户列显示格式:"{省名}省团队 ({账户序列号})"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:35:22 -08:00
hailin 04d3b2470a feat(admin-web): 将USDT显示文本统一替换为"绿积分"
根据业务需求,将管理后台中所有面向用户显示的"USDT"文本改为"绿积分":

修改文件及内容:
1. system-transfer/page.tsx (7处)
   - 错误提示: "最小划转金额为 1 USDT" → "最小划转金额为 1 绿积分"
   - 余额显示: "余额: xxx USDT" → "余额: xxx 绿积分"
   - 表单标签: "划转金额 (USDT)" → "划转金额 (绿积分)"
   - 表单提示: "最小划转金额为 1 USDT" → "最小划转金额为 1 绿积分"
   - 订单金额、详情弹窗金额、确认弹窗金额显示

2. userDetail.types.ts (2处)
   - DEPOSIT_USDT: 'USDT充值' → '绿积分充值'
   - USDT: 'USDT' → '绿积分'

3. users/[id]/page.tsx (1处)
   - DEPOSIT_USDT: 'USDT充值' → '绿积分充值'

4. formatters.ts (1处)
   - formatCurrency函数中 USDT: '积分 ' → '绿积分 '

注意:所有修改均为纯UI显示文本,不影响程序逻辑和功能。
映射对象的key保持不变,仅修改显示给用户的value值。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 17:29:27 -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