# API 文档 Base URL:`http://localhost:8080/api` ## 通用约定 所有接口均返回统一 JSON 结构: ```typescript class Response { "code": number; "message": string; "data": T | null; } ``` - `code === 200` 表示成功;**`code !== 200` 时 `data` 恒为 `null`** - 除特别标注(公开)外,接口需在请求头携带 `Authorization: Bearer ` - 下文路径均省略 `/api` 前缀,`data` 仅给出 `T` 的声明 - 部分 `/test` 接口的返回值不遵循上述格式 - 前端类示例使用 **TypeScript** 类定义 ## 接口总览 | 分组 | 路径前缀 | 说明 | |--------------|--------------------|-------------------------------------------| | 测试 | `/test` | 连通性测试 | | 认证 | `/v1/auth` | 登录 / 注册 / 验证码 / Token 管理 | | 物品管理 | `/v1/items` | 物品 / 类别 / 图片 CRUD、借还、上下架查询 | | 使用记录 | `/v1/usages` | 使用记录 CRUD、图片、当前/按用户查询 | | 财务管理 | `/v1/finance` | 财务记录 / 分类 CRUD、凭证图片上传 | | 财务凭证图片 | `/v1/proof-images` | 财务凭证图片 CRUD | | 邮件通知 | `/v1/email` | 通知设置、收件邮箱启用状态 | --- ## 分组:测试 `/test` ### GET /hello 需要认证。 **响应** ```typescript "Hello Kotlin WebFlux!" ``` --- ## 分组:认证 `/v1/auth` | 方法 | 路径 | 认证 | 说明 | |--------|---------------------------|------|--------------------------| | POST | `/login` | 公开 | 登录,获取 Token | | GET | `/logout` | 需要 | 注销,Token 加入黑名单 | | GET | `/ask-code` | 公开 | 发送邮箱验证码 | | POST | `/register` | 公开 | 邮箱注册 | | POST | `/reset` | 公开 | 重置密码 | | GET | `/relogin` | 需要 | 用旧 Token 换取新 Token | ### POST /login 以 `application/x-www-form-urlencoded` 表单提交。 **请求参数** | 字段 | 类型 | 说明 | |----------|--------|----------| | username | string | 用户名 | | password | string | 密码 | **响应 data** ```typescript class data { "username": string; "role": string; "token": string; "expire": Date; } ``` ### GET /logout **请求参数**:无 **响应 data**:`null` ### GET /ask-code **请求参数** | 字段 | 类型 | 说明 | |-------|-----------------------------|------------------------------------| | email | string | 接收验证码的邮箱 | | type | `register` \| `reset` | 验证码用途(注册 / 重置密码) | **响应 data**:`null` ### POST /register **请求体字段**:`email`、`code`、`username`、`password` **响应 data**:`null` ### POST /reset **请求体字段**:`email`、`code`、`password` **响应 data**:`null` ### GET /relogin **请求参数**:无 **响应 data** ```typescript class data { "token": string; "expire": Date; } ``` --- ## 分组:物品管理 `/v1/items` | 方法 | 路径 | 认证 | 说明 | |--------|---------------------------------|------|----------------------------------------| | GET | `/items` | 需要 | 分页查询物品 | | POST | `/items` | 需要 | 创建物品 | | PUT | `/items` | 需要 | 更新物品 | | DELETE | `/items` | 需要 | 删除物品(同时清理其图片) | | POST | `/items/{id}/upload_images` | 需要 | 上传物品图片(multipart) | | POST | `/items/{id}/set_primary_image` | 需要 | 设置物品主图 | | POST | `/items/{id}/borrow` | 需要 | 借用物品(扣减可用库存) | | POST | `/items/{id}/return_item` | 需要 | 归还物品(恢复可用库存) | | GET | `/items/available` | 需要 | 获取可用物品列表 | | GET | `/items/in_use` | 需要 | 获取使用中物品列表 | | GET | `/items/categories` | 需要 | 查询物品类别列表 | | POST | `/items/categories` | 需要 | 创建物品类别 | | PUT | `/items/categories` | 需要 | 更新物品类别 | | DELETE | `/items/categories` | 需要 | 删除物品类别 | | GET | `/items/images` | 需要 | 查询物品图片列表 | | POST | `/items/images` | 需要 | 创建物品图片 | | PUT | `/items/images` | 需要 | 更新物品图片 | | DELETE | `/items/images` | 需要 | 删除物品图片(同时删除物理文件) | ### 实体定义 ```typescript class Item { "id": number | null; "code": string; // 物品编号 / 资产编号 "name": string; "categoryId": number | null; "model": string | null; "brand": string | null; "location": string | null; "totalQuantity": number; "availableQuantity": number; "unit": string; // 默认 "件" "price": number | null; "purchaseDate": string | null; "supplier": string | null; "status": string; // normal / disabled / lost / repair "description": string | null; "imagePath": string | null; "createdBy": number | null; "createdAt": string | null; "updatedAt": string | null; } ``` ```typescript class Category { "id": number | null; "name": string; "parentId": number | null; "description": string | null; "createdAt": string | null; "updatedAt": string | null; } ``` ```typescript class Attachment { "id": number | null; "relatedTable": string | null; // 关联表名,如 "items" "relatedId": number | null; // 关联记录 ID "fileName": string | null; "filePath": string | null; "fileSize": number | null; "contentType": string | null; "uploadedBy": number | null; "uploadedAt": string | null; } ``` ```typescript class Page { "records": T[]; "total": number; "size": number; "current": number; "pages": number; } ``` ### GET /items **请求参数** | 字段 | 类型 | 说明 | |----------|---------|-----------------------------------| | pageNum | number | 页码,默认 `1` | | pageSize | number | 每页条数,默认 `10` | | keyword | string? | 按名称 / 编号模糊搜索 | | status | string? | 按状态过滤,如 `normal` | **响应 data**:`Page` ### POST /items **请求体**:`Item`(`id` / `createdAt` / `updatedAt` 由服务端填充) **响应 data**:`null` ### PUT /items **请求体**:`Item`(须包含 `id`) **响应 data**:`null` ### DELETE /items **请求参数** | 字段 | 类型 | 说明 | |------|--------|---------| | id | number | 物品 ID | **响应 data**:`null` ### POST /items/{id}/upload_images **请求**:`multipart/form-data`,字段名 `files`,可传多个图片文件 **响应 data**:`null` ### POST /items/{id}/set_primary_image **请求参数** | 字段 | 类型 | 说明 | |---------|--------|------------------------------------------| | imageId | number | 附件 ID,须属于该物品 | **响应 data**:`null` ### POST /items/{id}/borrow **请求参数** | 字段 | 类型 | 说明 | |----------|--------|--------------------| | quantity | number | 借用数量,默认 `1` | **响应 data**:`null` ### POST /items/{id}/return_item **请求参数** | 字段 | 类型 | 说明 | |----------|--------|--------------------| | quantity | number | 归还数量,默认 `1` | **响应 data**:`null` ### GET /items/available **请求参数**:无 **响应 data**:`Item[]` ### GET /items/in_use **请求参数**:无 **响应 data**:`Item[]` ### GET /items/categories **请求参数**:无 **响应 data**:`Category[]` ### POST /items/categories **请求体**:`Category`(`id` / `createdAt` / `updatedAt` 由服务端填充) **响应 data**:`null` ### PUT /items/categories **请求体**:`Category`(须包含 `id`) **响应 data**:`null` ### DELETE /items/categories **请求参数** | 字段 | 类型 | 说明 | |------|--------|----------| | id | number | 类别 ID | **响应 data**:`null` ### GET /items/images **请求参数**:无 **响应 data**:`Attachment[]`(`relatedTable` 为 `"items"` 的图片) ### POST /items/images **请求体**:`Attachment`(`id` / `uploadedAt` 由服务端填充) **响应 data**:`null` ### PUT /items/images **请求体**:`Attachment`(须包含 `id`) **响应 data**:`null` ### DELETE /items/images **请求参数** | 字段 | 类型 | 说明 | |------|--------|----------| | id | number | 图片 ID | **响应 data**:`null` --- ## 分组:使用记录 `/v1/usages` | 方法 | 路径 | 认证 | 说明 | |--------|------------------------------|------|--------------------------------------| | GET | `/usages` | 需要 | 分页查询使用记录 | | POST | `/usages` | 需要 | 创建使用记录 | | PUT | `/usages` | 需要 | 更新使用记录 | | DELETE | `/usages` | 需要 | 删除使用记录 | | POST | `/usages/{id}/upload_images` | 需要 | 上传使用记录图片(multipart) | | GET | `/usages/current` | 需要 | 获取当前使用中的记录 | | GET | `/usages/by_user` | 需要 | 根据用户姓名获取使用记录 | | GET | `/usages/images` | 需要 | 查询使用记录图片列表 | | POST | `/usages/images` | 需要 | 创建使用记录图片 | | PUT | `/usages/images` | 需要 | 更新使用记录图片 | | DELETE | `/usages/images` | 需要 | 删除使用记录图片(同时删除物理文件) | ### 实体定义 ```typescript class BorrowRecord { "id": number | null; "itemId": number; "borrower": string; "quantity": number; "borrowDate": string | null; "dueDate": string | null; "returnDate": string | null; "status": string; // BORROWED / RETURNED / OVERDUE / CANCELED "approver": string | null; "note": string | null; "createdAt": string | null; "updatedAt": string | null; } ``` ### GET /usages **请求参数** | 字段 | 类型 | 说明 | |----------|---------|---------------------| | pageNum | number | 页码,默认 `1` | | pageSize | number | 每页条数,默认 `10` | | keyword | string? | 按借入人模糊搜索 | | status | string? | 按状态过滤 | **响应 data**:`Page` ### POST /usages **请求体**:`BorrowRecord`(`id` / `createdAt` / `updatedAt` 由服务端填充) **响应 data**:`null` ### PUT /usages **请求体**:`BorrowRecord`(须包含 `id`) **响应 data**:`null` ### DELETE /usages **请求参数** | 字段 | 类型 | 说明 | |------|--------|---------| | id | number | 记录 ID | **响应 data**:`null` ### POST /usages/{id}/upload_images **请求**:`multipart/form-data`,字段名 `files`,可传多个图片文件 **响应 data**:`null` ### GET /usages/current **请求参数**:无 **响应 data**:`BorrowRecord[]`(当前 `BORROWED` 与 `OVERDUE` 记录) ### GET /usages/by_user **请求参数** | 字段 | 类型 | 说明 | |------|---------|------------| | name | string? | 借入人姓名 | **响应 data**:`BorrowRecord[]` ### GET /usages/images **请求参数**:无 **响应 data**:`Attachment[]`(`relatedTable` 为 `"borrow_records"` 的图片) ### POST /usages/images **请求体**:`Attachment`(`id` / `uploadedAt` 由服务端填充) **响应 data**:`null` ### PUT /usages/images **请求体**:`Attachment`(须包含 `id`) **响应 data**:`null` ### DELETE /usages/images **请求参数** | 字段 | 类型 | 说明 | |------|--------|----------| | id | number | 图片 ID | **响应 data**:`null` --- ## 分组:财务管理 `/v1/finance` | 方法 | 路径 | 认证 | 说明 | |--------|-------------------------------|------|---------------------------------------| | GET | `/finance` | 需要 | 分页查询财务记录 | | POST | `/finance` | 需要 | 创建财务记录 | | PUT | `/finance` | 需要 | 更新财务记录 | | DELETE | `/finance` | 需要 | 删除财务记录 | | POST | `/finance/{id}/upload_images` | 需要 | 上传财务凭证图片(multipart) | | DELETE | `/finance/{id}` | 需要 | 删除财务记录(发送邮件通知) | | GET | `/finance/categories` | 需要 | 查询财务分类列表 | | POST | `/finance/categories` | 需要 | 创建财务分类 | | PUT | `/finance/categories` | 需要 | 更新财务分类 | | DELETE | `/finance/categories` | 需要 | 删除财务分类 | ### 实体定义 ```typescript class FinanceRecord { "id": number | null; "recordNo": string | null; "type": string; // PURCHASE / REFUND / REPAIR / DEPRECIATION / OTHER "relatedItemId": number | null; "amount": number; // BigDecimal "currency": string; // 默认 "CNY" "vendor": string | null; "occurredAt": string | null; "recordedBy": number | null; "note": string | null; "createdAt": string | null; } ``` ### GET /finance **请求参数** | 字段 | 类型 | 说明 | |----------|---------|--------------------------------| | pageNum | number | 页码,默认 `1` | | pageSize | number | 每页条数,默认 `10` | | keyword | string? | 按单号 / 供应商 / 备注模糊搜索 | | type | string? | 按类型过滤 | | start | string? | 发生时间起点 | | end | string? | 发生时间终点 | | vendor | string? | 按供应商过滤 | | itemId | number? | 按关联物品 ID 过滤 | **响应 data**:`Page` ### POST /finance **请求体**:`FinanceRecord`(`id` / `createdAt` 由服务端填充) **响应 data**:`null` ### PUT /finance **请求体**:`FinanceRecord`(须包含 `id`) **响应 data**:`null` ### DELETE /finance **请求参数** | 字段 | 类型 | 说明 | |------|--------|---------| | id | number | 记录 ID | **响应 data**:`null` ### POST /finance/{id}/upload_images **请求**:`multipart/form-data`,字段名 `files`,可传多个图片文件 **响应 data**:`null` ### DELETE /finance/{id} 删除财务记录,并向 `recordedBy` 对应账号的邮箱发送删除通知。 **响应 data**:`null` ### GET /finance/categories **请求参数**:无 **响应 data**:`Category[]` ### POST /finance/categories **请求体**:`Category`(`id` / `createdAt` / `updatedAt` 由服务端填充) **响应 data**:`null` ### PUT /finance/categories **请求体**:`Category`(须包含 `id`) **响应 data**:`null` ### DELETE /finance/categories **请求参数** | 字段 | 类型 | 说明 | |------|--------|----------| | id | number | 分类 ID | **响应 data**:`null` --- ## 分组:财务凭证图片 `/v1/proof-images` | 方法 | 路径 | 认证 | 说明 | |--------|------------------------|------|-----------------------------------| | GET | `/proof-images` | 需要 | 查询财务凭证图片列表 | | POST | `/proof-images` | 需要 | 创建财务凭证图片 | | PUT | `/proof-images` | 需要 | 更新财务凭证图片 | | DELETE | `/proof-images` | 需要 | 删除财务凭证图片 | | DELETE | `/proof-images/{id}` | 需要 | 删除凭证图片(同时删除物理文件) | 凭证图片为 `relatedTable` 为 `"finance_records"` 的 `Attachment`,与 `/items/images` 共用 `Attachment` 实体。 ### GET /proof-images **请求参数**:无 **响应 data**:`Attachment[]` ### POST /proof-images **请求体**:`Attachment`(`id` / `uploadedAt` 由服务端填充) **响应 data**:`null` ### PUT /proof-images **请求体**:`Attachment`(须包含 `id`) **响应 data**:`null` ### DELETE /proof-images **请求参数** | 字段 | 类型 | 说明 | |------|--------|----------| | id | number | 图片 ID | **响应 data**:`null` ### DELETE /proof-images/{id} 删除图片并清理物理文件。 **响应 data**:`null` --- ## 分组:邮件通知 `/v1/email` | 方法 | 路径 | 认证 | 说明 | |--------|--------------------------|------|-------------------------| | GET | `/notification-settings` | 需要 | 获取通知设置和邮箱列表 | | POST | `/notification-settings` | 需要 | 创建 / 更新通知设置 | | POST | `/toggle-email-status` | 需要 | 切换邮箱启用 / 禁用状态 | ### 实体定义 ```typescript class EmailNotice { "id": number | null; "name": string | null; "targetEmails": string | null; "subject": string | null; "body": string | null; "enabled": boolean; // 默认 true "scheduleCron": string | null; "lastSentAt": string | null; "createdAt": string | null; "updatedAt": string | null; } ``` ### GET /notification-settings **请求参数**:无 **响应 data**:`EmailNotice[]` ### POST /notification-settings **请求体**:`EmailNotice`。`id` 为 `null` 时创建新记录,否则更新已有记录。 **响应 data**:`null` ### POST /toggle-email-status **请求参数** | 字段 | 类型 | 说明 | |------|---------|----------| | id | number? | 通知 ID | **响应 data**:`null` --- ## 其他 ### WebSocket `ws://localhost:8080/ws` — 目前不支持