欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net

一、项目概述

运行效果图

image-20260410201229084

image-20260410201251337

1.1 应用简介

手机号码归属地查询是一款实用工具应用,为用户提供快速、准确的手机号码信息查询服务。支持查询手机号码归属地、运营商信息、号码段信息等,让用户轻松了解陌生号码来源。应用内置完整的号码段数据库,支持离线查询,响应速度快,数据准确可靠。

应用以蓝色为主色调,象征科技与信任。涵盖号码查询、历史记录、号码段查询、关于信息四大模块。用户可以输入手机号码查询详细信息,查看历史查询记录,了解号码段分布情况。

1.2 核心功能

功能模块 功能描述 实现方式
号码查询 查询归属地和运营商 数据匹配
历史记录 保存查询历史 本地存储
号码段 查询号码段信息 列表展示
收藏夹 收藏重要号码 标记功能
号码验证 验证号码格式 正则匹配

1.3 运营商定义

序号 运营商名称 Emoji 号段范围
1 中国移动 📱 134-139, 147, 150-152, 157-159, 178, 182-184, 187-188, 198
2 中国联通 📞 130-132, 145, 155-156, 166, 175-176, 185-186, 196
3 中国电信 ☎️ 133, 149, 153, 173-174, 177, 180-181, 189, 191, 199
4 虚拟运营商 📟 170, 171

1.4 号码段分布

序号 号段 运营商 归属地示例
1 138 中国移动 全国各地
2 139 中国移动 全国各地
3 186 中国联通 全国各地
4 189 中国电信 全国各地

1.5 技术栈

技术领域 技术选型 版本要求
开发框架 Flutter >= 3.0.0
编程语言 Dart >= 2.17.0
设计规范 Material Design 3 -
状态管理 setState -
数据存储 内存存储 -
目标平台 鸿蒙OS / Web API 21+

1.6 项目结构

lib/
└── main_phone_location.dart
    ├── PhoneLocationApp              # 应用入口
    ├── Carrier                       # 运营商枚举
    ├── PhoneLocation                 # 号码归属地模型
    ├── PhoneSegment                  # 号码段模型
    ├── QueryRecord                   # 查询记录模型
    ├── PhoneLocationHomePage         # 主页面(底部导航)
    ├── _buildQueryPage               # 查询页面
    ├── _buildHistoryPage             # 历史页面
    ├── _buildSegmentsPage            # 号码段页面
    ├── _buildAboutPage               # 关于页面
    ├── PhoneLocationService          # 查询服务
    ├── PhoneInputField               # 输入框组件
    └── LocationCard                  # 结果卡片组件

二、系统架构

2.1 整体架构图

Data Layer

Business Layer

Presentation Layer

主页面
PhoneLocationHomePage

查询页

历史页

号码段页

关于页

号码输入

查询按钮

结果展示

历史列表

清空记录

号段列表

筛选功能

应用信息

使用说明

查询服务
PhoneLocationService

号码验证器
PhoneValidator

数据解析器
DataParser

PhoneLocation
归属地信息

PhoneSegment
号码段

QueryRecord
查询记录

Carrier
运营商

2.2 类图设计

has

references

references

creates

PhoneLocationApp

+Widget build()

«enumeration»

Carrier

+String label

+String emoji

+List<String> prefixes

+mobile()

+unicom()

+telecom()

+virtual()

PhoneLocation

+String phoneNumber

+String province

+String city

+Carrier carrier

+String areaCode

+String zipCode

+String segment

+bool isValid

PhoneSegment

+String prefix

+Carrier carrier

+String description

+int totalCount

QueryRecord

+String id

+String phoneNumber

+PhoneLocation location

+DateTime queryTime

+bool isFavorite

PhoneLocationService

+PhoneLocation query(String phone)

+bool validate(String phone)

+Carrier getCarrier(String prefix)

+String getProvince(String prefix)

+String getCity(String prefix)

2.3 页面导航流程

查询

历史

号码段

关于

应用启动

查询页

底部导航

输入号码

历史记录

号段列表

应用信息

验证格式

格式正确?

执行查询

提示错误

显示结果

保存记录?

保存到历史

继续查询

