Skip to content

Plugin Product Type

worable edited this page Oct 20, 2026 · 2 revisions

商品类型与上游关联(Product Type / Upstream)

StackPanel 的 store 插件是纯底层:商品、购物车、订单、履约调度、服务实例容器, 对任何具体商品类型零感知。每个商品类型(云服务器、发卡、会员…)由一个独立插件扩展, 外部上游(如智简魔方)通过「上游商品数据源」为商品表单提供可选的上游商品关联。

概念

  • 商品类型(ProductType):EXTENSION_POINTS.productType(store.productType)。 类型插件定义某类型商品的形态:类型展示名、类型配置字段(表单)与后端校验。是否能履约由 商品绑定的履约提供方决定;分类本身不能伪造开通结果。
  • 上游(Upstream):EXTENSION_POINTS.upstreamProductSource(upstream.product.source)。 上游插件提供「可关联的上游商品」(搜索/取单个)。商品可关联也可不关联; 关联时同步上游价格到 product.cost(成本,仅后台可见),标题/简介/图标默认预填上游信息(可改)。

两个概念正交:类型插件不依赖上游;上游插件不依赖具体类型。

商品类型插件

import { EXTENSION_POINTS, definePlugin } from '@stackpanel/sdk';
import type {
  ProductConfigField,
  ProductTypeProvider,
} from '@stackpanel/sdk';
import { z } from 'zod';

// 选项必须从插件实际拥有的服务能力或已验证的上游读取;这里仅声明字段形状,
// 不伪造任何区域、规格或价格。
const configFields: ProductConfigField[] = [
  { name: 'planId', label: '套餐', type: 'text', required: true },
];

const configSchema = z.object({ planId: z.string().min(1).max(191) });

const productType: ProductTypeProvider = {
  id: 'store-product-my-type',
  label: '我的类型',
  fulfillmentTypes: ['my_type'],
  configFields,
  configSchema,
};

export const plugin = definePlugin({
  manifest: { id: 'store-product-my-type', name: '我的类型', version: '0.1.0', requires: ['store'] },
  onActivate: (ctx) => {
    ctx.registerExtension(EXTENSION_POINTS.productType, productType);
  },
});
  • fulfillmentTypes:本插件认领的类型 key(写入 product.fulfillmentType)。
  • configFields:管理端商品表单的类型配置字段(数据驱动,store 通用渲染;存到 product.metadata)。
  • configSchema:创建/编辑商品时后端校验类型配置。
  • 本地履约只适用于插件真实拥有并能操作的服务;不得用状态写入、占位凭证或模拟运维动作伪造开通。 cloud_server 商品例外:必须绑定已启用且声明支持 cloud_server 的真实履约提供方。

上游插件(如 zjmf-upstream)

import { EXTENSION_POINTS } from '@stackpanel/sdk';
import type { UpstreamProductItem, UpstreamProductSource } from '@stackpanel/sdk';

const source: UpstreamProductSource = {
  id: 'zjmf', name: '智简魔方',
  async search(query, options) { /* 返回 UpstreamProductItem[] */ },
  async get(id) { /* 返回单个或 null */ },
  async associate({ productId, item }) {
    // 在自己的表里建立 本地商品 ↔ 上游商品 映射(履约时据此定位上游实例)。
  },
  async dissociate(productId) { /* 删除映射 */ },
};

onActivate: (ctx) => ctx.registerExtension(EXTENSION_POINTS.upstreamProductSource, source);

UpstreamProductItem:id(上游商品 id,→ product.providerProductId)、name、 price(分单位,→ product.cost)、description/icon/specs(预填默认值)、sourceRef(上游实例标识)。

商品表单的「关联上游商品」

  • 仅当 ≥1 个上游插件激活时,商品表单才显示「关联上游商品」区块。
  • 搜索由 store 代理到上游 source(GET /store/upstream-products/:provider?q=)。
  • 选择上游商品 → 写入 providerId + providerProductId、同步 cost,标题/简介/图标默认预填(可改)。
  • 非云服务器商品可不绑定上游,但仅在其类型插件具有真实本地履约能力时才能交付;云服务器商品未绑定提供方会被服务端拒绝。

store 通用 API

方法 路径 说明
GET /store/product-types 活跃商品类型(含 configFields)
GET /store/upstream-sources 活跃上游插件
GET /store/upstream-products/:provider?q= 搜索上游商品
GET /store/upstream-products/:provider/:productId 取单个上游商品

示例插件

  • store-product-server:云服务器分类。它不提供区域、镜像、价格或本地履约;创建商品时必须 绑定如 zjmf 的已启用真实履约提供方,选项与计价由上游商品配置提供。
  • store-product-card:发卡/兑换码(card_codes 码池 + 付款弹码履约 + 码池管理路由)。

Clone this wiki locally