HarmonyOS ArkTS 实战:实现一个校园快递代取与跑腿应用

HarmonyOS ArkTS 实战:实现一个校园快递代取与跑腿应用

项目效果

本文使用 HarmonyOS 和 ArkTS 实现一个校园快递代取与跑腿应用。

应用可以发布快递代取和跑腿需求,设置取件地点和送达地点,设置跑腿费用,接单跑腿,查看订单状态,并提供订单筛选、进度更新和收入统计等功能。

项目使用 DevEco Studio 开发,适配 API 23 及以上版本。

运行效果

功能介绍

本项目实现了以下功能:

  • 发布代取或跑腿需求
  • 填写快递信息或跑腿内容
  • 设置取件地点和送达地点
  • 设置期望送达时间
  • 设置跑腿费用
  • 留下联系方式
  • 跑腿员接单
  • 更新订单进度
  • 确认送达完成
  • 按订单状态筛选
  • 统计发布订单、已接单、已完成数量
  • 统计跑腿收入
  • 取消未接单订单

定义数据结构

首先定义跑腿订单的数据结构:

typescript 复制代码
interface ErrandsOrder {
  id: number;
  title: string;
  description: string;
  pickupLocation: string;
  deliveryLocation: string;
  deliveryTime: string;
  fee: number;
  orderType: string;
  publisher: string;
  contact: string;
  runner: string;
  status: string;
  publishTime: string;
}

字段说明如下:

  • id:订单的唯一编号
  • title:订单标题
  • description:详细描述
  • pickupLocation:取件地点
  • deliveryLocation:送达地点
  • deliveryTime:期望送达时间
  • fee:跑腿费用
  • orderType:订单类型(快递代取/食堂带饭/其他跑腿)
  • publisher:发布人
  • contact:联系方式
  • runner:接单跑腿员
  • status:订单状态(待接单/已接单/配送中/已完成/已取消)
  • publishTime:发布时间

初始化页面状态

使用 @State 保存输入内容、订单类型、筛选条件和当前用户:

typescript 复制代码
@State private titleText: string = '';
@State private descriptionText: string = '';
@State private pickupText: string = '';
@State private deliveryText: string = '';
@State private timeText: string = '';
@State private feeText: string = '';
@State private contactText: string = '';
@State private publisherText: string = '';
@State private currentUser: string = '跑腿小哥';
@State private orderType: string = '快递代取';
@State private filterType: string = '全部';
@State private nextId: number = 6;

准备一些初始数据,让应用运行后可以直接展示完整效果:

typescript 复制代码
@State private orders: ErrandsOrder[] = [
  {
    id: 1,
    title: '代取顺丰快递',
    description: '快递码:SF123456,一个小盒子,很轻',
    pickupLocation: '菜鸟驿站(南门)',
    deliveryLocation: '12号楼302宿舍',
    deliveryTime: '今天18:00前',
    fee: 3,
    orderType: '快递代取',
    publisher: '张同学',
    contact: '微信:zhang2026',
    runner: '',
    status: '待接单',
    publishTime: '2026-07-17 14:30'
  },
  {
    id: 2,
    title: '食堂带一份黄焖鸡',
    description: '微辣,不要香菜,多放米饭',
    pickupLocation: '二食堂三楼',
    deliveryLocation: '图书馆四楼A区',
    deliveryTime: '现在就去',
    fee: 5,
    orderType: '食堂带饭',
    publisher: '李同学',
    contact: '电话:138****1234',
    runner: '王同学',
    status: '配送中',
    publishTime: '2026-07-17 11:50'
  },
  {
    id: 3,
    title: '代取京东快递',
    description: '快递码:JD654321,有点重,一箱水',
    pickupLocation: '京东快递点',
    deliveryLocation: '8号楼501宿舍',
    deliveryTime: '今天晚上',
    fee: 4,
    orderType: '快递代取',
    publisher: '赵同学',
    contact: 'QQ:987654321',
    runner: '跑腿小哥',
    status: '已接单',
    publishTime: '2026-07-17 15:20'
  },
  {
    id: 4,
    title: '超市帮买一瓶可乐',
    description: '冰的可口可乐,大瓶',
    pickupLocation: '教育超市',
    deliveryLocation: '操场看台',
    deliveryTime: '10分钟内',
    fee: 2,
    orderType: '其他跑腿',
    publisher: '孙同学',
    contact: '微信:sun123',
    runner: '周同学',
    status: '已完成',
    publishTime: '2026-07-17 10:15'
  }
];

