import 'dart:convert'; import 'package:flutter/services.dart' show rootBundle; /// 省市区节点(省 → 市 → 区三级树)。 /// /// 对应 `assets/data/MCityPiker/province.json` 结构: /// `{code, name, sub:[{code, name, sub:[{code, name}]}]}`。 class RegionNode { const RegionNode({ required this.code, required this.name, this.sub = const [], }); /// 行政区划代码(省 6 位、市 6 位、区 6 位)。 final String code; /// 行政区划名称(如「北京市」「朝阳区」)。 final String name; /// 下一级子节点(省含市,市含区,区无 sub)。 final List sub; factory RegionNode.fromJson(Map json) { final subRaw = json['sub']; final List children = subRaw is List ? subRaw .whereType>() .map(RegionNode.fromJson) .toList() : const []; return RegionNode( code: json['code']?.toString() ?? '', name: json['name']?.toString() ?? '', sub: children, ); } } /// 省市区数据源。 /// /// 统一由 [RegionData.load] 懒加载 `province.json` 并缓存为 /// `List` 树;组件禁止直接 `rootBundle` 读取,避免重复解析 /// (文件约 284KB)。 class RegionData { RegionData._(); /// 全局单例。 static final RegionData instance = RegionData._(); /// 是否已加载。 bool get isLoaded => _loaded; bool _loaded = false; /// 省级节点树(已缓存)。 List get provinces => List.unmodifiable(_tree); final List _tree = []; /// 省份名称缓存(code → 名称),用于反查。 final Map _nameByCode = {}; /// 懒加载省市区数据。重复调用安全(仅首次解析)。 Future load() async { if (_loaded) return; final raw = await rootBundle .loadString('assets/data/MCityPiker/province.json'); final decoded = jsonDecode(raw); final list = decoded is List ? decoded.whereType>().map(RegionNode.fromJson) : const []; _tree ..clear() ..addAll(list); _buildNameIndex(_tree); _loaded = true; } /// 构建 code → 名称 反查索引(省/市/区全部登记)。 void _buildNameIndex(List nodes) { for (final node in nodes) { if (node.code.isNotEmpty) { _nameByCode[node.code] = node.name; } if (node.sub.isNotEmpty) { _buildNameIndex(node.sub); } } } /// 获取某省下的市级节点;[provinceCode] 为空或不存在时返回空列表。 List citiesOf(String provinceCode) { for (final province in _tree) { if (province.code == provinceCode) return province.sub; } return const []; } /// 获取某市下的区级节点; /// [provinceCode]/[cityCode] 任一为空或不存在时返回空列表。 List districtsOf(String provinceCode, String cityCode) { for (final province in _tree) { if (province.code != provinceCode) continue; for (final city in province.sub) { if (city.code == cityCode) return city.sub; } } return const []; } /// 按 code 反查名称(省/市/区通用)。 String nameOf(String code) => _nameByCode[code] ?? ''; /// 由历历史纯文本地址尽力映射省市区。 /// /// 当前实现:遍历所有省份/城市/区名称,若 [address] 包含该名称, /// 则按「省 → 市 → 区」优先级取最长命中,返回 /// `[provinceCode, cityCode, districtCode]`;匹配不到的维度为空字符串。 /// 由于区名可能重复,此映射仅作尽力回显,无法保证 100% 准确。 List tryMapAddress(String address) { final text = address.trim(); if (text.isEmpty) return const ['', '', '']; String provinceCode = ''; String cityCode = ''; String districtCode = ''; for (final province in _tree) { if (text.contains(province.name)) { provinceCode = province.code; for (final city in province.sub) { if (text.contains(city.name)) { cityCode = city.code; for (final district in city.sub) { if (text.contains(district.name)) { districtCode = district.code; } } } } } } return [provinceCode, cityCode, districtCode]; } }