十三、实现任务添加到数据库
创建任务类RecordVO
和成就页面数据类KeepInfo
// 定义一个名为RecordVO的视图模型类,默认导出
export default class RecordVO {
// 记录ID,唯一标识一条记录
id: number;
// 运动ID,关联到具体的运动项目
keepId: number;
// 消耗卡路里,表示该运动项目每单位时间或次数消耗的卡路里
calorie: number;
// 记录运动信息,包含运动项目的名称、图片、单位等信息
recordItem: RecordItem;
// 运动时长或个数,表示用户计划完成的运动时长或次数
amount: number = 0;
// 已完成运动时长或个数,表示用户实际完成的运动时长或次数
successAmount: number = 0;
// 记录日期,表示该记录创建或更新的日期
createTime: number;
// 类的构造函数,用于初始化RecordVO实例
constructor(id: number, keepId: number, calorie: number,
amount: number, successAmount: number, createTime: number) {
this.id = id; // 初始化记录ID
this.keepId = keepId; // 初始化运动ID
this.calorie = calorie; // 初始化消耗卡路里
this.amount = amount; // 初始化计划运动时长或个数
this.successAmount = successAmount; // 初始化已完成运动时长或个数
this.createTime = createTime; // 初始化记录日期
// 根据keepId初始化recordItem属性,从RecordItemModel中获取具体的运动项目信息
this.recordItem = RecordItemModel.getById(this.keepId);
}
}
// 定义一个名为KeepInfo的类,默认导出
export default class KeepInfo {
// 日期,表示记录的日期
day: number = 0;
// 当日消耗卡路里,表示用户在那一天消耗的总卡路里数
expend: number = 0;
// 当日任务总数,表示用户在那一天设定的所有任务数量
task: number = 0;
// 当日完成任务数量,表示用户在那一天实际完成的任务数量
successTask: number = 0;
// 是否全部完成,表示用户在那一天是否完成了所有任务
isSuccess: boolean = false;
// 类的构造函数,用于初始化KeepInfo实例
constructor(day: number = 0, expend: number = 0, task: number = 0, successTask: number = 0) {
this.day = day; // 初始化日期
this.expend = expend; // 初始化消耗的卡路里
this.task = task; // 初始化任务总数
this.successTask = successTask; // 初始化完成的任务数量
// 根据任务总数和完成数判断是否全部完成,并设置isSuccess状态
if(this.successTask === this.task && this.task !== 0) {
this.isSuccess = true;
}
}
}//通过实例化 KeepInfo 类并设置相应的属性,可以记录用户每天的健身数据,并判断用户是否完成了当天设定的所有健身任务。
完成业务逻辑类KeepService
class KeepService {
// 插入新的运动记录
insert(keepId: number, amount: number) {
let createTime = (AppStorage.Get('selectedDate') || DateUtil.beginTimeOfDay(new Date())) as number // 获取当前选中的日期或当天的开始时间作为创建时间
return RecordModel.insert({keepId: keepId, amount: amount, createTime: createTime, successAmount: 0}) // 调用 RecordModel 的 insert 方法添加记录
}
// 根据ID删除运动记录
deleteById(id: number) {
return RecordModel.delete(id) // 调用 RecordModel 的 delete 方法根据ID删除记录
}
// 更新运动记录信息
update(record: RecordVO) {
return RecordModel.update({
id: record.id, keepId: record.keepId, amount: record.amount,
successAmount: record.successAmount, createTime: record.createTime
}, record.id) // 调用 RecordModel 的 update 方法更新记录
}
// 查询所有运动记录并转换为 RecordVO 数组
async selectAllRecord(): Promise<RecordVO[]> {
let rps = await RecordModel.queryAll() // 调用 RecordModel 的 queryAll 方法查询所有记录
return rps.map(rp => {
// 将 RecordPO 对象转换为 RecordVO 对象,并添加额外信息
let rv = {
id: rp.id, keepId: rp.keepId, amount: rp.amount, successAmount: rp.successAmount, createTime: rp.createTime
} as RecordVO
rv.recordItem = RecordItemModel.getById(rp.keepId) // 根据 keepId 查询运动项目信息
rv.calorie = rp.amount * rv.recordItem.calorie // 计算卡路里消耗
return rv
})
}
// 根据日期查询运动记录并转换为 RecordVO 数组
async selectRecordByDate(date: number): Promise<RecordVO[]> {
let rps = await RecordModel.queryByDate(date) // 调用 RecordModel 的 queryByDate 方法按日期查询记录
return rps.map(rp => {
let rv = {
id: rp.id, keepId: rp.keepId, amount: rp.amount, successAmount: rp.successAmount, createTime: rp.createTime
} as RecordVO
rv.recordItem = RecordItemModel.getById(rp.keepId) // 查询运动项目信息
rv.calorie = rp.amount * rv.recordItem.calorie // 计算卡路里消耗
return rv
})
}
// 根据记录数组计算运动统计信息
calculateKeepInfo(records: RecordVO[]): KeepInfo {
let info = new KeepInfo() // 创建 KeepInfo 实例
if(!records || records.length <= 0) {
return info // 如果记录数组为空,直接返回
}
info.task = records.length // 设置总任务数
records.forEach(rv => {
if(rv.amount !== 0 && rv.successAmount === rv.amount) {
info.successTask += 1 // 如果完成量等于计划量,增加成功任务数
}
info.expend += rv.calorie // 累加消耗的卡路里
info.day = rv.createTime // 设置任务日期
})
if(info.task === info.successTask && info.task !== 0) {
info.isSuccess = true // 如果成功任务数等于总任务数,设置为完成任务
}
Logger.debug(info.task + '/' + info.successTask + ',任务时间:' + info.day + ', 总任务/已完成任务') // 记录日志
return info // 返回计算后的 KeepInfo 实例
}
}
// 创建 KeepService 类的实例并导出为默认
let keepService = new KeepService();
export default keepService as KeepService;
十三、成就页面数据部分
提示:
1. `RecordVO`中存有运动个数和已完成个数 2. `KeepInfo`中存有是否完成当天任务的属性注意:
变量的装饰器,需要父子组件双向传递的要用到
@Link
装饰器,父向子单向传递要使用@Prop
装饰器;传递参数时的格式也要注意。
export default class AchievementInfo {
// 成就所需的连续完成任务的天数
days: number;
// 表示成就已达成时显示的图标资源字符串
icOn: ResourceStr;
// 表示成就未达成时显示的图标资源字符串
icOff: ResourceStr;
// 类的构造函数,用于初始化 AchievementInfo 实例
constructor(days: number, icOn: ResourceStr, icOff: ResourceStr) {
// 将传入的参数赋值给实例变量
this.days = days;
this.icOn = icOn;
this.icOff = icOff;
}
}
整个项目用到的关键技术:
- 生命周期方法:使用 @Watch 装饰器监听组件的生命周期方法,aboutToAppear 和 onRecordsChange,以处理数据加载和状态更新。
- 异步数据加载:通过 KeepService 服务的异步方法 selectRecordByDate 和 selectAllRecord 加载数据,并使用 await 关键字等待数据加载完成。
- 日志记录:使用 Logger 工具记录应用程序的运行时信息,有助于调试和监控应用程序的行为。
- 条件渲染:在构建 UI 时,根据状态和数据条件渲染不同的 UI 元素,例如根据 successDays 判断显示成就解锁图标或未解锁图标。
- 事件处理:
- 为组件添加事件处理器,如 onClick 处理用户点击事件,onRefreshing 处理下拉刷新事件。
- 自定义组件:定义和使用自定义组件 AchievementTop 来展示特定的 UI 布局和信息。
- 资源引用:使用 $r 函数引用应用程序资源,如图标和颜色,以便于管理和维护。
- 布局和样式:使用 Column、Row、Flex 等布局组件来创建复杂的用户界面布局,并使用内边距、宽度、高度、圆角等样式属性来美化界面。
- 数据模型:使用 RecordVO 和 KeepInfo 等数据模型来组织和表示应用程序的数据结构。
- 服务层抽象:通过 KeepService 类抽象了数据操作逻辑,与后端数据模型 RecordItemModel 分离,提高了代码的模块化和可维护性。
- 日期和时间处理:使用 DateUtil 工具类处理日期和时间相关的逻辑,如获取一天的开始时间或格式化日期显示。
- 主要页面展示: