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>
This commit is contained in:
parent
e1cd8ed7f2
commit
27751731e8
|
|
@ -96,4 +96,14 @@ class ApiEndpoints {
|
|||
// Pending Actions (-> Identity Service)
|
||||
static const String pendingActions = '/user/pending-actions';
|
||||
static const String pendingActionsComplete = '/user/pending-actions'; // POST /:id/complete
|
||||
|
||||
// [2026-02-17] 预种计划 (-> Planting Service / PrePlantingModule)
|
||||
// 3171 USDT/份预种,累计 5 份自动合成 1 棵树
|
||||
// 所有端点与现有 /planting/* 完全独立
|
||||
static const String prePlanting = '/pre-planting';
|
||||
static const String prePlantingConfig = '$prePlanting/config'; // 开关配置
|
||||
static const String prePlantingEligibility = '$prePlanting/eligibility'; // 购买资格检查
|
||||
static const String prePlantingPosition = '$prePlanting/position'; // 持仓信息
|
||||
static const String prePlantingOrders = '$prePlanting/orders'; // 订单 CRUD
|
||||
static const String prePlantingMerges = '$prePlanting/merges'; // 合并记录
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import '../services/authorization_service.dart';
|
|||
import '../services/deposit_service.dart';
|
||||
import '../services/wallet_service.dart';
|
||||
import '../services/planting_service.dart';
|
||||
// [2026-02-17] 新增:预种计划服务(3171 USDT/份,独立于现有认种)
|
||||
import '../services/pre_planting_service.dart';
|
||||
import '../services/reward_service.dart';
|
||||
import '../services/notification_service.dart';
|
||||
import '../services/system_config_service.dart';
|
||||
|
|
@ -95,6 +97,13 @@ final plantingServiceProvider = Provider<PlantingService>((ref) {
|
|||
return PlantingService(apiClient: apiClient);
|
||||
});
|
||||
|
||||
// [2026-02-17] Pre-Planting Service Provider (调用 planting-service / PrePlantingModule)
|
||||
// 预种计划:3171 USDT/份,累计 5 份合成 1 棵树。与上方 PlantingService 完全独立。
|
||||
final prePlantingServiceProvider = Provider<PrePlantingService>((ref) {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
return PrePlantingService(apiClient: apiClient);
|
||||
});
|
||||
|
||||
// Reward Service Provider (直接调用 reward-service)
|
||||
final rewardServiceProvider = Provider<RewardService>((ref) {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,511 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import '../network/api_client.dart';
|
||||
|
||||
// ============================================
|
||||
// [2026-02-17] 预种计划 API 服务
|
||||
// ============================================
|
||||
//
|
||||
// 3171 预种计划(拼种/团购计划)的 Flutter 端 API 调用服务。
|
||||
// 用户以 3171 USDT/份参与认种,累计 5 份自动合成 1 棵树。
|
||||
//
|
||||
// === API 端点 ===
|
||||
// 所有端点走 planting-service 的 PrePlantingModule:
|
||||
// - GET /pre-planting/position 获取预种持仓
|
||||
// - GET /pre-planting/config 获取预种开关状态
|
||||
// - POST /pre-planting/orders 创建预种订单
|
||||
// - POST /pre-planting/orders/:no/pay 支付预种订单
|
||||
// - GET /pre-planting/orders 获取预种订单列表
|
||||
// - GET /pre-planting/merges 获取合并记录列表
|
||||
// - GET /pre-planting/merges/:id 获取合并详情
|
||||
// - POST /pre-planting/merges/:id/sign 签署合并合同
|
||||
//
|
||||
// === 与现有 PlantingService 的关系 ===
|
||||
// 完全独立。PlantingService 处理整棵树认种(15831 USDT/棵),
|
||||
// PrePlantingService 处理预种份额(3171 USDT/份)。
|
||||
// 两者调用不同的 API 端点,互不影响。
|
||||
|
||||
/// 预种订单状态
|
||||
enum PrePlantingOrderStatus {
|
||||
created, // 已创建(待支付)
|
||||
paid, // 已支付(算力已生效)
|
||||
merged, // 已合并(5 份合成 1 棵树)
|
||||
}
|
||||
|
||||
/// 预种合同签署状态
|
||||
enum PrePlantingContractStatus {
|
||||
pending, // 待签署
|
||||
signed, // 已签署
|
||||
expired, // 已过期
|
||||
}
|
||||
|
||||
/// 预种开关配置
|
||||
class PrePlantingConfig {
|
||||
final bool isActive; // 预种功能是否开启
|
||||
final DateTime? activatedAt; // 开启时间
|
||||
|
||||
PrePlantingConfig({
|
||||
required this.isActive,
|
||||
this.activatedAt,
|
||||
});
|
||||
|
||||
factory PrePlantingConfig.fromJson(Map<String, dynamic> json) {
|
||||
return PrePlantingConfig(
|
||||
isActive: json['isActive'] ?? false,
|
||||
activatedAt: json['activatedAt'] != null
|
||||
? DateTime.parse(json['activatedAt'])
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 预种持仓信息(每用户一条)
|
||||
class PrePlantingPosition {
|
||||
final int totalPortions; // 累计购买份数(含已合并)
|
||||
final int availablePortions; // 待合并份数(0-4)
|
||||
final int mergedPortions; // 已合并份数
|
||||
final int totalTreesMerged; // 已合成的树数
|
||||
final String? provinceCode; // 省代码(首次购买时选择,后续复用)
|
||||
final String? cityCode; // 市代码
|
||||
final String? provinceName; // 省名称
|
||||
final String? cityName; // 市名称
|
||||
final DateTime? firstPurchaseAt; // 首次购买时间(1 年冻结起点)
|
||||
|
||||
PrePlantingPosition({
|
||||
required this.totalPortions,
|
||||
required this.availablePortions,
|
||||
required this.mergedPortions,
|
||||
required this.totalTreesMerged,
|
||||
this.provinceCode,
|
||||
this.cityCode,
|
||||
this.provinceName,
|
||||
this.cityName,
|
||||
this.firstPurchaseAt,
|
||||
});
|
||||
|
||||
/// 距离下一次合并还需多少份
|
||||
int get portionsToNextMerge => availablePortions == 0 ? 5 : 5 - availablePortions;
|
||||
|
||||
/// 合并进度 (0.0 - 1.0)
|
||||
double get mergeProgress => availablePortions / 5.0;
|
||||
|
||||
/// 是否已选择省市(首次购买后即锁定)
|
||||
bool get hasProvinceCity => provinceCode != null && cityCode != null;
|
||||
|
||||
factory PrePlantingPosition.fromJson(Map<String, dynamic> json) {
|
||||
return PrePlantingPosition(
|
||||
totalPortions: json['totalPortions'] ?? 0,
|
||||
availablePortions: json['availablePortions'] ?? 0,
|
||||
mergedPortions: json['mergedPortions'] ?? 0,
|
||||
totalTreesMerged: json['totalTreesMerged'] ?? 0,
|
||||
provinceCode: json['provinceCode'],
|
||||
cityCode: json['cityCode'],
|
||||
provinceName: json['provinceName'],
|
||||
cityName: json['cityName'],
|
||||
firstPurchaseAt: json['firstPurchaseAt'] != null
|
||||
? DateTime.parse(json['firstPurchaseAt'])
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 预种订单
|
||||
class PrePlantingOrder {
|
||||
final String orderNo;
|
||||
final int portionCount; // 购买份数(通常为 1)
|
||||
final double pricePerPortion; // 每份价格(3171 USDT)
|
||||
final double totalAmount; // 总金额
|
||||
final PrePlantingOrderStatus status;
|
||||
final String? mergedToMergeId; // 合并后指向的 MergeId
|
||||
final DateTime? paidAt;
|
||||
final DateTime? mergedAt;
|
||||
final DateTime createdAt;
|
||||
|
||||
PrePlantingOrder({
|
||||
required this.orderNo,
|
||||
required this.portionCount,
|
||||
required this.pricePerPortion,
|
||||
required this.totalAmount,
|
||||
required this.status,
|
||||
this.mergedToMergeId,
|
||||
this.paidAt,
|
||||
this.mergedAt,
|
||||
required this.createdAt,
|
||||
});
|
||||
|
||||
factory PrePlantingOrder.fromJson(Map<String, dynamic> json) {
|
||||
return PrePlantingOrder(
|
||||
orderNo: json['orderNo'] ?? '',
|
||||
portionCount: json['portionCount'] ?? 1,
|
||||
pricePerPortion: (json['pricePerPortion'] ?? 3171).toDouble(),
|
||||
totalAmount: (json['totalAmount'] ?? 3171).toDouble(),
|
||||
status: _parseStatus(json['status']),
|
||||
mergedToMergeId: json['mergedToMergeId']?.toString(),
|
||||
paidAt: json['paidAt'] != null ? DateTime.parse(json['paidAt']) : null,
|
||||
mergedAt: json['mergedAt'] != null ? DateTime.parse(json['mergedAt']) : null,
|
||||
createdAt: json['createdAt'] != null
|
||||
? DateTime.parse(json['createdAt'])
|
||||
: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
static PrePlantingOrderStatus _parseStatus(String? status) {
|
||||
switch (status) {
|
||||
case 'CREATED': return PrePlantingOrderStatus.created;
|
||||
case 'PAID': return PrePlantingOrderStatus.paid;
|
||||
case 'MERGED': return PrePlantingOrderStatus.merged;
|
||||
default: return PrePlantingOrderStatus.created;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 预种合并记录(5 份 → 1 棵树)
|
||||
class PrePlantingMerge {
|
||||
final String mergeNo;
|
||||
final List<String> sourceOrderNos; // 5 笔来源订单号
|
||||
final int treeCount; // 合并产生的树数(固定 1)
|
||||
final PrePlantingContractStatus contractStatus;
|
||||
final DateTime? contractSignedAt;
|
||||
final DateTime? miningEnabledAt;
|
||||
final String? selectedProvince;
|
||||
final String? selectedCity;
|
||||
final DateTime mergedAt;
|
||||
|
||||
PrePlantingMerge({
|
||||
required this.mergeNo,
|
||||
required this.sourceOrderNos,
|
||||
required this.treeCount,
|
||||
required this.contractStatus,
|
||||
this.contractSignedAt,
|
||||
this.miningEnabledAt,
|
||||
this.selectedProvince,
|
||||
this.selectedCity,
|
||||
required this.mergedAt,
|
||||
});
|
||||
|
||||
/// 是否已签约
|
||||
bool get isSigned => contractStatus == PrePlantingContractStatus.signed;
|
||||
|
||||
/// 是否挖矿已开启
|
||||
bool get isMiningEnabled => miningEnabledAt != null;
|
||||
|
||||
factory PrePlantingMerge.fromJson(Map<String, dynamic> json) {
|
||||
return PrePlantingMerge(
|
||||
mergeNo: json['mergeNo'] ?? '',
|
||||
sourceOrderNos: (json['sourceOrderNos'] as List<dynamic>?)
|
||||
?.map((e) => e.toString())
|
||||
.toList() ??
|
||||
[],
|
||||
treeCount: json['treeCount'] ?? 1,
|
||||
contractStatus: _parseContractStatus(json['contractStatus']),
|
||||
contractSignedAt: json['contractSignedAt'] != null
|
||||
? DateTime.parse(json['contractSignedAt'])
|
||||
: null,
|
||||
miningEnabledAt: json['miningEnabledAt'] != null
|
||||
? DateTime.parse(json['miningEnabledAt'])
|
||||
: null,
|
||||
selectedProvince: json['selectedProvince'],
|
||||
selectedCity: json['selectedCity'],
|
||||
mergedAt: json['mergedAt'] != null
|
||||
? DateTime.parse(json['mergedAt'])
|
||||
: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
static PrePlantingContractStatus _parseContractStatus(String? status) {
|
||||
switch (status) {
|
||||
case 'PENDING': return PrePlantingContractStatus.pending;
|
||||
case 'SIGNED': return PrePlantingContractStatus.signed;
|
||||
case 'EXPIRED': return PrePlantingContractStatus.expired;
|
||||
default: return PrePlantingContractStatus.pending;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 创建预种订单响应
|
||||
class CreatePrePlantingOrderResponse {
|
||||
final String orderNo;
|
||||
final int portionCount;
|
||||
final double totalAmount;
|
||||
final double pricePerPortion;
|
||||
|
||||
CreatePrePlantingOrderResponse({
|
||||
required this.orderNo,
|
||||
required this.portionCount,
|
||||
required this.totalAmount,
|
||||
required this.pricePerPortion,
|
||||
});
|
||||
|
||||
factory CreatePrePlantingOrderResponse.fromJson(Map<String, dynamic> json) {
|
||||
return CreatePrePlantingOrderResponse(
|
||||
orderNo: json['orderNo'] ?? '',
|
||||
portionCount: json['portionCount'] ?? 1,
|
||||
totalAmount: (json['totalAmount'] ?? 3171).toDouble(),
|
||||
pricePerPortion: (json['pricePerPortion'] ?? 3171).toDouble(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 预种购买资格检查结果
|
||||
class PrePlantingEligibility {
|
||||
final bool canPurchase; // 是否可以购买
|
||||
final int? maxAdditional; // 最多还能买几份(开关关闭时的凑满限制)
|
||||
final String? message; // 不可购买的原因说明
|
||||
|
||||
PrePlantingEligibility({
|
||||
required this.canPurchase,
|
||||
this.maxAdditional,
|
||||
this.message,
|
||||
});
|
||||
|
||||
factory PrePlantingEligibility.fromJson(Map<String, dynamic> json) {
|
||||
return PrePlantingEligibility(
|
||||
canPurchase: json['canPurchase'] ?? false,
|
||||
maxAdditional: json['maxAdditional'],
|
||||
message: json['message'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// 预种计划 API 服务
|
||||
// ============================================
|
||||
|
||||
/// 预种计划 API 服务
|
||||
///
|
||||
/// [2026-02-17] 新增:提供预种计划的所有 API 调用
|
||||
///
|
||||
/// 所有端点走 planting-service 的 /pre-planting/* 路由,
|
||||
/// 由 PrePlantingModule 的 PrePlantingController 处理。
|
||||
/// 与现有 PlantingService 的 /planting/* 端点完全隔离。
|
||||
class PrePlantingService {
|
||||
final ApiClient _apiClient;
|
||||
|
||||
PrePlantingService({required ApiClient apiClient}) : _apiClient = apiClient;
|
||||
|
||||
// === 配置与资格 ===
|
||||
|
||||
/// 获取预种功能配置(开关状态)
|
||||
///
|
||||
/// 调用 admin-service 的预种配置 API
|
||||
Future<PrePlantingConfig> getConfig() async {
|
||||
try {
|
||||
debugPrint('[PrePlantingService] 获取预种配置');
|
||||
final response = await _apiClient.get('/pre-planting/config');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
return PrePlantingConfig.fromJson(data);
|
||||
}
|
||||
|
||||
throw Exception('获取预种配置失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PrePlantingService] 获取预种配置失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 检查购买资格
|
||||
///
|
||||
/// 开关开启时任何人可买;关闭时已有未满份额的用户可继续凑满
|
||||
Future<PrePlantingEligibility> checkEligibility() async {
|
||||
try {
|
||||
debugPrint('[PrePlantingService] 检查购买资格');
|
||||
final response = await _apiClient.get('/pre-planting/eligibility');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
return PrePlantingEligibility.fromJson(data);
|
||||
}
|
||||
|
||||
throw Exception('检查购买资格失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PrePlantingService] 检查购买资格失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// === 持仓查询 ===
|
||||
|
||||
/// 获取我的预种持仓信息
|
||||
///
|
||||
/// 返回累计份数、待合并份数、已合成树数、省市信息等
|
||||
Future<PrePlantingPosition> getMyPosition() async {
|
||||
try {
|
||||
debugPrint('[PrePlantingService] 获取预种持仓');
|
||||
final response = await _apiClient.get('/pre-planting/position');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
debugPrint(
|
||||
'[PrePlantingService] 持仓: total=${data['totalPortions']}, '
|
||||
'available=${data['availablePortions']}, '
|
||||
'merged=${data['totalTreesMerged']}',
|
||||
);
|
||||
return PrePlantingPosition.fromJson(data);
|
||||
}
|
||||
|
||||
throw Exception('获取预种持仓失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PrePlantingService] 获取预种持仓失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// === 订单操作 ===
|
||||
|
||||
/// 创建预种订单
|
||||
///
|
||||
/// [portionCount] 购买份数(通常为 1)
|
||||
/// [provinceCode] 省代码(首次购买时必填,续购自动复用)
|
||||
/// [provinceName] 省名称
|
||||
/// [cityCode] 市代码
|
||||
/// [cityName] 市名称
|
||||
///
|
||||
/// 购买流程:创建订单 → 自动扣款 → 分配权益 → 检查合并
|
||||
/// 省市信息首次购买时由用户选择,后续购买自动复用。
|
||||
Future<CreatePrePlantingOrderResponse> createOrder({
|
||||
int portionCount = 1,
|
||||
String? provinceCode,
|
||||
String? provinceName,
|
||||
String? cityCode,
|
||||
String? cityName,
|
||||
}) async {
|
||||
try {
|
||||
debugPrint('[PrePlantingService] 创建预种订单: portionCount=$portionCount');
|
||||
|
||||
final Map<String, dynamic> data = {
|
||||
'portionCount': portionCount,
|
||||
};
|
||||
// 首次购买需要提供省市信息
|
||||
if (provinceCode != null) data['provinceCode'] = provinceCode;
|
||||
if (provinceName != null) data['provinceName'] = provinceName;
|
||||
if (cityCode != null) data['cityCode'] = cityCode;
|
||||
if (cityName != null) data['cityName'] = cityName;
|
||||
|
||||
final response = await _apiClient.post(
|
||||
'/pre-planting/orders',
|
||||
data: data,
|
||||
);
|
||||
|
||||
if (response.statusCode == 201 || response.statusCode == 200) {
|
||||
final responseData = response.data as Map<String, dynamic>;
|
||||
debugPrint('[PrePlantingService] 订单创建成功: ${responseData['orderNo']}');
|
||||
return CreatePrePlantingOrderResponse.fromJson(responseData);
|
||||
}
|
||||
|
||||
throw Exception('创建预种订单失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PrePlantingService] 创建预种订单失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取我的预种订单列表
|
||||
Future<List<PrePlantingOrder>> getMyOrders({
|
||||
int page = 1,
|
||||
int pageSize = 20,
|
||||
}) async {
|
||||
try {
|
||||
debugPrint('[PrePlantingService] 获取预种订单列表');
|
||||
final response = await _apiClient.get(
|
||||
'/pre-planting/orders',
|
||||
queryParameters: {'page': page, 'pageSize': pageSize},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
List<dynamic> items;
|
||||
if (response.data is List) {
|
||||
items = response.data as List<dynamic>;
|
||||
} else if (response.data is Map<String, dynamic>) {
|
||||
items = (response.data as Map<String, dynamic>)['items'] as List<dynamic>? ?? [];
|
||||
} else {
|
||||
items = [];
|
||||
}
|
||||
return items
|
||||
.map((e) => PrePlantingOrder.fromJson(e as Map<String, dynamic>))
|
||||
.toList();
|
||||
}
|
||||
|
||||
throw Exception('获取预种订单列表失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PrePlantingService] 获取预种订单列表失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
// === 合并记录 ===
|
||||
|
||||
/// 获取我的合并记录列表(5 份 → 1 棵树)
|
||||
Future<List<PrePlantingMerge>> getMyMerges({
|
||||
int page = 1,
|
||||
int pageSize = 20,
|
||||
}) async {
|
||||
try {
|
||||
debugPrint('[PrePlantingService] 获取合并记录列表');
|
||||
final response = await _apiClient.get(
|
||||
'/pre-planting/merges',
|
||||
queryParameters: {'page': page, 'pageSize': pageSize},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
List<dynamic> items;
|
||||
if (response.data is List) {
|
||||
items = response.data as List<dynamic>;
|
||||
} else if (response.data is Map<String, dynamic>) {
|
||||
items = (response.data as Map<String, dynamic>)['items'] as List<dynamic>? ?? [];
|
||||
} else {
|
||||
items = [];
|
||||
}
|
||||
return items
|
||||
.map((e) => PrePlantingMerge.fromJson(e as Map<String, dynamic>))
|
||||
.toList();
|
||||
}
|
||||
|
||||
throw Exception('获取合并记录失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PrePlantingService] 获取合并记录失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取合并详情
|
||||
Future<PrePlantingMerge> getMergeDetail(String mergeNo) async {
|
||||
try {
|
||||
debugPrint('[PrePlantingService] 获取合并详情: mergeNo=$mergeNo');
|
||||
final response = await _apiClient.get('/pre-planting/merges/$mergeNo');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
return PrePlantingMerge.fromJson(data);
|
||||
}
|
||||
|
||||
throw Exception('获取合并详情失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PrePlantingService] 获取合并详情失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 签署合并合同
|
||||
///
|
||||
/// 5 份合并后需要签约,签约后解锁交易/提现/授权限制
|
||||
Future<PrePlantingMerge> signMergeContract(String mergeNo) async {
|
||||
try {
|
||||
debugPrint('[PrePlantingService] 签署合并合同: mergeNo=$mergeNo');
|
||||
final response = await _apiClient.post(
|
||||
'/pre-planting/merges/$mergeNo/sign',
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
debugPrint('[PrePlantingService] 合同签署成功');
|
||||
return PrePlantingMerge.fromJson(data);
|
||||
}
|
||||
|
||||
throw Exception('签署合同失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PrePlantingService] 签署合同失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue