> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aftersell.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 订阅升级块

> Aftersell Cart 的订阅升级（Subscription upgrade）子块：在购物车中将符合条件的一次性购买行项目转换为订阅。

> \*\*Subscription upgrade（订阅升级）\*\*块是嵌套在 [**Cart items**](/zh/aftersell/cart/cart-items-block) 内的子块。它提示购物者直接在购物车中将符合条件的一次性购买行项目切换为订阅，在决策时刻把一次性购买变为经常性收入，并让已订阅的购物者在该行项目上更改或取消其计划。

<div id="behavior">
  ## 行为
</div>

* \*\*仅出现在符合条件的行项目上。\*\*该块会读取产品的销售计划，对没有订阅计划的产品所在的行项目不渲染任何内容。
* \*\*绝不在奖励赠品上提供。\*\*订阅自动发放的免费赠品会剥夺其奖励状态，因此在这些行项目上不显示提示。
* 在**一次性购买行项目**上，它显示升级号召按钮。
* 在**已订阅的行项目**上，它显示计划选择器以及"降级为一次性购买"选项。

<div id="settings">
  ## 设置
</div>

| 设置                   | 控制的内容                                                     | 默认值                             |
| -------------------- | --------------------------------------------------------- | ------------------------------- |
| **Button text**      | 一次性购买行项目上的升级号召文案。支持 `{{discount}}` 和 `{{plan name}}` 占位符。 | `Subscribe & Save`              |
| **Unsubscribe text** | 将已订阅行项目恢复为一次性购买的选项文案。                                     | `Downgrade - One time purchase` |

<div id="placement-and-limits">
  ## 位置与限制
</div>

* \*\*父级：\*\*仅可嵌套在 Cart items 内。
* \*\*最大数量：\*\*每个购物车 1 个。
* 默认不添加。未锁定，因此你可以移除或隐藏它。

由于它是子块，它会按行项目渲染，根据你相对于 Product row 的放置位置显示在产品内容的上方或下方。参见[子块如何定位](/zh/aftersell/cart/cart-items-block#sub-blocks-and-how-they-position)。

<div id="custom-template">
  ## 自定义模板
</div>

支持在其 Code 选项卡中使用[自定义模板](/zh/aftersell/cart/custom-templates)，用你的 JSX 替换此块的内置标记。以下是它接收的 props。

此块渲染两种状态之一，`view.state` 告诉你是哪一种。在自定义模板中 `view` 永远不会是 `null`：当行项目没有计划时，该块不渲染任何内容，你的模板也不会被调用。

| Prop              | 类型                                 | 用途                                                                                                    |
| ----------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `view`            | `object`                           | 行项目的状态。为 `{ state: 'upgrade', buttonText, planId }` 或 `{ state: 'subscribed', plans, activePlanId }`。 |
| `title`           | `string`                           | **产品**的标题，而不是此块的标题。内置模板仅用它来构建计划选择器的无障碍标签。                                                             |
| `unsubscribeText` | `string`                           | 降级为一次性购买选项的标签。                                                                                        |
| `busy`            | `boolean`                          | 计划变更进行中时为 `true`。                                                                                     |
| `selectPlan`      | `(planId: number \| null) => void` | 订阅或切换计划。传 `null` 表示取消订阅。                                                                              |
| `onChange`        | `(event: Event) => void`           | 为 `<select>` 准备好的 `onChange`，让你无需自己解析值。                                                               |
| `oneTimeValue`    | `string`                           | 代表"一次性购买"的哨兵 `<option>` 值。                                                                            |
| `line`            | `AftersellCartLine`                | 此块所属的[购物车行项目](/zh/aftersell/cart/sdk-cart-object#cart-lines)。                                         |
| `productId`       | `number`                           | Shopify 产品 ID。                                                                                        |
| `variantId`       | `number`                           | Shopify 变体 ID。                                                                                        |

`view.plans` 中的每个条目为 `{ id: number, name: string, discountPercent: number }`。

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomTemplate(props) {
  const { view } = props;

  if (view.state === 'upgrade') {
    return (
      <button type="button" onClick={() => props.selectPlan(view.planId)} disabled={props.busy}>
        {view.buttonText}
      </button>
    );
  }

  return (
    <div>
      <select
        aria-label={`Subscription plan — ${props.title}`}
        value={String(view.activePlanId)}
        onChange={props.onChange}
        disabled={props.busy}
      >
        {view.plans.map((plan) => (
          <option key={plan.id} value={String(plan.id)}>
            {plan.name}{plan.discountPercent > 0 ? ` (${plan.discountPercent}% off)` : ''}
          </option>
        ))}
        <option value={props.oneTimeValue}>{props.unsubscribeText}</option>
      </select>
    </div>
  );
}
```

<Note>
  `<select>` 用 `onChange`，按钮用 `selectPlan`。`onChange` 已经处理了 `oneTimeValue` 哨兵值；如果你给 `<select>` 接自己的处理函数，就必须自行与 `oneTimeValue` 比较并调用 `selectPlan(null)`。
</Note>

<div id="design">
  ## 设计
</div>

通过设置面板中的 **Design** 部分为此块设置样式。这些是块级覆盖设置，会叠加在你的全局设计之上，留空时回退到全局设计。

什么是设计设置？在这里了解更多：[设计设置](/zh/aftersell/cart/design-settings)。
