28 KiB
28 KiB
迭代1总体设计 —— 数据库设计(hr-web,ocai 口径)
- 版本:v2.0(迭代1-总体设计,取代 v1 Java/JPA 口径,v1 已归档至
docs/_archive/01-design-v1-old/) - 状态:评审通过(主agent评审,基线冻结)
- 需求基线:
docs/00-requirement/requirement-spec.md(SRS v2)+iteration1-function-detail.md(F01~F15) - 架构基线:
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 导入hr库。本文 DDL 为生成物等价示例,开发以 models JSON 为准。 - 统一约定:InnoDB;utf8mb4 / utf8mb4_unicode_ci;主键
id VARCHAR(32)(getID() 雪花串,sqlor 惯例);公共审计列created_by/updated_by/created_at/updated_at;sor.C不自动填时间戳,写入时显式created_at=curDateString()。 - 逻辑删除策略:迭代1员工与组织不做物理删除,统一走"停用(status=inactive)/离职流程"(对 baseline-decision Q6 的裁决落地)。
- 自定义字段(EAV):花名册字段(F03)与组织字段(F01)采用"字段定义表 + 字段值表"EAV 方案,支撑字段/分组/类型规则自定义;固定高频查询字段(组织、职位、状态、入离职日期)冗余在员工主表保证列表性能。
- 敏感字段:身份证号密文列 + 哈希列(确定性,供唯一性与黑名单匹配),手机号明文存储、按角色脱敏展示;
roster_field_def.sensitive驱动字段级脱敏与可见性。 - 库划分:单库
hr,表前缀区分模块:org_(hr-org)、roster_(hr-roster)、flow_(hr-flow)、contract_(hr-contract)、sys_(hr-system);appbase(users/orgs/appcodes)与 rbac 表沿用基础包自带结构,不在本文重复。
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 │ 提醒规则
│ ▼ │ └────────▲─────────┘
│ 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 │ ▼
│ │审批流转 │ ┌──────────────┐
└────────┴──────────────┴────►│ flow_def │ 流程定义
biz_type+biz_id │ flow_form_def│ 表单定义(引用花名册字段)
│ flow_node_def│ 节点(审批人/字段权限)
│ flow_role │ 审批角色
│ flow_instance│ 实例 ──► flow_task(待办)
│ │ └► flow_op_log
└──────────────┘
hr-report 无自有表:只读聚合 org_/roster_/flow_ 表,叠加 sys_data_scope 范围过滤。
核心关系说明:
roster_employee为全系统员工数据唯一事实源;org_entry/regularization/transfer/leave/concurrent_post通过employee_id(入职审批阶段可为空)关联,审批通过后经 hr-roster 回写接口更新主档。- 所有审批类记录通过
flow_instance_id关联流程实例;flow_instance.biz_type + biz_id反向定位业务单据,流程完成后回调业务模块回写。 roster_field_value/org_field_value为 EAV 值表,外键指向roster_field_def/org_field_def。- 所有表与 appbase.users 之间为逻辑外键(operator_id/leader_id/approver_id),不建物理外键(sqlor 惯例,跨模块解耦)。
3. models JSON 示例(规范格式,json2ddl 输入)
hr-roster/models/roster_employee.json:
{
"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_number_cipher", "title": "证件号密文", "type": "varchar", "length": 256},
{"name": "id_number_hash", "title": "证件号哈希", "type": "varchar", "length": 64},
{"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": "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": "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_direct_leader", "fields": ["direct_leader_id"]}
],
"codes": [
{"name": "gender", "source": "appcodes", "code": "GENDER"},
{"name": "employee_type", "source": "appcodes", "code": "EMP_TYPE"},
{"name": "employee_status", "source": "appcodes", "code": "EMP_STATUS"}
]
}
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. 表结构设计(43 张业务表)
公共列约定:凡标【审计】的表均含
created_by/updated_by/created_at/updated_at;日志类表仅含created_at。DDL 示例见 §4.6。
4.1 hr-org 组织人事(18 张,前缀 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) | id, job_code, job_name, status, sort_no, remark【审计】 | uk_job_code |
| 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_number_cipher/hash, 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(登记表填写状态), flow_instance_id, remark【审计】 | idx_entry_status; idx_hire_date; idx_flow_instance_id |
| 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/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 |
4.2 hr-roster 花名册(7 张,前缀 roster_)
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 19 | roster_field_group | 字段分组(F03) | id, group_code, group_name(工作信息/个人信息/绩效结果/培训记录), sort_no, status【审计】 | uk_group_code |
| 20 | 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 |
| 21 | roster_employee | 员工主档(F03) | 见 §3 models 示例 | 见 §3 |
| 22 | 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 |
| 23 | roster_empno_rule | 工号规则(F03) | id, rule_name, prefix, match_field(如company_id), match_value, seq_length, current_seq(int), status【审计】 | — |
| 24 | roster_timeline | 员工时间轴(F03/F12 联动) | id, employee_id, event_type(entry/regular/transfer/leave/concurrent/contract/field_change/migrate), event_date, title, content_json, source_type, source_id, created_at | idx_emp_date(employee_id,event_date) |
| 25 | roster_type_rule | 员工类型字段规则(F03 分类管理) | id, employee_type, field_rules_json(按类型必填/隐藏字段), status【审计】 | uk(employee_type) |
4.3 hr-flow 流程审批(7 张,前缀 flow_)
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 26 | 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), fields_json(引用roster_field_def或自定义项), status【审计】 | uk_form_code |
| 27 | flow_def | 流程定义(F10) | id, flow_code, flow_name, form_id, biz_type, match_cond_json(员工类型/部门匹配条件), version, status【审计】 | uk_flow_code; idx_biz_type |
| 28 | 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 |
| 29 | flow_role | 审批角色(F10) | id, role_name, flow_scope_json(可用流程), op_perm_json(操作权限), data_scope_json(数据查看范围), status【审计】 | — |
| 30 | 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 |
| 31 | 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 |
| 32 | 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_)
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 33 | contract_type | 合同类型(F09 自定义) | id, type_code, type_name(劳动合同/保密协议/竞业协议…), status【审计】 | uk_type_code |
| 34 | contract_template | 合同模板(F09) | id, template_name, type_id, file_path, field_marks_json(占位符映射), status【审计】 | — |
| 35 | 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, flow_instance_id, remind_rule_id, esign_status(预留), remark【审计】 | idx_employee; idx_end_date; idx_status |
| 36 | contract_remind_rule | 到期提醒规则(F09) | id, rule_name, days_before(int), target_role(self/leader/hr), content_template, status【审计】 | — |
4.5 hr-system 权限日志与通用服务(7 张,前缀 sys_)
| # | 表 | 用途 | 关键字段 | 关键索引 |
|---|---|---|---|---|
| 37 | sys_data_scope | 数据范围(F11) | id, admin_user_id(管理员), scope_type(org/field), org_ids_json(组织维度,含子树), field_ids_json(花名册字段维度), remark【审计】 | idx_admin_user |
| 38 | sys_audit_log | 操作日志(F12,只增不改) | id, module, target_type, target_id, operation(create/update/delete/import/export/approve/login), 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) |
| 39 | sys_message | 站内消息(F15) | id, receiver_id, msg_type(todo/approval/remind/care/notice), title, content, biz_type, biz_id, send_channel(site; sms/email预留), is_read, created_at | idx_receiver_read(receiver_id,is_read); idx_created_at |
| 40 | sys_remind_rule | 通用提醒规则(F12 场景) | 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) |
| 41 | sys_announcement | 企业公告(F15) | id, title, content, publish_scope_json, publish_time, status(draft/published/offline), created_by【审计】 | idx_status |
| 42 | sys_policy | 企业政策(F15) | id, title, file_path, view_scope_json, downloadable(0/1), publish_time, status, created_by【审计】 | idx_status |
| 43 | sys_care_config | 关怀配置(F15 生日/周年) | id, care_type(birthday/anniversary), template, enable(0/1), push_target(employee/leader), updated_by, updated_at | uk_care_type |
4.6 核心表 DDL 示例(json2ddl 生成等价物)
-- roster_employee(完整 DDL 见 §3 models JSON)
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_number_cipher VARCHAR(256) DEFAULT NULL COMMENT '证件号密文',
id_number_hash VARCHAR(64) DEFAULT NULL COMMENT '证件号哈希(唯一)',
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,
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 '直属主管',
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_direct_leader (direct_leader_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 '业务类型', 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',
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='操作日志(只增)';
5. 索引与性能策略
- 100 人规模全表扫描亦可满足 ≤500ms,但仍按查询模式建索引:列表筛选列(status/org_id/hire_date/end_date)、EAV 值表 uk(employee_id,field_id)、待办 idx(approver_id,task_status)。
- 组织树、职位职级主数据一次性全量加载(≤200/≤500 行),前端缓存,无需分页。
- EAV 查询模式:花名册列表先按主表条件分页取员工,再批量
IN查值表拼装(每页 ≤50 人 × 显示字段数),避免 EAV 行转列大 JOIN。 - 报表(hr-report)直接 SQL 聚合(sor.sqlExe 只读),100 人规模不建物化视图;sys_audit_log 按月保留,冷数据归档不删除。
- 唯一性:工号、组织编码、职位/职务/职级/职等编码、审批编号均唯一索引;证件号经哈希列唯一(加密为非确定性,哈希列承担唯一与黑名单匹配)。
6. 数据字典(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 | 员工状态(待入职/试用/正式/待离职/离职) |
| POS_CATEGORY | management/professional/skill | 职位类别 |
| TRANSFER_TYPE | promotion/demotion/position_change/org_adjust | 调动类型 |
| LEAVE_REASON | personal/company/contract_expire/retire/other | 离职原因 |
| CONTRACT_STATUS | active/expired/stopped/renewing | 合同状态 |
| FLOW_BIZ_TYPE | entry/regular/transfer/leave/handover/concurrent/contract_sign/contract_renew/contract_change/contract_stop/roster_self_edit | 审批业务类型 |
| INST_STATUS | running/approved/rejected/cancelled | 实例状态 |
| REMIND_SCENE | entry/regular/leave/retire/contract_expire/health_cert/social_insurance/custom | 提醒场景 |
| AUDIT_OP | create/update/delete/import/export/approve/login | 操作类型 |
枚举一律不硬编码于 dspy;CRUD 下拉经 models codes 段引用。
7. staff-mgr 数据迁移策略(v1 → 迭代1)
迁移工具: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);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 去重,重跑仅补差;证件号哈希冲突时输出冲突报告人工裁决(对 baseline-decision Q6:冲突员工按离职记录保留,不入在职)。
- 切换:迭代1 UAT 通过后一次性迁移+双库比对 → staff-mgr 服务下线、仓库冻结只读(保留一个迭代周期)。
- 迁移全程写 sys_audit_log(operation=migrate),迁移数据在时间轴/日志中可辨识。
8. 与需求验收项的映射(摘选)
| 验收项(function-detail) | 数据支撑 |
|---|---|
| F01-4 时间轴留痕 | org_unit_change |
| 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 黑名单拦截 | org_blacklist(id_number_hash 匹配) |
| F07-5 离职证明 | org_leave.certificate_file(files/ 存储) |
| F09-6 电子签预留 | contract_info.esign_status |
| 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 |
| F15-4 多场景提醒 | sys_remind_rule(scene_code) |