Commit 6e2b549e by luoqi

feat(sync/friday): 病历摄入 Phase 1 — EMR/诊断/治疗/影像/治疗计划 五资源接入

FRIDAY 病历链落地(直连勘查 2026-07-18 定案,零新算子,纯配置+导出脚本):
- export.sh:host 等价单表 dump(MySQL 7 表 CSV + Mongo med_emr_info status∈{3,4}
  平铺 JSON;id 字段字符串化对齐 CSV 契约;数组字段双形态:原生数组给 split,
  JSON 字符串给 emr 自由文本位)。凭据走 env 不入 git。
- manifest:EMR 链 transforms —— diag[] 拆行→std_diag lookup(linkCode→std_code,
  K 开头截 K 码,非 K/未命中自然落 code=null 自由文本)→normalize/coalesce;
  treat[] 拆行(=本次治疗 actual,病历无计划字段已用全字段枚举证实);
  med_check lookup 类型字典;customer_treat_plan 行 join 头表(无诊所行显式 filter 丢弃)。
- assemblers ×5:emr/diagnosis/treatment_actual/treatment_planned/image,
  全部 dict_includes 共享字典(diagnosis-kcode / treatment-category-core+
  actual/planned-rules / image-modality)—— 分层重构的首个第二宿主消费者。
- 锚点:临床事实 sourceEncounterExternalId=emr_sub_id(同诊聚合);
  emr 挂 appointment_id(56.5%);影像挂 emr_id 病历号。

