diff --git a/contract/jktj.go b/contract/jktj.go index 1e7ba10..05a959d 100644 --- a/contract/jktj.go +++ b/contract/jktj.go @@ -17,3 +17,28 @@ type HealthCheckSummary struct { PersonName string `json:"personName"` 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"` +} diff --git a/osi/jktj.go b/osi/jktj.go index 6a94c24..05fe80c 100644 --- a/osi/jktj.go +++ b/osi/jktj.go @@ -2,6 +2,7 @@ package osi import ( "context" + "fmt" "chis_osi/contract" ) @@ -32,3 +33,44 @@ func (q FindHealthCheckQuery) baseInfo() (map[string]string, error) { } 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 +} diff --git a/osi/jktj_test.go b/osi/jktj_test.go index 41f14c5..f0c48e5 100644 --- a/osi/jktj_test.go +++ b/osi/jktj_test.go @@ -2,6 +2,7 @@ package osi import ( "context" + "encoding/json" "net/http" "net/http/httptest" "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) { if _, err := (FindHealthCheckQuery{}).baseInfo(); err == nil { t.Fatal("empty query should error")