简介:一套基于JavaScript与微信小程序技术开发的稳态血药浓度计算器项目源码,面向医疗信息化系统开发者、小程序学习爱好者与药学相关从业者,旨在解决临床长期用药过程中,血药浓度需反复计算且人工估算易出错的实际问题。资源包共包含22个文件,主要涉及JSON配置文件、JavaScript逻辑脚本、WXSS样式表、WXML页面模板、Markdown说明文档及文本说明,其中JS脚本用于处理用药剂量、给药间隔、清除速率等关键参数并执行稳态浓度公式运算,WXML与WXSS则搭建了药物描述、计算器、原理介绍等多个功能页面,整体目录清晰、模块边界明确,便于直接导入微信开发者工具运行,也方便按需修改和扩展。压缩包大小约1.02MB,已有346人学习浏览。通过这份源码,读者既能完整梳理微信小程序的全局配置、页面生命周期和组件通信方式,也能深入理解稳态血药浓度的医学计算原理,可用于医疗类课程设计、工具开发或临床辅助参考。
1. 稳态血药浓度计算器:用 JavaScript 在微信里解决药动学手算问题
治疗药物监测(TDM)查房时最常遇到的不是「浓度是多少」,而是「这个浓度对应的给药方案合不合理」。稳态血药浓度(Css)依赖清除率、生物利用度、给药间隔和分布容积四个参数,公式不难,但单位换算一多,手算就容易把 mg 当 μg、把 L/h 当 mL/min。把这一套计算逻辑用 JavaScript 写成微信小程序,是这类工具开发最省事的路径:纯前端计算、无后端依赖、扫码即用。对工程师来说,核心工作有两块:一是把药动学公式封装成可测试的 JS 函数,二是用小程序表单做好参数输入与结果绑定。下文按公式选型、计算核心、页面实现、验算排错的顺序完整走一遍,新入行的能看到每一步怎么落地,有经验的能直接在参数边界和公式选型上找到可复用判断。
2. 稳态血药浓度公式选型:口服、静滴、负荷剂量分别怎么算
2.1 平均稳态浓度 Css_avg:口服多次给药的基础式
所谓稳态,是指按固定剂量和固定间隔多次给药后,体内药量不再逐次累积,进入「每次给药增加的量 = 每个间隔消除的量」的平衡状态。通常经过 4~5 个半衰期即可认为达到稳态。平均稳态血药浓度的计算式是:
Css_avg = (F × D) / (CL × τ)
其中 D 是单次给药剂量,τ 是给药间隔,CL 是清除率,F 是生物利用度。这个式子是从「稳态下每个给药间隔内消除的药量等于吸收的药量」推导出来的,不需要假设峰谷的具体形态,所以口服、肌注这类按固定间隔给药的方案都适用。
需要提醒的是,Css_avg 不等于峰浓度和谷浓度的算术平均值。当半衰期和给药间隔接近时,峰谷波动会很明显,Css_avg 只是评估「总暴露量」的指标。临床上要判断疗效和毒性,还得看峰浓度或谷浓度,这就要用到下面 2.3 节的峰谷公式。
2.2 恒速静滴:Css = k0 / CL 的直接应用
静脉持续输注时,没有吸收相和间隔波动,稳态浓度就是输注速率 k0(单位时间给入的药量)除以清除率:
Css = k0 / CL
这个式子比口服多次给药简单,但单位坑最多。k0 如果按 mg/h 给,CL 必须换算成 L/h;如果医嘱上写的是「5% 葡萄糖 250 mL 加药 1g,8 小时滴完」,k0 = 1000 mg / 8 h = 125 mg/h,这个换算应该写进程序里由用户选「单次剂量 + 输注时长」自动算,而不是让药师手填 k0。恒速输注场景下没有间隔概念,界面不需要出现 τ 字段,这能避免用户把静滴和间断给药搞混。
2.3 峰浓度与谷浓度:静脉间断给药的完整模型
间断静脉推注或短时间输注,要分别算峰和谷,需要引入分布容积 Vd 和消除速率常数 ke:
ke = CL / Vd
Css_peak = (F × D / Vd) / (1 − e^(−ke × τ))
Css_trough = Css_peak × e^(−ke × τ)
这里的逻辑是:每次给药瞬间把药量 D 分布到 Vd 中形成「初始峰值」F × D / Vd,然后在一个间隔 τ 内按 ke 指数衰减,到下次给药前剩下 e^(−ke×τ),如此反复叠加,稳态峰值就是首剂量峰值除以 1 − e^(−ke×τ),这是等比级数求和的结果。谷浓度等于峰值乘上一个间隔的衰减因子。这个模型假设静注瞬间完成分布,临床上短时间点滴(30~60 分钟)按此近似是可接受的。
2.4 负荷剂量与达稳态时间:什么时候需要用 D_L
当药物半衰期很长(比如地高辛约 36 小时、胺碘酮数十天),等 4~5 个半衰期自然达稳态太慢,临床会先给一个负荷剂量 D_L 让血药浓度快速到达目标:
D_L = C_target × Vd / F
实现时注意:D_L 计算用的是 Vd 而不是 CL,这和维持剂量的计算参数完全不同,两套参数必须在界面上分开输入。另外,半衰期 t1/2 = 0.693 / ke,程序里可以顺带输出「预计达稳态时间 ≈ 4~5 × t1/2」,这个值对药师决定什么时候抽血测浓度很有用。下面把三种主流计算场景的公式和适用条件整理成表:
| 场景 | 计算公式 | 关键参数 | 适用情况 |
|---|---|---|---|
| 口服/肌注多次给药 | Css_avg = F·D / (CL·τ) | D、τ、F、CL | 地高辛口服维持方案 |
| 恒速静滴 | Css = k0 / CL | k0、CL | 万古霉素持续输注 |
| 间断静注峰谷 | Css_peak = (F·D/Vd)/(1−e^(−keτ)) | D、Vd、ke、τ | 万古霉素 1g q12h 方案评估 |
| 负荷剂量 | D_L = C_target·Vd / F | C_target、Vd、F | 地高辛快速洋地黄化 |
选型原则很简单:先确认给药途径是口服还是静注、是间断还是恒速,再决定用哪个函数。程序里不建议做成一个「万能输入框」,而是让用户先选场景,再动态显示对应参数,可以少掉一半的无效输入错误。
3. 用 JavaScript 封装药动学计算核心:纯函数、单位归一与浮点处理
3.1 计算模块为什么要做成纯函数
稳态血药浓度计算器的业务逻辑不复杂,但药动学公式对参数单位极其敏感。常见做法是单独建一个pk-core.js,把所有计算写成无副作用的纯函数——输入参数对象,返回结果对象,不碰页面状态,不做数据持久化。这样做的直接收益是可以在 Node 环境或小程序开发者工具里单独做单元测试,也可以被后续的管理后台直接复用同一套逻辑。
模块内部统一使用国际单位:剂量一律先转成 mg,体积一律用 L,时间一律用 h,浓度输出时再转成 μg/mL 或 ng/mL。输入层允许用户用 mg、g、μg 以及 L/h、mL/min 等单位,换算集中在入口处完成,公式体内部不出现任何单位转换代码。
3.2 核心计算函数实现
下面是pk-core.js的完整实现,覆盖上一章的四个场景:
// pk-core.js —— 稳态血药浓度计算核心模块 const PK = { // 半衰期 t1/2 = 0.693 / ke halfLife(ke) { if (!ke || ke <= 0) return NaN; return 0.693 / ke; }, // 平均稳态浓度 Css_avg = F * D / (CL * tau) cssAvg({ dose, f = 1, cl, tau }) { if (dose <= 0 || cl <= 0 || tau <= 0) return NaN; return (f * dose) / (cl * tau); }, // 恒速静滴稳态浓度 Css = k0 / CL cssInfusion({ k0, cl }) { if (k0 < 0 || cl <= 0) return NaN; return k0 / cl; }, // 消除速率常数 ke = CL / Vd ke({ cl, vd }) { if (cl <= 0 || vd <= 0) return NaN; return cl / vd; }, // 间断静注稳态峰浓度与谷浓度 peakTrough({ dose, f = 1, vd, cl, tau }) { const ke = this.ke({ cl, vd }); const peak0 = (f * dose) / vd; // 首剂瞬时峰值 const decay = Math.exp(-ke * tau); // 一个间隔后的残留比例 const peak = peak0 / (1 - decay); // 等比级数求和 const trough = peak * decay; return { peak, trough, ke }; }, // 负荷剂量 D_L = C_target * Vd / F loadingDose({ target, vd, f = 1 }) { if (target <= 0 || vd <= 0) return NaN; return (target * vd) / f; }, }; module.exports = PK;逻辑说明:peakTrough内部先算 ke,再算首剂瞬时峰值peak0,decay是每间隔的残留比例,稳态峰值等于首剂峰值乘以1/(1-decay),这对应等比数列求和收敛值,谷浓度则再乘一次decay。cssAvg的分母是cl * tau,注意这里是清除率乘间隔,不是分布容积乘间隔,两者物理含义完全不同。所有函数入口都做了基础校验,非法输入返回NaN而非抛异常,这样小程序页面上可以直接用isNaN(result)判断是否需要提示用户补充参数。
3.3 单位换算与浮点精度处理
上述函数要求 dose 单位为 mg、cl 单位为 L/h、vd 单位为 L、tau 单位为 h。但临床输入习惯五花八门,比如剂量可能填 0.25(mg 的地高辛片),也可能填 1000(mg 的万古霉素),清除率经常是实验室给的 mL/min。因此在调入计算核心之前,要做一个独立的单位归一化层:
// unit.js —— 单位归一化工具 const U = { // 质量转 mg:支持 mg/g/μg 字符串后缀 toMg(value, unit) { const map = { mg: 1, g: 1000, ug: 0.001, mcg: 0.001 }; return value * (map[unit] ?? 1); }, // 清除率转 L/h:输入 mL/min 时除以 1000 再乘 60 toLH(value, unit) { return unit === 'mL/min' ? (value / 1000) * 60 : unit === 'L/h' ? value : NaN; }, // 浓度输出:默认 μg/mL,按需转换成 ng/mL toDisplay(concentration, outputUnit) { if (outputUnit === 'ng/mL') { return parseFloat((concentration * 1000).toFixed(2)); } return parseFloat(concentration.toFixed(2)); }, };浮点问题在药动学计算里比想象中常见:0.175 / 144在 JavaScript 里会得到0.0012152777777777778这类长小数,直接显示会劝退用户。处理方式统一用toFixed(2)做显示层截断,但计算层保留原始精度,不要用Math.round把中间结果提前四舍五入——峰谷公式里1 - decay如果被舍入,对长半衰期药物会造成指数级的误差放大。判断相等也用Math.abs(a - b) < 1e-9而不是===。
4. 微信小程序页面搭建:WXML 表单绑定与动态参数面板
4.1 小程序项目的最小目录结构
微信小程序的项目结构相比普通 Web 项目多了几个强制文件:app.json、app.js、app.wxss和页面目录下的index.wxml、index.js、index.wxss、index.json。稳态血药浓度计算器只需要一个主页面,目录安排如下:
miniprogram/ ├── app.json ├── app.js ├── pages/ │ └── index/ │ ├── index.wxml │ ├── index.wxss │ ├── index.js │ └── index.json └── utils/ ├── pk-core.js └── unit.jsapp.json里注册页面路径并设置窗口标题,utils下放上一章的计算核心。页面逻辑里不直接写公式,只用require('../../utils/pk-core.js')引入模块做计算调用,这是保证计算逻辑可测试的关键一步。index.json可以设置"navigationBarTitleText": "稳态血药浓度计算器"让小程序顶部导航栏直接显示工具名。
4.2 场景选择与动态表单绑定
界面设计上,第一步先让用户选给药场景:口服多次给药、恒速静滴、间断静注峰谷、负荷剂量。选择不同场景时,表单字段需要联动变化,WXML 中用wx:if按scene字段渲染对应的输入组。以「间断静注峰谷」为例,核心 WXML 如下:
<view class="card"> <picker mode="selector" range="{{sceneList}}" bindchange="onSceneChange"> <view class="picker-value">{{sceneList[scene]}}</view> </picker> </view> <view class="card" wx:if="{{scene === 2}}"> <view class="field"> <text>单次剂量 D (mg)</text> <input type="digit" value="{{dose}}" bindinput="onInput">const PK = require('../../utils/pk-core.js'); const U = require('../../utils/unit.js'); Page({ data: { sceneList: ['口服多次给药', '恒速静滴', '间断静注峰谷', '负荷剂量'], scene: 2, dose: '', cl: '', vd: '', tau: '', clUnit: 0, clUnitList: ['L/h', 'mL/min'], result: null, }, onSceneChange(e) { this.setData({ scene: Number(e.detail.value), result: null }); }, onInput(e) { const key = e.currentTarget.dataset.key; this.setData({ [key]: e.detail.value }); this.recalc(); }, onClUnitChange(e) { this.setData({ clUnit: Number(e.detail.value) }); this.recalc(); }, recalc() { const scene = this.data.scene; const dose = parseFloat(this.data.dose); const vd = parseFloat(this.data.vd); const tau = parseFloat(this.data.tau); const cl = U.toLH(parseFloat(this.data.cl), this.data.clUnitList[this.data.clUnit]); if (scene === 2) { const r = PK.peakTrough({ dose, vd, cl, tau }); this.setData({ result: r && !isNaN(r.peak) ? { peak: U.toDisplay(r.peak, 'μg/mL'), trough: U.toDisplay(r.trough, 'μg/mL'), ke: r.ke.toFixed(3), } : null }); } // 其他场景分支结构与上一致,按 scene 值分别调用 PK.cssAvg / PK.cssInfusion / PK.loadingDose }, });事件绑定说明:bindinput在用户每次输入时触发,>onShareAppMessage() { return { title: '稳态血药浓度计算器——按给药方案快速算峰谷浓度' }; }
onShareAppMessage是微信小程序页面内置的生命周期方法,只需返回分享标题即可开启右上角菜单的转发能力。如果希望分享时带上当前输入参数,可以把表单值编码进path字段,接收方打开小程序时在onLoad里解析并回填表单,实现参数随分享卡片流转。
5. 用真实药物数据验算与边界情况处理
5.1 地高辛与万古霉素的标准算例验算
计算器写完,第一件事不是接 UI,而是拿教科书上的标准算例验算。地高辛口服维持方案:D = 0.25 mg,F = 0.7,CL = 6 L/h,τ = 24 h,代入cssAvg得到 0.7 × 0.25 / (6 × 24) = 0.001215 mg/L,换算成显示单位 μg/mL 就是 1.21,地高辛有效治疗浓度范围约 0.8~2.0 ng/mL,结果符合预期。注意这里 mg/L 和 μg/mL 数值上相等,但 ng/mL 是前者的 1000 倍,显示层必须明确标注单位,否则药师会误读。
万古霉素间断静注验算:剂量 1000 mg,CL = 4.5 L/h,Vd = 50 L,τ = 12 h。先算 ke = 4.5/50 = 0.09 h⁻¹,decay = e^(−0.09×12) = e^(−1.08) ≈ 0.3396,峰浓度 = (1000/50)/(1−0.3396) = 20/0.6604 ≈ 30.3 μg/mL,谷浓度 = 30.3 × 0.3396 ≈ 10.3 μg/mL。这两个数可以手工还原:
node -e " const PK = require('./utils/pk-core.js'); const r = PK.peakTrough({dose:1000, vd:50, cl:4.5, tau:12}); console.log('Cpeak(μg/mL)=', r.peak.toFixed(2)); console.log('Ctrough(μg/mL)=', r.trough.toFixed(2)); console.log('ke(1/h)=', r.ke.toFixed(4)); "输出应为Cpeak=30.29、Ctrough=10.29、ke=0.0900。这类用 Node 直接跑模块的验证方式,比在小程序端边点边看效率高得多;建议在每次修改pk-core.js后都跑一遍这组数字,防止回归。
5.2 边界输入与异常值防御
药动学计算最容易踩的边界坑有三个。第一个是清除率为 0 或负数:肾功能衰竭患者的 CL 可能趋近于 0,公式分母为 0 会得到 Infinity,界面必须提示「清除率过低,建议确认参数」,而不是显示一个无穷大符号。第二个是极端长半衰期药物,decay = Math.exp(-ke * tau)在 tau 很小或 ke 很小时接近于 1,1 - decay出现精度损失,此时峰浓度计算结果会异常偏大,可接受的工程做法是当decay > 0.999时改用持续输注模型近似并给出提示。第三个是剂量单位输入错误:万古霉素按 g 填 1 和按 mg 填 1000 只差一个toMg的映射,遗漏单位选择器会直接产出百倍误差,所以单位字段要用picker强制选择而不是靠用户手输单位文本。
提示:所有数值输入框统一用
type="digit",该类型允许小数点输入;不要用type="number",后者在部分 iOS 版本上无法输入小数点。
最后一个实用技巧:在app.js的onLaunch里加入版本标记,例如version: '1.0.0',并在页面底部显示「公式版本:依据一室模型药动学,v1.0」,当临床药师反馈计算结果与科室标准不同时,先确认计算公式版本再排查数据,避免在公式选型上反复扯皮。计算器类小程序的信任度完全建立在可复核性上,能展示公式、参数单位和算例对照,就能减少一半以上的质疑。
本文还有配套的精品资源,点击获取