收银台设计规范
=======

#### 功能需求

开发者可在应用项目中实现支付收银台。应用项目由配置文件（module.json5）、页面代码（ets文件）以及资源文件（图片、字符串等）组成，实现的收银台包含以下功能：展示商户信息、金额、支付方式列表（用户选择的支付方式会变成选中状态）和支付按钮。

实现效果如下（具体实现可参见[示例代码](https://gitcode.com/HarmonyOS_Samples/paymentkit-samplecode-uxcodeproject-arkts)）。

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/f9/v3/zvMNQxF5Tga8C68ZLJV4FQ/zh-cn_image_0000002594669370.png?HW-CC-KV=V1&HW-CC-Date=20260612T073631Z&HW-CC-Expire=86400&HW-CC-Sign=7EF6B94228501EEB7F91773D1C54801B720BF74CCBA662152128BCDC092E7434)

#### 定义收银台页面容器

定义收银台页面容器用于展示支付收银台。UX规范要求以半模态弹窗展示收银台，使用说明可参考[半模态转场](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-sheet-transition#示例1不同高度的半模态弹窗)。

半模态容器CashierBindSheetContainer.ets示例代码如下：

import { CashierComponent } from './CashierComponent';

@Component
export struct CashierBindSheetContainer {
  @Builder
  cashierBuilder() {
    Column() {
      CashierComponent();
    }
  }

  build() {
    Column() {
      Column() {
      }.bindSheet(true, this.cashierBuilder(), {
        title: () => {},
        height: SheetSize.FIT\_CONTENT,
        showClose: true,
        enableOutsideInteractive: false,
        backgroundColor: '#E5FFFFFF',
        blurStyle: BlurStyle.COMPONENT\_THICK,
        onWillDismiss: ((action: DismissSheetAction) => {
          // 退出事件监听
        }),
      });
    }.width('100%');
  }
}

#### 搭建收银台页面

收银台首页CashierComponent.ets从整体上可分为三个部分：头部-商户信息展示、中部-支付方式列表、底部-支付按钮。

**示例代码如下：**

import { LengthMetrics } from '@kit.ArkUI';
import { getBorderRadius, isNewCardPaymentType } from '../util/PaymentUtil';
import { PaymentOrderComp } from './PaymentOrderComp';
import { PaymentItemComp } from './PaymentItemComp';
import { ConfirmButton } from './ConfirmButton';
import { PaymentType } from '../data/PaymentType';
import { paymentTypeList, paymentTypes3PayShow } from '../data/TestData';

@Preview
@Component
export struct CashierComponent {
  // 商户名称
  private mercShortName: string = "华为支付测试商户";
  // 支付金额（单位为分）
  private paymentAmount: string = '0.01';
  // 当前选中的支付方式信息
  @State selectedPaymentType: PaymentType = new PaymentType();
  @State selectedPayTypeSerialNo: string = '';

  // 头部：商户订单信息
  @Builder
  orderDetail() {
    // 后续展示实现
  }

  // 中部：支付方式列表的标题
  @Builder
  displayHeader() {
    // 后续展示实现
  }

  // 中部：其他支付方式选项
  @Builder
  moreBankFooter() {
    // 后续展示实现
  }

  // 中部：选择支付方式事件
  select(PaymentType: PaymentType) {
    // 后续展示实现
  }

  // 中部：支付方式列表
  @Builder
  paymentListBuilder() {
    // 后续展示实现
  }

  // 中部：支付方式列表 容器
  @Builder
  paymentListContent() {
    Column() {
      this.paymentListBuilder();
    }
    .margin({
      bottom: 12,
    })
  }

  // 底部：按钮区域
  @Builder
  buttonArea() {
    // 后续展示实现
  }

  // 收银台首页
  @Builder
  cashierUI() {
    // 订单信息+支付方式区域
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
      this.orderDetail();
      this.paymentListContent();
    }
    .align(Alignment.Top)
    .padding({
      left: $r('sys.float.ohos\_id\_elements\_margin\_horizontal\_l'),
      right: $r('sys.float.ohos\_id\_elements\_margin\_horizontal\_l'),
    })

    // 按钮区域
    Column() {
      this.buttonArea();
      // 底部aiBar的高度
      Row()
        .width('100%')
        .height(28)
        .margin({ top: $r('sys.float.ohos\_id\_elements\_margin\_vertical\_l') })
    }
    .flexShrink(0)
    .padding({
      left: $r('sys.float.ohos\_id\_elements\_margin\_horizontal\_l'),
      right: $r('sys.float.ohos\_id\_elements\_margin\_horizontal\_l'),
    })
  }

  // 页面容器
  build() {
    Column() {
      this.cashierUI();
    }
  }
}