发布跑腿订单

用户填写订单信息后,可以发布新的跑腿需求:

typescript 复制代码
private addOrder(): void {
  const title: string = this.titleText.trim();
  const pickup: string = this.pickupText.trim();
  const delivery: string = this.deliveryText.trim();
  const fee: number = parseInt(this.feeText);
  const publisher: string = this.publisherText.trim();
  const contact: string = this.contactText.trim();

  if (title.length === 0 || pickup.length === 0 || delivery.length === 0 || 
      isNaN(fee) || publisher.length === 0 || contact.length === 0) {
    return;
  }

  const now = new Date();
  const timeStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;

  const order: ErrandsOrder = {
    id: this.nextId,
    title,
    description: this.descriptionText.trim(),
    pickupLocation: pickup,
    deliveryLocation: delivery,
    deliveryTime: this.timeText.trim() || '尽快送达',
    fee,
    orderType: this.orderType,
    publisher,
    contact,
    runner: '',
    status: '待接单',
    publishTime: timeStr
  };

  this.orders = [order, ...this.orders];
  this.nextId += 1;
  this.titleText = '';
  this.descriptionText = '';
  this.pickupText = '';
  this.deliveryText = '';
  this.timeText = '';
  this.feeText = '';
  this.publisherText = '';
  this.contactText = '';
}

新发布的订单默认处于"待接单"状态。

订单状态流转

跑腿订单按照以下流程处理:

复制代码
待接单 -> 已接单 -> 配送中 -> 已完成
   |
   -> 已取消

使用以下方法更新订单状态:

typescript 复制代码
private takeOrder(id: number): void {
  this.orders = this.orders.map((order: ErrandsOrder) => {
    if (order.id === id && order.status === '待接单') {
      return {
        id: order.id,
        title: order.title,
        description: order.description,
        pickupLocation: order.pickupLocation,
        deliveryLocation: order.deliveryLocation,
        deliveryTime: order.deliveryTime,
        fee: order.fee,
        orderType: order.orderType,
        publisher: order.publisher,
        contact: order.contact,
        runner: this.currentUser,
        status: '已接单',
        publishTime: order.publishTime
      };
    }
    return order;
  });
}

private startDelivery(id: number): void {
  this.orders = this.orders.map((order: ErrandsOrder) => {
    if (order.id === id && order.status === '已接单' && order.runner === this.currentUser) {
      return {
        id: order.id,
        title: order.title,
        description: order.description,
        pickupLocation: order.pickupLocation,
        deliveryLocation: order.deliveryLocation,
        deliveryTime: order.deliveryTime,
        fee: order.fee,
        orderType: order.orderType,
        publisher: order.publisher,
        contact: order.contact,
        runner: order.runner,
        status: '配送中',
        publishTime: order.publishTime
      };
    }
    return order;
  });
}

private completeOrder(id: number): void {
  this.orders = this.orders.map((order: ErrandsOrder) => {
    if (order.id === id && order.status === '配送中') {
      return {
        id: order.id,
        title: order.title,
        description: order.description,
        pickupLocation: order.pickupLocation,
        deliveryLocation: order.deliveryLocation,
        deliveryTime: order.deliveryTime,
        fee: order.fee,
        orderType: order.orderType,
        publisher: order.publisher,
        contact: order.contact,
        runner: order.runner,
        status: '已完成',
        publishTime: order.publishTime
      };
    }
    return order;
  });
}

待接单状态点击"接单"后变为已接单;已接单状态点击"开始配送"后变为配送中;配送中状态点击"确认送达"后变为已完成。

取消订单

未接单的订单可以取消:

