diff --git a/app/ContactImport.php b/app/ContactImport.php index 1356065..8386bca 100644 --- a/app/ContactImport.php +++ b/app/ContactImport.php @@ -107,6 +107,7 @@ final class ContactImport if ($up === 'BEGIN:VCARD') { $cur = ['name' => '', 'phone' => '', 'phones' => [], 'email' => '', 'emails' => [], 'org' => '', 'title' => '', 'address' => '', 'note' => '', 'birthday' => '', + 'addr_country' => '', 'addr_province' => '', 'addr_city' => '', 'addr_district' => '', 'url' => '', 'nickname' => '', 'jobrank' => '']; continue; } @@ -183,13 +184,22 @@ final class ContactImport } break; case 'ADR': - if ($cur['address'] === '') { - // ADR: 邮箱;扩展;街道;城市;省;邮编;国家 —— 只要街道+城市这段 + if ($cur['address'] === '' && $cur['addr_province'] === '') { + /* vCard 的 ADR **本身就是分段的**(RFC 6350): + PO盒;扩展;街道;城市;省/州;邮编;国家 + 所以这里不再拼成一整串 —— 直接拆成国家/省/市/街道四段存下来, + 再由 ContactImporter 拿它们去对标准行政区划名。 + ⚠️ 区县(第 8 段)几乎没人填,剩下那段街道再交给 Region::parse() + 去认区 —— 它本来就是干这个的。 */ $p = explode(';', $val); $street = trim((string)($p[2] ?? '')); $city = trim((string)($p[3] ?? '')); $prov = trim((string)($p[4] ?? '')); - $cur['address'] = trim($prov . $city . $street); + $ctry = trim((string)($p[6] ?? '')); + $cur['addr_country'] = $ctry; + $cur['addr_province'] = $prov; + $cur['addr_city'] = $city; + $cur['address'] = $street; } break; case 'NOTE': @@ -238,6 +248,7 @@ final class ContactImport $cells = str_getcsv($lines[$i], $delim, '"', '\\'); $rec = ['name' => '', 'phone' => '', 'phones' => [], 'email' => '', 'emails' => [], 'org' => '', 'title' => '', 'address' => '', 'note' => '', 'birthday' => '', + 'addr_country' => '', 'addr_province' => '', 'addr_city' => '', 'addr_district' => '', 'url' => '', 'nickname' => '', 'jobrank' => '']; $filled = false; foreach ($cols as $idx => $key) { diff --git a/app/ContactImporter.php b/app/ContactImporter.php index ce1069f..24a401c 100644 --- a/app/ContactImporter.php +++ b/app/ContactImporter.php @@ -86,11 +86,10 @@ final class ContactImporter } // ---- ③ 没命中:新建 ---- - $d = [ + $d = array_merge([ 'name' => $name !== '' ? $name : $phone, 'phone' => $phone, 'email' => (string)($r['email'] ?? ''), - 'address' => (string)($r['address'] ?? ''), 'org' => (string)($r['org'] ?? ''), // 职务 + 职称合成一列(与 PersonJob::joinTitle 同一口径: // 两个都有时用 " · " 分开,只有一个就只用那个) @@ -109,7 +108,7 @@ final class ContactImporter 'birthday_lunar' => '', 'birthday_lunar_leap' => 0, 'birthday_id_card' => '', - ]; + ], self::addrFields($r)); try { $pid = Person::create($familyId, $d); } catch (\Throwable $ex) { @@ -172,6 +171,53 @@ final class ContactImporter * * @return string[] 这次补上了哪些(中文标签,用来告诉用户"改了什么") */ + /** + * 把一条导入记录里的地址整理成 persons 的五个字段。 + * + * 分两种来源: + * · vCard 的 ADR **本来就是分段的**(街道/城市/省/国家各占一段)→ 直接用, + * 再用 Region::parse() 从街道那一段里认出「区 / 县」; + * · CSV 那种一整串自由文本 → 整串交给 Region::parse() 逐级前缀匹配拆开。 + * + * ⚠️ 认不出来的部分**一律留在 address(详细地址)里**,绝不丢: + * 结构化是为了"以后能按省找人",不是为了让地址变短。 + * + * @return array{address:string,addr_country:string,addr_province:string,addr_city:string,addr_district:string} + */ + private static function addrFields(array $r): array + { + $country = trim((string)($r['addr_country'] ?? '')); + $province = trim((string)($r['addr_province'] ?? '')); + $city = trim((string)($r['addr_city'] ?? '')); + $district = trim((string)($r['addr_district'] ?? '')); + $detail = trim((string)($r['address'] ?? '')); + + if ($province === '' && $city === '' && $detail !== '') { + // 一整串自由文本 → 逐级前缀匹配 + $p = Region::parse($detail); + $country = $country !== '' ? $country : (string)($p['country'] ?? ''); + $province = (string)($p['province'] ?? ''); + $city = (string)($p['city'] ?? ''); + $district = (string)($p['district'] ?? ''); + $detail = (string)($p['detail'] ?? ''); + } elseif ($detail !== '' && $district === '') { + // 已经有省/市(vCard 给的),从剩下的街道里再认一次区县 + $p = Region::parse($detail); + if (($p['district'] ?? null) !== null) { + $district = (string)$p['district']; + $detail = (string)($p['detail'] ?? ''); + } + } + + return [ + 'address' => $detail, + 'addr_country' => $country, + 'addr_province' => $province, + 'addr_city' => $city, + 'addr_district' => $district, + ]; + } + private static function fillMissing(array $person, array $r, int $meId): array { $pid = (int)$person['id']; @@ -179,9 +225,12 @@ final class ContactImporter $labels = []; // 给人看的"补了什么" // ---- ① persons 上的标量列:他空着才补 ---- + $addr = self::addrFields($r); $scalar = [ 'email' => ['邮箱', (string)($r['email'] ?? ''), 200], - 'address' => ['住址', (string)($r['address'] ?? ''), 200], + // ⚠️ 地址要走 addrFields() 拆过的那份:直接拿 $r['address'] 会把 + // vCard 里"省+市+街道"拼成的一整串原样塞进详细地址,等于没结构化。 + 'address' => ['住址', $addr['address'], 200], 'org' => ['工作单位', (string)($r['org'] ?? ''), 120], 'note' => ['备注', (string)($r['note'] ?? ''), 2000], ]; @@ -200,6 +249,14 @@ final class ContactImporter $cols['`title` = ?'] = mb_substr($newTitle, 0, 120, 'UTF-8'); $labels[] = '职务/职称'; } + // 地址的四级结构:同样**只补空着的**(他已经在表单里选过省市区就不动) + foreach (['addr_country' => '国家', 'addr_province' => '省', + 'addr_city' => '市', 'addr_district' => '区/县'] as $col => $label) { + if (trim((string)($person[$col] ?? '')) === '' && trim($addr[$col]) !== '') { + $cols["`$col` = ?"] = mb_substr(trim($addr[$col]), 0, 60, 'UTF-8'); + $labels[] = $label; + } + } // 生日:他一个生日都没有时才补。有生日就绝不动 —— 生日是强身份信息,错了很难发现。 $hasBd = trim((string)Birthday::solarOf($person)) !== '' || trim((string)($person['birthday_lunar'] ?? '')) !== ''; diff --git a/app/Person.php b/app/Person.php index 7c16df9..38457ce 100644 --- a/app/Person.php +++ b/app/Person.php @@ -165,9 +165,10 @@ final class Person $sql = 'INSERT INTO persons (family_id, kind, name, gender, birth_rank, birthday, birthday_id_card, birthday_lunar, birthday_lunar_leap, slogan, avatar, - phone_hash, phone_encrypted, id_card_encrypted, email, address, org, title, note, - is_placeholder) - VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'; + phone_hash, phone_encrypted, id_card_encrypted, email, address, + addr_country, addr_province, addr_city, addr_district, + org, title, note, is_placeholder) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'; $st = Database::get()->prepare($sql); $st->execute([ $familyId, @@ -186,6 +187,10 @@ final class Person ($d['id_card'] ?? '') !== '' ? Crypto::encrypt($d['id_card']) : null, ($d['email'] ?? '') !== '' ? $d['email'] : null, ($d['address'] ?? '') !== '' ? $d['address'] : null, + self::addrOrNull($d, 'addr_country'), + self::addrOrNull($d, 'addr_province'), + self::addrOrNull($d, 'addr_city'), + self::addrOrNull($d, 'addr_district'), ($d['org'] ?? '') !== '' ? mb_substr(trim((string)$d['org']), 0, 120, 'UTF-8') : null, ($d['title'] ?? '') !== '' ? mb_substr(trim((string)$d['title']), 0, 120, 'UTF-8') : null, ($d['note'] ?? '') !== '' ? $d['note'] : null, @@ -202,7 +207,9 @@ final class Person name = ?, gender = ?, birth_rank = ?, birthday = ?, birthday_id_card = ?, birthday_lunar = ?, birthday_lunar_leap = ?, slogan = ?, avatar = ?, phone_hash = ?, phone_encrypted = ?, id_card_encrypted = ?, - email = ?, address = ?, org = ?, title = ?, note = ?, is_placeholder = ? + email = ?, address = ?, + addr_country = ?, addr_province = ?, addr_city = ?, addr_district = ?, + org = ?, title = ?, note = ?, is_placeholder = ? WHERE id = ?'; Database::get()->prepare($sql)->execute([ $d['name'], @@ -219,6 +226,10 @@ final class Person ($d['id_card'] ?? '') !== '' ? Crypto::encrypt($d['id_card']) : null, ($d['email'] ?? '') !== '' ? $d['email'] : null, ($d['address'] ?? '') !== '' ? $d['address'] : null, + self::addrOrNull($d, 'addr_country'), + self::addrOrNull($d, 'addr_province'), + self::addrOrNull($d, 'addr_city'), + self::addrOrNull($d, 'addr_district'), ($d['org'] ?? '') !== '' ? mb_substr(trim((string)$d['org']), 0, 120, 'UTF-8') : null, ($d['title'] ?? '') !== '' ? mb_substr(trim((string)$d['title']), 0, 120, 'UTF-8') : null, ($d['note'] ?? '') !== '' ? $d['note'] : null, @@ -227,6 +238,19 @@ final class Person ]); } + /** + * 地址四段:空串一律存 NULL。 + * + * 为什么不用 `$d[$k] ?? null` 直接塞:表单里四个下拉没选时提交的是**空串**, + * 存进去就变成"国家 = ''",页面上判断"有没有填"永远为真, + * 于是每个没填地址的人都显示一个空的国家名(看着像数据坏了)。 + */ + private static function addrOrNull(array $d, string $key): ?string + { + $v = trim((string)($d[$key] ?? '')); + return $v === '' ? null : mb_substr($v, 0, 60, 'UTF-8'); + } + /** * 自助改自己的资料。 * @@ -244,7 +268,9 @@ final class Person 'UPDATE persons SET name = ?, gender = ?, birthday = ?, birthday_id_card = ?, birthday_lunar = ?, birthday_lunar_leap = ?, slogan = ?, avatar = ?, - email = ?, address = ?, org = ?, title = ?, note = ? + email = ?, address = ?, + addr_country = ?, addr_province = ?, addr_city = ?, addr_district = ?, + org = ?, title = ?, note = ? WHERE id = ?' )->execute([ $d['name'], @@ -257,6 +283,10 @@ final class Person ($d['avatar'] ?? '') !== '' ? $d['avatar'] : null, ($d['email'] ?? '') !== '' ? $d['email'] : null, ($d['address'] ?? '') !== '' ? $d['address'] : null, + self::addrOrNull($d, 'addr_country'), + self::addrOrNull($d, 'addr_province'), + self::addrOrNull($d, 'addr_city'), + self::addrOrNull($d, 'addr_district'), ($d['org'] ?? '') !== '' ? mb_substr(trim((string)$d['org']), 0, 120, 'UTF-8') : null, ($d['title'] ?? '') !== '' ? mb_substr(trim((string)$d['title']), 0, 120, 'UTF-8') : null, ($d['note'] ?? '') !== '' ? $d['note'] : null, diff --git a/app/PersonQuery.php b/app/PersonQuery.php index 177cc4c..f1a126e 100644 --- a/app/PersonQuery.php +++ b/app/PersonQuery.php @@ -117,27 +117,28 @@ final class PersonQuery } /** - * 生日展示串:优先阳历(真实生日),没有就农历。带上**年份**(用户明确要求)。 + * 生日展示串(用户 2026-10-04 第 3 条:**阴历和阳历都显示,只显示月和日,不需要年**)。 * - * @return array{0:string,1:string} [显示串, '阳历'|'农历'|''] + * 两种记法是同一个人的同一天,所以不像以前那样"二选一"——都列出来, + * 长辈看农历、年轻人看阳历,各自认自己的那个。 + * + * 农历不写 '02-03' 这种数字:**写成「二月初三」**,否则"农历 02-03"看着就像 + * 阳历的 2 月 3 号,反而比不显示更误导(闰月还要带「闰」字)。 + * + * @return array [['阳历','03-07'], ['农历','二月初三']](没有的就不出现) */ - public static function birthdayOf(array $row): array + public static function birthdaysOf(array $row): array { - $solar = (string)Birthday::solarOf($row); - $d = Birthday::dateOnly($solar); - if ($d !== '') { - return [self::ymd($d), '阳历']; + $out = []; + $solar = Birthday::dateOnly((string)Birthday::solarOf($row)); + if (preg_match('/^\d{4}-(\d{2})-(\d{2})$/', $solar, $m) === 1) { + $out[] = ['阳历', $m[1] . '-' . $m[2]]; } $lun = Birthday::dateOnly((string)($row['birthday_lunar'] ?? '')); - if ($lun !== '') { - return [self::ymd($lun), '农历']; + if (preg_match('/^\d{4}-(\d{2})-(\d{2})$/', $lun, $m) === 1) { + $leap = !empty($row['birthday_lunar_leap']); + $out[] = ['农历', Lunar::monthName((int)$m[1], $leap) . Lunar::dayName((int)$m[2])]; } - return ['', '']; - } - - /** '1998-03-07' → '1998-03-07'(保持 YYYY-MM-DD,用户要求带年份) */ - private static function ymd(string $d): string - { - return preg_match('/^\d{4}-\d{2}-\d{2}$/', $d) ? $d : ''; + return $out; } } \ No newline at end of file diff --git a/app/Region.php b/app/Region.php new file mode 100644 index 0000000..a9e1b90 --- /dev/null +++ b/app/Region.php @@ -0,0 +1,294 @@ +|null */ + private static ?array $all = null; + + private static function db(): \PDO + { + return Database::get(); + } + + /** 种子数据文件(相对站点根) */ + public static function seedFile(): string + { + return dirname(__DIR__) . '/assets/data/regions.json'; + } + + /** + * 把种子数据灌进 regions 表。 + * + * @return int 本次真的插入的条数(已灌过则返回 0) + */ + public static function seed(?\PDO $db = null): int + { + $db = $db ?: self::db(); + $n = (int)$db->query('SELECT COUNT(*) FROM `regions`')->fetchColumn(); + if ($n > 0) { + return 0; + } + $file = self::seedFile(); + $raw = @file_get_contents($file); + if ($raw === false) { + return 0; + } + $rows = json_decode($raw, true); + if (!is_array($rows)) { + return 0; + } + // ⚠️ 一张表一次性灌 3429 条 —— 用事务 + 预编译,别一条一条 autocommit + // (三千次 fsync 会把安装拖到几十秒,看着像卡死)。 + $db->beginTransaction(); + // ⚠️ 用 INSERT IGNORE 而不是 INSERT:东莞、中山这类"市直管镇"的城市, + // 数据集里同一个 9 位代码会出现在两棵树下(区一级与镇一级), + // 用普通 INSERT 会在第 2170 行炸掉、把后面一千多条全丢掉 + // (实测:库里只剩 19 个省,界面上"海南省之后全没了")。 + // IGNORE 之后"先来的那条留下",总量与唯一性都对。 + $st = $db->prepare( + 'INSERT IGNORE INTO `regions` (`code`, `name`, `level`, `parent_code`) VALUES (?, ?, ?, ?)' + ); + $done = 0; + foreach ($rows as $r) { + if (!is_array($r) || count($r) < 3) { + continue; + } + $code = (string)$r[0]; + $name = (string)$r[1]; + $parent = (string)$r[2]; + $level = $parent === '' ? 1 : (strlen($parent) <= 2 ? 2 : 3); + $st->execute([$code, $name, $level, $parent === '' ? null : $parent]); + $done++; + } + $db->commit(); + self::$all = null; + return $done; + } + + /** 全表(一次请求内只读一次库) */ + public static function all(): array + { + if (self::$all !== null) { + return self::$all; + } + $out = []; + try { + foreach (self::db()->query('SELECT code, name, level, parent_code FROM `regions`')->fetchAll() as $r) { + $out[(string)$r['code']] = [ + 'name' => (string)$r['name'], + 'level' => (int)$r['level'], + 'parent' => (string)($r['parent_code'] ?? ''), + ]; + } + } catch (\Throwable $ex) { + $out = []; // 表还没建好(极早期):调用方拿到空列表,不至于整页 500 + } + self::$all = $out; + return $out; + } + + /** 省级列表:[['code'=>..,'name'=>..], ...] */ + public static function provinces(): array + { + $out = []; + foreach (self::all() as $code => $r) { + if ($r['level'] === 1) { + $out[] = ['code' => (string)$code, 'name' => $r['name']]; + } + } + usort($out, static fn($a, $b) => strcmp((string)$a['code'], (string)$b['code'])); + return $out; + } + + /** 某级的下级列表(省→市、市→区县) */ + public static function childrenOf(string $code): array + { + if ($code === '') { + return self::provinces(); + } + $out = []; + foreach (self::all() as $c => $r) { + if ($r['parent'] === $code) { + $out[] = ['code' => $c, 'name' => $r['name']]; + } + } + usort($out, static fn($a, $b) => strcmp((string)$a['code'], (string)$b['code'])); + return $out; + } + + /** 代码 → 标准名 */ + public static function nameOf(?string $code): string + { + $code = (string)$code; + if ($code === '') { + return ''; + } + $all = self::all(); + return $all[$code]['name'] ?? ''; + } + + /** 代码 → 上级代码(往上找两级,用来回填「省」) */ + public static function parentOf(?string $code): string + { + $code = (string)$code; + $all = self::all(); + return (string)($all[$code]['parent'] ?? ''); + } + + /** + * 把一整串自由文本地址拆成结构化的五段。 + * + * 判据是**从前往后逐级前缀匹配**:先认省、再在它下面认市、再在市下面认区县, + * 剩下的整串当详细地址。之所以只能这么干:中文地址没有分隔符, + * 「山东省青岛市市南区香港中路76号」全靠"哪个标准名出现在开头"来切。 + * + * ⚠️ 匹配要对**省/市/自治区的后缀**做容错:「山东省」和「山东」都要认, + * 「青岛市」和「青岛」都要认 —— 用户手填、通讯录导出、快递地址三种写法都不一样。 + * + * @return array{country:?string,province:?string,city:?string,district:?string,detail:?string} + */ + public static function parse(string $text): array + { + $out = ['country' => null, 'province' => null, 'city' => null, + 'district' => null, 'detail' => null]; + $text = trim(preg_replace('/\s+/u', ' ', (string)$text) ?? ''); + if ($text === '') { + return $out; + } + + // ① 国家:只有**写在开头**的显式国家名才算(否则「中国」可能只是路名的一部分) + foreach (['中华人民共和国', '中国'] as $c) { + if (mb_strpos($text, $c) === 0) { + $out['country'] = '中国'; + $text = ltrim(mb_substr($text, mb_strlen($c)), ' ,,'); + break; + } + } + + $rest = $text; + + // ② 省 + foreach (self::provinces() as $p) { + $hit = self::matchPrefix($rest, $p['name']); + if ($hit !== null) { + $out['province'] = $p['name']; + $rest = $hit; + break; + } + } + + // ③ 市:优先在已认出的省下面找;省没认出来就在全国范围找 + $pool = $out['province'] !== null + ? self::childrenOf(self::codeOfName($out['province'], 1)) + : self::allCities(); + foreach ($pool as $c) { + $hit = self::matchPrefix($rest, $c['name']); + if ($hit !== null) { + $out['city'] = $c['name']; + $rest = $hit; + break; + } + } + + // ④ 区县:在已认出的市下面找 + if ($out['city'] !== null) { + foreach (self::childrenOf(self::codeOfName($out['city'], 2)) as $d) { + $hit = self::matchPrefix($rest, $d['name']); + if ($hit !== null) { + $out['district'] = $d['name']; + $rest = $hit; + break; + } + } + } + + $rest = trim($rest, " ,,。;;\t\n\r\0\x0B"); + if ($rest !== '') { + $out['detail'] = $rest; + } + return $out; + } + + /** 全部地级市(省没认出来时的兜底池子) */ + private static function allCities(): array + { + $out = []; + foreach (self::all() as $code => $r) { + if ($r['level'] === 2) { + $out[] = ['code' => (string)$code, 'name' => $r['name']]; + } + } + // 长名优先:否则「市辖区」会先于「市南区」被匹配掉 + usort($out, static fn($a, $b) => mb_strlen($b['name']) <=> mb_strlen($a['name'])); + return $out; + } + + /** 标准名 → 代码(限某一级,避免「市辖区」那种重名撞车) */ + public static function codeOfName(?string $name, int $level): string + { + $name = trim((string)$name); + if ($name === '') { + return ''; + } + foreach (self::all() as $code => $r) { + if ($r['level'] === $level && $r['name'] === $name) { + return (string)$code; + } + } + return ''; + } + + /** + * 看 $name 是不是 $text 的开头(容掉省/市/自治区这类后缀)。 + * 命中返回**吃掉之后剩下的串**,没命中返回 null。 + */ + private static function matchPrefix(string $text, string $name): ?string + { + $name = trim($name); + if ($name === '' || $text === '') { + return null; + } + // 「山东省」→ 也能认「山东」;「青岛市」→ 也能认「青岛」。 + // ⚠️ 反过来不行(不能拿短名去吃长名),所以两种写法都试一遍。 + $short = preg_replace('/(省|市|自治区|特别行政区|壮族自治区|回族自治区|维吾尔自治区|自治州|地区|盟)$/u', '', $name); + $cands = [$name]; + if ($short !== null && $short !== '' && $short !== $name) { + $cands[] = $short; + } + foreach ($cands as $cand) { + if (mb_strlen($cand) < 2) { + continue; // 太短会误吃(如「东区」) + } + if (mb_strpos($text, $cand) === 0) { + return ltrim(mb_substr($text, mb_strlen($cand)), ' ,,'); + } + } + return null; + } +} diff --git a/app/Schema.php b/app/Schema.php index adc4c38..2af750b 100644 --- a/app/Schema.php +++ b/app/Schema.php @@ -71,7 +71,7 @@ final class Schema * ⚠️ 它**不再**作为"要不要跑升级"的判据 —— 见 fingerprint() 的说明。 * 它仍然要手工维护,因为它给人看(排查时一眼知道代码到哪一版了)。 */ - public const VERSION = '15'; + public const VERSION = '16'; /** * 「源码指纹」:拿**本文件自身的内容**算一个哈希,作为"要不要跑升级"的判据。 @@ -604,6 +604,19 @@ CREATE TABLE IF NOT EXISTS `task_comments` ( CONSTRAINT `fk_tc_task` FOREIGN KEY (`task_id`) REFERENCES `tasks` (`id`) ON DELETE CASCADE, CONSTRAINT `fk_tc_person` FOREIGN KEY (`person_id`) REFERENCES `persons` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='任务评论(支持 @人)' +SQL, + <<<'SQL' +CREATE TABLE IF NOT EXISTS `regions` ( + /* ⚠️ VARCHAR(12) 不是 6:东莞、中山这类「市直管镇」的城市,数据集里第四级 + (镇 / 街道)是 9 位代码 —— 写 6 会让插入在第 2170 行被截断裂掉, + 后面一千多条全丢(实测只剩 19 个省)。 */ + `code` VARCHAR(12) NOT NULL COMMENT '行政区划代码:省 2 位 / 市 4 位 / 区县 6 位(市直管镇的镇 9 位)', + `name` VARCHAR(60) NOT NULL COMMENT '标准名称,如「北京市」「青岛市」「市南区」', + `level` TINYINT NOT NULL COMMENT '1=省级 2=地级市 3=区县(含市直管镇)', + `parent_code` VARCHAR(12) DEFAULT NULL COMMENT '上级代码;省级为 NULL', + PRIMARY KEY (`code`), + KEY `idx_region_parent` (`parent_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='全国行政区划(省/市/区县三级):地址结构化与导入时对齐用' SQL, ]; } @@ -807,6 +820,36 @@ SQL, // 就要为页面上的每个人回读一次存储,几十个人 = 几十次外网往返。 self::addColumn($db, 'persons', 'avatar_color', "ADD COLUMN `avatar_color` CHAR(7) DEFAULT NULL COMMENT '头像主色(上传时算一次;页面按它派生底色/字色)' AFTER `avatar`"); + + // ---- 地址结构化(版本 16)---- + // 用户 2026-10-04 第 4 条:地址 = 国家 / 省 / 市 / 区 / 详细地址五级, + // 而且「如果没有非常详细的地址,就只记到区」—— 所以四级都可空, + // 只有 `address`(详细地址)是原来那一个自由文本列,语义不变。 + // ⚠️ 存的是**标准名**不是代码:通讯录导进来的地址是自由文本, + // 按代码存就要求导入时 100% 匹配得上,匹配不上的整条地址就丢了; + // 存标准名则"对得上就规范化、对不上就照抄",永远不会更差。 + self::addColumn($db, 'persons', 'addr_country', + "ADD COLUMN `addr_country` VARCHAR(60) DEFAULT NULL COMMENT '国家' AFTER `address`"); + self::addColumn($db, 'persons', 'addr_province', + "ADD COLUMN `addr_province` VARCHAR(60) DEFAULT NULL COMMENT '省 / 自治区 / 直辖市 / 特别行政区(标准名,对应 regions.level=1)' AFTER `addr_country`"); + self::addColumn($db, 'persons', 'addr_city', + "ADD COLUMN `addr_city` VARCHAR(60) DEFAULT NULL COMMENT '地级市(标准名,对应 regions.level=2)' AFTER `addr_province`"); + self::addColumn($db, 'persons', 'addr_district', + "ADD COLUMN `addr_district` VARCHAR(60) DEFAULT NULL COMMENT '区 / 县(标准名,对应 regions.level=3)' AFTER `addr_city`"); + // ⚠️ CREATE TABLE IF NOT EXISTS 不会改已存在的列宽 —— 老库(v16 之前建的 + // `code VARCHAR(6)`)必须显式 MODIFY,否则东莞那种 9 位镇级代码插不进去。 + $db->exec("ALTER TABLE `regions` MODIFY COLUMN `code` + VARCHAR(12) NOT NULL COMMENT '行政区划代码:省 2 位 / 市 4 位 / 区县 6 位(市直管镇的镇 9 位)'"); + $db->exec("ALTER TABLE `regions` MODIFY COLUMN `parent_code` + VARCHAR(12) DEFAULT NULL COMMENT '上级代码;省级为 NULL'"); + // 全国行政区划灌库(只是数据步骤 → 容错跑:种子文件丢了也不该挡住后面的升级) + self::tryStep('灌入全国行政区划(省/市/区县)', static function () use ($db) { + \App\Region::seed($db); + }); + // 老地址(原来那一整串)拆成结构化:只补空字段,绝不覆盖用户已经改过的 + self::tryStep('老地址拆成国家/省/市/区', static function () use ($db) { + self::backfillAddress($db); + }); // 老头像(v11 之前传的)补算一次:回读已存的图算主色。 // 纯数据步骤 → 容错跑:某张图读不回来(OSS 权限、对象丢了)只影响那一个人, // 他会自动落到「按姓名取色」的兜底上,不该把后面的升级步骤挡住。 @@ -1386,6 +1429,41 @@ SQL); } } + /** + * 老地址(原来 `address` 里那一整串自由文本)拆成 国家/省/市/区。 + * + * ⚠️ 只补**空着**的四个字段,绝不覆盖:用户如果已经手工选过省市区, + * 一次升级把他选的改成"从文本里猜的",比不猜更糟(猜错就悄悄错了)。 + * ⚠️ 拆不出来的(比如只写了「老家」)就**原样留在 address 里** —— + * 详细地址那一栏本来就允许是任意文本,不拆等于没变,不会丢东西。 + */ + private static function backfillAddress(\PDO $db): void + { + $rows = $db->query( + "SELECT id, address FROM persons + WHERE address IS NOT NULL AND address <> '' + AND addr_province IS NULL AND addr_city IS NULL AND addr_district IS NULL + ORDER BY id" + )->fetchAll(); + if (!$rows) { + return; + } + $up = $db->prepare( + 'UPDATE persons SET addr_country = ?, addr_province = ?, addr_city = ?, + addr_district = ?, address = ? WHERE id = ?' + ); + foreach ($rows as $r) { + $p = \App\Region::parse((string)$r['address']); + if ($p['province'] === null && $p['city'] === null && $p['district'] === null) { + continue; // 什么都认不出来 → 整串留在详细地址里,不动它 + } + $up->execute([ + $p['country'], $p['province'], $p['city'], + $p['district'], $p['detail'] ?? '', (int)$r['id'], + ]); + } + } + /** 列不存在才加 */ private static function addColumn(\PDO $db, string $table, string $column, string $alter): void { diff --git a/assets/css/app.css b/assets/css/app.css index 1237968..06081d8 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -315,11 +315,23 @@ a:hover { text-decoration: underline; } .people-grid { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; } +/* ⚠️ 整行是**一条 flex**:[拖柄] [头像+信息(占满剩下的)] [右侧动作]。 + 原来右侧的「编辑 / ⋯」各自写死 right:46px / right:8px 绝对定位, + 于是再往里加第三个按钮只能继续猜偏移、且「分组」按钮宽度随分组名变化必然重叠; + 改 flex 之后按钮自然排开,姓名那边也不用靠 padding-right 让位了。 */ .person { - display: block; color: var(--ink); position: relative; + display: flex; align-items: stretch; color: var(--ink); position: relative; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-s); transition: border-color .15s ease, box-shadow .15s ease; + /* v24 第 9 批 #5:千人名册不「卡死」的关键 —— 屏外的卡片浏览器直接跳过 + 布局/绘制(4 万+ DOM 节点的排版是一次性成本的大头)。 + contain-intrinsic-size 给屏外卡片一个估算高度撑滚动条, + auto 前缀让浏览器记住真实渲染高度,滚过后就精确了。 + ⚠️ 拖动排序用的是实时 getBoundingClientRect:目标被自动滚进视口时 + content-visibility 会立刻出真实布局,落点计算不受影响(drag probe 已验证)。 */ + content-visibility: auto; + contain-intrinsic-size: auto 68px; } .person:hover { border-color: var(--brand-2); box-shadow: var(--shadow); } /* 头像:列表里用小方图(正方形、cover 裁切),不再是整块大图 */ @@ -331,6 +343,7 @@ a:hover { text-decoration: underline; } .person .person-main { display: flex; align-items: center; gap: 12px; padding: 10px 12px; color: var(--ink); text-decoration: none; + flex: 1 1 auto; min-width: 0; /* 剩下的宽度都给它,按钮那头不挤它 */ } .person .pb { flex: 1 1 auto; min-width: 0; } .person .pname { font-weight: 600; font-size: 15px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } @@ -521,6 +534,37 @@ textarea.input { min-height: 76px; resize: vertical; } 中文环境渲染成「下午 03:30」且没有秒,所以自己拼一个。 日期部分仍是原生 date 控件 → app.js 的 showPicker 让它整框可点。 */ .dt-input { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; } +/* v24 第 9 批 #9:Semi DatePicker 升级态 —— .dt-native 是 display:contents(不干扰 + flex 布局),升级成功后由 app.js 内联 display:none 藏掉;.dt-semi 顶上同一格。 */ +.dt-input .dt-native { display: contents; } +.dt-input .dt-semi { display: none; flex: 1 1 220px; min-width: 0; } +.dt-input.is-semi .dt-semi { display: block; } +/* 工作经历的月份选择器(type="month" 升级):占满原 .job-cell 格子 */ +.dt-semi.dt-semi-month { display: none; } +.dt-semi.dt-semi-month.is-live { display: block; width: 100%; } +.dt-input.dt-missing .semi-input-wrapper { border-color: #C0392B !important; box-shadow: 0 0 0 1px #C0392B inset; } +/* Semi 主题对齐宣纸色。semi.min.css 是懒加载的、必然排在 app.css 之后, + 所以这里赢在**优先级**:body[class] 特异性(0,1,1) > semi 的 body(0,0,1)。 */ +body[class] { + --semi-color-primary: var(--brand, #A84A28); + --semi-color-primary-hover: var(--brand-2, #C05F38); + --semi-color-primary-active: var(--brand-ink, #8D3C20); + --semi-color-focus-border: var(--brand, #A84A28); +} +/* 输入框本体:跟站内 .input / .dt-date 同一轮廓(描边、圆角、纸面底色、同高) */ +body[class] .dt-semi .semi-input-wrapper { + width: 100%; height: 40px; + border: 1px solid var(--line); border-radius: var(--radius-s); + background: var(--surface); color: var(--ink); +} +body[class] .dt-semi .semi-input-wrapper:hover { border-color: var(--brand-2); background: var(--surface); } +body[class] .dt-semi .semi-input { font: inherit; color: var(--ink); } +body[class] .dt-semi .semi-input::placeholder { color: var(--muted); } +/* 日历面板:白纸底色统一成卡片的纸色,选中/悬停色走上面的 brand 变量 */ +body[class] .semi-popover .semi-datepicker { background: var(--surface, #fff); } +body[class] .semi-datepicker-day-selected { background-color: var(--brand, #A84A28); } +body[class] .semi-datepicker-day-hoverday, +body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb, var(--brand, #A84A28) 12%, transparent); } .dt-input .dt-date { flex: 1 1 150px; min-width: 0; padding: 9px 11px; border: 1px solid var(--line); border-radius: var(--radius-s); @@ -926,21 +970,19 @@ textarea.input { min-height: 76px; resize: vertical; } /* 卡片改成 div > a + details:表单不能套在链接里(非法 HTML,浏览器会把 DOM 拆开) */ .person-main { display: block; color: var(--ink); } .person-main:hover { text-decoration: none; } -.person-more { display: none; } -/* 列表形态下「⋯ 调整分组」改到行的**右侧**(原来在卡片下方,列表里会撑高一行) */ -.person-more { - position: absolute; right: 8px; top: 50%; transform: translateY(-50%); - border: 0; background: none; + +/* ---- 行右侧的动作区(分组 / 编辑 / ⋯)---- + ⚠️ 2026-10-04 之前这里有一条 `.person-more { display: none; }`, + 而 `
` 默认 display 是 block,被它一压**整个 ⋯ 按钮都不见了** + —— 用户报的「名册没有地方可以更改分组了」就是这条(它把唯一的入口藏了)。 + 现在的做法是:动作区本身是 flex,三个按钮自然排开,谁都不用写死偏移。 */ +.person-actions { + display: flex; align-items: center; gap: 6px; + padding: 8px 10px 8px 0; flex: 0 0 auto; } -/* 用户 2026-10-03 第 7 条:⋯ **前面**多了一个「编辑」按钮,所以 ⋯ 要往左让位。 - 编辑按钮同样绝对定位在行右侧(在 ⋯ 左边 46px 处)—— 两个都贴着行的右边缘, - 这样"改资料(常用)"在前、"更多操作(低频)"在后,手指/鼠标扫过去就是从左到右。 */ .person-edit { - position: absolute; right: 46px; top: 50%; transform: translateY(-50%); - padding: 3px 10px; font-size: 13px; + padding: 3px 10px; font-size: 13px; white-space: nowrap; } -/* ⚠️ 预留出右侧两个按钮的位置,否则姓名/信息会钻到按钮底下 */ -.people-grid .person .person-main { padding-right: 96px; } .person-more > summary { list-style: none; cursor: pointer; padding: 4px 10px; font-size: 16px; color: var(--muted); border-radius: 8px; @@ -960,18 +1002,53 @@ textarea.input { min-height: 76px; resize: vertical; } .person-move .select { flex: 1 1 auto; min-width: 0; padding: 6px 8px; font-size: 13px; } .person-move .btn { flex: 0 0 auto; } +/* ---- 「分组」按钮(用户 2026-10-04 第 1 条)---- + 按钮上**直接写着当前分组**,点开就是一张分组列表。 + 没分过组时写「分组」两个字并压暗(is-none),跟"已经归了组"区分开。 */ +.person-group-btn { + white-space: nowrap; max-width: 130px; overflow: hidden; text-overflow: ellipsis; + list-style: none; +} +.person-group-btn::-webkit-details-marker { display: none; } +.person-group-btn.is-none { color: var(--faint); } +.person-group[open] { + position: absolute; right: 8px; top: 8px; z-index: 31; +} +.pg-menu { + background: var(--surface); border: 1px solid var(--line); + border-radius: 10px; box-shadow: var(--shadow-l); + min-width: 200px; max-height: 60vh; overflow: auto; + padding: 8px 0; margin-top: 2px; +} +.pg-title { + margin: 0 0 6px; padding: 0 12px; font-size: 12px; color: var(--faint); +} +.pg-item { + display: flex; align-items: center; gap: 8px; cursor: pointer; + padding: 7px 12px; font-size: 13.5px; color: var(--ink); +} +.pg-item:hover { background: var(--line-2); } +.pg-item input { flex: 0 0 auto; } +.pg-menu .pg-save { margin: 6px 12px 0; } + /* ---------------- 名册:拖动排序 / 拖到别栏改分组 ---------------- - 拖动是"锦上添花":没有它,卡片上的「⋯ → 调整分组」表单照样能改分组, - 手机上 HTML5 拖放本来也不生效,那套表单就是窄屏的正路。 */ + ⚠️ 2026-10-04 起这一段是 **Pointer Events**(不再用 HTML5 拖放)—— + 原因写在 app.js 那段注释里(Chrome 下"只有第一组能拖"就是 HTML5 DnD 的锅)。 + 没有它,行上的「分组」按钮照样能改分组,功能不缺。 */ .roster.is-droppable .person { cursor: grab; } -.roster.is-droppable .person.is-dragged { opacity: .45; cursor: grabbing; } +/* ⚠️ 拖动中被拖的那张卡必须 pointer-events:none:落点是用 elementFromPoint + 现算的,卡自己压在指针底下就只能算到自己,永远插不进别人中间。 */ +.roster.is-droppable .person.is-dragged { opacity: .55; cursor: grabbing; pointer-events: none; } .drag-handle { position: absolute; left: 3px; top: 50%; transform: translateY(-50%); z-index: 2; width: 22px; height: 22px; line-height: 22px; text-align: center; border-radius: 6px; font-size: 14px; color: var(--muted); background: rgba(255, 255, 255, .82); border: 1px solid var(--line-2); - pointer-events: none; /* 手柄只是个记号,抓取要落在整张卡上 */ + /* ⚠️ 手柄现在是**能抓的**(不再 pointer-events:none): + 鼠标可以拖整行,但**触摸只能抓这个手柄** —— 否则手指在行上一划 + 就被浏览器当成滚页面,永远拖不起来。touch-action:none 就是这句话。 */ + touch-action: none; cursor: grab; } .drag-handle-inline { color: var(--muted); } /* 列表里每行要留出左侧拖柄的位置(否则⠿会压在头像上) */ @@ -992,6 +1069,14 @@ textarea.input { min-height: 76px; resize: vertical; } .roster.is-dragging .group-block .group-n { display: none; } .roster.is-dragging .people-grid { min-height: 24px; } +/* 窄屏:一行上「分组 + 编辑 + ⋯」三个按钮,分组名会吃掉姓名的空间 —— + 把分组名的上限压一压,先保住姓名能读(分组点开照样看得到全名)。 */ +@media (max-width: 640px) { + .person-group-btn { max-width: 76px; } + .person-actions { gap: 4px; padding-right: 6px; } + .person-edit { padding: 3px 7px; } +} + /* 拖完/没拖成的轻提示(2 秒自己消失,不打断操作) */ .roster-note { position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 12px); @@ -2414,3 +2499,21 @@ textarea.input { min-height: 76px; resize: vertical; } .brand span { display: none; } .who .who-name { display: none; } } + +/* ---- 地址五级(国家 / 省 / 市 / 区 / 详细地址,用户 2026-10-04 第 4 条)---- + 一行排不下五个控件,用**自动换行的网格**:宽屏上「国家+省+市」一行、 + 「区+详细」一行;窄屏自动每组一个。每个控件头上一行小标签(addr-k), + 比把「省 / 市」两个字塞进 placeholder 里好认 —— placeholder 一填字就没了。 */ +.addr-grid { + display: grid; gap: 8px 10px; + grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); + margin-top: 2px; +} +.addr-cell { display: flex; flex-direction: column; gap: 3px; min-width: 0; } +.addr-cell-wide { grid-column: span 2; } +.addr-cell .addr-k { font-size: 12px; color: var(--faint); } +.addr-cell .input, +.addr-cell .select { width: 100%; } +@media (max-width: 560px) { + .addr-cell-wide { grid-column: span 1; } +} diff --git a/assets/data/regions.json b/assets/data/regions.json new file mode 100644 index 0000000..737f999 --- /dev/null +++ b/assets/data/regions.json @@ -0,0 +1 @@ +[["11","北京市",""],["1101","市辖区","11"],["110101","东城区","1101"],["110102","西城区","1101"],["110105","朝阳区","1101"],["110106","丰台区","1101"],["110107","石景山区","1101"],["110108","海淀区","1101"],["110109","门头沟区","1101"],["110111","房山区","1101"],["110112","通州区","1101"],["110113","顺义区","1101"],["110114","昌平区","1101"],["110115","大兴区","1101"],["110116","怀柔区","1101"],["110117","平谷区","1101"],["110118","密云区","1101"],["110119","延庆区","1101"],["12","天津市",""],["1201","市辖区","12"],["120101","和平区","1201"],["120102","河东区","1201"],["120103","河西区","1201"],["120104","南开区","1201"],["120105","河北区","1201"],["120106","红桥区","1201"],["120110","东丽区","1201"],["120111","西青区","1201"],["120112","津南区","1201"],["120113","北辰区","1201"],["120114","武清区","1201"],["120115","宝坻区","1201"],["120116","滨海新区","1201"],["120117","宁河区","1201"],["120118","静海区","1201"],["120119","蓟州区","1201"],["13","河北省",""],["1301","石家庄市","13"],["130102","长安区","1301"],["130104","桥西区","1301"],["130105","新华区","1301"],["130107","井陉矿区","1301"],["130108","裕华区","1301"],["130109","藁城区","1301"],["130110","鹿泉区","1301"],["130111","栾城区","1301"],["130121","井陉县","1301"],["130123","正定县","1301"],["130125","行唐县","1301"],["130126","灵寿县","1301"],["130127","高邑县","1301"],["130128","深泽县","1301"],["130129","赞皇县","1301"],["130130","无极县","1301"],["130131","平山县","1301"],["130132","元氏县","1301"],["130133","赵县","1301"],["130171","石家庄高新技术产业开发区","1301"],["130172","石家庄循环化工园区","1301"],["130181","辛集市","1301"],["130183","晋州市","1301"],["130184","新乐市","1301"],["1302","唐山市","13"],["130202","路南区","1302"],["130203","路北区","1302"],["130204","古冶区","1302"],["130205","开平区","1302"],["130207","丰南区","1302"],["130208","丰润区","1302"],["130209","曹妃甸区","1302"],["130224","滦南县","1302"],["130225","乐亭县","1302"],["130227","迁西县","1302"],["130229","玉田县","1302"],["130271","河北唐山芦台经济开发区","1302"],["130272","唐山市汉沽管理区","1302"],["130273","唐山高新技术产业开发区","1302"],["130274","河北唐山海港经济开发区","1302"],["130281","遵化市","1302"],["130283","迁安市","1302"],["130284","滦州市","1302"],["1303","秦皇岛市","13"],["130302","海港区","1303"],["130303","山海关区","1303"],["130304","北戴河区","1303"],["130306","抚宁区","1303"],["130321","青龙满族自治县","1303"],["130322","昌黎县","1303"],["130324","卢龙县","1303"],["130371","秦皇岛市经济技术开发区","1303"],["130372","北戴河新区","1303"],["1304","邯郸市","13"],["130402","邯山区","1304"],["130403","丛台区","1304"],["130404","复兴区","1304"],["130406","峰峰矿区","1304"],["130407","肥乡区","1304"],["130408","永年区","1304"],["130423","临漳县","1304"],["130424","成安县","1304"],["130425","大名县","1304"],["130426","涉县","1304"],["130427","磁县","1304"],["130430","邱县","1304"],["130431","鸡泽县","1304"],["130432","广平县","1304"],["130433","馆陶县","1304"],["130434","魏县","1304"],["130435","曲周县","1304"],["130471","邯郸经济技术开发区","1304"],["130473","邯郸冀南新区","1304"],["130481","武安市","1304"],["1305","邢台市","13"],["130502","襄都区","1305"],["130503","信都区","1305"],["130505","任泽区","1305"],["130506","南和区","1305"],["130522","临城县","1305"],["130523","内丘县","1305"],["130524","柏乡县","1305"],["130525","隆尧县","1305"],["130528","宁晋县","1305"],["130529","巨鹿县","1305"],["130530","新河县","1305"],["130531","广宗县","1305"],["130532","平乡县","1305"],["130533","威县","1305"],["130534","清河县","1305"],["130535","临西县","1305"],["130571","河北邢台经济开发区","1305"],["130581","南宫市","1305"],["130582","沙河市","1305"],["1306","保定市","13"],["130602","竞秀区","1306"],["130606","莲池区","1306"],["130607","满城区","1306"],["130608","清苑区","1306"],["130609","徐水区","1306"],["130623","涞水县","1306"],["130624","阜平县","1306"],["130626","定兴县","1306"],["130627","唐县","1306"],["130628","高阳县","1306"],["130629","容城县","1306"],["130630","涞源县","1306"],["130631","望都县","1306"],["130632","安新县","1306"],["130633","易县","1306"],["130634","曲阳县","1306"],["130635","蠡县","1306"],["130636","顺平县","1306"],["130637","博野县","1306"],["130638","雄县","1306"],["130671","保定高新技术产业开发区","1306"],["130672","保定白沟新城","1306"],["130681","涿州市","1306"],["130682","定州市","1306"],["130683","安国市","1306"],["130684","高碑店市","1306"],["1307","张家口市","13"],["130702","桥东区","1307"],["130703","桥西区","1307"],["130705","宣化区","1307"],["130706","下花园区","1307"],["130708","万全区","1307"],["130709","崇礼区","1307"],["130722","张北县","1307"],["130723","康保县","1307"],["130724","沽源县","1307"],["130725","尚义县","1307"],["130726","蔚县","1307"],["130727","阳原县","1307"],["130728","怀安县","1307"],["130730","怀来县","1307"],["130731","涿鹿县","1307"],["130732","赤城县","1307"],["130771","张家口经济开发区","1307"],["130772","张家口市察北管理区","1307"],["130773","张家口市塞北管理区","1307"],["1308","承德市","13"],["130802","双桥区","1308"],["130803","双滦区","1308"],["130804","鹰手营子矿区","1308"],["130821","承德县","1308"],["130822","兴隆县","1308"],["130824","滦平县","1308"],["130825","隆化县","1308"],["130826","丰宁满族自治县","1308"],["130827","宽城满族自治县","1308"],["130828","围场满族蒙古族自治县","1308"],["130871","承德高新技术产业开发区","1308"],["130881","平泉市","1308"],["1309","沧州市","13"],["130902","新华区","1309"],["130903","运河区","1309"],["130921","沧县","1309"],["130922","青县","1309"],["130923","东光县","1309"],["130924","海兴县","1309"],["130925","盐山县","1309"],["130926","肃宁县","1309"],["130927","南皮县","1309"],["130928","吴桥县","1309"],["130929","献县","1309"],["130930","孟村回族自治县","1309"],["130971","河北沧州经济开发区","1309"],["130972","沧州高新技术产业开发区","1309"],["130973","沧州渤海新区","1309"],["130981","泊头市","1309"],["130982","任丘市","1309"],["130983","黄骅市","1309"],["130984","河间市","1309"],["1310","廊坊市","13"],["131002","安次区","1310"],["131003","广阳区","1310"],["131022","固安县","1310"],["131023","永清县","1310"],["131024","香河县","1310"],["131025","大城县","1310"],["131026","文安县","1310"],["131028","大厂回族自治县","1310"],["131071","廊坊经济技术开发区","1310"],["131081","霸州市","1310"],["131082","三河市","1310"],["1311","衡水市","13"],["131102","桃城区","1311"],["131103","冀州区","1311"],["131121","枣强县","1311"],["131122","武邑县","1311"],["131123","武强县","1311"],["131124","饶阳县","1311"],["131125","安平县","1311"],["131126","故城县","1311"],["131127","景县","1311"],["131128","阜城县","1311"],["131171","河北衡水高新技术产业开发区","1311"],["131172","衡水滨湖新区","1311"],["131182","深州市","1311"],["14","山西省",""],["1401","太原市","14"],["140105","小店区","1401"],["140106","迎泽区","1401"],["140107","杏花岭区","1401"],["140108","尖草坪区","1401"],["140109","万柏林区","1401"],["140110","晋源区","1401"],["140121","清徐县","1401"],["140122","阳曲县","1401"],["140123","娄烦县","1401"],["140171","山西转型综合改革示范区","1401"],["140181","古交市","1401"],["1402","大同市","14"],["140212","新荣区","1402"],["140213","平城区","1402"],["140214","云冈区","1402"],["140215","云州区","1402"],["140221","阳高县","1402"],["140222","天镇县","1402"],["140223","广灵县","1402"],["140224","灵丘县","1402"],["140225","浑源县","1402"],["140226","左云县","1402"],["140271","山西大同经济开发区","1402"],["1403","阳泉市","14"],["140302","城区","1403"],["140303","矿区","1403"],["140311","郊区","1403"],["140321","平定县","1403"],["140322","盂县","1403"],["1404","长治市","14"],["140403","潞州区","1404"],["140404","上党区","1404"],["140405","屯留区","1404"],["140406","潞城区","1404"],["140423","襄垣县","1404"],["140425","平顺县","1404"],["140426","黎城县","1404"],["140427","壶关县","1404"],["140428","长子县","1404"],["140429","武乡县","1404"],["140430","沁县","1404"],["140431","沁源县","1404"],["1405","晋城市","14"],["140502","城区","1405"],["140521","沁水县","1405"],["140522","阳城县","1405"],["140524","陵川县","1405"],["140525","泽州县","1405"],["140581","高平市","1405"],["1406","朔州市","14"],["140602","朔城区","1406"],["140603","平鲁区","1406"],["140621","山阴县","1406"],["140622","应县","1406"],["140623","右玉县","1406"],["140671","山西朔州经济开发区","1406"],["140681","怀仁市","1406"],["1407","晋中市","14"],["140702","榆次区","1407"],["140703","太谷区","1407"],["140721","榆社县","1407"],["140722","左权县","1407"],["140723","和顺县","1407"],["140724","昔阳县","1407"],["140725","寿阳县","1407"],["140727","祁县","1407"],["140728","平遥县","1407"],["140729","灵石县","1407"],["140781","介休市","1407"],["1408","运城市","14"],["140802","盐湖区","1408"],["140821","临猗县","1408"],["140822","万荣县","1408"],["140823","闻喜县","1408"],["140824","稷山县","1408"],["140825","新绛县","1408"],["140826","绛县","1408"],["140827","垣曲县","1408"],["140828","夏县","1408"],["140829","平陆县","1408"],["140830","芮城县","1408"],["140881","永济市","1408"],["140882","河津市","1408"],["1409","忻州市","14"],["140902","忻府区","1409"],["140921","定襄县","1409"],["140922","五台县","1409"],["140923","代县","1409"],["140924","繁峙县","1409"],["140925","宁武县","1409"],["140926","静乐县","1409"],["140927","神池县","1409"],["140928","五寨县","1409"],["140929","岢岚县","1409"],["140930","河曲县","1409"],["140931","保德县","1409"],["140932","偏关县","1409"],["140971","五台山风景名胜区","1409"],["140981","原平市","1409"],["1410","临汾市","14"],["141002","尧都区","1410"],["141021","曲沃县","1410"],["141022","翼城县","1410"],["141023","襄汾县","1410"],["141024","洪洞县","1410"],["141025","古县","1410"],["141026","安泽县","1410"],["141027","浮山县","1410"],["141028","吉县","1410"],["141029","乡宁县","1410"],["141030","大宁县","1410"],["141031","隰县","1410"],["141032","永和县","1410"],["141033","蒲县","1410"],["141034","汾西县","1410"],["141081","侯马市","1410"],["141082","霍州市","1410"],["1411","吕梁市","14"],["141102","离石区","1411"],["141121","文水县","1411"],["141122","交城县","1411"],["141123","兴县","1411"],["141124","临县","1411"],["141125","柳林县","1411"],["141126","石楼县","1411"],["141127","岚县","1411"],["141128","方山县","1411"],["141129","中阳县","1411"],["141130","交口县","1411"],["141181","孝义市","1411"],["141182","汾阳市","1411"],["15","内蒙古自治区",""],["1501","呼和浩特市","15"],["150102","新城区","1501"],["150103","回民区","1501"],["150104","玉泉区","1501"],["150105","赛罕区","1501"],["150121","土默特左旗","1501"],["150122","托克托县","1501"],["150123","和林格尔县","1501"],["150124","清水河县","1501"],["150125","武川县","1501"],["150172","呼和浩特经济技术开发区","1501"],["1502","包头市","15"],["150202","东河区","1502"],["150203","昆都仑区","1502"],["150204","青山区","1502"],["150205","石拐区","1502"],["150206","白云鄂博矿区","1502"],["150207","九原区","1502"],["150221","土默特右旗","1502"],["150222","固阳县","1502"],["150223","达尔罕茂明安联合旗","1502"],["150271","包头稀土高新技术产业开发区","1502"],["1503","乌海市","15"],["150302","海勃湾区","1503"],["150303","海南区","1503"],["150304","乌达区","1503"],["1504","赤峰市","15"],["150402","红山区","1504"],["150403","元宝山区","1504"],["150404","松山区","1504"],["150421","阿鲁科尔沁旗","1504"],["150422","巴林左旗","1504"],["150423","巴林右旗","1504"],["150424","林西县","1504"],["150425","克什克腾旗","1504"],["150426","翁牛特旗","1504"],["150428","喀喇沁旗","1504"],["150429","宁城县","1504"],["150430","敖汉旗","1504"],["1505","通辽市","15"],["150502","科尔沁区","1505"],["150521","科尔沁左翼中旗","1505"],["150522","科尔沁左翼后旗","1505"],["150523","开鲁县","1505"],["150524","库伦旗","1505"],["150525","奈曼旗","1505"],["150526","扎鲁特旗","1505"],["150571","通辽经济技术开发区","1505"],["150581","霍林郭勒市","1505"],["1506","鄂尔多斯市","15"],["150602","东胜区","1506"],["150603","康巴什区","1506"],["150621","达拉特旗","1506"],["150622","准格尔旗","1506"],["150623","鄂托克前旗","1506"],["150624","鄂托克旗","1506"],["150625","杭锦旗","1506"],["150626","乌审旗","1506"],["150627","伊金霍洛旗","1506"],["1507","呼伦贝尔市","15"],["150702","海拉尔区","1507"],["150703","扎赉诺尔区","1507"],["150721","阿荣旗","1507"],["150722","莫力达瓦达斡尔族自治旗","1507"],["150723","鄂伦春自治旗","1507"],["150724","鄂温克族自治旗","1507"],["150725","陈巴尔虎旗","1507"],["150726","新巴尔虎左旗","1507"],["150727","新巴尔虎右旗","1507"],["150781","满洲里市","1507"],["150782","牙克石市","1507"],["150783","扎兰屯市","1507"],["150784","额尔古纳市","1507"],["150785","根河市","1507"],["1508","巴彦淖尔市","15"],["150802","临河区","1508"],["150821","五原县","1508"],["150822","磴口县","1508"],["150823","乌拉特前旗","1508"],["150824","乌拉特中旗","1508"],["150825","乌拉特后旗","1508"],["150826","杭锦后旗","1508"],["1509","乌兰察布市","15"],["150902","集宁区","1509"],["150921","卓资县","1509"],["150922","化德县","1509"],["150923","商都县","1509"],["150924","兴和县","1509"],["150925","凉城县","1509"],["150926","察哈尔右翼前旗","1509"],["150927","察哈尔右翼中旗","1509"],["150928","察哈尔右翼后旗","1509"],["150929","四子王旗","1509"],["150981","丰镇市","1509"],["1522","兴安盟","15"],["152201","乌兰浩特市","1522"],["152202","阿尔山市","1522"],["152221","科尔沁右翼前旗","1522"],["152222","科尔沁右翼中旗","1522"],["152223","扎赉特旗","1522"],["152224","突泉县","1522"],["1525","锡林郭勒盟","15"],["152501","二连浩特市","1525"],["152502","锡林浩特市","1525"],["152522","阿巴嘎旗","1525"],["152523","苏尼特左旗","1525"],["152524","苏尼特右旗","1525"],["152525","东乌珠穆沁旗","1525"],["152526","西乌珠穆沁旗","1525"],["152527","太仆寺旗","1525"],["152528","镶黄旗","1525"],["152529","正镶白旗","1525"],["152530","正蓝旗","1525"],["152531","多伦县","1525"],["152571","乌拉盖管理区管委会","1525"],["1529","阿拉善盟","15"],["152921","阿拉善左旗","1529"],["152922","阿拉善右旗","1529"],["152923","额济纳旗","1529"],["152971","内蒙古阿拉善高新技术产业开发区","1529"],["21","辽宁省",""],["2101","沈阳市","21"],["210102","和平区","2101"],["210103","沈河区","2101"],["210104","大东区","2101"],["210105","皇姑区","2101"],["210106","铁西区","2101"],["210111","苏家屯区","2101"],["210112","浑南区","2101"],["210113","沈北新区","2101"],["210114","于洪区","2101"],["210115","辽中区","2101"],["210123","康平县","2101"],["210124","法库县","2101"],["210181","新民市","2101"],["2102","大连市","21"],["210202","中山区","2102"],["210203","西岗区","2102"],["210204","沙河口区","2102"],["210211","甘井子区","2102"],["210212","旅顺口区","2102"],["210213","金州区","2102"],["210214","普兰店区","2102"],["210224","长海县","2102"],["210281","瓦房店市","2102"],["210283","庄河市","2102"],["2103","鞍山市","21"],["210302","铁东区","2103"],["210303","铁西区","2103"],["210304","立山区","2103"],["210311","千山区","2103"],["210321","台安县","2103"],["210323","岫岩满族自治县","2103"],["210381","海城市","2103"],["2104","抚顺市","21"],["210402","新抚区","2104"],["210403","东洲区","2104"],["210404","望花区","2104"],["210411","顺城区","2104"],["210421","抚顺县","2104"],["210422","新宾满族自治县","2104"],["210423","清原满族自治县","2104"],["2105","本溪市","21"],["210502","平山区","2105"],["210503","溪湖区","2105"],["210504","明山区","2105"],["210505","南芬区","2105"],["210521","本溪满族自治县","2105"],["210522","桓仁满族自治县","2105"],["2106","丹东市","21"],["210602","元宝区","2106"],["210603","振兴区","2106"],["210604","振安区","2106"],["210624","宽甸满族自治县","2106"],["210681","东港市","2106"],["210682","凤城市","2106"],["2107","锦州市","21"],["210702","古塔区","2107"],["210703","凌河区","2107"],["210711","太和区","2107"],["210726","黑山县","2107"],["210727","义县","2107"],["210781","凌海市","2107"],["210782","北镇市","2107"],["2108","营口市","21"],["210802","站前区","2108"],["210803","西市区","2108"],["210804","鲅鱼圈区","2108"],["210811","老边区","2108"],["210881","盖州市","2108"],["210882","大石桥市","2108"],["2109","阜新市","21"],["210902","海州区","2109"],["210903","新邱区","2109"],["210904","太平区","2109"],["210905","清河门区","2109"],["210911","细河区","2109"],["210921","阜新蒙古族自治县","2109"],["210922","彰武县","2109"],["2110","辽阳市","21"],["211002","白塔区","2110"],["211003","文圣区","2110"],["211004","宏伟区","2110"],["211005","弓长岭区","2110"],["211011","太子河区","2110"],["211021","辽阳县","2110"],["211081","灯塔市","2110"],["2111","盘锦市","21"],["211102","双台子区","2111"],["211103","兴隆台区","2111"],["211104","大洼区","2111"],["211122","盘山县","2111"],["2112","铁岭市","21"],["211202","银州区","2112"],["211204","清河区","2112"],["211221","铁岭县","2112"],["211223","西丰县","2112"],["211224","昌图县","2112"],["211281","调兵山市","2112"],["211282","开原市","2112"],["2113","朝阳市","21"],["211302","双塔区","2113"],["211303","龙城区","2113"],["211321","朝阳县","2113"],["211322","建平县","2113"],["211324","喀喇沁左翼蒙古族自治县","2113"],["211381","北票市","2113"],["211382","凌源市","2113"],["2114","葫芦岛市","21"],["211402","连山区","2114"],["211403","龙港区","2114"],["211404","南票区","2114"],["211421","绥中县","2114"],["211422","建昌县","2114"],["211481","兴城市","2114"],["22","吉林省",""],["2201","长春市","22"],["220102","南关区","2201"],["220103","宽城区","2201"],["220104","朝阳区","2201"],["220105","二道区","2201"],["220106","绿园区","2201"],["220112","双阳区","2201"],["220113","九台区","2201"],["220122","农安县","2201"],["220171","长春经济技术开发区","2201"],["220172","长春净月高新技术产业开发区","2201"],["220173","长春高新技术产业开发区","2201"],["220174","长春汽车经济技术开发区","2201"],["220182","榆树市","2201"],["220183","德惠市","2201"],["220184","公主岭市","2201"],["2202","吉林市","22"],["220202","昌邑区","2202"],["220203","龙潭区","2202"],["220204","船营区","2202"],["220211","丰满区","2202"],["220221","永吉县","2202"],["220271","吉林经济开发区","2202"],["220272","吉林高新技术产业开发区","2202"],["220273","吉林中国新加坡食品区","2202"],["220281","蛟河市","2202"],["220282","桦甸市","2202"],["220283","舒兰市","2202"],["220284","磐石市","2202"],["2203","四平市","22"],["220302","铁西区","2203"],["220303","铁东区","2203"],["220322","梨树县","2203"],["220323","伊通满族自治县","2203"],["220382","双辽市","2203"],["2204","辽源市","22"],["220402","龙山区","2204"],["220403","西安区","2204"],["220421","东丰县","2204"],["220422","东辽县","2204"],["2205","通化市","22"],["220502","东昌区","2205"],["220503","二道江区","2205"],["220521","通化县","2205"],["220523","辉南县","2205"],["220524","柳河县","2205"],["220581","梅河口市","2205"],["220582","集安市","2205"],["2206","白山市","22"],["220602","浑江区","2206"],["220605","江源区","2206"],["220621","抚松县","2206"],["220622","靖宇县","2206"],["220623","长白朝鲜族自治县","2206"],["220681","临江市","2206"],["2207","松原市","22"],["220702","宁江区","2207"],["220721","前郭尔罗斯蒙古族自治县","2207"],["220722","长岭县","2207"],["220723","乾安县","2207"],["220771","吉林松原经济开发区","2207"],["220781","扶余市","2207"],["2208","白城市","22"],["220802","洮北区","2208"],["220821","镇赉县","2208"],["220822","通榆县","2208"],["220871","吉林白城经济开发区","2208"],["220881","洮南市","2208"],["220882","大安市","2208"],["2224","延边朝鲜族自治州","22"],["222401","延吉市","2224"],["222402","图们市","2224"],["222403","敦化市","2224"],["222404","珲春市","2224"],["222405","龙井市","2224"],["222406","和龙市","2224"],["222424","汪清县","2224"],["222426","安图县","2224"],["23","黑龙江省",""],["2301","哈尔滨市","23"],["230102","道里区","2301"],["230103","南岗区","2301"],["230104","道外区","2301"],["230108","平房区","2301"],["230109","松北区","2301"],["230110","香坊区","2301"],["230111","呼兰区","2301"],["230112","阿城区","2301"],["230113","双城区","2301"],["230123","依兰县","2301"],["230124","方正县","2301"],["230125","宾县","2301"],["230126","巴彦县","2301"],["230127","木兰县","2301"],["230128","通河县","2301"],["230129","延寿县","2301"],["230183","尚志市","2301"],["230184","五常市","2301"],["2302","齐齐哈尔市","23"],["230202","龙沙区","2302"],["230203","建华区","2302"],["230204","铁锋区","2302"],["230205","昂昂溪区","2302"],["230206","富拉尔基区","2302"],["230207","碾子山区","2302"],["230208","梅里斯达斡尔族区","2302"],["230221","龙江县","2302"],["230223","依安县","2302"],["230224","泰来县","2302"],["230225","甘南县","2302"],["230227","富裕县","2302"],["230229","克山县","2302"],["230230","克东县","2302"],["230231","拜泉县","2302"],["230281","讷河市","2302"],["2303","鸡西市","23"],["230302","鸡冠区","2303"],["230303","恒山区","2303"],["230304","滴道区","2303"],["230305","梨树区","2303"],["230306","城子河区","2303"],["230307","麻山区","2303"],["230321","鸡东县","2303"],["230381","虎林市","2303"],["230382","密山市","2303"],["2304","鹤岗市","23"],["230402","向阳区","2304"],["230403","工农区","2304"],["230404","南山区","2304"],["230405","兴安区","2304"],["230406","东山区","2304"],["230407","兴山区","2304"],["230421","萝北县","2304"],["230422","绥滨县","2304"],["2305","双鸭山市","23"],["230502","尖山区","2305"],["230503","岭东区","2305"],["230505","四方台区","2305"],["230506","宝山区","2305"],["230521","集贤县","2305"],["230522","友谊县","2305"],["230523","宝清县","2305"],["230524","饶河县","2305"],["2306","大庆市","23"],["230602","萨尔图区","2306"],["230603","龙凤区","2306"],["230604","让胡路区","2306"],["230605","红岗区","2306"],["230606","大同区","2306"],["230621","肇州县","2306"],["230622","肇源县","2306"],["230623","林甸县","2306"],["230624","杜尔伯特蒙古族自治县","2306"],["230671","大庆高新技术产业开发区","2306"],["2307","伊春市","23"],["230717","伊美区","2307"],["230718","乌翠区","2307"],["230719","友好区","2307"],["230722","嘉荫县","2307"],["230723","汤旺县","2307"],["230724","丰林县","2307"],["230725","大箐山县","2307"],["230726","南岔县","2307"],["230751","金林区","2307"],["230781","铁力市","2307"],["2308","佳木斯市","23"],["230803","向阳区","2308"],["230804","前进区","2308"],["230805","东风区","2308"],["230811","郊区","2308"],["230822","桦南县","2308"],["230826","桦川县","2308"],["230828","汤原县","2308"],["230881","同江市","2308"],["230882","富锦市","2308"],["230883","抚远市","2308"],["2309","七台河市","23"],["230902","新兴区","2309"],["230903","桃山区","2309"],["230904","茄子河区","2309"],["230921","勃利县","2309"],["2310","牡丹江市","23"],["231002","东安区","2310"],["231003","阳明区","2310"],["231004","爱民区","2310"],["231005","西安区","2310"],["231025","林口县","2310"],["231081","绥芬河市","2310"],["231083","海林市","2310"],["231084","宁安市","2310"],["231085","穆棱市","2310"],["231086","东宁市","2310"],["2311","黑河市","23"],["231102","爱辉区","2311"],["231123","逊克县","2311"],["231124","孙吴县","2311"],["231181","北安市","2311"],["231182","五大连池市","2311"],["231183","嫩江市","2311"],["2312","绥化市","23"],["231202","北林区","2312"],["231221","望奎县","2312"],["231222","兰西县","2312"],["231223","青冈县","2312"],["231224","庆安县","2312"],["231225","明水县","2312"],["231226","绥棱县","2312"],["231281","安达市","2312"],["231282","肇东市","2312"],["231283","海伦市","2312"],["2327","大兴安岭地区","23"],["232701","漠河市","2327"],["232721","呼玛县","2327"],["232722","塔河县","2327"],["232761","加格达奇区","2327"],["232762","松岭区","2327"],["232763","新林区","2327"],["232764","呼中区","2327"],["31","上海市",""],["3101","市辖区","31"],["310101","黄浦区","3101"],["310104","徐汇区","3101"],["310105","长宁区","3101"],["310106","静安区","3101"],["310107","普陀区","3101"],["310109","虹口区","3101"],["310110","杨浦区","3101"],["310112","闵行区","3101"],["310113","宝山区","3101"],["310114","嘉定区","3101"],["310115","浦东新区","3101"],["310116","金山区","3101"],["310117","松江区","3101"],["310118","青浦区","3101"],["310120","奉贤区","3101"],["310151","崇明区","3101"],["32","江苏省",""],["3201","南京市","32"],["320102","玄武区","3201"],["320104","秦淮区","3201"],["320105","建邺区","3201"],["320106","鼓楼区","3201"],["320111","浦口区","3201"],["320113","栖霞区","3201"],["320114","雨花台区","3201"],["320115","江宁区","3201"],["320116","六合区","3201"],["320117","溧水区","3201"],["320118","高淳区","3201"],["3202","无锡市","32"],["320205","锡山区","3202"],["320206","惠山区","3202"],["320211","滨湖区","3202"],["320213","梁溪区","3202"],["320214","新吴区","3202"],["320281","江阴市","3202"],["320282","宜兴市","3202"],["3203","徐州市","32"],["320302","鼓楼区","3203"],["320303","云龙区","3203"],["320305","贾汪区","3203"],["320311","泉山区","3203"],["320312","铜山区","3203"],["320321","丰县","3203"],["320322","沛县","3203"],["320324","睢宁县","3203"],["320371","徐州经济技术开发区","3203"],["320381","新沂市","3203"],["320382","邳州市","3203"],["3204","常州市","32"],["320402","天宁区","3204"],["320404","钟楼区","3204"],["320411","新北区","3204"],["320412","武进区","3204"],["320413","金坛区","3204"],["320481","溧阳市","3204"],["3205","苏州市","32"],["320505","虎丘区","3205"],["320506","吴中区","3205"],["320507","相城区","3205"],["320508","姑苏区","3205"],["320509","吴江区","3205"],["320576","苏州工业园区","3205"],["320581","常熟市","3205"],["320582","张家港市","3205"],["320583","昆山市","3205"],["320585","太仓市","3205"],["3206","南通市","32"],["320612","通州区","3206"],["320613","崇川区","3206"],["320614","海门区","3206"],["320623","如东县","3206"],["320671","南通经济技术开发区","3206"],["320681","启东市","3206"],["320682","如皋市","3206"],["320685","海安市","3206"],["3207","连云港市","32"],["320703","连云区","3207"],["320706","海州区","3207"],["320707","赣榆区","3207"],["320722","东海县","3207"],["320723","灌云县","3207"],["320724","灌南县","3207"],["320771","连云港经济技术开发区","3207"],["3208","淮安市","32"],["320803","淮安区","3208"],["320804","淮阴区","3208"],["320812","清江浦区","3208"],["320813","洪泽区","3208"],["320826","涟水县","3208"],["320830","盱眙县","3208"],["320831","金湖县","3208"],["320871","淮安经济技术开发区","3208"],["3209","盐城市","32"],["320902","亭湖区","3209"],["320903","盐都区","3209"],["320904","大丰区","3209"],["320921","响水县","3209"],["320922","滨海县","3209"],["320923","阜宁县","3209"],["320924","射阳县","3209"],["320925","建湖县","3209"],["320971","盐城经济技术开发区","3209"],["320981","东台市","3209"],["3210","扬州市","32"],["321002","广陵区","3210"],["321003","邗江区","3210"],["321012","江都区","3210"],["321023","宝应县","3210"],["321071","扬州经济技术开发区","3210"],["321081","仪征市","3210"],["321084","高邮市","3210"],["3211","镇江市","32"],["321102","京口区","3211"],["321111","润州区","3211"],["321112","丹徒区","3211"],["321171","镇江新区","3211"],["321181","丹阳市","3211"],["321182","扬中市","3211"],["321183","句容市","3211"],["3212","泰州市","32"],["321202","海陵区","3212"],["321203","高港区","3212"],["321204","姜堰区","3212"],["321281","兴化市","3212"],["321282","靖江市","3212"],["321283","泰兴市","3212"],["3213","宿迁市","32"],["321302","宿城区","3213"],["321311","宿豫区","3213"],["321322","沭阳县","3213"],["321323","泗阳县","3213"],["321324","泗洪县","3213"],["321371","宿迁经济技术开发区","3213"],["33","浙江省",""],["3301","杭州市","33"],["330102","上城区","3301"],["330105","拱墅区","3301"],["330106","西湖区","3301"],["330108","滨江区","3301"],["330109","萧山区","3301"],["330110","余杭区","3301"],["330111","富阳区","3301"],["330112","临安区","3301"],["330113","临平区","3301"],["330114","钱塘区","3301"],["330122","桐庐县","3301"],["330127","淳安县","3301"],["330182","建德市","3301"],["3302","宁波市","33"],["330203","海曙区","3302"],["330205","江北区","3302"],["330206","北仑区","3302"],["330211","镇海区","3302"],["330212","鄞州区","3302"],["330213","奉化区","3302"],["330225","象山县","3302"],["330226","宁海县","3302"],["330281","余姚市","3302"],["330282","慈溪市","3302"],["3303","温州市","33"],["330302","鹿城区","3303"],["330303","龙湾区","3303"],["330304","瓯海区","3303"],["330305","洞头区","3303"],["330324","永嘉县","3303"],["330326","平阳县","3303"],["330327","苍南县","3303"],["330328","文成县","3303"],["330329","泰顺县","3303"],["330381","瑞安市","3303"],["330382","乐清市","3303"],["330383","龙港市","3303"],["3304","嘉兴市","33"],["330402","南湖区","3304"],["330411","秀洲区","3304"],["330421","嘉善县","3304"],["330424","海盐县","3304"],["330481","海宁市","3304"],["330482","平湖市","3304"],["330483","桐乡市","3304"],["3305","湖州市","33"],["330502","吴兴区","3305"],["330503","南浔区","3305"],["330521","德清县","3305"],["330522","长兴县","3305"],["330523","安吉县","3305"],["3306","绍兴市","33"],["330602","越城区","3306"],["330603","柯桥区","3306"],["330604","上虞区","3306"],["330624","新昌县","3306"],["330681","诸暨市","3306"],["330683","嵊州市","3306"],["3307","金华市","33"],["330702","婺城区","3307"],["330703","金东区","3307"],["330723","武义县","3307"],["330726","浦江县","3307"],["330727","磐安县","3307"],["330781","兰溪市","3307"],["330782","义乌市","3307"],["330783","东阳市","3307"],["330784","永康市","3307"],["3308","衢州市","33"],["330802","柯城区","3308"],["330803","衢江区","3308"],["330822","常山县","3308"],["330824","开化县","3308"],["330825","龙游县","3308"],["330881","江山市","3308"],["3309","舟山市","33"],["330902","定海区","3309"],["330903","普陀区","3309"],["330921","岱山县","3309"],["330922","嵊泗县","3309"],["3310","台州市","33"],["331002","椒江区","3310"],["331003","黄岩区","3310"],["331004","路桥区","3310"],["331022","三门县","3310"],["331023","天台县","3310"],["331024","仙居县","3310"],["331081","温岭市","3310"],["331082","临海市","3310"],["331083","玉环市","3310"],["3311","丽水市","33"],["331102","莲都区","3311"],["331121","青田县","3311"],["331122","缙云县","3311"],["331123","遂昌县","3311"],["331124","松阳县","3311"],["331125","云和县","3311"],["331126","庆元县","3311"],["331127","景宁畲族自治县","3311"],["331181","龙泉市","3311"],["34","安徽省",""],["3401","合肥市","34"],["340102","瑶海区","3401"],["340103","庐阳区","3401"],["340104","蜀山区","3401"],["340111","包河区","3401"],["340121","长丰县","3401"],["340122","肥东县","3401"],["340123","肥西县","3401"],["340124","庐江县","3401"],["340176","合肥高新技术产业开发区","3401"],["340177","合肥经济技术开发区","3401"],["340178","合肥新站高新技术产业开发区","3401"],["340181","巢湖市","3401"],["3402","芜湖市","34"],["340202","镜湖区","3402"],["340207","鸠江区","3402"],["340209","弋江区","3402"],["340210","湾沚区","3402"],["340212","繁昌区","3402"],["340223","南陵县","3402"],["340271","芜湖经济技术开发区","3402"],["340272","安徽芜湖三山经济开发区","3402"],["340281","无为市","3402"],["3403","蚌埠市","34"],["340302","龙子湖区","3403"],["340303","蚌山区","3403"],["340304","禹会区","3403"],["340311","淮上区","3403"],["340321","怀远县","3403"],["340322","五河县","3403"],["340323","固镇县","3403"],["340371","蚌埠市高新技术开发区","3403"],["340372","蚌埠市经济开发区","3403"],["3404","淮南市","34"],["340402","大通区","3404"],["340403","田家庵区","3404"],["340404","谢家集区","3404"],["340405","八公山区","3404"],["340406","潘集区","3404"],["340421","凤台县","3404"],["340422","寿县","3404"],["3405","马鞍山市","34"],["340503","花山区","3405"],["340504","雨山区","3405"],["340506","博望区","3405"],["340521","当涂县","3405"],["340522","含山县","3405"],["340523","和县","3405"],["3406","淮北市","34"],["340602","杜集区","3406"],["340603","相山区","3406"],["340604","烈山区","3406"],["340621","濉溪县","3406"],["3407","铜陵市","34"],["340705","铜官区","3407"],["340706","义安区","3407"],["340711","郊区","3407"],["340722","枞阳县","3407"],["3408","安庆市","34"],["340802","迎江区","3408"],["340803","大观区","3408"],["340811","宜秀区","3408"],["340822","怀宁县","3408"],["340825","太湖县","3408"],["340826","宿松县","3408"],["340827","望江县","3408"],["340828","岳西县","3408"],["340871","安徽安庆经济开发区","3408"],["340881","桐城市","3408"],["340882","潜山市","3408"],["3410","黄山市","34"],["341002","屯溪区","3410"],["341003","黄山区","3410"],["341004","徽州区","3410"],["341021","歙县","3410"],["341022","休宁县","3410"],["341023","黟县","3410"],["341024","祁门县","3410"],["3411","滁州市","34"],["341102","琅琊区","3411"],["341103","南谯区","3411"],["341122","来安县","3411"],["341124","全椒县","3411"],["341125","定远县","3411"],["341126","凤阳县","3411"],["341171","中新苏滁高新技术产业开发区","3411"],["341172","滁州经济技术开发区","3411"],["341181","天长市","3411"],["341182","明光市","3411"],["3412","阜阳市","34"],["341202","颍州区","3412"],["341203","颍东区","3412"],["341204","颍泉区","3412"],["341221","临泉县","3412"],["341222","太和县","3412"],["341225","阜南县","3412"],["341226","颍上县","3412"],["341271","阜阳合肥现代产业园区","3412"],["341272","阜阳经济技术开发区","3412"],["341282","界首市","3412"],["3413","宿州市","34"],["341302","埇桥区","3413"],["341321","砀山县","3413"],["341322","萧县","3413"],["341323","灵璧县","3413"],["341324","泗县","3413"],["341371","宿州马鞍山现代产业园区","3413"],["341372","宿州经济技术开发区","3413"],["3415","六安市","34"],["341502","金安区","3415"],["341503","裕安区","3415"],["341504","叶集区","3415"],["341522","霍邱县","3415"],["341523","舒城县","3415"],["341524","金寨县","3415"],["341525","霍山县","3415"],["3416","亳州市","34"],["341602","谯城区","3416"],["341621","涡阳县","3416"],["341622","蒙城县","3416"],["341623","利辛县","3416"],["3417","池州市","34"],["341702","贵池区","3417"],["341721","东至县","3417"],["341722","石台县","3417"],["341723","青阳县","3417"],["3418","宣城市","34"],["341802","宣州区","3418"],["341821","郎溪县","3418"],["341823","泾县","3418"],["341824","绩溪县","3418"],["341825","旌德县","3418"],["341871","宣城市经济开发区","3418"],["341881","宁国市","3418"],["341882","广德市","3418"],["35","福建省",""],["3501","福州市","35"],["350102","鼓楼区","3501"],["350103","台江区","3501"],["350104","仓山区","3501"],["350105","马尾区","3501"],["350111","晋安区","3501"],["350112","长乐区","3501"],["350121","闽侯县","3501"],["350122","连江县","3501"],["350123","罗源县","3501"],["350124","闽清县","3501"],["350125","永泰县","3501"],["350128","平潭县","3501"],["350181","福清市","3501"],["3502","厦门市","35"],["350203","思明区","3502"],["350205","海沧区","3502"],["350206","湖里区","3502"],["350211","集美区","3502"],["350212","同安区","3502"],["350213","翔安区","3502"],["3503","莆田市","35"],["350302","城厢区","3503"],["350303","涵江区","3503"],["350304","荔城区","3503"],["350305","秀屿区","3503"],["350322","仙游县","3503"],["3504","三明市","35"],["350404","三元区","3504"],["350405","沙县区","3504"],["350421","明溪县","3504"],["350423","清流县","3504"],["350424","宁化县","3504"],["350425","大田县","3504"],["350426","尤溪县","3504"],["350428","将乐县","3504"],["350429","泰宁县","3504"],["350430","建宁县","3504"],["350481","永安市","3504"],["3505","泉州市","35"],["350502","鲤城区","3505"],["350503","丰泽区","3505"],["350504","洛江区","3505"],["350505","泉港区","3505"],["350521","惠安县","3505"],["350524","安溪县","3505"],["350525","永春县","3505"],["350526","德化县","3505"],["350527","金门县","3505"],["350581","石狮市","3505"],["350582","晋江市","3505"],["350583","南安市","3505"],["3506","漳州市","35"],["350602","芗城区","3506"],["350603","龙文区","3506"],["350604","龙海区","3506"],["350605","长泰区","3506"],["350622","云霄县","3506"],["350623","漳浦县","3506"],["350624","诏安县","3506"],["350626","东山县","3506"],["350627","南靖县","3506"],["350628","平和县","3506"],["350629","华安县","3506"],["3507","南平市","35"],["350702","延平区","3507"],["350703","建阳区","3507"],["350721","顺昌县","3507"],["350722","浦城县","3507"],["350723","光泽县","3507"],["350724","松溪县","3507"],["350725","政和县","3507"],["350781","邵武市","3507"],["350782","武夷山市","3507"],["350783","建瓯市","3507"],["3508","龙岩市","35"],["350802","新罗区","3508"],["350803","永定区","3508"],["350821","长汀县","3508"],["350823","上杭县","3508"],["350824","武平县","3508"],["350825","连城县","3508"],["350881","漳平市","3508"],["3509","宁德市","35"],["350902","蕉城区","3509"],["350921","霞浦县","3509"],["350922","古田县","3509"],["350923","屏南县","3509"],["350924","寿宁县","3509"],["350925","周宁县","3509"],["350926","柘荣县","3509"],["350981","福安市","3509"],["350982","福鼎市","3509"],["36","江西省",""],["3601","南昌市","36"],["360102","东湖区","3601"],["360103","西湖区","3601"],["360104","青云谱区","3601"],["360111","青山湖区","3601"],["360112","新建区","3601"],["360113","红谷滩区","3601"],["360121","南昌县","3601"],["360123","安义县","3601"],["360124","进贤县","3601"],["3602","景德镇市","36"],["360202","昌江区","3602"],["360203","珠山区","3602"],["360222","浮梁县","3602"],["360281","乐平市","3602"],["3603","萍乡市","36"],["360302","安源区","3603"],["360313","湘东区","3603"],["360321","莲花县","3603"],["360322","上栗县","3603"],["360323","芦溪县","3603"],["3604","九江市","36"],["360402","濂溪区","3604"],["360403","浔阳区","3604"],["360404","柴桑区","3604"],["360423","武宁县","3604"],["360424","修水县","3604"],["360425","永修县","3604"],["360426","德安县","3604"],["360428","都昌县","3604"],["360429","湖口县","3604"],["360430","彭泽县","3604"],["360481","瑞昌市","3604"],["360482","共青城市","3604"],["360483","庐山市","3604"],["3605","新余市","36"],["360502","渝水区","3605"],["360521","分宜县","3605"],["3606","鹰潭市","36"],["360602","月湖区","3606"],["360603","余江区","3606"],["360681","贵溪市","3606"],["3607","赣州市","36"],["360702","章贡区","3607"],["360703","南康区","3607"],["360704","赣县区","3607"],["360722","信丰县","3607"],["360723","大余县","3607"],["360724","上犹县","3607"],["360725","崇义县","3607"],["360726","安远县","3607"],["360728","定南县","3607"],["360729","全南县","3607"],["360730","宁都县","3607"],["360731","于都县","3607"],["360732","兴国县","3607"],["360733","会昌县","3607"],["360734","寻乌县","3607"],["360735","石城县","3607"],["360781","瑞金市","3607"],["360783","龙南市","3607"],["3608","吉安市","36"],["360802","吉州区","3608"],["360803","青原区","3608"],["360821","吉安县","3608"],["360822","吉水县","3608"],["360823","峡江县","3608"],["360824","新干县","3608"],["360825","永丰县","3608"],["360826","泰和县","3608"],["360827","遂川县","3608"],["360828","万安县","3608"],["360829","安福县","3608"],["360830","永新县","3608"],["360881","井冈山市","3608"],["3609","宜春市","36"],["360902","袁州区","3609"],["360921","奉新县","3609"],["360922","万载县","3609"],["360923","上高县","3609"],["360924","宜丰县","3609"],["360925","靖安县","3609"],["360926","铜鼓县","3609"],["360981","丰城市","3609"],["360982","樟树市","3609"],["360983","高安市","3609"],["3610","抚州市","36"],["361002","临川区","3610"],["361003","东乡区","3610"],["361021","南城县","3610"],["361022","黎川县","3610"],["361023","南丰县","3610"],["361024","崇仁县","3610"],["361025","乐安县","3610"],["361026","宜黄县","3610"],["361027","金溪县","3610"],["361028","资溪县","3610"],["361030","广昌县","3610"],["3611","上饶市","36"],["361102","信州区","3611"],["361103","广丰区","3611"],["361104","广信区","3611"],["361123","玉山县","3611"],["361124","铅山县","3611"],["361125","横峰县","3611"],["361126","弋阳县","3611"],["361127","余干县","3611"],["361128","鄱阳县","3611"],["361129","万年县","3611"],["361130","婺源县","3611"],["361181","德兴市","3611"],["37","山东省",""],["3701","济南市","37"],["370102","历下区","3701"],["370103","市中区","3701"],["370104","槐荫区","3701"],["370105","天桥区","3701"],["370112","历城区","3701"],["370113","长清区","3701"],["370114","章丘区","3701"],["370115","济阳区","3701"],["370116","莱芜区","3701"],["370117","钢城区","3701"],["370124","平阴县","3701"],["370126","商河县","3701"],["370176","济南高新技术产业开发区","3701"],["3702","青岛市","37"],["370202","市南区","3702"],["370203","市北区","3702"],["370211","黄岛区","3702"],["370212","崂山区","3702"],["370213","李沧区","3702"],["370214","城阳区","3702"],["370215","即墨区","3702"],["370281","胶州市","3702"],["370283","平度市","3702"],["370285","莱西市","3702"],["3703","淄博市","37"],["370302","淄川区","3703"],["370303","张店区","3703"],["370304","博山区","3703"],["370305","临淄区","3703"],["370306","周村区","3703"],["370321","桓台县","3703"],["370322","高青县","3703"],["370323","沂源县","3703"],["3704","枣庄市","37"],["370402","市中区","3704"],["370403","薛城区","3704"],["370404","峄城区","3704"],["370405","台儿庄区","3704"],["370406","山亭区","3704"],["370481","滕州市","3704"],["3705","东营市","37"],["370502","东营区","3705"],["370503","河口区","3705"],["370505","垦利区","3705"],["370522","利津县","3705"],["370523","广饶县","3705"],["370571","东营经济技术开发区","3705"],["370572","东营港经济开发区","3705"],["3706","烟台市","37"],["370602","芝罘区","3706"],["370611","福山区","3706"],["370612","牟平区","3706"],["370613","莱山区","3706"],["370614","蓬莱区","3706"],["370671","烟台高新技术产业开发区","3706"],["370676","烟台经济技术开发区","3706"],["370681","龙口市","3706"],["370682","莱阳市","3706"],["370683","莱州市","3706"],["370685","招远市","3706"],["370686","栖霞市","3706"],["370687","海阳市","3706"],["3707","潍坊市","37"],["370702","潍城区","3707"],["370703","寒亭区","3707"],["370704","坊子区","3707"],["370705","奎文区","3707"],["370724","临朐县","3707"],["370725","昌乐县","3707"],["370772","潍坊滨海经济技术开发区","3707"],["370781","青州市","3707"],["370782","诸城市","3707"],["370783","寿光市","3707"],["370784","安丘市","3707"],["370785","高密市","3707"],["370786","昌邑市","3707"],["3708","济宁市","37"],["370811","任城区","3708"],["370812","兖州区","3708"],["370826","微山县","3708"],["370827","鱼台县","3708"],["370828","金乡县","3708"],["370829","嘉祥县","3708"],["370830","汶上县","3708"],["370831","泗水县","3708"],["370832","梁山县","3708"],["370871","济宁高新技术产业开发区","3708"],["370881","曲阜市","3708"],["370883","邹城市","3708"],["3709","泰安市","37"],["370902","泰山区","3709"],["370911","岱岳区","3709"],["370921","宁阳县","3709"],["370923","东平县","3709"],["370982","新泰市","3709"],["370983","肥城市","3709"],["3710","威海市","37"],["371002","环翠区","3710"],["371003","文登区","3710"],["371071","威海火炬高技术产业开发区","3710"],["371072","威海经济技术开发区","3710"],["371073","威海临港经济技术开发区","3710"],["371082","荣成市","3710"],["371083","乳山市","3710"],["3711","日照市","37"],["371102","东港区","3711"],["371103","岚山区","3711"],["371121","五莲县","3711"],["371122","莒县","3711"],["371171","日照经济技术开发区","3711"],["3713","临沂市","37"],["371302","兰山区","3713"],["371311","罗庄区","3713"],["371312","河东区","3713"],["371321","沂南县","3713"],["371322","郯城县","3713"],["371323","沂水县","3713"],["371324","兰陵县","3713"],["371325","费县","3713"],["371326","平邑县","3713"],["371327","莒南县","3713"],["371328","蒙阴县","3713"],["371329","临沭县","3713"],["371371","临沂高新技术产业开发区","3713"],["3714","德州市","37"],["371402","德城区","3714"],["371403","陵城区","3714"],["371422","宁津县","3714"],["371423","庆云县","3714"],["371424","临邑县","3714"],["371425","齐河县","3714"],["371426","平原县","3714"],["371427","夏津县","3714"],["371428","武城县","3714"],["371471","德州天衢新区","3714"],["371481","乐陵市","3714"],["371482","禹城市","3714"],["3715","聊城市","37"],["371502","东昌府区","3715"],["371503","茌平区","3715"],["371521","阳谷县","3715"],["371522","莘县","3715"],["371524","东阿县","3715"],["371525","冠县","3715"],["371526","高唐县","3715"],["371581","临清市","3715"],["3716","滨州市","37"],["371602","滨城区","3716"],["371603","沾化区","3716"],["371621","惠民县","3716"],["371622","阳信县","3716"],["371623","无棣县","3716"],["371625","博兴县","3716"],["371681","邹平市","3716"],["3717","菏泽市","37"],["371702","牡丹区","3717"],["371703","定陶区","3717"],["371721","曹县","3717"],["371722","单县","3717"],["371723","成武县","3717"],["371724","巨野县","3717"],["371725","郓城县","3717"],["371726","鄄城县","3717"],["371728","东明县","3717"],["371771","菏泽经济技术开发区","3717"],["371772","菏泽高新技术开发区","3717"],["41","河南省",""],["4101","郑州市","41"],["410102","中原区","4101"],["410103","二七区","4101"],["410104","管城回族区","4101"],["410105","金水区","4101"],["410106","上街区","4101"],["410108","惠济区","4101"],["410122","中牟县","4101"],["410171","郑州经济技术开发区","4101"],["410172","郑州高新技术产业开发区","4101"],["410173","郑州航空港经济综合实验区","4101"],["410181","巩义市","4101"],["410182","荥阳市","4101"],["410183","新密市","4101"],["410184","新郑市","4101"],["410185","登封市","4101"],["4102","开封市","41"],["410202","龙亭区","4102"],["410203","顺河回族区","4102"],["410204","鼓楼区","4102"],["410205","禹王台区","4102"],["410212","祥符区","4102"],["410221","杞县","4102"],["410222","通许县","4102"],["410223","尉氏县","4102"],["410225","兰考县","4102"],["4103","洛阳市","41"],["410302","老城区","4103"],["410303","西工区","4103"],["410304","瀍河回族区","4103"],["410305","涧西区","4103"],["410307","偃师区","4103"],["410308","孟津区","4103"],["410311","洛龙区","4103"],["410323","新安县","4103"],["410324","栾川县","4103"],["410325","嵩县","4103"],["410326","汝阳县","4103"],["410327","宜阳县","4103"],["410328","洛宁县","4103"],["410329","伊川县","4103"],["410371","洛阳高新技术产业开发区","4103"],["4104","平顶山市","41"],["410402","新华区","4104"],["410403","卫东区","4104"],["410404","石龙区","4104"],["410411","湛河区","4104"],["410421","宝丰县","4104"],["410422","叶县","4104"],["410423","鲁山县","4104"],["410425","郏县","4104"],["410471","平顶山高新技术产业开发区","4104"],["410472","平顶山市城乡一体化示范区","4104"],["410481","舞钢市","4104"],["410482","汝州市","4104"],["4105","安阳市","41"],["410502","文峰区","4105"],["410503","北关区","4105"],["410505","殷都区","4105"],["410506","龙安区","4105"],["410522","安阳县","4105"],["410523","汤阴县","4105"],["410526","滑县","4105"],["410527","内黄县","4105"],["410571","安阳高新技术产业开发区","4105"],["410581","林州市","4105"],["4106","鹤壁市","41"],["410602","鹤山区","4106"],["410603","山城区","4106"],["410611","淇滨区","4106"],["410621","浚县","4106"],["410622","淇县","4106"],["410671","鹤壁经济技术开发区","4106"],["4107","新乡市","41"],["410702","红旗区","4107"],["410703","卫滨区","4107"],["410704","凤泉区","4107"],["410711","牧野区","4107"],["410721","新乡县","4107"],["410724","获嘉县","4107"],["410725","原阳县","4107"],["410726","延津县","4107"],["410727","封丘县","4107"],["410771","新乡高新技术产业开发区","4107"],["410772","新乡经济技术开发区","4107"],["410773","新乡市平原城乡一体化示范区","4107"],["410781","卫辉市","4107"],["410782","辉县市","4107"],["410783","长垣市","4107"],["4108","焦作市","41"],["410802","解放区","4108"],["410803","中站区","4108"],["410804","马村区","4108"],["410811","山阳区","4108"],["410821","修武县","4108"],["410822","博爱县","4108"],["410823","武陟县","4108"],["410825","温县","4108"],["410871","焦作城乡一体化示范区","4108"],["410882","沁阳市","4108"],["410883","孟州市","4108"],["4109","濮阳市","41"],["410902","华龙区","4109"],["410922","清丰县","4109"],["410923","南乐县","4109"],["410926","范县","4109"],["410927","台前县","4109"],["410928","濮阳县","4109"],["410971","河南濮阳工业园区","4109"],["410972","濮阳经济技术开发区","4109"],["4110","许昌市","41"],["411002","魏都区","4110"],["411003","建安区","4110"],["411024","鄢陵县","4110"],["411025","襄城县","4110"],["411071","许昌经济技术开发区","4110"],["411081","禹州市","4110"],["411082","长葛市","4110"],["4111","漯河市","41"],["411102","源汇区","4111"],["411103","郾城区","4111"],["411104","召陵区","4111"],["411121","舞阳县","4111"],["411122","临颍县","4111"],["411171","漯河经济技术开发区","4111"],["4112","三门峡市","41"],["411202","湖滨区","4112"],["411203","陕州区","4112"],["411221","渑池县","4112"],["411224","卢氏县","4112"],["411271","河南三门峡经济开发区","4112"],["411281","义马市","4112"],["411282","灵宝市","4112"],["4113","南阳市","41"],["411302","宛城区","4113"],["411303","卧龙区","4113"],["411321","南召县","4113"],["411322","方城县","4113"],["411323","西峡县","4113"],["411324","镇平县","4113"],["411325","内乡县","4113"],["411326","淅川县","4113"],["411327","社旗县","4113"],["411328","唐河县","4113"],["411329","新野县","4113"],["411330","桐柏县","4113"],["411371","南阳高新技术产业开发区","4113"],["411372","南阳市城乡一体化示范区","4113"],["411381","邓州市","4113"],["4114","商丘市","41"],["411402","梁园区","4114"],["411403","睢阳区","4114"],["411421","民权县","4114"],["411422","睢县","4114"],["411423","宁陵县","4114"],["411424","柘城县","4114"],["411425","虞城县","4114"],["411426","夏邑县","4114"],["411471","豫东综合物流产业聚集区","4114"],["411472","河南商丘经济开发区","4114"],["411481","永城市","4114"],["4115","信阳市","41"],["411502","浉河区","4115"],["411503","平桥区","4115"],["411521","罗山县","4115"],["411522","光山县","4115"],["411523","新县","4115"],["411524","商城县","4115"],["411525","固始县","4115"],["411526","潢川县","4115"],["411527","淮滨县","4115"],["411528","息县","4115"],["411571","信阳高新技术产业开发区","4115"],["4116","周口市","41"],["411602","川汇区","4116"],["411603","淮阳区","4116"],["411621","扶沟县","4116"],["411622","西华县","4116"],["411623","商水县","4116"],["411624","沈丘县","4116"],["411625","郸城县","4116"],["411627","太康县","4116"],["411628","鹿邑县","4116"],["411671","周口临港开发区","4116"],["411681","项城市","4116"],["4117","驻马店市","41"],["411702","驿城区","4117"],["411721","西平县","4117"],["411722","上蔡县","4117"],["411723","平舆县","4117"],["411724","正阳县","4117"],["411725","确山县","4117"],["411726","泌阳县","4117"],["411727","汝南县","4117"],["411728","遂平县","4117"],["411729","新蔡县","4117"],["411771","河南驻马店经济开发区","4117"],["4190","省直辖县级行政区划","41"],["419001","济源市","4190"],["42","湖北省",""],["4201","武汉市","42"],["420102","江岸区","4201"],["420103","江汉区","4201"],["420104","硚口区","4201"],["420105","汉阳区","4201"],["420106","武昌区","4201"],["420107","青山区","4201"],["420111","洪山区","4201"],["420112","东西湖区","4201"],["420113","汉南区","4201"],["420114","蔡甸区","4201"],["420115","江夏区","4201"],["420116","黄陂区","4201"],["420117","新洲区","4201"],["4202","黄石市","42"],["420202","黄石港区","4202"],["420203","西塞山区","4202"],["420204","下陆区","4202"],["420205","铁山区","4202"],["420222","阳新县","4202"],["420281","大冶市","4202"],["4203","十堰市","42"],["420302","茅箭区","4203"],["420303","张湾区","4203"],["420304","郧阳区","4203"],["420322","郧西县","4203"],["420323","竹山县","4203"],["420324","竹溪县","4203"],["420325","房县","4203"],["420381","丹江口市","4203"],["4205","宜昌市","42"],["420502","西陵区","4205"],["420503","伍家岗区","4205"],["420504","点军区","4205"],["420505","猇亭区","4205"],["420506","夷陵区","4205"],["420525","远安县","4205"],["420526","兴山县","4205"],["420527","秭归县","4205"],["420528","长阳土家族自治县","4205"],["420529","五峰土家族自治县","4205"],["420581","宜都市","4205"],["420582","当阳市","4205"],["420583","枝江市","4205"],["4206","襄阳市","42"],["420602","襄城区","4206"],["420606","樊城区","4206"],["420607","襄州区","4206"],["420624","南漳县","4206"],["420625","谷城县","4206"],["420626","保康县","4206"],["420682","老河口市","4206"],["420683","枣阳市","4206"],["420684","宜城市","4206"],["4207","鄂州市","42"],["420702","梁子湖区","4207"],["420703","华容区","4207"],["420704","鄂城区","4207"],["4208","荆门市","42"],["420802","东宝区","4208"],["420804","掇刀区","4208"],["420822","沙洋县","4208"],["420881","钟祥市","4208"],["420882","京山市","4208"],["4209","孝感市","42"],["420902","孝南区","4209"],["420921","孝昌县","4209"],["420922","大悟县","4209"],["420923","云梦县","4209"],["420981","应城市","4209"],["420982","安陆市","4209"],["420984","汉川市","4209"],["4210","荆州市","42"],["421002","沙市区","4210"],["421003","荆州区","4210"],["421022","公安县","4210"],["421024","江陵县","4210"],["421071","荆州经济技术开发区","4210"],["421081","石首市","4210"],["421083","洪湖市","4210"],["421087","松滋市","4210"],["421088","监利市","4210"],["4211","黄冈市","42"],["421102","黄州区","4211"],["421121","团风县","4211"],["421122","红安县","4211"],["421123","罗田县","4211"],["421124","英山县","4211"],["421125","浠水县","4211"],["421126","蕲春县","4211"],["421127","黄梅县","4211"],["421171","龙感湖管理区","4211"],["421181","麻城市","4211"],["421182","武穴市","4211"],["4212","咸宁市","42"],["421202","咸安区","4212"],["421221","嘉鱼县","4212"],["421222","通城县","4212"],["421223","崇阳县","4212"],["421224","通山县","4212"],["421281","赤壁市","4212"],["4213","随州市","42"],["421303","曾都区","4213"],["421321","随县","4213"],["421381","广水市","4213"],["4228","恩施土家族苗族自治州","42"],["422801","恩施市","4228"],["422802","利川市","4228"],["422822","建始县","4228"],["422823","巴东县","4228"],["422825","宣恩县","4228"],["422826","咸丰县","4228"],["422827","来凤县","4228"],["422828","鹤峰县","4228"],["4290","省直辖县级行政区划","42"],["429004","仙桃市","4290"],["429005","潜江市","4290"],["429006","天门市","4290"],["429021","神农架林区","4290"],["43","湖南省",""],["4301","长沙市","43"],["430102","芙蓉区","4301"],["430103","天心区","4301"],["430104","岳麓区","4301"],["430105","开福区","4301"],["430111","雨花区","4301"],["430112","望城区","4301"],["430121","长沙县","4301"],["430181","浏阳市","4301"],["430182","宁乡市","4301"],["4302","株洲市","43"],["430202","荷塘区","4302"],["430203","芦淞区","4302"],["430204","石峰区","4302"],["430211","天元区","4302"],["430212","渌口区","4302"],["430223","攸县","4302"],["430224","茶陵县","4302"],["430225","炎陵县","4302"],["430281","醴陵市","4302"],["4303","湘潭市","43"],["430302","雨湖区","4303"],["430304","岳塘区","4303"],["430321","湘潭县","4303"],["430371","湖南湘潭高新技术产业园区","4303"],["430372","湘潭昭山示范区","4303"],["430373","湘潭九华示范区","4303"],["430381","湘乡市","4303"],["430382","韶山市","4303"],["4304","衡阳市","43"],["430405","珠晖区","4304"],["430406","雁峰区","4304"],["430407","石鼓区","4304"],["430408","蒸湘区","4304"],["430412","南岳区","4304"],["430421","衡阳县","4304"],["430422","衡南县","4304"],["430423","衡山县","4304"],["430424","衡东县","4304"],["430426","祁东县","4304"],["430473","湖南衡阳松木经济开发区","4304"],["430476","湖南衡阳高新技术产业园区","4304"],["430481","耒阳市","4304"],["430482","常宁市","4304"],["4305","邵阳市","43"],["430502","双清区","4305"],["430503","大祥区","4305"],["430511","北塔区","4305"],["430522","新邵县","4305"],["430523","邵阳县","4305"],["430524","隆回县","4305"],["430525","洞口县","4305"],["430527","绥宁县","4305"],["430528","新宁县","4305"],["430529","城步苗族自治县","4305"],["430581","武冈市","4305"],["430582","邵东市","4305"],["4306","岳阳市","43"],["430602","岳阳楼区","4306"],["430603","云溪区","4306"],["430611","君山区","4306"],["430621","岳阳县","4306"],["430623","华容县","4306"],["430624","湘阴县","4306"],["430626","平江县","4306"],["430671","岳阳市屈原管理区","4306"],["430681","汨罗市","4306"],["430682","临湘市","4306"],["4307","常德市","43"],["430702","武陵区","4307"],["430703","鼎城区","4307"],["430721","安乡县","4307"],["430722","汉寿县","4307"],["430723","澧县","4307"],["430724","临澧县","4307"],["430725","桃源县","4307"],["430726","石门县","4307"],["430771","常德市西洞庭管理区","4307"],["430781","津市市","4307"],["4308","张家界市","43"],["430802","永定区","4308"],["430811","武陵源区","4308"],["430821","慈利县","4308"],["430822","桑植县","4308"],["4309","益阳市","43"],["430902","资阳区","4309"],["430903","赫山区","4309"],["430921","南县","4309"],["430922","桃江县","4309"],["430923","安化县","4309"],["430971","益阳市大通湖管理区","4309"],["430972","湖南益阳高新技术产业园区","4309"],["430981","沅江市","4309"],["4310","郴州市","43"],["431002","北湖区","4310"],["431003","苏仙区","4310"],["431021","桂阳县","4310"],["431022","宜章县","4310"],["431023","永兴县","4310"],["431024","嘉禾县","4310"],["431025","临武县","4310"],["431026","汝城县","4310"],["431027","桂东县","4310"],["431028","安仁县","4310"],["431081","资兴市","4310"],["4311","永州市","43"],["431102","零陵区","4311"],["431103","冷水滩区","4311"],["431122","东安县","4311"],["431123","双牌县","4311"],["431124","道县","4311"],["431125","江永县","4311"],["431126","宁远县","4311"],["431127","蓝山县","4311"],["431128","新田县","4311"],["431129","江华瑶族自治县","4311"],["431171","永州经济技术开发区","4311"],["431173","永州市回龙圩管理区","4311"],["431181","祁阳市","4311"],["4312","怀化市","43"],["431202","鹤城区","4312"],["431221","中方县","4312"],["431222","沅陵县","4312"],["431223","辰溪县","4312"],["431224","溆浦县","4312"],["431225","会同县","4312"],["431226","麻阳苗族自治县","4312"],["431227","新晃侗族自治县","4312"],["431228","芷江侗族自治县","4312"],["431229","靖州苗族侗族自治县","4312"],["431230","通道侗族自治县","4312"],["431271","怀化市洪江管理区","4312"],["431281","洪江市","4312"],["4313","娄底市","43"],["431302","娄星区","4313"],["431321","双峰县","4313"],["431322","新化县","4313"],["431381","冷水江市","4313"],["431382","涟源市","4313"],["4331","湘西土家族苗族自治州","43"],["433101","吉首市","4331"],["433122","泸溪县","4331"],["433123","凤凰县","4331"],["433124","花垣县","4331"],["433125","保靖县","4331"],["433126","古丈县","4331"],["433127","永顺县","4331"],["433130","龙山县","4331"],["44","广东省",""],["4401","广州市","44"],["440103","荔湾区","4401"],["440104","越秀区","4401"],["440105","海珠区","4401"],["440106","天河区","4401"],["440111","白云区","4401"],["440112","黄埔区","4401"],["440113","番禺区","4401"],["440114","花都区","4401"],["440115","南沙区","4401"],["440117","从化区","4401"],["440118","增城区","4401"],["4402","韶关市","44"],["440203","武江区","4402"],["440204","浈江区","4402"],["440205","曲江区","4402"],["440222","始兴县","4402"],["440224","仁化县","4402"],["440229","翁源县","4402"],["440232","乳源瑶族自治县","4402"],["440233","新丰县","4402"],["440281","乐昌市","4402"],["440282","南雄市","4402"],["4403","深圳市","44"],["440303","罗湖区","4403"],["440304","福田区","4403"],["440305","南山区","4403"],["440306","宝安区","4403"],["440307","龙岗区","4403"],["440308","盐田区","4403"],["440309","龙华区","4403"],["440310","坪山区","4403"],["440311","光明区","4403"],["4404","珠海市","44"],["440402","香洲区","4404"],["440403","斗门区","4404"],["440404","金湾区","4404"],["4405","汕头市","44"],["440507","龙湖区","4405"],["440511","金平区","4405"],["440512","濠江区","4405"],["440513","潮阳区","4405"],["440514","潮南区","4405"],["440515","澄海区","4405"],["440523","南澳县","4405"],["4406","佛山市","44"],["440604","禅城区","4406"],["440605","南海区","4406"],["440606","顺德区","4406"],["440607","三水区","4406"],["440608","高明区","4406"],["4407","江门市","44"],["440703","蓬江区","4407"],["440704","江海区","4407"],["440705","新会区","4407"],["440781","台山市","4407"],["440783","开平市","4407"],["440784","鹤山市","4407"],["440785","恩平市","4407"],["4408","湛江市","44"],["440802","赤坎区","4408"],["440803","霞山区","4408"],["440804","坡头区","4408"],["440811","麻章区","4408"],["440823","遂溪县","4408"],["440825","徐闻县","4408"],["440881","廉江市","4408"],["440882","雷州市","4408"],["440883","吴川市","4408"],["4409","茂名市","44"],["440902","茂南区","4409"],["440904","电白区","4409"],["440981","高州市","4409"],["440982","化州市","4409"],["440983","信宜市","4409"],["4412","肇庆市","44"],["441202","端州区","4412"],["441203","鼎湖区","4412"],["441204","高要区","4412"],["441223","广宁县","4412"],["441224","怀集县","4412"],["441225","封开县","4412"],["441226","德庆县","4412"],["441284","四会市","4412"],["4413","惠州市","44"],["441302","惠城区","4413"],["441303","惠阳区","4413"],["441322","博罗县","4413"],["441323","惠东县","4413"],["441324","龙门县","4413"],["4414","梅州市","44"],["441402","梅江区","4414"],["441403","梅县区","4414"],["441422","大埔县","4414"],["441423","丰顺县","4414"],["441424","五华县","4414"],["441426","平远县","4414"],["441427","蕉岭县","4414"],["441481","兴宁市","4414"],["4415","汕尾市","44"],["441502","城区","4415"],["441521","海丰县","4415"],["441523","陆河县","4415"],["441581","陆丰市","4415"],["4416","河源市","44"],["441602","源城区","4416"],["441621","紫金县","4416"],["441622","龙川县","4416"],["441623","连平县","4416"],["441624","和平县","4416"],["441625","东源县","4416"],["4417","阳江市","44"],["441702","江城区","4417"],["441704","阳东区","4417"],["441721","阳西县","4417"],["441781","阳春市","4417"],["4418","清远市","44"],["441802","清城区","4418"],["441803","清新区","4418"],["441821","佛冈县","4418"],["441823","阳山县","4418"],["441825","连山壮族瑶族自治县","4418"],["441826","连南瑶族自治县","4418"],["441881","英德市","4418"],["441882","连州市","4418"],["4419","东莞市","44"],["441900003","东城街道","4419"],["441900004","南城街道","4419"],["441900005","万江街道","4419"],["441900006","莞城街道","4419"],["441900101","石碣镇","4419"],["441900102","石龙镇","4419"],["441900103","茶山镇","4419"],["441900104","石排镇","4419"],["441900105","企石镇","4419"],["441900106","横沥镇","4419"],["441900107","桥头镇","4419"],["441900108","谢岗镇","4419"],["441900109","东坑镇","4419"],["441900110","常平镇","4419"],["441900111","寮步镇","4419"],["441900112","樟木头镇","4419"],["441900113","大朗镇","4419"],["441900114","黄江镇","4419"],["441900115","清溪镇","4419"],["441900116","塘厦镇","4419"],["441900117","凤岗镇","4419"],["441900118","大岭山镇","4419"],["441900119","长安镇","4419"],["441900121","虎门镇","4419"],["441900122","厚街镇","4419"],["441900123","沙田镇","4419"],["441900124","道滘镇","4419"],["441900125","洪梅镇","4419"],["441900126","麻涌镇","4419"],["441900127","望牛墩镇","4419"],["441900128","中堂镇","4419"],["441900129","高埗镇","4419"],["441900401","松山湖","4419"],["441900402","东莞港","4419"],["441900403","东莞生态园","4419"],["441900404","东莞滨海湾新区","4419"],["4420","中山市","44"],["442000001","石岐街道","4420"],["442000002","东区街道","4420"],["442000003","中山港街道","4420"],["442000004","西区街道","4420"],["442000005","南区街道","4420"],["442000006","五桂山街道","4420"],["442000007","民众街道","4420"],["442000008","南朗街道","4420"],["442000101","黄圃镇","4420"],["442000103","东凤镇","4420"],["442000105","古镇镇","4420"],["442000106","沙溪镇","4420"],["442000107","坦洲镇","4420"],["442000108","港口镇","4420"],["442000109","三角镇","4420"],["442000110","横栏镇","4420"],["442000111","南头镇","4420"],["442000112","阜沙镇","4420"],["442000114","三乡镇","4420"],["442000115","板芙镇","4420"],["442000116","大涌镇","4420"],["442000117","神湾镇","4420"],["442000118","小榄镇","4420"],["4451","潮州市","44"],["445102","湘桥区","4451"],["445103","潮安区","4451"],["445122","饶平县","4451"],["4452","揭阳市","44"],["445202","榕城区","4452"],["445203","揭东区","4452"],["445222","揭西县","4452"],["445224","惠来县","4452"],["445281","普宁市","4452"],["4453","云浮市","44"],["445302","云城区","4453"],["445303","云安区","4453"],["445321","新兴县","4453"],["445322","郁南县","4453"],["445381","罗定市","4453"],["45","广西壮族自治区",""],["4501","南宁市","45"],["450102","兴宁区","4501"],["450103","青秀区","4501"],["450105","江南区","4501"],["450107","西乡塘区","4501"],["450108","良庆区","4501"],["450109","邕宁区","4501"],["450110","武鸣区","4501"],["450123","隆安县","4501"],["450124","马山县","4501"],["450125","上林县","4501"],["450126","宾阳县","4501"],["450181","横州市","4501"],["4502","柳州市","45"],["450202","城中区","4502"],["450203","鱼峰区","4502"],["450204","柳南区","4502"],["450205","柳北区","4502"],["450206","柳江区","4502"],["450222","柳城县","4502"],["450223","鹿寨县","4502"],["450224","融安县","4502"],["450225","融水苗族自治县","4502"],["450226","三江侗族自治县","4502"],["4503","桂林市","45"],["450302","秀峰区","4503"],["450303","叠彩区","4503"],["450304","象山区","4503"],["450305","七星区","4503"],["450311","雁山区","4503"],["450312","临桂区","4503"],["450321","阳朔县","4503"],["450323","灵川县","4503"],["450324","全州县","4503"],["450325","兴安县","4503"],["450326","永福县","4503"],["450327","灌阳县","4503"],["450328","龙胜各族自治县","4503"],["450329","资源县","4503"],["450330","平乐县","4503"],["450332","恭城瑶族自治县","4503"],["450381","荔浦市","4503"],["4504","梧州市","45"],["450403","万秀区","4504"],["450405","长洲区","4504"],["450406","龙圩区","4504"],["450421","苍梧县","4504"],["450422","藤县","4504"],["450423","蒙山县","4504"],["450481","岑溪市","4504"],["4505","北海市","45"],["450502","海城区","4505"],["450503","银海区","4505"],["450512","铁山港区","4505"],["450521","合浦县","4505"],["4506","防城港市","45"],["450602","港口区","4506"],["450603","防城区","4506"],["450621","上思县","4506"],["450681","东兴市","4506"],["4507","钦州市","45"],["450702","钦南区","4507"],["450703","钦北区","4507"],["450721","灵山县","4507"],["450722","浦北县","4507"],["4508","贵港市","45"],["450802","港北区","4508"],["450803","港南区","4508"],["450804","覃塘区","4508"],["450821","平南县","4508"],["450881","桂平市","4508"],["4509","玉林市","45"],["450902","玉州区","4509"],["450903","福绵区","4509"],["450921","容县","4509"],["450922","陆川县","4509"],["450923","博白县","4509"],["450924","兴业县","4509"],["450981","北流市","4509"],["4510","百色市","45"],["451002","右江区","4510"],["451003","田阳区","4510"],["451022","田东县","4510"],["451024","德保县","4510"],["451026","那坡县","4510"],["451027","凌云县","4510"],["451028","乐业县","4510"],["451029","田林县","4510"],["451030","西林县","4510"],["451031","隆林各族自治县","4510"],["451081","靖西市","4510"],["451082","平果市","4510"],["4511","贺州市","45"],["451102","八步区","4511"],["451103","平桂区","4511"],["451121","昭平县","4511"],["451122","钟山县","4511"],["451123","富川瑶族自治县","4511"],["4512","河池市","45"],["451202","金城江区","4512"],["451203","宜州区","4512"],["451221","南丹县","4512"],["451222","天峨县","4512"],["451223","凤山县","4512"],["451224","东兰县","4512"],["451225","罗城仫佬族自治县","4512"],["451226","环江毛南族自治县","4512"],["451227","巴马瑶族自治县","4512"],["451228","都安瑶族自治县","4512"],["451229","大化瑶族自治县","4512"],["4513","来宾市","45"],["451302","兴宾区","4513"],["451321","忻城县","4513"],["451322","象州县","4513"],["451323","武宣县","4513"],["451324","金秀瑶族自治县","4513"],["451381","合山市","4513"],["4514","崇左市","45"],["451402","江州区","4514"],["451421","扶绥县","4514"],["451422","宁明县","4514"],["451423","龙州县","4514"],["451424","大新县","4514"],["451425","天等县","4514"],["451481","凭祥市","4514"],["46","海南省",""],["4601","海口市","46"],["460105","秀英区","4601"],["460106","龙华区","4601"],["460107","琼山区","4601"],["460108","美兰区","4601"],["4602","三亚市","46"],["460202","海棠区","4602"],["460203","吉阳区","4602"],["460204","天涯区","4602"],["460205","崖州区","4602"],["4603","三沙市","46"],["460321","西沙群岛","4603"],["460322","南沙群岛","4603"],["460323","中沙群岛的岛礁及其海域","4603"],["4604","儋州市","46"],["460400100","那大镇","4604"],["460400101","和庆镇","4604"],["460400102","南丰镇","4604"],["460400103","大成镇","4604"],["460400104","雅星镇","4604"],["460400105","兰洋镇","4604"],["460400106","光村镇","4604"],["460400107","木棠镇","4604"],["460400108","海头镇","4604"],["460400109","峨蔓镇","4604"],["460400111","王五镇","4604"],["460400112","白马井镇","4604"],["460400113","中和镇","4604"],["460400114","排浦镇","4604"],["460400115","东成镇","4604"],["460400116","新州镇","4604"],["460400499","洋浦经济开发区","4604"],["460400500","华南热作学院","4604"],["4690","省直辖县级行政区划","46"],["469001","五指山市","4690"],["469002","琼海市","4690"],["469005","文昌市","4690"],["469006","万宁市","4690"],["469007","东方市","4690"],["469021","定安县","4690"],["469022","屯昌县","4690"],["469023","澄迈县","4690"],["469024","临高县","4690"],["469025","白沙黎族自治县","4690"],["469026","昌江黎族自治县","4690"],["469027","乐东黎族自治县","4690"],["469028","陵水黎族自治县","4690"],["469029","保亭黎族苗族自治县","4690"],["469030","琼中黎族苗族自治县","4690"],["50","重庆市",""],["5001","市辖区","50"],["500101","万州区","5001"],["500102","涪陵区","5001"],["500103","渝中区","5001"],["500104","大渡口区","5001"],["500105","江北区","5001"],["500106","沙坪坝区","5001"],["500107","九龙坡区","5001"],["500108","南岸区","5001"],["500109","北碚区","5001"],["500110","綦江区","5001"],["500111","大足区","5001"],["500112","渝北区","5001"],["500113","巴南区","5001"],["500114","黔江区","5001"],["500115","长寿区","5001"],["500116","江津区","5001"],["500117","合川区","5001"],["500118","永川区","5001"],["500119","南川区","5001"],["500120","璧山区","5001"],["500151","铜梁区","5001"],["500152","潼南区","5001"],["500153","荣昌区","5001"],["500154","开州区","5001"],["500155","梁平区","5001"],["500156","武隆区","5001"],["5002","县","50"],["500229","城口县","5002"],["500230","丰都县","5002"],["500231","垫江县","5002"],["500233","忠县","5002"],["500235","云阳县","5002"],["500236","奉节县","5002"],["500237","巫山县","5002"],["500238","巫溪县","5002"],["500240","石柱土家族自治县","5002"],["500241","秀山土家族苗族自治县","5002"],["500242","酉阳土家族苗族自治县","5002"],["500243","彭水苗族土家族自治县","5002"],["51","四川省",""],["5101","成都市","51"],["510104","锦江区","5101"],["510105","青羊区","5101"],["510106","金牛区","5101"],["510107","武侯区","5101"],["510108","成华区","5101"],["510112","龙泉驿区","5101"],["510113","青白江区","5101"],["510114","新都区","5101"],["510115","温江区","5101"],["510116","双流区","5101"],["510117","郫都区","5101"],["510118","新津区","5101"],["510121","金堂县","5101"],["510129","大邑县","5101"],["510131","蒲江县","5101"],["510181","都江堰市","5101"],["510182","彭州市","5101"],["510183","邛崃市","5101"],["510184","崇州市","5101"],["510185","简阳市","5101"],["5103","自贡市","51"],["510302","自流井区","5103"],["510303","贡井区","5103"],["510304","大安区","5103"],["510311","沿滩区","5103"],["510321","荣县","5103"],["510322","富顺县","5103"],["5104","攀枝花市","51"],["510402","东区","5104"],["510403","西区","5104"],["510411","仁和区","5104"],["510421","米易县","5104"],["510422","盐边县","5104"],["5105","泸州市","51"],["510502","江阳区","5105"],["510503","纳溪区","5105"],["510504","龙马潭区","5105"],["510521","泸县","5105"],["510522","合江县","5105"],["510524","叙永县","5105"],["510525","古蔺县","5105"],["5106","德阳市","51"],["510603","旌阳区","5106"],["510604","罗江区","5106"],["510623","中江县","5106"],["510681","广汉市","5106"],["510682","什邡市","5106"],["510683","绵竹市","5106"],["5107","绵阳市","51"],["510703","涪城区","5107"],["510704","游仙区","5107"],["510705","安州区","5107"],["510722","三台县","5107"],["510723","盐亭县","5107"],["510725","梓潼县","5107"],["510726","北川羌族自治县","5107"],["510727","平武县","5107"],["510781","江油市","5107"],["5108","广元市","51"],["510802","利州区","5108"],["510811","昭化区","5108"],["510812","朝天区","5108"],["510821","旺苍县","5108"],["510822","青川县","5108"],["510823","剑阁县","5108"],["510824","苍溪县","5108"],["5109","遂宁市","51"],["510903","船山区","5109"],["510904","安居区","5109"],["510921","蓬溪县","5109"],["510923","大英县","5109"],["510981","射洪市","5109"],["5110","内江市","51"],["511002","市中区","5110"],["511011","东兴区","5110"],["511024","威远县","5110"],["511025","资中县","5110"],["511083","隆昌市","5110"],["5111","乐山市","51"],["511102","市中区","5111"],["511111","沙湾区","5111"],["511112","五通桥区","5111"],["511113","金口河区","5111"],["511123","犍为县","5111"],["511124","井研县","5111"],["511126","夹江县","5111"],["511129","沐川县","5111"],["511132","峨边彝族自治县","5111"],["511133","马边彝族自治县","5111"],["511181","峨眉山市","5111"],["5113","南充市","51"],["511302","顺庆区","5113"],["511303","高坪区","5113"],["511304","嘉陵区","5113"],["511321","南部县","5113"],["511322","营山县","5113"],["511323","蓬安县","5113"],["511324","仪陇县","5113"],["511325","西充县","5113"],["511381","阆中市","5113"],["5114","眉山市","51"],["511402","东坡区","5114"],["511403","彭山区","5114"],["511421","仁寿县","5114"],["511423","洪雅县","5114"],["511424","丹棱县","5114"],["511425","青神县","5114"],["5115","宜宾市","51"],["511502","翠屏区","5115"],["511503","南溪区","5115"],["511504","叙州区","5115"],["511523","江安县","5115"],["511524","长宁县","5115"],["511525","高县","5115"],["511526","珙县","5115"],["511527","筠连县","5115"],["511528","兴文县","5115"],["511529","屏山县","5115"],["5116","广安市","51"],["511602","广安区","5116"],["511603","前锋区","5116"],["511621","岳池县","5116"],["511622","武胜县","5116"],["511623","邻水县","5116"],["511681","华蓥市","5116"],["5117","达州市","51"],["511702","通川区","5117"],["511703","达川区","5117"],["511722","宣汉县","5117"],["511723","开江县","5117"],["511724","大竹县","5117"],["511725","渠县","5117"],["511781","万源市","5117"],["5118","雅安市","51"],["511802","雨城区","5118"],["511803","名山区","5118"],["511822","荥经县","5118"],["511823","汉源县","5118"],["511824","石棉县","5118"],["511825","天全县","5118"],["511826","芦山县","5118"],["511827","宝兴县","5118"],["5119","巴中市","51"],["511902","巴州区","5119"],["511903","恩阳区","5119"],["511921","通江县","5119"],["511922","南江县","5119"],["511923","平昌县","5119"],["5120","资阳市","51"],["512002","雁江区","5120"],["512021","安岳县","5120"],["512022","乐至县","5120"],["5132","阿坝藏族羌族自治州","51"],["513201","马尔康市","5132"],["513221","汶川县","5132"],["513222","理县","5132"],["513223","茂县","5132"],["513224","松潘县","5132"],["513225","九寨沟县","5132"],["513226","金川县","5132"],["513227","小金县","5132"],["513228","黑水县","5132"],["513230","壤塘县","5132"],["513231","阿坝县","5132"],["513232","若尔盖县","5132"],["513233","红原县","5132"],["5133","甘孜藏族自治州","51"],["513301","康定市","5133"],["513322","泸定县","5133"],["513323","丹巴县","5133"],["513324","九龙县","5133"],["513325","雅江县","5133"],["513326","道孚县","5133"],["513327","炉霍县","5133"],["513328","甘孜县","5133"],["513329","新龙县","5133"],["513330","德格县","5133"],["513331","白玉县","5133"],["513332","石渠县","5133"],["513333","色达县","5133"],["513334","理塘县","5133"],["513335","巴塘县","5133"],["513336","乡城县","5133"],["513337","稻城县","5133"],["513338","得荣县","5133"],["5134","凉山彝族自治州","51"],["513401","西昌市","5134"],["513402","会理市","5134"],["513422","木里藏族自治县","5134"],["513423","盐源县","5134"],["513424","德昌县","5134"],["513426","会东县","5134"],["513427","宁南县","5134"],["513428","普格县","5134"],["513429","布拖县","5134"],["513430","金阳县","5134"],["513431","昭觉县","5134"],["513432","喜德县","5134"],["513433","冕宁县","5134"],["513434","越西县","5134"],["513435","甘洛县","5134"],["513436","美姑县","5134"],["513437","雷波县","5134"],["52","贵州省",""],["5201","贵阳市","52"],["520102","南明区","5201"],["520103","云岩区","5201"],["520111","花溪区","5201"],["520112","乌当区","5201"],["520113","白云区","5201"],["520115","观山湖区","5201"],["520121","开阳县","5201"],["520122","息烽县","5201"],["520123","修文县","5201"],["520181","清镇市","5201"],["5202","六盘水市","52"],["520201","钟山区","5202"],["520203","六枝特区","5202"],["520204","水城区","5202"],["520281","盘州市","5202"],["5203","遵义市","52"],["520302","红花岗区","5203"],["520303","汇川区","5203"],["520304","播州区","5203"],["520322","桐梓县","5203"],["520323","绥阳县","5203"],["520324","正安县","5203"],["520325","道真仡佬族苗族自治县","5203"],["520326","务川仡佬族苗族自治县","5203"],["520327","凤冈县","5203"],["520328","湄潭县","5203"],["520329","余庆县","5203"],["520330","习水县","5203"],["520381","赤水市","5203"],["520382","仁怀市","5203"],["5204","安顺市","52"],["520402","西秀区","5204"],["520403","平坝区","5204"],["520422","普定县","5204"],["520423","镇宁布依族苗族自治县","5204"],["520424","关岭布依族苗族自治县","5204"],["520425","紫云苗族布依族自治县","5204"],["5205","毕节市","52"],["520502","七星关区","5205"],["520521","大方县","5205"],["520523","金沙县","5205"],["520524","织金县","5205"],["520525","纳雍县","5205"],["520526","威宁彝族回族苗族自治县","5205"],["520527","赫章县","5205"],["520581","黔西市","5205"],["5206","铜仁市","52"],["520602","碧江区","5206"],["520603","万山区","5206"],["520621","江口县","5206"],["520622","玉屏侗族自治县","5206"],["520623","石阡县","5206"],["520624","思南县","5206"],["520625","印江土家族苗族自治县","5206"],["520626","德江县","5206"],["520627","沿河土家族自治县","5206"],["520628","松桃苗族自治县","5206"],["5223","黔西南布依族苗族自治州","52"],["522301","兴义市","5223"],["522302","兴仁市","5223"],["522323","普安县","5223"],["522324","晴隆县","5223"],["522325","贞丰县","5223"],["522326","望谟县","5223"],["522327","册亨县","5223"],["522328","安龙县","5223"],["5226","黔东南苗族侗族自治州","52"],["522601","凯里市","5226"],["522622","黄平县","5226"],["522623","施秉县","5226"],["522624","三穗县","5226"],["522625","镇远县","5226"],["522626","岑巩县","5226"],["522627","天柱县","5226"],["522628","锦屏县","5226"],["522629","剑河县","5226"],["522630","台江县","5226"],["522631","黎平县","5226"],["522632","榕江县","5226"],["522633","从江县","5226"],["522634","雷山县","5226"],["522635","麻江县","5226"],["522636","丹寨县","5226"],["5227","黔南布依族苗族自治州","52"],["522701","都匀市","5227"],["522702","福泉市","5227"],["522722","荔波县","5227"],["522723","贵定县","5227"],["522725","瓮安县","5227"],["522726","独山县","5227"],["522727","平塘县","5227"],["522728","罗甸县","5227"],["522729","长顺县","5227"],["522730","龙里县","5227"],["522731","惠水县","5227"],["522732","三都水族自治县","5227"],["53","云南省",""],["5301","昆明市","53"],["530102","五华区","5301"],["530103","盘龙区","5301"],["530111","官渡区","5301"],["530112","西山区","5301"],["530113","东川区","5301"],["530114","呈贡区","5301"],["530115","晋宁区","5301"],["530124","富民县","5301"],["530125","宜良县","5301"],["530126","石林彝族自治县","5301"],["530127","嵩明县","5301"],["530128","禄劝彝族苗族自治县","5301"],["530129","寻甸回族彝族自治县","5301"],["530181","安宁市","5301"],["5303","曲靖市","53"],["530302","麒麟区","5303"],["530303","沾益区","5303"],["530304","马龙区","5303"],["530322","陆良县","5303"],["530323","师宗县","5303"],["530324","罗平县","5303"],["530325","富源县","5303"],["530326","会泽县","5303"],["530381","宣威市","5303"],["5304","玉溪市","53"],["530402","红塔区","5304"],["530403","江川区","5304"],["530423","通海县","5304"],["530424","华宁县","5304"],["530425","易门县","5304"],["530426","峨山彝族自治县","5304"],["530427","新平彝族傣族自治县","5304"],["530428","元江哈尼族彝族傣族自治县","5304"],["530481","澄江市","5304"],["5305","保山市","53"],["530502","隆阳区","5305"],["530521","施甸县","5305"],["530523","龙陵县","5305"],["530524","昌宁县","5305"],["530581","腾冲市","5305"],["5306","昭通市","53"],["530602","昭阳区","5306"],["530621","鲁甸县","5306"],["530622","巧家县","5306"],["530623","盐津县","5306"],["530624","大关县","5306"],["530625","永善县","5306"],["530626","绥江县","5306"],["530627","镇雄县","5306"],["530628","彝良县","5306"],["530629","威信县","5306"],["530681","水富市","5306"],["5307","丽江市","53"],["530702","古城区","5307"],["530721","玉龙纳西族自治县","5307"],["530722","永胜县","5307"],["530723","华坪县","5307"],["530724","宁蒗彝族自治县","5307"],["5308","普洱市","53"],["530802","思茅区","5308"],["530821","宁洱哈尼族彝族自治县","5308"],["530822","墨江哈尼族自治县","5308"],["530823","景东彝族自治县","5308"],["530824","景谷傣族彝族自治县","5308"],["530825","镇沅彝族哈尼族拉祜族自治县","5308"],["530826","江城哈尼族彝族自治县","5308"],["530827","孟连傣族拉祜族佤族自治县","5308"],["530828","澜沧拉祜族自治县","5308"],["530829","西盟佤族自治县","5308"],["5309","临沧市","53"],["530902","临翔区","5309"],["530921","凤庆县","5309"],["530922","云县","5309"],["530923","永德县","5309"],["530924","镇康县","5309"],["530925","双江拉祜族佤族布朗族傣族自治县","5309"],["530926","耿马傣族佤族自治县","5309"],["530927","沧源佤族自治县","5309"],["5323","楚雄彝族自治州","53"],["532301","楚雄市","5323"],["532302","禄丰市","5323"],["532322","双柏县","5323"],["532323","牟定县","5323"],["532324","南华县","5323"],["532325","姚安县","5323"],["532326","大姚县","5323"],["532327","永仁县","5323"],["532328","元谋县","5323"],["532329","武定县","5323"],["5325","红河哈尼族彝族自治州","53"],["532501","个旧市","5325"],["532502","开远市","5325"],["532503","蒙自市","5325"],["532504","弥勒市","5325"],["532523","屏边苗族自治县","5325"],["532524","建水县","5325"],["532525","石屏县","5325"],["532527","泸西县","5325"],["532528","元阳县","5325"],["532529","红河县","5325"],["532530","金平苗族瑶族傣族自治县","5325"],["532531","绿春县","5325"],["532532","河口瑶族自治县","5325"],["5326","文山壮族苗族自治州","53"],["532601","文山市","5326"],["532622","砚山县","5326"],["532623","西畴县","5326"],["532624","麻栗坡县","5326"],["532625","马关县","5326"],["532626","丘北县","5326"],["532627","广南县","5326"],["532628","富宁县","5326"],["5328","西双版纳傣族自治州","53"],["532801","景洪市","5328"],["532822","勐海县","5328"],["532823","勐腊县","5328"],["5329","大理白族自治州","53"],["532901","大理市","5329"],["532922","漾濞彝族自治县","5329"],["532923","祥云县","5329"],["532924","宾川县","5329"],["532925","弥渡县","5329"],["532926","南涧彝族自治县","5329"],["532927","巍山彝族回族自治县","5329"],["532928","永平县","5329"],["532929","云龙县","5329"],["532930","洱源县","5329"],["532931","剑川县","5329"],["532932","鹤庆县","5329"],["5331","德宏傣族景颇族自治州","53"],["533102","瑞丽市","5331"],["533103","芒市","5331"],["533122","梁河县","5331"],["533123","盈江县","5331"],["533124","陇川县","5331"],["5333","怒江傈僳族自治州","53"],["533301","泸水市","5333"],["533323","福贡县","5333"],["533324","贡山独龙族怒族自治县","5333"],["533325","兰坪白族普米族自治县","5333"],["5334","迪庆藏族自治州","53"],["533401","香格里拉市","5334"],["533422","德钦县","5334"],["533423","维西傈僳族自治县","5334"],["54","西藏自治区",""],["5401","拉萨市","54"],["540102","城关区","5401"],["540103","堆龙德庆区","5401"],["540104","达孜区","5401"],["540121","林周县","5401"],["540122","当雄县","5401"],["540123","尼木县","5401"],["540124","曲水县","5401"],["540127","墨竹工卡县","5401"],["540171","格尔木藏青工业园区","5401"],["540172","拉萨经济技术开发区","5401"],["540173","西藏文化旅游创意园区","5401"],["540174","达孜工业园区","5401"],["5402","日喀则市","54"],["540202","桑珠孜区","5402"],["540221","南木林县","5402"],["540222","江孜县","5402"],["540223","定日县","5402"],["540224","萨迦县","5402"],["540225","拉孜县","5402"],["540226","昂仁县","5402"],["540227","谢通门县","5402"],["540228","白朗县","5402"],["540229","仁布县","5402"],["540230","康马县","5402"],["540231","定结县","5402"],["540232","仲巴县","5402"],["540233","亚东县","5402"],["540234","吉隆县","5402"],["540235","聂拉木县","5402"],["540236","萨嘎县","5402"],["540237","岗巴县","5402"],["5403","昌都市","54"],["540302","卡若区","5403"],["540321","江达县","5403"],["540322","贡觉县","5403"],["540323","类乌齐县","5403"],["540324","丁青县","5403"],["540325","察雅县","5403"],["540326","八宿县","5403"],["540327","左贡县","5403"],["540328","芒康县","5403"],["540329","洛隆县","5403"],["540330","边坝县","5403"],["5404","林芝市","54"],["540402","巴宜区","5404"],["540421","工布江达县","5404"],["540423","墨脱县","5404"],["540424","波密县","5404"],["540425","察隅县","5404"],["540426","朗县","5404"],["540481","米林市","5404"],["5405","山南市","54"],["540502","乃东区","5405"],["540521","扎囊县","5405"],["540522","贡嘎县","5405"],["540523","桑日县","5405"],["540524","琼结县","5405"],["540525","曲松县","5405"],["540526","措美县","5405"],["540527","洛扎县","5405"],["540528","加查县","5405"],["540529","隆子县","5405"],["540531","浪卡子县","5405"],["540581","错那市","5405"],["5406","那曲市","54"],["540602","色尼区","5406"],["540621","嘉黎县","5406"],["540622","比如县","5406"],["540623","聂荣县","5406"],["540624","安多县","5406"],["540625","申扎县","5406"],["540626","索县","5406"],["540627","班戈县","5406"],["540628","巴青县","5406"],["540629","尼玛县","5406"],["540630","双湖县","5406"],["5425","阿里地区","54"],["542521","普兰县","5425"],["542522","札达县","5425"],["542523","噶尔县","5425"],["542524","日土县","5425"],["542525","革吉县","5425"],["542526","改则县","5425"],["542527","措勤县","5425"],["61","陕西省",""],["6101","西安市","61"],["610102","新城区","6101"],["610103","碑林区","6101"],["610104","莲湖区","6101"],["610111","灞桥区","6101"],["610112","未央区","6101"],["610113","雁塔区","6101"],["610114","阎良区","6101"],["610115","临潼区","6101"],["610116","长安区","6101"],["610117","高陵区","6101"],["610118","鄠邑区","6101"],["610122","蓝田县","6101"],["610124","周至县","6101"],["6102","铜川市","61"],["610202","王益区","6102"],["610203","印台区","6102"],["610204","耀州区","6102"],["610222","宜君县","6102"],["6103","宝鸡市","61"],["610302","渭滨区","6103"],["610303","金台区","6103"],["610304","陈仓区","6103"],["610305","凤翔区","6103"],["610323","岐山县","6103"],["610324","扶风县","6103"],["610326","眉县","6103"],["610327","陇县","6103"],["610328","千阳县","6103"],["610329","麟游县","6103"],["610330","凤县","6103"],["610331","太白县","6103"],["6104","咸阳市","61"],["610402","秦都区","6104"],["610403","杨陵区","6104"],["610404","渭城区","6104"],["610422","三原县","6104"],["610423","泾阳县","6104"],["610424","乾县","6104"],["610425","礼泉县","6104"],["610426","永寿县","6104"],["610428","长武县","6104"],["610429","旬邑县","6104"],["610430","淳化县","6104"],["610431","武功县","6104"],["610481","兴平市","6104"],["610482","彬州市","6104"],["6105","渭南市","61"],["610502","临渭区","6105"],["610503","华州区","6105"],["610522","潼关县","6105"],["610523","大荔县","6105"],["610524","合阳县","6105"],["610525","澄城县","6105"],["610526","蒲城县","6105"],["610527","白水县","6105"],["610528","富平县","6105"],["610581","韩城市","6105"],["610582","华阴市","6105"],["6106","延安市","61"],["610602","宝塔区","6106"],["610603","安塞区","6106"],["610621","延长县","6106"],["610622","延川县","6106"],["610625","志丹县","6106"],["610626","吴起县","6106"],["610627","甘泉县","6106"],["610628","富县","6106"],["610629","洛川县","6106"],["610630","宜川县","6106"],["610631","黄龙县","6106"],["610632","黄陵县","6106"],["610681","子长市","6106"],["6107","汉中市","61"],["610702","汉台区","6107"],["610703","南郑区","6107"],["610722","城固县","6107"],["610723","洋县","6107"],["610724","西乡县","6107"],["610725","勉县","6107"],["610726","宁强县","6107"],["610727","略阳县","6107"],["610728","镇巴县","6107"],["610729","留坝县","6107"],["610730","佛坪县","6107"],["6108","榆林市","61"],["610802","榆阳区","6108"],["610803","横山区","6108"],["610822","府谷县","6108"],["610824","靖边县","6108"],["610825","定边县","6108"],["610826","绥德县","6108"],["610827","米脂县","6108"],["610828","佳县","6108"],["610829","吴堡县","6108"],["610830","清涧县","6108"],["610831","子洲县","6108"],["610881","神木市","6108"],["6109","安康市","61"],["610902","汉滨区","6109"],["610921","汉阴县","6109"],["610922","石泉县","6109"],["610923","宁陕县","6109"],["610924","紫阳县","6109"],["610925","岚皋县","6109"],["610926","平利县","6109"],["610927","镇坪县","6109"],["610929","白河县","6109"],["610981","旬阳市","6109"],["6110","商洛市","61"],["611002","商州区","6110"],["611021","洛南县","6110"],["611022","丹凤县","6110"],["611023","商南县","6110"],["611024","山阳县","6110"],["611025","镇安县","6110"],["611026","柞水县","6110"],["62","甘肃省",""],["6201","兰州市","62"],["620102","城关区","6201"],["620103","七里河区","6201"],["620104","西固区","6201"],["620105","安宁区","6201"],["620111","红古区","6201"],["620121","永登县","6201"],["620122","皋兰县","6201"],["620123","榆中县","6201"],["620171","兰州新区","6201"],["6202","嘉峪关市","62"],["620201001","雄关街道","6202"],["620201002","钢城街道","6202"],["620201100","新城镇","6202"],["620201101","峪泉镇","6202"],["620201102","文殊镇","6202"],["6203","金昌市","62"],["620302","金川区","6203"],["620321","永昌县","6203"],["6204","白银市","62"],["620402","白银区","6204"],["620403","平川区","6204"],["620421","靖远县","6204"],["620422","会宁县","6204"],["620423","景泰县","6204"],["6205","天水市","62"],["620502","秦州区","6205"],["620503","麦积区","6205"],["620521","清水县","6205"],["620522","秦安县","6205"],["620523","甘谷县","6205"],["620524","武山县","6205"],["620525","张家川回族自治县","6205"],["6206","武威市","62"],["620602","凉州区","6206"],["620621","民勤县","6206"],["620622","古浪县","6206"],["620623","天祝藏族自治县","6206"],["6207","张掖市","62"],["620702","甘州区","6207"],["620721","肃南裕固族自治县","6207"],["620722","民乐县","6207"],["620723","临泽县","6207"],["620724","高台县","6207"],["620725","山丹县","6207"],["6208","平凉市","62"],["620802","崆峒区","6208"],["620821","泾川县","6208"],["620822","灵台县","6208"],["620823","崇信县","6208"],["620825","庄浪县","6208"],["620826","静宁县","6208"],["620881","华亭市","6208"],["6209","酒泉市","62"],["620902","肃州区","6209"],["620921","金塔县","6209"],["620922","瓜州县","6209"],["620923","肃北蒙古族自治县","6209"],["620924","阿克塞哈萨克族自治县","6209"],["620981","玉门市","6209"],["620982","敦煌市","6209"],["6210","庆阳市","62"],["621002","西峰区","6210"],["621021","庆城县","6210"],["621022","环县","6210"],["621023","华池县","6210"],["621024","合水县","6210"],["621025","正宁县","6210"],["621026","宁县","6210"],["621027","镇原县","6210"],["6211","定西市","62"],["621102","安定区","6211"],["621121","通渭县","6211"],["621122","陇西县","6211"],["621123","渭源县","6211"],["621124","临洮县","6211"],["621125","漳县","6211"],["621126","岷县","6211"],["6212","陇南市","62"],["621202","武都区","6212"],["621221","成县","6212"],["621222","文县","6212"],["621223","宕昌县","6212"],["621224","康县","6212"],["621225","西和县","6212"],["621226","礼县","6212"],["621227","徽县","6212"],["621228","两当县","6212"],["6229","临夏回族自治州","62"],["622901","临夏市","6229"],["622921","临夏县","6229"],["622922","康乐县","6229"],["622923","永靖县","6229"],["622924","广河县","6229"],["622925","和政县","6229"],["622926","东乡族自治县","6229"],["622927","积石山保安族东乡族撒拉族自治县","6229"],["6230","甘南藏族自治州","62"],["623001","合作市","6230"],["623021","临潭县","6230"],["623022","卓尼县","6230"],["623023","舟曲县","6230"],["623024","迭部县","6230"],["623025","玛曲县","6230"],["623026","碌曲县","6230"],["623027","夏河县","6230"],["63","青海省",""],["6301","西宁市","63"],["630102","城东区","6301"],["630103","城中区","6301"],["630104","城西区","6301"],["630105","城北区","6301"],["630106","湟中区","6301"],["630121","大通回族土族自治县","6301"],["630123","湟源县","6301"],["6302","海东市","63"],["630202","乐都区","6302"],["630203","平安区","6302"],["630222","民和回族土族自治县","6302"],["630223","互助土族自治县","6302"],["630224","化隆回族自治县","6302"],["630225","循化撒拉族自治县","6302"],["6322","海北藏族自治州","63"],["632221","门源回族自治县","6322"],["632222","祁连县","6322"],["632223","海晏县","6322"],["632224","刚察县","6322"],["6323","黄南藏族自治州","63"],["632301","同仁市","6323"],["632322","尖扎县","6323"],["632323","泽库县","6323"],["632324","河南蒙古族自治县","6323"],["6325","海南藏族自治州","63"],["632521","共和县","6325"],["632522","同德县","6325"],["632523","贵德县","6325"],["632524","兴海县","6325"],["632525","贵南县","6325"],["6326","果洛藏族自治州","63"],["632621","玛沁县","6326"],["632622","班玛县","6326"],["632623","甘德县","6326"],["632624","达日县","6326"],["632625","久治县","6326"],["632626","玛多县","6326"],["6327","玉树藏族自治州","63"],["632701","玉树市","6327"],["632722","杂多县","6327"],["632723","称多县","6327"],["632724","治多县","6327"],["632725","囊谦县","6327"],["632726","曲麻莱县","6327"],["6328","海西蒙古族藏族自治州","63"],["632801","格尔木市","6328"],["632802","德令哈市","6328"],["632803","茫崖市","6328"],["632821","乌兰县","6328"],["632822","都兰县","6328"],["632823","天峻县","6328"],["632857","大柴旦行政委员会","6328"],["64","宁夏回族自治区",""],["6401","银川市","64"],["640104","兴庆区","6401"],["640105","西夏区","6401"],["640106","金凤区","6401"],["640121","永宁县","6401"],["640122","贺兰县","6401"],["640181","灵武市","6401"],["6402","石嘴山市","64"],["640202","大武口区","6402"],["640205","惠农区","6402"],["640221","平罗县","6402"],["6403","吴忠市","64"],["640302","利通区","6403"],["640303","红寺堡区","6403"],["640323","盐池县","6403"],["640324","同心县","6403"],["640381","青铜峡市","6403"],["6404","固原市","64"],["640402","原州区","6404"],["640422","西吉县","6404"],["640423","隆德县","6404"],["640424","泾源县","6404"],["640425","彭阳县","6404"],["6405","中卫市","64"],["640502","沙坡头区","6405"],["640521","中宁县","6405"],["640522","海原县","6405"],["65","新疆维吾尔自治区",""],["6501","乌鲁木齐市","65"],["650102","天山区","6501"],["650103","沙依巴克区","6501"],["650104","新市区","6501"],["650105","水磨沟区","6501"],["650106","头屯河区","6501"],["650107","达坂城区","6501"],["650109","米东区","6501"],["650121","乌鲁木齐县","6501"],["6502","克拉玛依市","65"],["650202","独山子区","6502"],["650203","克拉玛依区","6502"],["650204","白碱滩区","6502"],["650205","乌尔禾区","6502"],["6504","吐鲁番市","65"],["650402","高昌区","6504"],["650421","鄯善县","6504"],["650422","托克逊县","6504"],["6505","哈密市","65"],["650502","伊州区","6505"],["650521","巴里坤哈萨克自治县","6505"],["650522","伊吾县","6505"],["6523","昌吉回族自治州","65"],["652301","昌吉市","6523"],["652302","阜康市","6523"],["652323","呼图壁县","6523"],["652324","玛纳斯县","6523"],["652325","奇台县","6523"],["652327","吉木萨尔县","6523"],["652328","木垒哈萨克自治县","6523"],["6527","博尔塔拉蒙古自治州","65"],["652701","博乐市","6527"],["652702","阿拉山口市","6527"],["652722","精河县","6527"],["652723","温泉县","6527"],["6528","巴音郭楞蒙古自治州","65"],["652801","库尔勒市","6528"],["652822","轮台县","6528"],["652823","尉犁县","6528"],["652824","若羌县","6528"],["652825","且末县","6528"],["652826","焉耆回族自治县","6528"],["652827","和静县","6528"],["652828","和硕县","6528"],["652829","博湖县","6528"],["6529","阿克苏地区","65"],["652901","阿克苏市","6529"],["652902","库车市","6529"],["652922","温宿县","6529"],["652924","沙雅县","6529"],["652925","新和县","6529"],["652926","拜城县","6529"],["652927","乌什县","6529"],["652928","阿瓦提县","6529"],["652929","柯坪县","6529"],["6530","克孜勒苏柯尔克孜自治州","65"],["653001","阿图什市","6530"],["653022","阿克陶县","6530"],["653023","阿合奇县","6530"],["653024","乌恰县","6530"],["6531","喀什地区","65"],["653101","喀什市","6531"],["653121","疏附县","6531"],["653122","疏勒县","6531"],["653123","英吉沙县","6531"],["653124","泽普县","6531"],["653125","莎车县","6531"],["653126","叶城县","6531"],["653127","麦盖提县","6531"],["653128","岳普湖县","6531"],["653129","伽师县","6531"],["653130","巴楚县","6531"],["653131","塔什库尔干塔吉克自治县","6531"],["6532","和田地区","65"],["653201","和田市","6532"],["653221","和田县","6532"],["653222","墨玉县","6532"],["653223","皮山县","6532"],["653224","洛浦县","6532"],["653225","策勒县","6532"],["653226","于田县","6532"],["653227","民丰县","6532"],["6540","伊犁哈萨克自治州","65"],["654002","伊宁市","6540"],["654003","奎屯市","6540"],["654004","霍尔果斯市","6540"],["654021","伊宁县","6540"],["654022","察布查尔锡伯自治县","6540"],["654023","霍城县","6540"],["654024","巩留县","6540"],["654025","新源县","6540"],["654026","昭苏县","6540"],["654027","特克斯县","6540"],["654028","尼勒克县","6540"],["6542","塔城地区","65"],["654201","塔城市","6542"],["654202","乌苏市","6542"],["654203","沙湾市","6542"],["654221","额敏县","6542"],["654224","托里县","6542"],["654225","裕民县","6542"],["654226","和布克赛尔蒙古自治县","6542"],["6543","阿勒泰地区","65"],["654301","阿勒泰市","6543"],["654321","布尔津县","6543"],["654322","富蕴县","6543"],["654323","福海县","6543"],["654324","哈巴河县","6543"],["654325","青河县","6543"],["654326","吉木乃县","6543"],["6590","自治区直辖县级行政区划","65"],["659001","石河子市","6590"],["659002","阿拉尔市","6590"],["659003","图木舒克市","6590"],["659004","五家渠市","6590"],["659005","北屯市","6590"],["659006","铁门关市","6590"],["659007","双河市","6590"],["659008","可克达拉市","6590"],["659009","昆玉市","6590"],["659010","胡杨河市","6590"],["659011","新星市","6590"],["659012","白杨市","6590"]] \ No newline at end of file diff --git a/assets/js/app.js b/assets/js/app.js index b3796c8..6a1ad67 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -430,33 +430,76 @@ // 落库的是**整版布局**(每栏的有序 id 列表),一次提交写完 —— // 逐条提交会在中途留下自相矛盾的中间态(两个人暂时同号),刷新一下就变样。 // - // 没有这段 JS 也完全能用:卡片上的「⋯ → 调整分组」表单还在, - // 而且手机上 HTML5 拖放本来就不生效,那套表单就是窄屏的正路。 + // 🔴🔴 这一段**不用 HTML5 拖放**(dragstart/dragover/drop),改用 Pointer Events。 + // 换掉的原因(用户 2026-10-04 第 6 条:「chrome 下只有第一组可以拖动」): + // · HTML5 DnD 的拖放是浏览器在"协商"的:dragstart 之后必须由我们在 + // dragover 里持续 preventDefault 才允许放下,而一旦拖动过程中**改了 DOM** + // (本功能本来就要把卡片挪来挪去),Chrome 会中途撤销这次拖放 —— + // 表现就是"第一栏能拖,后面的栏拖着拖着就断了"。 + // · 它**没有自动滚动**:名册长了以后下面的分组在视口外,根本够不着。 + // · 手机上 HTML5 DnD 一律不生效(这条以前是靠「⋯」表单兜的)。 + // Pointer Events 三件事全都自己说了算:落点、自动滚动、触摸。 + // + // 没有这段 JS 也完全能用:行上的「分组」按钮(
里的表单)照样能改分组。 (function () { var roster = document.querySelector('.roster.is-droppable'); if (!roster || !window.FormData || !window.fetch) { return; } var url = roster.getAttribute('data-reorder'); var csrf = roster.getAttribute('data-csrf') || ''; - var dragging = null; - var noteEl = null; + var MIN_MOVE = 5; // 超过这个位移才算"在拖",否则只是点了一下 + var EDGE = 72; // 指针离视口上下边缘多少像素开始自动滚动 + var EDGE_SPD = 18; // 自动滚动速度(像素/帧) + var pending = null; // 按下但还没到门槛 + var dragging = null; // 真正在拖的那张卡 + var suppressClick = false; // 拖完要掐掉紧接着的那次 click(否则会跳进详情页) + var startPt = null; + var lastPt = null; + var rafId = 0; + var noteEl = null; function each(list, fn) { Array.prototype.forEach.call(list, fn); } + function blocks() { + return roster.querySelectorAll('.group-block'); + } + /** 从事件目标往上找那张可拖的卡片(点在卡片里的链接/表单上时也算这张卡) */ - function cardFrom(e) { - var t = e.target; + function cardFrom(node) { + var t = node; while (t && t !== roster) { - if (t.classList && t.classList.contains('person') - && t.getAttribute('draggable') === 'true') { - return t; - } + if (t.classList && t.classList.contains('person')) { return t; } t = t.parentNode; } return null; } - function blocks() { - return roster.querySelectorAll('.group-block'); + /** + * 这次按下该不该算"拖动"? + * + * ⚠️ 按钮 / 输入框 / 下拉 / 一律不算 —— 在那儿按下是"要用它", + * 不是"要拖这张卡"。唯一例外是 `.drag-handle`(它是专门用来抓的)。 + * ⚠️ 大链接 `.person-main` **算**:整行都能拖才顺手(这也是原来的手感), + * 靠 MIN_MOVE 门槛区分"点进去看详情"和"拖着走",并且拖过之后要掐掉那次 click。 + */ + function isControl(node) { + var t = node; + while (t && t !== roster) { + if (t.nodeType !== 1) { t = t.parentNode; continue; } + // ⚠️ 判定顺序不能乱:先认"专门用来抓的"和"整行那个大链接", + // 再认"点了就有别的作用的控件"。 + if (t.classList && t.classList.contains('drag-handle')) { return false; } + // `.person-main` 虽然是 (点它会进详情页),但整行都能拖才顺手 —— + // 靠 MIN_MOVE 区分"点"与"拖",拖过之后掐掉那次 click。 + if (t.classList && t.classList.contains('person-main')) { return false; } + if (t.getAttribute && t.getAttribute('data-no-drag') !== null) { return true; } + var tag = t.tagName; + if (tag === 'BUTTON' || tag === 'INPUT' || tag === 'SELECT' || tag === 'TEXTAREA' + || tag === 'SUMMARY' || tag === 'LABEL' || tag === 'A') { + return true; + } + t = t.parentNode; + } + return false; } /** 每栏人数与"空栏"标记跟着 DOM 走 —— 不然拖完之后标题上的「N 人」还是旧的 */ @@ -466,6 +509,12 @@ var nEl = b.querySelector('.group-n .n'); if (nEl) { nEl.textContent = String(n); } b.classList.toggle('is-empty', n === 0); + // 🔴 empty 的栏被 filter.js 标了 hidden(筛完没人剩就整栏收起)。 + // 拖了一张卡进来之后必须**把 hidden 也清掉** —— 只去掉 is-empty 没用: + // 作者样式里 .group-block 没有写 display,于是浏览器默认的 + // [hidden]{display:none} 照样生效,那一栏连同刚放进去的人一起看不见 + // (症状就是"拖到后面的分组里,松手什么都没有")。 + b.hidden = (n === 0); }); } @@ -518,51 +567,32 @@ }); } - roster.addEventListener('dragstart', function (e) { - var card = cardFrom(e); - if (!card) { return; } - // 「⋯」菜单里的下拉与按钮不参与拖动 —— 在那儿按下多半是想选项,不是想拖卡 - var t = e.target; - while (t && t !== roster) { - if (t.getAttribute && t.getAttribute('data-no-drag') !== null) { - e.preventDefault(); - return; - } - t = t.parentNode; - } - dragging = card; - roster.classList.add('is-dragging'); - card.classList.add('is-dragged'); - if (e.dataTransfer) { - e.dataTransfer.effectAllowed = 'move'; - try { e.dataTransfer.setData('text/plain', card.getAttribute('data-person')); } catch (err) { /* 老浏览器忽略 */ } - } - }); - - roster.addEventListener('dragover', function (e) { - if (!dragging) { return; } - var block = e.target && e.target.closest ? e.target.closest('.group-block') : null; - if (!block) { return; } - e.preventDefault(); - if (e.dataTransfer) { e.dataTransfer.dropEffect = 'move'; } + /** 按当前指针位置把拖着的卡插到正确的栏、正确的位置 */ + function placeAt(pt) { + // ⚠️ 落点必须用 elementFromPoint 现算:拖动的卡自己就在指针底下, + // 而它在 CSS 里是 pointer-events:none(见 .person.is-dragged), + // 所以拿到的永远是它**下面**那个元素 —— 正是落点。 + var under = document.elementFromPoint(pt.x, pt.y); + if (!under) { return; } + var block = under.closest ? under.closest('.group-block') : null; + if (!block || !roster.contains(block)) { return; } var grid = block.querySelector('.people-grid'); + if (!grid) { return; } + /* 落点判定(用户 2026-10-03 第 4 条:"好像只能往后调整,不能往前调整")。 - 名册已从网格改成**竖向列表**,所以: - 指针在某行的**上半部分** → 插到它前面;下半部分 → 插到它后面。 - ⚠️ 原来只记了"第一个满足 clientY < 中点 的卡片"然后 insertBefore —— - 当目标就在**当前拖着的这张之后**时,insertBefore 到它的位置 - 等于没动(因为 dragged 自己先被移走、后面的元素整体前移一位), - 于是"往前拖"看起来完全无效。现在改成显式记录"插到谁前面/后面", - 并且在计算时**排除 dragged 自己**,两种方向都成立。 */ + 名册是**竖向列表**,所以:指针在某行的**上半部分** → 插到它前面; + 下半部分 → 插到它后面。 + ⚠️ 候选里要**排除 dragging 自己**,否则它自己会变成参照物、 + 两个方向都会算成"不动"(这正是"往前拖无效"的根因)。 */ var kids = []; each(grid.querySelectorAll('.person'), function (c) { if (c !== dragging) { kids.push(c); } }); - var target = null; // 落点参照物 - var before = true; // 插到它的前面还是后面 + var target = null; // 落点参照物 + var before = true; // 插到它的前面还是后面 for (var i = 0; i < kids.length; i++) { var r = kids[i].getBoundingClientRect(); - if (e.clientY < r.top + r.height / 2) { + if (pt.y < r.top + r.height / 2) { target = kids[i]; before = true; break; @@ -571,29 +601,207 @@ before = false; } if (!target) { - grid.appendChild(dragging); + if (grid.lastChild !== dragging) { grid.appendChild(dragging); } } else if (before) { - grid.insertBefore(dragging, target); + if (target.previousSibling !== dragging) { grid.insertBefore(dragging, target); } } else { - grid.insertBefore(dragging, target.nextSibling); + if (target.nextSibling !== dragging) { grid.insertBefore(dragging, target.nextSibling); } } - }); + } - roster.addEventListener('drop', function (e) { - // 不 preventDefault 的话浏览器会按"跳到某个地址"处理,整页就跳走了 - if (dragging) { e.preventDefault(); } - }); + /** + * 自动滚动:指针靠近视口上下边缘时带着页面走。 + * 名册长到一千人时,下面的分组在视口外面 —— 没有它根本拖不过去。 + */ + function autoScroll() { + rafId = 0; + if (!dragging || !lastPt) { return; } + var dy = 0; + if (lastPt.y < EDGE) { dy = -Math.round(EDGE_SPD * (1 - lastPt.y / EDGE)); } + else if (lastPt.y > window.innerHeight - EDGE) { + dy = Math.round(EDGE_SPD * (1 - (window.innerHeight - lastPt.y) / EDGE)); + } + if (dy !== 0) { + window.scrollBy(0, dy); + placeAt(lastPt); + } + rafId = window.requestAnimationFrame(autoScroll); + } - roster.addEventListener('dragend', function () { - if (!dragging) { return; } + function beginDrag(card, pt) { + dragging = card; + roster.classList.add('is-dragging'); + card.classList.add('is-dragged'); + placeAt(pt); + if (!rafId) { rafId = window.requestAnimationFrame(autoScroll); } + } + + function endDrag() { + if (rafId) { window.cancelAnimationFrame(rafId); rafId = 0; } + if (!dragging) { pending = null; return; } dragging.classList.remove('is-dragged'); roster.classList.remove('is-dragging'); dragging = null; + pending = null; + // ⚠️ 紧接着的那次 click 要掐掉:指针从卡片上的链接按下、拖走了又松开, + // 浏览器会当成"点了那个链接"→ 直接跳进详情页,拖了半天等于白拖。 + suppressClick = true; + window.setTimeout(function () { suppressClick = false; }, 0); refreshCounts(); save(); + } + + roster.addEventListener('pointerdown', function (e) { + if (e.button !== 0 && e.pointerType === 'mouse') { return; } + var card = cardFrom(e.target); + if (!card) { return; } + // 触摸时整行都能拖会让页面没法上下滚 —— 触摸只认那个 ⠿ 手柄 + var fromHandle = !!(e.target.closest && e.target.closest('.drag-handle')); + if (e.pointerType !== 'mouse' && !fromHandle) { return; } + if (!fromHandle && isControl(e.target)) { return; } + pending = { card: card, id: e.pointerId, type: e.pointerType }; + startPt = { x: e.clientX, y: e.clientY }; + lastPt = { x: e.clientX, y: e.clientY }; + /* 🔴 空栏必须在**按下的这一刻**就露出来,不能等"真的开始拖"才露。 + 露出来会让页面变高、下面的分组整体下移 —— + 如果等到拖动开始才露,用户瞄准的那个位置在手指一动之后就跑了 + (症状:想拖到「未分类」,松手却落进了别的栏,或者干脆没动静)。 + 按下时就露,布局在**瞄准之前**已经稳定,之后全程不变。 + ⚠️ 只点一下不拖的情况:松手时会收回去(见下面的 pointerup); + 而"点一下"多半是点这一行看详情,页面本来就要跳走,看不到这一下。 */ + roster.classList.add('is-dragging'); + if (fromHandle) { e.preventDefault(); } // 别顺手选中文字 }); + + document.addEventListener('pointermove', function (e) { + if (pending && !dragging && e.pointerId === pending.id) { + if (Math.abs(e.clientX - startPt.x) < MIN_MOVE + && Math.abs(e.clientY - startPt.y) < MIN_MOVE) { + return; + } + beginDrag(pending.card, { x: e.clientX, y: e.clientY }); + } + if (!dragging) { return; } + lastPt = { x: e.clientX, y: e.clientY }; + placeAt(lastPt); + }); + + document.addEventListener('pointerup', function (e) { + if (dragging) { endDrag(); } + else if (pending && e.pointerId === pending.id) { + pending = null; + roster.classList.remove('is-dragging'); // 只是点了一下:把露出来的空栏收回去 + } + }); + document.addEventListener('pointercancel', function () { + if (dragging) { endDrag(); } + else if (pending) { + pending = null; + roster.classList.remove('is-dragging'); + } + }); + + // 拖完掐掉那一次 click(捕获阶段就拦,别等它冒泡到链接上) + document.addEventListener('click', function (e) { + if (!suppressClick) { return; } + e.preventDefault(); + e.stopPropagation(); + }, true); })(); + // ===== 地址:省 → 市 → 区 三级联动(用户 2026-10-04 第 4 条)===== + // + // 数据有 3429 条,一次性塞进页面会让表单页重一百多 KB,所以按级去取: + // 换了省就把「市」换成这个省下面的市、并把「区」清空;换了市同理。 + // + // ⚠️ 这是**纯增强**:服务端已经把当前这一条链(省→市→区)的选项渲染好了, + // 没有这段 JS 时三个下拉照样能选、照样能提交,只是换了省不会自动带出新的市。 + (function () { + var wrap = document.querySelector('[data-addr]'); + if (!wrap) { return; } + var src = wrap.getAttribute('data-src'); + var selProvince = wrap.querySelector('[data-addr-lvl="1"]'); + var selCity = wrap.querySelector('[data-addr-lvl="2"]'); + var selDistrict = wrap.querySelector('[data-addr-lvl="3"]'); + if (!selProvince || !src) { return; } + + var cache = {}; // 同一个父级取过一次就不再问(省下面那几个市来回切很常见) + + function fill(sel, items, keep) { + sel.innerHTML = ''; + var none = document.createElement('option'); + none.value = ''; + none.textContent = '(不填)'; + sel.appendChild(none); + Array.prototype.forEach.call(items, function (it) { + var o = document.createElement('option'); + o.value = it.name; + o.setAttribute('data-code', it.code); + o.textContent = it.name; + if (keep && keep === it.name) { o.selected = true; } + sel.appendChild(o); + }); + sel.setAttribute('data-code', ''); + } + + function codeOf(sel) { + var o = sel.selectedOptions && sel.selectedOptions[0]; + return (o && o.getAttribute('data-code')) || sel.getAttribute('data-code') || ''; + } + + function load(parent, done) { + var key = parent || '_root'; + if (cache[key]) { done(cache[key]); return; } + if (!window.fetch) { done([]); return; } + window.fetch(src + (parent ? '&parent=' + encodeURIComponent(parent) : ''), { + credentials: 'same-origin', + headers: { 'X-Requested-With': 'XMLHttpRequest' }, + }).then(function (r) { return r.ok ? r.json() : null; }) + .then(function (j) { + var items = (j && j.items) || []; + cache[key] = items; + done(items); + }).catch(function () { done([]); }); + } + + selProvince.addEventListener('change', function () { + var keep = selCity.value; + load(codeOf(selProvince), function (items) { + // ⚠️ 换了省之后**原来看中的市多半不在这个省里** —— + // 但也不一律清空:省没变只是重取了一次时,保留用户选过的那个。 + var still = false; + Array.prototype.forEach.call(items, function (it) { if (it.name === keep) { still = true; } }); + fill(selCity, items, still ? keep : ''); + fill(selDistrict, [], ''); + }); + }); + + if (selCity) { + selCity.addEventListener('change', function () { + load(codeOf(selCity), function (items) { + fill(selDistrict, items, selDistrict.value); + }); + }); + } + })(); + + // ===== 名册行的「分组」按钮:选中即提交 ===== + // 用事件委托:名册有几行就有几个这种表单,而且以后动态加进来的一样生效。 + // ⚠️ 只是"选中即提交"的锦上添花 —— 表单里那个「保存」按钮一直都在, + // 没有 JS(或 JS 出错)时照样能改分组,不会变成"点了没反应"。 + document.addEventListener('change', function (e) { + var inp = e.target; + if (!inp || inp.type !== 'radio' || inp.name !== 'group_id') { return; } + var form = inp.form; + if (!form || !form.classList || !form.classList.contains('pg-menu')) { return; } + // requestSubmit 才会跑浏览器的原生校验;老浏览器退回 submit() + if (typeof form.requestSubmit === 'function') { + form.requestSubmit(); + } else { + form.submit(); + } + }); + // ===== 点页面其它地方 / 按 Esc 就收起下拉菜单 ===== // 用户 2026-10-03 第 3 条:「菜单栏点击后面,应该自动关闭,不应该一直保持打开」。 // 原生
只在再点一次 summary(或按 Esc)时收起 —— 点别处一律不管, @@ -645,3 +853,220 @@ }); })(); })(); + +// ==================== Semi Design DatePicker(v24 第 9 批 #9) ==================== +// 用户点名「所有日期选择换 https://semi.design 的 DatePicker,样式与系统统一」。 +// 这里是**渐进增强**的升级层:templates/_datetime.php 照旧渲染原生「日期+时/分/秒」 +// 四字段(表单契约与服务端 read_dt_input() 不动),Semi 的资源(合计约 4 MB)只在 +// 页面上真出现 .dt-input 时才懒加载;加载成功 → 藏原生、挂 DatePicker、值回写原字段; +// 加载失败 → 原生控件原样可用,页面不会坏。 +(function () { + var boxes = Array.prototype.slice.call(document.querySelectorAll('.dt-input[data-dt]')); + var hasMonth = !!document.querySelector('input[type="month"]'); + if (!boxes.length && !hasMonth) { return; } + var meta = document.querySelector('meta[name="fb-semi"]'); + if (!meta) { return; } + var conf; + try { conf = JSON.parse(meta.getAttribute('content')); } catch (e) { return; } + if (!conf || !conf.css || !conf.react || !conf.dom || !conf.ui) { return; } + + function loadCss(href) { + return new Promise(function (res) { + var l = document.createElement('link'); + l.rel = 'stylesheet'; + l.href = href; + l.onload = function () { res(true); }; + l.onerror = function () { res(false); }; + document.head.appendChild(l); + }); + } + function loadJs(src) { + return new Promise(function (res, rej) { + var s = document.createElement('script'); + s.src = src; + s.onload = function () { res(); }; + s.onerror = function () { rej(new Error('加载失败: ' + src)); }; + document.head.appendChild(s); + }); + } + + function pad(n) { return (n < 10 ? '0' : '') + n; } + + function parseDT(str) { + // 'YYYY-MM-DD [HH:mm[:ss]]' → 本地时区 Date | undefined + var m = (str || '').trim().match(/^(\d{4})-(\d{1,2})-(\d{1,2})(?:[ T](\d{1,2}):(\d{1,2})(?::(\d{1,2}))?)?$/); + if (!m) { return undefined; } + var d = new Date(+m[1], +m[2] - 1, +m[3], +(m[4] || 0), +(m[5] || 0), +(m[6] || 0)); + return isNaN(d.getTime()) ? undefined : d; + } + + function part(native, sel) { + var n = native.querySelector(sel); + return n ? String(n.value || '') : ''; + } + + function upgrade(box) { + if (box.getAttribute('data-semi-done')) { return; } + if (typeof window.SemiUI === 'undefined' || !window.SemiUI.DatePicker) { return; } + if (!window.ReactDOM || !window.ReactDOM.createRoot) { return; } + var cfg = {}; + try { cfg = JSON.parse(box.getAttribute('data-dt') || '{}'); } catch (e) { /* 空配置按默认走 */ } + var host = box.querySelector('.dt-semi'); + var native = box.querySelector('.dt-native'); + if (!host || !native) { return; } + + var fmt = 'yyyy-MM-dd HH:mm' + (cfg.seconds === false ? '' : ':ss'); + var init = parseDT( + part(native, '.dt-date') + ' ' + + (part(native, '.dt-hour') || '00') + ':' + + (part(native, '.dt-minute') || '00') + ':' + + (part(native, '.dt-second') || '00') + ); + + // Semi 的 onChange → 写回原生四字段(POST 契约),并派 change 事件给可能的监听者 + function writeBack(date, str) { + var m = (str || '').trim().match(/^(\d{4})-(\d{1,2})-(\d{1,2})[ T](\d{1,2}):(\d{1,2})(?::(\d{1,2}))?$/); + function set(sel, v) { + var n = box.querySelector(sel); + if (!n || n.value === v) { return; } + n.value = v; + n.dispatchEvent(new Event('change', { bubbles: true })); + } + if (m) { + set('.dt-date', m[1] + '-' + pad(+m[2]) + '-' + pad(+m[3])); + set('.dt-hour', pad(+m[4])); + set('.dt-minute', pad(+m[5])); + set('.dt-second', pad(+(m[6] || 0))); + } else { + set('.dt-date', ''); + set('.dt-hour', '00'); + set('.dt-minute', '00'); + set('.dt-second', '00'); + } + } + + try { + ReactDOM.createRoot(host).render(React.createElement(SemiUI.DatePicker, { + type: 'dateTime', + format: fmt, + showClear: true, + defaultValue: init, + placeholder: '选择日期时间', + position: window.matchMedia('(max-width: 640px)').matches ? 'bottom' : 'bottomLeft', + onChange: writeBack + })); + } catch (e) { + if (window.console) { console.warn('Semi DatePicker 挂载失败,留在原生控件:', e && e.message); } + return; + } + + box.classList.add('is-semi'); + native.style.display = 'none'; + if (init) { box.classList.add('has-value'); } + // required 不能留在 display:none 的输入上(Chrome 会拦提交却不显示提示), + // 改成提交前自己查一遍。 + var req = native.querySelector('.dt-date[required]'); + if (req) { + req.removeAttribute('required'); + box.setAttribute('data-required', '1'); + var form = box.closest('form'); + if (form && !form.getAttribute('data-dt-guard')) { + form.setAttribute('data-dt-guard', '1'); + form.addEventListener('submit', function (ev) { + // 不能用 :not([value]) 这类选择器:value 是动态写回的属性,得手动筛 + var bad = []; + form.querySelectorAll('.dt-input[data-required="1"]').forEach(function (b) { + var d = b.querySelector('.dt-date'); + if (d && !d.value) { bad.push(b); } + }); + if (bad.length) { + ev.preventDefault(); + bad.forEach(function (b) { b.classList.add('dt-missing'); }); + var inp = bad[0].querySelector('.dt-semi input'); + if (inp) { inp.focus(); } + } + }); + } + } + box.setAttribute('data-semi-done', '1'); + } + + var kicked = false; + function boot() { + if (kicked) { return; } + kicked = true; + loadCss(conf.css); + loadJs(conf.react) + .then(function () { return loadJs(conf.dom); }) + .then(function () { return loadJs(conf.ui); }) + .then(function () { + boxes.forEach(upgrade); + upgradeAllMonths(); + watchNewMonths(); + }) + .catch(function (err) { + // 资源拉不动就留在原生控件上 —— 渐进增强的兜底,不弹任何打扰 + if (window.console) { console.warn('Semi DatePicker 未启用:', err && err.message); } + }); + } + + // ---- 工作经历的 (YYYY-MM)也换 Semi DatePicker ---- + // 原生 type="month" Firefox 压根不支持;同样渐进增强:原 input 藏起来当值载体, + // POST 契约(job_start[]/job_end[])不变。「再加一段」新增的行由 observer 补挂。 + function parseYm(str) { + var m = (str || '').trim().match(/^(\d{4})-(\d{1,2})$/); + if (!m) { return undefined; } + var d = new Date(+m[1], +m[2] - 1, 1); + return isNaN(d.getTime()) ? undefined : d; + } + + function upgradeMonth(inp) { + if (inp.getAttribute('data-semi-month')) { return; } + inp.setAttribute('data-semi-month', '1'); + var host = document.createElement('span'); + host.className = 'dt-semi dt-semi-month'; + inp.parentNode.insertBefore(host, inp); + try { + ReactDOM.createRoot(host).render(React.createElement(SemiUI.DatePicker, { + type: 'month', + format: 'yyyy-MM', + showClear: true, + defaultValue: parseYm(inp.value), + placeholder: '选择年月', + position: window.matchMedia('(max-width: 640px)').matches ? 'bottom' : 'bottomLeft', + onChange: function (date, str) { + var v = (str || '').trim(); + if (inp.value !== v) { + inp.value = v; + inp.dispatchEvent(new Event('change', { bubbles: true })); + } + } + })); + } catch (e) { + if (window.console) { console.warn('月份选择器挂载失败,留在原生控件:', e && e.message); } + return; + } + host.classList.add('is-live'); + inp.style.display = 'none'; + } + + function upgradeAllMonths() { + Array.prototype.forEach.call(document.querySelectorAll('input[type="month"]'), upgradeMonth); + } + + function watchNewMonths() { + if (!window.MutationObserver) { return; } + var timer = null; + new MutationObserver(function () { + if (timer) { return; } + timer = setTimeout(function () { + timer = null; + upgradeAllMonths(); + }, 200); + }).observe(document.body, { childList: true, subtree: true }); + } + + // 错开首屏:idle 时再拉 4 MB 资源,别挡首屏渲染 + if ('requestIdleCallback' in window) { requestIdleCallback(boot, { timeout: 3000 }); } + else { setTimeout(boot, 500); } +})(); diff --git a/assets/vendor/semi/react-dom.min.js b/assets/vendor/semi/react-dom.min.js new file mode 100644 index 0000000..fb4e099 --- /dev/null +++ b/assets/vendor/semi/react-dom.min.js @@ -0,0 +1,267 @@ +/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +(function(){/* + Modernizr 3.0.0pre (Custom Build) | MIT +*/ +'use strict';(function(Q,zb){"object"===typeof exports&&"undefined"!==typeof module?zb(exports,require("react")):"function"===typeof define&&define.amd?define(["exports","react"],zb):(Q=Q||self,zb(Q.ReactDOM={},Q.React))})(this,function(Q,zb){function m(a){for(var b="https://reactjs.org/docs/error-decoder.html?invariant="+a,c=1;cb}return!1}function Y(a,b,c,d,e,f,g){this.acceptsBooleans=2===b||3===b||4===b;this.attributeName=d;this.attributeNamespace=e;this.mustUseProperty=c;this.propertyName=a;this.type=b;this.sanitizeURL=f;this.removeEmptyString=g}function $d(a,b,c,d){var e=R.hasOwnProperty(b)?R[b]:null;if(null!==e?0!==e.type:d||!(2h||e[g]!==f[h]){var k="\n"+e[g].replace(" at new "," at ");a.displayName&&k.includes("")&&(k=k.replace("",a.displayName));return k}while(1<=g&&0<=h)}break}}}finally{ce=!1,Error.prepareStackTrace=c}return(a=a?a.displayName||a.name:"")?bc(a): +""}function fj(a){switch(a.tag){case 5:return bc(a.type);case 16:return bc("Lazy");case 13:return bc("Suspense");case 19:return bc("SuspenseList");case 0:case 2:case 15:return a=be(a.type,!1),a;case 11:return a=be(a.type.render,!1),a;case 1:return a=be(a.type,!0),a;default:return""}}function de(a){if(null==a)return null;if("function"===typeof a)return a.displayName||a.name||null;if("string"===typeof a)return a;switch(a){case Bb:return"Fragment";case Cb:return"Portal";case ee:return"Profiler";case fe:return"StrictMode"; +case ge:return"Suspense";case he:return"SuspenseList"}if("object"===typeof a)switch(a.$$typeof){case gg:return(a.displayName||"Context")+".Consumer";case hg:return(a._context.displayName||"Context")+".Provider";case ie:var b=a.render;a=a.displayName;a||(a=b.displayName||b.name||"",a=""!==a?"ForwardRef("+a+")":"ForwardRef");return a;case je:return b=a.displayName||null,null!==b?b:de(a.type)||"Memo";case Ta:b=a._payload;a=a._init;try{return de(a(b))}catch(c){}}return null}function gj(a){var b=a.type; +switch(a.tag){case 24:return"Cache";case 9:return(b.displayName||"Context")+".Consumer";case 10:return(b._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return a=b.render,a=a.displayName||a.name||"",b.displayName||(""!==a?"ForwardRef("+a+")":"ForwardRef");case 7:return"Fragment";case 5:return b;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return de(b);case 8:return b===fe?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler"; +case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if("function"===typeof b)return b.displayName||b.name||null;if("string"===typeof b)return b}return null}function Ua(a){switch(typeof a){case "boolean":case "number":case "string":case "undefined":return a;case "object":return a;default:return""}}function ig(a){var b=a.type;return(a=a.nodeName)&&"input"===a.toLowerCase()&&("checkbox"===b||"radio"=== +b)}function hj(a){var b=ig(a)?"checked":"value",c=Object.getOwnPropertyDescriptor(a.constructor.prototype,b),d=""+a[b];if(!a.hasOwnProperty(b)&&"undefined"!==typeof c&&"function"===typeof c.get&&"function"===typeof c.set){var e=c.get,f=c.set;Object.defineProperty(a,b,{configurable:!0,get:function(){return e.call(this)},set:function(a){d=""+a;f.call(this,a)}});Object.defineProperty(a,b,{enumerable:c.enumerable});return{getValue:function(){return d},setValue:function(a){d=""+a},stopTracking:function(){a._valueTracker= +null;delete a[b]}}}}function Pc(a){a._valueTracker||(a._valueTracker=hj(a))}function jg(a){if(!a)return!1;var b=a._valueTracker;if(!b)return!0;var c=b.getValue();var d="";a&&(d=ig(a)?a.checked?"true":"false":a.value);a=d;return a!==c?(b.setValue(a),!0):!1}function Qc(a){a=a||("undefined"!==typeof document?document:void 0);if("undefined"===typeof a)return null;try{return a.activeElement||a.body}catch(b){return a.body}}function ke(a,b){var c=b.checked;return E({},b,{defaultChecked:void 0,defaultValue:void 0, +value:void 0,checked:null!=c?c:a._wrapperState.initialChecked})}function kg(a,b){var c=null==b.defaultValue?"":b.defaultValue,d=null!=b.checked?b.checked:b.defaultChecked;c=Ua(null!=b.value?b.value:c);a._wrapperState={initialChecked:d,initialValue:c,controlled:"checkbox"===b.type||"radio"===b.type?null!=b.checked:null!=b.value}}function lg(a,b){b=b.checked;null!=b&&$d(a,"checked",b,!1)}function le(a,b){lg(a,b);var c=Ua(b.value),d=b.type;if(null!=c)if("number"===d){if(0===c&&""===a.value||a.value!= +c)a.value=""+c}else a.value!==""+c&&(a.value=""+c);else if("submit"===d||"reset"===d){a.removeAttribute("value");return}b.hasOwnProperty("value")?me(a,b.type,c):b.hasOwnProperty("defaultValue")&&me(a,b.type,Ua(b.defaultValue));null==b.checked&&null!=b.defaultChecked&&(a.defaultChecked=!!b.defaultChecked)}function mg(a,b,c){if(b.hasOwnProperty("value")||b.hasOwnProperty("defaultValue")){var d=b.type;if(!("submit"!==d&&"reset"!==d||void 0!==b.value&&null!==b.value))return;b=""+a._wrapperState.initialValue; +c||b===a.value||(a.value=b);a.defaultValue=b}c=a.name;""!==c&&(a.name="");a.defaultChecked=!!a._wrapperState.initialChecked;""!==c&&(a.name=c)}function me(a,b,c){if("number"!==b||Qc(a.ownerDocument)!==a)null==c?a.defaultValue=""+a._wrapperState.initialValue:a.defaultValue!==""+c&&(a.defaultValue=""+c)}function Db(a,b,c,d){a=a.options;if(b){b={};for(var e=0;e>>=0;return 0===a?32:31-(qj(a)/rj|0)|0}function hc(a){switch(a&-a){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return a& +4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return a&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return a}}function Vc(a,b){var c=a.pendingLanes;if(0===c)return 0;var d=0,e=a.suspendedLanes,f=a.pingedLanes,g=c&268435455;if(0!==g){var h=g&~e;0!==h?d=hc(h):(f&=g,0!==f&&(d=hc(f)))}else g=c&~e,0!==g?d=hc(g):0!==f&&(d=hc(f));if(0===d)return 0;if(0!==b&&b!==d&&0===(b&e)&& +(e=d&-d,f=b&-b,e>=f||16===e&&0!==(f&4194240)))return b;0!==(d&4)&&(d|=c&16);b=a.entangledLanes;if(0!==b)for(a=a.entanglements,b&=d;0c;c++)b.push(a); +return b}function ic(a,b,c){a.pendingLanes|=b;536870912!==b&&(a.suspendedLanes=0,a.pingedLanes=0);a=a.eventTimes;b=31-ta(b);a[b]=c}function uj(a,b){var c=a.pendingLanes&~b;a.pendingLanes=b;a.suspendedLanes=0;a.pingedLanes=0;a.expiredLanes&=b;a.mutableReadLanes&=b;a.entangledLanes&=b;b=a.entanglements;var d=a.eventTimes;for(a=a.expirationTimes;0=b)return{node:c,offset:b-a};a=d}a:{for(;c;){if(c.nextSibling){c=c.nextSibling;break a}c=c.parentNode}c=void 0}c=$g(c)}}function bh(a,b){return a&&b?a===b?!0:a&&3===a.nodeType?!1:b&&3===b.nodeType?bh(a,b.parentNode):"contains"in a?a.contains(b):a.compareDocumentPosition?!!(a.compareDocumentPosition(b)&16):!1:!1}function ch(){for(var a=window,b=Qc();b instanceof a.HTMLIFrameElement;){try{var c="string"===typeof b.contentWindow.location.href}catch(d){c=!1}if(c)a=b.contentWindow;else break; +b=Qc(a.document)}return b}function Ie(a){var b=a&&a.nodeName&&a.nodeName.toLowerCase();return b&&("input"===b&&("text"===a.type||"search"===a.type||"tel"===a.type||"url"===a.type||"password"===a.type)||"textarea"===b||"true"===a.contentEditable)}function Tj(a){var b=ch(),c=a.focusedElem,d=a.selectionRange;if(b!==c&&c&&c.ownerDocument&&bh(c.ownerDocument.documentElement,c)){if(null!==d&&Ie(c))if(b=d.start,a=d.end,void 0===a&&(a=b),"selectionStart"in c)c.selectionStart=b,c.selectionEnd=Math.min(a,c.value.length); +else if(a=(b=c.ownerDocument||document)&&b.defaultView||window,a.getSelection){a=a.getSelection();var e=c.textContent.length,f=Math.min(d.start,e);d=void 0===d.end?f:Math.min(d.end,e);!a.extend&&f>d&&(e=d,d=f,f=e);e=ah(c,f);var g=ah(c,d);e&&g&&(1!==a.rangeCount||a.anchorNode!==e.node||a.anchorOffset!==e.offset||a.focusNode!==g.node||a.focusOffset!==g.offset)&&(b=b.createRange(),b.setStart(e.node,e.offset),a.removeAllRanges(),f>d?(a.addRange(b),a.extend(g.node,g.offset)):(b.setEnd(g.node,g.offset), +a.addRange(b)))}b=[];for(a=c;a=a.parentNode;)1===a.nodeType&&b.push({element:a,left:a.scrollLeft,top:a.scrollTop});"function"===typeof c.focus&&c.focus();for(c=0;cMb||(a.current=Se[Mb],Se[Mb]=null,Mb--)} +function y(a,b,c){Mb++;Se[Mb]=a.current;a.current=b}function Nb(a,b){var c=a.type.contextTypes;if(!c)return cb;var d=a.stateNode;if(d&&d.__reactInternalMemoizedUnmaskedChildContext===b)return d.__reactInternalMemoizedMaskedChildContext;var e={},f;for(f in c)e[f]=b[f];d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=b,a.__reactInternalMemoizedMaskedChildContext=e);return e}function ea(a){a=a.childContextTypes;return null!==a&&void 0!==a}function th(a,b,c){if(J.current!==cb)throw Error(m(168)); +y(J,b);y(S,c)}function uh(a,b,c){var d=a.stateNode;b=b.childContextTypes;if("function"!==typeof d.getChildContext)return c;d=d.getChildContext();for(var e in d)if(!(e in b))throw Error(m(108,gj(a)||"Unknown",e));return E({},c,d)}function ld(a){a=(a=a.stateNode)&&a.__reactInternalMemoizedMergedChildContext||cb;pb=J.current;y(J,a);y(S,S.current);return!0}function vh(a,b,c){var d=a.stateNode;if(!d)throw Error(m(169));c?(a=uh(a,b,pb),d.__reactInternalMemoizedMergedChildContext=a,v(S),v(J),y(J,a)):v(S); +y(S,c)}function wh(a){null===La?La=[a]:La.push(a)}function jk(a){md=!0;wh(a)}function db(){if(!Te&&null!==La){Te=!0;var a=0,b=z;try{var c=La;for(z=1;a>=g;e-=g;Ma=1<<32-ta(b)+e|c<t?(q=l,l=null):q=l.sibling;var A=r(e,l,h[t],k);if(null===A){null===l&&(l=q);break}a&&l&&null===A.alternate&&b(e,l);g=f(A,g,t);null===m?n=A:m.sibling=A;m=A;l=q}if(t===h.length)return c(e,l),D&&qb(e,t),n;if(null===l){for(;t< +h.length;t++)l=u(e,h[t],k),null!==l&&(g=f(l,g,t),null===m?n=l:m.sibling=l,m=l);D&&qb(e,t);return n}for(l=d(e,l);tt?(A=q,q=null):A=q.sibling;var x=r(e,q,w.value,k);if(null===x){null===q&&(q=A);break}a&&q&&null===x.alternate&&b(e,q);g=f(x,g,t);null===l?n=x:l.sibling=x;l=x;q=A}if(w.done)return c(e,q),D&&qb(e,t),n;if(null===q){for(;!w.done;t++,w=h.next())w=u(e,w.value,k),null!==w&&(g=f(w,g,t),null===l?n=w:l.sibling=w,l=w);D&&qb(e,t);return n}for(q=d(e,q);!w.done;t++,w=h.next())w=p(q,e,t,w.value,k),null!==w&&(a&&null!==w.alternate&&q.delete(null===w.key?t:w.key),g=f(w,g,t),null===l?n=w:l.sibling= +w,l=w);a&&q.forEach(function(a){return b(e,a)});D&&qb(e,t);return n}function v(a,d,f,h){"object"===typeof f&&null!==f&&f.type===Bb&&null===f.key&&(f=f.props.children);if("object"===typeof f&&null!==f){switch(f.$$typeof){case sd:a:{for(var k=f.key,n=d;null!==n;){if(n.key===k){k=f.type;if(k===Bb){if(7===n.tag){c(a,n.sibling);d=e(n,f.props.children);d.return=a;a=d;break a}}else if(n.elementType===k||"object"===typeof k&&null!==k&&k.$$typeof===Ta&&Ch(k)===n.type){c(a,n.sibling);d=e(n,f.props);d.ref=vc(a, +n,f);d.return=a;a=d;break a}c(a,n);break}else b(a,n);n=n.sibling}f.type===Bb?(d=sb(f.props.children,a.mode,h,f.key),d.return=a,a=d):(h=rd(f.type,f.key,f.props,null,a.mode,h),h.ref=vc(a,d,f),h.return=a,a=h)}return g(a);case Cb:a:{for(n=f.key;null!==d;){if(d.key===n)if(4===d.tag&&d.stateNode.containerInfo===f.containerInfo&&d.stateNode.implementation===f.implementation){c(a,d.sibling);d=e(d,f.children||[]);d.return=a;a=d;break a}else{c(a,d);break}else b(a,d);d=d.sibling}d=$e(f,a.mode,h);d.return=a; +a=d}return g(a);case Ta:return n=f._init,v(a,d,n(f._payload),h)}if(cc(f))return x(a,d,f,h);if(ac(f))return I(a,d,f,h);qd(a,f)}return"string"===typeof f&&""!==f||"number"===typeof f?(f=""+f,null!==d&&6===d.tag?(c(a,d.sibling),d=e(d,f),d.return=a,a=d):(c(a,d),d=Ze(f,a.mode,h),d.return=a,a=d),g(a)):c(a,d)}return v}function af(){bf=Rb=td=null}function cf(a,b){b=ud.current;v(ud);a._currentValue=b}function df(a,b,c){for(;null!==a;){var d=a.alternate;(a.childLanes&b)!==b?(a.childLanes|=b,null!==d&&(d.childLanes|= +b)):null!==d&&(d.childLanes&b)!==b&&(d.childLanes|=b);if(a===c)break;a=a.return}}function Sb(a,b){td=a;bf=Rb=null;a=a.dependencies;null!==a&&null!==a.firstContext&&(0!==(a.lanes&b)&&(ha=!0),a.firstContext=null)}function qa(a){var b=a._currentValue;if(bf!==a)if(a={context:a,memoizedValue:b,next:null},null===Rb){if(null===td)throw Error(m(308));Rb=a;td.dependencies={lanes:0,firstContext:a}}else Rb=Rb.next=a;return b}function ef(a){null===tb?tb=[a]:tb.push(a)}function Eh(a,b,c,d){var e=b.interleaved; +null===e?(c.next=c,ef(b)):(c.next=e.next,e.next=c);b.interleaved=c;return Oa(a,d)}function Oa(a,b){a.lanes|=b;var c=a.alternate;null!==c&&(c.lanes|=b);c=a;for(a=a.return;null!==a;)a.childLanes|=b,c=a.alternate,null!==c&&(c.childLanes|=b),c=a,a=a.return;return 3===c.tag?c.stateNode:null}function ff(a){a.updateQueue={baseState:a.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Fh(a,b){a=a.updateQueue;b.updateQueue===a&&(b.updateQueue= +{baseState:a.baseState,firstBaseUpdate:a.firstBaseUpdate,lastBaseUpdate:a.lastBaseUpdate,shared:a.shared,effects:a.effects})}function Pa(a,b){return{eventTime:a,lane:b,tag:0,payload:null,callback:null,next:null}}function fb(a,b,c){var d=a.updateQueue;if(null===d)return null;d=d.shared;if(0!==(p&2)){var e=d.pending;null===e?b.next=b:(b.next=e.next,e.next=b);d.pending=b;return kk(a,c)}e=d.interleaved;null===e?(b.next=b,ef(d)):(b.next=e.next,e.next=b);d.interleaved=b;return Oa(a,c)}function vd(a,b,c){b= +b.updateQueue;if(null!==b&&(b=b.shared,0!==(c&4194240))){var d=b.lanes;d&=a.pendingLanes;c|=d;b.lanes=c;xe(a,c)}}function Gh(a,b){var c=a.updateQueue,d=a.alternate;if(null!==d&&(d=d.updateQueue,c===d)){var e=null,f=null;c=c.firstBaseUpdate;if(null!==c){do{var g={eventTime:c.eventTime,lane:c.lane,tag:c.tag,payload:c.payload,callback:c.callback,next:null};null===f?e=f=g:f=f.next=g;c=c.next}while(null!==c);null===f?e=f=b:f=f.next=b}else e=f=b;c={baseState:d.baseState,firstBaseUpdate:e,lastBaseUpdate:f, +shared:d.shared,effects:d.effects};a.updateQueue=c;return}a=c.lastBaseUpdate;null===a?c.firstBaseUpdate=b:a.next=b;c.lastBaseUpdate=b}function wd(a,b,c,d){var e=a.updateQueue;gb=!1;var f=e.firstBaseUpdate,g=e.lastBaseUpdate,h=e.shared.pending;if(null!==h){e.shared.pending=null;var k=h,n=k.next;k.next=null;null===g?f=n:g.next=n;g=k;var l=a.alternate;null!==l&&(l=l.updateQueue,h=l.lastBaseUpdate,h!==g&&(null===h?l.firstBaseUpdate=n:h.next=n,l.lastBaseUpdate=k))}if(null!==f){var m=e.baseState;g=0;l= +n=k=null;h=f;do{var r=h.lane,p=h.eventTime;if((d&r)===r){null!==l&&(l=l.next={eventTime:p,lane:0,tag:h.tag,payload:h.payload,callback:h.callback,next:null});a:{var x=a,v=h;r=b;p=c;switch(v.tag){case 1:x=v.payload;if("function"===typeof x){m=x.call(p,m,r);break a}m=x;break a;case 3:x.flags=x.flags&-65537|128;case 0:x=v.payload;r="function"===typeof x?x.call(p,m,r):x;if(null===r||void 0===r)break a;m=E({},m,r);break a;case 2:gb=!0}}null!==h.callback&&0!==h.lane&&(a.flags|=64,r=e.effects,null===r?e.effects= +[h]:r.push(h))}else p={eventTime:p,lane:r,tag:h.tag,payload:h.payload,callback:h.callback,next:null},null===l?(n=l=p,k=m):l=l.next=p,g|=r;h=h.next;if(null===h)if(h=e.shared.pending,null===h)break;else r=h,h=r.next,r.next=null,e.lastBaseUpdate=r,e.shared.pending=null}while(1);null===l&&(k=m);e.baseState=k;e.firstBaseUpdate=n;e.lastBaseUpdate=l;b=e.shared.interleaved;if(null!==b){e=b;do g|=e.lane,e=e.next;while(e!==b)}else null===f&&(e.shared.lanes=0);ra|=g;a.lanes=g;a.memoizedState=m}}function Hh(a, +b,c){a=b.effects;b.effects=null;if(null!==a)for(b=0;bc?c:4;a(!0);var d=sf.transition;sf.transition= +{};try{a(!1),b()}finally{z=c,sf.transition=d}}function $h(){return sa().memoizedState}function qk(a,b,c){var d=hb(a);c={lane:d,action:c,hasEagerState:!1,eagerState:null,next:null};if(ai(a))bi(b,c);else if(c=Eh(a,b,c,d),null!==c){var e=Z();xa(c,a,d,e);ci(c,b,d)}}function ok(a,b,c){var d=hb(a),e={lane:d,action:c,hasEagerState:!1,eagerState:null,next:null};if(ai(a))bi(b,e);else{var f=a.alternate;if(0===a.lanes&&(null===f||0===f.lanes)&&(f=b.lastRenderedReducer,null!==f))try{var g=b.lastRenderedState, +h=f(g,c);e.hasEagerState=!0;e.eagerState=h;if(ua(h,g)){var k=b.interleaved;null===k?(e.next=e,ef(b)):(e.next=k.next,k.next=e);b.interleaved=e;return}}catch(n){}finally{}c=Eh(a,b,e,d);null!==c&&(e=Z(),xa(c,a,d,e),ci(c,b,d))}}function ai(a){var b=a.alternate;return a===C||null!==b&&b===C}function bi(a,b){zc=Ad=!0;var c=a.pending;null===c?b.next=b:(b.next=c.next,c.next=b);a.pending=b}function ci(a,b,c){if(0!==(c&4194240)){var d=b.lanes;d&=a.pendingLanes;c|=d;b.lanes=c;xe(a,c)}}function ya(a,b){if(a&& +a.defaultProps){b=E({},b);a=a.defaultProps;for(var c in a)void 0===b[c]&&(b[c]=a[c]);return b}return b}function tf(a,b,c,d){b=a.memoizedState;c=c(d,b);c=null===c||void 0===c?b:E({},b,c);a.memoizedState=c;0===a.lanes&&(a.updateQueue.baseState=c)}function di(a,b,c,d,e,f,g){a=a.stateNode;return"function"===typeof a.shouldComponentUpdate?a.shouldComponentUpdate(d,f,g):b.prototype&&b.prototype.isPureReactComponent?!qc(c,d)||!qc(e,f):!0}function ei(a,b,c){var d=!1,e=cb;var f=b.contextType;"object"===typeof f&& +null!==f?f=qa(f):(e=ea(b)?pb:J.current,d=b.contextTypes,f=(d=null!==d&&void 0!==d)?Nb(a,e):cb);b=new b(c,f);a.memoizedState=null!==b.state&&void 0!==b.state?b.state:null;b.updater=Dd;a.stateNode=b;b._reactInternals=a;d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=e,a.__reactInternalMemoizedMaskedChildContext=f);return b}function fi(a,b,c,d){a=b.state;"function"===typeof b.componentWillReceiveProps&&b.componentWillReceiveProps(c,d);"function"===typeof b.UNSAFE_componentWillReceiveProps&& +b.UNSAFE_componentWillReceiveProps(c,d);b.state!==a&&Dd.enqueueReplaceState(b,b.state,null)}function uf(a,b,c,d){var e=a.stateNode;e.props=c;e.state=a.memoizedState;e.refs={};ff(a);var f=b.contextType;"object"===typeof f&&null!==f?e.context=qa(f):(f=ea(b)?pb:J.current,e.context=Nb(a,f));e.state=a.memoizedState;f=b.getDerivedStateFromProps;"function"===typeof f&&(tf(a,b,f,c),e.state=a.memoizedState);"function"===typeof b.getDerivedStateFromProps||"function"===typeof e.getSnapshotBeforeUpdate||"function"!== +typeof e.UNSAFE_componentWillMount&&"function"!==typeof e.componentWillMount||(b=e.state,"function"===typeof e.componentWillMount&&e.componentWillMount(),"function"===typeof e.UNSAFE_componentWillMount&&e.UNSAFE_componentWillMount(),b!==e.state&&Dd.enqueueReplaceState(e,e.state,null),wd(a,c,e,d),e.state=a.memoizedState);"function"===typeof e.componentDidMount&&(a.flags|=4194308)}function Ub(a,b){try{var c="",d=b;do c+=fj(d),d=d.return;while(d);var e=c}catch(f){e="\nError generating stack: "+f.message+ +"\n"+f.stack}return{value:a,source:b,stack:e,digest:null}}function vf(a,b,c){return{value:a,source:null,stack:null!=c?c:null,digest:null!=b?b:null}}function wf(a,b){try{console.error(b.value)}catch(c){setTimeout(function(){throw c;})}}function gi(a,b,c){c=Pa(-1,c);c.tag=3;c.payload={element:null};var d=b.value;c.callback=function(){Ed||(Ed=!0,xf=d);wf(a,b)};return c}function hi(a,b,c){c=Pa(-1,c);c.tag=3;var d=a.type.getDerivedStateFromError;if("function"===typeof d){var e=b.value;c.payload=function(){return d(e)}; +c.callback=function(){wf(a,b)}}var f=a.stateNode;null!==f&&"function"===typeof f.componentDidCatch&&(c.callback=function(){wf(a,b);"function"!==typeof d&&(null===ib?ib=new Set([this]):ib.add(this));var c=b.stack;this.componentDidCatch(b.value,{componentStack:null!==c?c:""})});return c}function ii(a,b,c){var d=a.pingCache;if(null===d){d=a.pingCache=new rk;var e=new Set;d.set(b,e)}else e=d.get(b),void 0===e&&(e=new Set,d.set(b,e));e.has(c)||(e.add(c),a=sk.bind(null,a,b,c),b.then(a,a))}function ji(a){do{var b; +if(b=13===a.tag)b=a.memoizedState,b=null!==b?null!==b.dehydrated?!0:!1:!0;if(b)return a;a=a.return}while(null!==a);return null}function ki(a,b,c,d,e){if(0===(a.mode&1))return a===b?a.flags|=65536:(a.flags|=128,c.flags|=131072,c.flags&=-52805,1===c.tag&&(null===c.alternate?c.tag=17:(b=Pa(-1,1),b.tag=2,fb(c,b,1))),c.lanes|=1),a;a.flags|=65536;a.lanes=e;return a}function aa(a,b,c,d){b.child=null===a?li(b,null,c,d):Vb(b,a.child,c,d)}function mi(a,b,c,d,e){c=c.render;var f=b.ref;Sb(b,e);d=mf(a,b,c,d,f, +e);c=nf();if(null!==a&&!ha)return b.updateQueue=a.updateQueue,b.flags&=-2053,a.lanes&=~e,Qa(a,b,e);D&&c&&Ue(b);b.flags|=1;aa(a,b,d,e);return b.child}function ni(a,b,c,d,e){if(null===a){var f=c.type;if("function"===typeof f&&!yf(f)&&void 0===f.defaultProps&&null===c.compare&&void 0===c.defaultProps)return b.tag=15,b.type=f,oi(a,b,f,d,e);a=rd(c.type,null,d,b,b.mode,e);a.ref=b.ref;a.return=b;return b.child=a}f=a.child;if(0===(a.lanes&e)){var g=f.memoizedProps;c=c.compare;c=null!==c?c:qc;if(c(g,d)&&a.ref=== +b.ref)return Qa(a,b,e)}b.flags|=1;a=eb(f,d);a.ref=b.ref;a.return=b;return b.child=a}function oi(a,b,c,d,e){if(null!==a){var f=a.memoizedProps;if(qc(f,d)&&a.ref===b.ref)if(ha=!1,b.pendingProps=d=f,0!==(a.lanes&e))0!==(a.flags&131072)&&(ha=!0);else return b.lanes=a.lanes,Qa(a,b,e)}return zf(a,b,c,d,e)}function pi(a,b,c){var d=b.pendingProps,e=d.children,f=null!==a?a.memoizedState:null;if("hidden"===d.mode)if(0===(b.mode&1))b.memoizedState={baseLanes:0,cachePool:null,transitions:null},y(Ga,ba),ba|=c; +else{if(0===(c&1073741824))return a=null!==f?f.baseLanes|c:c,b.lanes=b.childLanes=1073741824,b.memoizedState={baseLanes:a,cachePool:null,transitions:null},b.updateQueue=null,y(Ga,ba),ba|=a,null;b.memoizedState={baseLanes:0,cachePool:null,transitions:null};d=null!==f?f.baseLanes:c;y(Ga,ba);ba|=d}else null!==f?(d=f.baseLanes|c,b.memoizedState=null):d=c,y(Ga,ba),ba|=d;aa(a,b,e,c);return b.child}function qi(a,b){var c=b.ref;if(null===a&&null!==c||null!==a&&a.ref!==c)b.flags|=512,b.flags|=2097152}function zf(a, +b,c,d,e){var f=ea(c)?pb:J.current;f=Nb(b,f);Sb(b,e);c=mf(a,b,c,d,f,e);d=nf();if(null!==a&&!ha)return b.updateQueue=a.updateQueue,b.flags&=-2053,a.lanes&=~e,Qa(a,b,e);D&&d&&Ue(b);b.flags|=1;aa(a,b,c,e);return b.child}function ri(a,b,c,d,e){if(ea(c)){var f=!0;ld(b)}else f=!1;Sb(b,e);if(null===b.stateNode)Fd(a,b),ei(b,c,d),uf(b,c,d,e),d=!0;else if(null===a){var g=b.stateNode,h=b.memoizedProps;g.props=h;var k=g.context,n=c.contextType;"object"===typeof n&&null!==n?n=qa(n):(n=ea(c)?pb:J.current,n=Nb(b, +n));var l=c.getDerivedStateFromProps,m="function"===typeof l||"function"===typeof g.getSnapshotBeforeUpdate;m||"function"!==typeof g.UNSAFE_componentWillReceiveProps&&"function"!==typeof g.componentWillReceiveProps||(h!==d||k!==n)&&fi(b,g,d,n);gb=!1;var r=b.memoizedState;g.state=r;wd(b,d,g,e);k=b.memoizedState;h!==d||r!==k||S.current||gb?("function"===typeof l&&(tf(b,c,l,d),k=b.memoizedState),(h=gb||di(b,c,h,d,r,k,n))?(m||"function"!==typeof g.UNSAFE_componentWillMount&&"function"!==typeof g.componentWillMount|| +("function"===typeof g.componentWillMount&&g.componentWillMount(),"function"===typeof g.UNSAFE_componentWillMount&&g.UNSAFE_componentWillMount()),"function"===typeof g.componentDidMount&&(b.flags|=4194308)):("function"===typeof g.componentDidMount&&(b.flags|=4194308),b.memoizedProps=d,b.memoizedState=k),g.props=d,g.state=k,g.context=n,d=h):("function"===typeof g.componentDidMount&&(b.flags|=4194308),d=!1)}else{g=b.stateNode;Fh(a,b);h=b.memoizedProps;n=b.type===b.elementType?h:ya(b.type,h);g.props= +n;m=b.pendingProps;r=g.context;k=c.contextType;"object"===typeof k&&null!==k?k=qa(k):(k=ea(c)?pb:J.current,k=Nb(b,k));var p=c.getDerivedStateFromProps;(l="function"===typeof p||"function"===typeof g.getSnapshotBeforeUpdate)||"function"!==typeof g.UNSAFE_componentWillReceiveProps&&"function"!==typeof g.componentWillReceiveProps||(h!==m||r!==k)&&fi(b,g,d,k);gb=!1;r=b.memoizedState;g.state=r;wd(b,d,g,e);var x=b.memoizedState;h!==m||r!==x||S.current||gb?("function"===typeof p&&(tf(b,c,p,d),x=b.memoizedState), +(n=gb||di(b,c,n,d,r,x,k)||!1)?(l||"function"!==typeof g.UNSAFE_componentWillUpdate&&"function"!==typeof g.componentWillUpdate||("function"===typeof g.componentWillUpdate&&g.componentWillUpdate(d,x,k),"function"===typeof g.UNSAFE_componentWillUpdate&&g.UNSAFE_componentWillUpdate(d,x,k)),"function"===typeof g.componentDidUpdate&&(b.flags|=4),"function"===typeof g.getSnapshotBeforeUpdate&&(b.flags|=1024)):("function"!==typeof g.componentDidUpdate||h===a.memoizedProps&&r===a.memoizedState||(b.flags|= +4),"function"!==typeof g.getSnapshotBeforeUpdate||h===a.memoizedProps&&r===a.memoizedState||(b.flags|=1024),b.memoizedProps=d,b.memoizedState=x),g.props=d,g.state=x,g.context=k,d=n):("function"!==typeof g.componentDidUpdate||h===a.memoizedProps&&r===a.memoizedState||(b.flags|=4),"function"!==typeof g.getSnapshotBeforeUpdate||h===a.memoizedProps&&r===a.memoizedState||(b.flags|=1024),d=!1)}return Af(a,b,c,d,f,e)}function Af(a,b,c,d,e,f){qi(a,b);var g=0!==(b.flags&128);if(!d&&!g)return e&&vh(b,c,!1), +Qa(a,b,f);d=b.stateNode;tk.current=b;var h=g&&"function"!==typeof c.getDerivedStateFromError?null:d.render();b.flags|=1;null!==a&&g?(b.child=Vb(b,a.child,null,f),b.child=Vb(b,null,h,f)):aa(a,b,h,f);b.memoizedState=d.state;e&&vh(b,c,!0);return b.child}function si(a){var b=a.stateNode;b.pendingContext?th(a,b.pendingContext,b.pendingContext!==b.context):b.context&&th(a,b.context,!1);gf(a,b.containerInfo)}function ti(a,b,c,d,e){Qb();Ye(e);b.flags|=256;aa(a,b,c,d);return b.child}function Bf(a){return{baseLanes:a, +cachePool:null,transitions:null}}function ui(a,b,c){var d=b.pendingProps,e=F.current,f=!1,g=0!==(b.flags&128),h;(h=g)||(h=null!==a&&null===a.memoizedState?!1:0!==(e&2));if(h)f=!0,b.flags&=-129;else if(null===a||null!==a.memoizedState)e|=1;y(F,e&1);if(null===a){Xe(b);a=b.memoizedState;if(null!==a&&(a=a.dehydrated,null!==a))return 0===(b.mode&1)?b.lanes=1:"$!"===a.data?b.lanes=8:b.lanes=1073741824,null;g=d.children;a=d.fallback;return f?(d=b.mode,f=b.child,g={mode:"hidden",children:g},0===(d&1)&&null!== +f?(f.childLanes=0,f.pendingProps=g):f=Gd(g,d,0,null),a=sb(a,d,c,null),f.return=b,a.return=b,f.sibling=a,b.child=f,b.child.memoizedState=Bf(c),b.memoizedState=Cf,a):Df(b,g)}e=a.memoizedState;if(null!==e&&(h=e.dehydrated,null!==h))return uk(a,b,g,d,h,e,c);if(f){f=d.fallback;g=b.mode;e=a.child;h=e.sibling;var k={mode:"hidden",children:d.children};0===(g&1)&&b.child!==e?(d=b.child,d.childLanes=0,d.pendingProps=k,b.deletions=null):(d=eb(e,k),d.subtreeFlags=e.subtreeFlags&14680064);null!==h?f=eb(h,f):(f= +sb(f,g,c,null),f.flags|=2);f.return=b;d.return=b;d.sibling=f;b.child=d;d=f;f=b.child;g=a.child.memoizedState;g=null===g?Bf(c):{baseLanes:g.baseLanes|c,cachePool:null,transitions:g.transitions};f.memoizedState=g;f.childLanes=a.childLanes&~c;b.memoizedState=Cf;return d}f=a.child;a=f.sibling;d=eb(f,{mode:"visible",children:d.children});0===(b.mode&1)&&(d.lanes=c);d.return=b;d.sibling=null;null!==a&&(c=b.deletions,null===c?(b.deletions=[a],b.flags|=16):c.push(a));b.child=d;b.memoizedState=null;return d} +function Df(a,b,c){b=Gd({mode:"visible",children:b},a.mode,0,null);b.return=a;return a.child=b}function Hd(a,b,c,d){null!==d&&Ye(d);Vb(b,a.child,null,c);a=Df(b,b.pendingProps.children);a.flags|=2;b.memoizedState=null;return a}function uk(a,b,c,d,e,f,g){if(c){if(b.flags&256)return b.flags&=-257,d=vf(Error(m(422))),Hd(a,b,g,d);if(null!==b.memoizedState)return b.child=a.child,b.flags|=128,null;f=d.fallback;e=b.mode;d=Gd({mode:"visible",children:d.children},e,0,null);f=sb(f,e,g,null);f.flags|=2;d.return= +b;f.return=b;d.sibling=f;b.child=d;0!==(b.mode&1)&&Vb(b,a.child,null,g);b.child.memoizedState=Bf(g);b.memoizedState=Cf;return f}if(0===(b.mode&1))return Hd(a,b,g,null);if("$!"===e.data){d=e.nextSibling&&e.nextSibling.dataset;if(d)var h=d.dgst;d=h;f=Error(m(419));d=vf(f,d,void 0);return Hd(a,b,g,d)}h=0!==(g&a.childLanes);if(ha||h){d=O;if(null!==d){switch(g&-g){case 4:e=2;break;case 16:e=8;break;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:e= +32;break;case 536870912:e=268435456;break;default:e=0}e=0!==(e&(d.suspendedLanes|g))?0:e;0!==e&&e!==f.retryLane&&(f.retryLane=e,Oa(a,e),xa(d,a,e,-1))}Ef();d=vf(Error(m(421)));return Hd(a,b,g,d)}if("$?"===e.data)return b.flags|=128,b.child=a.child,b=vk.bind(null,a),e._reactRetry=b,null;a=f.treeContext;fa=Ka(e.nextSibling);la=b;D=!0;wa=null;null!==a&&(na[oa++]=Ma,na[oa++]=Na,na[oa++]=rb,Ma=a.id,Na=a.overflow,rb=b);b=Df(b,d.children);b.flags|=4096;return b}function vi(a,b,c){a.lanes|=b;var d=a.alternate; +null!==d&&(d.lanes|=b);df(a.return,b,c)}function Ff(a,b,c,d,e){var f=a.memoizedState;null===f?a.memoizedState={isBackwards:b,rendering:null,renderingStartTime:0,last:d,tail:c,tailMode:e}:(f.isBackwards=b,f.rendering=null,f.renderingStartTime=0,f.last=d,f.tail=c,f.tailMode=e)}function wi(a,b,c){var d=b.pendingProps,e=d.revealOrder,f=d.tail;aa(a,b,d.children,c);d=F.current;if(0!==(d&2))d=d&1|2,b.flags|=128;else{if(null!==a&&0!==(a.flags&128))a:for(a=b.child;null!==a;){if(13===a.tag)null!==a.memoizedState&& +vi(a,c,b);else if(19===a.tag)vi(a,c,b);else if(null!==a.child){a.child.return=a;a=a.child;continue}if(a===b)break a;for(;null===a.sibling;){if(null===a.return||a.return===b)break a;a=a.return}a.sibling.return=a.return;a=a.sibling}d&=1}y(F,d);if(0===(b.mode&1))b.memoizedState=null;else switch(e){case "forwards":c=b.child;for(e=null;null!==c;)a=c.alternate,null!==a&&null===xd(a)&&(e=c),c=c.sibling;c=e;null===c?(e=b.child,b.child=null):(e=c.sibling,c.sibling=null);Ff(b,!1,e,c,f);break;case "backwards":c= +null;e=b.child;for(b.child=null;null!==e;){a=e.alternate;if(null!==a&&null===xd(a)){b.child=e;break}a=e.sibling;e.sibling=c;c=e;e=a}Ff(b,!0,c,null,f);break;case "together":Ff(b,!1,null,null,void 0);break;default:b.memoizedState=null}return b.child}function Fd(a,b){0===(b.mode&1)&&null!==a&&(a.alternate=null,b.alternate=null,b.flags|=2)}function Qa(a,b,c){null!==a&&(b.dependencies=a.dependencies);ra|=b.lanes;if(0===(c&b.childLanes))return null;if(null!==a&&b.child!==a.child)throw Error(m(153));if(null!== +b.child){a=b.child;c=eb(a,a.pendingProps);b.child=c;for(c.return=b;null!==a.sibling;)a=a.sibling,c=c.sibling=eb(a,a.pendingProps),c.return=b;c.sibling=null}return b.child}function wk(a,b,c){switch(b.tag){case 3:si(b);Qb();break;case 5:Ih(b);break;case 1:ea(b.type)&&ld(b);break;case 4:gf(b,b.stateNode.containerInfo);break;case 10:var d=b.type._context,e=b.memoizedProps.value;y(ud,d._currentValue);d._currentValue=e;break;case 13:d=b.memoizedState;if(null!==d){if(null!==d.dehydrated)return y(F,F.current& +1),b.flags|=128,null;if(0!==(c&b.child.childLanes))return ui(a,b,c);y(F,F.current&1);a=Qa(a,b,c);return null!==a?a.sibling:null}y(F,F.current&1);break;case 19:d=0!==(c&b.childLanes);if(0!==(a.flags&128)){if(d)return wi(a,b,c);b.flags|=128}e=b.memoizedState;null!==e&&(e.rendering=null,e.tail=null,e.lastEffect=null);y(F,F.current);if(d)break;else return null;case 22:case 23:return b.lanes=0,pi(a,b,c)}return Qa(a,b,c)}function Dc(a,b){if(!D)switch(a.tailMode){case "hidden":b=a.tail;for(var c=null;null!== +b;)null!==b.alternate&&(c=b),b=b.sibling;null===c?a.tail=null:c.sibling=null;break;case "collapsed":c=a.tail;for(var d=null;null!==c;)null!==c.alternate&&(d=c),c=c.sibling;null===d?b||null===a.tail?a.tail=null:a.tail.sibling=null:d.sibling=null}}function W(a){var b=null!==a.alternate&&a.alternate.child===a.child,c=0,d=0;if(b)for(var e=a.child;null!==e;)c|=e.lanes|e.childLanes,d|=e.subtreeFlags&14680064,d|=e.flags&14680064,e.return=a,e=e.sibling;else for(e=a.child;null!==e;)c|=e.lanes|e.childLanes, +d|=e.subtreeFlags,d|=e.flags,e.return=a,e=e.sibling;a.subtreeFlags|=d;a.childLanes=c;return b}function xk(a,b,c){var d=b.pendingProps;Ve(b);switch(b.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return W(b),null;case 1:return ea(b.type)&&(v(S),v(J)),W(b),null;case 3:d=b.stateNode;Tb();v(S);v(J);jf();d.pendingContext&&(d.context=d.pendingContext,d.pendingContext=null);if(null===a||null===a.child)pd(b)?b.flags|=4:null===a||a.memoizedState.isDehydrated&&0===(b.flags& +256)||(b.flags|=1024,null!==wa&&(Gf(wa),wa=null));xi(a,b);W(b);return null;case 5:hf(b);var e=ub(xc.current);c=b.type;if(null!==a&&null!=b.stateNode)yk(a,b,c,d,e),a.ref!==b.ref&&(b.flags|=512,b.flags|=2097152);else{if(!d){if(null===b.stateNode)throw Error(m(166));W(b);return null}a=ub(Ea.current);if(pd(b)){d=b.stateNode;c=b.type;var f=b.memoizedProps;d[Da]=b;d[uc]=f;a=0!==(b.mode&1);switch(c){case "dialog":B("cancel",d);B("close",d);break;case "iframe":case "object":case "embed":B("load",d);break; +case "video":case "audio":for(e=0;e\x3c/script>",a=a.removeChild(a.firstChild)):"string"===typeof d.is?a=g.createElement(c,{is:d.is}):(a=g.createElement(c),"select"===c&&(g=a,d.multiple?g.multiple=!0:d.size&&(g.size=d.size))):a=g.createElementNS(a,c);a[Da]=b;a[uc]=d;zk(a,b,!1,!1);b.stateNode=a;a:{g=qe(c,d);switch(c){case "dialog":B("cancel",a);B("close",a);e=d;break;case "iframe":case "object":case "embed":B("load",a);e=d;break; +case "video":case "audio":for(e=0;eHf&&(b.flags|=128,d=!0,Dc(f,!1),b.lanes=4194304)}else{if(!d)if(a=xd(g),null!==a){if(b.flags|=128,d=!0,c=a.updateQueue,null!==c&&(b.updateQueue=c,b.flags|=4),Dc(f,!0),null===f.tail&&"hidden"===f.tailMode&&!g.alternate&&!D)return W(b),null}else 2*P()-f.renderingStartTime>Hf&&1073741824!==c&&(b.flags|= +128,d=!0,Dc(f,!1),b.lanes=4194304);f.isBackwards?(g.sibling=b.child,b.child=g):(c=f.last,null!==c?c.sibling=g:b.child=g,f.last=g)}if(null!==f.tail)return b=f.tail,f.rendering=b,f.tail=b.sibling,f.renderingStartTime=P(),b.sibling=null,c=F.current,y(F,d?c&1|2:c&1),b;W(b);return null;case 22:case 23:return ba=Ga.current,v(Ga),d=null!==b.memoizedState,null!==a&&null!==a.memoizedState!==d&&(b.flags|=8192),d&&0!==(b.mode&1)?0!==(ba&1073741824)&&(W(b),b.subtreeFlags&6&&(b.flags|=8192)):W(b),null;case 24:return null; +case 25:return null}throw Error(m(156,b.tag));}function Bk(a,b,c){Ve(b);switch(b.tag){case 1:return ea(b.type)&&(v(S),v(J)),a=b.flags,a&65536?(b.flags=a&-65537|128,b):null;case 3:return Tb(),v(S),v(J),jf(),a=b.flags,0!==(a&65536)&&0===(a&128)?(b.flags=a&-65537|128,b):null;case 5:return hf(b),null;case 13:v(F);a=b.memoizedState;if(null!==a&&null!==a.dehydrated){if(null===b.alternate)throw Error(m(340));Qb()}a=b.flags;return a&65536?(b.flags=a&-65537|128,b):null;case 19:return v(F),null;case 4:return Tb(), +null;case 10:return cf(b.type._context),null;case 22:case 23:return ba=Ga.current,v(Ga),null;case 24:return null;default:return null}}function Wb(a,b){var c=a.ref;if(null!==c)if("function"===typeof c)try{c(null)}catch(d){G(a,b,d)}else c.current=null}function If(a,b,c){try{c()}catch(d){G(a,b,d)}}function Ck(a,b){Jf=Zc;a=ch();if(Ie(a)){if("selectionStart"in a)var c={start:a.selectionStart,end:a.selectionEnd};else a:{c=(c=a.ownerDocument)&&c.defaultView||window;var d=c.getSelection&&c.getSelection(); +if(d&&0!==d.rangeCount){c=d.anchorNode;var e=d.anchorOffset,f=d.focusNode;d=d.focusOffset;try{c.nodeType,f.nodeType}catch(M){c=null;break a}var g=0,h=-1,k=-1,n=0,q=0,u=a,r=null;b:for(;;){for(var p;;){u!==c||0!==e&&3!==u.nodeType||(h=g+e);u!==f||0!==d&&3!==u.nodeType||(k=g+d);3===u.nodeType&&(g+=u.nodeValue.length);if(null===(p=u.firstChild))break;r=u;u=p}for(;;){if(u===a)break b;r===c&&++n===e&&(h=g);r===f&&++q===d&&(k=g);if(null!==(p=u.nextSibling))break;u=r;r=u.parentNode}u=p}c=-1===h||-1===k?null: +{start:h,end:k}}else c=null}c=c||{start:0,end:0}}else c=null;Kf={focusedElem:a,selectionRange:c};Zc=!1;for(l=b;null!==l;)if(b=l,a=b.child,0!==(b.subtreeFlags&1028)&&null!==a)a.return=b,l=a;else for(;null!==l;){b=l;try{var x=b.alternate;if(0!==(b.flags&1024))switch(b.tag){case 0:case 11:case 15:break;case 1:if(null!==x){var v=x.memoizedProps,z=x.memoizedState,w=b.stateNode,A=w.getSnapshotBeforeUpdate(b.elementType===b.type?v:ya(b.type,v),z);w.__reactInternalSnapshotBeforeUpdate=A}break;case 3:var t= +b.stateNode.containerInfo;1===t.nodeType?t.textContent="":9===t.nodeType&&t.documentElement&&t.removeChild(t.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(m(163));}}catch(M){G(b,b.return,M)}a=b.sibling;if(null!==a){a.return=b.return;l=a;break}l=b.return}x=zi;zi=!1;return x}function Gc(a,b,c){var d=b.updateQueue;d=null!==d?d.lastEffect:null;if(null!==d){var e=d=d.next;do{if((e.tag&a)===a){var f=e.destroy;e.destroy=void 0;void 0!==f&&If(b,c,f)}e=e.next}while(e!==d)}} +function Id(a,b){b=b.updateQueue;b=null!==b?b.lastEffect:null;if(null!==b){var c=b=b.next;do{if((c.tag&a)===a){var d=c.create;c.destroy=d()}c=c.next}while(c!==b)}}function Lf(a){var b=a.ref;if(null!==b){var c=a.stateNode;switch(a.tag){case 5:a=c;break;default:a=c}"function"===typeof b?b(a):b.current=a}}function Ai(a){var b=a.alternate;null!==b&&(a.alternate=null,Ai(b));a.child=null;a.deletions=null;a.sibling=null;5===a.tag&&(b=a.stateNode,null!==b&&(delete b[Da],delete b[uc],delete b[Me],delete b[Dk], +delete b[Ek]));a.stateNode=null;a.return=null;a.dependencies=null;a.memoizedProps=null;a.memoizedState=null;a.pendingProps=null;a.stateNode=null;a.updateQueue=null}function Bi(a){return 5===a.tag||3===a.tag||4===a.tag}function Ci(a){a:for(;;){for(;null===a.sibling;){if(null===a.return||Bi(a.return))return null;a=a.return}a.sibling.return=a.return;for(a=a.sibling;5!==a.tag&&6!==a.tag&&18!==a.tag;){if(a.flags&2)continue a;if(null===a.child||4===a.tag)continue a;else a.child.return=a,a=a.child}if(!(a.flags& +2))return a.stateNode}}function Mf(a,b,c){var d=a.tag;if(5===d||6===d)a=a.stateNode,b?8===c.nodeType?c.parentNode.insertBefore(a,b):c.insertBefore(a,b):(8===c.nodeType?(b=c.parentNode,b.insertBefore(a,c)):(b=c,b.appendChild(a)),c=c._reactRootContainer,null!==c&&void 0!==c||null!==b.onclick||(b.onclick=kd));else if(4!==d&&(a=a.child,null!==a))for(Mf(a,b,c),a=a.sibling;null!==a;)Mf(a,b,c),a=a.sibling}function Nf(a,b,c){var d=a.tag;if(5===d||6===d)a=a.stateNode,b?c.insertBefore(a,b):c.appendChild(a); +else if(4!==d&&(a=a.child,null!==a))for(Nf(a,b,c),a=a.sibling;null!==a;)Nf(a,b,c),a=a.sibling}function jb(a,b,c){for(c=c.child;null!==c;)Di(a,b,c),c=c.sibling}function Di(a,b,c){if(Ca&&"function"===typeof Ca.onCommitFiberUnmount)try{Ca.onCommitFiberUnmount(Uc,c)}catch(h){}switch(c.tag){case 5:X||Wb(c,b);case 6:var d=T,e=za;T=null;jb(a,b,c);T=d;za=e;null!==T&&(za?(a=T,c=c.stateNode,8===a.nodeType?a.parentNode.removeChild(c):a.removeChild(c)):T.removeChild(c.stateNode));break;case 18:null!==T&&(za? +(a=T,c=c.stateNode,8===a.nodeType?Re(a.parentNode,c):1===a.nodeType&&Re(a,c),nc(a)):Re(T,c.stateNode));break;case 4:d=T;e=za;T=c.stateNode.containerInfo;za=!0;jb(a,b,c);T=d;za=e;break;case 0:case 11:case 14:case 15:if(!X&&(d=c.updateQueue,null!==d&&(d=d.lastEffect,null!==d))){e=d=d.next;do{var f=e,g=f.destroy;f=f.tag;void 0!==g&&(0!==(f&2)?If(c,b,g):0!==(f&4)&&If(c,b,g));e=e.next}while(e!==d)}jb(a,b,c);break;case 1:if(!X&&(Wb(c,b),d=c.stateNode,"function"===typeof d.componentWillUnmount))try{d.props= +c.memoizedProps,d.state=c.memoizedState,d.componentWillUnmount()}catch(h){G(c,b,h)}jb(a,b,c);break;case 21:jb(a,b,c);break;case 22:c.mode&1?(X=(d=X)||null!==c.memoizedState,jb(a,b,c),X=d):jb(a,b,c);break;default:jb(a,b,c)}}function Ei(a){var b=a.updateQueue;if(null!==b){a.updateQueue=null;var c=a.stateNode;null===c&&(c=a.stateNode=new Fk);b.forEach(function(b){var d=Gk.bind(null,a,b);c.has(b)||(c.add(b),b.then(d,d))})}}function Aa(a,b,c){c=b.deletions;if(null!==c)for(var d=0;de&&(e=g);d&=~f}d=e;d=P()-d;d=(120>d?120:480>d?480:1080>d?1080:1920>d?1920:3E3>d?3E3:4320>d?4320:1960*Mk(d/1960))-d;if(10a?16:a;if(null===lb)var d=!1;else{a=lb;lb=null;Qd=0;if(0!==(p&6))throw Error(m(331));var e=p;p|=4;for(l=a.current;null!==l;){var f=l,g=f.child;if(0!==(l.flags&16)){var h=f.deletions;if(null!==h){for(var k=0;kP()-Of?wb(a,0):Sf|=c);ia(a,b)}function Ti(a,b){0===b&&(0===(a.mode&1)?b=1:(b=Rd,Rd<<=1,0===(Rd&130023424)&&(Rd=4194304)));var c=Z();a=Oa(a,b);null!==a&&(ic(a,b,c),ia(a,c))}function vk(a){var b=a.memoizedState,c=0;null!==b&&(c=b.retryLane);Ti(a,c)}function Gk(a,b){var c=0;switch(a.tag){case 13:var d=a.stateNode;var e=a.memoizedState;null!==e&&(c=e.retryLane); +break;case 19:d=a.stateNode;break;default:throw Error(m(314));}null!==d&&d.delete(b);Ti(a,c)}function Mi(a,b){return xh(a,b)}function Tk(a,b,c,d){this.tag=a;this.key=c;this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null;this.index=0;this.ref=null;this.pendingProps=b;this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null;this.mode=d;this.subtreeFlags=this.flags=0;this.deletions=null;this.childLanes=this.lanes=0;this.alternate=null}function yf(a){a= +a.prototype;return!(!a||!a.isReactComponent)}function Uk(a){if("function"===typeof a)return yf(a)?1:0;if(void 0!==a&&null!==a){a=a.$$typeof;if(a===ie)return 11;if(a===je)return 14}return 2}function eb(a,b){var c=a.alternate;null===c?(c=pa(a.tag,b,a.key,a.mode),c.elementType=a.elementType,c.type=a.type,c.stateNode=a.stateNode,c.alternate=a,a.alternate=c):(c.pendingProps=b,c.type=a.type,c.flags=0,c.subtreeFlags=0,c.deletions=null);c.flags=a.flags&14680064;c.childLanes=a.childLanes;c.lanes=a.lanes;c.child= +a.child;c.memoizedProps=a.memoizedProps;c.memoizedState=a.memoizedState;c.updateQueue=a.updateQueue;b=a.dependencies;c.dependencies=null===b?null:{lanes:b.lanes,firstContext:b.firstContext};c.sibling=a.sibling;c.index=a.index;c.ref=a.ref;return c}function rd(a,b,c,d,e,f){var g=2;d=a;if("function"===typeof a)yf(a)&&(g=1);else if("string"===typeof a)g=5;else a:switch(a){case Bb:return sb(c.children,e,f,b);case fe:g=8;e|=8;break;case ee:return a=pa(12,c,b,e|2),a.elementType=ee,a.lanes=f,a;case ge:return a= +pa(13,c,b,e),a.elementType=ge,a.lanes=f,a;case he:return a=pa(19,c,b,e),a.elementType=he,a.lanes=f,a;case Ui:return Gd(c,e,f,b);default:if("object"===typeof a&&null!==a)switch(a.$$typeof){case hg:g=10;break a;case gg:g=9;break a;case ie:g=11;break a;case je:g=14;break a;case Ta:g=16;d=null;break a}throw Error(m(130,null==a?a:typeof a,""));}b=pa(g,c,b,e);b.elementType=a;b.type=d;b.lanes=f;return b}function sb(a,b,c,d){a=pa(7,a,d,b);a.lanes=c;return a}function Gd(a,b,c,d){a=pa(22,a,d,b);a.elementType= +Ui;a.lanes=c;a.stateNode={isHidden:!1};return a}function Ze(a,b,c){a=pa(6,a,null,b);a.lanes=c;return a}function $e(a,b,c){b=pa(4,null!==a.children?a.children:[],a.key,b);b.lanes=c;b.stateNode={containerInfo:a.containerInfo,pendingChildren:null,implementation:a.implementation};return b}function Vk(a,b,c,d,e){this.tag=b;this.containerInfo=a;this.finishedWork=this.pingCache=this.current=this.pendingChildren=null;this.timeoutHandle=-1;this.callbackNode=this.pendingContext=this.context=null;this.callbackPriority= +0;this.eventTimes=we(0);this.expirationTimes=we(-1);this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0;this.entanglements=we(0);this.identifierPrefix=d;this.onRecoverableError=e;this.mutableSourceEagerHydrationData=null}function Vf(a,b,c,d,e,f,g,h,k,l){a=new Vk(a,b,c,h,k);1===b?(b=1,!0===f&&(b|=8)):b=0;f=pa(3,null,null,b);a.current=f;f.stateNode=a;f.memoizedState={element:d,isDehydrated:c,cache:null,transitions:null, +pendingSuspenseBoundaries:null};ff(f);return a}function Wk(a,b,c){var d=3