#我的鸿蒙开发手记#鸿蒙待办事项开发实现 原创

翰龙GH
发布于 2025-5-6 09:33
浏览
0收藏

一、介绍与准备
1.整体介绍
本项目是鸿蒙待办事项的开发过程。其应用整体构建布局设计中,模块设计包含了待办模块等。待办模块拥有独立的入口 UI,主入口页面借助底部导航栏来切换不同功能模块。项目重点描述了待办功能模块的实现,其 UI 结构由待办列表页、任务详情页、新增 / 编辑页等核心组件构成,待办列表页可分栏展示 “待处理” 与 “已处理” 任务,并支持搜索与筛选功能;任务详情页用于显示任务的详细描述、附件、子任务及相应的操作按钮;新增 / 编辑页则提供表单输入、附件上传及子任务添加等功能。在根目录 OfficeAttendance 下创建 scenes 场景文件目录后,实现了任务的展示、搜索、筛选、添加、编辑、删除以及侧滑删除等丰富功能,为用户打造出便捷的待办事项管理工具。
2.基础准备
(1)设备类型:华为手机(直板机)
(2)HarmonyOS版本:HarmonyOS 5.0.0 Release及以上
(3)DevEco Studio版本:DevEco Studio 5.0.0 Release及以上
(4)HarmonyOS SDK版本:HarmonyOS 5.0.0 Release SDK及以上
二、应用整体构建布局设计
1.模块设计
打卡模块:CheckInView.ets
三、待办入口UI实现
(1)products产品层下的pages>MainEntry.ets关键代码实现:

// 导入模块:底部导航配置、各功能模块视图、类型定义等
import { TAB_LIST } from '../constants/Constants';
import { AgencyTaskView } from '@ohos_agcit/office_attendance_agency';
import { ScheduleView } from '@ohos_agcit/office_attendance_schedule';
import { TabListItem } from '@ohos_agcit/office_attendance_agency';
import { CheckInView } from '@ohos_agcit/office_attendance_checkin';
import { CommonConstants, MainEntryVM } from '@ohos_agcit/office_attendance_common_lib';
import { MineView } from '@ohos_agcit/office_attendance_account';
import { router } from '@kit.ArkUI';

// --------------------------
// 主入口页面构建器(供外部调用)
// --------------------------
@Builder
export function mainEntryBuilder() {
  MainEntry();
}
@Entry // 标记为应用入口组件
@ComponentV2 // 声明为ArkUI V2版本组件
struct MainEntry {
  // 路由管理单例
  vm: MainEntryVM = MainEntryVM.instance;
  
  // 页面状态控制
  @Provider() isPageShow: boolean = false; // 页面是否显示
  @Provider() currentTabIndex: number = this.vm.curIndex; // 当前选中Tab索引
  onPageShow(): void {
    this.isPageShow = true; // 页面显示时更新状态
  }