查看详情

再次查询

2.4 查询处理流程

数据库 查询服务 验证器 查询页 用户 数据库 查询服务 验证器 查询页 用户 alt [格式正确] [格式错误] 输入手机号 验证格式 返回验证结果 执行查询 查询归属地 返回信息 返回结果 保存记录 显示结果 提示错误

三、核心模块设计

3.1 数据模型设计

3.1.1 运营商枚举 (Carrier)
enum Carrier {
  mobile(
    label: '中国移动',
    emoji: '📱',
    prefixes: ['134', '135', '136', '137', '138', '139', '147', '150', '151', '152', '157', '158', '159', '178', '182', '183', '184', '187', '188', '198'],
  ),
  unicom(
    label: '中国联通',
    emoji: '📞',
    prefixes: ['130', '131', '132', '145', '155', '156', '166', '175', '176', '185', '186', '196'],
  ),
  telecom(
    label: '中国电信',
    emoji: '☎️',
    prefixes: ['133', '149', '153', '173', '174', '177', '180', '181', '189', '191', '199'],
  ),
  virtual(
    label: '虚拟运营商',
    emoji: '📟',
    prefixes: ['170', '171'],
  );

  final String label;
  final String emoji;
  final List<String> prefixes;
}
3.1.2 号码归属地模型 (PhoneLocation)
class PhoneLocation {
  final String phoneNumber;    // 手机号码
  final String province;       // 省份
  final String city;           // 城市
  final Carrier carrier;       // 运营商
  final String areaCode;       // 区号
  final String zipCode;        // 邮编
  final String segment;        // 号码段
  final bool isValid;          // 是否有效
}
3.1.3 号码段模型 (PhoneSegment)
class PhoneSegment {
  final String prefix;         // 号段前缀
  final Carrier carrier;       // 运营商
  final String description;    // 描述
  final int totalCount;        // 号码总数
}
3.1.4 查询记录模型 (QueryRecord)
class QueryRecord {
  final String id;             // 记录ID
  final String phoneNumber;    // 手机号码
  final PhoneLocation location; // 归属地信息
  final DateTime queryTime;    // 查询时间
  final bool isFavorite;       // 是否收藏
}
3.1.5 运营商分布
45% 25% 20% 10% 运营商号码段分布示例 中国移动 中国联通 中国电信 虚拟运营商

3.2 页面结构设计

3.2.1 主页面布局

PhoneLocationHomePage

IndexedStack

查询页

历史页

号码段页

关于页

NavigationBar

查询 Tab

历史 Tab

号码段 Tab

关于 Tab

3.2.2 查询页结构

查询页

SliverAppBar

号码输入区

查询按钮

结果展示区

快捷操作

号码输入框

格式提示

清除按钮

归属地信息

运营商信息

号码段信息

区号邮编

收藏按钮

分享按钮

复制按钮

3.2.3 历史页结构

历史页

SliverAppBar

统计信息

历史列表

清空按钮

查询总数

今日查询

收藏数量

日期分组

记录卡片

删除操作

3.2.4 号码段页结构

号码段页

SliverAppBar

运营商筛选

号码段列表

搜索功能

全部

中国移动

中国联通

中国电信

号段卡片

运营商标识

号码数量

3.3 号码验证逻辑

长度=11

长度≠11

全是数字

包含非数字

有效号段

无效号段

获取输入号码

长度检查

格式检查

返回错误: 长度不正确

号段检查

返回错误: 格式不正确

返回验证通过

返回错误: 无效号段

执行查询

3.4 归属地查询逻辑

提取前3位

匹配运营商

提取前7位

查询归属地数据库

找到记录?

获取省份城市

返回默认值

获取区号邮编

组装结果

返回归属地信息


四、UI设计规范

4.1 配色方案

应用以蓝色为主色调,象征科技与信任:

颜色类型 色值 用途
主色 #2196F3 (Blue) 导航、主题元素
辅助色 #42A5F5 查询页面
第三色 #64B5F6 历史页面
强调色 #90CAF9 号码段页面
背景色 #FAFAFA 页面背景
卡片背景 #FFFFFF 结果卡片

4.2 运营商颜色

