开源鸿蒙跨平台Flutter开发:快递单号批量查询应用
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
一、项目概述
运行效果图



1.1 应用简介
快递单号批量查询应用是一款便捷的物流查询工具,用户可以一次输入多个快递单号,批量查询物流状态,还能设置到货提醒,再也不用一个个查快递了。
应用以蓝色为主色调,象征物流的高效与可靠。涵盖快递查询、批量管理、到货提醒、历史记录四大模块。用户可以通过简洁的界面输入多个快递单号,系统自动识别快递公司并查询物流状态,同时支持设置到货提醒,让用户及时了解快递动态。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 批量查询 | 一次输入多个单号 | 文本解析 |
| 自动识别 | 自动识别快递公司 | 正则匹配 |
| 物流追踪 | 实时物流状态查询 | API调用 |
| 到货提醒 | 设置到货通知 | 本地通知 |
| 历史记录 | 保存查询历史 | 本地存储 |
| 快递分类 | 按状态分类管理 | 数据排序 |
1.3 快递状态定义
| 序号 | 状态名称 | 描述 | 颜色标识 |
|---|---|---|---|
| 1 | 待揽收 | 快递尚未被揽收 | 灰色 |
| 2 | 运输中 | 快递正在运输途中 | 蓝色 |
| 3 | 派送中 | 快递正在派送中 | 黄色 |
| 4 | 已签收 | 快递已被签收 | 绿色 |
| 5 | 异常 | 快递出现异常 | 红色 |
| 6 | 未知 | 无法查询到信息 | 灰色 |
1.4 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design 3 | - |
| 网络请求 | http | - |
| 本地存储 | shared_preferences | - |
| 通知系统 | flutter_local_notifications | - |
| 目标平台 | 鸿蒙OS / Web | API 21+ |
1.5 项目结构
lib/
└── main_courier_tracker.dart
├── CourierTrackerApp # 应用入口
├── TrackingNumber # 快递单号模型
├── CourierStatus # 快递状态枚举
├── CourierService # 快递服务
├── TrackingController # 追踪控制器
├── NotificationService # 通知服务
├── CourierTrackerHomePage # 主页面
├── _buildInputPage # 输入页面
├── _buildTrackingPage # 追踪页面
├── _buildHistoryPage # 历史页面
└── _buildSettingsPage # 设置页面
二、系统架构
2.1 整体架构图
2.2 类图设计
2.3 页面导航流程
2.4 物流查询流程
三、核心模块设计
3.1 数据模型设计
3.1.1 快递单号模型 (TrackingNumber)
class TrackingNumber {
final String number;
final String courierName;
CourierStatus status;
String latestUpdate;
List<String> trackingDetails;
final DateTime createdAt;
bool notifyOnDelivery;
TrackingNumber({
required this.number,
required this.courierName,
required this.status,
required this.latestUpdate,
required this.trackingDetails,
required this.createdAt,
this.notifyOnDelivery = false,
});
}
3.1.2 快递状态枚举 (CourierStatus)
enum CourierStatus {
awaitingPickup(label: '待揽收', color: Colors.grey),
inTransit(label: '运输中', color: Colors.blue),
outForDelivery(label: '派送中', color: Colors.yellow),
delivered(label: '已签收', color: Colors.green),
exception(label: '异常', color: Colors.red),
unknown(label: '未知', color: Colors.grey);
final String label;
final Color color;
const CourierStatus({required this.label, required this.color});
}
3.1.3 快递服务 (CourierService)
class CourierService {
final http.Client _client;
CourierService(this._client);
Future<CourierStatus> track(String number) async {
// 模拟物流状态查询
await Future.delayed(Duration(seconds: 1));
return CourierStatus.inTransit;
}
String identifyCourier(String number) {
// 模拟快递公司识别
return '顺丰速运';
}
Future<List<String>> getTrackingDetails(String number) async {
// 模拟获取物流详情
await Future.delayed(Duration(seconds: 1));
return [
'【深圳市】快递已到达【深圳转运中心】',
'【广州市】快递离开【广州转运中心】,下一站【深圳转运中心】',
'【广州市】快递已到达【广州转运中心】',
'【广州市】快递已揽收',
];
}
}
3.2 页面结构设计
3.2.1 主页面布局
3.2.2 输入页面结构
3.2.3 追踪页面结构
3.3 物流查询逻辑
3.4 到货提醒逻辑
四、UI设计规范
4.1 配色方案
应用以蓝色为主色调,象征物流的高效与可靠:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | #1976D2 (Blue) | 导航、主题元素 |
| 辅助色 | #64B5F6 | 按钮、强调 |
| 第三色 | #BBDEFB | 背景、卡片 |
| 背景色 | #F5F5F5 | 页面背景 |
| 卡片背景 | #FFFFFF | 信息卡片 |
4.2 状态色彩映射
| 状态 | 色值 | 视觉效果 |
|---|---|---|
| 待揽收 | #9E9E9E | 灰色 |
| 运输中 | #1976D2 | 蓝色 |
| 派送中 | #FFC107 | 黄色 |
| 已签收 | #4CAF50 | 绿色 |
| 异常 | #F44336 | 红色 |
| 未知 | #9E9E9E | 灰色 |
4.3 字体规范
| 元素 | 字号 | 字重 | 颜色 |
|---|---|---|---|
| 页面标题 | 24px | Bold | 主色 |
| 单号信息 | 18px | Medium | #333333 |
| 状态文本 | 16px | Regular | 对应状态色 |
| 物流信息 | 14px | Regular | #666666 |
| 时间信息 | 12px | Light | #999999 |
4.4 组件规范
4.4.1 输入框
┌─────────────────────────────────────┐
│ 输入快递单号(一行一个) │
│ │
│ 123456789012 │
│ 987654321098 │
│ │
└─────────────────────────────────────┘
4.4.2 物流卡片
┌─────────────────────────────────────┐
│ 顺丰速运 │
│ 123456789012 │
│ ───────────────────────────────── │
│ 📦 运输中 │
│ 【深圳市】快递已到达【深圳转运中心】 │
│ 2024-01-01 12:00:00 │
│ │
│ [查看详情] [设置提醒] │
└─────────────────────────────────────┘
4.4.3 物流详情
┌─────────────────────────────────────┐
│ 物流详情 │
│ ───────────────────────────────── │
│ ● 【深圳市】快递已到达【深圳转运中心】 │
│ 2024-01-01 12:00:00 │
│ ● 【广州市】快递离开【广州转运中心】 │
│ 2024-01-01 10:00:00 │
│ ● 【广州市】快递已到达【广州转运中心】 │
│ 2024-01-01 08:00:00 │
│ ● 【广州市】快递已揽收 │
│ 2024-01-01 06:00:00 │
└─────────────────────────────────────┘
4.4.4 提醒设置
┌─────────────────────────────────────┐
│ 到货提醒 │
│ ───────────────────────────────── │
│ ☐ 开启到货提醒 │
│ ☐ 开启派送提醒 │
│ ☐ 开启异常提醒 │
│ │
│ [保存设置] │
└─────────────────────────────────────┘
五、核心功能实现
5.1 追踪控制器实现
class TrackingController {
final CourierService _courierService;
final NotificationService _notificationService;
final DataManager _dataManager;
final List<TrackingNumber> trackingNumbers = [];
TrackingController(this._courierService, this._notificationService, this._dataManager);
Future<void> initialize() async {
await _notificationService.initialize();
final savedNumbers = await _dataManager.loadTrackingNumbers();
trackingNumbers.addAll(savedNumbers);
}
Future<void> addTrackingNumber(String number) async {
final courierName = _courierService.identifyCourier(number);
final status = await _courierService.track(number);
final details = await _courierService.getTrackingDetails(number);
final trackingNumber = TrackingNumber(
number: number,
courierName: courierName,
status: status,
latestUpdate: details.isNotEmpty ? details[0] : '暂无信息',
trackingDetails: details,
createdAt: DateTime.now(),
);
trackingNumbers.add(trackingNumber);
await _dataManager.saveTrackingNumbers(trackingNumbers);
}
Future<void> addMultipleTrackingNumbers(List<String> numbers) async {
for (final number in numbers) {
await addTrackingNumber(number);
}
}
Future<void> updateTrackingStatus(TrackingNumber number) async {
final index = trackingNumbers.indexOf(number);
if (index == -1) return;
final status = await _courierService.track(number.number);
final details = await _courierService.getTrackingDetails(number.number);
trackingNumbers[index] = TrackingNumber(
number: number.number,
courierName: number.courierName,
status: status,
latestUpdate: details.isNotEmpty ? details[0] : '暂无信息',
trackingDetails: details,
createdAt: number.createdAt,
notifyOnDelivery: number.notifyOnDelivery,
);
await _dataManager.saveTrackingNumbers(trackingNumbers);
if (number.notifyOnDelivery && status == CourierStatus.delivered) {
await _notificationService.scheduleNotification(trackingNumbers[index]);
}
}
void toggleNotification(TrackingNumber number) {
final index = trackingNumbers.indexOf(number);
if (index == -1) return;
trackingNumbers[index] = TrackingNumber(
number: number.number,
courierName: number.courierName,
status: number.status,
latestUpdate: number.latestUpdate,
trackingDetails: number.trackingDetails,
createdAt: number.createdAt,
notifyOnDelivery: !number.notifyOnDelivery,
);
if (trackingNumbers[index].notifyOnDelivery) {
_notificationService.scheduleNotification(trackingNumbers[index]);
} else {
_notificationService.cancelNotification(trackingNumbers[index]);
}
_dataManager.saveTrackingNumbers(trackingNumbers);
}
void removeTrackingNumber(TrackingNumber number) {
trackingNumbers.remove(number);
_notificationService.cancelNotification(number);
_dataManager.saveTrackingNumbers(trackingNumbers);
}
}
5.2 快递服务实现
class CourierService {
final http.Client _client;
CourierService(this._client);
Future<CourierStatus> track(String number) async {
try {
// 模拟API调用
await Future.delayed(Duration(seconds: 1));
// 模拟返回不同状态
final random = Random();
final statuses = [
CourierStatus.awaitingPickup,
CourierStatus.inTransit,
CourierStatus.outForDelivery,
CourierStatus.delivered,
CourierStatus.exception,
];
return statuses[random.nextInt(statuses.length)];
} catch (e) {
print('Error tracking package: $e');
return CourierStatus.unknown;
}
}
String identifyCourier(String number) {
// 模拟快递公司识别
final couriers = [
'顺丰速运',
'中通快递',
'申通快递',
'韵达快递',
'圆通快递',
'百世快递',
];
final random = Random();
return couriers[random.nextInt(couriers.length)];
}
Future<List<String>> getTrackingDetails(String number) async {
try {
// 模拟API调用
await Future.delayed(Duration(seconds: 1));
// 模拟返回物流详情
return [
'【深圳市】快递已到达【深圳转运中心】',
'【广州市】快递离开【广州转运中心】,下一站【深圳转运中心】',
'【广州市】快递已到达【广州转运中心】',
'【广州市】快递已揽收',
];
} catch (e) {
print('Error getting tracking details: $e');
return [];
}
}
}
5.3 通知服务实现
class NotificationService {
late FlutterLocalNotificationsPlugin _notifications;
Future<void> initialize() async {
_notifications = FlutterLocalNotificationsPlugin();
const AndroidInitializationSettings initializationSettingsAndroid = AndroidInitializationSettings('app_icon');
final InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
);
await _notifications.initialize(initializationSettings);
}
Future<void> scheduleNotification(TrackingNumber number) async {
const AndroidNotificationDetails androidPlatformChannelSpecifics = AndroidNotificationDetails(
'courier_tracker_channel',
'快递追踪',
importance: Importance.max,
priority: Priority.high,
);
const NotificationDetails platformChannelSpecifics = NotificationDetails(
android: androidPlatformChannelSpecifics,
);
await _notifications.schedule(
number.number.hashCode,
'快递到货提醒',
'您的快递 ${number.number} 已到达,请及时取件',
DateTime.now().add(const Duration(seconds: 5)), // 模拟5秒后通知
platformChannelSpecifics,
);
}
Future<void> cancelNotification(TrackingNumber number) async {
await _notifications.cancel(number.number.hashCode);
}
}
5.4 数据管理实现
class DataManager {
static const String _trackingNumbersKey = 'tracking_numbers';
Future<List<TrackingNumber>> loadTrackingNumbers() async {
final prefs = await SharedPreferences.getInstance();
final jsonString = prefs.getString(_trackingNumbersKey);
if (jsonString == null) return [];
final jsonList = json.decode(jsonString) as List;
return jsonList.map((json) => TrackingNumber.fromJson(json)).toList();
}
Future<void> saveTrackingNumbers(List<TrackingNumber> numbers) async {
final prefs = await SharedPreferences.getInstance();
final jsonList = numbers.map((number) => number.toJson()).toList();
await prefs.setString(_trackingNumbersKey, json.encode(jsonList));
}
}
六、交互设计
6.1 输入页面交互流程
6.2 追踪页面交互流程
6.3 历史页面交互流程
七、扩展功能规划
7.1 后续版本规划
7.2 功能扩展建议
7.2.1 扫码录入
扫码功能:
- 支持扫描快递单条形码
- 自动识别单号并添加
- 批量扫描多个快递单
- 支持二维码识别
7.2.2 多语言支持
多语言功能:
- 支持中文、英文等多语言
- 根据系统语言自动切换
- 提供语言手动切换选项
- 适配不同语言的UI布局
7.2.3 云同步功能
云同步功能:
- 支持账号登录
- 云端备份快递信息
- 多设备同步数据
- 数据恢复功能
八、注意事项
8.1 开发注意事项
-
API调用限制:物流查询API可能有调用频率限制,需做好限流处理
-
权限管理:通知功能需要申请权限,需合理处理权限请求
-
数据安全:快递单号属于敏感信息,需做好本地存储加密
-
网络依赖:物流查询需要网络连接,需处理离线情况
-
用户体验:批量查询时需显示加载状态,避免用户等待焦虑
8.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 单号识别失败 | 单号格式不正确 | 提示用户检查单号 |
| 查询无结果 | 网络连接问题 | 检查网络连接 |
| 通知不生效 | 权限未开启 | 引导用户开启权限 |
| 应用崩溃 | 数据解析错误 | 增加异常处理 |
| 保存失败 | 存储空间不足 | 提示用户清理空间 |
8.3 使用技巧
📦 快递单号批量查询使用技巧 📦
输入技巧
- 一行输入一个快递单号
- 支持复制粘贴多个单号
- 系统会自动去重处理
- 支持不同快递公司的单号
查询技巧
- 点击开始查询后耐心等待
- 下拉刷新可更新物流状态
- 点击卡片查看详细轨迹
- 长按卡片可进行管理操作
提醒设置
- 开启到货提醒及时获取通知
- 可同时设置多个快递提醒
- 到货后自动发送通知
- 在设置页面管理所有提醒
历史管理
- 自动保存查询历史
- 可查看历史快递状态
- 支持清空历史记录
- 可重新追踪历史单号
九、运行说明
9.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
| Web浏览器 | Chrome 90+ |
| 网络连接 | 稳定网络 |
9.2 运行命令
# 查看可用设备
flutter devices
# 运行到Web服务器
flutter run -d web-server -t lib/main_courier_tracker.dart --web-port 8146
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_courier_tracker.dart
# 代码分析
flutter analyze lib/main_courier_tracker.dart
十、总结
快递单号批量查询应用通过简洁的界面和高效的功能,为用户提供了便捷的物流查询体验。用户可以一次输入多个快递单号,系统自动识别快递公司并查询物流状态,同时支持设置到货提醒,让用户及时了解快递动态。
核心功能包括批量查询、自动识别、物流追踪、到货提醒、历史记录等。用户可以通过简洁的界面输入多个快递单号,系统自动处理并显示查询结果,同时支持设置到货提醒,让用户不再错过快递。
应用采用蓝色为主色调,象征物流的高效与可靠。通过本应用,希望能够帮助用户更方便地管理快递,节省时间和精力,让快递查询变得更加简单和高效。
快递单号批量查询——让物流追踪更简单
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)