  onPageHide(): void {
    this.isPageShow = false; // 页面隐藏时更新状态
  }
  build() {
    Navigation(this.vm.navStack) { // 导航容器(管理页面堆栈)
      // 底部导航栏配置
      Tabs({ 
        barPosition: BarPosition.End, // 导航栏位置(底部)
        index: this.vm.curIndex // 当前选中索引
      }) {
        // Tab1: 考勤打卡模块
        TabContent() {
          CheckInView(); // 加载打卡组件
        }
        .tabBar(this.tabBarBuilder(TAB_LIST[0], 0)); // 绑定导航栏样式

        // Tab2: 待办任务模块
        TabContent() {
          AgencyTaskView(); // 加载待办组件
        }
        .tabBar(this.tabBarBuilder(TAB_LIST[1], 1));

        // Tab3: 日程管理模块
        TabContent() {
          //ScheduleView(); // 加载日程组件
        }
        .tabBar(this.tabBarBuilder(TAB_LIST[2], 2));

        // Tab4: 个人中心模块
        TabContent() {
          //MineView({ // 加载个人中心组件
          //  callback: () => { // 退出登录回调
          //    router.replaceUrl({ url: 'pages/Login' }) // 跳转登录页
          //  }
          });
        }
        .tabBar(this.tabBarBuilder(TAB_LIST[3], 3));
      }
      // 导航栏样式配置
      .scrollable(false) // 禁止滑动切换
      .barHeight(80) // 导航栏高度
      .height(CommonConstants.FULL_HEIGHT) // 全屏高度
      .animationDuration(0) // 禁用切换动画
      .barMode(BarMode.Fixed) // 固定模式(不随内容滚动)
      .onChange((index: number) => { // Tab切换事件
        this.vm.curIndex = index; // 更新路由管理状态
        this.currentTabIndex = index; // 更新当前索引
      });
    }
    // 导航栏标题配置
    .title({ 
      builder: this.titleBuilder(TAB_LIST[this.vm.curIndex]), // 动态标题
      height: 92 // 标题栏高度
    })
    .mode(NavigationMode.Stack) // 堆栈导航模式
  }
  @Builder
  titleBuilder(title: TabListItem) {
    Row() {
      Text(title.label) // 显示当前模块名称
        .fontWeight(FontWeight.Bold) // 加粗
        .fontColor('rgba(0,0,0,0.90)') // 字体颜色
        .fontSize($r('app.float.navigation_title_font_size')) // 字体大小(资源引用)
        .margin({ left: 16, top: 36 }) // 边距
        .height(56) // 高度
    }
    .justifyContent(FlexAlign.Start) // 左对齐
    .backgroundColor(title.titleBackgroundColor) // 背景色(动态配置)
    .width('100%') // 全宽
    .height('100%') // 全高
    .alignItems(VerticalAlign.Bottom) // 垂直底部对齐
  }

  // --------------------------
  // 底部导航栏Item构建器
  // --------------------------
  @Builder
  tabBarBuilder(item: TabListItem, index: number) {
    Column() { // 垂直布局
      // 动态显示选中/未选中图标
      Image(this.vm.curIndex === index ? item.iconChecked : item.icon)
        .width($r('app.float.navigation_image_size')) // 图标宽度(资源引用)
        .height($r('app.float.navigation_image_size')) // 图标高度
        .margin({ top: $r('app.string.margin_xs') }); // 上边距
      
      // Tab文字标签
      Text(item.label)
        .fontColor(this.vm.curIndex === index ? 
          $r('app.color.icon_color_highlight') : // 选中高亮色
          $r('app.color.icon_color_level2')) // 未选中默认色
        .fontSize($r('app.float.navigation_navi_size')) // 字体大小
        .height(14) // 固定高度
        .margin({ 
          top: $r('app.string.margin_xs'), 
          bottom: $r('app.string.margin_xs') 
        });
    }
    .height(80) // 固定高度
    .width('100%') // 全宽
    .justifyContent(FlexAlign.Start); // 顶部对齐
  }
}

四、待办功能模块与实现流程
1.待办模块UI结构设计
待办由以下核心组件构成:
·待办列表页:分栏展示“待处理”与“已处理”任务,支持搜索与筛选;
·任务详情页:显示任务描述、附件、子任务及操作按钮;
·新增/编辑页:提供表单输入、附件上传及子任务添加功能。
2.功能实现步骤
(1)AgencyTaskView.ets文件创建与实现代码:
①在根目录OfficeAttendance下创建scenes场景文件目录
②在scenes目录下创建agency模块(HSP动态共享)

#我的鸿蒙开发手记#鸿蒙待办事项开发实现-鸿蒙开发者社区
③AgencyTaskView.ets代码实现:

// 导入任务项类型定义、列表项组件和基础工具模块
import { TaskItem } from '../types/Types'
import { AgencyTaskListItem } from './AgencyTaskListItem';
import {
  CommonConstants,
  AppStorageData,
  RouterModule,
  DialogMap,
  MainEntryVM
} from '@ohos_agcit/office_attendance_common_lib';
import { AppStorageV2, promptAction } from '@kit.ArkUI';
import { RequestProxy } from '../api/RequestProxy';
import { ConfirmView } from '@ohos_agcit/office_attendance_component_lib';
@ComponentV2
export struct AgencyTaskView {
  // 状态管理
  vm: MainEntryVM = MainEntryVM.instance; // 路由管理单例
  private controller: Scroller = new Scroller(); // 列表滚动控制器
  @Local myStorage: AppStorageData = // 应用存储数据
    AppStorageV2.connect(AppStorageData, CommonConstants.APP_STORAGE_DATA_KEY, () => new AppStorageData())!;
  @Local agencyTasks: TaskItem[] = []; // 待办任务列表数据
  @Local selectIdx: number = 0; // 当前选中的Tab索引(0-未完成,1-已完成)
  @Local searchTxt: string = ''; // 搜索关键词
  taskID: string | undefined; // 当前操作的任务ID
  public newAgencyTask() {
    RouterModule.openDialog(DialogMap.NEW_AGENCY_TASK, {
      onPop: () => { this.load(); } // 弹窗关闭后刷新数据
    });
  }