typescript 复制代码
private cancelOrder(id: number): void {
  this.orders = this.orders.map((order: ErrandsOrder) => {
    if (order.id === id && order.status === '待接单') {
      return {
        id: order.id,
        title: order.title,
        description: order.description,
        pickupLocation: order.pickupLocation,
        deliveryLocation: order.deliveryLocation,
        deliveryTime: order.deliveryTime,
        fee: order.fee,
        orderType: order.orderType,
        publisher: order.publisher,
        contact: order.contact,
        runner: order.runner,
        status: '已取消',
        publishTime: order.publishTime
      };
    }
    return order;
  });
}

只有待接单状态的订单可以取消。

筛选订单

页面支持按照订单状态筛选:

typescript 复制代码
private getFilteredOrders(): ErrandsOrder[] {
  if (this.filterType === '待接单') {
    return this.orders.filter(
      (order: ErrandsOrder) => order.status === '待接单'
    );
  }
  if (this.filterType === '进行中') {
    return this.orders.filter(
      (order: ErrandsOrder) => order.status === '已接单' || order.status === '配送中'
    );
  }
  if (this.filterType === '已完成') {
    return this.orders.filter(
      (order: ErrandsOrder) => order.status === '已完成'
    );
  }
  if (this.filterType === '我接的单') {
    return this.orders.filter(
      (order: ErrandsOrder) => order.runner === this.currentUser
    );
  }
  return this.orders;
}

筛选按钮封装如下:

typescript 复制代码
@Builder
FilterButton(text: string) {
  Button(text)
    .height(34)
    .layoutWeight(1)
    .fontSize(12)
    .fontColor(this.filterType === text ? Color.White : '#344054')
    .backgroundColor(
      this.filterType === text ? '#65A30D' : '#ECFCCB'
    )
    .borderRadius(8)
    .onClick(() => {
      this.filterType = text;
    });
}

选择订单类型

页面支持多种跑腿类型选择:

typescript 复制代码
@Builder
TypeButton(text: string) {
  Button(text)
    .height(34)
    .layoutWeight(1)
    .fontSize(12)
    .fontColor(this.orderType === text ? Color.White : '#344054')
    .backgroundColor(
      this.orderType === text ? '#65A30D' : '#F3F4F6'
    )
    .borderRadius(8)
    .onClick(() => {
      this.orderType = text;
    });
}

不同订单类型使用黄绿色主题色高亮显示。

统计订单和收入

统计各类订单数量和跑腿收入:

typescript 复制代码
private getOrderCount(status: string): number {
  if (status === '待接单') {
    return this.orders.filter((o: ErrandsOrder) => o.status === '待接单').length;
  }
  if (status === '进行中') {
    return this.orders.filter((o: ErrandsOrder) => 
      o.status === '已接单' || o.status === '配送中'
    ).length;
  }
  if (status === '已完成') {
    return this.orders.filter((o: ErrandsOrder) => o.status === '已完成').length;
  }
  return this.orders.length;
}

private getMyIncome(): number {
  return this.orders
    .filter((o: ErrandsOrder) => o.runner === this.currentUser && o.status === '已完成')
    .reduce((sum: number, o: ErrandsOrder) => sum + o.fee, 0);
}

顶部统计区域展示全部订单、待接单、进行中和我的收入:

typescript 复制代码
this.StatCard(
  '全部订单',
  `${this.orders.length}`,
  '#65A30D',
  '#F7FEE7'
);
this.StatCard(
  '待接单',
  `${this.getOrderCount('待接单')}`,
  '#D97706',
  '#FFF7E8'
);
this.StatCard(
  '进行中',
  `${this.getOrderCount('进行中')}`,
  '#2563EB',
  '#EFF6FF'
);
this.StatCard(
  '我的收入',
  `¥${this.getMyIncome()}`,
  '#059669',
  '#ECFDF5'
);

设置状态颜色

不同订单状态使用不同颜色:

