| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970 |
- """中国行政区划(bas_china_region)树形结构,供运营端与小程序共用。"""
- from __future__ import annotations
- import copy
- import threading
- import time
- from collections import defaultdict
- from typing import Dict, List
- from sqlalchemy.orm import Session
- from app.models.models import BasChinaRegion
- _CHINA_REGION_TREE_CACHE_TTL_SEC = 600
- _china_region_tree_cache = {"expires_at": 0.0, "tree": None}
- _china_region_tree_cache_lock = threading.Lock()
- def query_china_regions_active(db: Session) -> List[BasChinaRegion]:
- return (
- db.query(
- BasChinaRegion.id,
- BasChinaRegion.parent_id,
- BasChinaRegion.region_code,
- BasChinaRegion.region_name,
- BasChinaRegion.sort_order,
- )
- .filter(BasChinaRegion.is_del == 0)
- .order_by(BasChinaRegion.sort_order.asc(), BasChinaRegion.region_code.asc())
- .all()
- )
- def build_china_region_tree(rows: List[BasChinaRegion]) -> List[dict]:
- """{ value: region_code, label: region_name, children?: [...] },与历史 china-region-cascader.json 结构一致。"""
- children_map: Dict[str, List[BasChinaRegion]] = defaultdict(list)
- for r in rows:
- key = getattr(r, "parent_id", None) or ""
- children_map[key].append(r)
- for key in children_map:
- children_map[key].sort(key=lambda x: (getattr(x, "sort_order", 0), getattr(x, "region_code", "")))
- def to_node(r: BasChinaRegion) -> dict:
- rid = getattr(r, "id", None)
- subs = children_map.get(rid, [])
- node: dict = {"value": getattr(r, "region_code", None), "label": getattr(r, "region_name", None)}
- if subs:
- node["children"] = [to_node(c) for c in subs]
- return node
- roots = children_map.get("", [])
- return [to_node(r) for r in roots]
- def get_china_region_tree_cached(db: Session) -> List[dict]:
- """获取中国行政区划树,带进程内短 TTL 缓存。"""
- now = time.time()
- with _china_region_tree_cache_lock:
- cache_tree = _china_region_tree_cache.get("tree")
- expires_at = float(_china_region_tree_cache.get("expires_at") or 0.0)
- if cache_tree is not None and now < expires_at:
- return copy.deepcopy(cache_tree)
- rows = query_china_regions_active(db)
- tree = build_china_region_tree(rows)
- with _china_region_tree_cache_lock:
- _china_region_tree_cache["tree"] = tree
- _china_region_tree_cache["expires_at"] = now + _CHINA_REGION_TREE_CACHE_TTL_SEC
- return copy.deepcopy(tree)
|