HarmonyOS ArkTS 实战:实现一个校园打印复印预约应用

HarmonyOS ArkTS 实战:实现一个校园打印复印预约应用

项目效果

本文使用 HarmonyOS 和 ArkTS 实现一个校园打印复印预约应用。

应用可以上传文件,选择打印参数,选择打印店,预约取件时间,在线支付,并提供打印状态跟踪、取件码和消费统计等功能。

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

运行效果

功能介绍

本项目实现了以下功能:

  • 上传打印文件
  • 选择打印类型(黑白/彩色)
  • 选择单双面
  • 设置打印份数
  • 选择打印店
  • 预约取件时间
  • 费用计算
  • 在线支付
  • 打印状态跟踪
  • 取件码生成
  • 按状态筛选订单
  • 消费统计

定义数据结构

首先定义打印订单的数据结构:

typescript 复制代码
interface PrintOrder {
  id: number;
  fileName: string;
  fileType: string;
  printType: string;
  duplex: string;
  copies: number;
  pages: number;
  shopName: string;
  pickupTime: string;
  price: number;
  status: string;
  pickupCode: string;
  remark: string;
  submitTime: string;
  payTime: string;
  completeTime: string;
}

字段说明如下:

  • PrintOrder:打印订单
    • id:订单编号
    • fileName:文件名
    • fileType:文件类型(文档/图片/PPT/PDF)
    • printType:打印类型(黑白/彩色)
    • duplex:单双面(单面/双面)
    • copies:份数
    • pages:页数
    • shopName:打印店
    • pickupTime:取件时间
    • price:价格
    • status:状态(待支付/打印中/待取件/已完成/已取消)
    • pickupCode:取件码
    • remark:备注
    • submitTime:提交时间
    • payTime:支付时间
    • completeTime:完成时间

初始化页面状态

使用 @State 保存打印参数、选择项:

typescript 复制代码
@State private fileNameText: string = '';
@State private copiesText: string = '1';
@State private pagesText: string = '';
@State private pickupTimeText: string = '';
@State private remarkText: string = '';
@State private selectedFileType: string = 'PDF';
@State private selectedPrintType: string = '黑白';
@State private selectedDuplex: string = '单面';
@State private selectedShop: string = '图书馆打印店';
@State private filterStatus: string = '全部';
@State private nextOrderId: number = 5;

准备一些初始订单数据:

typescript 复制代码
@State private orders: PrintOrder[] = [
  {
    id: 1,
    fileName: '毕业论文初稿.pdf',
    fileType: 'PDF',
    printType: '黑白',
    duplex: '双面',
    copies: 2,
    pages: 30,
    shopName: '图书馆打印店',
    pickupTime: '2026-07-16 15:00',
    price: 6,
    status: '待取件',
    pickupCode: 'A302',
    remark: '装订成册',
    submitTime: '2026-07-15 10:30',
    payTime: '2026-07-15 10:32',
    completeTime: ''
  },
  {
    id: 2,
    fileName: '竞赛海报.png',
    fileType: '图片',
    printType: '彩色',
    duplex: '单面',
    copies: 5,
    pages: 1,
    shopName: '东门图文店',
    pickupTime: '2026-07-15 14:00',
    price: 25,
    status: '已完成',
    pickupCode: 'B105',
    remark: '铜版纸打印',
    submitTime: '2026-07-14 16:20',
    payTime: '2026-07-14 16:22',
    completeTime: '2026-07-15 13:45'
  },
  {
    id: 3,
    fileName: '复习资料.docx',
    fileType: '文档',
    printType: '黑白',
    duplex: '双面',
    copies: 1,
    pages: 20,
    shopName: '宿舍楼下打印店',
    pickupTime: '2026-07-18 10:00',
    price: 2,
    status: '待支付',
    pickupCode: '',
    remark: '',
    submitTime: '2026-07-17 20:15',
    payTime: '',
    completeTime: ''
  }
];

计算价格

根据打印参数自动计算价格:

typescript 复制代码
private calculatePrice(): number {
  const pages = parseInt(this.pagesText) || 0;
  const copies = parseInt(this.copiesText) || 1;
  let pricePerPage = 0.1; // 黑白单面
  
  if (this.selectedPrintType === '彩色' && this.selectedDuplex === '单面') {
    pricePerPage = 1;
  } else if (this.selectedPrintType === '彩色' && this.selectedDuplex === '双面') {
    pricePerPage = 0.8;
  } else if (this.selectedPrintType === '黑白' && this.selectedDuplex === '双面') {
    pricePerPage = 0.08;
  }

  const totalPages = pages * copies;
  let total = totalPages * pricePerPage;
  
  if (this.selectedShop === '东门图文店') {
    total += 1; // 服务费
  }
  
  return Math.round(total * 10) / 10;
}

