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';
}

颜色含义如下:

  • 绿色:招聘中/已录用
  • 橙色:待审核/已截止
  • 蓝色:已完成
  • 灰色:已拒绝/已结束
  • 玫瑰色:页面主题色

使用列表展示岗位

使用 ListForEach 渲染筛选后的岗位:

List({ space: 12 }) {
  ForEach(
    this.getFilteredJobs(),
    (job: PartTimeJob) => {
      ListItem() {
        this.JobCard(job)
      }
    },
    (job: PartTimeJob) => job.id.toString()
  );
}
.width('100%')
.layoutWeight(1)
.scrollBar(BarState.Off);

每个岗位使用独立卡片展示,卡片中包含岗位名称、薪资、工作时间、地点、类型、招聘方、状态、收藏按钮和操作按钮。

页面设计说明

应用使用玫瑰色作为主题色,充满活力适合兼职招聘场景。

页面主要分为以下区域:

  1. 顶部标题和兼职季提示
  2. 数据统计区域
  3. 发布岗位表单
  4. 岗位类型筛选区域
  5. 岗位列表
  6. 申请弹窗和申请管理

页面采用浅灰色背景和白色卡片。薪资使用大号玫瑰色字体突出显示,招聘中使用绿色标签,收藏使用心形图标,申请状态使用对应颜色标签,便于快速浏览岗位信息。

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 状态管理
  • 招聘申请流程
  • ListForEach 列表渲染
  • mapfilter 数组操作
  • 收藏功能实现
  • 多状态管理
  • 自定义 @Builder 组件
  • HarmonyOS 招聘类应用布局

后续还可以加入企业认证、薪资结算、工作评价、简历上传、面试通知、兼职保险、黑名单机制和薪资维权等功能。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