feat: 完成智能电网电工端 Flutter 应用初始化

创建完整的 Flutter 项目结构,包含 Android 和 iOS 平台配置、核心网络层、路由、状态管理及业务模块(订单、收益、认证),适配原 uni-app 项目功能逻辑
This commit is contained in:
andyesfly committed 2026-10-06 11:54:10 +08:00
commit 56830e94ec
108 files changed
+9272

No files matched your search

+46
View File
@@ -0,0 +1,46 @@
import '../../../core/network/api_client.dart';
import '../../../core/network/api_response.dart';
import 'order_models.dart';
/// 订单接口,对应后端 `/api/worker-app/orders*`。
class OrderApi {
OrderApi(this._client);
final ApiClient _client;
/// 订单池:四类未被接单的订单合并。
Future<ApiResponse<List<Order>>> pool() => _client.get<List<Order>>(
'/worker-app/orders/pool',
parse: _parseList,
);
/// 我的订单。`status` 传 `pending` / `completed`,留空取全部。
Future<ApiResponse<List<Order>>> myOrders({String? status}) =>
_client.get<List<Order>>(
'/worker-app/orders',
query: {'status': status},
parse: _parseList,
);
/// 订单详情。
Future<ApiResponse<Order>> detail(String source, int id) =>
_client.get<Order>(
'/worker-app/orders/$source/$id',
parse: (d) => Order.fromJson((d as Map).cast<String, dynamic>()),
);
/// 接单。订单被他人接走时后端返回 409。
Future<ApiResponse<void>> grab(String source, int id) =>
_client.post<void>('/worker-app/orders/$source/$id/grab');
/// 完成订单。非本人订单后端返回 403。
Future<ApiResponse<void>> complete(String source, int id) =>
_client.put<void>('/worker-app/orders/$source/$id/complete');
static List<Order> _parseList(dynamic data) {
final map = (data as Map).cast<String, dynamic>();
return (map['list'] as List? ?? const [])
.map((e) => Order.fromJson((e as Map).cast<String, dynamic>()))
.toList();
}
}
+113
View File
@@ -0,0 +1,113 @@
import '../../../core/utils/id_util.dart';
/// 统一订单视图,对应后端 `WorkerAppService.toOrderView()`。
///
/// `id` 形如 `repair-12` / `install-5`,`source` 为四类来源之一。
class Order {
const Order({
required this.id,
required this.source,
required this.status,
required this.jobId,
required this.title,
required this.type,
required this.amount,
required this.distance,
required this.schedule,
required this.description,
required this.customerName,
required this.customerPhone,
required this.photos,
required this.address,
required this.laborFee,
required this.materialFee,
required this.estimatedDuration,
});
/// `repair-12`
final String id;
/// repair | install | maintenance | survey
final String source;
final int status;
/// 业务单号(repairNo / installNo / maintenanceNo / surveyNo)
final String jobId;
final String title;
/// urgent | standard | regular
final String type;
final double amount;
final double distance;
final String schedule;
final String description;
final String customerName;
final String customerPhone;
final List<String> photos;
final String address;
final double laborFee;
final double materialFee;
final String estimatedDuration;
/// 来源中文名,用于收益明细副标题等场景。
String get sourceName => switch (source) {
'repair' => '家庭电路维修',
'install' => '设备安装',
'maintenance' => '设备维保',
'survey' => '现场勘察',
_ => '服务订单',
};
/// 列表页类型标签:紧急呼叫 / 标准预约 / 常规巡检。
String get listTypeText => switch (type) {
'urgent' => '紧急呼叫',
'standard' => '标准预约',
_ => '常规巡检',
};
/// 详情页类型标签:紧急 / 标准 / 常规。
String get detailTypeText => switch (type) {
'urgent' => '紧急',
'standard' => '标准',
_ => '常规',
};
/// 客户头像占位文字:后端无头像字段,用姓名首字(与「我的」页一致)。
String get customerAvatarText => customerName.isEmpty
? '客'
: String.fromCharCode(customerName.runes.first);
/// 卡片上展示的订单号:后端 `id` 前缀即来源,取 `jobId` 更贴近源 `#EL-8821` 的观感。
String get displayNo => jobId.isNotEmpty ? jobId : id;
/// 后端接口里的数字主键:`repair-12` → 12。
int get intId {
final idx = id.lastIndexOf('-');
return toIntOr(idx >= 0 ? id.substring(idx + 1) : id, 0);
}
factory Order.fromJson(Map<String, dynamic> json) => Order(
id: json['id'] as String? ?? '',
source: json['source'] as String? ?? '',
status: toIntOr(json['status'], 0),
jobId: json['jobId'] as String? ?? '',
title: json['title'] as String? ?? '',
type: json['type'] as String? ?? 'regular',
amount: toDoubleOr(json['amount'], 0),
distance: toDoubleOr(json['distance'], 0),
schedule: json['schedule'] as String? ?? '',
description: json['description'] as String? ?? '',
customerName: json['customerName'] as String? ?? '',
customerPhone: json['customerPhone'] as String? ?? '',
photos:
(json['photos'] as List?)?.map((e) => e.toString()).toList() ??
const [],
address: json['address'] as String? ?? '',
laborFee: toDoubleOr(json['laborFee'], 0),
materialFee: toDoubleOr(json['materialFee'], 0),
estimatedDuration: json['estimatedDuration'] as String? ?? '',
);
}