欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。


在企业人力资源管理体系中,部门级考勤汇总是从“员工个体”到“组织整体”的关键数据聚合环节,其核心诉求在于多维度数据的精准统计、部门间数据对比分析、跨终端数据展示适配,同时需支持手动录入与自动生成的双重数据来源。鸿蒙系统的分布式全场景能力为企业级组织维度数据统计应用提供了跨设备协同的底层支撑,而React Native凭借“一次开发、多端运行”的技术特性,成为部门考勤汇总这类组织级数据统计应用跨端开发的最优选择。本文将从组织维度数据模型设计、多指标统计逻辑、跨端交互适配到鸿蒙生态融合的底层实现,全方位拆解这款部门考勤汇总应用的技术架构,剖析React Native与鸿蒙生态深度融合的关键技术要点。

从组件适配层面来看

这款部门考勤汇总应用的核心架构完全基于React Native通用API体系构建,未引入任何平台专属代码,这是实现鸿蒙跨端兼容的核心前提。React Native for HarmonyOS框架会将React Native的通用组件无缝映射为鸿蒙ArkUI原生组件,保证组织维度数据录入、统计展示、详情查看等核心交互在鸿蒙设备上的原生质感。

从组件适配层面来看,TextInput作为核心数据录入组件,在鸿蒙系统中会被映射为TextInput原生控件,其placeholder属性适配鸿蒙原生提示文本样式,同时支持百分比(出勤率)、整数(迟到次数)等不同类型数值的录入,完美适配部门考勤汇总“多类型数值+格式化文本”的录入需求;TouchableOpacity组件转换为鸿蒙Button原生组件,保留点击反馈的同时适配鸿蒙系统的交互规范,尤其适合部门选择、添加汇总、查看详情等操作,避免因跨端交互差异导致的操作误判;Modal组件对应鸿蒙Dialog原生模态框,通过animationType="slide"实现的滑动弹窗效果,在鸿蒙系统中解析为原生动效,用于展示包含多维度组织考勤数据的完整详情,符合鸿蒙系统的交互体验标准;Alert组件调用鸿蒙系统级弹窗能力,在添加汇总成功/失败、选择部门等关键节点推送提示,确保操作结果的即时反馈,契合企业组织级考勤统计“数据录入可确认、操作结果可感知”的核心诉求。

此外,应用通过Dimensions.get('window')获取设备屏幕尺寸,该API在鸿蒙系统中被适配为getWindowSize原生能力,能够精准识别鸿蒙手机、平板、智慧屏等不同形态设备的屏幕参数——例如在鸿蒙平板上展示多部门月度考勤汇总对比列表(适配大屏多组织数据展示场景),在手机上呈现精简的部门考勤数据录入界面,在智慧屏上适配企业考勤大屏的组织维度统计数据可视化展示,完美契合企业多终端办公的业务场景。

跨端编译阶段拦截数据格式偏差

部门考勤汇总的核心是“部门-统计周期-多维度数值指标”的三层关联,代码中通过TypeScript构建了强类型数据模型,尤其是百分比、计数型字段的精准定义,既规避前端开发中的数据类型错误,又在跨端编译阶段拦截数据格式偏差,适配鸿蒙ArkTS的静态类型特性。

// 部门模型:组织维度基础信息,支撑考勤汇总的组织关联
type Department = {
  id: string;
  name: string;         // 字符串型部门名称,适配企业组织架构的标准化描述
};

// 考勤汇总核心模型:多类型数值字段设计,实现组织维度多指标精准统计
type AttendanceSummary = {
  id: string;
  departmentId: string;          // 关联部门ID,实现统计数据与组织的精准绑定
  month: string;                 // 字符串型月份,兼容跨端统一的YYYY-MM格式
  attendanceRate: number;        // 数值型出勤率(百分比),保证考勤核心指标的精准计算
  lateCount: number;             // 数值型迟到次数,适配组织维度考勤异常的量化统计
  leaveCount: number;            // 数值型请假次数,支持组织维度假期核算的精准性
  abnormalCount: number;         // 数值型异常次数,适配组织维度考勤合规性分析
};

其中,attendanceRate(出勤率)采用number类型是核心设计亮点:在鸿蒙系统中,React Native的TypeScript编译器会对JS层与ArkTS层之间的数值传递进行严格校验,避免出现字符串型百分比(如"95%")导致的跨端计算错误;同时,数值型出勤率设计适配了企业组织级考勤分析的核心诉求——出勤率需要参与部门绩效核算、考勤合规性评估等后续计算,number类型保证了跨端数据计算的精准性,不会因鸿蒙系统的数值解析规则差异导致统计结果偏差。lateCountleaveCountabnormalCount等计数型字段同样采用number类型,适配组织维度“量化统计、对比分析”的业务需求,确保不同部门间的考勤异常数据可直接对比,符合企业组织级考勤管理的核心要求。

