在这里插入图片描述

1. 项目概览与数据模型设计

这个打卡器应用旨在提供一个简单、直观的考勤打卡功能,并记录历史打卡数据。

  • 技术栈:Flutter 3.x、Dart 2.x

  • 主题:浅色模式,使用 HarmonyColors 定义统一的颜色风格。

  • 核心功能

    • CheckinRecord 数据模型:存储每日打卡详情。
    • CheckinStatus 枚举:清晰定义今日打卡状态(未打卡、上班已打卡、已完成)。
    • 状态管理:根据打卡状态动态更新 UI。
    • 上班/下班打卡:基于时间顺序进行打卡。
    • 历史记录:展示过去的打卡数据。
    • 自定义组件:引入 CommonButtonCommonDialog 提升组件复用性。
    • 多语言支持:通过 flutter_localizations 实现本地化。
1.1 CheckinRecord 类与 CheckinStatus 枚举:数据的骨架

清晰的数据模型和状态定义是构建打卡应用的基础。

// lib/main.dart (数据模型类和枚举)
/// 每日打卡记录类
class CheckinRecord {
  final DateTime date;        // 打卡日期
  String? morningCheckin;    // 上班打卡时间 (HH:mm 格式)
  String? eveningCheckin;    // 下班打卡时间 (HH:mm 格式)

  CheckinRecord({
    required this.date,
    this.morningCheckin,
    this.eveningCheckin,
  });
}

/// 今日打卡状态枚举
enum CheckinStatus {
  none,            // 今日未打卡
  morningChecked,  // 已打上班卡,待打下班卡
  completed,       // 今日打卡已完成
}
解读:
  • CheckinRecord 精准地记录了每天的打卡日期和对应的上班/下班时间。
  • CheckinStatus 枚举让我们的代码更具可读性,清晰地表达了今日打卡的当前阶段。

2. 核心打卡逻辑与状态管理

应用的生命周期中,打卡状态的准确判断和及时更新是至关重要的。

2.1 初始化与今日状态判断 (initState, _loadCheckinRecords, _checkTodayStatus)

应用启动时,会加载历史记录并判断今天的打卡状态。

// lib/main.dart (_CheckinPageState 部分)
class _CheckinPageState extends State<CheckinPage> {
  DateTime _currentDate = DateTime.now(); // 当前日期
  List<CheckinRecord> _checkinRecords = []; // 模拟加载的打卡记录
  CheckinStatus _todayStatus = CheckinStatus.none; // 今日打卡状态
  String? _morningCheckinTime; // 今日上班打卡时间
  String? _eveningCheckinTime; // 今日下班打卡时间

  
  void initState() {
    super.initState();
    _loadCheckinRecords(); // 模拟加载历史记录
    _checkTodayStatus();   // 检查今日打卡状态
  }

  void _loadCheckinRecords() {
    // 模拟数据加载 (实际应用中会从 shared_preferences 或后端加载)
    _checkinRecords = [
      CheckinRecord(date: DateTime.now().subtract(Duration(days: 1)), morningCheckin: '09:00', eveningCheckin: '18:00'),
      // ... 更多历史记录
    ];
  }

  void _checkTodayStatus() {
    final today = DateTime.now();
    // 查找今日记录,如果不存在则创建一个空记录
    final todayRecord = _checkinRecords.firstWhere(
      (record) => record.date.year == today.year && record.date.month == today.month && record.date.day == today.day,
      orElse: () => CheckinRecord(date: today),
    );

    setState(() { // 更新UI状态
      if (todayRecord.morningCheckin != null && todayRecord.eveningCheckin != null) {
        _todayStatus = CheckinStatus.completed;
        _morningCheckinTime = todayRecord.morningCheckin;
        _eveningCheckinTime = todayRecord.eveningCheckin;
      } else if (todayRecord.morningCheckin != null) {
        _todayStatus = CheckinStatus.morningChecked;
        _morningCheckinTime = todayRecord.morningCheckin;
      } else {
        _todayStatus = CheckinStatus.none;
      }
    });
  }
}
解读:
  • _loadCheckinRecords() 模拟了从数据源加载历史打卡记录的过程。在实际应用中,这里会集成 shared_preferences 或后端 API。
  • _checkTodayStatus() 是核心逻辑之一。它会遍历 _checkinRecords 列表,找出今日的记录,并根据上班和下班打卡时间的有无,精确地将 _todayStatus 设置为 none, morningCheckedcompletedorElse 参数处理了今日尚无记录的情况。
2.2 打卡操作 (_checkin)

用户点击打卡按钮时,会根据当前状态执行不同的打卡逻辑。

