HarmonyOS ArkTS 实战:校园竞赛报名与项目管理完整实现
摘要
项目难度:⭐⭐⭐ 中级实战
适用人群:有 ArkTS 基础、希望学习学习类应用开发的 HarmonyOS 开发者
开发环境:DevEco Studio Next / API 24+
代码规模:单页面约 700 行,可直接运行
通过本项目,你将掌握:
- 进度条组件的实现与进度状态管理
- 多模型关联的数据结构设计
- 竞赛日历与时间轴展示技巧
- 组队管理与成员增删逻辑
- 项目状态流转与获奖展示
目录
- [一、项目概述与功能架构]
- [1.1 应用场景与项目价值]
- [1.2 完整功能清单]
- [1.3 技术选型说明]
- [二、数据结构设计]
- [2.1 团队成员模型 TeamMember]
- [2.2 竞赛模型 Competition]
- [2.3 项目模型 Project]
- [2.4 设计思路说明]
- [三、核心功能实现详解]
- [3.1 竞赛浏览与筛选]
- [3.2 报名竞赛与创建项目]
- [3.3 团队成员管理]
- [3.4 项目进度更新]
- [四、UI 设计与交互体验]
- [4.1 整体布局结构]
- [4.2 主题色与视觉规范]
- [4.3 状态视觉区分表]
- [五、关键技术点解析]
- [5.1 进度条的设计与实现思路]
- [5.2 多对多关系的数据建模]
- [六、常见问题与优化建议]
- [七、项目总结与扩展方向]
- [附录:运行方式]
一、项目概述与功能架构
1.1 应用场景与项目价值
学科竞赛是大学生活的重要组成部分,从"互联网+“到"挑战杯”,从数学建模到程序设计竞赛,各类竞赛为学生提供了实践锻炼和能力提升的广阔平台。然而,竞赛信息分散、组队困难、项目进度难以追踪等问题一直困扰着参赛学生。
本项目基于 HarmonyOS ArkTS 实现了一个校园竞赛报名与项目管理应用,整合了竞赛信息浏览、在线报名、组队管理、进度跟踪、作品提交、获奖记录等全流程功能,帮助学生系统化管理竞赛生涯。
项目核心价值:
- 信息聚合价值:集中展示各类竞赛信息,避免信息遗漏
- 协作效率价值:系统化的组队和项目管理,提升团队协作效率
- 成长记录价值:完整记录参赛历程和获奖情况,形成个人成长档案
1.2 完整功能清单
| 功能模块 | 具体功能 | 实现难度⭐ |
|---|---|---|
| 竞赛信息 | 竞赛浏览、按类型筛选、竞赛详情、收藏竞赛 | ⭐⭐ |
| 报名参赛 | 在线报名、选择赛道、填写信息、报名确认 | ⭐⭐ |
| 组队管理 | 创建团队、添加成员、成员角色分配、人数限制 | ⭐⭐⭐ |
| 项目管理 | 项目创建、进度跟踪、状态更新、作品提交 | ⭐⭐⭐ |
| 获奖记录 | 获奖展示、证书管理、奖项统计、荣誉墙 | ⭐⭐ |
| 辅助功能 | 竞赛日历、报名提醒、赛程安排、数据统计 | ⭐⭐⭐ |
1.3 技术选型说明
| 技术维度 | 选型方案 | 选型理由 |
|---|---|---|
| 开发语言 | ArkTS | 强类型支持,适合复杂业务逻辑和多模型关联场景 |
| 状态管理 | @State 装饰器 | 单页面应用轻量方案,响应式更新及时 |
| UI 组件 | ArkUI 基础组件 + 自定义进度条 | 灵活定制,满足进度可视化需求 |
| 数据存储 | 内存状态 | 演示简化,生产环境建议接入云端数据库 |
| 最低版本 | API 24 | 兼容主流 HarmonyOS 设备 |
⚠️ 注意:本项目为前端演示版本,报名、组队等操作均在本地模拟。真实竞赛系统需要对接学校教务系统或竞赛组委会后台,进行身份核验和数据同步。
二、数据结构设计
2.1 团队成员模型 TeamMember
团队成员是项目的参与者,每个人有明确的角色分工。
/** * 团队成员数据模型 * 描述参赛团队中单个成员的信息 */interfaceTeamMember{name:string;// 成员姓名studentId:string;// 学号role:string;// 角色:队长/技术/文案/设计 等}2.2 竞赛模型 Competition
竞赛是整个系统的基础实体,包含竞赛的基本信息和报名状态。
/** * 竞赛数据模型 * 描述单个竞赛的完整信息 */interfaceCompetition{id:number;// 竞赛IDname:string;// 竞赛名称type:string;// 竞赛类型:学科类/创新创业类/文体类level:string;// 竞赛级别:校级/省级/国家级/国际级deadline:string;// 报名截止时间award:string;// 最高奖项设置description:string;// 竞赛简介organizer:string;// 主办方maxMembers:number;// 每队最大人数status:string;// 报名状态:报名中/已截止/进行中/已结束isCollected:boolean;// 是否已收藏}2.3 项目模型 Project
项目是学生报名竞赛后产生的参赛实体,关联具体竞赛和团队成员。
/** * 参赛项目数据模型 * 记录学生参与某个竞赛的具体项目信息 */interfaceProject{id:number;// 项目IDcompetitionId:number;// 关联的竞赛IDcompetitionName:string;// 竞赛名称(冗余存储,便于展示)projectName:string;// 项目名称members:TeamMember[];// 团队成员列表progress:number;// 项目进度 0-100status:string;// 项目状态:进行中/已提交/已获奖/未获奖submitTime:string;// 提交时间award:string;// 获得奖项}2.4 设计思路说明
为什么采用竞赛-项目分离的双层模型?
这是一个典型的一对多关系设计:
- 语义清晰:竞赛是"赛事",项目是"我的参赛记录",两者概念不同
- 灵活扩展:同一个竞赛可以报名多个项目(不同赛道),同一个项目也可能跨竞赛参赛
- 状态独立:竞赛的报名状态和项目的完成状态是两个维度,分开管理更清晰
- 数据解耦:竞赛信息是公共数据,项目是个人数据,分离后便于权限控制
关于成员角色的设计考量
角色字段采用字符串而非枚举,原因是:
- 不同竞赛的角色分工差异很大(技术赛和商业赛角色完全不同)
- 字符串灵活性高,用户可以自定义角色名称
- 演示项目简化处理,生产环境可建立角色字典表
三、核心功能实现详解
3.1 页面状态初始化
/** * 页面状态变量定义 */@StateprivateprojectNameText:string='';// 新项目名称输入@StateprivatememberNameText:string='';// 新成员姓名输入@StateprivateselectedType:string='全部';// 竞赛筛选类型@StateprivatenextProjectId:number=5;// 下一个项目ID@Stateprivatecompetitions:Competition[]=[];// 竞赛列表@Stateprivateprojects:Project[]=[];// 我的项目列表3.2 竞赛浏览与筛选
/** * 获取筛选后的竞赛列表 * 支持按类型筛选和收藏筛选 */privategetFilteredCompetitions():Competition[]{letresult=this.competitions;// 按类型筛选if(this.selectedType!=='全部'){result=result.filter(c=>c.type===this.selectedType);}// 按截止时间排序,即将截止的排在前面returnresult.sort((a,b)=>{returnnewDate(a.deadline).getTime()-newDate(b.deadline).getTime();});}/** * 切换竞赛收藏状态 * @param compId 竞赛ID */privatetoggleCollectCompetition(compId:number):void{this.competitions=this.competitions.map(c=>{if(c.id===compId){return{...c,isCollected:!c.isCollected};}returnc;});}3.3 报名竞赛与创建项目
用户报名某个竞赛时,会自动创建一个关联的项目记录。
/** * 报名竞赛并创建项目 * @param compId 竞赛ID * @param compName 竞赛名称 */privateregisterCompetition(compId:number,compName:string):void{// 校验项目名称constprojectName=this.projectNameText.trim();if(projectName.length===0){// 生产环境增加提示return;}// 创建新项目constproject:Project={id:this.nextProjectId,competitionId:compId,competitionName:compName,projectName:projectName,members:[],progress:0,status:'进行中',submitTime:'',award:''};this.projects=[project,...this.projects];this.nextProjectId++;this.projectNameText='';}3.4 团队成员管理
添加和移除团队成员,同时校验人数上限。
/** * 向项目添加团队成员 * @param projectId 项目ID * @param maxMembers 最大人数限制(来自竞赛配置) */privateaddTeamMember(projectId:number,maxMembers:number):void{constmemberName=this.memberNameText.trim();if(memberName.length===0)return;this.projects=this.projects.map(p=>{if(p.id===projectId){// 校验人数上限if(p.members.length>=maxMembers){// 已达人数上限,生产环境提示用户returnp;}constnewMember:TeamMember={name:memberName,studentId:'',role:'成员'};return{...p,members:[...p.members,newMember]};}returnp;});this.memberNameText='';}/** * 移除团队成员 * @param projectId 项目ID * @param memberIndex 成员索引 */privateremoveTeamMember(projectId:number,memberIndex:number):void{this.projects=this.projects.map(p=>{if(p.id===projectId){constnewMembers=p.members.filter((_,idx)=>idx!==memberIndex);return{...p,members:newMembers};}returnp;});}3.5 项目进度更新
进度条是项目管理的核心可视化组件,支持步进更新和直接设置。
/** * 更新项目进度 * @param projectId 项目ID * @param progress 新的进度值(0-100) */privateupdateProgress(projectId:number,progress:number):void{// 进度值边界校验constvalidProgress=Math.max(0,Math.min(100,progress));this.projects=this.projects.map(p=>{if(p.id===projectId){letnewStatus=p.status;// 进度达到100%自动标记为待提交状态if(validProgress>=100&&p.status==='进行中'){newStatus='待提交';}return{...p,progress:validProgress,status:newStatus};}returnp;});}/** * 标记项目已提交 */privatesubmitProject(projectId:number):void{this.projects=this.projects.map(p=>{if(p.id===projectId){return{...p,status:'已提交',submitTime:newDate().toLocaleString(),progress:100};}returnp;});}四、UI 设计与交互体验
4.1 整体布局结构
┌─────────────────────────┐ │ 顶部数据统计栏 │ ← 进行中/已获奖/参赛数/团队人数 ├─────────────────────────┤ │ Tab 切换栏 │ ← 竞赛大厅 / 我的项目 ├─────────────────────────┤ │ 筛选标签栏 │ ← 按类型/级别筛选 ├─────────────────────────┤ │ │ │ 列表内容区 │ ← 竞赛卡片 或 项目卡片 │ │ └─────────────────────────┘4.2 主题色与视觉规范
主色调:亮蓝色 #3B82F6
选择亮蓝色作为主题色的设计考量:
- 科技感契合:蓝色是科技、创新、智慧的代表色,与学科竞赛的学术属性高度匹配
- 专业感传递:相比活泼的暖色调,蓝色传递理性、专业、可信赖的视觉感受
- 状态扩展性强:蓝色系有丰富的色阶变化,可用于进度条渐变、级别区分等场景
- 护眼长时间使用:竞赛准备是长时间的活动,低饱和度蓝色视觉疲劳度更低
辅助色规范:
- 主色调:#3B82F6(亮蓝色)
- 进度条填充:#3B82F6 → #60A5FA 渐变
- 国家级竞赛:#EF4444(红色标签,最高优先级)
- 省级竞赛:#F59E0B(琥珀色标签)
- 校级竞赛:#6B7280(灰色标签)
- 获奖高亮:#F59E0B(金色徽章)
4.3 状态视觉区分表
| 项目状态 | 进度条颜色 | 状态标签 | 操作按钮 |
|---|---|---|---|
| 进行中 | 蓝色渐变 | 蓝色实心标签 | 更新进度、添加成员 |
| 待提交 | 蓝色满格 | 蓝色闪烁标签 | 提交作品 |
| 已提交 | 绿色满格 | 绿色实心标签 | 查看详情 |
| 已获奖 | 金色渐变 | 金色徽章 + 奖项名 | 查看证书 |
| 未获奖 | 灰色满格 | 灰色空心标签 | 复盘总结 |
| 竞赛级别 | 标签颜色 | 视觉权重 | 排序优先级 |
|---|---|---|---|
| 国际级 | 深紫色 | 最高 | 1 |
| 国家级 | 红色 | 高 | 2 |
| 省级 | 琥珀色 | 中 | 3 |
| 校级 | 灰色 | 低 | 4 |
五、关键技术点解析
5.1 进度条的设计与实现思路
进度条是项目管理类应用的核心视觉组件,设计时需要考虑多个维度:
视觉设计三要素:
- 背景轨道:浅灰色背景,定义进度条的总长度和边界
- 填充进度:主题色渐变填充,宽度随进度值变化
- 进度文本:百分比数字,放在进度条右侧或内部
交互设计要点:
- 进度变化时增加平滑过渡动画,避免生硬跳动
- 不同阶段使用不同颜色(如0-30%起步、30-80%进行中、80-100%冲刺)
- 关键节点(25%/50%/75%/100%)可增加里程碑标记
技术实现方案:
在 ArkUI 中,可以使用 Stack 组件叠加背景和填充,通过 width 属性控制填充比例,配合 animation 实现平滑过渡。
5.2 多对多关系的数据建模
学生和竞赛之间本质上是多对多关系:一个学生可以参加多个竞赛,一个竞赛有多个学生参加。
本项目的简化方案:
通过 Project 中间表实现关联,Project 同时持有 competitionId 和成员列表,形成"竞赛-项目-成员"的三级结构。
生产环境的标准方案:
- 建立 User 表、Competition 表、Team 表、TeamMember 表
- Team 关联 Competition,TeamMember 关联 Team 和 User
- 支持一个用户加入多个团队,一个团队对应一个竞赛
这种设计虽然复杂,但支持更丰富的业务场景,如跨项目人员复用、历史队伍复用等。
六、常见问题与优化建议
踩坑点 1:进度值边界溢出
问题表现:用户连续点击增加进度,导致进度超过100%或低于0%
解决方案:更新进度时使用Math.max(0, Math.min(100, value))进行边界钳制
踩坑点 2:成员重复添加
问题表现:同一个人被多次添加到团队中
解决方案:添加前根据学号或姓名查重,重复则提示不添加
踩坑点 3:截止时间计算错误
问题表现:跨时区或日期格式问题导致倒计时不准
解决方案:统一使用时间戳存储和计算,展示层再格式化
踩坑点 4:竞赛列表排序混乱
问题表现:筛选后排序逻辑失效,已截止的竞赛排在前面
解决方案:按状态分组排序(报名中优先),同状态内按截止时间升序
优化方向
- 增加竞赛日历视图,以月历形式展示各竞赛时间节点
- 实现组队大厅功能,支持发布招人信息和寻找队伍
- 接入导师匹配系统,根据竞赛类型推荐指导老师
- 增加作品互评功能,赛前互相评审提升作品质量
七、项目总结与扩展方向
核心收获
通过完成竞赛报名与项目管理项目,你将掌握:
- 多模型关联的数据结构设计方法
- 进度条组件的实现与动画优化
- 团队成员增删改的完整管理逻辑
- 列表筛选与多维度排序的实现技巧
后续扩展功能
- 👥组队大厅:发布招人帖,浏览队伍信息,一键申请加入
- 👨🏫导师匹配:根据竞赛类型和研究方向智能推荐指导老师
- 📝作品互评:赛前匿名互评,互相提建议共同提升
- ⏰赛程提醒:重要时间节点自动推送提醒,不错过截止日期
- 🏆证书生成:获奖后自动生成电子证书,支持分享和下载
- 📊竞赛日历:月视图展示所有竞赛安排,一目了然