openapi: 3.0.3 info: {title: Firstleg Container Overview API, version: 1.0.0} paths: /api/platform/v1/containers/{id}/overview: get: operationId: getContainerOverview description: '权限:platform:firstleg:container:list' parameters: [{$ref: '#/components/parameters/ContainerId'}] responses: {'200': {description: OK, content: {application/json: {schema: {$ref: '#/components/schemas/OverviewEnvelope'}}}}} /api/platform/v1/containers/overseas/{id}/overview: get: operationId: getOverseasContainerOverview description: '权限:platform:firstleg:terminal-drayage:list;仅真实国内离仓后的国外工作台货柜' parameters: [{$ref: '#/components/parameters/ContainerId'}] responses: {'200': {description: OK, content: {application/json: {schema: {$ref: '#/components/schemas/OverviewEnvelope'}}}}} /api/platform/v1/containers/{id}/pickup-code: put: operationId: updateContainerPickupCode description: '权限:platform:firstleg:terminal-drayage:document:edit;PU资料为1至64位数字码,以字符串保存并保留前导零' parameters: [{$ref: '#/components/parameters/ContainerId'}] requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/PickupCodeRequest'}}}} responses: {'200': {description: OK, content: {application/json: {schema: {$ref: '#/components/schemas/OverviewEnvelope'}}}}} /api/platform/v1/containers/{id}/exception: parameters: [{$ref: '#/components/parameters/ContainerId'}] post: {operationId: markContainerException, description: '权限:platform:firstleg:container:edit', parameters: [{name: Idempotency-Key, in: header, required: true, schema: {type: string, minLength: 1, maxLength: 128}}], requestBody: {$ref: '#/components/requestBodies/ExceptionRequest'}, responses: {'200': {description: OK}}} delete: {operationId: cancelContainerException, description: '权限:platform:firstleg:container:edit', parameters: [{name: Idempotency-Key, in: header, required: true, schema: {type: string, minLength: 1, maxLength: 128}}], requestBody: {$ref: '#/components/requestBodies/ExceptionRequest'}, responses: {'200': {description: OK}}} /api/platform/v1/containers/{id}/pda/photos/{fileId}/download: get: operationId: downloadContainerPdaPhoto description: '权限:platform:firstleg:container:list;PDA完成及国内离仓后仍可读取ACTIVE历史照片;Firstleg按柜次、装柜计划、入库单和文件归属代理下载,不暴露内部服务令牌' parameters: [{$ref: '#/components/parameters/ContainerId'}, {name: fileId, in: path, required: true, schema: {type: integer, format: int64}}] responses: {'200': {description: photo bytes, content: {application/octet-stream: {schema: {type: string, format: binary}}}}, '404': {description: photo missing or not owned by the container}} /api/platform/v1/containers/{id}/documents/{documentType}: get: operationId: getContainerDocument description: '权限:platform:firstleg:terminal-drayage:list;仅国外工作台DO,completed恒为false' parameters: [{$ref: '#/components/parameters/ContainerId'}, {$ref: '#/components/parameters/DocumentType'}] responses: {'200': {description: OK, content: {application/json: {schema: {$ref: '#/components/schemas/DocumentEnvelope'}}}}} /api/platform/v1/containers/{id}/documents/{documentType}/upload: post: operationId: uploadContainerDocument description: '权限:platform:firstleg:terminal-drayage:document:edit;仅已进入海外履约且未还柜的非海铁渠道可上传DO,无完成动作' parameters: [{$ref: '#/components/parameters/ContainerId'}, {$ref: '#/components/parameters/DocumentType'}, {name: Idempotency-Key, in: header, required: true, schema: {type: string}}] requestBody: {required: true, content: {multipart/form-data: {schema: {type: object, required: [file, expectedVersion], properties: {file: {type: string, format: binary}, expectedVersion: {type: integer, minimum: 0}, operationReason: {type: string, maxLength: 500}}}}}} responses: {'200': {description: OK, content: {application/json: {schema: {$ref: '#/components/schemas/DocumentEnvelope'}}}}, '409': {description: '尚未进入海外履约、海铁渠道不适用DO或货柜已还柜'}} /api/platform/v1/containers/{id}/documents/{documentType}/{fileId}/download: get: operationId: downloadContainerDocument description: '权限:platform:firstleg:terminal-drayage:list;Firstleg代理File内部下载,不向调用方暴露内部令牌' parameters: [{$ref: '#/components/parameters/ContainerId'}, {$ref: '#/components/parameters/DocumentType'}, {name: fileId, in: path, required: true, schema: {type: integer, format: int64}}] responses: {'200': {description: file bytes, content: {application/octet-stream: {schema: {type: string, format: binary}}}}} /api/platform/v1/containers/{id}/clearance/document/{fileId}/download: get: operationId: downloadContainerDestinationClearance description: '权限:platform:firstleg:terminal-drayage:list;校验当前 DESTINATION_CLEARANCE fileId 以及 File tenantId=0、businessType=CONTAINER_CLEARANCE_DOCUMENT、businessId=id;返回 attachment 与 no-store,完成态仍可下载' parameters: [{$ref: '#/components/parameters/ContainerId'}, {name: fileId, in: path, required: true, schema: {type: integer, format: int64}}] responses: {'200': {description: clearance file bytes, content: {application/octet-stream: {schema: {type: string, format: binary}}}}, '404': {description: current file or ownership mismatch}} components: parameters: ContainerId: {name: id, in: path, required: true, schema: {type: integer, format: int64}} DocumentType: {name: documentType, in: path, required: true, schema: {type: string, enum: [DELIVERY_ORDER]}, description: '通用单证仅支持DO;PU资料使用 /pickup-code;目的港清关使用 /clearance;出口报关由 customs-v1 柜级聚合接口承载'} requestBodies: ExceptionRequest: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/ExceptionRequest'}}}} schemas: OverviewEnvelope: {type: object, properties: {code: {type: string}, message: {type: string}, data: {$ref: '#/components/schemas/Overview'}}} DocumentEnvelope: {type: object, properties: {code: {type: string}, message: {type: string}, data: {$ref: '#/components/schemas/Document'}}} Overview: type: object properties: container: {$ref: '#/components/schemas/Container'} loadingPlanId: {type: integer, format: int64} pda: {$ref: '#/components/schemas/PdaSummary'} documents: {type: array, description: '按 documentType 稳定排序返回 DESTINATION_CLEARANCE、DELIVERY_ORDER 的当前唯一记录和真实 version;PU码位于 container.pickupCode;出口报关只由 customs-v1 柜级聚合承载', items: {$ref: '#/components/schemas/Document'}} exception: {$ref: '#/components/schemas/ExceptionState'} exceptionHistory: {type: array, items: {$ref: '#/components/schemas/ExceptionHistory'}} timeline: {type: array, items: {$ref: '#/components/schemas/TimelineEntry'}} Container: {type: object, properties: {id: {type: integer, format: int64}, bookingNo: {type: string, pattern: '^CB-[0-9]{6}-[0-9]{4}$', example: CB-260818-0001}, cabinetNo: {type: string, pattern: '^CAB-[0-9]{6}-[0-9]{4}$', example: CAB-260818-0001}, containerNo: {type: string}, status: {type: string}, warehouseId: {type: integer, format: int64}, warehouseName: {type: string}, voyageNo: {type: string}, vesselName: {type: string}, pickupCode: {type: string, pattern: '^[0-9]{1,64}$', nullable: true}, pickupCodeUpdatedBy: {type: integer, format: int64, nullable: true}, pickupCodeUpdatedByName: {type: string, nullable: true}, pickupCodeUpdatedAt: {type: string, format: date-time, nullable: true}, version: {type: integer, minimum: 0}}} PdaSummary: {type: object, properties: {taskId: {type: integer, format: int64}, loadingPlanId: {type: integer, format: int64}, containerBookingId: {type: integer, format: int64}, taskStatus: {type: string, description: '持久化任务态:LOADING/COMPLETED'}, workflowStatus: {type: string, enum: [IN_PROGRESS, AWAITING_REVIEW, COMPLETED], description: 'PDA作业展示态'}, taskVersion: {type: integer}, itemCount: {type: integer}, completedItemCount: {type: integer}, unresolvedItemCount: {type: integer}, photoCounts: {type: array, items: {$ref: '#/components/schemas/PhotoCount'}}, photos: {type: array, items: {$ref: '#/components/schemas/Photo'}}, exceptionReasons: {type: array, items: {type: string}}}} PhotoCount: {type: object, properties: {evidenceType: {type: string}, count: {type: integer}}} Photo: {type: object, properties: {evidenceId: {type: integer, format: int64}, tenantId: {type: integer, format: int64}, inboundId: {type: integer, format: int64}, evidenceType: {type: string}, fileId: {type: integer, format: int64}, fileName: {type: string}, status: {type: string, enum: [ACTIVE, VOID]}, downloadPath: {type: string, nullable: true, description: '仅 ACTIVE 照片提供鉴权下载路径;VOID 历史照片为空'}, uploadedAt: {type: string, format: date-time}}} Document: {type: object, properties: {id: {type: integer, format: int64}, documentType: {type: string, enum: [DESTINATION_CLEARANCE, DELIVERY_ORDER]}, fileId: {type: integer, format: int64}, fileName: {type: string}, fileHash: {type: string}, uploadedBy: {type: integer, format: int64}, uploadedByName: {type: string}, uploadedAt: {type: string, format: date-time}, version: {type: integer, description: '当前唯一记录的真实乐观锁版本;更新时必须原样作为 expectedVersion'}, completed: {type: boolean}}} ExceptionState: {type: object, properties: {active: {type: boolean}, reason: {type: string}, markedBy: {type: integer, format: int64}, markedByName: {type: string}, markedAt: {type: string, format: date-time}}} ExceptionHistory: {type: object, properties: {id: {type: integer, format: int64}, action: {type: string, enum: [MARK, CANCEL]}, reason: {type: string}, operatorId: {type: integer, format: int64}, operatorName: {type: string}, occurredAt: {type: string, format: date-time}}} TimelineEntry: {type: object, properties: {eventType: {type: string}, detail: {type: string}, operatorId: {type: integer, format: int64}, operatorName: {type: string}, occurredAt: {type: string, format: date-time}}} ExceptionRequest: {type: object, required: [expectedVersion, reason], properties: {expectedVersion: {type: integer, minimum: 0}, reason: {type: string, maxLength: 500}}} PickupCodeRequest: {type: object, required: [pickupCode, expectedVersion], properties: {pickupCode: {type: string, pattern: '^[0-9]{1,64}$'}, expectedVersion: {type: integer, minimum: 0}}}