Commit Graph

18 Commits

Author SHA1 Message Date
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 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 2ad1936126 fix(pre-planting): 合并详情页 USDT 改为绿积分
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 10:17:12 -08:00
hailin 7bad0a8935 fix(pre-planting): 修复编译错误(getMerges→getMyMerges、RoutePaths 缺失导入、Future.wait 类型)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 10:00:17 -08:00
hailin b9b23c36d7 feat(pre-planting): 合并后走正常签合同流程,购买第5份直接跳合并详情页
- pre_planting_service: CreatePrePlantingOrderResponse 增加 merged/mergeNo 字段
- pre_planting_purchase_page: 购买成功若触发合并,直接跳转合并详情签合同
- contract_check_service: 注入 PrePlantingService,checkAll 增加预种待签合并检查
- pending_contracts_page: 同时展示普通合同和预种合并待签卡片,复用现有签合同弹窗流程
- injection_container: contractCheckServiceProvider 注入 prePlantingService

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 09:51:21 -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 eea38b2b86 fix(pre-planting): 购买页面和弹窗中 USDT 改为绿积分
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 07:20:51 -08:00
hailin 9b6effe63d debug(pre-planting): 添加购买流程详细日志以排查 List cast 错误
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 07:19:35 -08:00
hailin 606d3c0b22 fix(pre-planting): 修复购买失败时 List<dynamic> 类型转换错误和续购省市缺失
1. api_client.dart: NestJS validation error 返回 message 为数组时,
   用 join(', ') 转为字符串,避免直接传给 ApiException(String) 崩溃
2. pre_planting_purchase_page.dart: 续购时传 _position 中已保存的
   provinceCode/cityCode,满足后端 DTO 必填校验

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 06:56:49 -08:00
hailin 2d7b02aa96 fix(pre-planting): 修复预种页面 5 个 UI 问题(纯前端,零后端改动)
=== 问题 1:流水明细合同按钮 500 错误 ===
文件: ledger_detail_page.dart
原因: 预种订单(PPL 前缀)无合同,但流水详情弹窗显示「查看合同/下载合同」按钮
修复: _showTransactionDetail 检测 refOrderId.startsWith('PPL'),
      预种订单传 showContractButtons: false,弹窗不渲染合同按钮区

=== 问题 2:流水备注显示英文 ===
文件: ledger_detail_page.dart
原因: 备注字段存储的是 'Plant payment (from frozen)'(后端写入,不改后端)
修复: _TransactionDetailSheet 展示备注时,若订单号以 PPL 开头则显示「预种」

=== 问题 3:预种明细订单金额单位错误 ===
文件: pre_planting_position_page.dart
修复: '${order.totalAmount.toInt()} USDT' → '${order.totalAmount.toInt()} 绿积分'

=== 问题 4:省市显示数字代码(如 44 · 4401)===
文件: pre_planting_position_page.dart / pre_planting_purchase_page.dart
原因: provinceName/cityName 为 null 时回退显示 provinceCode/cityCode
修复:
  - position 页:条件改为 provinceName != null && cityName != null,无中文名则不显示省市行
  - purchase 页:加载时不再 fallback 到代码;锁定显示无名称时显示「已锁定」;
    购买确认弹窗省市行无名称时显示「-」

=== 问题 5:「合并进度」改为「合成进度」===
文件: pre_planting_position_page.dart / pre_planting_purchase_page.dart
修复: 两处 Text('合并进度') → Text('合成进度')

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 06:25:38 -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 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 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