文件
hl-api-changelog/changelogs-v2/2026-08/26_6350_行政区划主数据与三级联动-新增接口-管理后台.md
lc 6461e1ce39
changelog-filename-gate / validate (pull_request) Successful in 2s
docs(changelog): 交付行政区划主数据接口(#6350)
2026-08-26 15:52:27 +08:00

13 KiB

schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer author change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 6350 行政区划主数据与三级联动 admin lc(GIT) 新增接口 deployed verified pending 2026-08-26 主工单 #6350 及补充工单 #6384、#6389、#6395、#6399、#6409 的六个 PR 均已合并 dev-v3。精确提交 b62054035a139e3c689179ef75e2d052d08dde52 已由 Deploy Panel 任务 52771074(hl-user-service)和 b1db24b2(hl-gateway)部署 TEST;真实管理员经 Gateway 完成未认证、读取、失败零写入、创建、CAS 更新、数据库和 Redis 一致性验收,临时数据、缓存快照及登录会话均已恢复。管理端尚待接入新增接口。 2026-08-26 dev-v3

行政区划主数据与三级联动

管理后台新增可版本化的行政区划主数据接口,统一提供省、市、县三级联动、任意节点父链回显,以及受权限、有效期、层级和并发版本保护的创建与更新能力。

服务:hl-user-service,统一经 Gateway /admin/region/** 访问 Issue:#6350、#6384、#6389、#6395、#6399、#6409 PR:#6359、#6387、#6393、#6398、#6402、#6412 影响范围:管理后台行政区划维护、三级选择器和历史值父链回显

关键约定

  • 所有响应中的行政区划 ID 均为 JSON 字符串,包括 data、parentId、defaultId、selectedId、provinceId、prefectureId、countyId 和节点 id;没有父级或对应层级时保持 null。
  • 当前写入边界为省、市、县三级,层级代码依次为 PROVINCE、PREFECTURE、COUNTY;服务端根据父链计算 depth,请求不能直接指定深度。
  • ADMINISTRATIVE 表示可作为业务行政区的节点;AGGREGATION 只用于导航分组,必须使用 HL_GROUP、navigable=true、selectable=false。
  • 有效期使用左闭右开区间 [validFrom, validTo);validTo=null 表示持续有效。
  • 读接口只要求真实管理员登录;创建还要求 system:region:create,更新要求 system:region:update。
  • 统一响应为 Result<T>。业务失败可能仍是 HTTP 200,调用方必须同时检查 code、success、message 和 data。

变更接口清单

方法 路径 权限 用途
POST /admin/region system:region:create 创建行政区或导航聚合节点
PUT /admin/region/{id} system:region:update 使用 rowVersion 更新可变字段
GET /admin/region/children 管理员登录 查询根层或指定父节点的当前有效直接子节点
GET /admin/region/{id}/path 管理员登录 返回任意节点从省级根开始的完整父链

1. 单级联动列表

GET /admin/region/children?parentId=1&selectedId=35
Authorization: Bearer <管理员令牌>

查询省级根列表时省略 parentId。selectedId 只有在本次 items 中存在时才作为 defaultId;否则回退为排序后的首项,空列表返回 null。

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "parentId": "1",
    "items": [
      {
        "id": "35",
        "parentId": "1",
        "codeStandard": "GB/T 2260",
        "regionCode": "110100",
        "levelCode": "PREFECTURE",
        "depth": 2,
        "name": "北京市",
        "shortName": null,
        "nodeKind": "ADMINISTRATIVE",
        "navigable": true,
        "selectable": true,
        "hasChildren": true,
        "currentlyEffective": true,
        "status": "ACTIVE",
        "validFrom": "2025-12-31",
        "validTo": null,
        "sortOrder": 100,
        "rowVersion": 0
      }
    ],
    "defaultId": "35"
  }
}

仅返回中国业务当日有效且状态为 ACTIVE 的直接子节点,排序稳定为 sortOrder、regionCode、id。停用或历史节点不会进入联动列表,但仍可通过父链接口回显。

2. 父链回显

GET /admin/region/376/path
Authorization: Bearer <管理员令牌>
{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": {
    "selectedId": "376",
    "provinceId": "1",
    "prefectureId": "35",
    "countyId": "376",
    "path": [
      {
        "id": "1",
        "parentId": null,
        "levelCode": "PROVINCE",
        "depth": 1,
        "name": "北京市",
        "nodeKind": "ADMINISTRATIVE",
        "currentlyEffective": true
      },
      {
        "id": "35",
        "parentId": "1",
        "levelCode": "PREFECTURE",
        "depth": 2,
        "name": "北京市",
        "nodeKind": "ADMINISTRATIVE",
        "currentlyEffective": true
      },
      {
        "id": "376",
        "parentId": "35",
        "levelCode": "COUNTY",
        "depth": 3,
        "name": "东城区",
        "nodeKind": "ADMINISTRATIVE",
        "currentlyEffective": true
      }
    ]
  }
}

目标为省级或地级时,尚未到达的快捷层级字段返回 null。历史停用节点可返回,但节点自身的 currentlyEffective=false,调用方不能把它重新放入当前可选列表。父链存在孤儿、环、越级或超过当前安全深度时,接口失败且不返回部分路径。

3. 创建节点

POST /admin/region
Authorization: Bearer <具有 system:region:create 的管理员令牌>
Content-Type: application/json

创建一个县级业务行政区示例:

{
  "codeStandard": "HL_CUSTOM",
  "regionCode": "DEMO-COUNTY-001",
  "parentId": "35",
  "levelCode": "COUNTY",
  "nodeKind": "ADMINISTRATIVE",
  "name": "示例业务区",
  "shortName": "示例区",
  "navigable": true,
  "selectable": true,
  "validFrom": "2026-08-26",
  "validTo": null,
  "status": "ACTIVE",
  "sortOrder": 10000,
  "sourceVersion": "ADMIN-20260826",
  "sourceRef": "工单或数据批次定位",
  "extension": {
    "businessNote": "示例扩展信息"
  }
}

成功响应的 data 是字符串 ID:

{
  "code": 200,
  "message": "成功",
  "success": true,
  "data": "2090000000000000001"
}

extension 只能是 JSON 对象;历史入参名 extJson 仅作为请求别名兼容,响应统一使用 extension。服务端会记录来源版本、来源定位、操作人和来源校验值,并在事务提交后刷新行政区划独立缓存。

4. 更新节点

PUT /admin/region/2090000000000000001
Authorization: Bearer <具有 system:region:update 的管理员令牌>
Content-Type: application/json
{
  "parentId": "35",
  "levelCode": "COUNTY",
  "name": "示例业务区(更新)",
  "shortName": "示例区",
  "navigable": true,
  "selectable": true,
  "validFrom": "2026-08-26",
  "validTo": null,
  "status": "ACTIVE",
  "sortOrder": 10001,
  "extension": {
    "businessNote": "名称已更新"
  },
  "rowVersion": 0
}
{
  "code": 200,
  "message": "行政区划更新成功",
  "success": true,
  "data": null
}

更新采用完整可变字段加 rowVersion 的 CAS 语义。成功后版本号递增;并发版本过期返回 210807,不会覆盖另一位管理员的提交。编码标准、地区编码、节点类型和来源证据不可通过更新接口改写。

已到生效日的 GB/T 2260 法定节点不能原位修改历史属性;只能保持其他字段不变,将旧版本关闭,再创建不重叠的新版本。有子节点的分支不能直接移动或改变层级,父节点的状态、导航能力和有效期必须持续覆盖当前或未来仍会生效的子版本。

字段说明

字段 JSON 类型 说明
id、parentId string / null 行政区划节点与父节点 ID;响应始终为字符串
codeStandard string GB/T 2260、HL_CUSTOM 或聚合节点专用 HL_GROUP
regionCode string 同一编码标准内的业务标识;GB/T 2260 必须为六位数字
levelCode string 当前三级固定为 PROVINCE、PREFECTURE、COUNTY
nodeKind string ADMINISTRATIVE 或 AGGREGATION
navigable boolean 是否可继续逐级导航
selectable boolean 是否可作为最终业务值
hasChildren boolean 是否存在当前有效、启用的直接子节点
currentlyEffective boolean 节点在中国业务当日是否处于有效时间窗且为 ACTIVE
validFrom、validTo string / null yyyy-MM-dd;结束日为开区间
status string ACTIVE 或 INACTIVE
rowVersion integer 更新 CAS 版本;创建后从 0 开始

业务错误码

code message 典型场景
210801 行政区划节点不存在 查询不存在的父级或父链目标
210802 无行政区划维护权限 创建或更新缺少细粒度权限
210803 行政区划父节点不合法 父级不可导航或有效期不能覆盖子级
210804 行政区划层级超过当前允许深度 写入超过当前三级边界
210805 行政区划父链存在循环 自引用或移动后形成祖先环
210806 行政区划当前编码已存在 当前唯一键冲突
210807 行政区划已被其他操作更新,请刷新后重试 rowVersion 过期
210808 行政区划有效期不合法 validTo 不晚于 validFrom
210809 该行政区划编码标准为系统保留值 新写入继续使用旧 HL_INTERNAL
210810 存在子节点的行政区划不能移动或变更层级 分支移动或改层级
210811 行政区划父链数据不完整 孤儿、越级、环或异常终止
210812 行政区划扩展字段必须是合法 JSON extension 不是 JSON 对象
210813 行政区划层级代码与父链深度不一致 省市县代码与派生深度不匹配
210814 行政区划更新与现有子节点状态或有效期冲突 父级提前停用、取消导航或缩短窗口
210815 行政区划编码的版本有效期与既有数据重叠 同编码版本时间窗重叠
210816 行政区划节点类型或编码命名空间不合法 聚合节点类型、命名空间或可选性组合错误
210817 已生效法定行政区划只能关闭旧版本后新增 原位改写生效中的法定节点
210818 行政区划数据来源信息不完整 缺少来源版本或定位
210819 法定行政区划代码必须为六位数字 GB/T 2260 新版本编码格式错误

参数格式错误继续使用统一参数错误响应,例如未登录返回业务码 401,parentId=0 或空创建请求返回业务码 400。

兼容与接入建议

  • 三级选择器首次加载调用不带 parentId 的 children;选择省、市后分别以当前 ID 继续查询下一层。
  • 编辑历史数据时先调用 /{id}/path 得到完整选中链,再逐层加载 children;不要根据行政区编码截位推断父子关系。
  • AGGREGATION 节点可能可导航但不可选,页面应分别使用 navigable 和 selectable,不要只根据 hasChildren 判断。
  • 客户端必须把响应 ID 当字符串保存和比较;请求路径与查询参数可以继续发送十进制字符串。
  • 旧行政区划缓存中的数字 ID 与新缓存中的字符串 ID 均可被后端读取,滚动部署期间无需调用方切换缓存版本。

验证证据

  • PR #6359、#6387、#6393、#6398、#6402、#6412 均已合并 dev-v3,六个合并提交都包含在 TEST 精确提交 b62054035a139e3c689179ef75e2d052d08dde52 中。
  • Deploy Panel API 任务 52771074 部署 hl-user-service,任务 b1db24b2 部署 hl-gateway;两项脚本均为 /opt/hulalv/scripts/deploy-backend.sh,终态 success、退出码 0,双实例、Nacos 健康注册、滚动采样与部署窗口日志检查通过。
  • 真实 TEST 管理员经 Gateway 验证未认证返回 401、根级/子级联动、父链回显、失败零写入、创建字符串 ID、数据库落行、Redis 回填、CAS 更新和更新后缓存一致性。
  • 验收创建的唯一测试行已精确删除;数据库总量与测试命名空间恢复基线,四个 Redis 快照按原值和绝对过期时间恢复,缓存锁释放,登录会话注销。操作审计按系统设计保留。

撤回

代码撤回需回退上述六个 PR 并按依赖逆序重新部署 hl-gateway 与 hl-user-service;调用方停止访问 /admin/region/**,并经 Gateway 验证新增路由已不可达、既有 User 接口正常。数据库迁移已经在 TEST 应用,回退代码时保留行政区划表和权限元数据,不执行降版 DDL;Redis 仅在确需重建时精确清理 hl:user:region:v1: 命名空间,禁止触碰登录及其他业务缓存。无 MQ 或跨服务写入需要补偿。