价格规则:

  • 黑白单面:0.1元/页
  • 黑白双面:0.08元/页
  • 彩色单面:1元/页
  • 彩色双面:0.8元/页
  • 东门图文店加收1元服务费

提交订单

用户提交打印订单:

typescript 复制代码
private submitOrder(): void {
  const fileName = this.fileNameText.trim();
  const pages = parseInt(this.pagesText);
  const copies = parseInt(this.copiesText);
  const pickupTime = this.pickupTimeText.trim();

  if (fileName.length === 0 || isNaN(pages) || isNaN(copies) || pickupTime.length === 0) {
    return;
  }

  const now = new Date();
  const submitTime = `${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 code = String.fromCharCode(65 + Math.floor(Math.random() * 3)) + 
               String(Math.floor(Math.random() * 900) + 100);

  const order: PrintOrder = {
    id: this.nextOrderId,
    fileName,
    fileType: this.selectedFileType,
    printType: this.selectedPrintType,
    duplex: this.selectedDuplex,
    copies,
    pages,
    shopName: this.selectedShop,
    pickupTime,
    price: this.calculatePrice(),
    status: '待支付',
    pickupCode: '',
    remark: this.remarkText.trim(),
    submitTime,
    payTime: '',
    completeTime: ''
  };

  this.orders = [order, ...this.orders];
  this.nextOrderId += 1;
  this.fileNameText = '';
  this.pagesText = '';
  this.copiesText = '1';
  this.pickupTimeText = '';
  this.remarkText = '';
}

支付和状态更新

typescript 复制代码
private payOrder(orderId: number): void {
  const now = new Date();
  const payTime = `${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 code = String.fromCharCode(65 + Math.floor(Math.random() * 3)) + 
               String(Math.floor(Math.random() * 900) + 100);

  this.orders = this.orders.map((order: PrintOrder) => {
    if (order.id === orderId && order.status === '待支付') {
      return {
        id: order.id,
        fileName: order.fileName,
        fileType: order.fileType,
        printType: order.printType,
        duplex: order.duplex,
        copies: order.copies,
        pages: order.pages,
        shopName: order.shopName,
        pickupTime: order.pickupTime,
        price: order.price,
        status: '打印中',
        pickupCode: code,
        remark: order.remark,
        submitTime: order.submitTime,
        payTime,
        completeTime: ''
      };
    }
    return order;
  });
}

private completeOrder(orderId: number): void {
  const now = new Date();
  const completeTime = `${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')}`;

  this.orders = this.orders.map((order: PrintOrder) => {
    if (order.id === orderId && order.status === '待取件') {
      return {
        id: order.id,
        fileName: order.fileName,
        fileType: order.fileType,
        printType: order.printType,
        duplex: order.duplex,
        copies: order.copies,
        pages: order.pages,
        shopName: order.shopName,
        pickupTime: order.pickupTime,
        price: order.price,
        status: '已完成',
        pickupCode: order.pickupCode,
        remark: order.remark,
        submitTime: order.submitTime,
        payTime: order.payTime,
        completeTime
      };
    }
    return order;
  });
}

打印店自动更新状态:待支付 -> 打印中 -> 待取件 -> 已完成

取消订单

typescript 复制代码
private cancelOrder(orderId: number): void {
  this.orders = this.orders.map((order: PrintOrder) => {
    if (order.id === orderId && order.status === '待支付') {
      return {
        id: order.id,
        fileName: order.fileName,
        fileType: order.fileType,
        printType: order.printType,
        duplex: order.duplex,
        copies: order.copies,
        pages: order.pages,
        shopName: order.shopName,
        pickupTime: order.pickupTime,
        price: order.price,
        status: '已取消',
        pickupCode: '',
        remark: order.remark,
        submitTime: order.submitTime,
        payTime: '',
        completeTime: ''
      };
    }
    return order;
  });
}

筛选订单

typescript 复制代码
private getFilteredOrders(): PrintOrder[] {
  if (this.filterStatus === '全部') {
    return this.orders;
  }
  return this.orders.filter(o => o.status === this.filterStatus);
}

打印类型按钮封装:

typescript 复制代码
@Builder
PrintTypeButton(text: string) {
  Button(text)
    .height(32)
    .padding({ left: 14, right: 14 })
    .fontSize(12)
    .fontColor(this.selectedPrintType === text ? Color.White : '#344054')
    .backgroundColor(
      this.selectedPrintType === text ? '#06B6D4' : '#CFFAFE'
    )
    .borderRadius(16)
    .onClick(() => {
      this.selectedPrintType = text;
    });
}

统计数据

typescript 复制代码
private getPrintingCount(): number {
  return this.orders.filter(o => o.status === '打印中' || o.status === '待取件').length;
}

private getCompletedCount(): number {
  return this.orders.filter(o => o.status === '已完成').length;
}

private getTotalSpent(): number {
  return this.orders
    .filter(o => o.status !== '待支付' && o.status !== '已取消')
    .reduce((sum, o) => sum + o.price, 0);
}

private getTotalPages(): number {
  return this.orders
    .filter(o => o.status === '已完成')
    .reduce((sum, o) => sum + o.pages * o.copies, 0);
}

顶部统计区域展示打印中、已完成、总消费、总页数:

typescript 复制代码
this.StatCard(
  '打印中',
  `${this.getPrintingCount()}`,
  '#06B6D4',
  '#ECFEFF'
);
this.StatCard(
  '已完成',
  `${this.getCompletedCount()}`,
  '#059669',
  '#ECFDF5'
);
this.StatCard(
  '总消费',
  `¥${this.getTotalSpent().toFixed(1)}`,
  '#D97706',
  '#FFF7E8'
);
this.StatCard(
  '总页数',
  `${this.getTotalPages()}页`,
  '#2563EB',
  '#EFF6FF'
);

设置状态颜色

typescript 复制代码
private getStatusColor(status: string): ResourceColor {
  if (status === '待支付') return '#DC2626';
  if (status === '打印中') return '#D97706';
  if (status === '待取件') return '#06B6D4';
  if (status === '已完成') return '#059669';
  return '#6B7280';
}

private getStatusBgColor(status: string): ResourceColor {
  if (status === '待支付') return '#FEE2E2';
  if (status === '打印中') return '#FEF3C7';
  if (status === '待取件') return '#CFFAFE';
  if (status === '已完成') return '#DCFCE7';
  return '#F3F4F6';
}
  • 红色:待支付
  • 橙色:打印中
  • 青色:待取件
  • 绿色:已完成
  • 灰色:已取消
  • 青色:页面主题色

页面设计说明

应用使用青色作为主题色,体现高效、便捷、科技的感觉。

页面主要分为以下区域:

  1. 顶部标题
  2. 数据统计区域
  3. 提交打印表单
  4. 打印参数选择
  5. 价格实时计算
  6. 状态筛选
  7. 订单列表
  8. 取件码弹窗

页面采用浅灰色背景和白色卡片。待取件订单突出显示取件码(大号字体),打印参数使用按钮组选择,价格使用大号绿色字体实时显示,文件类型使用图标区分。

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)"
}

