feat(osi): 体检已检/未检名单查询打通(T-305)
- osi.ListHealthCheckPeople(JKTJLIST00002 /auto/jktjlist/query) - ListHealthCheckQuery:checkYear 必填、page/rows 默认、idCard/checkType 可选 - contract.HealthCheckPerson 名单行 20 字段,字段名按实测校正(birthday/phrId/manaDoctorId/manaDocterName/empiId) - 单测:名单解码/路径/baseInfo 分页/checkYear 校验(脱敏假数据) - 实测端点已部署,code=01 返回分页人员名单 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -17,3 +17,28 @@ type HealthCheckSummary struct {
|
|||||||
PersonName string `json:"personName"`
|
PersonName string `json:"personName"`
|
||||||
CheckDate string `json:"checkDate"`
|
CheckDate string `json:"checkDate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HealthCheckPerson 是 JKTJLIST00002 已检/未检名单里的一行(人员 + 体检状态,非体检明细)。
|
||||||
|
// 字段名以实测样本为准(docx 多处有误,见 docs/04 §11.4)。字段稳定且均为字符串,故全部建模。
|
||||||
|
type HealthCheckPerson struct {
|
||||||
|
CheckType string `json:"checkType"` // 体检状态:0 已检 / 1 未检
|
||||||
|
IDCard string `json:"idCard"`
|
||||||
|
PersonName string `json:"personName"`
|
||||||
|
PhrID string `json:"phrId"` // 注意驼峰(docx 误写 phrid)
|
||||||
|
EMPIID string `json:"empiId"`
|
||||||
|
Age string `json:"age"`
|
||||||
|
Birthday string `json:"birthday"` // docx 误写 birthDay
|
||||||
|
SexCode string `json:"sexCode"`
|
||||||
|
SignFlag string `json:"signFlag"` // 签约:y 已签约 / n 未签约
|
||||||
|
Rqbj string `json:"rqbj"` // 人群标志(同 personSign 码表,多值逗号分隔)
|
||||||
|
RegionCode string `json:"regionCode"`
|
||||||
|
RegionCodeText string `json:"regionCodeText"`
|
||||||
|
ManaUnitID string `json:"manaUnitId"`
|
||||||
|
ManaUnitText string `json:"manaUnitText"`
|
||||||
|
ManaDoctorID string `json:"manaDoctorId"` // docx 误写 manadoctorId
|
||||||
|
ManaDoctorName string `json:"manaDocterName"` // 实测拼写就是 Docter
|
||||||
|
Address string `json:"address"`
|
||||||
|
MobileNumber string `json:"mobileNumber"`
|
||||||
|
Contact string `json:"contact"`
|
||||||
|
ContactPhone string `json:"contactPhone"`
|
||||||
|
}
|
||||||
|
|||||||
+42
@@ -2,6 +2,7 @@ package osi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"chis_osi/contract"
|
"chis_osi/contract"
|
||||||
)
|
)
|
||||||
@@ -32,3 +33,44 @@ func (q FindHealthCheckQuery) baseInfo() (map[string]string, error) {
|
|||||||
}
|
}
|
||||||
return singleBaseInfo("last health check", fields)
|
return singleBaseInfo("last health check", fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ListHealthCheckQuery struct {
|
||||||
|
CheckYear string // 必填:检查年度,如 "2025"
|
||||||
|
IDCard string // 可选:过滤到某人
|
||||||
|
CheckType string // 可选:0 已检 / 1 未检 / 2 全部
|
||||||
|
Page string // 默认 "1"
|
||||||
|
Rows string // 默认 "10"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListHealthCheckPeople 查询某年度已检/未检人员名单(JKTJLIST00002 /auto/jktjlist/query)。
|
||||||
|
// 返回人员名单 + checkType 状态,非体检明细;分页参数在 baseInfo 内,见 docs/04 §11.4。
|
||||||
|
func (c *Client) ListHealthCheckPeople(ctx context.Context, query ListHealthCheckQuery) ([]contract.HealthCheckPerson, Result, error) {
|
||||||
|
baseInfo, err := query.baseInfo()
|
||||||
|
if err != nil {
|
||||||
|
return nil, Result{}, err
|
||||||
|
}
|
||||||
|
var people []contract.HealthCheckPerson
|
||||||
|
result, err := c.Call(ctx, ServiceIDJKTJList, baseInfo, &people)
|
||||||
|
return people, result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q ListHealthCheckQuery) baseInfo() (map[string]string, error) {
|
||||||
|
if q.CheckYear == "" {
|
||||||
|
return nil, fmt.Errorf("list health check requires checkYear")
|
||||||
|
}
|
||||||
|
page, rows := q.Page, q.Rows
|
||||||
|
if page == "" {
|
||||||
|
page = "1"
|
||||||
|
}
|
||||||
|
if rows == "" {
|
||||||
|
rows = "10"
|
||||||
|
}
|
||||||
|
base := map[string]string{"checkYear": q.CheckYear, "page": page, "rows": rows}
|
||||||
|
if q.CheckType != "" {
|
||||||
|
base["checkType"] = q.CheckType
|
||||||
|
}
|
||||||
|
if q.IDCard != "" {
|
||||||
|
base["idCard"] = q.IDCard
|
||||||
|
}
|
||||||
|
return base, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package osi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -43,6 +44,56 @@ func TestLastHealthCheckDecodesSummaryAndHitsPath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListHealthCheckPeopleDecodesRosterAndHitsPath(t *testing.T) {
|
||||||
|
var seenPath string
|
||||||
|
var seenBody map[string]any
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
seenPath = r.URL.Path
|
||||||
|
_ = json.NewDecoder(r.Body).Decode(&seenBody)
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
// data 为人员名单数组;字段名取自实测,值均为脱敏假数据
|
||||||
|
_, _ = w.Write([]byte(`{"code":"01","message":"操作成功","data":[` +
|
||||||
|
`{"idCard":"TEST-1","personName":"甲","phrId":"PHR-1","checkType":"0","rqbj":"PU"},` +
|
||||||
|
`{"idCard":"TEST-2","personName":"乙","phrId":"PHR-2","checkType":"1","rqbj":"LAO"}]}`))
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
transport, err := NewTransport(TransportConfig{Timeout: time.Second})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewTransport: %v", err)
|
||||||
|
}
|
||||||
|
client := NewClient(ClientConfig{BaseURL: server.URL, UserName: "u", Ask: "k", Transport: transport})
|
||||||
|
|
||||||
|
people, result, err := client.ListHealthCheckPeople(context.Background(), ListHealthCheckQuery{CheckYear: "2025", IDCard: "TEST-1", CheckType: "2"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ListHealthCheckPeople: %v", err)
|
||||||
|
}
|
||||||
|
if seenPath != "/osi/api/auto/jktjlist/query" {
|
||||||
|
t.Fatalf("path = %q", seenPath)
|
||||||
|
}
|
||||||
|
if !result.Success || len(people) != 2 {
|
||||||
|
t.Fatalf("people = %d result = %#v", len(people), result)
|
||||||
|
}
|
||||||
|
if people[0].CheckType != "0" || people[0].PhrID != "PHR-1" {
|
||||||
|
t.Fatalf("row0 = %#v", people[0])
|
||||||
|
}
|
||||||
|
// checkYear/page/rows 应落在 uploadinfo.baseInfo
|
||||||
|
base := seenBody["uploadinfo"].(map[string]any)["baseInfo"].(map[string]any)
|
||||||
|
if base["checkYear"] != "2025" || base["page"] != "1" || base["rows"] != "10" {
|
||||||
|
t.Fatalf("baseInfo = %#v", base)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListHealthCheckQueryRequiresCheckYear(t *testing.T) {
|
||||||
|
if _, err := (ListHealthCheckQuery{IDCard: "x"}).baseInfo(); err == nil {
|
||||||
|
t.Fatal("missing checkYear should error")
|
||||||
|
}
|
||||||
|
base, err := (ListHealthCheckQuery{CheckYear: "2025"}).baseInfo()
|
||||||
|
if err != nil || base["page"] != "1" || base["rows"] != "10" {
|
||||||
|
t.Fatalf("default page/rows wrong: %v err=%v", base, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFindHealthCheckQueryRequiresExactlyOneKey(t *testing.T) {
|
func TestFindHealthCheckQueryRequiresExactlyOneKey(t *testing.T) {
|
||||||
if _, err := (FindHealthCheckQuery{}).baseInfo(); err == nil {
|
if _, err := (FindHealthCheckQuery{}).baseInfo(); err == nil {
|
||||||
t.Fatal("empty query should error")
|
t.Fatal("empty query should error")
|
||||||
|
|||||||
Reference in New Issue
Block a user