import type { EndpointSpec, ParamSpec } from './types' // 通用响应体字段说明,所有接口共用。 export const commonResponseFields: ParamSpec[] = [ { name: 'code', type: 'int', required: true, desc: '0 表示成功,非 0 表示失败' }, { name: 'message', type: 'string', required: true, desc: '成功为 "ok",失败为错误描述' }, { name: 'data', type: 'object', desc: '业务数据,失败时省略' }, ] // 通用错误码。 export const errorCodes: ParamSpec[] = [ { name: '400', type: 'int', desc: '参数错误 / 业务校验失败(余额不足、库存不足、状态非法等)' }, { name: '401', type: 'int', desc: '鉴权失败(Key 缺失、签名错误、时间戳过期、Nonce 重复)' }, { name: '403', type: 'int', desc: '权限不足(缺少所需 scope 或商户功能未开通)' }, { name: '404', type: 'int', desc: '资源不存在(订单号不存在等)' }, { name: '500', type: 'int', desc: '服务端内部错误' }, ] // 订单状态与可发货说明。 export const orderStatusTable: ParamSpec[] = [ { name: 'paid', type: 'order_status', desc: '已支付/已扣款,可发货', example: 'can_ship=true' }, { name: 'delivering', type: 'order_status', desc: '发货中', example: 'can_ship=false' }, { name: 'delivered', type: 'order_status', desc: '已交付', example: 'can_ship=false' }, { name: 'ship_failed', type: 'order_status', desc: '发货失败,可重试', example: 'can_ship=true' }, { name: 'cancelled', type: 'order_status', desc: '已取消', example: 'can_ship=false' }, ] // 订单对象公共字段说明,下单/查询/取消响应共用。 const orderFields: ParamSpec[] = [ { name: 'order_no', type: 'string', required: true, desc: '平台订单号' }, { name: 'client_order_no', type: 'string', required: true, desc: '调用方传入的幂等单号' }, { name: 'order_status', type: 'enum', desc: '订单状态,见「状态说明」' }, { name: 'can_ship', type: 'bool', desc: '是否允许发货' }, { name: 'cannot_ship_reason', type: 'string', desc: 'can_ship=false 时的原因' }, { name: 'product.sku', type: 'string', desc: '商品标识,发货以此为准' }, { name: 'product.name', type: 'string', desc: '商品展示名' }, { name: 'quantity', type: 'int', desc: '数量' }, { name: 'base_amount', type: 'int', desc: '商品基础金额(最小货币单位)' }, { name: 'fee_type', type: 'enum(rate|fixed)', desc: '手续费类型' }, { name: 'service_fee_amount', type: 'int', desc: '手续费金额' }, { name: 'amount', type: 'int', desc: '实付总额 = base_amount + service_fee_amount' }, { name: 'currency', type: 'string', desc: '货币,默认 POINT' }, { name: 'buyer_reference', type: 'string', desc: '买家标识/备注' }, { name: 'data', type: 'object', desc: '下单时透传的请求数据(原样回显)' }, { name: 'result', type: 'object', desc: '发货平台回调的结果数据(原样回显)' }, { name: 'provider_order_no', type: 'string', desc: '发货平台侧单号' }, { name: 'failure_reason', type: 'string', desc: '最近一次失败原因' }, { name: 'created_at', type: 'datetime', desc: '创建时间' }, { name: 'delivered_at', type: 'datetime', desc: '交付时间' }, { name: 'cancelled_at', type: 'datetime', desc: '取消时间' }, ] const orderResponseExample = `{ "code": 0, "message": "ok", "data": { "order_no": "FO20260730000123", "client_order_no": "shop-10001", "order_status": "paid", "can_ship": true, "cannot_ship_reason": "", "product": { "sku": "suit_pink_sheep", "name": "套装-糯粉咩咩" }, "quantity": 1, "base_amount": 100, "fee_type": "rate", "service_fee_amount": 5, "amount": 105, "currency": "POINT", "buyer_reference": "buyer-001", "data": { "server": "ios-wechat", "uid": "player-id" }, "provider_order_no": "", "failure_reason": "", "created_at": "2026-07-30T10:00:00+08:00", "delivered_at": null, "cancelled_at": null } }` 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:00+08:00", "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": "delivering", "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[] = [ { key: 'list-products', method: 'GET', path: '/api/client/v1/products', title: '商品列表', summary: '查询商户已授权且上架的商品列表', scope: 'products:read', queryParams: [ { name: 'page', type: 'int', desc: '页码,默认 1', example: '1' }, { name: 'size', type: 'int', desc: '每页条数,默认 20', example: '20' }, ], responseExample: `{ "code": 0, "message": "ok", "data": { "list": [ { "id": 12, "sku": "suit_pink_sheep", "display_name": "套装-糯粉咩咩", "price_amount": 100, "cost_amount": 80, "currency": "POINT", "stock": -1, "status": "active", "product": { "code": "suit_pink_sheep", "name": "套装-糯粉咩咩", "category": "和平精英" } } ], "total": 1, "page": 1, "size": 20 } }`, responseFields: [ { name: 'list[].sku', type: 'string', desc: '商品标识,下单时作为 sku 传入' }, { name: 'list[].display_name', type: 'string', desc: '商户自定义展示名' }, { name: 'list[].price_amount', type: 'int', desc: '单价(最小货币单位)' }, { name: 'list[].stock', type: 'int', desc: '库存,-1 表示不限' }, { name: 'list[].status', type: 'enum', desc: '商品状态,active 可售' }, { name: 'list[].product', type: 'object', desc: '平台商品目录快照' }, { name: 'total', type: 'int', desc: '总条数' }, { name: 'page', type: 'int', desc: '当前页码' }, { name: 'size', type: 'int', desc: '每页条数' }, ], }, { key: 'create-order', method: 'POST', path: '/api/client/v1/orders', title: '创建订单', summary: '幂等创建订单并扣款(成功返回 201,重复请求返回 200 且 idempotent=true)', scope: 'orders:write', bodyParams: [ { name: 'client_order_no', type: 'string', required: true, desc: '调用方幂等单号,同一商户下唯一', example: 'shop-10001' }, { name: 'sku', type: 'string', required: true, desc: '商品标识,取自商品列表', example: 'suit_pink_sheep' }, { name: 'quantity', type: 'int', desc: '数量,默认 1', example: '1' }, { name: 'buyer_reference', type: 'string', desc: '买家标识/备注', example: 'buyer-001' }, { name: 'data', type: 'object', desc: '透传给发货流程的业务数据(区服、账号等),原样存储并回显' }, ], requestExample: `{ "client_order_no": "shop-10001", "sku": "suit_pink_sheep", "quantity": 1, "buyer_reference": "buyer-001", "data": { "server": "ios-wechat", "uid": "player-id" } }`, responseExample: `{ "code": 0, "message": "ok", "data": { "idempotent": false, "order": { "order_no": "FO20260730000123", "client_order_no": "shop-10001", "order_status": "paid", "can_ship": true, "cannot_ship_reason": "", "product": { "sku": "suit_pink_sheep", "name": "套装-糯粉咩咩" }, "quantity": 1, "base_amount": 100, "fee_type": "rate", "service_fee_amount": 5, "amount": 105, "currency": "POINT", "buyer_reference": "buyer-001", "data": { "server": "ios-wechat", "uid": "player-id" }, "provider_order_no": "", "failure_reason": "", "created_at": "2026-07-30T10:00:00+08:00", "delivered_at": null, "cancelled_at": null } } }`, responseFields: [ { name: 'idempotent', type: 'bool', desc: 'true 表示该 client_order_no 已存在,返回既有订单(未重复扣款)' }, { name: 'order', type: 'object', desc: '订单完整对象,字段见下方「订单字段说明」' }, ], notes: [ 'client_order_no 是唯一幂等单号,请保证同一商户下不重复;重复请求不会重复扣款,返回 idempotent=true 及既有订单。', '当前无真实支付流程,下单成功即扣款并进入 order_status=paid,余额不足返回 400。', '下单成功后请保存 order_no,后续查询/发货/回调均以 order_no 为准;client_order_no 仅用于幂等。', 'data 字段会原样存储并回显,可用于透传区服、账号等业务数据。', ], }, { key: 'query-order', method: 'GET', path: '/api/client/v1/orders/{order_no}', title: '查询订单', summary: '查询订单状态与详情', scope: 'orders:read', pathParams: [{ name: 'order_no', type: 'string', required: true, desc: '平台订单号', example: 'FO20260730000123' }], responseExample: orderResponseExample, responseFields: orderFields, }, { key: 'cancel-order', method: 'POST', path: '/api/client/v1/orders/{order_no}/cancel', title: '取消订单', summary: '取消未发货订单并退款(仅 paid/ship_failed 可取消)', scope: 'orders:write', pathParams: [{ name: 'order_no', type: 'string', required: true, desc: '平台订单号', example: 'FO20260730000123' }], bodyParams: [{ name: 'reason', type: 'string', desc: '取消原因(可选)', example: '买家主动取消' }], requestExample: `{ "reason": "买家主动取消" }`, responseExample: orderResponseExample, responseFields: orderFields, notes: [ '取消成功后 order_status 变为 cancelled,金额退回商户钱包。', '已进入 delivering/delivered 的订单不可取消,返回 400。', ], }, { key: 'delivery-link', method: 'GET', path: '/api/client/v1/orders/{order_no}/delivery-link', title: '获取发货链接', summary: '获取签名发货链接,适合直接跳转平台 Web 发货页', scope: 'orders:read 或 shipping: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', title: '查询发货数据', summary: '查询发货页结构化数据,适合商户自建发货界面', scope: 'orders:read 或 shipping: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', title: '发起绑定', 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', title: '提交发货', 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', method: 'GET', path: '/api/client/v1/wallet', title: '余额查询', summary: '查询商户钱包余额', scope: 'wallet:read', responseExample: `{ "code": 0, "message": "ok", "data": { "id": 1, "merchant_id": 2, "currency": "POINT", "available_balance": 895, "frozen_balance": 0 } }`, responseFields: [ { name: 'currency', type: 'string', desc: '货币,默认 POINT' }, { name: 'available_balance', type: 'int', desc: '可用余额(最小货币单位)' }, { name: 'frozen_balance', type: 'int', desc: '冻结余额' }, ], }, ]