39 KiB
39 KiB
一期批次1总体设计 —— 数据库设计(hr-web,ocai 口径)
- 版本:v3.0(批次1设计定稿;v3.0 变更:对齐 SRS v3.1 —— 库名 hrs/MariaDB、新增编制(F16)/项目式(F17) 5 张表与 sys_openapp 预留表(43→49 张)、roster_employee 证件字段扩展(D1 手工录入)、org_entry 登记链接/二维码字段(扫码入职降级)、org_leave_handover 钉钉交接占位、字典扩充)
- 状态:设计定稿(批次1评审修订版)
- 需求基线:
docs/00-requirement/requirement-spec.md(SRS v3.1)+iteration1-function-detail.md(F01F15)+ approved-features.md(FEAT-B1-0112) - 架构基线:
docs/01-design/architecture.md - 规范依据:ocai 技能集 database-table-definition-spec(models/*.json + json2ddl)、crud-definition-spec、sqlor-database-module
1. 设计总则
- 表定义声明式管理:所有表以
models/{table}.json(summary/fields/indexes/codes 四段)定义,build.sh 中json2ddl mysql . > mysql.ddl.sql生成 DDL 导入 hrs 库。本文 DDL 为生成物等价示例,开发以 models JSON 为准。 - 统一约定:InnoDB;utf8mb4 / utf8mb4_unicode_ci;数据库 MariaDB,库名
hrs;主键id VARCHAR(32)(getID() 雪花串,sqlor 惯例);公共审计列created_by/updated_by/created_at/updated_at;sor.C不自动填时间戳,写入时显式created_at=curDateString()。 - 逻辑删除策略:员工与组织不做物理删除,统一走"停用(status=inactive)/离职流程";物理删除仅 admin 可执行且必须留审计(SRS §5.2-2)。
- 自定义字段(EAV):花名册字段(F03)与组织字段(F01)采用"字段定义表 + 字段值表"EAV 方案;固定高频查询字段(组织、职位、状态、入离职日期)冗余在员工主表保证列表性能。
- 敏感字段:身份证号密文列 + 哈希列(确定性哈希,供唯一性与黑名单匹配),手机号明文存储、按角色脱敏展示;
roster_field_def.sensitive驱动字段级脱敏与可见性(SRS §2.2-4)。 - 库划分:单库
hrs,表前缀区分模块:org_(hr-org)、roster_(hr-roster)、flow_(hr-flow)、contract_(hr-contract)、sys_(hr-system);appbase(users/orgs/appcodes)与 rbac 表沿用基础包自带结构,不在本文重复。 - 预留字段约定:二期对接预留字段一律带明确默认值与字典枚举位(如 esign_status='not_enabled'、id_source='manual'、send_channel='site'),不参与一期业务分支。
2. ER 图(实体关系描述)
┌──────────────┐
│ appbase │
│ users/orgs/ │◄── 登录用户、字典 appcodes
│ appcodes │
└──────┬───────┘
│ user_id 引用
┌─────────────┐ parent_id │ ┌──────────────────┐
│ org_unit │◄─自引用──────┼──────│ sys_data_scope │ 组织维度数据范围
│ 组织 │ │ │ sys_audit_log │ 操作日志(F12)
└──┬───┬──────┘ │ │ sys_message │ 站内消息(F15)
│ │org_field_value │ │ sys_remind_rule │ 提醒规则
│ ▼ │ │ sys_openapp │ API开放预留
│ org_field_def │ └────────▲─────────┘
│ │ │ 推送
│ ┌─────────────┐ ┌─────▼───────────────┴───┐
│ │org_job/ │ │ roster_employee │ 员工唯一事实源(F03)
│ │org_position◄─┼──│ org_id/position_id/ │
│ │org_sequence/ │ │ employee_status/证件字段组│
│ │org_grade_* │ └──┬──────┬──────┬─────────┘
│ └─────────────┘ │ │ │
│ │ │ ▼
│ roster_field_def◄────┘ roster_field_value(EAV)
│ roster_field_group roster_timeline(时间轴)
│ │
│ 异动业务(hr-org) │ 合同(hr-contract)
│ org_entry ──────────┤ contract_info ── employee_id
│ org_regularization ─┼──► contract_type / contract_template
│ org_transfer(+detail)│ contract_remind_rule
│ org_leave(+handover) │ │审批
│ org_concurrent_post │ ▼
│ org_headcount_scheme │ ┌──────────────┐
│ └ headcount_item │ │ flow_def │ 流程定义
│ └ headcount_snapshot│ │ flow_form_def│ 表单定义(引用花名册字段)
│ org_project(F17) │ │ flow_node_def│ 节点(审批人/字段权限)
│ └ org_project_post │ │ flow_role │ 审批角色
│ │审批流转 │ │ flow_instance│ 实例 ──► flow_task(待办)
└────────┴──────────────┴────►│ │ └► flow_op_log
biz_type+biz_id └──────────────┘
hr-report 无自有表:只读聚合 org_/roster_/flow_ 表,叠加 sys_data_scope 范围过滤。
核心关系说明:
roster_employee为全系统员工数据唯一事实源;org_entry/regularization/transfer/leave/concurrent_post通过employee_id(入职审批阶段可为空)关联,审批通过后经 hr-rosterroster_writeback更新主档。- 所有审批类记录通过
flow_instance_id关联流程实例;flow_instance.biz_type + biz_id反向定位业务单据,流程完成后回调业务模块回写。 - 编制(F16):
org_headcount_scheme1─Nheadcount_item(细分额度);headcount_snapshot按日快照历史;员工异动回写后同步触发占编重算。占编范围条件以 JSON 表达(员工类型/状态/职位/职级/自定义字段),与 roster_employee + roster_field_value 联查计数。 - 项目式组织(F17):
org_project为横向组织(自引用多层级),员工经org_project_post同时挂纵向部门(roster_employee.org_id)与横向项目;横向职务体系复用 org_job 表(org_job.job_category=horizontal 区分,被花名册/薪酬引用)。 - 所有表与 appbase.users 之间为逻辑外键(operator_id/leader_id/approver_id),不建物理外键(sqlor 惯例,跨模块解耦)。
3. models JSON 示例(规范格式,json2ddl 输入)
hr-roster/models/roster_employee.json(含 D1 证件字段组扩展):
{
"summary": [
{"name": "roster_employee", "title": "员工主档", "pk": ["id"], "charset": "utf8mb4", "collate": "utf8mb4_unicode_ci"}
],
"fields": [
{"name": "id", "title": "主键", "type": "varchar", "length": 32},
{"name": "employee_no", "title": "工号", "type": "varchar", "length": 32},
{"name": "name", "title": "姓名", "type": "varchar", "length": 64},
{"name": "gender", "title": "性别", "type": "varchar", "length": 16},
{"name": "id_type", "title": "证件类型", "type": "varchar", "length": 16, "default": "id_card"},
{"name": "id_number_cipher", "title": "证件号密文", "type": "varchar", "length": 256},
{"name": "id_number_hash", "title": "证件号哈希", "type": "varchar", "length": 64},
{"name": "id_valid_from", "title": "证件有效期起", "type": "date"},
{"name": "id_valid_to", "title": "证件有效期止(长期=9999-12-31)", "type": "date"},
{"name": "id_authority", "title": "证件签发机关", "type": "varchar", "length": 128},
{"name": "id_source", "title": "证件信息来源", "type": "varchar", "length": 16, "default": "manual"},
{"name": "birthday", "title": "出生日期", "type": "date"},
{"name": "phone", "title": "手机号", "type": "varchar", "length": 20},
{"name": "email", "title": "邮箱", "type": "varchar", "length": 128},
{"name": "org_id", "title": "组织", "type": "varchar", "length": 32},
{"name": "position_id", "title": "职位", "type": "varchar", "length": 32},
{"name": "job_id", "title": "职务", "type": "varchar", "length": 32},
{"name": "grade_level_id", "title": "职级", "type": "varchar", "length": 32},
{"name": "grade_rank_id", "title": "职等", "type": "varchar", "length": 32},
{"name": "sequence_id", "title": "序列", "type": "varchar", "length": 32},
{"name": "employee_type", "title": "员工类型", "type": "varchar", "length": 16},
{"name": "employee_status", "title": "员工状态", "type": "varchar", "length": 16},
{"name": "hire_date", "title": "入职日期", "type": "date"},
{"name": "probation_end_date", "title": "试用期止(预计转正日)", "type": "date"},
{"name": "regular_date", "title": "转正日期", "type": "date"},
{"name": "leave_date", "title": "离职日期", "type": "date"},
{"name": "company_id", "title": "合同公司", "type": "varchar", "length": 32},
{"name": "work_location", "title": "办公地点", "type": "varchar", "length": 128},
{"name": "direct_leader_id", "title": "直属主管", "type": "varchar", "length": 32},
{"name": "prev_employee_id", "title": "复职关联原档案ID", "type": "varchar", "length": 32},
{"name": "remark", "title": "备注", "type": "text"},
{"name": "created_by", "title": "创建人", "type": "varchar", "length": 32},
{"name": "updated_by", "title": "更新人", "type": "varchar", "length": 32},
{"name": "created_at", "title": "创建时间", "type": "timestamp"},
{"name": "updated_at", "title": "更新时间", "type": "timestamp"}
],
"indexes": [
{"name": "uk_employee_no", "unique": true, "fields": ["employee_no"]},
{"name": "uk_id_number_hash", "unique": true, "fields": ["id_number_hash"]},
{"name": "idx_org_id", "fields": ["org_id"]},
{"name": "idx_status", "fields": ["employee_status"]},
{"name": "idx_hire_date", "fields": ["hire_date"]},
{"name": "idx_probation_end", "fields": ["probation_end_date"]},
{"name": "idx_direct_leader", "fields": ["direct_leader_id"]},
{"name": "idx_prev_employee", "fields": ["prev_employee_id"]}
],
"codes": [
{"name": "gender", "source": "appcodes", "code": "GENDER"},
{"name": "employee_type", "source": "appcodes", "code": "EMP_TYPE"},
{"name": "employee_status", "source": "appcodes", "code": "EMP_STATUS"},
{"name": "id_source", "source": "appcodes", "code": "ID_SOURCE"}
]
}
CRUD 侧配套 hr-roster/json/roster_employee_list.json(crud-definition-spec):tblname=roster_employee,params 顶层配置 new_data_url/update_data_url/delete_data_url 指向 wwwroot/api/roster_employee_{create,update,delete}.dspy,data_filter 声明姓名/工号/组织/状态筛选项,browserfields.alters 引用 GENDER/EMP_TYPE/EMP_STATUS 字典。
4. 表结构设计(49 张业务表)
公共列约定:凡标【审计】的表均含
created_by/updated_by/created_at/updated_at;日志/快照类表仅含created_at。DDL 示例见 §5。 v3.0 变化:hr-org 18→23(+编制 3 表+项目式 2 表)、hr-system 7→8(+sys_openapp 预留)、roster_employee/org_entry/org_leave_handover 字段扩展;合计 49 张。
4.1 hr-org 组织人事(23 张,前缀 org_)
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 1 | org_unit | 组织(F01) | id, org_code, org_name, parent_id(自引用), org_type(字典ORG_TYPE), leader_id, effective_date, expire_date(空=长期), status(active/inactive), sort_no【审计】 | uk_org_code; idx_parent_id; idx_status |
| 2 | org_unit_change | 组织变更时间轴(F01) | id, org_id, change_type(add/edit/disable/move/split/merge/delete), before_json, after_json, effective_date, operator_id, flow_instance_id, created_at | idx_org_id; idx_created_at |
| 3 | org_field_def | 组织自定义字段(F01) | id, field_code, field_name, field_type(text/number/date/select/file), options_json, required, sort_no, status【审计】 | uk_field_code |
| 4 | org_field_value | 组织字段值 EAV | id, org_id, field_id, value_text, value_date, value_file, updated_at | uk(org_id,field_id) |
| 5 | org_job | 职务(F02/F17) | id, job_code, job_name, job_category(vertical/horizontal,F17 横向职务), status, sort_no, remark【审计】 | uk_job_code; idx_job_category |
| 6 | org_position | 职位(F02) | id, position_code, position_name, job_id, sequence_id, category(字典POS_CATEGORY), dept_ids(多值,逗号分隔), description, status, sort_no【审计】 | uk_position_code; idx_job_id |
| 7 | org_sequence | 序列(F02) | id, seq_category, seq_name, grade_level_ids(关联职级类别), status【审计】 | — |
| 8 | org_grade_level | 职级(F02) | id, level_code, level_name, level_category, start_rank_id, end_rank_id, sort_no【审计】 | uk_level_code |
| 9 | org_grade_rank | 职等(F02) | id, rank_code, rank_name, rank_level(int), sort_no【审计】 | uk_rank_code |
| 10 | org_blacklist | 黑名单(F04/F07) | id, name, id_number_hash, id_number_cipher, reason, source(leave/manual), source_employee_id, created_by, created_at | idx_id_number_hash |
| 11 | org_contract_company | 合同公司(F01/F09) | id, company_code, company_name, credit_code(统一社会信用代码), legal_person, contact_info, status【审计】 | uk_company_code |
| 12 | org_entry | 入职记录(F04) | id, employee_id(可空,待入职), name, id_type, id_number_cipher/hash, id_valid_from/id_valid_to/id_authority/id_source(手工录入 D1), employee_type, org_id, position_id, company_id, work_location, hire_date, entry_status(pending_approval/pending_entry/entered/cancelled/blocked), is_rehire, register_status(none/invited/filled), register_token, register_url, qrcode_file, register_expire(登记链接/二维码,扫码入职降级), flow_instance_id, remark【审计】 | idx_entry_status; idx_hire_date; idx_flow_instance_id; uk_register_token |
| 13 | org_regularization | 转正记录(F05) | id, employee_id, probation_end_date, regular_date, apply_type(self/proxy/manual), status(pending/approved/rejected/cancelled), flow_instance_id, remark【审计】 | idx_employee_id; idx_regular_date |
| 14 | org_transfer | 调动单(F06,支持批量) | id, transfer_type(promotion/demotion/position_change/org_adjust), status(pending/confirmed/cancelled), effective_date, batch_no, flow_instance_id, remark【审计】 | idx_status; idx_effective_date |
| 15 | org_transfer_detail | 调动明细(逐人) | id, transfer_id, employee_id, from_org_id, to_org_id, from_position_id, to_position_id, from_grade_level_id, to_grade_level_id, status | idx_transfer_id; idx_employee_id |
| 16 | org_leave | 离职记录(F07) | id, employee_id, leave_type(辞职/劝退/合同到期/退休), leave_reason(字典LEAVE_REASON), leave_date, apply_type(self/proxy/manual), status(pending_leave/left/cancelled), handover_status, certificate_file, blacklist_flag, flow_instance_id, remark【审计】 | idx_employee_id; idx_status; idx_leave_date |
| 17 | org_leave_handover | 离职交接项 | id, leave_id, item_type(approval/file/subordinate/permission/dingtalk_resource(钉钉资源交接占位,D3)/other), item_content, handover_to_id, status(pending/done), remark | idx_leave_id |
| 18 | org_concurrent_post | 兼岗(F08) | id, employee_id, org_id, position_id, start_date, end_date, status(awaiting/active/expired), flow_instance_id【审计】 | idx_employee_id; idx_status |
| 19 | org_headcount_scheme | 编制方案(F16) | id, scheme_name, cycle_type(year/quarter/month,字典HEADCOUNT_CYCLE), cycle_start, cycle_end, status(active/inactive), remark【审计】 | idx_cycle(cycle_start,cycle_end); idx_status |
| 20 | headcount_item | 编制细分项(F16) | id, scheme_id, scope_json(占编范围:员工类型/状态/职位/职级/自定义字段条件), seg_json(细分维度,可空=整体), head_limit(int), remark【审计】 | idx_scheme_id |
| 21 | headcount_snapshot | 编制快照(F16 历史回溯/实时计数) | id, scheme_id, item_id, snap_date, used_count(int), over_count(int,超编数), created_at | uk(scheme_id,item_id,snap_date); idx_snap_date |
| 22 | org_project | 项目式组织(F17) | id, project_code, project_name, parent_id(自引用多层级), owner_id(负责人), start_date, end_date, project_status(active/expired/inactive), attrs_json(项目属性), sort_no【审计】 | uk_project_code; idx_parent_id; idx_project_status |
| 23 | org_project_post | 项目任职(F17 员工挂横向组织) | id, project_id, employee_id, job_id(横向职务,引用 org_job job_category=horizontal), start_date, end_date, status(active/expired)【审计】 | uk(project_id,employee_id,job_id,start_date); idx_employee_id |
4.2 hr-roster 花名册(7 张,前缀 roster_)
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 24 | roster_field_group | 字段分组(F03) | id, group_code, group_name(工作信息/个人信息/绩效结果/培训记录), sort_no, status【审计】 | uk_group_code |
| 25 | roster_field_def | 字段定义(F03 核心) | id, group_id, field_code, field_name, field_type(text/number/date/select/multiselect/file), options_json(字典code或自定义项), required, sensitive(0/1), editable_self(0/1), need_audit(0/1自助修改审核), apply_types(JSON适用员工类型), sort_no, status【审计】 | uk_field_code; idx_group_id |
| 26 | roster_employee | 员工主档(F03) | 见 §3 models 示例(含证件字段组/probation_end_date/prev_employee_id) | 见 §3 |
| 27 | roster_field_value | 字段值 EAV | id, employee_id, field_id, value_text, value_number(decimal(18,4)), value_date, value_file, updated_by, updated_at | uk(employee_id,field_id); idx_field_id |
| 28 | roster_empno_rule | 工号规则(F03) | id, rule_name, prefix, match_field(如company_id), match_value, seq_length, current_seq(int), status【审计】 | — |
| 29 | roster_timeline | 员工时间轴(F03/F12 联动) | id, employee_id, event_type(entry/regular/transfer/leave/concurrent/contract/field_change/headcount/project/migrate), event_date, title, content_json, source_type, source_id, created_at | idx_emp_date(employee_id,event_date) |
| 30 | roster_type_rule | 员工类型字段规则(F03 分类管理) | id, employee_type, field_rules_json(按类型必填/隐藏字段), status【审计】 | uk(employee_type) |
4.3 hr-flow 流程审批(7 张,前缀 flow_)
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 31 | flow_form_def | 表单定义(F10) | id, form_code, form_name, biz_type(entry/regular/transfer/leave/handover/concurrent/contract_sign/contract_renew/contract_change/contract_stop/roster_self_edit/attendance_*桩位), fields_json(引用roster_field_def或自定义项), status【审计】 | uk_form_code |
| 32 | flow_def | 流程定义(F10) | id, flow_code, flow_name, form_id, biz_type, match_cond_json(员工类型/部门匹配条件), version, status【审计】 | uk_flow_code; idx_biz_type |
| 33 | flow_node_def | 流程节点 | id, flow_id, node_seq, node_name, approver_type(user/role/leader/admin/flow_role), approver_value, pass_rule(any/all), field_perm_json(节点字段可读写), cc_to(抄送) | idx_flow_id |
| 34 | flow_role | 审批角色(F10) | id, role_name, flow_scope_json(可用流程), op_perm_json(操作权限), data_scope_json(数据查看范围), status【审计】 | — |
| 35 | flow_instance | 流程实例 | id, inst_no(审批编号), flow_id, form_id, biz_type, biz_id, title, initiator_id, inst_status(running/approved/rejected/cancelled), submit_data_json, start_time, finish_time | uk_inst_no; idx_biz(biz_type,biz_id); idx_initiator; idx_status |
| 36 | flow_task | 审批任务(待办/已办) | id, instance_id, node_id, node_name, approver_id, task_status(pending/approved/rejected/forwarded/cancelled), comment, handle_time, created_at | idx_approver_status(approver_id,task_status); idx_instance |
| 37 | flow_op_log | 流转日志 | id, instance_id, op_type(submit/approve/reject/forward/cancel/withdraw), operator_id, comment, created_at | idx_instance |
4.4 hr-contract 合同(4 张,前缀 contract_)
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 38 | contract_type | 合同类型(F09 自定义) | id, type_code, type_name(劳动合同/保密协议/竞业协议…), status【审计】 | uk_type_code |
| 39 | contract_template | 合同模板(F09) | id, template_name, type_id, file_path, field_marks_json(占位符映射), status【审计】 | — |
| 40 | contract_info | 合同台账(F09) | id, contract_no, employee_id, type_id, company_id, template_id, start_date, end_date, sign_date, contract_status(active/expired/stopped/renewing), file_path, text_file_path(模板生成合同文本,D4), flow_instance_id, remind_rule_id, esign_status(not_enabled/待二期流转,D4), remark【审计】 | idx_employee; idx_end_date; idx_status |
| 41 | contract_remind_rule | 到期提醒规则(F09) | id, rule_name, days_before(int), target_role(self/leader/hr), content_template, status【审计】 | — |
4.5 hr-system 权限日志与通用服务(8 张,前缀 sys_)
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 42 | sys_data_scope | 数据范围(F11) | id, admin_user_id(管理员), scope_type(org/field), org_ids_json(组织维度,含子树), field_ids_json(花名册字段维度), remark【审计】 | idx_admin_user |
| 43 | sys_audit_log | 操作日志(F12,只增不改) | id, module, target_type, target_id, operation(create/update/delete/import/export/approve/login/migrate), operator_id, operator_name, before_json, after_json, request_ip, created_at | idx_target(target_type,target_id); idx_operator; idx_created_at; idx_module_op(module,operation) |
| 44 | sys_message | 站内消息(F15) | id, receiver_id, msg_type(todo/approval/remind/care/notice), title, content, biz_type, biz_id, send_channel(site; sms/email预留 D9), is_read, created_at | idx_receiver_read(receiver_id,is_read); idx_created_at |
| 45 | sys_remind_rule | 通用提醒规则(F15 多场景) | id, scene_code(entry/regular/leave/retire/contract_expire/health_cert/social_insurance/custom), rule_name, days_before, content_template, target_role(admin/employee/leader), status【审计】 | uk(scene_code,rule_name) |
| 46 | sys_announcement | 企业公告(F15) | id, title, content, publish_scope_json, publish_time, status(draft/published/offline), created_by【审计】 | idx_status |
| 47 | sys_policy | 企业政策(F15) | id, title, file_path, view_scope_json, downloadable(0/1), publish_time, status, created_by【审计】 | idx_status |
| 48 | sys_care_config | 关怀配置(F15 生日/周年) | id, care_type(birthday/anniversary), template, enable(0/1), push_target(employee/leader), updated_by, updated_at | uk_care_type |
| 49 | sys_openapp | API 开放应用(一期预留,FEAT-B1-01⑦) | id, app_key, app_secret_cipher, app_name, scope_json(授权资源), rate_limit(int), status(active/inactive)【审计】 | uk_app_key |
5. 核心表 DDL 示例(json2ddl 生成等价物)
-- roster_employee(完整字段见 §3 models JSON;此处为等价 DDL 含证件字段组)
CREATE TABLE roster_employee (
id VARCHAR(32) NOT NULL COMMENT '主键',
employee_no VARCHAR(32) NOT NULL COMMENT '工号',
name VARCHAR(64) NOT NULL COMMENT '姓名',
gender VARCHAR(16) DEFAULT NULL COMMENT '性别(字典GENDER)',
id_type VARCHAR(16) DEFAULT 'id_card' COMMENT '证件类型',
id_number_cipher VARCHAR(256) DEFAULT NULL COMMENT '证件号密文',
id_number_hash VARCHAR(64) DEFAULT NULL COMMENT '证件号哈希(唯一)',
id_valid_from DATE DEFAULT NULL COMMENT '证件有效期起',
id_valid_to DATE DEFAULT NULL COMMENT '证件有效期止(长期=9999-12-31)',
id_authority VARCHAR(128) DEFAULT NULL COMMENT '证件签发机关',
id_source VARCHAR(16) DEFAULT 'manual' COMMENT '证件来源(字典ID_SOURCE: manual/card_reader预留)',
birthday DATE DEFAULT NULL,
phone VARCHAR(20) DEFAULT NULL,
email VARCHAR(128) DEFAULT NULL,
org_id VARCHAR(32) DEFAULT NULL COMMENT '组织',
position_id VARCHAR(32) DEFAULT NULL COMMENT '职位',
job_id VARCHAR(32) DEFAULT NULL COMMENT '职务',
grade_level_id VARCHAR(32) DEFAULT NULL COMMENT '职级',
grade_rank_id VARCHAR(32) DEFAULT NULL COMMENT '职等',
sequence_id VARCHAR(32) DEFAULT NULL COMMENT '序列',
employee_type VARCHAR(16) DEFAULT NULL COMMENT '员工类型(字典EMP_TYPE)',
employee_status VARCHAR(16) DEFAULT NULL COMMENT '状态(字典EMP_STATUS)',
hire_date DATE DEFAULT NULL,
probation_end_date DATE DEFAULT NULL COMMENT '试用期止(预计转正日,转正提醒依据)',
regular_date DATE DEFAULT NULL,
leave_date DATE DEFAULT NULL,
company_id VARCHAR(32) DEFAULT NULL COMMENT '合同公司',
work_location VARCHAR(128) DEFAULT NULL,
direct_leader_id VARCHAR(32) DEFAULT NULL COMMENT '直属主管',
prev_employee_id VARCHAR(32) DEFAULT NULL COMMENT '复职关联原档案ID(F04-5)',
remark TEXT DEFAULT NULL,
created_by VARCHAR(32) DEFAULT NULL, updated_by VARCHAR(32) DEFAULT NULL,
created_at TIMESTAMP NULL DEFAULT NULL, updated_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_employee_no (employee_no),
UNIQUE KEY uk_id_number_hash (id_number_hash),
KEY idx_org_id (org_id),
KEY idx_status (employee_status),
KEY idx_hire_date (hire_date),
KEY idx_probation_end (probation_end_date),
KEY idx_direct_leader (direct_leader_id),
KEY idx_prev_employee (prev_employee_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='员工主档';
CREATE TABLE org_unit (
id VARCHAR(32) NOT NULL,
org_code VARCHAR(32) NOT NULL COMMENT '组织编码',
org_name VARCHAR(128) NOT NULL COMMENT '组织名称',
parent_id VARCHAR(32) DEFAULT NULL COMMENT '上级组织',
org_type VARCHAR(16) DEFAULT NULL COMMENT '组织类型(字典ORG_TYPE)',
leader_id VARCHAR(32) DEFAULT NULL COMMENT '负责人',
effective_date DATE DEFAULT NULL COMMENT '生效日期',
expire_date DATE DEFAULT NULL COMMENT '失效日期(空=长期)',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT 'active/inactive',
sort_no INT DEFAULT 0,
remark TEXT DEFAULT NULL,
created_by VARCHAR(32) DEFAULT NULL, updated_by VARCHAR(32) DEFAULT NULL,
created_at TIMESTAMP NULL DEFAULT NULL, updated_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_org_code (org_code),
KEY idx_parent_id (parent_id),
KEY idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='组织';
CREATE TABLE flow_instance (
id VARCHAR(32) NOT NULL,
inst_no VARCHAR(32) NOT NULL COMMENT '审批编号',
flow_id VARCHAR(32) NOT NULL, form_id VARCHAR(32) NOT NULL,
biz_type VARCHAR(32) NOT NULL COMMENT '业务类型(字典FLOW_BIZ_TYPE)',
biz_id VARCHAR(32) DEFAULT NULL COMMENT '业务单据ID',
title VARCHAR(256) DEFAULT NULL,
initiator_id VARCHAR(32) NOT NULL,
inst_status VARCHAR(16) NOT NULL DEFAULT 'running' COMMENT 'running/approved/rejected/cancelled',
submit_data_json TEXT DEFAULT NULL COMMENT '提交表单数据快照',
start_time TIMESTAMP NULL DEFAULT NULL, finish_time TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_inst_no (inst_no),
KEY idx_biz (biz_type, biz_id),
KEY idx_initiator (initiator_id),
KEY idx_status (inst_status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='流程实例';
CREATE TABLE sys_audit_log (
id VARCHAR(32) NOT NULL,
module VARCHAR(32) NOT NULL COMMENT 'hr-org/hr-roster/...',
target_type VARCHAR(32) NOT NULL COMMENT 'roster_employee/org_unit/...',
target_id VARCHAR(32) NOT NULL,
operation VARCHAR(16) NOT NULL COMMENT 'create/update/delete/import/export/approve/login/migrate',
operator_id VARCHAR(32) NOT NULL, operator_name VARCHAR(64) DEFAULT '',
before_json TEXT DEFAULT NULL COMMENT '变更前快照',
after_json TEXT DEFAULT NULL COMMENT '变更后快照',
request_ip VARCHAR(64) DEFAULT NULL,
created_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_target (target_type, target_id),
KEY idx_operator (operator_id),
KEY idx_created_at (created_at),
KEY idx_module_op (module, operation)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='操作日志(只增)';
-- F16 编制管理(新增)
CREATE TABLE org_headcount_scheme (
id VARCHAR(32) NOT NULL,
scheme_name VARCHAR(128) NOT NULL COMMENT '方案名称',
cycle_type VARCHAR(16) NOT NULL COMMENT '周期(字典HEADCOUNT_CYCLE: year/quarter/month)',
cycle_start DATE NOT NULL, cycle_end DATE NOT NULL,
status VARCHAR(16) NOT NULL DEFAULT 'active',
remark TEXT DEFAULT NULL,
created_by VARCHAR(32) DEFAULT NULL, updated_by VARCHAR(32) DEFAULT NULL,
created_at TIMESTAMP NULL DEFAULT NULL, updated_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_cycle (cycle_start, cycle_end),
KEY idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='编制方案';
CREATE TABLE headcount_item (
id VARCHAR(32) NOT NULL,
scheme_id VARCHAR(32) NOT NULL COMMENT '编制方案',
scope_json TEXT NOT NULL COMMENT '占编范围条件(员工类型/状态/职位/职级/自定义字段)',
seg_json TEXT DEFAULT NULL COMMENT '细分维度(空=整体)',
head_limit INT NOT NULL DEFAULT 0 COMMENT '编制数量',
remark TEXT DEFAULT NULL,
created_by VARCHAR(32) DEFAULT NULL, updated_by VARCHAR(32) DEFAULT NULL,
created_at TIMESTAMP NULL DEFAULT NULL, updated_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_scheme_id (scheme_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='编制细分项';
CREATE TABLE headcount_snapshot (
id VARCHAR(32) NOT NULL,
scheme_id VARCHAR(32) NOT NULL,
item_id VARCHAR(32) NOT NULL COMMENT '细分项',
snap_date DATE NOT NULL COMMENT '快照日期',
used_count INT NOT NULL DEFAULT 0 COMMENT '占编人数',
over_count INT NOT NULL DEFAULT 0 COMMENT '超编数(0=未超编)',
created_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_scheme_item_date (scheme_id, item_id, snap_date),
KEY idx_snap_date (snap_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='编制快照(历史回溯)';
-- F17 项目式组织(新增)
CREATE TABLE org_project (
id VARCHAR(32) NOT NULL,
project_code VARCHAR(32) NOT NULL COMMENT '项目编码',
project_name VARCHAR(128) NOT NULL COMMENT '项目名称',
parent_id VARCHAR(32) DEFAULT NULL COMMENT '上级项目(多层级)',
owner_id VARCHAR(32) DEFAULT NULL COMMENT '负责人',
start_date DATE DEFAULT NULL, end_date DATE DEFAULT NULL COMMENT '时间范围',
project_status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT 'active/expired/inactive(到期自动标识)',
attrs_json TEXT DEFAULT NULL COMMENT '项目属性',
sort_no INT DEFAULT 0,
created_by VARCHAR(32) DEFAULT NULL, updated_by VARCHAR(32) DEFAULT NULL,
created_at TIMESTAMP NULL DEFAULT NULL, updated_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_project_code (project_code),
KEY idx_parent_id (parent_id),
KEY idx_project_status (project_status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='项目式组织';
CREATE TABLE org_project_post (
id VARCHAR(32) NOT NULL,
project_id VARCHAR(32) NOT NULL COMMENT '项目组织',
employee_id VARCHAR(32) NOT NULL COMMENT '员工',
job_id VARCHAR(32) DEFAULT NULL COMMENT '横向职务(org_job.job_category=horizontal)',
start_date DATE DEFAULT NULL, end_date DATE DEFAULT NULL,
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT 'active/expired',
created_by VARCHAR(32) DEFAULT NULL, updated_by VARCHAR(32) DEFAULT NULL,
created_at TIMESTAMP NULL DEFAULT NULL, updated_at TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_proj_emp_job (project_id, employee_id, job_id, start_date),
KEY idx_employee_id (employee_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='项目任职(横向)';
6. 索引与性能策略
- 100 人规模全表扫描亦可满足 ≤500ms,但仍按查询模式建索引:列表筛选列(status/org_id/hire_date/end_date)、EAV 值表 uk(employee_id,field_id)、待办 idx(approver_id,task_status)、转正提醒 idx(probation_end_date)。
- 组织树、职位职级主数据一次性全量加载(≤200/≤500 行),前端缓存,无需分页。
- EAV 查询模式:花名册列表先按主表条件分页取员工,再批量
IN查值表拼装(每页 ≤50 人 × 显示字段数),避免 EAV 行转列大 JOIN。 - 报表(hr-report)直接 SQL 聚合(sor.sqlExe 只读),100 人规模不建物化视图,满足"延迟 ≤5 分钟"(实为实时);sys_audit_log 按月保留,冷数据归档不删除。
- 编制计数:headcount_snapshot 以"异动事件触发 + 每日兜底扫描"双机制维护;实时查询取最新 snap_date,历史回溯按 snap_date 精确取数(F16 验收③)。
- 唯一性:工号、组织编码、项目编码、职位/职务/职级/职等编码、审批编号、登记表 token 均唯一索引;证件号经哈希列唯一(密文为非确定性加密,哈希列承担唯一性与黑名单匹配)。
7. 数据字典(appbase appcodes,init/data.json 初始化)
| code | 值 | 说明 |
|---|---|---|
| GENDER | male/female/unknown | 性别 |
| ORG_TYPE | group/subsidiary/dept/team | 组织类型 |
| EMP_TYPE | formal/temp/dispatch/intern | 员工类型(正式/临时/派遣/实习) |
| EMP_STATUS | pending_entry/probation/regular/pending_leave/left | 员工状态(待入职/试用/正式/待离职/离职) |
| ID_TYPE | id_card/passport/other | 证件类型 |
| ID_SOURCE | manual/card_reader(预留,二期) | 证件信息来源(D1) |
| POS_CATEGORY | management/professional/skill | 职位类别 |
| JOB_CATEGORY | vertical/horizontal | 职务类别(F17 横向职务) |
| TRANSFER_TYPE | promotion/demotion/position_change/org_adjust | 调动类型 |
| LEAVE_REASON | personal/company/contract_expire/retire/other | 离职原因 |
| HANDOVER_TYPE | approval/file/subordinate/permission/dingtalk_resource(占位)/other | 离职交接项类型(D3) |
| CONTRACT_STATUS | active/expired/stopped/renewing | 合同状态 |
| ESIGN_STATUS | not_enabled/signing/signed(后两者二期启用) | 电子签状态(D4 预留) |
| FLOW_BIZ_TYPE | entry/regular/transfer/leave/handover/concurrent/contract_sign/contract_renew/contract_change/contract_stop/roster_self_edit/attendance_*(桩位) | 审批业务类型 |
| INST_STATUS | running/approved/rejected/cancelled | 实例状态 |
| REMIND_SCENE | entry/regular/leave/retire/contract_expire/health_cert/social_insurance/custom | 提醒场景(≥6 类,F15 验收④) |
| HEADCOUNT_CYCLE | year/quarter/month | 编制周期(F16) |
| PROJECT_STATUS | active/expired/inactive | 项目状态(F17,到期自动 expired) |
| MSG_CHANNEL | site/sms(预留)/email(预留) | 消息渠道(D9) |
| AUDIT_OP | create/update/delete/import/export/approve/login/migrate | 操作类型 |
| ENTRY_STATUS | pending_approval/pending_entry/entered/cancelled/blocked | 入职状态 |
| REGISTER_STATUS | none/invited/filled | 登记表状态 |
枚举一律不硬编码于 dspy;CRUD 下拉经 models codes 段引用。
8. staff-mgr 数据迁移策略(v1 → 一期,NFR-8)
迁移工具:repos/hr-system 仓内规划 scripts/migrate_staff_mgr.py(Python + sqlor,幂等可重跑,输出核对报告:总数一致 + 抽样字段一致)。
| v1 源表(staff-mgr) | 目标表 | 映射规则 |
|---|---|---|
| staff_department_cache | org_unit | 按树形重建 parent_id;org_code=DEPT{id};status 映射 active/inactive |
| staff_employee | roster_employee | employee_no/name/gender/phone/email 直映;id_number AES 解密后按新方案重加密(cipher+hash),id_source='manual',证件有效期/签发机关置空待补;department_id→org_id;position 文本→预置 org_position(无匹配则建"未定职");status: active→regular、probation→probation、inactive→left;hire_date 直映 |
| staff_employee_extra | roster_field_value + contract_info | education/major/school/graduation_date/previous_company/work_years → 预置 roster_field_def 字段值;technical_level/salary_grade → 预置敏感字段值;contract_type/start/end → contract_info(type_id 映射正式/外包/实习协议) |
| staff_change_log | roster_timeline | change_type→event_type(transfer/field_change),old/new 值入 content_json,event_type 前缀 migrate: 标识迁移来源 |
| staff_audit_log | sys_audit_log | 字段直映,module 标记 staff-mgr-legacy |
策略与约束:
- 顺序:org_unit → org_position(预置)→ roster_field_def/group(预置)→ roster_employee → roster_field_value → contract_info → timeline/audit。
- 幂等:按 employee_no/org_code 去重,重跑仅补差;证件号哈希冲突时输出冲突报告人工裁决(冲突员工按离职记录保留,不入在职)。
- 范围:默认"在职 + 离职保留档案"全量;仅迁在职/含历史的最终范围与切换时间点待 PM 确认(SRS §11-Q3),脚本参数
--scope=active|all支持两种口径。 - 切换:UAT 通过后一次性迁移+双库比对 → staff-mgr 服务下线、仓库冻结只读(保留一个迭代周期)。
- 迁移全程写 sys_audit_log(operation=migrate),迁移数据在时间轴/日志中可辨识。
9. 与需求验收项的映射(摘选)
| 验收项 | 数据支撑 |
|---|---|
| F01-4 时间轴留痕 | org_unit_change |
| F01-5 历史架构图 | org_unit.effective_date/expire_date + org_unit_change 回放 |
| F02-1~5 五套体系 | org_job/position/sequence/grade_level/grade_rank |
| F03-1/2 自定义字段与分组 | roster_field_def/group/value |
| F03-3 多规则工号 | roster_empno_rule |
| F03-4 自助修改审核 | roster_field_def.editable_self/need_audit + flow biz_type=roster_self_edit |
| F03-6 类型差异规则 | roster_type_rule + apply_types |
| F04-4 身份证手工录入(D1) | roster_employee/org_entry 证件字段组 + id_source='manual' |
| F04-5 复职 | roster_employee.prev_employee_id |
| F04-6 黑名单拦截 | org_blacklist(id_number_hash 匹配) |
| F05-3 转正提醒 | roster_employee.probation_end_date + sys_remind_rule(scene=regular) |
| F07-3 钉钉交接占位(D3) | org_leave_handover.item_type=dingtalk_resource |
| F07-5 离职证明 | org_leave.certificate_file(files/ 存储) |
| F09-6 电子签预留(D4) | contract_info.esign_status + contract_template.text_file_path |
| F10-2 字段权限 | flow_node_def.field_perm_json |
| F11-2 双维度数据范围 | sys_data_scope(scope_type=org/field) |
| F12-3 前后对比 | sys_audit_log.before_json/after_json |
| F13-6 报表数据范围受控 | 聚合查询叠加 sys_data_scope |
| F15-4 多场景提醒(≥6 类) | sys_remind_rule(scene_code) + REMIND_SCENE 字典 |
| F16-1~6 编制 | org_headcount_scheme/headcount_item/headcount_snapshot |
| F17-1~3 项目式组织 | org_project/org_project_post + org_job(job_category=horizontal) |
| FEAT-B1-01⑦ API 开放预留 | sys_openapp(一期不启用) |