运营商 色值 视觉效果
中国移动 #00A0E9 科技蓝
中国联通 #FF6600 活力橙
中国电信 #0085D0 稳重蓝
虚拟运营商 #9C27B0 神秘紫

4.3 字体规范

元素 字号 字重 颜色
页面标题 24px Bold 主色
号码显示 28px Bold #000000
归属地 18px Regular #333333
运营商 16px Medium 运营商色
提示文字 12px Regular #999999

4.4 组件规范

4.4.1 号码输入框
┌─────────────────────────────────────┐
│  输入手机号码                        │
│                                     │
│  ┌─────────────────────────────┐   │
│  │  138 0013 8000          ✕  │   │
│  └─────────────────────────────┘   │
│                                     │
│  请输入11位手机号码                  │
└─────────────────────────────────────┘
4.4.2 查询结果卡片
┌─────────────────────────────────────┐
│  查询结果                            │
│                                     │
│  ┌─────────────────────────────┐   │
│  │  138 0013 8000              │   │
│  │                             │   │
│  │  📍 北京市 北京              │   │
│  │  📱 中国移动                 │   │
│  │  🔢 号段: 138                │   │
│  │  ☎️ 区号: 010               │   │
│  │  📮 邮编: 100000            │   │
│  │                             │   │
│  │  [收藏] [分享] [复制]        │   │
│  └─────────────────────────────┘   │
└─────────────────────────────────────┘
4.4.3 历史记录卡片
┌─────────────────────────────────────┐
│  查询历史                            │
│                                     │
│  📅 今天                            │
│  ┌─────────────────────────────┐   │
│  │ 138****8000                 │   │
│  │ 北京市 北京 | 中国移动        │   │
│  │ 10:30                       │   │
│  └─────────────────────────────┘   │
│                                     │
│  📅 昨天                            │
│  ┌─────────────────────────────┐   │
│  │ 186****1234                 │   │
│  │ 上海市 上海 | 中国联通        │   │
│  │ 15:20                       │   │
│  └─────────────────────────────┘   │
└─────────────────────────────────────┘
4.4.4 号码段列表
┌─────────────────────────────────────┐
│  号码段信息                          │
│                                     │
│  [全部] [移动] [联通] [电信]         │
│                                     │
│  ┌─────────────────────────────┐   │
│  │ 📱 138号段                   │   │
│  │ 中国移动 | 约1000万个号码     │   │
│  └─────────────────────────────┘   │
│                                     │
│  ┌─────────────────────────────┐   │
│  │ 📞 186号段                   │   │
│  │ 中国联通 | 约800万个号码      │   │
│  └─────────────────────────────┘   │
└─────────────────────────────────────┘
4.4.5 运营商筛选
┌─────────────────────────────────────┐
│  选择运营商                          │
│                                     │
│  ┌──────┐ ┌──────┐ ┌──────┐        │
│  │  📱  │ │  📞  │ │  ☎️  │        │
│  │ 移动 │ │ 联通 │ │ 电信 │        │
│  └──────┘ └──────┘ └──────┘        │
│  ┌──────┐                          │
│  │  📟  │                          │
│  │ 虚拟 │                          │
│  └──────┘                          │
└─────────────────────────────────────┘

五、核心功能实现

5.1 号码验证实现

class PhoneValidator {
  static bool validate(String phone) {
    // 验证长度
    if (phone.length != 11) {
      return false;
    }
    
    // 验证是否全为数字
    if (!RegExp(r'^\d{11}$').hasMatch(phone)) {
      return false;
    }
    
    // 验证号段
    final prefix = phone.substring(0, 3);
    return Carrier.values.any((carrier) => 
      carrier.prefixes.contains(prefix)
    );
  }
  
  static String? validateWithMessage(String phone) {
    if (phone.length != 11) {
      return '请输入11位手机号码';
    }
    
    if (!RegExp(r'^\d{11}$').hasMatch(phone)) {
      return '手机号码只能包含数字';
    }
    
    final prefix = phone.substring(0, 3);
    final isValidPrefix = Carrier.values.any((carrier) => 
      carrier.prefixes.contains(prefix)
    );
    
    if (!isValidPrefix) {
      return '无效的手机号码段';
    }
    
    return null;
  }
}

