Encrypted Card

介绍

Encrypted Card 用于收集并加密卡号、过期时间和 CVV 信息。如果您使用自定义支付表单并希望符合 PCI 标准,建议采用 Encrypted Card。

该方式基于支付 API,接入前需完成商户身份校验,请确认以下条件:

  1. 已注册商户并获取有效客户端密钥(Client key)。
  2. 能够自行调用我们的支付 API。

开始前准备

可以安装 PayKKa Checkout UI npm 包,或者通过 CDN 的方式嵌入到 HTML 中:

安装 @paykka/card-checkout-ui

npm i @paykka/card-checkout-ui

为了正常的展示组件,需要全局引入样式:

import '@paykka/card-checkout-ui/style.css'

创建 DOM

在您的收银台页面创建 DOM 元素,该元素用于呈现 Encrypted Card。

Encrypted Card 支持将卡号、过期时间和 CVV 合并分开展示,您需要在 HTML 中预先定义好。

无论您选择如何展示,都需要使用 idencryptedCardWrapper 的祖先元素将放置子表单域的元素包裹,data-eci 则表示对应表单域名称。

下面是两种展示方式的 DOM 定义示例:

<!-- 包裹整个表单的元素 -->
<div id="encryptedCardWrapper">
  <!-- 卡号 -->
  <div data-eci="cardNumber"></div>
  <!-- 有效期 -->
  <div data-eci="expiryDate"></div>
  <!-- CVV -->
  <div data-eci="securityCode"></div>
</div>

Encrypted Card 会根据元素的 iddata-eci 属性将表单域插入到指定位置,请务必对元素设置正确的属性名和值。

构建 Encrypted Card

构建参数

创建 Encrypted Card 实例时可传递参数及事件如下:

必填参数用 * 标识

名称 说明 类型
*merchantId商户 ID。string
*clientKey客户端密钥。string
locale表单项所展示的语言。
  • 不传则获取浏览器语言,若浏览器语言不在支持范围内,则默认使用 en-GB
  • 目前支持如下 11 种国际化语言,按照 IETF BCP 47 格式展示:
    • de-DE:德语(德国)
    • en-GB:英语(英国)
    • es-ES:西班牙语(西班牙)
    • fr-FR:法语(法国)
    • ja-JP:日语(日本)
    • ko-KR:韩语(韩国)
    • pt-PT:葡萄牙语(葡萄牙)
    • ru-RU:俄语(俄罗斯)
    • zh-CN:中文(中国)
    • zh-HK:中文(香港)
    • zh-TW:中文(台湾)
string
brands有效的卡品牌数组。
  • 身份验证完成后会获取商户可用的卡品牌,然后两者取交集。
  • 如果不传,则直接取商户可用卡品牌。
string
styles输入框、label 和错误提示文字的样式ElementStylesConfig
showLabel是否展示表单项 label,默认为 trueboolean
sandbox是否使用 Sandbox 环境。boolean
onReady身份校验完成后调用,并返回校验结果,若校验成功则返回可用卡品牌(status: boolean, res?: { brands: string[] }) => void
onActivated表单域渲染完成后触发,并返回对应表单域类型(fieldType: FieldType) => void
onFocus表单域获得焦点时触发,并返回对应表单域类型(fieldType: FieldType) => void
onBlur表单域失去焦点时触发,并返回对应表单域类型(fieldType: FieldType) => void
onBinChanged卡 bin 信息改变时触发。
  • 返回包含卡号前 1-6 位的值和卡品牌
  • 如果用户删除卡号,或卡号不足 6 位,则 binValue 为空。
(binInfo: { binValue: string; brand?: CardBrand }) => void
onBrand检测到卡品牌时调用,返回对应卡品牌(brand?: CardBrand) => void
onCardEncrypted卡信息加密成功后触发,返回加密结果(encryptedInfo: EncryptCardRes) => void
onCardEncryptionFailed卡信息加密失败后触发。() => void
onValidationChanged通知表单项验证信息,返回对应表单域类型和验证状态。(validationInfo: { fieldType: FieldType; status: FormValidationStatus) }) => void

初始化

调用 init 方法,携带 Encrypted Card 构建参数进行初始化:

import { PayKKaEncryptedCard } from '@paykka/card-checkout-ui'

const EncryptedCard = PayKKaEncryptedCard.init({

  merchantId: 'xxx',
  clientKey: 'xxx',
  brands: ['VISA', 'MASTER_CARD'],
  showLabel: true,
  styles: {
    input: {
      base: {
        fontSize: '16px'
      },
      focus: {
        color: 'blue'
      },
      valid: {
        border: '1px solid yellowgreen',
        color: 'yellowgreen'
      },
      invalid: {
        border: '1px solid red',
        color: 'red'
      }
    }
  }
})

设置 Encrypted Card 样式

Encrypted Card 自带默认样式,您可以自定义输入框、label 和错误提示文案下对应状态的样式,初始化时传递 styles 即可。

styles 对象类型如下,CSSStyleDeclaration 表示我们支持绝大部分符合标准的样式:

interface ElementStylesConfig {
  /** input 元素的样式 */
  input?: InputStylesConfig
  /** label 文案的样式 */
  label?: StylesConfig
  /** 错误提示文案的样式 */
  errorMessage?: Partial<CSSStyleDeclaration>
}

interface StylesConfig {
  /** 默认样式 */
  base?: Partial<CSSStyleDeclaration>
  /** 校验通过时样式 */
  valid?: Partial<CSSStyleDeclaration>
  /** 校验不通过时样式 */
  invalid?: Partial<CSSStyleDeclaration>
  /** 聚焦元素时样式 */
  focus?: Partial<CSSStyleDeclaration>
}

