鸿蒙跨端家庭用药管理系统开发指南 原创

进修的泡芙
发布于 2025-6-22 17:55
浏览
0收藏

鸿蒙跨端家庭用药管理系统开发指南

一、系统架构设计

基于HarmonyOS的分布式能力,构建智能家庭用药管理系统:
药品管理层:管理药品信息和服药计划

提醒服务层:定时提醒用户服药

数据同步层:多设备间同步药品数据和提醒状态

健康数据层:记录服药历史和健康数据

!https://example.com/harmony-medication-system-arch.png

二、核心代码实现
药品管理服务

// MedicationService.ets
import distributedData from ‘@ohos.distributedData’;
import notification from ‘@ohos.notification’;
import { Medicine, MedicationPlan, Reminder } from ‘./MedicationTypes’;

class MedicationService {
private static instance: MedicationService = null;
private dataManager: distributedData.DataManager;
private listeners: MedicationListener[] = [];
private medicines: Medicine[] = [];
private plans: MedicationPlan[] = [];

private constructor() {
this.initDataManager();
public static getInstance(): MedicationService {

if (!MedicationService.instance) {
  MedicationService.instance = new MedicationService();

return MedicationService.instance;

private initDataManager(): void {

this.dataManager = distributedData.createDataManager({
  bundleName: 'com.example.medication',
  area: distributedData.Area.GLOBAL,
  isEncrypted: true
});

this.dataManager.registerDataListener('medication_sync', (data) => {
  this.handleSyncData(data);
});

public async requestPermissions(): Promise<boolean> {

try {
  const permissions = [
    'ohos.permission.NOTIFICATION',
    'ohos.permission.DISTRIBUTED_DATASYNC'
  ];
  
  const result = await abilityAccessCtrl.requestPermissionsFromUser(
    getContext(), 
    permissions
  );
  
  return result.grantedPermissions.length === permissions.length;

catch (err) {

  console.error('请求权限失败:', JSON.stringify(err));
  return false;

}

public async addMedicine(medicine: Medicine): Promise<void> {
const newMedicine = {
…medicine,
id: Date.now().toString(),
createdAt: Date.now()
};

this.medicines = [...this.medicines, newMedicine];
this.syncMedicine(newMedicine);

public async updateMedicine(medicine: Medicine): Promise<void> {

this.medicines = this.medicines.map(m => 
  m.id === medicine.id ? medicine : m
);
this.syncMedicine(medicine);

public async removeMedicine(medicineId: string): Promise<void> {

this.medicines = this.medicines.filter(m => m.id !== medicineId);
this.dataManager.syncData('medicine_remove', {
  type: 'medicine_removed',
  data: { medicineId },
  timestamp: Date.now()
});

public async addMedicationPlan(plan: MedicationPlan): Promise<void> {

const newPlan = {
  ...plan,
  id: Date.now().toString(),
  createdAt: Date.now(),
  reminders: this.generateReminders(plan)
};

this.plans = [...this.plans, newPlan];
this.syncPlan(newPlan);
this.scheduleReminders(newPlan.reminders);

private generateReminders(plan: MedicationPlan): Reminder[] {

const reminders: Reminder[] = [];
const startDate = new Date(plan.startDate);
const endDate = new Date(plan.endDate);

for (let day = 0; day <= (endDate.getTime() - startDate.getTime()) / (1000  60  60 * 24); day++) {
  const currentDate = new Date(startDate);
  currentDate.setDate(startDate.getDate() + day);
  
  plan.times.forEach(time => {
    const [hours, minutes] = time.split(':').map(Number);
    const reminderTime = new Date(currentDate);
    reminderTime.setHours(hours, minutes, 0, 0);
    
    if (reminderTime <= endDate) {
      reminders.push({
        id: {plan.id}_{day}_${time},
        planId: plan.id,
        medicineId: plan.medicineId,
        scheduledTime: reminderTime.getTime(),
        status: 'pending',
        takenTime: null
      });

});

return reminders;

private scheduleReminders(reminders: Reminder[]): void {

reminders.forEach(reminder => {
  if (reminder.scheduledTime > Date.now()) {
    notification.schedule({
      id: parseInt(reminder.id),
      content: {
        title: '服药提醒',
        text: 该服用 ${this.getMedicineName(reminder.medicineId)} 了,
        additionalText: 剂量: ${this.getMedicineDosage(reminder.medicineId)},
        tapAction: {
          bundleName: 'com.example.medication',
          abilityName: 'MainAbility'

},

      deliveryTime: reminder.scheduledTime
    });

});

public async markAsTaken(reminderId: string): Promise<void> {

const updatedReminders = this.plans.flatMap(plan => 
  plan.reminders.map(r => 
    r.id === reminderId ? { ...r, status: 'taken', takenTime: Date.now() } : r
  )
);

this.plans = this.plans.map(plan => ({
  ...plan,
  reminders: updatedReminders.filter(r => r.planId === plan.id)
}));

this.syncReminderUpdate({
  reminderId,
  status: 'taken',
  takenTime: Date.now()
});

public async skipReminder(reminderId: string): Promise<void> {

const updatedReminders = this.plans.flatMap(plan => 
  plan.reminders.map(r => 
    r.id === reminderId ? { ...r, status: 'skipped' } : r
  )
);

this.plans = this.plans.map(plan => ({
  ...plan,
  reminders: updatedReminders.filter(r => r.planId === plan.id)
}));

this.syncReminderUpdate({
  reminderId,
  status: 'skipped'
});

private getMedicineName(medicineId: string): string {

return this.medicines.find(m => m.id === medicineId)?.name || '未知药品';

private getMedicineDosage(medicineId: string): string {

return this.medicines.find(m => m.id === medicineId)?.dosage || '请咨询医生';

private syncMedicine(medicine: Medicine): void {

this.dataManager.syncData('medicine_sync', {
  type: 'medicine_updated',
  data: medicine,
  timestamp: Date.now()
});

private syncPlan(plan: MedicationPlan): void {

this.dataManager.syncData('plan_sync', {
  type: 'plan_updated',
  data: plan,
  timestamp: Date.now()
});

private syncReminderUpdate(update: ReminderUpdate): void {

this.dataManager.syncData('reminder_sync', {
  type: 'reminder_updated',
  data: update,
  timestamp: Date.now()
});

private handleSyncData(data: any): void {

if (!data) return;

switch (data.type) {
  case 'medicine_updated':
    this.handleMedicineUpdated(data.data);
    break;
  case 'medicine_removed':
    this.handleMedicineRemoved(data.data.medicineId);
    break;
  case 'plan_updated':
    this.handlePlanUpdated(data.data);
    break;
  case 'reminder_updated':
    this.handleReminderUpdated(data.data);
    break;

}

private handleMedicineUpdated(medicine: Medicine): void {
const existingIndex = this.medicines.findIndex(m => m.id === medicine.id);

if (existingIndex >= 0) {
  this.medicines[existingIndex] = medicine;

else {

  this.medicines = [...this.medicines, medicine];

this.notifyMedicineUpdated(medicine);

private handleMedicineRemoved(medicineId: string): void {

this.medicines = this.medicines.filter(m => m.id !== medicineId);
this.notifyMedicineRemoved(medicineId);

private handlePlanUpdated(plan: MedicationPlan): void {

const existingIndex = this.plans.findIndex(p => p.id === plan.id);

if (existingIndex >= 0) {
  this.plans[existingIndex] = plan;

else {

  this.plans = [...this.plans, plan];

this.notifyPlanUpdated(plan);

private handleReminderUpdated(update: ReminderUpdate): void {

this.plans = this.plans.map(plan => ({
  ...plan,
  reminders: plan.reminders.map(r => 
    r.id === update.reminderId ? { ...r, status: update.status, takenTime: update.takenTime || null } : r
  )
}));

this.notifyReminderUpdated(update);

private notifyMedicineUpdated(medicine: Medicine): void {

this.listeners.forEach(listener => {
  listener.onMedicineUpdated?.(medicine);
});

private notifyMedicineRemoved(medicineId: string): void {

this.listeners.forEach(listener => {
  listener.onMedicineRemoved?.(medicineId);
});

private notifyPlanUpdated(plan: MedicationPlan): void {

this.listeners.forEach(listener => {
  listener.onPlanUpdated?.(plan);
});

private notifyReminderUpdated(update: ReminderUpdate): void {

this.listeners.forEach(listener => {
  listener.onReminderUpdated?.(update);
});

public addListener(listener: MedicationListener): void {

if (!this.listeners.includes(listener)) {
  this.listeners.push(listener);

}

public removeListener(listener: MedicationListener): void {
this.listeners = this.listeners.filter(l => l !== listener);
}

interface MedicationListener {
onMedicineUpdated?(medicine: Medicine): void;
onMedicineRemoved?(medicineId: string): void;
onPlanUpdated?(plan: MedicationPlan): void;
onReminderUpdated?(update: ReminderUpdate): void;
interface ReminderUpdate {

reminderId: string;
status: ‘pending’ ‘taken’
‘skipped’;
takenTime?: number;
export const medicationService = MedicationService.getInstance();

主界面实现

// MainScreen.ets
import { medicationService } from ‘./MedicationService’;
import { Medicine, MedicationPlan, Reminder } from ‘./MedicationTypes’;

@Component
export struct MainScreen {
@State hasPermission: boolean = false;
@State medicines: Medicine[] = [];
@State plans: MedicationPlan[] = [];
@State showAddMedicineDialog: boolean = false;
@State showAddPlanDialog: boolean = false;
@State newMedicine: Medicine = this.createEmptyMedicine();
@State newPlan: MedicationPlan = this.createEmptyPlan();
@State selectedTab: ‘medicines’ ‘plans’
‘history’ = ‘medicines’;

build() {
Column() {
// 标题栏
Row() {
Text(‘家庭用药管理’)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)

    Button(this.hasPermission ? '添加' : '授权')
      .width(80)
      .onClick(() => {
        if (this.hasPermission) {
          this.showAddDialog();

else {

          this.requestPermissions();

})

.padding(10)

  .width('100%')
  
  // 标签栏
  Tabs({ barPosition: BarPosition.Start }) {
    TabContent() {
      // 药品列表
      this.buildMedicinesView()
    }.tabBar('药品')
    
    TabContent() {
      // 服药计划
      this.buildPlansView()
    }.tabBar('计划')
    
    TabContent() {
      // 服药历史
      this.buildHistoryView()
    }.tabBar('历史')

.index(this.getTabIndex())

  .vertical(false)
  .barWidth('100%')
  .barHeight(40)
  .onChange((index: number) => {
    this.selectedTab = ['medicines', 'plans', 'history'][index] as 'medicines' 'plans'

‘history’;
})
.width(‘100%’)

.height('100%')
.padding(20)

// 添加药品对话框
if (this.showAddMedicineDialog) {
  DialogComponent({
    title: '添加药品',
    content: this.buildMedicineDialogContent(),
    confirm: {
      value: '添加',
      action: () => this.addMedicine()
    },
    cancel: {
      value: '取消',
      action: () => {
        this.showAddMedicineDialog = false;
        this.newMedicine = this.createEmptyMedicine();

}

  })

// 添加计划对话框

if (this.showAddPlanDialog) {
  DialogComponent({
    title: '添加服药计划',
    content: this.buildPlanDialogContent(),
    confirm: {
      value: '添加',
      action: () => this.addPlan()
    },
    cancel: {
      value: '取消',
      action: () => {
        this.showAddPlanDialog = false;
        this.newPlan = this.createEmptyPlan();

}

  })

}

private buildMedicinesView(): void {
if (this.medicines.length === 0) {
Column() {
Text(‘暂无药品’)
.fontSize(18)
.margin({ bottom: 10 })

    Text('点击"添加"按钮添加您的药品')
      .fontSize(16)
      .fontColor('#666666')

.padding(20)

  .width('90%')
  .backgroundColor('#F5F5F5')
  .borderRadius(8)
  .margin({ top: 50 })

else {

  List({ space: 10 }) {
    ForEach(this.medicines, (medicine) => {
      ListItem() {
        Row() {
          Image(medicine.image || $r('app.media.ic_pill'))
            .width(50)
            .height(50)
            .margin({ right: 15 })
          
          Column() {
            Text(medicine.name)
              .fontSize(16)
              .fontWeight(FontWeight.Bold)
              .margin({ bottom: 5 })
            
            Row() {
              Text(剂量: ${medicine.dosage})
                .fontSize(14)
                .fontColor('#666666')
                .margin({ right: 15 })
              
              Text(剩余: {medicine.remaining}{medicine.unit})
                .fontSize(14)
                .fontColor('#666666')

}

          .layoutWeight(1)

.padding(10)

        .width('100%')

.onClick(() => {

        this.showMedicineDetails(medicine);
      })
    })

.height(‘80%’)

}

private buildPlansView(): void {
if (this.plans.length === 0) {
Column() {
Text(‘暂无服药计划’)
.fontSize(18)
.margin({ bottom: 10 })

    Text('点击"添加"按钮创建服药计划')
      .fontSize(16)
      .fontColor('#666666')

.padding(20)

  .width('90%')
  .backgroundColor('#F5F5F5')
  .borderRadius(8)
  .margin({ top: 50 })

else {

  Column() {
    // 今日提醒
    Column() {
      Text('今日提醒')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 10 })
      
      if (this.getTodayReminders().length === 0) {
        Text('今日没有服药提醒')
          .fontSize(16)
          .fontColor('#666666')
          .padding(15)
          .backgroundColor('#FFFFFF')
          .borderRadius(8)

else {

        List({ space: 5 }) {
          ForEach(this.getTodayReminders(), (reminder) => {
            ListItem() {
              this.buildReminderItem(reminder)

})

.height(150)

}

    .margin({ bottom: 20 })
    
    // 服药计划列表
    Text('所有服药计划')
      .fontSize(18)
      .fontWeight(FontWeight.Bold)
      .margin({ bottom: 10 })
    
    List({ space: 10 }) {
      ForEach(this.plans, (plan) => {
        ListItem() {
          this.buildPlanItem(plan)

})

.height(300)

.width(‘100%’)

}

private buildHistoryView(): void {
const history = this.getHistoryRecords();

if (history.length === 0) {
  Column() {
    Text('暂无服药记录')
      .fontSize(18)
      .margin({ bottom: 10 })
    
    Text('服药记录将显示在这里')
      .fontSize(16)
      .fontColor('#666666')

.padding(20)

  .width('90%')
  .backgroundColor('#F5F5F5')
  .borderRadius(8)
  .margin({ top: 50 })

else {

  List({ space: 10 }) {
    ForEach(history, (record) => {
      ListItem() {
        Row() {
          Column() {
            Text(this.getMedicineName(record.medicineId))
              .fontSize(16)
              .fontWeight(FontWeight.Bold)
              .margin({ bottom: 5 })
            
            Text(this.formatDateTime(record.takenTime))
              .fontSize(14)
              .fontColor('#666666')

.layoutWeight(1)

          Text('已服用')
            .fontSize(14)
            .fontColor('#4CAF50')

.padding(10)

        .width('100%')

})

.height(‘80%’)

}

private buildReminderItem(reminder: Reminder): void {
const medicine = this.medicines.find(m => m.id === reminder.medicineId);

Row() {
  Column() {
    Text(medicine?.name || '未知药品')
      .fontSize(16)
      .fontWeight(FontWeight.Bold)
      .margin({ bottom: 5 })
    
    Text({this.formatTime(reminder.scheduledTime)} - {medicine?.dosage || ''})
      .fontSize(14)
      .fontColor('#666666')

.layoutWeight(1)

  if (reminder.status === 'pending') {
    Row() {
      Button('服用')
        .width(80)
        .height(30)
        .fontSize(14)
        .onClick(() => {
          medicationService.markAsTaken(reminder.id);
        })
      
      Button('跳过')
        .width(80)
        .height(30)
        .fontSize(14)
        .margin({ left: 10 })
        .onClick(() => {
          medicationService.skipReminder(reminder.id);
        })

} else if (reminder.status === ‘taken’) {

    Text('已服用')
      .fontSize(14)
      .fontColor('#4CAF50')

else {

    Text('已跳过')
      .fontSize(14)
      .fontColor('#F44336')

}

.padding(15)
.width('100%')
.backgroundColor('#FFFFFF')
.borderRadius(8)

private buildPlanItem(plan: MedicationPlan): void {

const medicine = this.medicines.find(m => m.id === plan.medicineId);

Row() {
  Image(medicine?.image || $r('app.media.ic_pill'))
    .width(50)
    .height(50)
    .margin({ right: 15 })
  
  Column() {
    Text(medicine?.name || '未知药品')
      .fontSize(16)
      .fontWeight(FontWeight.Bold)
      .margin({ bottom: 5 })
    
    Text(每日 ${plan.times.join(', ')})
      .fontSize(14)
      .fontColor('#666666')
      .margin({ bottom: 5 })
    
    Text({this.formatDate(plan.startDate)} 至 {this.formatDate(plan.endDate)})
      .fontSize(14)
      .fontColor('#666666')

.layoutWeight(1)

.padding(10)

.width('100%')
.backgroundColor('#FFFFFF')
.borderRadius(8)

private buildMedicineDialogContent(): void {

Column() {
  TextInput({ placeholder: '药品名称', text: this.newMedicine.name })
    .onChange((value: string) => {
      this.newMedicine.name = value;
    })
    .margin({ bottom: 15 })
  
  TextInput({ placeholder: '剂量 (如: 1片, 10ml)', text: this.newMedicine.dosage })
    .onChange((value: string) => {
      this.newMedicine.dosage = value;
    })
    .margin({ bottom: 15 })
  
  Row() {
    TextInput({ placeholder: '剩余数量', text: this.newMedicine.remaining.toString() })
      .onChange((value: string) => {
        this.newMedicine.remaining = parseInt(value) || 0;
      })
      .layoutWeight(1)
    
    TextInput({ placeholder: '单位 (如: 片, 瓶)', text: this.newMedicine.unit })
      .onChange((value: string) => {
        this.newMedicine.unit = value;
      })
      .margin({ left: 15 })
      .width(100)

.margin({ bottom: 15 })

  Button('选择图片')
    .width(200)
    .onClick(() => {
      this.pickMedicineImage();
    })

.padding(20)

private buildPlanDialogContent(): void {

Column() {
  // 选择药品
  Row() {
    Text('药品:')
      .fontSize(16)
      .margin({ right: 15 })
    
    if (this.newPlan.medicineId) {
      const medicine = this.medicines.find(m => m.id === this.newPlan.medicineId);
      
      Chip({
        label: medicine?.name || '未知药品',
        selected: true,
        selectIcon: false
      })
      .onClick(() => {
        this.showMedicinePicker = true;
      })

else {

      Button('选择药品')
        .onClick(() => {
          this.showMedicinePicker = true;
        })

}

  .margin({ bottom: 20 })
  
  // 服药时间
  Column() {
    Text('服药时间:')
      .fontSize(16)
      .margin({ bottom: 10 })
    
    ForEach(this.newPlan.times, (time, index) => {
      Row() {
        TimePicker({
          selected: new Date(1970/01/01 ${time}),
          onTimeChange: (value: Date) => {
            this.updatePlanTime(index, value);

})

        if (this.newPlan.times.length > 1) {
          Button($r('app.media.ic_delete'))
            .width(30)
            .height(30)
            .margin({ left: 10 })
            .onClick(() => {
              this.removePlanTime(index);
            })

}

      .margin({ bottom: 10 })
    })
    
    Button('添加时间')
      .width(120)
      .onClick(() => {
        this.addPlanTime();
      })

.margin({ bottom: 20 })

  // 计划日期
  Row() {
    Column() {
      Text('开始日期:')
        .fontSize(16)
        .margin({ bottom: 5 })
      
      DatePicker({
        selected: new Date(this.newPlan.startDate),
        onDateChange: (value: Date) => {
          this.newPlan.startDate = value.getTime();

})

.layoutWeight(1)

    Column() {
      Text('结束日期:')
        .fontSize(16)
        .margin({ bottom: 5 })
      
      DatePicker({
        selected: new Date(this.newPlan.endDate),
        onDateChange: (value: Date) => {
          this.newPlan.endDate = value.getTime();

})

.layoutWeight(1)

    .margin({ left: 20 })

}

.padding(20)

private createEmptyMedicine(): Medicine {

return {
  id: '',
  name: '',
  dosage: '',
  remaining: 0,
  unit: '片',
  image: undefined,
  createdAt: 0
};

private createEmptyPlan(): MedicationPlan {

return {
  id: '',
  medicineId: '',
  times: ['08:00'],
  startDate: Date.now(),
  endDate: Date.now() + 7  24  60  60  1000, // 默认一周
  reminders: [],
  createdAt: 0
};

private getTabIndex(): number {

switch (this.selectedTab) {
  case 'medicines': return 0;
  case 'plans': return 1;
  case 'history': return 2;
  default: return 0;

}

private getTodayReminders(): Reminder[] {
const today = new Date();
today.setHours(0, 0, 0, 0);
const tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);

return this.plans.flatMap(plan => 
  plan.reminders.filter(r => 
    r.scheduledTime >= today.getTime() && 
    r.scheduledTime < tomorrow.getTime()
  )
);

private getHistoryRecords(): Reminder[] {

return this.plans.flatMap(plan => 
  plan.reminders.filter(r => r.status === 'taken')
).sort((a, b) => b.takenTime! - a.takenTime!);

private getMedicineName(medicineId: string): string {

return this.medicines.find(m => m.id === medicineId)?.name || '未知药品';

private formatTime(timestamp: number): string {

const date = new Date(timestamp);
return {date.getHours().toString().padStart(2, '0')}:{date.getMinutes().toString().padStart(2, '0')};

private formatDate(timestamp: number): string {

const date = new Date(timestamp);
return {date.getFullYear()}/{date.getMonth() + 1}/${date.getDate()};

private formatDateTime(timestamp: number): string {

const date = new Date(timestamp);
return {date.getFullYear()}/{date.getMonth() + 1}/{date.getDate()} {date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')};

private updatePlanTime(index: number, time: Date): void {

const newTimes = [...this.newPlan.times];
newTimes[index] = {time.getHours().toString().padStart(2, '0')}:{time.getMinutes().toString().padStart(2, '0')};
this.newPlan.times = newTimes;

private addPlanTime(): void {

this.newPlan.times = [...this.newPlan.times, '08:00'];

private removePlanTime(index: number): void {

const newTimes = [...this.newPlan.times];
newTimes.splice(index, 1);
this.newPlan.times = newTimes;

aboutToAppear() {

this.checkPermissions();
medicationService.addListener({
  onMedicineUpdated: (medicine) => {
    this.handleMedicineUpdated(medicine);
  },
  onMedicineRemoved: (medicineId) => {
    this.handleMedicineRemoved(medicineId);
  },
  onPlanUpdated: (plan) => {
    this.handlePlanUpdated(plan);
  },
  onReminderUpdated: (update) => {
    this.handleReminderUpdated(update);

});

aboutToDisappear() {

medicationService.removeListener({
  onMedicineUpdated: (medicine) => {
    this.handleMedicineUpdated(medicine);
  },
  onMedicineRemoved: (medicineId) => {
    this.handleMedicineRemoved(medicineId);
  },
  onPlanUpdated: (plan) => {
    this.handlePlanUpdated(plan);
  },
  onReminderUpdated: (update) => {
    this.handleReminderUpdated(update);

});

private async checkPermissions(): Promise<void> {

try {
  const permissions = [
    'ohos.permission.NOTIFICATION',
    'ohos.permission.DISTRIBUTED_DATASYNC'
  ];
  
  const result = await abilityAccessCtrl.verifyPermissions(
    getContext(),
    permissions
  );
  
  this.hasPermission = result.every(perm => perm.granted);

catch (err) {

  console.error('检查权限失败:', JSON.stringify(err));
  this.hasPermission = false;

}

private async requestPermissions(): Promise<void> {
this.hasPermission = await medicationService.requestPermissions();

if (!this.hasPermission) {
  prompt.showToast({ message: '授权失败,无法使用提醒功能' });

}

private showAddDialog(): void {
if (this.selectedTab === ‘medicines’) {
this.showAddMedicineDialog = true;
else if (this.selectedTab === ‘plans’) {

  if (this.medicines.length === 0) {
    prompt.showToast({ message: '请先添加药品' });

else {

    this.newPlan = this.createEmptyPlan();
    this.showAddPlanDialog = true;

}

private async addMedicine(): Promise<void> {

if (!this.newMedicine.name.trim()) {
  prompt.showToast({ message: '请输入药品名称' });
  return;

if (!this.newMedicine.dosage.trim()) {

  prompt.showToast({ message: '请输入药品剂量' });
  return;

try {

  await medicationService.addMedicine(this.newMedicine);
  this.showAddMedicineDialog = false;
  this.newMedicine = this.createEmptyMedicine();

catch (err) {

  console.error('添加药品失败:', JSON.stringify(err));
  prompt.showToast({ message: '添加药品失败,请重试' });

}

private async addPlan(): Promise<void> {
if (!this.newPlan.medicineId) {
prompt.showToast({ message: ‘请选择药品’ });
return;
if (this.newPlan.times.length === 0) {

  prompt.showToast({ message: '请至少添加一个服药时间' });
  return;

try {

  await medicationService.addMedicationPlan(this.newPlan);
  this.showAddPlanDialog = false;
  this.newPlan = this.createEmptyPlan();

catch (err) {

  console.error('添加计划失败:', JSON.stringify(err));
  prompt.showToast({ message: '添加计划失败,请重试' });

}

private async pickMedicineImage(): Promise<void> {
try {
const picker = new photo.Picker();
const result = await picker.select({
type: photo.PickerType.IMAGE,
maxSelectNumber: 1
});

  if (result.photoUris.length > 0) {
    const file = await fileIo.open(result.photoUris[0], fileIo.OpenMode.READ_ONLY);
    const buffer = await fileIo.read(file.fd, { length: 0 });
    await fileIo.close(file.fd);
    
    this.newMedicine.image = buffer.buffer;

} catch (err) {

  console.error('选择图片失败:', JSON.stringify(err));
  prompt.showToast({ message: '选择图片失败,请重试' });

}

private showMedicineDetails(medicine: Medicine): void {
// 导航到药品详情页面
router.push({
url: ‘pages/MedicineDetail’,
params: { medicineId: medicine.id }
});
private handleMedicineUpdated(medicine: Medicine): void {

const existingIndex = this.medicines.findIndex(m => m.id === medicine.id);

if (existingIndex >= 0) {
  this.medicines[existingIndex] = medicine;

else {

  this.medicines = [...this.medicines, medicine];

}

private handleMedicineRemoved(medicineId: string): void {
this.medicines = this.medicines.filter(m => m.id !== medicineId);
this.plans = this.plans.filter(p => p.medicineId !== medicineId);
private handlePlanUpdated(plan: MedicationPlan): void {

const existingIndex = this.plans.findIndex(p => p.id === plan.id);

if (existingIndex >= 0) {
  this.plans[existingIndex] = plan;

else {

  this.plans = [...this.plans, plan];

}

private handleReminderUpdated(update: ReminderUpdate): void {
this.plans = this.plans.map(plan => ({
…plan,
reminders: plan.reminders.map(r =>
r.id === update.reminderId ? { …r, status: update.status, takenTime: update.takenTime || null } : r
)
}));
}

类型定义

// MedicationTypes.ets
export interface Medicine {
id: string;
name: string;
dosage: string;
remaining: number;
unit: string;
image?: ArrayBuffer;
createdAt: number;
export interface MedicationPlan {

id: string;
medicineId: string;
times: string[]; // 格式: “08:00”
startDate: number; // 时间戳
endDate: number; // 时间戳
reminders: Reminder[];
createdAt: number;
export interface Reminder {

id: string;
planId: string;
medicineId: string;
scheduledTime: number; // 时间戳
status: ‘pending’ ‘taken’
‘skipped’;
takenTime?: number; // 时间戳

三、项目配置与权限
权限配置

// module.json5
“module”: {

"requestPermissions": [

“name”: “ohos.permission.NOTIFICATION”,

    "reason": "发送服药提醒通知"
  },

“name”: “ohos.permission.DISTRIBUTED_DATASYNC”,

    "reason": "同步药品数据和提醒状态"

],

"abilities": [

“name”: “MainAbility”,

    "type": "page",
    "visible": true

]

}

四、总结与扩展

本家庭用药管理系统实现了以下核心功能:
药品管理:记录药品信息和剩余数量

智能提醒:按计划定时提醒服药

服药记录:记录服药历史和状态

多设备同步:家庭成员间共享药品数据和提醒

扩展方向:
药品库存预警:药品不足时自动提醒

药品相互作用检查:检查药品组合安全性

处方药管理:管理医生处方和用药指导

健康数据整合:与健康监测设备数据关联

语音提醒:支持语音播报提醒

紧急联系人通知:漏服时通知家人

通过HarmonyOS的分布式技术,我们构建了一个智能化的家庭用药管理系统,帮助用户科学管理服药计划,提高用药安全性,并在家庭成员间实现用药信息的无缝同步。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