# 失效卡片

`expiredWidget()` 用于把已经过期的业务 Widget 实例更新成框架内置失效卡，通常在业务 Widget 内容失效后调用。

`__doubao_apps__expired-widget` 是框架内置虚拟 Widget，不需要在 `src/widgets` 中创建同名目录，也不要手动注册到
`src/app.config.ts`。

`expiredWidget()` 的 `url` 是用户点击失效卡后跳转的目标 Page 路径或 schema。

---

## 当前 Widget 标记为失效

在 Widget 内部可以通过 `getWidgetInstanceId()` 获取当前实例 ID，再调用 `expiredWidget()`。`getWidgetInstanceId()`
只在 Widget 环境有值，在 Page 中通常返回 `undefined`。

```ts
import { getWidgetInstanceId } from '@doubao-dev/framework';
import { expiredWidget } from '@doubao-dev/framework/api';

async function markCurrentWidgetExpired() {
  const widgetInstanceId = getWidgetInstanceId();
  if (!widgetInstanceId) {
    return;
  }

  await expiredWidget({
    widgetInstanceId,
    url: '/pages/detail/index?from=expired',
    title: '内容已失效',
    detailText: '点击查看最新内容'
  });
}
```

---

## 从 Widget 打开 Page 并传递 widgetInstanceId

如果需要在 Page 中处理过期逻辑，先在 Widget 中拿到 `widgetInstanceId`，通过页面跳转参数传给目标 Page。

```tsx
import { getWidgetInstanceId } from '@doubao-dev/framework';
import { navigateTo } from '@doubao-dev/framework/api';

export default function OrderWidget() {
  const handleOpenDetail = async () => {
    const widgetInstanceId = getWidgetInstanceId();
    const query = widgetInstanceId ? `?widgetInstanceId=${encodeURIComponent(widgetInstanceId)}` : '';

    await navigateTo({
      url: `/pages/order-detail/index${query}`
    });
  };

  return (
    <view className="order-widget">
      <button text="查看详情" onClick={handleOpenDetail} />
    </view>
  );
}
```

---

## Page 中读取 widgetInstanceId 并标记失效

Page 不直接拥有 Widget 实例 ID。需要从 `useViewData<T>()` 读取上一步传入的 `widgetInstanceId`，或通过业务数据、通信等方式拿到目标实例 ID。

```tsx
import { useViewData } from '@doubao-dev/framework';
import { expiredWidget } from '@doubao-dev/framework/api';
import './index.scss';

interface OrderDetailPageData {
  widgetInstanceId?: string;
}

export default function OrderDetailPage() {
  const viewData = useViewData<OrderDetailPageData>();

  const handleMarkExpired = async () => {
    if (!viewData.widgetInstanceId) {
      return;
    }

    await expiredWidget({
      widgetInstanceId: viewData.widgetInstanceId,
      url: '/pages/order-detail/index?from=expired',
      title: '订单状态已更新',
      detailText: '点击查看最新订单状态'
    });
  };

  return (
    <view className="order-detail-page">
      <button text="标记原卡片失效" disabled={!viewData.widgetInstanceId} onClick={handleMarkExpired} />
    </view>
  );
}
```
