
鸿蒙跨端家庭用药管理系统开发指南 原创
鸿蒙跨端家庭用药管理系统开发指南
一、系统架构设计
基于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的分布式技术,我们构建了一个智能化的家庭用药管理系统,帮助用户科学管理服药计划,提高用药安全性,并在家庭成员间实现用药信息的无缝同步。
