From 36a55e116e2c06a92bb065abbb3403b68f64d404 Mon Sep 17 00:00:00 2001 From: iven Date: Thu, 30 Apr 2026 16:48:39 +0800 Subject: [PATCH] =?UTF-8?q?feat(miniprogram):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E5=B0=8F=E7=A8=8B=E5=BA=8F=E9=80=8F=E6=9E=90=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=20=E2=80=94=20=E6=82=A3=E8=80=85=E7=AB=AF=E6=9F=A5=E7=9C=8B=20?= =?UTF-8?q?+=20=E5=8C=BB=E6=8A=A4=E7=AB=AF=E5=BD=95=E5=85=A5/=E5=AE=A1?= =?UTF-8?q?=E9=98=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 审计后续 H1: 补齐小程序端透析功能,对接后端 12 个 API 路由。 新增内容: - 患者端: 透析记录列表/详情 + 透析处方列表/详情(只读,4 页面) - 医护端: 透析记录列表/详情/创建 + 处方列表/详情/创建(6 页面) - Service 层: dialysis.ts(患者端只读)+ doctor/dialysis.ts(医护端 CRUD) - 集成入口: 医生工作台快捷操作 + 患者"我的"菜单 + 路由注册 - 基础设施: api.delete 扩展支持 data 参数(后端 delete 需要 version) --- apps/miniprogram/src/app.config.ts | 4 + .../pages/doctor/dialysis/create/index.scss | 97 +++++ .../pages/doctor/dialysis/create/index.tsx | 244 ++++++++++++ .../pages/doctor/dialysis/detail/index.scss | 155 ++++++++ .../pages/doctor/dialysis/detail/index.tsx | 172 +++++++++ .../src/pages/doctor/dialysis/index.scss | 193 ++++++++++ .../src/pages/doctor/dialysis/index.tsx | 169 +++++++++ apps/miniprogram/src/pages/doctor/index.tsx | 2 + .../doctor/prescription/create/index.scss | 92 +++++ .../doctor/prescription/create/index.tsx | 196 ++++++++++ .../doctor/prescription/detail/index.scss | 136 +++++++ .../doctor/prescription/detail/index.tsx | 161 ++++++++ .../src/pages/doctor/prescription/index.scss | 175 +++++++++ .../src/pages/doctor/prescription/index.tsx | 163 ++++++++ .../dialysis-prescriptions/detail/index.scss | 118 ++++++ .../dialysis-prescriptions/detail/index.tsx | 111 ++++++ .../dialysis-prescriptions/index.scss | 98 +++++ .../dialysis-prescriptions/index.tsx | 98 +++++ .../dialysis-records/detail/index.scss | 119 ++++++ .../dialysis-records/detail/index.tsx | 113 ++++++ .../pkg-profile/dialysis-records/index.scss | 111 ++++++ .../pkg-profile/dialysis-records/index.tsx | 103 +++++ apps/miniprogram/src/pages/profile/index.tsx | 2 + apps/miniprogram/src/services/dialysis.ts | 92 +++++ apps/miniprogram/src/services/doctor.ts | 352 +----------------- .../src/services/doctor/dialysis.ts | 141 +++++++ apps/miniprogram/src/services/request.ts | 2 +- 27 files changed, 3076 insertions(+), 343 deletions(-) create mode 100644 apps/miniprogram/src/pages/doctor/dialysis/create/index.scss create mode 100644 apps/miniprogram/src/pages/doctor/dialysis/create/index.tsx create mode 100644 apps/miniprogram/src/pages/doctor/dialysis/detail/index.scss create mode 100644 apps/miniprogram/src/pages/doctor/dialysis/detail/index.tsx create mode 100644 apps/miniprogram/src/pages/doctor/dialysis/index.scss create mode 100644 apps/miniprogram/src/pages/doctor/dialysis/index.tsx create mode 100644 apps/miniprogram/src/pages/doctor/prescription/create/index.scss create mode 100644 apps/miniprogram/src/pages/doctor/prescription/create/index.tsx create mode 100644 apps/miniprogram/src/pages/doctor/prescription/detail/index.scss create mode 100644 apps/miniprogram/src/pages/doctor/prescription/detail/index.tsx create mode 100644 apps/miniprogram/src/pages/doctor/prescription/index.scss create mode 100644 apps/miniprogram/src/pages/doctor/prescription/index.tsx create mode 100644 apps/miniprogram/src/pages/pkg-profile/dialysis-prescriptions/detail/index.scss create mode 100644 apps/miniprogram/src/pages/pkg-profile/dialysis-prescriptions/detail/index.tsx create mode 100644 apps/miniprogram/src/pages/pkg-profile/dialysis-prescriptions/index.scss create mode 100644 apps/miniprogram/src/pages/pkg-profile/dialysis-prescriptions/index.tsx create mode 100644 apps/miniprogram/src/pages/pkg-profile/dialysis-records/detail/index.scss create mode 100644 apps/miniprogram/src/pages/pkg-profile/dialysis-records/detail/index.tsx create mode 100644 apps/miniprogram/src/pages/pkg-profile/dialysis-records/index.scss create mode 100644 apps/miniprogram/src/pages/pkg-profile/dialysis-records/index.tsx create mode 100644 apps/miniprogram/src/services/dialysis.ts create mode 100644 apps/miniprogram/src/services/doctor/dialysis.ts diff --git a/apps/miniprogram/src/app.config.ts b/apps/miniprogram/src/app.config.ts index f6e80c4..faa16e5 100644 --- a/apps/miniprogram/src/app.config.ts +++ b/apps/miniprogram/src/app.config.ts @@ -26,6 +26,8 @@ export default defineAppConfig({ 'followup/index', 'followup/detail/index', 'report/index', 'report/detail/index', 'alerts/index', 'alerts/detail/index', + 'dialysis/index', 'dialysis/detail/index', 'dialysis/create/index', + 'prescription/index', 'prescription/detail/index', 'prescription/create/index', ], }, { @@ -37,6 +39,8 @@ export default defineAppConfig({ pages: [ 'family/index', 'family-add/index', 'reports/index', 'followups/index', 'medication/index', 'settings/index', + 'dialysis-records/index', 'dialysis-records/detail/index', + 'dialysis-prescriptions/index', 'dialysis-prescriptions/detail/index', ], }, { diff --git a/apps/miniprogram/src/pages/doctor/dialysis/create/index.scss b/apps/miniprogram/src/pages/doctor/dialysis/create/index.scss new file mode 100644 index 0000000..d80a720 --- /dev/null +++ b/apps/miniprogram/src/pages/doctor/dialysis/create/index.scss @@ -0,0 +1,97 @@ +@import '../../../../styles/variables.scss'; + +.create-page { + min-height: 100vh; + background: $bg; + padding: 24px; + padding-bottom: 200px; +} + +.section { + background: $card; + border-radius: $r; + padding: 24px; + margin-bottom: 16px; + box-shadow: $shadow-sm; +} + +.section-title { + font-size: 28px; + font-weight: bold; + color: $tx; + display: block; + margin-bottom: 16px; +} + +.form-row { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px 0; + border-bottom: 1px solid $bd-l; + + &:last-child { + border-bottom: none; + } + + &--textarea { + flex-direction: column; + align-items: flex-start; + } +} + +.form-label { + font-size: 26px; + color: $tx2; + flex-shrink: 0; + min-width: 140px; +} + +.form-input { + flex: 1; + text-align: right; + font-size: 26px; + color: $tx; +} + +.form-value { + font-size: 26px; + color: $tx; + + &.placeholder { + color: $tx3; + } +} + +.form-textarea { + width: 100%; + margin-top: 12px; + font-size: 26px; + color: $tx; + min-height: 120px; + background: $bg; + border-radius: $r-sm; + padding: 16px; +} + +.submit-btn { + background: $pri; + border-radius: $r-sm; + padding: 24px; + text-align: center; + margin-top: 24px; + + &:active { + background: $pri-d; + } + + &--disabled { + opacity: 0.5; + } +} + +.submit-btn__text { + font-size: 30px; + font-weight: bold; + color: #fff; +} diff --git a/apps/miniprogram/src/pages/doctor/dialysis/create/index.tsx b/apps/miniprogram/src/pages/doctor/dialysis/create/index.tsx new file mode 100644 index 0000000..dfd6f87 --- /dev/null +++ b/apps/miniprogram/src/pages/doctor/dialysis/create/index.tsx @@ -0,0 +1,244 @@ +import { useState, useEffect } from 'react'; +import { View, Text, Input, Textarea, Picker, ScrollView } from '@tarojs/components'; +import Taro, { useRouter } from '@tarojs/taro'; +import * as doctorApi from '@/services/doctor'; +import Loading from '@/components/Loading'; +import './index.scss'; + +const DIALYSIS_TYPES = ['HD', 'HDF', 'HF']; + +interface FormState { + patient_id: string; + dialysis_date: string; + start_time: string; + end_time: string; + dialysis_type: string; + dialysis_duration: string; + blood_flow_rate: string; + dry_weight: string; + pre_weight: string; + post_weight: string; + pre_bp_systolic: string; + pre_bp_diastolic: string; + post_bp_systolic: string; + post_bp_diastolic: string; + pre_heart_rate: string; + post_heart_rate: string; + ultrafiltration_volume: string; + complication_notes: string; +} + +const initialForm: FormState = { + patient_id: '', + dialysis_date: '', + start_time: '', + end_time: '', + dialysis_type: 'HD', + dialysis_duration: '', + blood_flow_rate: '', + dry_weight: '', + pre_weight: '', + post_weight: '', + pre_bp_systolic: '', + pre_bp_diastolic: '', + post_bp_systolic: '', + post_bp_diastolic: '', + pre_heart_rate: '', + post_heart_rate: '', + ultrafiltration_volume: '', + complication_notes: '', +}; + +export default function DialysisCreate() { + const router = useRouter(); + const id = router.params.id || ''; + const version = router.params.version ? Number(router.params.version) : 0; + const patientIdFromRoute = router.params.patientId || ''; + const isEdit = !!id; + + const [form, setForm] = useState({ ...initialForm, patient_id: patientIdFromRoute }); + const [loading, setLoading] = useState(isEdit); + const [submitting, setSubmitting] = useState(false); + + useEffect(() => { + if (isEdit && id) loadRecord(); + }, [id]); + + const loadRecord = async () => { + setLoading(true); + try { + const r = await doctorApi.getDialysisRecord(id); + setForm({ + patient_id: r.patient_id, + dialysis_date: r.dialysis_date || '', + start_time: r.start_time || '', + end_time: r.end_time || '', + dialysis_type: r.dialysis_type || 'HD', + dialysis_duration: r.dialysis_duration != null ? String(r.dialysis_duration) : '', + blood_flow_rate: r.blood_flow_rate != null ? String(r.blood_flow_rate) : '', + dry_weight: r.dry_weight != null ? String(r.dry_weight) : '', + pre_weight: r.pre_weight != null ? String(r.pre_weight) : '', + post_weight: r.post_weight != null ? String(r.post_weight) : '', + pre_bp_systolic: r.pre_bp_systolic != null ? String(r.pre_bp_systolic) : '', + pre_bp_diastolic: r.pre_bp_diastolic != null ? String(r.pre_bp_diastolic) : '', + post_bp_systolic: r.post_bp_systolic != null ? String(r.post_bp_systolic) : '', + post_bp_diastolic: r.post_bp_diastolic != null ? String(r.post_bp_diastolic) : '', + pre_heart_rate: r.pre_heart_rate != null ? String(r.pre_heart_rate) : '', + post_heart_rate: r.post_heart_rate != null ? String(r.post_heart_rate) : '', + ultrafiltration_volume: r.ultrafiltration_volume != null ? String(r.ultrafiltration_volume) : '', + complication_notes: r.complication_notes || '', + }); + } catch { + Taro.showToast({ title: '加载失败', icon: 'none' }); + } finally { + setLoading(false); + } + }; + + const updateField = (key: keyof FormState, value: string) => { + setForm((prev) => ({ ...prev, [key]: value })); + }; + + const handleSubmit = async () => { + if (!form.dialysis_date) { + Taro.showToast({ title: '请选择透析日期', icon: 'none' }); + return; + } + if (!form.patient_id) { + Taro.showToast({ title: '缺少患者信息', icon: 'none' }); + return; + } + + setSubmitting(true); + const num = (v: string) => v ? Number(v) : undefined; + const payload = { + patient_id: form.patient_id, + dialysis_date: form.dialysis_date, + start_time: form.start_time || undefined, + end_time: form.end_time || undefined, + dialysis_type: form.dialysis_type, + dialysis_duration: num(form.dialysis_duration), + blood_flow_rate: num(form.blood_flow_rate), + dry_weight: num(form.dry_weight), + pre_weight: num(form.pre_weight), + post_weight: num(form.post_weight), + pre_bp_systolic: num(form.pre_bp_systolic), + pre_bp_diastolic: num(form.pre_bp_diastolic), + post_bp_systolic: num(form.post_bp_systolic), + post_bp_diastolic: num(form.post_bp_diastolic), + pre_heart_rate: num(form.pre_heart_rate), + post_heart_rate: num(form.post_heart_rate), + ultrafiltration_volume: num(form.ultrafiltration_volume), + complication_notes: form.complication_notes || undefined, + }; + + try { + if (isEdit) { + const { patient_id, ...updateData } = payload; + await doctorApi.updateDialysisRecord(id, updateData, version); + Taro.showToast({ title: '更新成功', icon: 'success' }); + } else { + await doctorApi.createDialysisRecord(payload); + Taro.showToast({ title: '创建成功', icon: 'success' }); + } + setTimeout(() => Taro.navigateBack(), 1000); + } catch { + Taro.showToast({ title: isEdit ? '更新失败' : '创建失败', icon: 'none' }); + } finally { + setSubmitting(false); + } + }; + + if (loading) return ; + + const InputField = ({ label, field, placeholder, type = 'digit' }: { + label: string; field: keyof FormState; placeholder: string; type?: string; + }) => ( + + {label} + updateField(field, e.detail.value)} + /> + + ); + + return ( + + + 基本信息 + + 透析日期 + updateField('dialysis_date', e.detail.value)}> + + {form.dialysis_date || '请选择日期'} + + + + + 开始时间 + updateField('start_time', e.detail.value)}> + + {form.start_time || '请选择时间'} + + + + + 结束时间 + updateField('end_time', e.detail.value)}> + + {form.end_time || '请选择时间'} + + + + + 透析类型 + updateField('dialysis_type', DIALYSIS_TYPES[Number(e.detail.value)])}> + {form.dialysis_type} + + + + + + + + 体重 + + + + + + + 血压与心率 + + + + + + + + + + 超滤与备注 + + + 并发症备注 +