hailin
5ee94b3672
fix(notifications): NotificationPriority 类型从 string 改为 Prisma 枚举
...
修复后端编译错误: priority 字段类型应使用 @prisma/client 的
NotificationPriority 枚举而非 string。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 08:38:25 -08:00
hailin
7c781c7d62
feat(notifications): 2.0系统通知弹窗功能(后端+管理端+APP端)
...
复制1.0通知系统架构到2.0系统,实现完整的通知推送功能:
后端 (mining-admin-service):
- Prisma Schema: 添加 Notification/NotificationRead/NotificationUserTarget 表
- NotificationService: 完整 CRUD + 移动端通知查询/已读标记
- AdminNotificationController: 管理端通知 CRUD API
- MobileNotificationController: 移动端通知列表/未读数/标记已读 API
管理端 (mining-admin-web):
- 通知管理页面: 列表/筛选/新建/编辑/删除 Dialog
- 支持类型/优先级/目标用户/强制弹窗/发布时间等完整配置
- 侧边栏添加"通知管理"入口
APP端 (mining-app):
- NotificationService: 通知API服务(经Kong网关路由)
- NotificationBadgeProvider: 30秒轮询未读数量+生命周期监听
- ForceReadNotificationDialog: 强制阅读弹窗(橙色主题,逐条查看+确认)
- NotificationInboxPage: 通知收件箱(支持dark/light主题)
- MainShell: 添加强制弹窗检查(启动+前台恢复,60秒冷却)
- ProfilePage: 用户头部添加通知图标+未读角标
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 08:35:16 -08:00
hailin
59f7bdc137
feat(admin): 功能8修正 — 自助申请照片独立展示页(纯新增方案)
...
用户在 App 自助申请社区/市团队/省团队授权时上传的办公室照片,
之前错误放在授权管理页且因 CDC 未同步导致全显示"-"。
本次采用纯新增方案:绕过 CDC,通过内部 HTTP API 直连
authorization-service 源头数据库读取照片,保证数据 100% 准确。
=== 数据流 ===
admin-web 新页面 → admin-service 新 Controller
→ authorization-service 新 Internal API
→ authorization_roles 表 (源头, officePhotoUrls 字段)
=== 后端 — authorization-service ===
- 新建 internal-self-apply-photos.controller.ts
GET /authorization/self-apply-photos?page=1&limit=20&roleType=COMMUNITY
使用 $queryRaw 查询 office_photo_urls != '{}' 的记录
支持 roleType 筛选 + 分页
- index.ts 新增 export, app.module.ts 注册 controller
=== 后端 — admin-service ===
- 新建 authorization/authorization-proxy.service.ts
axios 代理调用 authorization-service 内部 API
批量查 user_query_view 补充 nickname + avatarUrl
- 新建 api/controllers/authorization-photos.controller.ts
GET /admin/authorization-photos (admin-web 调用)
- app.module.ts 注册 controller + provider
- docker-compose.yml 追加 AUTHORIZATION_SERVICE_URL 环境变量
=== 前端 — admin-web ===
- 新建 authorization-photos/ 页面 (page.tsx + SCSS)
表格展示:头像、昵称、账户序列号、授权类型、地区、照片数、申请时间
点击照片弹出 Modal 网格 → 点击单张弹出全屏 Lightbox
支持 roleType 筛选 + 分页
- Sidebar.tsx 追加"申请照片"菜单项 (紧随"授权管理"之后)
- endpoints.ts 追加 SELF_APPLY_PHOTOS 端点
- authorization/page.tsx 移除"申请照片"列、photo modal、lightbox
- authorization.module.scss 清理照片相关样式
=== 风险 ===
- CDC 链路: 零修改
- 现有 API: 零冲突 (新 controller 独立文件)
- 2.0 系统: 零影响
- 所有操作均为只读查询
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 08:08:32 -08:00
hailin
41818eb8e2
feat(mining-admin-web): 添加全局兑换记录页面
...
后端(trading-service):
- OrderRepository 新增 findAllOrders/findAllTrades 全局查询方法
- AdminController 新增 GET /admin/orders 和 GET /admin/trades 端点
支持 type/status/source/search/日期范围筛选 + 分页
前端(mining-admin-web):
- 新增 /exchange-records 页面,包含「订单记录」和「成交明细」两个 Tab
- 订单 Tab: 支持按类型/状态/来源筛选,显示订单号/账号/价格/数量等
- 成交 Tab: 支持按来源筛选,显示买卖双方/价格/数量/销毁量/手续费等
- 侧边栏添加「兑换记录」菜单项
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 07:38:46 -08:00
hailin
a55201b3b3
feat(referral+mobile): 功能6 — App 团队预种数量展示
...
纯新增实现,不修改任何现有业务逻辑,对现有系统零风险。
## 后端 — referral-service
新建 TeamPrePlantingController(JWT 认证),2 个公开端点:
1. GET /referral/me/team-pre-planting
- 返回当前用户的个人预种份数、团队预种总量
- 返回直推成员列表及每人的预种份数
- 从 TeamStatistics 表读取(CDC 事件维护的数据)
2. GET /referral/me/team-pre-planting/members?limit=20&offset=0
- 分页返回全部团队成员的预种明细(仅有预种份数 > 0 的成员)
- 使用 ancestor_path 数组查询所有下级用户
- JOIN team_statistics 获取每人的 selfPrePlantingPortions
Kong 网关无需修改(/api/v1/referral/* 已覆盖)。
## 前端 — Flutter mobile-app
新建 TeamPrePlantingPage 页面:
- 顶部统计卡片:个人预种 + 团队预种总量
- 直推预种明细列表(所有用户可见)
- 全部团队成员预种明细(仅市/省公司管理者可见,分页加载更多)
- 普通用户看到锁定提示"仅市公司/省公司管理者可查看"
入口:个人中心页预种按钮行新增绿色「团队预种」按钮。
## 文件清单
新建文件:
- backend/.../controllers/team-pre-planting.controller.ts(核心后端控制器)
- frontend/.../pages/team_pre_planting_page.dart(Flutter 团队预种页面)
微量修改(仅追加新行):
- controllers/index.ts: +1 行 export
- api.module.ts: +2 行 import/注册
- api_endpoints.dart: +2 行端点常量
- referral_service.dart: +4 模型类 +2 API 方法
- route_paths.dart, route_names.dart: +1 行路由定义
- app_router.dart: +1 import +1 GoRoute
- profile_page.dart: 预种按钮行追加第三个按钮
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 07:15:17 -08:00
hailin
d3969710be
fix(wallet): 系统账户划转前自动结算 settleableUsdt,解决全额划转余额不足
...
## 问题
省/市区域和团队账户收到的奖励进入 settleableUsdt,
但划转验证只检查 usdtAvailable,导致全额划转报"余额不足"。
## 修复
在 requestSystemWithdrawal 事务中,划转前自动执行结算:
1. 检测账户是否为区域/团队账户(6/7/8/9开头)
2. 若 settleableUsdt > 0,自动结算到 usdtAvailable
3. 记录 REWARD_SETTLED 流水明细(含 trigger=SYSTEM_WITHDRAWAL_AUTO_SETTLE)
4. 结算和划转在同一事务中,保证原子性
## 审计流水
每次自动结算会产生一条独立的 REWARD_SETTLED 流水:
- memo: "系统账户自动结算: 待结算 X 绿积分转入可用余额(划转前自动执行)"
- payloadJson: { settledAmount, previousAvailable, newAvailable, trigger }
## 其他
- 划转白名单扩展支持 6xxx(市团队)、7xxx(省团队)
- getSystemAccountName 添加省团队/市团队名称映射
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 06:30:34 -08:00
hailin
17df9b6df1
feat(admin): 预种管理页添加"待合并总量"统计项
...
- planting-service stats 端点新增 pendingMergePortions 字段
从 PrePlantingPosition 表聚合 SUM(available_portions)
- admin-web 统计卡片区新增"待合并总量(份)"显示
- 网格布局从 4 列调整为 5 列
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 04:17:38 -08:00
hailin
24fe10ee36
fix(authorization): 修复 queryAuthorizations 返回类型缺少 officePhotoUrls
...
application service 的 queryAuthorizations 方法返回类型声明中
缺少 officePhotoUrls 字段,导致 TypeScript 编译报错。
实际数据映射已正确包含该字段,只是类型注解遗漏。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 03:24:47 -08:00
hailin
ac15d6682a
feat(admin): 用户预种数量展示 & 授权申请照片查看
...
## 功能7:用户管理展示预种数量
### 需求
在用户管理(列表+详情页)展示个人及团队预种份数,
并支持跳转预种管理页查看团队中哪些ID购买了预种。
### 后端变更
referral-service — 新增内部 API:
- GET /internal/referral/pre-planting-stats/:accountSequence
- POST /internal/referral/pre-planting-stats/batch
从 TeamStatistics 表查询 selfPrePlantingPortions/teamPrePlantingPortions
admin-service:
- 新建 ReferralProxyService (src/referral/) 代理 referral-service 内部 API
- UserFullDetailDto 新增 selfPrePlantingPortions, teamPrePlantingPortions
- user-detail.controller 并行调用获取预种统计
- user.controller 批量获取用户列表预种统计
- UserListItemDto 新增 selfPrePlantingPortions, teamPrePlantingPortions
- pre-planting-config.controller 新增 teamOf 查询参数
→ 先从 referralQueryView 获取团队成员列表
→ 将 accountSequences 传递给 planting-service 过滤
planting-service:
- internal-pre-planting.controller 的 admin orders/positions 端点
新增 accountSequences 查询参数,支持按用户列表过滤
### 前端变更
admin-web:
- 用户列表页表格新增"个人预种(份)"、"团队预种(份)"两列
- 用户详情页新增预种统计卡片(个人/团队预种份数)
- 团队预种数字可点击,跳转 /pre-planting?teamOf={accountSequence}
- 预种管理页支持 teamOf URL 参数,团队过滤模式下显示提示条+返回链接
---
## 功能8:授权管理查看申请照片
### 需求
管理后台无法查看社区/市公司/省公司申请时提供的办公室照片。
原因:authorization-service 收到 officePhotoUrls 后只验证未持久化。
照片文件本身已存储在 MinIO,只需持久化 URL 到数据库。
### 后端变更
authorization-service:
- schema.prisma: AuthorizationRole 新增 officePhotoUrls String[] 字段
- authorization-role.aggregate: props/字段/getter/构造/toPersistence/所有工厂方法
- repository: save() create/update 块 + toDomain() 映射
- application service: 3个 self-apply 方法传递 officePhotoUrls 到 aggregate
- admin controller: queryAuthorizations 响应包含 officePhotoUrls
admin-service:
- schema.prisma: AuthorizationRoleQueryView 新增 officePhotoUrls 字段
- user-detail-query.repository 接口 + impl: 包含 officePhotoUrls
- user-detail.dto: AuthorizationRoleDto 新增 officePhotoUrls
### 前端变更
admin-web:
- 授权管理页表格新增"申请照片"列,点击弹出照片网格 Modal
- 照片支持点击放大(全屏 lightbox 覆盖层)
- 用户详情页授权信息 Tab 同样支持查看照片
- authorization.types.ts / userDetail.types.ts 类型更新
---
## 部署注意事项
1. authorization-service 需运行: npx prisma migrate dev --name add-office-photo-urls
2. admin-service 需运行: npx prisma migrate dev --name add-auth-role-office-photos
3. 需部署: authorization-service, admin-service, referral-service, planting-service, admin-web
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 03:09:17 -08:00
hailin
0cd0bd5694
fix(transfer): Outbox 配置值 Number() 转型,修复 Prisma take 参数类型错误
...
环境变量读取的值始终是 string,ConfigService.get<number> 不会自动转型,
导致 Prisma findMany({ take: "100" }) 报 String 类型错误。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:55:51 -08:00
hailin
5110915aa8
feat(transfer): 添加 transfer-service 初始数据库 migration
...
基于 schema.prisma 创建初始 migration SQL,包含:
- transfer_orders: 转让订单表(Saga 聚合根)
- transfer_status_logs: 状态变更审计日志
- outbox_events: Outbox Pattern 事件表
- processed_events: 幂等性保证表
容器启动时 Dockerfile 会自动执行 prisma migrate deploy 建表。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:16:28 -08:00
hailin
b3984c861c
feat(pre-planting): 预种方案调整 — 18870 USDT/棵,10份合1树
...
=== 方案变更 ===
- 全树基础价: 17830 → 18870 USDT
- 每份价格: 3566 → 1887 USDT
- 合并阈值: 5 份 → 10 份
=== 后端改动 (planting-service) ===
1. pre-planting-right-amounts.ts:
- PRE_PLANTING_PRICE_PER_PORTION: 3566 → 1887
- PRE_PLANTING_PORTIONS_PER_TREE: 5 → 10
- 10类权益金额按 floor(整棵树/10) 重算,余数归 HQ_BASE_FEE(319)
2. pre-planting-merge.aggregate.ts:
- 合并校验从硬编码 5 改为引用 PRE_PLANTING_PORTIONS_PER_TREE 常量
3. purchase-pre-planting.dto.ts:
- portionCount @Max(5) → @Max(10)
4. pre-planting-application.service.ts:
- 加价补贴计算 /5 → /PRE_PLANTING_PORTIONS_PER_TREE
- 错误文案引用常量,消除硬编码
=== 前端改动 (mobile-app) ===
1. pre_planting_purchase_page.dart: 默认价格、份数、协议文本(1/10、4%)
2. pre_planting_position_page.dart: _portionsPerTree 5→10
3. pre_planting_merge_detail_page.dart: 总价值计算和单份显示金额
4. tree_pricing_service.dart: fallback 默认值
5. pre_planting_service.dart: JSON 解析 fallback 默认值
6. 各文件注释同步更新
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 18:32:32 -08:00
hailin
28cf0b7769
fix(wallet): settleUserPendingRewards 补创建 REWARD_TO_SETTLEABLE 流水
...
转换 PENDING→SETTLEABLE 时,为每笔奖励创建带来源信息的
REWARD_TO_SETTLEABLE 流水,解决"分享收益"筛选缺失问题。
统计排除逻辑同步更新,通过 convertedFromPending 标记避免双重计算。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:15:19 -08:00
hailin
fda79304c6
Revert "fix(ledger): 分享收益筛选支持多类型(REWARD_TO_SETTLEABLE + REWARD_PENDING)"
...
This reverts commit d223671db7 .
2026-03-01 11:07:19 -08:00
hailin
d223671db7
fix(ledger): 分享收益筛选支持多类型(REWARD_TO_SETTLEABLE + REWARD_PENDING)
...
后端 entryType 筛选支持逗号分隔多值,前端"分享收益"同时查询两种类型,
解决未认种时收到的 REWARD_PENDING 分享权益在筛选中丢失的问题。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:02:08 -08:00
hailin
e4a2a0e37a
feat(ledger): 流水明细显示来源用户ID + 统计兼容历史批量转换数据
...
- wallet_service.dart: LedgerEntry 新增 sourceAccountFromMemo 从 memo 提取来源用户
- ledger_detail_page.dart: 流水列表项显示"来自 Dxxx"金色文字
- ledger_detail_page.dart: 权益详情弹窗添加来源用户行和备注行
- wallet-application.service.ts: 统计/趋势保留 memo 兼容历史批量转换记录
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:41:11 -08:00
hailin
d876dd1591
fix(wallet): 区分直接入账和批量转换的 REWARD_TO_SETTLEABLE
...
新增 REWARD_PENDING_CONVERTED 类型用于批量转换(待领取→可结算),
REWARD_TO_SETTLEABLE 保留给直接入账(hasPlanted=true时的新收入)。
统计排除:REWARD_PENDING_CONVERTED + REWARD_SETTLED(状态转换)
统计计入:REWARD_PENDING + REWARD_TO_SETTLEABLE(首次入账)
已迁移7条历史数据的 entry_type。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:30:47 -08:00
hailin
eba125901c
fix(wallet): 统计排除 REWARD_SETTLED 避免三重计入
...
奖励流水三阶段 REWARD_PENDING → REWARD_TO_SETTLEABLE → REWARD_SETTLED
是同一笔钱的状态转换,只在 REWARD_PENDING 阶段计入收入。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:07:22 -08:00
hailin
b905e8cb23
fix(wallet): 统计概览排除 REWARD_TO_SETTLEABLE 避免重复计入
...
REWARD_PENDING(入账) 和 REWARD_TO_SETTLEABLE(状态转换) 是同一笔收入
的两个阶段,统计时只应计入 REWARD_PENDING,排除 REWARD_TO_SETTLEABLE。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:01:36 -08:00
hailin
ecaaf68a27
fix(wallet): settle 时清除 pending_expire_at 避免残留倒计时
...
settleUserPendingRewards 全量结算后 pendingUsdt=0,
但 pendingExpireAt 未清除导致 API 仍返回过期时间。
与 expirePendingReward/claimRewards 行为保持一致。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 09:52:19 -08:00
hailin
d849ca7bc2
fix(wallet): getPendingRewards 只返回 PENDING 状态记录
...
之前 getPendingRewards 没有传 status 过滤参数,返回了所有状态
(包括 SETTLED 和 EXPIRED)的记录,导致前端误将已结算的预种条目
显示在待领取列表中。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 09:07:31 -08:00
hailin
718e70e61a
fix(pre-planting): 修复 settleAfterPrePlanting 响应解包(TransformInterceptor)
...
wallet-service 的 TransformInterceptor 会将响应包装为 { data: {...} },
需要从 response.data.data 中提取实际数据,与 allocatePrePlantingFunds 一致。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 08:57:45 -08:00
hailin
722c124cc9
feat(pre-planting): 预种购买后自动触发待领取→可结算转换
...
购买预种份额后,planting-service 调用 wallet-service 新增的内部 API,
将用户标记为 hasPlanted=true 并结算所有 PENDING 奖励为 SETTLED。
纯新增代码,不修改任何现有方法逻辑,两步均幂等,失败不阻塞购买流程。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 08:51:03 -08:00
hailin
27cd72fe01
feat(pre-planting): 预种可结算收益结算 + 前端可结算金额修正
...
背景:
预种奖励通过 planting-service → wallet-service allocateFunds 链路
直接写入 wallet_accounts.settleable_usdt,不经过 reward-service。
因此 reward-service 的一键结算(settleToBalance)无法覆盖预种部分,
且 reward-service 的 summary.settleableUsdt 不包含预种金额。
改动:
1. wallet-service 新增 POST /wallet/settle-pre-planting 端点
- 将 wallet 中剩余的 settleable_usdt 转入 available 余额
- settleable_usdt=0 时幂等跳过,不创建空流水
- 流水备注标注 [预种],payloadJson.source='pre-planting'
2. mobile-app 兑换页(trading_page):
- 可结算金额改为从 wallet-service 的 wallet.rewards.settleableUsdt 取值
(包含正常认种 + 预种的可结算部分,是唯一的 source of truth)
- 一键结算流程改为两步串行:
先调 reward-service settleToBalance(正常认种,不动现有逻辑),
再调 wallet-service settle-pre-planting(预种部分,纯增量)
3. mobile-app 我的页(profile_page):
- 并行加载新增 walletService.getMyWallet() 调用
- _settleableUsdt 改为从 wallet.rewards.settleableUsdt 取值
不涉及的系统:
- reward-service:零改动
- planting-service:零改动
- wallet-service 现有结算逻辑:零改动
- admin-web:零改动
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 07:33:53 -08:00
hailin
05e590ef04
fix(pre-planting): 修复可结算收益重复计算
...
pre-planting getMyRewards API 错误地将所有分配记录金额算作
settleableUsdt(包括 PENDING 状态的待领取奖励)。
预种奖励的 PENDING/SETTLEABLE 状态由 wallet-service 管理,
reward-service 的 getMyRewardSummary 已包含预种可结算部分,
不应重复累加。
修复:
- 后端 getMyRewards 返回 settleableUsdt: 0
- 前端"我"页面和"兑换"页面不再额外加预种 settleableUsdt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 03:34:22 -08:00
hailin
1157760d4d
fix(pre-planting): 补充社区/省团队/市团队 API 缺失的 treeCount 参数
...
三个接口调用时未传 treeCount,导致 authorization-service 收到
Number(undefined)=NaN,addMonthlyTrees(NaN) 使字段变为 NaN,
Prisma upsert 报 PrismaClientValidationError。
修复:全部传 treeCount=0(预种不计入月度考核),
省团队补充 provinceCode,市团队补充 cityCode,
同时修正社区/团队接口返回格式为 distributions 数组。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 02:30:35 -08:00
hailin
e32658fc5e
fix(pre-planting): 修复 authorization-service 响应包装格式解析
...
authorization-service 全局 TransformInterceptor 将响应包装为
{ success, data: T, timestamp },预种客户端需读取 response.data.data
而非 response.data。此前因解析失败静默 fallback 到系统账户。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 02:22:01 -08:00
hailin
a15a4a97b1
fix(docker): 为 planting-service 添加 AUTHORIZATION_SERVICE_URL 环境变量
...
planting-service 缺少 AUTHORIZATION_SERVICE_URL 配置,
默认回退到 http://localhost:3006,在容器内无法访问 authorization-service,
导致所有授权分配请求失败走 fallback。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 02:15:23 -08:00
hailin
d880242807
fix(pre-planting): 修复 authorization-service API 路径错误
...
预种 client 使用 /internal/authorization/... 但 authorization-service
全局前缀为 api/v1,实际路由是 /api/v1/authorization/...。
路径不对导致所有请求 404 → catch → fallback → 全部进系统账户。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 02:04:09 -08:00
hailin
530aeb2a6f
feat(authorization): 新增行政区划代码↔中文名映射表,修复省市公司查询不到的问题
...
authorization_roles表的regionCode存储格式不一致(有中文名"北京"、"广东省"也有数字代码"110100"),
但查询时统一传入6位数字代码,导致findProvinceCompanyByRegion/findCityCompanyByRegion永远返回null。
新增 RegionCodeResolver 静态映射表(34个省+333个地级市),
将精确匹配 regionCode = provinceCode 改为多形式匹配 regionCode IN (所有可能形式)。
此修复同时影响正常认种和预种的省区域/市区域/省团队/市团队权益分配。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 01:41:48 -08:00
hailin
b9ddda2532
fix(pre-planting): 修复省市代码格式不一致导致授权分配失败
...
预种DTO接收2位省代码(如"44")和4位市代码(如"4401"),
但authorization-service需要6位标准格式(如"440000"/"440100")。
- resolveAllocations中新增padEnd(6,'0')标准化转换
- fallback系统账户生成从padStart改为padEnd(右补零)
- 正常认种不受影响(SelectProvinceCityDto直接接收6位格式)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 01:23:55 -08:00
hailin
3be7b47678
feat(pre-planting+mobile): 预种奖励在"我"页面展示
...
## 问题
预种奖励直接走 planting-service → wallet-service,绕过 reward-service,
导致前端"我"页面读 reward-service 的 summary/settleable 数据时看不到预种奖励。
## 方案
前端同时读 reward-service(正常认种)和 planting-service(预种),合并展示。
## 后端(planting-service)
- PrePlantingRewardEntryRepository: 新增 findByRecipientAccountSequence() 方法,
按收款方账户查询预种奖励记录(注入 PrismaService 替代事务 client)
- PrePlantingController: 新增 GET /pre-planting/my-rewards 端点,
返回当前用户作为收款方收到的预种奖励汇总+明细列表
格式与 reward-service 的 settleable 对齐(id, rightType, usdtAmount, sourceOrderNo 等)
## 前端(Flutter mobile-app)
- PrePlantingService: 新增 getMyRewards() 方法 + PrePlantingMyRewards/PrePlantingRewardItem 数据类
- profile_page.dart: 并行调用 prePlantingService.getMyRewards(),
将预种奖励转为 SettleableRewardItem 合并到可结算列表,
summary.settleableUsdt 也加上预种金额
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:03:53 -08:00
hailin
f32748c1d5
fix(pre-planting): 修复推荐链 API 调用的 URL 路径和返回格式解析
...
1. URL: /referrals/:id/chain → /referral/chain/:id(与正常认种对齐)
2. 返回格式: 正确解析 { ancestors: [{accountSequence, hasPlanted}] }
之前错误期望 { directReferrer: {...} },导致有推荐人也被当成无推荐人
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:39:07 -08:00
hailin
545e897c1f
fix(pre-planting): 预种省/市区域 API 传 treeCount=0,不计入考核
...
预种 1 份 = 1/5 棵树,如果将 portionCount 作为 treeCount 传给
authorization-service,会导致省/市公司月度考核进度被多算 5 倍。
修正:传 treeCount=0,预种阶段不累计考核棵数。
等 5 份合成 1 棵完整树后,由合成流程负责累计 1 棵的考核进度。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 20:57:27 -08:00
hailin
1c71cda2ec
fix(pre-planting): 修复省/市区域权益分配的三个 bug
...
问题:
1. 省/市区域 API 调用缺少必需的 treeCount 参数,导致 authorization-service
报错,每次都走 fallback 路径
2. fallback 路径没有对省/市代码做 padStart(6,'0') 补位,
生成了错误的账户ID(如 944 而非 9440000,84401 而非 8440100)
3. API 返回格式解析错误:authorization-service 返回
{ distributions: [{accountSequence, ...}] },但预种客户端错误地期望
{ accountSequence: string },导致取到 undefined
修复:
- getProvinceAreaDistribution / getCityAreaDistribution 新增 portionCount 参数
- 正确解析 distributions 数组,优先取非系统账户(省/市公司)
- fallback 中使用 padStart(6,'0') 确保 7 位标准账户 ID 格式
- resolveAllocations 调用时传入 portionCount
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 20:53:12 -08:00
hailin
bf50810830
feat(wallet+admin-web): 系统账户流水增加来源用户账户和来源备注列
...
问题:系统账户(S0000000001等)、省/市区域/团队账户的流水明细
只显示 allocationType 英文标识,无法追溯是哪个用户的认种产生的。
解决方案:从 wallet_ledger_entries.payload_json.metadata 中提取
sourceAccountSequence 和 memo 字段,通过 API 返回给前端展示。
后端 wallet-service 改动:
- LedgerEntryDTO 新增 sourceAccountSequence / sourceMemo 两个可选字段
- 新增 extractPayloadInfo() 辅助函数统一从 payloadJson 提取信息
- 替换所有 5 处 LedgerEntryDTO 映射,使用 extractPayloadInfo()
- 向后兼容:旧记录无 metadata 时返回 null,不影响已有功能
前端 admin-web 改动:
- LedgerEntryDTO 类型新增 sourceAccountSequence / sourceMemo 字段
- 固定账户明细表格和分类账明细表格增加"来源账户"和"来源备注"列
- 新增 .sourceAccount 样式(等宽字体显示账户序列号)
数据来源说明:
- 正常认种:reward-service 传入 metadata 含完整中文 memo 和 sourceAccountSequence
- 预种:planting-service 传入 metadata 含 sourceAccountSequence 和中文 memo
- 历史记录(2026-01-04前):metadata 可能为空,显示为"-"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 20:22:40 -08:00
hailin
90fad63fed
fix(wallet): 优化流水memo避免正常认种来源信息重复
...
正常认种的 reward-service memo 已含"来自用户Dxxx的认种",
增加 hasSourceInfo 检查,包含"来自"时不再重复拼接来源账户。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 20:10:09 -08:00
hailin
299c82fc4f
fix(wallet): 流水备注增加来源用户AccountSequence和订单号
...
所有分配类型(系统账户/区域账户/用户钱包/社区权益)的流水 memo
从原来的纯英文标识改为:中文描述 | 来源: 账户序列号 (订单号)
例: [预种] 预种成本费 | 来源: D26022600000 (PPLMM6670DO9VETGK)
修改方法:
- 新增 buildAllocationMemo() 统一从 metadata 中提取 memo/sourceAccountSequence
- 替换 allocateToSystemAccount/allocateToUserWallet/allocateCommunityRight/allocateToRegionAccount 中的 memo 生成
- 兼容无 metadata 的历史调用(回退到 allocationType 英文标识)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 20:08:52 -08:00
hailin
19fca05a81
fix(pre-planting): 预种权益分配metadata与正常认种对齐 + 删除retry-rewards
...
1. executeAllocations() metadata 修复:
- 原:仅传 { source: 'PRE_PLANTING' },wallet流水缺失所有业务信息
- 现:传完整 metadata(rightType, sourceOrderNo, sourceAccountSequence,
treeCount, provinceCode, cityCode, memo),与正常认种 reward-service 一致
- wallet-service 的 prePlantingPrefix() 通过 metadata.source 添加[预种]前缀
2. SHARE_RIGHT PENDING 机制说明(无代码变更):
- 预种侧只确定收款人,全部标记 SETTLED 发给 wallet-service
- wallet-service.allocateToUserWallet() 内部根据收款方 hasPlanted 判断:
已种→SETTLEABLE / 未种→PENDING(24h过期归总部)
- 与正常认种走同一套 wallet-service 代码
3. 删除无用的 retry-rewards 端点及其 WalletServiceClient 依赖
不涉及历史数据修改,不影响正常认种流程。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 19:27:16 -08:00
hailin
d9c238702e
feat(pre-planting): 预种权益流水备注添加[预种]前缀
...
wallet-service 新增 prePlantingPrefix 私有方法,
当 FundAllocationItem.metadata.source === 'PRE_PLANTING' 时,
在流水 memo 中添加 "[预种] " 前缀,使用户可区分预种与普通认种权益。
仅影响 pre-planting 新增的分配流水,不修改任何普通认种 memo。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 12:34:01 -08:00
hailin
1d0e4352df
fix(pre-planting): 修复预种权益资金分配字段名错误(allocationType 丢失)
...
原 executeAllocations 使用了错误的 FundAllocationItem 字段名:
- targetAccountId → 应为 targetId
- 缺少 allocationType 字段
- targetType 错误地使用了 rightType 值而非 'USER'|'SYSTEM'
导致所有预种订单的 SHARE_RIGHT/COMMUNITY_RIGHT 等权益分配静默失败,
资金未能分配到推荐人/社区/省市账户,同时流水明细中也不显示预种记录。
修复内容:
1. WalletServiceClient 新增 allocatePrePlantingFunds 方法(使用正确格式)
2. executeAllocations 改用新方法,正确设置 targetType/targetId/allocationType
3. InternalPrePlantingController 新增 POST /admin/retry-rewards 历史数据修复端点
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 12:29:03 -08:00
hailin
724fb08be4
fix(contribution): 发布过期份额同步事件 + 管理后台/挖矿app状态显示
...
- contribution-service: swapContributionForMerge 作废旧份额记录后,
立即发布 ContributionRecordSynced outbox 事件(isExpired=true),
mining-admin-service 收到后 upsert syncedContributionRecord
- mining-admin-web: 算力记录状态列改为绿色"有效"/红色"无效"
- mining-app: 贡献值记录卡片始终显示有效/无效状态标签
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 11:35:55 -08:00
hailin
1431c89684
fix(pre-planting): Decimal -> Number in totalAmount reduce
2026-02-28 11:01:37 -08:00
hailin
cd73b2dec4
fix(pre-planting): 签署合同前检查实名认证 + 修正合同金额
...
- getMergeContractPdf: KYC 为 null 时返回 400,不允许查看合同
- getMergeContractPdf: 从源订单汇总实际绿积分金额,CNY = 绿积分 × 1.1
- Flutter: KYC 错误时显示专用提示 + "去完成实名认证" 按钮
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 10:59:26 -08:00
hailin
b1e5e6b29f
feat(pre-planting): 合并合同走完整签署流程(PDF展示+手写签名)
...
- planting-service: 新增 GET /merges/:mergeNo/contract-pdf 接口,复用现有 PDF 模板
- planting-service: PrePlantingApplicationService 注入 PdfGeneratorService/IdentityServiceClient
- pre_planting_service.dart: 新增 downloadMergeContractPdf,signMergeContract 简化返回值
- 新建 PrePlantingMergeSigningPage:PDF展示→滚动到底→确认法律效力→手写签名→提交
- pending_contracts_page: 合并卡片点击跳签名页(prePlantingMergeSigning)
- pre_planting_merge_detail_page: 签署按钮跳签名页,移除直接调用逻辑
- 新增路由 /pre-planting/merge-signing/:mergeNo
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 10:35:22 -08:00
hailin
b17bf82443
feat(pre-planting): 新增 GET /merges/:mergeNo 合并详情接口
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 10:07:53 -08:00
hailin
26dcd1d2de
fix(pre-planting): 修复购买省市名称存储及多项购买失败问题
...
== 问题修复 ==
1. 购买失败:NestJS 返回数组 message 导致 Flutter 类型转换错误
- 症状:List<dynamic> is not a subtype of String
- 原因:ValidationPipe 校验失败时 message 字段为 List<String>(每条字段错误一条),
Flutter _handleDioError 直接用 data['message'] 作为 String 参数导致运行时崩溃
- 修复:api_client.dart 中对 rawMsg 判断是否 List,若是则 join(', ')
2. 续购省市为空导致 400 校验失败
- 症状:续购时后端返回 "provinceCode should not be empty"
- 原因:购买页面续购分支未传入省市,导致 provinceCode/cityCode 为 null
- 修复:pre_planting_purchase_page.dart 中续购时使用 _position?.provinceCode
3. 购买请求携带 provinceName/cityName 被后端 forbidNonWhitelisted 拒绝
- 症状:400 "property provinceName should not exist"
- 原因:前端发送名称字段,但 PurchasePrePlantingDto 未声明这些字段
- 修复:在 DTO 中添加 @IsOptional() 的 provinceName / cityName 字段
== 功能新增 ==
4. 预种持仓表新增省市名称存储(参照正式认种的处理方式)
- 迁移:20260228000000_add_province_city_name_to_position
- Prisma schema:PrePlantingPosition 新增 provinceName / cityName 可空字段
- 聚合根:addPortions() 接受可选 provinceName/cityName,首购时写入,续购忽略
- Repository:save/toDomain 同步处理名称字段
- Application Service:purchasePortion 透传名称,getPosition 返回名称
- Controller:purchase 端点透传 dto.provinceName / dto.cityName
5. 预种合并时算力精确回滚(contribution-service)
- 新增 9a-team 步骤:事务内查询即将作废的 TEAM_LEVEL/TEAM_BONUS 算力记录
- 新增 9c-team 步骤:按账户聚合后精确 decrement 上游推荐人的各档位 pending 和 effective
- 目的:确保旧份额算力精确回滚,避免新树算力 9d 叠加后造成双倍计入
== UI 优化 ==
- 购买页面将 "USDT" 改为 "绿积分"(单价、总价、成功提示)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 08:02:14 -08:00
hailin
20b8d41212
feat(pre-planting): 支持省市名称存储,参照正常认种处理方式
...
- PurchasePrePlantingDto 添加可选字段 provinceName/cityName,
与 SelectProvinceCityDto 保持一致,解决 NestJS forbidNonWhitelisted 400 错误
- pre_planting_positions 表新增 province_name/city_name 列(迁移)
- PrePlantingPosition aggregate 增加 provinceName/cityName 字段
- addPortions() 接受并存储省市名称
- getPosition() 返回 provinceName/cityName 供续购时显示
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 07:48:47 -08:00
hailin
5aa17b05c5
fix(pre-planting): 代码审查修复 2 处小问题
...
1. handler: 删除冗余三元表达式(两边相同),改用 new Date(raw) 直接解析
2. service: swapContributionForMerge 增加源订单数量不足时的 warn 日志(不阻断执行)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 07:28:30 -08:00
hailin
4c6fd424b5
feat(pre-planting): 合成树后算力切换(预种 5 份合同签署触发)
...
当用户购买满5份预种后合成1棵树并签署合同时,自动执行算力切换:
1. 作废5份份额的算力记录(is_expired=true,remark 标注合成原因,已挖积分不受影响)
2. 从认种人账户扣减旧个人算力(保持账户余额准确)
3. 以1棵完整树的算力单价创建新算力记录(remark 标注来源订单)
4. 写入 pre_planting_synced_merges 幂等标记
== 实现方式 ==
- 触发节点:Debezium CDC on pre_planting_merges.mining_enabled_at(null → 非null)
- 新增 Debezium table:public.pre_planting_merges
- 新增 Kafka topic 订阅:cdc.pre-planting.public.pre_planting_merges
- 新增 handler:PrePlantingMergeSyncedHandler(解析 CDC 事件)
- 新增 service 方法:swapContributionForMerge(核心算力切换逻辑)
- 新增常量:PRE_PLANTING_MERGE_SOURCE_ID_OFFSET = 20B(区别于份额的 10B 偏移)
- 新增 DB 表:pre_planting_synced_merges(幂等标记,migration 已包含)
== 幂等保证 ==
- CDC 层:processedCdcEvent 表(sourceTopic + offset 唯一)
- 业务层:contribution_records WHERE sourceAdoptionId=20B+mergeId 存在性检查
- 标记层:pre_planting_synced_merges(best-effort,事务提交后写入)
== 对现有系统的影响 ==
- 零修改现有 contribution 调度器 / freeze scheduler
- 团队分润账户净效果≈0(旧5份=1棵树,切换后金额一致)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 07:22:09 -08:00