补开放接口文档

This commit is contained in:
yml2213
2026-07-31 12:29:43 +08:00
parent 761522e808
commit 667bfbde06
2 changed files with 234 additions and 2 deletions
+165
View File
@@ -85,6 +85,68 @@ const orderResponseExample = `{
} }
}` }`
const deliveryOrderResponseExample = `{
"code": 0,
"message": "ok",
"data": {
"order_no": "FO20260730000123",
"status": "paid",
"can_ship": true,
"cannot_ship_reason": "",
"product": { "name": "套装-糯粉咩咩", "sku": "suit_pink_sheep", "game": "和平精英" },
"buyer_name": "buyer-001",
"amount": 105,
"created_at": "2026-07-30T10:00:00+08:00",
"shipped_at": null,
"ship_fail_reason": "",
"game_channel": "安卓-QQ",
"game_uid": "4808146277",
"role_name": "巫师哈丁12",
"pay_score": 360,
"good": { "title": "套装-糯粉咩咩", "image": "https://..." }
}
}`
const deliveryLinkResponseExample = `{
"code": 0,
"message": "ok",
"data": {
"order_no": "FO20260730000123",
"delivery_url": "https://shop.example/delivery/dlc/FO20260730000123?exp=1753934400&sign=...",
"expires_at": "2026-07-31T12:00:00Z",
"exp": 1753934400,
"sign": "..."
}
}`
const deliveryBindResponseExample = `{
"code": 0,
"message": "ok",
"data": {
"bind_uuid": "bind-123",
"bind_url": "https://bind.example/qrcode",
"qr_url": "https://api.qrserver.com/v1/create-qr-code/?size=240x240&data=https%3A%2F%2Fbind.example%2Fqrcode"
}
}`
const deliverySubmitResponseExample = `{
"code": 0,
"message": "ok",
"data": {
"order_no": "FO20260730000123",
"status": "processing",
"message": "已提交上游发货,等待发货结果回传",
"provider_order_no": "provider-1",
"game_account": {
"game_account": "4808146277",
"game_account_role_name": "巫师哈丁12"
},
"upstream_order": {
"order_no": "provider-1"
}
}
}`
export const endpoints: EndpointSpec[] = [ export const endpoints: EndpointSpec[] = [
{ {
key: 'list-products', key: 'list-products',
@@ -200,6 +262,109 @@ export const endpoints: EndpointSpec[] = [
'已进入 processing/succeeded 的订单不可取消,返回 400。', '已进入 processing/succeeded 的订单不可取消,返回 400。',
], ],
}, },
{
key: 'delivery-link',
method: 'GET',
path: '/api/client/v1/orders/{order_no}/delivery-link',
summary: '获取签名发货链接,适合直接跳转平台 Web 发货页',
scope: 'orders:read + fulfillment:read',
pathParams: [{ name: 'order_no', type: 'string', required: true, desc: '平台订单号', example: 'FO20260730000123' }],
responseExample: deliveryLinkResponseExample,
responseFields: [
{ name: 'order_no', type: 'string', desc: '平台订单号' },
{ name: 'delivery_url', type: 'string', desc: '可直接打开的发货链接' },
{ name: 'expires_at', type: 'datetime', desc: '链接过期时间' },
{ name: 'exp', type: 'int', desc: '过期 Unix 秒时间戳' },
{ name: 'sign', type: 'string', desc: '签名,供链接校验使用' },
],
notes: [
'适合商户系统只想“返回一个链接”给终端用户的场景。',
'delivery_url 可以直接给用户打开,sign 仅供后端或调试使用,不建议展示。',
],
},
{
key: 'delivery-order',
method: 'GET',
path: '/api/client/v1/orders/{order_no}/delivery',
summary: '查询发货页结构化数据,适合商户自建发货界面',
scope: 'orders:read + fulfillment:read',
pathParams: [{ name: 'order_no', type: 'string', required: true, desc: '平台订单号', example: 'FO20260730000123' }],
responseExample: deliveryOrderResponseExample,
responseFields: [
{ name: 'order_no', type: 'string', desc: '平台订单号' },
{ name: 'status', type: 'string', desc: '订单状态' },
{ name: 'can_ship', type: 'bool', desc: '是否可以发货' },
{ name: 'cannot_ship_reason', type: 'string', desc: '不可发货原因' },
{ name: 'product', type: 'object', desc: '商品信息' },
{ name: 'buyer_name', type: 'string', desc: '买家名称 / 备注' },
{ name: 'amount', type: 'int', desc: '订单金额' },
{ name: 'created_at', type: 'datetime', desc: '创建时间' },
{ name: 'shipped_at', type: 'datetime', desc: '发货时间' },
{ name: 'ship_fail_reason', type: 'string', desc: '最近一次失败原因' },
{ name: 'game_channel', type: 'string', desc: '区服渠道' },
{ name: 'game_uid', type: 'string', desc: 'UID / 角色编号' },
{ name: 'role_name', type: 'string', desc: '角色名' },
{ name: 'pay_score', type: 'int', desc: '消耗积分' },
{ name: 'good', type: 'object', desc: '上游商品详情' },
],
notes: [
'该接口返回的是结构化数据,适合商户自有页面渲染。',
'如果只是想直接给用户一个发货页链接,优先用 delivery-link。',
],
},
{
key: 'delivery-bind',
method: 'POST',
path: '/api/client/v1/orders/{order_no}/delivery/bind',
summary: '发起绑定,返回绑定跳转链接与二维码地址',
scope: 'orders:write',
pathParams: [{ name: 'order_no', type: 'string', required: true, desc: '平台订单号', example: 'FO20260730000123' }],
bodyParams: [
{ name: 'game_account', type: 'string', required: true, desc: '玩家编号 / UID', example: '4808146277' },
],
requestExample: `{
"game_account": "4808146277"
}`,
responseExample: deliveryBindResponseExample,
responseFields: [
{ name: 'bind_uuid', type: 'string', desc: '绑定凭证,提交发货时使用' },
{ name: 'bind_url', type: 'string', desc: '绑定跳转地址' },
{ name: 'qr_url', type: 'string', desc: '绑定二维码地址' },
],
notes: [
'适合商户自建页面先让用户确认 UID,再去拿绑定结果。',
'同一订单重复绑定时,请以最新返回的绑定凭证为准。',
],
},
{
key: 'delivery-submit',
method: 'POST',
path: '/api/client/v1/orders/{order_no}/delivery/submit',
summary: '提交发货到上游并进入履约中状态',
scope: 'orders:write',
pathParams: [{ name: 'order_no', type: 'string', required: true, desc: '平台订单号', example: 'FO20260730000123' }],
bodyParams: [
{ name: 'game_account', type: 'string', required: true, desc: '玩家编号 / UID', example: '4808146277' },
{ name: 'bind_uuid', type: 'string', required: true, desc: '绑定凭证', example: 'bind-123' },
],
requestExample: `{
"game_account": "4808146277",
"bind_uuid": "bind-123"
}`,
responseExample: deliverySubmitResponseExample,
responseFields: [
{ name: 'order_no', type: 'string', desc: '平台订单号' },
{ name: 'status', type: 'string', desc: '提交后的履约状态' },
{ name: 'message', type: 'string', desc: '处理结果说明' },
{ name: 'provider_order_no', type: 'string', desc: '上游订单号' },
{ name: 'game_account', type: 'object', desc: '上游绑定结果' },
{ name: 'upstream_order', type: 'object', desc: '上游创建结果' },
],
notes: [
'同一订单重复提交应直接返回已有结果,不应重复创建上游队列。',
'提交成功后,最终成功/失败仍以 `ship_notify` 回传结果为准。',
],
},
{ {
key: 'get-wallet', key: 'get-wallet',
method: 'GET', method: 'GET',
+69 -2
View File
@@ -28,6 +28,20 @@ const preStyle: CSSProperties = {
wordBreak: 'break-all', 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() { export default function OpenApiDocs() {
return ( return (
<div> <div>
@@ -37,10 +51,13 @@ export default function OpenApiDocs() {
<Paragraph type="secondary"> <Paragraph type="secondary">
API / API API / API
<Text code>X-App-Key</Text> + HMAC-SHA256 <Text code>X-App-Key</Text> + HMAC-SHA256
<Text code>/api/open/v1</Text>
<Text code>/api/open/v1</Text> API
</Paragraph> </Paragraph>
<Tabs <Tabs
tabPosition="left"
style={{ minHeight: 680 }}
items={[ items={[
{ {
key: 'overview', key: 'overview',
@@ -57,6 +74,11 @@ export default function OpenApiDocs() {
label: '接口列表', label: '接口列表',
children: <EndpointsTab />, children: <EndpointsTab />,
}, },
{
key: 'delivery',
label: '发货模式',
children: <DeliveryModeTab />,
},
{ {
key: 'status', key: 'status',
label: '状态说明', label: '状态说明',
@@ -80,10 +102,29 @@ function OverviewTab() {
<li> / API <Text code>AppKey</Text> <Text code>AppSecret</Text></li> <li> / API <Text code>AppKey</Text> <Text code>AppSecret</Text></li>
<li> <Text code>X-App-Key / X-Timestamp / X-Nonce / X-Sign</Text> </li> <li> <Text code>X-App-Key / X-Timestamp / X-Nonce / X-Sign</Text> </li>
<li> <Text code>sku</Text></li> <li> <Text code>sku</Text></li>
<li> <Text code>order_no</Text> </li> <li> <Text code>order_no</Text> </li>
</ol> </ol>
} }
/> />
<Card size="small" title="发货链路概览">
<Table
size="small"
pagination={false}
rowKey="mode"
dataSource={deliveryModes}
columns={[
{ title: '模式', dataIndex: 'mode', width: 140 },
{ title: '适用场景', dataIndex: 'scene' },
{
title: '相关接口',
dataIndex: 'interfaces',
render: (v: string) => (
<pre style={preStyle}>{v}</pre>
),
},
]}
/>
</Card>
<Card size="small" title="环境信息"> <Card size="small" title="环境信息">
<Descriptions size="small" column={1} bordered> <Descriptions size="small" column={1} bordered>
<Descriptions.Item label="Base URL"> <Descriptions.Item label="Base URL">
@@ -101,6 +142,32 @@ function OverviewTab() {
) )
} }
function DeliveryModeTab() {
return (
<Space direction="vertical" size="middle" style={{ width: '100%' }}>
<Card size="small" title="推荐用法">
<Descriptions size="small" column={1} bordered>
<Descriptions.Item label="只想给用户一个链接">
<Text code>delivery-link</Text> Web
</Descriptions.Item>
<Descriptions.Item label="想自建发货页面">
<Text code>delivery</Text> <Text code>bind</Text> <Text code>submit</Text>
</Descriptions.Item>
<Descriptions.Item label="取消作废">
</Descriptions.Item>
</Descriptions>
</Card>
<Alert
type="info"
showIcon
message="两种模式共用同一套底层履约逻辑"
description="不管是 Web 发货页还是商户自建页面,最终都会走同一套订单校验、绑定和提交逻辑,只是前端形态不同。"
/>
</Space>
)
}
function AuthTab() { function AuthTab() {
return ( return (
<Space direction="vertical" size="middle" style={{ width: '100%' }}> <Space direction="vertical" size="middle" style={{ width: '100%' }}>