React Hooks驱动的跨端组织维度统计流程

应用的核心业务逻辑(自动生成部门考勤汇总、手动录入汇总信息、详情查看)均基于React Hooks(useStateuseEffect)实现,这种轻量级状态管理方式完美适配React Native的跨端生命周期模型,同时与鸿蒙组件生命周期深度融合,保障了组织维度考勤统计流程的跨端稳定运行。

状态设计

应用通过useState管理核心状态,包括部门列表、考勤汇总列表、选中部门、新汇总数据录入表单、弹窗状态等。其中,新汇总数据录入表单(newSummary)的字段均为字符串型(适配TextInput的文本输入特性),在提交时通过parseInt转换为数值型,这一设计是跨端数据兼容的关键:

const newSum: AttendanceSummary = {
  id: (attendanceSummaries.length + 1).toString(),
  departmentId: selectedDepartment,
  month: newSummary.month,
  attendanceRate: parseInt(newSummary.attendanceRate), // 字符串转数值,适配TypeScript类型约束
  lateCount: parseInt(newSummary.lateCount),
  leaveCount: parseInt(newSummary.leaveCount),
  abnormalCount: parseInt(newSummary.abnormalCount)
};

在鸿蒙系统中,parseInt作为ES6标准方法被完整适配,保证字符串型数字到数值型的精准转换,避免因鸿蒙ArkTS的静态类型校验导致数据录入失败。同时,所有状态更新均采用“不可变更新”策略——即通过解构赋值创建新数据副本:

setAttendanceSummaries([...attendanceSummaries, newSum]);

这一设计适配了鸿蒙分布式数据管理的核心要求:不可变更新保证每次状态变更都会生成新的数据源,避免多端数据同步时的冲突问题,确保部门考勤汇总数据在鸿蒙多设备间的同步准确性,符合企业组织级考勤“数据单一来源、更新可追溯”的核心要求。

自动生成汇总

应用通过useEffect实现每分钟一次的自动部门考勤汇总生成逻辑,这一核心逻辑在鸿蒙系统中稳定运行的关键在于:

useEffect(() => {
  const interval = setInterval(() => {
    const randomDepartment = departments[Math.floor(Math.random() * departments.length)];
    const newSummary: AttendanceSummary = {
      id: (attendanceSummaries.length + 1).toString(),
      departmentId: randomDepartment.id,
      month: new Date().toISOString().slice(0, 7), // 跨端兼容的月份格式化
      attendanceRate: Math.floor(Math.random() * 100), // 0-100的数值范围,模拟合理出勤率
      lateCount: Math.floor(Math.random() * 10),
      leaveCount: Math.floor(Math.random() * 5),
      abnormalCount: Math.floor(Math.random() * 3)
    };
    setAttendanceSummaries([...attendanceSummaries, newSummary]);
  }, 60000);

  return () => clearInterval(interval);
}, [departments, attendanceSummaries]);

setInterval/clearInterval是React Native封装的通用定时器API,已适配鸿蒙的任务调度机制,不会因鸿蒙系统的后台任务管理策略导致定时器失效;new Date().toISOString().slice(0, 7)是跨端通用的月份格式化方法,在鸿蒙系统中解析为标准的YYYY-MM格式,保证不同鸿蒙设备上生成的统计周期一致性;随机数生成逻辑(Math.floor(Math.random() * 100))限定了出勤率0-100的合理范围,迟到次数、请假次数等也匹配企业真实考勤数据分布,生成的汇总数据完全符合TypeScript类型约束,避免跨端运行时错误。useEffect的依赖数组包含departmentsattendanceSummaries,保证数据源变更时重新创建定时器,适配鸿蒙组件的更新生命周期;返回的清理函数对应鸿蒙组件onDestroy生命周期,确保组件卸载时销毁定时器,避免鸿蒙设备内存泄漏。

手动录入

handleAddSummary函数是手动录入部门考勤汇总数据的核心入口,其内部首先校验“部门选中状态+月份+所有数值字段”的完整性,这是组织维度考勤统计的核心校验逻辑,保证录入数据的合规性;随后将字符串型录入数据转换为数值型,构建符合TypeScript类型约束的新汇总对象,通过不可变更新添加到状态中,确保鸿蒙分布式数据环境下的同步准确性。校验逻辑中对所有必填字段的检查,避免了因数据缺失导致的跨端统计错误,符合企业组织级考勤“数据完整、统计精准”的核心要求。


应用的UI层基于React Native的StyleSheet统一管理样式,既保证鸿蒙系统中的原生渲染效果,又兼顾部门考勤汇总这类组织维度数据密集型应用对数据展示清晰性、操作辨识度的特殊要求。

样式

StyleSheet将CSS样式抽象为跨平台的样式对象,核心样式属性在鸿蒙系统中会被精准转换为ArkUI的布局属性,同时针对组织维度统计场景设计了差异化的视觉样式:

