From 4aa5258c2d40562db05b7a0c230ef99771c533d5 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Fri, 31 Jul 2026 17:45:20 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=8F=91=E8=B4=A7=E5=8F=A3?= =?UTF-8?q?=E5=BE=84=E5=B9=B6=E4=BF=9D=E6=8A=A4=E7=BB=93=E6=9E=9C=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- backend/internal/config/config.go | 4 +- .../internal/database/migrations/001_init.sql | 2 +- backend/internal/handler/open.go | 2 +- backend/internal/handler/open_v1.go | 12 ++--- backend/internal/model/merchant.go | 2 +- backend/internal/service/delivery.go | 6 +-- backend/internal/service/fulfillment.go | 47 +++++++++--------- backend/internal/service/fulfillment_state.go | 8 ++-- backend/internal/service/fulfillment_test.go | 48 ++++++++++++++++++- docs/API对接关系.md | 2 +- frontend/src/App.tsx | 2 +- frontend/src/layouts/MainLayout.tsx | 4 +- frontend/src/openapi/endpoints.ts | 34 ++++++------- frontend/src/pages/Delivery.tsx | 2 +- frontend/src/pages/MerchantCenter.tsx | 8 ++-- frontend/src/pages/OpenApiDocs.tsx | 6 +-- 17 files changed, 120 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index de25b19..05776ae 100644 --- a/README.md +++ b/README.md @@ -112,8 +112,8 @@ make docker-down # 停止并移除 | `OPEN_SIGN_SKEW` | 签名时间戳偏差(秒) | `300` | | `OPEN_API_DEBUG` | 开放接口调试日志 | debug 模式默认开启 | | `LOG_FILE` | 日志文件路径 | `logs/app.log` | -| `FULFILLMENT_PROCESSING_TIMEOUT_MINUTES` | 履约中订单自动标记失败的超时分钟数,<=0 关闭 | `30` | -| `FULFILLMENT_TIMEOUT_SCAN_INTERVAL_SECONDS` | 履约超时巡检间隔秒数 | `60` | +| `FULFILLMENT_PROCESSING_TIMEOUT_MINUTES` | 发货中订单自动标记失败的超时分钟数,<=0 关闭 | `30` | +| `FULFILLMENT_TIMEOUT_SCAN_INTERVAL_SECONDS` | 发货超时巡检间隔秒数 | `60` | ## 开放接口(皮肤源头对接) diff --git a/backend/internal/config/config.go b/backend/internal/config/config.go index 406d9a5..e3ec8d0 100644 --- a/backend/internal/config/config.go +++ b/backend/internal/config/config.go @@ -36,9 +36,9 @@ type Config struct { DeliveryLinkSecret string // DeliveryLinkTTLMinutes 发货链接默认有效分钟数。 DeliveryLinkTTLMinutes int - // FulfillmentProcessingTimeoutMinutes 履约中订单超过该分钟数自动标记失败;<=0 表示关闭。 + // FulfillmentProcessingTimeoutMinutes 发货中订单超过该分钟数自动标记失败;<=0 表示关闭。 FulfillmentProcessingTimeoutMinutes int - // FulfillmentTimeoutScanIntervalSeconds 履约超时巡检间隔秒数。 + // FulfillmentTimeoutScanIntervalSeconds 发货超时巡检间隔秒数。 FulfillmentTimeoutScanIntervalSeconds int } diff --git a/backend/internal/database/migrations/001_init.sql b/backend/internal/database/migrations/001_init.sql index ca3e679..d638ff4 100644 --- a/backend/internal/database/migrations/001_init.sql +++ b/backend/internal/database/migrations/001_init.sql @@ -190,7 +190,7 @@ CREATE INDEX IF NOT EXISTS idx_wallet_ledger_entries_type ON wallet_ledger_entri CREATE INDEX IF NOT EXISTS idx_wallet_ledger_entries_reference_no ON wallet_ledger_entries (reference_no); -- ---------------------------------------------------------------------------- --- 履约订单 +-- 发货订单 -- ---------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS fulfillment_orders ( diff --git a/backend/internal/handler/open.go b/backend/internal/handler/open.go index b2b6ba2..890dbdf 100644 --- a/backend/internal/handler/open.go +++ b/backend/internal/handler/open.go @@ -11,7 +11,7 @@ import ( "github.com/gin-gonic/gin" ) -// OpenHandler 皮肤源头开放接口(上游 SourceOpen),基于 FulfillmentOrder 履约模型。 +// OpenHandler 皮肤源头开放接口(上游 SourceOpen),基于 FulfillmentOrder 发货模型。 type OpenHandler struct { fulfillmentSvc *service.FulfillmentService } diff --git a/backend/internal/handler/open_v1.go b/backend/internal/handler/open_v1.go index bd61aea..b8ad76f 100644 --- a/backend/internal/handler/open_v1.go +++ b/backend/internal/handler/open_v1.go @@ -255,13 +255,13 @@ func (h *OpenV1Handler) SubmitDeliveryOrder(c *gin.Context) { } func buildOpenOrderResponse(order *model.FulfillmentOrder) gin.H { - canFulfill, reason := service.CanFulfill(order) + canShip, reason := service.CanFulfill(order) data := gin.H{ - "order_no": order.OrderNo, - "client_order_no": order.ClientOrderNo, - "order_status": order.OrderStatus, - "can_fulfill": canFulfill, - "cannot_fulfill_reason": reason, + "order_no": order.OrderNo, + "client_order_no": order.ClientOrderNo, + "order_status": order.OrderStatus, + "can_ship": canShip, + "cannot_ship_reason": reason, "product": gin.H{ "sku": order.ProductSKU, "name": order.ProductName, diff --git a/backend/internal/model/merchant.go b/backend/internal/model/merchant.go index b53ba46..d2518a4 100644 --- a/backend/internal/model/merchant.go +++ b/backend/internal/model/merchant.go @@ -136,7 +136,7 @@ type Product struct { Status string `gorm:"size:16;not null;default:active;index" json:"status"` } -// MerchantProduct 是商户可售商品及其价格、库存和履约配置。 +// MerchantProduct 是商户可售商品及其价格、库存和发货配置。 type MerchantProduct struct { ID uint `gorm:"primarykey" json:"id"` CreatedAt time.Time `json:"created_at"` diff --git a/backend/internal/service/delivery.go b/backend/internal/service/delivery.go index e885f8f..3c4dcfd 100644 --- a/backend/internal/service/delivery.go +++ b/backend/internal/service/delivery.go @@ -266,7 +266,7 @@ func (s *DeliveryService) submit(orderNo, gameAccount, bindUUID string, apiClien if existing := buildExistingDeliverySubmitResult(claimed); existing != nil { return existing, nil } - return nil, newDeliveryHTTPError(http.StatusConflict, "订单暂时正在履约中,请稍后查询") + return nil, newDeliveryHTTPError(http.StatusConflict, "订单暂时正在发货中,请稍后查询") } boundAccount, err := s.accountBound(bindUUID, goodID) if err != nil { @@ -507,10 +507,10 @@ func buildExistingDeliverySubmitResult(order *model.FulfillmentOrder) *DeliveryS order.ProviderOrderNo, stringFromMap(resultData, "provider_order_no"), ) - message := "订单暂时正在履约中,请稍后查询" + message := "订单暂时正在发货中,请稍后查询" status := normalizeOrderStatus(order) if status == model.OrderStatusDelivered { - message = "订单已履约成功" + message = "订单已交付" } return &DeliverySubmitResult{ OrderNo: order.OrderNo, diff --git a/backend/internal/service/fulfillment.go b/backend/internal/service/fulfillment.go index caa4c0f..44c4f77 100644 --- a/backend/internal/service/fulfillment.go +++ b/backend/internal/service/fulfillment.go @@ -366,11 +366,12 @@ func (s *FulfillmentService) UpdateFulfillment(in FulfillmentUpdateInput) (*mode return nil, errors.New("无效的订单状态") } nextOrderStatus := in.Status - resultData := "" + var resultData string + hasResultData := in.ResultData != nil if in.ResultData != nil { raw, err := json.Marshal(in.ResultData) if err != nil { - return nil, errors.New("履约结果无法序列化") + return nil, errors.New("发货结果无法序列化") } resultData = string(raw) } @@ -394,7 +395,9 @@ func (s *FulfillmentService) UpdateFulfillment(in FulfillmentUpdateInput) (*mode } now := time.Now() updates := map[string]interface{}{"order_status": nextOrderStatus} - updates["result_data"] = resultData + if hasResultData { + updates["result_data"] = resultData + } if in.ProviderOrderNo != "" { updates["provider_order_no"] = in.ProviderOrderNo } @@ -473,7 +476,7 @@ func (s *FulfillmentService) markProcessingTimeout(id uint, timeout time.Duratio if err := validateOrderStatusTransition(&order, model.OrderStatusShipFailed, fulfillmentTransitionTimeout); err != nil { return nil } - reason := fmt.Sprintf("履约超时:订单已处于 delivering 超过 %d 分钟", int(timeout.Minutes())) + reason := fmt.Sprintf("发货超时:订单已处于 delivering 超过 %d 分钟", int(timeout.Minutes())) updates := map[string]interface{}{"order_status": model.OrderStatusShipFailed} updates["failure_reason"] = reason updates["result_data"] = buildProcessingTimeoutResultData(order.ResultData, timeout, now) @@ -747,22 +750,22 @@ func CanFulfill(order *model.FulfillmentOrder) (bool, string) { } func orderCallbackData(order *model.FulfillmentOrder) map[string]interface{} { - canFulfill, cannotFulfillReason := CanFulfill(order) + canShip, cannotShipReason := CanFulfill(order) return map[string]interface{}{ - "order_no": order.OrderNo, - "client_order_no": order.ClientOrderNo, - "product_sku": order.ProductSKU, - "quantity": order.Quantity, - "base_amount": order.BaseAmount, - "fee_type": order.FeeType, - "service_fee_amount": order.ServiceFeeAmount, - "amount": order.Amount, - "currency": order.Currency, - "order_status": normalizeOrderStatus(order), - "can_fulfill": canFulfill, - "cannot_fulfill_reason": cannotFulfillReason, - "provider_order_no": order.ProviderOrderNo, - "failure_reason": order.FailureReason, + "order_no": order.OrderNo, + "client_order_no": order.ClientOrderNo, + "product_sku": order.ProductSKU, + "quantity": order.Quantity, + "base_amount": order.BaseAmount, + "fee_type": order.FeeType, + "service_fee_amount": order.ServiceFeeAmount, + "amount": order.Amount, + "currency": order.Currency, + "order_status": normalizeOrderStatus(order), + "can_ship": canShip, + "cannot_ship_reason": cannotShipReason, + "provider_order_no": order.ProviderOrderNo, + "failure_reason": order.FailureReason, } } @@ -1097,7 +1100,7 @@ func (s *FulfillmentService) HandleShipNotify(in ShipNotifyInput) (*ShipNotifyRe return err } - // 已履约成功:success 推送幂等成功。状态读取和后续更新必须在同一把行锁内完成。 + // 已交付:success 推送幂等成功。状态读取和后续更新必须在同一把行锁内完成。 if normalizeOrderStatus(&order) == model.OrderStatusDelivered && in.ShipStatus == "success" { result = ShipNotifyResult{ OrderNo: order.OrderNo, @@ -1105,7 +1108,7 @@ func (s *FulfillmentService) HandleShipNotify(in ShipNotifyInput) (*ShipNotifyRe Message: "订单已交付,幂等成功", } return writeAudit(tx, &order.MerchantID, nil, nil, "ship.notify", "fulfillment_order", order.OrderNo, - shipNotifyAuditMetadata(in, normalizeOrderStatus(&order), "订单已履约成功,幂等忽略")) + shipNotifyAuditMetadata(in, normalizeOrderStatus(&order), "订单已交付,幂等忽略")) } if normalizeOrderStatus(&order) == model.OrderStatusCancelled { @@ -1265,7 +1268,7 @@ func buildProcessingTimeoutResultData(existing string, timeout time.Duration, no m["timeout_minutes"] = int(timeout.Minutes()) m["timeout_at"] = timeutil.FormatAPITime(now) m["ship_status"] = "failed" - m["fail_reason"] = fmt.Sprintf("履约超时:订单已处于 delivering 超过 %d 分钟", int(timeout.Minutes())) + m["fail_reason"] = fmt.Sprintf("发货超时:订单已处于 delivering 超过 %d 分钟", int(timeout.Minutes())) raw, err := json.Marshal(m) if err != nil { return existing diff --git a/backend/internal/service/fulfillment_state.go b/backend/internal/service/fulfillment_state.go index 8a5ebc6..6c8953f 100644 --- a/backend/internal/service/fulfillment_state.go +++ b/backend/internal/service/fulfillment_state.go @@ -86,11 +86,11 @@ func validateOrderStatusTransition(order *model.FulfillmentOrder, next string, k if next == model.OrderStatusPaid || next == model.OrderStatusCancelled { return nil } - return errors.New("订单未支付,不能履约") + return errors.New("订单未支付,不能发货") case model.OrderStatusCancelled: return errors.New("订单已取消,不能更新状态") case model.OrderStatusDelivered: - return errors.New("订单已履约成功,不能回退状态") + return errors.New("订单已交付,不能回退状态") } switch next { case model.OrderStatusDelivering: @@ -105,7 +105,7 @@ func validateOrderStatusTransition(order *model.FulfillmentOrder, next string, k } case model.OrderStatusShipFailed: if kind == fulfillmentTransitionTimeout && current != model.OrderStatusDelivering { - return errors.New("只有履约中的订单可以标记超时") + return errors.New("只有发货中的订单可以标记超时") } if current == model.OrderStatusPaid || current == model.OrderStatusShipFailed || @@ -134,7 +134,7 @@ func canCancelOrder(order *model.FulfillmentOrder) error { case model.OrderStatusPending: return errors.New("订单未支付,不能取消") case model.OrderStatusDelivering, model.OrderStatusDelivered: - return errors.New("订单已进入履约流程,不能取消") + return errors.New("订单已进入发货流程,不能取消") default: return errors.New("订单当前状态不能取消") } diff --git a/backend/internal/service/fulfillment_test.go b/backend/internal/service/fulfillment_test.go index 934f1a9..e049ada 100644 --- a/backend/internal/service/fulfillment_test.go +++ b/backend/internal/service/fulfillment_test.go @@ -393,6 +393,47 @@ func TestOrderStatusTransitions(t *testing.T) { } } +func TestUpdateFulfillmentKeepsResultDataWhenOmitted(t *testing.T) { + db := newServiceTestDB(t) + merchantID, product := seedFulfillmentMerchant(t, db, "merchant-result-data", 1000, -1, 100) + svc := NewFulfillmentService(db, nil) + created, err := svc.CreateOrder(CreateFulfillmentOrderInput{ + MerchantID: merchantID, + APIClientID: 13, + ClientOrderNo: "client-result-data", + SKU: product.SKU, + }) + if err != nil { + t.Fatalf("create order: %v", err) + } + delivering, err := svc.UpdateFulfillment(FulfillmentUpdateInput{ + MerchantID: merchantID, + APIClientID: 13, + OrderNo: created.Order.OrderNo, + Status: model.OrderStatusDelivering, + ResultData: map[string]string{"stage": "claimed"}, + }) + if err != nil { + t.Fatalf("mark delivering: %v", err) + } + if !strings.Contains(delivering.ResultData, `"stage":"claimed"`) { + t.Fatalf("expected initial result_data, got %s", delivering.ResultData) + } + failed, err := svc.UpdateFulfillment(FulfillmentUpdateInput{ + MerchantID: merchantID, + APIClientID: 13, + OrderNo: created.Order.OrderNo, + Status: model.OrderStatusShipFailed, + FailureReason: "上游暂不可用", + }) + if err != nil { + t.Fatalf("mark failed: %v", err) + } + if failed.ResultData != delivering.ResultData { + t.Fatalf("result_data should be kept when omitted, before=%s after=%s", delivering.ResultData, failed.ResultData) + } +} + func TestMarkProcessingTimeoutsMarksStaleOrdersFailed(t *testing.T) { db := newServiceTestDB(t) merchantID, product := seedFulfillmentMerchant(t, db, "merchant-timeout", 1000, -1, 100) @@ -432,7 +473,7 @@ func TestMarkProcessingTimeoutsMarksStaleOrdersFailed(t *testing.T) { if err := db.First(&order, delivering.ID).Error; err != nil { t.Fatalf("query order: %v", err) } - if order.OrderStatus != model.OrderStatusShipFailed || !strings.Contains(order.FailureReason, "履约超时") { + if order.OrderStatus != model.OrderStatusShipFailed || !strings.Contains(order.FailureReason, "发货超时") { t.Fatalf("expected failed timeout order, got %+v", order) } if !strings.Contains(order.ResultData, `"timeout":true`) { @@ -668,7 +709,7 @@ func TestHandleShipNotifyUpdatesOrderAndEnqueuesMerchantCallback(t *testing.T) { t.Fatalf("create order: %v", err) } if _, err := callbackSvc.CreateSubscription(merchantID, CreateCallbackInput{ - Name: "履约回调", + Name: "发货回调", URL: "https://example.com/callback", Events: "order.fulfillment.updated", }, 7); err != nil { @@ -702,6 +743,9 @@ func TestHandleShipNotifyUpdatesOrderAndEnqueuesMerchantCallback(t *testing.T) { if !strings.Contains(delivery.Payload, created.Order.OrderNo) || !strings.Contains(delivery.Payload, "SRC-10001") { t.Fatalf("callback payload should contain updated order data, got %s", delivery.Payload) } + if !strings.Contains(delivery.Payload, `"can_ship":false`) || strings.Contains(delivery.Payload, "can_fulfill") { + t.Fatalf("callback payload should use can_ship fields, got %s", delivery.Payload) + } var auditCount int64 db.Model(&model.AuditLog{}).Where("entity_id = ? AND action = ?", created.Order.OrderNo, "ship.notify").Count(&auditCount) if auditCount != 1 { diff --git a/docs/API对接关系.md b/docs/API对接关系.md index 0c574d1..2dd4d75 100644 --- a/docs/API对接关系.md +++ b/docs/API对接关系.md @@ -11,7 +11,7 @@ |------|--------|--------|-------------|------|------| | 商户侧开放 API | 商户自己的商城 / 系统 | 本平台 | `/api/client/v1` | `X-App-Key` + HMAC | 查商品、创建订单、查订单、取消订单、查钱包 | | 源头侧发货 API | 上游发货平台 | 本平台 | `/api/open/v1` | `X-Api-Key` + HMAC | 按订单号查可发货信息,回传发货成功 / 失败 | -| 商户回调 | 本平台 | 商户自己的回调 URL | 商户后台配置 URL | `X-Event-ID` + `X-Timestamp` + `X-Sign` | 把订单创建、履约变化、取消等事件推给商户 | +| 商户回调 | 本平台 | 商户自己的回调 URL | 商户后台配置 URL | `X-Event-ID` + `X-Timestamp` + `X-Sign` | 把订单创建、发货状态变化、取消等事件推给商户 | ## 2. 订单流 diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 065bb8a..d0f6dd8 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -39,7 +39,7 @@ function AppRoutes() { } /> } /> } /> - } /> + } /> } /> } /> } /> diff --git a/frontend/src/layouts/MainLayout.tsx b/frontend/src/layouts/MainLayout.tsx index f2470e1..27e25ac 100644 --- a/frontend/src/layouts/MainLayout.tsx +++ b/frontend/src/layouts/MainLayout.tsx @@ -66,7 +66,7 @@ const adminSections: SidebarSection[] = [ key: 'orders', label: '订单管理', icon: , - children: [{ key: 'fulfillment-orders', label: '履约订单', path: '/merchant-orders' }], + children: [{ key: 'fulfillment-orders', label: '发货订单', path: '/merchant-orders' }], }, { key: 'staff', @@ -110,7 +110,7 @@ const merchantSections: SidebarSection[] = [ key: 'orders', label: '订单管理', icon: , - children: [{ key: 'fulfillment-orders', label: '履约订单', path: '/merchant-orders' }], + children: [{ key: 'fulfillment-orders', label: '发货订单', path: '/merchant-orders' }], }, { key: 'funds', diff --git a/frontend/src/openapi/endpoints.ts b/frontend/src/openapi/endpoints.ts index 4df1813..d6cc0ff 100644 --- a/frontend/src/openapi/endpoints.ts +++ b/frontend/src/openapi/endpoints.ts @@ -16,14 +16,14 @@ export const errorCodes: ParamSpec[] = [ { name: '500', type: 'int', desc: '服务端内部错误' }, ] -// 订单状态与可履约说明。 +// 订单状态与可发货说明。 export const orderStatusTable: ParamSpec[] = [ - { name: 'pending', type: 'order_status', desc: '待支付(当前无真实支付流程,仅预留)', example: 'can_fulfill=false' }, - { name: 'paid', type: 'order_status', desc: '已支付/已扣款,可发货', example: 'can_fulfill=true' }, - { name: 'delivering', type: 'order_status', desc: '发货中', example: 'can_fulfill=false' }, - { name: 'delivered', type: 'order_status', desc: '已交付', example: 'can_fulfill=false' }, - { name: 'ship_failed', type: 'order_status', desc: '发货失败,可重试', example: 'can_fulfill=true' }, - { name: 'cancelled', type: 'order_status', desc: '已取消', example: 'can_fulfill=false' }, + { name: 'pending', type: 'order_status', desc: '待支付(当前无真实支付流程,仅预留)', example: 'can_ship=false' }, + { 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' }, ] // 订单对象公共字段说明,下单/查询/取消响应共用。 @@ -31,9 +31,9 @@ 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_fulfill', type: 'bool', desc: '是否允许履约器接单/发货' }, - { name: 'cannot_fulfill_reason', type: 'string', desc: 'can_fulfill=false 时的原因' }, - { name: 'product.sku', type: 'string', 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: '商品基础金额(最小货币单位)' }, @@ -47,7 +47,7 @@ const orderFields: ParamSpec[] = [ { 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: 'delivered_at', type: 'datetime', desc: '交付时间' }, { name: 'cancelled_at', type: 'datetime', desc: '取消时间' }, ] @@ -58,8 +58,8 @@ const orderResponseExample = `{ "order_no": "FO20260730000123", "client_order_no": "shop-10001", "order_status": "paid", - "can_fulfill": true, - "cannot_fulfill_reason": "", + "can_ship": true, + "cannot_ship_reason": "", "product": { "sku": "suit_pink_sheep", "name": "套装-糯粉咩咩" }, "quantity": 1, "base_amount": 100, @@ -197,7 +197,7 @@ export const endpoints: EndpointSpec[] = [ { 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: '透传给履约器的业务数据(区服、账号等),原样存储并回显' }, + { name: 'data', type: 'object', desc: '透传给发货流程的业务数据(区服、账号等),原样存储并回显' }, ], requestExample: `{ "client_order_no": "shop-10001", @@ -215,7 +215,7 @@ export const endpoints: EndpointSpec[] = [ "order_no": "FO20260730000123", "client_order_no": "shop-10001", "order_status": "paid", - "can_fulfill": true + "can_ship": true } } }`, @@ -339,7 +339,7 @@ export const endpoints: EndpointSpec[] = [ method: 'POST', path: '/api/client/v1/orders/{order_no}/delivery/submit', title: '提交发货', - summary: '提交发货到上游并进入履约中状态', + summary: '提交发货到上游并进入发货中状态', scope: 'orders:write', pathParams: [{ name: 'order_no', type: 'string', required: true, desc: '平台订单号', example: 'FO20260730000123' }], bodyParams: [ @@ -353,7 +353,7 @@ export const endpoints: EndpointSpec[] = [ responseExample: deliverySubmitResponseExample, responseFields: [ { name: 'order_no', type: 'string', desc: '平台订单号' }, - { name: 'status', 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: '上游绑定结果' }, diff --git a/frontend/src/pages/Delivery.tsx b/frontend/src/pages/Delivery.tsx index a0d8a6b..6837b7f 100644 --- a/frontend/src/pages/Delivery.tsx +++ b/frontend/src/pages/Delivery.tsx @@ -27,7 +27,7 @@ import { formatDateTime } from '../utils/time' const statusMap: Record = { paid: { color: 'orange', text: '待发货' }, - delivering: { color: 'blue', text: '履约中' }, + delivering: { color: 'blue', text: '发货中' }, delivered: { color: 'green', text: '已交付' }, ship_failed: { color: 'red', text: '发货失败' }, cancelled: { color: 'default', text: '已取消' }, diff --git a/frontend/src/pages/MerchantCenter.tsx b/frontend/src/pages/MerchantCenter.tsx index a7111ae..81d95e7 100644 --- a/frontend/src/pages/MerchantCenter.tsx +++ b/frontend/src/pages/MerchantCenter.tsx @@ -61,13 +61,13 @@ const scopeOptions = [ { value: 'products:read', label: '商品读取' }, { value: 'orders:read', label: '订单读取' }, { value: 'orders:write', label: '订单写入' }, - { value: 'fulfillment:read', label: '履约读取' }, + { value: 'fulfillment:read', label: '发货读取' }, { value: 'wallet:read', label: '钱包读取' }, ] const eventOptions = [ { value: 'order.created', label: '订单创建' }, - { value: 'order.fulfillment.updated', label: '履约更新' }, + { value: 'order.fulfillment.updated', label: '发货更新' }, { value: 'order.cancelled', label: '订单取消' }, ] @@ -689,7 +689,7 @@ export default function MerchantCenter({ fixedTab, title = '商户中心' }: Mer const tabItems = [ { key: 'products', label: '商品', disabled: !hasFeature('products'), children: productContent }, - { key: 'orders', label: '履约订单', disabled: !hasFeature('orders'), children: orderContent }, + { key: 'orders', label: '发货订单', disabled: !hasFeature('orders'), children: orderContent }, { key: 'wallet', label: '钱包', disabled: !hasFeature('wallet'), children: walletContent }, { key: 'api', label: 'API 密钥', disabled: !hasFeature('api'), children: apiKeyContent }, { key: 'callbacks', label: '回调', disabled: !hasFeature('callbacks'), children: callbackContent }, @@ -765,7 +765,7 @@ export default function MerchantCenter({ fixedTab, title = '商户中心' }: Mer )} - + diff --git a/frontend/src/pages/OpenApiDocs.tsx b/frontend/src/pages/OpenApiDocs.tsx index d331de0..be08906 100644 --- a/frontend/src/pages/OpenApiDocs.tsx +++ b/frontend/src/pages/OpenApiDocs.tsx @@ -452,7 +452,7 @@ function EndpointSection({ spec }: { spec: EndpointSpec }) { function StatusSection() { return ( - + {v} }, { - title: 'can_fulfill', + title: 'can_ship', dataIndex: 'example', width: 160, render: (v: string) => - v === 'can_fulfill=true' ? true : false, + v === 'can_ship=true' ? true : false, }, { title: '说明', dataIndex: 'desc' }, ]}