API 文档
所有接口返回格式:
{
"code": 200,
"message": "错误信息(仅失败时)",
"data": {}
}
需要认证的接口需在请求头携带:Authorization: Bearer <token>
认证
注册
POST /auth/register
请求体:
{
"username": "admin",
"password": "123456",
"role_ids": [1]
}
username、password 为必填,password 最少 6 位。role_ids 可选:
- 不传则默认 staff 角色
- 第一个注册的用户自动成为 admin(忽略传入的 role_ids)
- 非首次注册时 role_ids 仅 admin 可指定
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 缺少必填字段 | 400 | invalid request body |
| 用户名已存在 | 400 | username already exists |
登录
POST /auth/login
请求体:
{
"username": "admin",
"password": "123456"
}
响应:
{
"code": 200,
"data": { "token": "eyJhbGciOi..." }
}
JWT Token 存入 Redis,过期时间 24 小时。
Token payload 包含以下字段:
{
"user_id": 1,
"username": "admin",
"role": "admin",
"employee_id": 3,
"jti": "xxx",
"exp": 1746000000
}
| 字段 | 类型 | 说明 |
|---|---|---|
| user_id | uint | 用户 ID |
| username | string | 用户名 |
| role | string | 角色:admin / manager / staff |
| employee_id | *uint | 关联的员工 ID,未关联时不存在此字段 |
| 响应 | code | message |
|---|---|---|
| 账号被禁用 | 403 | user is disabled |
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 用户名或密码错误 | 401 | invalid username or password |
获取当前用户信息
GET /auth/me
需要 JWT 认证。
响应示例:
{
"code": 200,
"data": {
"id": 1,
"username": "admin"
}
}
错误响应:
| 状态码 | 说明 |
|---|---|
| 401 | 未认证 |
| 404 | 用户不存在 |
注销
POST /auth/logout
需要认证。从 Redis 删除对应 Token。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 未认证 | 401 | unauthorized |
部门
创建部门
POST /depts(需认证,admin/manager 且为部门负责人)
请求体:
{
"name": "研发部",
"description": "负责产品研发和技术创新",
"leader_id": 3,
"parent_id": null
}
name 为必填,description、leader_id、parent_id 可选。名称不能重复。leader_id 指定部门负责人(Employee ID),null 或不传表示暂无负责人。parent_id 指定父部门,null 或不传表示顶级部门。manager 只能在自己管辖范围内的父部门下创建子部门。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 缺少必填字段 | 400 | invalid request body |
| 名称已存在 | 400 | department name already exists |
| 父部门不存在 | 400 | parent department not found |
| 无权限 | 403 | forbidden: cannot create department outside your department scope |
查询部门列表(分页+搜索+排序)
GET /depts(需认证)
查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| keyword | string | - | 按 name 模糊搜索 |
| sort_by | string | id | 排序字段:id, name |
| sort_desc | bool | false | 是否降序(传 "true") |
| page | int | 1 | 页码 |
| page_size | int | 10 | 每页数量,最大 100 |
查询部门树
GET /depts/tree(需认证)
返回部门层级树结构,一次性加载全部部门。
响应示例:
{
"code": 200,
"data": [
{
"id": 1,
"name": "研发部",
"description": "负责产品研发和技术创新",
"parent_id": null,
"children": [
{
"id": 4,
"name": "前端组",
"description": "前端开发",
"parent_id": 1,
"children": []
}
]
}
]
}
查询单个部门
GET /depts/:id(需认证,manager 仅可查看管辖范围内的部门)
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 无权限 | 403 | forbidden: cannot access department outside your scope |
| 不存在 | 404 | department not found |
更新部门
PUT /depts/:id(需认证,admin/manager 且为部门负责人,manager 仅可更新管辖范围内的部门)
请求体(只传需要更新的字段):
{
"name": "技术部",
"description": "技术中心",
"leader_id": 5,
"parent_id": 2
}
更新 parent_id 时会校验:不能设自己为父、不能产生循环引用、父部门必须存在。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 请求体无效 | 400 | invalid request body |
| 名称已存在 | 400 | department name already exists |
| 循环引用 | 400 | cannot set parent: circular reference |
| 无权限 | 403 | forbidden: cannot update department outside your department scope |
| 父部门不存在 | 404 | department not found |
| 部门不存在 | 404 | department not found |
删除部门
DELETE /depts/:id(需认证,admin)
有子部门或有员工的部门不能删除,需先迁移子部门和员工。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 有子部门 | 400 | department has child departments |
| 有员工 | 400 | department has employees |
| 部门不存在 | 404 | department not found |
员工
创建员工
POST /employees(需认证,admin/manager 且为部门负责人,manager 仅可在管辖范围内创建员工)
请求体:
{
"name": "张伟",
"email": "zhangwei@pms.com",
"phone": "13800000001",
"id_number": "110101199001011234",
"dept_id": 1,
"user_id": 2,
"status": "active"
}
name、email、dept_id 为必填。phone、id_number、user_id、status 可选。status 默认 "active"。user_id 关联登录账号,一个 User 最多关联一个 Employee。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 缺少必填字段 | 400 | invalid request body |
| 邮箱已存在 | 400 | email already exists |
| user_id 已关联其他员工 | 400 | employee already linked to a user |
| 部门不存在 | 400 | department not found |
| 无权限 | 403 | forbidden: cannot create employee outside your department scope |
查询员工列表(分页+搜索+排序)
GET /employees(需认证,admin 查全部,manager 查本部门+子部门,staff 返回 403)
查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| keyword | string | - | 按 name/email/phone/id_number 模糊搜索 |
| sort_by | string | id | 排序字段:id, name, email, phone, status, created_at |
| sort_desc | bool | false | 是否降序(传 "true") |
| page | int | 1 | 页码 |
| page_size | int | 10 | 每页数量,最大 100 |
响应:
{
"code": 200,
"data": {
"data": [
{
"id": 1,
"name": "张伟",
"email": "zhangwei@pms.com",
"phone": "13800000001",
"id_number": "110101199001011234",
"dept_id": 1,
"department": { "id": 1, "name": "研发部" },
"status": "active",
"created_at": "2026-04-28T12:00:00Z",
"updated_at": "2026-04-28T12:00:00Z",
"created_by": "admin",
"updated_by": "admin"
}
],
"total": 50,
"page": 1,
"page_size": 10,
"total_pages": 5
}
}
列表结果通过 Redis 缓存,过期时间 10 分钟。创建/更新/删除员工后自动清除缓存。
获取当前用户员工档案
GET /employees/me(需认证,所有角色)
根据 JWT 中的 user_id 查询关联的 Employee。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 未认证 | 401 | unauthorized |
| 未关联员工档案 | 404 | employee profile not found |
查询单个员工
GET /employees/:id(需认证,admin 全量,manager 仅本部门+子部门,staff 仅本部门)
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 无权限 | 403 | forbidden: cannot access employee outside your department scope |
| 不存在 | 404 | employee not found |
更新员工
PUT /employees/:id(需认证,admin/manager 且为部门负责人,manager 仅可更新管辖范围内的员工,不能将员工移出管辖范围)
请求体(只传需要更新的字段):
{
"name": "张伟2",
"phone": "13900000001"
}
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 请求体无效 | 400 | invalid request body |
| 邮箱已存在 | 400 | email already exists |
| 部门不存在 | 400 | department not found |
| 无权限 | 403 | forbidden: cannot update employee outside your department scope |
删除员工
DELETE /employees/:id(需认证,仅 admin)
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 不存在 | 404 | employee not found |
薪资结构
创建薪资结构
POST /salaries/structures(需 admin 角色)
请求体:
{
"employee_id": 1,
"base_salary": 10000,
"position_allowance": 2000,
"performance_factor": 1.0
}
employee_id、base_salary、position_allowance 为必填。performance_factor 可选,默认 1.0。每个员工只能有一个薪资结构。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 缺少必填字段 | 400 | invalid request body |
| 员工不存在 | 400 | employee not found |
| 薪资结构已存在 | 400 | salary structure already exists for this employee |
查询薪资结构列表(分页+搜索+排序)
GET /salaries/structures(需 admin 角色)
查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| keyword | string | - | 按员工姓名/邮箱模糊搜索 |
| sort_by | string | id | 排序字段:id, base_salary, position_allowance, performance_factor, created_at |
| sort_desc | bool | false | 是否降序(传 "true") |
| page | int | 1 | 页码 |
| page_size | int | 10 | 每页数量,最大 100 |
查询员工的薪资结构
GET /salaries/structures/employees/:emp_id(需 admin 角色)
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效员工 ID | 400 | invalid employee id |
| 不存在 | 404 | salary structure not found |
更新薪资结构
PUT /salaries/structures/:id(需 admin 角色)
请求体(只传需要更新的字段):
{
"base_salary": 12000,
"performance_factor": 1.2
}
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 请求体无效 | 400 | invalid request body |
| 薪资结构不存在 | 404 | salary structure not found |
删除薪资结构
DELETE /salaries/structures/:id(需 admin 角色)
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 薪资结构不存在 | 404 | salary structure not found |
薪资记录
生成月度薪资记录
POST /salaries/records(需 admin 角色)
请求体:
{
"employee_id": 1,
"year": 2026,
"month": 4,
"performance_factor": 1.2
}
employee_id、year、month 为必填。performance_factor 可选,传 0 或不传则使用薪资结构中的系数。
计算公式:实际薪资 = (基本工资 + 岗位津贴) × 绩效系数
生成时自动关联薪资结构(structure_id),状态为 draft。
同一员工同一年月不能重复生成。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 缺少必填字段 | 400 | invalid request body |
| 年月无效 | 400 | invalid year or month |
| 员工不存在 | 400 | employee not found |
| 薪资结构不存在 | 400 | salary structure not found for this employee |
| 记录已存在 | 400 | salary record already exists for this employee and month |
批量生成月度薪资记录
POST /salaries/records/batch(需 admin 角色)
请求体:
{
"year": 2026,
"month": 4,
"employee_ids": [1, 2, 3],
"dept_id": null
}
year、month 为必填。employee_ids 和 dept_id 可选,优先级:
- employee_ids 不为空:为指定员工生成
- dept_id 不为空:为该部门下有薪资结构的在职员工生成
- 都不传:为所有有薪资结构的在职员工生成
已存在的记录自动跳过,不报错。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 缺少必填字段 | 400 | invalid request body |
| 年月无效 | 400 | invalid year or month |
| 部门不存在 | 400 | department not found |
修改薪资记录
PUT /salaries/records/:id(需 admin 角色)
仅 draft 或 rejected 状态可修改。
请求体(只传需要更新的字段):
{
"performance_factor": 1.5
}
修改 performance_factor 时自动重算 actual_salary。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 非草稿/驳回状态 | 400 | salary record is not in draft/rejected status |
| 不存在 | 404 | salary record not found |
提交审核
PUT /salaries/records/:id/submit(需 admin 角色)
draft 或 rejected → pending。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 非草稿/驳回状态 | 400 | salary record is not in draft/rejected status |
| 不存在 | 404 | salary record not found |
审核通过
PUT /salaries/records/:id/approve(需 admin 角色)
pending → approved。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 非待审核状态 | 400 | salary record is not in pending status |
| 不存在 | 404 | salary record not found |
审核驳回
PUT /salaries/records/:id/reject(需 admin 角色)
pending → rejected。驳回后可修改绩效系数再重新提交。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 非待审核状态 | 400 | salary record is not in pending status |
| 不存在 | 404 | salary record not found |
确认发放
PUT /salaries/records/:id/pay(需 admin 角色)
approved → paid。发放后不可修改。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 非已审核状态 | 400 | salary record is not in approved status |
| 不存在 | 404 | salary record not found |
查询薪资记录列表(分页+筛选+排序)
GET /salaries/records(需 admin 角色)
查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| employee_id | int | - | 按员工 ID 筛选 |
| year | int | - | 按年份筛选 |
| month | int | - | 按月份筛选 |
| status | string | - | 按状态筛选:draft, pending, approved, rejected, paid |
| sort_by | string | id | 排序字段:id, year, month, actual_salary, status, created_at |
| sort_desc | bool | false | 是否降序(传 "true") |
| page | int | 1 | 页码 |
| page_size | int | 10 | 每页数量,最大 100 |
查询单条薪资记录
GET /salaries/records/:id(需 admin 角色)
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 不存在 | 404 | salary record not found |
考勤管理
上班打卡
POST /attendance/clock-in(需认证,staff 仅能为自己打卡)
请求体:
{
"employee_id": 1
}
employee_id 为必填。同一天同一员工不能重复打卡。staff 角色只能传自己的 employee_id(从 JWT 的 employee_id 字段获取),否则返回 403。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 缺少必填字段 | 400 | invalid request body |
| 已打卡 | 400 | already clocked in today |
| 员工不存在 | 400 | employee not found |
| staff 替别人打卡 | 403 | can only clock in for yourself |
| staff 未关联员工档案 | 403 | no employee profile linked |
下班打卡
PUT /attendance/clock-out(需认证,staff 仅能为自己打卡)
请求体:
{
"employee_id": 1
}
必须先上班打卡才能下班打卡。staff 角色只能传自己的 employee_id,否则返回 403。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 缺少必填字段 | 400 | invalid request body |
| 未上班打卡 | 400 | not clocked in today |
| 已下班打卡 | 400 | already clocked out today |
| staff 替别人打卡 | 403 | can only clock out for yourself |
| staff 未关联员工档案 | 403 | no employee profile linked |
查询打卡记录列表
GET /attendance/records(需认证,staff 仅能查看自己记录)
查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| employee_id | int | - | 按员工 ID 筛选 |
| start_date | string | - | 起始日期 YYYY-MM-DD |
| end_date | string | - | 结束日期 YYYY-MM-DD |
| keyword | string | - | 按员工姓名/邮箱搜索 |
| sort_by | string | date | 排序字段:id, date, created_at |
| sort_desc | bool | false | 是否降序 |
| page | int | 1 | 页码 |
| page_size | int | 10 | 每页数量,最大 100 |
查询单条打卡记录
GET /attendance/records/:id(需认证)
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 不存在 | 404 | attendance record not found |
删除打卡记录
DELETE /attendance/records/:id(需 admin 角色)
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 不存在 | 404 | attendance record not found |
批量删除打卡记录
DELETE /attendance/records/batch(需 admin 角色)
请求体:
{
"ids": [1, 2, 3]
}
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 缺少必填字段 | 400 | invalid request body |
生成考勤月度统计
POST /attendance/summaries/generate(需 admin/manager 角色,manager 仅可生成管辖范围内员工的汇总)
请求体:
{
"employee_id": 1,
"year": 2026,
"month": 4
}
根据员工工作时间(WorkStartTime/WorkEndTime,默认 09:00/18:00)判定迟到/早退/缺勤。重复生成会覆盖旧数据。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 缺少必填字段 | 400 | invalid request body |
| 年月无效 | 400 | invalid year or month |
| 员工不存在 | 400 | employee not found |
| 无权限 | 403 | forbidden: cannot generate summary for employee outside your department scope |
查询考勤统计列表
GET /attendance/summaries(需认证,staff 仅能查看自己统计)
查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| employee_id | int | - | 按员工 ID 筛选 |
| year | int | - | 按年份筛选 |
| month | int | - | 按月份筛选 |
| sort_by | string | id | 排序字段:id, year, month, created_at |
| sort_desc | bool | false | 是否降序 |
| page | int | 1 | 页码 |
| page_size | int | 10 | 每页数量,最大 100 |
请假管理
提交请假申请
POST /leaves(需认证,staff 仅能为本人申请,manager 仅能为管辖范围内员工申请)
请求体:
{
"employee_id": 1,
"type": "annual",
"start_date": "2026-04-28",
"end_date": "2026-04-29",
"reason": "年假"
}
employee_id、type、start_date、end_date 为必填。type 取值:annual(年假)/sick(病假)/personal(事假)。staff 角色只能传自己的 employee_id,否则返回 403。manager 只能为管辖范围内的员工创建请假。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 缺少必填字段 | 400 | invalid request body |
| 无效请假类型 | 400 | invalid leave type, must be annual/sick/personal |
| 日期无效 | 400 | end date must be >= start date |
| 员工不存在 | 400 | employee not found |
| staff 替别人请假 | 403 | can only create leave for yourself |
| staff 未关联员工档案 | 403 | no employee profile linked |
| 无权限 | 403 | forbidden: cannot create leave for employee outside your department scope |
查询请假列表
GET /leaves(需认证,staff 仅能查看自己请假)
查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| employee_id | int | - | 按员工 ID 筛选 |
| status | string | - | 按状态筛选:pending/approved/rejected |
| keyword | string | - | 按员工姓名/邮箱搜索 |
| sort_by | string | id | 排序字段:id, type, status, start_date, created_at |
| sort_desc | bool | false | 是否降序 |
| page | int | 1 | 页码 |
| page_size | int | 10 | 每页数量,最大 100 |
查询单条请假申请
GET /leaves/:id(需认证)
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 不存在 | 404 | leave request not found |
审批通过
PUT /leaves/:id/approve(需 admin/manager 且为部门负责人)
pending → approved。manager 仅能审批本部门及子部门的请假。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 非待审批状态 | 400 | leave request is not in pending status |
| 不存在 | 404 | leave request not found |
| manager 审批非本部门 | 403 | forbidden: cannot approve leave outside your department |
审批驳回
PUT /leaves/:id/reject(需 admin/manager 且为部门负责人)
pending → rejected。manager 仅能驳回本部门及子部门的请假。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 非待审批状态 | 400 | leave request is not in pending status |
| 不存在 | 404 | leave request not found |
| manager 驳回非本部门 | 403 | forbidden: cannot reject leave outside your department |
获取角色列表
GET /roles(需认证,所有角色可查看)
用户管理
创建用户
POST /users(需 admin 角色)
请求体:
{
"username": "newuser",
"password": "123456",
"role_ids": [2]
}
password最少 6 位role_ids可选,不传则默认分配 staff 角色
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 用户名已存在 | 400 | username already exists |
| 请求体无效 | 400 | invalid request body |
获取用户列表(分页+搜索+排序)
GET /users(需 admin 角色)
查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| keyword | string | - | 按 username 模糊搜索 |
| sort_by | string | id | 排序字段:id, username, status, created_at |
| sort_desc | bool | false | 是否降序(传 "true") |
| page | int | 1 | 页码 |
| page_size | int | 10 | 每页数量,最大 100 |
响应:
{
"code": 200,
"data": {
"data": [
{
"id": 1,
"username": "admin",
"status": "active",
"roles": [{"id": 1, "name": "admin"}],
"created_at": "2026-04-29T12:00:00Z",
"updated_at": "2026-04-29T12:00:00Z"
}
],
"total": 10,
"page": 1,
"page_size": 10,
"total_pages": 1
}
}
获取单个用户
GET /users/:id(需 admin 角色)
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 不存在 | 404 | user not found |
修改用户状态
PUT /users/:id/status(需 admin 角色)
请求体:
{
"status": "disabled"
}
status 取值:active / disabled
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 请求体无效 | 400 | invalid request body |
| 无效状态 | 400 | invalid status |
分配角色
PUT /users/:id/roles(需 admin 角色)
请求体:
{
"role_ids": [1, 2]
}
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 请求体无效 | 400 | invalid request body |
修改密码
PUT /users/:id/password(需 admin 角色)
请求体:
{
"new_password": "654321"
}
admin 可重置任意用户密码,仅需提供 new_password。new_password 最少 6 位。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 请求体无效 | 400 | invalid request body |
删除用户
DELETE /users/:id(需 admin 角色)
不能删除自己。
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 删除自己 | 400 | cannot delete yourself |
权限矩阵
| 操作 | admin | manager(部门负责人) | staff |
|---|---|---|---|
| 查看部门/部门树 | Y | Y | Y |
| 创建/编辑部门 | Y | Y(本部门范围) | - |
| 删除部门 | Y | - | - |
| 查看员工列表 | Y(全部) | Y(本部门+子部门) | - |
| 查看 /employees/me | Y | Y | Y |
| 创建/编辑员工 | Y | Y(本部门范围) | - |
| 删除员工 | Y | - | - |
| 管理用户(含删除) | Y | - | - |
| 查看角色列表 | Y | Y | Y |
| 薪资管理(全部) | Y | - | - |
| 打卡 | Y | Y | 仅自己 |
| 删除考勤记录 | Y | - | - |
| 查看考勤记录/统计 | Y | Y | 仅自己 |
| 生成考勤统计 | Y | Y | - |
| 提交请假 | Y | Y | 仅自己 |
| 查看请假列表 | Y | Y | 仅自己 |
| 审批请假 | Y | Y(本部门范围) | - |
| 查看审计日志 | Y | - | - |
| 删除审计日志 | Y | - | - |
"本部门范围" 指该 manager 作为 leader_id 所属部门及其子部门。manager 如果不是任何部门的负责人,访问需要部门权限的接口会返回 403。
"仅自己" 指后端强制使用 JWT 中的 employee_id,忽略请求中的 employee_id 参数或列表筛选。
操作日志
所有写操作(创建、更新、删除、审批等)自动记录审计日志,包含操作人、操作类型、实体类型、实体 ID、变更内容、IP 地址和时间。
查询审计日志
GET /audit-logs(需 admin 角色)
查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| operator | string | - | 按操作人筛选 |
| entity_type | string | - | 按实体类型筛选:user, department, employee, salary_structure, salary_record, attendance_record, attendance_summary, leave_request |
| start_time | string | - | 起始时间 RFC3339 格式 |
| end_time | string | - | 结束时间 RFC3339 格式 |
| sort_by | string | id | 排序字段:id, created_at, action, entity_type |
| sort_desc | bool | false | 是否降序(传 "true") |
| page | int | 1 | 页码 |
| page_size | int | 10 | 每页数量,最大 100 |
响应示例:
{
"code": 200,
"data": {
"data": [
{
"id": 1,
"operator": "admin",
"action": "create",
"entity_type": "employee",
"entity_id": 1,
"changes": "{\"name\":\"Alice\",\"email\":\"alice@test.com\"}",
"ip_address": "192.168.1.1",
"created_at": "2026-04-28T12:00:00Z"
}
],
"total": 50,
"page": 1,
"page_size": 10,
"total_pages": 5
}
}
action 取值:create, update, delete, update_status, assign_roles, reset_password, update_password, clock_in, clock_out, generate_summary, approve, reject, submit, pay, batch_create
删除审计日志
DELETE /audit-logs/:id(需 admin 角色)
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 无效 ID | 400 | invalid id |
| 不存在 | 404 | audit log not found |
批量删除审计日志
DELETE /audit-logs/batch(需 admin 角色)
请求体:
{
"ids": [1, 2, 3]
}
| 响应 | code | message |
|---|---|---|
| 成功 | 200 | - |
| 缺少必填字段 | 400 | invalid request body |
健康检查
GET /ping
{ "message": "pong" }