# 05-API接口契约

BasePath: `/api`
端口: `8080`

## 全局约定

### 响应格式
```json
{"code": 200, "message": "操作成功", "data": {}, "timestamp": 1700000000000}
```

### 错误码
| 范围 | 含义 |
|---|---|
| 200 | 成功 |
| 400xx | 客户端参数错误 |
| 401xx | 认证/授权错误 |
| 403xx | 权限不足 |
| 404xx | 资源不存在 |
| 500xx | 服务端内部错误 |

### 鉴权

除 `POST /api/usr/auth/login` 外，所有接口必须在 HTTP 头携带：

```
Authorization: Bearer <JWT-access-token>
```

后端由 `JwtAuthenticationFilter` 校验签名 + 过期时间；缺失或失效返回 `401xx`。

### 分页参数

列表查询统一接收 query 参数：`pageNum`（1 起，默认 1）、`pageSize`（默认 20，上限 100）。
响应 `data` 字段结构：

```json
{ "records": [], "total": 0, "pageNum": 1, "pageSize": 20 }
```

## 接口清单

（各模块接口段落见下方，由 `downstream-gen` 按 REQ 填入）

---

## module_mod 模块管理

### REQ-MOD-001 模块新增

- **Method**: POST
- **Path**: `/api/mod/modules`
- **Auth**: 必需
- **Permission**: 系统管理（仅超级管理员）
- **请求**: `CreateModuleDTO` —— `sDisplayType`、`sProcedureName`、`sModuleType`、`sManageDeptEn`、`bShowPermission`、`sModuleNameZh`、`iParentId?`、`iSortOrder?`
- **响应**: `data` = `{ "iIncrement": 123 }`（新模块 id）

#### 错误码
- `40001` — 必填字段缺失或类型错误（含字段定位）
- `40010` — `sDisplayType` 不在枚举范围
- `40020` — `sProcedureName` 已存在（唯一冲突）
- `40021` — `iParentId` 指定的父模块不存在或已软删除
- `40300` — 当前用户非超级管理员

### REQ-MOD-002 模块修改

- **Method**: PUT
- **Path**: `/api/mod/modules/{id}`
- **Auth**: 必需
- **Permission**: 系统管理（仅超级管理员）
- **请求**: path `{id}` = `iIncrement`；body `UpdateModuleDTO` 字段同新增（除 `sProcedureName` 之外可改，`sProcedureName` 不可修改）
- **响应**: `data` = `{ "iIncrement": 123 }`

#### 错误码
- `40001` — 字段格式错误
- `40021` — `iParentId` 形成环或指向自身
- `40400` — 模块 id 不存在或已删除

### REQ-MOD-003 模块删除

- **Method**: DELETE
- **Path**: `/api/mod/modules/{id}`
- **Auth**: 必需
- **Permission**: 系统管理（仅超级管理员）
- **请求**: path `{id}` = `iIncrement`
- **响应**: `data` = `null`（成功）

#### 错误码
- `40400` — 模块不存在
- `40901` — 模块仍有未删除子节点
- `40902` — 模块被外部业务引用（菜单 / 权限 / 角色等）

### REQ-MOD-004 模块查询

- **Method**: GET
- **Path**: `/api/mod/modules`
- **Auth**: 必需
- **Permission**: 所有登录用户
- **请求**: query `keyword?`（对 `sModuleNameZh` 模糊匹配，空匹配全部）
- **响应**: `data` = 模块树数组：`[{ iIncrement, sModuleNameZh, sDisplayType, sManageDeptEn, iParentId, iSortOrder, children: [...] }]`

#### 错误码
- `40001` — `keyword` 长度超限

---

## module_usr 用户管理

### REQ-USR-001 用户新增

- **Method**: POST
- **Path**: `/api/usr/users`
- **Auth**: 必需
- **Permission**: 用户管理（仅超级管理员）
- **请求**: `CreateUserDTO` —— `sUserNo`、`sUserName`、`iStaffId?`、`sUserType`、`sLanguage`、`bCanModifyDocs?`、`permissionCategoryIds[]`（权限组）；密码后端按规则生成默认 `666666` 哈希
- **响应**: `data` = `{ "iIncrement": 456, "sUserNo": "..." }`

#### 错误码
- `40001` — 字段格式错误
- `40020` — `sUserName` 或 `sUserNo` 已存在
- `40022` — `iStaffId` 不存在
- `40023` — `permissionCategoryIds` 中含无效分类 id

### REQ-USR-002 用户修改

- **Method**: PUT
- **Path**: `/api/usr/users/{id}`
- **Auth**: 必需
- **Permission**: 用户管理（仅超级管理员；密码不在此接口修改）
- **请求**: path `{id}` = `iIncrement`；body `UpdateUserDTO` 字段同新增（不含密码）；`permissionCategoryIds[]` 重建权限组
- **响应**: `data` = `{ "iIncrement": 456 }`

#### 错误码
- `40001` — 字段格式错误
- `40020` — 用户名 / 用户号唯一冲突
- `40400` — 用户 id 不存在

### REQ-USR-003 用户查询

- **Method**: GET
- **Path**: `/api/usr/users`
- **Auth**: 必需
- **Permission**: 用户管理 / 本人查询
- **请求**: query `field`（用户名 / 员工名 / 用户号 / 部门 / 用户类型 / 作废 / 登录日期 / 制单人）、`match`（包含 / 不包含 / 等于）、`value?`、`pageNum?`、`pageSize?`
- **响应**: 分页对象，`records[]` 字段：`iIncrement`、`sUserName`、员工名、`sUserNo`、部门、`sUserType`、`sLanguage`、`bDeleted`、`tLastLoginDate`、`sCreatedBy`、`tCreateDate`（密码字段不返回）

#### 错误码
- `40001` — `field` / `match` 取值非法
- `40002` — `pageSize` 超过 100

### REQ-USR-004 用户登录

- **Method**: POST
- **Path**: `/api/usr/auth/login`
- **Auth**: 无（公开）
- **Permission**: —
- **请求**: `LoginDTO` —— `sUserName`、`password`、`version`（标准版 / -）
- **响应**: `data` = `{ "accessToken": "<jwt>", "refreshToken": "<jwt>", "expiresIn": 28800, "user": { "iIncrement", "sUserNo", "sUserName", "sUserType", "sLanguage" } }`

#### 错误码
- `40001` — 用户名 / 密码字段为空
- `40101` — 用户名或密码错误
- `40102` — 账号已禁用（`bDeleted = 1`）
- `42301` — 账号临时锁定（连续失败超过阈值），`message` 含剩余冷却秒数
