# 如何使用 FHIR R4 存储医疗记录

> 教程：创建 Patient、血压 Observation 和 Condition，使用事务，搜索，带历史记录的更新和读取溯源 — 每个请求都使用 curl 和真实响应，在免费沙盒中进行。

Source: https://developers.anpheros.com/zh/guides/store-medical-records-fhir

**本教程将 HL7 FHIR R4 资源存储为一个小型医疗记录：一个 `Patient`，一个血压 `Observation` 和一个诊断作为 `Condition`，然后将患者和测量结果一起放入一个事务中。它会搜索它们，在不丢失早期版本的情况下更新诊断，并读取谁写了什么。** 每个请求都是直接针对免费 Anpheros 沙盒的 `curl`，并且显示的每个响应都是 API 返回的内容。

如果您是 FHIR 新手，请先阅读 [FHIR 平台](https://developers.anpheros.com/zh/guides/fhir) 以了解概念。本页是实践部分。

## 大多数记录的起始三个资源

| 资源 | 包含内容 | 编码方式 |
|---|---|---|
| `Patient` | 记录的主体：姓名、出生日期、性别、其他系统的标识符 | 您的标识符系统 |
| `Observation` | 任何测量或报告的内容：生命体征、实验室结果、体重、症状评分 | LOINC, UCUM 单位 |
| `Condition` | 诊断或健康问题，及其随时间的变化状态 | ICD-10 (SNOMED CT 在许可标志后) |

药物 (`MedicationStatement`)、过敏 (`AllergyIntolerance`)、免疫接种和文档遵循相同的模式；[26 种支持的资源类型](https://developers.anpheros.com/zh/guides/fhir) 列在 `/fhir/R4/metadata` 的能力声明中。

## 开始之前

在 [platform.anpheros.com/dashboard](https://platform.anpheros.com/dashboard/) 使用 **获取沙盒密钥** 获取一个沙盒密钥 (`sk_test_…`)。您在那里创建的任何内容都不是真实的患者数据，并且对其他项目不可见。

```bash
export BASE=https://platform.anpheros.com/fhir/R4
export KEY=sk_test_…
```

## 步骤 1：创建患者

```bash
curl -X POST "$BASE/Patient" -H "Authorization: Bearer $KEY" -H "Content-Type: application/fhir+json" -d '{
  "resourceType": "Patient",
  "identifier": [{"system": "https://clinic.example/mrn", "value": "MRN-10442"}],
  "name": [{"family": "Marin", "given": ["Ioana"]}],
  "gender": "female",
  "birthDate": "1979-04-12"
}'
```

`201 Created`，并附带服务器分配的 id 和版本：

```json
{"resourceType": "Patient",
 "identifier": [{"system": "https://clinic.example/mrn", "value": "MRN-10442"}],
 "name": [{"family": "Marin", "given": ["Ioana"]}], "gender": "female", "birthDate": "1979-04-12",
 "id": "d09e3942-ed86-4458-b099-fa674ab21b84",
 "meta": {"versionId": "1", "lastUpdated": "2026-10-12T20:16:51.043Z"}}
```

在 `identifier` 中保留您自己的 id，并使用您控制的 `system`（此处为诊所的记录编号），以便您始终可以使用 `GET $BASE/Patient?identifier=https://clinic.example/mrn|MRN-10442` 再次找到该患者。FHIR `id` 是平台的，并且特定于您的项目：另一个项目会看到同一个人，但使用不同的 id。

```bash
export PID=d09e3942-ed86-4458-b099-fa674ab21b84
```

## 步骤 2：将测量值存储为 Observation

血压是一个具有两个组成部分（收缩压和舒张压）的 Observation，每个组成部分都有自己的 LOINC 代码。说明谁进行了测量：此处为家用设备。

```bash
curl -X POST "$BASE/Observation" -H "Authorization: Bearer $KEY" -H "Content-Type: application/fhir+json" \
     -H "X-Anpheros-Author-Type: device" -H "Idempotency-Key: bp-2026-10-10-0830" -d '{
  "resourceType": "Observation",
  "status": "final",
  "category": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "vital-signs"}]}],
  "code": {"coding": [{"system": "http://loinc.org", "code": "85354-9", "display": "Blood pressure panel"}]},
  "subject": {"reference": "Patient/'$PID'"},
  "effectiveDateTime": "2026-10-10T08:30:00Z",
  "component": [
    {"code": {"coding": [{"system": "http://loinc.org", "code": "8480-6"}]},
     "valueQuantity": {"value": 138, "unit": "mmHg", "system": "http://unitsofmeasure.org", "code": "mm[Hg]"}},
    {"code": {"coding": [{"system": "http://loinc.org", "code": "8462-4"}]},
     "valueQuantity": {"value": 88, "unit": "mmHg", "system": "http://unitsofmeasure.org", "code": "mm[Hg]"}}
  ]
}'
```

响应是已存储的资源，包含 `id` 和 `meta.versionId: "1"`。三个细节对于可用的记录很重要：

- **代码，而非标签。** `85354-9` 在所有 FHIR 系统中都表示“血压面板”；而自由文本“BP”则不表示。使用 `GET /v1/terminology/loinc?q=blood pressure` ([FHIR 代码系统](https://developers.anpheros.com/zh/guides/fhir-code-systems)) 查找代码。
- **UCUM 单位**（`mm[Hg]`、`kg`、`mg/dL`）在 `valueQuantity.code` 中，以便可以比较和转换值。
- **`Idempotency-Key`。** 超时后的重试会返回第一个响应，而不是重复存储读数。

实验室结果是相同的资源，包含 `category`、`laboratory`，通常还有一个 `referenceRange`。要将完整的实验室报告导入，请参阅 [如何将实验室结果导入 FHIR 记录](https://developers.anpheros.com/zh/guides/import-lab-results-fhir)。

## 步骤 3：将诊断记录为 Condition

```bash
curl -X POST "$BASE/Condition" -H "Authorization: Bearer $KEY" -H "Content-Type: application/fhir+json" \
     -H "X-Anpheros-Author-Type: practitioner" -d '{
  "resourceType": "Condition",
  "subject": {"reference": "Patient/'$PID'"},
  "clinicalStatus": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/condition-clinical", "code": "active"}]},
  "verificationStatus": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/condition-ver-status", "code": "confirmed"}]},
  "code": {"coding": [{"system": "http://hl7.org/fhir/sid/icd-10", "code": "I10", "display": "Essential (primary) hypertension"}]},
  "onsetDateTime": "2026-03-02"
}'
```

`clinicalStatus`（active, resolved, in remission）和 `verificationStatus`（confirmed, provisional）是特意分开的：疑似诊断与已确认诊断不同，已解决的问题仍然是病史的一部分。

## 步骤 4：在一个事务中创建相关资源

当患者及其首次测量数据同时到达时（例如，来自诊所系统），请将它们作为 `transaction` Bundle 发送。要么全部存储，要么全部不存储。新资源之间的引用使用临时的 `urn:uuid:` ID，服务器会替换它们：

```bash
curl -X POST "$BASE" -H "Authorization: Bearer $KEY" -H "Content-Type: application/fhir+json" -d '{
  "resourceType": "Bundle", "type": "transaction",
  "entry": [
    {"fullUrl": "urn:uuid:9f1c0d1e-0000-4000-8000-000000000001",
     "resource": {"resourceType": "Patient", "name": [{"family": "Stan", "given": ["Mihai"]}], "gender": "male", "birthDate": "1990-02-01"},
     "request": {"method": "POST", "url": "Patient"}},
    {"resource": {"resourceType": "Observation", "status": "final",
       "category": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "vital-signs"}]}],
       "code": {"coding": [{"system": "http://loinc.org", "code": "29463-7", "display": "Body weight"}]},
       "subject": {"reference": "urn:uuid:9f1c0d1e-0000-4000-8000-000000000001"},
       "effectiveDateTime": "2026-10-10",
       "valueQuantity": {"value": 82.4, "unit": "kg", "system": "http://unitsofmeasure.org", "code": "kg"}},
     "request": {"method": "POST", "url": "Observation"}}
  ]
}'
```

`transaction-response` 每个资源有一个条目，包含 `"status": "201 Created"`、其 `location` 和已存储的资源。Observation 的 `subject` 现在指向真实的 `Patient/fad3665a-…`。

## 第 5 步：搜索

```bash
curl "$BASE/Observation?patient=$PID&code=http://loinc.org|85354-9&date=ge2026-10-01&_sort=-date" \
     -H "Authorization: Bearer $KEY"
```

您将获得一个 `searchset` Bundle，其中包含 `total` 和匹配的资源，按最新排序。您经常会使用的其他搜索方式包括：`Condition?patient=$PID&clinical-status=active`、`Observation?patient=$PID&category=laboratory` 以及用于获取完整记录的 `Patient/$PID/$everything`。

## 步骤 6：在不丢失历史记录的情况下更新

高血压已解决。更改状态并添加结束日期，并使用 `If-Match` 和您读取的版本，这样您就不会覆盖其他人的更改：

```bash
curl -X PUT "$BASE/Condition/$CID" -H "Authorization: Bearer $KEY" -H "Content-Type: application/fhir+json" \
     -H 'If-Match: W/"1"' -d '{ …the same Condition…, "clinicalStatus": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/condition-clinical", "code": "resolved"}]}, "abatementDateTime": "2026-10-11" }'
```

使用 `200 OK` 和 `ETag: W/"2"`。如果其他写入先于您到达，您将收到 `412` 并重新读取。早期版本仍然存在：

```bash
curl "$BASE/Condition/$CID/_history" -H "Authorization: Bearer $KEY"
```

返回两个版本：`versionId` 2 (`resolved`) 和 1 (`active`)。`GET $BASE/Condition/$CID/_history/1` 读取旧版本。记录中的任何内容都不会被静默覆盖。

## 步骤 7：查看谁编写了什么

每一次写入都会创建一个 `Provenance` 资源。对于血压读数：

```bash
curl "$BASE/Provenance?target=Observation/$OBS" -H "Authorization: Bearer $KEY"
```

```json
{"resourceType": "Provenance",
 "target": [{"reference": "Observation/d83d9075-…/_history/1"}],
 "recorded": "2026-10-12T20:16:51.056000Z",
 "activity": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/v3-DataOperation", "code": "CREATE"}]},
 "agent": [{"type": {"coding": [{"system": "http://terminology.hl7.org/CodeSystem/provenance-participant-type", "code": "author"}]},
            "who": {"identifier": {"system": "https://anpheros.com/fhir/CodeSystem/author-type", "value": "device"}, "display": "proj_…"},
            "onBehalfOf": {"identifier": {"system": "https://anpheros.com/fhir/sid/organization", "value": "org_…"}, "display": "…"}}]}
```

您发送的作者类型 (`device`) 会与项目和组织一起记录。发送 `X-Anpheros-Author-Ref: Practitioner/<id>` 来命名写入背后的临床医生。

## 第 8 步：记录作为摘要

```bash
curl "$BASE/Patient/$PID/\$summary" -H "Authorization: Bearer $KEY"
```

返回一个国际患者摘要：一个 `document` Bundle，以一个 `Composition` 开头，并包含诸如“问题”、“药物”、“过敏症”和“生命体征”等部分，这些部分由上述资源构建而成。这就是要交给另一个系统或打印给医生的格式（[FHIR 平台](https://developers.anpheros.com/zh/guides/fhir)）。

## 偏好非 FHIR 的 JSON？

通过更简单的 REST 视图 `/v1` 也可以获得相同的数据，使用相同的 ID：`POST /v1/patients/{id}/observations` 获取 `{"code": "85354-9", "category": "vital-signs", "effective_at": "…", "components": […]}` 并存储相同的 FHIR Observation。根据您的代码选择使用哪种方式。请参阅 [Medical data API](https://developers.anpheros.com/zh/guides/medical-data-api) 和 [SDKs](https://developers.anpheros.com/zh/guides/sdks)。

## 常见问题解答

### 存储病历的最佳方式是什么？
以编码、版本化的资源形式存储，并记录每个资源的作者。HL7 FHIR R4 提供了结构（Patient、Observation、Condition 等）、标准代码系统（如 LOINC 和 ICD-10）以及历史记录；FHIR 后端则在此基础上增加了搜索、同意和来源追溯功能。

### 使用 FHIR 是否需要 FHIR 服务器？
您需要一个能够存储和搜索 FHIR 资源并强制执行访问权限的地方。您可以自行运行开源 FHIR 服务器，或使用托管服务，例如 Anpheros；[Anpheros 与其他 FHIR 服务器的比较](https://developers.anpheros.com/zh/guides/fhir-server-comparison) 对各种选项进行了权衡，而 [FHIR 与自定义医疗数据库](https://developers.anpheros.com/zh/guides/fhir-vs-custom-database) 则讨论了构建自己的模式。

### 如何在 FHIR 中存储血压？
作为一条 `Observation`，使用 LOINC 代码 `85354-9` 和两个 `component` 条目：收缩压 `8480-6` 和舒张压 `8462-4`，每个条目都有一个 `valueQuantity` 单位 `mm[Hg]`。

### 我可以修改已存储的资源吗？
可以，通过 `PUT` 和 `If-Match`。每次更改都会创建一个新版本；早期版本仍可通过 `_history` 读取，并且 Provenance 记录会保存每次更改的作者。删除是软删除，会保留历史记录。

## 相关

- [FHIR 平台](https://developers.anpheros.com/zh/guides/fhir)：概念、资源类型和操作
- [FHIR 代码系统](https://developers.anpheros.com/zh/guides/fhir-code-systems)：LOINC、ICD-10、ATC、UCUM
- [如何将实验室结果导入 FHIR 记录](https://developers.anpheros.com/zh/guides/import-lab-results-fhir)
- [医疗数据 API](https://developers.anpheros.com/zh/guides/medical-data-api)：相同数据的简化 REST 视图
- [免费 FHIR 数据库和沙盒](https://developers.anpheros.com/zh/guides/free-fhir-database)
