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>
This commit is contained in:
parent
28cf0b7769
commit
b3984c861c
|
|
@ -18,10 +18,10 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
* 参考:认种正式购买 SelectProvinceCityDto 的同名字段处理方式。
|
* 参考:认种正式购买 SelectProvinceCityDto 的同名字段处理方式。
|
||||||
*/
|
*/
|
||||||
export class PurchasePrePlantingDto {
|
export class PurchasePrePlantingDto {
|
||||||
@ApiProperty({ description: '购买份数', example: 1, minimum: 1, maximum: 5 })
|
@ApiProperty({ description: '购买份数', example: 1, minimum: 1, maximum: 10 })
|
||||||
@IsInt()
|
@IsInt()
|
||||||
@Min(1)
|
@Min(1)
|
||||||
@Max(5)
|
@Max(10)
|
||||||
portionCount: number;
|
portionCount: number;
|
||||||
|
|
||||||
@ApiProperty({ description: '省代码(行政区划代码前两位)', example: '44' })
|
@ApiProperty({ description: '省代码(行政区划代码前两位)', example: '44' })
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,8 @@ export class PrePlantingApplicationService {
|
||||||
|
|
||||||
// 获取当前定价配置(含总部运营成本压力涨价)
|
// 获取当前定价配置(含总部运营成本压力涨价)
|
||||||
const pricingConfig = await this.treePricingClient.getTreePricingConfig();
|
const pricingConfig = await this.treePricingClient.getTreePricingConfig();
|
||||||
// 预种每份加价 = Math.floor(每棵树加价 / 5),涨价部分全额归总部 (S0000000001)
|
// 预种每份加价 = Math.floor(每棵树加价 / 份数),涨价部分全额归总部 (S0000000001)
|
||||||
const portionSupplement = Math.floor(pricingConfig.currentSupplement / 5);
|
const portionSupplement = Math.floor(pricingConfig.currentSupplement / PRE_PLANTING_PORTIONS_PER_TREE);
|
||||||
|
|
||||||
const orderNo = this.generateOrderNo();
|
const orderNo = this.generateOrderNo();
|
||||||
const totalAmount = portionCount * (PRE_PLANTING_PRICE_PER_PORTION + portionSupplement);
|
const totalAmount = portionCount * (PRE_PLANTING_PRICE_PER_PORTION + portionSupplement);
|
||||||
|
|
@ -564,7 +564,7 @@ export class PrePlantingApplicationService {
|
||||||
throw new BadRequestException('预种功能已关闭,您当前份额已满,无法继续购买');
|
throw new BadRequestException('预种功能已关闭,您当前份额已满,无法继续购买');
|
||||||
}
|
}
|
||||||
if (portionCount > maxAdditional) {
|
if (portionCount > maxAdditional) {
|
||||||
throw new BadRequestException(`当前只可再购买 ${maxAdditional} 份以凑满5份`);
|
throw new BadRequestException(`当前只可再购买 ${maxAdditional} 份以凑满 ${PRE_PLANTING_PORTIONS_PER_TREE} 份`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -574,7 +574,7 @@ export class PrePlantingApplicationService {
|
||||||
accountSequence: string,
|
accountSequence: string,
|
||||||
position: import('../../domain/aggregates/pre-planting-position.aggregate').PrePlantingPosition,
|
position: import('../../domain/aggregates/pre-planting-position.aggregate').PrePlantingPosition,
|
||||||
) {
|
) {
|
||||||
// 获取 5 笔待合并的已支付订单
|
// 获取待合并的已支付订单(数量由 PRE_PLANTING_PORTIONS_PER_TREE 决定)
|
||||||
const paidOrders = await this.orderRepo.findPaidOrdersByUserId(
|
const paidOrders = await this.orderRepo.findPaidOrdersByUserId(
|
||||||
tx,
|
tx,
|
||||||
userId,
|
userId,
|
||||||
|
|
@ -582,7 +582,7 @@ export class PrePlantingApplicationService {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (paidOrders.length < PRE_PLANTING_PORTIONS_PER_TREE) {
|
if (paidOrders.length < PRE_PLANTING_PORTIONS_PER_TREE) {
|
||||||
throw new Error('不足 5 笔已支付订单进行合并');
|
throw new Error(`不足 ${PRE_PLANTING_PORTIONS_PER_TREE} 笔已支付订单进行合并`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sourceOrders = paidOrders.slice(0, PRE_PLANTING_PORTIONS_PER_TREE);
|
const sourceOrders = paidOrders.slice(0, PRE_PLANTING_PORTIONS_PER_TREE);
|
||||||
|
|
@ -605,7 +605,7 @@ export class PrePlantingApplicationService {
|
||||||
);
|
);
|
||||||
await this.mergeRepo.save(tx, merge);
|
await this.mergeRepo.save(tx, merge);
|
||||||
|
|
||||||
// 标记 5 笔订单为已合并
|
// 标记源订单为已合并
|
||||||
for (const order of sourceOrders) {
|
for (const order of sourceOrders) {
|
||||||
order.markAsMerged(merge.id!);
|
order.markAsMerged(merge.id!);
|
||||||
await this.orderRepo.save(tx, order);
|
await this.orderRepo.save(tx, order);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { PrePlantingContractStatus } from '../value-objects/pre-planting-contract-status.enum';
|
import { PrePlantingContractStatus } from '../value-objects/pre-planting-contract-status.enum';
|
||||||
|
import { PRE_PLANTING_PORTIONS_PER_TREE } from '../value-objects/pre-planting-right-amounts';
|
||||||
import { DomainEvent } from '../../../domain/events/domain-event.interface';
|
import { DomainEvent } from '../../../domain/events/domain-event.interface';
|
||||||
import { PrePlantingMergedEvent } from '../events/pre-planting-merged.event';
|
import { PrePlantingMergedEvent } from '../events/pre-planting-merged.event';
|
||||||
import { PrePlantingContractSignedEvent } from '../events/pre-planting-contract-signed.event';
|
import { PrePlantingContractSignedEvent } from '../events/pre-planting-contract-signed.event';
|
||||||
|
|
@ -69,8 +70,8 @@ export class PrePlantingMerge {
|
||||||
cityCode: string,
|
cityCode: string,
|
||||||
totalTreesMergedAfter: number,
|
totalTreesMergedAfter: number,
|
||||||
): PrePlantingMerge {
|
): PrePlantingMerge {
|
||||||
if (sourceOrderNos.length !== 5) {
|
if (sourceOrderNos.length !== PRE_PLANTING_PORTIONS_PER_TREE) {
|
||||||
throw new Error(`合并需要 5 个订单,收到 ${sourceOrderNos.length} 个`);
|
throw new Error(`合并需要 ${PRE_PLANTING_PORTIONS_PER_TREE} 个订单,收到 ${sourceOrderNos.length} 个`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const merge = new PrePlantingMerge(
|
const merge = new PrePlantingMerge(
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ export class PrePlantingPosition {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行合并(消耗 5 份)
|
* 执行合并(消耗 PRE_PLANTING_PORTIONS_PER_TREE 份)
|
||||||
*/
|
*/
|
||||||
performMerge(): void {
|
performMerge(): void {
|
||||||
if (!this.canMerge()) {
|
if (!this.canMerge()) {
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,53 @@
|
||||||
/**
|
/**
|
||||||
* 预种 1/5 分配金额常量
|
* 预种 1/10 分配金额常量
|
||||||
*
|
*
|
||||||
* 基准:reward-service 的 RIGHT_AMOUNTS(15831 整棵树)
|
* === 变更历史 ===
|
||||||
* 9 项 = floor(整棵树金额 / 5) 取整,余额全归总部社区(HQ_BASE_FEE)
|
* [2026-03-01] 调整预种方案:
|
||||||
|
* - 全树基础价 15831 → 18870 USDT
|
||||||
|
* - 每树份数 5 份 → 10 份
|
||||||
|
* - 每份价格 3566 → 1887 USDT
|
||||||
|
*
|
||||||
|
* === 计算规则 ===
|
||||||
|
* 基准:reward-service 的 RIGHT_AMOUNTS(整棵树的 10 类权益金额)
|
||||||
|
* 9 项 = floor(整棵树金额 / 10) 取整,余额全归总部社区(HEADQUARTERS_BASE_FEE)
|
||||||
|
*
|
||||||
|
* === 整棵树权益金额 & 每份拆分 ===
|
||||||
|
* 权益类型 整棵树金额 floor(/10) 10份合计 余数(归HQ)
|
||||||
|
* COST_FEE 2880 288 2880 0
|
||||||
|
* OPERATION_FEE 2100 210 2100 0
|
||||||
|
* RWAD_POOL_INJECTION 5760 576 5760 0
|
||||||
|
* SHARE_RIGHT 3600 360 3600 0
|
||||||
|
* PROVINCE_AREA_RIGHT 108 10 100 8
|
||||||
|
* PROVINCE_TEAM_RIGHT 144 14 140 4
|
||||||
|
* CITY_AREA_RIGHT 252 25 250 2
|
||||||
|
* CITY_TEAM_RIGHT 288 28 280 8
|
||||||
|
* COMMUNITY_RIGHT 576 57 570 6
|
||||||
|
* ─────────────────────────────────────────────────────────────
|
||||||
|
* 小计(9项) 15708 1568 15680 28
|
||||||
|
* HQ_BASE_FEE = 1887 - 1568 = 319(吸收全部整除余数 28)
|
||||||
|
* ─────────────────────────────────────────────────────────────
|
||||||
|
* 合计每份 18870/10 1887 18870 0
|
||||||
*/
|
*/
|
||||||
export const PRE_PLANTING_RIGHT_AMOUNTS = {
|
export const PRE_PLANTING_RIGHT_AMOUNTS = {
|
||||||
COST_FEE: 576, // floor(2880/5)
|
COST_FEE: 288, // floor(2880/10)
|
||||||
OPERATION_FEE: 420, // floor(2100/5)
|
OPERATION_FEE: 210, // floor(2100/10)
|
||||||
HEADQUARTERS_BASE_FEE: 427, // 3566 - 3139 = 427(吸收全部余额)
|
HEADQUARTERS_BASE_FEE: 319, // 1887 - 1568 = 319(吸收全部余额)
|
||||||
RWAD_POOL_INJECTION: 1152, // floor(5760/5)
|
RWAD_POOL_INJECTION: 576, // floor(5760/10)
|
||||||
SHARE_RIGHT: 720, // floor(3600/5)
|
SHARE_RIGHT: 360, // floor(3600/10)
|
||||||
PROVINCE_AREA_RIGHT: 21, // floor(108/5)
|
PROVINCE_AREA_RIGHT: 10, // floor(108/10)
|
||||||
PROVINCE_TEAM_RIGHT: 28, // floor(144/5)
|
PROVINCE_TEAM_RIGHT: 14, // floor(144/10)
|
||||||
CITY_AREA_RIGHT: 50, // floor(252/5)
|
CITY_AREA_RIGHT: 25, // floor(252/10)
|
||||||
CITY_TEAM_RIGHT: 57, // floor(288/5)
|
CITY_TEAM_RIGHT: 28, // floor(288/10)
|
||||||
COMMUNITY_RIGHT: 115, // floor(576/5)
|
COMMUNITY_RIGHT: 57, // floor(576/10)
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// 合计 = 576 + 420 + 427 + 1152 + 720 + 21 + 28 + 50 + 57 + 115 = 3566
|
// 合计 = 288 + 210 + 319 + 576 + 360 + 10 + 14 + 25 + 28 + 57 = 1887
|
||||||
|
|
||||||
export const PRE_PLANTING_PRICE_PER_PORTION = 3566;
|
/** 每份价格(USDT),全树 18870 / 10 = 1887 */
|
||||||
export const PRE_PLANTING_PORTIONS_PER_TREE = 5;
|
export const PRE_PLANTING_PRICE_PER_PORTION = 1887;
|
||||||
|
|
||||||
|
/** 合并阈值:购满此数量自动合并为 1 棵树 */
|
||||||
|
export const PRE_PLANTING_PORTIONS_PER_TREE = 10;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 预种分配权益类型
|
* 预种分配权益类型
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,11 @@ import { PrePlantingReferralClient } from './infrastructure/external/pre-plantin
|
||||||
import { PrePlantingAuthorizationClient } from './infrastructure/external/pre-planting-authorization.client';
|
import { PrePlantingAuthorizationClient } from './infrastructure/external/pre-planting-authorization.client';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 预种计划模块 (3566 预种计划 / 拼种团购计划)
|
* 预种计划模块 (预种计划 / 拼种团购计划)
|
||||||
*
|
*
|
||||||
* === 功能概述 ===
|
* === 功能概述 ===
|
||||||
* 用户以 3566 USDT/份 参与认种(1棵树的1/5价格),累计5份自动合成1棵树,
|
* [2026-03-01] 方案调整:1887 USDT/份 × 10 份 = 18870 USDT/棵(原 3566 × 5 = 17830)
|
||||||
|
* 用户以 1887 USDT/份 参与认种(1棵树的1/10价格),累计10份自动合成1棵树,
|
||||||
* 触发合同签署和挖矿开启,同时解除交易和提现限制。
|
* 触发合同签署和挖矿开启,同时解除交易和提现限制。
|
||||||
*
|
*
|
||||||
* === 架构设计 ===
|
* === 架构设计 ===
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ class ApiEndpoints {
|
||||||
static const String pendingActionsComplete = '/user/pending-actions'; // POST /:id/complete
|
static const String pendingActionsComplete = '/user/pending-actions'; // POST /:id/complete
|
||||||
|
|
||||||
// [2026-02-17] 预种计划 (-> Planting Service / PrePlantingModule)
|
// [2026-02-17] 预种计划 (-> Planting Service / PrePlantingModule)
|
||||||
// 3566 USDT/份预种,累计 5 份自动合成 1 棵树
|
// 1887 USDT/份预种,累计 10 份自动合成 1 棵树
|
||||||
// 所有端点与现有 /planting/* 完全独立
|
// 所有端点与现有 /planting/* 完全独立
|
||||||
static const String prePlanting = '/pre-planting';
|
static const String prePlanting = '/pre-planting';
|
||||||
static const String prePlantingConfig = '$prePlanting/config'; // 开关配置
|
static const String prePlantingConfig = '$prePlanting/config'; // 开关配置
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import '../services/authorization_service.dart';
|
||||||
import '../services/deposit_service.dart';
|
import '../services/deposit_service.dart';
|
||||||
import '../services/wallet_service.dart';
|
import '../services/wallet_service.dart';
|
||||||
import '../services/planting_service.dart';
|
import '../services/planting_service.dart';
|
||||||
// [2026-02-17] 新增:预种计划服务(3566 USDT/份,独立于现有认种)
|
// [2026-02-17] 新增:预种计划服务(1887 USDT/份,独立于现有认种)
|
||||||
import '../services/pre_planting_service.dart';
|
import '../services/pre_planting_service.dart';
|
||||||
// [2026-02-19] 纯新增:树转让服务(已认种树所有权转让)
|
// [2026-02-19] 纯新增:树转让服务(已认种树所有权转让)
|
||||||
import '../services/transfer_service.dart';
|
import '../services/transfer_service.dart';
|
||||||
|
|
@ -102,7 +102,7 @@ final plantingServiceProvider = Provider<PlantingService>((ref) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// [2026-02-17] Pre-Planting Service Provider (调用 planting-service / PrePlantingModule)
|
// [2026-02-17] Pre-Planting Service Provider (调用 planting-service / PrePlantingModule)
|
||||||
// 预种计划:3566 USDT/份,累计 5 份合成 1 棵树。与上方 PlantingService 完全独立。
|
// 预种计划:1887 USDT/份,累计 10 份合成 1 棵树。与上方 PlantingService 完全独立。
|
||||||
final prePlantingServiceProvider = Provider<PrePlantingService>((ref) {
|
final prePlantingServiceProvider = Provider<PrePlantingService>((ref) {
|
||||||
final apiClient = ref.watch(apiClientProvider);
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
return PrePlantingService(apiClient: apiClient);
|
return PrePlantingService(apiClient: apiClient);
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@ import '../network/api_client.dart';
|
||||||
// [2026-02-17] 预种计划 API 服务
|
// [2026-02-17] 预种计划 API 服务
|
||||||
// ============================================
|
// ============================================
|
||||||
//
|
//
|
||||||
// 3566 预种计划(拼种/团购计划)的 Flutter 端 API 调用服务。
|
// 预种计划(拼种/团购计划)的 Flutter 端 API 调用服务。
|
||||||
// 用户以 3566 USDT/份参与认种,累计 5 份自动合成 1 棵树。
|
// [2026-03-01] 方案调整:1887 USDT/份 × 10 份 = 18870 USDT/棵
|
||||||
|
// 用户以 1887 USDT/份参与认种,累计 10 份自动合成 1 棵树。
|
||||||
//
|
//
|
||||||
// === API 端点 ===
|
// === API 端点 ===
|
||||||
// 所有端点走 planting-service 的 PrePlantingModule:
|
// 所有端点走 planting-service 的 PrePlantingModule:
|
||||||
|
|
@ -22,8 +23,8 @@ import '../network/api_client.dart';
|
||||||
// - POST /pre-planting/sign-contract 签署合并合同
|
// - POST /pre-planting/sign-contract 签署合并合同
|
||||||
//
|
//
|
||||||
// === 与现有 PlantingService 的关系 ===
|
// === 与现有 PlantingService 的关系 ===
|
||||||
// 完全独立。PlantingService 处理整棵树认种(15831 USDT/棵),
|
// 完全独立。PlantingService 处理整棵树认种(18870 USDT/棵),
|
||||||
// PrePlantingService 处理预种份额(3566 USDT/份)。
|
// PrePlantingService 处理预种份额(1887 USDT/份)。
|
||||||
// 两者调用不同的 API 端点,互不影响。
|
// 两者调用不同的 API 端点,互不影响。
|
||||||
|
|
||||||
/// 预种订单状态
|
/// 预种订单状态
|
||||||
|
|
@ -117,7 +118,7 @@ class PrePlantingPosition {
|
||||||
class PrePlantingOrder {
|
class PrePlantingOrder {
|
||||||
final String orderNo;
|
final String orderNo;
|
||||||
final int portionCount; // 购买份数(通常为 1)
|
final int portionCount; // 购买份数(通常为 1)
|
||||||
final double pricePerPortion; // 每份价格(3566 USDT)
|
final double pricePerPortion; // 每份价格(1887 USDT)
|
||||||
final double totalAmount; // 总金额
|
final double totalAmount; // 总金额
|
||||||
final PrePlantingOrderStatus status;
|
final PrePlantingOrderStatus status;
|
||||||
final String? mergedToMergeId; // 合并后指向的 MergeId
|
final String? mergedToMergeId; // 合并后指向的 MergeId
|
||||||
|
|
@ -141,8 +142,8 @@ class PrePlantingOrder {
|
||||||
return PrePlantingOrder(
|
return PrePlantingOrder(
|
||||||
orderNo: json['orderNo'] ?? '',
|
orderNo: json['orderNo'] ?? '',
|
||||||
portionCount: json['portionCount'] ?? 1,
|
portionCount: json['portionCount'] ?? 1,
|
||||||
pricePerPortion: (json['pricePerPortion'] ?? 3566).toDouble(),
|
pricePerPortion: (json['pricePerPortion'] ?? 1887).toDouble(),
|
||||||
totalAmount: (json['totalAmount'] ?? 3566).toDouble(),
|
totalAmount: (json['totalAmount'] ?? 1887).toDouble(),
|
||||||
status: _parseStatus(json['status']),
|
status: _parseStatus(json['status']),
|
||||||
mergedToMergeId: json['mergedToMergeId']?.toString(),
|
mergedToMergeId: json['mergedToMergeId']?.toString(),
|
||||||
paidAt: json['paidAt'] != null ? DateTime.parse(json['paidAt']) : null,
|
paidAt: json['paidAt'] != null ? DateTime.parse(json['paidAt']) : null,
|
||||||
|
|
@ -248,8 +249,8 @@ class CreatePrePlantingOrderResponse {
|
||||||
return CreatePrePlantingOrderResponse(
|
return CreatePrePlantingOrderResponse(
|
||||||
orderNo: json['orderNo'] ?? '',
|
orderNo: json['orderNo'] ?? '',
|
||||||
portionCount: json['portionCount'] ?? 1,
|
portionCount: json['portionCount'] ?? 1,
|
||||||
totalAmount: (json['totalAmount'] ?? 3566).toDouble(),
|
totalAmount: (json['totalAmount'] ?? 1887).toDouble(),
|
||||||
pricePerPortion: (json['pricePerPortion'] ?? 3566).toDouble(),
|
pricePerPortion: (json['pricePerPortion'] ?? 1887).toDouble(),
|
||||||
merged: json['merged'] == true,
|
merged: json['merged'] == true,
|
||||||
mergeNo: json['mergeNo']?.toString(),
|
mergeNo: json['mergeNo']?.toString(),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ import '../network/api_client.dart';
|
||||||
///
|
///
|
||||||
/// 总部运营成本压力涨价:基础价不变,加价部分全额归总部。
|
/// 总部运营成本压力涨价:基础价不变,加价部分全额归总部。
|
||||||
/// - 正式认种总价 = basePrice + currentSupplement
|
/// - 正式认种总价 = basePrice + currentSupplement
|
||||||
/// - 预种总价 = totalPrice / 5(取整)
|
/// - 预种总价 = totalPrice / 10(取整)
|
||||||
class TreePricingConfig {
|
class TreePricingConfig {
|
||||||
/// 正式认种基础价(固定 15831)
|
/// 正式认种基础价(固定 18870)
|
||||||
final int basePrice;
|
final int basePrice;
|
||||||
|
|
||||||
/// 预种基础价(固定 3566)
|
/// 预种基础价(固定 1887)
|
||||||
final int basePortionPrice;
|
final int basePortionPrice;
|
||||||
|
|
||||||
/// 当前加价金额
|
/// 当前加价金额
|
||||||
|
|
@ -48,11 +48,11 @@ class TreePricingConfig {
|
||||||
|
|
||||||
factory TreePricingConfig.fromJson(Map<String, dynamic> json) {
|
factory TreePricingConfig.fromJson(Map<String, dynamic> json) {
|
||||||
return TreePricingConfig(
|
return TreePricingConfig(
|
||||||
basePrice: json['basePrice'] ?? 15831,
|
basePrice: json['basePrice'] ?? 18870,
|
||||||
basePortionPrice: json['basePortionPrice'] ?? 3566,
|
basePortionPrice: json['basePortionPrice'] ?? 1887,
|
||||||
currentSupplement: json['currentSupplement'] ?? 0,
|
currentSupplement: json['currentSupplement'] ?? 0,
|
||||||
totalPrice: json['totalPrice'] ?? 15831,
|
totalPrice: json['totalPrice'] ?? 18870,
|
||||||
totalPortionPrice: json['totalPortionPrice'] ?? 3566,
|
totalPortionPrice: json['totalPortionPrice'] ?? 1887,
|
||||||
autoIncreaseEnabled: json['autoIncreaseEnabled'] ?? false,
|
autoIncreaseEnabled: json['autoIncreaseEnabled'] ?? false,
|
||||||
autoIncreaseAmount: json['autoIncreaseAmount'] ?? 0,
|
autoIncreaseAmount: json['autoIncreaseAmount'] ?? 0,
|
||||||
autoIncreaseIntervalDays: json['autoIncreaseIntervalDays'] ?? 0,
|
autoIncreaseIntervalDays: json['autoIncreaseIntervalDays'] ?? 0,
|
||||||
|
|
@ -65,11 +65,11 @@ class TreePricingConfig {
|
||||||
/// 默认配置(supplement=0,与原硬编码价格一致)
|
/// 默认配置(supplement=0,与原硬编码价格一致)
|
||||||
factory TreePricingConfig.defaultConfig() {
|
factory TreePricingConfig.defaultConfig() {
|
||||||
return TreePricingConfig(
|
return TreePricingConfig(
|
||||||
basePrice: 15831,
|
basePrice: 18870,
|
||||||
basePortionPrice: 3566,
|
basePortionPrice: 1887,
|
||||||
currentSupplement: 0,
|
currentSupplement: 0,
|
||||||
totalPrice: 15831,
|
totalPrice: 18870,
|
||||||
totalPortionPrice: 3566,
|
totalPortionPrice: 1887,
|
||||||
autoIncreaseEnabled: false,
|
autoIncreaseEnabled: false,
|
||||||
autoIncreaseAmount: 0,
|
autoIncreaseAmount: 0,
|
||||||
autoIncreaseIntervalDays: 0,
|
autoIncreaseIntervalDays: 0,
|
||||||
|
|
|
||||||
|
|
@ -324,7 +324,7 @@ class _PrePlantingMergeDetailPageState
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_buildDetailRow(
|
_buildDetailRow(
|
||||||
'总价值',
|
'总价值',
|
||||||
'${(merge.sourceOrderNos.length * 3566).toString()} 绿积分',
|
'${(merge.sourceOrderNos.length * 1887).toString()} 绿积分',
|
||||||
),
|
),
|
||||||
if (merge.selectedProvince != null) ...[
|
if (merge.selectedProvince != null) ...[
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
|
@ -508,7 +508,7 @@ class _PrePlantingMergeDetailPageState
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Text(
|
const Text(
|
||||||
'3,171 绿积分',
|
'1,887 绿积分',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
color: Color(0xFF745D43),
|
color: Color(0xFF745D43),
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import '../../../../routes/route_paths.dart';
|
||||||
//
|
//
|
||||||
// 显示用户的预种计划持仓信息,包括:
|
// 显示用户的预种计划持仓信息,包括:
|
||||||
// - 持仓概览卡片:累计份数、待合并份数、已合成树数
|
// - 持仓概览卡片:累计份数、待合并份数、已合成树数
|
||||||
// - 合并进度条:当前 N/5 份的进度可视化
|
// - 合并进度条:当前 N/10 份的进度可视化
|
||||||
// - 订单列表:所有预种订单记录(按时间倒序)
|
// - 订单列表:所有预种订单记录(按时间倒序)
|
||||||
// - 合并记录列表:已完成合并的树记录(可点击查看详情/签约)
|
// - 合并记录列表:已完成合并的树记录(可点击查看详情/签约)
|
||||||
//
|
//
|
||||||
|
|
@ -40,7 +40,7 @@ class _PrePlantingPositionPageState
|
||||||
extends ConsumerState<PrePlantingPositionPage>
|
extends ConsumerState<PrePlantingPositionPage>
|
||||||
with SingleTickerProviderStateMixin {
|
with SingleTickerProviderStateMixin {
|
||||||
// === 常量 ===
|
// === 常量 ===
|
||||||
static const int _portionsPerTree = 5;
|
static const int _portionsPerTree = 10;
|
||||||
|
|
||||||
// === 状态 ===
|
// === 状态 ===
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,9 @@ import '../../../../routes/route_paths.dart';
|
||||||
// ============================================
|
// ============================================
|
||||||
//
|
//
|
||||||
// 预种计划(拼种/团购计划)的购买页面:
|
// 预种计划(拼种/团购计划)的购买页面:
|
||||||
// - 用户以 3566 USDT/份 购买预种份额
|
// [2026-03-01] 方案调整:1887 USDT/份 × 10 份 = 18870 USDT/棵
|
||||||
// - 累计 5 份自动合成 1 棵树
|
// - 用户以 1887 USDT/份 购买预种份额
|
||||||
|
// - 累计 10 份自动合成 1 棵树
|
||||||
// - 首次购买需选择省市(后续复用,不可更改)
|
// - 首次购买需选择省市(后续复用,不可更改)
|
||||||
// - 显示余额、份数选择、合并进度、价格明细
|
// - 显示余额、份数选择、合并进度、价格明细
|
||||||
//
|
//
|
||||||
|
|
@ -24,12 +25,12 @@ import '../../../../routes/route_paths.dart';
|
||||||
// 4. 购买成功:后端自动扣款、分配权益、检查合并
|
// 4. 购买成功:后端自动扣款、分配权益、检查合并
|
||||||
//
|
//
|
||||||
// === 与现有认种页面的关系 ===
|
// === 与现有认种页面的关系 ===
|
||||||
// planting_quantity_page.dart → 整棵树认种(15831 USDT/棵)
|
// planting_quantity_page.dart → 整棵树认种(18870 USDT/棵)
|
||||||
// 本页面 → 预种份额购买(3566 USDT/份),完全独立的流程
|
// 本页面 → 预种份额购买(1887 USDT/份),完全独立的流程
|
||||||
|
|
||||||
/// 预种计划购买页面
|
/// 预种计划购买页面
|
||||||
///
|
///
|
||||||
/// 用户可以购买预种份额(3566 USDT/份),累计 5 份自动合成 1 棵树。
|
/// 用户可以购买预种份额(1887 USDT/份),累计 10 份自动合成 1 棵树。
|
||||||
/// 首次购买需选择省市(后续购买自动复用)。
|
/// 首次购买需选择省市(后续购买自动复用)。
|
||||||
class PrePlantingPurchasePage extends ConsumerStatefulWidget {
|
class PrePlantingPurchasePage extends ConsumerStatefulWidget {
|
||||||
const PrePlantingPurchasePage({super.key});
|
const PrePlantingPurchasePage({super.key});
|
||||||
|
|
@ -44,10 +45,10 @@ class _PrePlantingPurchasePageState
|
||||||
// === 常量 ===
|
// === 常量 ===
|
||||||
|
|
||||||
/// 每份预种价格(USDT)- 从 admin-service 动态获取
|
/// 每份预种价格(USDT)- 从 admin-service 动态获取
|
||||||
double _pricePerPortion = 3566.0;
|
double _pricePerPortion = 1887.0;
|
||||||
|
|
||||||
/// 合并所需份数
|
/// 合并所需份数
|
||||||
static const int _portionsPerTree = 5;
|
static const int _portionsPerTree = 10;
|
||||||
|
|
||||||
/// 定价配置(用于展示下次涨价信息)
|
/// 定价配置(用于展示下次涨价信息)
|
||||||
TreePricingConfig? _pricingConfig;
|
TreePricingConfig? _pricingConfig;
|
||||||
|
|
@ -328,8 +329,8 @@ class _PrePlantingPurchasePageState
|
||||||
static const String _defaultAgreementText =
|
static const String _defaultAgreementText =
|
||||||
'预种协议\n\n'
|
'预种协议\n\n'
|
||||||
'1. 用户成功购买预种计划后,自动获得分享权。\n'
|
'1. 用户成功购买预种计划后,自动获得分享权。\n'
|
||||||
'2. 每一份预种计划,对应享有1棵猫山王榴莲树40%产果分红权的1/5份额,'
|
'2. 每一份预种计划,对应享有1棵猫山王榴莲树40%产果分红权的1/10份额,'
|
||||||
'即单份预种计划可享受该果树8%的产果分红权。';
|
'即单份预种计划可享受该果树4%的产果分红权。';
|
||||||
|
|
||||||
/// 确认购买
|
/// 确认购买
|
||||||
Future<void> _confirmPurchase() async {
|
Future<void> _confirmPurchase() async {
|
||||||
|
|
@ -870,7 +871,7 @@ class _PrePlantingPurchasePageState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 合并进度卡片(显示当前 N/5 份的进度)
|
/// 合并进度卡片(显示当前 N/10 份的进度)
|
||||||
Widget _buildMergeProgressCard() {
|
Widget _buildMergeProgressCard() {
|
||||||
final available = _position!.availablePortions;
|
final available = _position!.availablePortions;
|
||||||
final treesMerged = _position!.totalTreesMerged;
|
final treesMerged = _position!.totalTreesMerged;
|
||||||
|
|
@ -1385,7 +1386,7 @@ class _PrePlantingPurchasePageState
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
'预计涨价: ${_pricingConfig!.nextAutoIncreaseAt!.month}月${_pricingConfig!.nextAutoIncreaseAt!.day}日后每份 +${(_pricingConfig!.autoIncreaseAmount / 5).floor()} 绿积分',
|
'预计涨价: ${_pricingConfig!.nextAutoIncreaseAt!.month}月${_pricingConfig!.nextAutoIncreaseAt!.day}日后每份 +${(_pricingConfig!.autoIncreaseAmount / _portionsPerTree).floor()} 绿积分',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: 'Inter',
|
fontFamily: 'Inter',
|
||||||
|
|
|
||||||
|
|
@ -2056,7 +2056,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
|
||||||
/// [2026-02-17] 构建预种计划按钮行(购买 + 查看持仓)
|
/// [2026-02-17] 构建预种计划按钮行(购买 + 查看持仓)
|
||||||
///
|
///
|
||||||
/// 两个按钮并排显示:
|
/// 两个按钮并排显示:
|
||||||
/// - 左侧「预种购买」:跳转到预种购买页(选择份数 → 支付 3566 USDT/份)
|
/// - 左侧「预种购买」:跳转到预种购买页(选择份数 → 支付 1887 USDT/份)
|
||||||
/// - 右侧「预种持仓」:跳转到预种持仓页(查看订单、合并记录、签约)
|
/// - 右侧「预种持仓」:跳转到预种持仓页(查看订单、合并记录、签约)
|
||||||
Widget _buildPrePlantingButtons() {
|
Widget _buildPrePlantingButtons() {
|
||||||
return Row(
|
return Row(
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ import '../features/kyc/presentation/pages/change_phone_page.dart';
|
||||||
import '../features/contract_signing/presentation/pages/contract_signing_page.dart';
|
import '../features/contract_signing/presentation/pages/contract_signing_page.dart';
|
||||||
import '../features/contract_signing/presentation/pages/pending_contracts_page.dart';
|
import '../features/contract_signing/presentation/pages/pending_contracts_page.dart';
|
||||||
import '../features/pending_actions/presentation/pages/pending_actions_page.dart';
|
import '../features/pending_actions/presentation/pages/pending_actions_page.dart';
|
||||||
// [2026-02-17] 新增:预种计划页面(3566 USDT/份,累计 5 份合成 1 棵树)
|
// [2026-02-17] 新增:预种计划页面(1887 USDT/份,累计 10 份合成 1 棵树)
|
||||||
import '../features/pre_planting/presentation/pages/pre_planting_purchase_page.dart';
|
import '../features/pre_planting/presentation/pages/pre_planting_purchase_page.dart';
|
||||||
import '../features/pre_planting/presentation/pages/pre_planting_position_page.dart';
|
import '../features/pre_planting/presentation/pages/pre_planting_position_page.dart';
|
||||||
import '../features/pre_planting/presentation/pages/pre_planting_merge_detail_page.dart';
|
import '../features/pre_planting/presentation/pages/pre_planting_merge_detail_page.dart';
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue