﻿# 前置组件 - CARD

## 1. 交互流程

```mermaid
%%{init: {
  'theme': 'base',
  'themeVariables': {
    'primaryColor': '#e6f0ff',
    'primaryTextColor': '#333',
    'primaryBorderColor': '#5b9bd5',
    'lineColor': '#888',
    'actorMargin': 40,
    'noteBkgColor': '#0056b3',
    'noteTextColor': '#ffffff',
    'noteBorderColor': '#004a99'
  }
}}%%
sequenceDiagram
    participant User as 用户
    participant Page as 商户页面
    participant Component as PayerMax
前置组件
    participant MServer as 商户服务端
    participant PMServer as PayerMax服务器
    participant Channel as 支付渠道
钱包/银行等

    %% 1. 初始化阶段
    User->>Page: 1.1 选择商品下单
    Page->>MServer: 1.2 发送订单信息
如：收单国家、订单币种等
    MServer->>PMServer: 1.3 获取前置组件初始化信息
clientKey和sessionKey
    PMServer-->>MServer: 1.4 返回结果
clientKey和sessionKey
    MServer-->>Page: 1.5 返回结果
含clientKey和sessionKey
    Page->>Component: 1.6 创建并挂载PayerMax组件

    %% 2. 获取 Token 阶段
    User->>Page: 2.1 用户输入支付信息
    Page->>Component: 2.2 获取paymentToken
    Component->>PMServer: 2.3 获取paymentToken
    PMServer-->>Component: 2.4 返回结果
含paymentToken
    Component-->>Page: 返回paymentToken

    %% 3. 提交订单与支付
    User->>Page: 3.1 确认支付
    Page->>Component: 3.2 提交支付
含paymentToken
    Component->>MServer: 3.3 提交订单
含paymentToken
    MServer->>PMServer: 3.4 创建支付
调用前置组件下单接口
    PMServer->>Channel: 3.5 支付请求
    PMServer-->>MServer: 3.6 返回结果
    MServer-->>Component: 3.7 返回结果
    Component-->>Page: 3.8 返回结果

    %% 4. 获取支付结果 (逻辑框)
    rect rgb(235, 245, 255)
        Note over MServer, PMServer: 获取支付结果
        
        Note over MServer, PMServer: 通过支付结果通知
        PMServer->>MServer: 4.1 支付结果异步通知
        MServer->>MServer: 4.2 更新支付结果
        MServer-->>PMServer: 4.3 返回响应

        Note over MServer, PMServer: 通过支付订单查询
        MServer->>PMServer: 5.1 查询支付交易单
        PMServer-->>MServer: 5.2 交易详情，含支付结果
        MServer->>MServer: 5.3 更新支付结果
    end
```

## 2. 接口介绍

### 2.1 接口列表

| 关联交互时序                       | 调用方向             | 接口类型   | 接口PATH                                                                                                                                                                      |
| ---------------------------------- | -------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 3.1 获取前置组件初始化信息         | `商户` -> `PayerMax` | `后端接口` | [/applyDropinSession](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-applyDropinSession/post.html)          |
| 3.3 创建支付，调用前置组件下单接口 | `商户` -> `PayerMax` | `后端接口` | [/orderAndPay](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-orderAndPay(for-drop-dont-copy-me)/post.html) |
| 3.4.1 支付结果异步通知             | `PayerMax` -> `商户` | `后端接口` | [/collectResultNotifyUrl](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/collectResultNotifyUrl/post.html)                            |
| 3.4.2 查询支付交易                 | `商户` -> `PayerMax` | `后端接口` | [/orderQuery](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-orderQuery/post.html)                          |

### 2.2 环境信息

- **测试环境**：https:// `pay-gate-uat.payermax.com`/aggregate-pay/api/gateway/ `<接口PATH>`

- **集成环境**：https:// `pay-gate.payermax.com`/aggregate-pay/api/gateway/ `<接口PATH>`

### 2.3 请求header

``` js
"headers": {
        "Accept": "application/json",
        "sign": "请参考签名规则：https://docs-v2.payermax.com/202606-version/developer/config-settings.html",//必须
        "Content-Type": "application/json"
}
```
## 3.开始集成
### 3.1 获取前置组件初始化信息

商户服务端通过[/applyDropinSession API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-applyDropinSession/post.html) 接口，发起HTTP POST请求，获取前置组件初始化所需的客户端令牌`clientKey`和会话令牌`sessionKey`。

+ [/applyDropinSession API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-applyDropinSession/post.html) 接口请求示例：

``` json
{
    "requestTime": "2024-11-20T01:56:36.753-02:00",
    "keyVersion": "1",
    "data": {
            "country":"US",
            "currency": "USD",
            "totalAmount": "19.99",
            "componentList": ["CARD","APPLEPAY"],
            "userId": "1447410849000200"
    },
    "appId": "381ded7c863c439a9e29b4519867965a",
    "version": "1.5",
    "merchantNo": ""
}
```

+ [/applyDropinSession API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-applyDropinSession/post.html) 接口响应示例：

``` json
{
    "msg": "",
    "code": "APPLY_SUCCESS",
    "data": {
            "sessionKey": "964bffa7c9eb4951bd5ba11a2691e5ed",
            "notSupportedComponent": [],
            "clientKey": "8eef820ecbd443b7a608c2e0863750eb"
    }
}
```

### 3.2 渲染前置组件

1. 在相关 HTML 页面上引入 CDN 包。

``` html

```

2. 通过过`div`标签，在商户页面嵌入一个`card`待展示区域。

``` html
  
    

```

3. 初始化 PayerMax Frames。

``` js
// 初始化卡组件
const card = PMdropin.create('card', {
  clientKey: "客户端公钥", // 在步骤3.1中获取到的 data.clientKey
  sessionKey: "会话令牌", // 在步骤3.1中获取到的 data.sessionKey
  sandbox: false, // 默认是 false，即生产环境
  hideSaveCard: false, //是否隐藏保存卡信息选项，默认是false展示
  hideCardBrands: false, //是否隐藏左上角卡品牌的Logo，默认是false展示
});
// 挂载实例
card.mount('.frame-card'); // 将挂载至匹配到的第一个dom元素上
// 组件加载完成时机
card.on('ready', () => {
    // 移除自定义loading               
})
```

4. 监听表单填写状态，动态设置支付按钮（可选）。通过表单监听事件，可实时监控用户填写信息的合法性，以此动态设定 **支付** 按钮是否可点击。

``` js
card.on('form-check', (res) => {
  // res.isFormValid 为表单状态。取值是false/true
  // true 表示表单校验通过，可支付；false 表示校验未通过，不可支付，无法点击支付按钮。
  console.log('[dropin][form-check]:', res)
})
```

5. 用户点击支付按钮，商户提交支付到PayerMax服务端

``` js
//用户点击支付按钮，提交支付
function goPay(){
    card.emit('setDisabled', true) // 点击支付按钮后冻结表单，防止重复提交支付过程
    card.emit('canMakePayment')
      .then(res => {
        if (res.code === 'APPLY_SUCCESS') {
          const paymentToken = res.data.paymentToken // 支付token，支付接口使用
          // 发起支付接口
          // 商户自己请求后端接口进行下单, 
          // 商户自己用params构造请求参数，需要带上paymentToken
            _postapi('orderAndPay',params).then(res =>{
              const code = (res || {}).code
              //商户将支付结果返回到前端
              if (code == 'APPLY_SUCCESS') {  
                  if(res.threeDSUrl){ 
                //使用PayerMax组件内弹窗完成3ds；也可以将threeDSUrl新开浏览器tab页打开完成3ds
                    handle3DS(threeDSUrl)
                }
                //支付成功，展示支付结果
              }  else {
                  //支付失败，展示失败结果
              }
        }
          card.emit('setDisabled', false) // 支付接口完成后解冻表单
        }
      })
      .catch(err => {
        card.emit('setDisabled', false) // 发生异常后解冻表单
      })
}

// orderAndPay后若获取到返回的url（即为threeDSUrl）就使用handle3DS方法唤起弹窗
function handle3DS(threeDSUrl) {
  card.create3DSPopup({
    url: threeDSUrl,
    // width/height 不传则按设备与视口自动计算；也可显式传入如 '80%'、'400px' 等
  })
  .then(res => {
    if (res.code === '3DS_PROCESSED') {
      // 3DS 流程完成，继续支付流程。
      console.log('3DS 流程完成', res.data);
      // 此处商户需要维持现有逻辑，商户侧应该主动查询支付结果 继续商户侧后续的交互
      proceedPayment(res.data);
    }
  })
  .catch(err => {
    if (err.code === 'USER_CANCEL') {
      // 商户也可不做处理，但是应允许用户继续点击支付按钮
      showMessage('您已关闭认证窗口');
    } else {
      showMessage('认证出现异常，请重试');
    }
  });
}
```

6. 当用户在前端确认支付后，前端`canMakePayment`接口会返回`paymentToken`，用作后端发起支付。

前端返回数据结构如下：
``` json
{
    "msg": "",
    "code": "APPLY_SUCCESS",
    "data": {
        "paymentToken": "CPT771e98494eff41f1a03a715ebab69cc9",
        "cardOrg": "VISA",
        "maskCardNumber": "444433****1111",
        "cardExpirationMonth": "12",
        "cardType": "CREDIT",
        "cardExpirationYear": "26",
        "cardHolderFullName": "Jemy Cheung",
        "agreementAccepted": true,
        "cardBinNo": "444433",
        "cardIssuingCountry": "US"
    }
}
```

### 3.3 创建支付

1. 商户服务端：调用[/orderAndPay API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-orderAndPay(for-drop-dont-copy-me)/post.html) 接口发起HTTP POST请求，创建支付。

[/orderAndPay API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-orderAndPay(for-drop-dont-copy-me)/post.html) 接口请求示例：

```diff js
{
    "requestTime": "2024-11-20T01:56:45.802-02:00",
    "keyVersion": "1.5", 
    "data": {
        "currency": "USD",
        "country": "US",
        "totalAmount": 19.99,      
        "expireTime": "3600",
        "paymentDetail": {
+           "paymentToken": "dbe78b7dd4fa4b668bacfdcc7153821d", // 用户输入卡信息后点击支付会回调前端paymentDetail
            "buyerInfo": {
                "clientIp": "146.75.136.237",
                "userAgent": "Chrome"
            },
+           "sessionKey": "abf62fdcf9c4408cb73117db6e740713"
        },
        "frontCallbackUrl": "https://",
        "subject": "xxx Game HK Limited",
        "outTradeNo": "ov1_5b89ced71d764ed9994e6882d88082f7",
        "notifyUrl": "https://",
        "userId": "1447410849000200",
        "integrate": "Direct_Payment",
        "terminalType": "WEB"
    },
    "appId": "381ded7c863c439a9e29b4519867965a",
    "version": "1.5",
    "merchantNo": "P04010116880289"
}
```

+ [/orderAndPay API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-orderAndPay(for-drop-dont-copy-me)/post.htlm) 接口响应示例：
::: warning 
注意：返回中可能存在data.redirectUrl，这时请返回给前端引导用户完成3ds认证。
:::

``` json
{
    "msg": "Success.",
    "code": "APPLY_SUCCESS",
    "data": {
        "outTradeNo": "test_da78b1f3c2f9443b966347fc89305fc9",
        "tradeToken": "T2024052805951921811176",
        "status": "SUCCESS"
    }
}
``` 

### 3.4 获取支付结果

[创建支付/orderAndPay API](https://docs.payermax.com/api.html?docName=New%20Version&docVer=v1.0&docLang=cn#/paths/aggregate-pay-api-gateway-orderAndPay/post.html) 接口响应的`data.status`并非支付终态，因此，商户不应直接使用其更新支付结果。

#### 3.4.1 支付结果通知

请查看[支付结果-支付结果通知](https://docs.payermax.com/202606-version/acquiring/start-integration/related-capabilities-integration/payment-result.md#_3-1-支付结果通知)。

#### 3.4.2 支付结果查询

请查看[支付结果-支付结果查询](https://docs.payermax.com/202606-version/acquiring/start-integration/related-capabilities-integration/payment-result.md#_3-2-支付结果查询)。

## 4.卡支付前端接口

### 4.1 API
使用方法 `PMdropin.API`。

| **API**            | **描述**          | **详情**          |
|---------------------|---------------------|---------------------|
| create | 实例化一个内置组件 |  参阅**4.1.1 create**    |
|  mount      | 将实例化组件挂载到`div`标签      |  参阅**4.1.2 mount**   |
| on           | 监听事件            |  参阅**4.1.3 on**    |
| emit            | 触发事件            |  参阅**4.1.5 emit**     |

#### 4.1.1 create
用于初始化组件，使用方法 `PMdropin.create(ComponentName, Options)`。

**ComponentName详解**

| **ComponentName**            | **字段类型**          | **描述**          |
|---------------------|---------------------|---------------------|
| card | string |  卡组件      |

**Options详解**

| **Options**            | **是否必填**          | **字段类型**          | **描述**          | **默认值**          |
|---------------------|---------------------|---------------------|---------------------|---------------------|
| clientKey | Y |  String      |  客户端公钥      |  -      |
| sessionKey | Y |  String      |  安全访问令牌      |  -      |
| sandbox | N |  Boolean      |  沙盒环境      |  `false`      |
| language | N |  String      |  语言      |  `en`      |
| theme | N |  String      |  主题      |  `light`      |
| customLocalization | N |  Object      |  自定义语言	      |  -      |
| customTheme | N |  Object      |  自定义主题	      |  -      |
| grayscale | N |  String      |  页面灰度      |  `'0'`      |
| isRtl | N |  Boolean      |  从右到左	      |  `false`      |
| hideSaveCard | N |  Boolean      |  隐藏Save保存	      |  `false`      |
| hideCardBrands | N |  Boolean      |  隐藏头部卡组织LOGO	      |  `false`      |
| hideCardHolderName | N |  Boolean      |  隐藏卡姓名	      |  `false`      |
| saveCardChecked | N |  Boolean      |  保存卡信息的checkbox是否选中
true - 勾选
false - 不勾选
注：当hideSaveCard = false时，该字段生效	      |  `true`      |
| ignoreUserCheckedCache | N |  Boolean      |  是否忽略用户勾选缓存
false - 默认不忽略
true - 忽略
注：当hideSaveCard = false时，该字段生效	      |  `false`      |
| hideRecommendAccount | N |  Boolean      |  是否隐藏推荐卡模块
	      |  `false`      |
| openTermsInCurrentPage | N |  Boolean      |  是否在当前页面打开协议弹框
	      |  `false`      |
| termsPopupConfig | N |  Object      |  协议弹框配置
注：当openTermsInCurrentPage = true时，该字段生效
	      |    -    |
| >>showMask | N |  Boolean      |  是否展示遮罩层
	      |  `true`      |
| >>closeOnClickMask | N |  Boolean      |  点击遮罩是否关闭弹框
	      |  `true`      |

#### 4.1.2 mount
用于挂载初始化组件实例，使用方法`PMdropin.mount(Tag)`。

**Tag详解**

| **Tag**            | **描述**          |
|---------------------|---------------------|
| id | 需要挂载的id元素值，如 `PMdropin.mount('#card-frame')`|
| class | 需要挂载的class元素值，如 `PMdropin.mount('.card-frame')`|

#### 4.1.3 on
用于监听组件内置响应事件，使用方法`PMdropin.on(Event, CallbackFunction)`。

**Event详解**

| **Tag**            | **描述**          | **返回值**          |
|---------------------|---------------------|---------------------|
| ready | 组件加载完成时触发 |`null` |
| form-check | 实时监听卡组件校验状态| **参阅下方 Event Response**|
| load | 组件加载完成时触发| Object 
 - type：组件类型card/applepay/googlepay 
- code：响应码 SUCCESS 表示加载成功，其余枚举表示加载失败
- msg：响应 message|

示例：

```js
PMdropin.on('form-check', function(event) {
  if (event.isFormValid) {
    // 表单校验通过
  }
});
```
#### 4.1.4 create3DSPopup
用于在组件内弹窗打开3DS认证页面

**语言设置说明：**SDK会会自动从实例配置中获取语言，无需在`create3DSPopup`中单独传入

入参说明：
| **参数** | **类型** | **必填** | **默认值** | **说明** |
| :--- | :--- | :--- | :--- | :--- |
| url | string | 是 | - | 3DS 认证页面 URL（从 `orderandpay` 接口获取） |
| showMask | boolean | 否 | true | 是否显示背景遮罩 |
| width | string | 否 | 响应式计算 | 弹框宽度，不传则按设备/视口自动计算 |
| height | string | 否 | 响应式计算 | 弹框高度，不传则按设备/视口自动计算 |

返回：
| **CODE** | **说明** | **处理建议** |
| :--- | :--- | :--- |
| `3DS_PROCESSED` | 3DS 流程已处理 | 继续后续支付流程，通过接口查询最终认证结果 |
| `USER_CANCEL` | 用户关闭弹框 | 提示用户已关闭，可重试 |
| `INVALID_PARAMS` | 调用入参不合法 | 根据 `err.msg` 检查入参（如 url 必填且非空、类型正确等），修正后重试 |

#### 4.1.5 emit
用于调用组件内置方法，使用方法`PMdropin.emit(Event, Params)`。

| **Event**            | **Params**          | **描述**          |
|---------------------|---------------------|---------------------|
| canMakePayment | - |  获取卡标识      |
| switchLanguage | string |  切换语言      |
| switchTheme | string |  切换主题      |
| addLocalization | Object |  添加自定义语言      |
| addTheme | Object |  添加自定义主题      |
| setDisabled | Boolean |  设置组件可用状态      |
| setRtl | Boolean |  设置组件从右到左布局      |
| setGrayscale | string |  设置组件页面灰度      |

##### 1. emit.canMakePayment
检查当前组件状态是否具备发起支付条件，如果校验通过则返回卡标识。

```js
// 示例
PMdropin.emit('canMakePayment')
  .then(function(response) {
    // 验证成功
    if (response.code === 'APPLY_SUCCESS') {
      // 获取 paymentToken 
      var paymentToken = response.data.paymentToken
      // 进行后续支付操作
    }
  })
  .catch(function(error) {
    // 捕获内部异常错误
    console.log(error);
  })
```

canMakePayment Response：

```js
// 接口成功示例
{
  code: 'APPLY_SUCCESS',
  data: {
    // 卡标识
    paymentToken: 'xxx'
  },
  msg: ''
}

// 接口失败示例
{
  code: 'FORM_INVALID',
  msg: 'Invalid params: cvv'
}
```

| **CODE码**            | **描述**          |
|---------------------|---------------------|
| APPLY_SUCCESS | 成功获取 `paymentToken` |
| FORM_INVALID | 表单校验失败 |
| UNKNOWN_ISSUE | 异常信息 |

##### 2. emit.switchLanguage
+您可以在我们预置语言列表中快速设置本地化参数。如`language: 'zh'`。
支持的预置语言如下：
| **语言**            | **语言编码**          |
|---------------------|---------------------|
| 英语 | en `默认` |
|  中文      |  zh      |

+ 初始化预置语言（zh）：

```js
PMdropin.create('card', {
  clientKey: '',
  sessionKey: '',
  language: 'zh',
  ...
});
```

+ 动态切换语言：

```js
PMdropin.emit('switchLanguage', 'zh')
```

##### 3. emit.switchTheme
当预置的语言无法满足您的使用场景，您可以通过`customLocalization`自定义语言。

```js
PMdropin.create('card', {
  clientKey: '',
  sessionKey: '',
  customLocalization: {
    // 添加中文示例
    'zh': {
      loading: '加载中',
      loadingFailed: '加载失败',
      refresh: '刷新',
      confirm: '确定',
      cancel: '取消',
      removeCard: '移除卡',
      removeCardTip: '确定移除当前选中卡吗?',
      addNewCard: '使用新卡',
      useSavedCard: '使用已存卡',
      cardnum: '银行卡号',
      cardnumHint: 'XXXX XXXX XXXX XXXX',
      cardnumErrTip: '卡号不正确',
      cardbinErrTip: {
        // {cardOrg} 变量字段，无需翻译
        CARD_NOT_SUPPORT: '不支持{cardOrg}，请检查卡号或者更换其他卡重试',
        // {cardType} 变量字段，无需翻译
        CARD_INVALID: '不支持{cardType}的卡类型',
        CARD_NO_INVALID: '请确认卡号输入是否正确',
      },
      expdate: '过期日期',
      expdateHint: '月/年',
      expdateErrTip: '过期日期不正确',
      cvv: 'CVV/CVC',
      cvvHint: '123',
      cvvErrTip: 'CVV/CVC 格式不正确',
      name: '持卡人姓名',
      nameHint: 'XX XX',
      nameErrTip: '姓名格式不正确',
      saveCardInfoTip: '为下次支付保存信息',
      // 以下为新增多语言字段
      // 本地卡额外采集要素
      buyerEmail: '邮箱',
      buyerEmailHint: '',
      buyerEmailErrTip: '格式错误，请复核',
      buyerFullName: '姓名',
      buyerFullNameHint: '',
      buyerFullNameErrTip: '格式错误，请复核',
      buyerFirstName: '名',
      buyerFirstNameHint: '',
      buyerFirstNameErrTip: '格式错误，请复核',
      buyerLastName: '姓',
      buyerLastNameHint: '',
      buyerLastNameErrTip: '格式错误，请复核',
      // 秘鲁 Document(ID)
      dni: 'DNI',
      dniHint: '',
      dniErrTip: '格式错误，请复核',
      // 阿根廷 Document(ID)
      dni_cuit: 'DNI/CUIT',
      dni_cuitHint: '',
      dni_cuitErrTip: '格式错误，请复核',
      // 南非 Document(ID)
      idCard: 'ID',
      idCardHint: '',
      idCardErrTip: '格式错误，请复核',
      // 哥伦比亚 Document(ID)
      cc: 'CC',
      ccHint: '',
      ccErrTip: '格式错误，请复核',
      // 墨西哥 Document(ID)
      curp: 'CURP',
      curpHint: '',
      curpErrTip: '格式错误，请复核',
      // 巴西 Document(ID)
      cpf: 'CPF',
      cpfHint: '',
      cpfErrTip: '格式错误，请复核',
      // 智利/巴拉圭/乌拉圭 Document(ID)
      ci: 'CI',
      ciHint: '',
      ciErrTip: '格式错误，请复核',
      buyerPhoneNo: '手机号码',
      buyerPhoneNoHint: '',
      buyerPhoneNoErrTip: '格式错误，请复核',
      buyerPhoneNoRegion: '手机区号',
      buyerPhoneNoRegionHint: '',
      buyerPhoneNoRegionErrTip: '格式错误，请复核',
    }
  },
  ...
});
```

+ 动态添加语言：

```js
PMdropin.emit('addLocalization', {
  'zh': {
    // 参数如上所示
  }
});
```

##### 4. emit.addLocalization
使用我们的主题功能，帮助您构建一个更加符合自身网站的样式搭配。
+ 使用预置主题
我们预置了两款主题色，您可以通过`theme`自定义主题。
支持的预置主题如下：

| **主题名称**            | **主题编码**          |
|---------------------|---------------------|
| 白色 | light `默认` |
|  黑色      |  dark      |

+ 初始化示例：

```js
PMdropin.create('card', {
  clientKey: '',
  sessionKey: '',
  theme: 'dark'
});
```

+ 或者动态切换：

```js
PMdropin.emit('switchTheme', 'dark');
```

##### 5. emit.addTheme
自定义主题，您可以通过自定义主题包来修改样式，示例如下：

```js
PMdropin.create('card', {
  clientKey: '',
  sessionKey: '',
  theme: 'red',
  customTheme: [
    {
      // 主题名称【必填】
      name: 'red', 
      // 用于填充底色的样式【可选】
      base: 'light',
      style: `:root {
          /* --- common --- */
          --bg-primary: #ffffff;
          --color-primary: #3782ff;
          --border-color-primary: #eaeaea;
          --border-color-hover-primary: #dcdcdc;
          --font-size-primary: 13px;
          --border-radius-primary: 6px;
        
          /* --- frame --- */
          --padding-frame: 16px;
          --bg-color-frame: var(--bg-primary);
          --bg-color-mask: rgba(255, 255, 255, 0.8);
        
          /* --- text --- */
          --color-text-primary: #333333;
          --color-text-secondary: #666666;
          --color-text-tip: #c8c8c8;
          --color-text-error: #e64949;
        
          /* --- button --- */
          /* plain button */
          --bg-color-btn-plain: var(--bg-primary);
          --border-color-btn-plain: var(--border-color-primary);
          --border-color-hover-btn-plain: var(--border-color-hover-primary);
          --font-size-btn-plain: var(--font-size-primary);
          --border-radius-btn-plain: var(--border-radius-primary);
        
          /* text button */
          --color-btn: var(--color-primary);
          --color-active-btn: #2c68cc;
          --font-size-btn-text: var(--font-size-primary);
        
          /* --- input --- */
          --bg-color-input: var(--bg-primary);
          --border-color-input: var(--border-color-primary);
          --border-color-hover-input: var(--border-color-hover-primary);
          --border-color-focus-input: var(--color-primary);
          --shadow-color-focus-input: rgba(55, 130, 255, 0.2);
          --label-color-input: var(--color-text-primary);
          --label-color-focus-input: var(--color-primary);
          --action-color-input: var(--border-color-input);
          --action-color-hover-input: var(--border-color-hover-input);
          --action-color-active-input: #bbbbbb;
          --color-placeholder-input: #dcdcdc;
          --color-input: var(--color-text-primary);
          --font-size-input: 12px;
          --font-size-input-label: var(--font-size-input);
          --font-size-input-tip: var(--font-size-input);
          --height-input: 36px;
          --size-checkbox: 16px;
          --border-radius-input: var(--border-radius-primary);
          --border-radius-checkbox: calc(var(--border-radius-input)/2);
        
          /* --- item --- */
          --bg-color-item: var(--bg-primary);
          --bg-color-selected-item: #f5f9ff;
          --border-color-item: var(--border-color-primary);
          --border-color-hover-item: var(--border-color-hover-primary);
          --border-color-selected-item: var(--color-primary);
          --font-size-item: 15px;
          --height-item: 36px;
          --height-item-btn: var(--height-item);
          --height-selected-item: 48px;
          --border-radius-item: var(--border-radius-primary);
        
          /* --- others --- */
          --divider-color: #f4f4f4;
        }`
    }
  ]
});
```

+ 或者动态添加主题：

```js
PMdropin.emit('addTheme', [
  {
    name: 'red', 
    base: 'light',
    style: ''
  }
]);
```

##### 6. emit.setDisabled
+ 设置组件可用状态
+ 类型 `Boolean`
+ 默认：`false`

```js
// 不可编辑状态
PMdropin.emit('setDisabled', true)

// 可编辑状态
PMdropin.emit('setDisabled', false)
```

##### 7. emit.setRtl
+ 设置组件从右到左布局
+ 类型： `Boolean`
+ 默认：`false`

```js
// 从右到左布局
PMdropin.emit('setRtl', true)

// 从左到右布局
PMdropin.emit('setRtl', false)
```

##### 8. emit.setGrayscale
+ 设置组件页面灰度
+ 类型： `String`
+ 默认：`0`

```js
// 设置 0 - 1 灰度值
PMdropin.emit('setGrayscale', '1')
```
