已完成用户APP首期功能开发

交付用户端首期页面、配套接口、后台资源及测试文档。用户APP构建、静态分析和三个管理后台构建通过;完整测试仍有2项失败,后端模型注释检查未通过,详见交付记录。
This commit is contained in:
czl231
2026-09-13 00:57:32 +08:00
parent a0a4bb1218
commit 3ef33b531d
793 changed files with 40959 additions and 1204 deletions

View File

@@ -0,0 +1,88 @@
// 功能描述:用户可见的隐私化配送轨迹、履约节点与人员摘要;版本:1.0.0。
class DeliveryTrackPoint {
DeliveryTrackPoint.fromJson(Map<String, Object?> data)
: longitude = _number(data, 'longitude'),
latitude = _number(data, 'latitude'),
occurredAt = DateTime.parse(_required(data, 'occurred_at')).toLocal();
final double longitude, latitude;
final DateTime occurredAt;
static double _number(Map<String, Object?> data, String key) {
final value = data[key];
if (value is! num) throw FormatException('配送轨迹坐标异常:$key');
return value.toDouble();
}
}
class DeliveryTrackEvent {
DeliveryTrackEvent.fromJson(Map<String, Object?> data)
: statusCode = data['status_code'] as int? ?? 0,
title = _required(data, 'title'),
detail = _required(data, 'detail'),
occurredAt = DateTime.parse(_required(data, 'occurred_at')).toLocal();
final int statusCode;
final String title, detail;
final DateTime occurredAt;
}
/// 只接受服务端明确返回的本人订单事实;客户端不推算路线、位置或送达时间。
class DeliveryTrack {
DeliveryTrack.fromJson(Map<String, Object?> data)
: identity = _required(data, 'identity'),
statusCode = data['status_code'] as int? ?? 0,
statusName = _required(data, 'status_name'),
statusMessage = _required(data, 'status_message'),
appointmentAt = DateTime.parse(_required(data, 'appointment_at')).toLocal(),
updatedAt = _date(data['updated_at']),
stationName = _text(data, 'station_name'),
staffName = _text(data, 'staff_name'),
staffAvatar = _text(data, 'staff_avatar'),
staffPhoneMasked = _text(data, 'staff_phone_masked'),
controlledCallAvailable = _flag(data, 'controlled_call_available'),
routeAvailable = _flag(data, 'route_available'),
destinationAvailable = _flag(data, 'destination_available'),
destinationLongitude = _optionalNumber(data['destination_longitude']),
destinationLatitude = _optionalNumber(data['destination_latitude']),
points = List.unmodifiable([
for (final row in data['points'] as List)
DeliveryTrackPoint.fromJson(Map<String, Object?>.from(row as Map)),
]),
timeline = List.unmodifiable([
for (final row in data['timeline'] as List)
DeliveryTrackEvent.fromJson(Map<String, Object?>.from(row as Map)),
]);
final String identity, statusName, statusMessage, stationName, staffName;
final String staffAvatar, staffPhoneMasked;
final int statusCode;
final DateTime appointmentAt;
final DateTime? updatedAt;
final bool controlledCallAvailable, routeAvailable, destinationAvailable;
final double? destinationLongitude, destinationLatitude;
final List<DeliveryTrackPoint> points;
final List<DeliveryTrackEvent> timeline;
static String _text(Map<String, Object?> data, String key) => data[key] as String? ?? '';
static String _required(Map<String, Object?> data, String key) {
final value = _text(data, key);
if (value.trim().isEmpty) throw FormatException('配送轨迹资料不完整:$key');
return value;
}
static bool _flag(Map<String, Object?> data, String key) {
if (data[key] is! bool) throw FormatException('配送轨迹状态异常:$key');
return data[key] as bool;
}
static double? _optionalNumber(Object? value) => value is num ? value.toDouble() : null;
static DateTime? _date(Object? value) =>
value == null ? null : DateTime.tryParse('$value')?.toLocal();
}
String _required(Map<String, Object?> data, String key) {
final value = data[key] as String? ?? '';
if (value.trim().isEmpty) throw FormatException('配送轨迹资料不完整:$key');
return value;
}