feat: complete leave approval MVP
This commit is contained in:
@@ -1,10 +1,170 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: AIOA API
|
||||
version: 0.4.0
|
||||
version: 0.12.0
|
||||
servers:
|
||||
- url: /api/v1
|
||||
security:
|
||||
- bearerAuth: []
|
||||
paths:
|
||||
/devices/register:
|
||||
post:
|
||||
operationId: registerCurrentDevice
|
||||
summary: 注册或刷新当前用户设备会话
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [id, name, platform]
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
name: { type: string, minLength: 1, maxLength: 200 }
|
||||
platform: { type: string, enum: [IOS, ANDROID, OTHER] }
|
||||
appVersion: { type: [string, "null"], maxLength: 64 }
|
||||
responses:
|
||||
"200": { description: 已注册的设备会话 }
|
||||
"401": { description: 设备已被撤销,禁止重新注册 }
|
||||
/devices:
|
||||
get:
|
||||
operationId: listOwnDevices
|
||||
summary: 查询当前用户的登录设备
|
||||
responses:
|
||||
"200": { description: 当前用户设备列表 }
|
||||
/devices/{id}:
|
||||
delete:
|
||||
operationId: revokeOwnDevice
|
||||
summary: 撤销当前用户的一台设备并使其后续请求失效
|
||||
parameters:
|
||||
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
||||
responses:
|
||||
"200": { description: 已撤销设备 }
|
||||
"404": { description: 设备不存在或不属于当前用户 }
|
||||
/devices/{id}/push-token:
|
||||
put:
|
||||
operationId: updateCurrentDevicePushToken
|
||||
summary: 注册、刷新或清除当前设备的 FCM 推送令牌
|
||||
parameters:
|
||||
- { name: id, in: path, required: true, schema: { type: string, format: uuid } }
|
||||
- { name: X-AIOA-Device-Id, in: header, required: true, schema: { type: string, format: uuid } }
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
token: { type: [string, "null"], maxLength: 4096 }
|
||||
responses:
|
||||
"200": { description: 推送令牌已更新 }
|
||||
"403": { description: 路径设备与当前设备不一致 }
|
||||
/ai/leave-progress-answers:
|
||||
post:
|
||||
operationId: answerOwnLeaveProgress
|
||||
summary: 使用自然语言只读查询本人请假流程进度
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [text, timezone]
|
||||
properties:
|
||||
text: { type: string, minLength: 1, maxLength: 2000 }
|
||||
timezone: { type: string, default: Asia/Shanghai }
|
||||
selectedRequestId: { type: string, format: uuid }
|
||||
responses:
|
||||
"200":
|
||||
description: 回答或需要用户选择的本人申请候选列表
|
||||
"400": { $ref: "#/components/responses/BadRequest" }
|
||||
"502":
|
||||
description: AI 上游不可用或输出无效
|
||||
/ai/leave-draft-suggestions:
|
||||
post:
|
||||
operationId: suggestLeaveDraft
|
||||
summary: 将自然语言转换为需要用户确认的请假草稿建议
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [text, timezone]
|
||||
properties:
|
||||
text: { type: string, minLength: 1, maxLength: 2000 }
|
||||
timezone: { type: string, default: Asia/Shanghai }
|
||||
responses:
|
||||
"200":
|
||||
description: 受约束的草稿建议,不执行业务写操作
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/AiLeaveDraftSuggestion" }
|
||||
"400": { $ref: "#/components/responses/BadRequest" }
|
||||
"502":
|
||||
description: AI 上游不可用或输出无效
|
||||
/notifications:
|
||||
get:
|
||||
operationId: listOwnNotifications
|
||||
summary: 查询当前用户站内通知
|
||||
responses:
|
||||
"200":
|
||||
description: 通知列表
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items: { $ref: "#/components/schemas/Notification" }
|
||||
/notifications/unread-count:
|
||||
get:
|
||||
operationId: getUnreadNotificationCount
|
||||
summary: 查询未读通知数
|
||||
responses:
|
||||
"200":
|
||||
description: 未读数
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [unreadCount]
|
||||
properties:
|
||||
unreadCount: { type: integer, minimum: 0 }
|
||||
/notifications/{id}/read:
|
||||
post:
|
||||
operationId: markNotificationRead
|
||||
summary: 标记本人通知已读
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, format: uuid }
|
||||
responses:
|
||||
"200":
|
||||
description: 已读通知
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/Notification" }
|
||||
"404": { $ref: "#/components/responses/NotFound" }
|
||||
/form-definitions/{formKey}:
|
||||
get:
|
||||
operationId: getFormDefinition
|
||||
summary: 获取版本化表单定义
|
||||
parameters:
|
||||
- name: formKey
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string }
|
||||
responses:
|
||||
"200":
|
||||
description: JSON Schema 与移动端 UI Schema
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/FormDefinition"
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
/me:
|
||||
get:
|
||||
operationId: getCurrentUser
|
||||
@@ -169,6 +329,81 @@ paths:
|
||||
$ref: "#/components/schemas/LeaveRequestEvent"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
/leave-requests/{id}/attachments/upload-tasks:
|
||||
post:
|
||||
operationId: createLeaveAttachmentUpload
|
||||
summary: 创建附件直传任务
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/LeaveRequestId"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CreateAttachmentUpload"
|
||||
responses:
|
||||
"201":
|
||||
description: 已创建上传任务
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/AttachmentUpload"
|
||||
"400": { $ref: "#/components/responses/BadRequest" }
|
||||
"404": { $ref: "#/components/responses/NotFound" }
|
||||
"409": { $ref: "#/components/responses/Conflict" }
|
||||
/leave-requests/{id}/attachments:
|
||||
get:
|
||||
operationId: listLeaveAttachments
|
||||
summary: 查询请假附件
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/LeaveRequestId"
|
||||
responses:
|
||||
"200":
|
||||
description: 附件列表
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items: { $ref: "#/components/schemas/LeaveAttachment" }
|
||||
/leave-requests/{id}/attachments/{attachmentId}/complete:
|
||||
post:
|
||||
operationId: completeLeaveAttachmentUpload
|
||||
summary: 确认附件上传完成
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/LeaveRequestId"
|
||||
- $ref: "#/components/parameters/AttachmentId"
|
||||
responses:
|
||||
"200":
|
||||
description: 附件已就绪
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: "#/components/schemas/LeaveAttachment" }
|
||||
/leave-requests/{id}/attachments/{attachmentId}/download:
|
||||
get:
|
||||
operationId: createLeaveAttachmentDownload
|
||||
summary: 获取附件短期下载地址
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/LeaveRequestId"
|
||||
- $ref: "#/components/parameters/AttachmentId"
|
||||
responses:
|
||||
"200":
|
||||
description: 短期下载地址
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [downloadUrl]
|
||||
properties:
|
||||
downloadUrl: { type: string, format: uri }
|
||||
/leave-requests/{id}/attachments/{attachmentId}:
|
||||
delete:
|
||||
operationId: deleteLeaveAttachment
|
||||
summary: 删除草稿附件
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/LeaveRequestId"
|
||||
- $ref: "#/components/parameters/AttachmentId"
|
||||
responses:
|
||||
"204": { description: 已删除 }
|
||||
/approval-tasks:
|
||||
get:
|
||||
operationId: listAssignedApprovalTasks
|
||||
@@ -231,6 +466,17 @@ paths:
|
||||
"409":
|
||||
$ref: "#/components/responses/Conflict"
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: oauth2
|
||||
flows:
|
||||
authorizationCode:
|
||||
authorizationUrl: http://localhost:8081/realms/aioa/protocol/openid-connect/auth
|
||||
tokenUrl: http://localhost:8081/realms/aioa/protocol/openid-connect/token
|
||||
scopes:
|
||||
openid: OpenID Connect identity
|
||||
profile: Basic profile
|
||||
email: Email address
|
||||
parameters:
|
||||
LeaveRequestId:
|
||||
name: id
|
||||
@@ -250,6 +496,11 @@ components:
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string }
|
||||
AttachmentId:
|
||||
name: attachmentId
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, format: uuid }
|
||||
responses:
|
||||
BadRequest:
|
||||
description: 请求无效
|
||||
@@ -282,9 +533,79 @@ components:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Problem"
|
||||
schemas:
|
||||
AiLeaveDraftSuggestion:
|
||||
type: object
|
||||
required: [suggestion, model, requiresUserConfirmation]
|
||||
properties:
|
||||
suggestion:
|
||||
type: object
|
||||
required: [assumptions, needsClarification]
|
||||
properties:
|
||||
type: { type: [string, "null"], enum: [PERSONAL, SICK, ANNUAL, null] }
|
||||
startsAt: { type: [string, "null"], format: date-time }
|
||||
endsAt: { type: [string, "null"], format: date-time }
|
||||
reason: { type: [string, "null"], maxLength: 2000 }
|
||||
assumptions:
|
||||
type: array
|
||||
items: { type: string }
|
||||
needsClarification:
|
||||
type: array
|
||||
items: { type: string }
|
||||
model: { type: string }
|
||||
requiresUserConfirmation: { type: boolean, const: true }
|
||||
Notification:
|
||||
type: object
|
||||
required: [id, type, title, body, createdAt]
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
type: { type: string }
|
||||
title: { type: string }
|
||||
body: { type: string }
|
||||
resourceType: { type: [string, "null"] }
|
||||
resourceId: { type: [string, "null"] }
|
||||
createdAt: { type: string, format: date-time }
|
||||
readAt: { type: [string, "null"], format: date-time }
|
||||
CreateAttachmentUpload:
|
||||
type: object
|
||||
required: [fileName, contentType, sizeBytes]
|
||||
properties:
|
||||
fileName: { type: string, minLength: 1, maxLength: 255 }
|
||||
contentType:
|
||||
type: string
|
||||
enum: [image/jpeg, image/png, application/pdf]
|
||||
sizeBytes: { type: integer, format: int64, minimum: 1, maximum: 10485760 }
|
||||
AttachmentUpload:
|
||||
type: object
|
||||
required: [attachment, uploadUrl]
|
||||
properties:
|
||||
attachment: { $ref: "#/components/schemas/LeaveAttachment" }
|
||||
uploadUrl: { type: string, format: uri }
|
||||
LeaveAttachment:
|
||||
type: object
|
||||
required: [id, fileName, contentType, sizeBytes, status, createdAt]
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
fileName: { type: string }
|
||||
contentType: { type: string }
|
||||
sizeBytes: { type: integer, format: int64 }
|
||||
status: { type: string, enum: [PENDING, READY] }
|
||||
createdAt: { type: string, format: date-time }
|
||||
completedAt: { type: [string, "null"], format: date-time }
|
||||
FormDefinition:
|
||||
type: object
|
||||
required: [key, version, dataSchema, uiSchema]
|
||||
properties:
|
||||
key: { type: string }
|
||||
version: { type: integer, minimum: 1 }
|
||||
dataSchema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
uiSchema:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
CurrentUser:
|
||||
type: object
|
||||
required: [id, tenantId, username, displayName, roles]
|
||||
required: [id, tenantId, username, displayName, roles, permissions, dataScopes]
|
||||
properties:
|
||||
id: { type: string, format: uuid }
|
||||
tenantId: { type: string, format: uuid }
|
||||
@@ -305,6 +626,16 @@ components:
|
||||
type: array
|
||||
uniqueItems: true
|
||||
items: { type: string }
|
||||
permissions:
|
||||
type: array
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: string
|
||||
enum: [LEAVE_REQUEST_READ_OWN, LEAVE_REQUEST_WRITE_OWN, LEAVE_ATTACHMENT_MANAGE_OWN, NOTIFICATION_READ_OWN, AI_LEAVE_DRAFT_SUGGEST, AI_LEAVE_PROGRESS_READ_OWN, APPROVAL_TASK_READ_ASSIGNED, APPROVAL_TASK_DECIDE_ASSIGNED]
|
||||
dataScopes:
|
||||
type: array
|
||||
uniqueItems: true
|
||||
items: { type: string, enum: [OWN, ASSIGNED] }
|
||||
OrganizationRef:
|
||||
type: object
|
||||
required: [id, name]
|
||||
|
||||
Reference in New Issue
Block a user