feat(fleet): enforce reviewed trips and original fee coverage for dispatch

This commit is contained in:
2026-10-03 04:18:52 +08:00
parent c50e9f97d1
commit 5e683da3b9
162 changed files with 9642 additions and 218 deletions
@@ -0,0 +1,310 @@
openapi: 3.0.3
info:
title: 平台车辆管理司机档案
version: 1.0.0
description: >-
平台司机主数据,列表权限包含详情、资格预览、历史和已关联证照读取。
写操作独立鉴权且要求当前recordVersion;创建版本0,后续每次成功写入递增。
证照或身份关键字段变化、替换附件后重新待审;电话和备注更正不撤销既有审核。
驾驶证是当前资格最低要求,其他资质不隐式必填。日期按licenseZone计算,
30天内到期但仍有效允许并提醒,任务结束达到有效截止日次日当地零点或更晚则禁止。
缺少预计结束时间时资格返回MISSING_TRIP_END;资格预览不预留司机,不代替发车事务复核。
新档案允许缺证照保存为PENDING,通过审核必须补齐编号、类型、有效期和真实附件。
所有业务错误遵循HTTP200加code,认证或基础设施错误可返回401/403/503。
security:
- bearerAuth: []
paths:
/api/platform/v1/last-leg/fleet/drivers:
get:
summary: 分页查询司机及资格
description: '权限:platform:overseas-master-data:driver:list;无逐行文件请求。'
parameters:
- {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}
- {name: size, in: query, schema: {type: integer, minimum: 1, maximum: 200, default: 20}}
- {name: keyword, in: query, schema: {type: string, maxLength: 128}}
- {name: active, in: query, schema: {type: boolean}}
- {name: reviewStatus, in: query, schema: {type: string, enum: [PENDING, APPROVED, REJECTED]}}
- {name: ownership, in: query, schema: {type: string, enum: [OWNED, DISPATCHED]}}
- {name: region, in: query, schema: {type: string, enum: [DOMESTIC, OVERSEAS]}}
- {name: licenseState, in: query, schema: {type: string, enum: [MISSING, VALID, EXPIRING, EXPIRED]}, description: 仅驾驶证日期状态,与审核和附件状态分别展示}
- {name: expectedEnd, in: query, schema: {type: string, format: date-time}}
responses:
'200':
description: 业务响应,分页数据
content:
application/json:
schema:
allOf:
- {$ref: '#/components/schemas/Envelope'}
- properties:
data:
type: object
properties:
records: {type: array, items: {$ref: '#/components/schemas/Driver'}}
page: {type: integer}
size: {type: integer}
total: {type: integer}
pages: {type: integer}
summary: {$ref: '#/components/schemas/Summary'}
post:
summary: 创建待审司机档案
description: '权限:platform:overseas-master-data:driver:create'
requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/Draft'}}}}
responses: {'200': {$ref: '#/components/responses/Driver'}}
/api/platform/v1/last-leg/fleet/drivers/warehouse-options:
get:
summary: 获取当前区域可关联的公共仓库
description: '权限:platform:overseas-master-data:driver:list;复用Warehouse内部有效目录,国内DOMESTIC,海外OVERSEAS/OVERSEAS_PARTNER,排除FBA目的仓;保存时再次校验。'
parameters:
- {name: region, in: query, required: true, schema: {type: string, enum: [DOMESTIC, OVERSEAS]}}
responses:
'200':
description: 业务响应,data为仓库候选
content:
application/json:
schema:
allOf:
- {$ref: '#/components/schemas/Envelope'}
- properties:
data: {type: array, items: {$ref: '#/components/schemas/WarehouseOption'}}
/api/platform/v1/last-leg/fleet/drivers/{id}:
parameters: [{$ref: '#/components/parameters/Id'}]
get:
summary: 司机详情
description: '权限:platform:overseas-master-data:driver:list'
parameters:
- {name: expectedEnd, in: query, schema: {type: string, format: date-time}}
responses: {'200': {$ref: '#/components/responses/Driver'}}
put:
summary: 编辑档案,关键字段变化后重新待审
description: '权限:platform:overseas-master-data:driver:edit'
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [recordVersion, details]
properties:
recordVersion: {type: integer, format: int64, minimum: 0}
details: {$ref: '#/components/schemas/Draft'}
responses: {'200': {$ref: '#/components/responses/Driver'}}
/api/platform/v1/last-leg/fleet/drivers/{id}/status:
parameters: [{$ref: '#/components/parameters/Id'}]
patch:
summary: 启停司机并记录原因
description: '权限:platform:overseas-master-data:driver:status;停用后不可派车,历史保留。'
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [recordVersion, active, reason]
properties:
recordVersion: {type: integer, format: int64, minimum: 0}
active: {type: boolean}
reason: {type: string, minLength: 1, maxLength: 1000}
responses: {'200': {$ref: '#/components/responses/Driver'}}
/api/platform/v1/last-leg/fleet/drivers/{id}/review:
parameters: [{$ref: '#/components/parameters/Id'}]
post:
summary: 通过或打回司机证照
description: '权限:platform:overseas-master-data:driver:review;仅PENDING允许审核;打回原因必填;通过前校验真实附件归属与证照有效性。'
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [recordVersion, decision]
properties:
recordVersion: {type: integer, format: int64, minimum: 0}
decision: {type: string, enum: [APPROVED, REJECTED]}
reason: {type: string, maxLength: 1000}
responses: {'200': {$ref: '#/components/responses/Driver'}}
/api/platform/v1/last-leg/fleet/drivers/{id}/submit:
parameters: [{$ref: '#/components/parameters/Id'}]
post:
summary: 已打回档案重新提交
description: '权限:platform:overseas-master-data:driver:edit;仅REJECTED;先校验证照完整及文件归属。'
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [recordVersion]
properties:
recordVersion: {type: integer, format: int64, minimum: 0}
responses: {'200': {$ref: '#/components/responses/Driver'}}
/api/platform/v1/last-leg/fleet/drivers/{id}/qualification:
parameters: [{$ref: '#/components/parameters/Id'}]
get:
summary: 按预计任务结束时间预览派车资格
description: '权限:platform:overseas-master-data:driver:list;预计结束应覆盖本司机承担的返程或转场。'
parameters:
- {name: expectedEnd, in: query, required: true, schema: {type: string, format: date-time}}
responses:
'200':
description: 资格结果,canDispatch与expiringSoon独立
content:
application/json:
schema:
allOf:
- {$ref: '#/components/schemas/Envelope'}
- properties:
data: {$ref: '#/components/schemas/Qualification'}
/api/platform/v1/last-leg/fleet/drivers/{id}/history:
parameters: [{$ref: '#/components/parameters/Id'}]
get:
summary: 分页读取司机操作与审核历史
description: '权限:platform:overseas-master-data:driver:list;按版本降序,snapshot是历史当时的档案及资格,不能用作当前派车门禁。'
parameters:
- {name: page, in: query, schema: {type: integer, minimum: 1, default: 1}}
- {name: size, in: query, schema: {type: integer, minimum: 1, maximum: 200, default: 20}}
responses:
'200':
description: 业务响应,data为含records/page/size/total/pages的分页
content:
application/json:
schema:
allOf:
- {$ref: '#/components/schemas/Envelope'}
- properties:
data:
type: object
properties:
records: {type: array, items: {$ref: '#/components/schemas/History'}}
page: {type: integer}
size: {type: integer}
total: {type: integer}
pages: {type: integer}
/api/platform/v1/last-leg/fleet/drivers/{id}/license:
parameters: [{$ref: '#/components/parameters/Id'}]
post:
summary: 上传并绑定驾驶证,重置为待审
description: '权限:platform:overseas-master-data:driver:upload;复合归属固定平台0、FLEET_DRIVER_LICENSE、当前司机;非空PDF/JPG/PNG不超过10MiB,校验MIME和签名,旧版本附件保留在历史中。'
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required: [recordVersion, file]
properties:
recordVersion: {type: integer, format: int64, minimum: 0}
file: {type: string, format: binary}
responses: {'200': {$ref: '#/components/responses/Driver'}}
/api/platform/v1/last-leg/fleet/drivers/{id}/license/{fileId}:
parameters:
- {$ref: '#/components/parameters/Id'}
- {name: fileId, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
get:
summary: 下载当前或历史已关联驾驶证
description: '权限:platform:overseas-master-data:driver:list;校验关联和File复合归属,attachment下载,Cache-Control no-store,拒绝未绑定文件。'
responses:
'200':
description: 文件内容;业务错误仍需识别JSON响应
content:
application/pdf: {schema: {type: string, format: binary}}
image/jpeg: {schema: {type: string, format: binary}}
image/png: {schema: {type: string, format: binary}}
components:
securitySchemes:
bearerAuth: {type: http, scheme: bearer, bearerFormat: JWT}
parameters:
Id: {name: id, in: path, required: true, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
responses:
Driver:
description: 业务响应,data为司机详情
content:
application/json:
schema:
allOf:
- {$ref: '#/components/schemas/Envelope'}
- properties:
data: {$ref: '#/components/schemas/Driver'}
schemas:
Envelope:
type: object
properties:
code: {type: string}
message: {type: string, nullable: true}
data: {type: object, nullable: true}
Draft:
type: object
required: [name, phone, ownership, region, licenseZone]
properties:
name: {type: string, minLength: 1, maxLength: 128}
phone: {type: string, minLength: 1, maxLength: 64}
ownership: {type: string, enum: [OWNED, DISPATCHED]}
region: {type: string, enum: [DOMESTIC, OVERSEAS]}
licenseNumber: {type: string, nullable: true, maxLength: 128}
licenseType: {type: string, nullable: true, maxLength: 64}
licenseIssuedOn: {type: string, format: date, nullable: true}
licenseExpiresOn: {type: string, format: date, nullable: true}
licenseZone: {type: string, maxLength: 64, description: IANA时区,如America/Los_Angeles}
remark: {type: string, nullable: true, maxLength: 1000}
profile: {$ref: '#/components/schemas/Profile'}
Profile:
type: object
nullable: true
description: 可选补充资料;当前其他资质日期不自动作为派车必需条件
properties:
warehouseId: {type: string, nullable: true, pattern: '^[1-9][0-9]*$'}
vehicleModels: {type: string, nullable: true, maxLength: 128}
languagesAndArea: {type: string, nullable: true, maxLength: 256}
medicalExpiresOn: {type: string, format: date, nullable: true}
trainingExpiresOn: {type: string, format: date, nullable: true}
insuranceExpiresOn: {type: string, format: date, nullable: true}
WarehouseOption:
type: object
properties:
id: {type: string}
code: {type: string}
name: {type: string}
region: {type: string, enum: [DOMESTIC, OVERSEAS]}
Summary:
type: object
description: 与列表共用筛选范围,按各证照时区计算30天(含)提醒,不以浏览器时区计算
properties:
total: {type: integer, format: int64}
owned: {type: integer, format: int64}
dispatched: {type: integer, format: int64}
expiringSoon: {type: integer, format: int64}
expired: {type: integer, format: int64}
Driver:
type: object
properties:
id: {type: string}
driverNo: {type: string, description: 独立生成的业务编号}
details: {$ref: '#/components/schemas/Draft'}
active: {type: boolean}
reviewStatus: {type: string, enum: [PENDING, APPROVED, REJECTED]}
licenseFileId: {type: string, nullable: true}
recordVersion: {type: integer, format: int64}
updatedBy: {type: string}
updatedAt: {type: string, description: UTC本地日期时间}
qualification: {$ref: '#/components/schemas/Qualification'}
licenseState: {type: string, enum: [MISSING, VALID, EXPIRING, EXPIRED]}
warehouseCode: {type: string, nullable: true}
warehouseName: {type: string, nullable: true}
Qualification:
type: object
properties:
canDispatch: {type: boolean}
expiringSoon: {type: boolean}
reason:
type: string
enum: [ELIGIBLE, INACTIVE, MISSING_LICENSE, MISSING_EXPIRY, PENDING_REVIEW, REJECTED, EXPIRED, MISSING_TRIP_END, INVALID_TRIP_END, EXPIRES_DURING_TRIP]
licenseExpiresOn: {type: string, format: date, nullable: true}
History:
type: object
properties:
recordVersion: {type: integer, format: int64}
action: {type: string, enum: [CREATE, UPDATE, ACTIVATE, DEACTIVATE, UPLOAD_LICENSE, APPROVED, REJECTED, RESUBMIT]}
reason: {type: string, nullable: true}
operatorId: {type: string}
occurredAt: {type: string, description: UTC本地日期时间}
snapshot: {$ref: '#/components/schemas/Driver'}