From 1a6409eb308f971c598fcbb3d70b6ec96101b35f Mon Sep 17 00:00:00 2001 From: iven Date: Sun, 3 May 2026 09:38:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(miniprogram):=20=E7=94=A8=E8=8D=AF?= =?UTF-8?q?=E6=8F=90=E9=86=92=E4=BB=8E=20localStorage=20=E8=BF=81=E7=A7=BB?= =?UTF-8?q?=E5=88=B0=E6=9C=8D=E5=8A=A1=E7=AB=AF=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 medication-reminder.ts service(list/create/update/delete) - 重写 medication/index.tsx 页面,通过后端 API 持久化数据 - 支持乐观锁(version)、患者 ID 关联、提醒时间数组 - 移除旧的 localStorage 读写逻辑 --- .../pages/pkg-profile/medication/index.tsx | 135 +++++++++++------- .../src/services/medication-reminder.ts | 68 +++++++++ 2 files changed, 148 insertions(+), 55 deletions(-) create mode 100644 apps/miniprogram/src/services/medication-reminder.ts diff --git a/apps/miniprogram/src/pages/pkg-profile/medication/index.tsx b/apps/miniprogram/src/pages/pkg-profile/medication/index.tsx index da743f5..784c3c4 100644 --- a/apps/miniprogram/src/pages/pkg-profile/medication/index.tsx +++ b/apps/miniprogram/src/pages/pkg-profile/medication/index.tsx @@ -1,111 +1,136 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { View, Text, Input, Picker } from '@tarojs/components'; import Taro from '@tarojs/taro'; import EmptyState from '../../../components/EmptyState'; +import { + listReminders, + createReminder, + updateReminder, + deleteReminder, + type MedicationReminder, +} from '../../../services/medication-reminder'; import './index.scss'; -interface MedicationReminder { - id: string; - name: string; - dosage: string; - time: string; - enabled: boolean; -} - -const STORAGE_KEY = 'medication_reminders'; - -function loadReminders(): MedicationReminder[] { - return Taro.getStorageSync(STORAGE_KEY) || []; -} - -function saveReminders(reminders: MedicationReminder[]) { - Taro.setStorageSync(STORAGE_KEY, reminders); -} - export default function MedicationReminder() { const [reminders, setReminders] = useState([]); + const [loading, setLoading] = useState(true); const [showForm, setShowForm] = useState(false); const [formName, setFormName] = useState(''); const [formDosage, setFormDosage] = useState(''); const [formTime, setFormTime] = useState('08:00'); - useEffect(() => { - setReminders(loadReminders()); + const fetchReminders = useCallback(async () => { + try { + const res = await listReminders(); + setReminders(res.data ?? []); + } catch { + Taro.showToast({ title: '加载失败', icon: 'none' }); + } finally { + setLoading(false); + } }, []); - const updateReminders = (updated: MedicationReminder[]) => { - setReminders(updated); - saveReminders(updated); + useEffect(() => { fetchReminders(); }, [fetchReminders]); + + const handleToggle = async (r: MedicationReminder) => { + try { + await updateReminder(r.id, { + is_active: !r.is_active, + version: r.version, + }); + fetchReminders(); + } catch { + Taro.showToast({ title: '操作失败', icon: 'none' }); + } }; - const handleToggle = (id: string) => { - const updated = reminders.map((r) => - r.id === id ? { ...r, enabled: !r.enabled } : r - ); - updateReminders(updated); - }; - - const handleDelete = (id: string) => { + const handleDelete = (r: MedicationReminder) => { Taro.showModal({ title: '确认删除', content: '确定要删除这个提醒吗?', - }).then((res) => { + }).then(async (res) => { if (res.confirm) { - updateReminders(reminders.filter((r) => r.id !== id)); + try { + await deleteReminder(r.id, r.version); + Taro.showToast({ title: '已删除', icon: 'success' }); + fetchReminders(); + } catch { + Taro.showToast({ title: '删除失败', icon: 'none' }); + } } }); }; - const handleAdd = () => { + const handleAdd = async () => { if (!formName.trim()) { Taro.showToast({ title: '请输入药品名称', icon: 'none' }); return; } - const newReminder: MedicationReminder = { - id: Date.now().toString(), - name: formName.trim(), - dosage: formDosage.trim(), - time: formTime, - enabled: true, - }; - updateReminders([...reminders, newReminder]); - setFormName(''); - setFormDosage(''); - setFormTime('08:00'); - setShowForm(false); - Taro.showToast({ title: '添加成功', icon: 'success' }); + const patientId = Taro.getStorageSync('current_patient_id'); + if (!patientId) { + Taro.showToast({ title: '请先绑定患者档案', icon: 'none' }); + return; + } + try { + await createReminder({ + patient_id: patientId, + medication_name: formName.trim(), + dosage: formDosage.trim() || undefined, + reminder_times: [formTime], + is_active: true, + }); + setFormName(''); + setFormDosage(''); + setFormTime('08:00'); + setShowForm(false); + Taro.showToast({ title: '添加成功', icon: 'success' }); + fetchReminders(); + } catch { + Taro.showToast({ title: '添加失败', icon: 'none' }); + } }; const nameInitial = (name: string) => { return name ? name.charAt(0) : '药'; }; + if (loading) { + return ( + + 用药提醒 + + 加载中... + + + ); + } + return ( 用药提醒 {reminders.map((r) => ( - + - {nameInitial(r.name)} + {nameInitial(r.medication_name)} - {r.name} + {r.medication_name} - {r.dosage} | {r.time} + {r.dosage || '-'} | {r.reminder_times?.join(', ') || '-'} handleToggle(r.id)} + className={`toggle ${r.is_active ? 'on' : 'off'}`} + onClick={() => handleToggle(r)} > handleDelete(r.id)} + onClick={() => handleDelete(r)} > 删除 diff --git a/apps/miniprogram/src/services/medication-reminder.ts b/apps/miniprogram/src/services/medication-reminder.ts new file mode 100644 index 0000000..4a54467 --- /dev/null +++ b/apps/miniprogram/src/services/medication-reminder.ts @@ -0,0 +1,68 @@ +import Taro from '@tarojs/taro'; +import { api } from './request'; + +export interface MedicationReminder { + id: string; + patient_id: string; + medication_name: string; + dosage?: string; + frequency?: string; + reminder_times: string[]; + start_date?: string; + end_date?: string; + is_active: boolean; + notes?: string; + version: number; + created_at: string; + updated_at: string; +} + +export interface CreateReminderReq { + patient_id: string; + medication_name: string; + dosage?: string; + frequency?: string; + reminder_times: string[]; + start_date?: string; + end_date?: string; + is_active?: boolean; + notes?: string; +} + +export interface UpdateReminderReq { + medication_name?: string; + dosage?: string; + frequency?: string; + reminder_times?: string[]; + start_date?: string; + end_date?: string; + is_active?: boolean; + notes?: string; + version: number; +} + +function getPatientId(): string { + return Taro.getStorageSync('current_patient_id') || ''; +} + +export async function listReminders() { + const patientId = getPatientId(); + if (!patientId) return { data: [] as MedicationReminder[], total: 0 }; + return api.get<{ data: MedicationReminder[]; total: number }>( + `/health/patients/${patientId}/medication-reminders`, + { page: 1, page_size: 100 }, + 0, + ); +} + +export async function createReminder(req: CreateReminderReq) { + return api.post('/health/medication-reminders', req); +} + +export async function updateReminder(id: string, req: UpdateReminderReq) { + return api.put(`/health/medication-reminders/${id}`, req); +} + +export async function deleteReminder(id: string, version: number) { + return api.delete(`/health/medication-reminders/${id}`, { version }); +}