**运行结果：**

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/10/v3/ygjN7Ym8S7G_KSinU5RkXg/zh-cn_image_0000002594669370.png?HW-CC-KV=V1&HW-CC-Date=20260612T073631Z&HW-CC-Expire=86400&HW-CC-Sign=D204BF831E6C9184C70C6D53A93FA2957D7A0938C02018439F2DD9189ED9BA77)

#### \[h2\]展示商户信息

收银台首页CashierComponent.ets的orderDetail组件为商户信息展示。商户信息竖向居中排列，包含商户名称以及订单金额。

**示例代码如下**：

@Builder
orderDetail() {
  Column() {
    PaymentOrderComp({
      mercShortName: this.mercShortName,
      paymentAmount: this.paymentAmount,
    })
    .margin({ bottom: 24 });
  }
  .width('100%')
  .padding({
    top: $r('sys.float.ohos\_id\_elements\_margin\_vertical\_m'),
  })
}

其中商户订单信息类PaymentOrderComp.ets实现如下：

import { Amount } from "./Amount";

@Component
export struct PaymentOrderComp {
  @Prop mercShortName: ResourceStr = '';
  @Prop paymentAmount: string = '';

  build() {
    Column() {
      Text(this.mercShortName)
        .fontFamily('HarmonyHeiTi')
        .fontSize($r('sys.float.ohos\_id\_text\_size\_body2'))
        .fontColor($r('sys.color.ohos\_id\_color\_text\_secondary'))
        .textAlign(TextAlign.Center)
        .fontWeight(FontWeight.Normal)

      Amount({
        amount: this.paymentAmount,
      }).margin({ top: 2 })
    }
  }
}

其中金额类Amount.ets实现如下：

const FONT\_FAMILY\_HEITI = 'HarmonyHeiTi';

@Component
@Preview
export struct Amount {
  @Prop amount: string = '';
  private currency: string = '¥';
  private color: ResourceStr = $r('sys.color.ohos\_id\_color\_text\_primary');

  build() {
    Row() {
      Text() {
        Span(this.currency)
          .fontSize(24)
          .fontFamily(FONT\_FAMILY\_HEITI)
          .fontWeight(FontWeight.Bold)
          .fontColor(this.color)
          .alignSelf(ItemAlign.Baseline)
        Span(this.amount)
          .fontSize(36)
          .fontFamily(FONT\_FAMILY\_HEITI)
          .fontWeight(FontWeight.Bold)
          .fontColor(this.color)
      }
    }.justifyContent(FlexAlign.Center)
    .alignItems(VerticalAlign.Bottom)
  }
}

**运行结果：**

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/70/v3/ypZc4D4WQnyFq19teqrILA/zh-cn_image_0000002594829298.png?HW-CC-KV=V1&HW-CC-Date=20260612T073631Z&HW-CC-Expire=86400&HW-CC-Sign=DFF73BB29733BFED4BB59265E4BD0E8E386EC33A385BDD92390F68D6C214AF6D)

#### \[h2\]构造支付方式列表

收银台首页CashierComponent.ets的paymentListBuilder组件为收银台中部信息，包含支付方式列表。用户点击选择的支付方式会变成选中状态。

**示例代码如下**：