全量实跑验证(本地):107,227 患者 / 288,383 txns / 285,986 facts,failed=0;
旧 450 样本幂等去重 ✓。诊断 83.5% 拿到 K 码(共享名称字典生效),治疗 11 类闭集
分布合理。周元策(987d743a)persona v1 + 召回计划与其 K04 诊断临床吻合,闭环通。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
parent c9c1e778
...@@ -3,5 +3,6 @@ ...@@ -3,5 +3,6 @@
* *
!.gitignore !.gitignore
!manifest.yaml !manifest.yaml
!export.sh
!assemblers !assemblers
!assemblers/*.yaml !assemblers/*.yaml
# diagnosis — FRIDAY 诊断 fact(med_emr_info.diag[] 拆行)
# 消费 transforms 输出表 diagnosis_rows(split + std_diag lookup + normalize/substring/coalesce)
#
# code 解析规则(用户定,2026-07-18):
# linkCode 非空 → std_diag.std_code K 开头 → 截 K 大类(std_code_k 直通下方共享字典 passthrough);
# 非 K(DA0E.50 等 ICD-11)→ substring 产物("DA0")不在字典 → _default → code=null(自由文本);
# linkCode 空(99.7%)→ 归一中文名 → 共享 diagnosis-kcode 字典救码(与 jvs-dw 完全同一套)。
# 任何情况下 name=原文保留(展示 + LLM 输入),不丢 fact。
canonical: diagnosis
emits:
action: diagnosis_recorded
subjectType: diagnosis
occurredAtField: occurredAt
primary:
table: diagnosis_rows
key: diag_external_id
dedup_by: diag_external_id
field_mapping:
externalId: diag_external_id
updatedAt: updated_gmt_at
createdAt: created_gmt_at
patientExternalId: patient_id
clinicId: organization_id
occurredAt: clinic_time # 就诊时刻(100% 填充)
sourceEncounterExternalId: emr_sub_id # 同诊聚合锚(病历不普遍挂预约,用小病历号)
code: diag_code_src # K 码 或 归一中文名 → 共享字典翻译
stdCodeRaw: std_code # 溯源:字典 join 到的原始 std_code(可 null)
name: value # 原始中文名(展示 + LLM 输入)
toothPosition: tooth_position # "41;42" / "42 L;43 D"(FDI+牙面,分号分隔)
doctorId: user_id
doctorName: user_name
# ── 字典分层:临床通用层(K 直通 + 中文术语→K 码 + keyword 兜底)全在共享文件 ──
dict_includes:
- ../../_shared/dict/diagnosis-kcode.yaml
enum_mapping:
code:
# 兜底:共享 enum/keyword 都翻不出 → 空 → code=null(不丢 fact,name 保留)
_default: ""
# emr — FRIDAY 病历自由文本(诊断/治疗已拆独立 fact,本资源只装自由文本)
# 直接消费 med_emr_info(数组列不映射即不入 canonical;dispose_text/examine_text 是导出侧
# 序列化的 JSON 字符串形态,与 jvs-dw examine/dispose "JSON 原文" 同语义)
canonical: emr
emits:
action: emr_submitted
subjectType: emr
# occurred = clinic_time(就诊时刻,100% 填充);created_gmt_at 是录入时点,留幂等键用
occurredAtField: submittedAt
primary:
table: med_emr_info
key: emr_sub_id # 小病历号 uuid(两侧连接键 + 临床事实锚点)
dedup_by: emr_sub_id
field_mapping:
externalId: emr_sub_id
# updatedAt 进 source_event_id 幂等键,host UPDATE → 新 transaction(同 jvs-dw 纪律)
updatedAt: updated_gmt_at
createdAt: created_gmt_at
patientExternalId: patient_id
clinicId: organization_id
submittedAt: clinic_time # 就诊时刻(100%)
encounterExternalId: appointment_id # 56.5% 有值 → 挂预约/接诊链;临床事实锚用 emr_sub_id
doctorId: user_id
doctorName: user_name
# SOAP 自由文本段落
illnessDesc: illness_desc # 主诉
preIllness: pre_illness # 现病史
pastHistory: past_hist # 既往史
generalCondition: gen_cond # 全身情况
examFindings: examine_text # 检查所见(JSON 原文,带牙位)
auxExamFindings: auxi_exam # 辅助检查(自由文本)
disposal: dispose_text # 处置叙述(98% 填充,JSON 原文带牙位;actual 治疗主源是 treat[])
doctorAdvice: doc_order # 医嘱
# image — FRIDAY 影像 metadata(MySQL emr.med_check;PAC 不持文件本体)
# 影像不在 Mongo 病历文档内(全字段枚举证实),挂 emr_id(10 位病历号)回病历。
# 消费 transforms 输出表 image_rows(med_check lookup std_check_class 附 class_name)
canonical: image
emits:
action: image_uploaded
subjectType: image
occurredAtField: uploadedAt
primary:
table: image_rows
key: id
dedup_by: id
field_mapping:
externalId: id
updatedAt: updated_gmt_at
createdAt: created_gmt_at
patientExternalId: patient_id
clinicId: organization_id
uploadedAt: shooting_time # 拍摄时间
encounterExternalId: emr_id # 病历号级挂载(= med_emr_info.emr_id,非 emr_sub_id)
modality: class_name # lookup 自 std_check_class 字典
fileUrl: file_url # OSS 相对路径(passthrough)
fileName: file_name
# ── 字典分层:真影像类型名共享(与 jvs-dw 实测同名);FRIDAY 特有名目留本地 ──
dict_includes:
- ../../_shared/dict/image-modality.yaml
enum_mapping:
modality:
# FRIDAY 特有:胸片(987d743a 字典)→ 非口腔影像归 other;
# 3a9d9c68 字典乱录("测试"/"1"/"11")与 lookup 未命中(class_name=null)→ _default
胸片: other
_default: other
# treatment_actual — FRIDAY 本次治疗(med_emr_info.treat[] 拆行)
# 语义(用户确认,2026-07-18):treat[] = 本次治疗(actual);病历无计划字段(全字段枚举证实),
# 治疗计划走独立表 customer_treat_plan(见 treatment_planned.yaml)。
# 覆盖率注:treat 填充 25%(dispose 98% 是处置叙述 → emr_record.disposal 全文保留不丢);
# 若实践发现漏召,Phase 2 评估 dispose keyword 路由补 actual。
canonical: treatment
emits:
action: treatment_completed
subjectType: treatment
occurredAtField: occurredAt
kind: actual
primary:
table: treatment_actual_rows
key: treat_external_id
dedup_by: treat_external_id
field_mapping:
externalId: treat_external_id
updatedAt: updated_gmt_at
createdAt: created_gmt_at
patientExternalId: patient_id
clinicId: organization_id
occurredAt: clinic_time # 就诊时刻(100% 填充)
sourceEncounterExternalId: emr_sub_id # 同诊聚合锚
category: category_raw # 归一治疗名 → 共享字典翻 11 类闭集
subtype: value # 原始 treat 文本留作 subtype(chain milestone fallback)
toothPosition: tooth_position
doctorId: user_id
doctorName: user_name
# ── 字典分层:临床核心词 + keyword/strip(actual 语义变体)全在共享文件;FRIDAY 尚无宿主特有词 ──
# (测试库 treat 一半键盘乱敲 → 高频宿主词等生产数据回来后按 mapping-miss 巡检补这里)
dict_includes:
- ../../_shared/dict/treatment-category-core.yaml
- ../../_shared/dict/treatment-category-actual-rules.yaml
enum_mapping:
category:
# 长尾兜底:未命中 → category='',parser 跳过该 fact(数据损失换质量,jvs-dw 同款纪律)
_default: ""
# treatment_planned — FRIDAY 治疗计划(customer_treat_plan + _item 独立表;用户确认此表为治疗计划)
# 消费 transforms 输出表 treatment_planned_rows(行表 lookup 头表拿 organization_id/plan_name)
# 行粒度 = 计划行项(牙位 + 术式 mode_name + 价格区间);externalId = 行表主键(host 稳定)
canonical: treatment
emits:
action: treatment_planned
subjectType: treatment
occurredAtField: occurredAt
kind: planned
primary:
table: treatment_planned_rows
key: id
dedup_by: id
field_mapping:
externalId: id
updatedAt: updated_gmt_at
createdAt: created_gmt_at
patientExternalId: customer_id
clinicId: organization_id # lookup 自头表(行表无诊所)
occurredAt: created_gmt_at # 计划制定时点
category: mode_norm # 归一术式名 → 共享字典翻 11 类闭集
subtype: mode_name # 原始术式名
toothPosition: tooth_position
planName: plan_name # 方案名(passthrough,展示用)
# ── 字典分层:planned 语义变体(不剥"建议/拟"措辞,只剥条件词)──
dict_includes:
- ../../_shared/dict/treatment-category-core.yaml
- ../../_shared/dict/treatment-category-planned-rules.yaml
enum_mapping:
category:
_default: ""
#!/usr/bin/env bash
# FRIDAY SaaS 测试环境 → PAC cold-import 导出(等价"host 侧单表 dump")
#
# 纪律(同 jvs-dw SQL 朴素化):每条导出 = 列选 + WHERE,零 join/零变换;
# 唯一例外是 tenant_id AS brand_id 别名(避免与 PAC tenant 概念撞名,与既有 CSV 一致)。
# 形态改造(拆 JSON 数组/字典 join/K 码截取)全部在 PAC transforms 层做。
#
# 凭据走 env(不入 git):
# export FRIDAY_MYSQL_HOST=… FRIDAY_MYSQL_PORT=3309 FRIDAY_MYSQL_USER=… FRIDAY_MYSQL_PASSWORD=…
# export FRIDAY_MONGO_URI='mongodb://user:pass@host:27017/emr_market' # 密码含 & 等须 URL 编码
#
# 依赖:docker(mysql:8 / mongo:7 客户端镜像),产物落本目录(.gitignore 已挡,不入 git)。
set -euo pipefail
cd "$(dirname "$0")"
: "${FRIDAY_MYSQL_HOST:?need FRIDAY_MYSQL_HOST}"
: "${FRIDAY_MYSQL_PORT:=3309}"
: "${FRIDAY_MYSQL_USER:?need FRIDAY_MYSQL_USER}"
: "${FRIDAY_MYSQL_PASSWORD:?need FRIDAY_MYSQL_PASSWORD}"
: "${FRIDAY_MONGO_URI:?need FRIDAY_MONGO_URI}"
# ── MySQL → CSV(TSV 中转,node 处理 mysql --batch 的 \t \n \\ 转义再按 RFC4180 引号)──
mysql_csv() {
local sql="$1" out="$2"
docker run --rm mysql:8 mysql \
-h"$FRIDAY_MYSQL_HOST" -P"$FRIDAY_MYSQL_PORT" -u"$FRIDAY_MYSQL_USER" -p"$FRIDAY_MYSQL_PASSWORD" \
--default-character-set=utf8mb4 --batch --raw=FALSE --connect-timeout=20 -e "$sql" \
| node -e '
const lines = require("fs").readFileSync(0, "utf-8").split("\n");
const unesc = (s) => { let r = ""; for (let i = 0; i < s.length; i++) { const c = s[i];
if (c === "\\" && i + 1 < s.length) { const n = s[++i];
r += n === "n" ? "\n" : n === "t" ? "\t" : n === "0" ? "\0" : n === "N" ? "" : n; }
else r += c; } return r; };
const q = (s) => /[",\n\r]/.test(s) ? `"${s.replace(/"/g, `""`)}"` : s;
const out = [];
for (const line of lines) { if (line === "") continue;
out.push(line.split("\t").map((f) => q(f === "NULL" ? "" : unesc(f))).join(",")); }
process.stdout.write(out.join("\n") + "\n");
' > "$out"
echo " $out: $(($(wc -l < "$out") - 1)) rows"
}
echo "── MySQL 导出 ──"
# 患者主档(全量;既有 450 行样本 → 扩全量,EMR 覆盖 ~1.65 万患者的前置)
mysql_csv "SELECT id,name,sex,birthday,file_number,tenant_id AS brand_id,organization_id,created_gmt_at,updated_gmt_at FROM customer.customer_basic_info" customer_basic_info.csv
# 联系方式 1:N(lookup 挑默认号 → patient.phone)
mysql_csv "SELECT id,customer_id,contacts_tel,is_default,contacts_type,tel_type,relationship FROM customer.customer_contacts" customer_contacts.csv
# 预约(全状态;transforms 丢草稿 10)
mysql_csv "SELECT id,patient_appointment_id,organization_id,tenant_id AS brand_id,appointment_date,appointment_start,appointment_status,doctor_user_id,appointment_time_length,in_time,created_gmt_at,updated_gmt_at FROM \`arrail-appointment-server\`.appointment_base" appointment_base.csv
# 影像档案(挂 emr_id 病历号;modality 经 std_check_class 字典翻)
mysql_csv "SELECT id,tenant_id AS brand_id,organization_id,patient_id,emr_id,class_code,file_name,file_type,file_url,files_size,shooting_time,created_gmt_at,updated_gmt_at FROM emr.med_check" med_check.csv
# 影像类型字典(class_code UUID 全局唯一,lookup 不需 tenant 限定)
mysql_csv "SELECT class_code,class_name,tenant_id AS brand_id FROM emr.std_check_class" std_check_class.csv
# 诊断字典(linkCode → std_code;K 码用,非 K 落自由文本)
mysql_csv "SELECT diag_code,diag_name,std_code FROM emr.std_diag" std_diag.csv
# 治疗计划(头:方案名/期望;行:牙位/术式/价格区间)→ treatment_planned
mysql_csv "SELECT id,tenant_id AS brand_id,organization_id,customer_id,plan_group_id,plan_name,desired_effect,emergency_urgency,expect_cost,created_gmt_at,updated_gmt_at FROM customer.customer_treat_plan" customer_treat_plan.csv
mysql_csv "SELECT id,tenant_id AS brand_id,customer_id,treat_plan_id,tooth_position,mode_name,charge_min,charge_max,created_gmt_at,updated_gmt_at FROM customer.customer_treat_plan_item" customer_treat_plan_item.csv
echo "── Mongo 导出(med_emr_info,status∈{3,4} 正式病历)──"
# 不用 mongoexport:Extended JSON 会把 Date/Long 包成 {$date}/{$numberLong} 对象,破坏平铺契约。
# mongosh 手动平铺:Date→ISO 字符串,Long→字符串,数组(diag/treat/dispose/examine)原样保留
# (PAC split_json_array 原生支持已 parse 数组)。产出 JSON 数组文件(cold-import json 格式)。
docker run --rm mongo:7 mongosh "$FRIDAY_MONGO_URI" --quiet --eval '
const flat = (v) => v instanceof Date ? v.toISOString()
: (v && v.constructor && v.constructor.name === "Long") ? String(v)
: v === undefined ? null : v;
// id 类字段字符串化:Mongo 存的是 number/Long 混型,canonical 契约要 string
// (CSV 源天然全字符串;JSON 导出须显式对齐,否则 patientExternalId 等校验失败)
const sid = (v) => (v === undefined || v === null || v === "") ? null : String(flat(v));
let first = true;
print("[");
db.med_emr_info.find({ status: { $in: [3, 4] } }).forEach((d) => {
const o = {
emr_sub_id: sid(d.emrSubId), emr_id: sid(d.emrId),
appointment_id: sid(d.appointmentId),
brand_id: sid(d.tenantId), organization_id: sid(d.organizationId),
patient_id: sid(d.patientId), user_id: sid(d.userId), user_name: flat(d.userName),
clinic_time: flat(d.clinicTime), visit_indicator: flat(d.visitIndicator), status: flat(d.status),
diag: d.diag ?? [], treat: d.treat ?? [], dispose: d.dispose ?? [], examine: d.examine ?? [],
// emr_record 自由文本位要字符串(fact 层 zod nullableString);数组原样给 split_json_array 拆行
dispose_text: (d.dispose ?? []).length ? JSON.stringify(d.dispose) : null,
examine_text: (d.examine ?? []).length ? JSON.stringify(d.examine) : null,
illness_desc: flat(d.illnessDesc), pre_illness: flat(d.preIllness), past_hist: flat(d.pastHist),
gen_cond: flat(d.genCond), auxi_exam: flat(d.auxiExam), doc_order: flat(d.docOrder),
created_gmt_at: flat(d.createdGmtAt), updated_gmt_at: flat(d.updatedGmtAt),
};
print((first ? "" : ",") + JSON.stringify(o)); first = false;
});
print("]");
' > med_emr_info.json
node -e "const a=JSON.parse(require('fs').readFileSync('med_emr_info.json','utf-8')); console.log(' med_emr_info.json:', a.length, 'docs')"
echo "── 导出完成 ──"
ls -la *.csv *.json | awk '{print " " $NF, $5}'
...@@ -31,6 +31,15 @@ tables: ...@@ -31,6 +31,15 @@ tables:
- { table: customer_basic_info, file: customer_basic_info.csv } # 患者主档(原始) - { table: customer_basic_info, file: customer_basic_info.csv } # 患者主档(原始)
- { table: customer_contacts, file: customer_contacts.csv } # 联系方式 1:N(原始) - { table: customer_contacts, file: customer_contacts.csv } # 联系方式 1:N(原始)
- { table: appointment_base, file: appointment_base.csv } # 预约(原始,全状态) - { table: appointment_base, file: appointment_base.csv } # 预约(原始,全状态)
# ── EMR 病历链(W FRIDAY-EMR:Mongo med_emr_info status∈{3,4} 正式病历;export.sh 平铺导出)──
# 数组字段(diag/treat/dispose/examine)导出保留原生数组(split_json_array 原生支持);
# dispose_text/examine_text 是同数据的 JSON 字符串形态(emr_record 自由文本位要 string)。
- { table: med_emr_info, file: med_emr_info.json } # 病历正文(Mongo,含 diag/treat 数组)
- { table: med_check, file: med_check.csv } # 影像档案(挂 emr_id 病历号)
- { table: std_check_class, file: std_check_class.csv } # 影像类型字典(class_code→class_name)
- { table: std_diag, file: std_diag.csv } # 诊断字典(linkCode→std_code;K 码用)
- { table: customer_treat_plan, file: customer_treat_plan.csv } # 治疗计划头(方案名/期望)
- { table: customer_treat_plan_item, file: customer_treat_plan_item.csv } # 治疗计划行(牙位/术式/价格)
transforms: transforms:
# ── 患者:把 1:N 联系方式归约成 patient.phone 标量(无需源侧 join)── # ── 患者:把 1:N 联系方式归约成 patient.phone 标量(无需源侧 join)──
...@@ -73,7 +82,148 @@ transforms: ...@@ -73,7 +82,148 @@ transforms:
appointment_status: { in: ['4', '5', '6'] } appointment_status: { in: ['4', '5', '6'] }
in_time: { not_empty: true } in_time: { not_empty: true }
# ═══════════ EMR 病历链(同 jvs-dw 分化模式:一张病历源喂多 canonical)═══════════
# med_emr_info → emr_record(自由文本) + diagnosis(diag[] 拆行) + treatment_actual(treat[] 拆行)
# 锚点:临床事实 sourceEncounterExternalId=emr_sub_id(同诊聚合);emr 自身挂 appointment_id(56.5%)。
# ── E.1 病历自由文本行(emr.yaml 直接消费 med_emr_info,无需 project:
# assembler field_mapping 天然只取所需列,数组列不映射即不入 canonical)──
# ── E.2 diag[] 拆行 → 诊断候选 ──
- kind: split_json_array
input: med_emr_info
output: _diag_raw
array_field: diag
parent_keys:
emr_sub_id: emr_sub_id
emr_id: emr_id
brand_id: brand_id
organization_id: organization_id
patient_id: patient_id
user_id: user_id
user_name: user_name
clinic_time: clinic_time
created_gmt_at: created_gmt_at
updated_gmt_at: updated_gmt_at
element_fields:
value: value
tooth_position: toothPosition
link_code: linkCode
where:
value: { not_empty: true } # 只要求有诊断名;linkCode 可空(仅 0.3% 有)
# E.2.1 linkCode → std_diag 字典(diag_code UUID 全局唯一,LEFT JOIN 未命中 → std_code=null)
- kind: lookup
input: _diag_raw
output: _diag_raw # in-place 附加 std_code
from: std_diag
left_key: link_code
right_key: diag_code
select:
std_code: std_code
# E.2.2 归一 + K 码截取 + coalesce
# 规则(用户定):std_code K 开头 → 截 K 大类;非 K(DA0E.50 等 ICD-11)/join 不上/linkCode 空
# → 自由文本处理:substring 产物("DA0"等)不在共享 K 码字典 → 落 _default → code=null,name 保留。
# linkCode 空(99.7%)→ coalesce 落到归一中文名 → 共享 diagnosis-kcode 字典救码。
- kind: derive
input: _diag_raw
output: _diag_norm
fields:
value_norm:
op: normalize
from: value
std_code_k:
op: substring
from: std_code
start: 0
end: 3
- kind: derive
input: _diag_norm
output: diagnosis_rows
fields:
diag_code_src:
op: coalesce
from: ['std_code_k', 'value_norm']
diag_external_id:
op: concat
parts: ['${emr_sub_id}', '|', '${std_code_k}', '|', '${value_norm}', '|', '${tooth_position}']
# ── E.3 treat[] 拆行 → 本次治疗(actual;用户确认 treat=本次治疗,病历无计划字段)──
# 注:treat 填充仅 25%(dispose 98% 是处置叙述,整段进 emr_record.disposal 不丢);
# 若后续漏召,可加 dispose keyword 路由补 actual(Phase 2 评估)。
- kind: split_json_array
input: med_emr_info
output: _treat_raw
array_field: treat
parent_keys:
emr_sub_id: emr_sub_id
emr_id: emr_id
brand_id: brand_id
organization_id: organization_id
patient_id: patient_id
user_id: user_id
user_name: user_name
clinic_time: clinic_time
created_gmt_at: created_gmt_at
updated_gmt_at: updated_gmt_at
element_fields:
value: value
tooth_position: toothPosition
where:
value: { not_empty: true }
- kind: derive
input: _treat_raw
output: treatment_actual_rows
fields:
category_raw:
op: normalize
from: value
treat_external_id:
op: concat
parts: ['${emr_sub_id}', '|treat|', '${value}', '|', '${tooth_position}']
# ── E.4 影像:med_check + 类型字典 → class_name(modality 经共享字典翻)──
- kind: lookup
input: med_check
output: image_rows
from: std_check_class
left_key: class_code
right_key: class_code
select:
class_name: class_name
# ── E.5 治疗计划:行表 join 头表拿 诊所/方案名 → planned 候选 ──
- kind: lookup
input: customer_treat_plan_item
output: _plan_item_joined
from: customer_treat_plan
left_key: treat_plan_id
right_key: id
select:
organization_id: organization_id
plan_name: plan_name
# 头表 lookup 未命中 / 头表无诊所 → 计划行无法归属诊所,显式丢弃(canonical clinicId 必填;
# 留着只会变 failed 噪音。测试库实测 75/187 行如此)
- kind: filter
input: _plan_item_joined
output: _plan_item_with_org
where:
organization_id: { not_empty: true }
- kind: derive
input: _plan_item_with_org
output: treatment_planned_rows
fields:
mode_norm:
op: normalize
from: mode_name
assemblers: assemblers:
- { file: assemblers/patient.yaml } - { file: assemblers/patient.yaml }
- { file: assemblers/appointment.yaml } - { file: assemblers/appointment.yaml }
- { file: assemblers/encounter.yaml } - { file: assemblers/encounter.yaml }
- { file: assemblers/emr.yaml }
- { file: assemblers/diagnosis.yaml }
- { file: assemblers/treatment_actual.yaml }
- { file: assemblers/treatment_planned.yaml }
- { file: assemblers/image.yaml }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment