import type { CSSProperties } from 'react'
import { Alert, Card, Collapse, Descriptions, Space, Table, Tabs, Tag, Typography } from 'antd'
import EndpointDoc, { CommonResponseDoc } from '../openapi/EndpointDoc'
import {
commonResponseFields,
endpoints,
errorCodes,
orderStatusTable,
paymentStatusTable,
} from '../openapi/endpoints'
const { Title, Paragraph, Text } = Typography
const baseUrl =
typeof window !== 'undefined'
? window.location.origin.replace(':5173', ':8080')
: 'http://localhost:8080'
const preStyle: CSSProperties = {
margin: 0,
padding: 12,
background: '#f6f8fa',
borderRadius: 6,
fontSize: 12.5,
lineHeight: 1.6,
overflow: 'auto',
whiteSpace: 'pre-wrap',
wordBreak: 'break-all',
}
const deliveryModes = [
{
mode: 'Web 发货页',
scene: '商户想要“只返回一个链接”,让用户直接打开平台页面填写 UID',
interfaces: '/api/client/v1/orders/{order_no}/delivery-link',
},
{
mode: '自建发货页',
scene: '商户自己有前端页面,想在自己的系统里完成发货流程',
interfaces:
'/api/client/v1/orders/{order_no}/delivery\n/api/client/v1/orders/{order_no}/delivery/bind\n/api/client/v1/orders/{order_no}/delivery/submit',
},
]
export default function OpenApiDocs() {
return (
开放接口
面向商户系统调用的开放 API。凭证在「商户中心 / API 客户端」创建,
采用 X-App-Key + HMAC-SHA256 签名鉴权。
发货链路同时支持「返回签名链接」和「返回结构化数据」两种模式。
/api/open/v1 仍是上游回调链路,和本页的商户 API 分开。
,
},
{
key: 'auth',
label: '鉴权与签名',
children:
,
},
{
key: 'endpoints',
label: '接口列表',
children:
,
},
{
key: 'delivery',
label: '发货模式',
children:
,
},
{
key: 'status',
label: '状态说明',
children:
,
},
]}
/>
)
}
function OverviewTab() {
return (
在「商户中心 / API 客户端」创建凭证,获得 AppKey 与 AppSecret。
每次请求携带 X-App-Key / X-Timestamp / X-Nonce / X-Sign 四个鉴权头。
调用「商品列表」拿到可售 sku,调用「下单」创建订单并扣款。
拿到 order_no 后,可选择返回发货链接,或者用结构化发货接口完成自建页面流程。
}
/>
(
{v}
),
},
]}
/>
{baseUrl}
X-App-Key、X-Timestamp、X-Nonce、X-Sign
允许 ±300 秒
POST 请求使用 application/json
)
}
function DeliveryModeTab() {
return (
用 delivery-link,后端直接返回签名后的 Web 发货页地址,前端只负责跳转或复制。
用 delivery 获取订单数据,再按需调用 bind 和 submit。
取消作废属于商户后台操作,恢复后会重新签发新有效期和新签名。
)
}
function AuthTab() {
return (
{v} },
{ title: '必填', dataIndex: 'required', width: 80, render: (v) => v ? 是 : 否 },
{ title: '说明', dataIndex: 'desc' },
]}
/>
app_key、body_sha256、method、nonce、path、timestamp
参数按 ASCII 字典序,用 & 拼成 k1=v1&k2=v2&...
app_key, body_sha256, method, nonce, path, timestamp
大写,如 GET / POST
仅 URL.Path,不含域名和 query
SHA256(原始 body 字节) 的十六进制小写;GET 用空 body 的摘要
原样拼接,不做 URL encode
hex( HMAC-SHA256( app_secret, 签名串 ) ),小写十六进制
{`app_key=ak_xxx&body_sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855&method=GET&nonce=a1b2c3d4e5f67890&path=/api/client/v1/products×tamp=1721450000`}
{`# body = {"client_order_no":"shop-10001","sku":"suit_pink_sheep"}
app_key=ak_xxx&body_sha256=<实际请求 body 字节的 SHA256 十六进制>&method=POST&nonce=a1b2c3d4e5f67890&path=/api/client/v1/orders×tamp=1721450000`}
POST 签名用的 body 必须与实际发送的 body 字节级一致,不要签名后再改空格或字段顺序。
value 不要 URL encode,原样参与拼接。
签名失败常见原因:secret 错、path 多了 query、body 与签名不一致、时间戳过期、nonce 重复、参数未按字典序拼接。
下单接口还需携带 Idempotency-Key,且必须与 client_order_no 一致。
}
/>
)
}
function EndpointsTab() {
return (
({
key: spec.key,
label: (
{spec.method}
{spec.path}
{spec.summary}
),
children: ,
}))}
/>
)
}
function StatusTab() {
return (
{v} },
{
title: 'can_fulfill',
dataIndex: 'example',
width: 160,
render: (v: string) =>
v === 'can_fulfill=true' ? true : false,
},
{ title: '说明', dataIndex: 'desc' },
]}
/>
{v} },
{ title: '说明', dataIndex: 'desc' },
]}
/>
{`拿到 sku(商品列表)
↓
POST /orders 下单(幂等,Idempotency-Key = client_order_no)
↓
拿响应里的 order_no 进入发货平台链接
↓
发货平台查询订单并执行发货
↓
发货平台通过上游回调更新 fulfillment_status
↓
GET /orders/{order_no} 轮询,或接收 order.fulfillment.updated 回调`}
}
/>
)
}