5.2 归属地查询实现

class PhoneLocationService {
  static final Map<String, Map<String, String>> _locationData = {
    '1380013': {'province': '北京', 'city': '北京', 'areaCode': '010', 'zipCode': '100000'},
    '1380014': {'province': '上海', 'city': '上海', 'areaCode': '021', 'zipCode': '200000'},
    '1860001': {'province': '广东', 'city': '广州', 'areaCode': '020', 'zipCode': '510000'},
    // ... 更多号码段数据
  };
  
  static PhoneLocation query(String phone) {
    if (!PhoneValidator.validate(phone)) {
      return PhoneLocation(
        phoneNumber: phone,
        isValid: false,
      );
    }
    
    final prefix = phone.substring(0, 3);
    final segment = phone.substring(0, 7);
    final carrier = _getCarrier(prefix);
    final location = _locationData[segment] ?? {
      'province': '未知',
      'city': '未知',
      'areaCode': '',
      'zipCode': '',
    };
    
    return PhoneLocation(
      phoneNumber: phone,
      province: location['province']!,
      city: location['city']!,
      carrier: carrier,
      areaCode: location['areaCode']!,
      zipCode: location['zipCode']!,
      segment: prefix,
      isValid: true,
    );
  }
  
  static Carrier _getCarrier(String prefix) {
    return Carrier.values.firstWhere(
      (carrier) => carrier.prefixes.contains(prefix),
      orElse: () => Carrier.mobile,
    );
  }
}

5.3 号码格式化实现

class PhoneFormatter {
  static String format(String phone) {
    if (phone.length != 11) {
      return phone;
    }
    
    return '${phone.substring(0, 3)} ${phone.substring(3, 7)} ${phone.substring(7)}';
  }
  
  static String mask(String phone) {
    if (phone.length != 11) {
      return phone;
    }
    
    return '${phone.substring(0, 3)}****${phone.substring(7)}';
  }
  
  static String clean(String phone) {
    return phone.replaceAll(RegExp(r'\D'), '');
  }
}

5.4 历史记录管理实现

class QueryHistoryManager {
  static final List<QueryRecord> _records = [];
  
  static void add(QueryRecord record) {
    // 检查是否已存在
    final existingIndex = _records.indexWhere((r) => r.phoneNumber == record.phoneNumber);
    
    if (existingIndex >= 0) {
      // 更新查询时间
      _records.removeAt(existingIndex);
    }
    
    // 添加到列表开头
    _records.insert(0, record);
    
    // 限制历史记录数量
    if (_records.length > 100) {
      _records.removeLast();
    }
  }
  
  static List<QueryRecord> getAll() {
    return List.from(_records);
  }
  
  static List<QueryRecord> getByDate(DateTime date) {
    return _records.where((record) =>
      record.queryTime.year == date.year &&
      record.queryTime.month == date.month &&
      record.queryTime.day == date.day
    ).toList();
  }
  
  static void clear() {
    _records.clear();
  }
  
  static void toggleFavorite(String id) {
    final index = _records.indexWhere((r) => r.id == id);
    if (index >= 0) {
      final record = _records[index];
      _records[index] = QueryRecord(
        id: record.id,
        phoneNumber: record.phoneNumber,
        location: record.location,
        queryTime: record.queryTime,
        isFavorite: !record.isFavorite,
      );
    }
  }
}

5.5 号码段查询实现

class PhoneSegmentService {
  static List<PhoneSegment> getAllSegments() {
    final segments = <PhoneSegment>[];
    
    for (var carrier in Carrier.values) {
      for (var prefix in carrier.prefixes) {
        segments.add(PhoneSegment(
          prefix: prefix,
          carrier: carrier,
          description: '${carrier.label}$prefix号段',
          totalCount: 10000000, // 每个号段约1000万个号码
        ));
      }
    }
    
    return segments;
  }
  
  static List<PhoneSegment> getSegmentsByCarrier(Carrier carrier) {
    return getAllSegments().where((segment) => segment.carrier == carrier).toList();
  }
  