// lib/main.dart (_checkin方法)
void _checkin() {
  final now = DateTime.now();
  final timeString = '${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}';

  setState(() {
    if (_todayStatus == CheckinStatus.none) {
      // 上班打卡逻辑
      _morningCheckinTime = timeString;
      _todayStatus = CheckinStatus.morningChecked;
      _checkinRecords.add(CheckinRecord(date: now, morningCheckin: timeString));
      CommonDialog.showInfo(context: context, title: '打卡成功', content: '上班打卡时间:$timeString');
    } else if (_todayStatus == CheckinStatus.morningChecked) {
      // 下班打卡逻辑
      _eveningCheckinTime = timeString;
      _todayStatus = CheckinStatus.completed;
      final todayRecord = _checkinRecords.firstWhere( /* ... 查找今日记录 ... */ );
      todayRecord.eveningCheckin = timeString; // 更新下班时间
      CommonDialog.showInfo(context: context, title: '打卡成功', content: '下班打卡时间:$timeString');
    } else {
      // 今日已完成打卡,提示用户
      CommonDialog.showInfo(context: context, title: '提示', content: '今天已经完成了全部打卡');
    }
    // 实际应用中,每次打卡成功后需要保存_checkinRecords到持久化存储
  });
}

在这里插入图片描述

解读:
  • _checkin() 方法是用户交互的入口。它根据 _todayStatus 的不同值,执行不同的打卡逻辑:

    • CheckinStatus.none:进行上班打卡,记录 _morningCheckinTime,并将状态更新为 morningChecked
    • CheckinStatus.morningChecked:进行下班打卡,记录 _eveningCheckinTime,并将状态更新为 completed
    • CheckinStatus.completed:提示用户今日已完成打卡。
  • 打卡成功后,通过 CommonDialog.showInfo 弹出提示框,告知用户打卡结果,提升交互友好性。

3. UI 渲染:直观的打卡界面 🖼️

应用界面简洁明了,通过动态的文本和颜色反馈当前打卡状态。

3.1 动态状态显示 (_getStatusText, _getStatusColor)

根据 _todayStatus 动态显示不同的提示文本和颜色。

// lib/main.dart (_getStatusText 和 _getStatusColor 方法)
String _getStatusText() {
  switch (_todayStatus) {
    case CheckinStatus.none: return '请进行上班打卡';
    case CheckinStatus.morningChecked: return '请进行下班打卡';
    case CheckinStatus.completed: return '今日打卡已完成';
    default: return '';
  }
}

Color _getStatusColor() {
  switch (_todayStatus) {
    case CheckinStatus.none: return HarmonyColors.warning; // 黄色警告
    case CheckinStatus.morningChecked: return HarmonyColors.primary; // 蓝色主色
    case CheckinStatus.completed: return HarmonyColors.success; // 绿色成功
    default: return HarmonyColors.textSecondary;
  }
}
解读:
  • 这两个方法将 CheckinStatus 枚举映射为用户友好的字符串和颜色,使得界面能够直观地反映当前状态。
  • HarmonyColors 是一个自定义的颜色主题类,确保应用整体配色风格统一。
3.2 历史打卡记录 (ListView.builder)

页面底部展示过去的打卡记录,方便用户回顾。

// lib/main.dart (CheckinPage的build方法中打卡记录部分)
ListView.builder(
  shrinkWrap: true, // 根据内容收缩高度
  physics: const NeverScrollableScrollPhysics(), // 禁用内部滚动,由外部SingleChildScrollView控制
  itemCount: _checkinRecords.length,
  itemBuilder: (context, index) {
    final record = _checkinRecords[index];
    return Card(
      elevation: 2, margin: const EdgeInsets.only(bottom: 12),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              '${record.date.month}${record.date.day}${_getWeekdayString(record.date.weekday)}', // 显示日期和星期
              style: TextStyle(fontWeight: FontWeight.w500, fontSize: 14, color: HarmonyColors.textPrimary),
            ),
            Row(
              children: [
                // 上班打卡时间显示 (动态背景色和文字色)
                Container( /* ... */ child: Text(record.morningCheckin ?? '--:--', style: TextStyle(color: record.morningCheckin != null ? HarmonyColors.success : HarmonyColors.textSecondary))),
                const SizedBox(width: 16),
                // 下班打卡时间显示 (动态背景色和文字色)
                Container( /* ... */ child: Text(record.eveningCheckin ?? '--:--', style: TextStyle(color: record.eveningCheckin != null ? HarmonyColors.success : HarmonyColors.textSecondary))),
              ],
            ),
          ],
        ),
      ),
    );
  },
),
解读:
  • ListView.builder 高效地渲染打卡记录列表。shrinkWrap: trueNeverScrollableScrollPhysics() 确保它在 SingleChildScrollView 内部正确工作。
  • 每条记录都以 Card 形式展示,通过 RowText 显示日期、星期、上班/下班时间。
  • 上班/下班时间显示区域的背景色和文字色会根据时间是否为空动态变化,提供了直观的视觉反馈。
  • _getWeekdayString 方法将 DateTime.weekday 的整数值转换为友好的中文星期字符串。

