feat(handler): 暴露公开查询 HTTP API(T-210)
This commit is contained in:
+62
-1
@@ -17,7 +17,7 @@ go run . -mode server -addr 127.0.0.1:9000 # 指定地址
|
||||
|
||||
凭据从 `config.yaml`(嵌套 `osi:` 段)读取;服务经 SOCKS5 代理访问内网 OSI 主机。
|
||||
|
||||
⚠ **默认仅绑 `127.0.0.1`**:所有端点回写真实居民档案/体检(含身份证等 PII)。**切勿绑 `0.0.0.0` 或反代到公网**;确需对外必须自行加鉴权。
|
||||
⚠ **默认仅绑 `127.0.0.1`**:所有端点回写真实居民档案/体检或平台主数据。后续内网部署可用 `-addr <内网IP>:<端口>` 监听内网地址,但本服务当前不内置鉴权;上线前必须通过内网访问控制/API 网关补鉴权、日志脱敏和限流。
|
||||
|
||||
---
|
||||
|
||||
@@ -108,6 +108,63 @@ GET /api/health-check/list
|
||||
- 上游:`JKTJLIST00002` `/auto/jktjlist/query`
|
||||
- 返回:`data` 为**数组**(人员名单 + `checkType` 状态,**非体检明细**,见 docs/04 §11.4)
|
||||
|
||||
### 6. 查询网格地址
|
||||
|
||||
```
|
||||
GET /api/dictionaries/grid-addresses
|
||||
```
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `parentCode` | 否 | 上级区划/网格编码 |
|
||||
| `pageNo` | 否 | 页码,整数 |
|
||||
| `operateUser` | 否 | 平台操作人编码 |
|
||||
|
||||
- 上游:`WGDZ00001` `/auto/wgdzcx/query`
|
||||
- 返回:`data` 为**数组**(网格地址主数据,含 `regionCode`、`regionName`、`isFamily` 等)
|
||||
|
||||
### 7. 查询责任医生
|
||||
|
||||
```
|
||||
GET /api/dictionaries/doctors
|
||||
```
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `manaUnitId` | 否 | 9 位管理机构码 |
|
||||
| `operateUser` | 否 | 平台操作人编码 |
|
||||
|
||||
- 上游:`ZRYS00001` `/auto/zryscx/query`
|
||||
- 返回:`data` 为**数组**(责任医生主数据,含 `personId`、`personName` 等)
|
||||
|
||||
### 8. 查询药品目录
|
||||
|
||||
```
|
||||
GET /api/dictionaries/drugs
|
||||
```
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `ypmc` | 否 | 药品名称关键字 |
|
||||
| `pym` | 否 | 拼音码 |
|
||||
| `pageNo` | 否 | 页码,整数 |
|
||||
|
||||
- 上游:`YPML00001` `/auto/ypmlcx/query`
|
||||
- 返回:`data` 为**数组**(药品目录主数据,含 `ypmc`、`ypdw`、`ypgg`、`jldw` 等)
|
||||
|
||||
### 9. 查询机构
|
||||
|
||||
```
|
||||
GET /api/dictionaries/orgs
|
||||
```
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `organizCode` | 否 | 机构编码 |
|
||||
| `parentId` | 否 | 上级机构 ID/编码 |
|
||||
|
||||
- 上游:`CXJG00002` `/auto/cxjg/query`
|
||||
- 返回:`data` 为**数组**(机构主数据,含 `organizCode`、`organizName`、`organizType`、`parentId` 等)
|
||||
---
|
||||
|
||||
## 调用示例
|
||||
@@ -118,6 +175,10 @@ curl "http://127.0.0.1:8080/api/health-record/crowd?idCard=<身份证>"
|
||||
curl "http://127.0.0.1:8080/api/health-check/last?idCard=<身份证>"
|
||||
curl "http://127.0.0.1:8080/api/health-check/all?idCard=<身份证>"
|
||||
curl "http://127.0.0.1:8080/api/health-check/list?checkYear=2025&idCard=<身份证>"
|
||||
curl "http://127.0.0.1:8080/api/dictionaries/grid-addresses?parentCode=<区划码>"
|
||||
curl "http://127.0.0.1:8080/api/dictionaries/doctors?manaUnitId=<机构码>"
|
||||
curl "http://127.0.0.1:8080/api/dictionaries/drugs?ypmc=<药品名>"
|
||||
curl "http://127.0.0.1:8080/api/dictionaries/orgs?parentId=<上级机构ID>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
+11
-7
@@ -6,11 +6,11 @@
|
||||
## 当前快照
|
||||
|
||||
- 日期:2026-07-09
|
||||
- 阶段:**Phase D 创建/更新代码基线完成,真实写入验收受阻;准备 T-210 公开查询 HTTP API**;T-001~T-006、T-201、T-203、T-102、T-202、T-205、T-101、T-103、T-209 已验收;T-206 已完成本地契约/客户端/映射组装代码,但未执行真实 `JKDA00001` create
|
||||
- 阶段:**Phase D 创建/更新代码基线完成,真实写入验收受阻;T-210 公开查询 HTTP API 已完成**;T-001~T-006、T-201、T-203、T-102、T-202、T-205、T-101、T-103、T-209、T-210 已验收;T-206 已完成本地契约/客户端/映射组装代码,但未执行真实 `JKDA00001` create
|
||||
- 技术栈:Go 1.24 单二进制;`main.go -mode server|deliver`;配置读取使用 viper,支持环境变量覆盖;OSI 客户端已具备签名、信封、传输、基础判码、JKDA00002 Find、JKDA00005 FindRqbj(人群分类,已按实测 auto 路径校准)、JKDA00001 Create、JKDA00003 Update,以及 WGDZ/ZRYS/YPML/CXJG 四个公开查询薄封装
|
||||
- 生产代码:已有 `main.go`、`config/`、`contract/envelope.go`、`contract/jkda.go`、`osi/` 薄客户端、`cache/dictionary.go`、`verify_jkda.go`、`go.mod`/`go.sum`;`mapping/dict.go`、`mapping/health_record.go`、`mapping/checkid.go` 已建立映射纯函数、码表基线、主数据反查接入点和创建请求组装;`handler/health_record.go`+`server.go` 提供 server 模式档案查询与人群分类查询端点;网格地址/责任医生/药品目录/机构查询已有 `osi` 客户端,待 T-210 暴露 HTTP API;`pipeline/` 等业务模块仍待后续任务建立
|
||||
- 生产代码:已有 `main.go`、`config/`、`contract/envelope.go`、`contract/jkda.go`、`osi/` 薄客户端、`cache/dictionary.go`、`verify_jkda.go`、`go.mod`/`go.sum`;`mapping/dict.go`、`mapping/health_record.go`、`mapping/checkid.go` 已建立映射纯函数、码表基线、主数据反查接入点和创建请求组装;`handler/health_record.go`+`handler/public.go`+`server.go` 提供 server 模式档案查询、人群分类查询、网格地址、责任医生、药品目录、机构查询端点;`pipeline/` 等业务模块仍待后续任务建立
|
||||
- 联调现实:**JKDA00002 个人档案查询已用 Go 侧真实请求打通**,返回 `code="01" message="操作成功" data_count=1`;**公开查询 WGDZ00001/ZRYS00001/CXJG00002 已用真实档案主数据验证通过**,均返回 `code="01"` 且数组非空;药品目录 YPML00001 已完成客户端封装和单测,尚未做真实药品关键字样本验证;**JKDA00001 create 未跑真实请求**,避免在没有安全测试居民/写入授权时污染平台档案
|
||||
- 测试:`go test ./...` 通过;当前测试覆盖 mode 解析、配置加载与环境变量覆盖、MD5 签名、请求头组装、JSON POST 传输、头名大小写保留、identity 响应编码声明、超时配置、SOCKS5 代理地址校验、信封结构、serviceId 路由、成功/重试判码、Client.Call 请求与响应解析、JKDA00002 查询响应契约、JKDA00001/00003 创建更新请求契约与客户端方法、JKDA00002 Find、JKDA00005 FindRqbj(personSign/idCard/phrId)、公开查询四接口、字典缓存快照与持久化失败不阻断、映射码表双向查找、民族 01~56 完整性、健康档案映射必填/码表校验、主数据名称反查、创建请求组装、checkId 确定性、docx/联调风格映射样本基线、JKDA00002 验证入口
|
||||
- 测试:`go test ./...` 通过;当前测试覆盖 mode 解析、配置加载与环境变量覆盖、MD5 签名、请求头组装、JSON POST 传输、头名大小写保留、identity 响应编码声明、超时配置、SOCKS5 代理地址校验、信封结构、serviceId 路由、成功/重试判码、Client.Call 请求与响应解析、JKDA00002 查询响应契约、JKDA00001/00003 创建更新请求契约与客户端方法、JKDA00002 Find、JKDA00005 FindRqbj(personSign/idCard/phrId)、公开查询四接口、公开查询 HTTP API、字典缓存快照与持久化失败不阻断、映射码表双向查找、民族 01~56 完整性、健康档案映射必填/码表校验、主数据名称反查、创建请求组装、checkId 确定性、docx/联调风格映射样本基线、JKDA00002 验证入口
|
||||
- 标准启动路径:`./init.sh` 已配置三步:依赖下载、`go test ./...`、`go run . -mode server -config config.yaml.example`
|
||||
- 标准验证路径:`go test ./...`、`go build ./...`
|
||||
- 当前 blocker:T-206 真实 create 验收缺少可写入沙箱的安全测试居民资料或明确写入授权。软限制:当前机器从 Git Bash 启动 Go 会出现标准库路径/构建缓存权限异常,`init.sh` 无法完整跑完;PowerShell 下等价 Go 命令和真实查询通过。厂家侧 B1/B2/B4/B5 契约缺口只影响阶段 4
|
||||
@@ -42,6 +42,7 @@
|
||||
| `mapping/health_record_baseline_test.go` | 已有 | docx 风格、联调风格、脏数据映射回归样本 |
|
||||
| `handler/health_record.go` | 已有 | `GET /api/health-record/find` 档案查询、`GET /api/health-record/crowd` 人群分类查询,均回写平台完整响应 |
|
||||
| `handler/health_check.go` | 已有 | 体检端点 `GET /api/health-check/last`(最近一次)+ `/all`(全部体检)+ `/list`(年度名单)|
|
||||
| `handler/public.go` | 已有 | 公开查询端点 `GET /api/dictionaries/grid-addresses`、`/doctors`、`/drugs`、`/orgs` |
|
||||
| `server.go` `osi_client.go` | 已有 | server 模式起 HTTP 服务、注册路由;`buildOSIClient` 共用构造(verify 与 server 复用) |
|
||||
| `pipeline/` 等 | 待建 | 后续任务 |
|
||||
|
||||
@@ -84,6 +85,10 @@ curl "http://127.0.0.1:8080/api/health-record/crowd?idCard=<idCard>" #
|
||||
curl "http://127.0.0.1:8080/api/health-check/last?idCard=<idCard>" # 最近一次体检
|
||||
curl "http://127.0.0.1:8080/api/health-check/all?idCard=<idCard>" # 某人全部体检(数组)
|
||||
curl "http://127.0.0.1:8080/api/health-check/list?checkYear=2025&idCard=<idCard>" # 年度已检/未检名单
|
||||
curl "http://127.0.0.1:8080/api/dictionaries/grid-addresses?parentCode=<区划码>" # 网格地址
|
||||
curl "http://127.0.0.1:8080/api/dictionaries/doctors?manaUnitId=<机构码>" # 责任医生
|
||||
curl "http://127.0.0.1:8080/api/dictionaries/drugs?ypmc=<药品名>" # 药品目录
|
||||
curl "http://127.0.0.1:8080/api/dictionaries/orgs?parentId=<上级机构ID>" # 机构查询
|
||||
|
||||
# 本地 Python 联调查询(脚本硬编码凭据,勿提交)
|
||||
python3 scripts/query_health_record.py
|
||||
@@ -94,10 +99,9 @@ python3 scripts/query_health_record.py
|
||||
> 读先行调整(2026-07-08):写入(T-206/T-204)被厂家授权锁死,先推其余业务线查询。
|
||||
|
||||
1. ✅ T-301/T-305 体检查询(最近一次 + 名单)、T-302 体检 HTTP 端点 —— 均已完成。
|
||||
2. **T-210 公开查询 HTTP API**:把人群分类、网格地址、责任医生、药品目录、机构查询暴露成 server 模式 HTTP API,并同步 `docs/07` 与 `docs/openapi.yaml`。
|
||||
3. T-303 老年人查询(自理/体质,serviceId 部分待 B4)——起 Python 探针试探。
|
||||
4. 并行催厂家(docs/06 ★ 优先催办):写入授权+测试档案、缺失单查/老年人 serviceId、checkId/完整度规则。
|
||||
5. 授权到位后回到 T-206 真实 create 验收 → T-204。
|
||||
2. **T-303 老年人查询**(自理/体质,serviceId 部分待 B4)——起 Python 探针试探。
|
||||
3. 并行催厂家(docs/06 ★ 优先催办):写入授权+测试档案、缺失单查/老年人 serviceId、checkId/完整度规则。
|
||||
4. 授权到位后回到 T-206 真实 create 验收 → T-204。
|
||||
|
||||
## 维护规则
|
||||
|
||||
|
||||
+333
-109
@@ -1,14 +1,21 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: chis_osi Server API
|
||||
version: "0.1.0"
|
||||
description: |
|
||||
chis_osi server 模式对外提供的本机 HTTP 查询接口。
|
||||
version: 0.1.0
|
||||
description: 'chis_osi server 模式对外提供的本机 HTTP 查询接口。
|
||||
|
||||
|
||||
本文档描述的是本项目自己的 HTTP API,不是上游 CHIS OSI 平台接口。
|
||||
|
||||
当前端点会原样透传上游平台返回的完整 JSON,响应中可能包含身份证、档案号、
|
||||
体检记录等个人敏感信息。默认只应监听 127.0.0.1;如需对外暴露,必须先补鉴权、
|
||||
访问日志脱敏与限流。
|
||||
|
||||
体检记录等个人敏感信息。默认只监听 127.0.0.1;内网部署可通过 -addr 监听内网地址,
|
||||
|
||||
但服务本身不内置鉴权。如需给多系统调用,必须先补内网访问控制、
|
||||
|
||||
API 鉴权、访问日志脱敏与限流。
|
||||
|
||||
'
|
||||
servers:
|
||||
- url: http://127.0.0.1:8080
|
||||
description: 本地默认 server 模式地址
|
||||
@@ -17,194 +24,343 @@ tags:
|
||||
description: 健康档案查询
|
||||
- name: health-check
|
||||
description: 健康体检查询
|
||||
- name: dictionaries
|
||||
description: 公开主数据查询
|
||||
paths:
|
||||
/api/health-record/find:
|
||||
get:
|
||||
tags:
|
||||
- health-record
|
||||
summary: 查询个人健康档案
|
||||
description: |
|
||||
查询个人健康档案,原样返回上游 JKDA00002 `/auto/jkda/find` 响应。
|
||||
description: '查询个人健康档案,原样返回上游 JKDA00002 `/auto/jkda/find` 响应。
|
||||
|
||||
|
||||
`idCard`、`phrid`、`personName`、`empiId` 四个查询参数必须且只能提供一个。
|
||||
|
||||
`data` 为数组,内容为平台返回的完整档案聚合对象。
|
||||
|
||||
'
|
||||
operationId: findHealthRecord
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/idCard"
|
||||
- $ref: "#/components/parameters/phrid"
|
||||
- $ref: "#/components/parameters/personName"
|
||||
- $ref: "#/components/parameters/empiId"
|
||||
- $ref: '#/components/parameters/idCard'
|
||||
- $ref: '#/components/parameters/phrid'
|
||||
- $ref: '#/components/parameters/personName'
|
||||
- $ref: '#/components/parameters/empiId'
|
||||
responses:
|
||||
"200":
|
||||
'200':
|
||||
description: 平台完整响应,成功和平台业务错误均原样透传。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/HealthRecordFindResponse"
|
||||
$ref: '#/components/schemas/HealthRecordFindResponse'
|
||||
examples:
|
||||
success:
|
||||
value:
|
||||
code: "01"
|
||||
code: '01'
|
||||
message: 操作成功
|
||||
data:
|
||||
- phrId: PHRID_PLACEHOLDER
|
||||
idCard: "440000********0000"
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
"405":
|
||||
$ref: "#/components/responses/MethodNotAllowed"
|
||||
"502":
|
||||
$ref: "#/components/responses/BadGateway"
|
||||
idCard: 440000********0000
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'405':
|
||||
$ref: '#/components/responses/MethodNotAllowed'
|
||||
'502':
|
||||
$ref: '#/components/responses/BadGateway'
|
||||
/api/health-record/crowd:
|
||||
get:
|
||||
tags:
|
||||
- health-record
|
||||
summary: 查询人群分类/子档案标记
|
||||
description: |
|
||||
查询居民人群分类与子档案标记,原样返回上游 JKDA00005
|
||||
description: '查询居民人群分类与子档案标记,原样返回上游 JKDA00005
|
||||
|
||||
`/auto/jkda/findrqbj` 响应。
|
||||
|
||||
|
||||
`idCard`、`phrid` 两个查询参数必须且只能提供一个。`personSign` 可能为逗号分隔
|
||||
|
||||
多值,码表见 docs/04 §3。
|
||||
|
||||
'
|
||||
operationId: findHealthRecordCrowd
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/idCard"
|
||||
- $ref: "#/components/parameters/phrid"
|
||||
- $ref: '#/components/parameters/idCard'
|
||||
- $ref: '#/components/parameters/phrid'
|
||||
responses:
|
||||
"200":
|
||||
'200':
|
||||
description: 平台完整响应,成功和平台业务错误均原样透传。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CrowdResponse"
|
||||
$ref: '#/components/schemas/CrowdResponse'
|
||||
examples:
|
||||
success:
|
||||
value:
|
||||
code: "01"
|
||||
code: '01'
|
||||
message: 操作成功
|
||||
data:
|
||||
personSign: "01,04"
|
||||
idCard: "440000********0000"
|
||||
personSign: 01,04
|
||||
idCard: 440000********0000
|
||||
phrId: PHRID_PLACEHOLDER
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
"405":
|
||||
$ref: "#/components/responses/MethodNotAllowed"
|
||||
"502":
|
||||
$ref: "#/components/responses/BadGateway"
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'405':
|
||||
$ref: '#/components/responses/MethodNotAllowed'
|
||||
'502':
|
||||
$ref: '#/components/responses/BadGateway'
|
||||
/api/health-check/last:
|
||||
get:
|
||||
tags:
|
||||
- health-check
|
||||
summary: 查询最近一次体检
|
||||
description: |
|
||||
查询某人最近一次健康体检,原样返回上游 JKTJLSJL00002
|
||||
description: '查询某人最近一次健康体检,原样返回上游 JKTJLSJL00002
|
||||
|
||||
`/auto/jktjlscx/query` 响应。
|
||||
|
||||
|
||||
`idCard`、`phrid`、`empiId` 三个查询参数必须且只能提供一个。
|
||||
|
||||
`data` 为单个完整体检对象。
|
||||
|
||||
'
|
||||
operationId: findLastHealthCheck
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/idCard"
|
||||
- $ref: "#/components/parameters/phrid"
|
||||
- $ref: "#/components/parameters/empiId"
|
||||
- $ref: '#/components/parameters/idCard'
|
||||
- $ref: '#/components/parameters/phrid'
|
||||
- $ref: '#/components/parameters/empiId'
|
||||
responses:
|
||||
"200":
|
||||
'200':
|
||||
description: 平台完整响应,成功和平台业务错误均原样透传。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/HealthCheckLastResponse"
|
||||
$ref: '#/components/schemas/HealthCheckLastResponse'
|
||||
examples:
|
||||
success:
|
||||
value:
|
||||
code: "01"
|
||||
code: '01'
|
||||
message: 操作成功
|
||||
data:
|
||||
checkId: CHECK_ID_PLACEHOLDER
|
||||
checkDate: "2025-01-01"
|
||||
idCard: "440000********0000"
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
"405":
|
||||
$ref: "#/components/responses/MethodNotAllowed"
|
||||
"502":
|
||||
$ref: "#/components/responses/BadGateway"
|
||||
checkDate: '2025-01-01'
|
||||
idCard: 440000********0000
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'405':
|
||||
$ref: '#/components/responses/MethodNotAllowed'
|
||||
'502':
|
||||
$ref: '#/components/responses/BadGateway'
|
||||
/api/health-check/all:
|
||||
get:
|
||||
tags:
|
||||
- health-check
|
||||
summary: 查询某人全部体检
|
||||
description: |
|
||||
查询某人的全部健康体检历史,原样返回上游 JKTJ00002 `/auto/jktj/query` 响应。
|
||||
description: '查询某人的全部健康体检历史,原样返回上游 JKTJ00002 `/auto/jktj/query` 响应。
|
||||
|
||||
|
||||
`idCard`、`phrid`、`empiId` 三个查询参数必须且只能提供一个。
|
||||
|
||||
`data` 为数组;历史记录的 `checkId` 可能为空,调用方应按 `checkDate` 等字段辅助区分。
|
||||
|
||||
'
|
||||
operationId: findAllHealthChecks
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/idCard"
|
||||
- $ref: "#/components/parameters/phrid"
|
||||
- $ref: "#/components/parameters/empiId"
|
||||
- $ref: '#/components/parameters/idCard'
|
||||
- $ref: '#/components/parameters/phrid'
|
||||
- $ref: '#/components/parameters/empiId'
|
||||
responses:
|
||||
"200":
|
||||
'200':
|
||||
description: 平台完整响应,成功和平台业务错误均原样透传。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/HealthCheckAllResponse"
|
||||
$ref: '#/components/schemas/HealthCheckAllResponse'
|
||||
examples:
|
||||
success:
|
||||
value:
|
||||
code: "01"
|
||||
code: '01'
|
||||
message: 操作成功
|
||||
data:
|
||||
- checkId: CHECK_ID_PLACEHOLDER
|
||||
checkDate: "2025-01-01"
|
||||
idCard: "440000********0000"
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
"405":
|
||||
$ref: "#/components/responses/MethodNotAllowed"
|
||||
"502":
|
||||
$ref: "#/components/responses/BadGateway"
|
||||
checkDate: '2025-01-01'
|
||||
idCard: 440000********0000
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'405':
|
||||
$ref: '#/components/responses/MethodNotAllowed'
|
||||
'502':
|
||||
$ref: '#/components/responses/BadGateway'
|
||||
/api/health-check/list:
|
||||
get:
|
||||
tags:
|
||||
- health-check
|
||||
summary: 查询年度已检/未检人员名单
|
||||
description: |
|
||||
查询年度体检人员名单,原样返回上游 JKTJLIST00002 `/auto/jktjlist/query` 响应。
|
||||
description: '查询年度体检人员名单,原样返回上游 JKTJLIST00002 `/auto/jktjlist/query` 响应。
|
||||
|
||||
|
||||
`data` 为人员名单和 `checkType` 状态,不是体检明细。
|
||||
|
||||
'
|
||||
operationId: listHealthCheckPeople
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/checkYear"
|
||||
- $ref: "#/components/parameters/idCard"
|
||||
- $ref: "#/components/parameters/checkType"
|
||||
- $ref: "#/components/parameters/page"
|
||||
- $ref: "#/components/parameters/rows"
|
||||
- $ref: '#/components/parameters/checkYear'
|
||||
- $ref: '#/components/parameters/idCard'
|
||||
- $ref: '#/components/parameters/checkType'
|
||||
- $ref: '#/components/parameters/page'
|
||||
- $ref: '#/components/parameters/rows'
|
||||
responses:
|
||||
"200":
|
||||
'200':
|
||||
description: 平台完整响应,成功和平台业务错误均原样透传。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/HealthCheckListResponse"
|
||||
$ref: '#/components/schemas/HealthCheckListResponse'
|
||||
examples:
|
||||
success:
|
||||
value:
|
||||
code: "01"
|
||||
code: '01'
|
||||
message: 操作成功
|
||||
data:
|
||||
- idCard: "440000********0000"
|
||||
checkYear: "2025"
|
||||
checkType: "0"
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
"405":
|
||||
$ref: "#/components/responses/MethodNotAllowed"
|
||||
"502":
|
||||
$ref: "#/components/responses/BadGateway"
|
||||
- idCard: 440000********0000
|
||||
checkYear: '2025'
|
||||
checkType: '0'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'405':
|
||||
$ref: '#/components/responses/MethodNotAllowed'
|
||||
'502':
|
||||
$ref: '#/components/responses/BadGateway'
|
||||
/api/dictionaries/grid-addresses:
|
||||
get:
|
||||
tags:
|
||||
- dictionaries
|
||||
summary: 查询网格地址
|
||||
description: 查询网格地址主数据,原样返回上游 WGDZ00001 `/auto/wgdzcx/query` 响应。
|
||||
operationId: listGridAddresses
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/parentCode'
|
||||
- $ref: '#/components/parameters/pageNo'
|
||||
- $ref: '#/components/parameters/operateUser'
|
||||
responses:
|
||||
'200':
|
||||
description: 平台完整响应,成功和平台业务错误均原样透传。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DictionaryListResponse'
|
||||
examples:
|
||||
success:
|
||||
value:
|
||||
code: '01'
|
||||
message: 操作成功
|
||||
data:
|
||||
- regionCode: '441625000000'
|
||||
regionName: 测试网格
|
||||
isFamily: '1'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'405':
|
||||
$ref: '#/components/responses/MethodNotAllowed'
|
||||
'502':
|
||||
$ref: '#/components/responses/BadGateway'
|
||||
/api/dictionaries/doctors:
|
||||
get:
|
||||
tags:
|
||||
- dictionaries
|
||||
summary: 查询责任医生
|
||||
description: 查询责任医生主数据,原样返回上游 ZRYS00001 `/auto/zryscx/query` 响应。
|
||||
operationId: listDoctors
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/manaUnitId'
|
||||
- $ref: '#/components/parameters/operateUser'
|
||||
responses:
|
||||
'200':
|
||||
description: 平台完整响应,成功和平台业务错误均原样透传。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DictionaryListResponse'
|
||||
examples:
|
||||
success:
|
||||
value:
|
||||
code: '01'
|
||||
message: 操作成功
|
||||
data:
|
||||
- personId: DOC_ID_PLACEHOLDER
|
||||
personName: 测试医生
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'405':
|
||||
$ref: '#/components/responses/MethodNotAllowed'
|
||||
'502':
|
||||
$ref: '#/components/responses/BadGateway'
|
||||
/api/dictionaries/drugs:
|
||||
get:
|
||||
tags:
|
||||
- dictionaries
|
||||
summary: 查询药品目录
|
||||
description: 查询药品目录主数据,原样返回上游 YPML00001 `/auto/ypmlcx/query` 响应。
|
||||
operationId: listDrugs
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/ypmc'
|
||||
- $ref: '#/components/parameters/pym'
|
||||
- $ref: '#/components/parameters/pageNo'
|
||||
responses:
|
||||
'200':
|
||||
description: 平台完整响应,成功和平台业务错误均原样透传。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DictionaryListResponse'
|
||||
examples:
|
||||
success:
|
||||
value:
|
||||
code: '01'
|
||||
message: 操作成功
|
||||
data:
|
||||
- ypmc: 测试药品
|
||||
ypdw: 盒
|
||||
ypgg: 10mg
|
||||
jldw: 片
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'405':
|
||||
$ref: '#/components/responses/MethodNotAllowed'
|
||||
'502':
|
||||
$ref: '#/components/responses/BadGateway'
|
||||
/api/dictionaries/orgs:
|
||||
get:
|
||||
tags:
|
||||
- dictionaries
|
||||
summary: 查询机构
|
||||
description: 查询机构主数据,原样返回上游 CXJG00002 `/auto/cxjg/query` 响应。
|
||||
operationId: listOrgs
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/organizCode'
|
||||
- $ref: '#/components/parameters/parentId'
|
||||
responses:
|
||||
'200':
|
||||
description: 平台完整响应,成功和平台业务错误均原样透传。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DictionaryListResponse'
|
||||
examples:
|
||||
success:
|
||||
value:
|
||||
code: '01'
|
||||
message: 操作成功
|
||||
data:
|
||||
- organizCode: '441625001'
|
||||
organizName: 测试机构
|
||||
organizType: '1'
|
||||
parentId: '441625'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'405':
|
||||
$ref: '#/components/responses/MethodNotAllowed'
|
||||
'502':
|
||||
$ref: '#/components/responses/BadGateway'
|
||||
components:
|
||||
parameters:
|
||||
idCard:
|
||||
@@ -242,8 +398,8 @@ components:
|
||||
description: 体检年度,如 2025。
|
||||
schema:
|
||||
type: string
|
||||
pattern: "^[0-9]{4}$"
|
||||
example: "2025"
|
||||
pattern: ^[0-9]{4}$
|
||||
example: '2025'
|
||||
checkType:
|
||||
name: checkType
|
||||
in: query
|
||||
@@ -252,9 +408,9 @@ components:
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- "0"
|
||||
- "1"
|
||||
- "2"
|
||||
- '0'
|
||||
- '1'
|
||||
- '2'
|
||||
page:
|
||||
name: page
|
||||
in: query
|
||||
@@ -262,7 +418,7 @@ components:
|
||||
description: 页码;未传时后端默认 1。
|
||||
schema:
|
||||
type: string
|
||||
default: "1"
|
||||
default: '1'
|
||||
rows:
|
||||
name: rows
|
||||
in: query
|
||||
@@ -270,24 +426,81 @@ components:
|
||||
description: 每页条数;未传时后端默认 10。
|
||||
schema:
|
||||
type: string
|
||||
default: "10"
|
||||
default: '10'
|
||||
parentCode:
|
||||
name: parentCode
|
||||
in: query
|
||||
required: false
|
||||
description: 上级区划/网格编码。
|
||||
schema:
|
||||
type: string
|
||||
pageNo:
|
||||
name: pageNo
|
||||
in: query
|
||||
required: false
|
||||
description: 页码,必须为整数。
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
operateUser:
|
||||
name: operateUser
|
||||
in: query
|
||||
required: false
|
||||
description: 平台操作人编码。
|
||||
schema:
|
||||
type: string
|
||||
manaUnitId:
|
||||
name: manaUnitId
|
||||
in: query
|
||||
required: false
|
||||
description: 9 位管理机构码。
|
||||
schema:
|
||||
type: string
|
||||
ypmc:
|
||||
name: ypmc
|
||||
in: query
|
||||
required: false
|
||||
description: 药品名称关键字。
|
||||
schema:
|
||||
type: string
|
||||
pym:
|
||||
name: pym
|
||||
in: query
|
||||
required: false
|
||||
description: 药品拼音码。
|
||||
schema:
|
||||
type: string
|
||||
organizCode:
|
||||
name: organizCode
|
||||
in: query
|
||||
required: false
|
||||
description: 机构编码。
|
||||
schema:
|
||||
type: string
|
||||
parentId:
|
||||
name: parentId
|
||||
in: query
|
||||
required: false
|
||||
description: 上级机构 ID/编码。
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
BadRequest:
|
||||
description: 请求参数错误。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
missingQueryKey:
|
||||
value:
|
||||
error: "provide one of: idCard, phrid, empiId"
|
||||
error: 'provide one of: idCard, phrid, empiId'
|
||||
MethodNotAllowed:
|
||||
description: HTTP 方法不支持。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
methodNotAllowed:
|
||||
value:
|
||||
@@ -297,7 +510,7 @@ components:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
examples:
|
||||
upstreamError:
|
||||
value:
|
||||
@@ -319,14 +532,14 @@ components:
|
||||
code:
|
||||
type: string
|
||||
description: 平台业务码。成功实测为字符串 "01";平台业务错误也会原样透传。
|
||||
example: "01"
|
||||
example: '01'
|
||||
message:
|
||||
type: string
|
||||
example: 操作成功
|
||||
additionalProperties: true
|
||||
HealthRecordFindResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/OSIBaseResponse"
|
||||
- $ref: '#/components/schemas/OSIBaseResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
@@ -337,18 +550,18 @@ components:
|
||||
additionalProperties: true
|
||||
CrowdResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/OSIBaseResponse"
|
||||
- $ref: '#/components/schemas/OSIBaseResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/CrowdData"
|
||||
$ref: '#/components/schemas/CrowdData'
|
||||
CrowdData:
|
||||
type: object
|
||||
properties:
|
||||
personSign:
|
||||
type: string
|
||||
description: 人群分类码,可能为逗号分隔多值。
|
||||
example: "01,04"
|
||||
example: 01,04
|
||||
idCard:
|
||||
type: string
|
||||
description: 身份证号。
|
||||
@@ -358,29 +571,29 @@ components:
|
||||
additionalProperties: true
|
||||
HealthCheckLastResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/OSIBaseResponse"
|
||||
- $ref: '#/components/schemas/OSIBaseResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/HealthCheckRecord"
|
||||
$ref: '#/components/schemas/HealthCheckRecord'
|
||||
HealthCheckAllResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/OSIBaseResponse"
|
||||
- $ref: '#/components/schemas/OSIBaseResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/HealthCheckRecord"
|
||||
$ref: '#/components/schemas/HealthCheckRecord'
|
||||
HealthCheckListResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/OSIBaseResponse"
|
||||
- $ref: '#/components/schemas/OSIBaseResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/HealthCheckPerson"
|
||||
$ref: '#/components/schemas/HealthCheckPerson'
|
||||
HealthCheckRecord:
|
||||
type: object
|
||||
description: 平台完整体检对象;字段很多,未在本项目裁剪。
|
||||
@@ -410,3 +623,14 @@ components:
|
||||
type: string
|
||||
description: 0 已检,1 未检,2 全部或平台返回状态。
|
||||
additionalProperties: true
|
||||
DictionaryListResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/OSIBaseResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
description: 平台公开查询主数据数组,字段按上游原始响应透传。
|
||||
items:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"chis_osi/osi"
|
||||
)
|
||||
|
||||
// PublicHandler 暴露 OSI 公开查询类 HTTP 入口。
|
||||
type PublicHandler struct {
|
||||
client *osi.Client
|
||||
}
|
||||
|
||||
func NewPublicHandler(client *osi.Client) *PublicHandler {
|
||||
return &PublicHandler{client: client}
|
||||
}
|
||||
|
||||
// GridAddresses 处理 GET /api/dictionaries/grid-addresses?parentCode=..&pageNo=..&operateUser=..
|
||||
func (h *PublicHandler) GridAddresses(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "only GET is supported")
|
||||
return
|
||||
}
|
||||
q := r.URL.Query()
|
||||
pageNo, ok := parseOptionalInt(w, q.Get("pageNo"), "pageNo")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
_, result, err := h.client.QueryGridAddress(r.Context(), osi.GridAddressQuery{
|
||||
ParentCode: q.Get("parentCode"),
|
||||
PageNo: pageNo,
|
||||
OperateUser: q.Get("operateUser"),
|
||||
})
|
||||
writeRawOrError(w, result, err)
|
||||
}
|
||||
|
||||
// Doctors 处理 GET /api/dictionaries/doctors?manaUnitId=..&operateUser=..
|
||||
func (h *PublicHandler) Doctors(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "only GET is supported")
|
||||
return
|
||||
}
|
||||
q := r.URL.Query()
|
||||
_, result, err := h.client.QueryDoctors(r.Context(), osi.DoctorQuery{
|
||||
ManaUnitID: q.Get("manaUnitId"),
|
||||
OperateUser: q.Get("operateUser"),
|
||||
})
|
||||
writeRawOrError(w, result, err)
|
||||
}
|
||||
|
||||
// Drugs 处理 GET /api/dictionaries/drugs?ypmc=..&pym=..&pageNo=..
|
||||
func (h *PublicHandler) Drugs(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "only GET is supported")
|
||||
return
|
||||
}
|
||||
q := r.URL.Query()
|
||||
pageNo, ok := parseOptionalInt(w, q.Get("pageNo"), "pageNo")
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
_, result, err := h.client.QueryDrugs(r.Context(), osi.DrugQuery{
|
||||
PageNo: pageNo,
|
||||
YPMC: q.Get("ypmc"),
|
||||
PYM: q.Get("pym"),
|
||||
})
|
||||
writeRawOrError(w, result, err)
|
||||
}
|
||||
|
||||
// Orgs 处理 GET /api/dictionaries/orgs?organizCode=..&parentId=..
|
||||
func (h *PublicHandler) Orgs(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "only GET is supported")
|
||||
return
|
||||
}
|
||||
q := r.URL.Query()
|
||||
_, result, err := h.client.QueryOrgs(r.Context(), osi.OrgQuery{
|
||||
OrganizCode: q.Get("organizCode"),
|
||||
ParentID: q.Get("parentId"),
|
||||
})
|
||||
writeRawOrError(w, result, err)
|
||||
}
|
||||
|
||||
func parseOptionalInt(w http.ResponseWriter, raw string, name string) (int, bool) {
|
||||
if raw == "" {
|
||||
return 0, true
|
||||
}
|
||||
value, err := strconv.Atoi(raw)
|
||||
if err != nil {
|
||||
writeJSONError(w, http.StatusBadRequest, name+" must be an integer")
|
||||
return 0, false
|
||||
}
|
||||
return value, true
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPublicGridAddressesReturnsRawResponse(t *testing.T) {
|
||||
client, seenPath := newTestClient(t, `{"code":"01","message":"操作成功","data":[{"regionCode":"441625000000","regionName":"测试网格"}]}`)
|
||||
h := NewPublicHandler(client)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/dictionaries/grid-addresses?parentCode=441625&pageNo=1&operateUser=712041", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
h.GridAddresses(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d", rec.Code)
|
||||
}
|
||||
if *seenPath != "/osi/api/auto/wgdzcx/query" {
|
||||
t.Fatalf("osi path = %q", *seenPath)
|
||||
}
|
||||
body, _ := io.ReadAll(rec.Body)
|
||||
if !strings.Contains(string(body), `"regionCode"`) {
|
||||
t.Fatalf("body missing grid address data: %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicDoctorsReturnsRawResponse(t *testing.T) {
|
||||
client, seenPath := newTestClient(t, `{"code":"01","message":"操作成功","data":[{"personId":"doc-001","personName":"测试医生"}]}`)
|
||||
h := NewPublicHandler(client)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/dictionaries/doctors?manaUnitId=441625001&operateUser=712041", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
h.Doctors(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d", rec.Code)
|
||||
}
|
||||
if *seenPath != "/osi/api/auto/zryscx/query" {
|
||||
t.Fatalf("osi path = %q", *seenPath)
|
||||
}
|
||||
body, _ := io.ReadAll(rec.Body)
|
||||
if !strings.Contains(string(body), `"personId"`) {
|
||||
t.Fatalf("body missing doctor data: %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicDrugsReturnsRawResponse(t *testing.T) {
|
||||
client, seenPath := newTestClient(t, `{"code":"01","message":"操作成功","data":[{"ypmc":"测试药品","ypdw":"盒"}]}`)
|
||||
h := NewPublicHandler(client)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/dictionaries/drugs?ypmc=测试&pageNo=1&pym=CS", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
h.Drugs(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d", rec.Code)
|
||||
}
|
||||
if *seenPath != "/osi/api/auto/ypmlcx/query" {
|
||||
t.Fatalf("osi path = %q", *seenPath)
|
||||
}
|
||||
body, _ := io.ReadAll(rec.Body)
|
||||
if !strings.Contains(string(body), `"ypmc"`) {
|
||||
t.Fatalf("body missing drug data: %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicOrgsReturnsRawResponse(t *testing.T) {
|
||||
client, seenPath := newTestClient(t, `{"code":"01","message":"操作成功","data":[{"organizCode":"441625001","organizName":"测试机构"}]}`)
|
||||
h := NewPublicHandler(client)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/dictionaries/orgs?organizCode=441625001&parentId=441625", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
h.Orgs(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d", rec.Code)
|
||||
}
|
||||
if *seenPath != "/osi/api/auto/cxjg/query" {
|
||||
t.Fatalf("osi path = %q", *seenPath)
|
||||
}
|
||||
body, _ := io.ReadAll(rec.Body)
|
||||
if !strings.Contains(string(body), `"organizCode"`) {
|
||||
t.Fatalf("body missing org data: %s", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublicDictionaryRejectsInvalidPageNo(t *testing.T) {
|
||||
h := NewPublicHandler(nil)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/dictionaries/drugs?pageNo=bad", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
h.Drugs(rec, req)
|
||||
|
||||
if rec.Code != http.StatusBadRequest {
|
||||
t.Fatalf("status = %d, want 400", rec.Code)
|
||||
}
|
||||
}
|
||||
+10
@@ -273,3 +273,13 @@
|
||||
- 决策:T-210 依赖 T-101(四类公开查询 OSI 客户端已完成)与 T-209(人群分类 HTTP 端点已存在)。实现时不再重复写 OSI 客户端,只补 handler/router、HTTP 测试、`docs/07` 与 OpenAPI。项目后续以内网部署为目标,但接口仍返回 PII/主数据,需在文档中明确绑定地址和鉴权边界。
|
||||
- 验证:文档登记阶段运行 `git diff --check`;代码实现阶段再跑 `go test ./...`、`go build ./...`。
|
||||
- 下一步:开始 T-210,实现公开查询 HTTP API。
|
||||
## 2026-07-09 T-210 公开查询 HTTP API
|
||||
|
||||
- 状态:DONE
|
||||
- 变更:新增 `handler/public.go` 与 `handler/public_test.go`,暴露 `GET /api/dictionaries/grid-addresses`、`/doctors`、`/drugs`、`/orgs`;`server.go` 注册四个公开查询路由并打印启动提示;既有人群分类端点 `/api/health-record/crowd` 保持不变。
|
||||
- 变更:同步 `docs/07-本项目HTTP接口.md` 与 `docs/openapi.yaml`,补网格地址、责任医生、药品目录、机构查询;更新内网部署说明,明确服务本身不内置鉴权。
|
||||
- RED:`go test ./handler -run TestPublic -count=1` 初次失败,缺少 `NewPublicHandler`。
|
||||
- GREEN:补最小实现后 `go test ./handler -run TestPublic -count=1` 通过。
|
||||
- 验证:`go test ./...` 通过;`go build ./...` 通过;`python -c "import yaml; yaml.safe_load(open('docs/openapi.yaml', encoding='utf-8'))"` 通过;`git diff --check` 通过。
|
||||
- 决策:公开查询端点继续原样回写平台 JSON,不裁字段;`pageNo` 做 HTTP 层整数校验,其余查询条件按上游查询透传。项目按内网部署推进,但 API 返回主数据/PII 相关上下文,生产暴露前仍需网关鉴权和日志脱敏。
|
||||
- 下一步:T-303 老年人查询探针;或继续补内网部署鉴权/访问控制任务。
|
||||
|
||||
@@ -17,12 +17,17 @@ func runServer(cfg config.Config, addr string) error {
|
||||
|
||||
hr := handler.NewHealthRecordHandler(client)
|
||||
hc := handler.NewHealthCheckHandler(client)
|
||||
pub := handler.NewPublicHandler(client)
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/api/health-record/find", hr.Find)
|
||||
mux.HandleFunc("/api/health-record/crowd", hr.Crowd)
|
||||
mux.HandleFunc("/api/health-check/last", hc.Last)
|
||||
mux.HandleFunc("/api/health-check/all", hc.All)
|
||||
mux.HandleFunc("/api/health-check/list", hc.List)
|
||||
mux.HandleFunc("/api/dictionaries/grid-addresses", pub.GridAddresses)
|
||||
mux.HandleFunc("/api/dictionaries/doctors", pub.Doctors)
|
||||
mux.HandleFunc("/api/dictionaries/drugs", pub.Drugs)
|
||||
mux.HandleFunc("/api/dictionaries/orgs", pub.Orgs)
|
||||
|
||||
fmt.Printf("chis_osi server listening on %s\n", addr)
|
||||
fmt.Printf(" GET http://%s/api/health-record/find?idCard=<身份证>\n", addr)
|
||||
@@ -30,6 +35,10 @@ func runServer(cfg config.Config, addr string) error {
|
||||
fmt.Printf(" GET http://%s/api/health-check/last?idCard=<身份证>\n", addr)
|
||||
fmt.Printf(" GET http://%s/api/health-check/all?idCard=<身份证>\n", addr)
|
||||
fmt.Printf(" GET http://%s/api/health-check/list?checkYear=<年度>&idCard=<身份证>\n", addr)
|
||||
fmt.Printf(" GET http://%s/api/dictionaries/grid-addresses?parentCode=<区划码>\n", addr)
|
||||
fmt.Printf(" GET http://%s/api/dictionaries/doctors?manaUnitId=<机构码>\n", addr)
|
||||
fmt.Printf(" GET http://%s/api/dictionaries/drugs?ypmc=<药品名>\n", addr)
|
||||
fmt.Printf(" GET http://%s/api/dictionaries/orgs?parentId=<上级机构ID>\n", addr)
|
||||
|
||||
server := &http.Server{Addr: addr, Handler: mux}
|
||||
return server.ListenAndServe()
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
| --- | --- | --- | --- | --- |
|
||||
| T-101 | `osi/public.go` 四个字典查询(网格/责任医生/药品/机构) | T-005 | 真实机构码能查到下级网格、责任医生、机构树 | DONE |
|
||||
| T-103 | 字典缓存(内存 + redis 可选) | T-101, T-102 | 映射层能反查 `regionCode/manaDoctorId/manaUnitId`;redis 不可用不阻断 | DONE |
|
||||
| T-210 | 公开查询 HTTP API(人群分类、网格地址、责任医生、药品目录、机构) | T-101, T-209 | server 模式暴露人群分类与四类公开查询 HTTP API;原样回写平台 JSON;同步 `docs/07` 与 `docs/openapi.yaml`;按内网部署场景明确绑定地址/鉴权边界 | TODO |
|
||||
| T-210 | 公开查询 HTTP API(人群分类、网格地址、责任医生、药品目录、机构) | T-101, T-209 | server 模式暴露人群分类与四类公开查询 HTTP API;原样回写平台 JSON;同步 `docs/07` 与 `docs/openapi.yaml`;按内网部署场景明确绑定地址/鉴权边界 | DONE |
|
||||
| T-206 | `osi/jkda.go`:**Create/Update** + `contract/jkda.go` 补创建请求结构体 | T-201, T-202, T-103 | 一条档案经映射(真实字典快照)→ create → 平台返回成功码与 `phrId`;Update 沿用 checkId | BLOCKED(代码完成;待写入授权/测试档案,排在 Phase Q2 之后) |
|
||||
| T-204 | `handler`+`router`:`/api/health-record/save` | T-206 | server 模式起服务,curl 全链路返回投递结果 | TODO(待 T-206 解阻塞) |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user