  static PhoneSegment? getSegment(String prefix) {
    final segments = getAllSegments();
    return segments.firstWhereOrNull((segment) => segment.prefix == prefix);
  }
}

六、交互设计

6.1 查询流程

历史管理 查询服务 验证器 查询页 用户 历史管理 查询服务 验证器 查询页 用户 输入号码 实时验证 返回验证状态 点击查询 完整验证 验证通过 执行查询 返回结果 保存记录 显示结果

6.2 历史记录流程

点击记录

删除记录

清空记录

打开历史页

加载历史记录

有记录?

按日期分组

显示列表

显示空状态

用户操作

显示详情

再次查询

确认删除

更新列表

确认清空

清空所有

6.3 号码段浏览流程

选择运营商

选择全部

输入搜索

清空搜索

点击号段

返回

全部号码段

筛选运营商

搜索号段

查看详情


七、扩展功能规划

7.1 后续版本规划

2024-01-07 2024-01-14 2024-01-21 2024-01-28 2024-02-04 2024-02-11 2024-02-18 2024-02-25 2024-03-03 2024-03-10 2024-03-17 2024-03-24 2024-03-31 基础UI框架 号码查询功能 历史记录功能 号码段数据库 批量查询功能 导出功能 API接口集成 号码标记功能 云端同步 V1.0 基础版本 V1.1 增强版本 V1.2 进阶版本 手机号码归属地查询应用开发计划

7.2 功能扩展建议

7.2.1 API接口集成

API功能:

  • 实时号码信息查询
  • 号码归属地更新
  • 号码状态检测
  • 号码标记查询
7.2.2 批量查询功能

批量功能:

  • 批量号码导入
  • 批量查询处理
  • 结果导出Excel
  • 统计分析报告
7.2.3 号码标记功能

标记功能:

  • 骚扰电话标记
  • 诈骗电话预警
  • 推销电话识别
  • 用户标记共享

八、注意事项

8.1 开发注意事项

  1. 数据准确性:号码段数据需定期更新

  2. 隐私保护:历史记录需脱敏处理

  3. 性能优化:大量历史记录需优化加载

  4. 用户体验:输入框需支持快捷操作

  5. 错误处理:无效号码需友好提示

8.2 常见问题

问题 原因 解决方案
查询结果不准 号段数据过时 更新数据库
历史记录丢失 未持久化 实现数据存储
号码验证错误 正则表达式错 修正验证规则
运营商识别错 号段未更新 添加新号段
查询速度慢 数据库未优化 优化索引

8.3 使用技巧

📱 号码查询技巧 📱

号码输入

  • 支持11位手机号码查询
  • 自动过滤非数字字符
  • 支持粘贴快捷输入
  • 实时格式验证

查询结果

  • 显示完整归属地信息
  • 提供运营商详细信息
  • 包含区号邮编参考
  • 支持一键复制分享

历史管理

  • 自动保存查询记录
  • 支持收藏重要号码
  • 按日期分组显示
  • 支持批量删除

号码段信息

  • 查看各运营商号段
  • 了解号码分布情况
  • 支持运营商筛选
  • 快速定位号段

九、运行说明

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_phone_location.dart --web-port 8141

# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_phone_location.dart

# 代码分析
flutter analyze lib/main_phone_location.dart

十、总结

手机号码归属地查询应用是一款实用工具应用,通过号码查询、历史记录、号码段查询、关于信息四大模块,为用户提供快速、准确的手机号码信息查询服务。应用支持查询手机号码归属地、运营商信息、号码段信息等,让用户轻松了解陌生号码来源。

核心功能涵盖号码查询、历史管理、号码段浏览、号码验证四大模块。号码查询支持11位手机号码查询,显示归属地、运营商、区号邮编等信息;历史管理自动保存查询记录,支持收藏和删除操作;号码段浏览展示各运营商号段分布,支持筛选和搜索;号码验证实时验证号码格式,提供友好的错误提示。

应用采用 Material Design 3 设计规范,以蓝色为主色调,象征科技与信任。通过本应用,希望能够帮助用户快速查询手机号码信息,识别陌生号码来源,提供便捷的号码管理服务。

手机号码归属地查询——快速准确,值得信赖


Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