Files
xiaotutongxue/backend/xt-server/src/main/resources/db/migration/V10__dict.sql
T
lovife 7090ee7d65 feat(ops): 操作日志留痕、字典管理、名册改删(V9 / V10)
PRD FR-506/FR-1202 的 P0 项:V9 给 sys_operation_log 补 target_type/target_id/
before_val/after_val,OperationLogService 显式留痕并统一强制脱敏;
已接入的敏感动作:名册改证件号/改名/删名册项、任务发布/暂停/恢复/截止/归档。

F-32 的教训落地:动作名由调用方显式给,不从 (原状态, 新状态) 反推——
「发布」与「恢复」都是 →收集中,反推必然把 resume 记成 PUBLISH_TASK。

字典:内置字典写在代码里(DictCatalog),库里只存客户自定义项与内置项停用开关,
两表分开才能「一键恢复默认」;表单下拉与字典共用同一份口径(BuiltinFields 加访问器)。

验证:e2e-m5-logs 44/44、e2e-m1-dict 53/53。
2026-09-30 09:02:53 +08:00

79 lines
4.5 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- ============================================================================
-- V10:数据字典(《03-接口设计》§13.3)
--
-- 为什么内置字典**不进这张表**
-- ---------------------------------------------------------------------------
-- 契约 §13.3 把字典分成两类,而这个区分是刻意的:
--
-- · **内置字典**(`builtin: true`):EDU_LEVEL / JOB_LEVEL / CERT_TYPE /
-- RETARGET_SUBJECT / REJECT_REASON 五项。它们的选项**照抄官方表格**,
-- 不许擅改(`BuiltinFields` 的类注释里写了这条)。所以它们定义在**代码里** ——
-- 和权限码同样的思路:能改的放库里,不能改的放代码里,改它必须走一次发布。
-- 放进表里会带来一个具体风险:有人从界面上把"四级/中级工"改名成"中级",
-- 导出的汇总表就与官方模板对不上了,而那时没有任何地方会报错。
--
-- · **可维护的字典**:客户填表时遇到的内置项不够用(例如多了个"技校"学历),
-- 由管理员自己加。这类进 `sys_dict_item` —— 它们**允许**被改,
-- 因为它们是客户自己的口径,不是官方的。
--
-- OCCUPATION(职业/工种)是第三种情况:它**来自 `sys_occupation_ref`**
-- (国标职业库,有自己的层级与别名),既不进代码也不进这张表。
-- 三处来源的取舍都写在 `DictCatalog` 的注释里。
-- ============================================================================
-- 自定义字典项(含对内置字典的"追加")
CREATE TABLE IF NOT EXISTS sys_dict_item (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
-- 字典码,如 EDU_LEVEL / JOB_LEVEL / CERT_TYPE
dict_code VARCHAR(64) NOT NULL,
item_code VARCHAR(64) NOT NULL,
item_name VARCHAR(128) NOT NULL,
-- 层级(如职业-工种):指向同字典内另一个 item_code
parent_item_code VARCHAR(64),
sort_no INTEGER NOT NULL DEFAULT 0,
-- 0 停用 / 1 启用
status SMALLINT NOT NULL DEFAULT 1,
-- true = 这个项是对**内置字典**的追加(内置项本身仍在代码里)
builtin_extend SMALLINT NOT NULL DEFAULT 0,
create_by BIGINT,
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_by BIGINT,
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted SMALLINT NOT NULL DEFAULT 0
);
COMMENT ON TABLE sys_dict_item IS '自定义字典项(内置字典的选项在代码里,见 DictCatalog;OCCUPATION 来自 sys_occupation_ref)';
COMMENT ON COLUMN sys_dict_item.dict_code IS '字典码:EDU_LEVEL/JOB_LEVEL/CERT_TYPE/RETARGET_SUBJECT/REJECT_REASON/OCCUPATION + 客户自定义';
COMMENT ON COLUMN sys_dict_item.item_code IS '项码。⚠️ **不许改**(改了会破坏历史数据里已经存下的值)';
COMMENT ON COLUMN sys_dict_item.parent_item_code IS '层级父项(如职业-工种);空表示顶层';
COMMENT ON COLUMN sys_dict_item.builtin_extend IS '1 = 对内置字典的追加项(内置项本身不出来在这里)';
-- 同一个字典里项码唯一(软删的不算)—— 手工建一条部分唯一索引:
-- 普通 UNIQUE 会把软删的行也算进去,于是"删过再想加回来"会失败,
-- 而用户看到的是"这个编码已存在",但他明明刚删掉它
CREATE UNIQUE INDEX IF NOT EXISTS uk_dict_item_code
ON sys_dict_item (tenant_id, dict_code, item_code)
WHERE deleted = 0;
CREATE INDEX IF NOT EXISTS idx_dict_item_code
ON sys_dict_item (tenant_id, dict_code, status, sort_no);
-- 内置字典的"停用单项"(契约 §13.3:内置字典不可删,只可停用单项)。
-- ⚠️ 不复用 sys_dict_item.status:那张表是"客户自己加的项",
-- 而这里是"官方项被客户停用了"。混在一起之后,
-- "恢复默认"就没法做了(分不清哪些是官方项、哪些是客户加的)。
CREATE TABLE IF NOT EXISTS sys_dict_disabled (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
dict_code VARCHAR(64) NOT NULL,
item_code VARCHAR(64) NOT NULL,
create_by BIGINT,
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
COMMENT ON TABLE sys_dict_disabled IS '被停用的**内置**字典项(契约 §13.3:内置字典不可删、只可停用单项)';
CREATE UNIQUE INDEX IF NOT EXISTS uk_dict_disabled
ON sys_dict_disabled (tenant_id, dict_code, item_code);