HarmonyOS ArkTS 实战:实现一个校园兼职与勤工助学应用
HarmonyOS ArkTS 实战:实现一个校园兼职与勤工助学应用
项目效果
本文使用 HarmonyOS 和 ArkTS 实现一个校园兼职与勤工助学应用。
应用可以发布兼职岗位信息,查看工作内容和薪资,在线申请兼职,招聘方审核申请,并提供岗位分类筛选、申请状态查看和薪资统计等功能。
项目使用 DevEco Studio 开发,适配 API 23 及以上版本。
运行效果

功能介绍
本项目实现了以下功能:
- 发布兼职岗位
- 设置岗位名称和工作内容
- 设置薪资待遇和工作时间
- 选择工作地点和兼职类型
- 设置招聘人数和联系方式
- 浏览兼职岗位
- 在线申请兼职
- 填写个人信息和自我介绍
- 招聘方审核申请
- 录用/不录用申请
- 完成工作确认
- 按兼职类型筛选
- 统计在招岗位、已申请、已录用数量
- 收藏岗位
- 取消申请
定义数据结构
首先定义兼职岗位和申请的数据结构:
interface JobApplication {
id: number;
studentId: string;
name: string;
phone: string;
introduce: string;
status: string;
applyTime: string;
}
interface PartTimeJob {
id: number;
title: string;
description: string;
salary: string;
workTime: string;
location: string;
jobType: string;
employer: string;
contact: string;
maxRecruits: number;
applications: JobApplication[];
status: string;
isCollected: boolean;
publishTime: string;
}
字段说明如下:
JobApplication:兼职申请id:申请编号studentId:学号name:姓名phone:联系方式introduce:自我介绍status:申请状态(待审核/已录用/已拒绝/已完成)applyTime:申请时间
PartTimeJob:兼职岗位id:岗位编号title:岗位名称description:工作内容salary:薪资待遇workTime:工作时间location:工作地点jobType:兼职类型(校内勤工/校外兼职/家教/实习)employer:招聘方contact:联系方式maxRecruits:招聘人数applications:申请列表status:岗位状态(招聘中/已截止/已结束)isCollected:是否收藏publishTime:发布时间
初始化页面状态
使用 @State 保存输入内容、类型选择、筛选条件和当前用户:
@State private jobTitleText: string = '';
@State private descText: string = '';
@State private salaryText: string = '';
@State private workTimeText: string = '';
@State private locationText: string = '';
@State private employerText: string = '';
@State private contactText: string = '';
@State private maxRecruitsText: string = '';
@State private applyNameText: string = '';
@State private applyIdText: string = '';
@State private applyPhoneText: string = '';
@State private applyIntroText: string = '';
@State private selectedType: string = '校内勤工';
@State private filterType: string = '全部';
@State private currentUserId: string = '2023001';
@State private nextJobId: number = 5;
@State private nextApplyId: number = 10;
准备一些初始兼职数据:
@State private jobs: PartTimeJob[] = [
{
id: 1,
title: '图书馆整理员',
description: '整理图书,上架归还书籍,维持阅览秩序,工作轻松',
salary: '18元/小时',
workTime: '每周一、三、五 18:00-21:00',
location: '校图书馆',
jobType: '校内勤工',
employer: '图书馆',
contact: '李老师 021-12345678',
maxRecruits: 5,
applications: [
{
id: 1,
studentId: '2023001',
name: '王同学',
phone: '138****1234',
introduce: '时间充裕,做事认真负责',
status: '待审核',
applyTime: '2026-07-15'
}
],
status: '招聘中',
isCollected: false,
publishTime: '2026-07-10'
},
{
id: 2,
title: '奶茶店兼职',
description: '制作饮品,点单收银,打扫卫生,有培训',
salary: '22元/小时,包饮品',
workTime: '周末全天,工作日晚班',
location: '学校门口奶茶店',
jobType: '校外兼职',
employer: '茶百道',
contact: '张店长 139****5678',
maxRecruits: 3,
applications: [],
status: '招聘中',
isCollected: true,
publishTime: '2026-07-12'
},
{
id: 3,
title: '初中数学家教',
description: '辅导初二数学,每周两次,每次两小时,要求数学基础好',
salary: '80元/小时',
workTime: '周六周日上午',
location: '学生家里(地铁可达)',
jobType: '家教',
employer: '陈女士',
contact: '137****9012',
maxRecruits: 1,
applications: [
{
id: 2,
studentId: '2022005',
name: '赵同学',
phone: '136****3456',
introduce: '高考数学140,有家教经验',
status: '已录用',
applyTime: '2026-07-08'
}
],
status: '招聘中',
isCollected: false,
publishTime: '2026-07-05'
},
{
id: 4,
title: '互联网公司运营实习',
description: '协助运营工作,内容编辑,数据整理,可开实习证明',
salary: '150元/天',
workTime: '周一至周五 9:00-18:00',
location: '张江高科技园区',
jobType: '实习',
employer: '某互联网公司',
contact: 'HR hr@company.com',
maxRecruits: 2,
applications: [],
status: '已截止',
isCollected: false,
publishTime: '2026-06-20'
}
];
发布兼职岗位
用户可以发布新的兼职岗位:
private publishJob(): void {
const title: string = this.jobTitleText.trim();
const desc: string = this.descText.trim();
const salary: string = this.salaryText.trim();
const workTime: string = this.workTimeText.trim();
const location: string = this.locationText.trim();
const employer: string = this.employerText.trim();
const contact: string = this.contactText.trim();
const max: number = parseInt(this.maxRecruitsText);
if (title.length === 0 || desc.length === 0 || salary.length === 0 ||
workTime.length === 0 || employer.length === 0 || isNaN(max)) {
return;
}
const job: PartTimeJob = {
id: this.nextJobId,
title,
description: desc,
salary,
workTime,
location,
jobType: this.selectedType,
employer,
contact,
maxRecruits: max,
applications: [],
status: '招聘中',
isCollected: false,
publishTime: new Date().toISOString().split('T')[0]
};
this.jobs = [job, ...this.jobs];
this.nextJobId += 1;
this.jobTitleText = '';
this.descText = '';
this.salaryText = '';
this.workTimeText = '';
this.locationText = '';
this.employerText = '';
this.contactText = '';
this.maxRecruitsText = '';
}
新发布的岗位默认处于"招聘中"状态。
申请兼职
学生可以申请兼职岗位:
private applyJob(jobId: number): void {
const name: string = this.applyNameText.trim();
const studentId: string = this.applyIdText.trim();
const phone: string = this.applyPhoneText.trim();
if (name.length === 0 || studentId.length === 0 || phone.length === 0) {
return;
}
this.jobs = this.jobs.map((job: PartTimeJob) => {
if (job.id === jobId && job.status === '招聘中') {
const alreadyApplied = job.applications.some(a => a.studentId === studentId);
if (!alreadyApplied) {
const newApplication: JobApplication = {
id: this.nextApplyId,
studentId,
name,
phone,
introduce: this.applyIntroText.trim(),
status: '待审核',
applyTime: new Date().toISOString().split('T')[0]
};
this.nextApplyId += 1;
return {
id: job.id,
title: job.title,
description: job.description,
salary: job.salary,
workTime: job.workTime,
location: job.location,
jobType: job.jobType,
employer: job.employer,
contact: job.contact,
maxRecruits: job.maxRecruits,
applications: [newApplication, ...job.applications],
status: job.status,
isCollected: job.isCollected,
publishTime: job.publishTime
};
}
}
return job;
});
this.applyNameText = '';
this.applyIdText = '';
this.applyPhoneText = '';
this.applyIntroText = '';
}
已经申请过的不能重复申请。
审核申请
招聘方可以审核申请:
private reviewApplication(jobId: number, applyId: number, approved: boolean): void {
this.jobs = this.jobs.map((job: PartTimeJob) => {
if (job.id === jobId) {
const updatedApplications = job.applications.map((app: JobApplication) => {
if (app.id === applyId && app.status === '待审核') {
return {
id: app.id,
studentId: app.studentId,
name: app.name,
phone: app.phone,
introduce: app.introduce,
status: approved ? '已录用' : '已拒绝',
applyTime: app.applyTime
};
}
return app;
});
return {
id: job.id,
title: job.title,
description: job.description,
salary: job.salary,
workTime: job.workTime,
location: job.location,
jobType: job.jobType,
employer: job.employer,
contact: job.contact,
maxRecruits: job.maxRecruits,
applications: updatedApplications,
status: job.status,
isCollected: job.isCollected,
publishTime: job.publishTime
};
}
return job;
});
}
审核通过标记为已录用,拒绝标记为已拒绝。
收藏和取消收藏
用户可以收藏感兴趣的岗位:
private toggleCollect(jobId: number): void {
this.jobs = this.jobs.map((job: PartTimeJob) => {
if (job.id === jobId) {
return {
id: job.id,
title: job.title,
description: job.description,
salary: job.salary,
workTime: job.workTime,
location: job.location,
jobType: job.jobType,
employer: job.employer,
contact: job.contact,
maxRecruits: job.maxRecruits,
applications: job.applications,
status: job.status,
isCollected: !job.isCollected,
publishTime: job.publishTime
};
}
return job;
});
}
点击收藏按钮切换收藏状态。
截止和结束岗位
招聘方可以截止招聘或标记工作完成:
private closeJob(jobId: number): void {
this.jobs = this.jobs.map((job: PartTimeJob) => {
if (job.id === jobId && job.status === '招聘中') {
return {
id: job.id,
title: job.title,
description: job.description,
salary: job.salary,
workTime: job.workTime,
location: job.location,
jobType: job.jobType,
employer: job.employer,
contact: job.contact,
maxRecruits: job.maxRecruits,
applications: job.applications,
status: '已截止',
isCollected: job.isCollected,
publishTime: job.publishTime
};
}
return job;
});
}
private completeJob(jobId: number): void {
this.jobs = this.jobs.map((job: PartTimeJob) => {
if (job.id === jobId) {
const updatedApplications = job.applications.map((app: JobApplication) => {
if (app.status === '已录用') {
return {
id: app.id,
studentId: app.studentId,
name: app.name,
phone: app.phone,
introduce: app.introduce,
status: '已完成',
applyTime: app.applyTime
};
}
return app;
});
return {
id: job.id,
title: job.title,
description: job.description,
salary: job.salary,
workTime: job.workTime,
location: job.location,
jobType: job.jobType,
employer: job.employer,
contact: job.contact,
maxRecruits: job.maxRecruits,
applications: updatedApplications,
status: '已结束',
isCollected: job.isCollected,
publishTime: job.publishTime
};
}
return job;
});
}
截止后不再接受新申请,工作结束后录用的申请标记为已完成。
筛选岗位
页面支持按类型筛选岗位:
private getFilteredJobs(): PartTimeJob[] {
if (this.filterType === '全部') {
return this.jobs;
}
if (this.filterType === '我收藏的') {
return this.jobs.filter((job: PartTimeJob) => job.isCollected);
}
if (this.filterType === '我申请的') {
return this.jobs.filter((job: PartTimeJob) =>
job.applications.some(a => a.studentId === this.currentUserId)
);
}
return this.jobs.filter(
(job: PartTimeJob) => job.jobType === this.filterType
);
}
类型选择按钮封装:
@Builder
TypeButton(text: string) {
Button(text)
.height(32)
.padding({ left: 12, right: 12 })
.fontSize(12)
.fontColor(this.selectedType === text ? Color.White : '#344054')
.backgroundColor(
this.selectedType === text ? '#E11D48' : '#F3F4F6'
)
.borderRadius(16)
.onClick(() => {
this.selectedType = text;
});
}
@Builder
FilterButton(text: string) {
Button(text)
.height(34)
.padding({ left: 12, right: 12 })
.fontSize(12)
.fontColor(this.filterType === text ? Color.White : '#344054')
.backgroundColor(
this.filterType === text ? '#E11D48' : '#FFE4E6'
)
.borderRadius(17)
.onClick(() => {
this.filterType = text;
});
}
统计数据
统计在招岗位、已申请和已录用数量:
private getRecruitingCount(): number {
return this.jobs.filter((j: PartTimeJob) => j.status === '招聘中').length;
}
private getMyAppliedCount(): number {
return this.jobs.filter((j: PartTimeJob) =>
j.applications.some(a => a.studentId === this.currentUserId)
).length;
}
private getMyAcceptedCount(): number {
let count = 0;
this.jobs.forEach((j: PartTimeJob) => {
j.applications.forEach(a => {
if (a.studentId === this.currentUserId && (a.status === '已录用' || a.status === '已完成')) {
count++;
}
});
});
return count;
}
顶部统计区域展示在招岗位、我申请的、已录用:
this.StatCard(
'在招岗位',
`${this.getRecruitingCount()}`,
'#E11D48',
'#FFF1F2'
);
this.StatCard(
'我申请的',
`${this.getMyAppliedCount()}`,
'#D97706',
'#FFF7E8'
);
this.StatCard(
'已录用',
`${this.getMyAcceptedCount()}`,
'#059669',
'#ECFDF5'
);
设置状态颜色
不同申请和岗位状态使用不同颜色:
private getApplyStatusColor(status: string): ResourceColor {
if (status === '待审核') {
return '#D97706';
}
if (status === '已录用') {
return '#059669';
}
if (status === '已完成') {
return '#2563EB';
}
return '#6B7280';
}
private getApplyStatusBgColor(status: string): ResourceColor {
if (status === '待审核') {
return '#FEF3C7';
}
if (status === '已录用') {
return '#DCFCE7';
}
if (status === '已完成') {
return '#DBEAFE';
}
return '#F3F4F6';
}
private getJobStatusColor(status: string): ResourceColor {
if (status === '招聘中') {
return '#059669';
}
if (status === '已截止') {
return '#D97706';
}
return '#6B7280';
}
颜色含义如下:
- 绿色:招聘中/已录用
- 橙色:待审核/已截止
- 蓝色:已完成
- 灰色:已拒绝/已结束
- 玫瑰色:页面主题色
使用列表展示岗位
使用 List 和 ForEach 渲染筛选后的岗位:
List({ space: 12 }) {
ForEach(
this.getFilteredJobs(),
(job: PartTimeJob) => {
ListItem() {
this.JobCard(job)
}
},
(job: PartTimeJob) => job.id.toString()
);
}
.width('100%')
.layoutWeight(1)
.scrollBar(BarState.Off);
每个岗位使用独立卡片展示,卡片中包含岗位名称、薪资、工作时间、地点、类型、招聘方、状态、收藏按钮和操作按钮。
页面设计说明
应用使用玫瑰色作为主题色,充满活力适合兼职招聘场景。
页面主要分为以下区域:
- 顶部标题和兼职季提示
- 数据统计区域
- 发布岗位表单
- 岗位类型筛选区域
- 岗位列表
- 申请弹窗和申请管理
页面采用浅灰色背景和白色卡片。薪资使用大号玫瑰色字体突出显示,招聘中使用绿色标签,收藏使用心形图标,申请状态使用对应颜色标签,便于快速浏览岗位信息。
SDK 配置
本项目使用 HarmonyOS API 24,满足 API 23 及以上要求:
{
"name": "default",
"compatibleSdkVersion": "6.1.1(24)",
"runtimeOS": "HarmonyOS",
"targetSdkVersion": "6.1.1(24)",
"compileSdkVersion": "6.1.1(24)"
}
entry 模块中的运行系统也要保持一致:
{
"apiType": "stageMode",
"targets": [
{
"name": "default",
"runtimeOS": "HarmonyOS"
}
]
}
运行项目
使用 DevEco Studio 打开项目,然后找到:
entry/src/main/ets/pages/Index.ets
等待项目同步完成,点击右侧的 Preview 按钮即可查看应用效果。
项目总结
本文使用 HarmonyOS 和 ArkTS 实现了一个校园兼职与勤工助学应用。
项目实现了岗位发布、类型选择、薪资展示、在线申请、申请审核、录用管理、收藏功能、岗位筛选、数据统计等功能。
通过这个项目可以掌握:
- ArkTS 接口定义和嵌套数据结构
@State状态管理- 招聘申请流程
List和ForEach列表渲染map和filter数组操作- 收藏功能实现
- 多状态管理
- 自定义
@Builder组件 - HarmonyOS 招聘类应用布局
后续还可以加入企业认证、薪资结算、工作评价、简历上传、面试通知、兼职保险、黑名单机制和薪资维权等功能。
更多推荐


所有评论(0)