const styles = StyleSheet.create({
  section: {
    backgroundColor: '#ffffff',
    marginHorizontal: 16,
    borderRadius: 12,
    padding: 16,
    // 阴影跨端适配:elevation适配鸿蒙/Android,shadow系列适配iOS
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
  },
  summaryCard: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#f0f9ff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 12,
  },
  selectedCard: {
    borderWidth: 2,
    borderColor: '#0284c7', // 统一的选中态边框,适配部门选择的可视化
  },
  input: {
    flex: 1,
    backgroundColor: '#f0f9ff',
    borderRadius: 8,
    paddingHorizontal: 12,
    paddingVertical: 8,
    fontSize: 14,
    color: '#0c4a6e',
    marginRight: 8,
  }
});

其中,elevation属性在鸿蒙系统中会被解析为原生阴影层级,borderRadius适配鸿蒙的圆角渲染规则,保证UI视觉效果的跨端一致性;summaryCard样式为组织维度统计列表项设计了统一的布局结构(图标+多维度组织数据),既保证不同部门间数据展示的一致性,又适配鸿蒙系统的布局渲染规则;input样式采用浅蓝背景色(#f0f9ff),降低长时间录入多部门数据的视觉疲劳,同时文字颜色(#0c4a6e)保证在鸿蒙不同屏幕亮度下的可读性,符合组织维度数据录入场景的视觉要求;selectedCard样式为部门选择项提供明确的选中态反馈,避免因跨端视觉差异导致的选错部门问题,符合组织维度考勤统计“部门关联精准”的核心要求。

交互组件

核心交互逻辑上,inputRow采用多行多列布局,将月份、出勤率、迟到次数等字段分组录入,适配组织维度考勤统计“多指标数据分类录入”的业务规则;TouchableOpacity组件在鸿蒙系统中渲染为具备原生点击反馈的按钮,保证添加汇总、查看详情等操作的交互质感;Modal弹窗展示部门考勤汇总的完整详情,包括部门名称、月份、所有数值型统计数据,通过可选链操作符(department?.name)处理空值情况,避免因关联ID错误导致的跨端运行时错误,符合鸿蒙系统对应用稳定性的严苛要求。


当前代码已实现基础的鸿蒙跨端兼容,在生产环境中,可针对鸿蒙系统特性和组织维度考勤统计业务需求进行深度优化,进一步提升应用的企业级服务能力:

1. 高性能列表

应用中部门考勤汇总列表采用ScrollView + map的方式渲染,在鸿蒙系统中面对大量部门月度统计数据时可能出现卡顿。可替换为React Native的FlatList组件,该组件在鸿蒙系统中会适配ArkUI的List原生组件,实现按需渲染和组件复用,通过getItemLayout优化列表滚动性能,尤其适合展示企业全部门年度考勤汇总数据、多维度组织对比数据等大数据量场景。

2. 鸿蒙原生

部门考勤汇总的核心诉求是组织维度数据精准性和可视化分析,可通过React Native的Native Module机制封装鸿蒙原生能力:

  • 分布式数据同步:集成鸿蒙DistributedDataManager,实现部门考勤汇总数据在HR鸿蒙平板、管理层鸿蒙手机、企业智慧屏之间的实时同步,确保组织维度统计数据的即时更新;
  • 数据可视化能力:封装鸿蒙ChartKit原生API,将部门考勤汇总数据转换为柱状图、雷达图等可视化图表,在鸿蒙大屏上展示各部门出勤率对比、异常次数排行,提升组织维度数据解读效率;
  • 系统级数据校验:利用鸿蒙DataValidationKit,在数据录入阶段进行实时校验(如出勤率0-100范围限制、异常次数不大于出勤天数),提前拦截不合理数据,保证组织维度统计精准性。

3. 组织维度

基于鸿蒙的AI能力和React Native的状态管理,可实现部门考勤汇总的智能化管理:

  • 通过鸿蒙的数据分析能力,自动计算各部门考勤异常率、出勤率达标率等组织维度指标,生成部门考勤健康度报告,为企业组织架构优化、考勤制度调整提供数据支撑;
  • 结合鸿蒙的任务调度能力,在每月月末自动生成全公司各部门的月度考勤汇总报表,推送给管理层;
  • 利用鸿蒙的分布式权限管理,为不同层级管理员分配对应权限(如部门经理仅查看本部门数据、HR查看全公司数据),实现精细化组织维度数据管控。

这款基于React Native开发的部门考勤汇总应用,通过组织维度数值型字段设计的强类型数据模型、React Hooks状态管理和通用UI组件设计,构建了具备完整鸿蒙跨端兼容能力的企业组织维度数据统计应用架构,核心技术要点可总结为:

  • 通用API选型是实现鸿蒙兼容的基础,基于React Native通用组件构建核心逻辑,规避平台专属代码,保证了组织维度考勤统计UI和交互的跨端一致性;
  • TypeScript多类型数值字段约束适配鸿蒙ArkTS的静态类型特性,避免跨端数据交互中的类型错误,保障组织维度考勤统计数据的精准计算和对比分析;
  • React Hooks不可变更新+类型转换策略与鸿蒙组件生命周期深度融合,实现组织维度统计数据的精准录入和更新,保障了核心考勤汇总流程的跨端稳定运行;
  • 统一的StyleSheet样式系统实现了UI在鸿蒙设备上的原生渲染,分组式输入布局设计兼顾了组织

在企业人力资源管理中,部门级别的考勤汇总分析对企业管理决策至关重要,如何高效、准确地生成部门考勤汇总报表是企业管理的重要环节。本文将深入剖析一个基于 React Native 构建的部门考勤汇总应用,探讨其技术实现细节及鸿蒙跨端能力的应用。

技术选型

该应用采用了现代 React Native 函数式组件架构,通过 TypeScript 类型系统和 React Hooks 实现了一个功能完整的部门考勤汇总管理系统。核心技术栈包括:

  • React Native:作为跨端开发框架,提供了统一的组件 API,确保应用在 iOS、Android 及鸿蒙平台上的一致性体验
  • TypeScript:通过严格的类型定义增强代码可维护性,明确了数据结构和组件接口
  • React Hooks:使用 useState 管理应用状态,useEffect 处理副作用逻辑,实现了声明式的状态管理
  • Base64 图标:采用 Base64 编码的图标资源,避免了不同平台资源格式的差异,提高了跨端兼容性
  • 响应式布局:使用 Dimensions API 获取屏幕尺寸,实现适配不同设备的响应式界面

数据模型

应用通过 TypeScript 接口定义了两个核心数据类型,构建了完整的部门考勤汇总数据模型体系:

// 部门类型
type Department = {
  id: string;
  name: string;
};

// 考勤汇总类型
type AttendanceSummary = {
  id: string;
  departmentId: string;
  month: string;
  attendanceRate: number;
  lateCount: number;
  leaveCount: number;
  abnormalCount: number;
};

这种强类型设计不仅提高了代码可读性,也为鸿蒙跨端适配提供了清晰的数据契约,确保不同平台间数据传递的一致性。数据模型的设计充分考虑了部门考勤汇总的核心要素,包含了出勤率、迟到次数、请假次数和异常次数等关键数据指标。

状态管理

应用使用 useState Hook 管理多个复杂状态,包括部门列表、考勤汇总、选中状态等:

const [departments] = useState<Department[]>([
  {
    id: '1',
    name: '技术部'
  },
  {
    id: '2',
    name: '市场部'
  },
  {
    id: '3',
    name: '管理部'
  }
]);

// 其他状态定义...

特别值得注意的是,应用通过 useEffect 实现了部门考勤汇总的自动生成机制:

// 自动生成部门考勤汇总
useEffect(() => {
  const interval = setInterval(() => {
    const randomDepartment = departments[Math.floor(Math.random() * departments.length)];
    const newSummary: AttendanceSummary = {
      id: (attendanceSummaries.length + 1).toString(),
      departmentId: randomDepartment.id,
      month: new Date().toISOString().slice(0, 7),
      attendanceRate: Math.floor(Math.random() * 100),
      lateCount: Math.floor(Math.random() * 10),
      leaveCount: Math.floor(Math.random() * 5),
      abnormalCount: Math.floor(Math.random() * 3)
    };
    setAttendanceSummaries([...attendanceSummaries, newSummary]);
  }, 60000);

  return () => clearInterval(interval);
}, [departments, attendanceSummaries]);

这种基于时间间隔的自动生成机制,模拟了真实场景中部门考勤汇总的生成过程,为企业管理提供了自动化的技术支持。同时,通过 useEffect 的清理函数,确保了定时器在组件卸载时被正确清除,避免了内存泄漏。


在 React Native 鸿蒙跨端开发中,该应用体现了以下关键技术点:

  1. 组件兼容性:使用 React Native 核心组件(如 SafeAreaView、View、Text、TouchableOpacity、ScrollView、Modal 等),确保在鸿蒙系统上的兼容性
  2. 资源管理:通过 Base64 编码的图标资源,避免了不同平台资源格式的差异,提高了跨端部署的一致性
  3. 尺寸适配:使用 Dimensions API 获取屏幕尺寸,实现响应式布局,适应不同设备屏幕
  4. 状态管理:采用 React Hooks 进行状态管理,保持跨平台代码一致性
  5. 类型安全:TypeScript 类型定义确保了数据结构在不同平台间的一致性
  6. API 调用:使用 React Native 统一的 API 调用方式,如 Alert 组件,确保在鸿蒙平台上的正确显示
  7. 中文命名支持:代码中使用了中文变量名和类型名,展示了 React Native 对中文命名的良好支持,这在鸿蒙等中文生态系统中尤为重要

部门管理与选择

应用实现了部门的选择功能,用户可以选择特定部门进行考勤汇总:

const handleSelectDepartment = (departmentId: string) => {
  setSelectedDepartment(departmentId);
  Alert.alert('选择部门', '您已选择该部门进行考勤汇总');
};

考勤汇总添加

应用提供了考勤汇总的添加功能,用户可以输入部门考勤数据:

const handleAddSummary = () => {
  if (newSummary.month && newSummary.attendanceRate && newSummary.lateCount && newSummary.leaveCount && newSummary.abnormalCount && selectedDepartment) {
    const newSum: AttendanceSummary = {
      id: (attendanceSummaries.length + 1).toString(),
      departmentId: selectedDepartment,
      month: newSummary.month,
      attendanceRate: parseInt(newSummary.attendanceRate),
      lateCount: parseInt(newSummary.lateCount),
      leaveCount: parseInt(newSummary.leaveCount),
      abnormalCount: parseInt(newSummary.abnormalCount)
    };
    setAttendanceSummaries([...attendanceSummaries, newSum]);
    setNewSummary({ month: '', attendanceRate: '', lateCount: '', leaveCount: '', abnormalCount: '' });
    Alert.alert('添加成功', '新的考勤汇总已添加');
  } else {
    Alert.alert('提示', '请选择部门并填写完整的汇总信息');
  }
};

汇总查看功能

应用提供了考勤汇总的查看功能,通过模态框展示详细信息:

const handleViewSummary = (summaryId: string) => {
  const summary = attendanceSummaries.find(s => s.id === summaryId);
  if (summary) {
    const department = departments.find(d => d.id === summary.departmentId);
    setModalContent(`部门: ${department?.name}\n月份: ${summary.month}\n出勤率: ${summary.attendanceRate}%\n迟到次数: ${summary.lateCount}\n请假次数: ${summary.leaveCount}\n异常次数: ${summary.abnormalCount}`);
    setIsModalVisible(true);
  }
};

自动汇总生成

应用通过定时任务自动生成部门考勤汇总,模拟了真实的人力资源管理流程。


应用的 UI 设计遵循了现代移动应用的设计原则,使用了以下组件和交互模式:

  • 安全区域:通过 SafeAreaView 确保内容显示在安全区域内,适应不同设备的屏幕刘海和底部指示条
  • 滚动视图:通过 ScrollView 实现内容的垂直滚动,适应不同长度的部门列表和汇总数据
  • 卡片布局:使用 TouchableOpacity 和 View 组合实现卡片式列表项,提供清晰的视觉层次和交互反馈
  • 表单输入:通过 TextInput 组件实现汇总信息的输入
  • 模态框:通过 Modal 组件展示详细信息,如考勤汇总详情
  • 交互反馈:使用 Alert 组件提供操作反馈和提示信息
  • 响应式设计:根据屏幕尺寸动态调整布局,确保在不同设备上的良好显示效果

  1. 跨端架构:基于 React Native 构建,实现了一次编码多平台运行的目标,特别关注了鸿蒙平台的适配
  2. 类型安全:全面使用 TypeScript 类型定义,提高代码质量和可维护性,确保考勤数据的准确性
  3. 自动化汇总:通过定时任务自动生成部门考勤汇总,提高了人力资源管理的效率
  4. 部门级分析:实现了部门级别的考勤汇总分析,为企业管理决策提供了数据支持
  5. 智能状态管理:通过 React Hooks 实现了简洁的状态管理,提高了代码的可读性和可维护性
  6. 模块化设计:通过清晰的类型定义和函数划分,实现了代码的模块化,提高了可维护性
  7. 实时数据反馈:通过即时的 Alert 反馈,增强用户操作体验
  8. 数据结构设计:通过关联的数据结构,如考勤汇总关联部门,实现了复杂人事数据的有效组织
  9. 中文命名支持:代码中使用了中文变量名和类型名,展示了 React Native 对中文命名的良好支持,这在鸿蒙等中文生态系统中尤为重要
  10. 数据可视化基础:通过完整的考勤汇总数据模型,为后续的数据可视化和分析奠定了基础

在实际应用中,还可以考虑以下性能优化策略:

  1. 状态管理优化:对于大型应用,可以考虑使用 Redux 或 Context API 进行全局状态管理,提高状态更新的效率
  2. 组件拆分:将大型组件拆分为更小的可复用组件,提高渲染性能和代码可维护性
  3. 数据缓存:对部门数据和考勤汇总进行本地缓存,减少重复计算和网络请求
  4. 动画性能:使用 React Native 的 Animated API 实现流畅的过渡动画,提升用户体验
  5. 内存管理:确保及时清理不再使用的状态和事件监听器,避免内存泄漏
  6. 网络优化:对于实际应用中的远程数据同步,实现合理的网络请求策略,如批量上传、增量同步等
  7. 计算优化:对于考勤数据的统计和分析,可以考虑使用 memoization 技术缓存计算结果
  8. 列表优化:对于长列表,使用 FlatList 组件替代 ScrollView,提高渲染性能

在开发过程中,可能面临的技术挑战及解决方案:

  1. 鸿蒙平台适配:通过使用 React Native 核心组件和统一的 API 调用方式,确保应用在鸿蒙系统上的兼容性
  2. 实时数据同步:在实际应用中,可以实现与后端服务器的实时数据同步,确保考勤汇总数据的一致性
  3. 数据可视化:可以集成图表库,实现部门考勤数据的可视化展示,提高数据的可读性和分析价值
  4. 数据安全:实现考勤数据的加密存储和传输,保护企业数据安全
  5. 离线功能:实现基本的离线操作能力,确保在网络不稳定情况下的正常使用
  6. 性能优化:针对不同设备性能差异,实现自适应的性能优化策略,确保在中低端设备上的流畅运行
  7. 用户体验一致性:确保在不同平台上的用户体验一致,特别是交互方式和视觉效果
  8. 多语言支持:实现多语言支持,满足不同地区企业的需求

通过对这个部门考勤汇总应用的技术解读,我们可以看到 React Native 在跨端开发中的强大能力。该应用不仅实现了完整的部门考勤汇总管理功能,还展示了如何通过 TypeScript、React Hooks 等现代前端技术构建高质量的跨端应用。


真实演示案例代码:





// App.tsx
import React, { useState, useEffect } from 'react';
import { SafeAreaView, View, Text, StyleSheet, TouchableOpacity, ScrollView, Dimensions, Alert, TextInput, Modal } from 'react-native';

// Base64 图标库
const ICONS_BASE64 = {
  统计: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  部门: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  警告: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
  图表: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
};

const { width, height } = Dimensions.get('window');

// 部门类型
type Department = {
  id: string;
  name: string;
};

// 考勤汇总类型
type AttendanceSummary = {
  id: string;
  departmentId: string;
  month: string;
  attendanceRate: number;
  lateCount: number;
  leaveCount: number;
  abnormalCount: number;
};

// 部门考勤汇总应用组件
const DepartmentAttendanceSummaryApp: React.FC = () => {
  const [departments] = useState<Department[]>([
    {
      id: '1',
      name: '技术部'
    },
    {
      id: '2',
      name: '市场部'
    },
    {
      id: '3',
      name: '管理部'
    }
  ]);

  const [attendanceSummaries, setAttendanceSummaries] = useState<AttendanceSummary[]>([
    {
      id: '1',
      departmentId: '1',
      month: '2023-12',
      attendanceRate: 95,
      lateCount: 5,
      leaveCount: 3,
      abnormalCount: 2
    }
  ]);

  const [selectedDepartment, setSelectedDepartment] = useState<string | null>(null);
  const [newSummary, setNewSummary] = useState({
    month: '',
    attendanceRate: '',
    lateCount: '',
    leaveCount: '',
    abnormalCount: ''
  });
  const [isModalVisible, setIsModalVisible] = useState(false);
  const [modalContent, setModalContent] = useState('');

  // 自动生成部门考勤汇总
  useEffect(() => {
    const interval = setInterval(() => {
      const randomDepartment = departments[Math.floor(Math.random() * departments.length)];
      const newSummary: AttendanceSummary = {
        id: (attendanceSummaries.length + 1).toString(),
        departmentId: randomDepartment.id,
        month: new Date().toISOString().slice(0, 7),
        attendanceRate: Math.floor(Math.random() * 100),
        lateCount: Math.floor(Math.random() * 10),
        leaveCount: Math.floor(Math.random() * 5),
        abnormalCount: Math.floor(Math.random() * 3)
      };
      setAttendanceSummaries([...attendanceSummaries, newSummary]);
    }, 60000);

    return () => clearInterval(interval);
  }, [departments, attendanceSummaries]);

  const handleSelectDepartment = (departmentId: string) => {
    setSelectedDepartment(departmentId);
    Alert.alert('选择部门', '您已选择该部门进行考勤汇总');
  };

  const handleAddSummary = () => {
    if (newSummary.month && newSummary.attendanceRate && newSummary.lateCount && newSummary.leaveCount && newSummary.abnormalCount && selectedDepartment) {
      const newSum: AttendanceSummary = {
        id: (attendanceSummaries.length + 1).toString(),
        departmentId: selectedDepartment,
        month: newSummary.month,
        attendanceRate: parseInt(newSummary.attendanceRate),
        lateCount: parseInt(newSummary.lateCount),
        leaveCount: parseInt(newSummary.leaveCount),
        abnormalCount: parseInt(newSummary.abnormalCount)
      };
      setAttendanceSummaries([...attendanceSummaries, newSum]);
      setNewSummary({ month: '', attendanceRate: '', lateCount: '', leaveCount: '', abnormalCount: '' });
      Alert.alert('添加成功', '新的考勤汇总已添加');
    } else {
      Alert.alert('提示', '请选择部门并填写完整的汇总信息');
    }
  };

  const handleViewSummary = (summaryId: string) => {
    const summary = attendanceSummaries.find(s => s.id === summaryId);
    if (summary) {
      const department = departments.find(d => d.id === summary.departmentId);
      setModalContent(`部门: ${department?.name}\n月份: ${summary.month}\n出勤率: ${summary.attendanceRate}%\n迟到次数: ${summary.lateCount}\n请假次数: ${summary.leaveCount}\n异常次数: ${summary.abnormalCount}`);
      setIsModalVisible(true);
    }
  };

  const openModal = (content: string) => {
    setModalContent(content);
    setIsModalVisible(true);
  };

  const closeModal = () => {
    setIsModalVisible(false);
  };

  return (
    <SafeAreaView style={styles.container}>
      {/* 头部 */}
      <View style={styles.header}>
        <Text style={styles.title}>部门考勤汇总</Text>
        <Text style={styles.subtitle}>管理员可查看各部门的考勤汇总,分析出勤率和异常情况</Text>
      </View>

      <ScrollView style={styles.content}>
        {/* 部门列表 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>部门列表</Text>
          {departments.map(department => (
            <TouchableOpacity 
              key={department.id}
              style={[
                styles.card,
                selectedDepartment === department.id && styles.selectedCard
              ]}
              onPress={() => handleSelectDepartment(department.id)}
            >
              <Text style={styles.icon}>🏢</Text>
              <View style={styles.cardInfo}>
                <Text style={styles.cardTitle}>{department.name}</Text>
              </View>
            </TouchableOpacity>
          ))}
        </View>

        {/* 添加考勤汇总 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>添加考勤汇总</Text>
          <View style={styles.inputRow}>
            <TextInput
              style={styles.input}
              placeholder="汇总月份 (YYYY-MM)"
              value={newSummary.month}
              onChangeText={(text) => setNewSummary({ ...newSummary, month: text })}
            />
            <TextInput
              style={styles.input}
              placeholder="出勤率 (%)"
              value={newSummary.attendanceRate}
              onChangeText={(text) => setNewSummary({ ...newSummary, attendanceRate: text })}
            />
          </View>
          <View style={styles.inputRow}>
            <TextInput
              style={styles.input}
              placeholder="迟到次数"
              value={newSummary.lateCount}
              onChangeText={(text) => setNewSummary({ ...newSummary, lateCount: text })}
            />
            <TextInput
              style={styles.input}
              placeholder="请假次数"
              value={newSummary.leaveCount}
              onChangeText={(text) => setNewSummary({ ...newSummary, leaveCount: text })}
            />
          </View>
          <View style={styles.inputRow}>
            <TextInput
              style={styles.input}
              placeholder="异常次数"
              value={newSummary.abnormalCount}
              onChangeText={(text) => setNewSummary({ ...newSummary, abnormalCount: text })}
            />
          </View>
          <TouchableOpacity 
            style={styles.addButton}
            onPress={handleAddSummary}
          >
            <Text style={styles.addText}>添加汇总</Text>
          </TouchableOpacity>
        </View>

        {/* 考勤汇总列表 */}
        <View style={styles.section}>
          <Text style={styles.sectionTitle}>考勤汇总列表</Text>
          {attendanceSummaries.map(summary => (
            <TouchableOpacity 
              key={summary.id}
              style={styles.summaryCard}
              onPress={() => handleViewSummary(summary.id)}
            >
              <Text style={styles.icon}>📊</Text>
              <View style={styles.cardInfo}>
                <Text style={styles.cardTitle}>汇总ID: {summary.id}</Text>
                <Text style={styles.cardDescription}>月份: {summary.month}</Text>
                <Text style={styles.cardDescription}>出勤率: {summary.attendanceRate}%</Text>
                <Text style={styles.cardDescription}>迟到次数: {summary.lateCount}</Text>
                <Text style={styles.cardDescription}>请假次数: {summary.leaveCount}</Text>
                <Text style={styles.cardDescription}>异常次数: {summary.abnormalCount}</Text>
              </View>
            </TouchableOpacity>
          ))}
        </View>

        {/* 使用说明 */}
        <View style={styles.infoCard}>
          <Text style={styles.sectionTitle}>📘 使用说明</Text>
          <Text style={styles.infoText}>• 选择部门进行考勤汇总</Text>
          <Text style={styles.infoText}>• 填写汇总月份和各项数据</Text>
          <Text style={styles.infoText}>• 系统自动生成部门报表</Text>
          <Text style={styles.infoText}>• 查看历史考勤汇总数据</Text>
        </View>

        {/* 弹框内容 */}
        <Modal
          animationType="slide"
          transparent={true}
          visible={isModalVisible}
          onRequestClose={closeModal}
        >
          <View style={styles.modalContainer}>
            <View style={styles.modalContent}>
              <Text style={styles.modalTitle}>详细信息</Text>
              <Text style={styles.modalText}>{modalContent}</Text>
              <TouchableOpacity
                style={styles.closeButton}
                onPress={closeModal}
              >
                <Text style={styles.closeButtonText}>关闭</Text>
              </TouchableOpacity>
            </View>
          </View>
        </Modal>
      </ScrollView>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f0f9ff',
  },
  header: {
    flexDirection: 'column',
    padding: 16,
    backgroundColor: '#ffffff',
    borderBottomWidth: 1,
    borderBottomColor: '#bae6fd',
  },
  title: {
    fontSize: 20,
    fontWeight: 'bold',
    color: '#0c4a6e',
    marginBottom: 4,
  },
  subtitle: {
    fontSize: 14,
    color: '#0284c7',
  },
  content: {
    flex: 1,
    marginTop: 12,
  },
  section: {
    backgroundColor: '#ffffff',
    marginHorizontal: 16,
    marginBottom: 12,
    borderRadius: 12,
    padding: 16,
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
  },
  sectionTitle: {
    fontSize: 16,
    fontWeight: '600',
    color: '#0c4a6e',
    marginBottom: 12,
  },
  card: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#f0f9ff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 12,
  },
  selectedCard: {
    borderWidth: 2,
    borderColor: '#0284c7',
  },
  summaryCard: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#f0f9ff',
    borderRadius: 12,
    padding: 16,
    marginBottom: 12,
  },
  icon: {
    fontSize: 28,
    marginRight: 12,
  },
  cardInfo: {
    flex: 1,
  },
  cardTitle: {
    fontSize: 16,
    fontWeight: '500',
    color: '#0c4a6e',
    marginBottom: 4,
  },
  cardDescription: {
    fontSize: 14,
    color: '#0284c7',
    marginBottom: 2,
  },
  inputRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    marginBottom: 12,
  },
  input: {
    flex: 1,
    backgroundColor: '#f0f9ff',
    borderRadius: 8,
    paddingHorizontal: 12,
    paddingVertical: 8,
    fontSize: 14,
    color: '#0c4a6e',
    marginRight: 8,
  },
  addButton: {
    backgroundColor: '#0284c7',
    padding: 12,
    borderRadius: 8,
    alignItems: 'center',
  },
  addText: {
    color: '#ffffff',
    fontSize: 14,
    fontWeight: '500',
  },
  infoCard: {
    backgroundColor: '#ffffff',
    marginHorizontal: 16,
    marginBottom: 80,
    borderRadius: 12,
    padding: 16,
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
  },
  infoText: {
    fontSize: 14,
    color: '#64748b',
    lineHeight: 20,
    marginBottom: 4,
  },
  modalContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'rgba(0, 0, 0, 0.5)',
  },
  modalContent: {
    width: '80%',
    backgroundColor: '#ffffff',
    borderRadius: 12,
    padding: 20,
    elevation: 5,
  },
  modalTitle: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#0c4a6e',
    marginBottom: 12,
    textAlign: 'center',
  },
  modalText: {
    fontSize: 14,
    color: '#0c4a6e',
    lineHeight: 20,
    marginBottom: 20,
  },
  closeButton: {
    backgroundColor: '#0284c7',
    padding: 10,
    borderRadius: 8,
    alignItems: 'center',
  },
  closeButtonText: {
    color: '#ffffff',
    fontSize: 14,
    fontWeight: '500',
  },
});

export default DepartmentAttendanceSummaryApp;

请添加图片描述


打包

接下来通过打包命令npn run harmony将reactNative的代码打包成为bundle,这样可以进行在开源鸿蒙OpenHarmony中进行使用。

在这里插入图片描述

打包之后再将打包后的鸿蒙OpenHarmony文件拷贝到鸿蒙的DevEco-Studio工程目录去:

在这里插入图片描述

最后运行效果图如下显示:

请添加图片描述
本文介绍了基于React Native开发的部门考勤汇总应用如何适配鸿蒙系统。通过TypeScript构建强类型数据模型,确保组织维度考勤数据的跨端兼容性;采用React Hooks实现状态管理,与鸿蒙组件生命周期深度融合;利用通用API体系实现多终端适配,包括数据录入、统计展示等核心功能。重点阐述了数值转换、定时任务、数据校验等关键技术点的跨端实现方案,保证了企业级考勤统计应用在鸿蒙生态中的稳定运行和数据准确性。该方案充分发挥了React Native"一次开发、多端运行"的优势,为鸿蒙生态的企业应用开发提供了实践参考。

欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

Logo

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

更多推荐