运行项目

使用 DevEco Studio 打开项目,然后找到:

复制代码
entry/src/main/ets/pages/Index.ets

等待项目同步完成,点击右侧的 Preview 按钮即可查看应用效果。

项目总结

本文使用 HarmonyOS 和 ArkTS 实现了一个校园打印复印预约应用。

项目实现了文件上传、打印参数选择、价格计算、在线支付、状态跟踪、取件码生成、订单筛选、消费统计等功能。

通过这个项目可以掌握:

  • ArkTS 接口定义
  • @State 状态管理
  • 价格实时计算
  • 订单状态流转
  • ListForEach 列表渲染
  • 取件码随机生成
  • 自定义 @Builder 组件
  • HarmonyOS 生活服务类应用布局

后续还可以加入文件在线预览、打印进度实时推送、配送上门、发票申请、会员折扣、打印模板、多文件合并打印和打印店评价等功能。

相关推荐
绝世番茄6 小时前
鸿蒙原生 ArkTS 布局之道:Grid 替代多层嵌套布局深度解析
华为·harmonyos·鸿蒙
●VON6 小时前
鸿蒙 PC Markdown 编辑器可靠性设计:未保存内容的崩溃恢复闭环
华为·中间件·编辑器·harmonyos·鸿蒙
●VON6 小时前
鸿蒙 PC Markdown 编辑器导出架构:安全 HTML 与系统 PDF
华为·架构·编辑器·harmonyos·鸿蒙
信仰8747 小时前
HCIA-华为数通基础理论与实践08
网络·笔记·华为
不羁的木木7 小时前
HarmonyOS技术精讲-Connectivity Kit(短距通信服务):初识统一短距通信框架
华为·wpf·harmonyos
爸爸6197 小时前
UIAbility 生命周期在日记 App 中的实践
后端·华为·harmonyos·鸿蒙系统
tyqtyq2215 小时前
旅行打包清单 App — HarmonyOS AI 应用开发技术博客
人工智能·学习·华为·生活·harmonyos
HONG````15 小时前
Lazy Import 动态加载:减少 HarmonyOS 应用冷启动时间
harmonyos
条tiao条19 小时前
Navigation页面跳转教学博客
ui·华为·harmonyos·鸿蒙·页面跳转