@Builder
paymentListBuilder() {
  Column() {
    List() {
      ListItemGroup({
        header: this.displayHeader(),
        style: ListItemGroupStyle.CARD,
      }) {
        ForEach(paymentTypeList, (paymentType: PaymentType) => {
          ListItem({ style: ListItemStyle.CARD }) {
            PaymentItemComp({
              paymentType: paymentType,
              canChecked: !isNewCardPaymentType(paymentType),
              isChecked: this.selectedPayTypeSerialNo === paymentType.payTypeSerialNo,
              onSelect: () => {
                if (paymentType.isAvailable) {
                  this.select(paymentType);
                }
              },
            })
          }
          .height(undefined)
          .constraintSize({ minHeight: 48 })
          .backgroundColor(Color.Transparent)
        })

        // 其他支付方式
        ListItem({ style: ListItemStyle.CARD }) {
          this.moreBankFooter();
        }
        .height(undefined)
        .constraintSize({ minHeight: 48 })
        .backgroundColor(Color.Transparent)
      }.divider({
        strokeWidth: 0.5,
        color: $r('sys.color.ohos\_id\_color\_list\_separator'),
        startMargin: 48,
        endMargin: 12,
      }).margin({
        left: 0,
        right: 0,
      }).backgroundColor($r('sys.color.comp\_background\_list\_card'))
    }.width('100%')

    // 三方支付方式
    List() {
      ListItemGroup({ style: ListItemGroupStyle.CARD }) {
        ForEach(paymentTypes3PayShow, (paymentType: PaymentType) => {
          ListItem({ style: ListItemStyle.CARD }) {
            PaymentItemComp({
              paymentType: paymentType,
              canChecked: true,
              isChecked: this.selectedPayTypeSerialNo === paymentType.payTypeSerialNo,
              onSelect: () => {
                if (paymentType.isAvailable) {
                  this.select(paymentType);
                }
              },
            })
          }
          .height(undefined)
          .constraintSize({ minHeight: 48 })
          .backgroundColor(Color.Transparent)
        })
      }.divider({
        strokeWidth: 0.5,
        color: $r('sys.color.ohos\_id\_color\_list\_separator'),
        startMargin: 48,
        endMargin: 12,
      })
      .margin({
        left: 0,
        right: 0,
      }).backgroundColor($r('sys.color.comp\_background\_list\_card'))
    }
    .width('100%')
    .margin({
      top: 12,
    })
  }
}

其中列表标题组件displayHeader示例代码如下：

@Builder
displayHeader() {
  Column() {
    Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
      Image($r('app.media.kit\_hwpay\_wallet'))
        .borderRadius(getBorderRadius(24))
        .width(24)
        .height(24)
        .margin({ end: LengthMetrics.vp(16) })

      Text($r('app.string.kit\_hwpay\_desc'))
        .fontSize(16)
        .fontWeight(FontWeight.Medium)
        .fontFamily('HarmonyHeiTi-Medium')
        .fontColor($r('sys.color.ohos\_id\_color\_text\_primary'))
    }
    .width('100%')
    .constraintSize({ minHeight: 48 })
    .padding({
      left: 8,
      right: 8,
      top: 12,
      bottom: 12,
    })

    Divider()
      .color($r('sys.color.ohos\_id\_color\_list\_separator'))
      .width('100%')
      .margin({
        start: LengthMetrics.vp(48),
        end: LengthMetrics.vp(12),
      })
  }
}

其中其它支付方式组件moreBankFooter示例代码如下：

@Builder
moreBankFooter() {
  Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
    Text($r('app.string.kit\_hwpay\_change\_other\_pay\_type'))
      .fontSize(16)
      .fontWeight(FontWeight.Medium)
      .fontFamily('HarmonyHeiTi-Medium')
      .fontColor($r('sys.color.ohos\_id\_color\_text\_primary'))

    Image($r('app.media.kit\_hwpay\_right\_v2'))
      .matchTextDirection(true)
      .width(12)
      .height(24)
      .fillColor($r('sys.color.ohos\_id\_color\_fourth'))
  }
  .padding({
    top: 12,
    bottom: 12,
  })
  .margin({ start: LengthMetrics.vp(40) })
}

其中支付方式组件类PaymentItemComp.ets实现展示可用、不可用的支付方式，添加银行卡以及用户选中支付方式后展示勾选效果。示例代码如下：

import { LengthMetrics } from '@kit.ArkUI';
import { PaymentType } from '../data/PaymentType';
import { getBorderRadius } from '../util/PaymentUtil';

