feat(mobile): integrate PlantingService with real API
- Add PlantingService for planting order management - createOrder: Create new planting order - selectProvinceCity: Select province and city - confirmProvinceCity: Confirm province/city selection - payOrder: Pay for order - getOrder/getMyOrders: Query orders - cancelOrder: Cancel unpaid orders - Register PlantingService in DI container - Update planting_quantity_page to create order before navigation - Update planting_location_page to call real API endpoints - Fix referral-service event-ack.publisher to use KafkaService 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
ba5b6141a3
commit
dfa21c0280
|
|
@ -1,5 +1,5 @@
|
|||
import { Injectable, Logger, Inject } from '@nestjs/common';
|
||||
import { ClientKafka } from '@nestjs/microservices';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { KafkaService } from '../messaging/kafka.service';
|
||||
|
||||
/**
|
||||
* 事件确认消息结构
|
||||
|
|
@ -30,10 +30,7 @@ export class EventAckPublisher {
|
|||
private readonly logger = new Logger(EventAckPublisher.name);
|
||||
private readonly serviceName = 'referral-service';
|
||||
|
||||
constructor(
|
||||
@Inject('KAFKA_SERVICE')
|
||||
private readonly kafkaClient: ClientKafka,
|
||||
) {}
|
||||
constructor(private readonly kafkaService: KafkaService) {}
|
||||
|
||||
/**
|
||||
* 发送处理成功确认
|
||||
|
|
@ -48,9 +45,10 @@ export class EventAckPublisher {
|
|||
};
|
||||
|
||||
try {
|
||||
this.kafkaClient.emit('planting.events.ack', {
|
||||
await this.kafkaService.publish({
|
||||
topic: 'planting.events.ack',
|
||||
key: eventId,
|
||||
value: JSON.stringify(ackMessage),
|
||||
value: ackMessage,
|
||||
});
|
||||
|
||||
this.logger.log(`[ACK] ✓ Sent success confirmation for event ${eventId} (${eventType})`);
|
||||
|
|
@ -73,9 +71,10 @@ export class EventAckPublisher {
|
|||
};
|
||||
|
||||
try {
|
||||
this.kafkaClient.emit('planting.events.ack', {
|
||||
await this.kafkaService.publish({
|
||||
topic: 'planting.events.ack',
|
||||
key: eventId,
|
||||
value: JSON.stringify(ackMessage),
|
||||
value: ackMessage,
|
||||
});
|
||||
|
||||
this.logger.warn(`[ACK] ✗ Sent failure confirmation for event ${eventId}: ${errorMessage}`);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import '../services/referral_service.dart';
|
|||
import '../services/authorization_service.dart';
|
||||
import '../services/deposit_service.dart';
|
||||
import '../services/wallet_service.dart';
|
||||
import '../services/planting_service.dart';
|
||||
|
||||
// Storage Providers
|
||||
final secureStorageProvider = Provider<SecureStorage>((ref) {
|
||||
|
|
@ -58,6 +59,12 @@ final walletServiceProvider = Provider<WalletService>((ref) {
|
|||
return WalletService(apiClient: apiClient);
|
||||
});
|
||||
|
||||
// Planting Service Provider
|
||||
final plantingServiceProvider = Provider<PlantingService>((ref) {
|
||||
final apiClient = ref.watch(apiClientProvider);
|
||||
return PlantingService(apiClient: apiClient);
|
||||
});
|
||||
|
||||
// Override provider with initialized instance
|
||||
ProviderContainer createProviderContainer(LocalStorage localStorage) {
|
||||
return ProviderContainer(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,299 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import '../network/api_client.dart';
|
||||
|
||||
/// 认种订单状态
|
||||
enum PlantingOrderStatus {
|
||||
created, // 已创建
|
||||
provinceCitySelected, // 已选择省市
|
||||
provinceCityConfirmed, // 已确认省市
|
||||
paid, // 已支付
|
||||
fundAllocated, // 资金已分配
|
||||
cancelled, // 已取消
|
||||
}
|
||||
|
||||
/// 认种订单响应
|
||||
class PlantingOrder {
|
||||
final String orderNo;
|
||||
final int treeCount;
|
||||
final double totalAmount;
|
||||
final PlantingOrderStatus status;
|
||||
final String? selectedProvince;
|
||||
final String? selectedCity;
|
||||
final DateTime? provinceCitySelectedAt;
|
||||
final DateTime? provinceCityConfirmedAt;
|
||||
final DateTime? paidAt;
|
||||
final bool isMiningEnabled;
|
||||
final DateTime createdAt;
|
||||
|
||||
PlantingOrder({
|
||||
required this.orderNo,
|
||||
required this.treeCount,
|
||||
required this.totalAmount,
|
||||
required this.status,
|
||||
this.selectedProvince,
|
||||
this.selectedCity,
|
||||
this.provinceCitySelectedAt,
|
||||
this.provinceCityConfirmedAt,
|
||||
this.paidAt,
|
||||
required this.isMiningEnabled,
|
||||
required this.createdAt,
|
||||
});
|
||||
|
||||
factory PlantingOrder.fromJson(Map<String, dynamic> json) {
|
||||
return PlantingOrder(
|
||||
orderNo: json['orderNo'] ?? '',
|
||||
treeCount: json['treeCount'] ?? 0,
|
||||
totalAmount: (json['totalAmount'] ?? 0).toDouble(),
|
||||
status: _parseStatus(json['status']),
|
||||
selectedProvince: json['selectedProvince'],
|
||||
selectedCity: json['selectedCity'],
|
||||
provinceCitySelectedAt: json['provinceCitySelectedAt'] != null
|
||||
? DateTime.parse(json['provinceCitySelectedAt'])
|
||||
: null,
|
||||
provinceCityConfirmedAt: json['provinceCityConfirmedAt'] != null
|
||||
? DateTime.parse(json['provinceCityConfirmedAt'])
|
||||
: null,
|
||||
paidAt: json['paidAt'] != null ? DateTime.parse(json['paidAt']) : null,
|
||||
isMiningEnabled: json['isMiningEnabled'] ?? false,
|
||||
createdAt: json['createdAt'] != null
|
||||
? DateTime.parse(json['createdAt'])
|
||||
: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
static PlantingOrderStatus _parseStatus(String? status) {
|
||||
switch (status) {
|
||||
case 'CREATED':
|
||||
return PlantingOrderStatus.created;
|
||||
case 'PROVINCE_CITY_SELECTED':
|
||||
return PlantingOrderStatus.provinceCitySelected;
|
||||
case 'PROVINCE_CITY_CONFIRMED':
|
||||
return PlantingOrderStatus.provinceCityConfirmed;
|
||||
case 'PAID':
|
||||
return PlantingOrderStatus.paid;
|
||||
case 'FUND_ALLOCATED':
|
||||
return PlantingOrderStatus.fundAllocated;
|
||||
case 'CANCELLED':
|
||||
return PlantingOrderStatus.cancelled;
|
||||
default:
|
||||
return PlantingOrderStatus.created;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 创建订单响应
|
||||
class CreateOrderResponse {
|
||||
final String orderNo;
|
||||
final int treeCount;
|
||||
final double totalAmount;
|
||||
final double pricePerTree;
|
||||
|
||||
CreateOrderResponse({
|
||||
required this.orderNo,
|
||||
required this.treeCount,
|
||||
required this.totalAmount,
|
||||
required this.pricePerTree,
|
||||
});
|
||||
|
||||
factory CreateOrderResponse.fromJson(Map<String, dynamic> json) {
|
||||
return CreateOrderResponse(
|
||||
orderNo: json['orderNo'] ?? '',
|
||||
treeCount: json['treeCount'] ?? 0,
|
||||
totalAmount: (json['totalAmount'] ?? 0).toDouble(),
|
||||
pricePerTree: (json['pricePerTree'] ?? 2199).toDouble(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 认种服务
|
||||
///
|
||||
/// 提供认种订单创建、省市选择、支付等功能
|
||||
class PlantingService {
|
||||
final ApiClient _apiClient;
|
||||
|
||||
PlantingService({required ApiClient apiClient}) : _apiClient = apiClient;
|
||||
|
||||
/// 创建认种订单
|
||||
///
|
||||
/// [treeCount] 认种数量
|
||||
/// 返回订单号和总金额
|
||||
Future<CreateOrderResponse> createOrder(int treeCount) async {
|
||||
try {
|
||||
debugPrint('[PlantingService] 创建认种订单: treeCount=$treeCount');
|
||||
|
||||
final response = await _apiClient.post(
|
||||
'/planting/orders',
|
||||
data: {'treeCount': treeCount},
|
||||
);
|
||||
|
||||
if (response.statusCode == 201 || response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
debugPrint('[PlantingService] 订单创建成功: ${data['orderNo']}');
|
||||
return CreateOrderResponse.fromJson(data);
|
||||
}
|
||||
|
||||
throw Exception('创建订单失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PlantingService] 创建订单失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 选择省市
|
||||
///
|
||||
/// [orderNo] 订单号
|
||||
/// [provinceCode] 省份代码
|
||||
/// [cityCode] 城市代码
|
||||
Future<PlantingOrder> selectProvinceCity(
|
||||
String orderNo,
|
||||
String provinceCode,
|
||||
String cityCode,
|
||||
) async {
|
||||
try {
|
||||
debugPrint('[PlantingService] 选择省市: orderNo=$orderNo, province=$provinceCode, city=$cityCode');
|
||||
|
||||
final response = await _apiClient.post(
|
||||
'/planting/orders/$orderNo/select-province-city',
|
||||
data: {
|
||||
'provinceCode': provinceCode,
|
||||
'cityCode': cityCode,
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
debugPrint('[PlantingService] 省市选择成功');
|
||||
return PlantingOrder.fromJson(data);
|
||||
}
|
||||
|
||||
throw Exception('选择省市失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PlantingService] 选择省市失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 确认省市选择
|
||||
///
|
||||
/// [orderNo] 订单号
|
||||
/// 确认后不可修改省市
|
||||
Future<PlantingOrder> confirmProvinceCity(String orderNo) async {
|
||||
try {
|
||||
debugPrint('[PlantingService] 确认省市选择: orderNo=$orderNo');
|
||||
|
||||
final response = await _apiClient.post(
|
||||
'/planting/orders/$orderNo/confirm-province-city',
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
debugPrint('[PlantingService] 省市确认成功');
|
||||
return PlantingOrder.fromJson(data);
|
||||
}
|
||||
|
||||
throw Exception('确认省市失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PlantingService] 确认省市失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 支付订单
|
||||
///
|
||||
/// [orderNo] 订单号
|
||||
/// 支付成功后开始挖矿
|
||||
Future<PlantingOrder> payOrder(String orderNo) async {
|
||||
try {
|
||||
debugPrint('[PlantingService] 支付订单: orderNo=$orderNo');
|
||||
|
||||
final response = await _apiClient.post(
|
||||
'/planting/orders/$orderNo/pay',
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
debugPrint('[PlantingService] 支付成功');
|
||||
return PlantingOrder.fromJson(data);
|
||||
}
|
||||
|
||||
throw Exception('支付失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PlantingService] 支付失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取订单详情
|
||||
///
|
||||
/// [orderNo] 订单号
|
||||
Future<PlantingOrder> getOrder(String orderNo) async {
|
||||
try {
|
||||
debugPrint('[PlantingService] 获取订单详情: orderNo=$orderNo');
|
||||
|
||||
final response = await _apiClient.get('/planting/orders/$orderNo');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
return PlantingOrder.fromJson(data);
|
||||
}
|
||||
|
||||
throw Exception('获取订单失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PlantingService] 获取订单失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取我的订单列表
|
||||
///
|
||||
/// [page] 页码
|
||||
/// [pageSize] 每页数量
|
||||
Future<List<PlantingOrder>> getMyOrders({int page = 1, int pageSize = 20}) async {
|
||||
try {
|
||||
debugPrint('[PlantingService] 获取我的订单列表: page=$page, pageSize=$pageSize');
|
||||
|
||||
final response = await _apiClient.get(
|
||||
'/planting/orders',
|
||||
queryParameters: {
|
||||
'page': page,
|
||||
'pageSize': pageSize,
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
final items = data['items'] as List<dynamic>? ?? [];
|
||||
return items.map((e) => PlantingOrder.fromJson(e)).toList();
|
||||
}
|
||||
|
||||
throw Exception('获取订单列表失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PlantingService] 获取订单列表失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// 取消订单
|
||||
///
|
||||
/// [orderNo] 订单号
|
||||
/// 只有未支付的订单可以取消
|
||||
Future<void> cancelOrder(String orderNo) async {
|
||||
try {
|
||||
debugPrint('[PlantingService] 取消订单: orderNo=$orderNo');
|
||||
|
||||
final response = await _apiClient.post(
|
||||
'/planting/orders/$orderNo/cancel',
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
debugPrint('[PlantingService] 订单取消成功');
|
||||
return;
|
||||
}
|
||||
|
||||
throw Exception('取消订单失败: ${response.statusCode}');
|
||||
} catch (e) {
|
||||
debugPrint('[PlantingService] 取消订单失败: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,15 +3,18 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:city_pickers/city_pickers.dart';
|
||||
import '../widgets/planting_confirm_dialog.dart';
|
||||
import '../../../../core/di/injection_container.dart';
|
||||
|
||||
/// 认种省市选择页面参数
|
||||
class PlantingLocationParams {
|
||||
final int quantity;
|
||||
final double totalPrice;
|
||||
final String orderNo; // 订单号
|
||||
|
||||
PlantingLocationParams({
|
||||
required this.quantity,
|
||||
required this.totalPrice,
|
||||
required this.orderNo,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -20,11 +23,13 @@ class PlantingLocationParams {
|
|||
class PlantingLocationPage extends ConsumerStatefulWidget {
|
||||
final int quantity;
|
||||
final double totalPrice;
|
||||
final String orderNo;
|
||||
|
||||
const PlantingLocationPage({
|
||||
super.key,
|
||||
required this.quantity,
|
||||
required this.totalPrice,
|
||||
required this.orderNo,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -33,11 +38,17 @@ class PlantingLocationPage extends ConsumerStatefulWidget {
|
|||
}
|
||||
|
||||
class _PlantingLocationPageState extends ConsumerState<PlantingLocationPage> {
|
||||
/// 选中的省份
|
||||
String? _selectedProvince;
|
||||
/// 选中的省份名称
|
||||
String? _selectedProvinceName;
|
||||
|
||||
/// 选中的城市
|
||||
String? _selectedCity;
|
||||
/// 选中的城市名称
|
||||
String? _selectedCityName;
|
||||
|
||||
/// 选中的省份代码
|
||||
String? _selectedProvinceCode;
|
||||
|
||||
/// 选中的城市代码
|
||||
String? _selectedCityCode;
|
||||
|
||||
/// 是否正在提交
|
||||
bool _isSubmitting = false;
|
||||
|
|
@ -66,8 +77,10 @@ class _PlantingLocationPageState extends ConsumerState<PlantingLocationPage> {
|
|||
|
||||
if (result != null) {
|
||||
setState(() {
|
||||
_selectedProvince = result.provinceName;
|
||||
_selectedCity = result.cityName;
|
||||
_selectedProvinceName = result.provinceName;
|
||||
_selectedCityName = result.cityName;
|
||||
_selectedProvinceCode = result.provinceId;
|
||||
_selectedCityCode = result.cityId;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -84,7 +97,7 @@ class _PlantingLocationPageState extends ConsumerState<PlantingLocationPage> {
|
|||
|
||||
/// 确认选择
|
||||
void _confirmSelection() async {
|
||||
if (_selectedProvince == null || _selectedCity == null) {
|
||||
if (_selectedProvinceName == null || _selectedCityName == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('请选择省份和城市'),
|
||||
|
|
@ -97,8 +110,8 @@ class _PlantingLocationPageState extends ConsumerState<PlantingLocationPage> {
|
|||
// 显示确认弹窗(带5秒倒计时)
|
||||
await PlantingConfirmDialog.show(
|
||||
context: context,
|
||||
province: _selectedProvince!,
|
||||
city: _selectedCity!,
|
||||
province: _selectedProvinceName!,
|
||||
city: _selectedCityName!,
|
||||
onConfirm: _submitPlanting,
|
||||
);
|
||||
}
|
||||
|
|
@ -108,8 +121,20 @@ class _PlantingLocationPageState extends ConsumerState<PlantingLocationPage> {
|
|||
setState(() => _isSubmitting = true);
|
||||
|
||||
try {
|
||||
// TODO: 调用 API 提交认种请求
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
final plantingService = ref.read(plantingServiceProvider);
|
||||
|
||||
// 1. 选择省市
|
||||
await plantingService.selectProvinceCity(
|
||||
widget.orderNo,
|
||||
_selectedProvinceCode!,
|
||||
_selectedCityCode!,
|
||||
);
|
||||
|
||||
// 2. 确认省市选择
|
||||
await plantingService.confirmProvinceCity(widget.orderNo);
|
||||
|
||||
// 3. 支付订单
|
||||
await plantingService.payOrder(widget.orderNo);
|
||||
|
||||
if (mounted) {
|
||||
// 显示成功提示
|
||||
|
|
@ -142,7 +167,7 @@ class _PlantingLocationPageState extends ConsumerState<PlantingLocationPage> {
|
|||
|
||||
/// 是否可以提交
|
||||
bool get _canSubmit =>
|
||||
_selectedProvince != null && _selectedCity != null && !_isSubmitting;
|
||||
_selectedProvinceName != null && _selectedCityName != null && !_isSubmitting;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -305,12 +330,12 @@ class _PlantingLocationPageState extends ConsumerState<PlantingLocationPage> {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
_selectedProvince ?? '选择省份',
|
||||
_selectedProvinceName ?? '选择省份',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Inter',
|
||||
height: 1.5,
|
||||
color: _selectedProvince != null
|
||||
color: _selectedProvinceName != null
|
||||
? const Color(0xFF5D4037)
|
||||
: const Color(0xFF5D4037).withValues(alpha: 0.5),
|
||||
),
|
||||
|
|
@ -363,12 +388,12 @@ class _PlantingLocationPageState extends ConsumerState<PlantingLocationPage> {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
_selectedCity ?? '选择市级',
|
||||
_selectedCityName ?? '选择市级',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Inter',
|
||||
height: 1.5,
|
||||
color: _selectedCity != null
|
||||
color: _selectedCityName != null
|
||||
? const Color(0xFF5D4037)
|
||||
: const Color(0xFF5D4037).withValues(alpha: 0.5),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ class _PlantingQuantityPageState extends ConsumerState<PlantingQuantityPage> {
|
|||
/// 是否正在加载
|
||||
bool _isLoading = false;
|
||||
|
||||
/// 是否正在创建订单
|
||||
bool _isCreatingOrder = false;
|
||||
|
||||
/// 加载错误信息
|
||||
String? _errorMessage;
|
||||
|
||||
|
|
@ -108,16 +111,44 @@ class _PlantingQuantityPageState extends ConsumerState<PlantingQuantityPage> {
|
|||
context.pop();
|
||||
}
|
||||
|
||||
/// 下一步:选择省市
|
||||
void _goToNextStep() {
|
||||
if (_quantity > 0 && _quantity <= _maxQuantity) {
|
||||
context.push(
|
||||
RoutePaths.plantingLocation,
|
||||
extra: PlantingLocationParams(
|
||||
quantity: _quantity,
|
||||
totalPrice: _quantity * _pricePerTree,
|
||||
),
|
||||
);
|
||||
/// 下一步:创建订单并选择省市
|
||||
Future<void> _goToNextStep() async {
|
||||
if (_quantity <= 0 || _quantity > _maxQuantity || _isCreatingOrder) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() => _isCreatingOrder = true);
|
||||
|
||||
try {
|
||||
// 1. 调用 API 创建订单
|
||||
final plantingService = ref.read(plantingServiceProvider);
|
||||
final response = await plantingService.createOrder(_quantity);
|
||||
|
||||
if (mounted) {
|
||||
// 2. 跳转到省市选择页面,传递订单号
|
||||
context.push(
|
||||
RoutePaths.plantingLocation,
|
||||
extra: PlantingLocationParams(
|
||||
quantity: _quantity,
|
||||
totalPrice: _quantity * _pricePerTree,
|
||||
orderNo: response.orderNo,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('创建订单失败: $e');
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('创建订单失败: $e'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() => _isCreatingOrder = false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -518,7 +549,7 @@ class _PlantingQuantityPageState extends ConsumerState<PlantingQuantityPage> {
|
|||
|
||||
/// 构建底部按钮
|
||||
Widget _buildBottomButton() {
|
||||
final bool canProceed = _quantity > 0 && _quantity <= _maxQuantity && !_isLoading;
|
||||
final bool canProceed = _quantity > 0 && _quantity <= _maxQuantity && !_isLoading && !_isCreatingOrder;
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 24),
|
||||
|
|
@ -547,17 +578,26 @@ class _PlantingQuantityPageState extends ConsumerState<PlantingQuantityPage> {
|
|||
]
|
||||
: null,
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'下一步:选择省市',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.56,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: _isCreatingOrder
|
||||
? const SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
color: Colors.white,
|
||||
),
|
||||
)
|
||||
: const Text(
|
||||
'下一步:选择省市',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Inter',
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.56,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in New Issue