7523ebe789
补上发布前置校验的最后一环(40019),同时确立任务的数据隔离边界 ——
班主任能看到哪些任务、能审哪些单子,全由 collect_task_org 决定。
后端 GET/PUT /tasks/{id}/orgs(整体替换语义 + 软移除 + 历史行复用);
前端「配置班级」抽屉:组织树只允许勾选班级,主班主任留空时显式提示
「将由该班负责人初审」而非留白。发布被拦时给出「去哪里补」的指引
(BLOCKING_HINTS),而不是只说"未设置覆盖班级"。
三条守住的规则:
1) 班级与初审人都必须在本租户内。跨租户的 id 一律当作"不存在或已删除",
不透露"它存在但不属于你" —— 漏了的后果是 A 校能把 B 校的班挂到自己
的任务上,B 校的班主任就出现在 A 校的审批流里。
2) 初审人必须持有班主任/副班主任角色。指定初审人本质上是一次授权,
那个人将能看到该班学生的身份证号与学籍材料;不校验角色就等于把
"谁能看学生隐私"变成任意授权。报错要给出下一步,不能只说"校验失败"。
3) 移除是软移除(status=0),且「移除再加回」必须复用原行。
后者不是优化而是必须:uk_task_org UNIQUE (task_id, org_id) 不带 status
条件,一个班在同一任务下只能有一行,直接 insert 会违反唯一约束。
本轮修掉的 3 个真问题:
1) 我此前误判 uk_task_org 不存在 —— grep 只匹配含表名的行,而
CONSTRAINT uk_task_org UNIQUE (task_id, org_id) 那行没有表名。
基于这个错误前提,我写了一个多余的部分唯一索引 uk_task_org_active
和一段基于错误前提的代码,已全部撤掉并更正注释。
教训:查约束要看 CREATE TABLE 整块,不能只 grep 表名。
2) collect_task_org.expected_count 是 NOT NULL DEFAULT 0,与接口契约矛盾:
DDL 注释说它是"由名册汇总"(系统算的),但《03-接口设计》§7.6 把它放在
PUT 请求体里、说"用于与名册实际人数比对" —— 只有"管理员填的期望值 vs
名册实际值"才需要比对。而 0 是有意义的业务值("预期 0 人"),拿它兼职
表示"没填"会让每个没填的班都触发"应填 0 人、实际 31 人"的假告警;告警
变噪音就没人看了,真正"应填 28、名册却有 31"(名册导错)反而被漏掉,
而这条告警的全部价值就在那一次。已由 V4 迁移改为可空 + 去掉默认值,
并同步更正 docs/db/schema-postgresql.sql 与 PRD 里的内联 DDL。
3) 删掉迁移文件后必须 mvn clean,否则它会"复活":我只跑 mvn package,
target/classes 里的旧副本被打进 jar,Flyway 发现历史里没有 v4 就又执行
了一遍 —— 索引回来了、历史行填回去了。之后又建了同名版本号的新 V4,
于是"两个 v4"→"checksum 冲突",排查绕了好几圈。
顺带修掉:
· 任务列表操作列从 3 个链接涨到 4 个,160px 会挤成竖排 —— 把「进度」并进
「状态」列腾出 40px,操作列给到 200px,合计 820px(可用约 824px)。
· defineEmits 必须用函数调用签名(frontend-pc/.agents/skills/code-vue)。
我此前写的 5 个组件都是被禁的 tuple 形式,一并改正:
OrgFormModal / TaskFormModal / TaskOrgDrawer / UserFormModal / UserImportModal。
· e2e-m1-orgs.py 的清理抽成幂等的 cleanup_all(),并在 __main__ 的 finally
里兜一次 —— 该脚本首次运行时崩在准备阶段、清理段没执行,把两个测试账号
留在了库里(是在浏览器里看到下拉框里有个「E2E班主任」才发现的)。
其余三条 E2E 脚本仍是老样子,下一轮一并改。
验收:e2e-m1-orgs.py 48/48(含跨租户隔离);e2e-m1-task.py 71/71、
e2e-m0-user.py 55/55、e2e-m0.py 36/36 回归通过,共 210 项断言;
前端 typecheck / eslint / lint:style 0 错、build 通过;
浏览器实测抽屉的开合、树的勾选规则与保存落库。
713 lines
37 KiB
SQL
713 lines
37 KiB
SQL
-- ============ 1) 建表 ============
|
||
|
||
CREATE TABLE sys_tenant (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_code varchar(32) NOT NULL,
|
||
tenant_name varchar(128) NOT NULL,
|
||
tenant_type smallint NOT NULL DEFAULT 1,
|
||
contact_name varchar(64),
|
||
contact_phone varchar(128),
|
||
package_id bigint,
|
||
expire_time timestamp,
|
||
status smallint NOT NULL DEFAULT 1,
|
||
logo_url varchar(512),
|
||
config_json jsonb,
|
||
create_by bigint,
|
||
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
update_by bigint,
|
||
update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
deleted smallint DEFAULT 0 NOT NULL,
|
||
PRIMARY KEY (id),
|
||
CONSTRAINT uk_tenant_code UNIQUE (tenant_code)
|
||
);
|
||
COMMENT ON TABLE sys_tenant IS '租户';
|
||
COMMENT ON COLUMN sys_tenant.id IS '租户ID';
|
||
COMMENT ON COLUMN sys_tenant.tenant_code IS '租户编码(短码,用于小程序扫码识别)';
|
||
COMMENT ON COLUMN sys_tenant.tenant_name IS '租户名称(学校/机构)';
|
||
COMMENT ON COLUMN sys_tenant.tenant_type IS '1学校 2认定机构 3报名点 4企业';
|
||
COMMENT ON COLUMN sys_tenant.contact_name IS '联系人';
|
||
COMMENT ON COLUMN sys_tenant.contact_phone IS '联系电话(AES加密存储;varchar(128)容纳密文,非明文长度)';
|
||
COMMENT ON COLUMN sys_tenant.package_id IS '套餐ID';
|
||
COMMENT ON COLUMN sys_tenant.expire_time IS '到期时间';
|
||
COMMENT ON COLUMN sys_tenant.status IS '0停用 1正常 2试用';
|
||
COMMENT ON COLUMN sys_tenant.logo_url IS 'Logo';
|
||
COMMENT ON COLUMN sys_tenant.config_json IS '租户配置(默认压缩参数/文件保留天数等)';
|
||
|
||
CREATE TABLE sys_org (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
parent_id bigint NOT NULL DEFAULT 0,
|
||
org_name varchar(128) NOT NULL,
|
||
org_type smallint NOT NULL DEFAULT 3,
|
||
org_code varchar(64),
|
||
ancestor_path varchar(512),
|
||
leader_user_id bigint,
|
||
sort_no integer NOT NULL DEFAULT 0,
|
||
status smallint NOT NULL DEFAULT 1,
|
||
create_by bigint,
|
||
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
update_by bigint,
|
||
update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
deleted smallint DEFAULT 0 NOT NULL,
|
||
PRIMARY KEY (id)
|
||
);
|
||
CREATE INDEX idx_tenant_parent ON sys_org (tenant_id, parent_id);
|
||
CREATE INDEX idx_tenant_name ON sys_org (tenant_id, org_name);
|
||
COMMENT ON TABLE sys_org IS '组织架构';
|
||
COMMENT ON COLUMN sys_org.parent_id IS '父级ID,0为根';
|
||
COMMENT ON COLUMN sys_org.org_name IS '组织名称,如 24中技数控1班';
|
||
COMMENT ON COLUMN sys_org.org_type IS '1学校 2院系/专业 3班级 4报名点';
|
||
COMMENT ON COLUMN sys_org.org_code IS '组织编码/班号';
|
||
COMMENT ON COLUMN sys_org.ancestor_path IS '祖先路径,如 0,1,5';
|
||
COMMENT ON COLUMN sys_org.leader_user_id IS '负责人(班主任)';
|
||
|
||
CREATE TABLE sys_occupation_ref (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
parent_id bigint NOT NULL DEFAULT 0,
|
||
name varchar(128) NOT NULL,
|
||
aliases varchar(512),
|
||
has_child smallint NOT NULL DEFAULT 0,
|
||
status smallint NOT NULL DEFAULT 1,
|
||
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id)
|
||
);
|
||
CREATE INDEX idx_parent ON sys_occupation_ref (parent_id);
|
||
CREATE INDEX idx_occref_name ON sys_occupation_ref (name);
|
||
COMMENT ON TABLE sys_occupation_ref IS '职业工种参考字典(仅拼写校验,非约束)';
|
||
COMMENT ON COLUMN sys_occupation_ref.parent_id IS '0=职业; 非0=该职业下的工种';
|
||
COMMENT ON COLUMN sys_occupation_ref.aliases IS '常见错写/别名,用于纠错提示';
|
||
COMMENT ON COLUMN sys_occupation_ref.has_child IS '该职业是否有工种';
|
||
|
||
CREATE TABLE sys_user (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL DEFAULT 0,
|
||
org_id bigint,
|
||
username varchar(64) NOT NULL,
|
||
password varchar(128),
|
||
real_name varchar(64) NOT NULL,
|
||
phone varchar(128),
|
||
phone_hash char(64),
|
||
open_id varchar(64),
|
||
union_id varchar(64),
|
||
id_card_no varchar(128),
|
||
id_card_hash char(64),
|
||
avatar_url varchar(512),
|
||
user_type smallint NOT NULL DEFAULT 1,
|
||
status smallint NOT NULL DEFAULT 1,
|
||
last_login_time timestamp,
|
||
create_by bigint,
|
||
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
update_by bigint,
|
||
update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
deleted smallint DEFAULT 0 NOT NULL,
|
||
PRIMARY KEY (id),
|
||
CONSTRAINT uk_tenant_username UNIQUE (tenant_id, username)
|
||
);
|
||
CREATE INDEX idx_phone_hash ON sys_user (phone_hash);
|
||
CREATE INDEX idx_idcard_hash ON sys_user (id_card_hash);
|
||
CREATE INDEX idx_openid ON sys_user (open_id);
|
||
COMMENT ON TABLE sys_user IS '用户';
|
||
COMMENT ON COLUMN sys_user.tenant_id IS '0=平台运营';
|
||
COMMENT ON COLUMN sys_user.org_id IS '所属组织';
|
||
COMMENT ON COLUMN sys_user.username IS '登录名(教师)';
|
||
COMMENT ON COLUMN sys_user.password IS 'BCrypt';
|
||
COMMENT ON COLUMN sys_user.phone IS '手机号(AES加密存储;varchar(128)容纳密文,非明文长度)';
|
||
COMMENT ON COLUMN sys_user.phone_hash IS '手机号HMAC,用于唯一检索';
|
||
COMMENT ON COLUMN sys_user.open_id IS '微信openid';
|
||
COMMENT ON COLUMN sys_user.id_card_no IS '证件号(AES加密存储)';
|
||
COMMENT ON COLUMN sys_user.id_card_hash IS '证件号HMAC,用于比对与去重';
|
||
COMMENT ON COLUMN sys_user.user_type IS '1平台运营 2学校管理员 3班主任 4学生(口径见 03-接口设计 §2.7)';
|
||
COMMENT ON COLUMN sys_user.status IS '0停用 1正常 2待激活';
|
||
|
||
CREATE TABLE collect_task (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
task_code varchar(64) NOT NULL,
|
||
task_name varchar(200) NOT NULL,
|
||
collect_mode smallint NOT NULL DEFAULT 1,
|
||
batch_no varchar(64),
|
||
major_name varchar(64),
|
||
job_name varchar(64),
|
||
job_level varchar(32),
|
||
cert_type smallint NOT NULL DEFAULT 1,
|
||
start_time timestamp,
|
||
end_time timestamp,
|
||
audit_config jsonb,
|
||
naming_template varchar(256) NOT NULL DEFAULT '{姓名}-{证件号}-{材料名}',
|
||
compress_config jsonb,
|
||
roster_required smallint NOT NULL DEFAULT 1,
|
||
status smallint NOT NULL DEFAULT 0,
|
||
published_time timestamp,
|
||
create_by bigint,
|
||
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
update_by bigint,
|
||
update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
deleted smallint DEFAULT 0 NOT NULL,
|
||
PRIMARY KEY (id),
|
||
CONSTRAINT uk_task_tenant_code UNIQUE (tenant_id, task_code)
|
||
);
|
||
CREATE INDEX idx_tenant_status ON collect_task (tenant_id, status);
|
||
CREATE INDEX idx_end_time ON collect_task (end_time);
|
||
COMMENT ON TABLE collect_task IS '收集任务';
|
||
COMMENT ON COLUMN collect_task.task_code IS '任务编码,用于文件路径';
|
||
COMMENT ON COLUMN collect_task.task_name IS '如 2026年9月机电专业认定材料收集';
|
||
COMMENT ON COLUMN collect_task.collect_mode IS '1学校收集 2社会收集';
|
||
COMMENT ON COLUMN collect_task.batch_no IS '批次号';
|
||
COMMENT ON COLUMN collect_task.major_name IS '专业';
|
||
COMMENT ON COLUMN collect_task.job_name IS '报考工种';
|
||
COMMENT ON COLUMN collect_task.job_level IS '报考等级';
|
||
COMMENT ON COLUMN collect_task.cert_type IS '1自主认定 2社会评价 3专项职业能力';
|
||
COMMENT ON COLUMN collect_task.end_time IS '截止时间';
|
||
COMMENT ON COLUMN collect_task.audit_config IS '审核流配置,见6.5';
|
||
COMMENT ON COLUMN collect_task.compress_config IS '任务级压缩默认参数';
|
||
COMMENT ON COLUMN collect_task.roster_required IS '是否需要名册: 固定为1,两种收集模式都必填(名单门禁)';
|
||
COMMENT ON COLUMN collect_task.status IS '0草稿 1收集中 2已截止 3已归档 4暂停';
|
||
|
||
CREATE TABLE collect_task_org (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
task_id bigint NOT NULL,
|
||
org_id bigint NOT NULL,
|
||
head_user_id bigint,
|
||
deputy_user_ids varchar(256),
|
||
expected_count integer,
|
||
status smallint NOT NULL DEFAULT 1,
|
||
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
CONSTRAINT uk_task_org UNIQUE (task_id, org_id)
|
||
);
|
||
CREATE INDEX idx_tenant_head ON collect_task_org (tenant_id, head_user_id);
|
||
COMMENT ON TABLE collect_task_org IS '任务覆盖组织与审核人绑定';
|
||
COMMENT ON COLUMN collect_task_org.head_user_id IS '该班初审人(班主任),为空则取 sys_org.leader_user_id';
|
||
COMMENT ON COLUMN collect_task_org.deputy_user_ids IS '副班主任/协办人,逗号分隔';
|
||
COMMENT ON COLUMN collect_task_org.expected_count IS '应填人数(期望值,管理员填写,可空);仅在与名册实际人数不一致时告警。NULL 表示未设置,与 0(预期 0 人)含义不同';
|
||
COMMENT ON COLUMN collect_task_org.status IS '0已移除 1生效';
|
||
|
||
CREATE TABLE collect_form_schema (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
task_id bigint NOT NULL,
|
||
version integer NOT NULL DEFAULT 1,
|
||
schema_json jsonb NOT NULL,
|
||
is_current smallint NOT NULL DEFAULT 1,
|
||
create_by bigint, create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id)
|
||
);
|
||
CREATE INDEX idx_task_version ON collect_form_schema (task_id, version);
|
||
COMMENT ON TABLE collect_form_schema IS '表单定义(版本化)';
|
||
COMMENT ON COLUMN collect_form_schema.version IS '版本号,已发布任务修改则+1';
|
||
COMMENT ON COLUMN collect_form_schema.schema_json IS '字段定义数组';
|
||
|
||
CREATE TABLE collect_material_def (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
task_id bigint NOT NULL,
|
||
material_code varchar(32) NOT NULL,
|
||
material_name varchar(64) NOT NULL,
|
||
aliases varchar(512),
|
||
name_pattern varchar(256),
|
||
required smallint NOT NULL DEFAULT 1,
|
||
visible_when varchar(256),
|
||
file_types varchar(128) NOT NULL DEFAULT 'jpg,jpeg,png',
|
||
max_size_kb integer NOT NULL DEFAULT 1024,
|
||
compress_profile varchar(8) NOT NULL DEFAULT 'AUTO',
|
||
min_long_side integer NOT NULL DEFAULT 1400,
|
||
min_quality smallint NOT NULL DEFAULT 70,
|
||
target_dpi integer,
|
||
fixed_size varchar(32),
|
||
output_format varchar(16) NOT NULL DEFAULT 'jpg',
|
||
max_count smallint NOT NULL DEFAULT 1,
|
||
merge_enabled smallint NOT NULL DEFAULT 0,
|
||
ocr_type varchar(32),
|
||
sample_url varchar(512),
|
||
tip_text varchar(512),
|
||
sort_no integer 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 DEFAULT 0 NOT NULL,
|
||
PRIMARY KEY (id),
|
||
CONSTRAINT uk_task_code UNIQUE (task_id, material_code)
|
||
);
|
||
CREATE INDEX idx_matdef_tenant ON collect_material_def (tenant_id);
|
||
COMMENT ON TABLE collect_material_def IS '材料项定义';
|
||
COMMENT ON COLUMN collect_material_def.material_code IS '如 IDCARD/PHOTO1/SCHOOL_ROLL/WORK_PROOF';
|
||
COMMENT ON COLUMN collect_material_def.material_name IS '规范材料名,如 身份证';
|
||
COMMENT ON COLUMN collect_material_def.aliases IS '别名,逗号分隔,用于历史文件名识别';
|
||
COMMENT ON COLUMN collect_material_def.name_pattern IS '命名模板,空则继承任务级';
|
||
COMMENT ON COLUMN collect_material_def.visible_when IS '条件显示表达式';
|
||
COMMENT ON COLUMN collect_material_def.file_types IS '格式白名单';
|
||
COMMENT ON COLUMN collect_material_def.max_size_kb IS '体积上限KB';
|
||
COMMENT ON COLUMN collect_material_def.compress_profile IS '压缩档位: AUTO自动判定/P1证件照/P2证件翻拍/P3扫描件/P4截图/P5文档, 见6.3';
|
||
COMMENT ON COLUMN collect_material_def.min_long_side IS '分辨率下限(仅P2证件翻拍档生效)';
|
||
COMMENT ON COLUMN collect_material_def.min_quality IS '质量下限,低于65视为不可接受';
|
||
COMMENT ON COLUMN collect_material_def.target_dpi IS '目标DPI(仅P3扫描件档生效,建议150-300)';
|
||
COMMENT ON COLUMN collect_material_def.fixed_size IS '固定像素尺寸(仅P1证件照档,如295x413)';
|
||
COMMENT ON COLUMN collect_material_def.output_format IS 'P4截图档固定输出png';
|
||
COMMENT ON COLUMN collect_material_def.max_count IS '允许上传份数,身份证正反面可2';
|
||
COMMENT ON COLUMN collect_material_def.merge_enabled IS '多份是否合并为一张';
|
||
COMMENT ON COLUMN collect_material_def.ocr_type IS 'IDCARD/GENERAL/NONE';
|
||
COMMENT ON COLUMN collect_material_def.sample_url IS '示例图';
|
||
COMMENT ON COLUMN collect_material_def.tip_text IS '填报提示语';
|
||
|
||
CREATE TABLE collect_roster (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
task_id bigint NOT NULL,
|
||
org_id bigint,
|
||
seq_no integer,
|
||
student_no varchar(64),
|
||
real_name varchar(64) NOT NULL,
|
||
name_pinyin varchar(128),
|
||
id_card_no varchar(128) NOT NULL,
|
||
id_card_hash char(64) NOT NULL,
|
||
id_card_mask varchar(32),
|
||
phone varchar(128),
|
||
phone_hash char(64),
|
||
ext_json jsonb,
|
||
bind_user_id bigint,
|
||
bind_time timestamp,
|
||
bind_type smallint,
|
||
submit_status 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 DEFAULT 0 NOT NULL,
|
||
PRIMARY KEY (id),
|
||
CONSTRAINT uk_task_idcard UNIQUE (task_id, id_card_hash)
|
||
);
|
||
CREATE INDEX idx_task_org ON collect_roster (task_id, org_id);
|
||
CREATE INDEX idx_bind_user ON collect_roster (bind_user_id);
|
||
CREATE INDEX idx_roster_name ON collect_roster (task_id, real_name);
|
||
COMMENT ON TABLE collect_roster IS '名册';
|
||
COMMENT ON COLUMN collect_roster.org_id IS '班级';
|
||
COMMENT ON COLUMN collect_roster.seq_no IS '序号(来自Excel)';
|
||
COMMENT ON COLUMN collect_roster.student_no IS '学号(⚠️初稿遗漏,名册唯一性依据之一)';
|
||
COMMENT ON COLUMN collect_roster.name_pinyin IS '拼音,用于近音纠错';
|
||
COMMENT ON COLUMN collect_roster.id_card_no IS 'AES加密';
|
||
COMMENT ON COLUMN collect_roster.id_card_hash IS 'HMAC,唯一性判断';
|
||
COMMENT ON COLUMN collect_roster.id_card_mask IS '脱敏展示 3601**********1234';
|
||
COMMENT ON COLUMN collect_roster.ext_json IS '名册其余字段(学历/工作单位/报考职业等)';
|
||
COMMENT ON COLUMN collect_roster.bind_user_id IS '绑定的填报人';
|
||
COMMENT ON COLUMN collect_roster.bind_type IS '1门禁核验匹配 2管理员指定';
|
||
COMMENT ON COLUMN collect_roster.submit_status IS '0未提交 1草稿 2待审 3已通过 4已驳回';
|
||
|
||
CREATE TABLE collect_submission (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
task_id bigint NOT NULL,
|
||
roster_id bigint,
|
||
org_id bigint,
|
||
submitter_id bigint NOT NULL,
|
||
form_version integer NOT NULL DEFAULT 1,
|
||
form_data jsonb,
|
||
-- ⚠️ 与 collect_roster 对称的 18 个业务列:存学生「确认/修改后」的最终值
|
||
-- 需要与名单值做 diff(留痕"学生改了哪些字段"),也是统计"实际报考各工种人数"的依据
|
||
occupation varchar(64),
|
||
worktype varchar(64),
|
||
job_level varchar(32),
|
||
education varchar(32),
|
||
is_student smallint,
|
||
school varchar(128),
|
||
major varchar(128),
|
||
enroll_date date,
|
||
work_unit varchar(128),
|
||
is_retake smallint,
|
||
retake_theory varchar(64),
|
||
retake_practice varchar(64),
|
||
retake_overall varchar(64),
|
||
work_years smallint,
|
||
cert_occupation varchar(128),
|
||
cert_level varchar(32),
|
||
cert_no varchar(64),
|
||
extras_json jsonb DEFAULT '{}'::jsonb, -- 逃生舱
|
||
changed_fields jsonb, -- 学生相对名单修改过的字段(留痕)
|
||
status smallint NOT NULL DEFAULT 0,
|
||
reject_count integer NOT NULL DEFAULT 0,
|
||
last_reject_reason varchar(512),
|
||
red_count integer NOT NULL DEFAULT 0,
|
||
yellow_count integer NOT NULL DEFAULT 0,
|
||
submit_time timestamp,
|
||
class_audit_by bigint, class_audit_time timestamp,
|
||
admin_audit_by bigint, admin_audit_time timestamp,
|
||
create_by bigint,
|
||
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
update_by bigint,
|
||
update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
deleted smallint DEFAULT 0 NOT NULL,
|
||
PRIMARY KEY (id),
|
||
CONSTRAINT uk_task_submitter UNIQUE (task_id, submitter_id)
|
||
);
|
||
CREATE INDEX idx_task_status ON collect_submission (task_id, status, org_id);
|
||
CREATE INDEX idx_submitter ON collect_submission (submitter_id);
|
||
COMMENT ON TABLE collect_submission IS '填报单';
|
||
COMMENT ON COLUMN collect_submission.roster_id IS '社会收集可为空';
|
||
COMMENT ON COLUMN collect_submission.submitter_id IS '填报人user_id';
|
||
COMMENT ON COLUMN collect_submission.form_data IS '表单数据快照(扩展字段;核心18列见上方独立列)';
|
||
COMMENT ON COLUMN collect_submission.occupation IS '最终报考职业(学生确认后,应与名单一致)';
|
||
COMMENT ON COLUMN collect_submission.worktype IS '最终报考工种';
|
||
COMMENT ON COLUMN collect_submission.job_level IS '最终报考等级';
|
||
COMMENT ON COLUMN collect_submission.is_student IS '是否在校生 0否 1是';
|
||
COMMENT ON COLUMN collect_submission.work_unit IS '工作单位(没有填"无")';
|
||
COMMENT ON COLUMN collect_submission.is_retake IS '是否补考 0否 1是';
|
||
COMMENT ON COLUMN collect_submission.extras_json IS '租户/机构额外追加字段(逃生舱)';
|
||
COMMENT ON COLUMN collect_submission.changed_fields IS '学生相对名单修改过的字段(留痕: {字段:{old,new,time}})';
|
||
COMMENT ON COLUMN collect_submission.status IS '0草稿 1待初审 2待终审 3已通过 4已驳回 5已归档';
|
||
COMMENT ON COLUMN collect_submission.red_count IS '红色问题数';
|
||
COMMENT ON COLUMN collect_submission.yellow_count IS '黄色问题数';
|
||
|
||
CREATE TABLE collect_file (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
task_id bigint NOT NULL,
|
||
submission_id bigint NOT NULL,
|
||
roster_id bigint,
|
||
material_code varchar(32) NOT NULL,
|
||
version integer NOT NULL DEFAULT 1,
|
||
is_current smallint NOT NULL DEFAULT 1,
|
||
original_name varchar(512) NOT NULL,
|
||
standard_name varchar(512),
|
||
file_ext varchar(16) NOT NULL,
|
||
mime_type varchar(64),
|
||
raw_size bigint NOT NULL,
|
||
final_size bigint NOT NULL,
|
||
file_hash char(64) NOT NULL,
|
||
raw_path varchar(512),
|
||
std_path varchar(512),
|
||
raw_expire_time timestamp,
|
||
width integer, height integer, quality smallint,
|
||
dpi integer,
|
||
ocr_status smallint NOT NULL DEFAULT 0,
|
||
ocr_result jsonb,
|
||
ocr_confidence numeric(4,3),
|
||
detected_material_code varchar(32),
|
||
detect_confidence numeric(4,3),
|
||
detect_source varchar(32),
|
||
detect_conflict smallint NOT NULL DEFAULT 0,
|
||
need_manual_place smallint NOT NULL DEFAULT 0,
|
||
vlm_called smallint NOT NULL DEFAULT 0,
|
||
validate_status smallint NOT NULL DEFAULT 0,
|
||
source smallint NOT NULL DEFAULT 1,
|
||
upload_ip varchar(64),
|
||
create_by bigint,
|
||
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
update_by bigint,
|
||
update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
deleted smallint DEFAULT 0 NOT NULL,
|
||
PRIMARY KEY (id)
|
||
);
|
||
CREATE INDEX idx_file_submission ON collect_file (submission_id, material_code, is_current);
|
||
CREATE INDEX idx_task_material ON collect_file (task_id, material_code);
|
||
CREATE INDEX idx_hash ON collect_file (file_hash);
|
||
CREATE INDEX idx_raw_expire ON collect_file (raw_expire_time);
|
||
COMMENT ON TABLE collect_file IS '文件实体';
|
||
COMMENT ON COLUMN collect_file.is_current IS '是否最新有效版本';
|
||
COMMENT ON COLUMN collect_file.original_name IS '原始文件名';
|
||
COMMENT ON COLUMN collect_file.standard_name IS '规范文件名';
|
||
COMMENT ON COLUMN collect_file.raw_size IS '原始字节';
|
||
COMMENT ON COLUMN collect_file.final_size IS '处理后字节';
|
||
COMMENT ON COLUMN collect_file.file_hash IS 'SHA-256,用于查重';
|
||
COMMENT ON COLUMN collect_file.raw_path IS '对象存储key-原始';
|
||
COMMENT ON COLUMN collect_file.std_path IS '对象存储key-规范';
|
||
COMMENT ON COLUMN collect_file.raw_expire_time IS '原始文件清理时间';
|
||
COMMENT ON COLUMN collect_file.ocr_status IS '0未识别 1成功 2失败';
|
||
COMMENT ON COLUMN collect_file.ocr_result IS 'OCR结构化结果(不存明文证件号,存hash)';
|
||
COMMENT ON COLUMN collect_file.detected_material_code IS '材料识别结果(材料类型编码),见功能逻辑卷3.5-B';
|
||
COMMENT ON COLUMN collect_file.detect_confidence IS '材料识别置信度';
|
||
COMMENT ON COLUMN collect_file.detect_source IS '识别来源: FILENAME/形态KEYWORD/POSITION/VLM/MIXED';
|
||
COMMENT ON COLUMN collect_file.detect_conflict IS '是否与槽位冲突(1=冲突)';
|
||
COMMENT ON COLUMN collect_file.need_manual_place IS '是否需要人工归属(散图分拣用)';
|
||
COMMENT ON COLUMN collect_file.vlm_called IS '是否触发了VLM兜底(用于成本核算)';
|
||
COMMENT ON COLUMN collect_file.validate_status IS '0未校验 1通过 2警告 3错误';
|
||
COMMENT ON COLUMN collect_file.source IS '1本人上传 2班主任代传 3管理员代传 4整理器导入';
|
||
|
||
CREATE TABLE collect_validation_issue (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
task_id bigint NOT NULL,
|
||
submission_id bigint NOT NULL,
|
||
file_id bigint,
|
||
rule_code varchar(32) NOT NULL,
|
||
severity smallint NOT NULL,
|
||
field_key varchar(64),
|
||
title varchar(128) NOT NULL,
|
||
detail varchar(512),
|
||
expected_val varchar(256),
|
||
actual_val varchar(256),
|
||
auto_fixed smallint NOT NULL DEFAULT 0,
|
||
resolved smallint NOT NULL DEFAULT 0,
|
||
resolved_by bigint, resolved_time timestamp,
|
||
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id)
|
||
);
|
||
CREATE INDEX idx_issue_submission ON collect_validation_issue (submission_id, resolved);
|
||
CREATE INDEX idx_task_severity ON collect_validation_issue (task_id, severity, resolved);
|
||
COMMENT ON TABLE collect_validation_issue IS '校验问题';
|
||
COMMENT ON COLUMN collect_validation_issue.file_id IS '可为空(表单级问题)';
|
||
COMMENT ON COLUMN collect_validation_issue.rule_code IS 'VAL-01..VAL-12';
|
||
COMMENT ON COLUMN collect_validation_issue.severity IS '1信息 2警告 3错误';
|
||
COMMENT ON COLUMN collect_validation_issue.expected_val IS '期望值(如名册中的证件号)';
|
||
COMMENT ON COLUMN collect_validation_issue.actual_val IS '实际值';
|
||
COMMENT ON COLUMN collect_validation_issue.auto_fixed IS '是否已自动修复';
|
||
|
||
CREATE TABLE collect_audit_record (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
task_id bigint NOT NULL,
|
||
submission_id bigint NOT NULL,
|
||
audit_node varchar(32) NOT NULL,
|
||
auditor_id bigint NOT NULL,
|
||
action smallint NOT NULL,
|
||
reason_code varchar(32),
|
||
reason_text varchar(512),
|
||
material_codes varchar(256),
|
||
duration_sec integer,
|
||
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id)
|
||
);
|
||
CREATE INDEX idx_audit_submission ON collect_audit_record (submission_id, create_time);
|
||
CREATE INDEX idx_task_node ON collect_audit_record (task_id, audit_node, create_time);
|
||
COMMENT ON TABLE collect_audit_record IS '审核记录';
|
||
COMMENT ON COLUMN collect_audit_record.audit_node IS 'CLASS_AUDIT/ADMIN_AUDIT';
|
||
COMMENT ON COLUMN collect_audit_record.action IS '1通过 2驳回 3批量通过 4批量驳回 5转交 6代传';
|
||
COMMENT ON COLUMN collect_audit_record.reason_code IS '驳回原因编码';
|
||
COMMENT ON COLUMN collect_audit_record.material_codes IS '被驳回的材料项';
|
||
COMMENT ON COLUMN collect_audit_record.duration_sec IS '处理耗时';
|
||
|
||
CREATE TABLE collect_export_task (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
task_id bigint NOT NULL,
|
||
export_name varchar(256) NOT NULL,
|
||
scope_json jsonb,
|
||
split_size_mb integer NOT NULL DEFAULT 0,
|
||
desensitize smallint NOT NULL DEFAULT 0,
|
||
status smallint NOT NULL DEFAULT 0,
|
||
progress smallint NOT NULL DEFAULT 0,
|
||
file_count integer, total_size bigint,
|
||
result_files jsonb,
|
||
error_msg varchar(512),
|
||
expire_time timestamp,
|
||
create_by bigint, create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
finish_time timestamp,
|
||
PRIMARY KEY (id)
|
||
);
|
||
CREATE INDEX idx_task ON collect_export_task (task_id, create_time);
|
||
CREATE INDEX idx_status ON collect_export_task (status);
|
||
COMMENT ON TABLE collect_export_task IS '导出任务';
|
||
COMMENT ON COLUMN collect_export_task.scope_json IS '范围:orgIds/userIds/仅通过终审/是否含原图';
|
||
COMMENT ON COLUMN collect_export_task.split_size_mb IS '0不分卷,>0按MB分卷';
|
||
COMMENT ON COLUMN collect_export_task.desensitize IS '是否脱敏';
|
||
COMMENT ON COLUMN collect_export_task.status IS '0排队 1处理中 2完成 3失败';
|
||
COMMENT ON COLUMN collect_export_task.progress IS '0-100';
|
||
COMMENT ON COLUMN collect_export_task.result_files IS '生成的包列表[{name,path,size,part}]';
|
||
COMMENT ON COLUMN collect_export_task.expire_time IS '下载有效期';
|
||
|
||
CREATE TABLE collect_file_process_log (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
file_id bigint NOT NULL,
|
||
step varchar(32) NOT NULL,
|
||
before_val varchar(512),
|
||
after_val varchar(512),
|
||
extra_json jsonb,
|
||
cost_ms integer,
|
||
success smallint NOT NULL DEFAULT 1,
|
||
error_msg varchar(512),
|
||
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id)
|
||
);
|
||
CREATE INDEX idx_file ON collect_file_process_log (file_id, step);
|
||
COMMENT ON TABLE collect_file_process_log IS '文件处理日志';
|
||
COMMENT ON COLUMN collect_file_process_log.step IS 'NORMALIZE_NAME/COMPRESS/CONVERT/OCR/EXIF_FIX';
|
||
COMMENT ON COLUMN collect_file_process_log.extra_json IS '如 {beforeSize,afterSize,attempts,quality,finalLongSide}';
|
||
|
||
CREATE TABLE collect_notify_record (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
task_id bigint,
|
||
channel varchar(16) NOT NULL, -- WECHAT_SUBSCRIBE / WECHAT_MP / SMS / INBOX
|
||
biz_type varchar(32) NOT NULL, -- TASK_PUBLISH / DEADLINE_REMIND / REJECT / APPROVE / EXPORT_DONE / AUDIT_TIMEOUT
|
||
receiver_id bigint NOT NULL, -- 接收人 sys_user.id
|
||
receiver_role varchar(16), -- 接收人角色(便于按角色统计)
|
||
template_code varchar(64),
|
||
content varchar(1024),
|
||
status smallint NOT NULL DEFAULT 0, -- 0待发 1成功 2失败 3额度不足跳过
|
||
fail_reason varchar(512),
|
||
send_time timestamp,
|
||
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id)
|
||
);
|
||
CREATE INDEX idx_notify_task ON collect_notify_record (task_id, biz_type, create_time);
|
||
CREATE INDEX idx_notify_recv ON collect_notify_record (receiver_id, create_time);
|
||
COMMENT ON TABLE collect_notify_record IS '通知记录';
|
||
COMMENT ON COLUMN collect_notify_record.channel IS '渠道: 微信订阅消息/服务号/短信/站内';
|
||
COMMENT ON COLUMN collect_notify_record.biz_type IS '业务类型';
|
||
COMMENT ON COLUMN collect_notify_record.status IS '0待发 1成功 2失败 3额度不足跳过';
|
||
COMMENT ON COLUMN collect_notify_record.fail_reason IS '失败原因;额度不足时记录(应对R12订阅消息次数限制)';
|
||
|
||
-- 订阅额度余额(微信一次性订阅消息,发一条消耗一条)
|
||
CREATE TABLE collect_subscribe_quota (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
user_id bigint NOT NULL,
|
||
template_code varchar(64) NOT NULL,
|
||
total integer NOT NULL DEFAULT 0, -- 累计授权次数
|
||
used integer NOT NULL DEFAULT 0, -- 已消耗次数
|
||
update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (id),
|
||
CONSTRAINT uk_quota_user_tpl UNIQUE (user_id, template_code)
|
||
);
|
||
COMMENT ON TABLE collect_subscribe_quota IS '微信订阅消息额度余额';
|
||
COMMENT ON COLUMN collect_subscribe_quota.total IS '累计授权次数';
|
||
COMMENT ON COLUMN collect_subscribe_quota.used IS '已消耗次数;余额=total-used,不足时自动降级到服务号或短信';
|
||
|
||
CREATE TABLE collect_rule_template (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
template_name varchar(128) NOT NULL,
|
||
cert_type smallint,
|
||
form_schema jsonb,
|
||
materials jsonb,
|
||
naming_template varchar(256),
|
||
is_public smallint NOT NULL DEFAULT 0,
|
||
use_count integer 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 DEFAULT 0 NOT NULL,
|
||
PRIMARY KEY (id)
|
||
);
|
||
CREATE INDEX idx_ruletpl_tenant ON collect_rule_template (tenant_id, is_public);
|
||
COMMENT ON TABLE collect_rule_template IS '规则模板';
|
||
COMMENT ON COLUMN collect_rule_template.tenant_id IS '0=平台公共模板';
|
||
COMMENT ON COLUMN collect_rule_template.template_name IS '如 自主认定标准模板';
|
||
COMMENT ON COLUMN collect_rule_template.cert_type IS '1自主认定 2社会评价 3专项职业能力';
|
||
COMMENT ON COLUMN collect_rule_template.form_schema IS '表单字段模板';
|
||
COMMENT ON COLUMN collect_rule_template.materials IS '材料清单模板';
|
||
|
||
CREATE TABLE collect_cleanup_job (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
job_name varchar(128) NOT NULL,
|
||
source_type smallint NOT NULL DEFAULT 1,
|
||
source_path varchar(512) NOT NULL,
|
||
target_task_id bigint,
|
||
naming_template varchar(256) NOT NULL DEFAULT '{姓名}-{证件号}-{材料名}',
|
||
compress_config jsonb,
|
||
status smallint NOT NULL DEFAULT 0,
|
||
progress smallint NOT NULL DEFAULT 0,
|
||
report_json jsonb,
|
||
total_files integer, fixed_files integer, failed_files integer,
|
||
result_path varchar(512),
|
||
create_by bigint, create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
finish_time timestamp,
|
||
PRIMARY KEY (id)
|
||
);
|
||
CREATE INDEX idx_cleanup_tenant ON collect_cleanup_job (tenant_id, create_time);
|
||
COMMENT ON TABLE collect_cleanup_job IS '历史数据整理任务';
|
||
COMMENT ON COLUMN collect_cleanup_job.source_type IS '1上传压缩包 2对象存储目录';
|
||
COMMENT ON COLUMN collect_cleanup_job.target_task_id IS '结果可导入某任务';
|
||
COMMENT ON COLUMN collect_cleanup_job.status IS '0排队 1解析中 2处理中 3完成 4失败';
|
||
COMMENT ON COLUMN collect_cleanup_job.report_json IS '体检报告:命名违规/证件号异常/体积超标/缺失/重复';
|
||
|
||
|
||
-- ============ 1b) 客户确认后新增(FR-509) ============
|
||
|
||
CREATE TABLE collect_join_request (
|
||
id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
||
tenant_id bigint NOT NULL,
|
||
task_id bigint NOT NULL,
|
||
real_name varchar(64) NOT NULL,
|
||
id_card_hash char(64) NOT NULL,
|
||
id_card_mask varchar(32) NOT NULL,
|
||
phone_hash char(64),
|
||
phone_mask varchar(32),
|
||
org_hint varchar(128),
|
||
reason varchar(500),
|
||
status smallint NOT NULL DEFAULT 0,
|
||
reject_reason varchar(500),
|
||
roster_id bigint,
|
||
audit_by bigint,
|
||
audit_time timestamp,
|
||
applicant_openid varchar(64) NOT NULL,
|
||
applicant_uid bigint,
|
||
source smallint NOT NULL DEFAULT 1,
|
||
create_by bigint,
|
||
create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
update_by bigint,
|
||
update_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
deleted smallint DEFAULT 0 NOT NULL,
|
||
PRIMARY KEY (id)
|
||
);
|
||
CREATE UNIQUE INDEX uk_join_task_idcard ON collect_join_request (task_id, id_card_hash)
|
||
WHERE deleted = 0 AND status IN (0, 1);
|
||
CREATE INDEX idx_join_task_status ON collect_join_request (task_id, status, create_time);
|
||
CREATE INDEX idx_join_openid ON collect_join_request (applicant_openid);
|
||
COMMENT ON TABLE collect_join_request IS '名单加入申请';
|
||
COMMENT ON COLUMN collect_join_request.real_name IS '申请人自述姓名(明文,业务必需)';
|
||
COMMENT ON COLUMN collect_join_request.id_card_hash IS 'HMAC,与门禁一致,不存明文';
|
||
COMMENT ON COLUMN collect_join_request.id_card_mask IS '脱敏展示';
|
||
COMMENT ON COLUMN collect_join_request.org_hint IS '申请人自述班级(选填,可由管理员修正)';
|
||
COMMENT ON COLUMN collect_join_request.reason IS '申请说明';
|
||
COMMENT ON COLUMN collect_join_request.status IS '0待审 1已通过 2已驳回 3已失效(任务截止)';
|
||
COMMENT ON COLUMN collect_join_request.reject_reason IS '驳回原因(驳回时必填)';
|
||
COMMENT ON COLUMN collect_join_request.roster_id IS '审批通过后生成的名册项';
|
||
COMMENT ON COLUMN collect_join_request.applicant_openid IS '用于限流(每任务<=2次)与审批通过后自动绑定';
|
||
COMMENT ON COLUMN collect_join_request.source IS '1门禁失败页申请 2管理员代录';
|
||
|
||
-- ============ 2) 补列 ALTER ============
|
||
|
||
ALTER TABLE collect_task ADD COLUMN plan_scope_json jsonb;
|
||
ALTER TABLE collect_task ADD COLUMN plan_scope_confirmed smallint NOT NULL DEFAULT 0;
|
||
COMMENT ON COLUMN collect_task.plan_scope_json IS '本期报考范围快照(从名单聚合): {occupations:[{name,worktypes:[{name,levels:[]}]}], confirmed:true}';
|
||
COMMENT ON COLUMN collect_task.plan_scope_confirmed IS '管理员是否已确认范围(未确认则追加名单不告警)';
|
||
|
||
-- 同学号的补齐:官方模板 21 字段中的非身份字段全部建为正式列
|
||
-- 姓名、身份证号已有独立列(real_name / id_card_no),此处补齐其余 18 个
|
||
ALTER TABLE collect_roster
|
||
ADD COLUMN occupation varchar(64), -- 报考职业 G
|
||
ADD COLUMN worktype varchar(64), -- 报考工种 H
|
||
ADD COLUMN job_level varchar(32), -- 报考等级 I
|
||
ADD COLUMN education varchar(32), -- 学历 D
|
||
ADD COLUMN is_student smallint, -- 是否在校生 N 0否 1是
|
||
ADD COLUMN school varchar(128), -- 在读学校 O
|
||
ADD COLUMN major varchar(128), -- 所学专业 P
|
||
ADD COLUMN enroll_date date, -- 入学时间 Q YYYY-MM-DD
|
||
ADD COLUMN work_unit varchar(128), -- 工作单位 F 无则填"无"
|
||
ADD COLUMN is_retake smallint, -- 是否补考 J 0否 1是
|
||
ADD COLUMN retake_theory varchar(64), -- 补考理论 K
|
||
ADD COLUMN retake_practice varchar(64), -- 补考实操 L
|
||
ADD COLUMN retake_overall varchar(64), -- 补考综合 M
|
||
ADD COLUMN work_years smallint, -- 本职业工作年限 R
|
||
ADD COLUMN cert_occupation varchar(128), -- 已获证书职业工种 S
|
||
ADD COLUMN cert_level varchar(32), -- 已获证书等级 T
|
||
ADD COLUMN cert_no varchar(64), -- 已获证书编号 U
|
||
ADD COLUMN extras_json jsonb DEFAULT '{}'::jsonb; -- 逃生舱:仅存租户/机构额外追加的字段
|
||
|
||
-- 报考范围聚合与按工种统计必需的索引
|
||
CREATE INDEX idx_roster_scope ON collect_roster (tenant_id, task_id, occupation, worktype, job_level);
|
||
CREATE INDEX idx_roster_org ON collect_roster (task_id, org_id, deleted);
|
||
|
||
COMMENT ON COLUMN collect_roster.occupation IS '报考职业(锁定,由老师确定)';
|
||
COMMENT ON COLUMN collect_roster.worktype IS '报考工种(锁定;该职业无工种时填"无";专项职业能力为空)';
|
||
COMMENT ON COLUMN collect_roster.job_level IS '报考等级(锁定;专项职业能力为空)';
|
||
COMMENT ON COLUMN collect_roster.education IS '学历(下拉11项)';
|
||
COMMENT ON COLUMN collect_roster.is_student IS '是否在校生 0否 1是';
|
||
COMMENT ON COLUMN collect_roster.school IS '在读学校(在校生=是时必填)';
|
||
COMMENT ON COLUMN collect_roster.major IS '所学专业(在校生=是时必填)';
|
||
COMMENT ON COLUMN collect_roster.enroll_date IS '入学时间(在校生=是时必填,格式YYYY-MM-DD)';
|
||
COMMENT ON COLUMN collect_roster.work_unit IS '工作单位(没有填"无")';
|
||
COMMENT ON COLUMN collect_roster.is_retake IS '是否补考 0否 1是';
|
||
COMMENT ON COLUMN collect_roster.retake_theory IS '补考理论(级联)';
|
||
COMMENT ON COLUMN collect_roster.retake_practice IS '补考实操(级联)';
|
||
COMMENT ON COLUMN collect_roster.retake_overall IS '补考综合(级联)';
|
||
COMMENT ON COLUMN collect_roster.work_years IS '本职业工作年限(仅阿拉伯数字)';
|
||
COMMENT ON COLUMN collect_roster.cert_occupation IS '已获证书职业工种(选填)';
|
||
COMMENT ON COLUMN collect_roster.cert_level IS '已获证书等级(选填)';
|
||
COMMENT ON COLUMN collect_roster.cert_no IS '已获证书编号(选填)';
|
||
COMMENT ON COLUMN collect_roster.extras_json IS '租户/机构额外追加的字段(逃生舱,不参与核心统计)';
|