export enum ButtonOpacity {
  // 默认不透明度
  PRIMARY = 1,
  // 按钮置灰不透明度
  DISABLED = 0.6,
  // 支付方式不可用导致的按钮不可用的不透明度
  PAYMENT\_UNAVAILABLE = 0.38
}

@Component
export struct PaymentItemComp {
  @Prop paymentType: PaymentType;
  @Prop canChecked: boolean = false;
  @Prop isChecked?: boolean = false;
  onSelect: () => void = () => {
  };

  build() {
    Row() {
      Image($r("app.media.payment\_logo"))
        .borderRadius(getBorderRadius(24))
        .width(24)
        .height(24)
        .margin({ end: LengthMetrics.vp(16) })

      Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center }) {
        Flex({
          direction: FlexDirection.Row,
          justifyContent: FlexAlign.Start,
          alignItems: ItemAlign.Center,
        }) {
          Text(this.paymentType?.payTypeDesc)
            .fontSize(16)
            .fontWeight(FontWeight.Medium)
            .fontFamily('HarmonyHeiTi-Medium')
            .fontColor($r('sys.color.ohos\_id\_color\_text\_primary'))
        }
        .padding({
          top: (this.paymentType?.paymentTypeTip) ? 4 : 0,
        })

        if (this.paymentType?.paymentTypeTip) {
          Row() {
            Text(this.paymentType?.paymentTypeTip)
              .fontSize($r('sys.float.ohos\_id\_text\_size\_body3'))
              .fontColor($r('sys.color.comp\_focused\_secondary'))
              .fontFamily('HarmonyHeiTi')
              .fontWeight(FontWeight.Normal)
              .width('90%')
              .padding({ top: 4, bottom: 4 })
          }
        }
      }
      .layoutWeight(1)

      if (this.canChecked) {
        Radio({ value: this.paymentType?.payTypeSerialNo as string, group: 'aggrPaymentRadioGroup' })
          .visibility(this.isChecked ? Visibility.Visible : Visibility.Hidden)
          .checked(this.isChecked)
          .height(20)
          .width(20)
          .margin(2)
      } else {
        Image($r('app.media.kit\_hwpay\_right\_v2'))
          .width(12)
          .height(24)
          .fillColor($r('sys.color.ohos\_id\_color\_fourth'))
          .visibility(this.paymentType?.isAvailable ? Visibility.Visible : Visibility.None)
      }
    }
    .padding({
      top: 12,
      bottom: 12,
    })
    .opacity(this.paymentType?.isAvailable ? ButtonOpacity.PRIMARY : ButtonOpacity.PAYMENT\_UNAVAILABLE)
    .alignItems(VerticalAlign.Center)
    .onClick(() => {
      if (!this.paymentType?.isAvailable) {
        return;
      }
      this.onSelect();
    })
  }
}

收银台首页CashierComponent.ets中选择支付方式事件示例代码如下：

select(PaymentType: PaymentType) {
  this.selectedPaymentType = PaymentType;
  this.selectedPayTypeSerialNo = PaymentType.payTypeSerialNo || '';
}

**运行结果：**

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/61/v3/LSWs4QhvRHWFmOSD5ukjkg/zh-cn_image_0000002625188745.png?HW-CC-KV=V1&HW-CC-Date=20260612T073631Z&HW-CC-Expire=86400&HW-CC-Sign=683F3A78AF63F210FDF3A9826F8B8D47838AA8D06FD0C34C05A42A5D343573A1)

#### \[h2\]添加支付按钮

收银台首页CashierComponent.ets的buttonArea组件为收银台底部信息，包含支付按钮。开发者可通过按钮点击事件实现具体支付处理逻辑。

**示例代码如下**：

@Builder
buttonArea() {
  ConfirmButton({
    text: $r('app.string.kit\_hwpay\_checkout\_confirm\_pay'),
  })
  .margin({
    top: $r('sys.float.ohos\_id\_elements\_margin\_vertical\_l'),
  });
}

其中确认支付按钮类ConfirmButton.ets示例代码如下：

@Component
@Preview
export struct ConfirmButton {
  @Prop text: ResourceStr = '';