interface InputStylesConfig extends StylesConfig {
  /** placeholder样式 */
  placeholder?: {
    /** 默认样式 */
    base?: Partial<CSSStyleDeclaration>
    /** 聚焦元素时样式 */
    focus?: Partial<CSSStyleDeclaration>
  }
  /** 将鼠标悬停在元素上的样式 */
  hover?: Partial<CSSStyleDeclaration>
}

下面是一个示例:

const EncryptedCard = PayKKaEncryptedCard.init({
  styles: {
    input: {
      base: {
        fontSize: '20px',
        fontWeight: 'bold',
        padding: '0 0 0 12px',
        borderRadius: '0px',
        boxShadow: 'none'
      },
      focus: {
        color: 'blue',
        caretColor: 'blue',
        border: '1px solid blue'
      },
      valid: {
        border: '1px solid yellowgreen',
        color: 'yellowgreen'
      },
      invalid: {
        border: '1px solid red',
        color: 'red'
      }
    },
    label: {
      base: {
        fontSize: '20px',
        fontWeight: 'bold',
        margin: '0',
        color: 'purple'
      },
      valid: {
        color: 'yellowgreen'
      },
      invalid: {
        color: 'red'
      },
      focus: {
        color: 'blue'
      }
    },
    errorMessage: {
      fontSize: '20px',
      fontWeight: 'bold',
      margin: '0',
      color: 'yellow'
    }
  }
})

除输入框、label 和错误提示文案外,如果您想更改其他样式,可以直接编写 CSS 代码覆盖我们的默认样式。

加密结果

提交表单的时候,您需要调用 encrypt 方法,如果表单验证通过,我们会对表单信息进行加密:

<button onClick="handleClick">支付</button>
const handleClick = () => {
  // 加密
  EncryptedCard.encrypt() 
}

由于加密过程是异步的,您需要通过注册 onCardEncrypted 事件回调获取加密结果:

let encryptedRes = null
const EncryptedCard = PayKKaEncryptedCard.init({
  // 此处省略其他属性
  onCardEncrypted: res => {

    console.log('加密成功', res)
    encryptedRes = res
    processPay()
  }
})

const processPay = () => {
  // 调用支付 API 并传递加密信息 encryptedRes
}

加密结果类型定义如下:

interface EncryptCardRes {
  /** 加密后的卡号 */
  encryptedCardNumber: string
  /** 加密后的 CVV */
  encryptedCVV: string
  /** 加密后的有效期年份 */
  encryptedExpireYear: string
  /** 加密后的有效期月份 */
  encryptedExpireMonth: string
  /** 卡信息 */
  cardInfo: {
    /** 卡 bin */
    bin: string
    /** 卡品牌 */
    brand: CardBrand
    /** 卡号后 4 位 */
    last4: string
  }
}

部分属性说明

卡品牌

CardBrand

目前我们支持的卡品牌枚举和对应卡品牌如下:

type CardBrand = keyof typeof CardBrandCode

enum CardBrandCode {
  /** Visa */
  VISA = 'VISA',
  /** Mater Card */
  MASTER_CARD = 'MASTER_CARD',
  /** JCB */
  JCB = 'JCB',
  /** American Express */
  AMEX = 'AMEX',
  /** Discover */
  DISCOVER = 'DISCOVER',
  /** Diners Club */
  DINERS_CLUB = 'DINERS_CLUB'
}

表单域类型

FieldType

表单类型枚举及对应描述如下:

type FieldType = keyof typeof EFieldType

enum EFieldType {
  /** 卡号 */
  CARD_NUMBER = 'CARD_NUMBER',
  /** cvv */
  CVV = 'CVV',
  /** 过期时间 */
  EXPIRE_DATE = 'EXPIRE_DATE'
}

验证状态

FormValidationStatus

表单验证状态分为三种,状态值和对应描述如下:

  • unValidate: 内容为空。
  • success: 校验成功。
  • error: 校验失败。
type FormValidationStatus = 'unValidate' | 'success' | 'error'

示例

下面是从初始化表单域到完成加密的代码示例:

<div id="encryptedCardWrapper">
  <!-- 卡号 -->
  <div data-eci="cardNumber"></div>
  <!-- 有效期 -->
  <div data-eci="expiryDate"></div>
  <!-- CVV -->
  <div data-eci="securityCode"></div>
  <button onClick="handleClick()">支付</button>
</div>
let encryptedRes = null
const EncryptedCard = PayKKaEncryptedCard.init({
  merchantId: 'xxx',
  clientKey: 'xxx',
  brands: ['VISA', 'MASTER_CARD'],
  showLabel: true,
  styles: {
    input: {
      base: {
        fontSize: '16px'
      },
      focus: {
        color: 'blue'
      },
      valid: {
        border: '1px solid yellowgreen',
        color: 'yellowgreen'
      },
      invalid: {
        border: '1px solid red',
        color: 'red'
      }
    }
  },
  onCardEncrypted: res => {
    console.log('加密成功', res)
    encryptedRes = res
    processPay()
  }
})

const handleClick = () => {
  // 加密
  EncryptedCard.encrypt()
}

const processPay = () => {
  // 调用支付 API 并将加密信息传入
}

Sandbox 环境接入

Sandbox 环境下接入,需要引入 Sandbox 环境的 CDN,并在初始化时设置 sandboxtrue

<link
  href="https://checkout-sandbox.aq.paykka.com/cp/style.css"
  rel="stylesheet"
/>
<script src="https://checkout-sandbox.aq.paykka.com/cp/encrypted-card.js"></script>
const EncryptedCard = PayKKaEncryptedCard.init({
  // 此处省略其他属性
  sandbox: true
})