4. 自定义组件:提升开发效率与UI一致性

代码中引入了 common_components.dart,这意味着应用使用了自定义的公共组件,如 CommonButtonCommonDialog,以及 HarmonyColors

// lib/main.dart (build方法中的打卡按钮部分)
CommonButton(
  text: _todayStatus == CheckinStatus.none ? '上班打卡' : _todayStatus == CheckinStatus.morningChecked ? '下班打卡' : '今日已完成打卡',
  onPressed: _checkin,
  disabled: _todayStatus == CheckinStatus.completed, // 打卡完成禁用按钮
  type: _todayStatus == CheckinStatus.completed ? ButtonType.success : ButtonType.primary, // 按钮类型
  size: ButtonSize.large, // 按钮大小
  fullWidth: true, // 宽度占满
),
解读:
  • CommonButtonCommonDialog 是对 Flutter 现有组件的封装,可以统一应用的按钮样式和对话框样式,减少重复代码,提高开发效率和UI的一致性。
  • HarmonyColors 则统一了应用的主题颜色,让整个应用的视觉风格保持协调。

5. 部署到 HarmonyOS:Flutter 的跨平台魔力

现在,我们将把这个实用的 Flutter 打卡器应用部署到 HarmonyOS 平台。得益于 Flutter 优秀的跨平台能力以及华为对 Flutter 生态的支持,这个过程变得越来越便捷!

前提条件

  1. Flutter SDK:确保您的开发环境中已安装 Flutter SDK,并推荐使用最新稳定版以获得最佳的 HarmonyOS 兼容性。
  2. DevEco Studio:已安装并配置好 HarmonyOS 开发环境。
  3. HarmonyOS SDK:在 DevEco Studio 中下载并配置好对应的 HarmonyOS SDK。
  4. Flutter for HarmonyOS 适配:请关注 Flutter for HarmonyOS 官方文档或社区指引,获取最准确和最新的部署方法。

部署步骤

  1. 创建或导入 Flutter 项目

    • 如果你还没有这个 Flutter 项目,请先通过命令行创建:flutter create my_checkin_app
    • 在 DevEco Studio 中打开 Flutter 项目:启动 DevEco Studio,选择 File -> Open,然后导航到你的 Flutter 项目的根目录并打开。
  2. DevEco Studio 自动识别与导入

    • DevEco Studio 会智能识别这是一个 Flutter 项目,并提示你将其导入为 HarmonyOS 应用。点击 ImportYes
    • 根据提示选择 HarmonyOS SDK 版本和模块类型(通常默认 entry 模块即可),DevEco Studio 会在你的 Flutter 项目内部创建 harmony 文件夹及必要的配置文件。
  3. 配置与同步

    • DevEco Studio 会自动进行项目同步,下载所有 HarmonyOS 相关的依赖和适配组件。确保网络连接稳定。
    • 对于调试目的,DevEco Studio 通常会处理调试签名。如果遇到签名问题,请在 DevEco Studio 的项目结构中检查并配置你的 HarmonyOS 模块的调试签名。
  4. 选择目标设备并运行

    • 在 DevEco Studio 顶部的设备选择下拉菜单中,选择一个可用的 HarmonyOS 模拟器或连接你的 HarmonyOS 真机设备。
    • 点击绿色的“运行”按钮。DevEco Studio 将会编译你的 Flutter 代码,将其集成到 HarmonyOS 项目中,然后构建并部署最终的 HarmonyOS 应用包(HAP)到你选择的设备上。
  5. 查看效果

    • 稍等片刻(首次构建可能需要较长时间),你的 Flutter 打卡器应用就会在 HarmonyOS 模拟器或真机上启动并运行起来!

6. 总结与展望

这个打卡器应用只是一个起点,你可以继续探索和扩展:

  • 数据持久化:集成 shared_preferences 或后端 API,确保打卡记录永久存储和跨设备同步。
  • 打卡规则:设置上班/下班的允许打卡时间范围,迟到/早退判断。
  • 月度/年度报表:统计考勤数据,生成可视化图表。
  • 提醒功能:设置打卡提醒。
  • GPS 打卡:结合地理位置服务,实现更精确的打卡地点限制。
  • 主题切换:提供暗黑模式等主题选择。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