  build() {
    Column() {
      Row() {
        Button(this.text) {
          Row() {
            Text(this.text)
              .fontSize($r('sys.float.Body\_L'))
              .fontWeight(FontWeight.Medium)
              .fontFamily('HarmonyHeiTi-Medium')
              .fontColor($r('sys.color.ohos\_fa\_text\_contrary'))
              .textAlign(TextAlign.Center)
              .textOverflow({
                overflow: TextOverflow.Ellipsis
              })
              .maxLines(1)
          }
          .alignItems(VerticalAlign.Center)
          .justifyContent(FlexAlign.Center)
        }
        .focusOnTouch(true)
        .type(ButtonType.Normal)
        .borderRadius(20)
        .backgroundColor($r('sys.color.ohos\_id\_color\_floating\_button\_bg\_normal'))
        .constraintSize({
          minWidth: '100%',
          maxWidth: '100%',
          minHeight: 40,
          maxHeight: 40,
        })
        .padding({
          top: 4,
          bottom: 4,
          left: 16,
          right: 16,
        })
        .opacity(1)
        .stateEffect(true)
      }
      .onClick(() => {
        // 按钮点击事件
      })
    }.width('100%')
    .alignItems(HorizontalAlign.Center)
  }
}

**运行结果：**

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/d0/v3/VASX58-KRaWfEDvrPIKd3g/zh-cn_image_0000002625108889.png?HW-CC-KV=V1&HW-CC-Date=20260612T073631Z&HW-CC-Expire=86400&HW-CC-Sign=276946DF19481F780DCCE8BDE33B97292B93575C8E40AFC96DB67B04B77B9918)

#### 页面数据定义

#### \[h2\]字符串、图片等资源

文件摆放位置为“src/main/resources”相应的目录下。

#### \[h2\]支付方式及支付类型枚举

支付方式PaymentType.ets类及支付类型枚举CustPayType.ets类定义示例代码如下：

// 支付方式：PaymentType.ets
export class PaymentType {
  payTypeSerialNo?: string;
  payTypeDesc?: string;
  paymentTypeTip?: string;
  isAvailable?: boolean;
  custPayType: string = '';
}

// 支付类型枚举：CustPayType.ets
export enum CustPayType {
  NewBankCard = 'NewBankCard',
}

#### \[h2\]支付方式测试数据

测试使用的支付方式数据TestData.ets类定义示例代码如下：

import { PaymentType } from "./PaymentType";

export const paymentTypeList: PaymentType\[\] = \[
  {
    payTypeSerialNo: '1',
    payTypeDesc: 'xx银行储蓄卡 (0606)',
    isAvailable: true,
    custPayType: 'BankFastPayment',
  },
  {
    payTypeSerialNo: '2',
    payTypeDesc: 'xx银行储蓄卡 (0909)',
    isAvailable: true,
    custPayType: 'BankFastPayment',
  }
\];

export const paymentTypes3PayShow: PaymentType\[\] = \[
  {
    payTypeSerialNo: '3',
    payTypeDesc: '云闪付',
    isAvailable: true,
    custPayType: 'CloudFlashPayment',
  },
  {
    payTypeSerialNo: '4',
    payTypeDesc: '微信支付',
    isAvailable: true,
    custPayType: 'WECHAT\_MICROPAY',
  }
\]

#### \[h2\]工具类

支付工具PaymentUtil.ets类定义示例代码如下：

import { CustPayType } from "../data/CustPayType";
import { PaymentType } from "../data/PaymentType";

/\*\*
 \* 支付工具是否是新卡
 \* @param paymentType 支付方式
 \* @returns 是否为新卡支付方式
 \*/
export const isNewCardPaymentType = (paymentType: PaymentType): boolean => {
  if (!paymentType) {
    return false;
  }
  return paymentType.custPayType === CustPayType.NewBankCard;
};

/\*\*
 \* 获取图标圆角值
 \* @param length 圆角值
 \* @returns 图标圆角值
 \*/
export const getBorderRadius = (length: number): number => {
  // 正方形图标圆角值为：14 / 54 \* 图标边长
  return 7 / 27 \* length;
}