  // --------------------------
  // 生命周期方法
  // --------------------------
  aboutToAppear(): void {
    this.load(); // 初始化加载数据
  }
  // 编辑任务
  edit(item: TaskItem) {
    RequestProxy.editTask(item).then(resp => {
      promptAction.showToast({ message: $r('app.string.edit_success') }) // 显示操作提示
    });
  }

  // 加载任务数据
  load() {
    let isQueryFinishedTask = this.selectIdx === 1; // 根据Tab决定查询类型
    this.agencyTasks.length = 0; // 清空当前数据
    RequestProxy.queryTasks(this.searchTxt, isQueryFinishedTask).then((data) => {
      data.forEach(t => { this.agencyTasks.push(t); }) // 填充新数据
    })
  }

  // 执行搜索
  search() {
    this.load();
  }

  // 辅助方法
  isUnfinishedPage() { return this.selectIdx === 0; } // 是否未完成页
  isEmptyTasks() { return this.agencyTasks.length === 0; } // 是否无数据

  // --------------------------
  // 删除确认弹窗
  // --------------------------
  private dController: CustomDialogController = new CustomDialogController({
    builder: ConfirmView({ // 自定义确认弹窗
      titleResID: $r('app.string.delete_agency_title'), // 标题资源
      contentResID: $r('app.string.delete_agency_content'), // 内容资源
      btnConfirmResID: $r('app.string.btn_delete'), // 确认按钮文本
      btnConfirmFontColor: $r('app.color.crimson'), // 红色警示色
      confirm: () => { // 确认回调
        if (this.taskID) {
          RequestProxy.deleteTask(this.taskID); // 调用删除接口
          this.agencyTasks = this.agencyTasks.filter(t => t.taskID !== this.taskID); // 本地过滤
          this.taskID = undefined; // 清空临时存储
        }
      }
    }),
    alignment: DialogAlignment.Center, // 居中显示
    customStyle: false
  })

  // --------------------------
  // 构建删除按钮(侧滑操作)
  // --------------------------
  @Builder
  deleteButton(taskID: string) {
    Column() {
      Text($r('app.string.btn_delete'))
        .fontColor(Color.White)
    }
    .width(48)
    .height(56)
    .backgroundColor(Color.Red) // 红色警示背景
    .onClick(() => {
      this.taskID = taskID;
      this.dController.open(); // 打开确认弹窗
    })
  }

  // --------------------------
  // 主构建方法
  // --------------------------
  build() {
    Stack() {
      // 1. 主内容区
      Row() {
        Column() {
          // 1.1 顶部间距
          Blank().height('2%')

          // 1.2 搜索框
          Search({ placeholder: $r('app.string.search_tip') })
            .onChange((data: string) => { // 输入变化实时搜索
              this.searchTxt = data;
              this.search();
            })
            .onSubmit((data: string) => { // 提交搜索
              this.searchTxt = data;
              this.search();
            })

          Blank().height('2%')

          // 1.3 Tab切换栏
          Row() {
            ForEach(CommonConstants.AGENCY_TASK_TABS, (item: string, index: number) => {
              Column() {
                Text(item)
                  .fontColor(index === this.selectIdx ? '#3093FA' : '#000000') // 选中态蓝色
                  .opacity(index === this.selectIdx ? 1 : 0.6) // 未选中半透明
              }
              .onClick(() => { // Tab切换事件
                this.selectIdx = index;
                this.load();
              })
            }, (item: string, index: number) => index + item) // 唯一键生成
          }

          // 1.4 Tab指示器
          Row() {
            Column() {
              Blank().color(this.selectIdx === 0 ? '#3093FA' : Color.White) // 蓝色指示条
            }.width('50%')
            Column() {
              Blank().color(this.selectIdx === 1 ? '#3093FA' : Color.White)
            }.width('50%')
          }

          // 1.5 任务列表
          List({ scroller: this.controller }) {
            ForEach(this.agencyTasks, (item: TaskItem, index) => {
              ListItem() {
                AgencyTaskListItem({ // 单条任务组件
                  checkCallback: (checked: boolean) => { // 完成状态回调
                    item.isFinished = checked;
                    this.edit(item);
                    this.load();
                  },
                  editCallback: () => { this.load() }, // 编辑回调
                  item: item // 任务数据
                })
              }.swipeAction({ end: this.deleteButton(item.taskID) }) // 左滑删除
            })
          }
          .edgeEffect(EdgeEffect.Spring) // 弹性边缘效果
          .visibility(this.isEmptyTasks() ? Visibility.None : Visibility.Visible) // 空数据隐藏

          // 1.6 空状态提示
          Column() {
            Image($r('app.media.ic_no_schedule')).width(120).height(120);
            Text($r('app.string.no_agency')) // "暂无待办"提示
          }
          .visibility(this.isEmptyTasks() && this.isUnfinishedPage() ? Visibility.Visible : Visibility.None)
        }.width('92%') // 内容区宽度
      }

      // 2. 悬浮添加按钮
      Image($r('app.media.ic_plus_filled'))
        .onClick(() => { this.newAgencyTask(); })
        .position({ 
          x: this.myStorage.windowWidthVp * 0.8, // 右侧20%位置
          y: this.myStorage.windowHeightVp * 0.7 // 底部30%位置
        })
    }
  }
}

