先更新1版记录下
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
CREATE SCHEMA IF NOT EXISTS sys;
|
||||
CREATE SCHEMA IF NOT EXISTS auth;
|
||||
CREATE SCHEMA IF NOT EXISTS upms;
|
||||
CREATE SCHEMA IF NOT EXISTS ai;
|
||||
CREATE SCHEMA IF NOT EXISTS course;
|
||||
CREATE SCHEMA IF NOT EXISTS question;
|
||||
CREATE SCHEMA IF NOT EXISTS achievement;
|
||||
CREATE SCHEMA IF NOT EXISTS recommendation;
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
\i /docker-entrypoint-initdb.d/upms/10_create_upms_tables.sql
|
||||
\i /docker-entrypoint-initdb.d/auth/10_create_auth_tables.sql
|
||||
\i /docker-entrypoint-initdb.d/ai/10_create_ai_tables.sql
|
||||
\i /docker-entrypoint-initdb.d/course/10_create_course_tables.sql
|
||||
\i /docker-entrypoint-initdb.d/question/10_create_question_tables.sql
|
||||
\i /docker-entrypoint-initdb.d/achievement/10_create_achievement_tables.sql
|
||||
\i /docker-entrypoint-initdb.d/recommendation/10_create_recommendation_tables.sql
|
||||
\i /docker-entrypoint-initdb.d/sys/sys_area.sql
|
||||
\i /docker-entrypoint-initdb.d/upms/20_init_upms_seed.sql
|
||||
\i /docker-entrypoint-initdb.d/auth/20_init_auth_seed.sql
|
||||
\i /docker-entrypoint-initdb.d/ai/20_init_ai_seed.sql
|
||||
\i /docker-entrypoint-initdb.d/course/20_init_course_seed.sql
|
||||
\i /docker-entrypoint-initdb.d/question/20_init_question_seed.sql
|
||||
\i /docker-entrypoint-initdb.d/achievement/20_init_achievement_seed.sql
|
||||
|
||||
407
init/pg/achievement/10_create_achievement_tables.sql
Normal file
407
init/pg/achievement/10_create_achievement_tables.sql
Normal file
@@ -0,0 +1,407 @@
|
||||
DROP SCHEMA IF EXISTS achievement CASCADE;
|
||||
CREATE SCHEMA IF NOT EXISTS achievement;
|
||||
|
||||
DROP TABLE IF EXISTS achievement.ac_achievement CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS achievement.ac_achievement (
|
||||
achievement_id VARCHAR(64) PRIMARY KEY,
|
||||
achievement_code VARCHAR(64) UNIQUE NOT NULL,
|
||||
achievement_name VARCHAR(128) NOT NULL,
|
||||
achievement_desc TEXT,
|
||||
achievement_category VARCHAR(32) NOT NULL DEFAULT 'SCORE',
|
||||
trigger_event VARCHAR(32) NOT NULL DEFAULT 'GRADE_PUBLISHED',
|
||||
trigger_rule_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
badge_level VARCHAR(16) NOT NULL DEFAULT 'BRONZE',
|
||||
badge_icon_url VARCHAR(512),
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_by VARCHAR(64),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_ac_achievement_category
|
||||
CHECK (achievement_category IN ('SCORE', 'PROGRESS', 'TEACHING', 'ENGAGEMENT', 'MANUAL')),
|
||||
CONSTRAINT chk_ac_achievement_trigger_event
|
||||
CHECK (trigger_event IN ('GRADE_PUBLISHED', 'WRONG_QUESTION_MASTERED', 'TASK_COMPLETED', 'REVIEW_COMPLETED', 'MANUAL')),
|
||||
CONSTRAINT chk_ac_achievement_badge_level
|
||||
CHECK (badge_level IN ('BRONZE', 'SILVER', 'GOLD', 'PLATINUM')),
|
||||
CONSTRAINT chk_ac_achievement_status
|
||||
CHECK (status IN ('ACTIVE', 'DISABLED')),
|
||||
CONSTRAINT chk_ac_achievement_trigger_rule_json
|
||||
CHECK (jsonb_typeof(trigger_rule_json) = 'object'),
|
||||
CONSTRAINT fk_ac_achievement_created_by
|
||||
FOREIGN KEY (created_by) REFERENCES upms.tb_sys_user(user_id)
|
||||
);
|
||||
COMMENT ON TABLE achievement.ac_achievement IS '成就定义表';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.achievement_id IS '成就ID';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.achievement_code IS '成就编码';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.achievement_name IS '成就名称';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.achievement_desc IS '成就描述';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.achievement_category IS '成就类别(SCORE/PROGRESS/TEACHING/ENGAGEMENT/MANUAL)';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.trigger_event IS '触发事件(GRADE_PUBLISHED/WRONG_QUESTION_MASTERED/TASK_COMPLETED/REVIEW_COMPLETED/MANUAL)';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.trigger_rule_json IS '触发规则JSON(可配置成绩阈值、次数阈值等)';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.badge_level IS '徽章等级(BRONZE/SILVER/GOLD/PLATINUM)';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.badge_icon_url IS '徽章图标URL';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.status IS '状态(ACTIVE/DISABLED)';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.created_by IS '创建人ID';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN achievement.ac_achievement.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS achievement.ac_achievement_role_rel CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS achievement.ac_achievement_role_rel (
|
||||
achievement_id VARCHAR(64) NOT NULL,
|
||||
role_id VARCHAR(64) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (achievement_id, role_id),
|
||||
CONSTRAINT fk_ac_achievement_role_rel_achievement
|
||||
FOREIGN KEY (achievement_id) REFERENCES achievement.ac_achievement(achievement_id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_ac_achievement_role_rel_role
|
||||
FOREIGN KEY (role_id) REFERENCES upms.tb_sys_role(role_id)
|
||||
);
|
||||
COMMENT ON TABLE achievement.ac_achievement_role_rel IS '成就-角色绑定表';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_role_rel.achievement_id IS '成就ID';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_role_rel.role_id IS '角色ID';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_role_rel.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_role_rel.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS achievement.ac_user_achievement CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS achievement.ac_user_achievement (
|
||||
user_achievement_id VARCHAR(64) PRIMARY KEY,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
achievement_id VARCHAR(64) NOT NULL,
|
||||
role_id VARCHAR(64) NOT NULL,
|
||||
summary_id VARCHAR(64),
|
||||
grading_task_id VARCHAR(64),
|
||||
score_snapshot NUMERIC(8,2),
|
||||
grade_level VARCHAR(8),
|
||||
surpass_ratio NUMERIC(5,2),
|
||||
used_seconds INTEGER,
|
||||
award_source VARCHAR(32) NOT NULL DEFAULT 'RULE_ENGINE',
|
||||
award_reason VARCHAR(256),
|
||||
evidence_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
achieved_count INTEGER NOT NULL DEFAULT 1,
|
||||
first_achieved_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
last_achieved_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_ac_user_achievement_user_achievement_role
|
||||
UNIQUE (user_id, achievement_id, role_id),
|
||||
CONSTRAINT chk_ac_user_achievement_award_source
|
||||
CHECK (award_source IN ('RULE_ENGINE', 'MANUAL', 'SYSTEM')),
|
||||
CONSTRAINT chk_ac_user_achievement_evidence_json
|
||||
CHECK (jsonb_typeof(evidence_json) = 'object'),
|
||||
CONSTRAINT chk_ac_user_achievement_achieved_count
|
||||
CHECK (achieved_count > 0),
|
||||
CONSTRAINT fk_ac_user_achievement_user
|
||||
FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id),
|
||||
CONSTRAINT fk_ac_user_achievement_role_binding
|
||||
FOREIGN KEY (achievement_id, role_id) REFERENCES achievement.ac_achievement_role_rel(achievement_id, role_id),
|
||||
CONSTRAINT fk_ac_user_achievement_summary
|
||||
FOREIGN KEY (summary_id) REFERENCES question.gd_score_summary(summary_id),
|
||||
CONSTRAINT fk_ac_user_achievement_task
|
||||
FOREIGN KEY (grading_task_id) REFERENCES question.gd_grading_task(grading_task_id)
|
||||
);
|
||||
COMMENT ON TABLE achievement.ac_user_achievement IS '用户成就记录表';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.user_achievement_id IS '用户成就记录ID';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.user_id IS '用户ID';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.achievement_id IS '成就ID';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.role_id IS '获奖时角色ID';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.summary_id IS '成绩汇总ID(来源于question.gd_score_summary)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.grading_task_id IS '批改任务ID(来源于question.gd_grading_task)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.score_snapshot IS '成绩快照分数';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.grade_level IS '成绩快照等级';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.surpass_ratio IS '成绩快照超越比例';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.used_seconds IS '成绩快照耗时(秒)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.award_source IS '发放来源(RULE_ENGINE/MANUAL/SYSTEM)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.award_reason IS '发放原因';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.evidence_json IS '发放证据JSON(可存规则命中明细)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.achieved_count IS '累计达成次数';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.first_achieved_at IS '首次达成时间';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.last_achieved_at IS '最近达成时间';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement.updated_at IS '更新时间';
|
||||
DROP TABLE IF EXISTS achievement.ac_user_achievement_progress CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS achievement.ac_user_achievement_progress (
|
||||
progress_id VARCHAR(64) PRIMARY KEY,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
achievement_id VARCHAR(64) NOT NULL,
|
||||
role_id VARCHAR(64) NOT NULL,
|
||||
current_value NUMERIC(12,2) NOT NULL DEFAULT 0,
|
||||
target_value NUMERIC(12,2) NOT NULL,
|
||||
progress_rate NUMERIC(5,2) NOT NULL DEFAULT 0,
|
||||
effort_index NUMERIC(6,2) NOT NULL DEFAULT 0,
|
||||
improvement_rate NUMERIC(6,2) NOT NULL DEFAULT 0,
|
||||
resilience_index NUMERIC(6,2) NOT NULL DEFAULT 0,
|
||||
streak_days INTEGER NOT NULL DEFAULT 0,
|
||||
last_checkin_date DATE,
|
||||
progress_status VARCHAR(16) NOT NULL DEFAULT 'IN_PROGRESS',
|
||||
progress_snapshot_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
last_evaluated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
achieved_at TIMESTAMP,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_ac_user_achievement_progress_user_achievement_role
|
||||
UNIQUE (user_id, achievement_id, role_id),
|
||||
CONSTRAINT chk_ac_user_achievement_progress_current
|
||||
CHECK (current_value >= 0),
|
||||
CONSTRAINT chk_ac_user_achievement_progress_target
|
||||
CHECK (target_value > 0),
|
||||
CONSTRAINT chk_ac_user_achievement_progress_rate
|
||||
CHECK (progress_rate >= 0 AND progress_rate <= 100),
|
||||
CONSTRAINT chk_ac_user_achievement_progress_effort_index
|
||||
CHECK (effort_index >= 0 AND effort_index <= 100),
|
||||
CONSTRAINT chk_ac_user_achievement_progress_improvement_rate
|
||||
CHECK (improvement_rate >= -100 AND improvement_rate <= 1000),
|
||||
CONSTRAINT chk_ac_user_achievement_progress_resilience_index
|
||||
CHECK (resilience_index >= 0 AND resilience_index <= 100),
|
||||
CONSTRAINT chk_ac_user_achievement_progress_streak_days
|
||||
CHECK (streak_days >= 0),
|
||||
CONSTRAINT chk_ac_user_achievement_progress_status
|
||||
CHECK (progress_status IN ('IN_PROGRESS', 'ACHIEVED', 'EXPIRED')),
|
||||
CONSTRAINT chk_ac_user_achievement_progress_snapshot_json
|
||||
CHECK (jsonb_typeof(progress_snapshot_json) = 'object'),
|
||||
CONSTRAINT chk_ac_user_achievement_progress_achieved_at
|
||||
CHECK (
|
||||
(progress_status = 'ACHIEVED' AND achieved_at IS NOT NULL)
|
||||
OR (progress_status IN ('IN_PROGRESS', 'EXPIRED') AND achieved_at IS NULL)
|
||||
),
|
||||
CONSTRAINT fk_ac_user_achievement_progress_user
|
||||
FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id),
|
||||
CONSTRAINT fk_ac_user_achievement_progress_role_binding
|
||||
FOREIGN KEY (achievement_id, role_id) REFERENCES achievement.ac_achievement_role_rel(achievement_id, role_id)
|
||||
);
|
||||
COMMENT ON TABLE achievement.ac_user_achievement_progress IS '用户成就进度表(含未达成记录)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.progress_id IS '成就进度ID';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.user_id IS '用户ID';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.achievement_id IS '成就ID';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.role_id IS '角色ID(学生/教师)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.current_value IS '当前进度值';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.target_value IS '目标值';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.progress_rate IS '完成率(0-100)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.effort_index IS '努力指数(0-100)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.improvement_rate IS '进步率(可为负)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.resilience_index IS '学习韧性指数(0-100)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.streak_days IS '连续打卡天数';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.last_checkin_date IS '最近打卡日期';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.progress_status IS '进度状态(IN_PROGRESS/ACHIEVED/EXPIRED)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.progress_snapshot_json IS '进度快照JSON(可记录最近一次评估明细)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.last_evaluated_at IS '最近评估时间';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.achieved_at IS '达成时间';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_progress.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS achievement.ac_user_achievement_daily_fact CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS achievement.ac_user_achievement_daily_fact (
|
||||
stat_date DATE NOT NULL,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
role_id VARCHAR(64) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
gained_achievement_count INTEGER NOT NULL DEFAULT 0,
|
||||
active_achievement_count INTEGER NOT NULL DEFAULT 0,
|
||||
progress_delta NUMERIC(10,4) NOT NULL DEFAULT 0,
|
||||
effort_index NUMERIC(6,2) NOT NULL DEFAULT 0,
|
||||
improvement_rate NUMERIC(6,2) NOT NULL DEFAULT 0,
|
||||
resilience_index NUMERIC(6,2) NOT NULL DEFAULT 0,
|
||||
streak_days INTEGER NOT NULL DEFAULT 0,
|
||||
learning_minutes INTEGER NOT NULL DEFAULT 0,
|
||||
checkin_status VARCHAR(16) NOT NULL DEFAULT 'NONE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (stat_date, user_id, role_id),
|
||||
CONSTRAINT chk_ac_user_achievement_daily_fact_gained
|
||||
CHECK (gained_achievement_count >= 0),
|
||||
CONSTRAINT chk_ac_user_achievement_daily_fact_active
|
||||
CHECK (active_achievement_count >= 0),
|
||||
CONSTRAINT chk_ac_user_achievement_daily_fact_effort
|
||||
CHECK (effort_index >= 0 AND effort_index <= 100),
|
||||
CONSTRAINT chk_ac_user_achievement_daily_fact_improvement
|
||||
CHECK (improvement_rate >= -100 AND improvement_rate <= 1000),
|
||||
CONSTRAINT chk_ac_user_achievement_daily_fact_resilience
|
||||
CHECK (resilience_index >= 0 AND resilience_index <= 100),
|
||||
CONSTRAINT chk_ac_user_achievement_daily_fact_streak
|
||||
CHECK (streak_days >= 0),
|
||||
CONSTRAINT chk_ac_user_achievement_daily_fact_learning_minutes
|
||||
CHECK (learning_minutes >= 0),
|
||||
CONSTRAINT chk_ac_user_achievement_daily_fact_checkin
|
||||
CHECK (checkin_status IN ('NONE', 'CHECKED_IN', 'BROKEN')),
|
||||
CONSTRAINT fk_ac_user_achievement_daily_fact_user
|
||||
FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id),
|
||||
CONSTRAINT fk_ac_user_achievement_daily_fact_role
|
||||
FOREIGN KEY (role_id) REFERENCES upms.tb_sys_role(role_id)
|
||||
);
|
||||
COMMENT ON TABLE achievement.ac_user_achievement_daily_fact IS '用户成就激励日事实表(激励数据即成就数据)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.stat_date IS '统计日期';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.user_id IS '用户ID';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.role_id IS '角色ID';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.gained_achievement_count IS '当日新增成就数';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.active_achievement_count IS '当日活跃成就数';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.progress_delta IS '当日进度变化量';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.effort_index IS '当日努力指数(0-100)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.improvement_rate IS '当日进步率(可为负)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.resilience_index IS '当日学习韧性指数(0-100)';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.streak_days IS '当日连续打卡天数';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.learning_minutes IS '当日学习分钟数';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.checkin_status IS '打卡状态';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN achievement.ac_user_achievement_daily_fact.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS achievement.ac_achievement_rule_template CASCADE;
|
||||
DROP TABLE IF EXISTS achievement.ac_achievement_metric_def CASCADE;
|
||||
DROP TABLE IF EXISTS achievement.ac_achievement_event_dict CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS achievement.ac_achievement_event_dict (
|
||||
event_code VARCHAR(64) PRIMARY KEY,
|
||||
event_name VARCHAR(128) NOT NULL,
|
||||
event_domain VARCHAR(32) NOT NULL DEFAULT 'LEARNING_LOOP',
|
||||
event_desc TEXT,
|
||||
payload_schema_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_ac_achievement_event_dict_domain
|
||||
CHECK (event_domain IN ('LEARNING_LOOP', 'GRADING', 'REVIEW', 'CHECKIN', 'SYSTEM')),
|
||||
CONSTRAINT chk_ac_achievement_event_dict_payload_json
|
||||
CHECK (jsonb_typeof(payload_schema_json) = 'object')
|
||||
);
|
||||
COMMENT ON TABLE achievement.ac_achievement_event_dict IS '成就事件字典表(通用触发事件定义)';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_event_dict.event_code IS '事件编码';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_event_dict.event_name IS '事件名称';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_event_dict.event_domain IS '事件域';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_event_dict.event_desc IS '事件描述';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_event_dict.payload_schema_json IS '事件载荷结构定义JSON';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_event_dict.enabled IS '是否启用';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_event_dict.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_event_dict.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_event_dict.updated_at IS '更新时间';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS achievement.ac_achievement_metric_def (
|
||||
metric_id VARCHAR(64) PRIMARY KEY,
|
||||
metric_code VARCHAR(64) NOT NULL,
|
||||
metric_name VARCHAR(128) NOT NULL,
|
||||
metric_type VARCHAR(16) NOT NULL DEFAULT 'NUM',
|
||||
metric_unit VARCHAR(32),
|
||||
source_domain VARCHAR(32) NOT NULL DEFAULT 'SYSTEM',
|
||||
agg_method VARCHAR(16) NOT NULL DEFAULT 'LATEST',
|
||||
default_value_num NUMERIC(18,6),
|
||||
default_value_text VARCHAR(255),
|
||||
expr_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_ac_achievement_metric_def_tenant_code
|
||||
UNIQUE (tenant_id, metric_code),
|
||||
CONSTRAINT chk_ac_achievement_metric_def_type
|
||||
CHECK (metric_type IN ('NUM', 'BOOL', 'TEXT', 'RATE', 'COUNT')),
|
||||
CONSTRAINT chk_ac_achievement_metric_def_source_domain
|
||||
CHECK (source_domain IN ('COURSE', 'HOMEWORK', 'GRADING', 'REVIEW', 'RECOMMENDATION', 'ACHIEVEMENT', 'SYSTEM')),
|
||||
CONSTRAINT chk_ac_achievement_metric_def_agg_method
|
||||
CHECK (agg_method IN ('LATEST', 'SUM', 'AVG', 'MAX', 'MIN', 'COUNT')),
|
||||
CONSTRAINT chk_ac_achievement_metric_def_expr_json
|
||||
CHECK (jsonb_typeof(expr_json) = 'object')
|
||||
);
|
||||
COMMENT ON TABLE achievement.ac_achievement_metric_def IS '成就指标定义表(通用指标注册)';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_id IS '指标ID';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_code IS '指标编码';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_name IS '指标名称';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_type IS '指标类型';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.metric_unit IS '指标单位';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.source_domain IS '指标来源域';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.agg_method IS '聚合方式';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.default_value_num IS '默认数值';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.default_value_text IS '默认文本值';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.expr_json IS '计算表达式JSON';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.enabled IS '是否启用';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_metric_def.updated_at IS '更新时间';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS achievement.ac_achievement_rule_template (
|
||||
template_id VARCHAR(64) PRIMARY KEY,
|
||||
template_code VARCHAR(64) NOT NULL,
|
||||
template_name VARCHAR(128) NOT NULL,
|
||||
event_code VARCHAR(64) NOT NULL,
|
||||
role_id VARCHAR(64),
|
||||
achievement_category VARCHAR(32) NOT NULL DEFAULT 'PROGRESS',
|
||||
rule_condition_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
reward_action_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
priority INTEGER NOT NULL DEFAULT 100,
|
||||
template_status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
|
||||
valid_from TIMESTAMP,
|
||||
valid_to TIMESTAMP,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_by VARCHAR(64),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_ac_achievement_rule_template_tenant_code
|
||||
UNIQUE (tenant_id, template_code),
|
||||
CONSTRAINT chk_ac_achievement_rule_template_category
|
||||
CHECK (achievement_category IN ('SCORE', 'PROGRESS', 'TEACHING', 'ENGAGEMENT', 'MANUAL')),
|
||||
CONSTRAINT chk_ac_achievement_rule_template_status
|
||||
CHECK (template_status IN ('ACTIVE', 'INACTIVE', 'ARCHIVED')),
|
||||
CONSTRAINT chk_ac_achievement_rule_template_condition_json
|
||||
CHECK (jsonb_typeof(rule_condition_json) = 'object'),
|
||||
CONSTRAINT chk_ac_achievement_rule_template_reward_json
|
||||
CHECK (jsonb_typeof(reward_action_json) = 'object'),
|
||||
CONSTRAINT chk_ac_achievement_rule_template_valid
|
||||
CHECK (valid_to IS NULL OR valid_from IS NULL OR valid_to >= valid_from),
|
||||
CONSTRAINT fk_ac_achievement_rule_template_event
|
||||
FOREIGN KEY (event_code) REFERENCES achievement.ac_achievement_event_dict(event_code),
|
||||
CONSTRAINT fk_ac_achievement_rule_template_role
|
||||
FOREIGN KEY (role_id) REFERENCES upms.tb_sys_role(role_id),
|
||||
CONSTRAINT fk_ac_achievement_rule_template_created_by
|
||||
FOREIGN KEY (created_by) REFERENCES upms.tb_sys_user(user_id)
|
||||
);
|
||||
COMMENT ON TABLE achievement.ac_achievement_rule_template IS '成就规则模板表(通用配置驱动)';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.template_id IS '模板ID';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.template_code IS '模板编码';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.template_name IS '模板名称';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.event_code IS '触发事件编码';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.role_id IS '适用角色ID';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.achievement_category IS '成就类别';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.rule_condition_json IS '规则条件JSON';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.reward_action_json IS '奖励动作JSON';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.priority IS '优先级';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.template_status IS '模板状态';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.valid_from IS '生效开始时间';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.valid_to IS '生效结束时间';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.created_by IS '创建人';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN achievement.ac_achievement_rule_template.updated_at IS '更新时间';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_achievement_tenant_status
|
||||
ON achievement.ac_achievement(tenant_id, status, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_achievement_role_rel_role
|
||||
ON achievement.ac_achievement_role_rel(role_id, tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_user_role
|
||||
ON achievement.ac_user_achievement(user_id, role_id, last_achieved_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_tenant_time
|
||||
ON achievement.ac_user_achievement(tenant_id, last_achieved_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_summary
|
||||
ON achievement.ac_user_achievement(summary_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_task
|
||||
ON achievement.ac_user_achievement(grading_task_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_progress_user_status
|
||||
ON achievement.ac_user_achievement_progress(user_id, role_id, progress_status, last_evaluated_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_progress_tenant_status
|
||||
ON achievement.ac_user_achievement_progress(tenant_id, progress_status, last_evaluated_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_progress_achievement
|
||||
ON achievement.ac_user_achievement_progress(achievement_id, role_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_progress_streak
|
||||
ON achievement.ac_user_achievement_progress(user_id, role_id, streak_days DESC, last_evaluated_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_daily_fact_tenant_date
|
||||
ON achievement.ac_user_achievement_daily_fact(tenant_id, stat_date DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_user_achievement_daily_fact_user_date
|
||||
ON achievement.ac_user_achievement_daily_fact(user_id, role_id, stat_date DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_achievement_event_dict_tenant_enabled
|
||||
ON achievement.ac_achievement_event_dict(tenant_id, enabled, event_domain);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_achievement_metric_def_tenant_enabled
|
||||
ON achievement.ac_achievement_metric_def(tenant_id, enabled, source_domain);
|
||||
CREATE INDEX IF NOT EXISTS idx_ac_achievement_rule_template_tenant_event
|
||||
ON achievement.ac_achievement_rule_template(tenant_id, event_code, template_status, priority);
|
||||
2
init/pg/achievement/20_init_achievement_seed.sql
Normal file
2
init/pg/achievement/20_init_achievement_seed.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- 成就模块初始化数据占位
|
||||
-- 按需补充学生成就、教师成就及角色绑定关系种子数据
|
||||
@@ -1,47 +1,215 @@
|
||||
CREATE TABLE IF NOT EXISTS ai.tb_ai_model_config (
|
||||
model_id VARCHAR(64) PRIMARY KEY,
|
||||
model_name VARCHAR(128) NOT NULL,
|
||||
provider VARCHAR(64) NOT NULL,
|
||||
endpoint VARCHAR(255),
|
||||
adcode VARCHAR(12),
|
||||
tenant_id VARCHAR(64),
|
||||
tenant_path VARCHAR(255),
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
COMMENT ON TABLE ai.tb_ai_model_config IS 'AI模型配置表';
|
||||
COMMENT ON COLUMN ai.tb_ai_model_config.model_id IS '模型ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_model_config.model_name IS '模型名称';
|
||||
COMMENT ON COLUMN ai.tb_ai_model_config.provider IS '模型提供商';
|
||||
COMMENT ON COLUMN ai.tb_ai_model_config.endpoint IS '模型服务地址';
|
||||
COMMENT ON COLUMN ai.tb_ai_model_config.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN ai.tb_ai_model_config.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_model_config.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN ai.tb_ai_model_config.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_model_config.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN ai.tb_ai_model_config.created_at IS '创建时间';
|
||||
DROP SCHEMA IF EXISTS ai CASCADE;
|
||||
CREATE SCHEMA IF NOT EXISTS ai;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ai.tb_ai_task_log (
|
||||
task_id VARCHAR(64) PRIMARY KEY,
|
||||
task_type VARCHAR(64) NOT NULL,
|
||||
task_status VARCHAR(32) NOT NULL,
|
||||
adcode VARCHAR(12),
|
||||
tenant_id VARCHAR(64),
|
||||
tenant_path VARCHAR(255),
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
payload_json TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
DROP TABLE IF EXISTS ai.tb_ai_knowledge_file CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS ai.tb_ai_knowledge_file (
|
||||
file_id VARCHAR(64) PRIMARY KEY,
|
||||
file_code VARCHAR(64) UNIQUE NOT NULL,
|
||||
file_name VARCHAR(255) NOT NULL,
|
||||
source_file_id VARCHAR(64),
|
||||
file_type VARCHAR(32) NOT NULL DEFAULT 'DOCUMENT',
|
||||
file_status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE',
|
||||
graph_sync_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
|
||||
vector_sync_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
|
||||
graph_doc_ref VARCHAR(128),
|
||||
vector_doc_ref VARCHAR(128),
|
||||
content_checksum VARCHAR(128),
|
||||
metadata_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
adcode VARCHAR(12),
|
||||
tenant_id VARCHAR(64),
|
||||
tenant_path VARCHAR(255),
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_ai_knowledge_file_type
|
||||
CHECK (file_type IN ('DOCUMENT', 'PDF', 'IMAGE', 'OTHER')),
|
||||
CONSTRAINT chk_ai_knowledge_file_status
|
||||
CHECK (file_status IN ('ACTIVE', 'DISABLED')),
|
||||
CONSTRAINT chk_ai_knowledge_file_graph_status
|
||||
CHECK (graph_sync_status IN ('PENDING', 'SYNCED', 'FAILED')),
|
||||
CONSTRAINT chk_ai_knowledge_file_vector_status
|
||||
CHECK (vector_sync_status IN ('PENDING', 'SYNCED', 'FAILED')),
|
||||
CONSTRAINT chk_ai_knowledge_file_metadata_json
|
||||
CHECK (jsonb_typeof(metadata_json) = 'object'),
|
||||
CONSTRAINT fk_ai_knowledge_file_source_file
|
||||
FOREIGN KEY (source_file_id) REFERENCES upms.tb_sys_file(file_id)
|
||||
);
|
||||
COMMENT ON TABLE ai.tb_ai_task_log IS 'AI任务日志表';
|
||||
COMMENT ON COLUMN ai.tb_ai_task_log.task_id IS '任务ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_task_log.task_type IS '任务类型';
|
||||
COMMENT ON COLUMN ai.tb_ai_task_log.task_status IS '任务状态';
|
||||
COMMENT ON COLUMN ai.tb_ai_task_log.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN ai.tb_ai_task_log.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_task_log.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN ai.tb_ai_task_log.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_task_log.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN ai.tb_ai_task_log.payload_json IS '任务载荷JSON';
|
||||
COMMENT ON COLUMN ai.tb_ai_task_log.created_at IS '创建时间';
|
||||
COMMENT ON TABLE ai.tb_ai_knowledge_file IS '知识文件主表(统一管理图谱和向量知识库入库对象)';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.file_id IS '知识文件ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.file_code IS '知识文件编码';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.file_name IS '知识文件名称';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.source_file_id IS '来源文件ID(upms.tb_sys_file.file_id)';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.file_type IS '文件类型';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.file_status IS '文件状态';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.graph_sync_status IS '图谱同步状态';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.vector_sync_status IS '向量库同步状态';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.graph_doc_ref IS '图谱侧文档/对象引用';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.vector_doc_ref IS '向量库侧文档/对象引用';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.content_checksum IS '内容校验值';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.metadata_json IS '文件元数据JSON';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_file.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS ai.tb_ai_knowledge_sync_task CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS ai.tb_ai_knowledge_sync_task (
|
||||
task_id VARCHAR(64) PRIMARY KEY,
|
||||
file_id VARCHAR(64) NOT NULL,
|
||||
target_store VARCHAR(16) NOT NULL,
|
||||
task_type VARCHAR(16) NOT NULL DEFAULT 'UPSERT',
|
||||
task_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
|
||||
retry_count INTEGER NOT NULL DEFAULT 0,
|
||||
error_message TEXT,
|
||||
payload_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
adcode VARCHAR(12),
|
||||
tenant_id VARCHAR(64),
|
||||
tenant_path VARCHAR(255),
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_ai_knowledge_sync_task_store
|
||||
CHECK (target_store IN ('GRAPH', 'VECTOR')),
|
||||
CONSTRAINT chk_ai_knowledge_sync_task_type
|
||||
CHECK (task_type IN ('UPSERT', 'DELETE', 'REBUILD')),
|
||||
CONSTRAINT chk_ai_knowledge_sync_task_status
|
||||
CHECK (task_status IN ('PENDING', 'RUNNING', 'SUCCESS', 'FAILED')),
|
||||
CONSTRAINT chk_ai_knowledge_sync_task_retry
|
||||
CHECK (retry_count >= 0),
|
||||
CONSTRAINT chk_ai_knowledge_sync_task_payload_json
|
||||
CHECK (jsonb_typeof(payload_json) = 'object'),
|
||||
CONSTRAINT fk_ai_knowledge_sync_task_file
|
||||
FOREIGN KEY (file_id) REFERENCES ai.tb_ai_knowledge_file(file_id) ON DELETE CASCADE
|
||||
);
|
||||
COMMENT ON TABLE ai.tb_ai_knowledge_sync_task IS '知识文件同步任务表(同步到图谱或向量知识库)';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.task_id IS '同步任务ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.file_id IS '知识文件ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.target_store IS '目标存储(GRAPH/VECTOR)';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.task_type IS '任务类型(UPSERT/DELETE/REBUILD)';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.task_status IS '任务状态';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.retry_count IS '重试次数';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.error_message IS '错误信息';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.payload_json IS '任务载荷JSON';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN ai.tb_ai_knowledge_sync_task.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS ai.tb_ai_graph_entity CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS ai.tb_ai_graph_entity (
|
||||
entity_id VARCHAR(64) PRIMARY KEY,
|
||||
file_id VARCHAR(64),
|
||||
entity_type VARCHAR(64) NOT NULL,
|
||||
entity_name VARCHAR(255) NOT NULL,
|
||||
normalized_name VARCHAR(255),
|
||||
graph_vertex_id VARCHAR(128),
|
||||
entity_status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE',
|
||||
sync_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
|
||||
properties_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
adcode VARCHAR(12),
|
||||
tenant_id VARCHAR(64),
|
||||
tenant_path VARCHAR(255),
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uk_ai_graph_entity_file_name_type
|
||||
UNIQUE (file_id, entity_name, entity_type),
|
||||
CONSTRAINT chk_ai_graph_entity_status
|
||||
CHECK (entity_status IN ('ACTIVE', 'DISABLED')),
|
||||
CONSTRAINT chk_ai_graph_entity_sync_status
|
||||
CHECK (sync_status IN ('PENDING', 'SYNCED', 'FAILED')),
|
||||
CONSTRAINT chk_ai_graph_entity_properties_json
|
||||
CHECK (jsonb_typeof(properties_json) = 'object'),
|
||||
CONSTRAINT fk_ai_graph_entity_file
|
||||
FOREIGN KEY (file_id) REFERENCES ai.tb_ai_knowledge_file(file_id) ON DELETE SET NULL
|
||||
);
|
||||
COMMENT ON TABLE ai.tb_ai_graph_entity IS '图谱实体表(用于实体绑定)';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.entity_id IS '实体ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.file_id IS '来源知识文件ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.entity_type IS '实体类型';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.entity_name IS '实体名称';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.normalized_name IS '标准化实体名称';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.graph_vertex_id IS '图数据库顶点ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.entity_status IS '实体状态';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.sync_status IS '同步状态';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.properties_json IS '实体属性JSON';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_entity.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS ai.tb_ai_graph_relation CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS ai.tb_ai_graph_relation (
|
||||
relation_id VARCHAR(64) PRIMARY KEY,
|
||||
src_entity_id VARCHAR(64) NOT NULL,
|
||||
dst_entity_id VARCHAR(64) NOT NULL,
|
||||
relation_type VARCHAR(64) NOT NULL,
|
||||
relation_name VARCHAR(128),
|
||||
graph_edge_id VARCHAR(128),
|
||||
relation_weight NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
|
||||
relation_status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE',
|
||||
sync_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
|
||||
properties_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
adcode VARCHAR(12),
|
||||
tenant_id VARCHAR(64),
|
||||
tenant_path VARCHAR(255),
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uk_ai_graph_relation_src_dst_type
|
||||
UNIQUE (src_entity_id, dst_entity_id, relation_type),
|
||||
CONSTRAINT chk_ai_graph_relation_src_dst
|
||||
CHECK (src_entity_id <> dst_entity_id),
|
||||
CONSTRAINT chk_ai_graph_relation_weight
|
||||
CHECK (relation_weight > 0 AND relation_weight <= 1),
|
||||
CONSTRAINT chk_ai_graph_relation_status
|
||||
CHECK (relation_status IN ('ACTIVE', 'DISABLED')),
|
||||
CONSTRAINT chk_ai_graph_relation_sync_status
|
||||
CHECK (sync_status IN ('PENDING', 'SYNCED', 'FAILED')),
|
||||
CONSTRAINT chk_ai_graph_relation_properties_json
|
||||
CHECK (jsonb_typeof(properties_json) = 'object'),
|
||||
CONSTRAINT fk_ai_graph_relation_src
|
||||
FOREIGN KEY (src_entity_id) REFERENCES ai.tb_ai_graph_entity(entity_id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_ai_graph_relation_dst
|
||||
FOREIGN KEY (dst_entity_id) REFERENCES ai.tb_ai_graph_entity(entity_id) ON DELETE CASCADE
|
||||
);
|
||||
COMMENT ON TABLE ai.tb_ai_graph_relation IS '图谱实体关联表(用于实体关系绑定)';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.relation_id IS '关系ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.src_entity_id IS '源实体ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.dst_entity_id IS '目标实体ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.relation_type IS '关系类型';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.relation_name IS '关系名称';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.graph_edge_id IS '图数据库边ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.relation_weight IS '关系权重';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.relation_status IS '关系状态';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.sync_status IS '同步状态';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.properties_json IS '关系属性JSON';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN ai.tb_ai_graph_relation.updated_at IS '更新时间';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ai_knowledge_file_sync_status
|
||||
ON ai.tb_ai_knowledge_file(graph_sync_status, vector_sync_status, updated_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_ai_knowledge_sync_task_status
|
||||
ON ai.tb_ai_knowledge_sync_task(task_status, target_store, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_ai_graph_entity_name
|
||||
ON ai.tb_ai_graph_entity(entity_type, entity_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_ai_graph_relation_src_dst
|
||||
ON ai.tb_ai_graph_relation(src_entity_id, dst_entity_id, relation_type);
|
||||
|
||||
@@ -1,6 +1,60 @@
|
||||
INSERT INTO ai.tb_ai_model_config (
|
||||
model_id, model_name, provider, endpoint, adcode, tenant_id, tenant_path, dept_id, dept_path
|
||||
INSERT INTO ai.tb_ai_knowledge_file (
|
||||
file_id, file_code, file_name, file_type, file_status,
|
||||
graph_sync_status, vector_sync_status, metadata_json,
|
||||
adcode, tenant_id, tenant_path, dept_id, dept_path
|
||||
) VALUES (
|
||||
'MODEL-MOCK-001', 'mock-python-ai', 'local', 'http://localhost:9000', '330100', 'SCH-HQ', '/SCH-HQ/', 'DEPT-HQ-ADMIN', '/DEPT-HQ/DEPT-HQ-ADMIN/'
|
||||
'KF-DEMO-001', 'K12_DEMO_KNOWLEDGE_FILE', 'K12示例知识文件', 'DOCUMENT', 'ACTIVE',
|
||||
'PENDING', 'PENDING', '{"source":"seed","scenario":"knowledge_file_management"}'::JSONB,
|
||||
'330100', 'SCH-HQ', '/SCH-HQ/', 'DEPT-HQ-ADMIN', '/DEPT-HQ/DEPT-HQ-ADMIN/'
|
||||
)
|
||||
ON CONFLICT (model_id) DO NOTHING;
|
||||
ON CONFLICT (file_id) DO NOTHING;
|
||||
|
||||
INSERT INTO ai.tb_ai_graph_entity (
|
||||
entity_id, file_id, entity_type, entity_name, normalized_name, sync_status, properties_json,
|
||||
adcode, tenant_id, tenant_path, dept_id, dept_path
|
||||
) VALUES (
|
||||
'GE-KP-001', 'KF-DEMO-001', 'KNOWLEDGE_POINT', '一次函数', '一次函数', 'PENDING',
|
||||
'{"subject":"math","grade":"7"}'::JSONB,
|
||||
'330100', 'SCH-HQ', '/SCH-HQ/', 'DEPT-HQ-ADMIN', '/DEPT-HQ/DEPT-HQ-ADMIN/'
|
||||
)
|
||||
ON CONFLICT (entity_id) DO NOTHING;
|
||||
|
||||
INSERT INTO ai.tb_ai_graph_entity (
|
||||
entity_id, file_id, entity_type, entity_name, normalized_name, sync_status, properties_json,
|
||||
adcode, tenant_id, tenant_path, dept_id, dept_path
|
||||
) VALUES (
|
||||
'GE-QUESTION-001', 'KF-DEMO-001', 'QUESTION', '一次函数应用题', '一次函数应用题', 'PENDING',
|
||||
'{"difficulty":"MEDIUM"}'::JSONB,
|
||||
'330100', 'SCH-HQ', '/SCH-HQ/', 'DEPT-HQ-ADMIN', '/DEPT-HQ/DEPT-HQ-ADMIN/'
|
||||
)
|
||||
ON CONFLICT (entity_id) DO NOTHING;
|
||||
|
||||
INSERT INTO ai.tb_ai_graph_relation (
|
||||
relation_id, src_entity_id, dst_entity_id, relation_type, relation_name, relation_weight, sync_status, properties_json,
|
||||
adcode, tenant_id, tenant_path, dept_id, dept_path
|
||||
) VALUES (
|
||||
'GR-001', 'GE-QUESTION-001', 'GE-KP-001', 'BELONGS_TO', '题目关联知识点', 1.0000, 'PENDING',
|
||||
'{"source":"manual_binding"}'::JSONB,
|
||||
'330100', 'SCH-HQ', '/SCH-HQ/', 'DEPT-HQ-ADMIN', '/DEPT-HQ/DEPT-HQ-ADMIN/'
|
||||
)
|
||||
ON CONFLICT (relation_id) DO NOTHING;
|
||||
|
||||
INSERT INTO ai.tb_ai_knowledge_sync_task (
|
||||
task_id, file_id, target_store, task_type, task_status, payload_json,
|
||||
adcode, tenant_id, tenant_path, dept_id, dept_path
|
||||
) VALUES (
|
||||
'KST-GRAPH-001', 'KF-DEMO-001', 'GRAPH', 'UPSERT', 'PENDING',
|
||||
'{"trigger":"seed","description":"sync to graph store"}'::JSONB,
|
||||
'330100', 'SCH-HQ', '/SCH-HQ/', 'DEPT-HQ-ADMIN', '/DEPT-HQ/DEPT-HQ-ADMIN/'
|
||||
)
|
||||
ON CONFLICT (task_id) DO NOTHING;
|
||||
|
||||
INSERT INTO ai.tb_ai_knowledge_sync_task (
|
||||
task_id, file_id, target_store, task_type, task_status, payload_json,
|
||||
adcode, tenant_id, tenant_path, dept_id, dept_path
|
||||
) VALUES (
|
||||
'KST-VECTOR-001', 'KF-DEMO-001', 'VECTOR', 'UPSERT', 'PENDING',
|
||||
'{"trigger":"seed","description":"sync to vector store"}'::JSONB,
|
||||
'330100', 'SCH-HQ', '/SCH-HQ/', 'DEPT-HQ-ADMIN', '/DEPT-HQ/DEPT-HQ-ADMIN/'
|
||||
)
|
||||
ON CONFLICT (task_id) DO NOTHING;
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
DROP SCHEMA IF EXISTS auth CASCADE;
|
||||
CREATE SCHEMA IF NOT EXISTS auth;
|
||||
|
||||
DROP TABLE IF EXISTS auth.tb_auth_refresh_token CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS auth.tb_auth_refresh_token (
|
||||
token_id VARCHAR(64) PRIMARY KEY,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
@@ -26,6 +30,7 @@ COMMENT ON COLUMN auth.tb_auth_refresh_token.expire_at IS '过期时间';
|
||||
COMMENT ON COLUMN auth.tb_auth_refresh_token.revoked IS '是否撤销';
|
||||
COMMENT ON COLUMN auth.tb_auth_refresh_token.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS auth.tb_auth_login_audit CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS auth.tb_auth_login_audit (
|
||||
audit_id VARCHAR(64) PRIMARY KEY,
|
||||
user_id VARCHAR(64),
|
||||
|
||||
512
init/pg/course/10_create_course_tables.sql
Normal file
512
init/pg/course/10_create_course_tables.sql
Normal file
@@ -0,0 +1,512 @@
|
||||
DROP SCHEMA IF EXISTS course CASCADE;
|
||||
CREATE SCHEMA IF NOT EXISTS course;
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_course CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_course (
|
||||
course_id VARCHAR(64) PRIMARY KEY,
|
||||
title VARCHAR(256) NOT NULL,
|
||||
subject_code VARCHAR(32) NOT NULL,
|
||||
grade_code VARCHAR(32) NOT NULL,
|
||||
difficulty_level VARCHAR(16),
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'DRAFT',
|
||||
adcode VARCHAR(12) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255) NOT NULL,
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
created_by VARCHAR(64),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
COMMENT ON TABLE course.cl_course IS '课程主表';
|
||||
COMMENT ON COLUMN course.cl_course.course_id IS '课程ID';
|
||||
COMMENT ON COLUMN course.cl_course.title IS '课程标题';
|
||||
COMMENT ON COLUMN course.cl_course.subject_code IS '学科编码';
|
||||
COMMENT ON COLUMN course.cl_course.grade_code IS '年级编码';
|
||||
COMMENT ON COLUMN course.cl_course.difficulty_level IS '难度等级';
|
||||
COMMENT ON COLUMN course.cl_course.status IS '状态(DRAFT/PUBLISHED/ARCHIVED)';
|
||||
COMMENT ON COLUMN course.cl_course.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN course.cl_course.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_course.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN course.cl_course.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN course.cl_course.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN course.cl_course.created_by IS '创建人ID';
|
||||
COMMENT ON COLUMN course.cl_course.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_course_chapter CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_course_chapter (
|
||||
chapter_id VARCHAR(64) PRIMARY KEY,
|
||||
course_id VARCHAR(64) NOT NULL,
|
||||
chapter_no INTEGER NOT NULL,
|
||||
chapter_title VARCHAR(256) NOT NULL,
|
||||
adcode VARCHAR(12) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_cl_course_chapter_course
|
||||
FOREIGN KEY (course_id) REFERENCES course.cl_course(course_id)
|
||||
);
|
||||
COMMENT ON TABLE course.cl_course_chapter IS '课程章节表';
|
||||
COMMENT ON COLUMN course.cl_course_chapter.chapter_id IS '章节ID';
|
||||
COMMENT ON COLUMN course.cl_course_chapter.course_id IS '课程ID';
|
||||
COMMENT ON COLUMN course.cl_course_chapter.chapter_no IS '章节序号';
|
||||
COMMENT ON COLUMN course.cl_course_chapter.chapter_title IS '章节标题';
|
||||
COMMENT ON COLUMN course.cl_course_chapter.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN course.cl_course_chapter.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_course_chapter.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN course.cl_course_chapter.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_course_node CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_course_node (
|
||||
node_id VARCHAR(64) PRIMARY KEY,
|
||||
chapter_id VARCHAR(64) NOT NULL,
|
||||
node_no INTEGER NOT NULL,
|
||||
node_title VARCHAR(256) NOT NULL,
|
||||
node_type VARCHAR(32) NOT NULL DEFAULT 'LESSON',
|
||||
class_type VARCHAR(32),
|
||||
duration_sec INTEGER,
|
||||
adcode VARCHAR(12) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_cl_course_node_type
|
||||
CHECK (node_type IN ('LESSON', 'IN_CLASS_ACTIVITY', 'AFTER_CLASS_TASK', 'MATERIAL', 'OTHER')),
|
||||
CONSTRAINT fk_cl_course_node_chapter
|
||||
FOREIGN KEY (chapter_id) REFERENCES course.cl_course_chapter(chapter_id)
|
||||
);
|
||||
COMMENT ON TABLE course.cl_course_node IS '课程学习节点表';
|
||||
COMMENT ON COLUMN course.cl_course_node.node_id IS '学习节点ID';
|
||||
COMMENT ON COLUMN course.cl_course_node.chapter_id IS '章节ID';
|
||||
COMMENT ON COLUMN course.cl_course_node.node_no IS '节点序号';
|
||||
COMMENT ON COLUMN course.cl_course_node.node_title IS '节点标题';
|
||||
COMMENT ON COLUMN course.cl_course_node.node_type IS '节点类型(LESSON/IN_CLASS_ACTIVITY/AFTER_CLASS_TASK/MATERIAL/OTHER)';
|
||||
COMMENT ON COLUMN course.cl_course_node.class_type IS '课堂类型(如讲授/讨论/测验)';
|
||||
COMMENT ON COLUMN course.cl_course_node.duration_sec IS '时长(秒)';
|
||||
COMMENT ON COLUMN course.cl_course_node.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN course.cl_course_node.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_course_node.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN course.cl_course_node.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_knowledge_point CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_knowledge_point (
|
||||
kp_id VARCHAR(64) PRIMARY KEY,
|
||||
kp_code VARCHAR(64) NOT NULL,
|
||||
kp_name VARCHAR(256) NOT NULL,
|
||||
kp_alias VARCHAR(256),
|
||||
kp_type VARCHAR(32) NOT NULL DEFAULT 'ATOMIC',
|
||||
parent_kp_id VARCHAR(64),
|
||||
kp_path VARCHAR(512),
|
||||
kp_desc TEXT,
|
||||
subject_code VARCHAR(32) NOT NULL,
|
||||
grade_code VARCHAR(32) NOT NULL,
|
||||
difficulty_level VARCHAR(16),
|
||||
importance_level NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
|
||||
graph_entity_id VARCHAR(64),
|
||||
source_db VARCHAR(64) NOT NULL DEFAULT 'postgresql',
|
||||
source_table VARCHAR(128) NOT NULL DEFAULT 'course.cl_knowledge_point',
|
||||
source_pk VARCHAR(128),
|
||||
metadata_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE',
|
||||
adcode VARCHAR(12) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255) NOT NULL,
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_cl_knowledge_point_tenant_code
|
||||
UNIQUE (tenant_id, kp_code),
|
||||
CONSTRAINT uq_cl_knowledge_point_tenant_graph_entity
|
||||
UNIQUE (tenant_id, graph_entity_id),
|
||||
CONSTRAINT chk_cl_knowledge_point_type
|
||||
CHECK (kp_type IN ('DOMAIN', 'TOPIC', 'ATOMIC')),
|
||||
CONSTRAINT chk_cl_knowledge_point_importance
|
||||
CHECK (importance_level > 0 AND importance_level <= 1),
|
||||
CONSTRAINT chk_cl_knowledge_point_metadata_json
|
||||
CHECK (jsonb_typeof(metadata_json) = 'object'),
|
||||
CONSTRAINT fk_cl_knowledge_point_parent
|
||||
FOREIGN KEY (parent_kp_id) REFERENCES course.cl_knowledge_point(kp_id) ON DELETE SET NULL
|
||||
);
|
||||
COMMENT ON TABLE course.cl_knowledge_point IS '知识点表';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.kp_id IS '知识点ID';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.kp_code IS '知识点编码';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.kp_name IS '知识点名称';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.kp_alias IS '知识点别名';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.kp_type IS '知识点类型(DOMAIN/TOPIC/ATOMIC)';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.parent_kp_id IS '父知识点ID';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.kp_path IS '知识点树路径';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.kp_desc IS '知识点描述';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.subject_code IS '学科编码';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.grade_code IS '年级编码';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.difficulty_level IS '难度等级';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.importance_level IS '重要性权重(0,1]';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.graph_entity_id IS '图谱实体ID(Nebula/Neo4j 映射)';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.source_db IS '来源数据库';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.source_table IS '来源表';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.source_pk IS '来源主键';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.metadata_json IS '扩展元数据JSON';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.status IS '状态(ACTIVE/DISABLED)';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN course.cl_knowledge_point.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_chapter_kp_rel CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_chapter_kp_rel (
|
||||
chapter_id VARCHAR(64) NOT NULL,
|
||||
kp_id VARCHAR(64) NOT NULL,
|
||||
relation_type VARCHAR(32) NOT NULL DEFAULT 'TEACHES',
|
||||
weight NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
|
||||
is_core BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (chapter_id, kp_id),
|
||||
CONSTRAINT chk_cl_chapter_kp_rel_type
|
||||
CHECK (relation_type IN ('TEACHES', 'REVIEWS', 'EXTENDS')),
|
||||
CONSTRAINT chk_cl_chapter_kp_rel_weight
|
||||
CHECK (weight > 0 AND weight <= 1),
|
||||
CONSTRAINT fk_cl_chapter_kp_rel_chapter
|
||||
FOREIGN KEY (chapter_id) REFERENCES course.cl_course_chapter(chapter_id),
|
||||
CONSTRAINT fk_cl_chapter_kp_rel_kp
|
||||
FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id)
|
||||
);
|
||||
COMMENT ON TABLE course.cl_chapter_kp_rel IS '章节-知识点关联表';
|
||||
COMMENT ON COLUMN course.cl_chapter_kp_rel.chapter_id IS '章节ID';
|
||||
COMMENT ON COLUMN course.cl_chapter_kp_rel.kp_id IS '知识点ID';
|
||||
COMMENT ON COLUMN course.cl_chapter_kp_rel.relation_type IS '关系类型(TEACHES/REVIEWS/EXTENDS)';
|
||||
COMMENT ON COLUMN course.cl_chapter_kp_rel.weight IS '关联权重(0,1]';
|
||||
COMMENT ON COLUMN course.cl_chapter_kp_rel.is_core IS '是否核心知识点';
|
||||
COMMENT ON COLUMN course.cl_chapter_kp_rel.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_chapter_kp_rel.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN course.cl_chapter_kp_rel.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_student_kp_mastery CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_student_kp_mastery (
|
||||
mastery_id VARCHAR(64) PRIMARY KEY,
|
||||
student_id VARCHAR(64) NOT NULL,
|
||||
kp_id VARCHAR(64) NOT NULL,
|
||||
mastery_score NUMERIC(6,4) NOT NULL DEFAULT 0,
|
||||
mastery_level VARCHAR(16) NOT NULL DEFAULT 'UNKNOWN',
|
||||
mastery_status VARCHAR(16) NOT NULL DEFAULT 'LEARNING',
|
||||
evidence_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
last_source_type VARCHAR(32),
|
||||
last_source_id VARCHAR(64),
|
||||
last_assessed_at TIMESTAMP,
|
||||
adcode VARCHAR(12) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255) NOT NULL,
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_cl_student_kp_mastery_student_kp
|
||||
UNIQUE (student_id, kp_id),
|
||||
CONSTRAINT chk_cl_student_kp_mastery_score
|
||||
CHECK (mastery_score >= 0 AND mastery_score <= 1),
|
||||
CONSTRAINT chk_cl_student_kp_mastery_level
|
||||
CHECK (mastery_level IN ('UNKNOWN', 'LOW', 'MEDIUM', 'HIGH', 'MASTERED')),
|
||||
CONSTRAINT chk_cl_student_kp_mastery_status
|
||||
CHECK (mastery_status IN ('LEARNING', 'STABLE', 'FORGOTTEN')),
|
||||
CONSTRAINT chk_cl_student_kp_mastery_evidence_json
|
||||
CHECK (jsonb_typeof(evidence_json) = 'object'),
|
||||
CONSTRAINT fk_cl_student_kp_mastery_student
|
||||
FOREIGN KEY (student_id) REFERENCES upms.tb_sys_user(user_id),
|
||||
CONSTRAINT fk_cl_student_kp_mastery_kp
|
||||
FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id)
|
||||
);
|
||||
COMMENT ON TABLE course.cl_student_kp_mastery IS '学生知识点掌握度表';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.mastery_id IS '掌握度记录ID';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.student_id IS '学生ID';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.kp_id IS '知识点ID';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.mastery_score IS '掌握度分值(0-1)';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.mastery_level IS '掌握等级';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.mastery_status IS '掌握状态(LEARNING/STABLE/FORGOTTEN)';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.evidence_json IS '证据数据JSON(错题、批改、学习行为等)';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.last_source_type IS '最近更新来源类型';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.last_source_id IS '最近更新来源ID';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.last_assessed_at IS '最近评估时间';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN course.cl_student_kp_mastery.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_kp_material_rel CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_kp_material_rel (
|
||||
rel_id VARCHAR(64) PRIMARY KEY,
|
||||
kp_id VARCHAR(64) NOT NULL,
|
||||
material_type VARCHAR(32) NOT NULL,
|
||||
material_ref_id VARCHAR(64) NOT NULL,
|
||||
material_uri VARCHAR(512),
|
||||
weight NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
|
||||
source_table VARCHAR(128),
|
||||
source_pk VARCHAR(128),
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_cl_kp_material_rel_type
|
||||
CHECK (material_type IN ('VECTOR_DOCUMENT', 'VECTOR_CHUNK', 'COURSE_RESOURCE', 'EXTERNAL_URI')),
|
||||
CONSTRAINT chk_cl_kp_material_rel_weight
|
||||
CHECK (weight > 0 AND weight <= 1),
|
||||
CONSTRAINT fk_cl_kp_material_rel_kp
|
||||
FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id)
|
||||
);
|
||||
COMMENT ON TABLE course.cl_kp_material_rel IS '知识点-学习资料关联表';
|
||||
COMMENT ON COLUMN course.cl_kp_material_rel.rel_id IS '关联ID';
|
||||
COMMENT ON COLUMN course.cl_kp_material_rel.kp_id IS '知识点ID';
|
||||
COMMENT ON COLUMN course.cl_kp_material_rel.material_type IS '资料类型(VECTOR_DOCUMENT/VECTOR_CHUNK/COURSE_RESOURCE/EXTERNAL_URI)';
|
||||
COMMENT ON COLUMN course.cl_kp_material_rel.material_ref_id IS '资料对象ID';
|
||||
COMMENT ON COLUMN course.cl_kp_material_rel.material_uri IS '资料URI';
|
||||
COMMENT ON COLUMN course.cl_kp_material_rel.weight IS '关联权重(0,1]';
|
||||
COMMENT ON COLUMN course.cl_kp_material_rel.source_table IS '来源表';
|
||||
COMMENT ON COLUMN course.cl_kp_material_rel.source_pk IS '来源主键';
|
||||
COMMENT ON COLUMN course.cl_kp_material_rel.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_kp_material_rel.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN course.cl_kp_material_rel.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_course_knowledge_rel CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_course_knowledge_rel (
|
||||
course_id VARCHAR(64) NOT NULL,
|
||||
kp_id VARCHAR(64) NOT NULL,
|
||||
weight NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (course_id, kp_id),
|
||||
CONSTRAINT chk_cl_course_knowledge_rel_weight
|
||||
CHECK (weight > 0 AND weight <= 1),
|
||||
CONSTRAINT fk_cl_course_knowledge_rel_course
|
||||
FOREIGN KEY (course_id) REFERENCES course.cl_course(course_id),
|
||||
CONSTRAINT fk_cl_course_knowledge_rel_kp
|
||||
FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id)
|
||||
);
|
||||
COMMENT ON TABLE course.cl_course_knowledge_rel IS '课程-知识点关联表';
|
||||
COMMENT ON COLUMN course.cl_course_knowledge_rel.course_id IS '课程ID';
|
||||
COMMENT ON COLUMN course.cl_course_knowledge_rel.kp_id IS '知识点ID';
|
||||
COMMENT ON COLUMN course.cl_course_knowledge_rel.weight IS '关联权重(0,1])';
|
||||
COMMENT ON COLUMN course.cl_course_knowledge_rel.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_course_knowledge_rel.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_course_tag CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_course_tag (
|
||||
tag_id VARCHAR(64) PRIMARY KEY,
|
||||
tag_name VARCHAR(128) NOT NULL,
|
||||
tag_type VARCHAR(32) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
COMMENT ON TABLE course.cl_course_tag IS '课程标签表';
|
||||
COMMENT ON COLUMN course.cl_course_tag.tag_id IS '标签ID';
|
||||
COMMENT ON COLUMN course.cl_course_tag.tag_name IS '标签名称';
|
||||
COMMENT ON COLUMN course.cl_course_tag.tag_type IS '标签类型';
|
||||
COMMENT ON COLUMN course.cl_course_tag.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_course_tag.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_course_tag_rel CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_course_tag_rel (
|
||||
course_id VARCHAR(64) NOT NULL,
|
||||
tag_id VARCHAR(64) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (course_id, tag_id),
|
||||
CONSTRAINT fk_cl_course_tag_rel_course
|
||||
FOREIGN KEY (course_id) REFERENCES course.cl_course(course_id),
|
||||
CONSTRAINT fk_cl_course_tag_rel_tag
|
||||
FOREIGN KEY (tag_id) REFERENCES course.cl_course_tag(tag_id)
|
||||
);
|
||||
COMMENT ON TABLE course.cl_course_tag_rel IS '课程-标签关联表';
|
||||
COMMENT ON COLUMN course.cl_course_tag_rel.course_id IS '课程ID';
|
||||
COMMENT ON COLUMN course.cl_course_tag_rel.tag_id IS '标签ID';
|
||||
COMMENT ON COLUMN course.cl_course_tag_rel.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_course_tag_rel.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_node_resource CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_node_resource (
|
||||
resource_id VARCHAR(64) PRIMARY KEY,
|
||||
node_id VARCHAR(64) NOT NULL,
|
||||
resource_type VARCHAR(32) NOT NULL,
|
||||
file_id VARCHAR(64),
|
||||
resource_url VARCHAR(512),
|
||||
resource_title VARCHAR(256),
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_cl_node_resource_type
|
||||
CHECK (resource_type IN ('PDF', 'VIDEO', 'DOC', 'IMAGE', 'LINK', 'OTHER')),
|
||||
CONSTRAINT chk_cl_node_resource_ref
|
||||
CHECK (file_id IS NOT NULL OR resource_url IS NOT NULL),
|
||||
CONSTRAINT fk_cl_node_resource_node
|
||||
FOREIGN KEY (node_id) REFERENCES course.cl_course_node(node_id),
|
||||
CONSTRAINT fk_cl_node_resource_file
|
||||
FOREIGN KEY (file_id) REFERENCES upms.tb_sys_file(file_id)
|
||||
);
|
||||
COMMENT ON TABLE course.cl_node_resource IS '学习节点资源表';
|
||||
COMMENT ON COLUMN course.cl_node_resource.resource_id IS '资源ID';
|
||||
COMMENT ON COLUMN course.cl_node_resource.node_id IS '学习节点ID';
|
||||
COMMENT ON COLUMN course.cl_node_resource.resource_type IS '资源类型(PDF/VIDEO/DOC/IMAGE/LINK/OTHER)';
|
||||
COMMENT ON COLUMN course.cl_node_resource.file_id IS '资源文件ID';
|
||||
COMMENT ON COLUMN course.cl_node_resource.resource_url IS '资源地址';
|
||||
COMMENT ON COLUMN course.cl_node_resource.resource_title IS '资源标题';
|
||||
COMMENT ON COLUMN course.cl_node_resource.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_node_resource.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_node_kp_rel CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_node_kp_rel (
|
||||
node_id VARCHAR(64) NOT NULL,
|
||||
kp_id VARCHAR(64) NOT NULL,
|
||||
relation_type VARCHAR(32) NOT NULL DEFAULT 'TEACHES',
|
||||
weight NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (node_id, kp_id),
|
||||
CONSTRAINT chk_cl_node_kp_rel_type
|
||||
CHECK (relation_type IN ('TEACHES', 'PRACTICES', 'REVIEWS')),
|
||||
CONSTRAINT chk_cl_node_kp_rel_weight
|
||||
CHECK (weight > 0 AND weight <= 1),
|
||||
CONSTRAINT fk_cl_node_kp_rel_node
|
||||
FOREIGN KEY (node_id) REFERENCES course.cl_course_node(node_id),
|
||||
CONSTRAINT fk_cl_node_kp_rel_kp
|
||||
FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id)
|
||||
);
|
||||
COMMENT ON TABLE course.cl_node_kp_rel IS '学习节点-知识点关联表';
|
||||
COMMENT ON COLUMN course.cl_node_kp_rel.node_id IS '学习节点ID';
|
||||
COMMENT ON COLUMN course.cl_node_kp_rel.kp_id IS '知识点ID';
|
||||
COMMENT ON COLUMN course.cl_node_kp_rel.relation_type IS '关系类型(TEACHES/PRACTICES/REVIEWS)';
|
||||
COMMENT ON COLUMN course.cl_node_kp_rel.weight IS '关联权重(0,1]';
|
||||
COMMENT ON COLUMN course.cl_node_kp_rel.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_node_kp_rel.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_node_homework_rel CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_node_homework_rel (
|
||||
node_id VARCHAR(64) NOT NULL,
|
||||
assignment_id VARCHAR(64) NOT NULL,
|
||||
relation_type VARCHAR(32) NOT NULL DEFAULT 'AFTER_CLASS',
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (node_id, assignment_id),
|
||||
CONSTRAINT chk_cl_node_homework_rel_type
|
||||
CHECK (relation_type IN ('IN_CLASS', 'AFTER_CLASS')),
|
||||
CONSTRAINT fk_cl_node_homework_rel_node
|
||||
FOREIGN KEY (node_id) REFERENCES course.cl_course_node(node_id)
|
||||
);
|
||||
COMMENT ON TABLE course.cl_node_homework_rel IS '学习节点-作业关联表';
|
||||
COMMENT ON COLUMN course.cl_node_homework_rel.node_id IS '学习节点ID';
|
||||
COMMENT ON COLUMN course.cl_node_homework_rel.assignment_id IS '作业ID(question.hw_assignment.assignment_id)';
|
||||
COMMENT ON COLUMN course.cl_node_homework_rel.relation_type IS '关系类型(IN_CLASS/AFTER_CLASS)';
|
||||
COMMENT ON COLUMN course.cl_node_homework_rel.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_node_homework_rel.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_learning_session CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_learning_session (
|
||||
session_id VARCHAR(64) PRIMARY KEY,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
course_id VARCHAR(64) NOT NULL,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'STARTED',
|
||||
started_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
ended_at TIMESTAMP,
|
||||
adcode VARCHAR(12) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255) NOT NULL,
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
CONSTRAINT fk_cl_learning_session_user
|
||||
FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id),
|
||||
CONSTRAINT fk_cl_learning_session_course
|
||||
FOREIGN KEY (course_id) REFERENCES course.cl_course(course_id)
|
||||
);
|
||||
COMMENT ON TABLE course.cl_learning_session IS '学习会话表';
|
||||
COMMENT ON COLUMN course.cl_learning_session.session_id IS '会话ID';
|
||||
COMMENT ON COLUMN course.cl_learning_session.user_id IS '学员ID';
|
||||
COMMENT ON COLUMN course.cl_learning_session.course_id IS '课程ID';
|
||||
COMMENT ON COLUMN course.cl_learning_session.status IS '会话状态(STARTED/PAUSED/COMPLETED)';
|
||||
COMMENT ON COLUMN course.cl_learning_session.started_at IS '开始时间';
|
||||
COMMENT ON COLUMN course.cl_learning_session.ended_at IS '结束时间';
|
||||
COMMENT ON COLUMN course.cl_learning_session.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN course.cl_learning_session.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_learning_session.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN course.cl_learning_session.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN course.cl_learning_session.dept_path IS '部门路径';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_learning_progress CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_learning_progress (
|
||||
progress_id VARCHAR(64) PRIMARY KEY,
|
||||
session_id VARCHAR(64) NOT NULL,
|
||||
node_id VARCHAR(64) NOT NULL,
|
||||
progress_pct NUMERIC(5,2) NOT NULL DEFAULT 0,
|
||||
last_position_sec INTEGER NOT NULL DEFAULT 0,
|
||||
mastery_level VARCHAR(16),
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_cl_learning_progress_session
|
||||
FOREIGN KEY (session_id) REFERENCES course.cl_learning_session(session_id),
|
||||
CONSTRAINT fk_cl_learning_progress_node
|
||||
FOREIGN KEY (node_id) REFERENCES course.cl_course_node(node_id)
|
||||
);
|
||||
COMMENT ON TABLE course.cl_learning_progress IS '学习进度表';
|
||||
COMMENT ON COLUMN course.cl_learning_progress.progress_id IS '进度ID';
|
||||
COMMENT ON COLUMN course.cl_learning_progress.session_id IS '学习会话ID';
|
||||
COMMENT ON COLUMN course.cl_learning_progress.node_id IS '学习节点ID';
|
||||
COMMENT ON COLUMN course.cl_learning_progress.progress_pct IS '进度百分比';
|
||||
COMMENT ON COLUMN course.cl_learning_progress.last_position_sec IS '最后学习位置(秒)';
|
||||
COMMENT ON COLUMN course.cl_learning_progress.mastery_level IS '掌握等级';
|
||||
COMMENT ON COLUMN course.cl_learning_progress.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN course.cl_learning_progress.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS course.cl_learning_event CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS course.cl_learning_event (
|
||||
event_id VARCHAR(64) PRIMARY KEY,
|
||||
session_id VARCHAR(64) NOT NULL,
|
||||
event_type VARCHAR(32) NOT NULL,
|
||||
event_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
payload_json JSONB,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
CONSTRAINT fk_cl_learning_event_session
|
||||
FOREIGN KEY (session_id) REFERENCES course.cl_learning_session(session_id)
|
||||
);
|
||||
COMMENT ON TABLE course.cl_learning_event IS '学习行为事件表';
|
||||
COMMENT ON COLUMN course.cl_learning_event.event_id IS '事件ID';
|
||||
COMMENT ON COLUMN course.cl_learning_event.session_id IS '会话ID';
|
||||
COMMENT ON COLUMN course.cl_learning_event.event_type IS '事件类型(start/pause/seek/finish)';
|
||||
COMMENT ON COLUMN course.cl_learning_event.event_time IS '事件时间';
|
||||
COMMENT ON COLUMN course.cl_learning_event.payload_json IS '事件扩展信息';
|
||||
COMMENT ON COLUMN course.cl_learning_event.tenant_id IS '租户ID';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_course_tenant_subject_grade
|
||||
ON course.cl_course(tenant_id, subject_code, grade_code);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_course_chapter_course_no
|
||||
ON course.cl_course_chapter(course_id, chapter_no);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_course_node_chapter_no
|
||||
ON course.cl_course_node(chapter_id, node_no);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_knowledge_point_subject_grade
|
||||
ON course.cl_knowledge_point(tenant_id, subject_code, grade_code);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_knowledge_point_parent
|
||||
ON course.cl_knowledge_point(tenant_id, parent_kp_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_knowledge_point_graph_entity
|
||||
ON course.cl_knowledge_point(tenant_id, graph_entity_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_chapter_kp_rel_chapter
|
||||
ON course.cl_chapter_kp_rel(tenant_id, chapter_id, relation_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_chapter_kp_rel_kp
|
||||
ON course.cl_chapter_kp_rel(tenant_id, kp_id, relation_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_student_kp_mastery_student
|
||||
ON course.cl_student_kp_mastery(tenant_id, student_id, mastery_score DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_student_kp_mastery_kp
|
||||
ON course.cl_student_kp_mastery(tenant_id, kp_id, mastery_score DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_kp_material_rel_kp
|
||||
ON course.cl_kp_material_rel(tenant_id, kp_id, material_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_node_resource_node
|
||||
ON course.cl_node_resource(node_id, resource_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_node_kp_rel_node
|
||||
ON course.cl_node_kp_rel(tenant_id, node_id, relation_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_node_kp_rel_kp
|
||||
ON course.cl_node_kp_rel(tenant_id, kp_id, relation_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_node_homework_rel_node
|
||||
ON course.cl_node_homework_rel(tenant_id, node_id, relation_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_learning_session_user_course
|
||||
ON course.cl_learning_session(tenant_id, user_id, course_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_learning_progress_session_node
|
||||
ON course.cl_learning_progress(session_id, node_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_cl_learning_event_session_time
|
||||
ON course.cl_learning_event(session_id, event_time DESC);
|
||||
2
init/pg/course/20_init_course_seed.sql
Normal file
2
init/pg/course/20_init_course_seed.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- 课程学习模块初始化数据占位
|
||||
-- 按需补充课程、章节、课时、知识点、标签等种子数据
|
||||
729
init/pg/question/10_create_question_tables.sql
Normal file
729
init/pg/question/10_create_question_tables.sql
Normal file
@@ -0,0 +1,729 @@
|
||||
DROP SCHEMA IF EXISTS question CASCADE;
|
||||
CREATE SCHEMA IF NOT EXISTS question;
|
||||
|
||||
DROP TABLE IF EXISTS question.hw_question_bank CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.hw_question_bank (
|
||||
bank_id VARCHAR(64) PRIMARY KEY,
|
||||
bank_name VARCHAR(256) NOT NULL,
|
||||
subject_code VARCHAR(32) NOT NULL,
|
||||
grade_code VARCHAR(32) NOT NULL,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE',
|
||||
adcode VARCHAR(12) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255) NOT NULL,
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
created_by VARCHAR(64),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
COMMENT ON TABLE question.hw_question_bank IS '题库表';
|
||||
COMMENT ON COLUMN question.hw_question_bank.bank_id IS '题库ID';
|
||||
COMMENT ON COLUMN question.hw_question_bank.bank_name IS '题库名称';
|
||||
COMMENT ON COLUMN question.hw_question_bank.subject_code IS '学科编码';
|
||||
COMMENT ON COLUMN question.hw_question_bank.grade_code IS '年级编码';
|
||||
COMMENT ON COLUMN question.hw_question_bank.status IS '状态';
|
||||
COMMENT ON COLUMN question.hw_question_bank.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN question.hw_question_bank.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.hw_question_bank.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN question.hw_question_bank.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN question.hw_question_bank.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN question.hw_question_bank.created_by IS '创建人ID';
|
||||
COMMENT ON COLUMN question.hw_question_bank.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.hw_question_item CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.hw_question_item (
|
||||
question_id VARCHAR(64) PRIMARY KEY,
|
||||
question_type VARCHAR(32) NOT NULL,
|
||||
stem TEXT NOT NULL,
|
||||
stem_json JSONB,
|
||||
difficulty VARCHAR(16),
|
||||
answer_payload JSONB,
|
||||
analysis TEXT,
|
||||
scoring_rule_json JSONB,
|
||||
question_status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE',
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_hw_question_item_type
|
||||
CHECK (question_type IN ('SINGLE_CHOICE', 'MULTIPLE_CHOICE', 'FILL_BLANK', 'JUDGE', 'SUBJECTIVE')),
|
||||
CONSTRAINT chk_hw_question_item_answer_payload
|
||||
CHECK (answer_payload IS NOT NULL AND jsonb_typeof(answer_payload) = 'object')
|
||||
);
|
||||
COMMENT ON TABLE question.hw_question_item IS '题目表(含标准答案)';
|
||||
COMMENT ON COLUMN question.hw_question_item.question_id IS '题目ID';
|
||||
COMMENT ON COLUMN question.hw_question_item.question_type IS '题型';
|
||||
COMMENT ON COLUMN question.hw_question_item.stem IS '题干';
|
||||
COMMENT ON COLUMN question.hw_question_item.stem_json IS '结构化题干JSON(富文本/图片公式等)';
|
||||
COMMENT ON COLUMN question.hw_question_item.difficulty IS '难度';
|
||||
COMMENT ON COLUMN question.hw_question_item.answer_payload IS '统一标准答案载荷JSONB(对应后端题型答案类型)';
|
||||
COMMENT ON COLUMN question.hw_question_item.analysis IS '题目解析';
|
||||
COMMENT ON COLUMN question.hw_question_item.scoring_rule_json IS '评分规则JSON(含主观题评分点)';
|
||||
COMMENT ON COLUMN question.hw_question_item.question_status IS '题目状态(ACTIVE/DISABLED)';
|
||||
COMMENT ON COLUMN question.hw_question_item.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.hw_question_item.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN question.hw_question_item.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.hw_bank_question_rel CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.hw_bank_question_rel (
|
||||
bank_id VARCHAR(64) NOT NULL,
|
||||
question_id VARCHAR(64) NOT NULL,
|
||||
question_order INTEGER,
|
||||
source_type VARCHAR(32) NOT NULL DEFAULT 'MANUAL',
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (bank_id, question_id),
|
||||
CONSTRAINT chk_hw_bank_question_rel_source_type
|
||||
CHECK (source_type IN ('MANUAL', 'AI_GENERATED', 'IMPORTED', 'MIGRATED')),
|
||||
CONSTRAINT fk_hw_bank_question_rel_bank
|
||||
FOREIGN KEY (bank_id) REFERENCES question.hw_question_bank(bank_id),
|
||||
CONSTRAINT fk_hw_bank_question_rel_question
|
||||
FOREIGN KEY (question_id) REFERENCES question.hw_question_item(question_id)
|
||||
);
|
||||
COMMENT ON TABLE question.hw_bank_question_rel IS '题库-题目关联表';
|
||||
COMMENT ON COLUMN question.hw_bank_question_rel.bank_id IS '题库ID';
|
||||
COMMENT ON COLUMN question.hw_bank_question_rel.question_id IS '题目ID';
|
||||
COMMENT ON COLUMN question.hw_bank_question_rel.question_order IS '题库内题目顺序';
|
||||
COMMENT ON COLUMN question.hw_bank_question_rel.source_type IS '题目来源类型(MANUAL/AI_GENERATED/IMPORTED/MIGRATED)';
|
||||
COMMENT ON COLUMN question.hw_bank_question_rel.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.hw_bank_question_rel.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.hw_question_kp_rel CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.hw_question_kp_rel (
|
||||
question_id VARCHAR(64) NOT NULL,
|
||||
kp_id VARCHAR(64) NOT NULL,
|
||||
relation_type VARCHAR(32) NOT NULL DEFAULT 'TESTS',
|
||||
weight NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
|
||||
confidence NUMERIC(5,4),
|
||||
graph_relation_id VARCHAR(64),
|
||||
source_table VARCHAR(128),
|
||||
source_pk VARCHAR(128),
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (question_id, kp_id),
|
||||
CONSTRAINT chk_hw_question_kp_rel_type
|
||||
CHECK (relation_type IN ('TESTS', 'RELATED', 'SUPPORTS')),
|
||||
CONSTRAINT chk_hw_question_kp_rel_weight
|
||||
CHECK (weight > 0 AND weight <= 1),
|
||||
CONSTRAINT chk_hw_question_kp_rel_confidence
|
||||
CHECK (confidence IS NULL OR (confidence >= 0 AND confidence <= 1)),
|
||||
CONSTRAINT fk_hw_question_kp_rel_question
|
||||
FOREIGN KEY (question_id) REFERENCES question.hw_question_item(question_id),
|
||||
CONSTRAINT fk_hw_question_kp_rel_kp
|
||||
FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id)
|
||||
);
|
||||
COMMENT ON TABLE question.hw_question_kp_rel IS '题目-知识点关联表';
|
||||
COMMENT ON COLUMN question.hw_question_kp_rel.question_id IS '题目ID';
|
||||
COMMENT ON COLUMN question.hw_question_kp_rel.kp_id IS '知识点ID';
|
||||
COMMENT ON COLUMN question.hw_question_kp_rel.relation_type IS '关系类型(TESTS/RELATED/SUPPORTS)';
|
||||
COMMENT ON COLUMN question.hw_question_kp_rel.weight IS '关联权重(0,1])';
|
||||
COMMENT ON COLUMN question.hw_question_kp_rel.confidence IS '抽取置信度';
|
||||
COMMENT ON COLUMN question.hw_question_kp_rel.graph_relation_id IS '图谱关系ID';
|
||||
COMMENT ON COLUMN question.hw_question_kp_rel.source_table IS '来源表';
|
||||
COMMENT ON COLUMN question.hw_question_kp_rel.source_pk IS '来源主键';
|
||||
COMMENT ON COLUMN question.hw_question_kp_rel.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.hw_question_kp_rel.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN question.hw_question_kp_rel.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.hw_paper CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.hw_paper (
|
||||
paper_id VARCHAR(64) PRIMARY KEY,
|
||||
paper_name VARCHAR(256) NOT NULL,
|
||||
paper_type VARCHAR(32) NOT NULL DEFAULT 'STANDARD',
|
||||
subject_code VARCHAR(32) NOT NULL,
|
||||
total_score NUMERIC(8,2) NOT NULL DEFAULT 100,
|
||||
source_file_id VARCHAR(64),
|
||||
adcode VARCHAR(12) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255) NOT NULL,
|
||||
created_by VARCHAR(64),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
grading_policy_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
CONSTRAINT chk_hw_paper_type
|
||||
CHECK (paper_type IN ('STANDARD', 'EXTERNAL_UPLOAD')),
|
||||
CONSTRAINT chk_hw_paper_grading_policy_json
|
||||
CHECK (jsonb_typeof(grading_policy_json) = 'object'),
|
||||
CONSTRAINT fk_hw_paper_source_file
|
||||
FOREIGN KEY (source_file_id) REFERENCES upms.tb_sys_file(file_id)
|
||||
);
|
||||
COMMENT ON TABLE question.hw_paper IS '试卷表';
|
||||
COMMENT ON COLUMN question.hw_paper.paper_id IS '试卷ID';
|
||||
COMMENT ON COLUMN question.hw_paper.paper_name IS '试卷名称';
|
||||
COMMENT ON COLUMN question.hw_paper.paper_type IS '试卷类型(STANDARD/EXTERNAL_UPLOAD)';
|
||||
COMMENT ON COLUMN question.hw_paper.subject_code IS '学科编码';
|
||||
COMMENT ON COLUMN question.hw_paper.total_score IS '总分';
|
||||
COMMENT ON COLUMN question.hw_paper.source_file_id IS '来源文件ID(课外上传作业解析来源)';
|
||||
COMMENT ON COLUMN question.hw_paper.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN question.hw_paper.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.hw_paper.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN question.hw_paper.created_by IS '创建人';
|
||||
COMMENT ON COLUMN question.hw_paper.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN question.hw_paper.grading_policy_json IS '试卷批改策略JSON(单选/判断完全匹配、多选得分策略、填空匹配策略、简答评估模式)';
|
||||
|
||||
DROP TABLE IF EXISTS question.hw_paper_question CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.hw_paper_question (
|
||||
paper_id VARCHAR(64) NOT NULL,
|
||||
question_id VARCHAR(64) NOT NULL,
|
||||
question_order INTEGER NOT NULL,
|
||||
score NUMERIC(8,2) NOT NULL DEFAULT 0,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (paper_id, question_id),
|
||||
CONSTRAINT fk_hw_paper_question_paper
|
||||
FOREIGN KEY (paper_id) REFERENCES question.hw_paper(paper_id),
|
||||
CONSTRAINT fk_hw_paper_question_question
|
||||
FOREIGN KEY (question_id) REFERENCES question.hw_question_item(question_id)
|
||||
);
|
||||
COMMENT ON TABLE question.hw_paper_question IS '试卷-题目关联表';
|
||||
COMMENT ON COLUMN question.hw_paper_question.paper_id IS '试卷ID';
|
||||
COMMENT ON COLUMN question.hw_paper_question.question_id IS '题目ID';
|
||||
COMMENT ON COLUMN question.hw_paper_question.question_order IS '题目顺序';
|
||||
COMMENT ON COLUMN question.hw_paper_question.score IS '题目分值';
|
||||
COMMENT ON COLUMN question.hw_paper_question.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.hw_paper_question.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.hw_assignment CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.hw_assignment (
|
||||
assignment_id VARCHAR(64) PRIMARY KEY,
|
||||
paper_id VARCHAR(64) NOT NULL,
|
||||
assignment_mode VARCHAR(32) NOT NULL DEFAULT 'PAPER',
|
||||
title VARCHAR(256) NOT NULL,
|
||||
publish_time TIMESTAMP,
|
||||
deadline TIMESTAMP,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'DRAFT',
|
||||
adcode VARCHAR(12) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255) NOT NULL,
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
created_by VARCHAR(64),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_hw_assignment_mode
|
||||
CHECK (assignment_mode IN ('PAPER', 'EXTERNAL_UPLOAD')),
|
||||
CONSTRAINT fk_hw_assignment_paper
|
||||
FOREIGN KEY (paper_id) REFERENCES question.hw_paper(paper_id)
|
||||
);
|
||||
COMMENT ON TABLE question.hw_assignment IS '作业表';
|
||||
COMMENT ON COLUMN question.hw_assignment.assignment_id IS '作业ID';
|
||||
COMMENT ON COLUMN question.hw_assignment.paper_id IS '试卷ID';
|
||||
COMMENT ON COLUMN question.hw_assignment.assignment_mode IS '作业模式(PAPER/EXTERNAL_UPLOAD)';
|
||||
COMMENT ON COLUMN question.hw_assignment.title IS '作业标题';
|
||||
COMMENT ON COLUMN question.hw_assignment.publish_time IS '发布时间';
|
||||
COMMENT ON COLUMN question.hw_assignment.deadline IS '截止时间';
|
||||
COMMENT ON COLUMN question.hw_assignment.status IS '状态(DRAFT/PUBLISHED/CLOSED)';
|
||||
COMMENT ON COLUMN question.hw_assignment.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN question.hw_assignment.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.hw_assignment.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN question.hw_assignment.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN question.hw_assignment.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN question.hw_assignment.created_by IS '创建人';
|
||||
COMMENT ON COLUMN question.hw_assignment.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.hw_assignment_target CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.hw_assignment_target (
|
||||
target_id VARCHAR(64) PRIMARY KEY,
|
||||
assignment_id VARCHAR(64) NOT NULL,
|
||||
target_type VARCHAR(32) NOT NULL,
|
||||
target_ref_id VARCHAR(64) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_hw_assignment_target_assignment
|
||||
FOREIGN KEY (assignment_id) REFERENCES question.hw_assignment(assignment_id)
|
||||
);
|
||||
COMMENT ON TABLE question.hw_assignment_target IS '作业投放对象表';
|
||||
COMMENT ON COLUMN question.hw_assignment_target.target_id IS '投放记录ID';
|
||||
COMMENT ON COLUMN question.hw_assignment_target.assignment_id IS '作业ID';
|
||||
COMMENT ON COLUMN question.hw_assignment_target.target_type IS '投放类型(CLASS/STUDENT)';
|
||||
COMMENT ON COLUMN question.hw_assignment_target.target_ref_id IS '投放对象ID';
|
||||
COMMENT ON COLUMN question.hw_assignment_target.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.hw_assignment_target.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.hw_submission CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.hw_submission (
|
||||
submission_id VARCHAR(64) PRIMARY KEY,
|
||||
assignment_id VARCHAR(64) NOT NULL,
|
||||
student_id VARCHAR(64) NOT NULL,
|
||||
submission_mode VARCHAR(32) NOT NULL DEFAULT 'ASSIGNMENT',
|
||||
origin_file_id VARCHAR(64),
|
||||
submit_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
used_seconds INTEGER,
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'SUBMITTED',
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_hw_submission_mode
|
||||
CHECK (submission_mode IN ('ASSIGNMENT', 'EXTERNAL_UPLOAD')),
|
||||
CONSTRAINT fk_hw_submission_assignment
|
||||
FOREIGN KEY (assignment_id) REFERENCES question.hw_assignment(assignment_id),
|
||||
CONSTRAINT fk_hw_submission_student
|
||||
FOREIGN KEY (student_id) REFERENCES upms.tb_sys_user(user_id),
|
||||
CONSTRAINT fk_hw_submission_origin_file
|
||||
FOREIGN KEY (origin_file_id) REFERENCES upms.tb_sys_file(file_id)
|
||||
);
|
||||
COMMENT ON TABLE question.hw_submission IS '作业提交表';
|
||||
COMMENT ON COLUMN question.hw_submission.submission_id IS '提交ID';
|
||||
COMMENT ON COLUMN question.hw_submission.assignment_id IS '作业ID';
|
||||
COMMENT ON COLUMN question.hw_submission.student_id IS '学员ID';
|
||||
COMMENT ON COLUMN question.hw_submission.submission_mode IS '提交模式(ASSIGNMENT/EXTERNAL_UPLOAD)';
|
||||
COMMENT ON COLUMN question.hw_submission.origin_file_id IS '原始上传文件ID(课外作业)';
|
||||
COMMENT ON COLUMN question.hw_submission.submit_time IS '提交时间';
|
||||
COMMENT ON COLUMN question.hw_submission.used_seconds IS '作答耗时(秒)';
|
||||
COMMENT ON COLUMN question.hw_submission.status IS '提交状态';
|
||||
COMMENT ON COLUMN question.hw_submission.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.hw_submission.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.hw_submission_answer CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.hw_submission_answer (
|
||||
answer_id VARCHAR(64) PRIMARY KEY,
|
||||
submission_id VARCHAR(64) NOT NULL,
|
||||
question_id VARCHAR(64) NOT NULL,
|
||||
answer_type VARCHAR(32) NOT NULL,
|
||||
answer_payload JSONB,
|
||||
file_id VARCHAR(64),
|
||||
file_type VARCHAR(32),
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_hw_submission_answer_type
|
||||
CHECK (answer_type IN ('SINGLE_CHOICE', 'MULTIPLE_CHOICE', 'FILL_BLANK', 'JUDGE', 'SUBJECTIVE')),
|
||||
CONSTRAINT chk_hw_submission_answer_payload
|
||||
CHECK (
|
||||
answer_payload IS NOT NULL
|
||||
OR file_id IS NOT NULL
|
||||
),
|
||||
CONSTRAINT chk_hw_submission_answer_payload_json
|
||||
CHECK (answer_payload IS NULL OR jsonb_typeof(answer_payload) = 'object'),
|
||||
CONSTRAINT chk_hw_submission_answer_file_type
|
||||
CHECK (file_type IS NULL OR file_type IN ('IMAGE', 'AUDIO', 'VIDEO', 'DOCUMENT', 'OTHER')),
|
||||
CONSTRAINT chk_hw_submission_answer_file_ref
|
||||
CHECK (
|
||||
(file_id IS NULL AND file_type IS NULL)
|
||||
OR (file_id IS NOT NULL AND file_type IS NOT NULL)
|
||||
),
|
||||
CONSTRAINT uq_hw_submission_answer_submission_question
|
||||
UNIQUE (submission_id, question_id),
|
||||
CONSTRAINT fk_hw_submission_answer_submission
|
||||
FOREIGN KEY (submission_id) REFERENCES question.hw_submission(submission_id),
|
||||
CONSTRAINT fk_hw_submission_answer_question
|
||||
FOREIGN KEY (question_id) REFERENCES question.hw_question_item(question_id),
|
||||
CONSTRAINT fk_hw_submission_answer_file
|
||||
FOREIGN KEY (file_id) REFERENCES upms.tb_sys_file(file_id)
|
||||
);
|
||||
COMMENT ON TABLE question.hw_submission_answer IS '提交答案明细表(一次提交中每题一行)';
|
||||
COMMENT ON COLUMN question.hw_submission_answer.answer_id IS '答案ID';
|
||||
COMMENT ON COLUMN question.hw_submission_answer.submission_id IS '提交ID';
|
||||
COMMENT ON COLUMN question.hw_submission_answer.question_id IS '题目ID';
|
||||
COMMENT ON COLUMN question.hw_submission_answer.answer_type IS '答案类型(与题型一致)';
|
||||
COMMENT ON COLUMN question.hw_submission_answer.answer_payload IS '统一作答载荷JSONB(对应后端答案类型)';
|
||||
COMMENT ON COLUMN question.hw_submission_answer.file_id IS '作答文件ID(图片/音频等)';
|
||||
COMMENT ON COLUMN question.hw_submission_answer.file_type IS '作答文件类型';
|
||||
COMMENT ON COLUMN question.hw_submission_answer.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.hw_submission_answer.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN question.hw_submission_answer.updated_at IS '更新时间';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_question_bank_tenant_subject_grade
|
||||
ON question.hw_question_bank(tenant_id, subject_code, grade_code);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_question_item_type
|
||||
ON question.hw_question_item(question_type, difficulty);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_question_item_tenant
|
||||
ON question.hw_question_item(tenant_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_bank_question_rel_question
|
||||
ON question.hw_bank_question_rel(question_id, bank_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_bank_question_rel_tenant_bank
|
||||
ON question.hw_bank_question_rel(tenant_id, bank_id, question_order);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_question_kp_rel_tenant_question
|
||||
ON question.hw_question_kp_rel(tenant_id, question_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_question_kp_rel_tenant_kp
|
||||
ON question.hw_question_kp_rel(tenant_id, kp_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_question_kp_rel_graph_relation
|
||||
ON question.hw_question_kp_rel(graph_relation_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_assignment_tenant_status_deadline
|
||||
ON question.hw_assignment(tenant_id, status, deadline);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_assignment_mode
|
||||
ON question.hw_assignment(assignment_mode, tenant_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_assignment_target_assignment
|
||||
ON question.hw_assignment_target(assignment_id, target_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_submission_assignment_student
|
||||
ON question.hw_submission(assignment_id, student_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_submission_mode
|
||||
ON question.hw_submission(submission_mode, tenant_id, submit_time DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_submission_origin_file
|
||||
ON question.hw_submission(origin_file_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_submission_answer_submission
|
||||
ON question.hw_submission_answer(submission_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_submission_answer_question
|
||||
ON question.hw_submission_answer(question_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_hw_submission_answer_file_id
|
||||
ON question.hw_submission_answer(file_id);
|
||||
|
||||
DROP TABLE IF EXISTS question.gd_grading_task CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.gd_grading_task (
|
||||
grading_task_id VARCHAR(64) PRIMARY KEY,
|
||||
submission_id VARCHAR(64) NOT NULL,
|
||||
paper_id VARCHAR(64) NOT NULL,
|
||||
task_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
|
||||
trigger_source VARCHAR(32) NOT NULL DEFAULT 'SUBMISSION',
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_gd_grading_task_submission
|
||||
FOREIGN KEY (submission_id) REFERENCES question.hw_submission(submission_id),
|
||||
CONSTRAINT fk_gd_grading_task_paper
|
||||
FOREIGN KEY (paper_id) REFERENCES question.hw_paper(paper_id)
|
||||
);
|
||||
COMMENT ON TABLE question.gd_grading_task IS '批改任务表';
|
||||
COMMENT ON COLUMN question.gd_grading_task.grading_task_id IS '批改任务ID';
|
||||
COMMENT ON COLUMN question.gd_grading_task.submission_id IS '提交ID';
|
||||
COMMENT ON COLUMN question.gd_grading_task.paper_id IS '试卷ID';
|
||||
COMMENT ON COLUMN question.gd_grading_task.task_status IS '任务状态(PENDING/RUNNING/WAIT_REVIEW/DONE)';
|
||||
COMMENT ON COLUMN question.gd_grading_task.trigger_source IS '触发来源';
|
||||
COMMENT ON COLUMN question.gd_grading_task.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.gd_grading_task.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN question.gd_grading_task.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.gd_answer_grade CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.gd_answer_grade (
|
||||
answer_grade_id VARCHAR(64) PRIMARY KEY,
|
||||
grading_task_id VARCHAR(64) NOT NULL,
|
||||
answer_id VARCHAR(64) NOT NULL,
|
||||
paper_id VARCHAR(64) NOT NULL,
|
||||
grade_mode VARCHAR(32) NOT NULL DEFAULT 'AUTO',
|
||||
grade_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
|
||||
score NUMERIC(8,2),
|
||||
grader_id VARCHAR(64),
|
||||
grade_comment TEXT,
|
||||
evidence_json JSONB,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_gd_answer_grade_mode
|
||||
CHECK (grade_mode IN ('AUTO', 'MANUAL', 'AI', 'AI_REVIEW')),
|
||||
CONSTRAINT chk_gd_answer_grade_status
|
||||
CHECK (grade_status IN ('PENDING', 'DONE', 'REVIEWED')),
|
||||
CONSTRAINT uq_gd_answer_grade_task_answer
|
||||
UNIQUE (grading_task_id, answer_id),
|
||||
CONSTRAINT fk_gd_answer_grade_task
|
||||
FOREIGN KEY (grading_task_id) REFERENCES question.gd_grading_task(grading_task_id),
|
||||
CONSTRAINT fk_gd_answer_grade_answer
|
||||
FOREIGN KEY (answer_id) REFERENCES question.hw_submission_answer(answer_id),
|
||||
CONSTRAINT fk_gd_answer_grade_paper
|
||||
FOREIGN KEY (paper_id) REFERENCES question.hw_paper(paper_id),
|
||||
CONSTRAINT fk_gd_answer_grade_grader
|
||||
FOREIGN KEY (grader_id) REFERENCES upms.tb_sys_user(user_id)
|
||||
);
|
||||
COMMENT ON TABLE question.gd_answer_grade IS '答案批改结果表(统一客观/主观)';
|
||||
COMMENT ON COLUMN question.gd_answer_grade.answer_grade_id IS '答案批改结果ID';
|
||||
COMMENT ON COLUMN question.gd_answer_grade.grading_task_id IS '批改任务ID';
|
||||
COMMENT ON COLUMN question.gd_answer_grade.answer_id IS '答案ID';
|
||||
COMMENT ON COLUMN question.gd_answer_grade.paper_id IS '试卷ID';
|
||||
COMMENT ON COLUMN question.gd_answer_grade.grade_mode IS '批改模式(AUTO/MANUAL/AI/AI_REVIEW)';
|
||||
COMMENT ON COLUMN question.gd_answer_grade.grade_status IS '批改状态(PENDING/DONE/REVIEWED)';
|
||||
COMMENT ON COLUMN question.gd_answer_grade.score IS '最终得分';
|
||||
COMMENT ON COLUMN question.gd_answer_grade.grader_id IS '评阅人ID';
|
||||
COMMENT ON COLUMN question.gd_answer_grade.grade_comment IS '批改评语';
|
||||
COMMENT ON COLUMN question.gd_answer_grade.evidence_json IS '判定依据JSON';
|
||||
COMMENT ON COLUMN question.gd_answer_grade.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.gd_answer_grade.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN question.gd_answer_grade.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.gd_score_summary CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.gd_score_summary (
|
||||
summary_id VARCHAR(64) PRIMARY KEY,
|
||||
grading_task_id VARCHAR(64) UNIQUE NOT NULL,
|
||||
total_score NUMERIC(8,2) NOT NULL DEFAULT 0,
|
||||
grade_level VARCHAR(8),
|
||||
surpass_ratio NUMERIC(5,2),
|
||||
used_seconds INTEGER,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_gd_score_summary_task
|
||||
FOREIGN KEY (grading_task_id) REFERENCES question.gd_grading_task(grading_task_id)
|
||||
);
|
||||
COMMENT ON TABLE question.gd_score_summary IS '批改结果汇总表';
|
||||
COMMENT ON COLUMN question.gd_score_summary.summary_id IS '汇总ID';
|
||||
COMMENT ON COLUMN question.gd_score_summary.grading_task_id IS '批改任务ID';
|
||||
COMMENT ON COLUMN question.gd_score_summary.total_score IS '总分';
|
||||
COMMENT ON COLUMN question.gd_score_summary.grade_level IS '等级(A/B/C)';
|
||||
COMMENT ON COLUMN question.gd_score_summary.surpass_ratio IS '超越比例';
|
||||
COMMENT ON COLUMN question.gd_score_summary.used_seconds IS '作答耗时';
|
||||
COMMENT ON COLUMN question.gd_score_summary.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.gd_score_summary.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.gd_error_tag CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.gd_error_tag (
|
||||
error_tag_id VARCHAR(64) PRIMARY KEY,
|
||||
tag_code VARCHAR(64) UNIQUE NOT NULL,
|
||||
tag_name VARCHAR(128) NOT NULL,
|
||||
category VARCHAR(32) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
COMMENT ON TABLE question.gd_error_tag IS '错因标签表';
|
||||
COMMENT ON COLUMN question.gd_error_tag.error_tag_id IS '标签ID';
|
||||
COMMENT ON COLUMN question.gd_error_tag.tag_code IS '标签编码';
|
||||
COMMENT ON COLUMN question.gd_error_tag.tag_name IS '标签名称';
|
||||
COMMENT ON COLUMN question.gd_error_tag.category IS '分类(审题/计算/概念等)';
|
||||
COMMENT ON COLUMN question.gd_error_tag.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.gd_error_tag.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.gd_answer_error_rel CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.gd_answer_error_rel (
|
||||
answer_id VARCHAR(64) NOT NULL,
|
||||
error_tag_id VARCHAR(64) NOT NULL,
|
||||
confidence NUMERIC(5,4),
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (answer_id, error_tag_id),
|
||||
CONSTRAINT fk_gd_answer_error_rel_answer
|
||||
FOREIGN KEY (answer_id) REFERENCES question.hw_submission_answer(answer_id),
|
||||
CONSTRAINT fk_gd_answer_error_rel_tag
|
||||
FOREIGN KEY (error_tag_id) REFERENCES question.gd_error_tag(error_tag_id)
|
||||
);
|
||||
COMMENT ON TABLE question.gd_answer_error_rel IS '答案-错因标签关联表';
|
||||
COMMENT ON COLUMN question.gd_answer_error_rel.answer_id IS '答案ID';
|
||||
COMMENT ON COLUMN question.gd_answer_error_rel.error_tag_id IS '错因标签ID';
|
||||
COMMENT ON COLUMN question.gd_answer_error_rel.confidence IS '置信度';
|
||||
COMMENT ON COLUMN question.gd_answer_error_rel.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.gd_answer_error_rel.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.gd_answer_kp_analysis CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.gd_answer_kp_analysis (
|
||||
answer_id VARCHAR(64) NOT NULL,
|
||||
kp_id VARCHAR(64) NOT NULL,
|
||||
grading_task_id VARCHAR(64),
|
||||
correctness VARCHAR(16) NOT NULL DEFAULT 'UNKNOWN',
|
||||
mastery_score NUMERIC(6,4),
|
||||
confidence NUMERIC(5,4),
|
||||
evidence_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (answer_id, kp_id),
|
||||
CONSTRAINT chk_gd_answer_kp_analysis_correctness
|
||||
CHECK (correctness IN ('CORRECT', 'PARTIAL', 'WRONG', 'UNKNOWN')),
|
||||
CONSTRAINT chk_gd_answer_kp_analysis_mastery
|
||||
CHECK (mastery_score IS NULL OR (mastery_score >= 0 AND mastery_score <= 1)),
|
||||
CONSTRAINT chk_gd_answer_kp_analysis_confidence
|
||||
CHECK (confidence IS NULL OR (confidence >= 0 AND confidence <= 1)),
|
||||
CONSTRAINT chk_gd_answer_kp_analysis_evidence_json
|
||||
CHECK (jsonb_typeof(evidence_json) = 'object'),
|
||||
CONSTRAINT fk_gd_answer_kp_analysis_answer
|
||||
FOREIGN KEY (answer_id) REFERENCES question.hw_submission_answer(answer_id),
|
||||
CONSTRAINT fk_gd_answer_kp_analysis_kp
|
||||
FOREIGN KEY (kp_id) REFERENCES course.cl_knowledge_point(kp_id),
|
||||
CONSTRAINT fk_gd_answer_kp_analysis_grading_task
|
||||
FOREIGN KEY (grading_task_id) REFERENCES question.gd_grading_task(grading_task_id)
|
||||
);
|
||||
COMMENT ON TABLE question.gd_answer_kp_analysis IS '答案-知识点分析表';
|
||||
COMMENT ON COLUMN question.gd_answer_kp_analysis.answer_id IS '答案ID';
|
||||
COMMENT ON COLUMN question.gd_answer_kp_analysis.kp_id IS '知识点ID';
|
||||
COMMENT ON COLUMN question.gd_answer_kp_analysis.grading_task_id IS '批改任务ID';
|
||||
COMMENT ON COLUMN question.gd_answer_kp_analysis.correctness IS '正确性(CORRECT/PARTIAL/WRONG/UNKNOWN)';
|
||||
COMMENT ON COLUMN question.gd_answer_kp_analysis.mastery_score IS '答案层知识点掌握度(0-1)';
|
||||
COMMENT ON COLUMN question.gd_answer_kp_analysis.confidence IS '分析置信度';
|
||||
COMMENT ON COLUMN question.gd_answer_kp_analysis.evidence_json IS '知识点分析依据JSON';
|
||||
COMMENT ON COLUMN question.gd_answer_kp_analysis.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.gd_answer_kp_analysis.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN question.gd_answer_kp_analysis.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.gd_wrong_question CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.gd_wrong_question (
|
||||
wrong_question_id VARCHAR(64) PRIMARY KEY,
|
||||
student_id VARCHAR(64) NOT NULL,
|
||||
question_id VARCHAR(64) NOT NULL,
|
||||
source_submission_id VARCHAR(64) NOT NULL,
|
||||
mastery_status VARCHAR(32) NOT NULL DEFAULT 'PENDING',
|
||||
review_count INTEGER NOT NULL DEFAULT 0,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_gd_wrong_question_student
|
||||
FOREIGN KEY (student_id) REFERENCES upms.tb_sys_user(user_id),
|
||||
CONSTRAINT fk_gd_wrong_question_question
|
||||
FOREIGN KEY (question_id) REFERENCES question.hw_question_item(question_id),
|
||||
CONSTRAINT fk_gd_wrong_question_submission
|
||||
FOREIGN KEY (source_submission_id) REFERENCES question.hw_submission(submission_id)
|
||||
);
|
||||
COMMENT ON TABLE question.gd_wrong_question IS '错题沉淀表';
|
||||
COMMENT ON COLUMN question.gd_wrong_question.wrong_question_id IS '错题记录ID';
|
||||
COMMENT ON COLUMN question.gd_wrong_question.student_id IS '学员ID';
|
||||
COMMENT ON COLUMN question.gd_wrong_question.question_id IS '题目ID';
|
||||
COMMENT ON COLUMN question.gd_wrong_question.source_submission_id IS '来源提交ID';
|
||||
COMMENT ON COLUMN question.gd_wrong_question.mastery_status IS '掌握状态';
|
||||
COMMENT ON COLUMN question.gd_wrong_question.review_count IS '复习次数';
|
||||
COMMENT ON COLUMN question.gd_wrong_question.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.gd_wrong_question.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN question.gd_wrong_question.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.gd_review_plan CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.gd_review_plan (
|
||||
review_plan_id VARCHAR(64) PRIMARY KEY,
|
||||
wrong_question_id VARCHAR(64) NOT NULL,
|
||||
plan_date DATE NOT NULL,
|
||||
plan_stage VARCHAR(16) NOT NULL,
|
||||
plan_status VARCHAR(32) NOT NULL DEFAULT 'TODO',
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_gd_review_plan_wrong_question
|
||||
FOREIGN KEY (wrong_question_id) REFERENCES question.gd_wrong_question(wrong_question_id)
|
||||
);
|
||||
COMMENT ON TABLE question.gd_review_plan IS '复习计划表';
|
||||
COMMENT ON COLUMN question.gd_review_plan.review_plan_id IS '复习计划ID';
|
||||
COMMENT ON COLUMN question.gd_review_plan.wrong_question_id IS '错题记录ID';
|
||||
COMMENT ON COLUMN question.gd_review_plan.plan_date IS '计划日期';
|
||||
COMMENT ON COLUMN question.gd_review_plan.plan_stage IS '阶段(E1/E2/E3)';
|
||||
COMMENT ON COLUMN question.gd_review_plan.plan_status IS '计划状态';
|
||||
COMMENT ON COLUMN question.gd_review_plan.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.gd_review_plan.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.gd_teacher_comment CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.gd_teacher_comment (
|
||||
comment_id VARCHAR(64) PRIMARY KEY,
|
||||
answer_grade_id VARCHAR(64) NOT NULL,
|
||||
reviewer_id VARCHAR(64) NOT NULL,
|
||||
comment_type VARCHAR(16) NOT NULL DEFAULT 'TEXT',
|
||||
content_ref TEXT,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_gd_teacher_comment_answer_grade
|
||||
FOREIGN KEY (answer_grade_id) REFERENCES question.gd_answer_grade(answer_grade_id),
|
||||
CONSTRAINT fk_gd_teacher_comment_reviewer
|
||||
FOREIGN KEY (reviewer_id) REFERENCES upms.tb_sys_user(user_id)
|
||||
);
|
||||
COMMENT ON TABLE question.gd_teacher_comment IS '教师点评表';
|
||||
COMMENT ON COLUMN question.gd_teacher_comment.comment_id IS '点评ID';
|
||||
COMMENT ON COLUMN question.gd_teacher_comment.answer_grade_id IS '答案批改结果ID';
|
||||
COMMENT ON COLUMN question.gd_teacher_comment.reviewer_id IS '教师ID';
|
||||
COMMENT ON COLUMN question.gd_teacher_comment.comment_type IS '点评类型(TEXT/VOICE)';
|
||||
COMMENT ON COLUMN question.gd_teacher_comment.content_ref IS '点评内容或资源引用';
|
||||
COMMENT ON COLUMN question.gd_teacher_comment.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.gd_teacher_comment.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS question.gd_explanation_dimension_score CASCADE;
|
||||
DROP TABLE IF EXISTS question.gd_explanation_assessment CASCADE;
|
||||
DROP TABLE IF EXISTS question.gd_explanation_submission CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS question.gd_explanation_submission (
|
||||
explanation_id VARCHAR(64) PRIMARY KEY,
|
||||
student_id VARCHAR(64) NOT NULL,
|
||||
wrong_question_id VARCHAR(64),
|
||||
source_submission_id VARCHAR(64),
|
||||
source_answer_id VARCHAR(64),
|
||||
audio_file_id VARCHAR(64) NOT NULL,
|
||||
duration_seconds INTEGER,
|
||||
transcript_text TEXT,
|
||||
submission_status VARCHAR(16) NOT NULL DEFAULT 'SUBMITTED',
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_gd_explanation_submission_status
|
||||
CHECK (submission_status IN ('SUBMITTED', 'EVALUATED', 'REJECTED')),
|
||||
CONSTRAINT fk_gd_explanation_submission_student
|
||||
FOREIGN KEY (student_id) REFERENCES upms.tb_sys_user(user_id),
|
||||
CONSTRAINT fk_gd_explanation_submission_wrong_question
|
||||
FOREIGN KEY (wrong_question_id) REFERENCES question.gd_wrong_question(wrong_question_id),
|
||||
CONSTRAINT fk_gd_explanation_submission_source_submission
|
||||
FOREIGN KEY (source_submission_id) REFERENCES question.hw_submission(submission_id),
|
||||
CONSTRAINT fk_gd_explanation_submission_source_answer
|
||||
FOREIGN KEY (source_answer_id) REFERENCES question.hw_submission_answer(answer_id),
|
||||
CONSTRAINT fk_gd_explanation_submission_audio_file
|
||||
FOREIGN KEY (audio_file_id) REFERENCES upms.tb_sys_file(file_id)
|
||||
);
|
||||
COMMENT ON TABLE question.gd_explanation_submission IS '费曼讲解提交表';
|
||||
COMMENT ON COLUMN question.gd_explanation_submission.explanation_id IS '讲解提交ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_submission.student_id IS '学员ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_submission.wrong_question_id IS '关联错题ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_submission.source_submission_id IS '来源作业提交ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_submission.source_answer_id IS '来源答案ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_submission.audio_file_id IS '讲解音频文件ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_submission.duration_seconds IS '时长(秒)';
|
||||
COMMENT ON COLUMN question.gd_explanation_submission.transcript_text IS '转写文本';
|
||||
COMMENT ON COLUMN question.gd_explanation_submission.submission_status IS '提交状态';
|
||||
COMMENT ON COLUMN question.gd_explanation_submission.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_submission.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN question.gd_explanation_submission.updated_at IS '更新时间';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS question.gd_explanation_assessment (
|
||||
assessment_id VARCHAR(64) PRIMARY KEY,
|
||||
explanation_id VARCHAR(64) NOT NULL UNIQUE,
|
||||
evaluator_type VARCHAR(16) NOT NULL DEFAULT 'AI',
|
||||
evaluator_id VARCHAR(64),
|
||||
total_score NUMERIC(8,2),
|
||||
pass_status VARCHAR(16) NOT NULL DEFAULT 'PENDING',
|
||||
improvement_suggestion TEXT,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_gd_explanation_assessment_evaluator_type
|
||||
CHECK (evaluator_type IN ('AI', 'TEACHER', 'HYBRID')),
|
||||
CONSTRAINT chk_gd_explanation_assessment_pass_status
|
||||
CHECK (pass_status IN ('PENDING', 'PASSED', 'FAILED')),
|
||||
CONSTRAINT fk_gd_explanation_assessment_explanation
|
||||
FOREIGN KEY (explanation_id) REFERENCES question.gd_explanation_submission(explanation_id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_gd_explanation_assessment_evaluator
|
||||
FOREIGN KEY (evaluator_id) REFERENCES upms.tb_sys_user(user_id)
|
||||
);
|
||||
COMMENT ON TABLE question.gd_explanation_assessment IS '费曼讲解评估汇总表';
|
||||
COMMENT ON COLUMN question.gd_explanation_assessment.assessment_id IS '评估ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_assessment.explanation_id IS '讲解提交ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_assessment.evaluator_type IS '评估类型';
|
||||
COMMENT ON COLUMN question.gd_explanation_assessment.evaluator_id IS '评估人ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_assessment.total_score IS '总分';
|
||||
COMMENT ON COLUMN question.gd_explanation_assessment.pass_status IS '通过状态';
|
||||
COMMENT ON COLUMN question.gd_explanation_assessment.improvement_suggestion IS '改进建议';
|
||||
COMMENT ON COLUMN question.gd_explanation_assessment.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_assessment.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN question.gd_explanation_assessment.updated_at IS '更新时间';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS question.gd_explanation_dimension_score (
|
||||
dimension_score_id VARCHAR(64) PRIMARY KEY,
|
||||
assessment_id VARCHAR(64) NOT NULL,
|
||||
dimension_code VARCHAR(32) NOT NULL,
|
||||
dimension_name VARCHAR(64) NOT NULL,
|
||||
score NUMERIC(8,2) NOT NULL DEFAULT 0,
|
||||
weight NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
|
||||
comment_text TEXT,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_gd_explanation_dimension_score_weight
|
||||
CHECK (weight > 0 AND weight <= 1),
|
||||
CONSTRAINT fk_gd_explanation_dimension_score_assessment
|
||||
FOREIGN KEY (assessment_id) REFERENCES question.gd_explanation_assessment(assessment_id) ON DELETE CASCADE
|
||||
);
|
||||
COMMENT ON TABLE question.gd_explanation_dimension_score IS '费曼讲解维度评分表';
|
||||
COMMENT ON COLUMN question.gd_explanation_dimension_score.dimension_score_id IS '维度评分ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_dimension_score.assessment_id IS '评估ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_dimension_score.dimension_code IS '维度编码';
|
||||
COMMENT ON COLUMN question.gd_explanation_dimension_score.dimension_name IS '维度名称';
|
||||
COMMENT ON COLUMN question.gd_explanation_dimension_score.score IS '维度得分';
|
||||
COMMENT ON COLUMN question.gd_explanation_dimension_score.weight IS '维度权重';
|
||||
COMMENT ON COLUMN question.gd_explanation_dimension_score.comment_text IS '维度评语';
|
||||
COMMENT ON COLUMN question.gd_explanation_dimension_score.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN question.gd_explanation_dimension_score.created_at IS '创建时间';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_grading_task_submission
|
||||
ON question.gd_grading_task(submission_id, task_status);
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_grading_task_paper_status
|
||||
ON question.gd_grading_task(paper_id, task_status, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_answer_grade_task_status
|
||||
ON question.gd_answer_grade(grading_task_id, grade_status);
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_answer_grade_paper_status
|
||||
ON question.gd_answer_grade(paper_id, grade_status, updated_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_answer_error_rel_answer
|
||||
ON question.gd_answer_error_rel(answer_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_answer_kp_analysis_kp
|
||||
ON question.gd_answer_kp_analysis(kp_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_answer_kp_analysis_task
|
||||
ON question.gd_answer_kp_analysis(grading_task_id, kp_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_wrong_question_student_status
|
||||
ON question.gd_wrong_question(student_id, mastery_status);
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_review_plan_wrong_question_date
|
||||
ON question.gd_review_plan(wrong_question_id, plan_date);
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_teacher_comment_answer_grade
|
||||
ON question.gd_teacher_comment(answer_grade_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_explanation_submission_student
|
||||
ON question.gd_explanation_submission(student_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_explanation_submission_wrong_question
|
||||
ON question.gd_explanation_submission(wrong_question_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_explanation_assessment_pass_status
|
||||
ON question.gd_explanation_assessment(pass_status, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_gd_explanation_dimension_score_assessment
|
||||
ON question.gd_explanation_dimension_score(assessment_id, dimension_code);
|
||||
5
init/pg/question/20_init_question_seed.sql
Normal file
5
init/pg/question/20_init_question_seed.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- 习题与作业模块初始化数据占位
|
||||
-- 按需补充题库、题目、试卷、作业模板等种子数据
|
||||
|
||||
-- 批改与反馈模块初始化数据占位
|
||||
-- 按需补充错因标签、统一答案批改结果、复习计划策略等种子数据
|
||||
440
init/pg/recommendation/10_create_recommendation_tables.sql
Normal file
440
init/pg/recommendation/10_create_recommendation_tables.sql
Normal file
@@ -0,0 +1,440 @@
|
||||
DROP SCHEMA IF EXISTS recommendation CASCADE;
|
||||
CREATE SCHEMA IF NOT EXISTS recommendation;
|
||||
|
||||
DROP TABLE IF EXISTS recommendation.rc_recommendation_task CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS recommendation.rc_recommendation_task (
|
||||
task_id VARCHAR(64) PRIMARY KEY,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
scene_code VARCHAR(32) NOT NULL,
|
||||
trigger_source VARCHAR(32) NOT NULL DEFAULT 'SCHEDULE',
|
||||
strategy_version VARCHAR(32),
|
||||
profile_snapshot_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'CREATED',
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_rc_recommendation_task_status
|
||||
CHECK (status IN ('CREATED', 'RUNNING', 'DONE', 'FAILED')),
|
||||
CONSTRAINT chk_rc_recommendation_task_profile_json
|
||||
CHECK (jsonb_typeof(profile_snapshot_json) = 'object'),
|
||||
CONSTRAINT fk_rc_recommendation_task_user
|
||||
FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id)
|
||||
);
|
||||
COMMENT ON TABLE recommendation.rc_recommendation_task IS '推荐任务表';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_task.task_id IS '推荐任务ID';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_task.user_id IS '推荐目标用户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_task.scene_code IS '推荐场景编码(HOME/WRONGBOOK/REVIEW等)';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_task.trigger_source IS '触发来源(SCHEDULE/EVENT/MANUAL)';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_task.strategy_version IS '推荐策略版本';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_task.profile_snapshot_json IS '画像快照JSON';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_task.status IS '任务状态';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_task.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_task.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_task.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS recommendation.rc_recommendation_item CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS recommendation.rc_recommendation_item (
|
||||
item_id VARCHAR(64) PRIMARY KEY,
|
||||
task_id VARCHAR(64) NOT NULL,
|
||||
content_type VARCHAR(32) NOT NULL,
|
||||
content_object_id VARCHAR(64) NOT NULL,
|
||||
content_object_type VARCHAR(64) NOT NULL,
|
||||
rank_no INTEGER NOT NULL,
|
||||
score NUMERIC(10,6),
|
||||
reason_codes VARCHAR(255),
|
||||
metadata_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_rc_recommendation_item_content_type
|
||||
CHECK (content_type IN ('COURSE', 'QUESTION', 'PAPER', 'WRONG_QUESTION', 'REVIEW_PLAN', 'MIXED')),
|
||||
CONSTRAINT chk_rc_recommendation_item_metadata_json
|
||||
CHECK (jsonb_typeof(metadata_json) = 'object'),
|
||||
CONSTRAINT uq_rc_recommendation_item_task_rank
|
||||
UNIQUE (task_id, rank_no),
|
||||
CONSTRAINT fk_rc_recommendation_item_task
|
||||
FOREIGN KEY (task_id) REFERENCES recommendation.rc_recommendation_task(task_id) ON DELETE CASCADE
|
||||
);
|
||||
COMMENT ON TABLE recommendation.rc_recommendation_item IS '推荐结果明细表';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_item.item_id IS '推荐项ID';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_item.task_id IS '推荐任务ID';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_item.content_type IS '内容类型';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_item.content_object_id IS '内容对象ID';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_item.content_object_type IS '内容对象类型';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_item.rank_no IS '推荐位次';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_item.score IS '推荐分';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_item.reason_codes IS '推荐原因编码集合';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_item.metadata_json IS '扩展元数据JSON';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_item.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_item.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS recommendation.rc_recommendation_feedback CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS recommendation.rc_recommendation_feedback (
|
||||
feedback_id VARCHAR(64) PRIMARY KEY,
|
||||
item_id VARCHAR(64) NOT NULL,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
event_type VARCHAR(16) NOT NULL,
|
||||
event_value NUMERIC(10,4),
|
||||
event_detail_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
event_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_rc_recommendation_feedback_event_type
|
||||
CHECK (event_type IN ('EXPOSE', 'CLICK', 'START', 'COMPLETE', 'DISLIKE', 'SKIP')),
|
||||
CONSTRAINT chk_rc_recommendation_feedback_detail_json
|
||||
CHECK (jsonb_typeof(event_detail_json) = 'object'),
|
||||
CONSTRAINT fk_rc_recommendation_feedback_item
|
||||
FOREIGN KEY (item_id) REFERENCES recommendation.rc_recommendation_item(item_id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_rc_recommendation_feedback_user
|
||||
FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id)
|
||||
);
|
||||
COMMENT ON TABLE recommendation.rc_recommendation_feedback IS '推荐反馈事件表';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_feedback.feedback_id IS '反馈事件ID';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_feedback.item_id IS '推荐项ID';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_feedback.user_id IS '用户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_feedback.event_type IS '事件类型';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_feedback.event_value IS '事件值(可选)';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_feedback.event_detail_json IS '事件详情JSON';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_feedback.event_time IS '事件发生时间';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_feedback.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_feedback.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS recommendation.rc_recommendation_effect_daily CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS recommendation.rc_recommendation_effect_daily (
|
||||
stat_date DATE NOT NULL,
|
||||
scene_code VARCHAR(32) NOT NULL,
|
||||
strategy_version VARCHAR(32) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
expose_count BIGINT NOT NULL DEFAULT 0,
|
||||
click_count BIGINT NOT NULL DEFAULT 0,
|
||||
complete_count BIGINT NOT NULL DEFAULT 0,
|
||||
dislike_count BIGINT NOT NULL DEFAULT 0,
|
||||
ctr NUMERIC(10,6) NOT NULL DEFAULT 0,
|
||||
complete_rate NUMERIC(10,6) NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (stat_date, scene_code, strategy_version, tenant_id)
|
||||
);
|
||||
COMMENT ON TABLE recommendation.rc_recommendation_effect_daily IS '推荐效果日统计表';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_effect_daily.stat_date IS '统计日期';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_effect_daily.scene_code IS '推荐场景编码';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_effect_daily.strategy_version IS '策略版本';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_effect_daily.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_effect_daily.expose_count IS '曝光次数';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_effect_daily.click_count IS '点击次数';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_effect_daily.complete_count IS '完成次数';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_effect_daily.dislike_count IS '不喜欢次数';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_effect_daily.ctr IS '点击率';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_effect_daily.complete_rate IS '完成率';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_effect_daily.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN recommendation.rc_recommendation_effect_daily.updated_at IS '更新时间';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_recommendation_task_user_scene
|
||||
ON recommendation.rc_recommendation_task(user_id, scene_code, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_recommendation_task_tenant_status
|
||||
ON recommendation.rc_recommendation_task(tenant_id, status, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_recommendation_item_task
|
||||
ON recommendation.rc_recommendation_item(task_id, rank_no);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_recommendation_item_content
|
||||
ON recommendation.rc_recommendation_item(content_object_type, content_object_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_recommendation_feedback_item_event
|
||||
ON recommendation.rc_recommendation_feedback(item_id, event_type, event_time DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_recommendation_feedback_user_event
|
||||
ON recommendation.rc_recommendation_feedback(user_id, event_type, event_time DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_recommendation_effect_daily_tenant_date
|
||||
ON recommendation.rc_recommendation_effect_daily(tenant_id, stat_date DESC);
|
||||
|
||||
DROP TABLE IF EXISTS recommendation.rc_student_profile_feature CASCADE;
|
||||
DROP TABLE IF EXISTS recommendation.rc_student_profile_snapshot CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS recommendation.rc_student_profile_snapshot (
|
||||
profile_id VARCHAR(64) PRIMARY KEY,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
profile_version VARCHAR(32) NOT NULL,
|
||||
profile_date DATE NOT NULL,
|
||||
feature_source_version VARCHAR(64),
|
||||
profile_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
confidence_score NUMERIC(6,4),
|
||||
profile_status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_rc_student_profile_snapshot_user_version
|
||||
UNIQUE (user_id, profile_version),
|
||||
CONSTRAINT chk_rc_student_profile_snapshot_json
|
||||
CHECK (jsonb_typeof(profile_json) = 'object'),
|
||||
CONSTRAINT chk_rc_student_profile_snapshot_status
|
||||
CHECK (profile_status IN ('ACTIVE', 'ARCHIVED')),
|
||||
CONSTRAINT fk_rc_student_profile_snapshot_user
|
||||
FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id)
|
||||
);
|
||||
COMMENT ON TABLE recommendation.rc_student_profile_snapshot IS '学员画像快照表';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_snapshot.profile_id IS '画像ID';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_snapshot.user_id IS '学员ID';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_snapshot.profile_version IS '画像版本';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_snapshot.profile_date IS '画像日期';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_snapshot.feature_source_version IS '特征来源版本';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_snapshot.profile_json IS '画像JSON';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_snapshot.confidence_score IS '画像置信度';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_snapshot.profile_status IS '画像状态';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_snapshot.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_snapshot.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_snapshot.updated_at IS '更新时间';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recommendation.rc_student_profile_feature (
|
||||
feature_id VARCHAR(64) PRIMARY KEY,
|
||||
profile_id VARCHAR(64) NOT NULL,
|
||||
feature_group VARCHAR(32) NOT NULL,
|
||||
feature_key VARCHAR(64) NOT NULL,
|
||||
feature_value_num NUMERIC(18,6),
|
||||
feature_value_text VARCHAR(512),
|
||||
feature_value_json JSONB,
|
||||
value_type VARCHAR(16) NOT NULL DEFAULT 'NUM',
|
||||
source_domain VARCHAR(32) NOT NULL,
|
||||
source_ref_id VARCHAR(64),
|
||||
sample_time TIMESTAMP,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_rc_student_profile_feature_value_type
|
||||
CHECK (value_type IN ('NUM', 'TEXT', 'JSON', 'BOOL')),
|
||||
CONSTRAINT chk_rc_student_profile_feature_source_domain
|
||||
CHECK (source_domain IN ('COURSE', 'HOMEWORK', 'GRADING', 'REVIEW', 'RECOMMENDATION', 'ACHIEVEMENT', 'SYSTEM')),
|
||||
CONSTRAINT chk_rc_student_profile_feature_json
|
||||
CHECK (feature_value_json IS NULL OR jsonb_typeof(feature_value_json) IN ('object', 'array', 'string', 'number', 'boolean')),
|
||||
CONSTRAINT fk_rc_student_profile_feature_profile
|
||||
FOREIGN KEY (profile_id) REFERENCES recommendation.rc_student_profile_snapshot(profile_id) ON DELETE CASCADE
|
||||
);
|
||||
COMMENT ON TABLE recommendation.rc_student_profile_feature IS '学员画像特征明细表';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_feature.feature_id IS '特征ID';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_feature.profile_id IS '画像ID';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_feature.feature_group IS '特征组';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_feature.feature_key IS '特征键';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_feature.feature_value_num IS '数值特征值';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_feature.feature_value_text IS '文本特征值';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_feature.feature_value_json IS 'JSON特征值';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_feature.value_type IS '值类型';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_feature.source_domain IS '来源域';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_feature.source_ref_id IS '来源对象ID';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_feature.sample_time IS '采样时间';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_feature.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_student_profile_feature.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS recommendation.rc_learning_loop_event CASCADE;
|
||||
DROP TABLE IF EXISTS recommendation.rc_learning_loop_case CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS recommendation.rc_learning_loop_case (
|
||||
loop_case_id VARCHAR(64) PRIMARY KEY,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
wrong_question_id VARCHAR(64) NOT NULL,
|
||||
review_plan_id VARCHAR(64),
|
||||
profile_id VARCHAR(64),
|
||||
recommendation_task_id VARCHAR(64),
|
||||
recommendation_item_id VARCHAR(64),
|
||||
feedback_id VARCHAR(64),
|
||||
user_achievement_id VARCHAR(64),
|
||||
loop_status VARCHAR(16) NOT NULL DEFAULT 'OPEN',
|
||||
effect_score NUMERIC(10,4),
|
||||
opened_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
closed_at TIMESTAMP,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_rc_learning_loop_case_status
|
||||
CHECK (loop_status IN ('OPEN', 'IN_PROGRESS', 'CLOSED', 'FAILED')),
|
||||
CONSTRAINT chk_rc_learning_loop_case_closed_at
|
||||
CHECK (closed_at IS NULL OR closed_at >= opened_at),
|
||||
CONSTRAINT fk_rc_learning_loop_case_user
|
||||
FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id),
|
||||
CONSTRAINT fk_rc_learning_loop_case_wrong_question
|
||||
FOREIGN KEY (wrong_question_id) REFERENCES question.gd_wrong_question(wrong_question_id),
|
||||
CONSTRAINT fk_rc_learning_loop_case_review_plan
|
||||
FOREIGN KEY (review_plan_id) REFERENCES question.gd_review_plan(review_plan_id),
|
||||
CONSTRAINT fk_rc_learning_loop_case_profile
|
||||
FOREIGN KEY (profile_id) REFERENCES recommendation.rc_student_profile_snapshot(profile_id),
|
||||
CONSTRAINT fk_rc_learning_loop_case_recommendation_task
|
||||
FOREIGN KEY (recommendation_task_id) REFERENCES recommendation.rc_recommendation_task(task_id),
|
||||
CONSTRAINT fk_rc_learning_loop_case_recommendation_item
|
||||
FOREIGN KEY (recommendation_item_id) REFERENCES recommendation.rc_recommendation_item(item_id),
|
||||
CONSTRAINT fk_rc_learning_loop_case_feedback
|
||||
FOREIGN KEY (feedback_id) REFERENCES recommendation.rc_recommendation_feedback(feedback_id),
|
||||
CONSTRAINT fk_rc_learning_loop_case_user_achievement
|
||||
FOREIGN KEY (user_achievement_id) REFERENCES achievement.ac_user_achievement(user_achievement_id)
|
||||
);
|
||||
COMMENT ON TABLE recommendation.rc_learning_loop_case IS '学习闭环主表(错题-复习-推荐-成就)';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.loop_case_id IS '闭环案例ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.user_id IS '用户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.wrong_question_id IS '错题ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.review_plan_id IS '复习计划ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.profile_id IS '画像ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.recommendation_task_id IS '推荐任务ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.recommendation_item_id IS '推荐项ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.feedback_id IS '反馈事件ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.user_achievement_id IS '成就记录ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.loop_status IS '闭环状态';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.effect_score IS '闭环效果分';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.opened_at IS '闭环开启时间';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.closed_at IS '闭环关闭时间';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_case.updated_at IS '更新时间';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recommendation.rc_learning_loop_event (
|
||||
loop_event_id VARCHAR(64) PRIMARY KEY,
|
||||
loop_case_id VARCHAR(64) NOT NULL,
|
||||
stage_code VARCHAR(32) NOT NULL,
|
||||
stage_status VARCHAR(16) NOT NULL DEFAULT 'DONE',
|
||||
event_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
event_score NUMERIC(10,4),
|
||||
event_detail_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_rc_learning_loop_event_stage_code
|
||||
CHECK (stage_code IN ('WRONG_CAPTURED', 'REVIEW_PLANNED', 'PROFILE_UPDATED', 'RECOMMENDED', 'EXPOSED', 'ENGAGED', 'REVIEW_COMPLETED', 'ACHIEVED')),
|
||||
CONSTRAINT chk_rc_learning_loop_event_stage_status
|
||||
CHECK (stage_status IN ('PENDING', 'DONE', 'FAILED', 'SKIPPED')),
|
||||
CONSTRAINT chk_rc_learning_loop_event_detail_json
|
||||
CHECK (jsonb_typeof(event_detail_json) = 'object'),
|
||||
CONSTRAINT fk_rc_learning_loop_event_case
|
||||
FOREIGN KEY (loop_case_id) REFERENCES recommendation.rc_learning_loop_case(loop_case_id) ON DELETE CASCADE
|
||||
);
|
||||
COMMENT ON TABLE recommendation.rc_learning_loop_event IS '学习闭环阶段事件表';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_event.loop_event_id IS '闭环事件ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_event.loop_case_id IS '闭环案例ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_event.stage_code IS '阶段编码';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_event.stage_status IS '阶段状态';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_event.event_time IS '事件时间';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_event.event_score IS '阶段得分';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_event.event_detail_json IS '事件详情JSON';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_event.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_event.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS recommendation.rc_learning_loop_effect_daily CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS recommendation.rc_learning_loop_effect_daily (
|
||||
stat_date DATE NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
opened_case_count BIGINT NOT NULL DEFAULT 0,
|
||||
closed_case_count BIGINT NOT NULL DEFAULT 0,
|
||||
achieved_case_count BIGINT NOT NULL DEFAULT 0,
|
||||
avg_effect_score NUMERIC(10,4) NOT NULL DEFAULT 0,
|
||||
avg_close_hours NUMERIC(10,4) NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (stat_date, tenant_id)
|
||||
);
|
||||
COMMENT ON TABLE recommendation.rc_learning_loop_effect_daily IS '学习闭环效果日统计表';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_effect_daily.stat_date IS '统计日期';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_effect_daily.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_effect_daily.opened_case_count IS '开启案例数';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_effect_daily.closed_case_count IS '关闭案例数';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_effect_daily.achieved_case_count IS '达成成就案例数';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_effect_daily.avg_effect_score IS '平均效果分';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_effect_daily.avg_close_hours IS '平均闭环时长(小时)';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_effect_daily.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN recommendation.rc_learning_loop_effect_daily.updated_at IS '更新时间';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_student_profile_snapshot_user_date
|
||||
ON recommendation.rc_student_profile_snapshot(user_id, profile_date DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_student_profile_snapshot_tenant_version
|
||||
ON recommendation.rc_student_profile_snapshot(tenant_id, profile_version, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_student_profile_feature_profile_group
|
||||
ON recommendation.rc_student_profile_feature(profile_id, feature_group, feature_key);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_student_profile_feature_source
|
||||
ON recommendation.rc_student_profile_feature(source_domain, source_ref_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_learning_loop_case_user_status
|
||||
ON recommendation.rc_learning_loop_case(user_id, loop_status, opened_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_learning_loop_case_wrong_question
|
||||
ON recommendation.rc_learning_loop_case(wrong_question_id, opened_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_learning_loop_case_tenant_status
|
||||
ON recommendation.rc_learning_loop_case(tenant_id, loop_status, opened_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_learning_loop_event_case_stage_time
|
||||
ON recommendation.rc_learning_loop_event(loop_case_id, stage_code, event_time DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_learning_loop_event_tenant_time
|
||||
ON recommendation.rc_learning_loop_event(tenant_id, event_time DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_learning_loop_effect_daily_tenant_date
|
||||
ON recommendation.rc_learning_loop_effect_daily(tenant_id, stat_date DESC);
|
||||
|
||||
DROP TABLE IF EXISTS recommendation.rc_loop_metric_map CASCADE;
|
||||
DROP TABLE IF EXISTS recommendation.rc_loop_stage_achievement_map CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS recommendation.rc_loop_stage_achievement_map (
|
||||
stage_map_id VARCHAR(64) PRIMARY KEY,
|
||||
stage_code VARCHAR(32) NOT NULL,
|
||||
event_code VARCHAR(64) NOT NULL,
|
||||
template_id VARCHAR(64),
|
||||
metric_id VARCHAR(64),
|
||||
award_source VARCHAR(32) NOT NULL DEFAULT 'RULE_ENGINE',
|
||||
priority INTEGER NOT NULL DEFAULT 100,
|
||||
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
ext_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_rc_loop_stage_achievement_map
|
||||
UNIQUE (tenant_id, stage_code, event_code, priority),
|
||||
CONSTRAINT chk_rc_loop_stage_achievement_map_stage_code
|
||||
CHECK (stage_code IN ('WRONG_CAPTURED', 'REVIEW_PLANNED', 'PROFILE_UPDATED', 'RECOMMENDED', 'EXPOSED', 'ENGAGED', 'REVIEW_COMPLETED', 'ACHIEVED')),
|
||||
CONSTRAINT chk_rc_loop_stage_achievement_map_award_source
|
||||
CHECK (award_source IN ('RULE_ENGINE', 'MANUAL', 'SYSTEM')),
|
||||
CONSTRAINT chk_rc_loop_stage_achievement_map_ext_json
|
||||
CHECK (jsonb_typeof(ext_json) = 'object'),
|
||||
CONSTRAINT fk_rc_loop_stage_achievement_map_event
|
||||
FOREIGN KEY (event_code) REFERENCES achievement.ac_achievement_event_dict(event_code),
|
||||
CONSTRAINT fk_rc_loop_stage_achievement_map_template
|
||||
FOREIGN KEY (template_id) REFERENCES achievement.ac_achievement_rule_template(template_id),
|
||||
CONSTRAINT fk_rc_loop_stage_achievement_map_metric
|
||||
FOREIGN KEY (metric_id) REFERENCES achievement.ac_achievement_metric_def(metric_id)
|
||||
);
|
||||
COMMENT ON TABLE recommendation.rc_loop_stage_achievement_map IS '闭环阶段到成就事件映射表(通用配置)';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_stage_achievement_map.stage_map_id IS '阶段映射ID';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_stage_achievement_map.stage_code IS '闭环阶段编码';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_stage_achievement_map.event_code IS '成就事件编码';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_stage_achievement_map.template_id IS '成就规则模板ID';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_stage_achievement_map.metric_id IS '成就指标ID';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_stage_achievement_map.award_source IS '发放来源';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_stage_achievement_map.priority IS '优先级';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_stage_achievement_map.enabled IS '是否启用';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_stage_achievement_map.ext_json IS '扩展配置JSON';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_stage_achievement_map.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_stage_achievement_map.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_stage_achievement_map.updated_at IS '更新时间';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recommendation.rc_loop_metric_map (
|
||||
metric_map_id VARCHAR(64) PRIMARY KEY,
|
||||
stage_code VARCHAR(32) NOT NULL,
|
||||
metric_id VARCHAR(64) NOT NULL,
|
||||
source_field VARCHAR(64) NOT NULL,
|
||||
agg_method VARCHAR(16) NOT NULL DEFAULT 'LATEST',
|
||||
weight NUMERIC(6,4) NOT NULL DEFAULT 1.0000,
|
||||
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
ext_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT uq_rc_loop_metric_map
|
||||
UNIQUE (tenant_id, stage_code, metric_id, source_field),
|
||||
CONSTRAINT chk_rc_loop_metric_map_stage_code
|
||||
CHECK (stage_code IN ('WRONG_CAPTURED', 'REVIEW_PLANNED', 'PROFILE_UPDATED', 'RECOMMENDED', 'EXPOSED', 'ENGAGED', 'REVIEW_COMPLETED', 'ACHIEVED')),
|
||||
CONSTRAINT chk_rc_loop_metric_map_agg_method
|
||||
CHECK (agg_method IN ('LATEST', 'SUM', 'AVG', 'MAX', 'MIN', 'COUNT')),
|
||||
CONSTRAINT chk_rc_loop_metric_map_weight
|
||||
CHECK (weight > 0 AND weight <= 1),
|
||||
CONSTRAINT chk_rc_loop_metric_map_ext_json
|
||||
CHECK (jsonb_typeof(ext_json) = 'object'),
|
||||
CONSTRAINT fk_rc_loop_metric_map_metric
|
||||
FOREIGN KEY (metric_id) REFERENCES achievement.ac_achievement_metric_def(metric_id)
|
||||
);
|
||||
COMMENT ON TABLE recommendation.rc_loop_metric_map IS '闭环指标映射表(通用配置)';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_metric_map.metric_map_id IS '指标映射ID';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_metric_map.stage_code IS '闭环阶段编码';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_metric_map.metric_id IS '成就指标ID';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_metric_map.source_field IS '来源字段名';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_metric_map.agg_method IS '聚合方法';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_metric_map.weight IS '权重';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_metric_map.enabled IS '是否启用';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_metric_map.ext_json IS '扩展配置JSON';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_metric_map.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_metric_map.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN recommendation.rc_loop_metric_map.updated_at IS '更新时间';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_loop_stage_achievement_map_tenant_stage
|
||||
ON recommendation.rc_loop_stage_achievement_map(tenant_id, stage_code, enabled, priority);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_loop_stage_achievement_map_event
|
||||
ON recommendation.rc_loop_stage_achievement_map(event_code, tenant_id, enabled);
|
||||
CREATE INDEX IF NOT EXISTS idx_rc_loop_metric_map_tenant_stage
|
||||
ON recommendation.rc_loop_metric_map(tenant_id, stage_code, enabled);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
-- 学校租户表
|
||||
DROP TABLE IF EXISTS upms.tb_sys_tenant CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_sys_tenant (
|
||||
tenant_id VARCHAR(64) PRIMARY KEY,
|
||||
parent_tenant_id VARCHAR(64),
|
||||
@@ -19,6 +20,7 @@ COMMENT ON COLUMN upms.tb_sys_tenant.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_tenant.status IS '租户状态';
|
||||
COMMENT ON COLUMN upms.tb_sys_tenant.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS upms.tb_sys_dept CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_sys_dept (
|
||||
dept_id VARCHAR(64) PRIMARY KEY,
|
||||
parent_dept_id VARCHAR(64),
|
||||
@@ -41,6 +43,10 @@ COMMENT ON COLUMN upms.tb_sys_dept.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_dept.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_dept.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS upms.tb_school_class_course_rel CASCADE;
|
||||
DROP TABLE IF EXISTS upms.tb_school_class_member CASCADE;
|
||||
DROP TABLE IF EXISTS upms.tb_school_class CASCADE;
|
||||
DROP TABLE IF EXISTS upms.tb_sys_user CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_sys_user (
|
||||
user_id VARCHAR(64) PRIMARY KEY,
|
||||
username VARCHAR(64) UNIQUE NOT NULL,
|
||||
@@ -66,7 +72,132 @@ COMMENT ON COLUMN upms.tb_sys_user.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_user.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_user.status IS '用户状态';
|
||||
COMMENT ON COLUMN upms.tb_sys_user.created_at IS '创建时间';
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_school_class (
|
||||
class_id VARCHAR(64) PRIMARY KEY,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
dept_id VARCHAR(64) NOT NULL,
|
||||
class_code VARCHAR(64),
|
||||
class_name VARCHAR(128) NOT NULL,
|
||||
grade_code VARCHAR(32),
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'ACTIVE',
|
||||
adcode VARCHAR(12),
|
||||
tenant_path VARCHAR(255),
|
||||
dept_path VARCHAR(255),
|
||||
created_by VARCHAR(64),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_school_class_status
|
||||
CHECK (status IN ('ACTIVE', 'INACTIVE', 'ARCHIVED')),
|
||||
CONSTRAINT fk_school_class_dept
|
||||
FOREIGN KEY (dept_id) REFERENCES upms.tb_sys_dept(dept_id),
|
||||
CONSTRAINT fk_school_class_created_by
|
||||
FOREIGN KEY (created_by) REFERENCES upms.tb_sys_user(user_id)
|
||||
);
|
||||
COMMENT ON TABLE upms.tb_school_class IS '班级主表';
|
||||
COMMENT ON COLUMN upms.tb_school_class.class_id IS '班级ID';
|
||||
COMMENT ON COLUMN upms.tb_school_class.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN upms.tb_school_class.dept_id IS '所属部门ID';
|
||||
COMMENT ON COLUMN upms.tb_school_class.class_code IS '班级编码';
|
||||
COMMENT ON COLUMN upms.tb_school_class.class_name IS '班级名称';
|
||||
COMMENT ON COLUMN upms.tb_school_class.grade_code IS '年级编码';
|
||||
COMMENT ON COLUMN upms.tb_school_class.status IS '班级状态';
|
||||
COMMENT ON COLUMN upms.tb_school_class.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN upms.tb_school_class.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN upms.tb_school_class.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN upms.tb_school_class.created_by IS '创建人';
|
||||
COMMENT ON COLUMN upms.tb_school_class.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN upms.tb_school_class.updated_at IS '更新时间';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_school_class_member (
|
||||
class_id VARCHAR(64) NOT NULL,
|
||||
user_id VARCHAR(64) NOT NULL,
|
||||
member_role VARCHAR(16) NOT NULL DEFAULT 'STUDENT',
|
||||
member_status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
joined_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
left_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (class_id, user_id),
|
||||
CONSTRAINT chk_school_class_member_role
|
||||
CHECK (member_role IN ('STUDENT', 'HEAD_TEACHER', 'TEACHER', 'ASSISTANT')),
|
||||
CONSTRAINT chk_school_class_member_status
|
||||
CHECK (member_status IN ('ACTIVE', 'LEFT', 'SUSPENDED')),
|
||||
CONSTRAINT chk_school_class_member_left_at
|
||||
CHECK (left_at IS NULL OR left_at >= joined_at),
|
||||
CONSTRAINT fk_school_class_member_class
|
||||
FOREIGN KEY (class_id) REFERENCES upms.tb_school_class(class_id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_school_class_member_user
|
||||
FOREIGN KEY (user_id) REFERENCES upms.tb_sys_user(user_id)
|
||||
);
|
||||
COMMENT ON TABLE upms.tb_school_class_member IS '班级成员表';
|
||||
COMMENT ON COLUMN upms.tb_school_class_member.class_id IS '班级ID';
|
||||
COMMENT ON COLUMN upms.tb_school_class_member.user_id IS '成员用户ID';
|
||||
COMMENT ON COLUMN upms.tb_school_class_member.member_role IS '成员角色';
|
||||
COMMENT ON COLUMN upms.tb_school_class_member.member_status IS '成员状态';
|
||||
COMMENT ON COLUMN upms.tb_school_class_member.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN upms.tb_school_class_member.joined_at IS '加入时间';
|
||||
COMMENT ON COLUMN upms.tb_school_class_member.left_at IS '离开时间';
|
||||
COMMENT ON COLUMN upms.tb_school_class_member.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN upms.tb_school_class_member.updated_at IS '更新时间';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_school_class_course_rel (
|
||||
class_id VARCHAR(64) NOT NULL,
|
||||
course_id VARCHAR(64) NOT NULL,
|
||||
relation_status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (class_id, course_id),
|
||||
CONSTRAINT chk_school_class_course_rel_status
|
||||
CHECK (relation_status IN ('ACTIVE', 'INACTIVE')),
|
||||
CONSTRAINT fk_school_class_course_rel_class
|
||||
FOREIGN KEY (class_id) REFERENCES upms.tb_school_class(class_id) ON DELETE CASCADE
|
||||
);
|
||||
COMMENT ON TABLE upms.tb_school_class_course_rel IS '班级课程关联表';
|
||||
COMMENT ON COLUMN upms.tb_school_class_course_rel.class_id IS '班级ID';
|
||||
COMMENT ON COLUMN upms.tb_school_class_course_rel.course_id IS '课程ID';
|
||||
COMMENT ON COLUMN upms.tb_school_class_course_rel.relation_status IS '关联状态';
|
||||
COMMENT ON COLUMN upms.tb_school_class_course_rel.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN upms.tb_school_class_course_rel.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN upms.tb_school_class_course_rel.updated_at IS '更新时间';
|
||||
|
||||
DROP TABLE IF EXISTS upms.tb_sys_file CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_sys_file (
|
||||
file_id VARCHAR(64) PRIMARY KEY,
|
||||
media_type VARCHAR(32) NOT NULL,
|
||||
object_key VARCHAR(512) NOT NULL,
|
||||
file_name VARCHAR(256),
|
||||
mime_type VARCHAR(128),
|
||||
file_size BIGINT,
|
||||
file_hash VARCHAR(128),
|
||||
duration_ms INTEGER,
|
||||
uploaded_by VARCHAR(64),
|
||||
adcode VARCHAR(12),
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_sys_file_media_type
|
||||
CHECK (media_type IN ('IMAGE', 'AUDIO', 'VIDEO', 'DOCUMENT', 'OTHER')),
|
||||
CONSTRAINT fk_sys_file_uploaded_by
|
||||
FOREIGN KEY (uploaded_by) REFERENCES upms.tb_sys_user(user_id)
|
||||
);
|
||||
COMMENT ON TABLE upms.tb_sys_file IS '系统文件资源表';
|
||||
COMMENT ON COLUMN upms.tb_sys_file.file_id IS '文件ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_file.media_type IS '媒体类型';
|
||||
COMMENT ON COLUMN upms.tb_sys_file.object_key IS '对象存储Key';
|
||||
COMMENT ON COLUMN upms.tb_sys_file.file_name IS '文件名';
|
||||
COMMENT ON COLUMN upms.tb_sys_file.mime_type IS 'MIME类型';
|
||||
COMMENT ON COLUMN upms.tb_sys_file.file_size IS '文件大小(字节)';
|
||||
COMMENT ON COLUMN upms.tb_sys_file.file_hash IS '文件哈希';
|
||||
COMMENT ON COLUMN upms.tb_sys_file.duration_ms IS '音频/视频时长(毫秒)';
|
||||
COMMENT ON COLUMN upms.tb_sys_file.uploaded_by IS '上传人ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_file.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN upms.tb_sys_file.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_file.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_file.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS upms.tb_sys_role CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_sys_role (
|
||||
role_id VARCHAR(64) PRIMARY KEY,
|
||||
role_code VARCHAR(64) UNIQUE NOT NULL,
|
||||
@@ -89,28 +220,8 @@ COMMENT ON COLUMN upms.tb_sys_role.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_role.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_role.created_at IS '创建时间';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_sys_permission (
|
||||
permission_id VARCHAR(64) PRIMARY KEY,
|
||||
permission_code VARCHAR(128) UNIQUE NOT NULL,
|
||||
permission_name VARCHAR(128) NOT NULL,
|
||||
adcode VARCHAR(12) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255) NOT NULL,
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
COMMENT ON TABLE upms.tb_sys_permission IS '权限表';
|
||||
COMMENT ON COLUMN upms.tb_sys_permission.permission_id IS '权限ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_permission.permission_code IS '权限编码';
|
||||
COMMENT ON COLUMN upms.tb_sys_permission.permission_name IS '权限名称';
|
||||
COMMENT ON COLUMN upms.tb_sys_permission.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN upms.tb_sys_permission.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_permission.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_permission.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_permission.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_permission.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS upms.tb_sys_menu CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_sys_menu (
|
||||
route_id VARCHAR(64) PRIMARY KEY,
|
||||
parent_route_id VARCHAR(64),
|
||||
@@ -146,8 +257,181 @@ COMMENT ON COLUMN upms.tb_sys_menu.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_menu.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_menu.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_menu.created_at IS '创建时间';
|
||||
DROP TABLE IF EXISTS upms.tb_sys_role_menu CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_sys_role_menu (
|
||||
role_id VARCHAR(64) NOT NULL,
|
||||
route_id VARCHAR(64) NOT NULL,
|
||||
adcode VARCHAR(12) NOT NULL,
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255) NOT NULL,
|
||||
dept_id VARCHAR(64),
|
||||
dept_path VARCHAR(255),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (role_id, route_id)
|
||||
);
|
||||
COMMENT ON TABLE upms.tb_sys_role_menu IS '角色菜单授权表';
|
||||
COMMENT ON COLUMN upms.tb_sys_role_menu.role_id IS '角色ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_role_menu.route_id IS '路由ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_role_menu.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN upms.tb_sys_role_menu.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_role_menu.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_role_menu.dept_id IS '部门ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_role_menu.dept_path IS '部门路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_role_menu.created_at IS '创建时间';
|
||||
|
||||
DROP TABLE IF EXISTS upms.tb_sys_area CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_sys_area (
|
||||
id BIGINT PRIMARY KEY,
|
||||
pid BIGINT NOT NULL,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
letter VARCHAR(32),
|
||||
adcode BIGINT NOT NULL,
|
||||
location VARCHAR(255),
|
||||
area_sort INTEGER,
|
||||
area_status VARCHAR(8) NOT NULL DEFAULT '1',
|
||||
area_type VARCHAR(8) NOT NULL DEFAULT '2',
|
||||
hot VARCHAR(8) NOT NULL DEFAULT '0',
|
||||
city_code VARCHAR(16),
|
||||
create_by VARCHAR(64),
|
||||
create_time TIMESTAMP,
|
||||
update_by VARCHAR(64),
|
||||
update_time TIMESTAMP,
|
||||
del_flag VARCHAR(8) NOT NULL DEFAULT '0'
|
||||
);
|
||||
COMMENT ON TABLE upms.tb_sys_area IS '行政区划表';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.id IS '主键ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.pid IS '父级行政区划编码';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.name IS '名称';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.letter IS '首字母';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.location IS '经纬度';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.area_sort IS '排序';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.area_status IS '状态';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.area_type IS '层级类型';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.hot IS '是否热门';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.city_code IS '城市区号';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.create_by IS '创建人';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.create_time IS '创建时间';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.update_by IS '更新人';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.update_time IS '更新时间';
|
||||
COMMENT ON COLUMN upms.tb_sys_area.del_flag IS '删除标记';
|
||||
DROP TABLE IF EXISTS upms.tb_sys_message_recipient CASCADE;
|
||||
DROP TABLE IF EXISTS upms.tb_sys_message CASCADE;
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_sys_message (
|
||||
message_id VARCHAR(64) PRIMARY KEY,
|
||||
message_type VARCHAR(32) NOT NULL DEFAULT 'INFO',
|
||||
biz_type VARCHAR(64) NOT NULL,
|
||||
title VARCHAR(256) NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
content_object_type VARCHAR(64) NOT NULL,
|
||||
content_object_id VARCHAR(64) NOT NULL,
|
||||
web_jump_url VARCHAR(512) NOT NULL,
|
||||
send_channel VARCHAR(16) NOT NULL DEFAULT 'INBOX',
|
||||
sender_user_id VARCHAR(64),
|
||||
adcode VARCHAR(12),
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255),
|
||||
message_status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
|
||||
send_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
expire_at TIMESTAMP,
|
||||
ext_json JSONB NOT NULL DEFAULT '{}'::JSONB,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT chk_sys_message_type
|
||||
CHECK (message_type IN ('TODO', 'INFO', 'ALERT', 'SYSTEM')),
|
||||
CONSTRAINT chk_sys_message_channel
|
||||
CHECK (send_channel IN ('INBOX')),
|
||||
CONSTRAINT chk_sys_message_status
|
||||
CHECK (message_status IN ('ACTIVE', 'CANCELLED', 'EXPIRED')),
|
||||
CONSTRAINT chk_sys_message_url
|
||||
CHECK (web_jump_url LIKE '/%'),
|
||||
CONSTRAINT chk_sys_message_expire
|
||||
CHECK (expire_at IS NULL OR expire_at >= send_at),
|
||||
CONSTRAINT chk_sys_message_ext_json
|
||||
CHECK (jsonb_typeof(ext_json) = 'object'),
|
||||
CONSTRAINT fk_sys_message_sender
|
||||
FOREIGN KEY (sender_user_id) REFERENCES upms.tb_sys_user(user_id)
|
||||
);
|
||||
COMMENT ON TABLE upms.tb_sys_message IS '站内信消息主表';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.message_id IS '消息ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.message_type IS '消息类型(TODO/INFO/ALERT/SYSTEM)';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.biz_type IS '业务类型(如 SUBJECTIVE_REVIEW)';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.title IS '消息标题';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.content IS '消息正文';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.content_object_type IS '内容对象类型(如 GRADING_TASK/TENANT)';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.content_object_id IS '内容对象ID(用于业务定位)';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.web_jump_url IS 'Web跳转URL(前端点击消息后跳转)';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.send_channel IS '发送通道(当前仅INBOX)';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.sender_user_id IS '发送人ID(系统消息可为空)';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.adcode IS '行政区划编码';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.message_status IS '消息状态(ACTIVE/CANCELLED/EXPIRED)';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.send_at IS '发送时间';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.expire_at IS '过期时间';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.ext_json IS '扩展字段JSON';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN upms.tb_sys_message.updated_at IS '更新时间';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS upms.tb_sys_message_recipient (
|
||||
message_id VARCHAR(64) NOT NULL,
|
||||
recipient_user_id VARCHAR(64) NOT NULL,
|
||||
delivery_status VARCHAR(16) NOT NULL DEFAULT 'DELIVERED',
|
||||
read_status VARCHAR(16) NOT NULL DEFAULT 'UNREAD',
|
||||
read_at TIMESTAMP,
|
||||
clicked_at TIMESTAMP,
|
||||
read_source VARCHAR(16),
|
||||
tenant_id VARCHAR(64) NOT NULL,
|
||||
tenant_path VARCHAR(255),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (message_id, recipient_user_id),
|
||||
CONSTRAINT chk_sys_message_recipient_delivery
|
||||
CHECK (delivery_status IN ('DELIVERED', 'FAILED', 'RECALLED')),
|
||||
CONSTRAINT chk_sys_message_recipient_read
|
||||
CHECK (read_status IN ('UNREAD', 'READ', 'ARCHIVED')),
|
||||
CONSTRAINT chk_sys_message_recipient_read_source
|
||||
CHECK (read_source IS NULL OR read_source IN ('WEB', 'APP', 'MINI_PROGRAM')),
|
||||
CONSTRAINT chk_sys_message_recipient_read_at
|
||||
CHECK (
|
||||
(read_status = 'UNREAD' AND read_at IS NULL)
|
||||
OR (read_status IN ('READ', 'ARCHIVED') AND read_at IS NOT NULL)
|
||||
),
|
||||
CONSTRAINT chk_sys_message_recipient_click_at
|
||||
CHECK (clicked_at IS NULL OR read_at IS NULL OR clicked_at >= read_at),
|
||||
CONSTRAINT fk_sys_message_recipient_message
|
||||
FOREIGN KEY (message_id) REFERENCES upms.tb_sys_message(message_id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_sys_message_recipient_user
|
||||
FOREIGN KEY (recipient_user_id) REFERENCES upms.tb_sys_user(user_id)
|
||||
);
|
||||
COMMENT ON TABLE upms.tb_sys_message_recipient IS '站内信收件人状态表';
|
||||
COMMENT ON COLUMN upms.tb_sys_message_recipient.message_id IS '消息ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_message_recipient.recipient_user_id IS '收件人用户ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_message_recipient.delivery_status IS '投递状态(DELIVERED/FAILED/RECALLED)';
|
||||
COMMENT ON COLUMN upms.tb_sys_message_recipient.read_status IS '读取状态(UNREAD/READ/ARCHIVED)';
|
||||
COMMENT ON COLUMN upms.tb_sys_message_recipient.read_at IS '读取时间';
|
||||
COMMENT ON COLUMN upms.tb_sys_message_recipient.clicked_at IS '点击跳转时间';
|
||||
COMMENT ON COLUMN upms.tb_sys_message_recipient.read_source IS '读取来源(WEB/APP/MINI_PROGRAM)';
|
||||
COMMENT ON COLUMN upms.tb_sys_message_recipient.tenant_id IS '租户ID';
|
||||
COMMENT ON COLUMN upms.tb_sys_message_recipient.tenant_path IS '租户路径';
|
||||
COMMENT ON COLUMN upms.tb_sys_message_recipient.created_at IS '创建时间';
|
||||
COMMENT ON COLUMN upms.tb_sys_message_recipient.updated_at IS '更新时间';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_tenant_adcode ON upms.tb_sys_tenant(adcode);
|
||||
CREATE INDEX IF NOT EXISTS idx_dept_tenant ON upms.tb_sys_dept(tenant_id, dept_path);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_tenant ON upms.tb_sys_user(tenant_id, dept_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_school_class_tenant_dept ON upms.tb_school_class(tenant_id, dept_id, grade_code);
|
||||
CREATE INDEX IF NOT EXISTS idx_school_class_member_tenant_user ON upms.tb_school_class_member(tenant_id, user_id, member_status);
|
||||
CREATE INDEX IF NOT EXISTS idx_school_class_course_rel_tenant_course ON upms.tb_school_class_course_rel(tenant_id, course_id, relation_status);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_file_tenant_media ON upms.tb_sys_file(tenant_id, media_type, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_file_uploaded_by ON upms.tb_sys_file(uploaded_by, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_route_tenant ON upms.tb_sys_menu(tenant_id, route_path);
|
||||
CREATE INDEX IF NOT EXISTS idx_role_menu_tenant ON upms.tb_sys_role_menu(tenant_id, role_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_area_pid ON upms.tb_sys_area(pid);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_area_adcode ON upms.tb_sys_area(adcode);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_message_tenant_biz ON upms.tb_sys_message(tenant_id, biz_type, send_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_message_object ON upms.tb_sys_message(content_object_type, content_object_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_message_status_send_at ON upms.tb_sys_message(message_status, send_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_message_recipient_user_status ON upms.tb_sys_message_recipient(recipient_user_id, read_status, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_message_recipient_tenant_user ON upms.tb_sys_message_recipient(tenant_id, recipient_user_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_sys_message_recipient_unread ON upms.tb_sys_message_recipient(recipient_user_id, created_at DESC) WHERE read_status = 'UNREAD';
|
||||
|
||||
@@ -25,12 +25,6 @@ INSERT INTO upms.tb_sys_role (
|
||||
('ROLE-ORG-ADMIN', 'ORG_ADMIN', '机构管理员', '330100', 'SCH-HQ', '/SCH-HQ/', 'DEPT-HQ-ADMIN', '/DEPT-HQ/DEPT-HQ-ADMIN/')
|
||||
ON CONFLICT (role_id) DO NOTHING;
|
||||
|
||||
INSERT INTO upms.tb_sys_permission (
|
||||
permission_id, permission_code, permission_name, adcode, tenant_id, tenant_path, dept_id, dept_path
|
||||
) VALUES
|
||||
('PERM-DASHBOARD', 'dashboard:view', '查看控制台', '330100', 'SCH-HQ', '/SCH-HQ/', 'DEPT-HQ-ADMIN', '/DEPT-HQ/DEPT-HQ-ADMIN/'),
|
||||
('PERM-TENANT', 'tenant:view', '查看租户组织', '330100', 'SCH-HQ', '/SCH-HQ/', 'DEPT-HQ-ADMIN', '/DEPT-HQ/DEPT-HQ-ADMIN/')
|
||||
ON CONFLICT (permission_id) DO NOTHING;
|
||||
|
||||
INSERT INTO upms.tb_sys_menu (
|
||||
route_id, parent_route_id, route_path, route_name, component_key, layout_type, title, icon, permission_code,
|
||||
@@ -41,3 +35,84 @@ INSERT INTO upms.tb_sys_menu (
|
||||
('ROUTE-TENANT', NULL, '/tenant', 'tenant-management', 'tenant', 'SIDEBAR', '租户组织', 'building-2', 'tenant:view', FALSE,
|
||||
'330100', 'SCH-HQ', '/SCH-HQ/', 'DEPT-HQ-ADMIN', '/DEPT-HQ/DEPT-HQ-ADMIN/')
|
||||
ON CONFLICT (route_id) DO NOTHING;
|
||||
|
||||
INSERT INTO upms.tb_sys_role_menu (
|
||||
role_id, route_id, adcode, tenant_id, tenant_path, dept_id, dept_path
|
||||
) VALUES
|
||||
('ROLE-ORG-ADMIN', 'ROUTE-DASHBOARD', '330100', 'SCH-HQ', '/SCH-HQ/', 'DEPT-HQ-ADMIN', '/DEPT-HQ/DEPT-HQ-ADMIN/'),
|
||||
('ROLE-ORG-ADMIN', 'ROUTE-TENANT', '330100', 'SCH-HQ', '/SCH-HQ/', 'DEPT-HQ-ADMIN', '/DEPT-HQ/DEPT-HQ-ADMIN/')
|
||||
ON CONFLICT (role_id, route_id) DO NOTHING;
|
||||
|
||||
INSERT INTO upms.tb_sys_message (
|
||||
message_id, message_type, biz_type, title, content, content_object_type, content_object_id, web_jump_url,
|
||||
send_channel, sender_user_id, adcode, tenant_id, tenant_path, message_status, send_at, ext_json
|
||||
) VALUES
|
||||
(
|
||||
'MSG-20260415001',
|
||||
'TODO',
|
||||
'SUBJECTIVE_REVIEW',
|
||||
'有 1 份主观题待审阅',
|
||||
'高一数学《函数综合训练》有主观题待你审阅,请尽快处理。',
|
||||
'GRADING_TASK',
|
||||
'GD-TASK-20260415001',
|
||||
'/grading/review?gradingTaskId=GD-TASK-20260415001&messageId=MSG-20260415001',
|
||||
'INBOX',
|
||||
NULL,
|
||||
'330100',
|
||||
'SCH-HQ',
|
||||
'/SCH-HQ/',
|
||||
'ACTIVE',
|
||||
CURRENT_TIMESTAMP,
|
||||
'{"priority":"high","source":"grading"}'::JSONB
|
||||
),
|
||||
(
|
||||
'MSG-20260415002',
|
||||
'INFO',
|
||||
'TENANT_NOTICE',
|
||||
'杭州分校租户信息有更新',
|
||||
'杭州分校基础资料已更新,可进入租户组织页查看详情。',
|
||||
'TENANT',
|
||||
'SCH-ZJ-HZ-01',
|
||||
'/tenant?tenantId=SCH-ZJ-HZ-01&messageId=MSG-20260415002',
|
||||
'INBOX',
|
||||
NULL,
|
||||
'330100',
|
||||
'SCH-HQ',
|
||||
'/SCH-HQ/',
|
||||
'ACTIVE',
|
||||
CURRENT_TIMESTAMP,
|
||||
'{"priority":"normal","source":"upms"}'::JSONB
|
||||
)
|
||||
ON CONFLICT (message_id) DO NOTHING;
|
||||
|
||||
INSERT INTO upms.tb_sys_message_recipient (
|
||||
message_id, recipient_user_id, delivery_status, read_status, read_at, clicked_at, read_source,
|
||||
tenant_id, tenant_path, created_at, updated_at
|
||||
) VALUES
|
||||
(
|
||||
'MSG-20260415001',
|
||||
'U10001',
|
||||
'DELIVERED',
|
||||
'UNREAD',
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
'SCH-HQ',
|
||||
'/SCH-HQ/',
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP
|
||||
),
|
||||
(
|
||||
'MSG-20260415002',
|
||||
'U10001',
|
||||
'DELIVERED',
|
||||
'READ',
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP,
|
||||
'WEB',
|
||||
'SCH-HQ',
|
||||
'/SCH-HQ/',
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP
|
||||
)
|
||||
ON CONFLICT (message_id, recipient_user_id) DO NOTHING;
|
||||
|
||||
Reference in New Issue
Block a user