21 KiB
21 KiB
迭代1总体设计 —— API/接口设计(hr-web,ocai 口径)
- 版本:v2.0(迭代1-总体设计,取代 v1 Spring Boot/JWT RESTful 口径,v1 已归档至
docs/_archive/01-design-v1-old/api-design.md) - 状态:评审通过(主agent评审,基线冻结)
- 规范依据:ocai 技能集 module-development-spec、dspy-file-implementation-spec、crud-definition-spec;架构基线
docs/01-design/architecture.md
1. 接口范式与通用约定(取代 v1 RESTful/JWT)
- 端点形态:全部接口为
.dspy端点(受控 Python),路径/{module}/api/{name}.dspy,由 ahserver wwwroot 自动路由,无需注册;GET query 与 POST body 统一解析进params_kw。dspy 必须显式return,且不得在async with db.sqlorContext块内 return(NoneType 陷阱)。 - 鉴权:session cookie(Redis 会话)+ rbac 路径级角色控制;每条路径经各模块
scripts/load_path.py注册,角色:admin / hr / manager / employee / logined;未注册路径默认拒绝。不使用 JWT。 - 数据范围:查询类接口强制叠加
get_data_scope(user_id)(hr-system 提供),范围外数据不可见。 - CRUD 列表/表单接口:由 json/*.json 经 xls2ui 自动生成(列表查询、add/update/delete 包装 dspy),不在本文逐一列出;本文列出业务自定义端点。CRUD 自动生成部分约定
new_data_url/update_data_url/delete_data_url位于 params 顶层。 - 统一响应结构:
- 列表:
{"status":"success","data":{"rows":[...],"total":N}}(DataViewer 强制格式) - 业务:
{"status":"success"|"error","message":"...","data":{...}} - 错误返回 HTTP 200 + status=error(bricks 前端惯例),鉴权失败由框架返回 401/403。
- 列表:
- 错误码规范(status=error 时 data.code):
| code | 含义 | 典型场景 |
|---|---|---|
| PARAM_INVALID | 参数缺失/格式错误 | 必填项为空、日期格式错 |
| NOT_FOUND | 对象不存在 | id 无效 |
| DUPLICATE | 唯一冲突 | 工号/编码重复 |
| NO_PERMISSION | 数据范围外/角色不足 | 越权访问他人档案 |
| BLACKLIST_HIT | 黑名单命中 | 入职校验拦截 |
| STATUS_CONFLICT | 状态不允许 | 已离职再调动、重复审批 |
| FLOW_NOT_MATCH | 无匹配审批流 | 该员工类型/部门未配置流程 |
| SCOPE_OVERDRAFT | 编制/范围超限 | 预留(编制管理范围外) |
| INTERNAL_ERROR | 服务异常 | 兜底 |
- 审计:所有写接口成功后调用
write_audit_log(module,target_type,target_id,op,before,after)(hr-system)。
2. 端点清单(按模块)
角色列:A=admin,H=hr,M=manager,E=employee,L=任意登录。数据范围=是 表示叠加数据范围过滤。 CRUD 列:该表的标准增删改查由 json/*.json 自动生成,路径为
/{module}/{tblname}_list(页面) +add_/update_/delete_{tblname}.dspy。
2.1 hr-org(/hrorg,F01/F02/F04~F08)
| 端点 | 方法 | 功能 | 关键请求参数 | 响应 data | 角色 | CRUD |
|---|---|---|---|---|---|---|
| /hrorg/api/org_tree.dspy | GET | 组织树(支持 as_of 历史日期、status 过滤) | as_of?, status?, keyword? | 树形节点数组(id,name,parent_id,children,status,leader_name) | L | — |
| /hrorg/api/org_unit_create.dspy | POST | 新建组织(编码唯一校验、写 org_unit_change) | org_code,org_name,parent_id,org_type,leader_id,effective_date,自定义字段kv | {id} | A,H | org_unit |
| /hrorg/api/org_unit_update.dspy | POST | 编辑组织(留痕) | id,... | {} | A,H | org_unit |
| /hrorg/api/org_unit_move.dspy | POST | 移动组织(变更上级) | id,new_parent_id,effective_date | {} | A,H | — |
| /hrorg/api/org_unit_disable.dspy | POST | 停用组织(校验无在职员工引用) | id | {} | A,H | — |
| /hrorg/api/org_change_timeline.dspy | GET | 组织时间轴 | org_id | {rows:[{change_type,before_json,after_json,operator,created_at}]} | L | — |
| /hrorg/api/org_import.dspy | POST | Excel 批量导入组织(后台任务+结果文件) | file(上传) | {task_id} | A,H | — |
| /hrorg/api/org_import_result.dspy | GET | 导入结果(成功/失败行下载) | task_id | {rows,total,error_file} | A,H | — |
| /hrorg/api/org_chart_export.dspy | GET | 架构图导出(图片/XMind) | as_of?, root_id?, fmt=png/xmind | 文件下载 | A,H | — |
| /hrorg/api/org_field_def_save.dspy | POST | 组织字段自定义 | fields[] | {} | A,H | org_field_def |
| /hrorg/api/job_import.dspy / job_export.dspy | POST/GET | 职务批量导入导出 | file / 筛选条件 | {task_id} / 文件 | A,H | org_job |
| /hrorg/api/position_import.dspy / position_export.dspy | POST/GET | 职位批量导入导出 | file / dept_id?,status? | {task_id} / 文件 | A,H | org_position |
| /hrorg/api/job_options.dspy / position_options.dspy / grade_options.dspy / rank_options.dspy / sequence_options.dspy / org_options.dspy / company_options.dspy | GET | 主数据下拉选项(状态=active;供花名册/异动表单引用) | 无/keyword | {rows:[{id,name}]} | L | org_job 等 |
| /hrorg/api/entry_approval.dspy | POST | 发起入职审批(单个,匹配审批流) | name,id_number,employee_type,org_id,position_id,hire_date,... | {instance_id} 或 BLACKLIST_HIT/FLOW_NOT_MATCH | A,H | org_entry |
| /hrorg/api/entry_manual.dspy | POST | 手动入职(批量,直接入花名册或待入职) | entries[]:{...}, to=pending/roster | {entered:[],pending:[],blocked:[]} | A,H | — |
| /hrorg/api/entry_invite_register.dspy | POST | 邀请待入职填写登记表(站内消息) | entry_ids[] | {} | A,H | — |
| /hrorg/api/entry_register_submit.dspy | POST | 待入职员工提交登记表 | entry_id,字段kv | {} | E(本人) | — |
| /hrorg/api/entry_blacklist_check.dspy | GET | 黑名单校验 | id_number 或 name | {hit:bool,blacklist_id?} | A,H | — |
| /hrorg/api/entry_notify.dspy | POST | 入职通知/欢迎(模板填充发送) | entry_ids[],template_id | {} | A,H | — |
| /hrorg/api/regular_apply.dspy | POST | 发起转正审批(自助/代发) | employee_id,regular_date | {instance_id} | E(自助),H,M | org_regularization |
| /hrorg/api/regular_manual.dspy | POST | 手动转正(直接更新花名册) | employee_id,regular_date | {} | A,H | — |
| /hrorg/api/transfer_apply.dspy | POST | 发起调动审批(支持批量人员) | transfer_type,effective_date,details[]:{employee_id,to_org_id,to_position_id,...} | {instance_id} | A,H,M | org_transfer |
| /hrorg/api/transfer_cancel.dspy | POST | 取消调动(保留历史不改现职) | transfer_id | {} | A,H | — |
| /hrorg/api/leave_apply.dspy | POST | 发起离职审批(自助/代发) | employee_id,leave_type,leave_reason,leave_date | {instance_id} | E(自助),H,M | org_leave |
| /hrorg/api/leave_manual.dspy | POST | 手动离职(直接入待离职/已离职) | employee_id,leave_date,leave_reason | {} | A,H | — |
| /hrorg/api/leave_handover_save.dspy | POST | 离职交接项保存 | leave_id,items[] | {} | A,H,M | org_leave_handover |
| /hrorg/api/leave_certificate.dspy | GET | 离职证明生成下载 | employee_id | 文件 | E(本人),A,H | — |
| /hrorg/api/blacklist_add.dspy | POST | 一键加入黑名单 | leave_id 或 id_number_hash,reason | {} | A,H | org_blacklist |
| /hrorg/api/concurrent_apply.dspy | POST | 发起兼岗审批 | employee_id,org_id,position_id,start_date,end_date | {instance_id} | A,H,M | org_concurrent_post |
| /hrorg/api/workbench_transfer.dspy | GET | 工作台入转调离汇总(经理/管理员视图) | scope=team/all | {entry_n,regular_n,transfer_n,leave_n,rows} | M,H,A | — |
2.2 hr-roster(/hrroster,F03)
| 端点 | 方法 | 功能 | 关键请求参数 | 响应 data | 角色 | CRUD |
|---|---|---|---|---|---|---|
| /hrroster/api/roster_list.dspy | GET | 花名册列表(主表条件分页 + EAV 拼装 + 范围过滤 + 脱敏) | keyword?,org_id?,status?,type?,field_filters?,page,size | {rows,total} | A,H(范围),M(团队) | roster_employee |
| /hrroster/api/roster_employee_create.dspy | POST | 新增员工(自动生成工号、写时间轴) | 主档字段+自定义字段kv | {id,employee_no} | A,H | roster_employee |
| /hrroster/api/roster_employee_update.dspy | POST | 更新员工(含自助修改路径:可改范围+可选审核) | id,字段kv | {} 或 {need_audit:true,instance_id} | A,H,E(本人受限) | roster_employee |
| /hrroster/api/employee_detail.dspy | GET | 员工档案详情(主档+分组字段+兼岗+合同摘要,按角色脱敏/字段可见) | id | {main,groups:[{group_name,fields:[...]}],concurrent,contracts} | L(按范围) | — |
| /hrroster/api/roster_field_def_save.dspy | POST | 字段定义维护(类型/必填/敏感/自助/审核/适用类型/排序) | fields[] | {} | A,H | roster_field_def |
| /hrroster/api/roster_field_group_save.dspy | POST | 分组维护(含拖拽排序持久化) | groups[] | {} | A,H | roster_field_group |
| /hrroster/api/roster_type_rule_save.dspy | POST | 员工类型字段规则 | employee_type,field_rules_json | {} | A,H | roster_type_rule |
| /hrroster/api/empno_rule_save.dspy | POST | 工号规则维护 | rules[] | {} | A,H | roster_empno_rule |
| /hrroster/api/check_employee_no.dspy | GET | 工号查重 | employee_no,exclude_id? | {exists} | A,H | — |
| /hrroster/api/roster_import.dspy | POST | 自定义导入(批量新增/批量修改,模板按当前字段定义生成) | file,mode=new/update | {task_id} | A,H | — |
| /hrroster/api/roster_import_template.dspy | GET | 导入模板下载(按字段定义+类型规则) | employee_type? | 文件 | A,H | — |
| /hrroster/api/roster_export.dspy | GET | 自定义导出(指定数据日期/字段/顺序) | as_of?,field_ids[],filters | {task_id}→文件 | A,H | — |
| /hrroster/api/timeline.dspy | GET | 员工时间轴(全周期记录) | employee_id,event_type? | {rows:[{event_type,event_date,title,content_json}]} | L(按范围) | — |
| /hrroster/api/timeline_add.dspy | POST | 时间轴记录编辑 | employee_id,event_type,event_date,title,content | {} | A,H | — |
| /hrroster/api/file_preview_url.dspy | GET | 附件在线预览 URL(files/ 受控访问) | file_id | {url} | L(按范围) | — |
| /hrroster/api/roster_writeback.dspy | 内部 | 异动回写入口(仅 hr-org/hr-flow 服务内调用,注册于 ServerEnv,不注册 HTTP 路径) | biz_type,biz_id,instance_id | {} | 服务内 | — |
2.3 hr-flow(/hrflow,F10)
| 端点 | 方法 | 功能 | 关键请求参数 | 响应 data | 角色 | CRUD |
|---|---|---|---|---|---|---|
| /hrflow/api/form_def_save.dspy | POST | 表单定义维护(引用花名册字段) | form_code,form_name,biz_type,fields_json | {id} | A,H | flow_form_def |
| /hrflow/api/flow_def_save.dspy | POST | 流程定义(匹配条件、版本) | flow_code,form_id,biz_type,match_cond_json | {id} | A,H | flow_def |
| /hrflow/api/flow_node_save.dspy | POST | 节点维护(审批人/通过规则/字段权限/抄送) | flow_id,nodes[] | {} | A,H | flow_node_def |
| /hrflow/api/flow_role_save.dspy | POST | 审批角色(流程范围/操作权限/数据范围) | role_name,flow_scope_json,op_perm_json,data_scope_json | {id} | A | flow_role |
| /hrflow/api/flow_match.dspy | GET | 按员工类型/部门匹配流程 | biz_type,employee_type,org_id | {flow_id,flow_name} 或 FLOW_NOT_MATCH | 服务内/HR | — |
| /hrflow/api/flow_start.dspy | POST | 发起审批(通用:业务模块统一入口) | biz_type,biz_id,form_data_json | {instance_id,inst_no} | L | — |
| /hrflow/api/task_todo.dspy | GET | 我的待办 | page,size | {rows,total} | L | — |
| /hrflow/api/task_done.dspy | GET | 已办 | page,size | {rows,total} | L | — |
| /hrflow/api/inst_mine.dspy | GET | 我发起的 | status?,page,size | {rows,total} | L | — |
| /hrflow/api/inst_received.dspy | GET | 我收到的(抄送/知会) | page,size | {rows,total} | L | — |
| /hrflow/api/inst_detail.dspy | GET | 审批单详情(表单数据+流转记录+字段权限) | instance_id | {form_data,nodes:[{op,operator,time,comment}],status} | L(参与者) | — |
| /hrflow/api/task_approve.dspy | POST | 同意 | task_id,comment? | {} | L(任务归属) | — |
| /hrflow/api/task_reject.dspy | POST | 驳回 | task_id,comment | {} | L(任务归属) | — |
| /hrflow/api/task_forward.dspy | POST | 转交 | task_id,to_user_id | {} | L(任务归属) | — |
| /hrflow/api/inst_withdraw.dspy | POST | 撤回(发起人,仅首节点未处理) | instance_id | {} | L(发起人) | — |
| /hrflow/api/inst_query.dspy | GET | 审批数据查询(表单/状态/发起人/编号/时间) | form_name?,status?,initiator?,inst_no?,date_range | {rows,total} | A,H | — |
| /hrflow/api/inst_export.dspy | GET | 审批数据导出 | 同上 | 文件 | A,H | — |
| /hrflow/api/inst_print.dspy | GET | 审批单打印视图 | instance_id | 打印 HTML | L(参与者) | — |
2.4 hr-contract(/hrcontract,F09)
| 端点 | 方法 | 功能 | 关键请求参数 | 响应 data | 角色 | CRUD |
|---|---|---|---|---|---|---|
| /hrcontract/api/contract_list.dspy | GET | 合同台账列表(范围过滤) | employee_id?,status?,type_id?,end_before? | {rows,total} | A,H | contract_info |
| /hrcontract/api/contract_create.dspy | POST | 新增合同(模板引用) | employee_id,type_id,company_id,start_date,end_date,file | {id} | A,H | contract_info |
| /hrcontract/api/contract_import.dspy | POST | 批量导入 | file | {task_id} | A,H | — |
| /hrcontract/api/contract_apply.dspy | POST | 合同审批(新签/续签/变更/终止) | contract_id?,biz_type=contract_sign/renew/change/stop,form_data_json | {instance_id} | A,H | — |
| /hrcontract/api/contract_remind_rule_save.dspy | POST | 到期提醒规则 | rule_name,days_before,target_role,content_template | {id} | A,H | contract_remind_rule |
| /hrcontract/api/contract_template_save.dspy | POST | 模板维护 | template_name,type_id,file,field_marks_json | {id} | A,H | contract_template |
| /hrcontract/api/contract_expire_soon.dspy | GET | 即将到期列表(工作台/提醒) | days | {rows} | A,H | — |
| /hrcontract/api/esign_stub.dspy | POST | 电子签预留桩(返回未启用提示) | contract_id | {status:'error',code:'NOT_ENABLED'} | A,H | — |
2.5 hr-report(/hrreport,F13,全部只读)
| 端点 | 方法 | 功能 | 关键请求参数 | 响应 data | 角色 |
|---|---|---|---|---|---|
| /hrreport/api/roster_analysis.dspy | GET | 花名册多维分布(维度可自定义) | dim=type/status/age/edu/location/gender/custom_field_id | {rows:[{dim_value,count}],total} | A,H,M(范围) |
| /hrreport/api/entry_analysis.dspy | GET | 入职数量与趋势 | dim=org/location/position,period=month/quarter | {trend:[],rows:[]} | A,H,M |
| /hrreport/api/regular_analysis.dspy | GET | 转正分析与近期待转正 | period? | {trend:[],upcoming:[]} | A,H,M |
| /hrreport/api/transfer_analysis.dspy | GET | 近期调动分析 | date_range? | {rows:[{type,count}]} | A,H,M |
| /hrreport/api/leave_analysis.dspy | GET | 离职分析(待离职数/原因/离职率/同环比) | period? | {pending_n,reasons:[],rate:{cur,yoy,mom}} | A,H,M |
| /hrreport/api/team_stats.dspy | GET | 团队人事统计(经理工作台卡片) | org_id? | {headcount,entry_n,leave_n,...} | M,H,A |
2.6 hr-system(/hrsystem,F11/F12/F14/F15)
| 端点 | 方法 | 功能 | 关键请求参数 | 响应 data | 角色 | CRUD |
|---|---|---|---|---|---|---|
| /hrsystem/api/role_save.dspy | POST | 管理角色创建与权限设置(rbac 角色+路径) | role_name,paths[] | {id} | A | sys_role(rbac) |
| /hrsystem/api/data_scope_save.dspy | POST | 人员范围(组织维度/花名册字段维度) | admin_user_id,scope_type,org_ids[]/field_ids[] | {} | A | sys_data_scope |
| /hrsystem/api/admin_save.dspy | POST | 管理员管理(创建/调整权限) | user_id,roles[] | {} | A | — |
| /hrsystem/api/get_data_scope.dspy | 内部 | 数据范围查询(ServerEnv 注册,供各模块查询叠加) | user_id | {scope_type,org_ids,field_ids} | 服务内 | — |
| /hrsystem/api/audit_log_list.dspy | GET | 操作日志查询(时间/类型/模块) | module?,operation?,date_range,target? | {rows,total} | A | sys_audit_log |
| /hrsystem/api/audit_log_detail.dspy | GET | 日志详情(前后对比) | id | {before_json,after_json,operator,ip,time} | A | — |
| /hrsystem/api/workbench_employee.dspy | GET | 员工工作台聚合(档案摘要/待办数/可发起流程) | — | {profile,todo_n,flows:[...]} | E | — |
| /hrsystem/api/workbench_manager.dspy | GET | 经理工作台聚合(团队统计/待审批/关怀提醒) | — | {stats,todos:[],care:[...]} | M | — |
| /hrsystem/api/workbench_admin.dspy | GET | 管理员工作台聚合(人事统计/合同到期/提醒) | — | {stats,contracts:[],care:[...]} | A,H | — |
| /hrsystem/api/remind_rule_save.dspy | POST | 通用提醒规则(多场景自定义) | scene_code,rule_name,days_before,content_template,target_role | {id} | A,H | sys_remind_rule |
| /hrsystem/api/care_config_save.dspy | POST | 生日/周年关怀文案配置 | care_type,template,enable | {} | A,H | sys_care_config |
| /hrsystem/api/announcement_save.dspy | POST | 公告发布 | title,content,publish_scope_json | {id} | A,H | sys_announcement |
| /hrsystem/api/policy_save.dspy | POST | 政策发布(查阅范围/下载权限) | title,file,view_scope_json,downloadable | {id} | A,H | sys_policy |
| /hrsystem/api/message_list.dspy | GET | 我的站内消息 | is_read?,msg_type? | {rows,total} | L | — |
| /hrsystem/api/message_read.dspy | POST | 标记已读 | ids[] | {} | L | — |
| /hrsystem/api/remind_scan.dspy | 内部 | 提醒扫描(cron/启动任务:转正/合同/生日等到期扫描推送) | — | {sent_n} | 服务内 | — |
2.7 appbase/rbac 沿用(不自研)
登录/登出、用户管理、字典 appcodes 维护、rbac 角色路径绑定由 appbase/rbac 包自带页面与端点承载(/appbase/*、/rbac/*),迭代1仅在各模块 init/data.json 中初始化字典与角色。
3. 典型调用链示例
3.1 转正审批(F05 流程2)
POST /hrorg/api/regular_apply.dspy{employee_id, regular_date} → hr-org 校验员工状态(probation);- 内部调用
flow_match(biz_type=regular, employee_type, org_id)→POST /hrflow/api/flow_start.dspy{biz_type:'regular', biz_id:regularization_id, form_data_json} → 生成 flow_instance + 首节点 flow_task,发站内消息给审批人; - 审批人
POST /hrflow/api/task_approve.dspy→ 全部节点通过 → flow_instance.inst_status=approved; - hr-flow 完成回调 → hr-org
regular_confirm→ hr-rosterroster_writeback:roster_employee.employee_status=regular、regular_date 更新,写 roster_timeline; - 各步均写 sys_audit_log;转正提醒由
remind_scan按预计日期提前推送管理员与直属主管。
3.2 花名册列表(F03)
GET /hrroster/api/roster_list.dspy?keyword=张&org_id=..&status=regular&page=1&size=50 → 权限校验(数据范围 org_ids/field_ids)→ 主表条件分页 → 值表批量拼装显示字段 → 敏感字段按角色脱敏 → {"status":"success","data":{"rows":[...],"total":N}}。
3.3 入职黑名单拦截(F04)
POST /hrorg/api/entry_approval.dspy → id_number 哈希匹配 org_blacklist → 命中返回 {"status":"error","data":{"code":"BLACKLIST_HIT"}},前端待入职列表高亮标注;手动入职返回 blocked 名单。
4. 与 v1 接口的替代关系(衔接 staff-mgr)
| v1 端点(JWT RESTful) | 迭代1替代 |
|---|---|
| POST /api/v1/staff | /hrorg/api/entry_manual.dspy 或 /hrroster/api/roster_employee_create.dspy |
| GET /api/v1/staff | /hrroster/api/roster_list.dspy(+ CRUD 列表页) |
| GET /api/v1/staff/{id} | /hrroster/api/employee_detail.dspy |
| PUT /api/v1/staff/{id} | /hrroster/api/roster_employee_update.dspy |
| DELETE /api/v1/staff/{id}、batch-delete | 离职流程 /hrorg/api/leave_manual.dspy(迭代1不做删除语义,裁决 Q6) |
| GET /api/v1/staff/{id}/change-logs | /hrroster/api/timeline.dspy |
| GET /api/v1/staff/audit-logs | /hrsystem/api/audit_log_list.dspy |
| GET /api/v1/staff/check/employee-no | /hrroster/api/check_employee_no.dspy |
| GET /api/v1/staff/departments | /hrorg/api/org_tree.dspy |
5. 安全设计要点
- 所有路径 load_path.py 注册;未注册即拒绝(含 .css/.js 静态资源)。
- 敏感字段(身份证全角色脱敏前3后3;手机前3后4;职级/薪资类字段仅 admin/hr)由 roster_field_def.sensitive + 角色矩阵驱动,服务端脱敏后返回。
- 全部 SQL 经 sqlor 绑定参数(
${var}$占位),禁止拼接用户输入。 - 审批操作校验任务归属人;员工自助类接口校验本人(或白名单字段)。
- 导入导出、登录、权限变更全量写 sys_audit_log(含 IP)。