(2)待办列表子项
描述:显示列表页,详情展示,新增/编辑子项
AgencyTaskListItem.ets代码实现:

// 导入日期工具、格式化工具和路由模块
import { DateUtils, FormatUtil, RouterMap, RouterModule } from '@ohos_agcit/office_attendance_common_lib';
import { TaskItem } from '../types/Types';

// --------------------------
// 待办任务列表项组件
// --------------------------
@ComponentV2
export struct AgencyTaskListItem {
  // 组件参数
  @Param item: TaskItem = {}; // 任务数据对象
  @Param checkCallback: (check: boolean) => void = (check) => {}; // 复选框状态回调
  @Param editCallback: () => void = () => {}; // 编辑完成回调

  // --------------------------
  // 格式化计划时间显示
  // --------------------------
  formatDate(): string {
    if (this.item.planTime) {
      // 格式化为"YYYY-MM-DD HH:mm"格式
      return FormatUtil.formatDate(new Date(this.item.planTime), FormatUtil.DATE_YYYY_MM_DD_24H_mm);
    }
    return ''; // 无计划时间返回空字符串
  }

  // --------------------------
  // 组件构建
  // --------------------------
  build() {
    Column() {
      // 1. 主内容行
      Row() {
        // 1.1 完成状态复选框
        Column() {
          Checkbox({ name: 'checkBox', group: 'checkBoxGroup' })
            .select(this.item.isFinished) // 绑定完成状态
            .width(20).height(20)
            .borderRadius(4)
            .backgroundColor($r('app.color.white')) // 白色背景
            .border({ color: $r('app.color.black_1'), style: BorderStyle.Solid }) // 1px边框
            .selectedColor($r('app.color.sys_default_blue')) // 选中状态蓝色
            .shape(CheckBoxShape.ROUNDED_SQUARE) // 圆角方形
            .onChange((value: boolean) => {
              this.checkCallback(value); // 状态变化回调
            })
        }.width(20)

        Column().width('3%') // 间距占位

        // 1.2 任务信息区
        Column() {
          // 任务标题(单行省略)
          Column() {
            Text(this.item.title)
              .fontSize(14)
              .width('100%')
              .maxLines(1)
              .textOverflow({ overflow: TextOverflow.Ellipsis }) // 超出显示省略号
              .fontWeight(FontWeight.Medium)
              .opacity(this.item.isFinished ? 0.4 : 0.9) // 完成状态降低透明度
          }.height(19)

          // 截止时间显示
          Row() {
            Text($r('app.string.deadTime')) // "截止时间"文案
              .fontSize(12)
              .opacity(this.item.isFinished ? 0.4 : 0.6)
            Text(this.formatDate()) // 格式化后的时间
              .fontSize(12)
              .opacity(this.item.isFinished ? 0.4 : 0.6)
          }.height(16)
        }
        .layoutWeight(1) // 占据剩余空间
      }
      .height(56)
      .backgroundColor(Color.White)
      .onClick(() => { // 点击进入编辑页
        RouterModule.push({
          url: RouterMap.EDIT_AGENCY_TASK, 
          param: this.item.taskID, // 传递任务ID
          onPop: () => { this.editCallback() } // 返回时刷新
        })
      })

      // 2. 底部分隔线
      Divider().width('100%').height(1)
    }
  }
}

五、最终成果展示
#我的鸿蒙开发手记#鸿蒙待办事项开发实现-鸿蒙开发者社区

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