typescript 复制代码
private getStatusColor(status: string): ResourceColor {
  if (status === '待接单') {
    return '#D97706';
  }
  if (status === '已接单') {
    return '#2563EB';
  }
  if (status === '配送中') {
    return '#7C3AED';
  }
  if (status === '已完成') {
    return '#059669';
  }
  return '#6B7280';
}

private getStatusBgColor(status: string): ResourceColor {
  if (status === '待接单') {
    return '#FEF3C7';
  }
  if (status === '已接单') {
    return '#DBEAFE';
  }
  if (status === '配送中') {
    return '#F3E8FF';
  }
  if (status === '已完成') {
    return '#DCFCE7';
  }
  return '#F3F4F6';
}

颜色含义如下:

  • 橙色:待接单
  • 蓝色:已接单
  • 紫色:配送中
  • 绿色:已完成
  • 灰色:已取消
  • 黄绿色:页面主题色

使用列表展示订单

使用 ListForEach 渲染筛选后的订单:

typescript 复制代码
List({ space: 12 }) {
  ForEach(
    this.getFilteredOrders(),
    (order: ErrandsOrder) => {
      ListItem() {
        this.OrderCard(order)
      }
    },
    (order: ErrandsOrder) => order.id.toString()
  );
}
.width('100%')
.layoutWeight(1)
.scrollBar(BarState.Off);

每个订单使用独立卡片展示,卡片中包含订单标题、描述、取件地点、送达地点、时间、费用、类型、发布人、状态和操作按钮。

页面设计说明

应用使用黄绿色作为主题色,适合跑腿服务充满活力的感觉。

页面主要分为以下区域:

  1. 顶部标题和今日订单数
  2. 订单数据和收入统计区域
  3. 发布跑腿订单表单
  4. 订单状态筛选区域
  5. 订单列表

页面采用浅灰色背景和白色卡片。待接单使用橙色,已接单使用蓝色,配送中使用紫色,已完成使用绿色,费用使用大号绿色字体突出显示,便于快速浏览。

SDK 配置

本项目使用 HarmonyOS API 24,满足 API 23 及以上要求:

json5 复制代码
{
  "name": "default",
  "compatibleSdkVersion": "6.1.1(24)",
  "runtimeOS": "HarmonyOS",
  "targetSdkVersion": "6.1.1(24)",
  "compileSdkVersion": "6.1.1(24)"
}

entry 模块中的运行系统也要保持一致:

json5 复制代码
{
  "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 订单卡片布局

后续还可以加入订单图片上传、实时位置共享、聊天功能、评价系统、跑腿员认证、悬赏功能和信用分机制等功能。

相关推荐
2301_768103496 小时前
HarmonyOS趣味相机实战第13篇:CameraPicker与CameraKit选型、系统拍照回退及架构边界
harmonyos·arkts·架构设计·camerapicker·camerakit
2301_768103497 小时前
HarmonyOS趣味相机实战第14篇:装饰素材强类型建模、锚点语义与套装组合校验
harmonyos·arkts·数据建模·arkui·相机贴纸
不羁的木木7 小时前
HarmonyOS技术精讲-Connectivity Kit:Wi-Fi进阶能力——热点、P2P与Aware
asp.net·harmonyos·p2p
Helen_cai8 小时前
HarmonyOS ArkTS 实战:实现一个校园宿舍管理与查寝应用
华为·harmonyos
listening7778 小时前
HarmonyOS ArkTS 实战:实现一个校园打印复印预约应用
华为·harmonyos
绝世番茄8 小时前
鸿蒙原生 ArkTS 布局之道:Grid 替代多层嵌套布局深度解析
华为·harmonyos·鸿蒙
●VON8 小时前
鸿蒙 PC Markdown 编辑器可靠性设计:未保存内容的崩溃恢复闭环
华为·中间件·编辑器·harmonyos·鸿蒙
listening7778 小时前
《从算法到落地:基于HarmonyOS API 23的端侧图像推理实战》
算法·华为·harmonyos
●VON9 小时前
鸿蒙 PC Markdown 编辑器导出架构:安全 HTML 与系统 PDF
华为·架构·编辑器·harmonyos·鸿蒙