@@ -0,0 +1,724 @@
-- ═══════════════════════════════════════════════════════════════════
-- V1 · 业务表(20 张)
--
-- ⚠️ 本文件由脚本生成,请勿手改!
-- 来源 : docs/db/schema-postgresql.sql
-- 重新生成 : python scripts/sync-ddl.py
-- 校验同步 : python scripts/sync-ddl.py --check
--
-- 源文件已在 PostgreSQL 16.15 实测零错误:
-- 20 表 / 177 列注释 / 65 索引 / 20 表注释
-- ═══════════════════════════════════════════════════════════════════
-- ============ 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社会人员 ' ;
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 NOT NULL DEFAULT 0 ,
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 ' 应填人数(冗余,由名册汇总) ' ;
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 ' 租户/机构额外追加的字段(逃生舱,不参与核心统计) ' ;